new plotter
This commit is contained in:
parent
2c0803da74
commit
b0608b8204
@ -282,5 +282,6 @@
|
|||||||
<string name="cpp_onscreen_remove_icon_message">You can remove second icon in applications\' list from application settings or by pressing next button</string>
|
<string name="cpp_onscreen_remove_icon_message">You can remove second icon in applications\' list from application settings or by pressing next button</string>
|
||||||
<string name="cpp_onscreen_remove_icon_button_text">Remove icon</string>
|
<string name="cpp_onscreen_remove_icon_button_text">Remove icon</string>
|
||||||
<string name="cpp_this_change_may_require_reboot">This change may require reboot</string>
|
<string name="cpp_this_change_may_require_reboot">This change may require reboot</string>
|
||||||
|
<string name="cpp_plot_3d">3D</string>
|
||||||
|
|
||||||
</resources>
|
</resources>
|
@ -85,7 +85,13 @@ public enum CalculatorDisplayMenuItem implements LabeledMenuItem<CalculatorDispl
|
|||||||
assert generic != null;
|
assert generic != null;
|
||||||
|
|
||||||
final List<Constant> variables = new ArrayList<Constant>(CalculatorUtils.getNotSystemConstants(generic));
|
final List<Constant> variables = new ArrayList<Constant>(CalculatorUtils.getNotSystemConstants(generic));
|
||||||
final Constant xVariable = variables.get(0);
|
|
||||||
|
final Constant xVariable;
|
||||||
|
if ( variables.size() > 0 ) {
|
||||||
|
xVariable = variables.get(0);
|
||||||
|
} else {
|
||||||
|
xVariable = null;
|
||||||
|
}
|
||||||
|
|
||||||
final Constant yVariable;
|
final Constant yVariable;
|
||||||
if ( variables.size() > 1 ) {
|
if ( variables.size() > 1 ) {
|
||||||
|
@ -15,7 +15,7 @@ public class PlotInput {
|
|||||||
@NotNull
|
@NotNull
|
||||||
private Generic function;
|
private Generic function;
|
||||||
|
|
||||||
@NotNull
|
@Nullable
|
||||||
private Constant xVariable;
|
private Constant xVariable;
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
@ -26,7 +26,7 @@ public class PlotInput {
|
|||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
public static PlotInput newInstance(@NotNull Generic function,
|
public static PlotInput newInstance(@NotNull Generic function,
|
||||||
@NotNull Constant xVariable,
|
@Nullable Constant xVariable,
|
||||||
@Nullable Constant yVariable) {
|
@Nullable Constant yVariable) {
|
||||||
PlotInput result = new PlotInput();
|
PlotInput result = new PlotInput();
|
||||||
|
|
||||||
@ -42,7 +42,7 @@ public class PlotInput {
|
|||||||
return function;
|
return function;
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
@Nullable
|
||||||
public Constant getXVariable() {
|
public Constant getXVariable() {
|
||||||
return xVariable;
|
return xVariable;
|
||||||
}
|
}
|
||||||
|
@ -8,8 +8,14 @@
|
|||||||
|
|
||||||
<menu xmlns:a="http://schemas.android.com/apk/res/android">
|
<menu xmlns:a="http://schemas.android.com/apk/res/android">
|
||||||
|
|
||||||
|
<item a:id="@+id/menu_plot_3d"
|
||||||
|
a:title="@string/cpp_plot_3d"
|
||||||
|
a:icon="@drawable/ab_icon"
|
||||||
|
a:showAsAction="always"/>
|
||||||
|
|
||||||
<item a:id="@+id/menu_plot_settings"
|
<item a:id="@+id/menu_plot_settings"
|
||||||
a:title="@string/c_settings"
|
a:title="@string/c_settings"
|
||||||
a:icon="@drawable/ab_settings"
|
a:icon="@drawable/ab_settings"
|
||||||
a:showAsAction="always"/>
|
a:showAsAction="always"/>
|
||||||
|
|
||||||
</menu>
|
</menu>
|
@ -48,9 +48,9 @@ public class AndroidCalculatorNotifier implements CalculatorNotifier {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void showDebugMessage(@Nullable final String tag, @NotNull final String message) {
|
public void showDebugMessage(@Nullable final String tag, @NotNull final String message) {
|
||||||
/*if (AndroidUtils.isDebuggable(application)) {
|
if (AndroidUtils.isDebuggable(application)) {
|
||||||
showMessageInUiThread(tag == null ? message : tag + ": " + message);
|
showMessageInUiThread(tag == null ? message : tag + ": " + message);
|
||||||
}*/
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void showMessageInUiThread(@NotNull final String message) {
|
private void showMessageInUiThread(@NotNull final String message) {
|
||||||
|
@ -102,11 +102,11 @@ public final class CalculatorActivityLauncher implements CalculatorEventListener
|
|||||||
|
|
||||||
public static void plotGraph(@NotNull final Context context,
|
public static void plotGraph(@NotNull final Context context,
|
||||||
@NotNull Generic generic,
|
@NotNull Generic generic,
|
||||||
@NotNull Constant xVariable,
|
@Nullable Constant xVariable,
|
||||||
@Nullable Constant yVariable){
|
@Nullable Constant yVariable){
|
||||||
final Intent intent = new Intent();
|
final Intent intent = new Intent();
|
||||||
intent.putExtra(ChartFactory.TITLE, context.getString(R.string.c_graph));
|
intent.putExtra(ChartFactory.TITLE, context.getString(R.string.c_graph));
|
||||||
final AbstractCalculatorPlotFragment.Input input = new CalculatorPlotFragment.Input(generic.toString(), xVariable.getName(), yVariable == null ? null : yVariable.getName());
|
final AbstractCalculatorPlotFragment.Input input = new CalculatorPlotFragment.Input(generic.toString(), xVariable == null ? null : xVariable.getName(), yVariable == null ? null : yVariable.getName());
|
||||||
intent.putExtra(CalculatorPlotFragment.INPUT, input);
|
intent.putExtra(CalculatorPlotFragment.INPUT, input);
|
||||||
intent.setClass(context, CalculatorPlotActivity.class);
|
intent.setClass(context, CalculatorPlotActivity.class);
|
||||||
AndroidUtils2.addFlags(intent, false, context);
|
AndroidUtils2.addFlags(intent, false, context);
|
||||||
|
@ -75,7 +75,7 @@ public abstract class AbstractCalculatorPlotFragment extends CalculatorFragment
|
|||||||
private PreparedInput preparedInput;
|
private PreparedInput preparedInput;
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
private ActivityMenu<Menu, MenuItem> fragmentMenu = ListActivityMenu.fromResource(R.menu.plot_menu, PlotMenu.class, SherlockMenuHelper.getInstance());
|
private ActivityMenu<Menu, MenuItem> fragmentMenu;
|
||||||
|
|
||||||
// thread which calculated data for graph view
|
// thread which calculated data for graph view
|
||||||
@NotNull
|
@NotNull
|
||||||
@ -150,8 +150,14 @@ public abstract class AbstractCalculatorPlotFragment extends CalculatorFragment
|
|||||||
final CalculatorEventHolder.Result result = this.lastEventHolder.apply(calculatorEventData);
|
final CalculatorEventHolder.Result result = this.lastEventHolder.apply(calculatorEventData);
|
||||||
if (result.isNewAfter()) {
|
if (result.isNewAfter()) {
|
||||||
preparedInput = prepareInputFromDisplay(((CalculatorDisplayChangeEventData) data).getNewValue(), null);
|
preparedInput = prepareInputFromDisplay(((CalculatorDisplayChangeEventData) data).getNewValue(), null);
|
||||||
this.preparedInput = preparedInput;
|
onNewPreparedInput(preparedInput);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void onNewPreparedInput(@NotNull PreparedInput preparedInput) {
|
||||||
|
this.preparedInput = preparedInput;
|
||||||
|
|
||||||
final PreparedInput finalPreparedInput = preparedInput;
|
final PreparedInput finalPreparedInput = preparedInput;
|
||||||
getUiHandler().post(new Runnable() {
|
getUiHandler().post(new Runnable() {
|
||||||
@ -172,10 +178,6 @@ public abstract class AbstractCalculatorPlotFragment extends CalculatorFragment
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected abstract void onError();
|
protected abstract void onError();
|
||||||
|
|
||||||
protected abstract void createGraphicalView(@NotNull View view, @NotNull PreparedInput preparedInput);
|
protected abstract void createGraphicalView(@NotNull View view, @NotNull PreparedInput preparedInput);
|
||||||
@ -230,12 +232,32 @@ public abstract class AbstractCalculatorPlotFragment extends CalculatorFragment
|
|||||||
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
|
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
|
||||||
super.onCreateOptionsMenu(menu, inflater);
|
super.onCreateOptionsMenu(menu, inflater);
|
||||||
|
|
||||||
|
final List<IdentifiableMenuItem<MenuItem>> menuItems = new ArrayList<IdentifiableMenuItem<MenuItem>>();
|
||||||
|
menuItems.add(PlotMenu.preferences);
|
||||||
|
if ( is3dPlotSupported() ) {
|
||||||
|
menuItems.add(new IdentifiableMenuItem<MenuItem>() {
|
||||||
|
@NotNull
|
||||||
|
@Override
|
||||||
|
public Integer getItemId() {
|
||||||
|
return R.id.menu_plot_3d;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onClick(@NotNull MenuItem data, @NotNull Context context) {
|
||||||
|
onNewPreparedInput(PreparedInput.force3dInstance(preparedInput));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
fragmentMenu = ListActivityMenu.fromResource(R.menu.plot_menu, menuItems, SherlockMenuHelper.getInstance());
|
||||||
|
|
||||||
final FragmentActivity activity = this.getActivity();
|
final FragmentActivity activity = this.getActivity();
|
||||||
if (activity != null) {
|
if (activity != null) {
|
||||||
fragmentMenu.onCreateOptionsMenu(activity, menu);
|
fragmentMenu.onCreateOptionsMenu(activity, menu);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected abstract boolean is3dPlotSupported();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onPrepareOptionsMenu(Menu menu) {
|
public void onPrepareOptionsMenu(Menu menu) {
|
||||||
super.onPrepareOptionsMenu(menu);
|
super.onPrepareOptionsMenu(menu);
|
||||||
@ -266,7 +288,13 @@ public abstract class AbstractCalculatorPlotFragment extends CalculatorFragment
|
|||||||
final Generic expression = displayState.getResult();
|
final Generic expression = displayState.getResult();
|
||||||
if (CalculatorUtils.isPlotPossible(expression, displayState.getOperation())) {
|
if (CalculatorUtils.isPlotPossible(expression, displayState.getOperation())) {
|
||||||
final List<Constant> variables = new ArrayList<Constant>(CalculatorUtils.getNotSystemConstants(expression));
|
final List<Constant> variables = new ArrayList<Constant>(CalculatorUtils.getNotSystemConstants(expression));
|
||||||
final Constant xVariable = variables.get(0);
|
|
||||||
|
final Constant xVariable;
|
||||||
|
if ( variables.size() > 0 ) {
|
||||||
|
xVariable = variables.get(0);
|
||||||
|
} else {
|
||||||
|
xVariable = null;
|
||||||
|
}
|
||||||
|
|
||||||
final Constant yVariable;
|
final Constant yVariable;
|
||||||
if ( variables.size() > 1 ) {
|
if ( variables.size() > 1 ) {
|
||||||
@ -275,7 +303,7 @@ public abstract class AbstractCalculatorPlotFragment extends CalculatorFragment
|
|||||||
yVariable = null;
|
yVariable = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
final Input input = new Input(expression.toString(), xVariable.getName(), yVariable == null ? null : yVariable.getName());
|
final Input input = new Input(expression.toString(), xVariable == null ? null : xVariable.getName(), yVariable == null ? null : yVariable.getName());
|
||||||
return prepareInput(input, false, savedInstanceState);
|
return prepareInput(input, false, savedInstanceState);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -293,7 +321,13 @@ public abstract class AbstractCalculatorPlotFragment extends CalculatorFragment
|
|||||||
try {
|
try {
|
||||||
final PreparedExpression preparedExpression = ToJsclTextProcessor.getInstance().process(input.getExpression());
|
final PreparedExpression preparedExpression = ToJsclTextProcessor.getInstance().process(input.getExpression());
|
||||||
final Generic expression = Expression.valueOf(preparedExpression.getExpression());
|
final Generic expression = Expression.valueOf(preparedExpression.getExpression());
|
||||||
final Constant xVar = new Constant(input.getXVariableName());
|
|
||||||
|
final Constant xVar;
|
||||||
|
if (input.getXVariableName() != null) {
|
||||||
|
xVar = new Constant(input.getXVariableName());
|
||||||
|
} else {
|
||||||
|
xVar = null;
|
||||||
|
}
|
||||||
|
|
||||||
final Constant yVar;
|
final Constant yVar;
|
||||||
if (input.getYVariableName() != null) {
|
if (input.getYVariableName() != null) {
|
||||||
@ -416,6 +450,8 @@ public abstract class AbstractCalculatorPlotFragment extends CalculatorFragment
|
|||||||
|
|
||||||
private boolean fromInputArgs;
|
private boolean fromInputArgs;
|
||||||
|
|
||||||
|
private boolean force3d = false;
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
private PlotBoundaries plotBoundaries = PlotBoundaries.newDefaultInstance();
|
private PlotBoundaries plotBoundaries = PlotBoundaries.newDefaultInstance();
|
||||||
|
|
||||||
@ -425,7 +461,7 @@ public abstract class AbstractCalculatorPlotFragment extends CalculatorFragment
|
|||||||
@NotNull
|
@NotNull
|
||||||
public static PreparedInput newInstance(@NotNull Input input,
|
public static PreparedInput newInstance(@NotNull Input input,
|
||||||
@NotNull Generic expression,
|
@NotNull Generic expression,
|
||||||
@NotNull Constant xVariable,
|
@Nullable Constant xVariable,
|
||||||
@Nullable Constant yVariable,
|
@Nullable Constant yVariable,
|
||||||
boolean fromInputArgs,
|
boolean fromInputArgs,
|
||||||
@NotNull PlotBoundaries plotBoundaries) {
|
@NotNull PlotBoundaries plotBoundaries) {
|
||||||
@ -454,6 +490,17 @@ public abstract class AbstractCalculatorPlotFragment extends CalculatorFragment
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
public static PreparedInput force3dInstance(final PreparedInput that) {
|
||||||
|
if (!that.isError()) {
|
||||||
|
final PreparedInput result = PreparedInput.newInstance(that.input, that.expression, that.xVariable, that.yVariable, that.fromInputArgs, that.plotBoundaries);
|
||||||
|
result.force3d = true;
|
||||||
|
return result;
|
||||||
|
} else {
|
||||||
|
return that;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public boolean isFromInputArgs() {
|
public boolean isFromInputArgs() {
|
||||||
return fromInputArgs;
|
return fromInputArgs;
|
||||||
}
|
}
|
||||||
@ -483,8 +530,12 @@ public abstract class AbstractCalculatorPlotFragment extends CalculatorFragment
|
|||||||
return yVariable;
|
return yVariable;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isForce3d() {
|
||||||
|
return force3d;
|
||||||
|
}
|
||||||
|
|
||||||
public boolean isError() {
|
public boolean isError() {
|
||||||
return input == null || expression == null || xVariable == null;
|
return input == null || expression == null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -493,14 +544,14 @@ public abstract class AbstractCalculatorPlotFragment extends CalculatorFragment
|
|||||||
@NotNull
|
@NotNull
|
||||||
private String expression;
|
private String expression;
|
||||||
|
|
||||||
@NotNull
|
@Nullable
|
||||||
private String xVariableName;
|
private String xVariableName;
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
private String yVariableName;
|
private String yVariableName;
|
||||||
|
|
||||||
public Input(@NotNull String expression,
|
public Input(@NotNull String expression,
|
||||||
@NotNull String xVariableName,
|
@Nullable String xVariableName,
|
||||||
@Nullable String yVariableName) {
|
@Nullable String yVariableName) {
|
||||||
this.expression = expression;
|
this.expression = expression;
|
||||||
this.xVariableName = xVariableName;
|
this.xVariableName = xVariableName;
|
||||||
@ -512,7 +563,7 @@ public abstract class AbstractCalculatorPlotFragment extends CalculatorFragment
|
|||||||
return expression;
|
return expression;
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
@Nullable
|
||||||
public String getXVariableName() {
|
public String getXVariableName() {
|
||||||
return xVariableName;
|
return xVariableName;
|
||||||
}
|
}
|
||||||
|
@ -57,19 +57,21 @@ public class CalculatorArityPlotFragment extends AbstractCalculatorPlotFragment
|
|||||||
final Constant xVariable = preparedInput.getXVariable();
|
final Constant xVariable = preparedInput.getXVariable();
|
||||||
final Constant yVariable = preparedInput.getYVariable();
|
final Constant yVariable = preparedInput.getYVariable();
|
||||||
|
|
||||||
final int arity = yVariable == null ? 1 : 2;
|
final int arity = xVariable == null ? 0 : (yVariable == null ? 1 : 2);
|
||||||
|
|
||||||
final List<FunctionPlotDef> functions = new ArrayList<FunctionPlotDef>();
|
final List<FunctionPlotDef> functions = new ArrayList<FunctionPlotDef>();
|
||||||
|
|
||||||
functions.add(FunctionPlotDef.newInstance(new RealArityFunction(arity, expression, xVariable, yVariable), FunctionLineDef.newInstance(realLineColor.getColor(), FunctionLineStyle.solid, 3f)));
|
functions.add(FunctionPlotDef.newInstance(new RealArityFunction(arity, expression, xVariable, yVariable), FunctionLineDef.newInstance(realLineColor.getColor(), FunctionLineStyle.solid, 3f)));
|
||||||
|
|
||||||
if (arity == 1) {
|
|
||||||
functions.add(FunctionPlotDef.newInstance(new ImaginaryArityFunction(arity, expression, xVariable, yVariable), FunctionLineDef.newInstance(imagLineColor.getColor(), FunctionLineStyle.solid, 3f)));
|
functions.add(FunctionPlotDef.newInstance(new ImaginaryArityFunction(arity, expression, xVariable, yVariable), FunctionLineDef.newInstance(imagLineColor.getColor(), FunctionLineStyle.solid, 3f)));
|
||||||
}
|
|
||||||
|
|
||||||
switch (arity) {
|
switch (arity) {
|
||||||
|
case 0:
|
||||||
case 1:
|
case 1:
|
||||||
|
if (preparedInput.isForce3d()) {
|
||||||
|
graphView = new Graph3dView(getActivity());
|
||||||
|
} else {
|
||||||
graphView = new Graph2dView(getActivity());
|
graphView = new Graph2dView(getActivity());
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
graphView = new Graph3dView(getActivity());
|
graphView = new Graph3dView(getActivity());
|
||||||
@ -91,6 +93,11 @@ public class CalculatorArityPlotFragment extends AbstractCalculatorPlotFragment
|
|||||||
protected void createChart(@NotNull PreparedInput preparedInput) {
|
protected void createChart(@NotNull PreparedInput preparedInput) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean is3dPlotSupported() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onResume() {
|
public void onResume() {
|
||||||
@ -133,19 +140,35 @@ public class CalculatorArityPlotFragment extends AbstractCalculatorPlotFragment
|
|||||||
@NotNull
|
@NotNull
|
||||||
protected final Generic expression;
|
protected final Generic expression;
|
||||||
|
|
||||||
@NotNull
|
@Nullable
|
||||||
protected final Constant xVariable;
|
protected final Constant xVariable;
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
protected final Constant yVariable;
|
protected final Constant yVariable;
|
||||||
|
|
||||||
public AbstractArityFunction(int arity, @NotNull Generic expression, @NotNull Constant xVariable, @Nullable Constant yVariable) {
|
@Nullable
|
||||||
|
private Double constant = null;
|
||||||
|
|
||||||
|
public AbstractArityFunction(int arity,
|
||||||
|
@NotNull Generic expression,
|
||||||
|
@Nullable Constant xVariable,
|
||||||
|
@Nullable Constant yVariable) {
|
||||||
this.arity = arity;
|
this.arity = arity;
|
||||||
this.expression = expression;
|
this.expression = expression;
|
||||||
this.xVariable = xVariable;
|
this.xVariable = xVariable;
|
||||||
this.yVariable = yVariable;
|
this.yVariable = yVariable;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final double eval() {
|
||||||
|
if (constant == null) {
|
||||||
|
constant = eval0();
|
||||||
|
}
|
||||||
|
return constant;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract double eval0();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public final int arity() {
|
public final int arity() {
|
||||||
return arity;
|
return arity;
|
||||||
@ -157,11 +180,16 @@ public class CalculatorArityPlotFragment extends AbstractCalculatorPlotFragment
|
|||||||
|
|
||||||
private RealArityFunction(int arity,
|
private RealArityFunction(int arity,
|
||||||
@NotNull Generic expression,
|
@NotNull Generic expression,
|
||||||
@NotNull Constant xVariable,
|
@Nullable Constant xVariable,
|
||||||
@Nullable Constant yVariable) {
|
@Nullable Constant yVariable) {
|
||||||
super(arity, expression, xVariable, yVariable);
|
super(arity, expression, xVariable, yVariable);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public double eval0() {
|
||||||
|
return PlotUtils.calculatorExpression(expression).realPart();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public double eval(double x) {
|
public double eval(double x) {
|
||||||
return PlotUtils.calculatorExpression(expression, xVariable, x).realPart();
|
return PlotUtils.calculatorExpression(expression, xVariable, x).realPart();
|
||||||
@ -177,11 +205,16 @@ public class CalculatorArityPlotFragment extends AbstractCalculatorPlotFragment
|
|||||||
|
|
||||||
private ImaginaryArityFunction(int arity,
|
private ImaginaryArityFunction(int arity,
|
||||||
@NotNull Generic expression,
|
@NotNull Generic expression,
|
||||||
@NotNull Constant xVariable,
|
@Nullable Constant xVariable,
|
||||||
@Nullable Constant yVariable) {
|
@Nullable Constant yVariable) {
|
||||||
super(arity, expression, xVariable, yVariable);
|
super(arity, expression, xVariable, yVariable);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public double eval0() {
|
||||||
|
return PlotUtils.calculatorExpression(expression).imaginaryPart();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public double eval(double x) {
|
public double eval(double x) {
|
||||||
return PlotUtils.calculatorExpression(expression, xVariable, x).imaginaryPart();
|
return PlotUtils.calculatorExpression(expression, xVariable, x).imaginaryPart();
|
||||||
|
@ -57,6 +57,11 @@ public class CalculatorPlotFragment extends AbstractCalculatorPlotFragment {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean is3dPlotSupported() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
@Override
|
@Override
|
||||||
protected PlotBoundaries getPlotBoundaries() {
|
protected PlotBoundaries getPlotBoundaries() {
|
||||||
|
@ -0,0 +1,12 @@
|
|||||||
|
package org.solovyev.android.calculator.plot;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* User: serso
|
||||||
|
* Date: 1/5/13
|
||||||
|
* Time: 10:45 PM
|
||||||
|
*/
|
||||||
|
public enum FunctionLineColorType {
|
||||||
|
|
||||||
|
color_map,
|
||||||
|
solid;
|
||||||
|
}
|
@ -30,6 +30,9 @@ public class FunctionLineDef {
|
|||||||
**********************************************************************
|
**********************************************************************
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
private FunctionLineColorType lineColorType = FunctionLineColorType.solid;
|
||||||
|
|
||||||
private int lineColor = Color.WHITE;
|
private int lineColor = Color.WHITE;
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
@ -57,6 +60,16 @@ public class FunctionLineDef {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
public static FunctionLineDef newInstance(int lineColor, @NotNull FunctionLineStyle lineStyle, float lineWidth, @NotNull FunctionLineColorType lineColorType) {
|
||||||
|
final FunctionLineDef result = new FunctionLineDef();
|
||||||
|
result.lineColor = lineColor;
|
||||||
|
result.lineColorType = lineColorType;
|
||||||
|
result.lineStyle = lineStyle;
|
||||||
|
result.lineWidth = lineWidth;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
public static FunctionLineDef newDefaultInstance() {
|
public static FunctionLineDef newDefaultInstance() {
|
||||||
return new FunctionLineDef();
|
return new FunctionLineDef();
|
||||||
@ -76,6 +89,11 @@ public class FunctionLineDef {
|
|||||||
return lineWidth;
|
return lineWidth;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
public FunctionLineColorType getLineColorType() {
|
||||||
|
return lineColorType;
|
||||||
|
}
|
||||||
|
|
||||||
public void applyToPaint(@NotNull Paint paint) {
|
public void applyToPaint(@NotNull Paint paint) {
|
||||||
paint.setColor(lineColor);
|
paint.setColor(lineColor);
|
||||||
paint.setStyle(Paint.Style.STROKE);
|
paint.setStyle(Paint.Style.STROKE);
|
||||||
|
@ -7,8 +7,10 @@ import android.graphics.Bitmap;
|
|||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import android.os.Message;
|
import android.os.Message;
|
||||||
import android.util.AttributeSet;
|
import android.util.AttributeSet;
|
||||||
|
import android.util.Log;
|
||||||
import android.view.SurfaceHolder;
|
import android.view.SurfaceHolder;
|
||||||
import android.view.SurfaceView;
|
import android.view.SurfaceView;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.solovyev.android.AndroidUtils2;
|
import org.solovyev.android.AndroidUtils2;
|
||||||
|
|
||||||
import javax.microedition.khronos.egl.*;
|
import javax.microedition.khronos.egl.*;
|
||||||
@ -28,9 +30,10 @@ abstract class GLView extends SurfaceView implements SurfaceHolder.Callback {
|
|||||||
private EGLContext eglContext;
|
private EGLContext eglContext;
|
||||||
private GL11 gl;
|
private GL11 gl;
|
||||||
protected int width, height;
|
protected int width, height;
|
||||||
private boolean mIsLooping;
|
private volatile boolean looping;
|
||||||
|
|
||||||
abstract void onDrawFrame(GL10 gl);
|
abstract void onDrawFrame(GL10 gl);
|
||||||
|
|
||||||
abstract void onSurfaceCreated(GL10 gl, int width, int height);
|
abstract void onSurfaceCreated(GL10 gl, int width, int height);
|
||||||
|
|
||||||
public String captureScreenshot() {
|
public String captureScreenshot() {
|
||||||
@ -52,9 +55,16 @@ abstract class GLView extends SurfaceView implements SurfaceHolder.Callback {
|
|||||||
return bitmap;
|
return bitmap;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Handler handler = new Handler() {
|
@NotNull
|
||||||
|
private final Handler uiHandler = new Handler() {
|
||||||
public void handleMessage(Message msg) {
|
public void handleMessage(Message msg) {
|
||||||
|
switch (msg.what) {
|
||||||
|
case 1:
|
||||||
glDraw();
|
glDraw();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
Log.e("GLView", "Incorrect message id: " + msg.what);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -69,7 +79,7 @@ abstract class GLView extends SurfaceView implements SurfaceHolder.Callback {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void init() {
|
private void init() {
|
||||||
SurfaceHolder holder = getHolder();
|
final SurfaceHolder holder = getHolder();
|
||||||
holder.setType(SurfaceHolder.SURFACE_TYPE_GPU);
|
holder.setType(SurfaceHolder.SURFACE_TYPE_GPU);
|
||||||
holder.addCallback(this);
|
holder.addCallback(this);
|
||||||
}
|
}
|
||||||
@ -129,7 +139,7 @@ abstract class GLView extends SurfaceView implements SurfaceHolder.Callback {
|
|||||||
if (egl.eglGetError() == EGL11.EGL_CONTEXT_LOST) {
|
if (egl.eglGetError() == EGL11.EGL_CONTEXT_LOST) {
|
||||||
paused = true;
|
paused = true;
|
||||||
}
|
}
|
||||||
if (mIsLooping) {
|
if (looping) {
|
||||||
requestDraw();
|
requestDraw();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -154,24 +164,24 @@ abstract class GLView extends SurfaceView implements SurfaceHolder.Callback {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void startLooping() {
|
public void startLooping() {
|
||||||
if (!mIsLooping) {
|
if (!looping) {
|
||||||
mIsLooping = true;
|
looping = true;
|
||||||
glDraw();
|
glDraw();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void stopLooping() {
|
public void stopLooping() {
|
||||||
if (mIsLooping) {
|
if (looping) {
|
||||||
mIsLooping = false;
|
looping = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isLooping() {
|
public boolean isLooping() {
|
||||||
return mIsLooping;
|
return looping;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void requestDraw() {
|
public void requestDraw() {
|
||||||
handler.sendEmptyMessage(1);
|
uiHandler.sendEmptyMessage(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void bitmapBGRtoRGB(Bitmap bitmap, int width, int height) {
|
static void bitmapBGRtoRGB(Bitmap bitmap, int width, int height) {
|
||||||
|
@ -2,7 +2,9 @@
|
|||||||
|
|
||||||
package org.solovyev.android.calculator.plot;
|
package org.solovyev.android.calculator.plot;
|
||||||
|
|
||||||
|
import android.graphics.Color;
|
||||||
import org.javia.arity.Function;
|
import org.javia.arity.Function;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
import javax.microedition.khronos.opengles.GL10;
|
import javax.microedition.khronos.opengles.GL10;
|
||||||
import javax.microedition.khronos.opengles.GL11;
|
import javax.microedition.khronos.opengles.GL11;
|
||||||
@ -82,17 +84,20 @@ class Graph3d {
|
|||||||
return bb;
|
return bb;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void update(GL11 gl, Function f, float zoom) {
|
public void update(@NotNull GL11 gl, @NotNull FunctionPlotDef fpd, float zoom) {
|
||||||
|
final Function function = fpd.getFunction();
|
||||||
|
final FunctionLineDef lineDef = fpd.getLineDef();
|
||||||
final int NTICK = useHighQuality3d ? 5 : 0;
|
final int NTICK = useHighQuality3d ? 5 : 0;
|
||||||
final float size = 4 * zoom;
|
final float size = 4 * zoom;
|
||||||
final float minX = -size, maxX = size, minY = -size, maxY = size;
|
final float minX = -size, maxX = size, minY = -size, maxY = size;
|
||||||
|
|
||||||
//Calculator.log("update VBOs " + vertexVbo + ' ' + colorVbo + ' ' + vertexElementVbo);
|
//Calculator.log("update VBOs " + vertexVbo + ' ' + colorVbo + ' ' + vertexElementVbo);
|
||||||
nVertex = N * N + 6 + 8 + NTICK * 6;
|
nVertex = N * N + 6 + 8 + NTICK * 6;
|
||||||
int nFloats = nVertex * 3;
|
|
||||||
float vertices[] = new float[nFloats];
|
final float vertices[] = new float[nVertex * 3];
|
||||||
byte colors[] = new byte[nVertex << 2];
|
final byte colors[] = new byte[nVertex * 4];
|
||||||
if (f != null) {
|
|
||||||
|
if (fpd != null) {
|
||||||
//Calculator.log("Graph3d update");
|
//Calculator.log("Graph3d update");
|
||||||
float sizeX = maxX - minX;
|
float sizeX = maxX - minX;
|
||||||
float sizeY = maxY - minY;
|
float sizeY = maxY - minY;
|
||||||
@ -103,43 +108,74 @@ class Graph3d {
|
|||||||
float y = minY;
|
float y = minY;
|
||||||
float x = minX - stepX;
|
float x = minX - stepX;
|
||||||
int nRealPoints = 0;
|
int nRealPoints = 0;
|
||||||
|
|
||||||
|
final int arity = function.arity();
|
||||||
|
|
||||||
for (int i = 0; i < N; i++, y += stepY) {
|
for (int i = 0; i < N; i++, y += stepY) {
|
||||||
float xinc = (i & 1) == 0 ? stepX : -stepX;
|
float xinc = (i & 1) == 0 ? stepX : -stepX;
|
||||||
|
|
||||||
x += xinc;
|
x += xinc;
|
||||||
for (int j = 0; j < N; ++j, x += xinc, pos += 3) {
|
for (int j = 0; j < N; ++j, x += xinc, pos += 3) {
|
||||||
float z = (float) f.eval(x, y);
|
|
||||||
|
final float z;
|
||||||
|
switch (arity) {
|
||||||
|
case 2:
|
||||||
|
z = (float) function.eval(x, y);
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
// todo serso: optimize (can be calculated once before loop)
|
||||||
|
z = (float) function.eval(x);
|
||||||
|
break;
|
||||||
|
case 0:
|
||||||
|
// todo serso: optimize (can be calculated once)
|
||||||
|
z = (float) function.eval();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new IllegalArgumentException();
|
||||||
|
}
|
||||||
|
|
||||||
vertices[pos] = x;
|
vertices[pos] = x;
|
||||||
vertices[pos + 1] = y;
|
vertices[pos + 1] = y;
|
||||||
vertices[pos + 2] = z;
|
vertices[pos + 2] = z;
|
||||||
if (z == z) { // not NAN
|
|
||||||
|
if (!Float.isNaN(z)) {
|
||||||
sum += z * z;
|
sum += z * z;
|
||||||
++nRealPoints;
|
++nRealPoints;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
float maxAbs = (float) Math.sqrt(sum / nRealPoints);
|
float maxAbs = (float) Math.sqrt(sum / nRealPoints);
|
||||||
maxAbs *= .9f;
|
maxAbs *= .9f;
|
||||||
maxAbs = Math.min(maxAbs, 15);
|
maxAbs = Math.min(maxAbs, 15);
|
||||||
maxAbs = Math.max(maxAbs, .001f);
|
maxAbs = Math.max(maxAbs, .001f);
|
||||||
|
|
||||||
|
final int lineColor = lineDef.getLineColor();
|
||||||
final int limitColor = N * N * 4;
|
final int limitColor = N * N * 4;
|
||||||
for (int i = 0, j = 2; i < limitColor; i += 4, j += 3) {
|
for (int i = 0, j = 2; i < limitColor; i += 4, j += 3) {
|
||||||
float z = vertices[j];
|
final float z = vertices[j];
|
||||||
if (z == z) {
|
|
||||||
|
if (!Float.isNaN(z)) {
|
||||||
|
if (lineDef.getLineColorType() == FunctionLineColorType.color_map) {
|
||||||
final float a = z / maxAbs;
|
final float a = z / maxAbs;
|
||||||
final float abs = a < 0 ? -a : a;
|
final float abs = a < 0 ? -a : a;
|
||||||
colors[i] = floatToByte(a);
|
colors[i] = floatToByte(a);
|
||||||
colors[i + 1] = floatToByte(1 - abs * .3f);
|
colors[i + 1] = floatToByte(1 - abs * .3f);
|
||||||
colors[i + 2] = floatToByte(-a);
|
colors[i + 2] = floatToByte(-a);
|
||||||
|
} else {
|
||||||
|
colors[i] = (byte) Color.red(lineColor);
|
||||||
|
colors[i + 1] = (byte) Color.green(lineColor);
|
||||||
|
colors[i + 2] = (byte) Color.blue(lineColor);
|
||||||
|
}
|
||||||
colors[i + 3] = (byte) 255;
|
colors[i + 3] = (byte) 255;
|
||||||
} else {
|
} else {
|
||||||
vertices[j] = 0;
|
vertices[j] = 0;
|
||||||
z = 0;
|
|
||||||
colors[i] = 0;
|
colors[i] = 0;
|
||||||
colors[i + 1] = 0;
|
colors[i + 1] = 0;
|
||||||
colors[i + 2] = 0;
|
colors[i + 2] = 0;
|
||||||
colors[i + 3] = 0;
|
colors[i + 3] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
int base = N * N * 3;
|
int base = N * N * 3;
|
||||||
@ -248,7 +284,15 @@ class Graph3d {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private byte floatToByte(float v) {
|
private byte floatToByte(float v) {
|
||||||
return (byte) (v <= 0 ? 0 : v >= 1 ? 255 : (int) (v * 255));
|
if (v <= 0) {
|
||||||
|
return (byte) 0;
|
||||||
|
} else {
|
||||||
|
if (v >= 1) {
|
||||||
|
return (byte) 255;
|
||||||
|
} else {
|
||||||
|
return (byte) (v * 255);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void draw(GL11 gl) {
|
public void draw(GL11 gl) {
|
||||||
|
@ -3,16 +3,18 @@
|
|||||||
package org.solovyev.android.calculator.plot;
|
package org.solovyev.android.calculator.plot;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
import android.graphics.Color;
|
||||||
import android.opengl.Matrix;
|
import android.opengl.Matrix;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.util.AttributeSet;
|
import android.util.AttributeSet;
|
||||||
import android.view.MotionEvent;
|
import android.view.MotionEvent;
|
||||||
import android.widget.ZoomButtonsController;
|
import android.widget.ZoomButtonsController;
|
||||||
import org.javia.arity.Function;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
import javax.microedition.khronos.opengles.GL10;
|
import javax.microedition.khronos.opengles.GL10;
|
||||||
import javax.microedition.khronos.opengles.GL11;
|
import javax.microedition.khronos.opengles.GL11;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public class Graph3dView extends GLView implements GraphView {
|
public class Graph3dView extends GLView implements GraphView {
|
||||||
@ -24,7 +26,12 @@ public class Graph3dView extends GLView implements GraphView {
|
|||||||
private ZoomButtonsController zoomController = new ZoomButtonsController(this);
|
private ZoomButtonsController zoomController = new ZoomButtonsController(this);
|
||||||
private float zoomLevel = 1, targetZoom, zoomStep = 0, currentZoom;
|
private float zoomLevel = 1, targetZoom, zoomStep = 0, currentZoom;
|
||||||
private FPS fps = new FPS();
|
private FPS fps = new FPS();
|
||||||
private Graph3d graph;
|
|
||||||
|
@NotNull
|
||||||
|
private List<Graph3d> graphs = new ArrayList<Graph3d>();
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
private GraphViewHelper graphViewHelper = GraphViewHelper.newDefaultInstance();
|
||||||
|
|
||||||
public Graph3dView(Context context, AttributeSet attrs) {
|
public Graph3dView(Context context, AttributeSet attrs) {
|
||||||
super(context, attrs);
|
super(context, attrs);
|
||||||
@ -149,7 +156,6 @@ public class Graph3dView extends GLView implements GraphView {
|
|||||||
private float[] matrix1 = new float[16], matrix2 = new float[16], matrix3 = new float[16];
|
private float[] matrix1 = new float[16], matrix2 = new float[16], matrix3 = new float[16];
|
||||||
private float angleX, angleY;
|
private float angleX, angleY;
|
||||||
private boolean isDirty;
|
private boolean isDirty;
|
||||||
private Function function;
|
|
||||||
private static final float DISTANCE = 15f;
|
private static final float DISTANCE = 15f;
|
||||||
|
|
||||||
void setRotation(float x, float y) {
|
void setRotation(float x, float y) {
|
||||||
@ -164,14 +170,18 @@ public class Graph3dView extends GLView implements GraphView {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void init(@NotNull FunctionViewDef functionViewDef) {
|
public void init(@NotNull FunctionViewDef functionViewDef) {
|
||||||
|
this.graphViewHelper = GraphViewHelper.newInstance(functionViewDef, Collections.<FunctionPlotDef>emptyList());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setFunctionPlotDefs(@NotNull List<FunctionPlotDef> functionPlotDefs) {
|
public void setFunctionPlotDefs(@NotNull List<FunctionPlotDef> functionPlotDefs) {
|
||||||
if (functionPlotDefs.size() > 0) {
|
for (FunctionPlotDef functionPlotDef: functionPlotDefs) {
|
||||||
function = functionPlotDefs.get(0).getFunction();
|
final int arity = functionPlotDef.getFunction().arity();
|
||||||
} else {
|
if (arity != 0 && arity != 1 && arity != 2) {
|
||||||
function = null;
|
throw new IllegalArgumentException("Function must have arity 0 or 1 or 2 for 3d plot!");
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.graphViewHelper = this.graphViewHelper.copy(functionPlotDefs);
|
||||||
zoomLevel = 1;
|
zoomLevel = 1;
|
||||||
isDirty = true;
|
isDirty = true;
|
||||||
}
|
}
|
||||||
@ -180,10 +190,13 @@ public class Graph3dView extends GLView implements GraphView {
|
|||||||
public void onSurfaceCreated(GL10 gl, int width, int height) {
|
public void onSurfaceCreated(GL10 gl, int width, int height) {
|
||||||
gl.glDisable(GL10.GL_DITHER);
|
gl.glDisable(GL10.GL_DITHER);
|
||||||
gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT, GL10.GL_FASTEST);
|
gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT, GL10.GL_FASTEST);
|
||||||
gl.glClearColor(0, 0, 0, 1);
|
|
||||||
|
final int backgroundColor = graphViewHelper.getFunctionViewDef().getBackgroundColor();
|
||||||
|
gl.glClearColor(Color.red(backgroundColor) / 255f, Color.green(backgroundColor) / 255f, Color.blue(backgroundColor) / 255f, Color.alpha(backgroundColor) / 255f);
|
||||||
|
|
||||||
gl.glShadeModel(useHighQuality3d ? GL10.GL_SMOOTH : GL10.GL_FLAT);
|
gl.glShadeModel(useHighQuality3d ? GL10.GL_SMOOTH : GL10.GL_FLAT);
|
||||||
gl.glDisable(GL10.GL_LIGHTING);
|
gl.glDisable(GL10.GL_LIGHTING);
|
||||||
graph = new Graph3d((GL11) gl, useHighQuality3d);
|
ensureGraphsSize((GL11) gl);
|
||||||
isDirty = true;
|
isDirty = true;
|
||||||
angleX = .5f;
|
angleX = .5f;
|
||||||
angleY = 0;
|
angleY = 0;
|
||||||
@ -201,7 +214,11 @@ public class Graph3dView extends GLView implements GraphView {
|
|||||||
currentZoom = zoomLevel;
|
currentZoom = zoomLevel;
|
||||||
}
|
}
|
||||||
if (isDirty) {
|
if (isDirty) {
|
||||||
graph.update(gl, function, zoomLevel);
|
ensureGraphsSize(gl);
|
||||||
|
for (int i = 0; i < graphViewHelper.getFunctionPlotDefs().size(); i++) {
|
||||||
|
graphs.get(i).update(gl, graphViewHelper.getFunctionPlotDefs().get(i), zoomLevel);
|
||||||
|
|
||||||
|
}
|
||||||
isDirty = false;
|
isDirty = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -233,8 +250,16 @@ public class Graph3dView extends GLView implements GraphView {
|
|||||||
Matrix.multiplyMM(matrix3, 0, matrix2, 0, matrix1, 0);
|
Matrix.multiplyMM(matrix3, 0, matrix2, 0, matrix1, 0);
|
||||||
gl.glMultMatrixf(matrix3, 0);
|
gl.glMultMatrixf(matrix3, 0);
|
||||||
System.arraycopy(matrix3, 0, matrix1, 0, 16);
|
System.arraycopy(matrix3, 0, matrix1, 0, 16);
|
||||||
|
for (Graph3d graph : graphs) {
|
||||||
graph.draw(gl);
|
graph.draw(gl);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ensureGraphsSize(@NotNull GL11 gl) {
|
||||||
|
while (graphViewHelper.getFunctionPlotDefs().size() > graphs.size()) {
|
||||||
|
graphs.add(new Graph3d(gl, useHighQuality3d));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void initFrustum(GL10 gl, float distance) {
|
private void initFrustum(GL10 gl, float distance) {
|
||||||
gl.glMatrixMode(GL10.GL_PROJECTION);
|
gl.glMatrixMode(GL10.GL_PROJECTION);
|
||||||
|
@ -51,7 +51,7 @@ public final class PlotUtils {
|
|||||||
public static boolean addXY(double minValue,
|
public static boolean addXY(double minValue,
|
||||||
double maxValue,
|
double maxValue,
|
||||||
@NotNull Generic expression,
|
@NotNull Generic expression,
|
||||||
@NotNull Constant variable,
|
@Nullable Constant variable,
|
||||||
@NotNull MyXYSeries realSeries,
|
@NotNull MyXYSeries realSeries,
|
||||||
@Nullable MyXYSeries imagSeries,
|
@Nullable MyXYSeries imagSeries,
|
||||||
boolean addExtra,
|
boolean addExtra,
|
||||||
@ -82,7 +82,7 @@ public final class PlotUtils {
|
|||||||
boolean needToCalculateRealY = realSeries.needToAdd(step, x);
|
boolean needToCalculateRealY = realSeries.needToAdd(step, x);
|
||||||
|
|
||||||
if (needToCalculateRealY) {
|
if (needToCalculateRealY) {
|
||||||
final Complex c = calculatorExpression(expression, variable, x);
|
final Complex c = variable == null ? calculatorExpression(expression) : calculatorExpression(expression, variable, x);
|
||||||
Double y = prepareY(c.realPart());
|
Double y = prepareY(c.realPart());
|
||||||
|
|
||||||
if (y != null) {
|
if (y != null) {
|
||||||
@ -106,7 +106,7 @@ public final class PlotUtils {
|
|||||||
} else {
|
} else {
|
||||||
boolean needToCalculateImagY = imagSeries != null && imagSeries.needToAdd(step, x);
|
boolean needToCalculateImagY = imagSeries != null && imagSeries.needToAdd(step, x);
|
||||||
if (needToCalculateImagY) {
|
if (needToCalculateImagY) {
|
||||||
final Complex c = calculatorExpression(expression, variable, x);
|
final Complex c = variable == null ? calculatorExpression(expression) : calculatorExpression(expression, variable, x);
|
||||||
Double y = prepareY(c.imaginaryPart());
|
Double y = prepareY(c.imaginaryPart());
|
||||||
if (y != null) {
|
if (y != null) {
|
||||||
imag.moveToNextPoint(x, y);
|
imag.moveToNextPoint(x, y);
|
||||||
@ -128,20 +128,28 @@ public final class PlotUtils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
static String getImagFunctionName(@NotNull Constant variable) {
|
static String getImagFunctionName(@Nullable Constant variable) {
|
||||||
|
if (variable != null) {
|
||||||
return "g(" + variable.getName() + ")" + " = " + "Im(ƒ(" + variable.getName() + "))";
|
return "g(" + variable.getName() + ")" + " = " + "Im(ƒ(" + variable.getName() + "))";
|
||||||
|
} else {
|
||||||
|
return "g = Im(ƒ)";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
private static String getRealFunctionName(@NotNull Generic expression, @NotNull Constant variable) {
|
private static String getRealFunctionName(@NotNull Generic expression, @Nullable Constant variable) {
|
||||||
|
if (variable != null) {
|
||||||
return "ƒ(" + variable.getName() + ")" + " = " + expression.toString();
|
return "ƒ(" + variable.getName() + ")" + " = " + expression.toString();
|
||||||
|
} else {
|
||||||
|
return "ƒ = " + expression.toString();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
static XYChart prepareChart(final double minValue,
|
static XYChart prepareChart(final double minValue,
|
||||||
final double maxValue,
|
final double maxValue,
|
||||||
@NotNull final Generic expression,
|
@NotNull final Generic expression,
|
||||||
@NotNull final Constant variable,
|
@Nullable final Constant variable,
|
||||||
int bgColor,
|
int bgColor,
|
||||||
boolean interpolate,
|
boolean interpolate,
|
||||||
int realLineColor,
|
int realLineColor,
|
||||||
@ -159,8 +167,12 @@ public final class PlotUtils {
|
|||||||
|
|
||||||
final XYMultipleSeriesRenderer renderer = new XYMultipleSeriesRenderer();
|
final XYMultipleSeriesRenderer renderer = new XYMultipleSeriesRenderer();
|
||||||
renderer.setShowGrid(true);
|
renderer.setShowGrid(true);
|
||||||
renderer.setXTitle(variable.getName());
|
renderer.setXTitle(variable != null ? variable.getName() : null);
|
||||||
|
if (variable != null) {
|
||||||
renderer.setYTitle("f(" + variable.getName() + ")");
|
renderer.setYTitle("f(" + variable.getName() + ")");
|
||||||
|
} else {
|
||||||
|
renderer.setYTitle("f");
|
||||||
|
}
|
||||||
renderer.setChartTitleTextSize(25);
|
renderer.setChartTitleTextSize(25);
|
||||||
renderer.setAxisTitleTextSize(25);
|
renderer.setAxisTitleTextSize(25);
|
||||||
renderer.setLabelsTextSize(25);
|
renderer.setLabelsTextSize(25);
|
||||||
@ -370,6 +382,15 @@ public final class PlotUtils {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
public static Complex calculatorExpression(@NotNull Generic expression) {
|
||||||
|
try {
|
||||||
|
return unwrap(expression.numeric());
|
||||||
|
} catch (RuntimeException e) {
|
||||||
|
return NaN;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
public static Complex calculatorExpression(@NotNull Generic expression, @NotNull Constant xVar, double x) {
|
public static Complex calculatorExpression(@NotNull Generic expression, @NotNull Constant xVar, double x) {
|
||||||
try {
|
try {
|
||||||
|
@ -162,6 +162,9 @@ public enum CalculatorEventType {
|
|||||||
//org.solovyev.android.calculator.plot.PlotInput
|
//org.solovyev.android.calculator.plot.PlotInput
|
||||||
plot_graph,
|
plot_graph,
|
||||||
|
|
||||||
|
|
||||||
|
plot_graph_3d,
|
||||||
|
|
||||||
//String
|
//String
|
||||||
show_evaluation_error;
|
show_evaluation_error;
|
||||||
|
|
||||||
|
@ -44,9 +44,9 @@ public final class CalculatorUtils {
|
|||||||
public static boolean isPlotPossible(@NotNull Generic expression, @NotNull JsclOperation operation) {
|
public static boolean isPlotPossible(@NotNull Generic expression, @NotNull JsclOperation operation) {
|
||||||
boolean result = false;
|
boolean result = false;
|
||||||
|
|
||||||
if (operation == JsclOperation.simplify) {
|
if (operation == JsclOperation.simplify || operation == JsclOperation.numeric) {
|
||||||
int size = getNotSystemConstants(expression).size();
|
int size = getNotSystemConstants(expression).size();
|
||||||
if (size == 1 || size == 2) {
|
if (size == 0 || size == 1 || size == 2) {
|
||||||
result = true;
|
result = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user