Plotter preferences
This commit is contained in:
parent
d8015e48c7
commit
8a525e270a
@ -1,57 +1,58 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:installLocation="auto" android:versionCode="81" android:versionName="1.3.2"
|
||||
package="org.solovyev.android.calculator">
|
||||
|
||||
<uses-permission android:name="android.permission.VIBRATE"/>
|
||||
<uses-permission android:name="android.permission.INTERNET"/>
|
||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
|
||||
<uses-permission android:name="com.android.vending.BILLING"/>
|
||||
|
||||
<uses-sdk android:minSdkVersion="4" android:targetSdkVersion="8"/>
|
||||
|
||||
<application android:debuggable="true" android:hardwareAccelerated="false" android:icon="@drawable/icon" android:label="@string/c_app_name" android:name=".CalculatorApplication" android:theme="@style/metro_blue_theme">
|
||||
|
||||
<activity android:label="@string/c_app_name" android:name=".CalculatorActivity" android:windowSoftInputMode="adjustPan">
|
||||
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN"/>
|
||||
<category android:name="android.intent.category.LAUNCHER"/>
|
||||
</intent-filter>
|
||||
|
||||
</activity>
|
||||
|
||||
<activity android:label="@string/c_app_settings" android:name=".CalculatorPreferencesActivity"/>
|
||||
|
||||
<activity android:label="@string/c_history" android:name=".history.CalculatorHistoryActivity"/>
|
||||
|
||||
<activity android:label="@string/c_about" android:name=".about.CalculatorAboutActivity"/>
|
||||
|
||||
<activity android:label="@string/c_help" android:name=".help.CalculatorHelpActivity"/>
|
||||
|
||||
<activity android:label="@string/c_functions" android:name=".math.edit.CalculatorFunctionsActivity"/>
|
||||
|
||||
<activity android:label="@string/c_operators" android:name=".math.edit.CalculatorOperatorsActivity"/>
|
||||
|
||||
<activity android:label="@string/c_vars_and_constants" android:name=".math.edit.CalculatorVarsActivity"/>
|
||||
|
||||
<activity android:label="@string/c_plot_graph" android:name=".plot.CalculatorPlotActivity"/>
|
||||
|
||||
<activity android:configChanges="keyboard|keyboardHidden|orientation|screenLayout|uiMode|screenSize|smallestScreenSize" android:name="com.google.ads.AdActivity"/>
|
||||
|
||||
<service android:name="net.robotmedia.billing.BillingService"/>
|
||||
<receiver android:name="net.robotmedia.billing.BillingReceiver">
|
||||
<intent-filter>
|
||||
<action android:name="com.android.vending.billing.IN_APP_NOTIFY"/>
|
||||
<action android:name="com.android.vending.billing.RESPONSE_CODE"/>
|
||||
<action android:name="com.android.vending.billing.PURCHASE_STATE_CHANGED"/>
|
||||
</intent-filter>
|
||||
</receiver>
|
||||
|
||||
<activity android:name="org.acra.CrashReportDialog"
|
||||
android:theme="@android:style/Theme.Dialog"
|
||||
android:launchMode="singleInstance"
|
||||
android:excludeFromRecents="true"
|
||||
android:finishOnTaskLaunch="true" />
|
||||
|
||||
</application>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:installLocation="auto" android:versionCode="81" android:versionName="1.3.2"
|
||||
package="org.solovyev.android.calculator">
|
||||
|
||||
<uses-permission android:name="android.permission.VIBRATE"/>
|
||||
<uses-permission android:name="android.permission.INTERNET"/>
|
||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
|
||||
<uses-permission android:name="com.android.vending.BILLING"/>
|
||||
|
||||
<uses-sdk android:minSdkVersion="4" android:targetSdkVersion="8"/>
|
||||
|
||||
<application android:debuggable="true" android:hardwareAccelerated="false" android:icon="@drawable/icon" android:label="@string/c_app_name" android:name=".CalculatorApplication" android:theme="@style/metro_blue_theme">
|
||||
|
||||
<activity android:label="@string/c_app_name" android:name=".CalculatorActivity" android:windowSoftInputMode="adjustPan">
|
||||
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN"/>
|
||||
<category android:name="android.intent.category.LAUNCHER"/>
|
||||
</intent-filter>
|
||||
|
||||
</activity>
|
||||
|
||||
<activity android:label="@string/c_app_settings" android:name=".CalculatorPreferencesActivity"/>
|
||||
|
||||
<activity android:label="@string/c_history" android:name=".history.CalculatorHistoryActivity"/>
|
||||
|
||||
<activity android:label="@string/c_about" android:name=".about.CalculatorAboutActivity"/>
|
||||
|
||||
<activity android:label="@string/c_help" android:name=".help.CalculatorHelpActivity"/>
|
||||
|
||||
<activity android:label="@string/c_functions" android:name=".math.edit.CalculatorFunctionsActivity"/>
|
||||
|
||||
<activity android:label="@string/c_operators" android:name=".math.edit.CalculatorOperatorsActivity"/>
|
||||
|
||||
<activity android:label="@string/c_vars_and_constants" android:name=".math.edit.CalculatorVarsActivity"/>
|
||||
|
||||
<activity android:label="@string/c_plot_graph" android:name=".plot.CalculatorPlotActivity"/>
|
||||
<activity android:label="@string/c_settings" android:name=".plot.CalculatorPlotPreferenceActivity"/>
|
||||
|
||||
<activity android:configChanges="keyboard|keyboardHidden|orientation|screenLayout|uiMode|screenSize|smallestScreenSize" android:name="com.google.ads.AdActivity"/>
|
||||
|
||||
<service android:name="net.robotmedia.billing.BillingService"/>
|
||||
<receiver android:name="net.robotmedia.billing.BillingReceiver">
|
||||
<intent-filter>
|
||||
<action android:name="com.android.vending.billing.IN_APP_NOTIFY"/>
|
||||
<action android:name="com.android.vending.billing.RESPONSE_CODE"/>
|
||||
<action android:name="com.android.vending.billing.PURCHASE_STATE_CHANGED"/>
|
||||
</intent-filter>
|
||||
</receiver>
|
||||
|
||||
<activity android:name="org.acra.CrashReportDialog"
|
||||
android:theme="@android:style/Theme.Dialog"
|
||||
android:launchMode="singleInstance"
|
||||
android:excludeFromRecents="true"
|
||||
android:finishOnTaskLaunch="true" />
|
||||
|
||||
</application>
|
||||
</manifest>
|
@ -87,4 +87,19 @@
|
||||
<item>bin</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="graph_line_color_names">
|
||||
<item>White</item>
|
||||
<item>Grey</item>
|
||||
<item>Red</item>
|
||||
<item>Blue</item>
|
||||
<item>Green</item>
|
||||
</string-array>
|
||||
<string-array name="graph_line_color_values">
|
||||
<item>white</item>
|
||||
<item>grey</item>
|
||||
<item>red</item>
|
||||
<item>blue</item>
|
||||
<item>green</item>
|
||||
</string-array>
|
||||
|
||||
</resources>
|
@ -108,6 +108,8 @@
|
||||
|
||||
<!-- action bar-->
|
||||
<item name="actionBarTabStyle">@style/default_actionbar_tab_style</item>
|
||||
<item name="android:actionBarTabStyle">@style/default_actionbar_tab_style</item>
|
||||
<item name="actionBarStyle">@style/default_actionbar_style</item>
|
||||
<item name="android:actionBarStyle">@style/default_actionbar_style</item>
|
||||
</style>
|
||||
</resources>
|
@ -38,7 +38,9 @@
|
||||
|
||||
<!--action bar-->
|
||||
<item name="actionBarTabStyle">@style/metro_blue_actionbar_tab_style</item>
|
||||
<item name="android:actionBarTabStyle">@style/metro_blue_actionbar_tab_style</item>
|
||||
<item name="actionBarStyle">@style/metro_blue_actionbar_style</item>
|
||||
<item name="android:actionBarStyle">@style/metro_blue_actionbar_style</item>
|
||||
</style>
|
||||
|
||||
</resources>
|
22
calculatorpp/res/xml/plot_preferences.xml
Normal file
22
calculatorpp/res/xml/plot_preferences.xml
Normal file
@ -0,0 +1,22 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<PreferenceScreen xmlns:a="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<android.preference.CheckBoxPreference
|
||||
a:key="graph_interpolate"
|
||||
a:title="Interpolate function's graph"
|
||||
a:summary="If checked cubic interpolation will be used in function graph drawing"/>
|
||||
|
||||
<ListPreference a:key="graph_line_color_real"
|
||||
a:title="Color of real part of functions graph"
|
||||
a:summary="Sets color of real part functions graph"
|
||||
a:entries="@array/graph_line_color_names"
|
||||
a:entryValues="@array/graph_line_color_values"/>
|
||||
|
||||
<ListPreference a:key="graph_line_color_imag"
|
||||
a:title="Color of imaginary part of functions graph"
|
||||
a:summary="Sets color of imaginary part functions graph"
|
||||
a:entries="@array/graph_line_color_names"
|
||||
a:entryValues="@array/graph_line_color_values"/>
|
||||
|
||||
</PreferenceScreen>
|
@ -1,56 +1,61 @@
|
||||
package org.solovyev.android.calculator;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.os.Bundle;
|
||||
import android.support.v4.app.Fragment;
|
||||
import android.view.View;
|
||||
import com.actionbarsherlock.app.SherlockFragmentActivity;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.solovyev.android.calculator.about.CalculatorFragmentType;
|
||||
|
||||
/**
|
||||
* User: serso
|
||||
* Date: 9/25/12
|
||||
* Time: 10:31 PM
|
||||
*/
|
||||
public interface CalculatorActivityHelper {
|
||||
|
||||
void onCreate(@NotNull SherlockFragmentActivity activity, @Nullable Bundle savedInstanceState);
|
||||
void onCreate(@NotNull Activity activity, @Nullable Bundle savedInstanceState);
|
||||
|
||||
void onSaveInstanceState(@NotNull SherlockFragmentActivity activity, @NotNull Bundle outState);
|
||||
void onSaveInstanceState(@NotNull Activity activity, @NotNull Bundle outState);
|
||||
|
||||
int getLayoutId();
|
||||
|
||||
@NotNull
|
||||
CalculatorPreferences.Gui.Theme getTheme();
|
||||
|
||||
void onResume(@NotNull SherlockFragmentActivity activity);
|
||||
void onResume(@NotNull Activity activity);
|
||||
|
||||
void onPause(@NotNull Activity activity);
|
||||
void onPause(@NotNull SherlockFragmentActivity activity);
|
||||
|
||||
void onDestroy(@NotNull SherlockFragmentActivity activity);
|
||||
void onDestroy(@NotNull Activity activity);
|
||||
|
||||
void addTab(@NotNull SherlockFragmentActivity activity,
|
||||
@NotNull String tag,
|
||||
@NotNull Class<? extends Fragment> fragmentClass,
|
||||
@Nullable Bundle fragmentArgs,
|
||||
int captionResId,
|
||||
int parentViewId);
|
||||
|
||||
void addTab(@NotNull SherlockFragmentActivity activity,
|
||||
@NotNull CalculatorFragmentType fragmentType,
|
||||
@Nullable Bundle fragmentArgs,
|
||||
int parentViewId);
|
||||
|
||||
|
||||
void logDebug(@NotNull String message);
|
||||
|
||||
void processButtons(@NotNull Activity activity, @NotNull View root);
|
||||
|
||||
}
|
||||
package org.solovyev.android.calculator;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.os.Bundle;
|
||||
import android.support.v4.app.Fragment;
|
||||
import android.view.View;
|
||||
import com.actionbarsherlock.app.SherlockFragmentActivity;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.solovyev.android.calculator.about.CalculatorFragmentType;
|
||||
|
||||
/**
|
||||
* User: serso
|
||||
* Date: 9/25/12
|
||||
* Time: 10:31 PM
|
||||
*/
|
||||
public interface CalculatorActivityHelper {
|
||||
|
||||
void onCreate(@NotNull SherlockFragmentActivity activity, @Nullable Bundle savedInstanceState);
|
||||
void onCreate(@NotNull Activity activity, @Nullable Bundle savedInstanceState);
|
||||
|
||||
void onSaveInstanceState(@NotNull SherlockFragmentActivity activity, @NotNull Bundle outState);
|
||||
void onSaveInstanceState(@NotNull Activity activity, @NotNull Bundle outState);
|
||||
|
||||
int getLayoutId();
|
||||
|
||||
@NotNull
|
||||
CalculatorPreferences.Gui.Theme getTheme();
|
||||
|
||||
void onResume(@NotNull SherlockFragmentActivity activity);
|
||||
void onResume(@NotNull Activity activity);
|
||||
|
||||
void onPause(@NotNull Activity activity);
|
||||
void onPause(@NotNull SherlockFragmentActivity activity);
|
||||
|
||||
void onDestroy(@NotNull SherlockFragmentActivity activity);
|
||||
void onDestroy(@NotNull Activity activity);
|
||||
|
||||
void addTab(@NotNull SherlockFragmentActivity activity,
|
||||
@NotNull String tag,
|
||||
@NotNull Class<? extends Fragment> fragmentClass,
|
||||
@Nullable Bundle fragmentArgs,
|
||||
int captionResId,
|
||||
int parentViewId);
|
||||
|
||||
void addTab(@NotNull SherlockFragmentActivity activity,
|
||||
@NotNull CalculatorFragmentType fragmentType,
|
||||
@Nullable Bundle fragmentArgs,
|
||||
int parentViewId);
|
||||
|
||||
void setFragment(@NotNull SherlockFragmentActivity activity,
|
||||
@NotNull CalculatorFragmentType fragmentType,
|
||||
@Nullable Bundle fragmentArgs,
|
||||
int parentViewId);
|
||||
|
||||
|
||||
void logDebug(@NotNull String message);
|
||||
|
||||
void processButtons(@NotNull Activity activity, @NotNull View root);
|
||||
|
||||
}
|
||||
|
@ -1,219 +1,230 @@
|
||||
package org.solovyev.android.calculator;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.res.Configuration;
|
||||
import android.os.Bundle;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.support.v4.app.Fragment;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
import com.actionbarsherlock.app.ActionBar;
|
||||
import com.actionbarsherlock.app.SherlockFragmentActivity;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.solovyev.android.AndroidUtils;
|
||||
import org.solovyev.android.calculator.about.CalculatorFragmentType;
|
||||
import org.solovyev.android.sherlock.tabs.ActionBarFragmentTabListener;
|
||||
|
||||
/**
|
||||
* User: serso
|
||||
* Date: 9/25/12
|
||||
* Time: 10:32 PM
|
||||
*/
|
||||
public class CalculatorActivityHelperImpl extends AbstractCalculatorHelper implements CalculatorActivityHelper {
|
||||
|
||||
/*
|
||||
**********************************************************************
|
||||
*
|
||||
* CONSTANTS
|
||||
*
|
||||
**********************************************************************
|
||||
*/
|
||||
|
||||
/*
|
||||
**********************************************************************
|
||||
*
|
||||
* FIELDS
|
||||
*
|
||||
**********************************************************************
|
||||
*/
|
||||
|
||||
private int layoutId;
|
||||
|
||||
private boolean homeIcon = false;
|
||||
|
||||
@NotNull
|
||||
private CalculatorPreferences.Gui.Theme theme;
|
||||
|
||||
private int selectedNavigationIndex = 0;
|
||||
|
||||
public CalculatorActivityHelperImpl(int layoutId, @NotNull String logTag) {
|
||||
super(logTag);
|
||||
this.layoutId = layoutId;
|
||||
}
|
||||
|
||||
public CalculatorActivityHelperImpl(int layoutId, boolean homeIcon) {
|
||||
this.layoutId = layoutId;
|
||||
this.homeIcon = homeIcon;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(@NotNull Activity activity, @Nullable Bundle savedInstanceState) {
|
||||
super.onCreate(activity);
|
||||
|
||||
if (activity instanceof CalculatorEventListener) {
|
||||
CalculatorLocatorImpl.getInstance().getCalculator().addCalculatorEventListener((CalculatorEventListener) activity);
|
||||
}
|
||||
|
||||
final SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(activity);
|
||||
|
||||
this.theme = CalculatorPreferences.Gui.getTheme(preferences);
|
||||
activity.setTheme(this.theme.getThemeId());
|
||||
|
||||
activity.setContentView(layoutId);
|
||||
|
||||
final View root = activity.findViewById(R.id.main_layout);
|
||||
if (root != null) {
|
||||
processButtons(activity, root);
|
||||
} else {
|
||||
Log.e(CalculatorActivityHelperImpl.class.getSimpleName(), "Root is null for " + activity.getClass().getName());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(@NotNull final SherlockFragmentActivity activity, @Nullable Bundle savedInstanceState) {
|
||||
this.onCreate((Activity) activity, savedInstanceState);
|
||||
|
||||
final ActionBar actionBar = activity.getSupportActionBar();
|
||||
actionBar.setDisplayUseLogoEnabled(false);
|
||||
actionBar.setDisplayHomeAsUpEnabled(homeIcon);
|
||||
actionBar.setHomeButtonEnabled(false);
|
||||
actionBar.setDisplayShowHomeEnabled(true);
|
||||
|
||||
toggleTitle(activity, true);
|
||||
|
||||
actionBar.setIcon(R.drawable.icon_action_bar);
|
||||
actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
|
||||
}
|
||||
|
||||
private void toggleTitle(@NotNull SherlockFragmentActivity activity, boolean showTitle) {
|
||||
final ActionBar actionBar = activity.getSupportActionBar();
|
||||
|
||||
if (activity instanceof CalculatorActivity) {
|
||||
if (AndroidUtils.getScreenOrientation(activity) == Configuration.ORIENTATION_PORTRAIT) {
|
||||
actionBar.setDisplayShowTitleEnabled(true);
|
||||
} else {
|
||||
actionBar.setDisplayShowTitleEnabled(false);
|
||||
}
|
||||
} else {
|
||||
actionBar.setDisplayShowTitleEnabled(showTitle);
|
||||
}
|
||||
}
|
||||
|
||||
public void restoreSavedTab(@NotNull SherlockFragmentActivity activity) {
|
||||
final ActionBar actionBar = activity.getSupportActionBar();
|
||||
if (selectedNavigationIndex >= 0 && selectedNavigationIndex < actionBar.getTabCount()) {
|
||||
actionBar.setSelectedNavigationItem(selectedNavigationIndex);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSaveInstanceState(@NotNull SherlockFragmentActivity activity, @NotNull Bundle outState) {
|
||||
onSaveInstanceState((Activity) activity, outState);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSaveInstanceState(@NotNull Activity activity, @NotNull Bundle outState) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume(@NotNull Activity activity) {
|
||||
final SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(activity);
|
||||
|
||||
final CalculatorPreferences.Gui.Theme newTheme = CalculatorPreferences.Gui.theme.getPreference(preferences);
|
||||
if (!theme.equals(newTheme)) {
|
||||
AndroidUtils.restartActivity(activity);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPause(@NotNull Activity activity) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPause(@NotNull SherlockFragmentActivity activity) {
|
||||
onPause((Activity) activity);
|
||||
|
||||
final int selectedNavigationIndex = activity.getSupportActionBar().getSelectedNavigationIndex();
|
||||
if (selectedNavigationIndex >= 0) {
|
||||
final SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(activity);
|
||||
final SharedPreferences.Editor editor = preferences.edit();
|
||||
editor.putInt(getSavedTabPreferenceName(activity), selectedNavigationIndex);
|
||||
editor.commit();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private String getSavedTabPreferenceName(@NotNull Activity activity) {
|
||||
return "tab_" + activity.getClass().getSimpleName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy(@NotNull Activity activity) {
|
||||
super.onDestroy(activity);
|
||||
|
||||
if (activity instanceof CalculatorEventListener) {
|
||||
CalculatorLocatorImpl.getInstance().getCalculator().removeCalculatorEventListener((CalculatorEventListener) activity);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy(@NotNull SherlockFragmentActivity activity) {
|
||||
this.onDestroy((Activity) activity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addTab(@NotNull SherlockFragmentActivity activity,
|
||||
@NotNull String tag,
|
||||
@NotNull Class<? extends Fragment> fragmentClass,
|
||||
@Nullable Bundle fragmentArgs,
|
||||
int captionResId,
|
||||
int parentViewId) {
|
||||
final ActionBar actionBar = activity.getSupportActionBar();
|
||||
|
||||
final ActionBar.Tab tab = actionBar.newTab();
|
||||
tab.setTag(tag);
|
||||
tab.setText(captionResId);
|
||||
|
||||
final ActionBarFragmentTabListener listener = new ActionBarFragmentTabListener(activity, tag, fragmentClass, fragmentArgs, parentViewId);
|
||||
tab.setTabListener(listener);
|
||||
actionBar.addTab(tab);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addTab(@NotNull SherlockFragmentActivity activity, @NotNull CalculatorFragmentType fragmentType, @Nullable Bundle fragmentArgs, int parentViewId) {
|
||||
addTab(activity, fragmentType.getFragmentTag(), fragmentType.getFragmentClass(), fragmentArgs, fragmentType.getDefaultTitleResId(), parentViewId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getLayoutId() {
|
||||
return layoutId;
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public CalculatorPreferences.Gui.Theme getTheme() {
|
||||
return theme;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume(@NotNull SherlockFragmentActivity activity) {
|
||||
onResume((Activity) activity);
|
||||
|
||||
final SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(activity);
|
||||
selectedNavigationIndex = preferences.getInt(getSavedTabPreferenceName(activity), -1);
|
||||
restoreSavedTab(activity);
|
||||
}
|
||||
}
|
||||
package org.solovyev.android.calculator;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.res.Configuration;
|
||||
import android.os.Bundle;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.support.v4.app.Fragment;
|
||||
import android.support.v4.app.FragmentManager;
|
||||
import android.support.v4.app.FragmentTransaction;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
import com.actionbarsherlock.app.ActionBar;
|
||||
import com.actionbarsherlock.app.SherlockFragmentActivity;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.solovyev.android.AndroidUtils;
|
||||
import org.solovyev.android.calculator.about.CalculatorFragmentType;
|
||||
import org.solovyev.android.sherlock.tabs.ActionBarFragmentTabListener;
|
||||
|
||||
/**
|
||||
* User: serso
|
||||
* Date: 9/25/12
|
||||
* Time: 10:32 PM
|
||||
*/
|
||||
public class CalculatorActivityHelperImpl extends AbstractCalculatorHelper implements CalculatorActivityHelper {
|
||||
|
||||
/*
|
||||
**********************************************************************
|
||||
*
|
||||
* CONSTANTS
|
||||
*
|
||||
**********************************************************************
|
||||
*/
|
||||
|
||||
/*
|
||||
**********************************************************************
|
||||
*
|
||||
* FIELDS
|
||||
*
|
||||
**********************************************************************
|
||||
*/
|
||||
|
||||
private int layoutId;
|
||||
|
||||
private boolean homeIcon = false;
|
||||
|
||||
@NotNull
|
||||
private CalculatorPreferences.Gui.Theme theme;
|
||||
|
||||
private int selectedNavigationIndex = 0;
|
||||
|
||||
public CalculatorActivityHelperImpl(int layoutId, @NotNull String logTag) {
|
||||
super(logTag);
|
||||
this.layoutId = layoutId;
|
||||
}
|
||||
|
||||
public CalculatorActivityHelperImpl(int layoutId, boolean homeIcon) {
|
||||
this.layoutId = layoutId;
|
||||
this.homeIcon = homeIcon;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(@NotNull Activity activity, @Nullable Bundle savedInstanceState) {
|
||||
super.onCreate(activity);
|
||||
|
||||
if (activity instanceof CalculatorEventListener) {
|
||||
CalculatorLocatorImpl.getInstance().getCalculator().addCalculatorEventListener((CalculatorEventListener) activity);
|
||||
}
|
||||
|
||||
final SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(activity);
|
||||
|
||||
this.theme = CalculatorPreferences.Gui.getTheme(preferences);
|
||||
activity.setTheme(this.theme.getThemeId());
|
||||
|
||||
activity.setContentView(layoutId);
|
||||
|
||||
final View root = activity.findViewById(R.id.main_layout);
|
||||
if (root != null) {
|
||||
processButtons(activity, root);
|
||||
} else {
|
||||
Log.e(CalculatorActivityHelperImpl.class.getSimpleName(), "Root is null for " + activity.getClass().getName());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(@NotNull final SherlockFragmentActivity activity, @Nullable Bundle savedInstanceState) {
|
||||
this.onCreate((Activity) activity, savedInstanceState);
|
||||
|
||||
final ActionBar actionBar = activity.getSupportActionBar();
|
||||
actionBar.setDisplayUseLogoEnabled(false);
|
||||
actionBar.setDisplayHomeAsUpEnabled(homeIcon);
|
||||
actionBar.setHomeButtonEnabled(false);
|
||||
actionBar.setDisplayShowHomeEnabled(true);
|
||||
|
||||
toggleTitle(activity, true);
|
||||
|
||||
actionBar.setIcon(R.drawable.icon_action_bar);
|
||||
actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
|
||||
}
|
||||
|
||||
private void toggleTitle(@NotNull SherlockFragmentActivity activity, boolean showTitle) {
|
||||
final ActionBar actionBar = activity.getSupportActionBar();
|
||||
|
||||
if (activity instanceof CalculatorActivity) {
|
||||
if (AndroidUtils.getScreenOrientation(activity) == Configuration.ORIENTATION_PORTRAIT) {
|
||||
actionBar.setDisplayShowTitleEnabled(true);
|
||||
} else {
|
||||
actionBar.setDisplayShowTitleEnabled(false);
|
||||
}
|
||||
} else {
|
||||
actionBar.setDisplayShowTitleEnabled(showTitle);
|
||||
}
|
||||
}
|
||||
|
||||
public void restoreSavedTab(@NotNull SherlockFragmentActivity activity) {
|
||||
final ActionBar actionBar = activity.getSupportActionBar();
|
||||
if (selectedNavigationIndex >= 0 && selectedNavigationIndex < actionBar.getTabCount()) {
|
||||
actionBar.setSelectedNavigationItem(selectedNavigationIndex);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSaveInstanceState(@NotNull SherlockFragmentActivity activity, @NotNull Bundle outState) {
|
||||
onSaveInstanceState((Activity) activity, outState);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSaveInstanceState(@NotNull Activity activity, @NotNull Bundle outState) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume(@NotNull Activity activity) {
|
||||
final SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(activity);
|
||||
|
||||
final CalculatorPreferences.Gui.Theme newTheme = CalculatorPreferences.Gui.theme.getPreference(preferences);
|
||||
if (!theme.equals(newTheme)) {
|
||||
AndroidUtils.restartActivity(activity);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPause(@NotNull Activity activity) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPause(@NotNull SherlockFragmentActivity activity) {
|
||||
onPause((Activity) activity);
|
||||
|
||||
final int selectedNavigationIndex = activity.getSupportActionBar().getSelectedNavigationIndex();
|
||||
if (selectedNavigationIndex >= 0) {
|
||||
final SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(activity);
|
||||
final SharedPreferences.Editor editor = preferences.edit();
|
||||
editor.putInt(getSavedTabPreferenceName(activity), selectedNavigationIndex);
|
||||
editor.commit();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private String getSavedTabPreferenceName(@NotNull Activity activity) {
|
||||
return "tab_" + activity.getClass().getSimpleName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy(@NotNull Activity activity) {
|
||||
super.onDestroy(activity);
|
||||
|
||||
if (activity instanceof CalculatorEventListener) {
|
||||
CalculatorLocatorImpl.getInstance().getCalculator().removeCalculatorEventListener((CalculatorEventListener) activity);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy(@NotNull SherlockFragmentActivity activity) {
|
||||
this.onDestroy((Activity) activity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addTab(@NotNull SherlockFragmentActivity activity,
|
||||
@NotNull String tag,
|
||||
@NotNull Class<? extends Fragment> fragmentClass,
|
||||
@Nullable Bundle fragmentArgs,
|
||||
int captionResId,
|
||||
int parentViewId) {
|
||||
final ActionBar actionBar = activity.getSupportActionBar();
|
||||
|
||||
final ActionBar.Tab tab = actionBar.newTab();
|
||||
tab.setTag(tag);
|
||||
tab.setText(captionResId);
|
||||
|
||||
final ActionBarFragmentTabListener listener = new ActionBarFragmentTabListener(activity, tag, fragmentClass, fragmentArgs, parentViewId);
|
||||
tab.setTabListener(listener);
|
||||
actionBar.addTab(tab);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addTab(@NotNull SherlockFragmentActivity activity, @NotNull CalculatorFragmentType fragmentType, @Nullable Bundle fragmentArgs, int parentViewId) {
|
||||
addTab(activity, fragmentType.getFragmentTag(), fragmentType.getFragmentClass(), fragmentArgs, fragmentType.getDefaultTitleResId(), parentViewId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFragment(@NotNull SherlockFragmentActivity activity, @NotNull CalculatorFragmentType fragmentType, @Nullable Bundle fragmentArgs, int parentViewId) {
|
||||
final Fragment fragment = Fragment.instantiate(activity, fragmentType.getFragmentClass().getName(), fragmentArgs);
|
||||
final FragmentManager fm = activity.getSupportFragmentManager();
|
||||
final FragmentTransaction ft = fm.beginTransaction();
|
||||
ft.add(parentViewId, fragment);
|
||||
ft.commit();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getLayoutId() {
|
||||
return layoutId;
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public CalculatorPreferences.Gui.Theme getTheme() {
|
||||
return theme;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume(@NotNull SherlockFragmentActivity activity) {
|
||||
onResume((Activity) activity);
|
||||
|
||||
final SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(activity);
|
||||
selectedNavigationIndex = preferences.getInt(getSavedTabPreferenceName(activity), -1);
|
||||
restoreSavedTab(activity);
|
||||
}
|
||||
}
|
||||
|
@ -5,6 +5,7 @@ import org.jetbrains.annotations.NotNull;
|
||||
import org.solovyev.android.AndroidUtils;
|
||||
import org.solovyev.android.calculator.math.MathType;
|
||||
import org.solovyev.android.calculator.model.AndroidCalculatorEngine;
|
||||
import org.solovyev.android.calculator.plot.GraphLineColor;
|
||||
import org.solovyev.android.prefs.BooleanPreference;
|
||||
import org.solovyev.android.prefs.IntegerPreference;
|
||||
import org.solovyev.android.prefs.Preference;
|
||||
@ -98,7 +99,9 @@ public final class CalculatorPreferences {
|
||||
}
|
||||
|
||||
public static class Graph {
|
||||
public static final Preference<Boolean> showComplexGraph = new BooleanPreference("show_complex_graph", false);
|
||||
public static final Preference<Boolean> interpolate = new BooleanPreference("graph_interpolate", true);
|
||||
public static final Preference<GraphLineColor> lineColorReal = StringPreference.newInstance("graph_line_color_real", GraphLineColor.white, GraphLineColor.class);
|
||||
public static final Preference<GraphLineColor> lineColorImag = StringPreference.newInstance("graph_line_color_imag", GraphLineColor.blue, GraphLineColor.class);
|
||||
|
||||
}
|
||||
|
||||
|
@ -39,7 +39,10 @@ public class CalculatorPreferencesActivity extends SherlockPreferenceActivity im
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
addPreferencesFromResource(R.xml.preferences);
|
||||
//noinspection deprecation
|
||||
addPreferencesFromResource(R.xml.preferences);
|
||||
//noinspection deprecation
|
||||
addPreferencesFromResource(R.xml.plot_preferences);
|
||||
|
||||
final Preference adFreePreference = findPreference(CalculatorApplication.AD_FREE_P_KEY);
|
||||
adFreePreference.setEnabled(false);
|
||||
|
@ -1,32 +1,34 @@
|
||||
package org.solovyev.android.calculator.plot;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.solovyev.android.calculator.CalculatorFragmentActivity;
|
||||
import org.solovyev.android.calculator.R;
|
||||
import org.solovyev.android.calculator.about.CalculatorFragmentType;
|
||||
|
||||
/**
|
||||
* User: serso
|
||||
* Date: 9/30/12
|
||||
* Time: 4:56 PM
|
||||
*/
|
||||
public class CalculatorPlotActivity extends CalculatorFragmentActivity {
|
||||
|
||||
@Override
|
||||
public void onCreate(@Nullable Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
final Intent intent = getIntent();
|
||||
|
||||
final Bundle arguments;
|
||||
if (intent != null) {
|
||||
arguments = intent.getExtras();
|
||||
} else {
|
||||
arguments = null;
|
||||
}
|
||||
|
||||
getActivityHelper().addTab(this, CalculatorFragmentType.plotter, arguments, R.id.main_layout);
|
||||
}
|
||||
}
|
||||
package org.solovyev.android.calculator.plot;
|
||||
|
||||
import android.app.ActionBar;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.solovyev.android.calculator.CalculatorFragmentActivity;
|
||||
import org.solovyev.android.calculator.R;
|
||||
import org.solovyev.android.calculator.about.CalculatorFragmentType;
|
||||
|
||||
/**
|
||||
* User: serso
|
||||
* Date: 9/30/12
|
||||
* Time: 4:56 PM
|
||||
*/
|
||||
public class CalculatorPlotActivity extends CalculatorFragmentActivity {
|
||||
|
||||
@Override
|
||||
public void onCreate(@Nullable Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
final Intent intent = getIntent();
|
||||
|
||||
final Bundle arguments;
|
||||
if (intent != null) {
|
||||
arguments = intent.getExtras();
|
||||
} else {
|
||||
arguments = null;
|
||||
}
|
||||
|
||||
getSupportActionBar().setNavigationMode(ActionBar.NAVIGATION_MODE_STANDARD);
|
||||
getActivityHelper().setFragment(this, CalculatorFragmentType.plotter, arguments, R.id.main_layout);
|
||||
}
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,21 @@
|
||||
package org.solovyev.android.calculator.plot;
|
||||
|
||||
import android.os.Bundle;
|
||||
import com.actionbarsherlock.app.SherlockPreferenceActivity;
|
||||
import org.solovyev.android.calculator.R;
|
||||
|
||||
/**
|
||||
* User: serso
|
||||
* Date: 10/4/12
|
||||
* Time: 9:01 PM
|
||||
*/
|
||||
public class CalculatorPlotPreferenceActivity extends SherlockPreferenceActivity {
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
//noinspection deprecation
|
||||
addPreferencesFromResource(R.xml.plot_preferences);
|
||||
}
|
||||
}
|
@ -0,0 +1,28 @@
|
||||
package org.solovyev.android.calculator.plot;
|
||||
|
||||
import android.graphics.Color;
|
||||
|
||||
/**
|
||||
* User: serso
|
||||
* Date: 10/4/12
|
||||
* Time: 10:08 PM
|
||||
*/
|
||||
public enum GraphLineColor {
|
||||
|
||||
white(Color.WHITE),
|
||||
grey(Color.GRAY),
|
||||
red(Color.RED),
|
||||
blue(Color.rgb(16, 100, 140)),
|
||||
green(Color.GREEN);
|
||||
|
||||
private final int color;
|
||||
|
||||
private GraphLineColor(int color) {
|
||||
this.color = color;
|
||||
}
|
||||
|
||||
|
||||
public int getColor() {
|
||||
return this.color;
|
||||
}
|
||||
}
|
@ -1,336 +1,420 @@
|
||||
/*
|
||||
* Copyright (c) 2009-2011. Created by serso aka se.solovyev.
|
||||
* For more information, please, contact se.solovyev@gmail.com
|
||||
* or visit http://se.solovyev.org
|
||||
*/
|
||||
|
||||
package org.solovyev.android.calculator.plot;
|
||||
|
||||
import android.util.Log;
|
||||
import jscl.math.Expression;
|
||||
import jscl.math.Generic;
|
||||
import jscl.math.JsclInteger;
|
||||
import jscl.math.NumericWrapper;
|
||||
import jscl.math.function.Constant;
|
||||
import jscl.math.numeric.Complex;
|
||||
import jscl.math.numeric.Numeric;
|
||||
import jscl.math.numeric.Real;
|
||||
import org.achartengine.util.MathHelper;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
/**
|
||||
* User: serso
|
||||
* Date: 12/5/11
|
||||
* Time: 8:58 PM
|
||||
*/
|
||||
public final class PlotUtils {
|
||||
|
||||
private static final double MAX_Y_DIFF = 1;
|
||||
private static final double MAX_X_DIFF = 1;
|
||||
|
||||
// not intended for instantiation
|
||||
private PlotUtils() {
|
||||
throw new AssertionError();
|
||||
}
|
||||
|
||||
public static boolean addXY(double minValue,
|
||||
double maxValue,
|
||||
@NotNull Generic expression,
|
||||
@NotNull Constant variable,
|
||||
@NotNull MyXYSeries realSeries,
|
||||
@Nullable MyXYSeries imagSeries,
|
||||
boolean addExtra,
|
||||
int numberOfSteps) throws ArithmeticException {
|
||||
|
||||
boolean imagExists = false;
|
||||
|
||||
double min = Math.min(minValue, maxValue);
|
||||
double max = Math.max(minValue, maxValue);
|
||||
double dist = max - min;
|
||||
if (addExtra) {
|
||||
min = min - dist;
|
||||
max = max + dist;
|
||||
}
|
||||
|
||||
final double eps = 0.000000001;
|
||||
|
||||
final double defaultStep = Math.max(dist / numberOfSteps, eps);
|
||||
double step = defaultStep;
|
||||
|
||||
final Point real = new Point();
|
||||
final Point imag = new Point();
|
||||
|
||||
double x = min;
|
||||
|
||||
while (x <= max) {
|
||||
|
||||
boolean needToCalculateRealY = realSeries.needToAdd(step, x);
|
||||
|
||||
if (needToCalculateRealY) {
|
||||
final Complex c = calculatorExpression(expression, variable, x);
|
||||
Double y = prepareY(c.realPart());
|
||||
|
||||
if (y != null) {
|
||||
real.moveToNextPoint(x, y);
|
||||
addSingularityPoint(realSeries, real);
|
||||
realSeries.add(x, y);
|
||||
}
|
||||
|
||||
boolean needToCalculateImagY = imagSeries != null && imagSeries.needToAdd(step, x);
|
||||
if (needToCalculateImagY) {
|
||||
y = prepareY(c.imaginaryPart());
|
||||
if (y != null) {
|
||||
imag.moveToNextPoint(x, y);
|
||||
addSingularityPoint(imagSeries, imag);
|
||||
imagSeries.add(x, y);
|
||||
}
|
||||
if (c.imaginaryPart() != 0d) {
|
||||
imagExists = true;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
boolean needToCalculateImagY = imagSeries != null && imagSeries.needToAdd(step, x);
|
||||
if (needToCalculateImagY) {
|
||||
final Complex c = calculatorExpression(expression, variable, x);
|
||||
Double y = prepareY(c.imaginaryPart());
|
||||
if (y != null) {
|
||||
imag.moveToNextPoint(x, y);
|
||||
addSingularityPoint(imagSeries, imag);
|
||||
imagSeries.add(x, y);
|
||||
}
|
||||
if (c.imaginaryPart() != 0d) {
|
||||
imagExists = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
step = updateStep(real, step, defaultStep / 2);
|
||||
|
||||
x += step;
|
||||
}
|
||||
|
||||
return imagExists;
|
||||
}
|
||||
|
||||
private static class Point {
|
||||
private static final double DEFAULT = Double.MIN_VALUE;
|
||||
|
||||
private double x0 = DEFAULT;
|
||||
private double x1 = DEFAULT;
|
||||
private double x2 = DEFAULT;
|
||||
|
||||
private double y0 = DEFAULT;
|
||||
private double y1 = DEFAULT;
|
||||
private double y2 = DEFAULT;
|
||||
|
||||
private Point() {
|
||||
}
|
||||
|
||||
public void moveToNextPoint(double x, double y) {
|
||||
if ( this.x2 == x ) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.x0 = this.x1;
|
||||
this.x1 = this.x2;
|
||||
this.x2 = x;
|
||||
|
||||
this.y0 = this.y1;
|
||||
this.y1 = this.y2;
|
||||
this.y2 = y;
|
||||
}
|
||||
|
||||
public boolean isFullyDefined() {
|
||||
return x0 != DEFAULT && x1 != DEFAULT && x2 != DEFAULT && y0 != DEFAULT && y1 != DEFAULT && y2 != DEFAULT;
|
||||
}
|
||||
|
||||
public double getDx2() {
|
||||
return x2 - x1;
|
||||
}
|
||||
|
||||
public double getAbsDx2() {
|
||||
if ( x2 > x1 ) {
|
||||
return Math.abs(x2 - x1);
|
||||
} else {
|
||||
return Math.abs(x1 - x2);
|
||||
}
|
||||
}
|
||||
|
||||
public double getAbsDx1() {
|
||||
if ( x1 > x0 ) {
|
||||
return Math.abs(x1 - x0);
|
||||
} else {
|
||||
return Math.abs(x0 - x1);
|
||||
}
|
||||
}
|
||||
|
||||
public double getAbsDy1() {
|
||||
if ( y1 > y0 ) {
|
||||
return Math.abs(y1 - y0);
|
||||
} else {
|
||||
return Math.abs(y0 - y1);
|
||||
}
|
||||
}
|
||||
|
||||
public double getAbsDy2() {
|
||||
if ( y2 > y1 ) {
|
||||
return Math.abs(y2 - y1);
|
||||
} else {
|
||||
return Math.abs(y1 - y2);
|
||||
}
|
||||
}
|
||||
|
||||
public double getX0() {
|
||||
return x0;
|
||||
}
|
||||
|
||||
public double getX1() {
|
||||
return x1;
|
||||
}
|
||||
|
||||
public double getX2() {
|
||||
return x2;
|
||||
}
|
||||
|
||||
public boolean isX2Defined() {
|
||||
return x2 != DEFAULT;
|
||||
}
|
||||
|
||||
public double getY0() {
|
||||
return y0;
|
||||
}
|
||||
|
||||
public double getY1() {
|
||||
return y1;
|
||||
}
|
||||
|
||||
public double getY2() {
|
||||
return y2;
|
||||
}
|
||||
|
||||
public void clearHistory () {
|
||||
this.x0 = DEFAULT;
|
||||
this.x1 = DEFAULT;
|
||||
this.y0 = DEFAULT;
|
||||
this.y1 = DEFAULT;
|
||||
}
|
||||
|
||||
public double getAbsDyDx2() {
|
||||
double dx2 = this.getAbsDx2();
|
||||
double dy2 = this.getAbsDy2();
|
||||
return dy2 / dx2;
|
||||
}
|
||||
|
||||
public double getAbsDyDx1() {
|
||||
double dx1 = this.getAbsDx1();
|
||||
double dy1 = this.getAbsDy1();
|
||||
return dy1 / dx1;
|
||||
}
|
||||
|
||||
public double getDyDx1() {
|
||||
double result = getAbsDyDx1();
|
||||
return y1 > y0 ? result : -result;
|
||||
}
|
||||
|
||||
public double getDyDx2() {
|
||||
double result = getAbsDyDx2();
|
||||
return y2 > y1 ? result : -result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Point{" +
|
||||
"x0=" + x0 +
|
||||
", x1=" + x1 +
|
||||
", x2=" + x2 +
|
||||
", y0=" + y0 +
|
||||
", y1=" + y1 +
|
||||
", y2=" + y2 +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
|
||||
private static double updateStep(@NotNull Point real,
|
||||
double step,
|
||||
double eps) {
|
||||
if ( !real.isFullyDefined() ) {
|
||||
return step;
|
||||
} else {
|
||||
double dydx2 = real.getAbsDyDx2();
|
||||
double dydx1 = real.getAbsDyDx1();
|
||||
|
||||
double k = dydx2 / dydx1;
|
||||
|
||||
if ( k > 1 ) {
|
||||
step = step / k;
|
||||
} else if ( k > 0 ) {
|
||||
step = step * k;
|
||||
}
|
||||
|
||||
return Math.max(step, eps);
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static Complex calculatorExpression(@NotNull Generic expression, @NotNull Constant variable, double x) {
|
||||
return unwrap(expression.substitute(variable, Expression.valueOf(x)).numeric());
|
||||
}
|
||||
|
||||
public static void addSingularityPoint(@NotNull MyXYSeries series,
|
||||
@NotNull Point point) {
|
||||
if (point.isFullyDefined()) {
|
||||
// y or prevY should be more than 1d because if they are too small false singularity may occur (e.g., 1/0.000000000000000001)
|
||||
// double dy0 = y1 - y0;
|
||||
// double dx0 = x1 - x0;
|
||||
// double dydx0 = dy0 / dx0;
|
||||
|
||||
double dy2 = point.getAbsDy2();
|
||||
double dx2 = point.getAbsDx2();
|
||||
//double dx1 = x2 - x1;
|
||||
// double dydx1 = dy2 / dx1;
|
||||
|
||||
if ( dy2 > MAX_Y_DIFF && dx2 < MAX_X_DIFF && isDifferentSign(point.getY2(), point.getY1()) && isDifferentSign(point.getDyDx1(), point.getDyDx2())) {
|
||||
Log.d(CalculatorPlotActivity.class.getName(), "Singularity: " + point);
|
||||
//Log.d(CalculatorPlotActivity.class.getName(), String.valueOf(prevX + Math.abs(x - prevX) / 2) + ", null");
|
||||
series.add(point.getX1() + point.getAbsDx2() / 2, MathHelper.NULL_VALUE);
|
||||
point.clearHistory();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean isDifferentSign(@NotNull Double y0, @NotNull Double y1) {
|
||||
return (y0 >= 0 && y1 < 0) || (y1 >= 0 && y0 < 0);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static Double prepareY(double y) {
|
||||
if (Double.isNaN(y)) {
|
||||
return null;
|
||||
} else {
|
||||
return y;
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static Complex unwrap(@Nullable Generic numeric) {
|
||||
if (numeric instanceof JsclInteger) {
|
||||
return Complex.valueOf(((JsclInteger) numeric).intValue(), 0d);
|
||||
} else if (numeric instanceof NumericWrapper) {
|
||||
return unwrap(((NumericWrapper) numeric).content());
|
||||
} else {
|
||||
throw new ArithmeticException();
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static Complex unwrap(@Nullable Numeric content) {
|
||||
if (content instanceof Real) {
|
||||
return Complex.valueOf(((Real) content).doubleValue(), 0d);
|
||||
} else if (content instanceof Complex) {
|
||||
return ((Complex) content);
|
||||
} else {
|
||||
throw new ArithmeticException();
|
||||
}
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Copyright (c) 2009-2011. Created by serso aka se.solovyev.
|
||||
* For more information, please, contact se.solovyev@gmail.com
|
||||
* or visit http://se.solovyev.org
|
||||
*/
|
||||
|
||||
package org.solovyev.android.calculator.plot;
|
||||
|
||||
import android.util.Log;
|
||||
import jscl.math.Expression;
|
||||
import jscl.math.Generic;
|
||||
import jscl.math.JsclInteger;
|
||||
import jscl.math.NumericWrapper;
|
||||
import jscl.math.function.Constant;
|
||||
import jscl.math.numeric.Complex;
|
||||
import jscl.math.numeric.Numeric;
|
||||
import jscl.math.numeric.Real;
|
||||
import org.achartengine.chart.CubicLineChart;
|
||||
import org.achartengine.chart.PointStyle;
|
||||
import org.achartengine.chart.ScatterChart;
|
||||
import org.achartengine.chart.XYChart;
|
||||
import org.achartengine.model.XYMultipleSeriesDataset;
|
||||
import org.achartengine.renderer.BasicStroke;
|
||||
import org.achartengine.renderer.XYMultipleSeriesRenderer;
|
||||
import org.achartengine.renderer.XYSeriesRenderer;
|
||||
import org.achartengine.util.MathHelper;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
/**
|
||||
* User: serso
|
||||
* Date: 12/5/11
|
||||
* Time: 8:58 PM
|
||||
*/
|
||||
public final class PlotUtils {
|
||||
|
||||
private static final double MAX_Y_DIFF = 1;
|
||||
private static final double MAX_X_DIFF = 1;
|
||||
static final int DEFAULT_NUMBER_OF_STEPS = 100;
|
||||
|
||||
// not intended for instantiation
|
||||
private PlotUtils() {
|
||||
throw new AssertionError();
|
||||
}
|
||||
|
||||
public static boolean addXY(double minValue,
|
||||
double maxValue,
|
||||
@NotNull Generic expression,
|
||||
@NotNull Constant variable,
|
||||
@NotNull MyXYSeries realSeries,
|
||||
@Nullable MyXYSeries imagSeries,
|
||||
boolean addExtra,
|
||||
int numberOfSteps) throws ArithmeticException {
|
||||
|
||||
boolean imagExists = false;
|
||||
|
||||
double min = Math.min(minValue, maxValue);
|
||||
double max = Math.max(minValue, maxValue);
|
||||
double dist = max - min;
|
||||
if (addExtra) {
|
||||
min = min - dist;
|
||||
max = max + dist;
|
||||
}
|
||||
|
||||
final double eps = 0.000000001;
|
||||
|
||||
final double defaultStep = Math.max(dist / numberOfSteps, eps);
|
||||
double step = defaultStep;
|
||||
|
||||
final Point real = new Point();
|
||||
final Point imag = new Point();
|
||||
|
||||
double x = min;
|
||||
|
||||
while (x <= max) {
|
||||
|
||||
boolean needToCalculateRealY = realSeries.needToAdd(step, x);
|
||||
|
||||
if (needToCalculateRealY) {
|
||||
final Complex c = calculatorExpression(expression, variable, x);
|
||||
Double y = prepareY(c.realPart());
|
||||
|
||||
if (y != null) {
|
||||
real.moveToNextPoint(x, y);
|
||||
addSingularityPoint(realSeries, real);
|
||||
realSeries.add(x, y);
|
||||
}
|
||||
|
||||
boolean needToCalculateImagY = imagSeries != null && imagSeries.needToAdd(step, x);
|
||||
if (needToCalculateImagY) {
|
||||
y = prepareY(c.imaginaryPart());
|
||||
if (y != null) {
|
||||
imag.moveToNextPoint(x, y);
|
||||
addSingularityPoint(imagSeries, imag);
|
||||
imagSeries.add(x, y);
|
||||
}
|
||||
if (c.imaginaryPart() != 0d) {
|
||||
imagExists = true;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
boolean needToCalculateImagY = imagSeries != null && imagSeries.needToAdd(step, x);
|
||||
if (needToCalculateImagY) {
|
||||
final Complex c = calculatorExpression(expression, variable, x);
|
||||
Double y = prepareY(c.imaginaryPart());
|
||||
if (y != null) {
|
||||
imag.moveToNextPoint(x, y);
|
||||
addSingularityPoint(imagSeries, imag);
|
||||
imagSeries.add(x, y);
|
||||
}
|
||||
if (c.imaginaryPart() != 0d) {
|
||||
imagExists = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
step = updateStep(real, step, defaultStep / 2);
|
||||
|
||||
x += step;
|
||||
}
|
||||
|
||||
return imagExists;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
static String getImagFunctionName(@NotNull Constant variable) {
|
||||
return "g(" + variable.getName() + ")" + " = " + "Im(ƒ(" + variable.getName() + "))";
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static String getRealFunctionName(@NotNull Generic expression, @NotNull Constant variable) {
|
||||
return "ƒ(" + variable.getName() + ")" + " = " + expression.toString();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
static XYChart prepareChart(final double minValue,
|
||||
final double maxValue,
|
||||
@NotNull final Generic expression,
|
||||
@NotNull final Constant variable,
|
||||
int bgColor,
|
||||
boolean interpolate,
|
||||
int realLineColor,
|
||||
int imagLineColor) {
|
||||
final MyXYSeries realSeries = new MyXYSeries(getRealFunctionName(expression, variable), DEFAULT_NUMBER_OF_STEPS * 2);
|
||||
final MyXYSeries imagSeries = new MyXYSeries(getImagFunctionName(variable), DEFAULT_NUMBER_OF_STEPS * 2);
|
||||
|
||||
boolean imagExists = addXY(minValue, maxValue, expression, variable, realSeries, imagSeries, false, DEFAULT_NUMBER_OF_STEPS);
|
||||
|
||||
final XYMultipleSeriesDataset data = new XYMultipleSeriesDataset();
|
||||
data.addSeries(realSeries);
|
||||
if (imagExists) {
|
||||
data.addSeries(imagSeries);
|
||||
}
|
||||
|
||||
final XYMultipleSeriesRenderer renderer = new XYMultipleSeriesRenderer();
|
||||
renderer.setShowGrid(true);
|
||||
renderer.setXTitle(variable.getName());
|
||||
renderer.setYTitle("f(" + variable.getName() + ")");
|
||||
renderer.setChartTitleTextSize(25);
|
||||
renderer.setAxisTitleTextSize(25);
|
||||
renderer.setLabelsTextSize(25);
|
||||
renderer.setLegendTextSize(25);
|
||||
renderer.setMargins(new int[]{25, 25, 25, 25});
|
||||
renderer.setApplyBackgroundColor(true);
|
||||
renderer.setBackgroundColor(bgColor);
|
||||
renderer.setMarginsColor(bgColor);
|
||||
|
||||
renderer.setZoomEnabled(true);
|
||||
renderer.setZoomButtonsVisible(true);
|
||||
|
||||
renderer.addSeriesRenderer(createCommonRenderer(realLineColor));
|
||||
if (imagExists) {
|
||||
renderer.addSeriesRenderer(createImagRenderer(imagLineColor));
|
||||
}
|
||||
|
||||
if (interpolate) {
|
||||
return new CubicLineChart(data, renderer, 0.1f);
|
||||
} else {
|
||||
return new ScatterChart(data, renderer);
|
||||
}
|
||||
}
|
||||
|
||||
static XYSeriesRenderer createImagRenderer(int color) {
|
||||
final XYSeriesRenderer imagRenderer = createCommonRenderer(color);
|
||||
imagRenderer.setStroke(BasicStroke.DASHED);
|
||||
return imagRenderer;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static XYSeriesRenderer createCommonRenderer(int color) {
|
||||
final XYSeriesRenderer renderer = new XYSeriesRenderer();
|
||||
renderer.setFillPoints(true);
|
||||
renderer.setPointStyle(PointStyle.CIRCLE);
|
||||
renderer.setLineWidth(3);
|
||||
renderer.setColor(color);
|
||||
renderer.setStroke(BasicStroke.SOLID);
|
||||
return renderer;
|
||||
}
|
||||
|
||||
private static class Point {
|
||||
private static final double DEFAULT = Double.MIN_VALUE;
|
||||
|
||||
private double x0 = DEFAULT;
|
||||
private double x1 = DEFAULT;
|
||||
private double x2 = DEFAULT;
|
||||
|
||||
private double y0 = DEFAULT;
|
||||
private double y1 = DEFAULT;
|
||||
private double y2 = DEFAULT;
|
||||
|
||||
private Point() {
|
||||
}
|
||||
|
||||
public void moveToNextPoint(double x, double y) {
|
||||
if ( this.x2 == x ) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.x0 = this.x1;
|
||||
this.x1 = this.x2;
|
||||
this.x2 = x;
|
||||
|
||||
this.y0 = this.y1;
|
||||
this.y1 = this.y2;
|
||||
this.y2 = y;
|
||||
}
|
||||
|
||||
public boolean isFullyDefined() {
|
||||
return x0 != DEFAULT && x1 != DEFAULT && x2 != DEFAULT && y0 != DEFAULT && y1 != DEFAULT && y2 != DEFAULT;
|
||||
}
|
||||
|
||||
public double getDx2() {
|
||||
return x2 - x1;
|
||||
}
|
||||
|
||||
public double getAbsDx2() {
|
||||
if ( x2 > x1 ) {
|
||||
return Math.abs(x2 - x1);
|
||||
} else {
|
||||
return Math.abs(x1 - x2);
|
||||
}
|
||||
}
|
||||
|
||||
public double getAbsDx1() {
|
||||
if ( x1 > x0 ) {
|
||||
return Math.abs(x1 - x0);
|
||||
} else {
|
||||
return Math.abs(x0 - x1);
|
||||
}
|
||||
}
|
||||
|
||||
public double getAbsDy1() {
|
||||
if ( y1 > y0 ) {
|
||||
return Math.abs(y1 - y0);
|
||||
} else {
|
||||
return Math.abs(y0 - y1);
|
||||
}
|
||||
}
|
||||
|
||||
public double getAbsDy2() {
|
||||
if ( y2 > y1 ) {
|
||||
return Math.abs(y2 - y1);
|
||||
} else {
|
||||
return Math.abs(y1 - y2);
|
||||
}
|
||||
}
|
||||
|
||||
public double getX0() {
|
||||
return x0;
|
||||
}
|
||||
|
||||
public double getX1() {
|
||||
return x1;
|
||||
}
|
||||
|
||||
public double getX2() {
|
||||
return x2;
|
||||
}
|
||||
|
||||
public boolean isX2Defined() {
|
||||
return x2 != DEFAULT;
|
||||
}
|
||||
|
||||
public double getY0() {
|
||||
return y0;
|
||||
}
|
||||
|
||||
public double getY1() {
|
||||
return y1;
|
||||
}
|
||||
|
||||
public double getY2() {
|
||||
return y2;
|
||||
}
|
||||
|
||||
public void clearHistory () {
|
||||
this.x0 = DEFAULT;
|
||||
this.x1 = DEFAULT;
|
||||
this.y0 = DEFAULT;
|
||||
this.y1 = DEFAULT;
|
||||
}
|
||||
|
||||
public double getAbsDyDx2() {
|
||||
double dx2 = this.getAbsDx2();
|
||||
double dy2 = this.getAbsDy2();
|
||||
return dy2 / dx2;
|
||||
}
|
||||
|
||||
public double getAbsDyDx1() {
|
||||
double dx1 = this.getAbsDx1();
|
||||
double dy1 = this.getAbsDy1();
|
||||
return dy1 / dx1;
|
||||
}
|
||||
|
||||
public double getDyDx1() {
|
||||
double result = getAbsDyDx1();
|
||||
return y1 > y0 ? result : -result;
|
||||
}
|
||||
|
||||
public double getDyDx2() {
|
||||
double result = getAbsDyDx2();
|
||||
return y2 > y1 ? result : -result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Point{" +
|
||||
"x0=" + x0 +
|
||||
", x1=" + x1 +
|
||||
", x2=" + x2 +
|
||||
", y0=" + y0 +
|
||||
", y1=" + y1 +
|
||||
", y2=" + y2 +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
|
||||
private static double updateStep(@NotNull Point real,
|
||||
double step,
|
||||
double eps) {
|
||||
if ( !real.isFullyDefined() ) {
|
||||
return step;
|
||||
} else {
|
||||
double dydx2 = real.getAbsDyDx2();
|
||||
double dydx1 = real.getAbsDyDx1();
|
||||
|
||||
double k = dydx2 / dydx1;
|
||||
|
||||
if ( k > 1 ) {
|
||||
step = step / k;
|
||||
} else if ( k > 0 ) {
|
||||
step = step * k;
|
||||
}
|
||||
|
||||
return Math.max(step, eps);
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static Complex calculatorExpression(@NotNull Generic expression, @NotNull Constant variable, double x) {
|
||||
return unwrap(expression.substitute(variable, Expression.valueOf(x)).numeric());
|
||||
}
|
||||
|
||||
public static void addSingularityPoint(@NotNull MyXYSeries series,
|
||||
@NotNull Point point) {
|
||||
if (point.isFullyDefined()) {
|
||||
// y or prevY should be more than 1d because if they are too small false singularity may occur (e.g., 1/0.000000000000000001)
|
||||
// double dy0 = y1 - y0;
|
||||
// double dx0 = x1 - x0;
|
||||
// double dydx0 = dy0 / dx0;
|
||||
|
||||
double dy2 = point.getAbsDy2();
|
||||
double dx2 = point.getAbsDx2();
|
||||
//double dx1 = x2 - x1;
|
||||
// double dydx1 = dy2 / dx1;
|
||||
|
||||
if ( dy2 > MAX_Y_DIFF && dx2 < MAX_X_DIFF && isDifferentSign(point.getY2(), point.getY1()) && isDifferentSign(point.getDyDx1(), point.getDyDx2())) {
|
||||
Log.d(CalculatorPlotActivity.class.getName(), "Singularity: " + point);
|
||||
//Log.d(CalculatorPlotActivity.class.getName(), String.valueOf(prevX + Math.abs(x - prevX) / 2) + ", null");
|
||||
series.add(point.getX1() + point.getAbsDx2() / 2, MathHelper.NULL_VALUE);
|
||||
point.clearHistory();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean isDifferentSign(@NotNull Double y0, @NotNull Double y1) {
|
||||
return (y0 >= 0 && y1 < 0) || (y1 >= 0 && y0 < 0);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static Double prepareY(double y) {
|
||||
if (Double.isNaN(y)) {
|
||||
return null;
|
||||
} else {
|
||||
return y;
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static Complex unwrap(@Nullable Generic numeric) {
|
||||
if (numeric instanceof JsclInteger) {
|
||||
return Complex.valueOf(((JsclInteger) numeric).intValue(), 0d);
|
||||
} else if (numeric instanceof NumericWrapper) {
|
||||
return unwrap(((NumericWrapper) numeric).content());
|
||||
} else {
|
||||
throw new ArithmeticException();
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static Complex unwrap(@Nullable Numeric content) {
|
||||
if (content instanceof Real) {
|
||||
return Complex.valueOf(((Real) content).doubleValue(), 0d);
|
||||
} else if (content instanceof Complex) {
|
||||
return ((Complex) content);
|
||||
} else {
|
||||
throw new ArithmeticException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user