Remove dependencies

This commit is contained in:
serso 2016-03-02 00:06:09 +01:00
parent 9bcc4d4d9f
commit ba6480d101
63 changed files with 223 additions and 5374 deletions

View File

@ -60,14 +60,11 @@ android {
dependencies { dependencies {
compile fileTree(include: ['*.jar'], dir: 'libs') compile fileTree(include: ['*.jar'], dir: 'libs')
compile 'org.solovyev:common-core:1.0.7'
compile 'org.solovyev:common-text:1.0.7'
compile 'org.solovyev:common-security:1.0.7'
compile 'org.solovyev:common-msg:1.0.7' compile 'org.solovyev:common-msg:1.0.7'
compile 'com.android.support:support-v4:23.1.1' compile 'com.android.support:support-v4:23.2.0'
compile 'com.android.support:appcompat-v7:23.1.1' compile 'com.android.support:appcompat-v7:23.2.0'
compile 'com.android.support:cardview-v7:23.1.1' compile 'com.android.support:cardview-v7:23.2.0'
compile 'com.android.support:design:23.1.1' compile 'com.android.support:design:23.2.0'
compile('ch.acra:acra:4.7.0') { compile('ch.acra:acra:4.7.0') {
exclude group: 'org.json' exclude group: 'org.json'
} }
@ -76,11 +73,6 @@ dependencies {
compile ':square-otto:1.3.9-SNAPSHOT' compile ':square-otto:1.3.9-SNAPSHOT'
apt ':square-otto-compiler:1.3.9-SNAPSHOT' apt ':square-otto-compiler:1.3.9-SNAPSHOT'
apt 'com.squareup:javapoet:1.5.1' apt 'com.squareup:javapoet:1.5.1'
compile 'org.solovyev.android:android-common-lists:1.1.18@aar'
compile 'org.solovyev.android:android-common-core:1.1.18@aar'
compile 'org.solovyev.android:android-common-other:1.1.18@aar'
compile 'org.solovyev.android:android-common-views:1.1.18@aar'
compile 'org.solovyev.android:android-common-menus:1.1.18@aar'
compile(project(':jscl')) { compile(project(':jscl')) {
exclude(module: 'xercesImpl') exclude(module: 'xercesImpl')
} }
@ -99,7 +91,6 @@ dependencies {
exclude(module: 'stax-api') exclude(module: 'stax-api')
exclude(module: 'xpp3') exclude(module: 'xpp3')
} }
compile 'commons-cli:commons-cli:1.2'
compile 'com.jakewharton:butterknife:7.0.1' compile 'com.jakewharton:butterknife:7.0.1'
compile 'org.solovyev.android.views:linear-layout-manager:0.5@aar' compile 'org.solovyev.android.views:linear-layout-manager:0.5@aar'
@ -115,7 +106,7 @@ dependencies {
testCompile 'org.skyscreamer:jsonassert:1.2.3' testCompile 'org.skyscreamer:jsonassert:1.2.3'
testCompile(name: 'org.apache.http.legacy', ext: 'jar') testCompile(name: 'org.apache.http.legacy', ext: 'jar')
androidTestCompile 'com.android.support:support-annotations:23.1.1' androidTestCompile 'com.android.support:support-annotations:23.2.0'
androidTestCompile 'com.android.support.test:runner:0.4.1' androidTestCompile 'com.android.support.test:runner:0.4.1'
androidTestCompile 'com.android.support.test:rules:0.4.1' androidTestCompile 'com.android.support.test:rules:0.4.1'
androidTestCompile 'org.hamcrest:hamcrest-library:1.3' androidTestCompile 'org.hamcrest:hamcrest-library:1.3'
@ -167,7 +158,7 @@ signing {
} }
gradle.taskGraph.afterTask { Task task -> gradle.taskGraph.afterTask { Task task ->
if (task.project.name == 'android-app') { if (task.project.name == 'app') {
if (task.name == 'mergeReleaseResources') { if (task.name == 'mergeReleaseResources') {
cleanGoogleServicesResources('release') cleanGoogleServicesResources('release')
} else if (task.name == 'mergeDebugResources') { } else if (task.name == 'mergeDebugResources') {
@ -178,13 +169,7 @@ gradle.taskGraph.afterTask { Task task ->
private void cleanGoogleServicesResources(buildType) { private void cleanGoogleServicesResources(buildType) {
ant.delete(includeEmptyDirs: 'true') { ant.delete(includeEmptyDirs: 'true') {
fileset(dir: file('./build/intermediates/res/merged/' + buildType), includes: '**/common_signin*') fileset(dir: file('./build/intermediates/res/merged/' + buildType), includes: '**/common_*')
}
ant.delete(includeEmptyDirs: 'true') {
fileset(dir: file('./build/intermediates/res/merged/' + buildType), includes: '**/ic_plusone*')
}
ant.delete(includeEmptyDirs: 'true') {
fileset(dir: file('./build/intermediates/res/merged/' + buildType), includes: '**/powered_by_google*')
} }
} }

View File

@ -65,6 +65,7 @@
-dontwarn com.actionbarsherlock.BuildConfig -dontwarn com.actionbarsherlock.BuildConfig
-dontwarn com.google.android.gms.internal.** -dontwarn com.google.android.gms.internal.**
-dontwarn com.google.android.gms.common.internal.** -dontwarn com.google.android.gms.common.internal.**
-dontwarn com.google.android.gms.common.GooglePlayServicesUtil
-keep class com.squareup.leakcanary.** { *; } -keep class com.squareup.leakcanary.** { *; }
-dontwarn com.squareup.leakcanary.** -dontwarn com.squareup.leakcanary.**

View File

@ -66,6 +66,7 @@
-dontwarn com.actionbarsherlock.BuildConfig -dontwarn com.actionbarsherlock.BuildConfig
-dontwarn com.google.android.gms.internal.** -dontwarn com.google.android.gms.internal.**
-dontwarn com.google.android.gms.common.internal.** -dontwarn com.google.android.gms.common.internal.**
-dontwarn com.google.android.gms.common.GooglePlayServicesUtil
-keep class com.squareup.leakcanary.** { *; } -keep class com.squareup.leakcanary.** { *; }
-dontwarn com.squareup.leakcanary.** -dontwarn com.squareup.leakcanary.**
@ -95,7 +96,7 @@
## ASSERTIONS ## ASSERTIONS
-assumenosideeffects class org.solovyev.android.Check { -assumenosideeffects class org.solovyev.android.Check {
*; public static *;
} }
## ACRA ## ACRA

View File

@ -139,15 +139,6 @@
android:label="@string/cpp_purchase_title" android:label="@string/cpp_purchase_title"
android:theme="@style/Cpp.Theme.Translucent" /> android:theme="@style/Cpp.Theme.Translucent" />
<!-- todo serso: strings-->
<activity
android:name=".matrix.CalculatorMatrixActivity"
android:label="@string/c_plot_graph">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
</intent-filter>
</activity>
<!-- ONSCREEN CONFIG --> <!-- ONSCREEN CONFIG -->
<activity <activity

View File

@ -33,7 +33,6 @@ import dagger.Lazy;
import jscl.math.Generic; import jscl.math.Generic;
import jscl.math.function.Constant; import jscl.math.function.Constant;
import jscl.math.function.CustomFunction; import jscl.math.function.CustomFunction;
import org.solovyev.android.Activities;
import org.solovyev.android.Check; import org.solovyev.android.Check;
import org.solovyev.android.calculator.about.AboutActivity; import org.solovyev.android.calculator.about.AboutActivity;
import org.solovyev.android.calculator.functions.CppFunction; import org.solovyev.android.calculator.functions.CppFunction;
@ -85,7 +84,7 @@ public final class ActivityLauncher {
private static void show(@Nonnull Context context, @NonNull Intent intent) { private static void show(@Nonnull Context context, @NonNull Intent intent) {
final boolean detached = !(context instanceof Activity); final boolean detached = !(context instanceof Activity);
Activities.addIntentFlags(intent, detached, context); App.addIntentFlags(intent, detached, context);
context.startActivity(intent); context.startActivity(intent);
} }

View File

@ -24,17 +24,14 @@ package org.solovyev.android.calculator;
import android.app.Activity; import android.app.Activity;
import android.app.Application; import android.app.Application;
import android.content.ActivityNotFoundException; import android.content.*;
import android.content.Context;
import android.content.ContextWrapper;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.PackageManager; import android.content.pm.PackageManager;
import android.content.res.Configuration; import android.content.res.Configuration;
import android.graphics.Color; import android.graphics.Color;
import android.net.Uri; import android.net.Uri;
import android.os.Build; import android.os.Build;
import android.os.IBinder; import android.os.IBinder;
import android.os.Looper;
import android.preference.PreferenceManager; import android.preference.PreferenceManager;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
import android.support.v4.app.DialogFragment; import android.support.v4.app.DialogFragment;
@ -55,7 +52,6 @@ import android.widget.TextView;
import com.squareup.otto.Bus; import com.squareup.otto.Bus;
import org.solovyev.android.Check; import org.solovyev.android.Check;
import org.solovyev.android.Views;
import org.solovyev.android.calculator.floating.FloatingCalculatorService; import org.solovyev.android.calculator.floating.FloatingCalculatorService;
import org.solovyev.android.calculator.ga.Ga; import org.solovyev.android.calculator.ga.Ga;
import org.solovyev.android.calculator.language.Languages; import org.solovyev.android.calculator.language.Languages;
@ -350,13 +346,13 @@ public final class App {
final StringBuilder helpText = new StringBuilder(); final StringBuilder helpText = new StringBuilder();
helpText.append("Size: "); helpText.append("Size: ");
if (Views.isLayoutSizeAtLeast(Configuration.SCREENLAYOUT_SIZE_XLARGE, c)) { if (isLayoutSizeAtLeast(Configuration.SCREENLAYOUT_SIZE_XLARGE, c)) {
helpText.append("xlarge"); helpText.append("xlarge");
} else if (Views.isLayoutSizeAtLeast(Configuration.SCREENLAYOUT_SIZE_LARGE, c)) { } else if (isLayoutSizeAtLeast(Configuration.SCREENLAYOUT_SIZE_LARGE, c)) {
helpText.append("large"); helpText.append("large");
} else if (Views.isLayoutSizeAtLeast(Configuration.SCREENLAYOUT_SIZE_NORMAL, c)) { } else if (isLayoutSizeAtLeast(Configuration.SCREENLAYOUT_SIZE_NORMAL, c)) {
helpText.append("normal"); helpText.append("normal");
} else if (Views.isLayoutSizeAtLeast(Configuration.SCREENLAYOUT_SIZE_SMALL, c)) { } else if (isLayoutSizeAtLeast(Configuration.SCREENLAYOUT_SIZE_SMALL, c)) {
helpText.append("small"); helpText.append("small");
} else { } else {
helpText.append("unknown"); helpText.append("unknown");
@ -393,4 +389,117 @@ public final class App {
static boolean isFloatingCalculator(@NonNull Context context) { static boolean isFloatingCalculator(@NonNull Context context) {
return unwrap(context) instanceof FloatingCalculatorService; return unwrap(context) instanceof FloatingCalculatorService;
} }
public static int getAppVersionCode(@Nonnull Context context) {
try {
return getAppVersionCode(context, context.getPackageName());
} catch (PackageManager.NameNotFoundException e) {
Check.shouldNotHappen();
}
return 0;
}
public static int getAppVersionCode(@Nonnull Context context, @Nonnull String appPackageName) throws PackageManager.NameNotFoundException {
return context.getPackageManager().getPackageInfo(appPackageName, 0).versionCode;
}
public static boolean isUiThread() {
return Looper.myLooper() == Looper.getMainLooper();
}
public static boolean isLayoutSizeAtLeast(int size, @Nonnull Configuration configuration) {
int cur = configuration.screenLayout & Configuration.SCREENLAYOUT_SIZE_MASK;
if (cur == Configuration.SCREENLAYOUT_SIZE_UNDEFINED) return false;
return cur >= size;
}
public static void restartActivity(@Nonnull Activity activity) {
final Intent intent = activity.getIntent();
activity.finish();
activity.startActivity(intent);
}
/**
* Method runs through view and all it's children recursively and process them via viewProcessor
*
* @param view parent view to be processed, if view is ViewGroup then all it's children will be processed
* @param viewProcessor object which processes views
*/
public static void processViews(@Nonnull View view, @Nonnull ViewProcessor<View> viewProcessor) {
processViewsOfType0(view, null, viewProcessor);
}
static <T> void processViewsOfType0(@Nonnull View view, @Nullable Class<T> viewClass, @Nonnull ViewProcessor<T> viewProcessor) {
if (view instanceof ViewGroup) {
final ViewGroup viewGroup = (ViewGroup) view;
if (viewClass == null || viewClass.isAssignableFrom(ViewGroup.class)) {
//noinspection unchecked
viewProcessor.process((T) viewGroup);
}
for (int index = 0; index < viewGroup.getChildCount(); index++) {
processViewsOfType0(viewGroup.getChildAt(index), viewClass, viewProcessor);
}
} else if (viewClass == null || viewClass.isAssignableFrom(view.getClass())) {
//noinspection unchecked
viewProcessor.process((T) view);
}
}
public static <T> void processViewsOfType(@Nonnull View view, @Nonnull Class<T> viewClass, @Nonnull ViewProcessor<T> viewProcessor) {
processViewsOfType0(view, viewClass, viewProcessor);
}
public interface ViewProcessor<V> {
void process(@Nonnull V view);
}
@SuppressWarnings("deprecation")
public static int getScreenOrientation(@Nonnull Activity activity) {
final android.view.Display display = activity.getWindowManager().getDefaultDisplay();
if (display.getWidth() <= display.getHeight()) {
return Configuration.ORIENTATION_PORTRAIT;
} else {
return Configuration.ORIENTATION_LANDSCAPE;
}
}
public static void addIntentFlags(@Nonnull Intent intent, boolean detached, @Nonnull Context context) {
int flags = 0;
if (!(context instanceof Activity)) {
flags = flags | Intent.FLAG_ACTIVITY_NEW_TASK;
}
if (detached) {
flags = flags | Intent.FLAG_ACTIVITY_NO_HISTORY;
}
intent.setFlags(flags);
}
public static void enableComponent(@Nonnull Context context,
@Nonnull Class<?> componentClass,
boolean enable) {
final PackageManager pm = context.getPackageManager();
final int componentState;
if (enable) {
componentState = PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
} else {
componentState = PackageManager.COMPONENT_ENABLED_STATE_DISABLED;
}
pm.setComponentEnabledSetting(new ComponentName(context, componentClass), componentState, PackageManager.DONT_KILL_APP);
}
public static boolean isComponentEnabled(@Nonnull Context context,
@Nonnull Class<? extends Context> componentClass) {
final PackageManager pm = context.getPackageManager();
int componentEnabledSetting = pm.getComponentEnabledSetting(new ComponentName(context, componentClass));
return componentEnabledSetting == PackageManager.COMPONENT_ENABLED_STATE_ENABLED || componentEnabledSetting == PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
}
public static int toPixels(@Nonnull DisplayMetrics dm, float dps) {
final float scale = dm.density;
return (int) (dps * scale + 0.5f);
}
} }

View File

@ -9,22 +9,20 @@ import android.os.Looper;
import android.preference.PreferenceManager; import android.preference.PreferenceManager;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
import android.util.Log; import android.util.Log;
import com.squareup.otto.Bus; import com.squareup.otto.Bus;
import com.squareup.otto.GeneratedHandlerFinder; import com.squareup.otto.GeneratedHandlerFinder;
import dagger.Module;
import org.solovyev.android.UiThreadExecutor; import dagger.Provides;
import jscl.JsclMathEngine;
import org.solovyev.android.calculator.language.Languages; import org.solovyev.android.calculator.language.Languages;
import org.solovyev.android.checkout.Billing; import org.solovyev.android.checkout.*;
import org.solovyev.android.checkout.Checkout;
import org.solovyev.android.checkout.Inventory;
import org.solovyev.android.checkout.ProductTypes;
import org.solovyev.android.checkout.Products;
import org.solovyev.android.checkout.RobotmediaDatabase;
import org.solovyev.android.checkout.RobotmediaInventory;
import org.solovyev.android.plotter.Plot; import org.solovyev.android.plotter.Plot;
import org.solovyev.android.plotter.Plotter; import org.solovyev.android.plotter.Plotter;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import javax.inject.Named;
import javax.inject.Singleton;
import java.io.File; import java.io.File;
import java.util.Collections; import java.util.Collections;
import java.util.concurrent.Executor; import java.util.concurrent.Executor;
@ -32,15 +30,6 @@ import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory; import java.util.concurrent.ThreadFactory;
import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicInteger;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import javax.inject.Named;
import javax.inject.Singleton;
import dagger.Module;
import dagger.Provides;
import jscl.JsclMathEngine;
@Module @Module
public class AppModule { public class AppModule {
@ -151,8 +140,17 @@ public class AppModule {
@Provides @Provides
@Singleton @Singleton
@Named(THREAD_UI) @Named(THREAD_UI)
Executor provideUiThread() { Executor provideUiThread(@NonNull final Handler handler) {
return new UiThreadExecutor(); return new Executor() {
@Override
public void execute(@NonNull Runnable command) {
if (App.isUiThread()) {
command.run();
} else {
handler.post(command);
}
}
};
} }
@Provides @Provides

View File

@ -18,10 +18,9 @@ import android.view.MenuItem;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.TextView; import android.widget.TextView;
import butterknife.Bind;
import org.solovyev.android.Activities; import butterknife.ButterKnife;
import org.solovyev.android.Check; import org.solovyev.android.Check;
import org.solovyev.android.Views;
import org.solovyev.android.calculator.history.History; import org.solovyev.android.calculator.history.History;
import org.solovyev.android.calculator.language.Language; import org.solovyev.android.calculator.language.Language;
import org.solovyev.android.calculator.language.Languages; import org.solovyev.android.calculator.language.Languages;
@ -31,9 +30,6 @@ import javax.annotation.Nonnull;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import javax.inject.Inject; import javax.inject.Inject;
import butterknife.Bind;
import butterknife.ButterKnife;
import static org.solovyev.android.calculator.App.cast; import static org.solovyev.android.calculator.App.cast;
public class BaseActivity extends AppCompatActivity { public class BaseActivity extends AppCompatActivity {
@ -101,7 +97,7 @@ public class BaseActivity extends AppCompatActivity {
public boolean restartIfLayoutChanged() { public boolean restartIfLayoutChanged() {
final Preferences.Gui.Layout newLayout = Preferences.Gui.layout.getPreference(preferences); final Preferences.Gui.Layout newLayout = Preferences.Gui.layout.getPreference(preferences);
if (newLayout != layout) { if (newLayout != layout) {
Activities.restartActivity(this); App.restartActivity(this);
return true; return true;
} }
return false; return false;
@ -112,7 +108,7 @@ public class BaseActivity extends AppCompatActivity {
final int themeId = theme.getThemeFor(this); final int themeId = theme.getThemeFor(this);
final int newThemeId = newTheme.getThemeFor(this); final int newThemeId = newTheme.getThemeFor(this);
if (themeId != newThemeId) { if (themeId != newThemeId) {
Activities.restartActivity(this); App.restartActivity(this);
return true; return true;
} }
return false; return false;
@ -121,7 +117,7 @@ public class BaseActivity extends AppCompatActivity {
public boolean restartIfLanguageChanged() { public boolean restartIfLanguageChanged() {
final Language current = languages.getCurrent(); final Language current = languages.getCurrent();
if (!current.equals(language)) { if (!current.equals(language)) {
Activities.restartActivity(this); App.restartActivity(this);
return true; return true;
} }
return false; return false;
@ -255,11 +251,13 @@ public class BaseActivity extends AppCompatActivity {
protected void fixFonts(@Nonnull View root) { protected void fixFonts(@Nonnull View root) {
// some devices ship own fonts which causes issues with rendering. Let's use our own font for all text views // some devices ship own fonts which causes issues with rendering. Let's use our own font for all text views
Views.processViewsOfType(root, TextView.class, new Views.ViewProcessor<TextView>() { App.processViewsOfType(root, TextView.class, new App.ViewProcessor<TextView>() {
@Override @Override
public void process(@Nonnull TextView view) { public void process(@Nonnull TextView view) {
setFont(view, typeface); setFont(view, typeface);
} }
}); });
} }
} }

View File

@ -28,27 +28,22 @@ import android.preference.PreferenceManager;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
import android.util.Log; import android.util.Log;
import android.util.TimingLogger; import android.util.TimingLogger;
import com.squareup.otto.Bus; import com.squareup.otto.Bus;
import jscl.MathEngine;
import org.acra.ACRA; import org.acra.ACRA;
import org.acra.ACRAConfiguration; import org.acra.ACRAConfiguration;
import org.acra.sender.HttpSender; import org.acra.sender.HttpSender;
import org.solovyev.android.Android;
import org.solovyev.android.calculator.floating.FloatingCalculatorActivity; import org.solovyev.android.calculator.floating.FloatingCalculatorActivity;
import org.solovyev.android.calculator.history.History; import org.solovyev.android.calculator.history.History;
import org.solovyev.android.calculator.language.Language; import org.solovyev.android.calculator.language.Language;
import org.solovyev.android.calculator.language.Languages; import org.solovyev.android.calculator.language.Languages;
import org.solovyev.common.msg.MessageType; import org.solovyev.common.msg.MessageType;
import java.util.Locale;
import java.util.concurrent.Executor;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import javax.inject.Inject; import javax.inject.Inject;
import javax.inject.Named; import javax.inject.Named;
import java.util.Locale;
import jscl.MathEngine; import java.util.concurrent.Executor;
public class CalculatorApplication extends android.app.Application implements SharedPreferences.OnSharedPreferenceChangeListener { public class CalculatorApplication extends android.app.Application implements SharedPreferences.OnSharedPreferenceChangeListener {
@ -192,7 +187,7 @@ public class CalculatorApplication extends android.app.Application implements Sh
public void onSharedPreferenceChanged(SharedPreferences prefs, String key) { public void onSharedPreferenceChanged(SharedPreferences prefs, String key) {
if (Preferences.Onscreen.showAppIcon.getKey().equals(key)) { if (Preferences.Onscreen.showAppIcon.getKey().equals(key)) {
boolean showAppIcon = Preferences.Onscreen.showAppIcon.getPreference(prefs); boolean showAppIcon = Preferences.Onscreen.showAppIcon.getPreference(prefs);
Android.enableComponent(this, FloatingCalculatorActivity.class, showAppIcon); App.enableComponent(this, FloatingCalculatorActivity.class, showAppIcon);
notifier.showMessage(R.string.cpp_this_change_may_require_reboot, MessageType.info); notifier.showMessage(R.string.cpp_this_change_may_require_reboot, MessageType.info);
} }
} }

View File

@ -29,7 +29,6 @@ import org.solovyev.android.calculator.about.ReleaseNotesFragment;
import org.solovyev.android.calculator.functions.FunctionsFragment; import org.solovyev.android.calculator.functions.FunctionsFragment;
import org.solovyev.android.calculator.history.RecentHistoryFragment; import org.solovyev.android.calculator.history.RecentHistoryFragment;
import org.solovyev.android.calculator.history.SavedHistoryFragment; import org.solovyev.android.calculator.history.SavedHistoryFragment;
import org.solovyev.android.calculator.matrix.EditMatrixFragment;
import org.solovyev.android.calculator.operators.OperatorsFragment; import org.solovyev.android.calculator.operators.OperatorsFragment;
import org.solovyev.android.calculator.variables.VariablesFragment; import org.solovyev.android.calculator.variables.VariablesFragment;
@ -43,9 +42,6 @@ public enum FragmentTab {
functions(FunctionsFragment.class, R.string.c_functions), functions(FunctionsFragment.class, R.string.c_functions),
operators(OperatorsFragment.class, R.string.c_operators), operators(OperatorsFragment.class, R.string.c_operators),
about(AboutFragment.class, R.string.cpp_about), about(AboutFragment.class, R.string.cpp_about),
// todo serso: strings
matrix_edit(EditMatrixFragment.class, R.string.c_release_notes),
release_notes(ReleaseNotesFragment.class, R.string.c_release_notes); release_notes(ReleaseNotesFragment.class, R.string.c_release_notes);
@Nonnull @Nonnull

View File

@ -26,7 +26,6 @@ import android.app.Application;
import android.os.Handler; import android.os.Handler;
import android.support.annotation.StringRes; import android.support.annotation.StringRes;
import android.widget.Toast; import android.widget.Toast;
import org.solovyev.android.Threads;
import org.solovyev.common.msg.Message; import org.solovyev.common.msg.Message;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
@ -57,7 +56,7 @@ public class Notifier {
} }
public void showMessage(@Nonnull final String message) { public void showMessage(@Nonnull final String message) {
if (Threads.isUiThread()) { if (App.isUiThread()) {
Toast.makeText(application, message, Toast.LENGTH_SHORT).show(); Toast.makeText(application, message, Toast.LENGTH_SHORT).show();
return; return;
} }

View File

@ -35,7 +35,8 @@ import android.support.annotation.NonNull;
import android.support.annotation.StyleRes; import android.support.annotation.StyleRes;
import android.support.v7.view.ContextThemeWrapper; import android.support.v7.view.ContextThemeWrapper;
import android.util.SparseArray; import android.util.SparseArray;
import jscl.AngleUnit;
import jscl.NumeralBase;
import org.solovyev.android.Check; import org.solovyev.android.Check;
import org.solovyev.android.calculator.about.AboutActivity; import org.solovyev.android.calculator.about.AboutActivity;
import org.solovyev.android.calculator.functions.FunctionsActivity; import org.solovyev.android.calculator.functions.FunctionsActivity;
@ -46,26 +47,15 @@ import org.solovyev.android.calculator.operators.OperatorsActivity;
import org.solovyev.android.calculator.preferences.PreferencesActivity; import org.solovyev.android.calculator.preferences.PreferencesActivity;
import org.solovyev.android.calculator.variables.VariablesActivity; import org.solovyev.android.calculator.variables.VariablesActivity;
import org.solovyev.android.calculator.wizard.WizardActivity; import org.solovyev.android.calculator.wizard.WizardActivity;
import org.solovyev.android.prefs.BooleanPreference; import org.solovyev.android.prefs.*;
import org.solovyev.android.prefs.IntegerPreference;
import org.solovyev.android.prefs.NumberToStringPreference;
import org.solovyev.android.prefs.Preference;
import org.solovyev.android.prefs.StringPreference;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.text.DecimalFormatSymbols; import java.text.DecimalFormatSymbols;
import java.util.EnumMap; import java.util.EnumMap;
import java.util.Locale; import java.util.Locale;
import java.util.Map; import java.util.Map;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import jscl.AngleUnit;
import jscl.NumeralBase;
import static org.solovyev.android.Android.isPhoneModel;
import static org.solovyev.android.DeviceModel.samsung_galaxy_s;
import static org.solovyev.android.DeviceModel.samsung_galaxy_s_2;
import static org.solovyev.android.prefs.IntegerPreference.DEF_VALUE; import static org.solovyev.android.prefs.IntegerPreference.DEF_VALUE;
public final class Preferences { public final class Preferences {
@ -143,13 +133,6 @@ public final class Preferences {
Engine.Preferences.angleUnit.tryPutDefault(preferences, editor); Engine.Preferences.angleUnit.tryPutDefault(preferences, editor);
Engine.Preferences.numeralBase.tryPutDefault(preferences, editor); Engine.Preferences.numeralBase.tryPutDefault(preferences, editor);
if (!Engine.Preferences.multiplicationSign.isSet(preferences)) {
if (isPhoneModel(samsung_galaxy_s) || isPhoneModel(samsung_galaxy_s_2)) {
// workaround ofr samsung galaxy s phones
Engine.Preferences.multiplicationSign.putPreference(editor, "*");
}
}
Gui.theme.tryPutDefault(preferences, editor); Gui.theme.tryPutDefault(preferences, editor);
Gui.layout.tryPutDefault(preferences, editor); Gui.layout.tryPutDefault(preferences, editor);
Gui.showReleaseNotes.tryPutDefault(preferences, editor); Gui.showReleaseNotes.tryPutDefault(preferences, editor);

View File

@ -25,22 +25,18 @@ package org.solovyev.android.calculator;
import android.app.Application; import android.app.Application;
import android.content.Context; import android.content.Context;
import android.content.SharedPreferences; import android.content.SharedPreferences;
import jscl.AngleUnit;
import jscl.NumeralBase;
import org.solovyev.android.calculator.errors.FixableError; import org.solovyev.android.calculator.errors.FixableError;
import org.solovyev.android.calculator.errors.FixableErrorType; import org.solovyev.android.calculator.errors.FixableErrorType;
import org.solovyev.android.calculator.errors.FixableErrorsActivity; import org.solovyev.android.calculator.errors.FixableErrorsActivity;
import org.solovyev.android.msg.AndroidMessage;
import org.solovyev.common.msg.MessageType; import org.solovyev.common.msg.MessageType;
import jscl.AngleUnit;
import jscl.NumeralBase;
import java.util.ArrayList;
import java.util.concurrent.TimeUnit;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import javax.inject.Inject; import javax.inject.Inject;
import javax.inject.Singleton; import javax.inject.Singleton;
import java.util.ArrayList;
import java.util.concurrent.TimeUnit;
@Singleton @Singleton
public class PreferredPreferences { public class PreferredPreferences {
@ -103,9 +99,7 @@ public class PreferredPreferences {
public void setAngleUnits(@Nonnull AngleUnit angleUnit) { public void setAngleUnits(@Nonnull AngleUnit angleUnit) {
Engine.Preferences.angleUnit.putPreference(preferences, angleUnit); Engine.Preferences.angleUnit.putPreference(preferences, angleUnit);
notifier.showMessage( notifier.showMessage(R.string.c_angle_units_changed_to, angleUnit.name());
new AndroidMessage(R.string.c_angle_units_changed_to, MessageType.info, application,
angleUnit.name()));
} }
public void setPreferredNumeralBase() { public void setPreferredNumeralBase() {
@ -114,9 +108,7 @@ public class PreferredPreferences {
public void setNumeralBase(@Nonnull NumeralBase numeralBase) { public void setNumeralBase(@Nonnull NumeralBase numeralBase) {
Engine.Preferences.numeralBase.putPreference(preferences, numeralBase); Engine.Preferences.numeralBase.putPreference(preferences, numeralBase);
notifier.showMessage( notifier.showMessage(R.string.c_numeral_base_changed_to, numeralBase.name());
new AndroidMessage(R.string.c_numeral_base_changed_to, MessageType.info,
application, numeralBase.name()));
} }
public boolean isShowWarningDialog() { public boolean isShowWarningDialog() {

View File

@ -9,8 +9,6 @@ import android.os.Bundle;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
import android.support.v7.app.AlertDialog; import android.support.v7.app.AlertDialog;
import android.support.v7.app.AppCompatActivity; import android.support.v7.app.AppCompatActivity;
import org.solovyev.android.Android;
import org.solovyev.android.calculator.wizard.CalculatorWizards; import org.solovyev.android.calculator.wizard.CalculatorWizards;
import org.solovyev.android.wizard.Wizard; import org.solovyev.android.wizard.Wizard;
import org.solovyev.android.wizard.Wizards; import org.solovyev.android.wizard.Wizards;
@ -20,9 +18,7 @@ import javax.inject.Named;
import javax.inject.Singleton; import javax.inject.Singleton;
import static org.solovyev.android.calculator.release.ReleaseNotes.hasReleaseNotes; import static org.solovyev.android.calculator.release.ReleaseNotes.hasReleaseNotes;
import static org.solovyev.android.wizard.WizardUi.continueWizard; import static org.solovyev.android.wizard.WizardUi.*;
import static org.solovyev.android.wizard.WizardUi.createLaunchIntent;
import static org.solovyev.android.wizard.WizardUi.startWizard;
@Singleton @Singleton
public class StartupHelper { public class StartupHelper {
@ -45,12 +41,12 @@ public class StartupHelper {
if (!App.isMonkeyRunner(activity)) { if (!App.isMonkeyRunner(activity)) {
handleOnMainActivityOpened(activity, editor, opened == null ? 0 : opened); handleOnMainActivityOpened(activity, editor, opened == null ? 0 : opened);
} }
UiPreferences.appVersion.putPreference(editor, Android.getAppVersionCode(activity)); UiPreferences.appVersion.putPreference(editor, App.getAppVersionCode(activity));
editor.apply(); editor.apply();
} }
private void handleOnMainActivityOpened(@NonNull final AppCompatActivity activity, @NonNull SharedPreferences.Editor editor, int opened) { private void handleOnMainActivityOpened(@NonNull final AppCompatActivity activity, @NonNull SharedPreferences.Editor editor, int opened) {
final int currentVersion = Android.getAppVersionCode(activity); final int currentVersion = App.getAppVersionCode(activity);
final Wizards wizards = App.getWizards(); final Wizards wizards = App.getWizards();
final Wizard wizard = wizards.getWizard(CalculatorWizards.FIRST_TIME_WIZARD); final Wizard wizard = wizards.getWizard(CalculatorWizards.FIRST_TIME_WIZARD);
if (wizard.isStarted() && !wizard.isFinished()) { if (wizard.isStarted() && !wizard.isFinished()) {

View File

@ -22,24 +22,22 @@
package org.solovyev.android.calculator.errors; package org.solovyev.android.calculator.errors;
import static org.solovyev.android.calculator.App.cast;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.content.SharedPreferences; import android.content.SharedPreferences;
import android.os.Bundle; import android.os.Bundle;
import android.support.v4.app.Fragment; import android.support.v4.app.Fragment;
import android.support.v7.app.AppCompatActivity; import android.support.v7.app.AppCompatActivity;
import org.solovyev.android.calculator.App;
import org.solovyev.android.Activities;
import org.solovyev.android.calculator.PreferredPreferences; import org.solovyev.android.calculator.PreferredPreferences;
import org.solovyev.common.msg.Message; import org.solovyev.common.msg.Message;
import javax.annotation.Nonnull;
import javax.inject.Inject;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import javax.annotation.Nonnull; import static org.solovyev.android.calculator.App.cast;
import javax.inject.Inject;
public class FixableErrorsActivity extends AppCompatActivity { public class FixableErrorsActivity extends AppCompatActivity {
@ -62,7 +60,7 @@ public class FixableErrorsActivity extends AppCompatActivity {
public static void show(@Nonnull Context context, @Nonnull ArrayList<FixableError> errors) { public static void show(@Nonnull Context context, @Nonnull ArrayList<FixableError> errors) {
final Intent intent = new Intent(context, FixableErrorsActivity.class); final Intent intent = new Intent(context, FixableErrorsActivity.class);
intent.putExtra(EXTRA_ERRORS, errors); intent.putExtra(EXTRA_ERRORS, errors);
Activities.addIntentFlags(intent, false, context); App.addIntentFlags(intent, false, context);
context.startActivity(intent); context.startActivity(intent);
} }

View File

@ -37,7 +37,6 @@ import com.squareup.otto.Bus;
import com.squareup.otto.Subscribe; import com.squareup.otto.Subscribe;
import org.solovyev.android.Check; import org.solovyev.android.Check;
import org.solovyev.android.Views;
import org.solovyev.android.calculator.App; import org.solovyev.android.calculator.App;
import org.solovyev.android.calculator.Display; import org.solovyev.android.calculator.Display;
import org.solovyev.android.calculator.Editor; import org.solovyev.android.calculator.Editor;
@ -99,7 +98,7 @@ public class FloatingCalculatorService extends Service implements FloatingViewLi
//noinspection deprecation //noinspection deprecation
final int maxWidth = 2 * Math.min(dd.getWidth(), dd.getHeight()) / 3; final int maxWidth = 2 * Math.min(dd.getWidth(), dd.getHeight()) / 3;
final int desiredWidth = Views.toPixels(dm, 300); final int desiredWidth = App.toPixels(dm, 300);
final int width = Math.min(maxWidth, desiredWidth); final int width = Math.min(maxWidth, desiredWidth);
final int height = getHeight(width); final int height = getHeight(width);

View File

@ -9,7 +9,6 @@ import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentManager; import android.support.v4.app.FragmentManager;
import android.support.v7.app.AlertDialog; import android.support.v7.app.AlertDialog;
import jscl.math.function.Function; import jscl.math.function.Function;
import org.solovyev.android.Activities;
import org.solovyev.android.Check; import org.solovyev.android.Check;
import org.solovyev.android.calculator.App; import org.solovyev.android.calculator.App;
import org.solovyev.android.calculator.Engine; import org.solovyev.android.calculator.Engine;
@ -32,7 +31,7 @@ public class EditFunctionFragment extends BaseFunctionFragment {
public static void show(@Nullable CppFunction function, @Nonnull Context context) { public static void show(@Nullable CppFunction function, @Nonnull Context context) {
if (!(context instanceof FunctionsActivity)) { if (!(context instanceof FunctionsActivity)) {
final Intent intent = new Intent(context, FunctionsActivity.getClass(context)); final Intent intent = new Intent(context, FunctionsActivity.getClass(context));
Activities.addIntentFlags(intent, false, context); App.addIntentFlags(intent, false, context);
intent.putExtra(FunctionsActivity.EXTRA_FUNCTION, function); intent.putExtra(FunctionsActivity.EXTRA_FUNCTION, function);
context.startActivity(intent); context.startActivity(intent);
} else { } else {

View File

@ -12,16 +12,7 @@ import android.util.TypedValue;
import android.view.View; import android.view.View;
import android.widget.ImageView; import android.widget.ImageView;
import android.widget.TextView; import android.widget.TextView;
import org.solovyev.android.calculator.*;
import org.solovyev.android.Views;
import org.solovyev.android.calculator.ActivityLauncher;
import org.solovyev.android.calculator.App;
import org.solovyev.android.calculator.BaseActivity;
import org.solovyev.android.calculator.Calculator;
import org.solovyev.android.calculator.Editor;
import org.solovyev.android.calculator.Keyboard;
import org.solovyev.android.calculator.Preferences;
import org.solovyev.android.calculator.PreferredPreferences;
import org.solovyev.android.calculator.buttons.CppSpecialButton; import org.solovyev.android.calculator.buttons.CppSpecialButton;
import org.solovyev.android.calculator.view.ScreenMetrics; import org.solovyev.android.calculator.view.ScreenMetrics;
import org.solovyev.android.views.Adjuster; import org.solovyev.android.views.Adjuster;
@ -30,15 +21,12 @@ import org.solovyev.android.views.dragbutton.DragButton;
import org.solovyev.android.views.dragbutton.DragDirection; import org.solovyev.android.views.dragbutton.DragDirection;
import org.solovyev.android.views.dragbutton.SimpleDragListener; import org.solovyev.android.views.dragbutton.SimpleDragListener;
import javax.annotation.Nonnull;
import javax.inject.Inject;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import javax.annotation.Nonnull; import static android.view.HapticFeedbackConstants.*;
import javax.inject.Inject;
import static android.view.HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING;
import static android.view.HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING;
import static android.view.HapticFeedbackConstants.KEYBOARD_TAP;
import static org.solovyev.android.calculator.App.cast; import static org.solovyev.android.calculator.App.cast;
import static org.solovyev.android.calculator.App.getScreenMetrics; import static org.solovyev.android.calculator.App.getScreenMetrics;
import static org.solovyev.android.calculator.Preferences.Gui.Layout.simple; import static org.solovyev.android.calculator.Preferences.Gui.Layout.simple;
@ -93,7 +81,7 @@ public abstract class BaseKeyboardUi implements SharedPreferences.OnSharedPrefer
cast(activity.getApplication()).getComponent().inject(this); cast(activity.getApplication()).getComponent().inject(this);
preferences.registerOnSharedPreferenceChangeListener(this); preferences.registerOnSharedPreferenceChangeListener(this);
orientation = Views.getScreenOrientation(activity); orientation = App.getScreenOrientation(activity);
layout = Preferences.Gui.layout.getPreferenceNoError(preferences); layout = Preferences.Gui.layout.getPreferenceNoError(preferences);
textSize = calculateTextSize(); textSize = calculateTextSize();
} }

View File

@ -1,44 +0,0 @@
/*
* Copyright 2013 serso aka se.solovyev
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* Contact details
*
* Email: se.solovyev@gmail.com
* Site: http://se.solovyev.org
*/
package org.solovyev.android.calculator.matrix;
import org.solovyev.android.calculator.BaseActivity;
import org.solovyev.android.calculator.FragmentTab;
import org.solovyev.android.calculator.R;
import org.solovyev.android.calculator.view.Tabs;
import javax.annotation.Nonnull;
public class CalculatorMatrixActivity extends BaseActivity {
public CalculatorMatrixActivity() {
super(R.string.c_plot_graph);
// FIXME: 2016-03-01 string
}
@Override
protected void populateTabs(@Nonnull Tabs tabs) {
super.populateTabs(tabs);
tabs.addTab(FragmentTab.matrix_edit);
}
}

View File

@ -1,111 +0,0 @@
/*
* Copyright 2013 serso aka se.solovyev
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* Contact details
*
* Email: se.solovyev@gmail.com
* Site: http://se.solovyev.org
*/
package org.solovyev.android.calculator.matrix;
import android.os.Bundle;
import android.view.View;
import org.solovyev.android.calculator.BaseFragment;
import org.solovyev.android.calculator.R;
import org.solovyev.android.view.IntegerRange;
import org.solovyev.android.view.Picker;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
public class EditMatrixFragment extends BaseFragment implements Picker.OnChangedListener<Integer> {
private static final int MAX_COUNT = 10;
private static final int MIN_COUNT = 2;
private static final int DEFAULT_ROWS = 2;
private static final int DEFAULT_COLS = 2;
private static final String MATRIX = "matrix";
public EditMatrixFragment() {
super(R.layout.matrix_edit_fragment);
setRetainInstance(true);
}
@Override
public void onViewCreated(View root, @Nullable Bundle in) {
super.onViewCreated(root, in);
final Picker<Integer> matrixRowsCountPicker = (Picker<Integer>) root.findViewById(R.id.matrix_rows_count_picker);
initPicker(matrixRowsCountPicker);
final Picker<Integer> matrixColsCountPicker = (Picker<Integer>) root.findViewById(R.id.matrix_cols_count_picker);
initPicker(matrixColsCountPicker);
MatrixUi matrix = null;
if (in != null) {
final Object matrixObject = in.getSerializable(MATRIX);
if (matrixObject instanceof MatrixUi) {
matrix = (MatrixUi) matrixObject;
}
}
final MatrixView matrixView = getMatrixView(root);
if (matrix == null) {
matrixView.setMatrixDimensions(DEFAULT_ROWS, DEFAULT_COLS);
} else {
matrixView.setMatrix(matrix.getBakingArray());
}
matrixRowsCountPicker.setCurrent(matrixView.getRows());
matrixColsCountPicker.setCurrent(matrixView.getCols());
}
@Override
public void onSaveInstanceState(@Nonnull Bundle out) {
super.onSaveInstanceState(out);
out.putSerializable(MATRIX, new MatrixUi(getMatrixView(getView()).toMatrix()));
}
@Nonnull
private MatrixView getMatrixView(@Nonnull View root) {
return (MatrixView) root.findViewById(R.id.matrix_layout);
}
private void initPicker(@Nonnull Picker<Integer> picker) {
picker.setRange(new IntegerRange(MIN_COUNT, MAX_COUNT, 1, 0, null));
picker.setOnChangeListener(this);
}
@Override
public void onChanged(@Nonnull Picker picker, @Nonnull Integer value) {
switch (picker.getId()) {
case R.id.matrix_rows_count_picker:
onRowsCountChange(value);
break;
case R.id.matrix_cols_count_picker:
onColsCountChange(value);
break;
}
}
private void onColsCountChange(@Nonnull Integer newCols) {
getMatrixView(getView()).setMatrixCols(newCols);
}
private void onRowsCountChange(@Nonnull Integer newRows) {
getMatrixView(getView()).setMatrixRows(newRows);
}
}

View File

@ -1,128 +0,0 @@
/*
* Copyright 2013 serso aka se.solovyev
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* Contact details
*
* Email: se.solovyev@gmail.com
* Site: http://se.solovyev.org
*/
package org.solovyev.android.calculator.plot;
import javax.annotation.Nonnull;
/**
* User: serso
* Date: 1/18/13
* Time: 9:03 PM
*/
public abstract class AbstractGraphCalculator implements GraphCalculator {
@Nonnull
protected final GraphData next = GraphData.newEmptyInstance();
@Nonnull
private final GraphData endGraph = GraphData.newEmptyInstance();
@Nonnull
private final GraphData startGraph = GraphData.newEmptyInstance();
@Override
public final void computeGraph(@Nonnull XyFunction f,
float xMin,
float xMax,
@Nonnull GraphData graph,
@Nonnull GraphsData graphsData,
@Nonnull Graph2dDimensions dimensions) {
if (f.getArity() == 0) {
final float v = (float) f.eval();
graph.clear();
graph.push(xMin, v);
graph.push(xMax, v);
return;
}
float yMin = graphsData.getLastYMin();
float yMax = graphsData.getLastYMax();
// prepare graph
if (!graph.empty()) {
if (xMin >= graphsData.getLastXMin()) {
// |------[---erased---|------data----|---erased--]------ old data
// |-------------------[------data----]------------------ new data
// xMin xMax
//
// OR
//
// |------[---erased---|------data----]----------- old data
// |-------------------[------data----<---->]----- new data
// xMin xMax
graph.eraseBefore(xMin);
if (xMax <= graphsData.getLastXMax()) {
graph.eraseAfter(xMax);
// nothing to compute
} else {
xMin = graph.getLastX();
compute(f, xMin, xMax, yMin, yMax, endGraph, dimensions);
}
} else {
// |--------------------[-----data----|---erased----]-- old data
// |------[<------------>-----data----]---------------- new data
// xMin xMax
//
// OR
//
// |--------------------[------data--]----|----------- old data
// |-------[<----------->------data--<--->]-----------new data
// xMin xMax
if (xMax <= graphsData.getLastXMax()) {
graph.eraseAfter(xMax);
xMax = graph.getFirstX();
compute(f, xMin, xMax, yMin, yMax, startGraph, dimensions);
} else {
compute(f, xMin, graph.getFirstX(), yMin, yMax, startGraph, dimensions);
compute(f, graph.getLastX(), xMax, yMin, yMax, endGraph, dimensions);
}
}
} else {
compute(f, xMin, xMax, yMin, yMax, graph, dimensions);
}
if (!endGraph.empty()) {
// first add ending because it's fast
graph.append(endGraph);
}
if (!startGraph.empty()) {
startGraph.append(graph);
graph.swap(startGraph);
}
next.clear();
endGraph.clear();
startGraph.clear();
}
protected abstract void compute(@Nonnull XyFunction f,
float xMin,
float xMax,
float yMin,
float yMax,
@Nonnull GraphData graph,
@Nonnull Graph2dDimensions dimensions);
}

View File

@ -1,202 +0,0 @@
/*
* Copyright 2013 serso aka se.solovyev
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* Contact details
*
* Email: se.solovyev@gmail.com
* Site: http://se.solovyev.org
*/
package org.solovyev.android.calculator.plot;
import android.content.Context;
import android.content.SharedPreferences;
import android.preference.PreferenceManager;
import org.solovyev.android.calculator.Preferences;
import java.util.List;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import jscl.math.Generic;
/**
* User: serso
* Date: 1/12/13
* Time: 11:03 PM
*/
public class AndroidCalculatorPlotter implements CalculatorPlotter, SharedPreferences.OnSharedPreferenceChangeListener {
@Nonnull
private final CalculatorPlotter plotter;
public AndroidCalculatorPlotter(@Nonnull Context context,
@Nonnull CalculatorPlotter plotter) {
this.plotter = plotter;
final SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context.getApplicationContext());
preferences.registerOnSharedPreferenceChangeListener(this);
onSharedPreferenceChanged(preferences, Preferences.Graph.plotImag.getKey());
}
@Override
@Nonnull
public PlotData getPlotData() {
return plotter.getPlotData();
}
@Override
public boolean addFunction(@Nonnull Generic expression) {
return plotter.addFunction(expression);
}
@Override
public boolean addFunction(@Nonnull PlotFunction plotFunction) {
return plotter.addFunction(plotFunction);
}
@Override
public boolean addFunction(@Nonnull XyFunction xyFunction) {
return plotter.addFunction(xyFunction);
}
@Override
public boolean addFunction(@Nonnull XyFunction xyFunction, @Nonnull PlotLineDef functionLineDef) {
return plotter.addFunction(xyFunction, functionLineDef);
}
@Override
public boolean updateFunction(@Nonnull PlotFunction newFunction) {
return plotter.updateFunction(newFunction);
}
@Override
public boolean updateFunction(@Nonnull XyFunction xyFunction, @Nonnull PlotLineDef functionLineDef) {
return plotter.updateFunction(xyFunction, functionLineDef);
}
@Override
public boolean removeFunction(@Nonnull PlotFunction plotFunction) {
return plotter.removeFunction(plotFunction);
}
@Override
public boolean removeFunction(@Nonnull XyFunction xyFunction) {
return plotter.removeFunction(xyFunction);
}
@Nonnull
@Override
public PlotFunction pin(@Nonnull PlotFunction plotFunction) {
return plotter.pin(plotFunction);
}
@Nonnull
@Override
public PlotFunction unpin(@Nonnull PlotFunction plotFunction) {
return plotter.unpin(plotFunction);
}
@Nonnull
@Override
public PlotFunction show(@Nonnull PlotFunction plotFunction) {
return plotter.show(plotFunction);
}
@Nonnull
@Override
public PlotFunction hide(@Nonnull PlotFunction plotFunction) {
return plotter.hide(plotFunction);
}
@Override
public void clearAllFunctions() {
plotter.clearAllFunctions();
}
@Nullable
@Override
public PlotFunction getFunctionById(@Nonnull String functionId) {
return plotter.getFunctionById(functionId);
}
@Override
@Nonnull
public List<PlotFunction> getFunctions() {
return plotter.getFunctions();
}
@Override
@Nonnull
public List<PlotFunction> getVisibleFunctions() {
return plotter.getVisibleFunctions();
}
@Override
public void plot() {
plotter.plot();
}
@Override
public void plot(@Nonnull Generic expression) {
plotter.plot(expression);
}
@Override
public boolean is2dPlotPossible() {
return plotter.is2dPlotPossible();
}
@Override
public boolean isPlotPossibleFor(@Nonnull Generic expression) {
return plotter.isPlotPossibleFor(expression);
}
@Override
public void setPlot3d(boolean plot3d) {
plotter.setPlot3d(plot3d);
}
@Override
public void removeAllUnpinned() {
plotter.removeAllUnpinned();
}
@Override
public void setPlotImag(boolean plotImag) {
plotter.setPlotImag(plotImag);
}
@Override
public void savePlotBoundaries(@Nonnull PlotBoundaries plotBoundaries) {
plotter.savePlotBoundaries(plotBoundaries);
}
@Override
public void setPlotBoundaries(@Nonnull PlotBoundaries plotBoundaries) {
plotter.setPlotBoundaries(plotBoundaries);
}
@Override
public void onSharedPreferenceChanged(SharedPreferences preferences, String key) {
if (Preferences.Graph.plotImag.getKey().equals(key)) {
setPlotImag(Preferences.Graph.plotImag.getPreference(preferences));
}
}
}

View File

@ -1,86 +0,0 @@
/*
* Copyright 2013 serso aka se.solovyev
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* Contact details
*
* Email: se.solovyev@gmail.com
* Site: http://se.solovyev.org
*/
package org.solovyev.android.calculator.plot;
import android.graphics.DashPathEffect;
import android.graphics.Paint;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
/**
* User: serso
* Date: 1/5/13
* Time: 7:37 PM
*/
public enum AndroidPlotLineStyle {
solid(PlotLineStyle.solid) {
@Override
public void applyToPaint(@Nonnull Paint paint) {
paint.setPathEffect(null);
}
},
dashed(PlotLineStyle.dashed) {
@Override
public void applyToPaint(@Nonnull Paint paint) {
paint.setPathEffect(new DashPathEffect(new float[]{10, 20}, 0));
}
},
dotted(PlotLineStyle.dotted) {
@Override
public void applyToPaint(@Nonnull Paint paint) {
paint.setPathEffect(new DashPathEffect(new float[]{5, 1}, 0));
}
},
dash_dotted(PlotLineStyle.dash_dotted) {
@Override
public void applyToPaint(@Nonnull Paint paint) {
paint.setPathEffect(new DashPathEffect(new float[]{10, 20, 5, 1}, 0));
}
};
@Nonnull
private final PlotLineStyle plotLineStyle;
AndroidPlotLineStyle(@Nonnull PlotLineStyle plotLineStyle) {
this.plotLineStyle = plotLineStyle;
}
@Nullable
public static AndroidPlotLineStyle valueOf(@Nonnull PlotLineStyle plotLineStyle) {
for (AndroidPlotLineStyle androidPlotLineStyle : values()) {
if (androidPlotLineStyle.plotLineStyle == plotLineStyle) {
return androidPlotLineStyle;
}
}
return null;
}
public abstract void applyToPaint(@Nonnull Paint paint);
}

View File

@ -1,423 +0,0 @@
/*
* Copyright 2013 serso aka se.solovyev
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* Contact details
*
* Email: se.solovyev@gmail.com
* Site: http://se.solovyev.org
*/
package org.solovyev.android.calculator.plot;
import android.content.Context;
import android.graphics.Color;
import android.opengl.Matrix;
import android.os.Build;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.widget.ZoomButtonsController;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import javax.annotation.Nonnull;
import javax.microedition.khronos.opengles.GL10;
import javax.microedition.khronos.opengles.GL11;
public class CalculatorGraph3dView extends GLView implements GraphView {
/*
**********************************************************************
*
* CONSTANTS
*
**********************************************************************
*/
/*
**********************************************************************
*
* FIELDS
*
**********************************************************************
*/
private static final float DISTANCE = 15f;
private boolean useHighQuality3d = Build.VERSION.SDK_INT >= 5;
private float lastTouchX, lastTouchY;
private TouchHandler touchHandler;
private ZoomButtonsController zoomController = new ZoomButtonsController(this);
private float zoomLevel = 1;
private float zoomTarget;
private float zoomStep = 0;
private float currentZoom;
@Nonnull
private List<Graph3d> graphs = new ArrayList<Graph3d>();
@Nonnull
private GraphViewHelper graphViewHelper = GraphViewHelper.newDefaultInstance();
/*
**********************************************************************
*
* CONSTRUCTORS
*
**********************************************************************
*/
@Nonnull
private Graph2dDimensions dimensions = new Graph2dDimensions(this);
private float[] matrix1 = new float[16], matrix2 = new float[16], matrix3 = new float[16];
private float angleX, angleY;
/*
**********************************************************************
*
* METHODS
*
**********************************************************************
*/
private boolean dirty;
public CalculatorGraph3dView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public CalculatorGraph3dView(Context context) {
super(context);
touchHandler = new TouchHandler(this);
init();
}
// ----
private void init() {
startLooping();
zoomController.setOnZoomListener(this);
Matrix.setIdentityM(matrix1, 0);
Matrix.rotateM(matrix1, 0, -75, 1, 0, 0);
}
protected void onSizeChanged(int w, int h, int ow, int oh) {
dimensions.setViewDimensions(w, h);
}
@Override
protected void glDraw() {
if (zoomStep < 0 && zoomLevel > zoomTarget) {
zoomLevel += zoomStep;
} else if (zoomStep > 0 && zoomLevel < zoomTarget) {
zoomLevel += zoomStep;
} else if (zoomStep != 0) {
zoomStep = 0;
zoomLevel = zoomTarget;
dirty = true;
if (!shouldRotate()) {
stopLooping();
}
}
super.glDraw();
}
@Override
public void onDetachedFromWindow() {
zoomController.setVisible(false);
super.onDetachedFromWindow();
}
void setRotation(float x, float y) {
angleX = x;
angleY = y;
}
boolean shouldRotate() {
final float limit = .5f;
return angleX < -limit || angleX > limit || angleY < -limit || angleY > limit;
}
@Override
public void init(@Nonnull PlotViewDef plotViewDef) {
this.graphViewHelper = GraphViewHelper.newInstance(plotViewDef, Collections.<PlotFunction>emptyList());
}
@Nonnull
@Override
public List<PlotFunction> getPlotFunctions() {
return this.graphViewHelper.getPlotFunctions();
}
@Override
public void setPlotFunctions(@Nonnull List<PlotFunction> plotFunctions) {
for (PlotFunction plotFunction : plotFunctions) {
final int arity = plotFunction.getXyFunction().getArity();
if (arity != 0 && arity != 1 && arity != 2) {
throw new IllegalArgumentException("Function must have arity 0 or 1 or 2 for 3d plot!");
}
}
this.graphViewHelper = this.graphViewHelper.copy(plotFunctions);
zoomLevel = 1;
dirty = true;
}
@Override
public void onDestroy() {
onPause();
}
@Override
public void setXRange(float xMin, float xMax) {
dimensions.setXRange(PlotBoundaries.DEFAULT_MIN_NUMBER, PlotBoundaries.DEFAULT_MAX_NUMBER);
dimensions.setXY(dimensions.getX0(), 0);
zoomLevel = 1;
dirty = true;
}
@Override
public void setYRange(float yMin, float yMax) {
}
@Override
public float getXMin() {
return dimensions.getXMin();
}
@Override
public float getXMax() {
return dimensions.getXMax();
}
@Override
public float getYMin() {
return dimensions.getYMin();
}
@Override
public float getYMax() {
return dimensions.getYMax();
}
@Override
public void invalidateGraphs() {
//To change body of implemented methods use File | Settings | File Templates.
}
@Override
public void setAdjustYAxis(boolean adjustYAxis) {
// not supported
}
@Override
public void onSurfaceCreated(GL10 gl, int width, int height) {
gl.glDisable(GL10.GL_DITHER);
gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT, GL10.GL_FASTEST);
final int backgroundColor = graphViewHelper.getPlotViewDef().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.glDisable(GL10.GL_LIGHTING);
ensureGraphsSize((GL11) gl);
dirty = true;
angleX = .5f;
angleY = 0;
gl.glViewport(0, 0, width, height);
initFrustum(gl, DISTANCE * zoomLevel);
currentZoom = zoomLevel;
}
@Override
public void onDrawFrame(GL10 gl10) {
GL11 gl = (GL11) gl10;
if (currentZoom != zoomLevel) {
initFrustum(gl, DISTANCE * zoomLevel);
currentZoom = zoomLevel;
}
if (dirty) {
ensureGraphsSize(gl);
final Graph2dDimensions dimensionsCopy = dimensions.copy();
dimensionsCopy.setGraphDimensions(dimensions.getGWidth() * zoomLevel / 4, dimensions.getGHeight() * zoomLevel / 4);
for (int i = 0; i < graphViewHelper.getPlotFunctions().size(); i++) {
graphs.get(i).update(gl, graphViewHelper.getPlotFunctions().get(i), dimensionsCopy);
}
dirty = false;
}
/*if (fps.incFrame()) {
Calculator.log("f/s " + fps.getValue());
}*/
gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
gl.glMatrixMode(GL10.GL_MODELVIEW);
gl.glLoadIdentity();
gl.glTranslatef(0, 0, -DISTANCE * zoomLevel);
Matrix.setIdentityM(matrix2, 0);
float ax = Math.abs(angleX);
float ay = Math.abs(angleY);
if (ay * 3 < ax) {
Matrix.rotateM(matrix2, 0, angleX, 0, 1, 0);
} else if (ax * 3 < ay) {
Matrix.rotateM(matrix2, 0, angleY, 1, 0, 0);
} else {
if (ax > ay) {
Matrix.rotateM(matrix2, 0, angleX, 0, 1, 0);
Matrix.rotateM(matrix2, 0, angleY, 1, 0, 0);
} else {
Matrix.rotateM(matrix2, 0, angleY, 1, 0, 0);
Matrix.rotateM(matrix2, 0, angleX, 0, 1, 0);
}
}
Matrix.multiplyMM(matrix3, 0, matrix2, 0, matrix1, 0);
gl.glMultMatrixf(matrix3, 0);
System.arraycopy(matrix3, 0, matrix1, 0, 16);
for (Graph3d graph : graphs) {
graph.draw(gl);
}
}
private void ensureGraphsSize(@Nonnull GL11 gl) {
while (graphViewHelper.getPlotFunctions().size() > graphs.size()) {
graphs.add(new Graph3d(gl, useHighQuality3d));
}
}
private void initFrustum(GL10 gl, float distance) {
gl.glMatrixMode(GL10.GL_PROJECTION);
gl.glLoadIdentity();
float near = distance * (1 / 3f);
float far = distance * 3f;
float dimen = near / 5f;
float h = dimen * height / width;
gl.glFrustumf(-dimen, dimen, -h, h, near, far);
gl.glMatrixMode(GL10.GL_MODELVIEW);
gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
gl.glEnableClientState(GL10.GL_COLOR_ARRAY);
}
private void printMatrix(float[] m, String name) {
StringBuilder b = new StringBuilder();
for (int i = 0; i < 16; ++i) {
b.append(m[i]).append(' ');
}
//Calculator.log(name + ' ' + b.toString());
}
/*
**********************************************************************
*
* ZOOM
*
**********************************************************************
*/
public void onVisibilityChanged(boolean visible) {
}
public void onZoom(boolean zoomIn) {
boolean changed = false;
if (zoomIn) {
if (canZoomIn(zoomLevel)) {
zoomTarget = zoomLevel * .625f;
zoomStep = -zoomLevel / 40;
changed = true;
}
} else {
if (canZoomOut(zoomLevel)) {
zoomTarget = zoomLevel * 1.6f;
zoomStep = zoomLevel / 20;
changed = true;
}
}
if (changed) {
zoomController.setZoomInEnabled(canZoomIn(zoomTarget));
zoomController.setZoomOutEnabled(canZoomOut(zoomTarget));
if (!shouldRotate()) {
setRotation(0, 0);
}
startLooping();
}
}
private boolean canZoomIn(float zoom) {
return true;
}
private boolean canZoomOut(float zoom) {
return true;
}
/*
**********************************************************************
*
* TOUCH
*
**********************************************************************
*/
public void onTouchDown(float x, float y) {
zoomController.setVisible(true);
stopLooping();
lastTouchX = x;
lastTouchY = y;
}
public void onTouchMove(float x, float y) {
float deltaX = x - lastTouchX;
float deltaY = y - lastTouchY;
if (deltaX > 1 || deltaX < -1 || deltaY > 1 || deltaY < -1) {
setRotation(deltaX, deltaY);
glDraw();
lastTouchX = x;
lastTouchY = y;
}
}
public void onTouchUp(float x, float y) {
float vx = touchHandler.getXVelocity();
float vy = touchHandler.getYVelocity();
// Calculator.log("velocity " + vx + ' ' + vy);
setRotation(vx / 100, vy / 100);
if (shouldRotate()) {
startLooping();
}
}
public void onTouchZoomDown(float x1, float y1, float x2, float y2) {
}
public void onTouchZoomMove(float x1, float y1, float x2, float y2) {
}
@Override
public boolean onTouchEvent(MotionEvent event) {
return touchHandler != null ? touchHandler.handleTouchEvent(event) : super.onTouchEvent(event);
}
}

View File

@ -1,98 +0,0 @@
/*
* Copyright 2013 serso aka se.solovyev
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* Contact details
*
* Email: se.solovyev@gmail.com
* Site: http://se.solovyev.org
*/
package org.solovyev.android.calculator.plot;
import java.util.List;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import jscl.math.Generic;
/**
* User: serso
* Date: 1/12/13
* Time: 8:23 PM
*/
public interface CalculatorPlotter {
@Nonnull
PlotData getPlotData();
boolean addFunction(@Nonnull Generic expression);
boolean addFunction(@Nonnull PlotFunction plotFunction);
boolean addFunction(@Nonnull XyFunction xyFunction);
boolean addFunction(@Nonnull XyFunction xyFunction, @Nonnull PlotLineDef functionLineDef);
boolean updateFunction(@Nonnull PlotFunction newFunction);
boolean updateFunction(@Nonnull XyFunction xyFunction, @Nonnull PlotLineDef functionLineDef);
boolean removeFunction(@Nonnull PlotFunction plotFunction);
boolean removeFunction(@Nonnull XyFunction xyFunction);
@Nonnull
PlotFunction pin(@Nonnull PlotFunction plotFunction);
@Nonnull
PlotFunction unpin(@Nonnull PlotFunction plotFunction);
@Nonnull
PlotFunction show(@Nonnull PlotFunction plotFunction);
@Nonnull
PlotFunction hide(@Nonnull PlotFunction plotFunction);
void clearAllFunctions();
@Nullable
PlotFunction getFunctionById(@Nonnull String functionId);
@Nonnull
List<PlotFunction> getFunctions();
@Nonnull
List<PlotFunction> getVisibleFunctions();
void plot();
void plot(@Nonnull Generic expression);
boolean is2dPlotPossible();
boolean isPlotPossibleFor(@Nonnull Generic expression);
void setPlot3d(boolean plot3d);
void removeAllUnpinned();
void setPlotImag(boolean plotImag);
void savePlotBoundaries(@Nonnull PlotBoundaries plotBoundaries);
void setPlotBoundaries(@Nonnull PlotBoundaries plotBoundaries);
}

View File

@ -1,38 +0,0 @@
/*
* Copyright 2013 serso aka se.solovyev
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* Contact details
*
* Email: se.solovyev@gmail.com
* Site: http://se.solovyev.org
*/
package org.solovyev.android.calculator.plot;
/**
* User: serso
* Date: 1/18/13
* Time: 7:44 PM
*/
interface FunctionEvaluator {
int getArity();
double eval();
double eval(double x);
double eval(double x, double y);
}

View File

@ -1,418 +0,0 @@
/*
* Copyright 2013 serso aka se.solovyev
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* Contact details
*
* Email: se.solovyev@gmail.com
* Site: http://se.solovyev.org
*/
// This is a OpenGL ES 1.0 dynamic font rendering system. It loads actual font
// files, generates a font map (texture) from them, and allows rendering of
// text strings.
//
// NOTE: the rendering portions of this class uses a sprite batcher in order
// provide decent speed rendering. Also, rendering assumes a BOTTOM-LEFT
// origin, and the (x,y) positions are relative to that, as well as the
// bottom-left of the string to render.
package org.solovyev.android.calculator.plot;
import android.content.res.AssetManager;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Typeface;
import android.opengl.GLUtils;
import javax.microedition.khronos.opengles.GL10;
public class GLText {
//--Constants--//
public final static int CHAR_START = 32; // First Character (ASCII Code)
public final static int CHAR_END = 126; // Last Character (ASCII Code)
public final static int CHAR_CNT = (((CHAR_END - CHAR_START) + 1) + 1); // Character Count (Including Character to use for Unknown)
public final static int CHAR_NONE = 32; // Character to Use for Unknown (ASCII Code)
public final static int CHAR_UNKNOWN = (CHAR_CNT - 1); // Index of the Unknown Character
public final static int FONT_SIZE_MIN = 6; // Minumum Font Size (Pixels)
public final static int FONT_SIZE_MAX = 180; // Maximum Font Size (Pixels)
public final static int CHAR_BATCH_SIZE = 100; // Number of Characters to Render Per Batch
final float[] charWidths; // Width of Each Character (Actual; Pixels)
//--Members--//
GL10 gl; // GL10 Instance
AssetManager assets; // Asset Manager
SpriteBatch batch; // Batch Renderer
int fontPadX, fontPadY; // Font Padding (Pixels; On Each Side, ie. Doubled on Both X+Y Axis)
float fontHeight; // Font Height (Actual; Pixels)
float fontAscent; // Font Ascent (Above Baseline; Pixels)
float fontDescent; // Font Descent (Below Baseline; Pixels)
int textureId; // Font Texture ID [NOTE: Public for Testing Purposes Only!]
int textureSize; // Texture Size for Font (Square) [NOTE: Public for Testing Purposes Only!]
TextureRegion textureRgn; // Full Texture Region
float charWidthMax; // Character Width (Maximum; Pixels)
float charHeight; // Character Height (Maximum; Pixels)
TextureRegion[] charRgn; // Region of Each Character (Texture Coordinates)
int cellWidth, cellHeight; // Character Cell Width/Height
int rowCnt, colCnt; // Number of Rows/Columns
float scaleX, scaleY; // Font Scale (X,Y Axis)
float spaceX; // Additional (X,Y Axis) Spacing (Unscaled)
//--Constructor--//
// D: save GL instance + asset manager, create arrays, and initialize the members
// A: gl - OpenGL ES 10 Instance
public GLText(GL10 gl, AssetManager assets) {
this.gl = gl; // Save the GL10 Instance
this.assets = assets; // Save the Asset Manager Instance
batch = new SpriteBatch(gl, CHAR_BATCH_SIZE); // Create Sprite Batch (with Defined Size)
charWidths = new float[CHAR_CNT]; // Create the Array of Character Widths
charRgn = new TextureRegion[CHAR_CNT]; // Create the Array of Character Regions
// initialize remaining members
fontPadX = 0;
fontPadY = 0;
fontHeight = 0.0f;
fontAscent = 0.0f;
fontDescent = 0.0f;
textureId = -1;
textureSize = 0;
charWidthMax = 0;
charHeight = 0;
cellWidth = 0;
cellHeight = 0;
rowCnt = 0;
colCnt = 0;
scaleX = 1.0f; // Default Scale = 1 (Unscaled)
scaleY = 1.0f; // Default Scale = 1 (Unscaled)
spaceX = 0.0f;
}
//--Load Font--//
// description
// this will load the specified font file, create a texture for the defined
// character range, and setup all required values used to render with it.
// arguments:
// file - Filename of the font (.ttf, .otf) to use. In 'Assets' folder.
// size - Requested pixel size of font (height)
// padX, padY - Extra padding per character (X+Y Axis); to prevent overlapping characters.
public boolean load(String file, int size, int padX, int padY) {
// setup requested values
fontPadX = padX; // Set Requested X Axis Padding
fontPadY = padY; // Set Requested Y Axis Padding
// load the font and setup paint instance for drawing
Typeface tf = Typeface.createFromAsset(assets, file); // Create the Typeface from Font File
Paint paint = new Paint(); // Create Android Paint Instance
paint.setAntiAlias(true); // Enable Anti Alias
paint.setTextSize(size); // Set Text Size
paint.setColor(0xffffffff); // Set ARGB (White, Opaque)
paint.setTypeface(tf); // Set Typeface
// get font metrics
Paint.FontMetrics fm = paint.getFontMetrics(); // Get Font Metrics
fontHeight = (float) Math.ceil(Math.abs(fm.bottom) + Math.abs(fm.top)); // Calculate Font Height
fontAscent = (float) Math.ceil(Math.abs(fm.ascent)); // Save Font Ascent
fontDescent = (float) Math.ceil(Math.abs(fm.descent)); // Save Font Descent
// determine the width of each character (including unknown character)
// also determine the maximum character width
char[] s = new char[2]; // Create Character Array
charWidthMax = charHeight = 0; // Reset Character Width/Height Maximums
float[] w = new float[2]; // Working Width Value
int cnt = 0; // Array Counter
for (char c = CHAR_START; c <= CHAR_END; c++) { // FOR Each Character
s[0] = c; // Set Character
paint.getTextWidths(s, 0, 1, w); // Get Character Bounds
charWidths[cnt] = w[0]; // Get Width
if (charWidths[cnt] > charWidthMax) // IF Width Larger Than Max Width
charWidthMax = charWidths[cnt]; // Save New Max Width
cnt++; // Advance Array Counter
}
s[0] = CHAR_NONE; // Set Unknown Character
paint.getTextWidths(s, 0, 1, w); // Get Character Bounds
charWidths[cnt] = w[0]; // Get Width
if (charWidths[cnt] > charWidthMax) // IF Width Larger Than Max Width
charWidthMax = charWidths[cnt]; // Save New Max Width
cnt++; // Advance Array Counter
// set character height to font height
charHeight = fontHeight; // Set Character Height
// find the maximum size, validate, and setup cell sizes
cellWidth = (int) charWidthMax + (2 * fontPadX); // Set Cell Width
cellHeight = (int) charHeight + (2 * fontPadY); // Set Cell Height
int maxSize = cellWidth > cellHeight ? cellWidth : cellHeight; // Save Max Size (Width/Height)
if (maxSize < FONT_SIZE_MIN || maxSize > FONT_SIZE_MAX) // IF Maximum Size Outside Valid Bounds
return false; // Return Error
// set texture size based on max font size (width or height)
// NOTE: these values are fixed, based on the defined characters. when
// changing start/end characters (CHAR_START/CHAR_END) this will need adjustment too!
if (maxSize <= 24) // IF Max Size is 18 or Less
textureSize = 256; // Set 256 Texture Size
else if (maxSize <= 40) // ELSE IF Max Size is 40 or Less
textureSize = 512; // Set 512 Texture Size
else if (maxSize <= 80) // ELSE IF Max Size is 80 or Less
textureSize = 1024; // Set 1024 Texture Size
else // ELSE IF Max Size is Larger Than 80 (and Less than FONT_SIZE_MAX)
textureSize = 2048; // Set 2048 Texture Size
// create an empty bitmap (alpha only)
Bitmap bitmap = Bitmap.createBitmap(textureSize, textureSize, Bitmap.Config.ALPHA_8); // Create Bitmap
Canvas canvas = new Canvas(bitmap); // Create Canvas for Rendering to Bitmap
bitmap.eraseColor(0x00000000); // Set Transparent Background (ARGB)
// calculate rows/columns
// NOTE: while not required for anything, these may be useful to have :)
colCnt = textureSize / cellWidth; // Calculate Number of Columns
rowCnt = (int) Math.ceil((float) CHAR_CNT / (float) colCnt); // Calculate Number of Rows
// render each of the characters to the canvas (ie. build the font map)
float x = fontPadX; // Set Start Position (X)
float y = (cellHeight - 1) - fontDescent - fontPadY; // Set Start Position (Y)
for (char c = CHAR_START; c <= CHAR_END; c++) { // FOR Each Character
s[0] = c; // Set Character to Draw
canvas.drawText(s, 0, 1, x, y, paint); // Draw Character
x += cellWidth; // Move to Next Character
if ((x + cellWidth - fontPadX) > textureSize) { // IF End of Line Reached
x = fontPadX; // Set X for New Row
y += cellHeight; // Move Down a Row
}
}
s[0] = CHAR_NONE; // Set Character to Use for NONE
canvas.drawText(s, 0, 1, x, y, paint); // Draw Character
// generate a new texture
int[] textureIds = new int[1]; // Array to Get Texture Id
gl.glGenTextures(1, textureIds, 0); // Generate New Texture
textureId = textureIds[0]; // Save Texture Id
// setup filters for texture
gl.glBindTexture(GL10.GL_TEXTURE_2D, textureId); // Bind Texture
gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_NEAREST); // Set Minification Filter
gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER, GL10.GL_LINEAR); // Set Magnification Filter
gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_S, GL10.GL_CLAMP_TO_EDGE); // Set U Wrapping
gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_T, GL10.GL_CLAMP_TO_EDGE); // Set V Wrapping
// load the generated bitmap onto the texture
GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, bitmap, 0); // Load Bitmap to Texture
gl.glBindTexture(GL10.GL_TEXTURE_2D, 0); // Unbind Texture
// release the bitmap
bitmap.recycle(); // Release the Bitmap
// setup the array of character texture regions
x = 0; // Initialize X
y = 0; // Initialize Y
for (int c = 0; c < CHAR_CNT; c++) { // FOR Each Character (On Texture)
charRgn[c] = new TextureRegion(textureSize, textureSize, x, y, cellWidth - 1, cellHeight - 1); // Create Region for Character
x += cellWidth; // Move to Next Char (Cell)
if (x + cellWidth > textureSize) {
x = 0; // Reset X Position to Start
y += cellHeight; // Move to Next Row (Cell)
}
}
// create full texture region
textureRgn = new TextureRegion(textureSize, textureSize, 0, 0, textureSize, textureSize); // Create Full Texture Region
// return success
return true; // Return Success
}
//--Begin/End Text Drawing--//
// D: call these methods before/after (respectively all draw() calls using a text instance
// NOTE: color is set on a per-batch basis, and fonts should be 8-bit alpha only!!!
// A: red, green, blue - RGB values for font (default = 1.0)
// alpha - optional alpha value for font (default = 1.0)
// R: [none]
public void begin() {
begin(1.0f, 1.0f, 1.0f, 1.0f); // Begin with White Opaque
}
public void begin(float alpha) {
begin(1.0f, 1.0f, 1.0f, alpha); // Begin with White (Explicit Alpha)
}
public void begin(float red, float green, float blue, float alpha) {
gl.glColor4f(red, green, blue, alpha); // Set Color+Alpha
gl.glBindTexture(GL10.GL_TEXTURE_2D, textureId); // Bind the Texture
batch.beginBatch(); // Begin Batch
}
public void end() {
batch.endBatch(); // End Batch
gl.glColor4f(1.0f, 1.0f, 1.0f, 1.0f); // Restore Default Color/Alpha
}
//--Draw Text--//
// D: draw text at the specified x,y position
// A: text - the string to draw
// x, y - the x,y position to draw text at (bottom left of text; including descent)
// R: [none]
public void draw(String text, float x, float y) {
float chrHeight = cellHeight * scaleY; // Calculate Scaled Character Height
float chrWidth = cellWidth * scaleX; // Calculate Scaled Character Width
int len = text.length(); // Get String Length
x += (chrWidth / 2.0f) - (fontPadX * scaleX); // Adjust Start X
y += (chrHeight / 2.0f) - (fontPadY * scaleY); // Adjust Start Y
for (int i = 0; i < len; i++) { // FOR Each Character in String
int c = (int) text.charAt(i) - CHAR_START; // Calculate Character Index (Offset by First Char in Font)
if (c < 0 || c >= CHAR_CNT) // IF Character Not In Font
c = CHAR_UNKNOWN; // Set to Unknown Character Index
batch.drawSprite(x, y, chrWidth, chrHeight, charRgn[c]); // Draw the Character
x += (charWidths[c] + spaceX) * scaleX; // Advance X Position by Scaled Character Width
}
}
//--Draw Text Centered--//
// D: draw text CENTERED at the specified x,y position
// A: text - the string to draw
// x, y - the x,y position to draw text at (bottom left of text)
// R: the total width of the text that was drawn
public float drawC(String text, float x, float y) {
float len = getLength(text); // Get Text Length
draw(text, x - (len / 2.0f), y - (getCharHeight() / 2.0f)); // Draw Text Centered
return len; // Return Length
}
public float drawCX(String text, float x, float y) {
float len = getLength(text); // Get Text Length
draw(text, x - (len / 2.0f), y); // Draw Text Centered (X-Axis Only)
return len; // Return Length
}
public void drawCY(String text, float x, float y) {
draw(text, x, y - (getCharHeight() / 2.0f)); // Draw Text Centered (Y-Axis Only)
}
//--Set Scale--//
// D: set the scaling to use for the font
// A: scale - uniform scale for both x and y axis scaling
// sx, sy - separate x and y axis scaling factors
// R: [none]
public void setScale(float scale) {
scaleX = scaleY = scale; // Set Uniform Scale
}
public void setScale(float sx, float sy) {
scaleX = sx; // Set X Scale
scaleY = sy; // Set Y Scale
}
//--Get Scale--//
// D: get the current scaling used for the font
// A: [none]
// R: the x/y scale currently used for scale
public float getScaleX() {
return scaleX; // Return X Scale
}
public float getScaleY() {
return scaleY; // Return Y Scale
}
//--Get Space--//
// D: get the current spacing used for the font
// A: [none]
// R: the x/y space currently used for scale
public float getSpace() {
return spaceX; // Return X Space
}
//--Set Space--//
// D: set the spacing (unscaled; ie. pixel size) to use for the font
// A: space - space for x axis spacing
// R: [none]
public void setSpace(float space) {
spaceX = space; // Set Space
}
//--Get Length of a String--//
// D: return the length of the specified string if rendered using current settings
// A: text - the string to get length for
// R: the length of the specified string (pixels)
public float getLength(String text) {
float len = 0.0f; // Working Length
int strLen = text.length(); // Get String Length (Characters)
for (int i = 0; i < strLen; i++) { // For Each Character in String (Except Last
int c = (int) text.charAt(i) - CHAR_START; // Calculate Character Index (Offset by First Char in Font)
len += (charWidths[c] * scaleX); // Add Scaled Character Width to Total Length
}
len += (strLen > 1 ? ((strLen - 1) * spaceX) * scaleX : 0); // Add Space Length
return len; // Return Total Length
}
//--Get Width/Height of Character--//
// D: return the scaled width/height of a character, or max character width
// NOTE: since all characters are the same height, no character index is required!
// NOTE: excludes spacing!!
// A: chr - the character to get width for
// R: the requested character size (scaled)
public float getCharWidth(char chr) {
int c = chr - CHAR_START; // Calculate Character Index (Offset by First Char in Font)
return (charWidths[c] * scaleX); // Return Scaled Character Width
}
public float getCharWidthMax() {
return (charWidthMax * scaleX); // Return Scaled Max Character Width
}
public float getCharHeight() {
return (charHeight * scaleY); // Return Scaled Character Height
}
//--Get Font Metrics--//
// D: return the specified (scaled) font metric
// A: [none]
// R: the requested font metric (scaled)
public float getAscent() {
return (fontAscent * scaleY); // Return Font Ascent
}
public float getDescent() {
return (fontDescent * scaleY); // Return Font Descent
}
public float getHeight() {
return (fontHeight * scaleY); // Return Font Height (Actual)
}
//--Draw Font Texture--//
// D: draw the entire font texture (NOTE: for testing purposes only)
// A: width, height - the width and height of the area to draw to. this is used
// to draw the texture to the top-left corner.
public void drawTexture(int width, int height) {
batch.beginBatch(textureId); // Begin Batch (Bind Texture)
batch.drawSprite(textureSize / 2, height - (textureSize / 2), textureSize, textureSize, textureRgn); // Draw
batch.endBatch(); // End Batch
}
}

View File

@ -1,242 +0,0 @@
/*
* Copyright 2013 serso aka se.solovyev
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* Contact details
*
* Email: se.solovyev@gmail.com
* Site: http://se.solovyev.org
*/
package org.solovyev.android.calculator.plot;
import android.content.Context;
import android.graphics.Bitmap;
import android.os.Handler;
import android.os.Message;
import android.util.AttributeSet;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.ShortBuffer;
import javax.annotation.Nonnull;
import javax.microedition.khronos.egl.EGL10;
import javax.microedition.khronos.egl.EGL11;
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.egl.EGLContext;
import javax.microedition.khronos.egl.EGLDisplay;
import javax.microedition.khronos.egl.EGLSurface;
import javax.microedition.khronos.opengles.GL10;
import javax.microedition.khronos.opengles.GL11;
abstract class GLView extends SurfaceView implements SurfaceHolder.Callback {
protected int width, height;
private boolean hasSurface;
private boolean paused;
private EGL10 egl;
private EGLDisplay display;
private EGLConfig config;
private EGLSurface surface;
private EGLContext eglContext;
private GL11 gl;
private volatile boolean looping;
@Nonnull
private final Handler uiHandler = new Handler() {
public void handleMessage(Message msg) {
switch (msg.what) {
case 1:
glDraw();
break;
default:
Log.e("GLView", "Incorrect message id: " + msg.what);
}
}
};
public GLView(Context context) {
super(context);
init();
}
public GLView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
private static Bitmap getRawPixels(GL10 gl, int width, int height) {
int size = width * height;
ByteBuffer buf = ByteBuffer.allocateDirect(size * 4);
buf.order(ByteOrder.nativeOrder());
gl.glReadPixels(0, 0, width, height, GL10.GL_RGBA, GL10.GL_UNSIGNED_BYTE, buf);
int data[] = new int[size];
buf.asIntBuffer().get(data);
buf = null;
Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565);
bitmap.setPixels(data, size - width, -width, 0, 0, width, height);
return bitmap;
}
static void bitmapBGRtoRGB(Bitmap bitmap, int width, int height) {
int size = width * height;
short data[] = new short[size];
ShortBuffer buf = ShortBuffer.wrap(data);
bitmap.copyPixelsToBuffer(buf);
for (int i = 0; i < size; ++i) {
//BGR-565 to RGB-565
short v = data[i];
data[i] = (short) (((v & 0x1f) << 11) | (v & 0x7e0) | ((v & 0xf800) >> 11));
}
buf.rewind();
bitmap.copyPixelsFromBuffer(buf);
}
abstract void onDrawFrame(GL10 gl);
abstract void onSurfaceCreated(GL10 gl, int width, int height);
@Nonnull
public Bitmap captureScreenshot() {
if (gl != null) {
final Bitmap result = getRawPixels(gl, width, height);
bitmapBGRtoRGB(result, width, height);
return result;
} else {
return Bitmap.createBitmap(width == 0 ? 1 : width, height == 0 ? 1 : height, Bitmap.Config.RGB_565);
}
}
private void init() {
final SurfaceHolder holder = getHolder();
holder.setType(SurfaceHolder.SURFACE_TYPE_GPU);
holder.addCallback(this);
}
public void onResume() {
paused = false;
if (hasSurface) {
initGL();
}
}
public void onPause() {
deinitGL();
}
private void initGL() {
egl = (EGL10) EGLContext.getEGL();
display = egl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY);
int[] ver = new int[2];
egl.eglInitialize(display, ver);
int[] configSpec = {EGL10.EGL_NONE};
EGLConfig[] configOut = new EGLConfig[1];
int[] nConfig = new int[1];
egl.eglChooseConfig(display, configSpec, configOut, 1, nConfig);
config = configOut[0];
eglContext = egl.eglCreateContext(display, config, EGL10.EGL_NO_CONTEXT, null);
surface = egl.eglCreateWindowSurface(display, config, getHolder(), null);
egl.eglMakeCurrent(display, surface, surface, eglContext);
gl = (GL11) eglContext.getGL();
onSurfaceCreated(gl, width, height);
requestDraw();
}
private void deinitGL() {
paused = true;
if (display != null) {
egl.eglMakeCurrent(display, EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_CONTEXT);
egl.eglDestroySurface(display, surface);
egl.eglDestroyContext(display, eglContext);
egl.eglTerminate(display);
egl = null;
config = null;
eglContext = null;
surface = null;
display = null;
gl = null;
}
}
protected void glDraw() {
if (hasSurface && !paused) {
onDrawFrame(gl);
if (!egl.eglSwapBuffers(display, surface)) {
paused = true;
}
if (egl.eglGetError() == EGL11.EGL_CONTEXT_LOST) {
paused = true;
}
if (paused) {
reinitGL();
}
if (looping) {
requestDraw();
}
}
}
public void surfaceCreated(SurfaceHolder holder) {
}
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
this.width = width;
this.height = height;
final boolean hadSurface = hasSurface;
boolean doInit = !hadSurface && !paused;
hasSurface = true;
if (doInit) {
initGL();
} else if (hadSurface) {
reinitGL();
}
}
private void reinitGL() {
deinitGL();
paused = false;
initGL();
}
public void surfaceDestroyed(SurfaceHolder holder) {
hasSurface = false;
deinitGL();
}
public void startLooping() {
if (!looping) {
looping = true;
glDraw();
}
}
public void stopLooping() {
if (looping) {
looping = false;
}
}
public boolean isLooping() {
return looping;
}
public void requestDraw() {
uiHandler.sendEmptyMessage(1);
}
}

View File

@ -1,265 +0,0 @@
/*
* Copyright 2013 serso aka se.solovyev
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* Contact details
*
* Email: se.solovyev@gmail.com
* Site: http://se.solovyev.org
*/
package org.solovyev.android.calculator.plot;
import android.view.View;
import org.solovyev.common.math.Point2d;
import javax.annotation.Nonnull;
/**
* User: serso
* Date: 1/18/13
* Time: 7:59 PM
*/
public class Graph2dDimensions {
// |<--------------gWidth-------------->|
// xMin xMax
// -------------------|------------------------------------|--------------------
// |<-------------vWidthPxs------------>|
//
/*
*
*
* yMax ------0------------------------------------|--> xPxs
* ^ |
* | |
* v | y
* H | ^
* e | |
* i | |
* g | |
* h |------------------0-----------------|--> x
* t | |
* | | |
* | | |
* v | |
* yMin ------- -
* | |
* v
* yPxs
*
* */
@Nonnull
private GraphView graphView;
// view width and height in pixels
private int vWidthPxs;
private int vHeightPxs;
// current position of camera in graph coordinates
private float x0;
private float y0;
// graph width and height in function units (NOT screen pixels)
private float gWidth = 20;
private float gHeight = 20;
public Graph2dDimensions(@Nonnull GraphView graphView) {
this.graphView = graphView;
}
/*
**********************************************************************
*
* METHODS
*
**********************************************************************
*/
@Nonnull
Point2d toGraphCoordinates(float xPxs, float yPxs) {
return new Point2d(scaleXPxs(xPxs) + getXMin(), (getGHeight() - scaleYPxs(yPxs)) + getYMin());
}
private float scaleXPxs(float pxs) {
return pxs * getXGraphToViewScale();
}
private float scaleYPxs(float pxs) {
return pxs * getYGraphToViewScale();
}
// X
public float getXMin() {
return x0 - gWidth / 2;
}
float getXMax(float minX) {
return minX + gWidth;
}
public float getXMax() {
return getXMax(getXMin());
}
// Y
public float getYMin() {
return y0 - gHeight / 2;
}
public float getYMax() {
return getYMax(getYMin());
}
public float getYMax(float yMin) {
return yMin + gHeight;
}
float getXGraphToViewScale() {
if (vWidthPxs != 0) {
return gWidth / ((float) vWidthPxs);
} else {
return 0f;
}
}
float getYGraphToViewScale() {
if (vHeightPxs != 0) {
return gHeight / ((float) vHeightPxs);
} else {
return 0f;
}
}
private float getViewAspectRatio() {
if (vWidthPxs != 0) {
return ((float) vHeightPxs) / vWidthPxs;
} else {
return 0f;
}
}
public int getVWidthPxs() {
return vWidthPxs;
}
public int getVHeightPxs() {
return vHeightPxs;
}
public float getX0() {
return x0;
}
public float getY0() {
return y0;
}
public float getGWidth() {
return gWidth;
}
float getGHeight() {
return gHeight;
}
/*
**********************************************************************
*
* SETTERS
*
**********************************************************************
*/
public void setXRange(float xMin, float xMax) {
setXRange0(xMin, xMax);
this.graphView.invalidateGraphs();
}
private void setXRange0(float xMin, float xMax) {
this.gWidth = xMax - xMin;
this.x0 = xMin + gWidth / 2;
}
public void setYRange(float yMin, float yMax) {
setYRange0(yMin, yMax);
this.graphView.invalidateGraphs();
}
private void setYRange0(float yMin, float yMax) {
this.gHeight = yMax - yMin;
this.y0 = yMin + gHeight / 2;
}
public void setRanges(float xMin, float xMax, float yMin, float yMax) {
setXRange0(xMin, xMax);
setYRange0(yMin, yMax);
this.graphView.invalidateGraphs();
}
public void setViewDimensions(@Nonnull View view) {
this.vWidthPxs = view.getWidth();
this.vHeightPxs = view.getHeight();
this.graphView.invalidateGraphs();
}
public void setGraphDimensions(float gWidth, float gHeight) {
this.gWidth = gWidth;
this.gHeight = gHeight;
this.graphView.invalidateGraphs();
}
public void setViewDimensions(int vWidthPxs, int vHeightPxs) {
this.vWidthPxs = vWidthPxs;
this.vHeightPxs = vHeightPxs;
this.graphView.invalidateGraphs();
}
void setXY(float x0, float y0) {
this.x0 = x0;
this.y0 = y0;
}
public void increaseXY(float dx, float dy) {
this.x0 += dx;
this.y0 += dy;
}
@Nonnull
public Graph2dDimensions copy() {
final Graph2dDimensions copy = new Graph2dDimensions(this.graphView);
copy.vWidthPxs = this.vWidthPxs;
copy.vHeightPxs = this.vHeightPxs;
copy.x0 = this.x0;
copy.y0 = this.y0;
copy.gWidth = this.gWidth;
copy.gHeight = this.gHeight;
return copy;
}
}

View File

@ -1,378 +0,0 @@
/*
* Copyright 2013 serso aka se.solovyev
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* Contact details
*
* Email: se.solovyev@gmail.com
* Site: http://se.solovyev.org
*/
package org.solovyev.android.calculator.plot;
import android.graphics.Color;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import java.nio.ShortBuffer;
import javax.annotation.Nonnull;
import javax.microedition.khronos.opengles.GL10;
import javax.microedition.khronos.opengles.GL11;
class Graph3d {
// vertices count per polygon (triangle = 3)
public static final int VERTICES_COUNT = 3;
// color components count per color
public static final int COLOR_COMPONENTS_COUNT = 4;
// linear polygons count
private final int n;
private final boolean useHighQuality3d;
private ShortBuffer verticeIdx;
private FloatBuffer vertexBuf;
private ByteBuffer colorBuf;
private int vertexVbo, colorVbo, vertexElementVbo;
private boolean useVBO;
private int polygonsⁿ;
Graph3d(GL11 gl, boolean useHighQuality3d) {
this.useHighQuality3d = useHighQuality3d;
this.n = useHighQuality3d ? 36 : 24;
short[] b = new short[n * n];
int p = 0;
for (int i = 0; i < n; i++) {
short v = 0;
for (int j = 0; j < n; v += n + n, j += 2) {
b[p++] = (short) (v + i);
b[p++] = (short) (v + n + n - 1 - i);
}
v = (short) (n * (n - 2));
i++;
for (int j = n - 1; j >= 0; v -= n + n, j -= 2) {
b[p++] = (short) (v + n + n - 1 - i);
b[p++] = (short) (v + i);
}
}
verticeIdx = buildBuffer(b);
String extensions = gl.glGetString(GL10.GL_EXTENSIONS);
useVBO = extensions.indexOf("vertex_buffer_object") != -1;
//Calculator.log("VBOs support: " + useVBO + " version " + gl.glGetString(GL10.GL_VERSION));
if (useVBO) {
int[] out = new int[3];
gl.glGenBuffers(3, out, 0);
vertexVbo = out[0];
colorVbo = out[1];
vertexElementVbo = out[2];
}
}
private static FloatBuffer buildBuffer(float[] b) {
ByteBuffer bb = ByteBuffer.allocateDirect(b.length << 2);
bb.order(ByteOrder.nativeOrder());
FloatBuffer sb = bb.asFloatBuffer();
sb.put(b);
sb.position(0);
return sb;
}
private static ShortBuffer buildBuffer(short[] b) {
ByteBuffer bb = ByteBuffer.allocateDirect(b.length << 1);
bb.order(ByteOrder.nativeOrder());
ShortBuffer sb = bb.asShortBuffer();
sb.put(b);
sb.position(0);
return sb;
}
private static ByteBuffer buildBuffer(byte[] b) {
ByteBuffer bb = ByteBuffer.allocateDirect(b.length << 1);
bb.order(ByteOrder.nativeOrder());
bb.put(b);
bb.position(0);
return bb;
}
public void update(@Nonnull GL11 gl, @Nonnull PlotFunction fpd, @Nonnull Graph2dDimensions dimensions) {
final XyFunction function = fpd.getXyFunction();
final PlotLineDef lineDef = fpd.getPlotLineDef();
final int NTICK = useHighQuality3d ? 5 : 0;
//Calculator.log("update VBOs " + vertexVbo + ' ' + colorVbo + ' ' + vertexElementVbo);
polygonsⁿ = n * n + 6 + 8 + NTICK * 6;
// triangle polygon => 3 vertices per polygon
final float vertices[] = new float[polygonsⁿ * VERTICES_COUNT];
float maxAbsZ = fillFunctionPolygonVertices(function, dimensions, vertices);
final byte[] colors = prepareFunctionPolygonColors(lineDef, vertices, maxAbsZ);
int base = n * n * 3;
int colorBase = n * n * 4;
final int baseSize = 2;
fillBasePolygonVectors(vertices, colors, base, colorBase, baseSize);
base += 8 * 3;
colorBase += 8 * 4;
fillAxisPolygonVectors(vertices, colors, base, colorBase);
base += 6 * 3;
colorBase += 6 * 4;
fillAxisGridPolygonVectors(NTICK, vertices, colors, base, colorBase);
vertexBuf = buildBuffer(vertices);
colorBuf = buildBuffer(colors);
if (useVBO) {
gl.glBindBuffer(GL11.GL_ARRAY_BUFFER, vertexVbo);
gl.glBufferData(GL11.GL_ARRAY_BUFFER, vertexBuf.capacity() * 4, vertexBuf, GL11.GL_STATIC_DRAW);
vertexBuf = null;
gl.glBindBuffer(GL11.GL_ARRAY_BUFFER, colorVbo);
gl.glBufferData(GL11.GL_ARRAY_BUFFER, colorBuf.capacity(), colorBuf, GL11.GL_STATIC_DRAW);
gl.glBindBuffer(GL11.GL_ARRAY_BUFFER, 0);
colorBuf = null;
gl.glBindBuffer(GL11.GL_ELEMENT_ARRAY_BUFFER, vertexElementVbo);
gl.glBufferData(GL11.GL_ELEMENT_ARRAY_BUFFER, verticeIdx.capacity() * 2, verticeIdx, GL11.GL_STATIC_DRAW);
gl.glBindBuffer(GL11.GL_ELEMENT_ARRAY_BUFFER, 0);
}
}
private void fillAxisGridPolygonVectors(int NTICK, float[] vertices, byte[] colors, int base, int colorBase) {
int p = base;
final float tick = .03f;
final float offset = .01f;
for (int i = 1; i <= NTICK; ++i) {
vertices[p] = i - tick;
vertices[p + 1] = -offset;
vertices[p + 2] = -offset;
vertices[p + 3] = i + tick;
vertices[p + 4] = offset;
vertices[p + 5] = offset;
p += 6;
vertices[p] = -offset;
vertices[p + 1] = i - tick;
vertices[p + 2] = -offset;
vertices[p + 3] = offset;
vertices[p + 4] = i + tick;
vertices[p + 5] = offset;
p += 6;
vertices[p] = -offset;
vertices[p + 1] = -offset;
vertices[p + 2] = i - tick;
vertices[p + 3] = offset;
vertices[p + 4] = offset;
vertices[p + 5] = i + tick;
p += 6;
}
for (int i = colorBase + NTICK * 6 * 4 - 1; i >= colorBase; --i) {
colors[i] = (byte) 255;
}
}
private void fillAxisPolygonVectors(float[] vertices, byte[] colors, int base, int colorBase) {
final float unit = 2;
final float axis[] = {
0, 0, 0,
unit, 0, 0,
0, 0, 0,
0, unit, 0,
0, 0, 0,
0, 0, unit,
};
System.arraycopy(axis, 0, vertices, base, 6 * 3);
for (int i = colorBase; i < colorBase + 6 * 4; i += 4) {
colors[i] = (byte) 255;
colors[i + 1] = (byte) 255;
colors[i + 2] = (byte) 255;
colors[i + 3] = (byte) 255;
}
}
private void fillBasePolygonVectors(float[] vertices, byte[] colors, int base, int colorBase, int baseSize) {
int p = base;
for (int i = -baseSize; i <= baseSize; i += 2 * baseSize) {
vertices[p] = i;
vertices[p + 1] = -baseSize;
vertices[p + 2] = 0;
p += 3;
vertices[p] = i;
vertices[p + 1] = baseSize;
vertices[p + 2] = 0;
p += 3;
vertices[p] = -baseSize;
vertices[p + 1] = i;
vertices[p + 2] = 0;
p += 3;
vertices[p] = baseSize;
vertices[p + 1] = i;
vertices[p + 2] = 0;
p += 3;
}
for (int i = colorBase; i < colorBase + 8 * 4; i += 4) {
colors[i] = (byte) 255;
colors[i + 1] = (byte) 255;
colors[i + 2] = (byte) 255;
colors[i + 3] = (byte) 255;
}
}
private float fillFunctionPolygonVertices(XyFunction function, @Nonnull Graph2dDimensions dimensions, float[] vertices) {
final int arity = function.getArity();
final float xMin = dimensions.getXMin();
final float xMax = dimensions.getXMax();
final float yMin = dimensions.getXMin();
final float yMax = dimensions.getXMax();
float Δx = (xMax - xMin) / (n - 1);
float Δy = (yMax - yMin) / (n - 1);
float y = yMin;
float x = xMin - Δx;
float maxAbsZ = 0;
float z = 0;
if (arity == 0) {
z = (float) function.eval();
}
int k = 0;
for (int i = 0; i < n; i++, y += Δy) {
float xinc = (i & 1) == 0 ? Δx : -Δx;
x += xinc;
if (arity == 1) {
z = (float) function.eval(y);
}
for (int j = 0; j < n; j++, x += xinc, k += VERTICES_COUNT) {
if (arity == 2) {
z = (float) function.eval(y, x);
}
vertices[k] = x;
vertices[k + 1] = y;
vertices[k + 2] = z;
if (!Float.isNaN(z)) {
final float absZ = Math.abs(z);
if (absZ > maxAbsZ) {
maxAbsZ = absZ;
}
} else {
vertices[k + 2] = 0;
}
}
}
return maxAbsZ;
}
private byte[] prepareFunctionPolygonColors(PlotLineDef lineDef, float[] vertices, float maxAbsZ) {
// 4 color components per polygon (color[i] = red, color[i+1] = green, color[i+2] = blue, color[i+3] = alpha )
final byte colors[] = new byte[polygonsⁿ * COLOR_COMPONENTS_COUNT];
final int lineColor = lineDef.getLineColor();
final int colorComponentsCount = n * n * COLOR_COMPONENTS_COUNT;
for (int i = 0, j = VERTICES_COUNT - 1; i < colorComponentsCount; i += COLOR_COMPONENTS_COUNT, j += VERTICES_COUNT) {
final float z = vertices[j];
if (!Float.isNaN(z)) {
if (lineDef.getLineColorType() == PlotLineColorType.color_map) {
final float color = z / maxAbsZ;
final float abs = Math.abs(color);
colors[i] = floatToByte(color);
colors[i + 1] = floatToByte(1 - abs * .3f);
colors[i + 2] = floatToByte(-color);
} 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;
} else {
colors[i] = 0;
colors[i + 1] = 0;
colors[i + 2] = 0;
colors[i + 3] = 0;
}
}
return colors;
}
private byte floatToByte(float v) {
if (v <= 0) {
return (byte) 0;
} else {
if (v >= 1) {
return (byte) 255;
} else {
return (byte) (v * 255);
}
}
}
public void draw(GL11 gl) {
if (useVBO) {
gl.glBindBuffer(GL11.GL_ARRAY_BUFFER, vertexVbo);
gl.glVertexPointer(3, GL10.GL_FLOAT, 0, 0);
gl.glBindBuffer(GL11.GL_ARRAY_BUFFER, colorVbo);
gl.glColorPointer(4, GL10.GL_UNSIGNED_BYTE, 0, 0);
gl.glBindBuffer(GL11.GL_ARRAY_BUFFER, 0);
// gl.glDrawArrays(GL10.GL_LINE_STRIP, 0, N*N);
gl.glBindBuffer(GL11.GL_ELEMENT_ARRAY_BUFFER, vertexElementVbo);
gl.glDrawElements(GL10.GL_LINE_STRIP, n * n, GL10.GL_UNSIGNED_SHORT, 0);
gl.glBindBuffer(GL11.GL_ELEMENT_ARRAY_BUFFER, 0);
} else {
gl.glVertexPointer(3, GL10.GL_FLOAT, 0, vertexBuf);
gl.glColorPointer(4, GL10.GL_UNSIGNED_BYTE, 0, colorBuf);
gl.glDrawElements(GL10.GL_LINE_STRIP, n * n, GL10.GL_UNSIGNED_SHORT, verticeIdx);
}
final int N2 = n * n;
gl.glDrawArrays(GL10.GL_LINE_STRIP, 0, N2);
gl.glDrawArrays(GL10.GL_LINES, N2, polygonsⁿ - N2);
}
public boolean isUseHighQuality3d() {
return useHighQuality3d;
}
}

View File

@ -1,40 +0,0 @@
/*
* Copyright 2013 serso aka se.solovyev
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* Contact details
*
* Email: se.solovyev@gmail.com
* Site: http://se.solovyev.org
*/
package org.solovyev.android.calculator.plot;
import javax.annotation.Nonnull;
/**
* User: serso
* Date: 1/18/13
* Time: 8:58 PM
*/
public interface GraphCalculator {
void computeGraph(@Nonnull XyFunction f,
float xMin,
float xMax,
@Nonnull GraphData graph,
@Nonnull GraphsData graphsData,
@Nonnull Graph2dDimensions dimensions);
}

View File

@ -1,123 +0,0 @@
/*
* Copyright 2013 serso aka se.solovyev
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* Contact details
*
* Email: se.solovyev@gmail.com
* Site: http://se.solovyev.org
*/
package org.solovyev.android.calculator.plot;
import javax.annotation.Nonnull;
/**
* User: serso
* Date: 1/18/13
* Time: 8:58 PM
*/
public class GraphCalculatorImpl extends AbstractGraphCalculator {
@Override
protected void compute(@Nonnull XyFunction f,
float xMin,
float xMax,
float yMin,
float yMax,
@Nonnull GraphData graph,
@Nonnull Graph2dDimensions dimensions) {
graph.push(xMin, (float) f.eval(xMin));
final float xScale = dimensions.getXGraphToViewScale();
final float yScale = dimensions.getYGraphToViewScale();
final float maxStep = 15.8976f * xScale;
final float minStep = .05f * xScale;
float yTheta = yScale;
yTheta = yTheta * yTheta;
float leftX;
float leftY;
float rightX = graph.getLastX();
float rightY = graph.getLastY();
while (true) {
leftX = rightX;
leftY = rightY;
if (leftX > xMax) {
break;
}
if (next.empty()) {
float x = leftX + maxStep;
next.push(x, (float) f.eval(x));
}
rightX = next.getLastX();
rightY = next.getLastY();
next.pop();
if (Float.isNaN(leftY) || Float.isNaN(rightY)) {
continue;
}
float dx = rightX - leftX;
float middleX = (leftX + rightX) / 2;
float middleY = (float) f.eval(middleX);
boolean middleIsOutside = (middleY < leftY && middleY < rightY) || (leftY < middleY && rightY < middleY);
if (dx < minStep) {
// Calculator.log("minStep");
if (middleIsOutside) {
graph.push(rightX, Float.NaN);
}
graph.push(rightX, rightY);
continue;
}
if (middleIsOutside && ((leftY < yMin && rightY > yMax) || (leftY > yMax && rightY < yMin))) {
graph.push(rightX, Float.NaN);
graph.push(rightX, rightY);
// Calculator.log("+-inf");
continue;
}
if (!middleIsOutside) {
if (distance2(leftX, leftY, rightX, rightY, middleY) < yTheta) {
graph.push(rightX, rightY);
continue;
}
}
next.push(rightX, rightY);
next.push(middleX, middleY);
rightX = leftX;
rightY = leftY;
}
}
// distance as above when x==(x1+x2)/2.
private float distance2(float x1, float y1, float x2, float y2, float y) {
final float dx = x2 - x1;
final float dy = y2 - y1;
final float up = dx * (y1 + y2 - y - y);
return up * up / (dx * dx + dy * dy);
}
}

View File

@ -1,187 +0,0 @@
/*
* Copyright 2013 serso aka se.solovyev
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* Contact details
*
* Email: se.solovyev@gmail.com
* Site: http://se.solovyev.org
*/
package org.solovyev.android.calculator.plot;
import javax.annotation.Nonnull;
class GraphData {
private int size = 0;
private int allocatedSize = 4;
private float[] xs = new float[allocatedSize];
private float[] ys = new float[allocatedSize];
private GraphData() {
}
@Nonnull
static GraphData newEmptyInstance() {
return new GraphData();
}
void swap(@Nonnull GraphData that) {
float savedXs[] = that.xs;
float savedYs[] = that.ys;
int savedSize = that.size;
int savedAllocatedSize = that.allocatedSize;
that.xs = this.xs;
that.ys = this.ys;
that.size = this.size;
that.allocatedSize = this.allocatedSize;
this.xs = savedXs;
this.ys = savedYs;
this.size = savedSize;
this.allocatedSize = savedAllocatedSize;
}
void push(float x, float y) {
if (size >= allocatedSize) {
makeSpaceAtTheEnd(size + 1);
}
xs[size] = x;
ys[size] = y;
++size;
}
private void makeSpaceAtTheEnd(int newSize) {
int oldAllocatedSize = allocatedSize;
while (newSize > allocatedSize) {
allocatedSize += allocatedSize;
}
if (oldAllocatedSize != allocatedSize) {
float[] a = new float[allocatedSize];
System.arraycopy(xs, 0, a, 0, this.size);
xs = a;
a = new float[allocatedSize];
System.arraycopy(ys, 0, a, 0, this.size);
ys = a;
}
}
float getLastX() {
return xs[size - 1];
}
float getLastY() {
return ys[size - 1];
}
float getFirstX() {
return xs[0];
}
float getFirstY() {
return ys[0];
}
void pop() {
--size;
}
boolean empty() {
return size == 0;
}
void clear() {
size = 0;
}
void eraseBefore(float x) {
int i = 0;
while (i < size && xs[i] < x) {
++i;
}
// step back as xs[i] >= x and xs[i-1] < x
--i;
if (i > 0) {
size -= i;
System.arraycopy(xs, i, xs, 0, size);
System.arraycopy(ys, i, ys, 0, size);
}
}
void eraseAfter(float x) {
int i = size - 1;
while (i >= 0 && x < xs[i]) {
--i;
}
// step next as xs[i] > x and xs[i+1] <= x
++i;
if (i < size - 1) {
size = i + 1;
}
}
int findPositionAfter(float x, float y) {
int i = 0;
while (i < size && xs[i] <= x) {
++i;
}
if (Float.isNaN(y)) {
while (i < size && Float.isNaN(ys[i])) {
++i;
}
}
return i;
}
void append(GraphData that) {
makeSpaceAtTheEnd(size + that.size);
int position = that.findPositionAfter(xs[size - 1], ys[size - 1]);
System.arraycopy(that.xs, position, xs, size, that.size - position);
System.arraycopy(that.ys, position, ys, size, that.size - position);
size += that.size - position;
}
public String toString() {
StringBuilder b = new StringBuilder();
b.append(size).append(": ");
for (int i = 0; i < size; ++i) {
b.append(xs[i]).append(", ");
}
return b.toString();
}
public float[] getXs() {
return xs;
}
public float[] getYs() {
return ys;
}
public int getSize() {
return size;
}
}

View File

@ -1,65 +0,0 @@
/*
* Copyright 2013 serso aka se.solovyev
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* Contact details
*
* Email: se.solovyev@gmail.com
* Site: http://se.solovyev.org
*/
package org.solovyev.android.calculator.plot;
import android.graphics.Bitmap;
import android.widget.ZoomButtonsController;
import java.util.List;
import javax.annotation.Nonnull;
public interface GraphView extends ZoomButtonsController.OnZoomListener, TouchHandler.TouchHandlerListener {
void init(@Nonnull PlotViewDef plotViewDef);
@Nonnull
List<PlotFunction> getPlotFunctions();
void setPlotFunctions(@Nonnull List<PlotFunction> plotFunctions);
void onDestroy();
void onPause();
void onResume();
@Nonnull
Bitmap captureScreenshot();
void setXRange(float xMin, float xMax);
void setYRange(float yMin, float yMax);
float getXMin();
float getXMax();
float getYMin();
float getYMax();
void invalidateGraphs();
void setAdjustYAxis(boolean adjustYAxis);
}

View File

@ -1,81 +0,0 @@
/*
* Copyright 2013 serso aka se.solovyev
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* Contact details
*
* Email: se.solovyev@gmail.com
* Site: http://se.solovyev.org
*/
package org.solovyev.android.calculator.plot;
import java.util.Collections;
import java.util.List;
import javax.annotation.Nonnull;
/**
* User: serso
* Date: 1/5/13
* Time: 8:06 PM
*/
public class GraphViewHelper {
@Nonnull
private PlotViewDef plotViewDef = PlotViewDef.newDefaultInstance();
@Nonnull
private List<PlotFunction> plotFunctions = Collections.emptyList();
private GraphViewHelper() {
}
@Nonnull
public static GraphViewHelper newDefaultInstance() {
return new GraphViewHelper();
}
@Nonnull
public static GraphViewHelper newInstance(@Nonnull PlotViewDef plotViewDef,
@Nonnull List<PlotFunction> plotFunctions) {
final GraphViewHelper result = new GraphViewHelper();
result.plotViewDef = plotViewDef;
result.plotFunctions = Collections.unmodifiableList(plotFunctions);
return result;
}
@Nonnull
public GraphViewHelper copy(@Nonnull List<PlotFunction> plotFunctions) {
final GraphViewHelper result = new GraphViewHelper();
result.plotViewDef = plotViewDef;
result.plotFunctions = Collections.unmodifiableList(plotFunctions);
return result;
}
@Nonnull
public List<PlotFunction> getPlotFunctions() {
return plotFunctions;
}
@Nonnull
public PlotViewDef getPlotViewDef() {
return plotViewDef;
}
}

View File

@ -1,110 +0,0 @@
/*
* Copyright 2013 serso aka se.solovyev
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* Contact details
*
* Email: se.solovyev@gmail.com
* Site: http://se.solovyev.org
*/
package org.solovyev.android.calculator.plot;
import java.util.ArrayList;
import java.util.List;
import javax.annotation.Nonnull;
/**
* User: serso
* Date: 1/18/13
* Time: 8:32 PM
*/
public class GraphsData {
@Nonnull
private final GraphView graphView;
@Nonnull
private List<GraphData> graphs;
private float lastXMin;
private float lastXMax;
private float lastYMin;
private float lastYMax;
public GraphsData(@Nonnull GraphView graphView) {
this.graphView = graphView;
graphs = new ArrayList<GraphData>(graphView.getPlotFunctions().size());
}
public void clear() {
for (GraphData graph : graphs) {
graph.clear();
}
while (graphView.getPlotFunctions().size() > graphs.size()) {
graphs.add(GraphData.newEmptyInstance());
}
lastYMin = 0;
lastYMax = 0;
}
@Nonnull
public List<GraphData> getGraphs() {
return graphs;
}
public float getLastXMin() {
return lastXMin;
}
public void setLastXMin(float lastXMin) {
this.lastXMin = lastXMin;
}
public float getLastXMax() {
return lastXMax;
}
public void setLastXMax(float lastXMax) {
this.lastXMax = lastXMax;
}
public float getLastYMin() {
return lastYMin;
}
public float getLastYMax() {
return lastYMax;
}
void checkBoundaries(float graphHeight, float yMin, float yMax) {
if (yMin < lastYMin || yMax > lastYMax) {
float halfGraphHeight = graphHeight / 2;
clear();
lastYMin = yMin - halfGraphHeight;
lastYMax = yMax + halfGraphHeight;
}
}
@Nonnull
public GraphData get(int i) {
return this.graphs.get(i);
}
}

View File

@ -1,140 +0,0 @@
/*
* Copyright 2013 serso aka se.solovyev
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* Contact details
*
* Email: se.solovyev@gmail.com
* Site: http://se.solovyev.org
*/
package org.solovyev.android.calculator.plot;
import com.google.common.base.Predicate;
import com.google.common.collect.Iterables;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
/**
* User: serso
* Date: 1/19/13
* Time: 12:48 AM
*/
public class MapPlotResourceManager implements PlotResourceManager {
@Nonnull
private final List<PlotLineDef> preparedLineDefs = new ArrayList<PlotLineDef>(PlotLineStyle.values().length * PlotLineColor.values().length);
@Nonnull
private Map<PlotLineDef, List<PlotLineDef>> registeredLineDefsMap = new HashMap<PlotLineDef, List<PlotLineDef>>();
public MapPlotResourceManager() {
for (PlotLineStyle plotLineStyle : PlotLineStyle.values()) {
for (PlotLineColor plotLineColor : PlotLineColor.values()) {
preparedLineDefs.add(PlotLineDef.newInstance(plotLineColor.getColor(), plotLineStyle));
}
}
}
@Nonnull
@Override
public PlotLineDef generateAndRegister() {
synchronized (this) {
for (PlotLineDef lineDef : preparedLineDefs) {
final List<PlotLineDef> registeredLineDefs = registeredLineDefsMap.get(lineDef);
if (registeredLineDefs == null || registeredLineDefs.isEmpty()) {
register(lineDef);
return lineDef;
}
}
return preparedLineDefs.get(0);
}
}
private void addLineDef(@Nonnull final PlotLineDef toBeAdded) {
if (!Thread.holdsLock(this)) throw new AssertionError();
List<PlotLineDef> registeredLineDefs = registeredLineDefsMap.get(toBeAdded);
if (registeredLineDefs == null) {
registeredLineDefs = new ArrayList<PlotLineDef>();
registeredLineDefsMap.put(toBeAdded, registeredLineDefs);
}
try {
Iterables.find(registeredLineDefs, new Predicate<PlotLineDef>() {
@Override
public boolean apply(@Nullable PlotLineDef lineDef) {
return lineDef == toBeAdded;
}
});
// already added
} catch (NoSuchElementException e) {
registeredLineDefs.add(toBeAdded);
}
}
private void removeLineDef(@Nonnull final PlotLineDef toBeRemoved) {
if (!Thread.holdsLock(this)) throw new AssertionError();
List<PlotLineDef> registeredLineDefs = registeredLineDefsMap.get(toBeRemoved);
if (registeredLineDefs != null) {
Iterables.removeIf(registeredLineDefs, new Predicate<PlotLineDef>() {
@Override
public boolean apply(@Nullable PlotLineDef lineDef) {
return lineDef == toBeRemoved;
}
});
if (registeredLineDefs.isEmpty()) {
registeredLineDefsMap.remove(toBeRemoved);
}
} else {
registeredLineDefsMap.remove(toBeRemoved);
}
}
@Override
public void register(@Nonnull PlotLineDef lineDef) {
synchronized (this) {
addLineDef(lineDef);
}
}
@Override
public void unregister(@Nonnull PlotLineDef lineDef) {
synchronized (this) {
removeLineDef(lineDef);
}
}
@Override
public void unregisterAll() {
synchronized (this) {
registeredLineDefsMap.clear();
}
}
}

View File

@ -1,124 +0,0 @@
/*
* Copyright 2013 serso aka se.solovyev
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* Contact details
*
* Email: se.solovyev@gmail.com
* Site: http://se.solovyev.org
*/
package org.solovyev.android.calculator.plot;
import java.io.Serializable;
import javax.annotation.Nonnull;
/**
* User: serso
* Date: 1/19/13
* Time: 4:51 PM
*/
public final class PlotBoundaries implements Serializable {
public static final float DEFAULT_MIN_NUMBER = -10f;
public static final float DEFAULT_MAX_NUMBER = 10f;
private float xMin;
private float xMax;
private float yMin;
private float yMax;
public PlotBoundaries() {
}
PlotBoundaries(float xMin, float xMax, float yMin, float yMax) {
this.xMin = Math.min(xMin, xMax);
this.xMax = Math.max(xMin, xMax);
this.yMin = Math.min(yMin, yMax);
this.yMax = Math.max(yMin, yMax);
}
@Nonnull
public static PlotBoundaries newInstance(float xMin, float xMax, float yMin, float yMax) {
return new PlotBoundaries(xMin, xMax, yMin, yMax);
}
@Nonnull
public static PlotBoundaries newInstance(float xMin, float xMax) {
return newInstance(xMin, xMax, DEFAULT_MIN_NUMBER, DEFAULT_MAX_NUMBER);
}
@Nonnull
public static PlotBoundaries newDefaultInstance() {
PlotBoundaries plotBoundaries = new PlotBoundaries();
plotBoundaries.xMin = DEFAULT_MIN_NUMBER;
plotBoundaries.yMin = DEFAULT_MIN_NUMBER;
plotBoundaries.xMax = DEFAULT_MAX_NUMBER;
plotBoundaries.yMax = DEFAULT_MAX_NUMBER;
return plotBoundaries;
}
public float getXMin() {
return xMin;
}
public float getXMax() {
return xMax;
}
public float getYMin() {
return yMin;
}
public float getYMax() {
return yMax;
}
@Override
public String toString() {
return "PlotBoundaries{" +
"yMax=" + yMax +
", yMin=" + yMin +
", xMax=" + xMax +
", xMin=" + xMin +
'}';
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof PlotBoundaries)) return false;
PlotBoundaries that = (PlotBoundaries) o;
if (Float.compare(that.xMax, xMax) != 0) return false;
if (Float.compare(that.xMin, xMin) != 0) return false;
if (Float.compare(that.yMax, yMax) != 0) return false;
return Float.compare(that.yMin, yMin) == 0;
}
@Override
public int hashCode() {
int result = (xMin != +0.0f ? Float.floatToIntBits(xMin) : 0);
result = 31 * result + (xMax != +0.0f ? Float.floatToIntBits(xMax) : 0);
result = 31 * result + (yMin != +0.0f ? Float.floatToIntBits(yMin) : 0);
result = 31 * result + (yMax != +0.0f ? Float.floatToIntBits(yMax) : 0);
return result;
}
}

View File

@ -1,73 +0,0 @@
/*
* Copyright 2013 serso aka se.solovyev
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* Contact details
*
* Email: se.solovyev@gmail.com
* Site: http://se.solovyev.org
*/
package org.solovyev.android.calculator.plot;
import java.util.List;
import javax.annotation.Nonnull;
/**
* User: serso
* Date: 1/12/13
* Time: 10:01 PM
*/
public class PlotData {
@Nonnull
private final List<PlotFunction> functions;
private final boolean plot3d;
private final boolean adjustYAxis;
@Nonnull
private final PlotBoundaries boundaries;
public PlotData(@Nonnull List<PlotFunction> functions,
boolean plot3d,
boolean adjustYAxis,
@Nonnull PlotBoundaries boundaries) {
this.functions = functions;
this.plot3d = plot3d;
this.adjustYAxis = adjustYAxis;
this.boundaries = boundaries;
}
@Nonnull
public List<PlotFunction> getFunctions() {
return functions;
}
public boolean isPlot3d() {
return plot3d;
}
@Nonnull
public PlotBoundaries getBoundaries() {
return boundaries;
}
public boolean isAdjustYAxis() {
return adjustYAxis;
}
}

View File

@ -1,139 +0,0 @@
/*
* Copyright 2013 serso aka se.solovyev
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* Contact details
*
* Email: se.solovyev@gmail.com
* Site: http://se.solovyev.org
*/
package org.solovyev.android.calculator.plot;
import javax.annotation.Nonnull;
/**
* User: serso
* Date: 1/12/13
* Time: 8:45 PM
*/
public class PlotFunction {
@Nonnull
private XyFunction xyFunction;
@Nonnull
private PlotLineDef plotLineDef;
private boolean pinned = false;
private boolean visible = true;
public PlotFunction(@Nonnull XyFunction xyFunction) {
this.xyFunction = xyFunction;
this.plotLineDef = PlotLineDef.newDefaultInstance();
}
public PlotFunction(@Nonnull XyFunction xyFunction,
@Nonnull PlotLineDef plotLineDef) {
this.xyFunction = xyFunction;
this.plotLineDef = plotLineDef;
}
@Nonnull
public static PlotFunction changePlotLineDef(@Nonnull PlotFunction that, @Nonnull PlotLineDef newPlotLineDef) {
final PlotFunction copy = that.copy();
copy.plotLineDef = newPlotLineDef;
return copy;
}
@Nonnull
public static PlotFunction pin(@Nonnull PlotFunction that) {
return togglePinned(that, true);
}
@Nonnull
public static PlotFunction togglePinned(@Nonnull PlotFunction that, boolean pinned) {
final PlotFunction copy = that.copy();
copy.pinned = pinned;
return copy;
}
@Nonnull
public static PlotFunction unpin(@Nonnull PlotFunction that) {
return togglePinned(that, false);
}
@Nonnull
public static PlotFunction visible(@Nonnull PlotFunction that) {
return toggleVisible(that, true);
}
@Nonnull
public static PlotFunction toggleVisible(@Nonnull PlotFunction that, boolean visible) {
final PlotFunction copy = that.copy();
copy.visible = visible;
return copy;
}
@Nonnull
public static PlotFunction invisible(@Nonnull PlotFunction that) {
return toggleVisible(that, false);
}
@Nonnull
private PlotFunction copy() {
final PlotFunction copy = new PlotFunction(this.xyFunction, this.plotLineDef);
copy.pinned = this.pinned;
copy.visible = this.visible;
return copy;
}
@Nonnull
public XyFunction getXyFunction() {
return xyFunction;
}
@Nonnull
public PlotLineDef getPlotLineDef() {
return plotLineDef;
}
public boolean isPinned() {
return pinned;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof PlotFunction)) return false;
PlotFunction that = (PlotFunction) o;
return xyFunction.equals(that.xyFunction);
}
@Override
public int hashCode() {
return xyFunction.hashCode();
}
public boolean isVisible() {
return visible;
}
}

View File

@ -1,68 +0,0 @@
/*
* Copyright 2013 serso aka se.solovyev
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* Contact details
*
* Email: se.solovyev@gmail.com
* Site: http://se.solovyev.org
*/
package org.solovyev.android.calculator.plot;
import javax.annotation.Nonnull;
/**
* User: serso
* Date: 10/4/12
* Time: 10:08 PM
*/
public enum PlotLineColor {
// Color.WHITE
white(0xFFBBBBBB),
blue(0xFF10648C),
// Color.RED
red(0xFFFF0000),
// Color.GREEN
green(0xFF00FF00),
// Color.GRAY
grey(0xFF888888);
private final int color;
PlotLineColor(int color) {
this.color = color;
}
@Nonnull
public static PlotLineColor valueOf(int color) {
for (PlotLineColor plotLineColor : PlotLineColor.values()) {
if (plotLineColor.color == color) {
return plotLineColor;
}
}
return PlotLineColor.white;
}
public int getColor() {
return this.color;
}
}

View File

@ -1,34 +0,0 @@
/*
* Copyright 2013 serso aka se.solovyev
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* Contact details
*
* Email: se.solovyev@gmail.com
* Site: http://se.solovyev.org
*/
package org.solovyev.android.calculator.plot;
/**
* User: serso
* Date: 1/5/13
* Time: 10:45 PM
*/
public enum PlotLineColorType {
monochrome,
color_map
}

View File

@ -1,186 +0,0 @@
/*
* Copyright 2013 serso aka se.solovyev
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* Contact details
*
* Email: se.solovyev@gmail.com
* Site: http://se.solovyev.org
*/
package org.solovyev.android.calculator.plot;
import javax.annotation.Nonnull;
/**
* User: serso
* Date: 1/5/13
* Time: 7:41 PM
*/
public class PlotLineDef {
/*
**********************************************************************
*
* CONSTANTS
*
**********************************************************************
*/
@Nonnull
private static final Float DEFAULT_LINE_WIDTH = 2f;
private static final int WHITE = 0xFFFFFFFF;
/*
**********************************************************************
*
* FIELDS
*
**********************************************************************
*/
@Nonnull
private PlotLineColorType lineColorType = PlotLineColorType.monochrome;
private int lineColor = WHITE;
@Nonnull
private PlotLineStyle lineStyle = PlotLineStyle.solid;
private float lineWidth = DEFAULT_LINE_WIDTH;
private PlotLineDef() {
}
@Nonnull
public static PlotLineDef newInstance(int lineColor, @Nonnull PlotLineStyle lineStyle) {
final PlotLineDef result = new PlotLineDef();
result.lineColor = lineColor;
result.lineStyle = lineStyle;
return result;
}
@Nonnull
public static PlotLineDef newInstance(int lineColor, @Nonnull PlotLineStyle lineStyle, float lineWidth) {
final PlotLineDef result = new PlotLineDef();
result.lineColor = lineColor;
result.lineStyle = lineStyle;
result.lineWidth = lineWidth;
return result;
}
@Nonnull
public static PlotLineDef newInstance(int lineColor, @Nonnull PlotLineStyle lineStyle, float lineWidth, @Nonnull PlotLineColorType lineColorType) {
final PlotLineDef result = new PlotLineDef();
result.lineColor = lineColor;
result.lineColorType = lineColorType;
result.lineStyle = lineStyle;
result.lineWidth = lineWidth;
return result;
}
@Nonnull
public static PlotLineDef changeLineColor(@Nonnull PlotLineDef plotLineDef, int newLineColor) {
final PlotLineDef result = plotLineDef.copy();
result.lineColor = newLineColor;
return result;
}
@Nonnull
public static PlotLineDef changeLineWidth(@Nonnull PlotLineDef plotLineDef, int newLineWidth) {
final PlotLineDef result = plotLineDef.copy();
result.lineWidth = newLineWidth;
return result;
}
@Nonnull
public static PlotLineDef changeLineColorType(@Nonnull PlotLineDef plotLineDef, @Nonnull PlotLineColorType newPlotLineColorType) {
final PlotLineDef result = plotLineDef.copy();
result.lineColorType = newPlotLineColorType;
return result;
}
@Nonnull
public static PlotLineDef changeLineStyle(@Nonnull PlotLineDef plotLineDef, @Nonnull PlotLineStyle newPlotLineStyle) {
final PlotLineDef result = plotLineDef.copy();
result.lineStyle = newPlotLineStyle;
return result;
}
@Nonnull
public static PlotLineDef changeColor(@Nonnull PlotLineDef plotLineDef, int newLineColor) {
final PlotLineDef result = plotLineDef.copy();
result.lineColor = newLineColor;
return result;
}
@Nonnull
public static PlotLineDef newDefaultInstance() {
return new PlotLineDef();
}
@Nonnull
private PlotLineDef copy() {
final PlotLineDef copy = new PlotLineDef();
copy.lineColor = lineColor;
copy.lineColorType = lineColorType;
copy.lineStyle = lineStyle;
copy.lineWidth = lineWidth;
return copy;
}
public int getLineColor() {
return lineColor;
}
@Nonnull
public PlotLineStyle getLineStyle() {
return lineStyle;
}
public float getLineWidth() {
return lineWidth;
}
@Nonnull
public PlotLineColorType getLineColorType() {
return lineColorType;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof PlotLineDef)) return false;
PlotLineDef that = (PlotLineDef) o;
if (lineColor != that.lineColor) return false;
if (Float.compare(that.lineWidth, lineWidth) != 0) return false;
if (lineColorType != that.lineColorType) return false;
return lineStyle == that.lineStyle;
}
@Override
public int hashCode() {
int result = lineColorType.hashCode();
result = 31 * result + lineColor;
result = 31 * result + lineStyle.hashCode();
result = 31 * result + (lineWidth != +0.0f ? Float.floatToIntBits(lineWidth) : 0);
return result;
}
}

View File

@ -1,38 +0,0 @@
/*
* Copyright 2013 serso aka se.solovyev
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* Contact details
*
* Email: se.solovyev@gmail.com
* Site: http://se.solovyev.org
*/
package org.solovyev.android.calculator.plot;
/**
* User: serso
* Date: 1/5/13
* Time: 7:37 PM
*/
public enum PlotLineStyle {
solid,
dashed,
dotted,
dash_dotted
}

View File

@ -1,42 +0,0 @@
/*
* Copyright 2013 serso aka se.solovyev
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* Contact details
*
* Email: se.solovyev@gmail.com
* Site: http://se.solovyev.org
*/
package org.solovyev.android.calculator.plot;
import javax.annotation.Nonnull;
/**
* User: serso
* Date: 1/13/13
* Time: 8:19 PM
*/
interface PlotResourceManager {
@Nonnull
PlotLineDef generateAndRegister();
void register(@Nonnull PlotLineDef lineDef);
void unregister(@Nonnull PlotLineDef lineDef);
void unregisterAll();
}

View File

@ -1,101 +0,0 @@
/*
* Copyright 2013 serso aka se.solovyev
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* Contact details
*
* Email: se.solovyev@gmail.com
* Site: http://se.solovyev.org
*/
package org.solovyev.android.calculator.plot;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
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;
/**
* User: serso
* Date: 12/5/11
* Time: 8:58 PM
*/
public final class PlotUtils {
private static final Complex NaN = Complex.valueOf(Double.NaN, 0d);
// not intended for instantiation
private PlotUtils() {
throw new AssertionError();
}
@Nonnull
public static Complex calculatorExpression(@Nonnull Generic expression) {
try {
return unwrap(expression.numeric());
} catch (RuntimeException e) {
return NaN;
}
}
@Nonnull
public static Complex calculatorExpression(@Nonnull Generic expression, @Nonnull Constant xVar, double x) {
try {
return unwrap(expression.substitute(xVar, Expression.valueOf(x)).numeric());
} catch (RuntimeException e) {
return NaN;
}
}
@Nonnull
public static Complex calculatorExpression(@Nonnull Generic expression, @Nonnull Constant xVar, double x, @Nonnull Constant yVar, double y) {
try {
Generic tmp = expression.substitute(xVar, Expression.valueOf(x));
tmp = tmp.substitute(yVar, Expression.valueOf(y));
return unwrap(tmp.numeric());
} catch (RuntimeException e) {
return NaN;
}
}
@Nonnull
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 {
return NaN;
}
}
@Nonnull
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();
}
}
}

View File

@ -1,99 +0,0 @@
/*
* Copyright 2013 serso aka se.solovyev
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* Contact details
*
* Email: se.solovyev@gmail.com
* Site: http://se.solovyev.org
*/
package org.solovyev.android.calculator.plot;
import android.graphics.Color;
import javax.annotation.Nonnull;
/**
* User: serso
* Date: 1/5/13
* Time: 9:11 PM
*/
public class PlotViewDef {
/*
**********************************************************************
*
* CONSTANTS
*
**********************************************************************
*/
private static final int DEFAULT_AXIS_COLOR = 0xff00a000;
private static final int DEFAULT_GRID_COLOR = 0xff004000;
private static final int DEFAULT_BACKGROUND_COLOR = Color.BLACK;
/*
**********************************************************************
*
* FIELDS
*
**********************************************************************
*/
private int axisColor = DEFAULT_AXIS_COLOR;
private int axisLabelsColor = DEFAULT_AXIS_COLOR;
private int gridColor = DEFAULT_GRID_COLOR;
private int backgroundColor = DEFAULT_BACKGROUND_COLOR;
private PlotViewDef() {
}
private PlotViewDef(int axisColor, int axisLabelColor, int gridColor, int backgroundColor) {
this.axisColor = axisColor;
this.axisLabelsColor = axisLabelColor;
this.gridColor = gridColor;
this.backgroundColor = backgroundColor;
}
@Nonnull
public static PlotViewDef newDefaultInstance() {
return new PlotViewDef();
}
@Nonnull
public static PlotViewDef newInstance(int axisColor, int axisLabelColor, int gridColor, int backgroundColor) {
return new PlotViewDef(axisColor, axisLabelColor, gridColor, backgroundColor);
}
public int getAxisColor() {
return axisColor;
}
public int getAxisLabelsColor() {
return axisLabelsColor;
}
public int getGridColor() {
return gridColor;
}
public int getBackgroundColor() {
return backgroundColor;
}
}

View File

@ -1,143 +0,0 @@
/*
* Copyright 2013 serso aka se.solovyev
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* Contact details
*
* Email: se.solovyev@gmail.com
* Site: http://se.solovyev.org
*/
package org.solovyev.android.calculator.plot;
import javax.microedition.khronos.opengles.GL10;
public class SpriteBatch {
//--Constants--//
final static int VERTEX_SIZE = 4; // Vertex Size (in Components) ie. (X,Y,U,V)
final static int VERTICES_PER_SPRITE = 4; // Vertices Per Sprite
final static int INDICES_PER_SPRITE = 6; // Indices Per Sprite
//--Members--//
GL10 gl; // GL Instance
Vertices vertices; // Vertices Instance Used for Rendering
float[] vertexBuffer; // Vertex Buffer
int bufferIndex; // Vertex Buffer Start Index
int maxSprites; // Maximum Sprites Allowed in Buffer
int numSprites; // Number of Sprites Currently in Buffer
//--Constructor--//
// D: prepare the sprite batcher for specified maximum number of sprites
// A: gl - the gl instance to use for rendering
// maxSprites - the maximum allowed sprites per batch
public SpriteBatch(GL10 gl, int maxSprites) {
this.gl = gl; // Save GL Instance
this.vertexBuffer = new float[maxSprites * VERTICES_PER_SPRITE * VERTEX_SIZE]; // Create Vertex Buffer
this.vertices = new Vertices(gl, maxSprites * VERTICES_PER_SPRITE, maxSprites * INDICES_PER_SPRITE, false, true, false); // Create Rendering Vertices
this.bufferIndex = 0; // Reset Buffer Index
this.maxSprites = maxSprites; // Save Maximum Sprites
this.numSprites = 0; // Clear Sprite Counter
short[] indices = new short[maxSprites * INDICES_PER_SPRITE]; // Create Temp Index Buffer
int len = indices.length; // Get Index Buffer Length
short j = 0; // Counter
for (int i = 0; i < len; i += INDICES_PER_SPRITE, j += VERTICES_PER_SPRITE) { // FOR Each Index Set (Per Sprite)
indices[i + 0] = (short) (j + 0); // Calculate Index 0
indices[i + 1] = (short) (j + 1); // Calculate Index 1
indices[i + 2] = (short) (j + 2); // Calculate Index 2
indices[i + 3] = (short) (j + 2); // Calculate Index 3
indices[i + 4] = (short) (j + 3); // Calculate Index 4
indices[i + 5] = (short) (j + 0); // Calculate Index 5
}
vertices.setIndices(indices, 0, len); // Set Index Buffer for Rendering
}
//--Begin Batch--//
// D: signal the start of a batch. set the texture and clear buffer
// NOTE: the overloaded (non-texture) version assumes that the texture is already bound!
// A: textureId - the ID of the texture to use for the batch
// R: [none]
public void beginBatch(int textureId) {
gl.glBindTexture(GL10.GL_TEXTURE_2D, textureId); // Bind the Texture
numSprites = 0; // Empty Sprite Counter
bufferIndex = 0; // Reset Buffer Index (Empty)
}
public void beginBatch() {
numSprites = 0; // Empty Sprite Counter
bufferIndex = 0; // Reset Buffer Index (Empty)
}
//--End Batch--//
// D: signal the end of a batch. render the batched sprites
// A: [none]
// R: [none]
public void endBatch() {
if (numSprites > 0) { // IF Any Sprites to Render
vertices.setVertices(vertexBuffer, 0, bufferIndex); // Set Vertices from Buffer
vertices.bind(); // Bind Vertices
vertices.draw(GL10.GL_TRIANGLES, 0, numSprites * INDICES_PER_SPRITE); // Render Batched Sprites
vertices.unbind(); // Unbind Vertices
}
}
//--Draw Sprite to Batch--//
// D: batch specified sprite to batch. adds vertices for sprite to vertex buffer
// NOTE: MUST be called after beginBatch(), and before endBatch()!
// NOTE: if the batch overflows, this will render the current batch, restart it,
// and then batch this sprite.
// A: x, y - the x,y position of the sprite (center)
// width, height - the width and height of the sprite
// region - the texture region to use for sprite
// R: [none]
public void drawSprite(float x, float y, float width, float height, TextureRegion region) {
if (numSprites == maxSprites) { // IF Sprite Buffer is Full
endBatch(); // End Batch
// NOTE: leave current texture bound!!
numSprites = 0; // Empty Sprite Counter
bufferIndex = 0; // Reset Buffer Index (Empty)
}
float halfWidth = width / 2.0f; // Calculate Half Width
float halfHeight = height / 2.0f; // Calculate Half Height
float x1 = x - halfWidth; // Calculate Left X
float y1 = y - halfHeight; // Calculate Bottom Y
float x2 = x + halfWidth; // Calculate Right X
float y2 = y + halfHeight; // Calculate Top Y
vertexBuffer[bufferIndex++] = x1; // Add X for Vertex 0
vertexBuffer[bufferIndex++] = y1; // Add Y for Vertex 0
vertexBuffer[bufferIndex++] = region.u1; // Add U for Vertex 0
vertexBuffer[bufferIndex++] = region.v2; // Add V for Vertex 0
vertexBuffer[bufferIndex++] = x2; // Add X for Vertex 1
vertexBuffer[bufferIndex++] = y1; // Add Y for Vertex 1
vertexBuffer[bufferIndex++] = region.u2; // Add U for Vertex 1
vertexBuffer[bufferIndex++] = region.v2; // Add V for Vertex 1
vertexBuffer[bufferIndex++] = x2; // Add X for Vertex 2
vertexBuffer[bufferIndex++] = y2; // Add Y for Vertex 2
vertexBuffer[bufferIndex++] = region.u2; // Add U for Vertex 2
vertexBuffer[bufferIndex++] = region.v1; // Add V for Vertex 2
vertexBuffer[bufferIndex++] = x1; // Add X for Vertex 3
vertexBuffer[bufferIndex++] = y2; // Add Y for Vertex 3
vertexBuffer[bufferIndex++] = region.u1; // Add U for Vertex 3
vertexBuffer[bufferIndex++] = region.v1; // Add V for Vertex 3
numSprites++; // Increment Sprite Count
}
}

View File

@ -1,111 +0,0 @@
/*
* Copyright 2013 serso aka se.solovyev
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* Contact details
*
* Email: se.solovyev@gmail.com
* Site: http://se.solovyev.org
*/
// This is based on the OpenGL ES 1.0 sample application from the Android Developer website:
// http://developer.android.com/resources/tutorials/opengl/opengl-es10.html
package org.solovyev.android.calculator.plot;
import android.content.Context;
import android.opengl.GLSurfaceView;
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;
public class TexampleRenderer implements GLSurfaceView.Renderer {
private GLText glText; // A GLText Instance
private Context context; // Context (from Activity)
private int width = 100; // Updated to the Current Width + Height in onSurfaceChanged()
private int height = 100;
public TexampleRenderer(Context context) {
super();
this.context = context; // Save Specified Context
}
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
// Set the background frame color
gl.glClearColor(0.5f, 0.5f, 0.5f, 1.0f);
// Create the GLText
glText = new GLText(gl, context.getAssets());
// Load the font from file (set size + padding), creates the texture
// NOTE: after a successful call to this the font is ready for rendering!
glText.load("Roboto-Regular.ttf", 14, 2, 2); // Create Font (Height: 14 Pixels / X+Y Padding 2 Pixels)
}
public void onDrawFrame(GL10 gl) {
// Redraw background color
gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
// Set to ModelView mode
gl.glMatrixMode(GL10.GL_MODELVIEW); // Activate Model View Matrix
gl.glLoadIdentity(); // Load Identity Matrix
// enable texture + alpha blending
// NOTE: this is required for text rendering! we could incorporate it into
// the GLText class, but then it would be called multiple times (which impacts performance).
gl.glEnable(GL10.GL_TEXTURE_2D); // Enable Texture Mapping
gl.glEnable(GL10.GL_BLEND); // Enable Alpha Blend
gl.glBlendFunc(GL10.GL_SRC_ALPHA, GL10.GL_ONE_MINUS_SRC_ALPHA); // Set Alpha Blend Function
// TEST: render the entire font texture
gl.glColor4f(1.0f, 1.0f, 1.0f, 1.0f); // Set Color to Use
glText.drawTexture(width, height); // Draw the Entire Texture
// TEST: render some strings with the font
glText.begin(1.0f, 1.0f, 1.0f, 1.0f); // Begin Text Rendering (Set Color WHITE)
glText.draw("Test String :)", 0, 0); // Draw Test String
glText.draw("Line 1", 50, 50); // Draw Test String
glText.draw("Line 2", 100, 100); // Draw Test String
glText.end(); // End Text Rendering
glText.begin(0.0f, 0.0f, 1.0f, 1.0f); // Begin Text Rendering (Set Color BLUE)
glText.draw("More Lines...", 50, 150); // Draw Test String
glText.draw("The End.", 50, 150 + glText.getCharHeight()); // Draw Test String
glText.end(); // End Text Rendering
// disable texture + alpha
gl.glDisable(GL10.GL_BLEND); // Disable Alpha Blend
gl.glDisable(GL10.GL_TEXTURE_2D); // Disable Texture Mapping
}
public void onSurfaceChanged(GL10 gl, int width, int height) {
gl.glViewport(0, 0, width, height);
// Setup orthographic projection
gl.glMatrixMode(GL10.GL_PROJECTION); // Activate Projection Matrix
gl.glLoadIdentity(); // Load Identity Matrix
gl.glOrthof( // Set Ortho Projection (Left,Right,Bottom,Top,Front,Back)
0, width,
0, height,
1.0f, -1.0f
);
// Save width and height
this.width = width; // Save Current Width
this.height = height; // Save Current Height
}
}

View File

@ -1,42 +0,0 @@
/*
* Copyright 2013 serso aka se.solovyev
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* Contact details
*
* Email: se.solovyev@gmail.com
* Site: http://se.solovyev.org
*/
package org.solovyev.android.calculator.plot;
class TextureRegion {
//--Members--//
public float u1, v1; // Top/Left U,V Coordinates
public float u2, v2; // Bottom/Right U,V Coordinates
//--Constructor--//
// D: calculate U,V coordinates from specified texture coordinates
// A: texWidth, texHeight - the width and height of the texture the region is for
// x, y - the top/left (x,y) of the region on the texture (in pixels)
// width, height - the width and height of the region on the texture (in pixels)
public TextureRegion(float texWidth, float texHeight, float x, float y, float width, float height) {
this.u1 = x / texWidth; // Calculate U1
this.v1 = y / texHeight; // Calculate V1
this.u2 = this.u1 + (width / texWidth); // Calculate U2
this.v2 = this.v1 + (height / texHeight); // Calculate V2
}
}

View File

@ -1,118 +0,0 @@
/*
* Copyright 2013 serso aka se.solovyev
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* Contact details
*
* Email: se.solovyev@gmail.com
* Site: http://se.solovyev.org
*/
package org.solovyev.android.calculator.plot;
import android.view.MotionEvent;
import android.view.VelocityTracker;
import org.solovyev.android.Views;
import javax.annotation.Nonnull;
class TouchHandler {
@Nonnull
private final VelocityTracker velocityTracker = VelocityTracker.obtain();
private boolean afterZoom;
@Nonnull
private TouchHandlerListener listener;
TouchHandler(@Nonnull TouchHandlerListener listener) {
this.listener = listener;
}
public boolean handleTouchEvent(@Nonnull MotionEvent event) {
// Calculator.log("touch " + event + ' ' + event.getPointerCount() + event.getPointerId(0));
final int fullAction = event.getAction();
final int action = fullAction & MotionEvent.ACTION_MASK;
final int pointer = (fullAction & MotionEvent.ACTION_POINTER_ID_MASK) >> MotionEvent.ACTION_POINTER_ID_SHIFT;
float x = event.getX();
float y = event.getY();
int pointerCount = Views.getPointerCountFromMotionEvent(event);
switch (action) {
case MotionEvent.ACTION_DOWN:
afterZoom = false;
velocityTracker.clear();
velocityTracker.addMovement(event);
listener.onTouchDown(x, y);
break;
case MotionEvent.ACTION_MOVE:
if (pointerCount == 1) {
if (afterZoom) {
velocityTracker.clear();
listener.onTouchDown(x, y);
afterZoom = false;
}
velocityTracker.addMovement(event);
listener.onTouchMove(x, y);
} else if (pointerCount == 2) {
listener.onTouchZoomMove(x, y, Views.getXFromMotionEvent(event, 1), Views.getYFromMotionEvent(event, 1));
}
break;
case MotionEvent.ACTION_UP:
velocityTracker.addMovement(event);
velocityTracker.computeCurrentVelocity(1000);
listener.onTouchUp(x, y);
break;
case MotionEvent.ACTION_POINTER_DOWN:
if (pointerCount == 2) {
listener.onTouchZoomDown(x, y, Views.getXFromMotionEvent(event, 1), Views.getYFromMotionEvent(event, 1));
}
break;
case MotionEvent.ACTION_POINTER_UP:
if (pointerCount == 2) {
afterZoom = true;
}
break;
}
return true;
}
public float getXVelocity() {
return velocityTracker.getXVelocity();
}
public float getYVelocity() {
return velocityTracker.getYVelocity();
}
interface TouchHandlerListener {
void onTouchDown(float x, float y);
void onTouchMove(float x, float y);
void onTouchUp(float x, float y);
void onTouchZoomDown(float x1, float y1, float x2, float y2);
void onTouchZoomMove(float x1, float y1, float x2, float y2);
}
}

View File

@ -1,282 +0,0 @@
/*
* Copyright 2013 serso aka se.solovyev
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* Contact details
*
* Email: se.solovyev@gmail.com
* Site: http://se.solovyev.org
*/
package org.solovyev.android.calculator.plot;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.IntBuffer;
import java.nio.ShortBuffer;
import javax.microedition.khronos.opengles.GL10;
public class Vertices {
//--Constants--//
final static int POSITION_CNT_2D = 2; // Number of Components in Vertex Position for 2D
final static int POSITION_CNT_3D = 3; // Number of Components in Vertex Position for 3D
final static int COLOR_CNT = 4; // Number of Components in Vertex Color
final static int TEXCOORD_CNT = 2; // Number of Components in Vertex Texture Coords
final static int NORMAL_CNT = 3; // Number of Components in Vertex Normal
final static int INDEX_SIZE = Short.SIZE / 8; // Index Byte Size (Short.SIZE = bits)
public final int positionCnt; // Number of Position Components (2=2D, 3=3D)
public final int vertexStride; // Vertex Stride (Element Size of a Single Vertex)
public final int vertexSize; // Bytesize of a Single Vertex
//--Members--//
// NOTE: all members are constant, and initialized in constructor!
final GL10 gl; // GL Instance
final boolean hasColor; // Use Color in Vertices
final boolean hasTexCoords; // Use Texture Coords in Vertices
final boolean hasNormals; // Use Normals in Vertices
final IntBuffer vertices; // Vertex Buffer
final ShortBuffer indices; // Index Buffer
final int[] tmpBuffer; // Temp Buffer for Vertex Conversion
public int numVertices; // Number of Vertices in Buffer
public int numIndices; // Number of Indices in Buffer
//--Constructor--//
// D: create the vertices/indices as specified (for 2d/3d)
// A: gl - the gl instance to use
// maxVertices - maximum vertices allowed in buffer
// maxIndices - maximum indices allowed in buffer
// hasColor - use color values in vertices
// hasTexCoords - use texture coordinates in vertices
// hasNormals - use normals in vertices
// use3D - (false, default) use 2d positions (ie. x/y only)
// (true) use 3d positions (ie. x/y/z)
public Vertices(GL10 gl, int maxVertices, int maxIndices, boolean hasColor, boolean hasTexCoords, boolean hasNormals) {
this(gl, maxVertices, maxIndices, hasColor, hasTexCoords, hasNormals, false); // Call Overloaded Constructor
}
public Vertices(GL10 gl, int maxVertices, int maxIndices, boolean hasColor, boolean hasTexCoords, boolean hasNormals, boolean use3D) {
this.gl = gl; // Save GL Instance
this.hasColor = hasColor; // Save Color Flag
this.hasTexCoords = hasTexCoords; // Save Texture Coords Flag
this.hasNormals = hasNormals; // Save Normals Flag
this.positionCnt = use3D ? POSITION_CNT_3D : POSITION_CNT_2D; // Set Position Component Count
this.vertexStride = this.positionCnt + (hasColor ? COLOR_CNT : 0) + (hasTexCoords ? TEXCOORD_CNT : 0) + (hasNormals ? NORMAL_CNT : 0); // Calculate Vertex Stride
this.vertexSize = this.vertexStride * 4; // Calculate Vertex Byte Size
ByteBuffer buffer = ByteBuffer.allocateDirect(maxVertices * vertexSize); // Allocate Buffer for Vertices (Max)
buffer.order(ByteOrder.nativeOrder()); // Set Native Byte Order
this.vertices = buffer.asIntBuffer(); // Save Vertex Buffer
if (maxIndices > 0) { // IF Indices Required
buffer = ByteBuffer.allocateDirect(maxIndices * INDEX_SIZE); // Allocate Buffer for Indices (MAX)
buffer.order(ByteOrder.nativeOrder()); // Set Native Byte Order
this.indices = buffer.asShortBuffer(); // Save Index Buffer
} else // ELSE Indices Not Required
indices = null; // No Index Buffer
numVertices = 0; // Zero Vertices in Buffer
numIndices = 0; // Zero Indices in Buffer
this.tmpBuffer = new int[maxVertices * vertexSize / 4]; // Create Temp Buffer
}
//--Set Vertices--//
// D: set the specified vertices in the vertex buffer
// NOTE: optimized to use integer buffer!
// A: vertices - array of vertices (floats) to set
// offset - offset to first vertex in array
// length - number of floats in the vertex array (total)
// for easy setting use: vtx_cnt * (this.vertexSize / 4)
// R: [none]
public void setVertices(float[] vertices, int offset, int length) {
this.vertices.clear(); // Remove Existing Vertices
int last = offset + length; // Calculate Last Element
for (int i = offset, j = 0; i < last; i++, j++) // FOR Each Specified Vertex
tmpBuffer[j] = Float.floatToRawIntBits(vertices[i]); // Set Vertex as Raw Integer Bits in Buffer
this.vertices.put(tmpBuffer, 0, length); // Set New Vertices
this.vertices.flip(); // Flip Vertex Buffer
this.numVertices = length / this.vertexStride; // Save Number of Vertices
//this.numVertices = length / ( this.vertexSize / 4 ); // Save Number of Vertices
}
//--Set Indices--//
// D: set the specified indices in the index buffer
// A: indices - array of indices (shorts) to set
// offset - offset to first index in array
// length - number of indices in array (from offset)
// R: [none]
public void setIndices(short[] indices, int offset, int length) {
this.indices.clear(); // Clear Existing Indices
this.indices.put(indices, offset, length); // Set New Indices
this.indices.flip(); // Flip Index Buffer
this.numIndices = length; // Save Number of Indices
}
//--Bind--//
// D: perform all required binding/state changes before rendering batches.
// USAGE: call once before calling draw() multiple times for this buffer.
// A: [none]
// R: [none]
public void bind() {
gl.glEnableClientState(GL10.GL_VERTEX_ARRAY); // Enable Position in Vertices
vertices.position(0); // Set Vertex Buffer to Position
gl.glVertexPointer(positionCnt, GL10.GL_FLOAT, vertexSize, vertices); // Set Vertex Pointer
if (hasColor) { // IF Vertices Have Color
gl.glEnableClientState(GL10.GL_COLOR_ARRAY); // Enable Color in Vertices
vertices.position(positionCnt); // Set Vertex Buffer to Color
gl.glColorPointer(COLOR_CNT, GL10.GL_FLOAT, vertexSize, vertices); // Set Color Pointer
}
if (hasTexCoords) { // IF Vertices Have Texture Coords
gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY); // Enable Texture Coords in Vertices
vertices.position(positionCnt + (hasColor ? COLOR_CNT : 0)); // Set Vertex Buffer to Texture Coords (NOTE: position based on whether color is also specified)
gl.glTexCoordPointer(TEXCOORD_CNT, GL10.GL_FLOAT, vertexSize, vertices); // Set Texture Coords Pointer
}
if (hasNormals) {
gl.glEnableClientState(GL10.GL_NORMAL_ARRAY); // Enable Normals in Vertices
vertices.position(positionCnt + (hasColor ? COLOR_CNT : 0) + (hasTexCoords ? TEXCOORD_CNT : 0)); // Set Vertex Buffer to Normals (NOTE: position based on whether color/texcoords is also specified)
gl.glNormalPointer(GL10.GL_FLOAT, vertexSize, vertices); // Set Normals Pointer
}
}
//--Draw--//
// D: draw the currently bound vertices in the vertex/index buffers
// USAGE: can only be called after calling bind() for this buffer.
// A: primitiveType - the type of primitive to draw
// offset - the offset in the vertex/index buffer to start at
// numVertices - the number of vertices (indices) to draw
// R: [none]
public void draw(int primitiveType, int offset, int numVertices) {
if (indices != null) { // IF Indices Exist
indices.position(offset); // Set Index Buffer to Specified Offset
gl.glDrawElements(primitiveType, numVertices, GL10.GL_UNSIGNED_SHORT, indices); // Draw Indexed
} else { // ELSE No Indices Exist
gl.glDrawArrays(primitiveType, offset, numVertices); // Draw Direct (Array)
}
}
//--Unbind--//
// D: clear binding states when done rendering batches.
// USAGE: call once before calling draw() multiple times for this buffer.
// A: [none]
// R: [none]
public void unbind() {
if (hasColor) // IF Vertices Have Color
gl.glDisableClientState(GL10.GL_COLOR_ARRAY); // Clear Color State
if (hasTexCoords) // IF Vertices Have Texture Coords
gl.glDisableClientState(GL10.GL_TEXTURE_COORD_ARRAY); // Clear Texture Coords State
if (hasNormals) // IF Vertices Have Normals
gl.glDisableClientState(GL10.GL_NORMAL_ARRAY); // Clear Normals State
}
//--Draw Full--//
// D: draw the vertices in the vertex/index buffers
// NOTE: unoptimized version! use bind()/draw()/unbind() for batches
// A: primitiveType - the type of primitive to draw
// offset - the offset in the vertex/index buffer to start at
// numVertices - the number of vertices (indices) to draw
// R: [none]
public void drawFull(int primitiveType, int offset, int numVertices) {
gl.glEnableClientState(GL10.GL_VERTEX_ARRAY); // Enable Position in Vertices
vertices.position(0); // Set Vertex Buffer to Position
gl.glVertexPointer(positionCnt, GL10.GL_FLOAT, vertexSize, vertices); // Set Vertex Pointer
if (hasColor) { // IF Vertices Have Color
gl.glEnableClientState(GL10.GL_COLOR_ARRAY); // Enable Color in Vertices
vertices.position(positionCnt); // Set Vertex Buffer to Color
gl.glColorPointer(COLOR_CNT, GL10.GL_FLOAT, vertexSize, vertices); // Set Color Pointer
}
if (hasTexCoords) { // IF Vertices Have Texture Coords
gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY); // Enable Texture Coords in Vertices
vertices.position(positionCnt + (hasColor ? COLOR_CNT : 0)); // Set Vertex Buffer to Texture Coords (NOTE: position based on whether color is also specified)
gl.glTexCoordPointer(TEXCOORD_CNT, GL10.GL_FLOAT, vertexSize, vertices); // Set Texture Coords Pointer
}
if (indices != null) { // IF Indices Exist
indices.position(offset); // Set Index Buffer to Specified Offset
gl.glDrawElements(primitiveType, numVertices, GL10.GL_UNSIGNED_SHORT, indices); // Draw Indexed
} else { // ELSE No Indices Exist
gl.glDrawArrays(primitiveType, offset, numVertices); // Draw Direct (Array)
}
if (hasTexCoords) // IF Vertices Have Texture Coords
gl.glDisableClientState(GL10.GL_TEXTURE_COORD_ARRAY); // Clear Texture Coords State
if (hasColor) // IF Vertices Have Color
gl.glDisableClientState(GL10.GL_COLOR_ARRAY); // Clear Color State
}
//--Set Vertex Elements--//
// D: use these methods to alter the values (position, color, textcoords, normals) for vertices
// WARNING: these do NOT validate any values, ensure that the index AND specified
// elements EXIST before using!!
// A: x, y, z - the x,y,z position to set in buffer
// r, g, b, a - the r,g,b,a color to set in buffer
// u, v - the u,v texture coords to set in buffer
// nx, ny, nz - the x,y,z normal to set in buffer
// R: [none]
void setVtxPosition(int vtxIdx, float x, float y) {
int index = vtxIdx * vertexStride; // Calculate Actual Index
vertices.put(index + 0, Float.floatToRawIntBits(x)); // Set X
vertices.put(index + 1, Float.floatToRawIntBits(y)); // Set Y
}
void setVtxPosition(int vtxIdx, float x, float y, float z) {
int index = vtxIdx * vertexStride; // Calculate Actual Index
vertices.put(index + 0, Float.floatToRawIntBits(x)); // Set X
vertices.put(index + 1, Float.floatToRawIntBits(y)); // Set Y
vertices.put(index + 2, Float.floatToRawIntBits(z)); // Set Z
}
void setVtxColor(int vtxIdx, float r, float g, float b, float a) {
int index = (vtxIdx * vertexStride) + positionCnt; // Calculate Actual Index
vertices.put(index + 0, Float.floatToRawIntBits(r)); // Set Red
vertices.put(index + 1, Float.floatToRawIntBits(g)); // Set Green
vertices.put(index + 2, Float.floatToRawIntBits(b)); // Set Blue
vertices.put(index + 3, Float.floatToRawIntBits(a)); // Set Alpha
}
void setVtxColor(int vtxIdx, float r, float g, float b) {
int index = (vtxIdx * vertexStride) + positionCnt; // Calculate Actual Index
vertices.put(index + 0, Float.floatToRawIntBits(r)); // Set Red
vertices.put(index + 1, Float.floatToRawIntBits(g)); // Set Green
vertices.put(index + 2, Float.floatToRawIntBits(b)); // Set Blue
}
void setVtxColor(int vtxIdx, float a) {
int index = (vtxIdx * vertexStride) + positionCnt; // Calculate Actual Index
vertices.put(index + 3, Float.floatToRawIntBits(a)); // Set Alpha
}
void setVtxTexCoords(int vtxIdx, float u, float v) {
int index = (vtxIdx * vertexStride) + positionCnt + (hasColor ? COLOR_CNT : 0); // Calculate Actual Index
vertices.put(index + 0, Float.floatToRawIntBits(u)); // Set U
vertices.put(index + 1, Float.floatToRawIntBits(v)); // Set V
}
void setVtxNormal(int vtxIdx, float x, float y, float z) {
int index = (vtxIdx * vertexStride) + positionCnt + (hasColor ? COLOR_CNT : 0) + (hasTexCoords ? TEXCOORD_CNT : 0); // Calculate Actual Index
vertices.put(index + 0, Float.floatToRawIntBits(x)); // Set X
vertices.put(index + 1, Float.floatToRawIntBits(y)); // Set Y
vertices.put(index + 2, Float.floatToRawIntBits(z)); // Set Z
}
}

View File

@ -1,247 +0,0 @@
/*
* Copyright 2013 serso aka se.solovyev
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* Contact details
*
* Email: se.solovyev@gmail.com
* Site: http://se.solovyev.org
*/
package org.solovyev.android.calculator.plot;
import jscl.math.Generic;
import jscl.math.function.Constant;
import org.solovyev.common.text.Strings;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
public class XyFunction implements FunctionEvaluator {
/*
**********************************************************************
*
* FIELDS
*
**********************************************************************
*/
@Nonnull
private final String id;
@Nonnull
private final FunctionEvaluator evaluator;
@Nonnull
private Generic expression;
@Nonnull
private String expressionString;
@Nullable
private Constant xVariable;
@Nullable
private String xVariableName;
@Nullable
private Constant yVariable;
private boolean imag;
@Nullable
private String yVariableName;
private int arity;
public XyFunction(@Nonnull Generic expression,
@Nullable Constant xVariable,
@Nullable Constant yVariable,
boolean imag) {
this.expression = expression;
this.xVariable = xVariable;
this.yVariable = yVariable;
this.imag = imag;
if (imag) {
this.expressionString = "Im(" + expression.toString() + ")";
this.evaluator = new ImaginaryEvaluator(this);
} else {
this.expressionString = expression.toString();
this.evaluator = new RealEvaluator(this);
}
this.xVariableName = xVariable == null ? null : xVariable.getName();
this.yVariableName = yVariable == null ? null : yVariable.getName();
this.arity = 2;
if (this.yVariableName == null) {
this.arity--;
}
if (this.xVariableName == null) {
this.arity--;
}
this.id = this.expressionString + "_" + Strings.getNotEmpty(this.xVariableName, "") + "_" + Strings.getNotEmpty(this.yVariableName, "");
}
public boolean isImag() {
return imag;
}
@Override
public int getArity() {
return arity;
}
@Override
public double eval() {
return evaluator.eval();
}
@Override
public double eval(double x) {
return evaluator.eval(x);
}
@Override
public double eval(double x, double y) {
return evaluator.eval(x, y);
}
@Nonnull
public Generic getExpression() {
return expression;
}
@Nullable
public Constant getXVariable() {
return xVariable;
}
@Nullable
public Constant getYVariable() {
return yVariable;
}
@Nonnull
public String getExpressionString() {
return expressionString;
}
@Nonnull
public String getId() {
return id;
}
@Nullable
public String getXVariableName() {
return xVariableName;
}
@Nullable
public String getYVariableName() {
return yVariableName;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof XyFunction)) return false;
final XyFunction that = (XyFunction) o;
return id.equals(that.id);
}
@Override
public int hashCode() {
return id.hashCode();
}
/*
**********************************************************************
*
* STATIC
*
**********************************************************************
*/
private static abstract class AbstractEvaluator implements FunctionEvaluator {
@Nonnull
protected final XyFunction xyFunction;
@Nullable
private Double constant = null;
public AbstractEvaluator(@Nonnull XyFunction xyFunction) {
this.xyFunction = xyFunction;
}
@Override
public final double eval() {
if (constant == null) {
constant = eval0();
}
return constant;
}
protected abstract double eval0();
@Override
public final int getArity() {
return xyFunction.getArity();
}
}
private static class RealEvaluator extends AbstractEvaluator {
private RealEvaluator(@Nonnull XyFunction xyFunction) {
super(xyFunction);
}
@Override
public double eval0() {
return PlotUtils.calculatorExpression(xyFunction.expression).realPart();
}
@Override
public double eval(double x) {
return PlotUtils.calculatorExpression(xyFunction.expression, xyFunction.xVariable, x).realPart();
}
@Override
public double eval(double x, double y) {
return PlotUtils.calculatorExpression(xyFunction.expression, xyFunction.xVariable, x, xyFunction.yVariable, y).realPart();
}
}
private static class ImaginaryEvaluator extends AbstractEvaluator {
private ImaginaryEvaluator(@Nonnull XyFunction xyFunction) {
super(xyFunction);
}
@Override
public double eval0() {
return PlotUtils.calculatorExpression(xyFunction.expression).imaginaryPart();
}
@Override
public double eval(double x) {
return PlotUtils.calculatorExpression(xyFunction.expression, xyFunction.xVariable, x).imaginaryPart();
}
@Override
public double eval(double x, double y) {
return PlotUtils.calculatorExpression(xyFunction.expression, xyFunction.xVariable, x, xyFunction.yVariable, y).imaginaryPart();
}
}
}

View File

@ -1,77 +0,0 @@
/*
* Copyright 2013 serso aka se.solovyev
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* Contact details
*
* Email: se.solovyev@gmail.com
* Site: http://se.solovyev.org
*/
package org.solovyev.android.calculator.plot;
class ZoomTracker {
public static final String TAG = "ZoomTracker";
private static final float EPS = 1.5f;
private static final float MIN_DISTANCE = distance(0f, 50f);
float xValue;
float yValue;
private float initialXDistance;
private float initialYDistance;
private float initialXValue;
private float initialYValue;
private static float distance(float x1, float x2) {
final float dx = x1 - x2;
return dx * dx;
}
void start(float xValue, float yValue,
float x1, float y1,
float x2, float y2) {
initialXDistance = distance(x1, x2);
initialYDistance = distance(y1, y2);
initialXValue = xValue;
initialYValue = yValue;
this.xValue = xValue;
this.yValue = yValue;
}
boolean update(float x1, float y1, float x2, float y2) {
boolean result = false;
if (initialXDistance > MIN_DISTANCE) {
final float xDistance = distance(x1, x2);
if (xDistance > EPS) {
xValue = initialXDistance / xDistance * initialXValue;
result = true;
}
}
if (initialYDistance > MIN_DISTANCE) {
final float yDistance = distance(y1, y2);
if (yDistance > EPS) {
yValue = initialYDistance / yDistance * initialYValue;
result = true;
}
}
return result;
}
}

View File

@ -1,19 +1,16 @@
package org.solovyev.android.calculator.release; package org.solovyev.android.calculator.release;
import android.content.Context; import android.content.Context;
import org.solovyev.android.calculator.App;
import org.solovyev.android.calculator.CalculatorApplication; import org.solovyev.android.calculator.CalculatorApplication;
import org.solovyev.android.calculator.R; import org.solovyev.android.calculator.R;
import org.solovyev.android.calculator.about.TextHelper; import org.solovyev.android.calculator.about.TextHelper;
import org.solovyev.common.text.Strings; import org.solovyev.common.text.Strings;
import javax.annotation.Nonnull;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import javax.annotation.Nonnull;
import static org.solovyev.android.Android.getAppVersionCode;
public final class ReleaseNotes { public final class ReleaseNotes {
@Nonnull @Nonnull
@ -26,7 +23,7 @@ public final class ReleaseNotes {
final StringBuilder result = new StringBuilder(); final StringBuilder result = new StringBuilder();
final String releaseNotesForTitle = context.getString(R.string.c_release_notes_for_title); final String releaseNotesForTitle = context.getString(R.string.c_release_notes_for_title);
final int currentVersionCode = getAppVersionCode(context); final int currentVersionCode = App.getAppVersionCode(context);
final TextHelper textHelper = new TextHelper(context.getResources(), CalculatorApplication.class.getPackage().getName()); final TextHelper textHelper = new TextHelper(context.getResources(), CalculatorApplication.class.getPackage().getName());
@ -53,7 +50,7 @@ public final class ReleaseNotes {
public static List<Integer> getReleaseNotesVersions(@Nonnull Context context, int minVersion) { public static List<Integer> getReleaseNotesVersions(@Nonnull Context context, int minVersion) {
final List<Integer> releaseNotes = new ArrayList<>(); final List<Integer> releaseNotes = new ArrayList<>();
final int currentVersionCode = getAppVersionCode(context); final int currentVersionCode = App.getAppVersionCode(context);
final TextHelper textHelper = new TextHelper(context.getResources(), CalculatorApplication.class.getPackage().getName()); final TextHelper textHelper = new TextHelper(context.getResources(), CalculatorApplication.class.getPackage().getName());
for (int versionCode = currentVersionCode; versionCode >= minVersion; versionCode--) { for (int versionCode = currentVersionCode; versionCode >= minVersion; versionCode--) {
@ -70,7 +67,7 @@ public final class ReleaseNotes {
} }
public static boolean hasReleaseNotes(@Nonnull Context context, int minVersion) { public static boolean hasReleaseNotes(@Nonnull Context context, int minVersion) {
final int currentVersionCode = getAppVersionCode(context); final int currentVersionCode = App.getAppVersionCode(context);
final TextHelper textHelper = new TextHelper(context.getResources(), CalculatorApplication.class.getPackage().getName()); final TextHelper textHelper = new TextHelper(context.getResources(), CalculatorApplication.class.getPackage().getName());
for (int versionCode = currentVersionCode; versionCode >= minVersion; versionCode--) { for (int versionCode = currentVersionCode; versionCode >= minVersion; versionCode--) {

View File

@ -45,7 +45,6 @@ import butterknife.Bind;
import butterknife.ButterKnife; import butterknife.ButterKnife;
import dagger.Lazy; import dagger.Lazy;
import jscl.math.function.IConstant; import jscl.math.function.IConstant;
import org.solovyev.android.Activities;
import org.solovyev.android.Check; import org.solovyev.android.Check;
import org.solovyev.android.calculator.*; import org.solovyev.android.calculator.*;
import org.solovyev.android.calculator.entities.EntityRemovalDialog; import org.solovyev.android.calculator.entities.EntityRemovalDialog;
@ -125,7 +124,7 @@ public class EditVariableFragment extends BaseDialogFragment implements View.OnF
public static void showDialog(@Nullable CppVariable variable, @Nonnull Context context) { public static void showDialog(@Nullable CppVariable variable, @Nonnull Context context) {
if (!(context instanceof VariablesActivity)) { if (!(context instanceof VariablesActivity)) {
final Intent intent = new Intent(context, VariablesActivity.getClass(context)); final Intent intent = new Intent(context, VariablesActivity.getClass(context));
Activities.addIntentFlags(intent, false, context); App.addIntentFlags(intent, false, context);
intent.putExtra(VariablesActivity.EXTRA_VARIABLE, variable); intent.putExtra(VariablesActivity.EXTRA_VARIABLE, variable);
context.startActivity(intent); context.startActivity(intent);
} else { } else {

View File

@ -8,7 +8,7 @@ import android.view.View;
import android.widget.Button; import android.widget.Button;
import android.widget.LinearLayout; import android.widget.LinearLayout;
import android.widget.TextView; import android.widget.TextView;
import org.solovyev.android.Views; import org.solovyev.android.calculator.App;
import org.solovyev.android.calculator.R; import org.solovyev.android.calculator.R;
import org.solovyev.android.calculator.keyboard.BaseFloatingKeyboard; import org.solovyev.android.calculator.keyboard.BaseFloatingKeyboard;
import org.solovyev.android.calculator.view.EditTextLongClickEraser; import org.solovyev.android.calculator.view.EditTextLongClickEraser;
@ -145,7 +145,7 @@ public class GreekFloatingKeyboard extends BaseFloatingKeyboard implements View.
private void changeCase(@NonNull Button button) { private void changeCase(@NonNull Button button) {
final boolean upperCase = button.getText().equals(""); final boolean upperCase = button.getText().equals("");
Views.processViewsOfType(user.getKeyboard(), Button.class, new Views.ViewProcessor<Button>() { App.processViewsOfType(user.getKeyboard(), Button.class, new App.ViewProcessor<Button>() {
@Override @Override
public void process(@Nonnull Button key) { public void process(@Nonnull Button key) {
final String letter = key.getText().toString(); final String letter = key.getText().toString();

View File

@ -41,7 +41,6 @@ import android.text.TextUtils;
import android.text.style.StyleSpan; import android.text.style.StyleSpan;
import android.widget.RemoteViews; import android.widget.RemoteViews;
import org.solovyev.android.Check; import org.solovyev.android.Check;
import org.solovyev.android.Views;
import org.solovyev.android.calculator.*; import org.solovyev.android.calculator.*;
import org.solovyev.android.calculator.Preferences.SimpleTheme; import org.solovyev.android.calculator.Preferences.SimpleTheme;
import org.solovyev.android.calculator.buttons.CppButton; import org.solovyev.android.calculator.buttons.CppButton;
@ -182,7 +181,7 @@ public class CalculatorWidget extends AppWidgetProvider {
return getDefaultLayout(theme); return getDefaultLayout(theme);
} }
final int widgetMinHeight = Views.toPixels(resources.getDisplayMetrics(), options.getInt(OPTION_APPWIDGET_MIN_HEIGHT, 0)); final int widgetMinHeight = App.toPixels(resources.getDisplayMetrics(), options.getInt(OPTION_APPWIDGET_MIN_HEIGHT, 0));
final int lockScreenMinHeight = resources.getDimensionPixelSize(R.dimen.min_expanded_height_lock_screen); final int lockScreenMinHeight = resources.getDimensionPixelSize(R.dimen.min_expanded_height_lock_screen);
final boolean expanded = widgetMinHeight >= lockScreenMinHeight; final boolean expanded = widgetMinHeight >= lockScreenMinHeight;
if (expanded) { if (expanded) {

View File

@ -30,18 +30,15 @@ import android.view.View;
import android.widget.AdapterView; import android.widget.AdapterView;
import android.widget.FrameLayout; import android.widget.FrameLayout;
import android.widget.Spinner; import android.widget.Spinner;
import org.solovyev.android.Views;
import org.solovyev.android.calculator.App; import org.solovyev.android.calculator.App;
import org.solovyev.android.calculator.Preferences; import org.solovyev.android.calculator.Preferences;
import org.solovyev.android.calculator.R; import org.solovyev.android.calculator.R;
import org.solovyev.android.calculator.keyboard.BaseKeyboardUi; import org.solovyev.android.calculator.keyboard.BaseKeyboardUi;
import javax.annotation.Nonnull;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import javax.annotation.Nonnull;
public class ChooseThemeWizardStep extends WizardFragment implements AdapterView.OnItemSelectedListener { public class ChooseThemeWizardStep extends WizardFragment implements AdapterView.OnItemSelectedListener {
@Nonnull @Nonnull
@ -89,7 +86,7 @@ public class ChooseThemeWizardStep extends WizardFragment implements AdapterView
preview.removeAllViews(); preview.removeAllViews();
final ContextThemeWrapper context = new ContextThemeWrapper(getActivity(), theme.theme); final ContextThemeWrapper context = new ContextThemeWrapper(getActivity(), theme.theme);
LayoutInflater.from(context).inflate(R.layout.cpp_wizard_step_choose_theme_preview, preview); LayoutInflater.from(context).inflate(R.layout.cpp_wizard_step_choose_theme_preview, preview);
Views.processViews(preview, new Views.ViewProcessor<View>() { App.processViews(preview, new App.ViewProcessor<View>() {
@Override @Override
public void process(@Nonnull View view) { public void process(@Nonnull View view) {
BaseKeyboardUi.adjustButton(view); BaseKeyboardUi.adjustButton(view);

View File

@ -1,84 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright 2013 serso aka se.solovyev
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
~
~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~ Contact details
~
~ Email: se.solovyev@gmail.com
~ Site: http://se.solovyev.org
-->
<LinearLayout
xmlns:a="http://schemas.android.com/apk/res/android"
xmlns:picker="http://schemas.android.com/apk/res-auto"
a:id="@+id/main_fragment_layout"
style="@style/CppFragment"
a:layout_width="match_parent"
a:layout_height="match_parent">
<org.solovyev.android.calculator.AdView style="@style/CppAd" />
<LinearLayout
a:layout_width="match_parent"
a:layout_height="match_parent"
a:orientation="vertical">
<org.solovyev.android.view.Picker
a:id="@+id/matrix_cols_count_picker"
a:layout_width="wrap_content"
a:layout_height="wrap_content"
a:layout_gravity="center"
picker:orientation="horizontal" />
<LinearLayout
a:layout_width="match_parent"
a:layout_height="match_parent"
a:gravity="center"
a:orientation="horizontal">
<org.solovyev.android.view.Picker
a:id="@+id/matrix_rows_count_picker"
a:layout_width="wrap_content"
a:layout_height="wrap_content" />
<ScrollView
a:layout_width="match_parent"
a:layout_height="match_parent"
a:scrollbars="vertical">
<HorizontalScrollView
a:layout_width="match_parent"
a:layout_height="wrap_content"
a:minHeight="300dp">
<org.solovyev.android.calculator.matrix.MatrixView
a:id="@+id/matrix_layout"
a:layout_width="wrap_content"
a:layout_height="match_parent"
a:minWidth="300dp" />
</HorizontalScrollView>
</ScrollView>
</LinearLayout>
</LinearLayout>
</LinearLayout>

View File

@ -15,4 +15,23 @@
<string name="dimensions_y_min" translatable="false">Y min</string> <string name="dimensions_y_min" translatable="false">Y min</string>
<string name="dimensions_y_max" translatable="false">Y max</string> <string name="dimensions_y_max" translatable="false">Y max</string>
<string name="cpp_function_body" translatable="false">f(x, y)</string> <string name="cpp_function_body" translatable="false">f(x, y)</string>
<string-array name="cpp_prefs_precisions" translatable="false">
<item>0</item>
<item>1</item>
<item>2</item>
<item>3</item>
<item>4</item>
<item>5</item>
<item>6</item>
<item>7</item>
<item>8</item>
<item>9</item>
<item>10</item>
<item>11</item>
<item>12</item>
<item>13</item>
<item>14</item>
<item>15</item>
<item>16</item>
</string-array>
</resources> </resources>

View File

@ -22,8 +22,7 @@
~ Site: http://se.solovyev.org ~ Site: http://se.solovyev.org
--> -->
<PreferenceScreen xmlns:a="http://schemas.android.com/apk/res/android" <PreferenceScreen xmlns:a="http://schemas.android.com/apk/res/android">
xmlns:range="http://schemas.android.com/apk/res-auto">
<android.preference.CheckBoxPreference <android.preference.CheckBoxPreference
a:defaultValue="true" a:defaultValue="true"
@ -31,12 +30,12 @@
a:summary="@string/c_calc_round_result_summary" a:summary="@string/c_calc_round_result_summary"
a:title="@string/c_calc_round_result_title" /> a:title="@string/c_calc_round_result_title" />
<org.solovyev.android.prefs.IntegerPickerDialogPreference <ListPreference
a:defaultValue="5" a:entries="@array/cpp_prefs_precisions"
a:entryValues="@array/cpp_prefs_precisions"
a:key="engine.output.precision" a:key="engine.output.precision"
a:summary="@string/c_calc_result_precision_summary" a:summary="@string/c_calc_result_precision_summary"
a:title="@string/p_calc_result_precision_title" a:title="@string/p_calc_result_precision_title" />
range:boundaries="0;16" />
<android.preference.CheckBoxPreference <android.preference.CheckBoxPreference
a:defaultValue="false" a:defaultValue="false"

View File

@ -24,7 +24,6 @@ apply plugin: 'java'
dependencies { dependencies {
compile fileTree(include: ['*.jar'], dir: 'libs') compile fileTree(include: ['*.jar'], dir: 'libs')
compile 'org.solovyev:common-core:1.0.7'
compile 'org.solovyev:common-msg:1.0.7' compile 'org.solovyev:common-msg:1.0.7'
compile 'com.google.code.findbugs:annotations:2.0.1' compile 'com.google.code.findbugs:annotations:2.0.1'
compile 'xerces:xercesImpl:2.8.0' compile 'xerces:xercesImpl:2.8.0'