From bbdba7aeb3754208d95b266104472f18c69b3c38 Mon Sep 17 00:00:00 2001 From: XDrake99 Date: Tue, 31 Jan 2017 22:29:49 +0100 Subject: [PATCH] Major Graphic Engine revision. Now most of the math functions are broken due to their outdated rendering methods. --- .classpath | 2 +- .settings/org.eclipse.jdt.core.prefs | 12 +- .settings/org.eclipse.jdt.ui.prefs | 60 ++ res/skin.png | Bin 4863 -> 4594 bytes res/skin.xcf | Bin 13957 -> 11532 bytes res/test.png | Bin 0 -> 1088 bytes src/com/rits/cloning/Cloner.java | 86 ++- src/com/rits/cloning/FastClonerCalendar.java | 2 +- src/com/rits/perspectives/Perspectives.java | 9 +- src/org/nevec/rjm/Bernoulli.java | 23 +- src/org/nevec/rjm/BigComplex.java | 8 +- src/org/nevec/rjm/BigDecimalMath.java | 710 ++++++++++-------- src/org/nevec/rjm/BigIntegerMath.java | 152 ++-- src/org/nevec/rjm/BigIntegerPoly.java | 202 ++--- src/org/nevec/rjm/BigSurd.java | 92 ++- src/org/nevec/rjm/BigSurdVec.java | 157 ++-- src/org/nevec/rjm/Euler.java | 12 +- src/org/nevec/rjm/EulerPhi.java | 16 +- src/org/nevec/rjm/Harmonic.java | 7 +- src/org/nevec/rjm/Ifactor.java | 162 ++-- src/org/nevec/rjm/PartitionsP.java | 8 +- src/org/nevec/rjm/Prime.java | 83 +- src/org/nevec/rjm/RatPoly.java | 226 +++--- src/org/nevec/rjm/Rational.java | 173 +++-- src/org/nevec/rjm/Wigner3j.java | 185 +++-- src/org/nevec/rjm/Wigner3jGUI.java | 35 +- src/org/warp/picalculator/BMPFile.java | 55 +- src/org/warp/picalculator/KeyboardTest.java | 10 + src/org/warp/picalculator/Main.java | 29 +- src/org/warp/picalculator/TestGPU.java | 68 +- src/org/warp/picalculator/Utils.java | 245 ++++-- .../warp/picalculator/device/Keyboard.java | 127 ++-- .../device/chip/ParallelToSerial.java | 18 +- .../device/chip/SerialToParallel.java | 14 +- .../warp/picalculator/gui/DisplayManager.java | 494 ++++++++++++ .../warp/picalculator/gui/GraphicUtils.java | 60 ++ src/org/warp/picalculator/gui/PIDisplay.java | 437 ----------- .../gui/graphicengine/Display.java | 20 +- .../gui/graphicengine/RAWFont.java | 176 +---- .../gui/graphicengine/RAWSkin.java | 12 + .../gui/graphicengine/Renderer.java | 32 +- .../gui/graphicengine/cpu/CPUDisplay.java | 299 +++++--- .../gui/graphicengine/cpu/CPUFont.java | 182 +++++ .../gui/graphicengine/cpu/CPUSkin.java | 53 ++ .../gui/graphicengine/cpu/SwingWindow.java | 51 +- .../graphicengine/gpu/CalculatorWindow.java | 673 ----------------- .../graphicengine/gpu/DeallocationHelper.java | 706 +++++++++++++++++ .../gui/graphicengine/gpu/GPUDisplay.java | 78 +- .../gui/graphicengine/gpu/GPUFont.java | 140 ++++ .../gui/graphicengine/gpu/GPURenderer.java | 256 +++++-- .../gui/graphicengine/gpu/GPUSkin.java | 58 ++ .../gui/graphicengine/gpu/NEWTWindow.java | 381 ++++++++++ .../screens/ChooseVariableValueScreen.java | 35 +- .../picalculator/gui/screens/EmptyScreen.java | 6 +- .../gui/screens/KeyboardDebugScreen.java | 185 +++-- .../gui/screens/LoadingScreen.java | 79 +- .../picalculator/gui/screens/MarioScreen.java | 118 ++- .../gui/screens/MathInputScreen.java | 314 ++++---- .../warp/picalculator/gui/screens/Screen.java | 10 +- .../gui/screens/SolveEquationScreen.java | 33 +- src/org/warp/picalculator/math/AngleMode.java | 4 +- .../warp/picalculator/math/Calculator.java | 42 +- .../math/MathematicalSymbols.java | 11 +- .../math/functions/AnteriorFunction.java | 62 +- .../picalculator/math/functions/Division.java | 87 ++- .../math/functions/EmptyNumber.java | 16 +- .../math/functions/Expression.java | 250 +++--- .../picalculator/math/functions/Function.java | 8 +- .../functions/FunctionMultipleValues.java | 30 +- .../math/functions/FunctionTwoValues.java | 74 +- .../picalculator/math/functions/Joke.java | 30 +- .../math/functions/Multiplication.java | 36 +- .../picalculator/math/functions/Negative.java | 40 +- .../picalculator/math/functions/Number.java | 152 ++-- .../picalculator/math/functions/Power.java | 52 +- .../picalculator/math/functions/Root.java | 58 +- .../math/functions/RootSquare.java | 28 +- .../math/functions/Subtraction.java | 44 +- .../warp/picalculator/math/functions/Sum.java | 58 +- .../math/functions/SumSubtraction.java | 50 +- .../math/functions/Undefined.java | 16 +- .../picalculator/math/functions/Variable.java | 38 +- .../math/functions/equations/Equation.java | 38 +- .../functions/equations/EquationsSystem.java | 67 +- .../equations/EquationsSystemPart.java | 28 +- .../functions/trigonometry/ArcCosine.java | 6 +- .../math/functions/trigonometry/ArcSine.java | 6 +- .../functions/trigonometry/ArcTangent.java | 6 +- .../math/functions/trigonometry/Cosine.java | 6 +- .../math/functions/trigonometry/Sine.java | 12 +- .../math/functions/trigonometry/Tangent.java | 6 +- .../picalculator/math/rules/ExpandRule1.java | 53 +- .../picalculator/math/rules/ExpandRule5.java | 22 +- .../math/rules/ExponentRule1.java | 9 +- .../math/rules/ExponentRule15.java | 17 +- .../math/rules/ExponentRule16.java | 17 +- .../math/rules/ExponentRule2.java | 7 +- .../math/rules/ExponentRule3.java | 5 +- .../math/rules/ExponentRule4.java | 29 +- .../math/rules/FractionsRule1.java | 11 +- .../math/rules/FractionsRule2.java | 9 +- .../math/rules/FractionsRule3.java | 5 +- .../math/rules/FractionsRule4.java | 15 +- .../math/rules/FractionsRule5.java | 22 +- .../picalculator/math/rules/NumberRule1.java | 11 +- .../picalculator/math/rules/NumberRule2.java | 21 +- .../picalculator/math/rules/NumberRule3.java | 15 +- .../picalculator/math/rules/NumberRule4.java | 7 +- .../picalculator/math/rules/NumberRule5.java | 11 +- .../picalculator/math/rules/NumberRule6.java | 25 +- .../picalculator/math/rules/NumberRule7.java | 7 +- .../picalculator/math/rules/SyntaxRule1.java | 15 +- .../picalculator/math/rules/SyntaxRule2.java | 19 +- .../math/rules/UndefinedRule1.java | 9 +- .../math/rules/UndefinedRule2.java | 11 +- .../math/rules/VariableRule1.java | 27 +- .../math/rules/VariableRule2.java | 21 +- .../math/rules/VariableRule3.java | 19 +- .../math/rules/methods/DivisionRule1.java | 38 +- .../rules/methods/MultiplicationMethod1.java | 37 +- .../math/rules/methods/SumMethod1.java | 55 +- test.png | Bin 200550 -> 0 bytes 122 files changed, 5722 insertions(+), 4084 deletions(-) create mode 100644 .settings/org.eclipse.jdt.ui.prefs create mode 100644 res/test.png create mode 100644 src/org/warp/picalculator/KeyboardTest.java create mode 100644 src/org/warp/picalculator/gui/DisplayManager.java create mode 100644 src/org/warp/picalculator/gui/GraphicUtils.java delete mode 100644 src/org/warp/picalculator/gui/PIDisplay.java create mode 100644 src/org/warp/picalculator/gui/graphicengine/RAWSkin.java create mode 100644 src/org/warp/picalculator/gui/graphicengine/cpu/CPUFont.java create mode 100644 src/org/warp/picalculator/gui/graphicengine/cpu/CPUSkin.java delete mode 100644 src/org/warp/picalculator/gui/graphicengine/gpu/CalculatorWindow.java create mode 100644 src/org/warp/picalculator/gui/graphicengine/gpu/DeallocationHelper.java create mode 100644 src/org/warp/picalculator/gui/graphicengine/gpu/GPUFont.java create mode 100644 src/org/warp/picalculator/gui/graphicengine/gpu/GPUSkin.java create mode 100644 src/org/warp/picalculator/gui/graphicengine/gpu/NEWTWindow.java delete mode 100644 test.png diff --git a/.classpath b/.classpath index c17f2bb6..f382bba6 100644 --- a/.classpath +++ b/.classpath @@ -3,6 +3,7 @@ + @@ -28,6 +29,5 @@ - diff --git a/.settings/org.eclipse.jdt.core.prefs b/.settings/org.eclipse.jdt.core.prefs index ace45cee..a7aa567c 100644 --- a/.settings/org.eclipse.jdt.core.prefs +++ b/.settings/org.eclipse.jdt.core.prefs @@ -1,12 +1,2 @@ eclipse.preferences.version=1 -org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled -org.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate -org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8 -org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve -org.eclipse.jdt.core.compiler.compliance=1.8 -org.eclipse.jdt.core.compiler.debug.lineNumber=generate -org.eclipse.jdt.core.compiler.debug.localVariable=generate -org.eclipse.jdt.core.compiler.debug.sourceFile=generate -org.eclipse.jdt.core.compiler.problem.assertIdentifier=error -org.eclipse.jdt.core.compiler.problem.enumIdentifier=error -org.eclipse.jdt.core.compiler.source=1.8 +org.eclipse.jdt.core.javaFormatter=org.eclipse.jdt.core.defaultJavaFormatter diff --git a/.settings/org.eclipse.jdt.ui.prefs b/.settings/org.eclipse.jdt.ui.prefs new file mode 100644 index 00000000..7800136e --- /dev/null +++ b/.settings/org.eclipse.jdt.ui.prefs @@ -0,0 +1,60 @@ +cleanup.add_default_serial_version_id=false +cleanup.add_generated_serial_version_id=true +cleanup.add_missing_annotations=true +cleanup.add_missing_deprecated_annotations=true +cleanup.add_missing_methods=true +cleanup.add_missing_nls_tags=false +cleanup.add_missing_override_annotations=true +cleanup.add_missing_override_annotations_interface_methods=true +cleanup.add_serial_version_id=true +cleanup.always_use_blocks=true +cleanup.always_use_parentheses_in_expressions=true +cleanup.always_use_this_for_non_static_field_access=false +cleanup.always_use_this_for_non_static_method_access=false +cleanup.convert_functional_interfaces=true +cleanup.convert_to_enhanced_for_loop=true +cleanup.correct_indentation=true +cleanup.format_source_code=true +cleanup.format_source_code_changes_only=false +cleanup.insert_inferred_type_arguments=false +cleanup.make_local_variable_final=true +cleanup.make_parameters_final=false +cleanup.make_private_fields_final=true +cleanup.make_type_abstract_if_missing_method=false +cleanup.make_variable_declarations_final=true +cleanup.never_use_blocks=false +cleanup.never_use_parentheses_in_expressions=false +cleanup.organize_imports=false +cleanup.qualify_static_field_accesses_with_declaring_class=false +cleanup.qualify_static_member_accesses_through_instances_with_declaring_class=true +cleanup.qualify_static_member_accesses_through_subtypes_with_declaring_class=true +cleanup.qualify_static_member_accesses_with_declaring_class=true +cleanup.qualify_static_method_accesses_with_declaring_class=false +cleanup.remove_private_constructors=true +cleanup.remove_redundant_type_arguments=true +cleanup.remove_trailing_whitespaces=false +cleanup.remove_trailing_whitespaces_all=true +cleanup.remove_trailing_whitespaces_ignore_empty=false +cleanup.remove_unnecessary_casts=true +cleanup.remove_unnecessary_nls_tags=true +cleanup.remove_unused_imports=true +cleanup.remove_unused_local_variables=false +cleanup.remove_unused_private_fields=true +cleanup.remove_unused_private_members=false +cleanup.remove_unused_private_methods=true +cleanup.remove_unused_private_types=true +cleanup.sort_members=false +cleanup.sort_members_all=false +cleanup.use_anonymous_class_creation=false +cleanup.use_blocks=true +cleanup.use_blocks_only_for_return_and_throw=false +cleanup.use_lambda=true +cleanup.use_parentheses_in_expressions=false +cleanup.use_this_for_non_static_field_access=true +cleanup.use_this_for_non_static_field_access_only_if_necessary=true +cleanup.use_this_for_non_static_method_access=true +cleanup.use_this_for_non_static_method_access_only_if_necessary=true +cleanup_profile=_Drake's Cleanup +cleanup_settings_version=2 +eclipse.preferences.version=1 +formatter_settings_version=12 diff --git a/res/skin.png b/res/skin.png index 3f137992309f14a2941f2716254d9bfb96cb37f5..3214bbc06c464d76bf04a9bb977c37caaf1c2b2d 100644 GIT binary patch literal 4594 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 diff --git a/res/skin.xcf b/res/skin.xcf index 8a724d7e3593ab17a034249ddfcd174295f94f40..d82e938b4603963b36040d2f8dc8b3903a9b3126 100644 GIT binary patch delta 792 zcmb8tOGs2v9LMqBE%Q-6MxBNjqOLVF_s(=f?Eyg$6D?~I2vUO^4J;uc6l7M-g&InF zK->r{S1l@p$eM~G2+6&;N~ldQD2Q-Tt3b!^nJYe)9{9{XbI$+#`JYE|@MbP{eqivD zoj=!ak92e#k+cc&@5DT-{`rYxR=j1KWWSf(88Z>KFeZ3leeVyu3|FyqTx$M_zbLN_ zW$u?${YlzdC)J;p8hWIrq7>=Hbv(mIEU-3#lNiDnrb_PSFO9)$WUnV#CUG{*E}yTx z+|Tljg#G0L&qfnLG5WaB@?-5VeTr>`eIJkTV*Pw81;(1B9j~PLH)-dvwCkX>JBp*| z!zd;(hedKEaSFsr`SCwzZrrCKG!YyEQV+ z9^THEOTSYWt2e%fC+%+v>ANP|YGtPK^h?R(NqGOH{o(XV9?$;gc^-G3pU-Jr z+7QTET^rco+`OX3xzXpFD9QGUA1n7|nMUf_>1D?7%mq^6LTOxx>#?J~CV0qrZnZbL z-bYFbNtt=@ViIPy*LT#|OerN->NihH+b^Y4Kk%9~s0lamK^i<9Q?Ukna2}5&2mLz= zL7$FQXh4%Za$KeHQp!k1A!cF~8qkERc*$gv!!MGa46uxJCe;%9ToD*h%J{LPzSK5K zGBzK6clnnE^-F98|KxKk(F6RZe=FgCVf+bLiT{e@PM|9KjEfAOdrRn3MWAm*D7plm ztk0?!SB;PSIzDnV*v%b_J`#)}i^)(v z#$qzcJKxOb&!nNpr0iKzPMtI&S#q*&^G@Ivm{fi?rlA&laRHAd7qu=o=+jlB33BbA z!Hup~v`GbaxKWN8?7#`MqK(Pe!*eq{>Ak^-yKWNxui-xpMyqpV@RReTaS7}aCG34A(XB05ZSD-#dzOb^jCo*KMqeq_cII2{ zTj!MfxANAVdFyZPI9{JhX|ZQKWyik~r|k8Ol(~(Mo4QwJ{WRuZb=Hl(tmfvP9u}xsXJCGenybN2OhdnO>&%la3B1({wkdbCGcCfn- zi@u(5CXvVzR4rY1yIp;M%BN0O-R{y?-~VV`!9$<1stYd4oK;zjqb^vN1*^JbU6!ot zf(Hn-J@h@a19*?x0rfrZd(;omrn>J>+C%29Z;Zo3PVMl{IiXGC8g?i89(td~9Ka2F z12@!1Tetm(@!jo2?tt2;aYy|?^%B(K^7;+YL`W0`fd~ab5DE%GL9FV6SyY4ppc%s0 zMgd@CV;C}?y^0s)Q!*0_eo@MDdp`=FqH{61Z-g96k? zpF4;Hs8GE$y~7_r{lM?!DTnp95DW#-MY3yAK73Mhc7{ZU6PAp%rDruHvEEhh({O7+IHgL5JvAU2r(h?E>4 z73!v&7I67LndkrYkNwd5kAi_%8#XUbs(`4Q4lNQQAOacc z#-=57g{1;8nLx&1D8`GEvD% zhKgW!$U6%JVocD&b|40vJ!)5iXs zCUA=YCp7_^D(59Z4ApvjWh_g+z-=%@(pf;KBxq&k0N%=&$u|pRb%Z#+5y~10xKwB+ zvI1a-q09)BlLKD0Eqi!38qAU}@Um?QVj{tWabW_xQvoo?!9bFyWYZc@)1V z^z{n9*}$VYd_EnYEjm8GhVv`@@iksv;qx0f+v52a&UScyY;U=oHJ(ZQDMlUQnV9O) zez_O%M3g6@JQcbYaRpp4wS}%=wkxd5oQo+N{-P{d)j6*YTPoa(2Jb)kR3k6r%dtALv88RG)BI8H#9`^=xd1f zk-7XrsEv$|GG&R=HD!z&I_!JnufKOlA`Tka@Ia{|8vFx4i}mwBdG2%o0000 T deepClone(T o, Map clones) { try { return cloneInternal(o, clones); - } catch (IllegalAccessException e) { + } catch (final IllegalAccessException e) { // just rethrow unchecked throw new IllegalStateException(e); } @@ -128,8 +128,9 @@ public class Cloner { protected Object fastClone(final Object o, final Map clones) throws IllegalAccessException { final Class c = o.getClass(); final IFastCloner fastCloner = fastCloners.get(c); - if (fastCloner != null) + if (fastCloner != null) { return fastCloner.clone(o, deepCloner, clones); + } return null; } @@ -281,8 +282,9 @@ public class Cloner { } public void registerFastCloner(final Class c, final IFastCloner fastCloner) { - if (fastCloners.containsKey(c)) + if (fastCloners.containsKey(c)) { throw new IllegalArgumentException(c + " already fast-cloned!"); + } fastCloners.put(c, fastCloner); } @@ -307,8 +309,9 @@ public class Cloner { public T fastCloneOrNewInstance(final Class c) { try { final T fastClone = (T) fastClone(c, null); - if (fastClone != null) + if (fastClone != null) { return fastClone; + } } catch (final IllegalAccessException e) { throw new RuntimeException(e); } @@ -326,10 +329,12 @@ public class Cloner { * @return a deep-clone of "o". */ public T deepClone(final T o) { - if (o == null) + if (o == null) { return null; - if (!cloningEnabled) + } + if (!cloningEnabled) { return o; + } if (dumpCloned != null) { dumpCloned.startCloning(o.getClass()); } @@ -342,10 +347,12 @@ public class Cloner { } public T deepCloneDontCloneInstances(final T o, final Object... dontCloneThese) { - if (o == null) + if (o == null) { return null; - if (!cloningEnabled) + } + if (!cloningEnabled) { return o; + } if (dumpCloned != null) { dumpCloned.startCloning(o.getClass()); } @@ -371,10 +378,12 @@ public class Cloner { * @return a shallow clone of "o" */ public T shallowClone(final T o) { - if (o == null) + if (o == null) { return null; - if (!cloningEnabled) + } + if (!cloningEnabled) { return o; + } try { return cloneInternal(o, null); } catch (final IllegalAccessException e) { @@ -411,10 +420,12 @@ public class Cloner { */ private boolean isImmutable(final Class clz) { final Boolean isIm = immutables.get(clz); - if (isIm != null) + if (isIm != null) { return isIm; - if (considerImmutable(clz)) + } + if (considerImmutable(clz)) { return true; + } final Class immutableAnnotation = getImmutableAnnotation(); for (final Annotation annotation : clz.getDeclaredAnnotations()) { @@ -442,34 +453,45 @@ public class Cloner { @SuppressWarnings("unchecked") protected T cloneInternal(final T o, final Map clones) throws IllegalAccessException { - if (o == null) + if (o == null) { return null; + } if (o == this) + { return null; // don't clone the cloner! - if (ignoredInstances.containsKey(o)) + } + if (ignoredInstances.containsKey(o)) { return o; - if (o instanceof Enum) + } + if (o instanceof Enum) { return o; + } final Class clz = (Class) o.getClass(); // skip cloning ignored classes - if (nullInstead.contains(clz)) + if (nullInstead.contains(clz)) { return null; - if (ignored.contains(clz)) - return o; - for (final Class iClz : ignoredInstanceOf) { - if (iClz.isAssignableFrom(clz)) - return o; } - if (isImmutable(clz)) + if (ignored.contains(clz)) { return o; + } + for (final Class iClz : ignoredInstanceOf) { + if (iClz.isAssignableFrom(clz)) { + return o; + } + } + if (isImmutable(clz)) { + return o; + } if (o instanceof IFreezable) { final IFreezable f = (IFreezable) o; - if (f.isFrozen()) + if (f.isFrozen()) { return o; + } } final Object clonedPreviously = clones != null ? clones.get(o) : null; - if (clonedPreviously != null) + if (clonedPreviously != null) { return (T) clonedPreviously; + } final Object fastClone = fastClone(o, clones); if (fastClone != null) { @@ -549,15 +571,18 @@ public class Cloner { * fields of src */ public void copyPropertiesOfInheritedClass(final T src, final E dest) { - if (src == null) + if (src == null) { throw new IllegalArgumentException("src can't be null"); - if (dest == null) + } + if (dest == null) { throw new IllegalArgumentException("dest can't be null"); + } final Class srcClz = src.getClass(); final Class destClz = dest.getClass(); if (srcClz.isArray()) { - if (!destClz.isArray()) + if (!destClz.isArray()) { throw new IllegalArgumentException("can't copy from array to non-array class " + destClz); + } final int length = Array.getLength(src); for (int i = 0; i < length; i++) { final Object v = Array.get(src, i); @@ -639,8 +664,9 @@ public class Cloner { System.out.println("cloned field>" + field + " -- of class " + clz); } }; - } else + } else { dumpCloned = null; + } } public boolean isCloningEnabled() { diff --git a/src/com/rits/cloning/FastClonerCalendar.java b/src/com/rits/cloning/FastClonerCalendar.java index 2f77aac8..5ace76ba 100644 --- a/src/com/rits/cloning/FastClonerCalendar.java +++ b/src/com/rits/cloning/FastClonerCalendar.java @@ -14,7 +14,7 @@ public class FastClonerCalendar implements IFastCloner { @Override public Object clone(final Object t, final IDeepCloner cloner, final Map clones) { final GregorianCalendar gc = new GregorianCalendar(); - Calendar c = (Calendar) t; + final Calendar c = (Calendar) t; gc.setTimeInMillis(c.getTimeInMillis()); gc.setTimeZone((TimeZone) c.getTimeZone().clone()); return gc; diff --git a/src/com/rits/perspectives/Perspectives.java b/src/com/rits/perspectives/Perspectives.java index 681e1de9..6201f823 100644 --- a/src/com/rits/perspectives/Perspectives.java +++ b/src/com/rits/perspectives/Perspectives.java @@ -43,10 +43,12 @@ public class Perspectives { * @return the E perspective of o */ public E viewAs(final Class c, final T o) { - if (o == null) + if (o == null) { return null; - if (o instanceof Collection) + } + if (o instanceof Collection) { throw new IllegalArgumentException("for collections please use viewCollectionAs() method. Invalid object " + o); + } final E newInstance = cloner.fastCloneOrNewInstance(c); cloner.copyPropertiesOfInheritedClass(o, newInstance); return newInstance; @@ -81,8 +83,9 @@ public class Perspectives { */ public , E extends Collection> E viewCollectionAs( final E newCollection, final Class perspectiveCollectionItemClass, final T currentCollection) { - if (currentCollection == null) + if (currentCollection == null) { return null; + } for (final I item : currentCollection) { final NI newItem = viewAs(perspectiveCollectionItemClass, item); newCollection.add(newItem); diff --git a/src/org/nevec/rjm/Bernoulli.java b/src/org/nevec/rjm/Bernoulli.java index d0de5b56..953087ec 100644 --- a/src/org/nevec/rjm/Bernoulli.java +++ b/src/org/nevec/rjm/Bernoulli.java @@ -35,11 +35,12 @@ public class Bernoulli { */ protected void set(final int n, final Rational value) { final int nindx = n / 2; - if (nindx < a.size()) + if (nindx < a.size()) { a.set(nindx, value); - else { - while (a.size() < nindx) + } else { + while (a.size() < nindx) { a.add(Rational.ZERO); + } a.add(value); } } @@ -53,15 +54,16 @@ public class Bernoulli { * @throws Error */ public Rational at(int n) throws Error { - if (n == 1) + if (n == 1) { return (new Rational(-1, 2)); - else if (n % 2 != 0) + } else if (n % 2 != 0) { return Rational.ZERO; - else { + } else { final int nindx = n / 2; if (a.size() <= nindx) { - for (int i = 2 * a.size(); i <= n; i += 2) + for (int i = 2 * a.size(); i <= n; i += 2) { set(i, doubleSum(i)); + } } return a.elementAt(nindx); } @@ -80,11 +82,12 @@ public class Bernoulli { Rational jsum = Rational.ZERO; BigInteger bin = BigInteger.ONE; for (int j = 0; j <= k; j++) { - BigInteger jpown = (new BigInteger("" + j)).pow(n); - if (j % 2 == 0) + final BigInteger jpown = (new BigInteger("" + j)).pow(n); + if (j % 2 == 0) { jsum = jsum.add(bin.multiply(jpown)); - else + } else { jsum = jsum.subtract(bin.multiply(jpown)); + } /* * update binomial(k,j) recursively diff --git a/src/org/nevec/rjm/BigComplex.java b/src/org/nevec/rjm/BigComplex.java index c1a19b16..a8c516f3 100644 --- a/src/org/nevec/rjm/BigComplex.java +++ b/src/org/nevec/rjm/BigComplex.java @@ -165,14 +165,16 @@ public class BigComplex { * and v= +- sqrt((l-re)/2 as the new real and imaginary parts. */ final BigDecimal l = abs(mc); - if (l.compareTo(BigDecimal.ZERO) == 0) + if (l.compareTo(BigDecimal.ZERO) == 0) { return new BigComplex(BigDecimalMath.scalePrec(BigDecimal.ZERO, mc), BigDecimalMath.scalePrec(BigDecimal.ZERO, mc)); + } final BigDecimal u = BigDecimalMath.sqrt(l.add(re).divide(half, mc), mc); final BigDecimal v = BigDecimalMath.sqrt(l.subtract(re).divide(half, mc), mc); - if (im.compareTo(BigDecimal.ZERO) >= 0) + if (im.compareTo(BigDecimal.ZERO) >= 0) { return new BigComplex(u, v); - else + } else { return new BigComplex(u, v.negate()); + } } /** diff --git a/src/org/nevec/rjm/BigDecimalMath.java b/src/org/nevec/rjm/BigDecimalMath.java index 47e5cdb7..c7db0a99 100644 --- a/src/org/nevec/rjm/BigDecimalMath.java +++ b/src/org/nevec/rjm/BigDecimalMath.java @@ -60,15 +60,15 @@ public class BigDecimalMath { */ static public BigDecimal pi(final MathContext mc) throws Error { /* look it up if possible */ - if (mc.getPrecision() < PI.precision()) + if (mc.getPrecision() < PI.precision()) { return PI.round(mc); - else { + } else { /* * Broadhurst arXiv:math/9803067 */ - int[] a = { 1, 0, 0, -1, -1, -1, 0, 0 }; - BigDecimal S = broadhurstBBP(1, 1, a, mc); + final int[] a = { 1, 0, 0, -1, -1, -1, 0, 0 }; + final BigDecimal S = broadhurstBBP(1, 1, a, mc); return multiplyRound(S, 8); } } /* BigDecimalMath.pi */ @@ -84,10 +84,10 @@ public class BigDecimalMath { */ static public BigDecimal gamma(MathContext mc) throws Error { /* look it up if possible */ - if (mc.getPrecision() < GAMMA.precision()) + if (mc.getPrecision() < GAMMA.precision()) { return GAMMA.round(mc); - else { - double eps = prec2err(0.577, mc.getPrecision()); + } else { + final double eps = prec2err(0.577, mc.getPrecision()); /* * Euler-Stieltjes as shown in Dilcher, Aequat Math 48 (1) (1994) @@ -104,7 +104,7 @@ public class BigDecimalMath { * Leading term zeta(3)/(4^1*3) is 0.017. Leading zeta(3) is 1.2. * Log(2) is 0.7 */ - int kmax = (int) ((Math.log(eps / 0.7) - 2.) / 4.); + final int kmax = (int) ((Math.log(eps / 0.7) - 2.) / 4.); mcloc = new MathContext(1 + err2prec(1.2, eps / kmax)); for (int n = 1;; n++) { /* @@ -116,8 +116,9 @@ public class BigDecimalMath { fourn = fourn.shiftLeft(2 * n); c = divideRound(c, fourn); resul = resul.subtract(c); - if (c.doubleValue() < 0.1 * eps) + if (c.doubleValue() < 0.1 * eps) { break; + } } return resul.round(mc); } @@ -134,16 +135,18 @@ public class BigDecimalMath { * @since 2008-10-27 */ static public BigDecimal sqrt(final BigDecimal x, final MathContext mc) { - if (x.compareTo(BigDecimal.ZERO) < 0) + if (x.compareTo(BigDecimal.ZERO) < 0) { throw new ArithmeticException("negative argument " + x.toString() + " of square root"); - if (x.abs().subtract(new BigDecimal(Math.pow(10., -mc.getPrecision()))).compareTo(BigDecimal.ZERO) < 0) + } + if (x.abs().subtract(new BigDecimal(Math.pow(10., -mc.getPrecision()))).compareTo(BigDecimal.ZERO) < 0) { return BigDecimalMath.scalePrec(BigDecimal.ZERO, mc); + } /* start the computation from a double precision estimate */ BigDecimal s = new BigDecimal(Math.sqrt(x.doubleValue()), mc); final BigDecimal half = new BigDecimal("2"); /* increase the local accuracy by 2 digits */ - MathContext locmc = new MathContext(mc.getPrecision() + 2, mc.getRoundingMode()); + final MathContext locmc = new MathContext(mc.getPrecision() + 2, mc.getRoundingMode()); /* * relative accuracy requested is 10^(-precision) @@ -157,8 +160,9 @@ public class BigDecimalMath { * (actually half of this, which we use for a little bit of * additional protection). */ - if (Math.abs(BigDecimal.ONE.subtract(x.divide(s.pow(2, locmc), locmc)).doubleValue()) <= eps) + if (Math.abs(BigDecimal.ONE.subtract(x.divide(s.pow(2, locmc), locmc)).doubleValue()) <= eps) { break; + } s = s.add(x.divide(s, locmc)).divide(half, locmc); /* debugging */ // System.out.println("itr "+x.round(locmc).toString() + " " + @@ -177,8 +181,9 @@ public class BigDecimalMath { * @since 2009-06-25 */ static public BigDecimal sqrt(final BigDecimal x) { - if (x.compareTo(BigDecimal.ZERO) < 0) + if (x.compareTo(BigDecimal.ZERO) < 0) { throw new ArithmeticException("negative argument " + x.toString() + " of square root"); + } return root(2, x); } /* BigDecimalMath.sqrt */ @@ -194,10 +199,11 @@ public class BigDecimalMath { * @since 2009-08-16 */ static public BigDecimal cbrt(final BigDecimal x) { - if (x.compareTo(BigDecimal.ZERO) < 0) + if (x.compareTo(BigDecimal.ZERO) < 0) { return root(3, x.negate()).negate(); - else + } else { return root(3, x); + } } /* BigDecimalMath.cbrt */ /** @@ -212,13 +218,16 @@ public class BigDecimalMath { * @since 2009-07-30 */ static public BigDecimal root(final int n, final BigDecimal x) { - if (x.compareTo(BigDecimal.ZERO) < 0) + if (x.compareTo(BigDecimal.ZERO) < 0) { throw new ArithmeticException("negative argument " + x.toString() + " of root"); - if (n <= 0) + } + if (n <= 0) { throw new ArithmeticException("negative power " + n + " of root"); + } - if (n == 1) + if (n == 1) { return x; + } /* start the computation from a double precision estimate */ BigDecimal s = new BigDecimal(Math.pow(x.doubleValue(), 1.0 / n)); @@ -233,7 +242,7 @@ public class BigDecimalMath { * slightly larger than what is demanded by 'eps' below. */ final BigDecimal xhighpr = scalePrec(x, 2); - MathContext mc = new MathContext(2 + x.precision()); + final MathContext mc = new MathContext(2 + x.precision()); /* * Relative accuracy of the result is eps. @@ -248,11 +257,12 @@ public class BigDecimalMath { */ BigDecimal c = xhighpr.divide(s.pow(n - 1), mc); c = s.subtract(c); - MathContext locmc = new MathContext(c.precision()); + final MathContext locmc = new MathContext(c.precision()); c = c.divide(nth, locmc); s = s.subtract(c); - if (Math.abs(c.doubleValue() / s.doubleValue()) < eps) + if (Math.abs(c.doubleValue() / s.doubleValue()) < eps) { break; + } } return s.round(new MathContext(err2prec(eps))); } /* BigDecimalMath.root */ @@ -280,7 +290,7 @@ public class BigDecimalMath { * where the two errors are 1/2 of the ulp's. Two intermediate protectio * digits. */ - BigDecimal zerr = x.abs().multiply(x.ulp()).add(y.abs().multiply(y.ulp())); + final BigDecimal zerr = x.abs().multiply(x.ulp()).add(y.abs().multiply(y.ulp())); MathContext mc = new MathContext(2 + err2prec(z, zerr)); /* Pull square root */ @@ -319,7 +329,7 @@ public class BigDecimalMath { * zerr is a signed value, but used only in conjunction with err2prec(), * so this feature does not harm. */ - double zerr = x.doubleValue() * x.ulp().doubleValue(); + final double zerr = x.doubleValue() * x.ulp().doubleValue(); MathContext mc = new MathContext(2 + err2prec(z.doubleValue(), zerr)); /* Pull square root */ @@ -365,7 +375,7 @@ public class BigDecimalMath { * errror in invx. * This is used to define the precision of the result. */ - MathContext mc = new MathContext(invx.precision()); + final MathContext mc = new MathContext(invx.precision()); return BigDecimal.ONE.divide(invx, mc); } else if (x.compareTo(BigDecimal.ZERO) == 0) { /* @@ -410,21 +420,22 @@ public class BigDecimalMath { * add noise beyond * what's already in x. */ - MathContext mcTay = new MathContext(err2prec(1., xUlpDbl / TAYLOR_NTERM)); + final MathContext mcTay = new MathContext(err2prec(1., xUlpDbl / TAYLOR_NTERM)); for (int i = 1; i <= TAYLOR_NTERM; i++) { ifac = ifac.multiply(new BigInteger("" + i)); xpowi = xpowi.multiply(x); final BigDecimal c = xpowi.divide(new BigDecimal(ifac), mcTay); resul = resul.add(c); - if (Math.abs(xpowi.doubleValue()) < i && Math.abs(c.doubleValue()) < 0.5 * xUlpDbl) + if (Math.abs(xpowi.doubleValue()) < i && Math.abs(c.doubleValue()) < 0.5 * xUlpDbl) { break; + } } /* * exp(x+deltax) = exp(x)(1+deltax) if deltax is <<1. So the * relative error * in the result equals the absolute error in the argument. */ - MathContext mc = new MathContext(err2prec(xUlpDbl / 2.)); + final MathContext mc = new MathContext(err2prec(xUlpDbl / 2.)); return resul.round(mc); } else { /* @@ -433,7 +444,7 @@ public class BigDecimalMath { * to loss of accuracy. */ int exSc = (int) (1.0 - Math.log10(TAYLOR_NTERM * (TAYLOR_NTERM - 1.0) * (TAYLOR_NTERM - 2.0) * xUlpDbl / Math.pow(xDbl, TAYLOR_NTERM)) / (TAYLOR_NTERM - 1.0)); - BigDecimal xby10 = x.scaleByPowerOfTen(-exSc); + final BigDecimal xby10 = x.scaleByPowerOfTen(-exSc); BigDecimal expxby10 = exp(xby10); /* @@ -443,7 +454,7 @@ public class BigDecimalMath { * binomial expansion). * This looses one digit. */ - MathContext mc = new MathContext(expxby10.precision() - exSc); + final MathContext mc = new MathContext(expxby10.precision() - exSc); /* * Rescaling the powers of 10 is done in chunks of a maximum of * 8 to avoid an invalid operation @@ -452,10 +463,11 @@ public class BigDecimalMath { while (exSc > 0) { int exsub = Math.min(8, exSc); exSc -= exsub; - MathContext mctmp = new MathContext(expxby10.precision() - exsub + 2); + final MathContext mctmp = new MathContext(expxby10.precision() - exsub + 2); int pex = 1; - while (exsub-- > 0) + while (exsub-- > 0) { pex *= 10; + } expxby10 = expxby10.pow(pex, mctmp); } return expxby10.round(mc); @@ -473,14 +485,14 @@ public class BigDecimalMath { */ static public BigDecimal exp(final MathContext mc) { /* look it up if possible */ - if (mc.getPrecision() < E.precision()) + if (mc.getPrecision() < E.precision()) { return E.round(mc); - else { + } else { /* * Instantiate a 1.0 with the requested pseudo-accuracy * and delegate the computation to the public method above. */ - BigDecimal uni = scalePrec(BigDecimal.ONE, mc.getPrecision()); + final BigDecimal uni = scalePrec(BigDecimal.ONE, mc.getPrecision()); return exp(uni); } } /* BigDecimalMath.exp */ @@ -500,9 +512,9 @@ public class BigDecimalMath { /* * the value is undefined if x is negative. */ - if (x.compareTo(BigDecimal.ZERO) < 0) + if (x.compareTo(BigDecimal.ZERO) < 0) { throw new ArithmeticException("Cannot take log of negative " + x.toString()); - else if (x.compareTo(BigDecimal.ONE) == 0) { + } else if (x.compareTo(BigDecimal.ONE) == 0) { /* log 1. = 0. */ return scalePrec(BigDecimal.ZERO, x.precision() - 1); } else if (Math.abs(x.doubleValue() - 1.0) <= 0.3) { @@ -511,21 +523,23 @@ public class BigDecimalMath { * Abramowitz-Stegun 4.124. * The absolute error is err(z)/(1+z) = err(x)/x. */ - BigDecimal z = scalePrec(x.subtract(BigDecimal.ONE), 2); + final BigDecimal z = scalePrec(x.subtract(BigDecimal.ONE), 2); BigDecimal zpown = z; - double eps = 0.5 * x.ulp().doubleValue() / Math.abs(x.doubleValue()); + final double eps = 0.5 * x.ulp().doubleValue() / Math.abs(x.doubleValue()); BigDecimal resul = z; for (int k = 2;; k++) { zpown = multiplyRound(zpown, z); - BigDecimal c = divideRound(zpown, k); - if (k % 2 == 0) + final BigDecimal c = divideRound(zpown, k); + if (k % 2 == 0) { resul = resul.subtract(c); - else + } else { resul = resul.add(c); - if (Math.abs(c.doubleValue()) < eps) + } + if (Math.abs(c.doubleValue()) < eps) { break; + } } - MathContext mc = new MathContext(err2prec(resul.doubleValue(), eps)); + final MathContext mc = new MathContext(err2prec(resul.doubleValue(), eps)); return resul.round(mc); } else { final double xDbl = x.doubleValue(); @@ -549,7 +563,7 @@ public class BigDecimalMath { /* * Compute r-th root with 2 additional digits of precision */ - BigDecimal xhighpr = scalePrec(x, 2); + final BigDecimal xhighpr = scalePrec(x, 2); BigDecimal resul = root(r, xhighpr); resul = log(resul).multiply(new BigDecimal(r)); @@ -559,7 +573,7 @@ public class BigDecimalMath { * in the result equals the relative error in the input, * xUlpDbl/xDbl . */ - MathContext mc = new MathContext(err2prec(resul.doubleValue(), xUlpDbl / xDbl)); + final MathContext mc = new MathContext(err2prec(resul.doubleValue(), xUlpDbl / xDbl)); return resul.round(mc); } } /* BigDecimalMath.log */ @@ -580,14 +594,14 @@ public class BigDecimalMath { /* * the value is undefined if x is negative. */ - if (n <= 0) + if (n <= 0) { throw new ArithmeticException("Cannot take log of negative " + n); - else if (n == 1) + } else if (n == 1) { return BigDecimal.ZERO; - else if (n == 2) { - if (mc.getPrecision() < LOG2.precision()) + } else if (n == 2) { + if (mc.getPrecision() < LOG2.precision()) { return LOG2.round(mc); - else { + } else { /* * Broadhurst arXiv:math/9803067= precision/1.87. */ - int kmax = (int) (mc.getPrecision() / 1.87); + final int kmax = (int) (mc.getPrecision() / 1.87); MathContext mcloc = new MathContext(mc.getPrecision() + 1 + (int) (Math.log10(kmax * 0.693 / 1.098))); BigDecimal log3 = multiplyRound(log(2, mcloc), 19); @@ -620,23 +634,25 @@ public class BigDecimalMath { * result will be divided by 12, so a conservative error is the one * already found in mc */ - double eps = prec2err(1.098, mc.getPrecision()) / kmax; - Rational r = new Rational(7153, 524288); + final double eps = prec2err(1.098, mc.getPrecision()) / kmax; + final Rational r = new Rational(7153, 524288); Rational pk = new Rational(7153, 524288); for (int k = 1;; k++) { - Rational tmp = pk.divide(k); - if (tmp.doubleValue() < eps) + final Rational tmp = pk.divide(k); + if (tmp.doubleValue() < eps) { break; + } /* * how many digits of tmp do we need in the sum? */ mcloc = new MathContext(err2prec(tmp.doubleValue(), eps)); - BigDecimal c = pk.divide(k).BigDecimalValue(mcloc); - if (k % 2 != 0) + final BigDecimal c = pk.divide(k).BigDecimalValue(mcloc); + if (k % 2 != 0) { log3 = log3.add(c); - else + } else { log3 = log3.subtract(c); + } pk = pk.multiply(r); } log3 = divideRound(log3, 12); @@ -650,7 +666,7 @@ public class BigDecimalMath { * -precision * so k>= precision/1.33. */ - int kmax = (int) (mc.getPrecision() / 1.33); + final int kmax = (int) (mc.getPrecision() / 1.33); MathContext mcloc = new MathContext(mc.getPrecision() + 1 + (int) (Math.log10(kmax * 0.693 / 1.609))); BigDecimal log5 = multiplyRound(log(2, mcloc), 14); @@ -660,19 +676,20 @@ public class BigDecimalMath { * result will be divided by 6, so a conservative error is the one * already found in mc */ - double eps = prec2err(1.6, mc.getPrecision()) / kmax; - Rational r = new Rational(759, 16384); + final double eps = prec2err(1.6, mc.getPrecision()) / kmax; + final Rational r = new Rational(759, 16384); Rational pk = new Rational(759, 16384); for (int k = 1;; k++) { - Rational tmp = pk.divide(k); - if (tmp.doubleValue() < eps) + final Rational tmp = pk.divide(k); + if (tmp.doubleValue() < eps) { break; + } /* * how many digits of tmp do we need in the sum? */ mcloc = new MathContext(err2prec(tmp.doubleValue(), eps)); - BigDecimal c = pk.divide(k).BigDecimalValue(mcloc); + final BigDecimal c = pk.divide(k).BigDecimalValue(mcloc); log5 = log5.subtract(c); pk = pk.multiply(r); } @@ -687,26 +704,27 @@ public class BigDecimalMath { * -precision * so k>= precision/0.903. */ - int kmax = (int) (mc.getPrecision() / 0.903); + final int kmax = (int) (mc.getPrecision() / 0.903); MathContext mcloc = new MathContext(mc.getPrecision() + 1 + (int) (Math.log10(kmax * 3 * 0.693 / 1.098))); BigDecimal log7 = multiplyRound(log(2, mcloc), 3); /* * log7 is roughly 1.9, so absolute and relative error are the same. */ - double eps = prec2err(1.9, mc.getPrecision()) / kmax; - Rational r = new Rational(1, 8); + final double eps = prec2err(1.9, mc.getPrecision()) / kmax; + final Rational r = new Rational(1, 8); Rational pk = new Rational(1, 8); for (int k = 1;; k++) { - Rational tmp = pk.divide(k); - if (tmp.doubleValue() < eps) + final Rational tmp = pk.divide(k); + if (tmp.doubleValue() < eps) { break; + } /* * how many digits of tmp do we need in the sum? */ mcloc = new MathContext(err2prec(tmp.doubleValue(), eps)); - BigDecimal c = pk.divide(k).BigDecimalValue(mcloc); + final BigDecimal c = pk.divide(k).BigDecimalValue(mcloc); log7 = log7.subtract(c); pk = pk.multiply(r); } @@ -724,7 +742,7 @@ public class BigDecimalMath { * error eps * log(n+errn) = log(n)+errn/n = log(n)+eps */ - double res = Math.log(n); + final double res = Math.log(n); double eps = prec2err(res, mc.getPrecision()); /* * errn = eps*n, convert absolute error in result to requirement on @@ -740,7 +758,7 @@ public class BigDecimalMath { * Padd n with a number of zeros to trigger the required accuracy in * the standard signature method */ - BigDecimal nb = scalePrec(new BigDecimal(n), mcloc); + final BigDecimal nb = scalePrec(new BigDecimal(n), mcloc); return log(nb); } } /* log */ @@ -760,25 +778,25 @@ public class BigDecimalMath { /* * the value is undefined if x is negative. */ - if (r.compareTo(Rational.ZERO) <= 0) + if (r.compareTo(Rational.ZERO) <= 0) { throw new ArithmeticException("Cannot take log of negative " + r.toString()); - else if (r.compareTo(Rational.ONE) == 0) + } else if (r.compareTo(Rational.ONE) == 0) { return BigDecimal.ZERO; - else { + } else { /* * log(r+epsr) = log(r)+epsr/r. Convert the precision to an absolute * error in the result. * eps contains the required absolute error of the result, epsr/r. */ - double eps = prec2err(Math.log(r.doubleValue()), mc.getPrecision()); + final double eps = prec2err(Math.log(r.doubleValue()), mc.getPrecision()); /* * Convert this further into a requirement of the relative precision * in r, given that * epsr/r is also the relative precision of r. Add one safety digit. */ - MathContext mcloc = new MathContext(1 + err2prec(eps)); + final MathContext mcloc = new MathContext(1 + err2prec(eps)); final BigDecimal resul = log(r.BigDecimalValue(mcloc)); @@ -799,24 +817,24 @@ public class BigDecimalMath { * @since 2009-06-01 */ static public BigDecimal pow(final BigDecimal x, final BigDecimal y) { - if (x.compareTo(BigDecimal.ZERO) < 0) + if (x.compareTo(BigDecimal.ZERO) < 0) { throw new ArithmeticException("Cannot power negative " + x.toString()); - else if (x.compareTo(BigDecimal.ZERO) == 0) + } else if (x.compareTo(BigDecimal.ZERO) == 0) { return BigDecimal.ZERO; - else { + } else { /* * return x^y = exp(y*log(x)) ; */ - BigDecimal logx = log(x); - BigDecimal ylogx = y.multiply(logx); - BigDecimal resul = exp(ylogx); + final BigDecimal logx = log(x); + final BigDecimal ylogx = y.multiply(logx); + final BigDecimal resul = exp(ylogx); /* * The estimation of the relative error in the result is * |log(x)*err(y)|+|y*err(x)/x| */ - double errR = Math.abs(logx.doubleValue() * y.ulp().doubleValue() / 2.) + Math.abs(y.doubleValue() * x.ulp().doubleValue() / 2. / x.doubleValue()); - MathContext mcR = new MathContext(err2prec(1.0, errR)); + final double errR = Math.abs(logx.doubleValue() * y.ulp().doubleValue() / 2.) + Math.abs(y.doubleValue() * x.ulp().doubleValue() / 2. / x.doubleValue()); + final MathContext mcR = new MathContext(err2prec(1.0, errR)); return resul.round(mcR); } } /* BigDecimalMath.pow */ @@ -836,11 +854,11 @@ public class BigDecimalMath { /** * Special cases: x^1=x and x^0 = 1 */ - if (n == 1) + if (n == 1) { return x; - else if (n == 0) + } else if (n == 0) { return BigDecimal.ONE; - else { + } else { /* * The relative error in the result is n times the relative error in * the input. @@ -849,11 +867,12 @@ public class BigDecimalMath { * Since the standard BigDecimal.pow can only handle positive n, we * split the algorithm. */ - MathContext mc = new MathContext(x.precision() - (int) Math.log10((Math.abs(n)))); - if (n > 0) + final MathContext mc = new MathContext(x.precision() - (int) Math.log10((Math.abs(n)))); + if (n > 0) { return x.pow(n, mc); - else + } else { return BigDecimal.ONE.divide(x.pow(-n), mc); + } } } /* BigDecimalMath.powRound */ @@ -876,10 +895,11 @@ public class BigDecimalMath { * implemented to decompose larger powers into cascaded calls to smaller * ones. */ - if (n.compareTo(Rational.MAX_INT) > 0 || n.compareTo(Rational.MIN_INT) < 0) + if (n.compareTo(Rational.MAX_INT) > 0 || n.compareTo(Rational.MIN_INT) < 0) { throw new ProviderException("Not implemented: big power " + n.toString()); - else + } else { return powRound(x, n.intValue()); + } } /* BigDecimalMath.powRound */ /** @@ -900,11 +920,11 @@ public class BigDecimalMath { /** * Special cases: x^1=x and x^0 = 1 */ - if (q.compareTo(BigInteger.ONE) == 0) + if (q.compareTo(BigInteger.ONE) == 0) { return x; - else if (q.signum() == 0) + } else if (q.signum() == 0) { return BigDecimal.ONE; - else if (q.isInteger()) { + } else if (q.isInteger()) { /* * We are sure that the denominator is positive here, because * normalize() has been @@ -916,9 +936,9 @@ public class BigDecimalMath { * Refuse to operate on the general negative basis. The integer q have * already been handled above. */ - else if (x.compareTo(BigDecimal.ZERO) < 0) + else if (x.compareTo(BigDecimal.ZERO) < 0) { throw new ArithmeticException("Cannot power negative " + x.toString()); - else { + } else { if (q.isIntegerFrac()) { /* * Newton method with first estimate in double precision. @@ -926,7 +946,7 @@ public class BigDecimalMath { * must fit in the * standard range of double precision numbers exponents. */ - double estim = Math.pow(x.doubleValue(), q.doubleValue()); + final double estim = Math.pow(x.doubleValue(), q.doubleValue()); BigDecimal res = new BigDecimal(estim); /* @@ -934,18 +954,18 @@ public class BigDecimalMath { * The relative error is q*Delta(x)/x, q times the relative * error of x. */ - BigDecimal reserr = new BigDecimal(0.5 * q.abs().doubleValue() * x.ulp().divide(x.abs(), MathContext.DECIMAL64).doubleValue()); + final BigDecimal reserr = new BigDecimal(0.5 * q.abs().doubleValue() * x.ulp().divide(x.abs(), MathContext.DECIMAL64).doubleValue()); /* * The main point in branching the cases above is that this * conversion * will succeed for numerator and denominator of q. */ - int qa = q.a.intValue(); - int qb = q.b.intValue(); + final int qa = q.a.intValue(); + final int qb = q.b.intValue(); /* Newton iterations. */ - BigDecimal xpowa = powRound(x, qa); + final BigDecimal xpowa = powRound(x, qa); for (;;) { /* * numerator and denominator of the Newton term. The major @@ -955,14 +975,14 @@ public class BigDecimalMath { * BigDecimal.pow(), * which becomes slow if the denominator of q is large. */ - BigDecimal nu = res.pow(qb).subtract(xpowa); - BigDecimal de = multiplyRound(res.pow(qb - 1), q.b); + final BigDecimal nu = res.pow(qb).subtract(xpowa); + final BigDecimal de = multiplyRound(res.pow(qb - 1), q.b); /* estimated correction */ BigDecimal eps = nu.divide(de, MathContext.DECIMAL64); - BigDecimal err = res.multiply(reserr, MathContext.DECIMAL64); - int precDiv = 2 + err2prec(eps, err); + final BigDecimal err = res.multiply(reserr, MathContext.DECIMAL64); + final int precDiv = 2 + err2prec(eps, err); if (precDiv <= 0) { /* * The case when the precision is already reached and @@ -971,7 +991,7 @@ public class BigDecimalMath { */ eps = nu.divide(de, MathContext.DECIMAL32); } else { - MathContext mc = new MathContext(precDiv); + final MathContext mc = new MathContext(precDiv); eps = nu.divide(de, mc); } @@ -986,7 +1006,7 @@ public class BigDecimalMath { * delete the bits of extra precision kept in this * working copy. */ - MathContext mc = new MathContext(err2prec(reserr.doubleValue())); + final MathContext mc = new MathContext(err2prec(reserr.doubleValue())); return res.round(mc); } } @@ -998,8 +1018,8 @@ public class BigDecimalMath { * number such that its relative error becomes negligible: * Delta(q)/q << Delta(x)/x/log(x) . */ - int precq = 3 + err2prec((x.ulp().divide(x, MathContext.DECIMAL64)).doubleValue() / Math.log(x.doubleValue())); - MathContext mc = new MathContext(precq); + final int precq = 3 + err2prec((x.ulp().divide(x, MathContext.DECIMAL64)).doubleValue() / Math.log(x.doubleValue())); + final MathContext mc = new MathContext(precq); /* * Perform the actual calculation as exponentiation of two @@ -1021,18 +1041,18 @@ public class BigDecimalMath { * @since 2009-06-01 */ static public BigDecimal sin(final BigDecimal x) throws Error { - if (x.compareTo(BigDecimal.ZERO) < 0) + if (x.compareTo(BigDecimal.ZERO) < 0) { return sin(x.negate()).negate(); - else if (x.compareTo(BigDecimal.ZERO) == 0) + } else if (x.compareTo(BigDecimal.ZERO) == 0) { return BigDecimal.ZERO; - else { + } else { /* * reduce modulo 2pi */ - BigDecimal res = mod2pi(x); - double errpi = 0.5 * Math.abs(x.ulp().doubleValue()); + final BigDecimal res = mod2pi(x); + final double errpi = 0.5 * Math.abs(x.ulp().doubleValue()); MathContext mc = new MathContext(2 + err2prec(3.14159, errpi)); - BigDecimal p = pi(mc); + final BigDecimal p = pi(mc); mc = new MathContext(x.precision()); if (res.compareTo(p) > 0) { /* @@ -1071,7 +1091,7 @@ public class BigDecimalMath { /* * The error in the result is set by the error in x itself. */ - double xUlpDbl = res.ulp().doubleValue(); + final double xUlpDbl = res.ulp().doubleValue(); /* * The error in the result is set by the error in x itself. @@ -1081,8 +1101,8 @@ public class BigDecimalMath { * 2k*log10(x)< -x.precision; * 2k*(-log10(x)) > x.precision; 2k*log10(1/x) > x.precision */ - int k = (int) (res.precision() / Math.log10(1.0 / res.doubleValue())) / 2; - MathContext mcTay = new MathContext(err2prec(res.doubleValue(), xUlpDbl / k)); + final int k = (int) (res.precision() / Math.log10(1.0 / res.doubleValue())) / 2; + final MathContext mcTay = new MathContext(err2prec(res.doubleValue(), xUlpDbl / k)); for (int i = 1;; i++) { /* * TBD: at which precision will 2*i or 2*i+1 overflow? @@ -1090,10 +1110,11 @@ public class BigDecimalMath { ifac = ifac.multiply(new BigInteger("" + (2 * i))); ifac = ifac.multiply(new BigInteger("" + (2 * i + 1))); xpowi = xpowi.multiply(res).multiply(res).negate(); - BigDecimal corr = xpowi.divide(new BigDecimal(ifac), mcTay); + final BigDecimal corr = xpowi.divide(new BigDecimal(ifac), mcTay); resul = resul.add(corr); - if (corr.abs().doubleValue() < 0.5 * xUlpDbl) + if (corr.abs().doubleValue() < 0.5 * xUlpDbl) { break; + } } /* * The error in the result is set by the error in x itself. @@ -1115,18 +1136,18 @@ public class BigDecimalMath { * @since 2009-06-01 */ static public BigDecimal cos(final BigDecimal x) throws Error { - if (x.compareTo(BigDecimal.ZERO) < 0) + if (x.compareTo(BigDecimal.ZERO) < 0) { return cos(x.negate()); - else if (x.compareTo(BigDecimal.ZERO) == 0) + } else if (x.compareTo(BigDecimal.ZERO) == 0) { return BigDecimal.ONE; - else { + } else { /* * reduce modulo 2pi */ - BigDecimal res = mod2pi(x); - double errpi = 0.5 * Math.abs(x.ulp().doubleValue()); + final BigDecimal res = mod2pi(x); + final double errpi = 0.5 * Math.abs(x.ulp().doubleValue()); MathContext mc = new MathContext(2 + err2prec(3.14159, errpi)); - BigDecimal p = pi(mc); + final BigDecimal p = pi(mc); mc = new MathContext(x.precision()); if (res.compareTo(p) > 0) { /* @@ -1167,7 +1188,7 @@ public class BigDecimalMath { * The absolute error in the result is the error in x^2/2 * which is x times the error in x. */ - double xUlpDbl = 0.5 * res.ulp().doubleValue() * res.doubleValue(); + final double xUlpDbl = 0.5 * res.ulp().doubleValue() * res.doubleValue(); /* * The error in the result is set by the error in x^2/2 @@ -1176,8 +1197,8 @@ public class BigDecimalMath { * this value. * x^(2k) < xUlpDbl; (2k)*log(x) < log(xUlpDbl); */ - int k = (int) (Math.log(xUlpDbl) / Math.log(res.doubleValue())) / 2; - MathContext mcTay = new MathContext(err2prec(1., xUlpDbl / k)); + final int k = (int) (Math.log(xUlpDbl) / Math.log(res.doubleValue())) / 2; + final MathContext mcTay = new MathContext(err2prec(1., xUlpDbl / k)); for (int i = 1;; i++) { /* * TBD: at which precision will 2*i-1 or 2*i overflow? @@ -1185,10 +1206,11 @@ public class BigDecimalMath { ifac = ifac.multiply(new BigInteger("" + (2 * i - 1))); ifac = ifac.multiply(new BigInteger("" + (2 * i))); xpowi = xpowi.multiply(res).multiply(res).negate(); - BigDecimal corr = xpowi.divide(new BigDecimal(ifac), mcTay); + final BigDecimal corr = xpowi.divide(new BigDecimal(ifac), mcTay); resul = resul.add(corr); - if (corr.abs().doubleValue() < 0.5 * xUlpDbl) + if (corr.abs().doubleValue() < 0.5 * xUlpDbl) { break; + } } /* * The error in the result is governed by the error in x @@ -1210,15 +1232,15 @@ public class BigDecimalMath { * @throws Error */ static public BigDecimal tan(final BigDecimal x) throws Error { - if (x.compareTo(BigDecimal.ZERO) == 0) + if (x.compareTo(BigDecimal.ZERO) == 0) { return BigDecimal.ZERO; - else if (x.compareTo(BigDecimal.ZERO) < 0) { + } else if (x.compareTo(BigDecimal.ZERO) < 0) { return tan(x.negate()).negate(); } else { /* * reduce modulo pi */ - BigDecimal res = modpi(x); + final BigDecimal res = modpi(x); /* * absolute error in the result is err(x)/cos^2(x) to lowest order @@ -1229,8 +1251,8 @@ public class BigDecimalMath { if (xDbl > 0.8) { /* tan(x) = 1/cot(x) */ - BigDecimal co = cot(x); - MathContext mc = new MathContext(err2prec(1. / co.doubleValue(), eps)); + final BigDecimal co = cot(x); + final MathContext mc = new MathContext(err2prec(1. / co.doubleValue(), eps)); return BigDecimal.ONE.divide(co, mc); } else { final BigDecimal xhighpr = scalePrec(res, 2); @@ -1241,7 +1263,7 @@ public class BigDecimalMath { /* x^(2i+1) */ BigDecimal xpowi = xhighpr; - Bernoulli b = new Bernoulli(); + final Bernoulli b = new Bernoulli(); /* 2^(2i) */ BigInteger fourn = new BigInteger("4"); @@ -1254,12 +1276,13 @@ public class BigDecimalMath { fac = fac.multiply(new BigInteger("" + (2 * i))).multiply(new BigInteger("" + (2 * i - 1))); f = f.multiply(fourn).multiply(fourn.subtract(BigInteger.ONE)).divide(fac); xpowi = multiplyRound(xpowi, xhighprSq); - BigDecimal c = multiplyRound(xpowi, f); + final BigDecimal c = multiplyRound(xpowi, f); resul = resul.add(c); - if (Math.abs(c.doubleValue()) < 0.1 * eps) + if (Math.abs(c.doubleValue()) < 0.1 * eps) { break; + } } - MathContext mc = new MathContext(err2prec(resul.doubleValue(), eps)); + final MathContext mc = new MathContext(err2prec(resul.doubleValue(), eps)); return resul.round(mc); } } @@ -1283,7 +1306,7 @@ public class BigDecimalMath { /* * reduce modulo pi */ - BigDecimal res = modpi(x); + final BigDecimal res = modpi(x); /* * absolute error in the result is err(x)/sin^2(x) to lowest order @@ -1301,7 +1324,7 @@ public class BigDecimalMath { /* x^(2i-1) */ BigDecimal xpowi = xhighpr; - Bernoulli b = new Bernoulli(); + final Bernoulli b = new Bernoulli(); /* 2^(2i) */ BigInteger fourn = new BigInteger("4"); @@ -1312,13 +1335,15 @@ public class BigDecimalMath { Rational f = b.at(2 * i); fac = fac.multiply(new BigInteger("" + (2 * i))).multiply(new BigInteger("" + (2 * i - 1))); f = f.multiply(fourn).divide(fac); - BigDecimal c = multiplyRound(xpowi, f); - if (i % 2 == 0) + final BigDecimal c = multiplyRound(xpowi, f); + if (i % 2 == 0) { resul = resul.add(c); - else + } else { resul = resul.subtract(c); - if (Math.abs(c.doubleValue()) < 0.1 * eps) + } + if (Math.abs(c.doubleValue()) < 0.1 * eps) { break; + } fourn = fourn.shiftLeft(2); xpowi = multiplyRound(xpowi, xhighprSq); @@ -1339,14 +1364,14 @@ public class BigDecimalMath { static public BigDecimal asin(final BigDecimal x) throws Error { if (x.compareTo(BigDecimal.ONE) > 0 || x.compareTo(BigDecimal.ONE.negate()) < 0) { throw new ArithmeticException("Out of range argument " + x.toString() + " of asin"); - } else if (x.compareTo(BigDecimal.ZERO) == 0) + } else if (x.compareTo(BigDecimal.ZERO) == 0) { return BigDecimal.ZERO; - else if (x.compareTo(BigDecimal.ONE) == 0) { + } else if (x.compareTo(BigDecimal.ONE) == 0) { /* * arcsin(1) = pi/2 */ - double errpi = Math.sqrt(x.ulp().doubleValue()); - MathContext mc = new MathContext(err2prec(3.14159, errpi)); + final double errpi = Math.sqrt(x.ulp().doubleValue()); + final MathContext mc = new MathContext(err2prec(3.14159, errpi)); return pi(mc).divide(new BigDecimal(2)); } else if (x.compareTo(BigDecimal.ZERO) < 0) { return asin(x.negate()).negate(); @@ -1371,18 +1396,20 @@ public class BigDecimalMath { for (int i = 1;; i++) { ifacN = ifacN.multiply(new BigInteger("" + (2 * i - 1))); ifacD = ifacD.multiply(new BigInteger("" + i)); - if (i == 1) + if (i == 1) { xpowi = xhighprV; - else + } else { xpowi = multiplyRound(xpowi, xhighprV); - BigDecimal c = divideRound(multiplyRound(xpowi, ifacN), ifacD.multiply(new BigInteger("" + (2 * i + 1)))); + } + final BigDecimal c = divideRound(multiplyRound(xpowi, ifacN), ifacD.multiply(new BigInteger("" + (2 * i + 1)))); resul = resul.add(c); /* * series started 1+x/12+... which yields an estimate of the * sum's error */ - if (Math.abs(c.doubleValue()) < xUlpDbl / 120.) + if (Math.abs(c.doubleValue()) < xUlpDbl / 120.) { break; + } } /* * sqrt(2*z)*(1+...) @@ -1391,7 +1418,7 @@ public class BigDecimalMath { resul = multiplyRound(xpowi, resul); MathContext mc = new MathContext(resul.precision()); - BigDecimal pihalf = pi(mc).divide(new BigDecimal(2)); + final BigDecimal pihalf = pi(mc).divide(new BigDecimal(2)); mc = new MathContext(err2prec(resul.doubleValue(), eps)); return pihalf.subtract(resul, mc); @@ -1420,12 +1447,13 @@ public class BigDecimalMath { ifacN = ifacN.multiply(new BigInteger("" + (2 * i - 1))); ifacD = ifacD.multiply(new BigInteger("" + (2 * i))); xpowi = multiplyRound(xpowi, xhighprSq); - BigDecimal c = divideRound(multiplyRound(xpowi, ifacN), ifacD.multiply(new BigInteger("" + (2 * i + 1)))); + final BigDecimal c = divideRound(multiplyRound(xpowi, ifacN), ifacD.multiply(new BigInteger("" + (2 * i + 1)))); resul = resul.add(c); - if (Math.abs(c.doubleValue()) < 0.1 * eps) + if (Math.abs(c.doubleValue()) < 0.1 * eps) { break; + } } - MathContext mc = new MathContext(err2prec(resul.doubleValue(), eps)); + final MathContext mc = new MathContext(err2prec(resul.doubleValue(), eps)); return resul.round(mc); } } /* BigDecimalMath.asin */ @@ -1448,7 +1476,7 @@ public class BigDecimalMath { double eps = resul.ulp().doubleValue() / 2.; MathContext mc = new MathContext(err2prec(3.14159, eps)); - BigDecimal pihalf = pi(mc).divide(new BigDecimal(2)); + final BigDecimal pihalf = pi(mc).divide(new BigDecimal(2)); resul = pihalf.subtract(resul); /* @@ -1476,27 +1504,27 @@ public class BigDecimalMath { static public BigDecimal atan(final BigDecimal x) throws Error { if (x.compareTo(BigDecimal.ZERO) < 0) { return atan(x.negate()).negate(); - } else if (x.compareTo(BigDecimal.ZERO) == 0) + } else if (x.compareTo(BigDecimal.ZERO) == 0) { return BigDecimal.ZERO; - else if (x.doubleValue() > 0.7 && x.doubleValue() < 3.0) { + } else if (x.doubleValue() > 0.7 && x.doubleValue() < 3.0) { /* * Abramowitz-Stegun 4.4.34 convergence acceleration * 2*arctan(x) = arctan(2x/(1-x^2)) = arctan(y). x=(sqrt(1+y^2)-1)/y * This maps 0<=y<=3 to 0<=x<=0.73 roughly. Temporarily with 2 * protectionist digits. */ - BigDecimal y = scalePrec(x, 2); - BigDecimal newx = divideRound(hypot(1, y).subtract(BigDecimal.ONE), y); + final BigDecimal y = scalePrec(x, 2); + final BigDecimal newx = divideRound(hypot(1, y).subtract(BigDecimal.ONE), y); /* intermediate result with too optimistic error estimate */ - BigDecimal resul = multiplyRound(atan(newx), 2); + final BigDecimal resul = multiplyRound(atan(newx), 2); /* * absolute error in the result is errx/(1+x^2), where errx = half * of the ulp. */ - double eps = x.ulp().doubleValue() / (2.0 * Math.hypot(1.0, x.doubleValue())); - MathContext mc = new MathContext(err2prec(resul.doubleValue(), eps)); + final double eps = x.ulp().doubleValue() / (2.0 * Math.hypot(1.0, x.doubleValue())); + final MathContext mc = new MathContext(err2prec(resul.doubleValue(), eps)); return resul.round(mc); } else if (x.doubleValue() < 0.71) { /* Taylor expansion around x=0; Abramowitz-Stegun 4.4.42 */ @@ -1513,17 +1541,18 @@ public class BigDecimalMath { * absolute error in the result is errx/(1+x^2), where errx = half * of the ulp. */ - double eps = x.ulp().doubleValue() / (2.0 * Math.hypot(1.0, x.doubleValue())); + final double eps = x.ulp().doubleValue() / (2.0 * Math.hypot(1.0, x.doubleValue())); for (int i = 1;; i++) { xpowi = multiplyRound(xpowi, xhighprSq); - BigDecimal c = divideRound(xpowi, 2 * i + 1); + final BigDecimal c = divideRound(xpowi, 2 * i + 1); resul = resul.add(c); - if (Math.abs(c.doubleValue()) < 0.1 * eps) + if (Math.abs(c.doubleValue()) < 0.1 * eps) { break; + } } - MathContext mc = new MathContext(err2prec(resul.doubleValue(), eps)); + final MathContext mc = new MathContext(err2prec(resul.doubleValue(), eps)); return resul.round(mc); } else { /* Taylor expansion around x=infinity; Abramowitz-Stegun 4.4.42 */ @@ -1532,14 +1561,14 @@ public class BigDecimalMath { * absolute error in the result is errx/(1+x^2), where errx = half * of the ulp. */ - double eps = x.ulp().doubleValue() / (2.0 * Math.hypot(1.0, x.doubleValue())); + final double eps = x.ulp().doubleValue() / (2.0 * Math.hypot(1.0, x.doubleValue())); /* * start with the term pi/2; gather its precision relative to the * expected result */ MathContext mc = new MathContext(2 + err2prec(3.1416, eps)); - BigDecimal onepi = pi(mc); + final BigDecimal onepi = pi(mc); BigDecimal resul = onepi.divide(new BigDecimal(2)); final BigDecimal xhighpr = divideRound(-1, scalePrec(x, 2)); @@ -1549,11 +1578,12 @@ public class BigDecimalMath { BigDecimal xpowi = xhighpr; for (int i = 0;; i++) { - BigDecimal c = divideRound(xpowi, 2 * i + 1); + final BigDecimal c = divideRound(xpowi, 2 * i + 1); resul = resul.add(c); - if (Math.abs(c.doubleValue()) < 0.1 * eps) + if (Math.abs(c.doubleValue()) < 0.1 * eps) { break; + } xpowi = multiplyRound(xpowi, xhighprSq); } mc = new MathContext(err2prec(resul.doubleValue(), eps)); @@ -1572,18 +1602,18 @@ public class BigDecimalMath { * @since 2009-08-19 */ static public BigDecimal cosh(final BigDecimal x) throws Error { - if (x.compareTo(BigDecimal.ZERO) < 0) + if (x.compareTo(BigDecimal.ZERO) < 0) { return cos(x.negate()); - else if (x.compareTo(BigDecimal.ZERO) == 0) + } else if (x.compareTo(BigDecimal.ZERO) == 0) { return BigDecimal.ONE; - else { + } else { if (x.doubleValue() > 1.5) { /* * cosh^2(x) = 1+ sinh^2(x). */ return hypot(1, sinh(x)); } else { - BigDecimal xhighpr = scalePrec(x, 2); + final BigDecimal xhighpr = scalePrec(x, 2); /* Simple Taylor expansion, sum_{0=1..infinity} x^(2i)/(2i)! */ BigDecimal resul = BigDecimal.ONE; @@ -1597,7 +1627,7 @@ public class BigDecimalMath { * The absolute error in the result is the error in x^2/2 which * is x times the error in x. */ - double xUlpDbl = 0.5 * x.ulp().doubleValue() * x.doubleValue(); + final double xUlpDbl = 0.5 * x.ulp().doubleValue() * x.doubleValue(); /* * The error in the result is set by the error in x^2/2 itself, @@ -1606,7 +1636,7 @@ public class BigDecimalMath { * value. * x^(2k) < xUlpDbl; (2k)*log(x) < log(xUlpDbl); */ - int k = (int) (Math.log(xUlpDbl) / Math.log(x.doubleValue())) / 2; + final int k = (int) (Math.log(xUlpDbl) / Math.log(x.doubleValue())) / 2; /* * The individual terms are all smaller than 1, so an estimate @@ -1614,7 +1644,7 @@ public class BigDecimalMath { * the absolute value will give a safe relative error estimate * for the indivdual terms */ - MathContext mcTay = new MathContext(err2prec(1., xUlpDbl / k)); + final MathContext mcTay = new MathContext(err2prec(1., xUlpDbl / k)); for (int i = 1;; i++) { /* * TBD: at which precision will 2*i-1 or 2*i overflow? @@ -1622,15 +1652,16 @@ public class BigDecimalMath { ifac = ifac.multiply(new BigInteger("" + (2 * i - 1))); ifac = ifac.multiply(new BigInteger("" + (2 * i))); xpowi = xpowi.multiply(xhighpr).multiply(xhighpr); - BigDecimal corr = xpowi.divide(new BigDecimal(ifac), mcTay); + final BigDecimal corr = xpowi.divide(new BigDecimal(ifac), mcTay); resul = resul.add(corr); - if (corr.abs().doubleValue() < 0.5 * xUlpDbl) + if (corr.abs().doubleValue() < 0.5 * xUlpDbl) { break; + } } /* * The error in the result is governed by the error in x itself. */ - MathContext mc = new MathContext(err2prec(resul.doubleValue(), xUlpDbl)); + final MathContext mc = new MathContext(err2prec(resul.doubleValue(), xUlpDbl)); return resul.round(mc); } } @@ -1647,18 +1678,18 @@ public class BigDecimalMath { * @since 2009-08-19 */ static public BigDecimal sinh(final BigDecimal x) throws Error { - if (x.compareTo(BigDecimal.ZERO) < 0) + if (x.compareTo(BigDecimal.ZERO) < 0) { return sinh(x.negate()).negate(); - else if (x.compareTo(BigDecimal.ZERO) == 0) + } else if (x.compareTo(BigDecimal.ZERO) == 0) { return BigDecimal.ZERO; - else { + } else { if (x.doubleValue() > 2.4) { /* * Move closer to zero with sinh(2x)= 2*sinh(x)*cosh(x). */ - BigDecimal two = new BigDecimal(2); - BigDecimal xhalf = x.divide(two); - BigDecimal resul = sinh(xhalf).multiply(cosh(xhalf)).multiply(two); + final BigDecimal two = new BigDecimal(2); + final BigDecimal xhalf = x.divide(two); + final BigDecimal resul = sinh(xhalf).multiply(cosh(xhalf)).multiply(two); /* * The error in the result is set by the error in x itself. * The first derivative of sinh(x) is cosh(x), so the absolute @@ -1666,11 +1697,11 @@ public class BigDecimalMath { * in the result is cosh(x)*errx, and the relative error is * coth(x)*errx = errx/tanh(x) */ - double eps = Math.tanh(x.doubleValue()); - MathContext mc = new MathContext(err2prec(0.5 * x.ulp().doubleValue() / eps)); + final double eps = Math.tanh(x.doubleValue()); + final MathContext mc = new MathContext(err2prec(0.5 * x.ulp().doubleValue() / eps)); return resul.round(mc); } else { - BigDecimal xhighpr = scalePrec(x, 2); + final BigDecimal xhighpr = scalePrec(x, 2); /* * Simple Taylor expansion, sum_{i=0..infinity} x^(2i+1)/(2i+1)! */ @@ -1685,7 +1716,7 @@ public class BigDecimalMath { /* * The error in the result is set by the error in x itself. */ - double xUlpDbl = x.ulp().doubleValue(); + final double xUlpDbl = x.ulp().doubleValue(); /* * The error in the result is set by the error in x itself. @@ -1695,8 +1726,8 @@ public class BigDecimalMath { * 2k*log10(x)< -x.precision; * 2k*(-log10(x)) > x.precision; 2k*log10(1/x) > x.precision */ - int k = (int) (x.precision() / Math.log10(1.0 / xhighpr.doubleValue())) / 2; - MathContext mcTay = new MathContext(err2prec(x.doubleValue(), xUlpDbl / k)); + final int k = (int) (x.precision() / Math.log10(1.0 / xhighpr.doubleValue())) / 2; + final MathContext mcTay = new MathContext(err2prec(x.doubleValue(), xUlpDbl / k)); for (int i = 1;; i++) { /* * TBD: at which precision will 2*i or 2*i+1 overflow? @@ -1704,15 +1735,16 @@ public class BigDecimalMath { ifac = ifac.multiply(new BigInteger("" + (2 * i))); ifac = ifac.multiply(new BigInteger("" + (2 * i + 1))); xpowi = xpowi.multiply(xhighpr).multiply(xhighpr); - BigDecimal corr = xpowi.divide(new BigDecimal(ifac), mcTay); + final BigDecimal corr = xpowi.divide(new BigDecimal(ifac), mcTay); resul = resul.add(corr); - if (corr.abs().doubleValue() < 0.5 * xUlpDbl) + if (corr.abs().doubleValue() < 0.5 * xUlpDbl) { break; + } } /* * The error in the result is set by the error in x itself. */ - MathContext mc = new MathContext(x.precision()); + final MathContext mc = new MathContext(x.precision()); return resul.round(mc); } } @@ -1728,23 +1760,23 @@ public class BigDecimalMath { * @since 2009-08-20 */ static public BigDecimal tanh(final BigDecimal x) { - if (x.compareTo(BigDecimal.ZERO) < 0) + if (x.compareTo(BigDecimal.ZERO) < 0) { return tanh(x.negate()).negate(); - else if (x.compareTo(BigDecimal.ZERO) == 0) + } else if (x.compareTo(BigDecimal.ZERO) == 0) { return BigDecimal.ZERO; - else { - BigDecimal xhighpr = scalePrec(x, 2); + } else { + final BigDecimal xhighpr = scalePrec(x, 2); /* * tanh(x) = (1-e^(-2x))/(1+e^(-2x)) . */ - BigDecimal exp2x = exp(xhighpr.multiply(new BigDecimal(-2))); + final BigDecimal exp2x = exp(xhighpr.multiply(new BigDecimal(-2))); /* * The error in tanh x is err(x)/cosh^2(x). */ - double eps = 0.5 * x.ulp().doubleValue() / Math.pow(Math.cosh(x.doubleValue()), 2.0); - MathContext mc = new MathContext(err2prec(Math.tanh(x.doubleValue()), eps)); + final double eps = 0.5 * x.ulp().doubleValue() / Math.pow(Math.cosh(x.doubleValue()), 2.0); + final MathContext mc = new MathContext(err2prec(Math.tanh(x.doubleValue()), eps)); return BigDecimal.ONE.subtract(exp2x).divide(BigDecimal.ONE.add(exp2x), mc); } } /* BigDecimalMath.tanh */ @@ -1759,22 +1791,22 @@ public class BigDecimalMath { * @since 2009-08-20 */ static public BigDecimal asinh(final BigDecimal x) { - if (x.compareTo(BigDecimal.ZERO) == 0) + if (x.compareTo(BigDecimal.ZERO) == 0) { return BigDecimal.ZERO; - else { - BigDecimal xhighpr = scalePrec(x, 2); + } else { + final BigDecimal xhighpr = scalePrec(x, 2); /* * arcsinh(x) = log(x+hypot(1,x)) */ - BigDecimal logx = log(hypot(1, xhighpr).add(xhighpr)); + final BigDecimal logx = log(hypot(1, xhighpr).add(xhighpr)); /* * The absolute error in arcsinh x is err(x)/sqrt(1+x^2) */ - double xDbl = x.doubleValue(); - double eps = 0.5 * x.ulp().doubleValue() / Math.hypot(1., xDbl); - MathContext mc = new MathContext(err2prec(logx.doubleValue(), eps)); + final double xDbl = x.doubleValue(); + final double eps = 0.5 * x.ulp().doubleValue() / Math.hypot(1., xDbl); + final MathContext mc = new MathContext(err2prec(logx.doubleValue(), eps)); return logx.round(mc); } } /* BigDecimalMath.asinh */ @@ -1789,24 +1821,24 @@ public class BigDecimalMath { * @since 2009-08-20 */ static public BigDecimal acosh(final BigDecimal x) { - if (x.compareTo(BigDecimal.ONE) < 0) + if (x.compareTo(BigDecimal.ONE) < 0) { throw new ArithmeticException("Out of range argument cosh " + x.toString()); - else if (x.compareTo(BigDecimal.ONE) == 0) + } else if (x.compareTo(BigDecimal.ONE) == 0) { return BigDecimal.ZERO; - else { - BigDecimal xhighpr = scalePrec(x, 2); + } else { + final BigDecimal xhighpr = scalePrec(x, 2); /* * arccosh(x) = log(x+sqrt(x^2-1)) */ - BigDecimal logx = log(sqrt(xhighpr.pow(2).subtract(BigDecimal.ONE)).add(xhighpr)); + final BigDecimal logx = log(sqrt(xhighpr.pow(2).subtract(BigDecimal.ONE)).add(xhighpr)); /* * The absolute error in arcsinh x is err(x)/sqrt(x^2-1) */ - double xDbl = x.doubleValue(); - double eps = 0.5 * x.ulp().doubleValue() / Math.sqrt(xDbl * xDbl - 1.); - MathContext mc = new MathContext(err2prec(logx.doubleValue(), eps)); + final double xDbl = x.doubleValue(); + final double eps = 0.5 * x.ulp().doubleValue() / Math.sqrt(xDbl * xDbl - 1.); + final MathContext mc = new MathContext(err2prec(logx.doubleValue(), eps)); return logx.round(mc); } } /* BigDecimalMath.acosh */ @@ -1825,14 +1857,14 @@ public class BigDecimalMath { * reduce to interval near 1.0 with the functional relation, * Abramowitz-Stegun 6.1.33 */ - if (x.compareTo(BigDecimal.ZERO) < 0) + if (x.compareTo(BigDecimal.ZERO) < 0) { return divideRound(Gamma(x.add(BigDecimal.ONE)), x); - else if (x.doubleValue() > 1.5) { + } else if (x.doubleValue() > 1.5) { /* * Gamma(x) = Gamma(xmin+n) = Gamma(xmin)*Pochhammer(xmin,n). */ - int n = (int) (x.doubleValue() - 0.5); - BigDecimal xmin1 = x.subtract(new BigDecimal(n)); + final int n = (int) (x.doubleValue() - 0.5); + final BigDecimal xmin1 = x.subtract(new BigDecimal(n)); return multiplyRound(Gamma(xmin1), pochhammer(xmin1, n)); } else { /* @@ -1856,7 +1888,7 @@ public class BigDecimalMath { if (x.compareTo(BigDecimal.ONE) != 0) { - BigDecimal gammCompl = BigDecimal.ONE.subtract(gamma(mcloc)); + final BigDecimal gammCompl = BigDecimal.ONE.subtract(gamma(mcloc)); resul = resul.add(multiplyRound(z, gammCompl)); for (int n = 2;; n++) { /* @@ -1884,24 +1916,27 @@ public class BigDecimalMath { * error in zeta, because zeta is * of the order of 1. */ - if (eps / 100. / c.doubleValue() < 0.01) + if (eps / 100. / c.doubleValue() < 0.01) { m = new MathContext(err2prec(eps / 100. / c.doubleValue())); - else + } else { m = new MathContext(2); + } /* zeta(n) -1 */ - BigDecimal zetm1 = zeta(n, m).subtract(BigDecimal.ONE); + final BigDecimal zetm1 = zeta(n, m).subtract(BigDecimal.ONE); c = multiplyRound(c, zetm1); - if (n % 2 == 0) + if (n % 2 == 0) { resul = resul.add(c); - else + } else { resul = resul.subtract(c); + } /* * alternating sum, so truncating as eps is reached suffices */ - if (Math.abs(c.doubleValue()) < eps) + if (Math.abs(c.doubleValue()) < eps) { break; + } } } @@ -1909,7 +1944,7 @@ public class BigDecimalMath { * The relative error in the result is the absolute error in the * input variable times the digamma (psi) value at that point. */ - double zdbl = z.doubleValue(); + final double zdbl = z.doubleValue(); eps = psi(zdbl) * x.ulp().doubleValue() / 2.; mcloc = new MathContext(err2prec(eps)); return exp(resul).round(mcloc); @@ -1929,19 +1964,19 @@ public class BigDecimalMath { */ static public BigDecimal Gamma(final Rational q, final MathContext mc) throws Error { if (q.isBigInteger()) { - if (q.compareTo(Rational.ZERO) <= 0) + if (q.compareTo(Rational.ZERO) <= 0) { throw new ArithmeticException("Gamma at " + q.toString()); - else { + } else { /* Gamma(n) = (n-1)! */ - Factorial f = new Factorial(); - BigInteger g = f.at(q.trunc().intValue() - 1); + final Factorial f = new Factorial(); + final BigInteger g = f.at(q.trunc().intValue() - 1); return scalePrec(new BigDecimal(g), mc); } } else if (q.b.intValue() == 2) { /* * half integer cases which are related to sqrt(pi) */ - BigDecimal p = sqrt(pi(mc)); + final BigDecimal p = sqrt(pi(mc)); if (q.compareTo(Rational.ZERO) >= 0) { Rational pro = Rational.ONE; Rational f = q.subtract(1); @@ -1965,11 +2000,11 @@ public class BigDecimalMath { * Delta(x) such * that this is equivalent to mc: Delta(x) = precision/psi(x). */ - double qdbl = q.doubleValue(); - double deltx = 5. * Math.pow(10., -mc.getPrecision()) / psi(qdbl); + final double qdbl = q.doubleValue(); + final double deltx = 5. * Math.pow(10., -mc.getPrecision()) / psi(qdbl); - MathContext mcx = new MathContext(err2prec(qdbl, deltx)); - BigDecimal x = q.BigDecimalValue(mcx); + final MathContext mcx = new MathContext(err2prec(qdbl, deltx)); + final BigDecimal x = q.BigDecimalValue(mcx); /* forward calculation to the general floating point case */ return Gamma(x); @@ -1991,19 +2026,19 @@ public class BigDecimalMath { * reduce to interval near 1.0 with the functional relation, * Abramowitz-Stegun 6.1.33 */ - if (n < 0) + if (n < 0) { throw new ProviderException("Not implemented: pochhammer with negative index " + n); - else if (n == 0) + } else if (n == 0) { return BigDecimal.ONE; - else { + } else { /* * internally two safety digits */ - BigDecimal xhighpr = scalePrec(x, 2); + final BigDecimal xhighpr = scalePrec(x, 2); BigDecimal resul = xhighpr; - double xUlpDbl = x.ulp().doubleValue(); - double xDbl = x.doubleValue(); + final double xUlpDbl = x.ulp().doubleValue(); + final double xDbl = x.doubleValue(); /* * relative error of the result is the sum of the relative errors of * the factors @@ -2037,19 +2072,20 @@ public class BigDecimalMath { * First get a guess of k to figure out how many digits of 2*pi are * needed. */ - int k = (int) (0.5 * x.doubleValue() / Math.PI); + final int k = (int) (0.5 * x.doubleValue() / Math.PI); /* * want to have err(2*pi*k)< err(x)=0.5*x.ulp, so err(pi) = err(x)/(4k) * with two safety digits */ double err2pi; - if (k != 0) + if (k != 0) { err2pi = 0.25 * Math.abs(x.ulp().doubleValue() / k); - else + } else { err2pi = 0.5 * Math.abs(x.ulp().doubleValue()); + } MathContext mc = new MathContext(2 + err2prec(6.283, err2pi)); - BigDecimal twopi = pi(mc).multiply(new BigDecimal(2)); + final BigDecimal twopi = pi(mc).multiply(new BigDecimal(2)); /* * Delegate the actual operation to the BigDecimal class, which may @@ -2057,8 +2093,9 @@ public class BigDecimalMath { * a negative value of x was negative . */ BigDecimal res = x.remainder(twopi); - if (res.compareTo(BigDecimal.ZERO) < 0) + if (res.compareTo(BigDecimal.ZERO) < 0) { res = res.add(twopi); + } /* * The actual precision is set by the input value, its absolute value of @@ -2086,20 +2123,21 @@ public class BigDecimalMath { * First get a guess of k to figure out how many digits of pi are * needed. */ - int k = (int) (x.doubleValue() / Math.PI); + final int k = (int) (x.doubleValue() / Math.PI); /* * want to have err(pi*k)< err(x)=x.ulp/2, so err(pi) = err(x)/(2k) with * two safety digits */ double errpi; - if (k != 0) + if (k != 0) { errpi = 0.5 * Math.abs(x.ulp().doubleValue() / k); - else + } else { errpi = 0.5 * Math.abs(x.ulp().doubleValue()); + } MathContext mc = new MathContext(2 + err2prec(3.1416, errpi)); - BigDecimal onepi = pi(mc); - BigDecimal pihalf = onepi.divide(new BigDecimal(2)); + final BigDecimal onepi = pi(mc); + final BigDecimal pihalf = onepi.divide(new BigDecimal(2)); /* * Delegate the actual operation to the BigDecimal class, which may @@ -2107,10 +2145,11 @@ public class BigDecimalMath { * a negative value of x was negative . */ BigDecimal res = x.remainder(onepi); - if (res.compareTo(pihalf) > 0) + if (res.compareTo(pihalf) > 0) { res = res.subtract(onepi); - else if (res.compareTo(pihalf.negate()) < 0) + } else if (res.compareTo(pihalf.negate()) < 0) { res = res.add(onepi); + } /* * The actual precision is set by the input value, its absolute value of @@ -2132,10 +2171,12 @@ public class BigDecimalMath { * @since 2009-08-05 */ static public BigDecimal zeta(final int n, final MathContext mc) throws Error { - if (n <= 0) + if (n <= 0) { throw new ProviderException("Not implemented: zeta at negative argument " + n); - if (n == 1) + } + if (n == 1) { throw new ArithmeticException("Pole at zeta(1) "); + } if (n % 2 == 0) { /* @@ -2154,7 +2195,7 @@ public class BigDecimalMath { * Need one more digit in pi if n=10, two digits if n=100 etc, and * add one extra digit. */ - MathContext mcpi = new MathContext(mc.getPrecision() + (int) (Math.log10(10.0 * n))); + final MathContext mcpi = new MathContext(mc.getPrecision() + (int) (Math.log10(10.0 * n))); final BigDecimal piton = pi(mcpi).pow(n, mc); return multiplyRound(piton, b); } else if (n == 3) { @@ -2163,8 +2204,8 @@ public class BigDecimalMath { * href="http://arxiv.org/abs/math/9803067">arXiv:math/9803067 * Error propagation: S31 is roughly 0.087, S33 roughly 0.131 */ - int[] a31 = { 1, -7, -1, 10, -1, -7, 1, 0 }; - int[] a33 = { 1, 1, -1, -2, -1, 1, 1, 0 }; + final int[] a31 = { 1, -7, -1, 10, -1, -7, 1, 0 }; + final int[] a33 = { 1, 1, -1, -2, -1, 1, 1, 0 }; BigDecimal S31 = broadhurstBBP(3, 1, a31, mc); BigDecimal S33 = broadhurstBBP(3, 3, a33, mc); S31 = S31.multiply(new BigDecimal(48)); @@ -2181,9 +2222,9 @@ public class BigDecimalMath { * The result is of the order 1.03, so we add 2 digits to S51 and * S52 and one digit to S55. */ - int[] a51 = { 31, -1614, -31, -6212, -31, -1614, 31, 74552 }; - int[] a53 = { 173, 284, -173, -457, -173, 284, 173, -111 }; - int[] a55 = { 1, 0, -1, -1, -1, 0, 1, 1 }; + final int[] a51 = { 31, -1614, -31, -6212, -31, -1614, 31, 74552 }; + final int[] a53 = { 173, 284, -173, -457, -173, 284, 173, -111 }; + final int[] a55 = { 1, 0, -1, -1, -1, 0, 1, 1 }; BigDecimal S51 = broadhurstBBP(5, 1, a51, new MathContext(2 + mc.getPrecision())); BigDecimal S53 = broadhurstBBP(5, 3, a53, new MathContext(2 + mc.getPrecision())); BigDecimal S55 = broadhurstBBP(5, 5, a55, new MathContext(1 + mc.getPrecision())); @@ -2196,16 +2237,17 @@ public class BigDecimalMath { * Cohen et al Exp Math 1 (1) (1992) 25 */ Rational betsum = new Rational(); - Bernoulli bern = new Bernoulli(); - Factorial fact = new Factorial(); + final Bernoulli bern = new Bernoulli(); + final Factorial fact = new Factorial(); for (int npr = 0; npr <= (n + 1) / 2; npr++) { Rational b = bern.at(2 * npr).multiply(bern.at(n + 1 - 2 * npr)); b = b.divide(fact.at(2 * npr)).divide(fact.at(n + 1 - 2 * npr)); b = b.multiply(1 - 2 * npr); - if (npr % 2 == 0) + if (npr % 2 == 0) { betsum = betsum.add(b); - else + } else { betsum = betsum.subtract(b); + } } betsum = betsum.divide(n - 1); /* @@ -2216,7 +2258,7 @@ public class BigDecimalMath { * and the precision * requested for 2*pi is in absolute terms adjusted. */ - MathContext mcloc = new MathContext(2 + mc.getPrecision() + (int) (Math.log10((n)))); + final MathContext mcloc = new MathContext(2 + mc.getPrecision() + (int) (Math.log10((n)))); BigDecimal ftrm = pi(mcloc).multiply(new BigDecimal(2)); ftrm = ftrm.pow(n); ftrm = multiplyRound(ftrm, betsum.BigDecimalValue(mcloc)); @@ -2237,7 +2279,7 @@ public class BigDecimalMath { * want 2 times these terms * fall below eps/10. */ - int kmax = mc.getPrecision() / 3; + final int kmax = mc.getPrecision() / 3; eps /= kmax; /* * need an error of eps for 2/(exp(2pi)-1) = 0.0037 @@ -2268,7 +2310,7 @@ public class BigDecimalMath { * 0.0096, 0.5e-7, 0.3e-11, 0.6e-15 etc. We want these terms * fall below eps/10. */ - int kmax = (1 + mc.getPrecision()) / 3; + final int kmax = (1 + mc.getPrecision()) / 3; eps /= kmax; /* * need an error of eps for @@ -2279,7 +2321,7 @@ public class BigDecimalMath { */ BigDecimal twop = pi(new MathContext(3 + err2prec(3.14, eps / 0.017))); twop = twop.multiply(new BigDecimal(2)); - BigDecimal exp2p = exp(twop); + final BigDecimal exp2p = exp(twop); BigDecimal c = exp2p.subtract(BigDecimal.ONE); exps = divideRound(1, c); c = BigDecimal.ONE.subtract(divideRound(1, exp2p)); @@ -2319,22 +2361,24 @@ public class BigDecimalMath { * precomputed static table in double precision */ final double[] zmin1 = { 0., 0., 6.449340668482264364724151666e-01, 2.020569031595942853997381615e-01, 8.232323371113819151600369654e-02, 3.692775514336992633136548646e-02, 1.734306198444913971451792979e-02, 8.349277381922826839797549850e-03, 4.077356197944339378685238509e-03, 2.008392826082214417852769232e-03, 9.945751278180853371459589003e-04, 4.941886041194645587022825265e-04, 2.460865533080482986379980477e-04, 1.227133475784891467518365264e-04, 6.124813505870482925854510514e-05, 3.058823630702049355172851064e-05, 1.528225940865187173257148764e-05, 7.637197637899762273600293563e-06, 3.817293264999839856461644622e-06, 1.908212716553938925656957795e-06, 9.539620338727961131520386834e-07, 4.769329867878064631167196044e-07, 2.384505027277329900036481868e-07, 1.192199259653110730677887189e-07, 5.960818905125947961244020794e-08, 2.980350351465228018606370507e-08, 1.490155482836504123465850663e-08, 7.450711789835429491981004171e-09, 3.725334024788457054819204018e-09, 1.862659723513049006403909945e-09, 9.313274324196681828717647350e-10, 4.656629065033784072989233251e-10, 2.328311833676505492001455976e-10, 1.164155017270051977592973835e-10, 5.820772087902700889243685989e-11, 2.910385044497099686929425228e-11, 1.455192189104198423592963225e-11, 7.275959835057481014520869012e-12, 3.637979547378651190237236356e-12, 1.818989650307065947584832101e-12, 9.094947840263889282533118387e-13, 4.547473783042154026799112029e-13, 2.273736845824652515226821578e-13, 1.136868407680227849349104838e-13, 5.684341987627585609277182968e-14, 2.842170976889301855455073705e-14, 1.421085482803160676983430714e-14, 7.105427395210852712877354480e-15, 3.552713691337113673298469534e-15, 1.776356843579120327473349014e-15, 8.881784210930815903096091386e-16, 4.440892103143813364197770940e-16, 2.220446050798041983999320094e-16, 1.110223025141066133720544570e-16, 5.551115124845481243723736590e-17, 2.775557562136124172581632454e-17, 1.387778780972523276283909491e-17, 6.938893904544153697446085326e-18, 3.469446952165922624744271496e-18, 1.734723476047576572048972970e-18, 8.673617380119933728342055067e-19, 4.336808690020650487497023566e-19, 2.168404344997219785013910168e-19, 1.084202172494241406301271117e-19, 5.421010862456645410918700404e-20, 2.710505431223468831954621312e-20, 1.355252715610116458148523400e-20, 6.776263578045189097995298742e-21, 3.388131789020796818085703100e-21, 1.694065894509799165406492747e-21, 8.470329472546998348246992609e-22, 4.235164736272833347862270483e-22, 2.117582368136194731844209440e-22, 1.058791184068023385226500154e-22, 5.293955920339870323813912303e-23, 2.646977960169852961134116684e-23, 1.323488980084899080309451025e-23, 6.617444900424404067355245332e-24, 3.308722450212171588946956384e-24, 1.654361225106075646229923677e-24, 8.271806125530344403671105617e-25, 4.135903062765160926009382456e-25, 2.067951531382576704395967919e-25, 1.033975765691287099328409559e-25, 5.169878828456431320410133217e-26, 2.584939414228214268127761771e-26, 1.292469707114106670038112612e-26, 6.462348535570531803438002161e-27, 3.231174267785265386134814118e-27, 1.615587133892632521206011406e-27, 8.077935669463162033158738186e-28, 4.038967834731580825622262813e-28, 2.019483917365790349158762647e-28, 1.009741958682895153361925070e-28, 5.048709793414475696084771173e-29, 2.524354896707237824467434194e-29, 1.262177448353618904375399966e-29, 6.310887241768094495682609390e-30, 3.155443620884047239109841220e-30, 1.577721810442023616644432780e-30, 7.888609052210118073520537800e-31 }; - if (n <= 0) + if (n <= 0) { throw new ProviderException("Not implemented: zeta at negative argument " + n); - if (n == 1) + } + if (n == 1) { throw new ArithmeticException("Pole at zeta(1) "); + } - if (n < zmin1.length) + if (n < zmin1.length) { /* look it up if available */ return zmin1[n]; - else { + } else { /* * Result is roughly 2^(-n), desired accuracy 18 digits. If zeta(n) * is computed, the equivalent accuracy * in relative units is higher, because zeta is around 1. */ - double eps = 1.e-18 * Math.pow(2., (-n)); - MathContext mc = new MathContext(err2prec(eps)); + final double eps = 1.e-18 * Math.pow(2., (-n)); + final MathContext mc = new MathContext(err2prec(eps)); return zeta(n, mc).subtract(BigDecimal.ONE).doubleValue(); } } /* zeta */ @@ -2371,11 +2415,12 @@ public class BigDecimalMath { * Reduce to a value near x=1 with the standard recurrence formula. * Abramowitz-Stegun 6.3.5 */ - int m = (int) (x - 0.5); - double xmin1 = x - m; + final int m = (int) (x - 0.5); + final double xmin1 = x - m; double resul = 0.; - for (int i = 1; i <= m; i++) + for (int i = 1; i <= m; i++) { resul += 1. / (x - i); + } return resul + psi(xmin1); } else if (Math.abs(x - psi0) < 0.55) { /* @@ -2384,15 +2429,16 @@ public class BigDecimalMath { final double[] psiT0 = { 9.67672245447621170427e-01, -4.42763168983592106093e-01, 2.58499760955651010624e-01, -1.63942705442406527504e-01, 1.07824050691262365757e-01, -7.21995612564547109261e-02, 4.88042881641431072251e-02, -3.31611264748473592923e-02, 2.25976482322181046596e-02, -1.54247659049489591388e-02, 1.05387916166121753881e-02, -7.20453438635686824097e-03, 4.92678139572985344635e-03, -3.36980165543932808279e-03, 2.30512632673492783694e-03, -1.57693677143019725927e-03, 1.07882520191629658069e-03, -7.38070938996005129566e-04, 5.04953265834602035177e-04, -3.45468025106307699556e-04, 2.36356015640270527924e-04, -1.61706220919748034494e-04, 1.10633727687474109041e-04, -7.56917958219506591924e-05, 5.17857579522208086899e-05, -3.54300709476596063157e-05, 2.42400661186013176527e-05, -1.65842422718541333752e-05, 1.13463845846638498067e-05, -7.76281766846209442527e-06, 5.31106092088986338732e-06, -3.63365078980104566837e-06, 2.48602273312953794890e-06, -1.70085388543326065825e-06, 1.16366753635488427029e-06, -7.96142543124197040035e-07, 5.44694193066944527850e-07, -3.72661612834382295890e-07, 2.54962655202155425666e-07, -1.74436951177277452181e-07, 1.19343948298302427790e-07, -8.16511518948840884084e-08, 5.58629968353217144428e-08, -3.82196006191749421243e-08, 2.61485769519618662795e-08, -1.78899848649114926515e-08, 1.22397314032336619391e-08, -8.37401629767179054290e-09, 5.72922285984999377160e-09 }; final double xdiff = x - psi0; double resul = 0.; - for (int i = psiT0.length - 1; i >= 0; i--) + for (int i = psiT0.length - 1; i >= 0; i--) { resul = resul * xdiff + psiT0[i]; + } return resul * xdiff; } else if (x < 0.) { /* Reflection formula */ - double xmin = 1. - x; + final double xmin = 1. - x; return psi(xmin) + Math.PI / Math.tan(Math.PI * xmin); } else { - double xmin1 = x - 1; + final double xmin1 = x - 1; double resul = 0.; for (int k = 26; k >= 1; k--) { resul -= zeta1(2 * k + 1); @@ -2421,8 +2467,9 @@ public class BigDecimalMath { * estimate. */ double x = 0.0; - for (int k = 1; k < 10; k++) + for (int k = 1; k < 10; k++) { x += a[(k - 1) % 8] / Math.pow(2., p * (k + 1) / 2) / Math.pow(k, n); + } /* * Convert the relative precision and estimate of the result into an @@ -2439,7 +2486,7 @@ public class BigDecimalMath { * 10^(-precision) with c the 8term * cycles yields c=log_2( 10^precision)/4p = 3.3*precision/4p with k=8c */ - int kmax = (int) (6.6 * mc.getPrecision() / p); + final int kmax = (int) (6.6 * mc.getPrecision() / p); /* Now eps is the absolute error in each term */ eps /= kmax; @@ -2451,14 +2498,15 @@ public class BigDecimalMath { /* * floor( (pk+p)/2) */ - int pk1h = p * (2 + 8 * c + k) / 2; + final int pk1h = p * (2 + 8 * c + k) / 2; tmp = tmp.divide(BigInteger.ONE.shiftLeft(pk1h)); r = r.add(tmp); } - if (Math.abs(r.doubleValue()) < eps) + if (Math.abs(r.doubleValue()) < eps) { break; - MathContext mcloc = new MathContext(1 + err2prec(r.doubleValue(), eps)); + } + final MathContext mcloc = new MathContext(1 + err2prec(r.doubleValue(), eps)); res = res.add(r.BigDecimalValue(mcloc)); } return res.round(mc); @@ -2489,17 +2537,17 @@ public class BigDecimalMath { * @since 2009-07-30 */ static public BigDecimal addRound(final BigDecimal x, final BigDecimal y) { - BigDecimal resul = x.add(y); + final BigDecimal resul = x.add(y); /* * The estimation of the absolute error in the result is * |err(y)|+|err(x)| */ - double errR = Math.abs(y.ulp().doubleValue() / 2.) + Math.abs(x.ulp().doubleValue() / 2.); + final double errR = Math.abs(y.ulp().doubleValue() / 2.) + Math.abs(x.ulp().doubleValue() / 2.); int err2prec = err2prec(resul.doubleValue(), errR); if (err2prec < 0) { err2prec = 0; } - MathContext mc = new MathContext(err2prec); + final MathContext mc = new MathContext(err2prec); return resul.round(mc); } /* addRound */ @@ -2545,13 +2593,13 @@ public class BigDecimalMath { * @since 2009-07-30 */ static public BigDecimal subtractRound(final BigDecimal x, final BigDecimal y) { - BigDecimal resul = x.subtract(y); + final BigDecimal resul = x.subtract(y); /* * The estimation of the absolute error in the result is * |err(y)|+|err(x)| */ - double errR = Math.abs(y.ulp().doubleValue() / 2.) + Math.abs(x.ulp().doubleValue() / 2.); - MathContext mc = new MathContext(err2prec(resul.doubleValue(), errR)); + final double errR = Math.abs(y.ulp().doubleValue() / 2.) + Math.abs(x.ulp().doubleValue() / 2.); + final MathContext mc = new MathContext(err2prec(resul.doubleValue(), errR)); return resul.round(mc); } /* subtractRound */ @@ -2582,13 +2630,13 @@ public class BigDecimalMath { * @since 2009-07-30 */ static public BigDecimal multiplyRound(final BigDecimal x, final BigDecimal y) { - BigDecimal resul = x.multiply(y); + final BigDecimal resul = x.multiply(y); /* * The estimation of the relative error in the result is the sum of the * relative * errors |err(y)/y|+|err(x)/x| */ - MathContext mc = new MathContext(Math.min(x.precision(), y.precision())); + final MathContext mc = new MathContext(Math.min(x.precision(), y.precision())); return resul.round(mc); } /* multiplyRound */ @@ -2603,8 +2651,8 @@ public class BigDecimalMath { * @since 2010-07-19 */ static public BigComplex multiplyRound(final BigComplex x, final BigDecimal y) { - BigDecimal R = multiplyRound(x.re, y); - BigDecimal I = multiplyRound(x.im, y); + final BigDecimal R = multiplyRound(x.re, y); + final BigDecimal I = multiplyRound(x.im, y); return new BigComplex(R, I); } /* multiplyRound */ @@ -2619,8 +2667,8 @@ public class BigDecimalMath { * @since 2010-07-19 */ static public BigComplex multiplyRound(final BigComplex x, final BigComplex y) { - BigDecimal R = subtractRound(multiplyRound(x.re, y.re), multiplyRound(x.im, y.im)); - BigDecimal I = addRound(multiplyRound(x.re, y.im), multiplyRound(x.im, y.re)); + final BigDecimal R = subtractRound(multiplyRound(x.re, y.re), multiplyRound(x.im, y.im)); + final BigDecimal I = addRound(multiplyRound(x.re, y.im), multiplyRound(x.im, y.re)); return new BigComplex(R, I); } /* multiplyRound */ @@ -2635,14 +2683,14 @@ public class BigDecimalMath { * @since 2009-07-30 */ static public BigDecimal multiplyRound(final BigDecimal x, final Rational f) { - if (f.compareTo(BigInteger.ZERO) == 0) + if (f.compareTo(BigInteger.ZERO) == 0) { return BigDecimal.ZERO; - else { + } else { /* * Convert the rational value with two digits of extra precision */ - MathContext mc = new MathContext(2 + x.precision()); - BigDecimal fbd = f.BigDecimalValue(mc); + final MathContext mc = new MathContext(2 + x.precision()); + final BigDecimal fbd = f.BigDecimalValue(mc); /* * and the precision of the product is then dominated by the @@ -2663,11 +2711,11 @@ public class BigDecimalMath { * @since 2009-07-30 */ static public BigDecimal multiplyRound(final BigDecimal x, final int n) { - BigDecimal resul = x.multiply(new BigDecimal(n)); + final BigDecimal resul = x.multiply(new BigDecimal(n)); /* * The estimation of the absolute error in the result is |n*err(x)| */ - MathContext mc = new MathContext(n != 0 ? x.precision() : 0); + final MathContext mc = new MathContext(n != 0 ? x.precision() : 0); return resul.round(mc); } @@ -2682,11 +2730,11 @@ public class BigDecimalMath { * @since 2009-07-30 */ static public BigDecimal multiplyRound(final BigDecimal x, final BigInteger n) { - BigDecimal resul = x.multiply(new BigDecimal(n)); + final BigDecimal resul = x.multiply(new BigDecimal(n)); /* * The estimation of the absolute error in the result is |n*err(x)| */ - MathContext mc = new MathContext(n.compareTo(BigInteger.ZERO) != 0 ? x.precision() : 0); + final MathContext mc = new MathContext(n.compareTo(BigInteger.ZERO) != 0 ? x.precision() : 0); return resul.round(mc); } @@ -2705,8 +2753,8 @@ public class BigDecimalMath { * The estimation of the relative error in the result is * |err(y)/y|+|err(x)/x| */ - MathContext mc = new MathContext(Math.min(x.precision(), y.precision())); - BigDecimal resul = x.divide(y, mc); + final MathContext mc = new MathContext(Math.min(x.precision(), y.precision())); + final BigDecimal resul = x.divide(y, mc); /* * If x and y are precise integer values that may have common factors, * the method above will truncate trailing zeros, which may result in @@ -2779,7 +2827,7 @@ public class BigDecimalMath { /* * The estimation of the relative error in the result is |err(x)/x| */ - MathContext mc = new MathContext(x.precision()); + final MathContext mc = new MathContext(x.precision()); return x.divide(new BigDecimal(n), mc); } @@ -2797,7 +2845,7 @@ public class BigDecimalMath { /* * The estimation of the relative error in the result is |err(x)/x| */ - MathContext mc = new MathContext(x.precision()); + final MathContext mc = new MathContext(x.precision()); return x.divide(new BigDecimal(n), mc); } /* divideRound */ @@ -2815,7 +2863,7 @@ public class BigDecimalMath { /* * The estimation of the relative error in the result is |err(x)/x| */ - MathContext mc = new MathContext(x.precision()); + final MathContext mc = new MathContext(x.precision()); return new BigDecimal(n).divide(x, mc); } /* divideRound */ @@ -2833,17 +2881,18 @@ public class BigDecimalMath { /* * catch case of real-valued denominator first */ - if (x.im.compareTo(BigDecimal.ZERO) == 0) + if (x.im.compareTo(BigDecimal.ZERO) == 0) { return new BigComplex(divideRound(n, x.re), BigDecimal.ZERO); - else if (x.re.compareTo(BigDecimal.ZERO) == 0) + } else if (x.re.compareTo(BigDecimal.ZERO) == 0) { return new BigComplex(BigDecimal.ZERO, divideRound(n, x.im).negate()); + } - BigComplex z = invertRound(x); + final BigComplex z = invertRound(x); /* * n/(x+iy) = nx/(x^2+y^2) -nyi/(x^2+y^2) */ - BigDecimal repart = multiplyRound(z.re, n); - BigDecimal impart = multiplyRound(z.im, n); + final BigDecimal repart = multiplyRound(z.re, n); + final BigDecimal impart = multiplyRound(z.im, n); return new BigComplex(repart, impart); } /* divideRound */ @@ -2861,7 +2910,7 @@ public class BigDecimalMath { /* * The estimation of the relative error in the result is |err(x)/x| */ - MathContext mc = new MathContext(x.precision()); + final MathContext mc = new MathContext(x.precision()); return new BigDecimal(n).divide(x, mc); } @@ -2913,10 +2962,11 @@ public class BigDecimalMath { */ static public BigDecimal scalePrec(final BigDecimal x, final MathContext mc) { final int diffPr = mc.getPrecision() - x.precision(); - if (diffPr > 0) + if (diffPr > 0) { return scalePrec(x, diffPr); - else + } else { return x; + } } /* BigDecimalMath.scalePrec */ /** diff --git a/src/org/nevec/rjm/BigIntegerMath.java b/src/org/nevec/rjm/BigIntegerMath.java index d9eddfd0..19a6ef0e 100644 --- a/src/org/nevec/rjm/BigIntegerMath.java +++ b/src/org/nevec/rjm/BigIntegerMath.java @@ -23,14 +23,17 @@ public class BigIntegerMath { * @return The binomial coefficient */ static public BigInteger binomial(final int n, final int k) { - if (k == 0) + if (k == 0) { return (BigInteger.ONE); + } BigInteger bin = new BigInteger("" + n); - BigInteger n2 = bin; - for (BigInteger i = new BigInteger("" + (k - 1)); i.compareTo(BigInteger.ONE) >= 0; i = i.subtract(BigInteger.ONE)) + final BigInteger n2 = bin; + for (BigInteger i = new BigInteger("" + (k - 1)); i.compareTo(BigInteger.ONE) >= 0; i = i.subtract(BigInteger.ONE)) { bin = bin.multiply(n2.subtract(i)); - for (BigInteger i = new BigInteger("" + k); i.compareTo(BigInteger.ONE) == 1; i = i.subtract(BigInteger.ONE)) + } + for (BigInteger i = new BigInteger("" + k); i.compareTo(BigInteger.ONE) == 1; i = i.subtract(BigInteger.ONE)) { bin = bin.divide(i); + } return (bin); } /* binomial */ @@ -48,8 +51,9 @@ public class BigIntegerMath { /* * binomial(n,0) =1 */ - if (k.compareTo(BigInteger.ZERO) == 0) + if (k.compareTo(BigInteger.ZERO) == 0) { return (BigInteger.ONE); + } BigInteger bin = new BigInteger("" + n); @@ -78,8 +82,9 @@ public class BigIntegerMath { * and in the integer domain. First replace C(n,k) by C(n,n-k) if n-k 120) + if (bl > 120) { x = n.shiftRight(bl / 2 - 1); - else { + } else { final double resul = Math.sqrt(n.doubleValue()); x = new BigInteger("" + Math.round(resul)); } @@ -221,13 +229,15 @@ public class BigIntegerMath { /* * check whether the result is accurate, x^2 =n */ - BigInteger x2 = x.pow(2); + final BigInteger x2 = x.pow(2); BigInteger xplus2 = x.add(BigInteger.ONE).pow(2); - if (x2.compareTo(n) <= 0 && xplus2.compareTo(n) > 0) + if (x2.compareTo(n) <= 0 && xplus2.compareTo(n) > 0) { return x; + } xplus2 = xplus2.subtract(x.shiftLeft(2)); - if (xplus2.compareTo(n) <= 0 && x2.compareTo(n) > 0) + if (xplus2.compareTo(n) <= 0 && x2.compareTo(n) > 0) { return x.subtract(BigInteger.ONE); + } /* * Newton algorithm. This correction is on the * low side caused by the integer divisions. So the value required @@ -251,8 +261,9 @@ public class BigIntegerMath { * @author Richard J. Mathar */ static public BigInteger core(final BigInteger n) { - if (n.compareTo(BigInteger.ZERO) < 0) + if (n.compareTo(BigInteger.ZERO) < 0) { throw new ArithmeticException("Negative argument " + n); + } final Ifactor i = new Ifactor(n); return i.core(); } @@ -278,17 +289,21 @@ public class BigIntegerMath { static public BigInteger[][] minor(final BigInteger[][] A, final int r, final int c) throws ArithmeticException { /* original row count */ final int rL = A.length; - if (rL == 0) + if (rL == 0) { throw new ArithmeticException("zero row count in matrix"); - if (r < 0 || r >= rL) + } + if (r < 0 || r >= rL) { throw new ArithmeticException("row number " + r + " out of range 0.." + (rL - 1)); + } /* original column count */ final int cL = A[0].length; - if (cL == 0) + if (cL == 0) { throw new ArithmeticException("zero column count in matrix"); - if (c < 0 || c >= cL) + } + if (c < 0 || c >= cL) { throw new ArithmeticException("column number " + c + " out of range 0.." + (cL - 1)); - BigInteger M[][] = new BigInteger[rL - 1][cL - 1]; + } + final BigInteger M[][] = new BigInteger[rL - 1][cL - 1]; int imrow = 0; for (int row = 0; row < rL; row++) { if (row != r) { @@ -327,15 +342,18 @@ public class BigIntegerMath { throws ArithmeticException { /* original row count */ final int rL = A.length; - if (rL == 0) + if (rL == 0) { throw new ArithmeticException("zero row count in matrix"); + } /* original column count */ final int cL = A[0].length; - if (cL == 0) + if (cL == 0) { throw new ArithmeticException("zero column count in matrix"); - if (c < 0 || c >= cL) + } + if (c < 0 || c >= cL) { throw new ArithmeticException("column number " + c + " out of range 0.." + (cL - 1)); - BigInteger M[][] = new BigInteger[rL][cL]; + } + final BigInteger M[][] = new BigInteger[rL][cL]; for (int row = 0; row < rL; row++) { for (int col = 0; col < cL; col++) { /* @@ -343,10 +361,11 @@ public class BigIntegerMath { * surplus * elements will be ignored. Shorter v lead to an exception. */ - if (col != c) + if (col != c) { M[row][col] = A[row][col]; - else + } else { M[row][col] = v[row]; + } } } return M; @@ -367,20 +386,21 @@ public class BigIntegerMath { BigInteger d = BigInteger.ZERO; /* row size */ final int rL = A.length; - if (rL == 0) + if (rL == 0) { throw new ArithmeticException("zero row count in matrix"); + } /* column size */ final int cL = A[0].length; - if (cL != rL) + if (cL != rL) { throw new ArithmeticException("Non-square matrix dim " + rL + " by " + cL); + } /* * Compute the low-order cases directly. */ - if (rL == 1) + if (rL == 1) { return A[0][0]; - - else if (rL == 2) { + } else if (rL == 2) { d = A[0][0].multiply(A[1][1]); return d.subtract(A[0][1].multiply(A[1][0])); } else { @@ -393,10 +413,11 @@ public class BigIntegerMath { final BigInteger M[][] = minor(A, r, 0); final BigInteger m = A[r][0].multiply(det(M)); /* recursive call */ - if (r % 2 == 0) + if (r % 2 == 0) { d = d.add(m); - else + } else { d = d.subtract(m); + } } } } @@ -421,26 +442,30 @@ public class BigIntegerMath { static public Rational[] solve(final BigInteger[][] A, final BigInteger[] rhs) throws ArithmeticException, Error { final int rL = A.length; - if (rL == 0) + if (rL == 0) { throw new ArithmeticException("zero row count in matrix"); + } /* column size */ final int cL = A[0].length; - if (cL != rL) + if (cL != rL) { throw new ArithmeticException("Non-square matrix dim " + rL + " by " + cL); - if (rhs.length != rL) + } + if (rhs.length != rL) { throw new ArithmeticException("Right hand side dim " + rhs.length + " unequal matrix dim " + rL); + } /* * Gauss elimination */ - Rational x[] = new Rational[rL]; + final Rational x[] = new Rational[rL]; /* * copy of r.h.s ito a mutable Rationalright hand side */ - for (int c = 0; c < cL; c++) + for (int c = 0; c < cL; c++) { x[c] = new Rational(rhs[c]); + } /* * Create zeros downwards column c by linear combination of row c and @@ -456,11 +481,11 @@ public class BigIntegerMath { for (int r = c + 1; r < rL; r++) { if (A[r][c].compareTo(BigInteger.ZERO) != 0) { for (int cpr = c; cpr < cL; cpr++) { - BigInteger tmp = A[c][cpr]; + final BigInteger tmp = A[c][cpr]; A[c][cpr] = A[r][cpr]; A[r][cpr] = tmp; } - Rational tmp = x[c]; + final Rational tmp = x[c]; x[c] = x[r]; x[r] = tmp; swpd = true; @@ -471,8 +496,9 @@ public class BigIntegerMath { * not swapped with a non-zero row: determinant zero and no * solution */ - if (!swpd) + if (!swpd) { throw new ArithmeticException("Zero determinant of main matrix"); + } } /* create zero at A[c+1..cL-1][c] */ for (int r = c + 1; r < rL; r++) { @@ -481,20 +507,22 @@ public class BigIntegerMath { * not visited again */ for (int cpr = c + 1; cpr < cL; cpr++) { - BigInteger tmp = A[c][c].multiply(A[r][cpr]).subtract(A[c][cpr].multiply(A[r][c])); + final BigInteger tmp = A[c][c].multiply(A[r][cpr]).subtract(A[c][cpr].multiply(A[r][c])); A[r][cpr] = tmp; } - Rational tmp = x[r].multiply(A[c][c]).subtract(x[c].multiply(A[r][c])); + final Rational tmp = x[r].multiply(A[c][c]).subtract(x[c].multiply(A[r][c])); x[r] = tmp; } } - if (A[cL - 1][cL - 1].compareTo(BigInteger.ZERO) == 0) + if (A[cL - 1][cL - 1].compareTo(BigInteger.ZERO) == 0) { throw new ArithmeticException("Zero determinant of main matrix"); + } /* backward elimination */ for (int r = cL - 1; r >= 0; r--) { x[r] = x[r].divide(A[r][r]); - for (int rpr = r - 1; rpr >= 0; rpr--) + for (int rpr = r - 1; rpr >= 0; rpr--) { x[rpr] = x[rpr].subtract(x[r].multiply(A[rpr][r])); + } } return x; @@ -512,7 +540,7 @@ public class BigIntegerMath { * @author Richard J. Mathar */ static public BigInteger lcm(final BigInteger a, final BigInteger b) { - BigInteger g = a.gcd(b); + final BigInteger g = a.gcd(b); return a.multiply(b).abs().divide(g); } @@ -529,11 +557,13 @@ public class BigIntegerMath { * @author Richard J. Mathar */ static public BigInteger valueOf(final Vector c, final BigInteger x) { - if (c.size() == 0) + if (c.size() == 0) { return BigInteger.ZERO; + } BigInteger res = c.lastElement(); - for (int i = c.size() - 2; i >= 0; i--) + for (int i = c.size() - 2; i >= 0; i--) { res = res.multiply(x).add(c.elementAt(i)); + } return res; } @@ -552,32 +582,34 @@ public class BigIntegerMath { * et al, Num. Funct. Anal. Opt. 10 (5)( 1989) 419-488 */ static public Rational centrlFactNumt(int n, int k) throws Error { - if (k > n || k < 0 || (k % 2) != (n % 2)) + if (k > n || k < 0 || (k % 2) != (n % 2)) { return Rational.ZERO; - else if (k == n) + } else if (k == n) { return Rational.ONE; - else { + } else { /* Proposition 6.2.6 */ - Factorial f = new Factorial(); + final Factorial f = new Factorial(); Rational jsum = new Rational(0, 1); - int kprime = n - k; + final int kprime = n - k; for (int j = 0; j <= kprime; j++) { Rational nusum = new Rational(0, 1); for (int nu = 0; nu <= j; nu++) { Rational t = new Rational(j - 2 * nu, 2); t = t.pow(kprime + j); t = t.multiply(binomial(j, nu)); - if (nu % 2 != 0) + if (nu % 2 != 0) { nusum = nusum.subtract(t); - else + } else { nusum = nusum.add(t); + } } nusum = nusum.divide(f.at(j)).divide(n + j); nusum = nusum.multiply(binomial(2 * kprime, kprime - j)); - if (j % 2 != 0) + if (j % 2 != 0) { jsum = jsum.subtract(nusum); - else + } else { jsum = jsum.add(nusum); + } } return jsum.multiply(k).multiply(binomial(n + kprime, k)); } @@ -597,11 +629,11 @@ public class BigIntegerMath { * et al, Num. Funct. Anal. Opt. 10 (5)( 1989) 419-488 */ static public Rational centrlFactNumT(int n, int k) { - if (k > n || k < 0 || (k % 2) != (n % 2)) + if (k > n || k < 0 || (k % 2) != (n % 2)) { return Rational.ZERO; - else if (k == n) + } else if (k == n) { return Rational.ONE; - else { + } else { /* Proposition 2.1 */ return centrlFactNumT(n - 2, k - 2).add(centrlFactNumT(n - 2, k).multiply(new Rational(k * k, 4))); } diff --git a/src/org/nevec/rjm/BigIntegerPoly.java b/src/org/nevec/rjm/BigIntegerPoly.java index f5e754de..91a92cf3 100644 --- a/src/org/nevec/rjm/BigIntegerPoly.java +++ b/src/org/nevec/rjm/BigIntegerPoly.java @@ -39,10 +39,11 @@ public class BigIntegerPoly implements Cloneable { */ public BigIntegerPoly(final String L) throws NumberFormatException { a = new Vector<>(); - Scanner sc = new Scanner(L); + final Scanner sc = new Scanner(L); sc.useDelimiter(","); - while (sc.hasNextBigInteger()) + while (sc.hasNextBigInteger()) { a.add(sc.nextBigInteger()); + } simplify(); sc.close(); } /* ctor */ @@ -66,8 +67,9 @@ public class BigIntegerPoly implements Cloneable { * The coefficients a0, a1, a2 etc in a0+a1*x+a2*x^2+... */ public BigIntegerPoly(final BigInteger[] c) { - for (int i = 0; i < c.length; i++) - a.add(c[i].add(BigInteger.ZERO)); + for (final BigInteger element : c) { + a.add(element.add(BigInteger.ZERO)); + } simplify(); } /* ctor */ @@ -87,9 +89,10 @@ public class BigIntegerPoly implements Cloneable { * @since 2012-03-02 */ public RatPoly toRatPoly() { - RatPoly bd = new RatPoly(); - for (int i = 0; i < a.size(); i++) + final RatPoly bd = new RatPoly(); + for (int i = 0; i < a.size(); i++) { bd.set(i, a.elementAt(i)); + } return bd; } /* toRatPoly */ @@ -102,10 +105,11 @@ public class BigIntegerPoly implements Cloneable { * @return the polynomial coefficient in front of x^n. */ public BigInteger at(final int n) { - if (n < a.size()) + if (n < a.size()) { return (a.elementAt(n)); - else + } else { return (BigInteger.ZERO); + } } /* at */ /** @@ -118,14 +122,16 @@ public class BigIntegerPoly implements Cloneable { * @author Richard J. Mathar */ public BigInteger valueOf(final BigInteger x) { - if (a.size() == 0) + if (a.size() == 0) { return BigInteger.ZERO; + } BigInteger res = a.lastElement(); /* * Heron casted form */ - for (int i = a.size() - 2; i >= 0; i--) + for (int i = a.size() - 2; i >= 0; i--) { res = res.multiply(x).add(a.elementAt(i)); + } return res; } /* valueOf */ @@ -154,9 +160,9 @@ public class BigIntegerPoly implements Cloneable { * the new value of the coefficient. */ public void set(final int n, final BigInteger value) { - if (n < a.size()) + if (n < a.size()) { a.set(n, value); - else { + } else { /* * fill intermediate powers with coefficients of zero */ @@ -180,7 +186,7 @@ public class BigIntegerPoly implements Cloneable { * the new value of the coefficient. */ public void set(final int n, final int value) { - BigInteger val2 = new BigInteger("" + value); + final BigInteger val2 = new BigInteger("" + value); set(n, val2); } /* set */ @@ -210,9 +216,11 @@ public class BigIntegerPoly implements Cloneable { * If the polynomial is identical to 0, 0 is returned. */ public int ldegree() { - for (int n = 0; n < a.size(); n++) - if (a.elementAt(n).compareTo(BigInteger.ZERO) != 0) + for (int n = 0; n < a.size(); n++) { + if (a.elementAt(n).compareTo(BigInteger.ZERO) != 0) { return n; + } + } return 0; } /* ldegree */ @@ -227,10 +235,12 @@ public class BigIntegerPoly implements Cloneable { * @since 2010-08-27 */ public BigIntegerPoly multiply(final BigInteger val) { - BigIntegerPoly resul = new BigIntegerPoly(); - if (val.compareTo(BigInteger.ZERO) != 0) - for (int n = 0; n < a.size(); n++) + final BigIntegerPoly resul = new BigIntegerPoly(); + if (val.compareTo(BigInteger.ZERO) != 0) { + for (int n = 0; n < a.size(); n++) { resul.set(n, a.elementAt(n).multiply(val)); + } + } return resul; } /* multiply */ @@ -242,15 +252,16 @@ public class BigIntegerPoly implements Cloneable { * @return the product of this with the other polynomial */ public BigIntegerPoly multiply(final BigIntegerPoly val) { - BigIntegerPoly resul = new BigIntegerPoly(); + final BigIntegerPoly resul = new BigIntegerPoly(); /* * the degree of the result is the sum of the two degrees. */ final int nmax = degree() + val.degree(); for (int n = 0; n <= nmax; n++) { BigInteger coef = BigInteger.ZERO; - for (int nleft = 0; nleft <= n; nleft++) + for (int nleft = 0; nleft <= n; nleft++) { coef = coef.add(at(nleft).multiply(val.at(n - nleft))); + } resul.set(n, coef); } resul.simplify(); @@ -266,11 +277,12 @@ public class BigIntegerPoly implements Cloneable { */ public BigIntegerPoly pow(final int n) throws ArithmeticException { BigIntegerPoly resul = new BigIntegerPoly("1"); - if (n < 0) + if (n < 0) { throw new ArithmeticException("negative polynomial power " + n); - else { - for (int i = 1; i <= n; i++) + } else { + for (int i = 1; i <= n; i++) { resul = resul.multiply(this); + } resul.simplify(); return resul; } @@ -285,14 +297,14 @@ public class BigIntegerPoly implements Cloneable { * @since 2010-08-27 */ public BigIntegerPoly add(final BigIntegerPoly val) { - BigIntegerPoly resul = new BigIntegerPoly(); + final BigIntegerPoly resul = new BigIntegerPoly(); /* * the degree of the result is the larger of the two degrees (before * simplify() at least). */ final int nmax = (degree() > val.degree()) ? degree() : val.degree(); for (int n = 0; n <= nmax; n++) { - BigInteger coef = at(n).add(val.at(n)); + final BigInteger coef = at(n).add(val.at(n)); resul.set(n, coef); } resul.simplify(); @@ -308,14 +320,14 @@ public class BigIntegerPoly implements Cloneable { * @since 2008-10-25 */ public BigIntegerPoly subtract(final BigIntegerPoly val) { - BigIntegerPoly resul = new BigIntegerPoly(); + final BigIntegerPoly resul = new BigIntegerPoly(); /* * the degree of the result is the larger of the two degrees (before * simplify() at least). */ final int nmax = (degree() > val.degree()) ? degree() : val.degree(); for (int n = 0; n <= nmax; n++) { - BigInteger coef = at(n).subtract(val.at(n)); + final BigInteger coef = at(n).subtract(val.at(n)); resul.set(n, coef); } resul.simplify(); @@ -334,19 +346,20 @@ public class BigIntegerPoly implements Cloneable { * @since 2012-03-01 */ public BigIntegerPoly[] divideAndRemainder(final BigIntegerPoly val) { - BigIntegerPoly[] ret = new BigIntegerPoly[2]; + final BigIntegerPoly[] ret = new BigIntegerPoly[2]; /* * remove any high-order zeros. note that the clone() operation calls * simplify(). */ - BigIntegerPoly valSimpl = val.clone(); - BigIntegerPoly thisSimpl = clone(); + final BigIntegerPoly valSimpl = val.clone(); + final BigIntegerPoly thisSimpl = clone(); /* * catch the case with val equal to zero */ - if (valSimpl.degree() == 0 && valSimpl.a.firstElement().compareTo(BigInteger.ZERO) == 0) + if (valSimpl.degree() == 0 && valSimpl.a.firstElement().compareTo(BigInteger.ZERO) == 0) { throw new ArithmeticException("Division through zero polynomial"); + } /* * degree of this smaller than degree of val: remainder is this */ @@ -363,9 +376,10 @@ public class BigIntegerPoly implements Cloneable { * polynomial division cannot be done with integer coefficients. */ ret[0] = new BigIntegerPoly(); - BigInteger[] newc = thisSimpl.a.lastElement().divideAndRemainder(valSimpl.a.lastElement()); - if (newc[1].compareTo(BigInteger.ZERO) != 0) + final BigInteger[] newc = thisSimpl.a.lastElement().divideAndRemainder(valSimpl.a.lastElement()); + if (newc[1].compareTo(BigInteger.ZERO) != 0) { throw new ArithmeticException("Incompatible leading term in " + this + " / " + val); + } ret[0].set(thisSimpl.degree() - valSimpl.degree(), newc[0]); /* @@ -378,10 +392,10 @@ public class BigIntegerPoly implements Cloneable { /* * any remainder left ? */ - if (ret[1].degree() < valSimpl.degree()) + if (ret[1].degree() < valSimpl.degree()) { ; - else { - BigIntegerPoly rem[] = ret[1].divideAndRemainder(val); + } else { + final BigIntegerPoly rem[] = ret[1].divideAndRemainder(val); ret[0] = ret[0].add(rem[0]); ret[1] = rem[1]; } @@ -399,13 +413,15 @@ public class BigIntegerPoly implements Cloneable { public String toString() { String str = new String(); for (int n = 0; n < a.size(); n++) { - if (n == 0) + if (n == 0) { str += a.elementAt(n).toString(); - else + } else { str += "," + a.elementAt(n).toString(); + } } - if (str.length() == 0) + if (str.length() == 0) { str = "0"; + } return str; } /* toString */ @@ -422,18 +438,21 @@ public class BigIntegerPoly implements Cloneable { final BigInteger num = a.elementAt(n); if (num.compareTo(BigInteger.ZERO) != 0) { str += " "; - if (num.compareTo(BigInteger.ZERO) > 0 && n > 0) + if (num.compareTo(BigInteger.ZERO) > 0 && n > 0) { str += "+"; + } str += a.elementAt(n).toString(); if (n > 0) { str += "*x"; - if (n > 1) + if (n > 1) { str += "^" + n; + } } } } - if (str.length() == 0) + if (str.length() == 0) { str = "0"; + } return str; } /* toPString */ @@ -443,12 +462,14 @@ public class BigIntegerPoly implements Cloneable { */ protected void simplify() { int n = a.size() - 1; - if (n >= 0) + if (n >= 0) { while (a.elementAt(n).compareTo(BigInteger.ZERO) == 0) { a.removeElementAt(n); - if (--n < 0) + if (--n < 0) { break; + } } + } } /* simplify */ /** @@ -464,7 +485,7 @@ public class BigIntegerPoly implements Cloneable { */ return new BigIntegerPoly(); } else { - BigIntegerPoly d = new BigIntegerPoly(); + final BigIntegerPoly d = new BigIntegerPoly(); for (int i = 1; i <= degree(); i++) { final BigInteger c = a.elementAt(i).multiply(new BigInteger("" + i)); d.set(i - 1, c); @@ -480,9 +501,10 @@ public class BigIntegerPoly implements Cloneable { * @since 2010-08-27 */ public BigIntegerPoly trunc(int newdeg) { - BigIntegerPoly t = new BigIntegerPoly(); - for (int i = 0; i <= newdeg; i++) + final BigIntegerPoly t = new BigIntegerPoly(); + for (int i = 0; i <= newdeg; i++) { t.set(i, at(i)); + } t.simplify(); return t; } /* trunc */ @@ -497,14 +519,16 @@ public class BigIntegerPoly implements Cloneable { * @since 2010-08-29 */ public BigIntegerPoly binomialTInv(int maxdeg) { - BigIntegerPoly r = new BigIntegerPoly(); + final BigIntegerPoly r = new BigIntegerPoly(); for (int i = 0; i <= maxdeg; i++) { BigInteger c = BigInteger.ZERO; - for (int j = 0; j <= i && j < a.size(); j++) - if ((j + i) % 2 != 0) + for (int j = 0; j <= i && j < a.size(); j++) { + if ((j + i) % 2 != 0) { c = c.subtract(a.elementAt(j).multiply(BigIntegerMath.binomial(i, j))); - else + } else { c = c.add(a.elementAt(j).multiply(BigIntegerMath.binomial(i, j))); + } + } r.set(i, c); } r.simplify(); @@ -537,31 +561,34 @@ public class BigIntegerPoly implements Cloneable { */ public Vector iroots() { /* The vector of the roots */ - Vector res = new Vector<>(); + final Vector res = new Vector<>(); /* * collect the zero */ - if (a.firstElement().compareTo(BigInteger.ZERO) == 0) + if (a.firstElement().compareTo(BigInteger.ZERO) == 0) { res.add(BigInteger.ZERO); + } /* * collect the divisors of the constant element (or the reduced * polynomial) */ - int l = ldegree(); + final int l = ldegree(); if (a.elementAt(l).compareTo(BigInteger.ZERO) != 0) { - Vector cand = BigIntegerMath.divisors(a.elementAt(l).abs()); + final Vector cand = BigIntegerMath.divisors(a.elementAt(l).abs()); /* check the divisors (both signs) */ for (int i = 0; i < cand.size(); i++) { BigInteger roo = valueOf(cand.elementAt(i)); - if (roo.compareTo(BigInteger.ZERO) == 0) + if (roo.compareTo(BigInteger.ZERO) == 0) { /* found a root cand[i] */ res.add(cand.elementAt(i)); + } roo = valueOf(cand.elementAt(i).negate()); - if (roo.compareTo(BigInteger.ZERO) == 0) + if (roo.compareTo(BigInteger.ZERO) == 0) { res.add(cand.elementAt(i).negate()); + } } } return res; @@ -581,15 +608,16 @@ public class BigIntegerPoly implements Cloneable { /* * The vector of the factors to be returned */ - Vector res = new Vector<>(); + final Vector res = new Vector<>(); - if (degree() < 2) + if (degree() < 2) { return res; + } - BigInteger bsco = a.firstElement().abs(); - Vector b = BigIntegerMath.divisors(bsco); - BigInteger csco = a.lastElement().abs(); - Vector c = BigIntegerMath.divisors(csco); + final BigInteger bsco = a.firstElement().abs(); + final Vector b = BigIntegerMath.divisors(bsco); + final BigInteger csco = a.lastElement().abs(); + final Vector c = BigIntegerMath.divisors(csco); /* * Generate the floating point values of roots. To have some reasonable @@ -601,8 +629,8 @@ public class BigIntegerPoly implements Cloneable { * estimate * and adding 6 safety digits */ - RatPoly thisDec = toRatPoly(); - Vector roo = thisDec.roots(6 + (int) (0.3 * bsco.bitCount())); + final RatPoly thisDec = toRatPoly(); + final Vector roo = thisDec.roots(6 + (int) (0.3 * bsco.bitCount())); final BigDecimal half = new BigDecimal("0.5"); @@ -613,9 +641,9 @@ public class BigIntegerPoly implements Cloneable { * coefficient. * Solve z*(c*z+a)=-b or c*z+a = -b/z or -b/z-c*z = some integer a. */ - for (BigComplex z : roo) { - for (BigInteger bco : b) - for (BigInteger cco : c) { + for (final BigComplex z : roo) { + for (final BigInteger bco : b) { + for (final BigInteger cco : c) { /* * the major reason to avoid the case b=0 is that this would * require precaution of double counting below. Note that @@ -624,7 +652,7 @@ public class BigIntegerPoly implements Cloneable { */ if (bco.signum() != 0) { for (int sig = -1; sig <= 1; sig += 2) { - BigInteger bcosig = (sig > 0) ? bco : bco.negate(); + final BigInteger bcosig = (sig > 0) ? bco : bco.negate(); /* * -a = b/z+c*z has real part b*Re(z)/|z|^2+c*Re(z) * = Re z *( b/|z|^2+c) @@ -634,22 +662,24 @@ public class BigIntegerPoly implements Cloneable { /* * convert to a with round-to-nearest */ - BigInteger a = negA.negate().add(half).toBigInteger(); + final BigInteger a = negA.negate().add(half).toBigInteger(); /* * test the polynomial remainder. if zero, add the * term * to the results. */ - BigIntegerPoly dtst = new BigIntegerPoly("" + bcosig + "," + a + "," + cco); + final BigIntegerPoly dtst = new BigIntegerPoly("" + bcosig + "," + a + "," + cco); try { - BigIntegerPoly[] rm = divideAndRemainder(dtst); - if (rm[1].isZero()) + final BigIntegerPoly[] rm = divideAndRemainder(dtst); + if (rm[1].isZero()) { res.add(dtst); - } catch (ArithmeticException ex) {} + } + } catch (final ArithmeticException ex) {} } } } + } } return res; @@ -679,16 +709,16 @@ public class BigIntegerPoly implements Cloneable { /* * this ought be entirely rewritten in terms of the LLL algorithm */ - Vector fac = new Vector<>(); + final Vector fac = new Vector<>(); /* collect integer roots (polynomial factors of degree 1) */ - Vector r = iroots(); + final Vector r = iroots(); BigIntegerPoly[] res = new BigIntegerPoly[2]; res[0] = this; - for (BigInteger i : r) { - int deg = rootDeg(i); + for (final BigInteger i : r) { + final int deg = rootDeg(i); /* construct the factor x-i */ - BigIntegerPoly f = new BigIntegerPoly("" + i.negate() + ",1"); + final BigIntegerPoly f = new BigIntegerPoly("" + i.negate() + ",1"); for (int mu = 0; mu < deg; mu++) { fac.add(f); res = res[0].divideAndRemainder(f); @@ -698,21 +728,22 @@ public class BigIntegerPoly implements Cloneable { /* * collect factors which are polynomials of degree 2 */ - Vector pol2 = i2roots(); - for (BigIntegerPoly i : pol2) { + final Vector pol2 = i2roots(); + for (final BigIntegerPoly i : pol2) { /* * the internal loop catches cases with higher * powers of individual polynomials (of actual degree 2 or 4...) */ while (res[0].degree() >= 2) { try { - BigIntegerPoly[] dtst = res[0].divideAndRemainder(i); + final BigIntegerPoly[] dtst = res[0].divideAndRemainder(i); if (dtst[1].isZero()) { fac.add(i); res = dtst; - } else + } else { break; - } catch (ArithmeticException ex) { + } + } catch (final ArithmeticException ex) { break; } } @@ -721,8 +752,9 @@ public class BigIntegerPoly implements Cloneable { /* * add remaining factor, if not equal to 1 */ - if (res[0].degree() > 0 || res[0].a.firstElement().compareTo(BigInteger.ONE) != 0) + if (res[0].degree() > 0 || res[0].a.firstElement().compareTo(BigInteger.ONE) != 0) { fac.add(res[0]); + } return fac; } /* ifactor */ diff --git a/src/org/nevec/rjm/BigSurd.java b/src/org/nevec/rjm/BigSurd.java index 1cb1520e..d5fd201c 100644 --- a/src/org/nevec/rjm/BigSurd.java +++ b/src/org/nevec/rjm/BigSurd.java @@ -60,17 +60,18 @@ public class BigSurd implements Cloneable, Comparable { * @since 2011-02-12 */ public BigSurd(Rational a, Rational b) { - this.pref = a; + pref = a; /* * reject attempts to use a negative b */ - if (b.signum() < 0) + if (b.signum() < 0) { throw new ProviderException("Not implemented: imaginary surds"); - this.disc = b; + } + disc = b; try { normalize(); normalizeG(); - } catch (Error e) { + } catch (final Error e) { e.printStackTrace(); } } @@ -112,8 +113,8 @@ public class BigSurd implements Cloneable, Comparable { */ @Override public BigSurd clone() { - Rational fclon = pref.clone(); - Rational dclon = disc.clone(); + final Rational fclon = pref.clone(); + final Rational dclon = disc.clone(); /* * the main intent here is to bypass any attempt to reduce the * discriminant @@ -121,7 +122,7 @@ public class BigSurd implements Cloneable, Comparable { * already done * in the current copy of the number. */ - BigSurd cl = new BigSurd(); + final BigSurd cl = new BigSurd(); cl.pref = fclon; cl.disc = dclon; return cl; @@ -136,13 +137,14 @@ public class BigSurd implements Cloneable, Comparable { public BigSurdVec add(final BigSurd val) { // zero plus somethings yields something - if (signum() == 0) + if (signum() == 0) { return new BigSurdVec(val); - else if (val.signum() == 0) + } else if (val.signum() == 0) { return new BigSurdVec(this); - else + } else { // let the ctor of BigSurdVec to the work return new BigSurdVec(this, val); + } } /* BigSurd.add */ /** @@ -190,7 +192,7 @@ public class BigSurd implements Cloneable, Comparable { * @since 2011-02-12 */ public BigSurd multiply(final int val) { - BigInteger tmp = new BigInteger("" + val); + final BigInteger tmp = new BigInteger("" + val); return multiply(tmp); } /* BigSurd.multiply */ @@ -216,14 +218,15 @@ public class BigSurd implements Cloneable, Comparable { * @since 2011-02-12 */ public BigSurd divide(final BigSurd val) throws Error { - if (val.signum() == 0) + if (val.signum() == 0) { throw new ArithmeticException("Dividing " + toFancyString() + " through zero."); + } return new BigSurd(pref.divide(val.pref), disc.divide(val.disc)); } /* BigSurd.divide */ private String toFancyString() { - BigSurd bs = this; - BigInteger denominator = pref.b; + final BigSurd bs = this; + final BigInteger denominator = pref.b; String s = ""; if (denominator.compareTo(BigInteger.ONE) != 0) { s += "("; @@ -233,7 +236,7 @@ public class BigSurd implements Cloneable, Comparable { } else if (bs.isRational()) { s += bs.toRational().toString(); } else { - BigInteger numerator = bs.pref.a; + final BigInteger numerator = bs.pref.a; if (numerator.compareTo(BigInteger.ONE) != 0) { s += numerator.toString(); s += "*"; @@ -262,8 +265,9 @@ public class BigSurd implements Cloneable, Comparable { * @since 2011-02-12 */ public BigSurd divide(final BigInteger val) throws Error { - if (val.signum() == 0) + if (val.signum() == 0) { throw new ArithmeticException("Dividing " + toFancyString() + " through zero."); + } return new BigSurd(pref.divide(val), disc); } /* BigSurd.divide */ @@ -277,8 +281,9 @@ public class BigSurd implements Cloneable, Comparable { * @since 2011-02-12 */ public BigSurd divide(int val) throws Error { - if (val == 0) + if (val == 0) { throw new ArithmeticException("Dividing " + toFancyString() + " through zero."); + } return new BigSurd(pref.divide(val), disc); } /* BigSurd.divide */ @@ -293,7 +298,7 @@ public class BigSurd implements Cloneable, Comparable { * This is trying to be quick, avoiding normalize(), by toggling * the sign in a clone() */ - BigSurd n = clone(); + final BigSurd n = clone(); n.pref = n.pref.negate(); return n; } /* BigSurd.negate */ @@ -325,16 +330,21 @@ public class BigSurd implements Cloneable, Comparable { */ final int sig = signum(); final int sigv = val.signum(); - if (sig < 0 && sigv >= 0) + if (sig < 0 && sigv >= 0) { return -1; - if (sig > 0 && sigv <= 0) + } + if (sig > 0 && sigv <= 0) { return 1; - if (sig == 0 && sigv == 0) + } + if (sig == 0 && sigv == 0) { return 0; - if (sig == 0 && sigv > 0) + } + if (sig == 0 && sigv > 0) { return -1; - if (sig == 0 && sigv < 0) + } + if (sig == 0 && sigv < 0) { return 1; + } /* * Work out the cases of equal sign. Compare absolute values by @@ -345,16 +355,13 @@ public class BigSurd implements Cloneable, Comparable { final Rational this2 = sqr(); final Rational val2 = val.sqr(); final int c = this2.compareTo(val2); - if (c == 0) + if (c == 0) { return 0; - /* - * If both values have negative sign, the one with the smaller square is - * the larger number. - */ - else if (sig > 0 && c > 0 || sig < 0 && c < 0) + } else if (sig > 0 && c > 0 || sig < 0 && c < 0) { return 1; - else + } else { return -1; + } } /* BigSurd.compareTo */ /** @@ -366,10 +373,11 @@ public class BigSurd implements Cloneable, Comparable { */ @Override public String toString() { - if (disc.compareTo(Rational.ONE) != 0 && disc.compareTo(Rational.ZERO) != 0) + if (disc.compareTo(Rational.ONE) != 0 && disc.compareTo(Rational.ZERO) != 0) { return ("(" + pref.toString() + ")*(" + disc.toString() + ")^(1/2)"); - else + } else { return pref.toString(); + } } /* BigSurd.toString */ /** @@ -383,9 +391,9 @@ public class BigSurd implements Cloneable, Comparable { * First compute the square to prevent overflows if the two pieces of * the prefactor and the discriminant are of very different magnitude. */ - Rational p2 = pref.pow(2).multiply(disc); + final Rational p2 = pref.pow(2).multiply(disc); System.out.println("dv sq " + p2.toString()); - double res = p2.doubleValue(); + final double res = p2.doubleValue(); System.out.println("dv sq " + res); return (pref.signum() >= 0) ? Math.sqrt(res) : -Math.sqrt(res); } /* BigSurd.doubleValue */ @@ -428,10 +436,11 @@ public class BigSurd implements Cloneable, Comparable { * @since 2012-02-15 */ public Rational toRational() { - if (isRational()) + if (isRational()) { return pref; - else + } else { throw new ArithmeticException("Undefined conversion " + toFancyString() + " to Rational."); + } } /* BigSurd.toRational */ /** @@ -463,7 +472,7 @@ public class BigSurd implements Cloneable, Comparable { /* * square-free part of the numerator: numer = numC*some^2 */ - BigInteger numC = BigIntegerMath.core(disc.numer()); + final BigInteger numC = BigIntegerMath.core(disc.numer()); /* * extract the perfect square of the numerator */ @@ -478,14 +487,15 @@ public class BigSurd implements Cloneable, Comparable { */ pref = pref.multiply(sqf); - BigInteger denC = BigIntegerMath.core(disc.denom()); + final BigInteger denC = BigIntegerMath.core(disc.denom()); sq = disc.denom().divide(denC); sqf = BigIntegerMath.isqrt(sq); pref = pref.divide(sqf); disc = new Rational(numC, denC); - } else + } else { pref = Rational.ZERO; + } } /* BigSurd.normalize */ /** @@ -544,13 +554,13 @@ public class BigSurd implements Cloneable, Comparable { /* * first the square root of the discriminant */ - BigDecimal sqrdis = BigDecimalMath.sqrt(disc.BigDecimalValue(locmc), locmc); + final BigDecimal sqrdis = BigDecimalMath.sqrt(disc.BigDecimalValue(locmc), locmc); /* * Then multiply by the prefactor. If sqrdis is a terminating decimal * fraction, * we prevent early truncation of the result by truncating later. */ - BigDecimal res = sqrdis.multiply(pref.BigDecimalValue(mc)); + final BigDecimal res = sqrdis.multiply(pref.BigDecimalValue(mc)); return BigDecimalMath.scalePrec(res, mc); } /* BigDecimalValue */ diff --git a/src/org/nevec/rjm/BigSurdVec.java b/src/org/nevec/rjm/BigSurdVec.java index c12ef143..e88f1b6e 100644 --- a/src/org/nevec/rjm/BigSurdVec.java +++ b/src/org/nevec/rjm/BigSurdVec.java @@ -69,7 +69,7 @@ public class BigSurdVec implements Comparable { terms.add(b); try { normalize(); - } catch (Error e) { + } catch (final Error e) { // TODO Auto-generated catch block e.printStackTrace(); } @@ -87,16 +87,17 @@ public class BigSurdVec implements Comparable { /* * nothing to be done if at most one term */ - if (terms.size() <= 1) + if (terms.size() <= 1) { return; + } - Vector newter = new Vector<>(); + final Vector newter = new Vector<>(); newter.add(terms.firstElement()); /* * add j-th element to the existing vector and combine were possible */ for (int j = 1; j < terms.size(); j++) { - BigSurd todo = terms.elementAt(j); + final BigSurd todo = terms.elementAt(j); boolean merged = false; for (int ex = 0; ex < newter.size(); ex++) { BigSurd v = newter.elementAt(ex); @@ -105,16 +106,16 @@ public class BigSurdVec implements Comparable { * rational number is needed. Replaces v with v+todo = v*(1+r) * if this reduction works. */ - BigSurd r = todo.divide(v); + final BigSurd r = todo.divide(v); if (r.isRational()) { /* compute r+1 */ - Rational newpref = r.toRational().add(1); + final Rational newpref = r.toRational().add(1); /* * eliminate accidental zeros; overwrite with v*(1+r). */ - if (newpref.compareTo(Rational.ZERO) == 0) + if (newpref.compareTo(Rational.ZERO) == 0) { newter.removeElementAt(ex); - else { + } else { v = v.multiply(newpref); newter.setElementAt(v, ex); } @@ -125,8 +126,9 @@ public class BigSurdVec implements Comparable { /* * append if none of the existing elements matched */ - if (!merged) + if (!merged) { newter.add(todo); + } } /* overwrite old version */ @@ -148,7 +150,7 @@ public class BigSurdVec implements Comparable { try { diff = this.subtract(oth); return diff.signum(); - } catch (Error e) { + } catch (final Error e) { // TODO Auto-generated catch block e.printStackTrace(); return 0; @@ -168,34 +170,40 @@ public class BigSurdVec implements Comparable { * the case of zero is unique, because no (reduced) vector of surds * other than the one element 0 itself can add/subtract to zero. */ - if (terms.size() == 0) + if (terms.size() == 0) { return 0; + } /* * if there is one term: forward to the signum function of BigSurd */ - if (terms.size() == 1) + if (terms.size() == 1) { return terms.firstElement().signum(); + } /* * if all terms have a common sign: take that one offsig is the index of * the first "offending" term in the sense that its sign doese not agree * with the term[0]. */ - int sig0 = terms.elementAt(0).signum(); + final int sig0 = terms.elementAt(0).signum(); int offsig = 1; - for (; offsig < terms.size(); offsig++) - if (terms.elementAt(offsig).signum() != sig0) + for (; offsig < terms.size(); offsig++) { + if (terms.elementAt(offsig).signum() != sig0) { break; - if (offsig >= terms.size()) + } + } + if (offsig >= terms.size()) { return sig0; + } /* * if there are two terms (now known to have different sign): forward to * the comparison of the two elements as BigSurds */ - if (terms.size() == 2) + if (terms.size() == 2) { return terms.elementAt(0).compareTo(terms.elementAt(1).negate()); + } /* * if there are three terms, move the one with the offending sign to the @@ -206,10 +214,11 @@ public class BigSurdVec implements Comparable { */ if (terms.size() == 3) { BigSurdVec lhs; - if (offsig == 2) + if (offsig == 2) { lhs = new BigSurdVec(terms.elementAt(0), terms.elementAt(1)); - else + } else { lhs = new BigSurdVec(terms.elementAt(0), terms.elementAt(2)); + } lhs = lhs.sqr(); /* * Strange line: this line isn't used, but it's present in this @@ -223,13 +232,14 @@ public class BigSurdVec implements Comparable { * * */ - if (lhs.compareTo(lhs) > 0) + if (lhs.compareTo(lhs) > 0) { /* * dominating sign was t(0)+t(offbar) */ return terms.elementAt(0).signum(); - else + } else { return terms.elementAt(offsig).signum(); + } } /* @@ -252,9 +262,9 @@ public class BigSurdVec implements Comparable { /* * simple cases with one term forwarded to the BigSurd class */ - if (terms.size() == 0) + if (terms.size() == 0) { return BigDecimal.ZERO; - else if (terms.size() == 1) { + } else if (terms.size() == 1) { return terms.firstElement().BigDecimalValue(mc); } @@ -263,18 +273,20 @@ public class BigSurdVec implements Comparable { * until we are stable to the required result. Keep the old (less * precise) estimate in res[0], and the newer, more precise in res[1]. */ - BigDecimal[] res = new BigDecimal[2]; + final BigDecimal[] res = new BigDecimal[2]; res[0] = BigDecimal.ZERO; for (int addpr = 1;; addpr += 3) { - MathContext locmc = new MathContext(mc.getPrecision() + addpr, mc.getRoundingMode()); + final MathContext locmc = new MathContext(mc.getPrecision() + addpr, mc.getRoundingMode()); res[1] = BigDecimal.ZERO; - for (BigSurd j : terms) + for (final BigSurd j : terms) { res[1] = BigDecimalMath.addRound(res[1], j.BigDecimalValue(locmc)); + } if (addpr > 1) { - BigDecimal err = res[1].subtract(res[0]).abs(); - int prec = BigDecimalMath.err2prec(res[1], err); - if (prec > mc.getPrecision()) + final BigDecimal err = res[1].subtract(res[0]).abs(); + final int prec = BigDecimalMath.err2prec(res[1], err); + if (prec > mc.getPrecision()) { break; + } } res[0] = res[1]; } @@ -288,7 +300,7 @@ public class BigSurdVec implements Comparable { * @return A truncated version with the precision described by mc */ public double doubleValue() { - BigDecimal bd = BigDecimalValue(MathContext.DECIMAL128); + final BigDecimal bd = BigDecimalValue(MathContext.DECIMAL128); return bd.doubleValue(); } /* doubleValue */ @@ -298,7 +310,7 @@ public class BigSurdVec implements Comparable { * @return A truncated version with the precision described by mc */ public double floatValue() { - BigDecimal bd = BigDecimalValue(MathContext.DECIMAL64); + final BigDecimal bd = BigDecimalValue(MathContext.DECIMAL64); return bd.floatValue(); } /* floatValue */ @@ -311,16 +323,16 @@ public class BigSurdVec implements Comparable { * @throws Error */ public BigSurdVec add(final BigSurdVec val) throws Error { - BigSurdVec sum = new BigSurdVec(); + final BigSurdVec sum = new BigSurdVec(); /* * concatenate the vectors and eliminate common overlaps */ - for (BigSurd term : terms) { + for (final BigSurd term : terms) { if (term.compareTo(BigSurd.ZERO) != 0) { sum.terms.add(term); } } - for (BigSurd term : val.terms) { + for (final BigSurd term : val.terms) { if (term.compareTo(BigSurd.ZERO) != 0) { sum.terms.add(term); } @@ -338,7 +350,7 @@ public class BigSurdVec implements Comparable { * @throws Error */ public BigSurdVec add(final BigSurd val) throws Error { - BigSurdVec sum = new BigSurdVec(); + final BigSurdVec sum = new BigSurdVec(); /* * concatenate the vectors and eliminate common overlaps */ @@ -357,13 +369,14 @@ public class BigSurdVec implements Comparable { * @throws Error */ public BigSurdVec subtract(final BigSurdVec val) throws Error { - BigSurdVec sum = new BigSurdVec(); + final BigSurdVec sum = new BigSurdVec(); /* * concatenate the vectors and eliminate common overlaps */ sum.terms.addAll(terms); - for (BigSurd s : val.terms) + for (final BigSurd s : val.terms) { sum.terms.add(s.negate()); + } sum.normalize(); return sum; } /* subtract */ @@ -377,7 +390,7 @@ public class BigSurdVec implements Comparable { * @throws Error */ public BigSurdVec subtract(final BigSurd val) throws Error { - BigSurdVec sum = new BigSurdVec(); + final BigSurdVec sum = new BigSurdVec(); /* * concatenate the vectors and eliminate common overlaps */ @@ -397,9 +410,10 @@ public class BigSurdVec implements Comparable { /* * accumulate the negated elements of term one by one */ - BigSurdVec resul = new BigSurdVec(); - for (BigSurd s : terms) + final BigSurdVec resul = new BigSurdVec(); + for (final BigSurd s : terms) { resul.terms.add(s.negate()); + } /* * no normalization step here, because the negation of all terms does * not introduce new common factors @@ -419,12 +433,15 @@ public class BigSurdVec implements Comparable { * Binomial expansion. First the sum of the terms squared, then 2 times * the mixed products. */ - BigSurdVec resul = new BigSurdVec(); - for (int i = 0; i < terms.size(); i++) + final BigSurdVec resul = new BigSurdVec(); + for (int i = 0; i < terms.size(); i++) { resul.terms.add(new BigSurd(terms.elementAt(i).sqr(), Rational.ONE)); - for (int i = 0; i < terms.size() - 1; i++) - for (int j = i + 1; j < terms.size(); j++) + } + for (int i = 0; i < terms.size() - 1; i++) { + for (int j = i + 1; j < terms.size(); j++) { resul.terms.add(terms.elementAt(i).multiply(terms.elementAt(j)).multiply(2)); + } + } resul.normalize(); return resul; } /* sqr */ @@ -439,28 +456,30 @@ public class BigSurdVec implements Comparable { * @since 2011-02-12 */ public BigSurdVec multiply(final BigSurd val) throws Error { - BigSurdVec resul = new BigSurdVec(); - for (BigSurd s : terms) + final BigSurdVec resul = new BigSurdVec(); + for (final BigSurd s : terms) { resul.terms.add(s.multiply(val)); + } resul.normalize(); return resul; } /* multiply */ public BigSurdVec multiply(final BigSurdVec val) throws Error { BigSurdVec resul = new BigSurdVec(); - for (BigSurd s : terms) { + for (final BigSurd s : terms) { resul.terms.add(s); } - for (BigSurd s : val.terms) { + for (final BigSurd s : val.terms) { resul = resul.multiply(s); } return resul; } /* multiply */ public BigSurdVec divide(final BigSurd val) throws Error { - BigSurdVec resul = new BigSurdVec(); - for (BigSurd s : terms) + final BigSurdVec resul = new BigSurdVec(); + for (final BigSurd s : terms) { resul.terms.add(s.divide(val)); + } resul.normalize(); return resul; } /* multiply */ @@ -468,7 +487,7 @@ public class BigSurdVec implements Comparable { public BigSurdVec divide(final BigSurdVec val) throws Error { BigSurdVec resul = new BigSurdVec(); resul.terms = terms; - for (BigSurd s : val.terms) { + for (final BigSurd s : val.terms) { resul = resul.divide(s); } return resul; @@ -482,7 +501,7 @@ public class BigSurdVec implements Comparable { */ public boolean isRational() { boolean val = false; - for (BigSurd s : terms) { + for (final BigSurd s : terms) { val = s.isRational(); if (val == false) { break; @@ -499,7 +518,7 @@ public class BigSurdVec implements Comparable { */ public boolean isBigInteger() { boolean val = false; - for (BigSurd s : terms) { + for (final BigSurd s : terms) { val = s.isBigInteger(); if (val == false) { break; @@ -515,9 +534,10 @@ public class BigSurdVec implements Comparable { */ public Rational toRational() { Rational rat = Rational.ZERO; - if (isRational() == false) + if (isRational() == false) { throw new ArithmeticException("Undefined conversion " + toString() + " to Rational."); - for (BigSurd s : terms) { + } + for (final BigSurd s : terms) { rat = rat.add(s.pref); } return rat; @@ -530,9 +550,10 @@ public class BigSurdVec implements Comparable { */ public BigInteger toBigInteger() { BigDecimal tmp = BigDecimal.ZERO.setScale(Utils.scale, Utils.scaleMode); - if (isBigInteger() == false) + if (isBigInteger() == false) { throw new ArithmeticException("Undefined conversion " + toString() + " to Rational."); - for (BigSurd s : terms) { + } + for (final BigSurd s : terms) { tmp = BigDecimalMath.addRound(tmp, s.pref.BigDecimalValue(new MathContext(Utils.scale, Utils.scaleMode2))); } return tmp.toBigInteger(); @@ -545,7 +566,7 @@ public class BigSurdVec implements Comparable { */ public BigDecimal toBigDecimal() { BigDecimal tmp = BigDecimal.ZERO.setScale(Utils.scale, Utils.scaleMode); - for (BigSurd s : terms) { + for (final BigSurd s : terms) { tmp = BigDecimalMath.addRound(tmp, s.BigDecimalValue(new MathContext(Utils.scale, Utils.scaleMode2))); } return tmp; @@ -563,14 +584,15 @@ public class BigSurdVec implements Comparable { /* * simple cases with one term forwarded to the BigSurd class */ - if (terms.size() == 0) + if (terms.size() == 0) { return new String("0"); - else { + } else { String s = new String(); for (int t = 0; t < terms.size(); t++) { - BigSurd bs = terms.elementAt(t); - if (bs.signum() > 0) + final BigSurd bs = terms.elementAt(t); + if (bs.signum() > 0) { s += "+"; + } s += bs.toString(); } return s; @@ -578,9 +600,9 @@ public class BigSurdVec implements Comparable { } /* toString */ public String toFancyString() { - if (terms.size() == 0) + if (terms.size() == 0) { return new String("0"); - else { + } else { BigInteger denominator = BigInteger.ONE; for (int i = 0; i < terms.size(); i++) { denominator = denominator.multiply(terms.elementAt(i).pref.b); @@ -590,15 +612,16 @@ public class BigSurdVec implements Comparable { s += "("; } for (int t = 0; t < terms.size(); t++) { - BigSurd bs = terms.elementAt(t); - if (bs.signum() > 0 && t > 0) + final BigSurd bs = terms.elementAt(t); + if (bs.signum() > 0 && t > 0) { s += "+"; + } if (bs.isBigInteger()) { s += bs.BigDecimalValue(new MathContext(Utils.scale, Utils.scaleMode2)).toBigInteger().toString(); } else if (bs.isRational()) { s += bs.toRational().toString(); } else { - BigInteger numerator = bs.pref.multiply(denominator).numer(); + final BigInteger numerator = bs.pref.multiply(denominator).numer(); if (numerator.compareTo(BigInteger.ONE) != 0) { s += numerator.toString(); s += "*"; diff --git a/src/org/nevec/rjm/Euler.java b/src/org/nevec/rjm/Euler.java index c28c31c5..76c1867d 100644 --- a/src/org/nevec/rjm/Euler.java +++ b/src/org/nevec/rjm/Euler.java @@ -38,20 +38,22 @@ public class Euler { while (n >= a.size()) { BigInteger val = BigInteger.ZERO; boolean sigPos = true; - int thisn = a.size(); + final int thisn = a.size(); for (int i = thisn - 1; i > 0; i--) { BigInteger f = new BigInteger("" + a.elementAt(i).toString()); f = f.multiply(BigIntegerMath.binomial(2 * thisn, 2 * i)); - if (sigPos) + if (sigPos) { val = val.add(f); - else + } else { val = val.subtract(f); + } sigPos = !sigPos; } - if (thisn % 2 == 0) + if (thisn % 2 == 0) { val = val.subtract(BigInteger.ONE); - else + } else { val = val.add(BigInteger.ONE); + } a.add(val); } } diff --git a/src/org/nevec/rjm/EulerPhi.java b/src/org/nevec/rjm/EulerPhi.java index 973e6944..90032917 100644 --- a/src/org/nevec/rjm/EulerPhi.java +++ b/src/org/nevec/rjm/EulerPhi.java @@ -36,16 +36,18 @@ public class EulerPhi { * @return phi(n) */ public BigInteger at(BigInteger n) { - if (n.compareTo(BigInteger.ZERO) <= 0) + if (n.compareTo(BigInteger.ZERO) <= 0) { throw new ArithmeticException("negative argument " + n + " of EulerPhi"); - Ifactor prFact = new Ifactor(n); + } + final Ifactor prFact = new Ifactor(n); BigInteger phi = n; - if (n.compareTo(BigInteger.ONE) > 0) + if (n.compareTo(BigInteger.ONE) > 0) { for (int i = 0; i < prFact.primeexp.size(); i += 2) { - BigInteger p = new BigInteger(prFact.primeexp.elementAt(i).toString()); - BigInteger p_1 = p.subtract(BigInteger.ONE); + final BigInteger p = new BigInteger(prFact.primeexp.elementAt(i).toString()); + final BigInteger p_1 = p.subtract(BigInteger.ONE); phi = phi.multiply(p_1).divide(p); } + } return phi; } /* at */ @@ -57,8 +59,8 @@ public class EulerPhi { * @since 2006-08-14 */ public static void main(String[] args) throws ArithmeticException { - EulerPhi a = new EulerPhi(); - int n = (new Integer(args[0])).intValue(); + final EulerPhi a = new EulerPhi(); + final int n = (new Integer(args[0])).intValue(); System.out.println("phi(" + n + ") = " + a.at(n)); } } /* EulerPhi */ diff --git a/src/org/nevec/rjm/Harmonic.java b/src/org/nevec/rjm/Harmonic.java index 37365b92..a3f733df 100644 --- a/src/org/nevec/rjm/Harmonic.java +++ b/src/org/nevec/rjm/Harmonic.java @@ -23,9 +23,9 @@ public class Harmonic { * For values of n less than 1, zero is returned. */ public Rational at(int n) { - if (n < 1) + if (n < 1) { return (new Rational(0, 1)); - else { + } else { /* * start with 1 as the result */ @@ -34,8 +34,9 @@ public class Harmonic { /* * add 1/i for i=2..n */ - for (int i = 2; i <= n; i++) + for (int i = 2; i <= n; i++) { a = a.add(new Rational(1, i)); + } return a; } } diff --git a/src/org/nevec/rjm/Ifactor.java b/src/org/nevec/rjm/Ifactor.java index dc5e22d3..c4cd9a98 100644 --- a/src/org/nevec/rjm/Ifactor.java +++ b/src/org/nevec/rjm/Ifactor.java @@ -48,7 +48,7 @@ public class Ifactor implements Cloneable, Comparable { primeexp = new Vector<>(); if (number > 1) { int primindx = 0; - Prime primes = new Prime(); + final Prime primes = new Prime(); /* * Test division against all primes. */ @@ -57,12 +57,13 @@ public class Ifactor implements Cloneable, Comparable { /* * primindx=0 refers to 2, =1 to 3, =2 to 5, =3 to 7 etc */ - int p = primes.at(primindx).intValue(); + final int p = primes.at(primindx).intValue(); while (number % p == 0) { ex++; number /= p; - if (number == 1) + if (number == 1) { break; + } } if (ex > 0) { primeexp.add(new Integer(p)); @@ -92,18 +93,19 @@ public class Ifactor implements Cloneable, Comparable { primeexp.add(new Integer(0)); } else { int primindx = 0; - Prime primes = new Prime(); + final Prime primes = new Prime(); /* * Test for division against all primes. */ while (number.compareTo(BigInteger.ONE) == 1) { int ex = 0; - BigInteger p = primes.at(primindx); + final BigInteger p = primes.at(primindx); while (number.remainder(p).compareTo(BigInteger.ZERO) == 0) { ex++; number = number.divide(p); - if (number.compareTo(BigInteger.ONE) == 0) + if (number.compareTo(BigInteger.ONE) == 0) { break; + } } if (ex > 0) { primeexp.add(new Integer(p.intValue())); @@ -128,19 +130,20 @@ public class Ifactor implements Cloneable, Comparable { primeexp = new Vector<>(2 * pows.size()); if (pows.size() > 0) { n = BigInteger.ONE; - Prime primes = new Prime(); + final Prime primes = new Prime(); /* * Build the full number by the product of all powers of the primes. */ for (int primindx = 0; primindx < pows.size(); primindx++) { - int ex = pows.elementAt(primindx).intValue(); + final int ex = pows.elementAt(primindx).intValue(); final BigInteger p = primes.at(primindx); n = n.multiply(p.pow(ex)); primeexp.add(new Integer(p.intValue())); primeexp.add(new Integer(ex)); } - } else + } else { n = BigInteger.ZERO; + } } /* Ifactor */ /** @@ -167,7 +170,7 @@ public class Ifactor implements Cloneable, Comparable { * Vector p = (Vector)primeexp.clone(); * */ - Ifactor cl = new Ifactor(0); + final Ifactor cl = new Ifactor(0); cl.n = new BigInteger("" + n); return cl; } /* Ifactor.clone */ @@ -267,7 +270,7 @@ public class Ifactor implements Cloneable, Comparable { * @return the product, gcd or lcm of both numbers. */ protected Ifactor multGcdLcm(final Ifactor oth, int type) { - Ifactor prod = new Ifactor(0); + final Ifactor prod = new Ifactor(0); /* * skip the case where 0*something =0, falling thru to the empty * representation for 0 @@ -278,19 +281,19 @@ public class Ifactor implements Cloneable, Comparable { * Cases of lcm(1, something) return something. * Cases of gcd(1, something) return 1. */ - if (primeexp.firstElement().intValue() == 1 && type == 0) + if (primeexp.firstElement().intValue() == 1 && type == 0) { return oth; - else if (primeexp.firstElement().intValue() == 1 && type == 2) + } else if (primeexp.firstElement().intValue() == 1 && type == 2) { return oth; - else if (primeexp.firstElement().intValue() == 1 && type == 1) + } else if (primeexp.firstElement().intValue() == 1 && type == 1) { return this; - else if (oth.primeexp.firstElement().intValue() == 1 && type == 0) + } else if (oth.primeexp.firstElement().intValue() == 1 && type == 0) { return this; - else if (oth.primeexp.firstElement().intValue() == 1 && type == 2) + } else if (oth.primeexp.firstElement().intValue() == 1 && type == 2) { return this; - else if (oth.primeexp.firstElement().intValue() == 1 && type == 1) + } else if (oth.primeexp.firstElement().intValue() == 1 && type == 1) { return oth; - else { + } else { int idxThis = 0; int idxOth = 0; switch (type) { @@ -417,10 +420,11 @@ public class Ifactor implements Cloneable, Comparable { /* * avoid refactorization if oth is zero... */ - if (oth.compareTo(BigInteger.ZERO) != 0) + if (oth.compareTo(BigInteger.ZERO) != 0) { return new Ifactor(n.add(oth)); - else + } else { return this; + } } /* Ifactor.add */ /** @@ -434,22 +438,23 @@ public class Ifactor implements Cloneable, Comparable { /* * three simple cases first */ - if (exponent < 0) + if (exponent < 0) { throw new ArithmeticException("Cannot raise " + toString() + " to negative " + exponent); - else if (exponent == 0) + } else if (exponent == 0) { return new Ifactor(1); - else if (exponent == 1) + } else if (exponent == 1) { return this; + } /* * general case, the vector with the prime factor powers, which are * component-wise * exponentiation of the individual prime factor powers. */ - Ifactor pows = new Ifactor(0); + final Ifactor pows = new Ifactor(0); for (int i = 0; i < primeexp.size(); i += 2) { - Integer p = primeexp.elementAt(i); - int ex = primeexp.elementAt(i + 1).intValue(); + final Integer p = primeexp.elementAt(i); + final int ex = primeexp.elementAt(i + 1).intValue(); pows.primeexp.add(p); pows.primeexp.add(new Integer(ex * exponent)); } @@ -469,24 +474,25 @@ public class Ifactor implements Cloneable, Comparable { * @since 2009-05-18 */ public Rational root(final int r) throws ArithmeticException, Error { - if (r == 0) + if (r == 0) { throw new ArithmeticException("Cannot pull zeroth root of " + toString()); - else if (r < 0) { + } else if (r < 0) { /* * a^(-1/b)= 1/(a^(1/b)) */ final Rational invRoot = root(-r); return Rational.ONE.divide(invRoot); } else { - BigInteger pows = BigInteger.ONE; + final BigInteger pows = BigInteger.ONE; for (int i = 0; i < primeexp.size(); i += 2) { /* * all exponents must be multiples of r to succeed (that is, to * stay in the range of rational results). */ - int ex = primeexp.elementAt(i + 1).intValue(); - if (ex % r != 0) + final int ex = primeexp.elementAt(i + 1).intValue(); + if (ex % r != 0) { throw new ArithmeticException("Cannot pull " + r + "th root of " + toString()); + } pows.multiply(new BigInteger("" + primeexp.elementAt(i)).pow(ex / r)); } @@ -512,18 +518,19 @@ public class Ifactor implements Cloneable, Comparable { * multiplied * by 1 or by a product that contains the factors p1..py. */ - Vector d = new Vector<>(); - if (n.compareTo(BigInteger.ZERO) == 0) + final Vector d = new Vector<>(); + if (n.compareTo(BigInteger.ZERO) == 0) { return d; + } d.add(BigInteger.ONE); if (n.compareTo(BigInteger.ONE) > 0) { /* Computes sigmaIncopml(p1^e*p2^e2...*py^ey) */ - Ifactor dp = dropPrime(); + final Ifactor dp = dropPrime(); /* get ez */ final int ez = primeexp.lastElement().intValue(); - Vector partd = dp.divisors(); + final Vector partd = dp.divisors(); /* obtain pz by lookup in the prime list */ final BigInteger pz = new BigInteger(primeexp.elementAt(primeexp.size() - 2).toString()); @@ -532,12 +539,14 @@ public class Ifactor implements Cloneable, Comparable { * the output contains all products of the form partd[]*pz^ez, ez>0, * and with the exception of the 1, all these are appended. */ - for (int i = 1; i < partd.size(); i++) + for (int i = 1; i < partd.size(); i++) { d.add(partd.elementAt(i)); + } for (int e = 1; e <= ez; e++) { final BigInteger pzez = pz.pow(e); - for (int i = 0; i < partd.size(); i++) + for (int i = 0; i < partd.size(); i++) { d.add(partd.elementAt(i).multiply(pzez)); + } } } Collections.sort(d); @@ -563,29 +572,29 @@ public class Ifactor implements Cloneable, Comparable { * the question is whether keeping a factorization is worth the effort * or whether one should simply multiply these to return a BigInteger... */ - if (n.compareTo(BigInteger.ONE) == 0) + if (n.compareTo(BigInteger.ONE) == 0) { return ONE; - else if (n.compareTo(BigInteger.ZERO) == 0) + } else if (n.compareTo(BigInteger.ZERO) == 0) { return ZERO; - else { + } else { /* * multiplicative: sigma_k(p^e) = [p^(k*(e+1))-1]/[p^k-1] * sigma_0(p^e) = e+1. */ Ifactor resul = Ifactor.ONE; for (int i = 0; i < primeexp.size(); i += 2) { - int ex = primeexp.elementAt(i + 1).intValue(); - if (k == 0) + final int ex = primeexp.elementAt(i + 1).intValue(); + if (k == 0) { resul = resul.multiply(ex + 1); - else { - Integer p = primeexp.elementAt(i); - BigInteger num = (new BigInteger(p.toString())).pow(k * (ex + 1)).subtract(BigInteger.ONE); - BigInteger deno = (new BigInteger(p.toString())).pow(k).subtract(BigInteger.ONE); + } else { + final Integer p = primeexp.elementAt(i); + final BigInteger num = (new BigInteger(p.toString())).pow(k * (ex + 1)).subtract(BigInteger.ONE); + final BigInteger deno = (new BigInteger(p.toString())).pow(k).subtract(BigInteger.ONE); /* * This division is of course exact, no remainder * The costly prime factorization is hidden here. */ - Ifactor f = new Ifactor(num.divide(deno)); + final Ifactor f = new Ifactor(num.divide(deno)); resul = resul.multiply(f); } } @@ -608,8 +617,9 @@ public class Ifactor implements Cloneable, Comparable { /* * the cases n==1 or n ==0 */ - if (n.compareTo(BigInteger.ONE) <= 0) + if (n.compareTo(BigInteger.ONE) <= 0) { return this; + } /* * The cases n>1 @@ -617,13 +627,13 @@ public class Ifactor implements Cloneable, Comparable { * the vector with the new prime factor powers, which contain the * old prime factor powers up to but not including the last one. */ - Ifactor pows = new Ifactor(0); + final Ifactor pows = new Ifactor(0); pows.n = BigInteger.ONE; for (int i = 0; i < primeexp.size() - 2; i += 2) { pows.primeexp.add(primeexp.elementAt(i)); pows.primeexp.add(primeexp.elementAt(i + 1)); - BigInteger p = new BigInteger(primeexp.elementAt(i).toString()); - int ex = primeexp.elementAt(i + 1).intValue(); + final BigInteger p = new BigInteger(primeexp.elementAt(i).toString()); + final int ex = primeexp.elementAt(i + 1).intValue(); pows.n = pows.n.multiply(p.pow(ex)); } return pows; @@ -639,8 +649,9 @@ public class Ifactor implements Cloneable, Comparable { * check the exponents, located at the odd-indexed positions */ for (int i = 1; i < primeexp.size(); i += 2) { - if (primeexp.elementAt(i).intValue() % 2 != 0) + if (primeexp.elementAt(i).intValue() % 2 != 0) { return false; + } } return true; } /* Ifactor.issquare */ @@ -652,8 +663,9 @@ public class Ifactor implements Cloneable, Comparable { */ public int bigomega() { int resul = 0; - for (int i = 1; i < primeexp.size(); i += 2) + for (int i = 1; i < primeexp.size(); i += 2) { resul += primeexp.elementAt(i).intValue(); + } return (resul); } /* Ifactor.bigomega */ @@ -675,9 +687,11 @@ public class Ifactor implements Cloneable, Comparable { */ public BigInteger core() { BigInteger resul = BigInteger.ONE; - for (int i = 0; i < primeexp.size(); i += 2) - if (primeexp.elementAt(i + 1).intValue() % 2 != 0) + for (int i = 0; i < primeexp.size(); i += 2) { + if (primeexp.elementAt(i + 1).intValue() % 2 != 0) { resul = resul.multiply(new BigInteger(primeexp.elementAt(i).toString())); + } + } return resul; } /* Ifactor.core */ @@ -690,17 +704,19 @@ public class Ifactor implements Cloneable, Comparable { * @return the moebius function. */ public int moebius() { - if (n.compareTo(BigInteger.ONE) <= 0) + if (n.compareTo(BigInteger.ONE) <= 0) { return 1; + } /* accumulate number of different primes in k */ int k = 1; for (int i = 0; i < primeexp.size(); i += 2) { final int e = primeexp.elementAt(i + 1).intValue(); - if (e > 1) + if (e > 1) { return 0; - else if (e == 1) + } else if (e == 1) { /* accumulates (-1)^k */ k *= -1; + } } return (k); @@ -714,10 +730,11 @@ public class Ifactor implements Cloneable, Comparable { * @return the larger of the two values. */ public Ifactor max(final Ifactor oth) { - if (n.compareTo(oth.n) >= 0) + if (n.compareTo(oth.n) >= 0) { return this; - else + } else { return oth; + } } /* Ifactor.max */ /** @@ -728,10 +745,11 @@ public class Ifactor implements Cloneable, Comparable { * @return the smaller of the two values. */ public Ifactor min(final Ifactor oth) { - if (n.compareTo(oth.n) <= 0) + if (n.compareTo(oth.n) <= 0) { return this; - else + } else { return oth; + } } /* Ifactor.min */ /** @@ -743,8 +761,9 @@ public class Ifactor implements Cloneable, Comparable { */ public static Ifactor max(final Vector set) { Ifactor resul = set.elementAt(0); - for (int i = 1; i < set.size(); i++) + for (int i = 1; i < set.size(); i++) { resul = resul.max(set.elementAt(i)); + } return resul; } /* Ifactor.max */ @@ -757,8 +776,9 @@ public class Ifactor implements Cloneable, Comparable { */ public static Ifactor min(final Vector set) { Ifactor resul = set.elementAt(0); - for (int i = 1; i < set.size(); i++) + for (int i = 1; i < set.size(); i++) { resul = resul.min(set.elementAt(i)); + } return resul; } /* Ifactor.min */ @@ -784,17 +804,19 @@ public class Ifactor implements Cloneable, Comparable { @Override public String toString() { String resul = new String(n.toString() + ":"); - if (n.compareTo(BigInteger.ONE) == 0) + if (n.compareTo(BigInteger.ONE) == 0) { resul += "1"; - else { + } else { boolean firstMul = true; for (int i = 0; i < primeexp.size(); i += 2) { - if (!firstMul) + if (!firstMul) { resul += "*"; - if (primeexp.elementAt(i + 1).intValue() > 1) + } + if (primeexp.elementAt(i + 1).intValue() > 1) { resul += primeexp.elementAt(i).toString() + "^" + primeexp.elementAt(i + 1).toString(); - else + } else { resul += primeexp.elementAt(i).toString(); + } firstMul = false; } } @@ -807,7 +829,7 @@ public class Ifactor implements Cloneable, Comparable { * java -cp . org.nevec.rjm.Ifactor n
*/ public static void main(String[] args) throws Exception { - BigInteger n = new BigInteger(args[0]); + final BigInteger n = new BigInteger(args[0]); System.out.println(new Ifactor(n)); } /* Ifactor.main */ } /* Ifactor */ diff --git a/src/org/nevec/rjm/PartitionsP.java b/src/org/nevec/rjm/PartitionsP.java index 163f169f..be05d656 100644 --- a/src/org/nevec/rjm/PartitionsP.java +++ b/src/org/nevec/rjm/PartitionsP.java @@ -63,9 +63,9 @@ public class PartitionsP { private void growto(BigInteger n) { while (a.size() <= n.intValue()) { BigInteger per = new BigInteger("0"); - BigInteger cursiz = new BigInteger("" + a.size()); + final BigInteger cursiz = new BigInteger("" + a.size()); for (int k = 0; k < a.size(); k++) { - BigInteger tmp = a.elementAt(k).multiply(BigIntegerMath.sigma(a.size() - k)); + final BigInteger tmp = a.elementAt(k).multiply(BigIntegerMath.sigma(a.size() - k)); per = per.add(tmp); } a.add(per.divide(cursiz)); @@ -81,8 +81,8 @@ public class PartitionsP { * @since 2008-10-15 */ public static void main(String[] args) throws Exception { - PartitionsP a = new PartitionsP(); - int n = (new Integer(args[0])).intValue(); + final PartitionsP a = new PartitionsP(); + final int n = (new Integer(args[0])).intValue(); System.out.println("P(" + n + ")=" + a.at(n)); } } diff --git a/src/org/nevec/rjm/Prime.java b/src/org/nevec/rjm/Prime.java index cce2e510..b5c9a541 100644 --- a/src/org/nevec/rjm/Prime.java +++ b/src/org/nevec/rjm/Prime.java @@ -86,38 +86,34 @@ public class Prime { /* * numbers less than 2 are not prime */ - if (n.compareTo(two) == -1) + if (n.compareTo(two) == -1) { return false; - /* - * 2 is prime - */ - else if (n.compareTo(two) == 0) + } else if (n.compareTo(two) == 0) { return true; - /* - * even numbers >2 are not prime - */ - else if (n.remainder(two).compareTo(BigInteger.ZERO) == 0) + } else if (n.remainder(two).compareTo(BigInteger.ZERO) == 0) { return false; - else { + } else { /* * q= n- 1 = d *2^s with d odd */ final BigInteger q = n.subtract(BigInteger.ONE); - int s = q.getLowestSetBit(); - BigInteger d = q.shiftRight(s); + final int s = q.getLowestSetBit(); + final BigInteger d = q.shiftRight(s); /* * test whether a^d = 1 (mod n) */ - if (a.modPow(d, n).compareTo(BigInteger.ONE) == 0) + if (a.modPow(d, n).compareTo(BigInteger.ONE) == 0) { return true; + } /* * test whether a^(d*2^r) = -1 (mod n), 0<=r= 0) + for (int i = 0; i < a.size(); i++) { + if (a.elementAt(i).compareTo(n) >= 0) { return (a.elementAt(i - 1)); + } + } return (a.lastElement()); } @@ -272,8 +278,9 @@ public class Prime { /* * Test the list of known primes only up to sqrt(n) */ - if (a.get(p).multiply(a.get(p)).compareTo(nMax) == 1) + if (a.get(p).multiply(a.get(p)).compareTo(nMax) == 1) { break; + } /* * The next case means that the p'th number in the list of known @@ -285,8 +292,9 @@ public class Prime { break; } } - if (isp) + if (isp) { a.add(nMax); + } } } @@ -299,11 +307,12 @@ public class Prime { * @since 2006-08-14 */ public static void main(String[] args) throws Exception { - Prime a = new Prime(); - int n = (new Integer(args[0])).intValue(); + final Prime a = new Prime(); + final int n = (new Integer(args[0])).intValue(); if (n >= 1) { - if (n >= 2) + if (n >= 2) { System.out.println("prime(" + (n - 1) + ") = " + a.at(n - 1)); + } System.out.println("prime(" + n + ") = " + a.at(n)); System.out.println("prime(" + (n + 1) + ") = " + a.at(n + 1)); System.out.println("pi(" + n + ") = " + a.pi(new BigInteger("" + n))); diff --git a/src/org/nevec/rjm/RatPoly.java b/src/org/nevec/rjm/RatPoly.java index 668b0305..a9c12a15 100644 --- a/src/org/nevec/rjm/RatPoly.java +++ b/src/org/nevec/rjm/RatPoly.java @@ -43,8 +43,9 @@ class RatPoly { */ public RatPoly(final Vector L) { a = new Vector<>(); - for (int i = 0; i < L.size(); i++) + for (int i = 0; i < L.size(); i++) { a.add(L.elementAt(i).clone()); + } simplify(); } /* ctor */ @@ -56,10 +57,10 @@ class RatPoly { */ public RatPoly(final String L) throws NumberFormatException { a = new Vector<>(); - Scanner sc = new Scanner(L); + final Scanner sc = new Scanner(L); sc.useDelimiter(","); while (sc.hasNext()) { - String tok = sc.next(); + final String tok = sc.next(); a.add(new Rational(tok)); } simplify(); @@ -103,16 +104,18 @@ class RatPoly { BigInteger Nmax = BigInteger.ONE.negate(); for (int j = 0; j < A.size(); j++) { if (A.elementAt(j).compareTo(BigInteger.ZERO) <= 0) { - if (Nmax.compareTo(BigInteger.ZERO) < 0) + if (Nmax.compareTo(BigInteger.ZERO) < 0) { Nmax = A.elementAt(j).negate(); - else + } else { Nmax = Nmax.min(A.elementAt(j).negate()); + } } } - if (Nmax.compareTo(BigInteger.ZERO) < 0) + if (Nmax.compareTo(BigInteger.ZERO) < 0) { throw new ArithmeticException("Infinite Number of Terms in Series " + Nmax.toString()); + } - int nmax = Nmax.intValue() - 1; + final int nmax = Nmax.intValue() - 1; init(A, B, nmax); } /* ctor */ @@ -130,15 +133,15 @@ class RatPoly { */ protected void init(final Vector A, final Vector B, int nmax) throws Error { a = new Vector<>(); - Factorial f = new Factorial(); + final Factorial f = new Factorial(); for (int n = 0; n <= nmax; n++) { Rational c = new Rational(1, 1); for (int j = 0; j < A.size(); j++) { - Rational aEl = new Rational(A.elementAt(j)); + final Rational aEl = new Rational(A.elementAt(j)); c = c.multiply(aEl.Pochhammer(n)); } for (int j = 0; j < B.size(); j++) { - Rational bEl = new Rational(B.elementAt(j)); + final Rational bEl = new Rational(B.elementAt(j)); c = c.divide(bEl.Pochhammer(n)); } c = c.divide(f.at(n)); @@ -155,7 +158,7 @@ class RatPoly { @Override @SuppressWarnings("unchecked") public RatPoly clone() { - RatPoly clo = new RatPoly(); + final RatPoly clo = new RatPoly(); clo.a = (Vector) a.clone(); return clo; } /* clone */ @@ -169,10 +172,11 @@ class RatPoly { * @return the polynomial coefficient in front of x^n. */ public Rational at(final int n) { - if (n < a.size()) + if (n < a.size()) { return (a.elementAt(n)); - else + } else { return (new Rational(0, 1)); + } } /* at */ /** @@ -187,8 +191,9 @@ class RatPoly { public BigComplex valueOf(BigComplex x, MathContext mc) { /* result is initialized to zero */ BigComplex f = new BigComplex(); - for (int i = degree(); i >= 0; i--) + for (int i = degree(); i >= 0; i--) { f = f.multiply(x, mc).add(a.elementAt(i).BigDecimalValue(mc)); + } return f; } /* valueOf */ @@ -202,8 +207,9 @@ class RatPoly { public Rational valueOf(Rational x) { /* result is initialized to zero */ Rational f = new Rational(0, 1); - for (int i = degree(); i >= 0; i--) + for (int i = degree(); i >= 0; i--) { f = f.multiply(x).add(a.elementAt(i)); + } return f; } /* valueOf */ @@ -240,14 +246,15 @@ class RatPoly { * @param value the new value of the coefficient. */ public void set(final int n, final Rational value) { - if (n < a.size()) + if (n < a.size()) { a.set(n, value); - else { + } else { /* * fill intermediate powers with coefficients of zero */ - while (a.size() < n) + while (a.size() < n) { a.add(new Rational(0, 1)); + } a.add(value); } } /* set */ @@ -265,7 +272,7 @@ class RatPoly { * the new value of the coefficient. */ public void set(final int n, final BigInteger value) { - Rational val2 = new Rational(value, BigInteger.ONE); + final Rational val2 = new Rational(value, BigInteger.ONE); set(n, val2); } /* set */ @@ -282,7 +289,7 @@ class RatPoly { * the new value of the coefficient. */ public void set(final int n, final int value) { - Rational val2 = new Rational(value, 1); + final Rational val2 = new Rational(value, 1); set(n, val2); } /* set */ @@ -293,9 +300,10 @@ class RatPoly { */ public void setExp(final int nmax) { a.clear(); - Factorial factorial = new Factorial(); - for (int n = 0; n <= nmax; n++) + final Factorial factorial = new Factorial(); + for (int n = 0; n <= nmax; n++) { set(n, new Rational(BigInteger.ONE, factorial.at(n))); + } } /* setExp */ /** @@ -336,9 +344,11 @@ class RatPoly { * @since 2010-08-27 */ public int ldegree() { - for (int n = 0; n < a.size(); n++) - if (a.elementAt(n).compareTo(BigInteger.ZERO) != 0) + for (int n = 0; n < a.size(); n++) { + if (a.elementAt(n).compareTo(BigInteger.ZERO) != 0) { return n; + } + } return 0; } /* ldegree */ @@ -352,10 +362,12 @@ class RatPoly { * factor. */ public RatPoly multiply(final Rational val) { - RatPoly resul = new RatPoly(); - if (val.compareTo(BigInteger.ZERO) != 0) - for (int n = 0; n < a.size(); n++) + final RatPoly resul = new RatPoly(); + if (val.compareTo(BigInteger.ZERO) != 0) { + for (int n = 0; n < a.size(); n++) { resul.set(n, a.elementAt(n).multiply(val)); + } + } return resul; } /* multiply */ @@ -370,10 +382,12 @@ class RatPoly { * @since 2010-08-27 */ public RatPoly multiply(final BigInteger val) { - RatPoly resul = new RatPoly(); - if (val.compareTo(BigInteger.ZERO) != 0) - for (int n = 0; n < a.size(); n++) + final RatPoly resul = new RatPoly(); + if (val.compareTo(BigInteger.ZERO) != 0) { + for (int n = 0; n < a.size(); n++) { resul.set(n, a.elementAt(n).multiply(val)); + } + } return resul; } /* multiply */ @@ -385,7 +399,7 @@ class RatPoly { * @return the product of this with the other polynomial */ public RatPoly multiply(final RatPoly val) { - RatPoly resul = new RatPoly(); + final RatPoly resul = new RatPoly(); /* * the degree of the result is the sum of the two degrees. */ @@ -410,15 +424,16 @@ class RatPoly { */ public RatPoly pow(final int n) throws ArithmeticException { RatPoly resul = new RatPoly("1"); - if (n < 0) + if (n < 0) { throw new ArithmeticException("negative polynomial power " + n); - else { + } else { /* * this ought probably be done with some binary representation * of the power and a smaller number of multiplications. */ - for (int i = 1; i <= n; i++) + for (int i = 1; i <= n; i++) { resul = resul.multiply(this); + } resul.simplify(); return resul; } @@ -447,7 +462,7 @@ class RatPoly { * scale the polynomial by division through the expansion coefficient of * the absolute term */ - RatPoly red = divide(a.elementAt(0)); + final RatPoly red = divide(a.elementAt(0)); /* * and remove the leading term (now equal to 1) @@ -477,14 +492,14 @@ class RatPoly { * @since 2008-10-25 */ public RatPoly add(final RatPoly val) { - RatPoly resul = new RatPoly(); + final RatPoly resul = new RatPoly(); /* * the degree of the result is the larger of the two degrees (before * simplify() at least). */ final int nmax = (degree() > val.degree()) ? degree() : val.degree(); for (int n = 0; n <= nmax; n++) { - Rational coef = at(n).add(val.at(n)); + final Rational coef = at(n).add(val.at(n)); resul.set(n, coef); } resul.simplify(); @@ -500,14 +515,14 @@ class RatPoly { * @since 2008-10-25 */ public RatPoly subtract(final RatPoly val) { - RatPoly resul = new RatPoly(); + final RatPoly resul = new RatPoly(); /* * the degree of the result is the larger of the two degrees (before * simplify() at least). */ final int nmax = (degree() > val.degree()) ? degree() : val.degree(); for (int n = 0; n <= nmax; n++) { - Rational coef = at(n).subtract(val.at(n)); + final Rational coef = at(n).subtract(val.at(n)); resul.set(n, coef); } resul.simplify(); @@ -525,12 +540,14 @@ class RatPoly { */ public RatPoly divide(final Rational val) throws Error { if (val.compareTo(Rational.ZERO) != 0) { - RatPoly resul = new RatPoly(); - for (int n = 0; n < a.size(); n++) + final RatPoly resul = new RatPoly(); + for (int n = 0; n < a.size(); n++) { resul.set(n, a.elementAt(n).divide(val)); + } return resul; - } else + } else { throw new ArithmeticException("Cannot divide " + toPString() + " through zero."); + } } /* divide */ /** @@ -544,8 +561,8 @@ class RatPoly { * @throws Error */ public RatPoly divide(final RatPoly val, int nmax) throws Error { - RatPoly num = this; - RatPoly denom = val; + final RatPoly num = this; + final RatPoly denom = val; /* * divide by a common smallest power/degree @@ -553,11 +570,12 @@ class RatPoly { while (num.at(0).compareTo(BigInteger.ZERO) == 0 && denom.at(0).compareTo(BigInteger.ZERO) == 0) { num.a.remove(0); denom.a.remove(0); - if (num.size() <= 1 || denom.size() <= 1) + if (num.size() <= 1 || denom.size() <= 1) { break; + } } - RatPoly resul = new RatPoly(); + final RatPoly resul = new RatPoly(); /* * todo: If the polynomial division is exact, we could leave * the loop earlier, indeed @@ -587,20 +605,21 @@ class RatPoly { * @since 2012-03-01 */ public RatPoly[] divideAndRemainder(final RatPoly val) throws Error { - RatPoly[] ret = new RatPoly[2]; + final RatPoly[] ret = new RatPoly[2]; /* * remove any high-order zeros */ - RatPoly valSimpl = val.clone(); + final RatPoly valSimpl = val.clone(); valSimpl.simplify(); - RatPoly thisSimpl = clone(); + final RatPoly thisSimpl = clone(); thisSimpl.simplify(); /* * catch the case with val equal to zero */ - if (valSimpl.degree() == 0 && valSimpl.a.firstElement().compareTo(Rational.ZERO) == 0) + if (valSimpl.degree() == 0 && valSimpl.a.firstElement().compareTo(Rational.ZERO) == 0) { throw new ArithmeticException("Division through zero polynomial"); + } /* * degree of this smaller than degree of val: remainder is this */ @@ -628,10 +647,10 @@ class RatPoly { /* * any remainder left ? */ - if (ret[1].degree() < valSimpl.degree()) + if (ret[1].degree() < valSimpl.degree()) { ; - else { - RatPoly rem[] = ret[1].divideAndRemainder(val); + } else { + final RatPoly rem[] = ret[1].divideAndRemainder(val); ret[0] = ret[0].add(rem[0]); ret[1] = rem[1]; } @@ -651,16 +670,18 @@ class RatPoly { public String toString() { String str = new String(); for (int n = 0; n < a.size(); n++) { - if (n == 0) + if (n == 0) { str += a.elementAt(n).toString(); - else + } else { str += "," + a.elementAt(n).toString(); + } } /* * print at least a sole zero */ - if (str.length() == 0) + if (str.length() == 0) { str = "0"; + } return str; } /* toString */ @@ -677,21 +698,24 @@ class RatPoly { final BigInteger num = a.elementAt(n).a; if (num.compareTo(BigInteger.ZERO) != 0) { str += " "; - if (num.compareTo(BigInteger.ZERO) > 0) + if (num.compareTo(BigInteger.ZERO) > 0) { str += "+"; + } str += a.elementAt(n).toString(); if (n > 0) { str += "*x"; - if (n > 1) + if (n > 1) { str += "^" + n; + } } } } /* * print at least a sole zero */ - if (str.length() == 0) + if (str.length() == 0) { str = "0"; + } return str; } /* toPString */ @@ -703,12 +727,14 @@ class RatPoly { */ private void simplify() { int n = a.size() - 1; - if (n >= 0) + if (n >= 0) { while (a.elementAt(n).compareTo(BigInteger.ZERO) == 0) { a.remove(n); - if (--n < 0) + if (--n < 0) { break; + } } + } } /* simplify */ /** @@ -718,13 +744,13 @@ class RatPoly { * @since 2008-10-26 */ public RatPoly derive() { - if (a.size() <= 1) + if (a.size() <= 1) { /* * derivative of the constant is just zero */ return new RatPoly(); - else { - RatPoly d = new RatPoly(); + } else { + final RatPoly d = new RatPoly(); for (int i = 1; i <= degree(); i++) { final Rational c = a.elementAt(i).multiply(i); d.set(i - 1, c); @@ -742,7 +768,7 @@ class RatPoly { * @since 2008-10-26 */ public RatPoly monic() throws Error { - RatPoly m = new RatPoly(); + final RatPoly m = new RatPoly(); final int d = degree(); for (int i = 0; i <= d; i++) { final Rational c = a.elementAt(i).divide(a.elementAt(d)); @@ -764,7 +790,7 @@ class RatPoly { /* * Start with the polynomial 0 */ - RatPoly r = new RatPoly(); + final RatPoly r = new RatPoly(); for (int i = 1; i <= maxdeg; i++) { Rational c = new Rational(); for (int d = 1; d <= i && d < a.size(); d++) { @@ -792,12 +818,13 @@ class RatPoly { /* * Start with the polynomial 0 */ - RatPoly r = new RatPoly(); + final RatPoly r = new RatPoly(); for (int i = 1; i <= maxdeg; i++) { Rational c = new Rational(); for (int d = 1; d <= i && d < a.size(); d++) { - if (i % d == 0) + if (i % d == 0) { c = c.add(a.elementAt(d)); + } } r.set(i, c); } @@ -815,11 +842,12 @@ class RatPoly { * @since 2008-10-26 */ public RatPoly binomialT(int maxdeg) { - RatPoly r = new RatPoly(); + final RatPoly r = new RatPoly(); for (int i = 0; i <= maxdeg; i++) { Rational c = new Rational(0, 1); - for (int j = 0; j <= i && j < a.size(); j++) + for (int j = 0; j <= i && j < a.size(); j++) { c = c.add(a.elementAt(j).multiply(BigIntegerMath.binomial(i, j))); + } r.set(i, c); } r.simplify(); @@ -836,14 +864,16 @@ class RatPoly { * @since 2008-10-26 */ public RatPoly binomialTInv(int maxdeg) { - RatPoly r = new RatPoly(); + final RatPoly r = new RatPoly(); for (int i = 0; i <= maxdeg; i++) { Rational c = new Rational(0, 1); - for (int j = 0; j <= i && j < a.size(); j++) - if ((j + i) % 2 != 0) + for (int j = 0; j <= i && j < a.size(); j++) { + if ((j + i) % 2 != 0) { c = c.subtract(a.elementAt(j).multiply(BigIntegerMath.binomial(i, j))); - else + } else { c = c.add(a.elementAt(j).multiply(BigIntegerMath.binomial(i, j))); + } + } r.set(i, c); } r.simplify(); @@ -865,9 +895,10 @@ class RatPoly { * @since 2008-10-26 */ public RatPoly trunc(int newdeg) { - RatPoly t = new RatPoly(); - for (int i = 0; i <= newdeg; i++) + final RatPoly t = new RatPoly(); + for (int i = 0; i <= newdeg; i++) { t.set(i, at(i)); + } t.simplify(); return t; } /* trunc */ @@ -883,10 +914,10 @@ class RatPoly { * @since 2008-10-26 */ public Vector roots(int digits) throws Error { - RatPoly mon = monic(); + final RatPoly mon = monic(); - Random rand = new Random(); - MathContext mc = new MathContext(digits + 3, RoundingMode.DOWN); + final Random rand = new Random(); + final MathContext mc = new MathContext(digits + 3, RoundingMode.DOWN); Vector res = new Vector<>(); @@ -894,9 +925,10 @@ class RatPoly { double randRad = 0.; for (int i = 0; i <= d; i++) { /* scale coefficient at maximum degree */ - double absi = Math.abs(mon.at(i).doubleValue()); - if (absi > randRad) + final double absi = Math.abs(mon.at(i).doubleValue()); + if (absi > randRad) { randRad = absi; + } } randRad += 1.0; @@ -904,8 +936,8 @@ class RatPoly { * initial values randomly in radius 1+randRad */ for (int i = 0; i < d; i++) { - double rad = randRad * rand.nextDouble(); - double phi = 2.0 * 3.14159 * rand.nextDouble(); + final double rad = randRad * rand.nextDouble(); + final double phi = 2.0 * 3.14159 * rand.nextDouble(); res.add(i, new BigComplex(rad * Math.cos(phi), rad * Math.sin(phi))); } @@ -918,7 +950,7 @@ class RatPoly { for (; !convr;)// ORIGINAL LINE: for(int itr =0 ; ! convr ; itr++) { convr = true; - Vector resPlus = new Vector<>(); + final Vector resPlus = new Vector<>(); for (int v = 0; v < d; v++) { /* * evaluate f(x)/(x-root1)/(x-root2)/... (x-rootdegr), Newton @@ -927,19 +959,22 @@ class RatPoly { BigComplex thisx = res.elementAt(v); BigComplex nv = mon.valueOf(thisx, mc); for (int j = 0; j < d; j++) { - if (j != v) + if (j != v) { nv = nv.divide(thisx.subtract(res.elementAt(j)), mc); + } } /* is this value converged ? */ - if (nv.abs(mc).doubleValue() > thisx.abs(mc).doubleValue() * Math.pow(10.0, -digits)) + if (nv.abs(mc).doubleValue() > thisx.abs(mc).doubleValue() * Math.pow(10.0, -digits)) { convr = false; + } thisx = thisx.subtract(nv); /* If unstable, start over */ - if (thisx.abs(MathContext.DECIMAL32).doubleValue() > randRad) + if (thisx.abs(MathContext.DECIMAL32).doubleValue() > randRad) { return roots(digits); + } resPlus.add(thisx); } @@ -959,9 +994,9 @@ class RatPoly { */ public Vector iroots() { /* The vector of the roots */ - Vector res = new Vector<>(); + final Vector res = new Vector<>(); - int lowd = ldegree(); + final int lowd = ldegree(); if (lowd == 0 && a.elementAt(0).compareTo(BigInteger.ZERO) == 0) { /* * Case of polynomial identical to zero: @@ -977,28 +1012,29 @@ class RatPoly { * start with denominator of first non-zero coefficient. */ BigInteger lcmDeno = a.elementAt(lowd).b; - for (int i = lowd + 1; i < degree(); i++) + for (int i = lowd + 1; i < degree(); i++) { lcmDeno = BigIntegerMath.lcm(lcmDeno, a.elementAt(i).b); + } /* * and eventually get the integer polynomial by ignoring the * denominators */ - Vector ipo = new Vector<>(); + final Vector ipo = new Vector<>(); for (int i = 0; i < a.size(); i++) { - BigInteger d = a.elementAt(i).a.multiply(lcmDeno).divide(a.elementAt(i).b); + final BigInteger d = a.elementAt(i).a.multiply(lcmDeno).divide(a.elementAt(i).b); ipo.add(d); } - BigIntegerPoly p = new BigIntegerPoly(ipo); + final BigIntegerPoly p = new BigIntegerPoly(ipo); /* * collect the integer roots (multiple roots only once). Since we * removed the zero already above, cand does not contain zeros. */ - Vector cand = p.iroots(); + final Vector cand = p.iroots(); for (int i = 0; i < cand.size(); i++) { final BigInteger r = cand.elementAt(i); - int deg = p.rootDeg(r); + final int deg = p.rootDeg(r); res.add(r); res.add(new BigInteger("" + deg)); } diff --git a/src/org/nevec/rjm/Rational.java b/src/org/nevec/rjm/Rational.java index 26ae7e96..2e8de13d 100644 --- a/src/org/nevec/rjm/Rational.java +++ b/src/org/nevec/rjm/Rational.java @@ -133,7 +133,7 @@ public class Rational implements Cloneable, Comparable { * does not yet test for a denominator equal to zero */ public Rational(String str, int radix) { - int hasslah = str.indexOf("/"); + final int hasslah = str.indexOf("/"); if (hasslah == -1) { a = new BigInteger(str, radix); b = new BigInteger("1", radix); @@ -159,8 +159,8 @@ public class Rational implements Cloneable, Comparable { * protected access means this does not work return new * Rational(a.clone(), b.clone()) ; */ - BigInteger aclon = new BigInteger("" + a); - BigInteger bclon = new BigInteger("" + b); + final BigInteger aclon = new BigInteger("" + a); + final BigInteger bclon = new BigInteger("" + b); return new Rational(aclon, bclon); } /* Rational.clone */ @@ -172,8 +172,8 @@ public class Rational implements Cloneable, Comparable { * @return the product of this with the val. */ public Rational multiply(final Rational val) { - BigInteger num = a.multiply(val.a); - BigInteger deno = b.multiply(val.b); + final BigInteger num = a.multiply(val.a); + final BigInteger deno = b.multiply(val.b); /* * Normalization to an coprime format will be done inside the ctor() and * is not duplicated here. @@ -189,7 +189,7 @@ public class Rational implements Cloneable, Comparable { * @return the product of this with the value. */ public Rational multiply(final BigInteger val) { - Rational val2 = new Rational(val, BigInteger.ONE); + final Rational val2 = new Rational(val, BigInteger.ONE); return (multiply(val2)); } /* Rational.multiply */ @@ -201,7 +201,7 @@ public class Rational implements Cloneable, Comparable { * @return the product of this with the value. */ public Rational multiply(final int val) { - BigInteger tmp = new BigInteger("" + val); + final BigInteger tmp = new BigInteger("" + val); return multiply(tmp); } /* Rational.multiply */ @@ -214,15 +214,17 @@ public class Rational implements Cloneable, Comparable { * exponent is 0, the value 1 is returned. */ public Rational pow(int exponent) { - if (exponent == 0) + if (exponent == 0) { return new Rational(1, 1); + } - BigInteger num = a.pow(Math.abs(exponent)); - BigInteger deno = b.pow(Math.abs(exponent)); - if (exponent > 0) + final BigInteger num = a.pow(Math.abs(exponent)); + final BigInteger deno = b.pow(Math.abs(exponent)); + if (exponent > 0) { return (new Rational(num, deno)); - else + } else { return (new Rational(deno, num)); + } } /* Rational.pow */ /** @@ -237,10 +239,12 @@ public class Rational implements Cloneable, Comparable { */ public Rational pow(BigInteger exponent) throws Error { /* test for overflow */ - if (exponent.compareTo(MAX_INT) == 1) + if (exponent.compareTo(MAX_INT) == 1) { throw new Error(Errors.NUMBER_TOO_LARGE); - if (exponent.compareTo(MIN_INT) == -1) + } + if (exponent.compareTo(MIN_INT) == -1) { throw new Error(Errors.NUMBER_TOO_SMALL); + } /* promote to the simpler interface above */ return pow(exponent.intValue()); @@ -259,15 +263,18 @@ public class Rational implements Cloneable, Comparable { */ public Rational root(BigInteger r) throws Error { /* test for overflow */ - if (r.compareTo(MAX_INT) == 1) + if (r.compareTo(MAX_INT) == 1) { throw new Error(Errors.NUMBER_TOO_LARGE); - if (r.compareTo(MIN_INT) == -1) + } + if (r.compareTo(MIN_INT) == -1) { throw new Error(Errors.NUMBER_TOO_SMALL); + } - int rthroot = r.intValue(); + final int rthroot = r.intValue(); /* cannot pull root of a negative value with even-valued root */ - if (compareTo(ZERO) == -1 && (rthroot % 2) == 0) + if (compareTo(ZERO) == -1 && (rthroot % 2) == 0) { throw new Error(Errors.NEGATIVE_PARAMETER); + } /* * extract a sign such that we calculate |n|^(1/r), still r carrying any @@ -278,13 +285,14 @@ public class Rational implements Cloneable, Comparable { /* * delegate the main work to ifactor#root() */ - Ifactor num = new Ifactor(a.abs()); - Ifactor deno = new Ifactor(b); + final Ifactor num = new Ifactor(a.abs()); + final Ifactor deno = new Ifactor(b); final Rational resul = num.root(rthroot).divide(deno.root(rthroot)); - if (flipsign) + if (flipsign) { return resul.negate(); - else + } else { return resul; + } } /* Rational.root */ /** @@ -298,14 +306,15 @@ public class Rational implements Cloneable, Comparable { * @since 2009-05-18 */ public Rational pow(Rational exponent) throws Error { - if (exponent.a.compareTo(BigInteger.ZERO) == 0) + if (exponent.a.compareTo(BigInteger.ZERO) == 0) { return new Rational(1, 1); + } /* * calculate (a/b)^(exponent.a/exponent.b) as * ((a/b)^exponent.a)^(1/exponent.b) = tmp^(1/exponent.b) */ - Rational tmp = pow(exponent.a); + final Rational tmp = pow(exponent.a); return tmp.root(exponent.b); } /* Rational.pow */ @@ -318,10 +327,11 @@ public class Rational implements Cloneable, Comparable { * @throws Error */ public Rational divide(final Rational val) throws Error { - if (val.compareTo(Rational.ZERO) == 0) + if (val.compareTo(Rational.ZERO) == 0) { throw new Error(Errors.DIVISION_BY_ZERO); - BigInteger num = a.multiply(val.b); - BigInteger deno = b.multiply(val.a); + } + final BigInteger num = a.multiply(val.b); + final BigInteger deno = b.multiply(val.a); /* * Reduction to a coprime format is done inside the ctor, and not * repeated here. @@ -338,9 +348,10 @@ public class Rational implements Cloneable, Comparable { * @throws Error */ public Rational divide(BigInteger val) throws Error { - if (val.compareTo(BigInteger.ZERO) == 0) + if (val.compareTo(BigInteger.ZERO) == 0) { throw new Error(Errors.DIVISION_BY_ZERO); - Rational val2 = new Rational(val, BigInteger.ONE); + } + final Rational val2 = new Rational(val, BigInteger.ONE); return (divide(val2)); } /* Rational.divide */ @@ -353,9 +364,10 @@ public class Rational implements Cloneable, Comparable { * @throws Error */ public Rational divide(int val) throws Error { - if (val == 0) + if (val == 0) { throw new Error(Errors.DIVISION_BY_ZERO); - Rational val2 = new Rational(val, 1); + } + final Rational val2 = new Rational(val, 1); return (divide(val2)); } /* Rational.divide */ @@ -367,8 +379,8 @@ public class Rational implements Cloneable, Comparable { * @return this+val. */ public Rational add(Rational val) { - BigInteger num = a.multiply(val.b).add(b.multiply(val.a)); - BigInteger deno = b.multiply(val.b); + final BigInteger num = a.multiply(val.b).add(b.multiply(val.a)); + final BigInteger deno = b.multiply(val.b); return (new Rational(num, deno)); } /* Rational.add */ @@ -380,7 +392,7 @@ public class Rational implements Cloneable, Comparable { * @return this+val. */ public Rational add(BigInteger val) { - Rational val2 = new Rational(val, BigInteger.ONE); + final Rational val2 = new Rational(val, BigInteger.ONE); return (add(val2)); } /* Rational.add */ @@ -393,7 +405,7 @@ public class Rational implements Cloneable, Comparable { * @since May 26 2010 */ public Rational add(int val) { - BigInteger val2 = a.add(b.multiply(new BigInteger("" + val))); + final BigInteger val2 = a.add(b.multiply(new BigInteger("" + val))); return new Rational(val2, b); } /* Rational.add */ @@ -414,7 +426,7 @@ public class Rational implements Cloneable, Comparable { * @return this - val. */ public Rational subtract(Rational val) { - Rational val2 = val.negate(); + final Rational val2 = val.negate(); return (add(val2)); } /* Rational.subtract */ @@ -426,7 +438,7 @@ public class Rational implements Cloneable, Comparable { * @return this - val. */ public Rational subtract(BigInteger val) { - Rational val2 = new Rational(val, BigInteger.ONE); + final Rational val2 = new Rational(val, BigInteger.ONE); return (subtract(val2)); } /* Rational.subtract */ @@ -438,7 +450,7 @@ public class Rational implements Cloneable, Comparable { * @return this - val. */ public Rational subtract(int val) { - Rational val2 = new Rational(val, 1); + final Rational val2 = new Rational(val, 1); return (subtract(val2)); } /* Rational.subtract */ @@ -455,8 +467,9 @@ public class Rational implements Cloneable, Comparable { * @throws Error */ public static Rational binomial(Rational n, BigInteger m) throws Error { - if (m.compareTo(BigInteger.ZERO) == 0) + if (m.compareTo(BigInteger.ZERO) == 0) { return Rational.ONE; + } Rational bin = n; for (BigInteger i = new BigInteger("2"); i.compareTo(m) != 1; i = i.add(BigInteger.ONE)) { bin = bin.multiply(n.subtract(i.subtract(BigInteger.ONE))).divide(i); @@ -477,8 +490,9 @@ public class Rational implements Cloneable, Comparable { * @throws Error */ public static Rational binomial(Rational n, int m) throws Error { - if (m == 0) + if (m == 0) { return Rational.ONE; + } Rational bin = n; for (int i = 2; i <= m; i++) { bin = bin.multiply(n.subtract(i - 1)).divide(i); @@ -499,13 +513,14 @@ public class Rational implements Cloneable, Comparable { * @throws Error */ public static Rational hankelSymb(Rational n, int k) throws Error { - if (k == 0) + if (k == 0) { return Rational.ONE; - else if (k < 0) + } else if (k < 0) { throw new Error(Errors.NEGATIVE_PARAMETER); + } Rational nkhalf = n.subtract(k).add(Rational.HALF); nkhalf = nkhalf.Pochhammer(2 * k); - Factorial f = new Factorial(); + final Factorial f = new Factorial(); return nkhalf.divide(f.at(k)); } /* Rational.binomial */ @@ -545,12 +560,13 @@ public class Rational implements Cloneable, Comparable { /* * is already integer: return the numerator */ - if (b.compareTo(BigInteger.ONE) == 0) + if (b.compareTo(BigInteger.ONE) == 0) { return a; - else if (a.compareTo(BigInteger.ZERO) > 0) + } else if (a.compareTo(BigInteger.ZERO) > 0) { return a.divide(b); - else + } else { return a.divide(b).subtract(BigInteger.ONE); + } } /* Rational.floor */ /** @@ -563,12 +579,13 @@ public class Rational implements Cloneable, Comparable { /* * is already integer: return the numerator */ - if (b.compareTo(BigInteger.ONE) == 0) + if (b.compareTo(BigInteger.ONE) == 0) { return a; - else if (a.compareTo(BigInteger.ZERO) > 0) + } else if (a.compareTo(BigInteger.ZERO) > 0) { return a.divide(b).add(BigInteger.ONE); - else + } else { return a.divide(b); + } } /* Rational.ceil */ /** @@ -580,10 +597,11 @@ public class Rational implements Cloneable, Comparable { /* * is already integer: return the numerator */ - if (b.compareTo(BigInteger.ONE) == 0) + if (b.compareTo(BigInteger.ONE) == 0) { return a; - else + } else { return a.divide(b); + } } /* Rational.trunc */ /** @@ -626,10 +644,11 @@ public class Rational implements Cloneable, Comparable { */ @Override public String toString() { - if (b.compareTo(BigInteger.ONE) != 0) + if (b.compareTo(BigInteger.ONE) != 0) { return (a.toString() + "/" + b.toString()); - else + } else { return a.toString(); + } } /* Rational.toString */ /** @@ -644,7 +663,7 @@ public class Rational implements Cloneable, Comparable { * separate invocation a.doubleValue() or b.doubleValue(), we divide * first in a BigDecimal environment and convert the result. */ - BigDecimal adivb = (new BigDecimal(a)).divide(new BigDecimal(b), MathContext.DECIMAL128); + final BigDecimal adivb = (new BigDecimal(a)).divide(new BigDecimal(b), MathContext.DECIMAL128); return adivb.doubleValue(); } /* Rational.doubleValue */ @@ -655,7 +674,7 @@ public class Rational implements Cloneable, Comparable { * @since 2009-08-06 */ public float floatValue() { - BigDecimal adivb = (new BigDecimal(a)).divide(new BigDecimal(b), MathContext.DECIMAL128); + final BigDecimal adivb = (new BigDecimal(a)).divide(new BigDecimal(b), MathContext.DECIMAL128); return adivb.floatValue(); } /* Rational.floatValue */ @@ -672,8 +691,8 @@ public class Rational implements Cloneable, Comparable { /* * numerator and denominator individually rephrased */ - BigDecimal n = new BigDecimal(a); - BigDecimal d = new BigDecimal(b); + final BigDecimal n = new BigDecimal(a); + final BigDecimal d = new BigDecimal(b); /* * the problem with n.divide(d,mc) is that the apparent precision might * be smaller than what is set by mc if the value has a precise @@ -692,11 +711,12 @@ public class Rational implements Cloneable, Comparable { */ public String toFString(int digits) { if (b.compareTo(BigInteger.ONE) != 0) { - MathContext mc = new MathContext(digits, RoundingMode.DOWN); - BigDecimal f = (new BigDecimal(a)).divide(new BigDecimal(b), mc); + final MathContext mc = new MathContext(digits, RoundingMode.DOWN); + final BigDecimal f = (new BigDecimal(a)).divide(new BigDecimal(b), mc); return (f.toString()); - } else + } else { return a.toString(); + } } /* Rational.toFString */ /** @@ -708,10 +728,11 @@ public class Rational implements Cloneable, Comparable { * @since 2008-10-19 */ public Rational max(final Rational val) { - if (compareTo(val) > 0) + if (compareTo(val) > 0) { return this; - else + } else { return val; + } } /* Rational.max */ /** @@ -723,10 +744,11 @@ public class Rational implements Cloneable, Comparable { * @since 2008-10-19 */ public Rational min(final Rational val) { - if (compareTo(val) < 0) + if (compareTo(val) < 0) { return this; - else + } else { return val; + } } /* Rational.min */ /** @@ -738,18 +760,19 @@ public class Rational implements Cloneable, Comparable { * @since 2008-10-25 */ public Rational Pochhammer(final BigInteger n) { - if (n.compareTo(BigInteger.ZERO) < 0) + if (n.compareTo(BigInteger.ZERO) < 0) { return null; - else if (n.compareTo(BigInteger.ZERO) == 0) + } else if (n.compareTo(BigInteger.ZERO) == 0) { return Rational.ONE; - else { + } else { /* * initialize results with the current value */ Rational res = new Rational(a, b); BigInteger i = BigInteger.ONE; - for (; i.compareTo(n) < 0; i = i.add(BigInteger.ONE)) + for (; i.compareTo(n) < 0; i = i.add(BigInteger.ONE)) { res = res.multiply(add(i)); + } return res; } } /* Rational.pochhammer */ @@ -784,8 +807,9 @@ public class Rational implements Cloneable, Comparable { * @since 2010-05-26 */ public boolean isInteger() { - if (!isBigInteger()) + if (!isBigInteger()) { return false; + } return (a.compareTo(MAX_INT) <= 0 && a.compareTo(MIN_INT) >= 0); } /* Rational.isInteger */ @@ -797,8 +821,9 @@ public class Rational implements Cloneable, Comparable { * @since 2011-02-13 */ int intValue() throws Error { - if (!isInteger()) + if (!isInteger()) { throw new Error(Errors.CONVERSION_ERROR); + } return a.intValue(); } @@ -810,8 +835,9 @@ public class Rational implements Cloneable, Comparable { * @since 2012-03-02 */ BigInteger BigIntegerValue() throws Error { - if (!isBigInteger()) + if (!isBigInteger()) { throw new Error(Errors.CONVERSION_ERROR); + } return a; } @@ -845,8 +871,9 @@ public class Rational implements Cloneable, Comparable { */ static public BigInteger lcmDenom(final Rational[] vals) { BigInteger l = BigInteger.ONE; - for (int v = 0; v < vals.length; v++) - l = BigIntegerMath.lcm(l, vals[v].b); + for (final Rational val : vals) { + l = BigIntegerMath.lcm(l, val.b); + } return l; } /* Rational.lcmDenom */ diff --git a/src/org/nevec/rjm/Wigner3j.java b/src/org/nevec/rjm/Wigner3j.java index 4173e81e..06b011c4 100644 --- a/src/org/nevec/rjm/Wigner3j.java +++ b/src/org/nevec/rjm/Wigner3j.java @@ -37,43 +37,45 @@ public class Wigner3j { static public void main(String args[]) throws Error { if (args[0].compareTo("6j") == 0) { try { - String m1 = "6"; - String t1 = "1 2 -3 -1 5 6"; - String t2 = "4 -5 3 -4 -2 -6"; + final String m1 = "6"; + final String t1 = "1 2 -3 -1 5 6"; + final String t2 = "4 -5 3 -4 -2 -6"; String j = ""; - for (int i = 1; i <= 6; i++) + for (int i = 1; i <= 6; i++) { j += args[i] + " "; - BigSurdVec w = wigner3j(m1, t1, t2, j); + } + final BigSurdVec w = wigner3j(m1, t1, t2, j); System.out.println(w.toString()); - } catch (Exception e) { + } catch (final Exception e) { System.out.println(e.getMessage()); } } else if (args[0].compareTo("9j") == 0) { try { - String m1 = "9"; - String t1 = "1 3 2 4 6 5 7 9 8"; - String t2 = "2 8 5 6 3 9 7 4 1"; + final String m1 = "9"; + final String t1 = "1 3 2 4 6 5 7 9 8"; + final String t2 = "2 8 5 6 3 9 7 4 1"; String j = ""; - for (int i = 1; i <= 9; i++) + for (int i = 1; i <= 9; i++) { j += args[i] + " "; - BigSurdVec w = wigner3j(m1, t1, t2, j); + } + final BigSurdVec w = wigner3j(m1, t1, t2, j); System.out.println(w.toString()); - } catch (Exception e) { + } catch (final Exception e) { System.out.println(e.getMessage()); } } else if (args[0].compareTo("3jm") == 0) { - int j1 = (new Integer(args[1])).intValue(); - int j2 = (new Integer(args[2])).intValue(); - int j3 = (new Integer(args[3])).intValue(); - int m1 = (new Integer(args[4])).intValue(); - int m2 = (new Integer(args[5])).intValue(); - int m3 = (new Integer(args[6])).intValue(); + final int j1 = (new Integer(args[1])).intValue(); + final int j2 = (new Integer(args[2])).intValue(); + final int j3 = (new Integer(args[3])).intValue(); + final int m1 = (new Integer(args[4])).intValue(); + final int m2 = (new Integer(args[5])).intValue(); + final int m3 = (new Integer(args[6])).intValue(); try { BigSurd w = wigner3jm(j1, j2, j3, m1, m2, m3); System.out.println(w.toString()); w = w.multiply(new BigSurd(j3 + 1, 1)); System.out.println("CG factor sqrt" + (j3 + 1) + "sign " + ((j2 - j2 - m3) / 2) + " " + w.toString()); - } catch (Exception e) { + } catch (final Exception e) { System.out.println(e.getMessage()); } } else { @@ -108,12 +110,12 @@ public class Wigner3j { * @throws Error */ static public BigSurd wigner3jm(int j1, int j2, int j3, int m1, int m2, int m3) throws Error { - Rational J1 = new Rational(j1, 2); - Rational J2 = new Rational(j2, 2); - Rational J3 = new Rational(j3, 2); - Rational M1 = new Rational(m1, 2); - Rational M2 = new Rational(m2, 2); - Rational M3 = new Rational(m3, 2); + final Rational J1 = new Rational(j1, 2); + final Rational J2 = new Rational(j2, 2); + final Rational J3 = new Rational(j3, 2); + final Rational M1 = new Rational(m1, 2); + final Rational M2 = new Rational(m2, 2); + final Rational M3 = new Rational(m3, 2); return wigner3jm(J1, J2, J3, M1, M2, M3); } /* wigner3jm */ @@ -148,7 +150,7 @@ public class Wigner3j { * The rest of the line is ignored. */ Scanner s = new Scanner(m1); - int m = s.nextInt(); + final int m = s.nextInt(); if (m % 3 != 0) { s.close(); throw new IllegalArgumentException("Angular momenta " + m + " not a multiple of three."); @@ -158,8 +160,8 @@ public class Wigner3j { * Scan the numbers in the line "j". Excess numbers beyond what has been * announced in the "m" line are ignored. */ - int[] jvec = new int[m]; - int[] tvec = new int[2 * m]; + final int[] jvec = new int[m]; + final int[] tvec = new int[2 * m]; s.close(); @@ -183,14 +185,16 @@ public class Wigner3j { */ s = new Scanner(t1); int ti = 0; - while (s.hasNextInt()) + while (s.hasNextInt()) { tvec[ti++] = s.nextInt(); + } s.close(); s = new Scanner(t2); - while (s.hasNextInt()) + while (s.hasNextInt()) { tvec[ti++] = s.nextInt(); + } /* * Basic sanity checks. All indices in the first two lines address a @@ -205,18 +209,19 @@ public class Wigner3j { throw new IllegalArgumentException("triad-count " + ti + " not twice j-count " + ji); } - int[] jfreq = new int[m]; - for (ji = 0; ji < jfreq.length; ji++) + final int[] jfreq = new int[m]; + for (ji = 0; ji < jfreq.length; ji++) { jfreq[ji] = 0; + } /* * maintain a 0-based index which shows where the j-value has its first * and second occurrence in the flattened list of triads. */ - int[][] jhash = new int[m][2]; + final int[][] jhash = new int[m][2]; for (ti = 0; ti < 2 * m; ti++) { - int t = tvec[ti]; + final int t = tvec[ti]; if (t == 0 || Math.abs(t) > jvec.length) { s.close(); throw new IllegalArgumentException("Triad index " + t + " out of bounds"); @@ -233,7 +238,7 @@ public class Wigner3j { * Move on from the 2j+1 values of the input to the j-values. Subtract * one and divide through 2. */ - Rational[] J = new Rational[jvec.length]; + final Rational[] J = new Rational[jvec.length]; for (ji = 0; ji < jvec.length; ji++) { J[ji] = new Rational(jvec[ji] - 1, 2); } @@ -242,14 +247,15 @@ public class Wigner3j { * Convert the 1-based indices to 0-based indices, loosing the sign * information. */ - int[] triadidx = new int[tvec.length]; - for (ti = 0; ti < tvec.length; ti++) + final int[] triadidx = new int[tvec.length]; + for (ti = 0; ti < tvec.length; ti++) { triadidx[ti] = Math.abs(tvec[ti]) - 1; + } /* * The M-values are all null (undetermined) at the start. */ - Rational[] M = new Rational[J.length]; + final Rational[] M = new Rational[J.length]; s.close(); return wigner3j(tvec, J, M, triadidx); } /* wigner3j */ @@ -286,10 +292,12 @@ public class Wigner3j { */ for (int t = 0; t < triadidx.length; t += 3) { /* Ensure |J[t]-J[t+1]| <= J[t+2] <= J[t]+J[t+1] */ - if (J[triadidx[t]].subtract(J[triadidx[t + 1]]).abs().compareTo(J[triadidx[t + 2]]) > 0) + if (J[triadidx[t]].subtract(J[triadidx[t + 1]]).abs().compareTo(J[triadidx[t + 2]]) > 0) { return res; - if (J[triadidx[t]].add(J[triadidx[t + 1]]).compareTo(J[triadidx[t + 2]]) < 0) + } + if (J[triadidx[t]].add(J[triadidx[t + 1]]).compareTo(J[triadidx[t + 2]]) < 0) { return res; + } } /* @@ -310,14 +318,14 @@ public class Wigner3j { * others values are set in the triad. or it is still to * maintain its own explicit loop. */ - int triadn = i / 3; - int triadr = i % 3; + final int triadn = i / 3; + final int triadr = i % 3; /* * the neighbors in the triad have indices triadn*3+ (tiradr+1) * mod 3 and triadn*3+(triadr+2) mod3 */ - int nei1 = 3 * triadn + (triadr + 1) % 3; - int nei2 = 3 * triadn + (triadr + 2) % 3; + final int nei1 = 3 * triadn + (triadr + 1) % 3; + final int nei2 = 3 * triadn + (triadr + 2) % 3; /* * found a candidate for which the two other values are already @@ -331,11 +339,13 @@ public class Wigner3j { * rough work load estimator: basically (2J1+1)*(2J2+1) */ Rational wt = J[triadidx[i]].multiply(2).add(1); - if (M[triadidx[nei1]] == null) + if (M[triadidx[nei1]] == null) { wt = wt.multiply(J[triadidx[nei1]].multiply(2).add(1)); - if (M[triadidx[nei2]] == null) + } + if (M[triadidx[nei2]] == null) { wt = wt.multiply(J[triadidx[nei2]].multiply(2).add(1)); - int thiswt = wt.intValue(); + } + final int thiswt = wt.intValue(); if (freeM < 0 || thiswt < freeMrank) { freeM = i; freeMrank = thiswt; @@ -349,24 +359,26 @@ public class Wigner3j { * found an m-value which has not yet been summed over. */ if (M[triadidx[freeM]] == null) { - Rational[] childM = new Rational[M.length]; - for (int ji = 0; ji < M.length; ji++) - if (M[ji] != null) + final Rational[] childM = new Rational[M.length]; + for (int ji = 0; ji < M.length; ji++) { + if (M[ji] != null) { childM[ji] = M[ji]; + } + } /* * two cases: value is fixed implicitly because already two * others values are set in the triad. or it is still to * maintain its own explicit loop. */ - int triadn = freeM / 3; - int triadr = freeM % 3; + final int triadn = freeM / 3; + final int triadr = freeM % 3; /* * the neighbors in the triad have indices triadn*3+ (triadr+1) * mod 3 and triadn*3+(triadr+2) mod3 */ - int nei1 = 3 * triadn + (triadr + 1) % 3; - int nei2 = 3 * triadn + (triadr + 2) % 3; + final int nei1 = 3 * triadn + (triadr + 1) % 3; + final int nei2 = 3 * triadn + (triadr + 2) % 3; if (M[triadidx[nei1]] == null || M[triadidx[nei2]] == null) { /* * The J-value is J[triadidx[freeM]]. Loop from -J to +J, @@ -390,12 +402,14 @@ public class Wigner3j { * negate if these are the second occurrences of the J in * the triads */ - if (tvec[nei1] < 0) + if (tvec[nei1] < 0) { m1 = m1.negate(); - if (tvec[nei2] < 0) + } + if (tvec[nei2] < 0) { m2 = m2.negate(); + } /* m3 = -(m1+m2) */ - Rational newm = tvec[freeM] > 0 ? m1.add(m2).negate() : m1.add(m2); + final Rational newm = tvec[freeM] > 0 ? m1.add(m2).negate() : m1.add(m2); /* * No contribution if the m-value enforced by the other two * entries is outside the range -|J|..|J| enforced by its @@ -429,34 +443,40 @@ public class Wigner3j { * negate if these are associated with in-flowing vectors in the * triads */ - if (tvec[ji] < 0) + if (tvec[ji] < 0) { m1 = m1.negate(); - if (tvec[ji + 1] < 0) + } + if (tvec[ji + 1] < 0) { m2 = m2.negate(); - if (tvec[ji + 2] < 0) + } + if (tvec[ji + 2] < 0) { m3 = m3.negate(); + } res = res.multiply(wigner3jm(J[triadidx[ji]], J[triadidx[ji + 1]], J[triadidx[ji + 2]], m1, m2, m3)); /* * if a partial product yields zero, the total product is zero, too, * and offers an early exit. */ - if (res.signum() == 0) + if (res.signum() == 0) { return BigSurdVec.ZERO; + } } /* * The overal sign is product_{J-Mpairs} (-1)^(J-M). This is an integer * because all the J-M are integer. */ Rational sig = new Rational(); - for (int ji = 0; ji < J.length; ji++) + for (int ji = 0; ji < J.length; ji++) { sig = sig.add(J[ji]).subtract(M[ji]); + } /* * sign depends on the sum being even or odd. We assume that "sig" is * integer and look only at the numerator */ - if (sig.a.abs().testBit(0)) + if (sig.a.abs().testBit(0)) { res = res.negate(); + } return res; } /* wigner3j */ @@ -487,36 +507,42 @@ public class Wigner3j { /* * Check that m1+m2+m3 = 0 */ - if (m1.add(m2).add(m3).signum() != 0) + if (m1.add(m2).add(m3).signum() != 0) { return BigSurd.ZERO; + } /* * Check that j1+j2+j3 is integer */ - if (j1.add(j2).add(j3).isBigInteger() == false) + if (j1.add(j2).add(j3).isBigInteger() == false) { return BigSurd.ZERO; + } /* * Check that |j1-j2|<=j3 <= |j1+j2| */ - Rational j1m2 = j1.subtract(j2); - if (j1m2.abs().compareTo(j3) > 0) + final Rational j1m2 = j1.subtract(j2); + if (j1m2.abs().compareTo(j3) > 0) { return BigSurd.ZERO; - Rational j1p2 = j1.add(j2); - if (j1p2.abs().compareTo(j3) < 0) + } + final Rational j1p2 = j1.add(j2); + if (j1p2.abs().compareTo(j3) < 0) { return BigSurd.ZERO; + } /* * Check that |m_i| <= j_i */ - if (m1.abs().compareTo(j1) > 0 || m2.abs().compareTo(j2) > 0 || m3.abs().compareTo(j3) > 0) + if (m1.abs().compareTo(j1) > 0 || m2.abs().compareTo(j2) > 0 || m3.abs().compareTo(j3) > 0) { return BigSurd.ZERO; + } /* * Check that m_i-j_i are integer. */ - if (!m1.subtract(j1).isBigInteger() || !m2.subtract(j2).isBigInteger() || !m3.subtract(j3).isBigInteger()) + if (!m1.subtract(j1).isBigInteger() || !m2.subtract(j2).isBigInteger() || !m3.subtract(j3).isBigInteger()) { return BigSurd.ZERO; + } /* * (-)^(j1-j2-m3)*delta(-m3,m1+m2)*sqrt[ (j3+j1-j2)! (j3-j1+j2)! @@ -548,28 +574,31 @@ public class Wigner3j { jj1m2k += k; } - Factorial f = new Factorial(); + final Factorial f = new Factorial(); Rational sumk = new Rational(); while (true) { - BigInteger d = f.at(k).multiply(f.at(j1j2jk)).multiply(f.at(j1m1k)).multiply(f.at(j2m2k)).multiply(f.at(jj2m1k)).multiply(f.at(jj1m2k)); - if (k % 2 == 0) + final BigInteger d = f.at(k).multiply(f.at(j1j2jk)).multiply(f.at(j1m1k)).multiply(f.at(j2m2k)).multiply(f.at(jj2m1k)).multiply(f.at(jj1m2k)); + if (k % 2 == 0) { sumk = sumk.add(new Rational(BigInteger.ONE, d)); - else + } else { sumk = sumk.subtract(new Rational(BigInteger.ONE, d)); + } j1j2jk--; j1m1k--; j2m2k--; jj2m1k++; jj1m2k++; - if (j1j2jk < 0 || j1m1k < 0 || j2m2k < 0) + if (j1j2jk < 0 || j1m1k < 0 || j2m2k < 0) { break; + } k++; } /* * sign factor (-1)^(j1-j2-m3) */ - if (j1m2.subtract(m3).intValue() % 2 != 0) + if (j1m2.subtract(m3).intValue() % 2 != 0) { sumk = sumk.negate(); + } k = j1m2.add(j3).intValue(); BigInteger s = f.at(k); @@ -591,7 +620,7 @@ public class Wigner3j { s = s.multiply(f.at(k)); k = j1p2.add(j3).intValue(); k++; - Rational disc = new Rational(s, f.at(k)); + final Rational disc = new Rational(s, f.at(k)); return new BigSurd(sumk, disc); } /* wigner3jm */ diff --git a/src/org/nevec/rjm/Wigner3jGUI.java b/src/org/nevec/rjm/Wigner3jGUI.java index eef42659..c841e86b 100644 --- a/src/org/nevec/rjm/Wigner3jGUI.java +++ b/src/org/nevec/rjm/Wigner3jGUI.java @@ -79,12 +79,12 @@ public class Wigner3jGUI implements ActionListener, ListSelectionListener { searJ.setLayoutOrientation(JList.HORIZONTAL_WRAP); searJ.addListSelectionListener(this); - Font defFont = new Font("Monospaced", Font.PLAIN, 11); + final Font defFont = new Font("Monospaced", Font.PLAIN, 11); fram.setBackground(new Color(250, 250, 250)); fram.setForeground(new Color(0, 0, 0)); - Color fg = new Color(0, 200, 0); - Color bg = new Color(10, 10, 10); + final Color fg = new Color(0, 200, 0); + final Color bg = new Color(10, 10, 10); gridbag = new GridBagLayout(); fram.setLayout(gridbag); @@ -138,8 +138,8 @@ public class Wigner3jGUI implements ActionListener, ListSelectionListener { * @since 2010-08-27 */ public void compute() throws Error { - String tr = inpGtria.getText(); - String[] trias = new String[4]; + final String tr = inpGtria.getText(); + final String[] trias = new String[4]; /* * Read the trias configuration from inpGtria into trias[0..2], skipping @@ -149,9 +149,10 @@ public class Wigner3jGUI implements ActionListener, ListSelectionListener { for (int l = 0; l < 3;) { try { trias[l] = s.nextLine().trim(); - if (!trias[l].startsWith("#")) + if (!trias[l].startsWith("#")) { l++; - } catch (Exception e) { + } + } catch (final Exception e) { s.close(); outG.setText("ERROR: less than 3 lines in the triad definition"); return; @@ -163,28 +164,28 @@ public class Wigner3jGUI implements ActionListener, ListSelectionListener { /* * Read the J values from inpGjval into trias[3] in a loop */ - String j = inpGjval.getText(); + final String j = inpGjval.getText(); s = new Scanner(j); while (true) { try { trias[3] = s.nextLine().trim(); - } catch (Exception e) { + } catch (final Exception e) { s.close(); return; } if (!trias[3].startsWith("#")) { try { - BigSurdVec w = Wigner3j.wigner3j(trias[0], trias[1], trias[2], trias[3]); + final BigSurdVec w = Wigner3j.wigner3j(trias[0], trias[1], trias[2], trias[3]); outG.append(w.toString() + " = " + w.doubleValue()); - } catch (Exception e) { + } catch (final Exception e) { outG.append(e.toString()); e.printStackTrace(); } outG.append(" # J = "); - Scanner num = new Scanner(trias[3]); + final Scanner num = new Scanner(trias[3]); while (num.hasNextInt()) { - int twoj1 = num.nextInt(); - Rational jfrac = new Rational(twoj1 - 1, 2); + final int twoj1 = num.nextInt(); + final Rational jfrac = new Rational(twoj1 - 1, 2); outG.append(jfrac.toString() + " "); } outG.append("\n"); @@ -202,7 +203,7 @@ public class Wigner3jGUI implements ActionListener, ListSelectionListener { */ @Override public void actionPerformed(ActionEvent e) { - String lin = e.getActionCommand(); + final String lin = e.getActionCommand(); /* * debugging System.out.println("Ac"+e.paramString()) ; * System.out.println(lin) ; @@ -211,7 +212,7 @@ public class Wigner3jGUI implements ActionListener, ListSelectionListener { outG.setText(""); try { compute(); - } catch (Error e1) { + } catch (final Error e1) { // TODO Auto-generated catch block e1.printStackTrace(); } @@ -327,7 +328,7 @@ public class Wigner3jGUI implements ActionListener, ListSelectionListener { * @author Richard J. Mathar */ public static void main(String[] args) { - Wigner3jGUI g = new Wigner3jGUI(); + final Wigner3jGUI g = new Wigner3jGUI(); g.init(); } /* main */ diff --git a/src/org/warp/picalculator/BMPFile.java b/src/org/warp/picalculator/BMPFile.java index bbb986c2..549efd73 100644 --- a/src/org/warp/picalculator/BMPFile.java +++ b/src/org/warp/picalculator/BMPFile.java @@ -16,26 +16,26 @@ public class BMPFile extends Component { // --- Private variable declaration // --- Bitmap file header @SuppressWarnings("unused") - private byte bitmapFileHeader[] = new byte[14]; - private byte bfType[] = { 'B', 'M' }; + private final byte bitmapFileHeader[] = new byte[14]; + private final byte bfType[] = { 'B', 'M' }; private int bfSize = 0; - private int bfReserved1 = 0; - private int bfReserved2 = 0; - private int bfOffBits = BITMAPFILEHEADER_SIZE + BITMAPINFOHEADER_SIZE; + private final int bfReserved1 = 0; + private final int bfReserved2 = 0; + private final int bfOffBits = BITMAPFILEHEADER_SIZE + BITMAPINFOHEADER_SIZE; // --- Bitmap info header @SuppressWarnings("unused") - private byte bitmapInfoHeader[] = new byte[40]; - private int biSize = BITMAPINFOHEADER_SIZE; + private final byte bitmapInfoHeader[] = new byte[40]; + private final int biSize = BITMAPINFOHEADER_SIZE; private int biWidth = 0; private int biHeight = 0; - private int biPlanes = 1; - private int biBitCount = 24; - private int biCompression = 0; + private final int biPlanes = 1; + private final int biBitCount = 24; + private final int biCompression = 0; private int biSizeImage = 0x030000; - private int biXPelsPerMeter = 0x0; - private int biYPelsPerMeter = 0x0; - private int biClrUsed = 0; - private int biClrImportant = 0; + private final int biXPelsPerMeter = 0x0; + private final int biYPelsPerMeter = 0x0; + private final int biClrUsed = 0; + private final int biClrImportant = 0; // --- Bitmap raw data private int bitmap[]; // --- File section @@ -49,7 +49,7 @@ public class BMPFile extends Component { fo = new FileOutputStream(parFilename); save(parImage, parWidth, parHeight); fo.close(); - } catch (Exception saveEx) { + } catch (final Exception saveEx) { saveEx.printStackTrace(); } } @@ -68,7 +68,7 @@ public class BMPFile extends Component { writeBitmapFileHeader(); writeBitmapInfoHeader(); writeBitmap(); - } catch (Exception saveEx) { + } catch (final Exception saveEx) { saveEx.printStackTrace(); } } @@ -81,10 +81,10 @@ public class BMPFile extends Component { private boolean convertImage(Image parImage, int parWidth, int parHeight) { int pad; bitmap = new int[parWidth * parHeight]; - PixelGrabber pg = new PixelGrabber(parImage, 0, 0, parWidth, parHeight, bitmap, 0, parWidth); + final PixelGrabber pg = new PixelGrabber(parImage, 0, 0, parWidth, parHeight, bitmap, 0, parWidth); try { pg.grabPixels(); - } catch (InterruptedException e) { + } catch (final InterruptedException e) { e.printStackTrace(); return (false); } @@ -113,11 +113,13 @@ public class BMPFile extends Component { int lastRowIndex; int pad; int padCount; - byte rgb[] = new byte[3]; + final byte rgb[] = new byte[3]; size = (biWidth * biHeight) - 1; pad = 4 - ((biWidth * 3) % 4); - if (pad == 4) // <==== Bug correction + if (pad == 4) + { pad = 0; // <==== Bug correction + } rowCount = 1; padCount = 0; rowIndex = size - biWidth; @@ -137,14 +139,15 @@ public class BMPFile extends Component { rowCount = 1; rowIndex = lastRowIndex - biWidth; lastRowIndex = rowIndex; - } else + } else { rowCount++; + } rowIndex++; } // --- Update the size of the file bfSize += padCount - pad; biSizeImage += padCount - pad; - } catch (Exception wb) { + } catch (final Exception wb) { wb.printStackTrace(); } } @@ -160,7 +163,7 @@ public class BMPFile extends Component { fo.write(intToWord(bfReserved1)); fo.write(intToWord(bfReserved2)); fo.write(intToDWord(bfOffBits)); - } catch (Exception wbfh) { + } catch (final Exception wbfh) { wbfh.printStackTrace(); } } @@ -184,7 +187,7 @@ public class BMPFile extends Component { fo.write(intToDWord(biYPelsPerMeter)); fo.write(intToDWord(biClrUsed)); fo.write(intToDWord(biClrImportant)); - } catch (Exception wbih) { + } catch (final Exception wbih) { wbih.printStackTrace(); } } @@ -196,7 +199,7 @@ public class BMPFile extends Component { * */ private byte[] intToWord(int parValue) { - byte retValue[] = new byte[2]; + final byte retValue[] = new byte[2]; retValue[0] = (byte) (parValue & 0x00FF); retValue[1] = (byte) ((parValue >> 8) & 0x00FF); return (retValue); @@ -209,7 +212,7 @@ public class BMPFile extends Component { * */ private byte[] intToDWord(int parValue) { - byte retValue[] = new byte[4]; + final byte retValue[] = new byte[4]; retValue[0] = (byte) (parValue & 0x00FF); retValue[1] = (byte) ((parValue >> 8) & 0x000000FF); retValue[2] = (byte) ((parValue >> 16) & 0x000000FF); diff --git a/src/org/warp/picalculator/KeyboardTest.java b/src/org/warp/picalculator/KeyboardTest.java new file mode 100644 index 00000000..5316d3cd --- /dev/null +++ b/src/org/warp/picalculator/KeyboardTest.java @@ -0,0 +1,10 @@ +package org.warp.picalculator; + +import org.warp.picalculator.gui.screens.KeyboardDebugScreen; + +public class KeyboardTest { + + public static void main(String[] args) throws InterruptedException { + new Main(new KeyboardDebugScreen()); + } +} diff --git a/src/org/warp/picalculator/Main.java b/src/org/warp/picalculator/Main.java index 44ab0e6a..e9bd75e8 100644 --- a/src/org/warp/picalculator/Main.java +++ b/src/org/warp/picalculator/Main.java @@ -1,8 +1,9 @@ package org.warp.picalculator; import org.warp.picalculator.device.Keyboard; -import org.warp.picalculator.gui.PIDisplay; +import org.warp.picalculator.gui.DisplayManager; import org.warp.picalculator.gui.screens.LoadingScreen; +import org.warp.picalculator.gui.screens.Screen; import com.pi4j.wiringpi.Gpio; @@ -12,42 +13,44 @@ public class Main { public static final boolean zoomed = true; public static Main instance; public static boolean haxMode = true; + public static String[] args; - public Main() throws InterruptedException { + public Main(String[] args) throws InterruptedException { + this(new LoadingScreen(), args); + } + + public Main(Screen screen, String[] args) { instance = this; Thread.currentThread().setPriority(Thread.MAX_PRIORITY); Thread.currentThread().setName("Main thread"); + this.args = args; beforeStart(); - new PIDisplay(new LoadingScreen()); + new DisplayManager(screen); Utils.debug.println("Shutdown..."); beforeShutdown(); Utils.debug.println(""); Utils.debug.println("Closed"); System.exit(0); } - + public void beforeStart() { - if (System.getProperty("os.name").equals("Linux")) { + if (Utils.isRunningOnRaspberry() && !Utils.isInArray("-noraspi", args)) { Gpio.wiringPiSetupPhys(); Gpio.pinMode(12, Gpio.PWM_OUTPUT); } else { - screenPos = new int[]{0,0}; + screenPos = new int[] { 0, 0 }; Utils.debugOn = true; } Utils.debugThirdScreen = Utils.debugOn & false; - PIDisplay.setBrightness(0.5f); - } - - - public void afterStart() { + DisplayManager.setBrightness(0.5f); Keyboard.startKeyboard(); } - + public void beforeShutdown() { Keyboard.stopKeyboard(); } public static void main(String[] args) throws InterruptedException { - new Main(); + new Main(args); } } diff --git a/src/org/warp/picalculator/TestGPU.java b/src/org/warp/picalculator/TestGPU.java index 0d35c7b4..31bc3ac3 100644 --- a/src/org/warp/picalculator/TestGPU.java +++ b/src/org/warp/picalculator/TestGPU.java @@ -1,57 +1,85 @@ package org.warp.picalculator; -import org.warp.picalculator.gui.PIDisplay; +import java.io.IOException; + import org.warp.picalculator.gui.graphicengine.Display; import org.warp.picalculator.gui.graphicengine.Drawable; import org.warp.picalculator.gui.graphicengine.RAWFont; -import org.warp.picalculator.gui.graphicengine.Renderer; +import org.warp.picalculator.gui.graphicengine.RAWSkin; import org.warp.picalculator.gui.graphicengine.gpu.GPUDisplay; import org.warp.picalculator.gui.graphicengine.gpu.GPURenderer; -import org.warp.picalculator.gui.screens.LoadingScreen; +import org.warp.picalculator.gui.screens.KeyboardDebugScreen; +import org.warp.picalculator.gui.screens.MarioScreen; + +import java.lang.management.ManagementFactory; +import java.lang.management.OperatingSystemMXBean; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.util.ArrayList; public class TestGPU { public static final GPUDisplay d = new GPUDisplay(); - - public static void main(String[] args) { + + public static void main(String[] args) throws IOException { + new Main(new KeyboardDebugScreen()); + if (true) return; Utils.debugOn = true; Utils.debugThirdScreen = false; d.create(); - - Scene s = new Scene(d); + + final Scene s = new Scene(d); } - + private static class Scene implements Drawable { - private RAWFont[] fonts; - private int[] textures; - - private GPURenderer r; - private Display d; - - public Scene(Display d) { + private RAWFont exampleFont; + private final RAWSkin exampleSkin; + + private final GPURenderer r; + private final Display d; + + public Scene(Display d) throws IOException { this.d = d; - this.r = (GPURenderer) d.getRenderer(); + r = (GPURenderer) d.getRenderer(); + + exampleFont = d.loadFont("ex"); + + exampleSkin = d.loadSkin("skin.png"); + d.start(this); // fonts = new RAWFont[1]; // textures = new int[100]; // fonts[0] = new RAWFont(); // fonts[0].create("big"); - new Thread(()->{ + new Thread(() -> { try { - Thread.sleep(60000); - } catch (InterruptedException e) { + for (int i = 0; i < 12; i++) { + Utils.printSystemResourcesUsage(); + Thread.sleep(5000); + } + } catch (final InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } System.exit(0); }).start(); + + d.waitUntilExit(); } @Override public void refresh() { + exampleSkin.use(d); + r.glClearColor(0xFFD0FDCF); + r.glClear(d.getWidth(), d.getHeight()); + r.glColor3f(1.0f, 1.0f, 1.0f); + r.glFillRect(2, 2, 160, 160, 0, 0, 16, 16); + exampleFont.use(d); + r.glColor3f(1, 0, 0); + r.glDrawStringLeft(10, 170, "Prova! 123456789"); } - + } } diff --git a/src/org/warp/picalculator/Utils.java b/src/org/warp/picalculator/Utils.java index c35d2f75..de40da74 100644 --- a/src/org/warp/picalculator/Utils.java +++ b/src/org/warp/picalculator/Utils.java @@ -1,9 +1,17 @@ package org.warp.picalculator; +import java.io.BufferedReader; import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; +import java.io.InputStreamReader; import java.io.StringWriter; +import java.lang.management.ManagementFactory; +import java.lang.management.OperatingSystemMXBean; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; import java.math.BigDecimal; import java.math.BigInteger; import java.math.RoundingMode; @@ -12,7 +20,7 @@ import java.util.List; import org.nevec.rjm.BigDecimalMath; import org.nevec.rjm.Rational; -import org.warp.picalculator.gui.PIDisplay; +import org.warp.picalculator.gui.DisplayManager; import org.warp.picalculator.gui.graphicengine.RAWFont; import org.warp.picalculator.math.functions.AnteriorFunction; import org.warp.picalculator.math.functions.Division; @@ -45,7 +53,7 @@ public class Utils { public static boolean debugThirdScreen; public static Cloner cloner = new Cloner(); - + public static final class DebugStream extends StringWriter { public void println(String str) { @@ -61,7 +69,7 @@ public class Utils { public static boolean isInArray(String ch, String[] a) { boolean contains = false; - for (String c : a) { + for (final String c : a) { if (c.equals(ch)) { contains = true; break; @@ -70,13 +78,13 @@ public class Utils { return contains; } - private static final String[] regexNormalSymbols = new String[]{"\\", ".", "[", "]", "{", "}", "(", ")", "*", "+", "-", "?", "^", "$", "|"}; - + private static final String[] regexNormalSymbols = new String[] { "\\", ".", "[", "]", "{", "}", "(", ")", "*", "+", "-", "?", "^", "$", "|" }; + public static String ArrayToRegex(String[] array) { String regex = null; - for (String symbol : array) { + for (final String symbol : array) { boolean contained = false; - for (String smb : regexNormalSymbols) { + for (final String smb : regexNormalSymbols) { if (smb.equals(symbol)) { contained = true; break; @@ -100,17 +108,17 @@ public class Utils { } public static String[] concat(String[] a, String[] b) { - int aLen = a.length; - int bLen = b.length; - String[] c = new String[aLen + bLen]; + final int aLen = a.length; + final int bLen = b.length; + final String[] c = new String[aLen + bLen]; System.arraycopy(a, 0, c, 0, aLen); System.arraycopy(b, 0, c, aLen, bLen); return c; } public static String[] add(String[] a, String b) { - int aLen = a.length; - String[] c = new String[aLen + 1]; + final int aLen = a.length; + final String[] c = new String[aLen + 1]; System.arraycopy(a, 0, c, 0, aLen); c[aLen] = b; return c; @@ -213,7 +221,7 @@ public class Utils { } return false; } - + public static boolean areThereEmptyMultiplications(ArrayList fl) { for (int i = 0; i < fl.size(); i++) { if (fl.get(i) instanceof Multiplication || fl.get(i) instanceof Division) { @@ -249,7 +257,7 @@ public class Utils { public static boolean areThereOtherSettedUpFunctions(ArrayList fl) { for (int i = 0; i < fl.size(); i++) { - if (!(fl.get(i) instanceof Number || fl.get(i) instanceof Variable || fl.get(i) instanceof Sum || fl.get(i) instanceof SumSubtraction || fl.get(i) instanceof Expression || fl.get(i) instanceof AnteriorFunction || fl.get(i) instanceof Multiplication || fl.get(i) instanceof Division)) { + if (!(fl.get(i) instanceof Number || fl.get(i) instanceof Variable || fl.get(i) instanceof Sum || fl.get(i) instanceof SumSubtraction || fl.get(i) instanceof Expression || fl.get(i) instanceof AnteriorFunction || fl.get(i) instanceof Multiplication || fl.get(i) instanceof Division)) { if (fl.get(i) instanceof AnteriorFunction) { if (((AnteriorFunction) fl.get(i)).getVariable() == null) { return true; @@ -269,7 +277,7 @@ public class Utils { public static Rational getRational(BigDecimal str) { try { return getRational(str.toString()); - } catch (Error e) { + } catch (final Error e) { //E' IMPOSSIBILE CHE VENGA THROWATO UN ERRORE return new Rational("0"); } @@ -278,17 +286,17 @@ public class Utils { public static Rational getRational(String str) throws Error { try { return new Rational(str); - } catch (NumberFormatException ex) { + } catch (final NumberFormatException ex) { if (new BigDecimal(str).compareTo(new BigDecimal(8000.0)) < 0 && new BigDecimal(str).compareTo(new BigDecimal(-8000.0)) > 0) { if (str.equals("-")) { str = "-1"; } - long bits = Double.doubleToLongBits(Double.parseDouble(str)); + final long bits = Double.doubleToLongBits(Double.parseDouble(str)); - long sign = bits >>> 63; - long exponent = ((bits >>> 52) ^ (sign << 11)) - 1023; - long fraction = bits << 12; // bits are "reversed" but that's - // not a problem + final long sign = bits >>> 63; + final long exponent = ((bits >>> 52) ^ (sign << 11)) - 1023; + final long fraction = bits << 12; // bits are "reversed" but that's + // not a problem long a = 1L; long b = 1L; @@ -298,13 +306,15 @@ public class Utils { b *= 2; } - if (exponent > 0) + if (exponent > 0) { a *= 1 << exponent; - else + } else { b *= 1 << -exponent; + } - if (sign == 1) + if (sign == 1) { a *= -1; + } if (b == 0) { a = 0; @@ -313,11 +323,11 @@ public class Utils { return new Rational(new BigInteger(a + ""), new BigInteger(b + "")); } else { - BigDecimal original = new BigDecimal(str); + final BigDecimal original = new BigDecimal(str); - BigInteger numerator = original.unscaledValue(); + final BigInteger numerator = original.unscaledValue(); - BigInteger denominator = BigDecimalMath.pow(BigDecimal.TEN, new BigDecimal(original.scale())).toBigIntegerExact(); + final BigInteger denominator = BigDecimalMath.pow(BigDecimal.TEN, new BigDecimal(original.scale())).toBigIntegerExact(); return new Rational(numerator, denominator); } @@ -332,7 +342,7 @@ public class Utils { if (variables.size() != variables2.size()) { return false; } else { - for (Variable v : variables) { + for (final Variable v : variables) { if (!variables2.contains(v)) { return false; } @@ -343,17 +353,17 @@ public class Utils { public static void writeSquareRoot(Function var, int x, int y, boolean small) { var.setSmall(small); - int w1 = var.getWidth(); - int h1 = var.getHeight(); - int wsegno = 5; - int hsegno = h1 + 2; - + final int w1 = var.getWidth(); + final int h1 = var.getHeight(); + final int wsegno = 5; + final int hsegno = h1 + 2; + var.draw(x + wsegno, y + (hsegno - h1)); - PIDisplay.renderer.glDrawLine(x + 1, y + hsegno - 3, x + 3, y + hsegno - 1); - PIDisplay.renderer.glDrawLine(x + 3, y + (hsegno - 1) / 2 + 1, x + 3, y + hsegno - 1); - PIDisplay.renderer.glDrawLine(x + 4, y, x + 4, y + (hsegno - 1) / 2); - PIDisplay.renderer.glDrawLine(x + 4, y, x + 4 + 1 + w1 + 1, y); + DisplayManager.renderer.glDrawLine(x + 1, y + hsegno - 3, x + 3, y + hsegno - 1); + DisplayManager.renderer.glDrawLine(x + 3, y + (hsegno - 1) / 2 + 1, x + 3, y + hsegno - 1); + DisplayManager.renderer.glDrawLine(x + 4, y, x + 4, y + (hsegno - 1) / 2); + DisplayManager.renderer.glDrawLine(x + 4, y, x + 4 + 1 + w1 + 1, y); } public static final int getFontHeight() { @@ -365,7 +375,7 @@ public class Utils { } public static final RAWFont getFont(boolean small, boolean zoomed) { - return PIDisplay.fonts[getFontIndex(small, zoomed)]; + return DisplayManager.fonts[getFontIndex(small, zoomed)]; } public static final int getFontIndex(boolean small, boolean zoomed) { @@ -387,56 +397,56 @@ public class Utils { public static final int getFontHeight(boolean small) { return getFontHeight(small, Main.zoomed); } - + public static final int getFontHeight(boolean small, boolean zoomed) { if (small) { if (zoomed) { - return PIDisplay.glyphsHeight[3]; + return DisplayManager.glyphsHeight[3]; } else { - return PIDisplay.glyphsHeight[1]; + return DisplayManager.glyphsHeight[1]; } } else { if (zoomed) { - return PIDisplay.glyphsHeight[2]; + return DisplayManager.glyphsHeight[2]; } else { - return PIDisplay.glyphsHeight[0]; + return DisplayManager.glyphsHeight[0]; } } } - + public static byte[] convertStreamToByteArray(InputStream stream, long size) throws IOException { - // check to ensure that file size is not larger than Integer.MAX_VALUE. - if (size > Integer.MAX_VALUE) { - return new byte[0]; - } + // check to ensure that file size is not larger than Integer.MAX_VALUE. + if (size > Integer.MAX_VALUE) { + return new byte[0]; + } - byte[] buffer = new byte[(int)size]; - ByteArrayOutputStream os = new ByteArrayOutputStream(); + final byte[] buffer = new byte[(int) size]; + final ByteArrayOutputStream os = new ByteArrayOutputStream(); - int line = 0; - // read bytes from stream, and store them in buffer - while ((line = stream.read(buffer)) != -1) { - // Writes bytes from byte array (buffer) into output stream. - os.write(buffer, 0, line); - } - stream.close(); - os.flush(); - os.close(); - return os.toByteArray(); + int line = 0; + // read bytes from stream, and store them in buffer + while ((line = stream.read(buffer)) != -1) { + // Writes bytes from byte array (buffer) into output stream. + os.write(buffer, 0, line); + } + stream.close(); + os.flush(); + os.close(); + return os.toByteArray(); } public static int[] realBytes(byte[] bytes) { - int len = bytes.length; - int[] realbytes = new int[len]; + final int len = bytes.length; + final int[] realbytes = new int[len]; for (int i = 0; i < len; i++) { realbytes[i] = Byte.toUnsignedInt(bytes[i]); } return realbytes; } - + public static boolean allSolved(List expressions) throws Error { - for (Function itm : expressions) { + for (final Function itm : expressions) { if (itm.isSolved() == false) { return false; } @@ -445,29 +455,33 @@ public class Utils { } public static Function[][] joinFunctionsResults(List l1, List l2) { - int size1 = l1.size(); - int size2 = l2.size(); + final int size1 = l1.size(); + final int size2 = l2.size(); int cur1 = 0; int cur2 = 0; - int total = l1.size()*l2.size(); - Function[][] results = new Function[total][2]; + final int total = l1.size() * l2.size(); + final Function[][] results = new Function[total][2]; for (int i = 0; i < total; i++) { - results[i] = new Function[]{l1.get(cur1), l2.get(cur2)}; + results[i] = new Function[] { l1.get(cur1), l2.get(cur2) }; if (i % size2 == 0) { - cur1+=1; + cur1 += 1; } if (i % size1 == 0) { - cur2+=1; + cur2 += 1; + } + if (cur1 >= size1) { + cur1 = 0; + } + if (cur2 >= size2) { + cur2 = 0; } - if (cur1 >= size1) cur1 = 0; - if (cur2 >= size2) cur2 = 0; } return results; } public static boolean isNegative(Function b) { if (b instanceof Negative) { - return true; + return true; } else if (b instanceof Number && ((Number) b).getTerm().compareTo(BigDecimal.ZERO) < 0) { return true; } @@ -477,28 +491,97 @@ public class Utils { public static CharSequence multipleChars(String string, int i) { String result = ""; for (int j = 0; j < i; j++) { - result+=string; + result += string; } return result; } - + public static boolean isIntegerValue(BigDecimal bd) { - return bd.signum() == 0 || bd.scale() <= 0 || bd.stripTrailingZeros().scale() <= 0; + return bd.signum() == 0 || bd.scale() <= 0 || bd.stripTrailingZeros().scale() <= 0; } public static String arrayToString(T... data) { String sdata = ""; - for (T o : data) { - sdata += ","+o.toString(); + for (final T o : data) { + sdata += "," + o.toString(); } return sdata.substring(1); } public static String arrayToString(boolean... data) { String sdata = ""; - for (boolean o : data) { - sdata += (o)?1:0; + for (final boolean o : data) { + sdata += (o) ? 1 : 0; } return sdata; } + + public static void printSystemResourcesUsage() { + System.out.println("============"); + OperatingSystemMXBean operatingSystemMXBean = ManagementFactory.getOperatingSystemMXBean(); + for (Method method : operatingSystemMXBean.getClass().getDeclaredMethods()) { + method.setAccessible(true); + if (method.getName().startsWith("get") && Modifier.isPublic(method.getModifiers())) { + Object value; + try { + value = method.invoke(operatingSystemMXBean); + } catch (Exception e) { + value = e; + } // try + boolean percent = false; + boolean mb = false; + String displayName = method.getName(); + String displayValue = value.toString(); + if (displayName.endsWith("CpuLoad")) { + percent = true; + } + if (displayName.endsWith("MemorySize")) { + mb = true; + } + ArrayList arr = new ArrayList<>(); + arr.add("getFreePhysicalMemorySize"); + arr.add("getProcessCpuLoad"); + arr.add("getSystemCpuLoad"); + arr.add("getTotalPhysicalMemorySize"); + if (arr.contains(displayName)) { + if (percent) { + try { + System.out.println(displayName + " = " + (((int)(Float.parseFloat(displayValue) * 10000f))/100f) + "%"); + }catch(Exception ex) { + System.out.println(displayName + " = " + displayValue); + } + } else if (mb) { + try { + System.out.println(displayName + " = " + (Long.parseLong(displayValue) / 1024L / 1024L) + " MB"); + }catch(Exception ex) { + System.out.println(displayName + " = " + displayValue); + } + } else { + System.out.println(displayName + " = " + displayValue); + } + } + } // if + } // for + System.out.println("============"); + } + + public static boolean isRunningOnRaspberry() { + if (System.getProperty("os.name").equals("Linux")) { + final File file = new File("/etc", "os-release"); + try (FileInputStream fis = new FileInputStream(file); + BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(fis))) { + String string; + while ((string = bufferedReader.readLine()) != null) { + if (string.toLowerCase().contains("raspbian")) { + if (string.toLowerCase().contains("name")) { + return true; + } + } + } + } catch (final Exception e) { + e.printStackTrace(); + } + } + return false; + } } diff --git a/src/org/warp/picalculator/device/Keyboard.java b/src/org/warp/picalculator/device/Keyboard.java index f5f41316..2ef7ab5b 100644 --- a/src/org/warp/picalculator/device/Keyboard.java +++ b/src/org/warp/picalculator/device/Keyboard.java @@ -5,8 +5,7 @@ import java.awt.event.KeyEvent; import org.warp.picalculator.Utils; import org.warp.picalculator.device.chip.ParallelToSerial; import org.warp.picalculator.device.chip.SerialToParallel; -import org.warp.picalculator.gui.PIDisplay; -import org.warp.picalculator.gui.graphicengine.cpu.CPUDisplay; +import org.warp.picalculator.gui.DisplayManager; import org.warp.picalculator.gui.screens.KeyboardDebugScreen; import org.warp.picalculator.gui.screens.MarioScreen; import org.warp.picalculator.gui.screens.Screen; @@ -16,7 +15,7 @@ import com.pi4j.wiringpi.Gpio; public class Keyboard { public static volatile boolean alpha = false; public static volatile boolean shift = false; - + //From Serial private static final int RCK_pin = 35; private static final int SCK_and_CLK_pin = 38; @@ -29,21 +28,20 @@ public class Keyboard { private static volatile boolean[][] precedentStates = new boolean[8][8]; public static volatile boolean[][] debugKeysDown = new boolean[8][8]; - public static volatile KeyEvent debugKeyEvent; - + public static volatile int debugKeyCode = -1; + public static void startKeyboard() { - Thread kt = new Thread(()->{ + final Thread kt = new Thread(() -> { if (Utils.debugOn) { try { - while(true) { - if (debugKeyEvent != null) { - debugKeyPressed(debugKeyEvent); - debugKeyEvent = null; + while (true) { + if (debugKeyCode != -1) { + debugKeyPressed(debugKeyCode); + debugKeyCode = -1; } Thread.sleep(50); } - } catch (InterruptedException e) { - } + } catch (final InterruptedException e) {} } else { Gpio.pinMode(CLK_INH_pin, Gpio.OUTPUT); Gpio.pinMode(RCK_pin, Gpio.OUTPUT); @@ -51,36 +49,36 @@ public class Keyboard { Gpio.pinMode(SH_LD_pin, Gpio.OUTPUT); Gpio.pinMode(SCK_and_CLK_pin, Gpio.OUTPUT); Gpio.pinMode(QH_pin, Gpio.INPUT); - + Gpio.digitalWrite(CLK_INH_pin, false); Gpio.digitalWrite(RCK_pin, false); Gpio.digitalWrite(SER_pin, false); Gpio.digitalWrite(SH_LD_pin, false); Gpio.digitalWrite(SCK_and_CLK_pin, false); Gpio.digitalWrite(QH_pin, false); - SerialToParallel chip1 = new SerialToParallel(RCK_pin, SCK_and_CLK_pin /*SCK*/, SER_pin); - ParallelToSerial chip2 = new ParallelToSerial(SH_LD_pin, CLK_INH_pin, QH_pin, SCK_and_CLK_pin/*CLK*/); - + final SerialToParallel chip1 = new SerialToParallel(RCK_pin, SCK_and_CLK_pin /*SCK*/, SER_pin); + final ParallelToSerial chip2 = new ParallelToSerial(SH_LD_pin, CLK_INH_pin, QH_pin, SCK_and_CLK_pin/*CLK*/); + KeyboardDebugScreen.log("Started keyboard system"); - - while(true) { + + while (true) { boolean[] data; for (int col = 0; col < 8; col++) { data = new boolean[8]; data[col] = true; chip1.write(data); - + data = chip2.read(); KeyboardDebugScreen.ks[col] = data; - + for (int row = 0; row < 8; row++) { if (data[row] == true && precedentStates[row][col] == false) { - System.out.println("Pressed button at "+(row+1) +", "+(col+1)); - KeyboardDebugScreen.log("Pressed button at "+(row+1) +", "+(col+1)); - keyPressedRaw(row+1, col+1); + System.out.println("Pressed button at " + (row + 1) + ", " + (col + 1)); + KeyboardDebugScreen.log("Pressed button at " + (row + 1) + ", " + (col + 1)); + keyPressedRaw(row + 1, col + 1); } else if (data[row] == false && precedentStates[row][col] == true) { - keyReleasedRaw(row+1, col+1); - KeyboardDebugScreen.log("Released button at "+(row+1) +", "+(col+1)); + keyReleasedRaw(row + 1, col + 1); + KeyboardDebugScreen.log("Released button at " + (row + 1) + ", " + (col + 1)); } precedentStates[row][col] = data[row]; } @@ -94,8 +92,8 @@ public class Keyboard { kt.start(); } - private static void debugKeyPressed(KeyEvent arg0) { - switch (arg0.getKeyCode()) { + private static void debugKeyPressed(int keyCode) { + switch (keyCode) { case KeyEvent.VK_ESCAPE: Keyboard.keyPressed(Key.POWER); break; @@ -177,6 +175,7 @@ public class Keyboard { Keyboard.keyPressed(Key.NONE); } break; + case com.jogamp.newt.event.KeyEvent.VK_ENTER: case KeyEvent.VK_ENTER: if (Keyboard.shift) { Keyboard.keyPressed(Key.SIMPLIFY); @@ -187,7 +186,7 @@ public class Keyboard { } int row = 2; int col = 1; - Keyboard.debugKeysDown[row-1][col-1] = true; + Keyboard.debugKeysDown[row - 1][col - 1] = true; break; case KeyEvent.VK_1: if (!Keyboard.shift && !Keyboard.alpha) { @@ -265,6 +264,7 @@ public class Keyboard { Keyboard.keyPressed(Key.NONE); } break; + case com.jogamp.newt.event.KeyEvent.VK_ADD: case KeyEvent.VK_ADD: if (!Keyboard.shift && !Keyboard.alpha) { Keyboard.keyPressed(Key.PLUS); @@ -274,6 +274,7 @@ public class Keyboard { Keyboard.keyPressed(Key.NONE); } break; + case com.jogamp.newt.event.KeyEvent.VK_SUBTRACT: case KeyEvent.VK_SUBTRACT: if (!Keyboard.shift && !Keyboard.alpha) { Keyboard.keyPressed(Key.MINUS); @@ -281,6 +282,7 @@ public class Keyboard { Keyboard.keyPressed(Key.NONE); } break; + case com.jogamp.newt.event.KeyEvent.VK_MULTIPLY: case KeyEvent.VK_MULTIPLY: if (!Keyboard.shift && !Keyboard.alpha) { Keyboard.keyPressed(Key.MULTIPLY); @@ -288,6 +290,7 @@ public class Keyboard { Keyboard.keyPressed(Key.NONE); } break; + case com.jogamp.newt.event.KeyEvent.VK_DIVIDE: case KeyEvent.VK_DIVIDE: if (!Keyboard.shift && !Keyboard.alpha) { Keyboard.keyPressed(Key.DIVIDE); @@ -302,6 +305,7 @@ public class Keyboard { Keyboard.keyPressed(Key.NONE); } break; + case com.jogamp.newt.event.KeyEvent.VK_DELETE: case KeyEvent.VK_DELETE: if (!Keyboard.shift && !Keyboard.alpha) { Keyboard.keyPressed(Key.RESET); @@ -309,28 +313,31 @@ public class Keyboard { Keyboard.keyPressed(Key.NONE); } break; + case com.jogamp.newt.event.KeyEvent.VK_LEFT: case KeyEvent.VK_LEFT: //LEFT row = 2; col = 3; - Keyboard.debugKeysDown[row-1][col-1] = true; + Keyboard.debugKeysDown[row - 1][col - 1] = true; if (!Keyboard.shift && !Keyboard.alpha) { Keyboard.keyPressed(Key.LEFT); } else { Keyboard.keyPressed(Key.NONE); } break; + case com.jogamp.newt.event.KeyEvent.VK_RIGHT: case KeyEvent.VK_RIGHT: //RIGHT row = 2; col = 5; - Keyboard.debugKeysDown[row-1][col-1] = true; + Keyboard.debugKeysDown[row - 1][col - 1] = true; if (!Keyboard.shift && !Keyboard.alpha) { Keyboard.keyPressed(Key.RIGHT); } else { Keyboard.keyPressed(Key.NONE); } break; + case com.jogamp.newt.event.KeyEvent.VK_NUMPAD4: case KeyEvent.VK_NUMPAD4: if (!Keyboard.shift && !Keyboard.alpha) { Keyboard.keyPressed(Key.HISTORY_BACK); @@ -338,6 +345,7 @@ public class Keyboard { Keyboard.keyPressed(Key.NONE); } break; + case com.jogamp.newt.event.KeyEvent.VK_NUMPAD6: case KeyEvent.VK_NUMPAD6: if (!Keyboard.shift && !Keyboard.alpha) { Keyboard.keyPressed(Key.HISTORY_FORWARD); @@ -352,21 +360,26 @@ public class Keyboard { Keyboard.keyPressed(Key.NONE); } break; + case com.jogamp.newt.event.KeyEvent.VK_SHIFT: case KeyEvent.VK_SHIFT: Keyboard.keyPressed(Key.SHIFT); break; case KeyEvent.VK_A: Keyboard.keyPressed(Key.ALPHA); break; + case com.jogamp.newt.event.KeyEvent.VK_NUMPAD1: case KeyEvent.VK_NUMPAD1: Keyboard.keyPressed(Key.SQRT); break; + case com.jogamp.newt.event.KeyEvent.VK_NUMPAD2: case KeyEvent.VK_NUMPAD2: Keyboard.keyPressed(Key.ROOT); break; + case com.jogamp.newt.event.KeyEvent.VK_NUMPAD3: case KeyEvent.VK_NUMPAD3: Keyboard.keyPressed(Key.POWER_OF_2); break; + case com.jogamp.newt.event.KeyEvent.VK_NUMPAD5: case KeyEvent.VK_NUMPAD5: Keyboard.keyPressed(Key.POWER_OF_x); break; @@ -375,12 +388,12 @@ public class Keyboard { public static boolean isKeyDown(int row, int col) { if (Utils.debugOn == false) { - return precedentStates[row-1][col-1]; + return precedentStates[row - 1][col - 1]; } else { - return debugKeysDown[row-1][col-1]; + return debugKeysDown[row - 1][col - 1]; } } - + private static void keyReleasedRaw(int row, int col) { KeyboardDebugScreen.keyX = row; KeyboardDebugScreen.keyY = col; @@ -395,7 +408,7 @@ public class Keyboard { if (row == 1 && col == 1) { keyPressed(Key.SHIFT); } else if (row == 1 && col == 2) { - keyPressed(Key.ALPHA); + keyPressed(Key.ALPHA); } else if (row == 1 && col == 7) { if (shift) { keyPressed(Key.BRIGHTNESS_CYCLE_REVERSE); @@ -580,7 +593,7 @@ public class Keyboard { } else { keyPressed(Key.LEFT); } - } else if (row ==2 && col == 5) { + } else if (row == 2 && col == 5) { if (shift) { keyPressed(Key.NONE); } else if (alpha) { @@ -664,8 +677,7 @@ public class Keyboard { System.out.println("PREMUTO >"); keyPressed(Key.HISTORY_FORWARD); } - } else { - } + } else {} } public static void stopKeyboard() { @@ -680,15 +692,15 @@ public class Keyboard { } public static void keyPressed(Key k) { - if (PIDisplay.INSTANCE != null) { - Screen scr = PIDisplay.INSTANCE.getScreen(); + if (DisplayManager.INSTANCE != null) { + final Screen scr = DisplayManager.INSTANCE.getScreen(); boolean refresh = false; - if(scr != null && scr.initialized && scr.keyPressed(k)) { + if (scr != null && scr.initialized && scr.keyPressed(k)) { refresh = true; } else { switch (k) { case POWER: - PIDisplay.display.destroy(); + DisplayManager.display.destroy(); break; case NONE: break; @@ -696,20 +708,20 @@ public class Keyboard { letterPressed('X'); break; case BRIGHTNESS_CYCLE: - PIDisplay.cycleBrightness(false); + DisplayManager.cycleBrightness(false); refresh = true; break; case BRIGHTNESS_CYCLE_REVERSE: - PIDisplay.INSTANCE.setScreen(new MarioScreen()); //TODO: rimuovere: prova - PIDisplay.cycleBrightness(true); + DisplayManager.INSTANCE.setScreen(new MarioScreen()); //TODO: rimuovere: prova + DisplayManager.cycleBrightness(true); refresh = true; break; case HISTORY_BACK: - PIDisplay.INSTANCE.goBack(); + DisplayManager.INSTANCE.goBack(); refresh = true; break; case HISTORY_FORWARD: - PIDisplay.INSTANCE.goForward(); + DisplayManager.INSTANCE.goForward(); refresh = true; break; default: @@ -736,20 +748,20 @@ public class Keyboard { refresh = true; } if (refresh) { - PIDisplay.display.repaint(); +// PIDisplay.display.repaint(); } } } private static void letterPressed(char L) { - + } public static void keyReleased(Key k) { boolean refresh = false; - if (PIDisplay.INSTANCE != null) { - Screen scr = PIDisplay.INSTANCE.getScreen(); - if(scr != null && scr.initialized && scr.keyReleased(k)) { + if (DisplayManager.INSTANCE != null) { + final Screen scr = DisplayManager.INSTANCE.getScreen(); + if (scr != null && scr.initialized && scr.keyReleased(k)) { refresh = true; } else { switch (k) { @@ -760,26 +772,17 @@ public class Keyboard { } } if (refresh) { - PIDisplay.display.repaint(); +// PIDisplay.display.repaint(); } } } public static enum Key { - POWER, debug_DEG, debug_RAD, debug_GRA, SHIFT, ALPHA, NONE, - HISTORY_BACK, HISTORY_FORWARD, SURD_MODE, DRG_CYCLE, - LETTER_X, LETTER_Y, SIMPLIFY, SOLVE, BRIGHTNESS_CYCLE, - BRIGHTNESS_CYCLE_REVERSE, DOT, NUM0, NUM1, NUM2, NUM3, NUM4, NUM5, NUM6, NUM7, NUM8, NUM9, - PARENTHESIS_OPEN, PARENTHESIS_CLOSE, PLUS, MINUS, PLUS_MINUS, MULTIPLY, DIVIDE, EQUAL, - DELETE, RESET, LEFT, RIGHT, UP, DOWN, OK, debug1, debug2, debug3, debug4, debug5, - SQRT, ROOT, POWER_OF_2, POWER_OF_x, - SINE, COSINE, TANGENT, ARCSINE, ARCCOSINE, ARCTANGENT, PI + POWER, debug_DEG, debug_RAD, debug_GRA, SHIFT, ALPHA, NONE, HISTORY_BACK, HISTORY_FORWARD, SURD_MODE, DRG_CYCLE, LETTER_X, LETTER_Y, SIMPLIFY, SOLVE, BRIGHTNESS_CYCLE, BRIGHTNESS_CYCLE_REVERSE, DOT, NUM0, NUM1, NUM2, NUM3, NUM4, NUM5, NUM6, NUM7, NUM8, NUM9, PARENTHESIS_OPEN, PARENTHESIS_CLOSE, PLUS, MINUS, PLUS_MINUS, MULTIPLY, DIVIDE, EQUAL, DELETE, RESET, LEFT, RIGHT, UP, DOWN, OK, debug1, debug2, debug3, debug4, debug5, SQRT, ROOT, POWER_OF_2, POWER_OF_x, SINE, COSINE, TANGENT, ARCSINE, ARCCOSINE, ARCTANGENT, PI } } - - /* diff --git a/src/org/warp/picalculator/device/chip/ParallelToSerial.java b/src/org/warp/picalculator/device/chip/ParallelToSerial.java index 691162d3..fbca3c1f 100644 --- a/src/org/warp/picalculator/device/chip/ParallelToSerial.java +++ b/src/org/warp/picalculator/device/chip/ParallelToSerial.java @@ -3,11 +3,11 @@ package org.warp.picalculator.device.chip; import com.pi4j.wiringpi.Gpio; public class ParallelToSerial { - - private int SH_LD; - private int CLK_INH; - private int QH; - private int CLK; + + private final int SH_LD; + private final int CLK_INH; + private final int QH; + private final int CLK; public ParallelToSerial(int SH_LD_pin, int CLK_INH_pin, int QH_pin, int CLK_pin) { SH_LD = SH_LD_pin; @@ -17,19 +17,19 @@ public class ParallelToSerial { } public boolean[] read() { - boolean[] data = new boolean[8]; + final boolean[] data = new boolean[8]; Gpio.digitalWrite(CLK_INH, Gpio.HIGH); Gpio.digitalWrite(SH_LD, Gpio.LOW); Gpio.delay(1); Gpio.digitalWrite(SH_LD, Gpio.HIGH); Gpio.digitalWrite(CLK_INH, Gpio.LOW); - + for (int i = 7; i >= 0; i--) { Gpio.digitalWrite(CLK, Gpio.HIGH); Gpio.digitalWrite(CLK, Gpio.LOW); - data[i] = Gpio.digitalRead(QH)==Gpio.HIGH?true:false; + data[i] = Gpio.digitalRead(QH) == Gpio.HIGH ? true : false; } - + return data; } } diff --git a/src/org/warp/picalculator/device/chip/SerialToParallel.java b/src/org/warp/picalculator/device/chip/SerialToParallel.java index 712549f9..5a455896 100644 --- a/src/org/warp/picalculator/device/chip/SerialToParallel.java +++ b/src/org/warp/picalculator/device/chip/SerialToParallel.java @@ -3,28 +3,28 @@ package org.warp.picalculator.device.chip; import com.pi4j.wiringpi.Gpio; public class SerialToParallel { - private int RCK; //Storage register clock pin (latch pin) - private int SCK; //Shift register clock pin - private int SER; //Serial data input - + private final int RCK; //Storage register clock pin (latch pin) + private final int SCK; //Shift register clock pin + private final int SER; //Serial data input + public SerialToParallel(int RCK_pin, int SCK_pin, int SER_pin) { RCK = RCK_pin; SCK = SCK_pin; SER = SER_pin; } - + public void write(boolean[] data) { if (data.length != 8) { return; } else { Gpio.digitalWrite(RCK, Gpio.LOW); - + for (int i = 7; i >= 0; i--) { Gpio.digitalWrite(SCK, Gpio.LOW); Gpio.digitalWrite(SER, data[i]); Gpio.digitalWrite(SCK, Gpio.HIGH); } - + Gpio.digitalWrite(RCK, Gpio.HIGH); } } diff --git a/src/org/warp/picalculator/gui/DisplayManager.java b/src/org/warp/picalculator/gui/DisplayManager.java new file mode 100644 index 00000000..1d23b3de --- /dev/null +++ b/src/org/warp/picalculator/gui/DisplayManager.java @@ -0,0 +1,494 @@ +package org.warp.picalculator.gui; + +import java.io.IOException; +import java.lang.management.ManagementFactory; +import java.lang.management.OperatingSystemMXBean; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.util.ArrayList; + +import org.warp.picalculator.Main; +import org.warp.picalculator.Utils; +import org.warp.picalculator.device.Keyboard; +import org.warp.picalculator.gui.graphicengine.Display; +import org.warp.picalculator.gui.graphicengine.Drawable; +import org.warp.picalculator.gui.graphicengine.Renderer; +import org.warp.picalculator.gui.graphicengine.cpu.CPUDisplay; +import org.warp.picalculator.gui.graphicengine.gpu.GPUDisplay; +import org.warp.picalculator.gui.graphicengine.RAWFont; +import org.warp.picalculator.gui.graphicengine.RAWSkin; +import org.warp.picalculator.gui.screens.Screen; + +import com.pi4j.wiringpi.Gpio; + +public final class DisplayManager implements Drawable { + public static DisplayManager INSTANCE; + private static float brightness; + + public static final Display display = chooseGraphicEngine(); + public static Renderer renderer; + + private static RAWSkin skin; + public static RAWFont[] fonts; + + public static String error = null; + public String[] errorStackTrace = null; + public final static int[] glyphsHeight = new int[] { 9, 6, 12, 9 }; + + public static Screen screen; + public static String displayDebugString = ""; + + public DisplayManager(Screen screen) { + setScreen(screen); + INSTANCE = this; + loop(); + } + /* + * private void load_skin() { + * try { + * skin_tex = glGenTextures(); + * glBindTexture(GL_TEXTURE_2D, skin_tex); + * glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + * + * InputStream in = new FileInputStream("skin.png"); + * PNGDecoder decoder = new PNGDecoder(in); + * + * System.out.println("width="+decoder.getWidth()); + * System.out.println("height="+decoder.getHeight()); + * + * ByteBuffer buf = + * ByteBuffer.allocateDirect(4*decoder.getWidth()*decoder.getHeight()); + * decoder.decode(buf, decoder.getWidth()*4, Format.RGBA); + * buf.flip(); + * + * skin = buf; + * skin_w = decoder.getWidth(); + * skin_h = decoder.getHeight(); + * glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, skin_w, + * skin_h, 0, GL_RGBA, GL_UNSIGNED_BYTE, skin); + * } catch (IOException ex) { + * ex.printStackTrace(); + * } + * } + */ + + private static Display chooseGraphicEngine() { + Display d; + d = new GPUDisplay(); + if (d.isSupported()) return d; + d = new CPUDisplay(); + if (d.isSupported()) return d; + throw new UnsupportedOperationException("No graphic engines available."); + } + + public void setScreen(Screen screen) { + if (screen.initialized == false) { + if (screen.canBeInHistory) { + DisplayManager.currentSession = 0; + for (int i = DisplayManager.sessions.length - 1; i >= 1; i--) { + DisplayManager.sessions[i] = DisplayManager.sessions[i - 1]; + } + DisplayManager.sessions[0] = screen; + } else { + DisplayManager.currentSession = -1; + } + } + screen.d = this; + try { + screen.create(); + DisplayManager.screen = screen; + if (screen.initialized == false) { + screen.initialize(); + } + } catch (final Exception e) { + e.printStackTrace(); + System.exit(0); + } + } + + public void replaceScreen(Screen screen) { + if (screen.initialized == false) { + if (screen.canBeInHistory) { + DisplayManager.sessions[DisplayManager.currentSession] = screen; + } else { + DisplayManager.currentSession = -1; + for (int i = 0; i < DisplayManager.sessions.length - 2; i++) { + DisplayManager.sessions[i] = DisplayManager.sessions[i + 1]; + } + } + } + screen.d = this; + try { + screen.create(); + DisplayManager.screen = screen; + if (screen.initialized == false) { + screen.initialize(); + } + } catch (final Exception e) { + e.printStackTrace(); + System.exit(0); + } + } + + public boolean canGoBack() { + if (DisplayManager.currentSession == -1) { + return DisplayManager.sessions[0] != null; + } + if (DisplayManager.screen != DisplayManager.sessions[DisplayManager.currentSession]) { + + } else if (DisplayManager.currentSession + 1 < DisplayManager.sessions.length) { + if (DisplayManager.sessions[DisplayManager.currentSession + 1] != null) { + + } else { + return false; + } + } else { + return false; + } + if (DisplayManager.sessions[DisplayManager.currentSession] != null) { + return true; + } + return false; + } + + public void goBack() { + if (canGoBack()) { + if (DisplayManager.currentSession >= 0 && DisplayManager.screen != DisplayManager.sessions[DisplayManager.currentSession]) {} else { + DisplayManager.currentSession += 1; + } + DisplayManager.screen = DisplayManager.sessions[DisplayManager.currentSession]; + } + } + + public boolean canGoForward() { + if (DisplayManager.currentSession <= 0) { // -1 e 0 + return false; + } + if (DisplayManager.screen != DisplayManager.sessions[DisplayManager.currentSession]) { + + } else if (DisplayManager.currentSession > 0) { + if (DisplayManager.sessions[DisplayManager.currentSession - 1] != null) { + + } else { + return false; + } + } else { + return false; + } + if (DisplayManager.sessions[DisplayManager.currentSession] != null) { + return true; + } + return false; + } + + public void goForward() { + if (canGoForward()) { + if (DisplayManager.screen != DisplayManager.sessions[DisplayManager.currentSession]) { + + } else { + DisplayManager.currentSession -= 1; + } + DisplayManager.screen = DisplayManager.sessions[DisplayManager.currentSession]; + } + } + + public Screen getScreen() { + return DisplayManager.screen; + } + + private void load_skin() throws IOException { + skin = display.loadSkin("skin.png"); + } + + private void load_fonts() throws IOException { + fonts = new RAWFont[7]; + fonts[0] = display.loadFont("big"); + fonts[1] = display.loadFont("small"); + fonts[2] = display.loadFont("ex"); + fonts[3] = display.loadFont("big"); + fonts[4] = display.loadFont("32"); + fonts[5] = display.loadFont("square"); + } + + private void draw_init() { + renderer.glClear(display.getWidth(), display.getHeight()); + } + + private void draw_status() { + renderer.glColor(0xFFc5c2af); + renderer.glFillColor(0, 0, display.getWidth(), 20); + renderer.glColor3i(0, 0, 0); + renderer.glDrawLine(0, 20, display.getWidth() - 1, 20); + renderer.glColor3i(255, 255, 255); + skin.use(display); + if (Keyboard.shift) { + renderer.glFillRect(2 + 18 * 0, 2, 16, 16, 16 * 2, 16 * 0, 16, 16); + } else { + renderer.glFillRect(2 + 18 * 0, 2, 16, 16, 16 * 3, 16 * 0, 16, 16); + } + if (Keyboard.alpha) { + renderer.glFillRect(2 + 18 * 1, 2, 16, 16, 16 * 0, 16 * 0, 16, 16); + } else { + renderer.glFillRect(2 + 18 * 1, 2, 16, 16, 16 * 1, 16 * 0, 16, 16); + } + /* + if (Calculator.angleMode == AngleMode.DEG) { + drawSkinPart(8 + 18 * 2, 2, 16 * 4, 16 * 0, 16 + 16 * 4, 16 + 16 * 0); + drawSkinPart(8 + 18 * 3, 2, 16 * 7, 16 * 0, 16 + 16 * 7, 16 + 16 * 0); + drawSkinPart(8 + 18 * 4, 2, 16 * 9, 16 * 0, 16 + 16 * 9, 16 + 16 * 0); + } else if (Calculator.angleMode == AngleMode.RAD) { + drawSkinPart(8 + 18 * 2, 2, 16 * 5, 16 * 0, 16 + 16 * 5, 16 + 16 * 0); + drawSkinPart(8 + 18 * 3, 2, 16 * 6, 16 * 0, 16 + 16 * 6, 16 + 16 * 0); + drawSkinPart(8 + 18 * 4, 2, 16 * 9, 16 * 0, 16 + 16 * 9, 16 + 16 * 0); + } else if (Calculator.angleMode == AngleMode.GRA) { + drawSkinPart(8 + 18 * 2, 2, 16 * 5, 16 * 0, 16 + 16 * 5, 16 + 16 * 0); + drawSkinPart(8 + 18 * 3, 2, 16 * 7, 16 * 0, 16 + 16 * 7, 16 + 16 * 0); + drawSkinPart(8 + 18 * 4, 2, 16 * 8, 16 * 0, 16 + 16 * 8, 16 + 16 * 0); + } else { + drawSkinPart(8 + 18 * 2, 2, 16 * 5, 16 * 0, 16 + 16 * 5, 16 + 16 * 0); + drawSkinPart(8 + 18 * 3, 2, 16 * 7, 16 * 0, 16 + 16 * 7, 16 + 16 * 0); + drawSkinPart(8 + 18 * 4, 2, 16 * 9, 16 * 0, 16 + 16 * 9, 16 + 16 * 0); + }*/ + + int padding = 2; + + final int brightness = (int) (Math.ceil(DisplayManager.brightness * 9)); + if (brightness <= 10) { + renderer.glFillRect(Main.screenSize[0] - (padding + 16), 2, 16, 16, 16 * brightness, 16 * 1, 16, 16); + } else { + Utils.debug.println("Brightness error"); + } + + padding += 18 + 6; + + final boolean canGoBack = canGoBack(); + final boolean canGoForward = canGoForward(); + + if (Main.haxMode) { + renderer.glFillRect(Main.screenSize[0] - (padding + 16), 2, 16, 16, 16 * 18, 16 * 0, 16, 16); + padding += 18 + 6; + } + + if (canGoBack && canGoForward) { + renderer.glFillRect(Main.screenSize[0] - (padding + 16), 2, 16, 16, 16 * 14, 16 * 0, 16, 16); + } else if (canGoBack) { + renderer.glFillRect(Main.screenSize[0] - (padding + 16), 2, 16, 16, 16 * 15, 16 * 0, 16, 16); + } else if (canGoForward) { + renderer.glFillRect(Main.screenSize[0] - (padding + 16), 2, 16, 16, 16 * 16, 16 * 0, 16, 16); + } else { + renderer.glFillRect(Main.screenSize[0] - (padding + 16), 2, 16, 16, 16 * 17, 16 * 0, 16, 16); + } + + padding += 18; + + screen.renderStatusbar(); + } + + private void draw_screen() { + screen.render(); + } + + private void draw_bottom() { + renderer.glDrawStringLeft(2, 90, displayDebugString); + + Utils.getFont(false, true).use(DisplayManager.display); + DisplayManager.renderer.glColor4i(255, 0, 0, 40); + DisplayManager.renderer.glDrawStringLeft(5 + 1, Main.screenSize[1] - 20 + 1, "WORK IN PROGRESS."); + DisplayManager.renderer.glColor4i(255, 0, 0, 80); + DisplayManager.renderer.glDrawStringLeft(5, Main.screenSize[1] - 20, "WORK IN PROGRESS."); + } + + private void draw_world() { + renderer.glColor3i(255, 255, 255); + + if (error != null) { + Utils.getFont(false, false).use(display); + renderer.glColor3i(129, 28, 22); + renderer.glDrawStringRight(Main.screenSize[0] - 2, Main.screenSize[1] - DisplayManager.glyphsHeight[1] - 2, "ANDREA CAVALLI'S CALCULATOR"); + renderer.glColor3i(149, 32, 26); + renderer.glDrawStringCenter((Main.screenSize[0] / 2), 22, error); + renderer.glColor3i(164, 34, 28); + int i = 22; + for (final String stackPart : errorStackTrace) { + renderer.glDrawStringLeft(2, 22 + i, stackPart); + i += 11; + } + fonts[0].use(display); + renderer.glColor3i(129, 28, 22); + renderer.glDrawStringCenter((Main.screenSize[0] / 2), 11, "UNEXPECTED EXCEPTION"); + } else { + fonts[0].use(display); + draw_screen(); + draw_status(); + draw_bottom(); + } + } + + private void draw() { + draw_init(); + draw_world(); + } + + private long precTime = -1; + + @Override + public void refresh() { + float dt = 0; + final long newtime = System.nanoTime(); + if (precTime == -1) { + dt = 0; + } else { + dt = (float) ((newtime - precTime) / 1000000000d); + } + precTime = newtime; + /* + * Calcoli + */ + checkDisplayResized(); + + screen.beforeRender(dt); + + if (dt >= 0.03 || screen.mustBeRefreshed()) { + draw(); + } + + } + + private void checkDisplayResized() { + if (display.wasResized()) { + Main.screenSize[0] = display.getWidth(); + Main.screenSize[1] = display.getHeight(); + } + }; + + public void loop() { + try { + load_skin(); + load_fonts(); + display.create(); + renderer = display.getRenderer(); + + try { + screen.initialize(); + } catch (final Exception e) { + e.printStackTrace(); + System.exit(0); + } + + //Debug thread + Thread dbgthrd = new Thread(() -> { + try { + while (true) { + for (int i = 0; i < 10; i++) { + System.out.println("============"); + OperatingSystemMXBean operatingSystemMXBean = ManagementFactory.getOperatingSystemMXBean(); + for (Method method : operatingSystemMXBean.getClass().getDeclaredMethods()) { + method.setAccessible(true); + if (method.getName().startsWith("get") && Modifier.isPublic(method.getModifiers())) { + Object value; + try { + value = method.invoke(operatingSystemMXBean); + } catch (Exception e) { + value = e; + } // try + boolean percent = false; + boolean mb = false; + String displayName = method.getName(); + String displayValue = value.toString(); + if (displayName.endsWith("CpuLoad")) { + percent = true; + } + if (displayName.endsWith("MemorySize")) { + mb = true; + } + ArrayList arr = new ArrayList<>(); + arr.add("getFreePhysicalMemorySize"); + arr.add("getProcessCpuLoad"); + arr.add("getSystemCpuLoad"); + arr.add("getTotalPhysicalMemorySize"); + if (arr.contains(displayName)) { + if (percent) { + try { + System.out.println(displayName + " = " + (((int)(Float.parseFloat(displayValue) * 10000f))/100f) + "%"); + }catch(Exception ex) { + System.out.println(displayName + " = " + displayValue); + } + } else if (mb) { + try { + System.out.println(displayName + " = " + (Long.parseLong(displayValue) / 1024L / 1024L) + " MB"); + }catch(Exception ex) { + System.out.println(displayName + " = " + displayValue); + } + } else { + System.out.println(displayName + " = " + displayValue); + } + } + } // if + } // for + System.out.println("============"); + Thread.sleep(5000); + } + } + } catch (final InterruptedException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + }); + dbgthrd.setDaemon(true); + dbgthrd.setName("Debug performance thread"); + dbgthrd.start(); + + display.start(this); + + display.waitUntilExit(); + } catch (final Exception ex) { + ex.printStackTrace(); + } finally {} + } + + public static void changeBrightness(float change) { + setBrightness(brightness + change); + } + + public static void setBrightness(float newval) { + if (newval >= 0 && newval <= 1) { + brightness = newval; + if (Utils.debugOn == false) { + Gpio.pwmWrite(12, (int) Math.ceil(brightness * 1024)); +// SoftPwm.softPwmWrite(12, (int)(Math.ceil(brightness*10))); + } + } + } + + public static void cycleBrightness(boolean reverse) { + final float step = reverse ? -0.1f : 0.1f; + if (brightness + step > 1f) { + setBrightness(0f); + } else if (brightness + step <= 0f) { + setBrightness(1.0f); + } else { + changeBrightness(step); + } + } + + public static float getBrightness() { + return brightness; + } + + public static int currentSession = 0; + public static Screen[] sessions = new Screen[5]; + + @Deprecated + public static void colore(float f1, float f2, float f3, float f4) { + renderer.glColor4f(f1,f2,f3,f4); + } + + public static Drawable getDrawable() { + return INSTANCE; + } + + @Deprecated + public static void drawSkinPart(int x, int y, int uvX, int uvY, int uvX2, int uvY2) { + renderer.glFillRect(x, y, uvX2-uvX, uvY2-uvY, uvX, uvY, uvX2-uvX, uvY2-uvY); + } +} \ No newline at end of file diff --git a/src/org/warp/picalculator/gui/GraphicUtils.java b/src/org/warp/picalculator/gui/GraphicUtils.java new file mode 100644 index 00000000..041906f6 --- /dev/null +++ b/src/org/warp/picalculator/gui/GraphicUtils.java @@ -0,0 +1,60 @@ +package org.warp.picalculator.gui; + +public class GraphicUtils { + public static final float sin(float rad) + { + return sin[(int) (rad * radToIndex) & SIN_MASK]; + } + + public static final float cos(float rad) + { + return cos[(int) (rad * radToIndex) & SIN_MASK]; + } + + public static final float sinDeg(float deg) + { + return sin[(int) (deg * degToIndex) & SIN_MASK]; + } + + public static final float cosDeg(float deg) + { + return cos[(int) (deg * degToIndex) & SIN_MASK]; + } + + private static final float RAD,DEG; + private static final int SIN_BITS,SIN_MASK,SIN_COUNT; + private static final float radFull,radToIndex; + private static final float degFull,degToIndex; + private static final float[] sin, cos; + + static + { + RAD = (float) Math.PI / 180.0f; + DEG = 180.0f / (float) Math.PI; + + SIN_BITS = 12; + SIN_MASK = ~(-1 << SIN_BITS); + SIN_COUNT = SIN_MASK + 1; + + radFull = (float) (Math.PI * 2.0); + degFull = (float) (360.0); + radToIndex = SIN_COUNT / radFull; + degToIndex = SIN_COUNT / degFull; + + sin = new float[SIN_COUNT]; + cos = new float[SIN_COUNT]; + + for (int i = 0; i < SIN_COUNT; i++) + { + sin[i] = (float) Math.sin((i + 0.5f) / SIN_COUNT * radFull); + cos[i] = (float) Math.cos((i + 0.5f) / SIN_COUNT * radFull); + } + + // Four cardinal directions (credits: Nate) + for (int i = 0; i < 360; i += 90) + { + sin[(int)(i * degToIndex) & SIN_MASK] = (float)Math.sin(i * Math.PI / 180.0); + cos[(int)(i * degToIndex) & SIN_MASK] = (float)Math.cos(i * Math.PI / 180.0); + } + } +} diff --git a/src/org/warp/picalculator/gui/PIDisplay.java b/src/org/warp/picalculator/gui/PIDisplay.java deleted file mode 100644 index bf626c95..00000000 --- a/src/org/warp/picalculator/gui/PIDisplay.java +++ /dev/null @@ -1,437 +0,0 @@ -package org.warp.picalculator.gui; - -import java.awt.image.BufferedImage; -import java.io.IOException; - -import javax.imageio.ImageIO; - -import org.warp.picalculator.Main; -import org.warp.picalculator.Utils; -import org.warp.picalculator.device.Keyboard; -import org.warp.picalculator.gui.graphicengine.Display; -import org.warp.picalculator.gui.graphicengine.Drawable; -import org.warp.picalculator.gui.graphicengine.RAWFont; -import org.warp.picalculator.gui.graphicengine.Renderer; -import org.warp.picalculator.gui.graphicengine.cpu.CPUDisplay; -import org.warp.picalculator.gui.screens.Screen; - -import com.pi4j.wiringpi.Gpio; - -public final class PIDisplay implements Drawable { - public static PIDisplay INSTANCE; - private static float brightness; - - public static final Display display = new CPUDisplay(); - public static final Renderer renderer = display.getRenderer(); - - private static int[] skin; - private static int[] skinSize; - public static RAWFont[] fonts; - - public static String error = null; - public String[] errorStackTrace = null; - public final static int[] glyphsHeight = new int[] { 9, 6, 12, 9 }; - - public static Screen screen; - public static String displayDebugString = ""; - - public PIDisplay(Screen screen) { - setScreen(screen); - INSTANCE = this; - loop(); - } - /* - * private void load_skin() { - * try { - * skin_tex = glGenTextures(); - * glBindTexture(GL_TEXTURE_2D, skin_tex); - * glPixelStorei(GL_UNPACK_ALIGNMENT, 1); - * - * InputStream in = new FileInputStream("skin.png"); - * PNGDecoder decoder = new PNGDecoder(in); - * - * System.out.println("width="+decoder.getWidth()); - * System.out.println("height="+decoder.getHeight()); - * - * ByteBuffer buf = - * ByteBuffer.allocateDirect(4*decoder.getWidth()*decoder.getHeight()); - * decoder.decode(buf, decoder.getWidth()*4, Format.RGBA); - * buf.flip(); - * - * skin = buf; - * skin_w = decoder.getWidth(); - * skin_h = decoder.getHeight(); - * glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, skin_w, - * skin_h, 0, GL_RGBA, GL_UNSIGNED_BYTE, skin); - * } catch (IOException ex) { - * ex.printStackTrace(); - * } - * } - */ - - public void setScreen(Screen screen) { - if (screen.initialized == false) { - if (screen.canBeInHistory) { - PIDisplay.currentSession = 0; - for (int i = PIDisplay.sessions.length - 1; i >= 1; i--) { - PIDisplay.sessions[i] = PIDisplay.sessions[i - 1]; - } - PIDisplay.sessions[0] = screen; - } else { - PIDisplay.currentSession = -1; - } - } - screen.d = this; - try { - screen.create(); - PIDisplay.screen = screen; - if (screen.initialized == false) { - screen.initialize(); - } - } catch (Exception e) { - e.printStackTrace(); - System.exit(0); - } - } - - public void replaceScreen(Screen screen) { - if (screen.initialized == false) { - if (screen.canBeInHistory) { - PIDisplay.sessions[PIDisplay.currentSession] = screen; - } else { - PIDisplay.currentSession = -1; - for (int i = 0; i < PIDisplay.sessions.length - 2; i++) { - PIDisplay.sessions[i] = PIDisplay.sessions[i + 1]; - } - } - } - screen.d = this; - try { - screen.create(); - PIDisplay.screen = screen; - if (screen.initialized == false) { - screen.initialize(); - } - } catch (Exception e) { - e.printStackTrace(); - System.exit(0); - } - } - - public boolean canGoBack() { - if (PIDisplay.currentSession == -1) { - return PIDisplay.sessions[0] != null; - } - if (PIDisplay.screen != PIDisplay.sessions[PIDisplay.currentSession]) { - - } else if (PIDisplay.currentSession + 1 < PIDisplay.sessions.length) { - if (PIDisplay.sessions[PIDisplay.currentSession + 1] != null) { - - } else { - return false; - } - } else { - return false; - } - if (PIDisplay.sessions[PIDisplay.currentSession] != null) { - return true; - } - return false; - } - - public void goBack() { - if (canGoBack()) { - if (PIDisplay.currentSession >= 0 && PIDisplay.screen != PIDisplay.sessions[PIDisplay.currentSession]) { - } else { - PIDisplay.currentSession += 1; - } - PIDisplay.screen = PIDisplay.sessions[PIDisplay.currentSession]; - } - } - - public boolean canGoForward() { - if (PIDisplay.currentSession <= 0) { // -1 e 0 - return false; - } - if (PIDisplay.screen != PIDisplay.sessions[PIDisplay.currentSession]) { - - } else if (PIDisplay.currentSession > 0) { - if (PIDisplay.sessions[PIDisplay.currentSession - 1] != null) { - - } else { - return false; - } - } else { - return false; - } - if (PIDisplay.sessions[PIDisplay.currentSession] != null) { - return true; - } - return false; - } - - public void goForward() { - if (canGoForward()) { - if (PIDisplay.screen != PIDisplay.sessions[PIDisplay.currentSession]) { - - } else { - PIDisplay.currentSession -= 1; - } - PIDisplay.screen = PIDisplay.sessions[PIDisplay.currentSession]; - } - } - - public Screen getScreen() { - return PIDisplay.screen; - } - - private void load_skin() throws IOException { - BufferedImage img = ImageIO.read(Main.instance.getClass().getResource("/skin.png")); - skin = renderer.getMatrixOfImage(img); - skinSize = new int[] { img.getWidth(), img.getHeight() }; - } - - private void load_fonts() { - fonts = new RAWFont[7]; - fonts[0] = new RAWFont(); - fonts[0].create("big"); - fonts[1] = new RAWFont(); - fonts[1].create("small"); - fonts[2] = new RAWFont(); - fonts[2].create("ex"); - fonts[3] = new RAWFont(); - fonts[3].create("big"); - fonts[4] = new RAWFont(); - fonts[4].create("32"); - fonts[5] = new RAWFont(); - fonts[5].create("square"); - renderer.glSetFont(fonts[0]); - } - - private void draw_init() { - renderer.glClear(); - } - - public static void drawSkinPart(int x, int y, int sx1, int sy1, int sx2, int sy2) { - renderer.glDrawSkin(skinSize[0], skin, x, y, sx1, sy1, sx2, sy2, false); - } - - private void draw_status() { - renderer.glColor(0xFFc5c2af); - renderer.glFillRect(0, 0, Main.screenSize[0], 20); - renderer.glColor3i(0, 0, 0); - renderer.glDrawLine(0, 20, Main.screenSize[0]-1, 20); - renderer.glColor3i(0, 0, 0); - if (Keyboard.shift) { - drawSkinPart(2 + 18 * 0, 2, 16 * 2, 16 * 0, 16 + 16 * 2, 16 + 16 * 0); - } else { - drawSkinPart(2 + 18 * 0, 2, 16 * 3, 16 * 0, 16 + 16 * 3, 16 + 16 * 0); - } - if (Keyboard.alpha) { - drawSkinPart(2 + 18 * 1, 2, 16 * 0, 16 * 0, 16 + 16 * 0, 16 + 16 * 0); - } else { - drawSkinPart(2 + 18 * 1, 2, 16 * 1, 16 * 0, 16 + 16 * 1, 16 + 16 * 0); - } - /* - if (Calculator.angleMode == AngleMode.DEG) { - drawSkinPart(8 + 18 * 2, 2, 16 * 4, 16 * 0, 16 + 16 * 4, 16 + 16 * 0); - drawSkinPart(8 + 18 * 3, 2, 16 * 7, 16 * 0, 16 + 16 * 7, 16 + 16 * 0); - drawSkinPart(8 + 18 * 4, 2, 16 * 9, 16 * 0, 16 + 16 * 9, 16 + 16 * 0); - } else if (Calculator.angleMode == AngleMode.RAD) { - drawSkinPart(8 + 18 * 2, 2, 16 * 5, 16 * 0, 16 + 16 * 5, 16 + 16 * 0); - drawSkinPart(8 + 18 * 3, 2, 16 * 6, 16 * 0, 16 + 16 * 6, 16 + 16 * 0); - drawSkinPart(8 + 18 * 4, 2, 16 * 9, 16 * 0, 16 + 16 * 9, 16 + 16 * 0); - } else if (Calculator.angleMode == AngleMode.GRA) { - drawSkinPart(8 + 18 * 2, 2, 16 * 5, 16 * 0, 16 + 16 * 5, 16 + 16 * 0); - drawSkinPart(8 + 18 * 3, 2, 16 * 7, 16 * 0, 16 + 16 * 7, 16 + 16 * 0); - drawSkinPart(8 + 18 * 4, 2, 16 * 8, 16 * 0, 16 + 16 * 8, 16 + 16 * 0); - } else { - drawSkinPart(8 + 18 * 2, 2, 16 * 5, 16 * 0, 16 + 16 * 5, 16 + 16 * 0); - drawSkinPart(8 + 18 * 3, 2, 16 * 7, 16 * 0, 16 + 16 * 7, 16 + 16 * 0); - drawSkinPart(8 + 18 * 4, 2, 16 * 9, 16 * 0, 16 + 16 * 9, 16 + 16 * 0); - }*/ - - int padding = 2; - - int brightness = (int) (Math.ceil(PIDisplay.brightness * 9)); - if (brightness <= 10) { - drawSkinPart(Main.screenSize[0] - (padding + 16), 2, 16 * brightness, 16 * 1, 16 + 16 * brightness, 16 + 16 * 1); - } else { - Utils.debug.println("Brightness error"); - } - - padding += 18 + 6; - - boolean canGoBack = canGoBack(); - boolean canGoForward = canGoForward(); - - if (Main.haxMode) { - drawSkinPart(Main.screenSize[0] - (padding + 16), 2, 16 * 18, 16 * 0, 16 + 16 * 18, 16 + 16 * 0); - padding += 18 + 6; - } - - if (canGoBack && canGoForward) { - drawSkinPart(Main.screenSize[0] - (padding + 16), 2, 16 * 14, 16 * 0, 16 + 16 * 14, 16 + 16 * 0); - } else if (canGoBack) { - drawSkinPart(Main.screenSize[0] - (padding + 16), 2, 16 * 15, 16 * 0, 16 + 16 * 15, 16 + 16 * 0); - } else if (canGoForward) { - drawSkinPart(Main.screenSize[0] - (padding + 16), 2, 16 * 16, 16 * 0, 16 + 16 * 16, 16 + 16 * 0); - } else { - drawSkinPart(Main.screenSize[0] - (padding + 16), 2, 16 * 17, 16 * 0, 16 + 16 * 17, 16 + 16 * 0); - } - - padding += 18; - - screen.renderStatusbar(); - } - - private void draw_screen() { - screen.render(); - } - - private void draw_bottom() { - renderer.glDrawStringLeft(2, 90, displayDebugString); - } - - private void draw_world() { - renderer.glColor3i(255, 255, 255); - - if (error != null) { - renderer.glSetFont(Utils.getFont(false, false)); - renderer.glColor3i(129, 28, 22); - renderer.glDrawStringRight(Main.screenSize[0] - 2, Main.screenSize[1]- PIDisplay.glyphsHeight[1] - 2, "ANDREA CAVALLI'S CALCULATOR"); - renderer.glColor3i(149, 32, 26); - renderer.glDrawStringCenter((Main.screenSize[0] / 2), 22, error); - renderer.glColor3i(164, 34, 28); - int i = 22; - for (String stackPart : errorStackTrace) { - renderer.glDrawStringLeft(2, 22 + i, stackPart); - i += 11; - } - renderer.glSetFont(fonts[0]); - renderer.glColor3i(129, 28, 22); - renderer.glDrawStringCenter((Main.screenSize[0] / 2), 11, "UNEXPECTED EXCEPTION"); - } else { - draw_screen(); - draw_status(); - draw_bottom(); - } - } - - private void draw() { - draw_init(); - draw_world(); - } - - private long precTime = -1; - - @Override - public void refresh() { - float dt = 0; - long newtime = System.nanoTime(); - if (precTime == -1) { - dt = 0; - } else { - dt = (float) ((newtime - precTime) / 1000000000d); - } - precTime = newtime; - /* - * Calcoli - */ - checkDisplayResized(); - - screen.beforeRender(dt); - - if(dt >= 0.03 || screen.mustBeRefreshed()) { - draw(); - } - - } - - private void checkDisplayResized() { - if (display.wasResized()) { - Main.screenSize[0] = display.getWidth(); - Main.screenSize[1]= display.getHeight(); - } - }; - - public void loop() { - try { - load_skin(); - load_fonts(); - display.create(); - - try { - screen.initialize(); - } catch (Exception e) { - e.printStackTrace(); - System.exit(0); - } - - display.start(this); - - Main.instance.afterStart(); - - double extratime = 0; - while (CPUDisplay.initialized) { - long start = System.currentTimeMillis(); - display.repaint(); - long end = System.currentTimeMillis(); - double delta = (end - start) / 1000d; - int deltaInt = (int) Math.floor(delta); - int extraTimeInt = (int) Math.floor(extratime); - if (extraTimeInt + deltaInt < 50) { - Thread.sleep(50 - (extraTimeInt + deltaInt)); - extratime = 0; - } else { - extratime += delta - 50d; - } - } - } catch (Exception ex) { - ex.printStackTrace(); - } finally { - } - } - - public static void changeBrightness(float change) { - setBrightness(brightness + change); - } - - public static void setBrightness(float newval) { - if (newval >= 0 && newval <= 1) { - brightness = newval; - if (Utils.debugOn == false) { - Gpio.pwmWrite(12, (int) Math.ceil(brightness*1024)); -// SoftPwm.softPwmWrite(12, (int)(Math.ceil(brightness*10))); - } - } - } - - public static void cycleBrightness(boolean reverse) { - final float step = reverse?-0.1f:0.1f; - if (brightness + step > 1f) { - setBrightness(0f); - } else if (brightness + step <= 0f) { - setBrightness(1.0f); - } else { - changeBrightness(step); - } - } - - public static float getBrightness() { - return brightness; - } - - public float[] colore = new float[] { 0.0f, 0.0f, 0.0f, 1.0f }; - public static int currentSession = 0; - public static Screen[] sessions = new Screen[5]; - - public static void colore(float f1, float f2, float f3, float f4) { - PIDisplay.INSTANCE.colore = new float[] { f1, f2, f3, f4 }; - renderer.glColor4i((int) (f1 * 255), (int) (f2 * 255), (int) (f3 * 255), (int) (f4 * 255)); - } - - public static Drawable getDrawable() { - return INSTANCE; - } -} \ No newline at end of file diff --git a/src/org/warp/picalculator/gui/graphicengine/Display.java b/src/org/warp/picalculator/gui/graphicengine/Display.java index efd60ef2..69d73c6f 100644 --- a/src/org/warp/picalculator/gui/graphicengine/Display.java +++ b/src/org/warp/picalculator/gui/graphicengine/Display.java @@ -1,21 +1,21 @@ package org.warp.picalculator.gui.graphicengine; -import java.awt.image.BufferedImage; +import java.io.IOException; public interface Display { public int[] getSize(); - + public boolean isInitialized(); public void setTitle(String title); public void setResizable(boolean r); - + public void setDisplayMode(final int ww, final int wh); - + public void create(); - + public boolean wasResized(); public int getWidth(); @@ -27,6 +27,14 @@ public interface Display { public void start(Drawable d); public void repaint(); - + public Renderer getRenderer(); + + public RAWFont loadFont(String file) throws IOException; + + public RAWSkin loadSkin(String file) throws IOException; + + public void waitUntilExit(); + + public boolean isSupported(); } diff --git a/src/org/warp/picalculator/gui/graphicengine/RAWFont.java b/src/org/warp/picalculator/gui/graphicengine/RAWFont.java index d8477629..d11478b1 100644 --- a/src/org/warp/picalculator/gui/graphicengine/RAWFont.java +++ b/src/org/warp/picalculator/gui/graphicengine/RAWFont.java @@ -1,182 +1,14 @@ package org.warp.picalculator.gui.graphicengine; -import java.awt.image.BufferedImage; -import java.awt.image.DataBufferInt; -import java.io.File; -import java.io.IOException; -import java.lang.ref.WeakReference; -import java.net.URL; -import java.util.logging.Level; -import java.util.logging.Logger; - -import javax.imageio.ImageIO; - -import org.warp.picalculator.Main; -import org.warp.picalculator.Utils; - /** * * @author andreacv */ -public class RAWFont { +public interface RAWFont extends RAWSkin { - public boolean[][] rawchars; - public int[] chars32; - public int minBound = 10; - public int maxBound = 0; - public int charW; - public int charH; - public int charS; - public int charIntCount; - public boolean installed; - public static final int intBits = 31; + public int getStringWidth(String text); - public void create(String name) { - try { - loadFont("/font_"+name+".rft"); - } catch (IOException e) { - e.printStackTrace(); - System.exit(1); - } - chars32 = new int[(maxBound-minBound)*charIntCount]; - for (int charIndex = 0; charIndex < maxBound-minBound; charIndex++) { - boolean[] currentChar = rawchars[charIndex]; - if (currentChar == null) { - int currentInt = 0; - int currentBit = 0; - for (int i = 0; i < charS; i++) { - if (currentInt*intBits+currentBit >= (currentInt+1)*intBits) { - currentInt += 1; - currentBit = 0; - } - chars32[charIndex*charIntCount+currentInt] = (chars32[charIndex*charIntCount+currentInt] << 1) + 1; - currentBit += 1; - } - } else { - int currentInt = 0; - int currentBit = 0; - for (int i = 0; i < charS; i++) { - if (currentBit >= intBits) { - currentInt += 1; - currentBit = 0; - } - chars32[charIndex*charIntCount+currentInt] = (chars32[charIndex*charIntCount+currentInt]) | ((currentChar[i] ? 1 : 0) << currentBit); - currentBit++; - } - } - } - - Object obj = new Object(); - WeakReference ref = new WeakReference<>(obj); - obj = null; - while (ref.get() != null) { - System.gc(); - } - } + public int getCharacterWidth(); - private void loadFont(String string) throws IOException { - URL res = Main.instance.getClass().getResource(string); - int[] file = Utils.realBytes(Utils.convertStreamToByteArray(res.openStream(), res.getFile().length())); - int filelength = file.length; - if (filelength >= 16) { - if (file[0x0] == 114 && file[0x1] == 97 && file[0x2] == 119 && file[0x3] == 0xFF && file[0x8] == 0xFF && file[0xD] == 0xFF) { - charW = file[0x4] << 8 | file[0x5]; - charH = file[0x6] << 8 | file[0x7]; - charS = charW*charH; - charIntCount = (int) Math.ceil(((double)charS)/((double)intBits)); - minBound = file[0x9] << 24 | file[0xA] << 16 | file[0xB] << 8 | file[0xC]; - maxBound = file[0xE] << 24 | file[0xF] << 16 | file[0x10] << 8 | file[0x11]; - if (maxBound <= minBound) { - maxBound = 10000; //TODO remove it: temp fix - } - rawchars = new boolean[maxBound-minBound][]; - int index = 0x12; - while (index < filelength) { - try { - int charIndex = file[index] << 8 | file[index+1]; - boolean[] rawchar = new boolean[charS]; - int charbytescount = 0; - while (charbytescount*8 < charS) { - charbytescount+=1; - } - int currentBit = 0; - for (int i = 0; i <= charbytescount; i++) { - for (int bit = 0; bit < 8; bit++) { - if (currentBit >= charS) { - break; - } - rawchar[currentBit] = (((file[index + 2 + i] >> (8-1-bit)) & 0x1)==1)?true:false; - currentBit++; - } - } - rawchars[charIndex - minBound] = rawchar; - index += 2 + charbytescount; - } - catch (Exception ex) { - ex.printStackTrace(); - System.out.println(string); - System.exit(-1); - } - } - } else { - throw new IOException(); - } - } else { - throw new IOException(); - } - } - - public int[] getCharIndexes(String txt) { - final int l = txt.length(); - int[] indexes = new int[l]; - char[] chars = txt.toCharArray(); - for (int i = 0; i < l; i++) { - indexes[i] = (chars[i] & 0xFFFF)-minBound; - } - return indexes; - } - - @SuppressWarnings("unused") - private void saveArray(int[] screen, String coutputpng) { - BufferedImage bi = new BufferedImage(300, 200, BufferedImage.TYPE_INT_RGB); - final int[] a = ((DataBufferInt) bi.getRaster().getDataBuffer()).getData(); - System.arraycopy(screen, 0, a, 0, screen.length); - try { - ImageIO.write(bi, "PNG", new File(coutputpng)); - } catch (IOException ex) { - Logger.getLogger(RAWFont.class.getName()).log(Level.SEVERE, null, ex); - } - } - - public void drawText(int[] screen, int[] screenSize, int x, int y, int[] text, int color) { - final int screenLength = screen.length; - int screenPos = 0; - - - int currentInt; - int currentIntBitPosition; - int bitData; - int cpos; - int j; - final int l = text.length; - for (int i = 0; i < l; i++) { - cpos = (i * (charW + 1)); - final int charIndex = text[i]; - for (int dy = 0; dy < charH; dy++) { - for (int dx = 0; dx < charW; dx++) { - j = x + cpos + dx; - if (j > 0 & j < screenSize[0]) { - int bit = dx + dy * charW; - currentInt = (int) (Math.floor(bit)/(intBits)); - currentIntBitPosition = bit-(currentInt*intBits); - bitData = (chars32[charIndex*charIntCount+currentInt] >> currentIntBitPosition) & 1; - screenPos = x + cpos + dx + (y + dy) * screenSize[0]; - if (bitData == 1 & screenLength > screenPos) { - screen[screenPos] = color; - } - } - } - } - } - } + public int getCharacterHeight(); } diff --git a/src/org/warp/picalculator/gui/graphicengine/RAWSkin.java b/src/org/warp/picalculator/gui/graphicengine/RAWSkin.java new file mode 100644 index 00000000..357a85e8 --- /dev/null +++ b/src/org/warp/picalculator/gui/graphicengine/RAWSkin.java @@ -0,0 +1,12 @@ +package org.warp.picalculator.gui.graphicengine; + +import java.io.IOException; + +public interface RAWSkin { + + public void load(String file) throws IOException; + + public void initialize(Display d); + + public void use(Display d); +} diff --git a/src/org/warp/picalculator/gui/graphicengine/Renderer.java b/src/org/warp/picalculator/gui/graphicengine/Renderer.java index aa369fc0..18ecfb99 100644 --- a/src/org/warp/picalculator/gui/graphicengine/Renderer.java +++ b/src/org/warp/picalculator/gui/graphicengine/Renderer.java @@ -1,43 +1,41 @@ package org.warp.picalculator.gui.graphicengine; import java.awt.FontMetrics; -import java.awt.image.BufferedImage; public interface Renderer { public void glColor3i(int r, int gg, int b); public void glColor(int c); + public void glColor4i(int red, int green, int blue, int alpha); + + public void glColor3f(float red, float green, float blue); + + public void glColor4f(float red, float green, float blue, float alpha); + + public void glClearColor4i(int red, int green, int blue, int alpha); + + public void glClearColor4f(float red, float green, float blue, float alpha); + public int glGetClearColor(); public void glClearColor(int c); - public void glColor4i(int red, int green, int blue, int alpha); - - public void glClearColor(int red, int green, int blue, int alpha); - - public void glClear(); - - public void glDrawSkin(int skinwidth, int[] skin, int x0, int y0, int s0, int t0, int s1, int t1, boolean transparent); + public void glClear(int screenWidth, int screenHeight); public void glDrawLine(int x0, int y0, int x1, int y1); - public void glFillRect(int x0, int y0, int w1, int h1); + public void glFillRect(int x, int y, int width, int height, float uvX, float uvY, float uvWidth, float uvHeight); - @Deprecated - public int[] getMatrixOfImage(BufferedImage bufferedImage); + public void glFillColor(int x, int y, int width, int height); public void glDrawStringLeft(int x, int y, String text); public void glDrawStringCenter(int x, int y, String text); public void glDrawStringRight(int x, int y, String text); - - public void glSetFont(RAWFont font); - - public int glGetStringWidth(RAWFont rf, String text); - - public int glGetFontWidth(FontMetrics fm, String text); + + public void glClearSkin(); public RAWFont getCurrentFont(); } \ No newline at end of file diff --git a/src/org/warp/picalculator/gui/graphicengine/cpu/CPUDisplay.java b/src/org/warp/picalculator/gui/graphicengine/cpu/CPUDisplay.java index 28991ff3..c4aa5210 100644 --- a/src/org/warp/picalculator/gui/graphicengine/cpu/CPUDisplay.java +++ b/src/org/warp/picalculator/gui/graphicengine/cpu/CPUDisplay.java @@ -1,35 +1,43 @@ package org.warp.picalculator.gui.graphicengine.cpu; import java.awt.FontMetrics; +import java.awt.GraphicsEnvironment; import java.awt.image.BufferedImage; +import java.io.IOException; import org.warp.picalculator.Main; import org.warp.picalculator.Utils; -import org.warp.picalculator.gui.PIDisplay; +import org.warp.picalculator.gui.DisplayManager; import org.warp.picalculator.gui.graphicengine.Display; import org.warp.picalculator.gui.graphicengine.Drawable; import org.warp.picalculator.gui.graphicengine.RAWFont; +import org.warp.picalculator.gui.graphicengine.RAWSkin; import org.warp.picalculator.gui.graphicengine.Renderer; public class CPUDisplay implements Display { - private static SwingWindow INSTANCE; - public static int[] size = new int[] { 1, 1 }; - public static BufferedImage g = new BufferedImage(size[0], size[1], BufferedImage.TYPE_INT_RGB); + private SwingWindow INSTANCE; + public int[] size = new int[] { 1, 1 }; + public BufferedImage g = new BufferedImage(size[0], size[1], BufferedImage.TYPE_INT_RGB); static int[] canvas2d = new int[1]; - public static int color = 0xFF000000; - public static boolean initialized = false; + public int color = 0xFF000000; + public volatile boolean initialized = false; + private final CPURenderer r = new CPURenderer(); + @Override public void setTitle(String title) { INSTANCE.setTitle(title); } + @Override public void setResizable(boolean r) { INSTANCE.setResizable(r); - if (!r) + if (!r) { INSTANCE.setUndecorated(true); + } } + @Override public void setDisplayMode(final int ww, final int wh) { INSTANCE.setSize(ww, wh); size = new int[] { ww, wh }; @@ -38,14 +46,16 @@ public class CPUDisplay implements Display { INSTANCE.wasResized = false; } + @Override public void create() { - INSTANCE = new SwingWindow(PIDisplay.getDrawable()); - setResizable(Utils.debugOn&!Utils.debugThirdScreen); + INSTANCE = new SwingWindow(this, DisplayManager.getDrawable()); + setResizable(Utils.debugOn & !Utils.debugThirdScreen); setDisplayMode(Main.screenSize[0], Main.screenSize[1]); INSTANCE.setVisible(true); initialized = true; } - + + @Override public boolean wasResized() { if (INSTANCE.wasResized) { size = new int[] { INSTANCE.getWidth(), INSTANCE.getHeight() }; @@ -57,37 +67,66 @@ public class CPUDisplay implements Display { return false; } + @Override public int getWidth() { - return INSTANCE.getWidth()-Main.screenPos[0]; + return INSTANCE.getWidth() - Main.screenPos[0]; } + @Override public int getHeight() { - return INSTANCE.getHeight()-Main.screenPos[1]; + return INSTANCE.getHeight() - Main.screenPos[1]; } + @Override public void destroy() { initialized = false; INSTANCE.setVisible(false); INSTANCE.dispose(); } + @Override public void start(Drawable d) { + Thread th = new Thread(() -> { + try { + double extratime = 0; + while (initialized) { + final long start = System.currentTimeMillis(); + repaint(); + final long end = System.currentTimeMillis(); + final double delta = (end - start) / 1000d; + final int deltaInt = (int) Math.floor(delta); + final int extraTimeInt = (int) Math.floor(extratime); + if (extraTimeInt + deltaInt < 50) { + Thread.sleep(50 - (extraTimeInt + deltaInt)); + extratime = 0; + } else { + extratime += delta - 50d; + } + } + } catch (final InterruptedException e) { + e.printStackTrace(); + } + }); + th.setName("Game loop thread"); + th.setDaemon(true); + th.start(); } @Deprecated() public void refresh() { - if (PIDisplay.screen == null || (PIDisplay.error != null && PIDisplay.error.length() > 0) || PIDisplay.screen == null || PIDisplay.screen.mustBeRefreshed()) { - CPUDisplay.INSTANCE.c.repaint(); + if (DisplayManager.screen == null || (DisplayManager.error != null && DisplayManager.error.length() > 0) || DisplayManager.screen == null || DisplayManager.screen.mustBeRefreshed()) { + INSTANCE.c.repaint(); } } + @Override public void repaint() { - CPUDisplay.INSTANCE.c.repaint(); + INSTANCE.c.repaint(); } public abstract class Startable { public Startable() { - this.force = false; + force = false; } public Startable(boolean force) { @@ -99,58 +138,70 @@ public class CPUDisplay implements Display { public abstract void run(); } - public class Render implements Renderer { + public class CPURenderer implements Renderer { public int clearcolor = 0xFFc5c2af; - public RAWFont currentFont; + public CPUFont currentFont; + public CPUSkin currentSkin; + @Override public void glColor3i(int r, int gg, int b) { glColor4i(r, gg, b, 255); } + @Override public void glColor(int c) { color = c & 0xFFFFFFFF; } + @Override public void glClearColor(int c) { clearcolor = c & 0xFFFFFFFF; } + @Override public void glColor4i(int red, int green, int blue, int alpha) { color = (alpha << 24) + (red << 16) + (green << 8) + (blue); } - public void glClearColor(int red, int green, int blue, int alpha) { + @Override + public void glClearColor4i(int red, int green, int blue, int alpha) { clearcolor = (alpha << 24) + (red << 16) + (green << 8) + (blue); } - public void glClear() { - for (int x = 0; x < size[0]; x++) { - for (int y = 0; y < size[1]; y++) { + @Override + public void glClearColor4f(float red, float green, float blue, float alpha) { + clearcolor = ((int)(alpha*255) << 24) + ((int)(red*255) << 16) + ((int)(green*255) << 8) + ((int)(blue*255)); + } + + @Override + public void glClear(int screenWidth, int screenHeight) { + for (int x = 0; x < screenWidth; x++) { + for (int y = 0; y < screenHeight; y++) { canvas2d[x + y * size[0]] = clearcolor; } } } - public void glDrawSkin(int skinwidth, int[] skin, int x0, int y0, int s0, int t0, int s1, int t1, boolean transparent) { - x0+=Main.screenPos[0]; - y0+=Main.screenPos[1]; + private void glDrawSkin(int x0, int y0, int s0, int t0, int s1, int t1, boolean transparent) { + x0 += Main.screenPos[0]; + y0 += Main.screenPos[1]; int oldColor; int newColor; - int onex = s0 <= s1?1:-1; - int oney = t0 <= t1?1:-1; + final int onex = s0 <= s1 ? 1 : -1; + final int oney = t0 <= t1 ? 1 : -1; int width = 0; int height = 0; if (onex == -1) { - int s00 = s0; + final int s00 = s0; s0 = s1; s1 = s00; - width = s1-s0; + width = s1 - s0; } if (oney == -1) { - int t00 = t0; + final int t00 = t0; t0 = t1; t1 = t00; - height = t1-t0; + height = t1 - t0; } if (x0 >= size[0] || y0 >= size[0]) { return; @@ -179,28 +230,35 @@ public class CPUDisplay implements Display { } y0 = 0; } + int pixelX; + int pixelY; for (int texx = 0; texx < s1 - s0; texx++) { for (int texy = 0; texy < t1 - t0; texy++) { - newColor = skin[(s0 + texx) + (t0 + texy) * skinwidth]; - if (transparent) { - oldColor = canvas2d[(x0 + texx*onex + width) + (y0 + texy*oney + height) * size[0]]; - float a2 = (newColor >> 24 & 0xFF) / 255f; - float a1 = 1f-a2; - int r = (int) ((oldColor >> 16 & 0xFF) * a1 + (newColor >> 16 & 0xFF) * a2); - int g = (int) ((oldColor >> 8 & 0xFF) * a1 + (newColor >> 8 & 0xFF) * a2); - int b = (int) ((oldColor & 0xFF) * a1 + (newColor & 0xFF) * a2); - newColor = 0xFF000000 | r << 16 | g << 8 | b; + pixelX = (x0 + texx * onex + width); + pixelY = (y0 + texy * oney + height); + if (pixelX - (pixelX % size[0]) == 0) { + newColor = currentSkin.skinData[(s0 + texx) + (t0 + texy) * currentSkin.skinSize[0]]; + if (transparent) { + oldColor = canvas2d[pixelX + pixelY * size[0]]; + final float a2 = (newColor >> 24 & 0xFF) / 255f; + final float a1 = 1f - a2; + final int r = (int) ((oldColor >> 16 & 0xFF) * a1 + (newColor >> 16 & 0xFF) * a2); + final int g = (int) ((oldColor >> 8 & 0xFF) * a1 + (newColor >> 8 & 0xFF) * a2); + final int b = (int) ((oldColor & 0xFF) * a1 + (newColor & 0xFF) * a2); + newColor = 0xFF000000 | r << 16 | g << 8 | b; + } + canvas2d[pixelX + pixelY * size[0]] = newColor; } - canvas2d[(x0 + texx*onex + width) + (y0 + texy*oney + height) * size[0]] = newColor; } } } + @Override public void glDrawLine(int x0, int y0, int x1, int y1) { - x0+=Main.screenPos[0]; - x1+=Main.screenPos[0]; - y0+=Main.screenPos[1]; - y1+=Main.screenPos[1]; + x0 += Main.screenPos[0]; + x1 += Main.screenPos[0]; + y0 += Main.screenPos[1]; + y1 += Main.screenPos[1]; if (x0 >= size[0] || y0 >= size[0]) { return; } @@ -213,7 +271,7 @@ public class CPUDisplay implements Display { canvas2d[x0 + (y0 + y) * size[0]] = color; } } else { - int m = (y1 - y0) / (x1 - x0); + final int m = (y1 - y0) / (x1 - x0); for (int texx = 0; texx <= x1 - x0; texx++) { if (x0 + texx < size[0] && y0 + (m * texx) < size[1]) { canvas2d[(x0 + texx) + (y0 + (m * texx)) * size[0]] = color; @@ -222,12 +280,23 @@ public class CPUDisplay implements Display { } } - public void glFillRect(int x0, int y0, int w1, int h1) { - x0+=Main.screenPos[0]; - y0+=Main.screenPos[1]; - int x1 = x0+w1; - int y1 = y0+h1; - if (x0 >= size[0] || y0 >= size[0]) { + @Override + public void glFillRect(int x, int y, int width, int height, float uvX, float uvY, float uvWidth, + float uvHeight) { + if (currentSkin != null) { + glDrawSkin(x, y, (int) uvX, (int) uvY, (int) (uvWidth + uvX), (int) (uvHeight + uvY), true); + } else { + glFillColor(x, y, width, height); + } + } + + @Override + public void glFillColor(int x, int y, int width, int height) { + x += Main.screenPos[0]; + y += Main.screenPos[1]; + int x1 = x + width; + int y1 = y + height; + if (x >= size[0] || y >= size[0]) { return; } if (x1 >= size[0]) { @@ -237,57 +306,62 @@ public class CPUDisplay implements Display { y1 = size[1]; } final int sizeW = size[0]; - for (int x = x0; x < x1; x++) { - for (int y = y0; y < y1; y++) { - canvas2d[(x) + (y) * sizeW] = color; + for (int px = x; px < x1; px++) { + for (int py = y; py < y1; py++) { + canvas2d[(px) + (py) * sizeW] = color; } } } - public int[] getMatrixOfImage(BufferedImage bufferedImage) { - int width = bufferedImage.getWidth(null); - int height = bufferedImage.getHeight(null); - int[] pixels = new int[width * height]; - for (int i = 0; i < width; i++) { - for (int j = 0; j < height; j++) { - pixels[i + j * width] = bufferedImage.getRGB(i, j); + @Override + public void glDrawStringLeft(int x, int y, String textString) { + x += Main.screenPos[0]; + y += Main.screenPos[1]; + + final int[] text = currentFont.getCharIndexes(textString); + final int[] screen = canvas2d; + final int[] screenSize = size; + final int screenLength = screen.length; + int screenPos = 0; + + int currentInt; + int currentIntBitPosition; + int bitData; + int cpos; + int j; + final int l = text.length; + for (int i = 0; i < l; i++) { + cpos = (i * (currentFont.charW + 1)); + final int charIndex = text[i]; + for (int dy = 0; dy < currentFont.charH; dy++) { + for (int dx = 0; dx < currentFont.charW; dx++) { + j = x + cpos + dx; + if (j > 0 & j < screenSize[0]) { + final int bit = dx + dy * currentFont.charW; + currentInt = (int) (Math.floor(bit) / (CPUFont.intBits)); + currentIntBitPosition = bit - (currentInt * CPUFont.intBits); + bitData = (currentFont.chars32[charIndex * currentFont.charIntCount + currentInt] >> currentIntBitPosition) & 1; + screenPos = x + cpos + dx + (y + dy) * screenSize[0]; + if (bitData == 1 & screenLength > screenPos) { + screen[screenPos] = color; + } + } + } } } - - return pixels; - } - - public void glDrawStringLeft(int x, int y, String text) { - x+=Main.screenPos[0]; - y+=Main.screenPos[1]; - final int[] chars = currentFont.getCharIndexes(text); - currentFont.drawText(canvas2d, size, x, y, chars, color); } + @Override public void glDrawStringCenter(int x, int y, String text) { - glDrawStringLeft(x - (glGetStringWidth(currentFont, text) / 2), y, text); + glDrawStringLeft(x - (currentFont.getStringWidth(text) / 2), y, text); } + @Override public void glDrawStringRight(int x, int y, String text) { - glDrawStringLeft(x - glGetStringWidth(currentFont, text), y, text); - } - - public void glSetFont(RAWFont font) { - if (currentFont != font) { - currentFont = font; - } - } - - public int glGetStringWidth(RAWFont rf, String text) { - int w =(rf.charW+1)*text.length(); - if (text.length() > 0) { - return w-1; - } else { - return 0; - } - // return text.length()*6; + glDrawStringLeft(x - currentFont.getStringWidth(text), y, text); } + @Deprecated public int glGetFontWidth(FontMetrics fm, String text) { return fm.stringWidth(text); } @@ -307,8 +381,23 @@ public class CPUDisplay implements Display { return currentFont; } + @Override + public void glColor3f(float red, float green, float blue) { + glColor3i((int) (red * 255f), (int) (green * 255f), (int) (blue * 255f)); + } + + @Override + public void glColor4f(float red, float green, float blue, float alpha) { + glColor4i((int) (red * 255f), (int) (green * 255f), (int) (blue * 255f), (int) (alpha * 255f)); + } + + @Override + public void glClearSkin() { + currentSkin = null; + } + } - + @Override public int[] getSize() { return size; @@ -320,7 +409,33 @@ public class CPUDisplay implements Display { } @Override - public Renderer getRenderer() { - return new Render(); + public CPURenderer getRenderer() { + return r; + } + + @Override + public RAWFont loadFont(String file) throws IOException { + return new CPUFont(file); + } + + @Override + public RAWSkin loadSkin(String file) throws IOException { + return new CPUSkin(file); + } + + @Override + public void waitUntilExit() { + try { + do { + Thread.sleep(500); + } while(initialized); + } catch (InterruptedException e) { + + } + } + + @Override + public boolean isSupported() { + return GraphicsEnvironment.isHeadless() == false; } } diff --git a/src/org/warp/picalculator/gui/graphicengine/cpu/CPUFont.java b/src/org/warp/picalculator/gui/graphicengine/cpu/CPUFont.java new file mode 100644 index 00000000..b70debf0 --- /dev/null +++ b/src/org/warp/picalculator/gui/graphicengine/cpu/CPUFont.java @@ -0,0 +1,182 @@ +package org.warp.picalculator.gui.graphicengine.cpu; + +import java.awt.image.BufferedImage; +import java.awt.image.DataBufferInt; +import java.io.File; +import java.io.IOException; +import java.lang.ref.WeakReference; +import java.net.URL; +import java.util.logging.Level; +import java.util.logging.Logger; + +import javax.imageio.ImageIO; + +import org.warp.picalculator.Utils; +import org.warp.picalculator.gui.graphicengine.Display; +import org.warp.picalculator.gui.graphicengine.RAWFont; +import org.warp.picalculator.gui.graphicengine.cpu.CPUDisplay.CPURenderer; + +public class CPUFont implements RAWFont { + + public boolean[][] rawchars; + public int[] chars32; + public int minBound = 10; + public int maxBound = 0; + public int charW; + public int charH; + public int charS; + public int charIntCount; + public static final int intBits = 31; + + CPUFont(String file) throws IOException { + load(file); + } + + public static CPUFont loadTemporaryFont(String name) throws IOException { + return new CPUFont(name); + } + + @Override + public void load(String name) throws IOException { + loadFont("/font_" + name + ".rft"); + chars32 = new int[(maxBound - minBound) * charIntCount]; + for (int charIndex = 0; charIndex < maxBound - minBound; charIndex++) { + final boolean[] currentChar = rawchars[charIndex]; + if (currentChar == null) { + int currentInt = 0; + int currentBit = 0; + for (int i = 0; i < charS; i++) { + if (currentInt * intBits + currentBit >= (currentInt + 1) * intBits) { + currentInt += 1; + currentBit = 0; + } + chars32[charIndex * charIntCount + currentInt] = (chars32[charIndex * charIntCount + currentInt] << 1) + 1; + currentBit += 1; + } + } else { + int currentInt = 0; + int currentBit = 0; + for (int i = 0; i < charS; i++) { + if (currentBit >= intBits) { + currentInt += 1; + currentBit = 0; + } + chars32[charIndex * charIntCount + currentInt] = (chars32[charIndex * charIntCount + currentInt]) | ((currentChar[i] ? 1 : 0) << currentBit); + currentBit++; + } + } + } + + Object obj = new Object(); + final WeakReference ref = new WeakReference<>(obj); + obj = null; + while (ref.get() != null) { + System.gc(); + } + } + + private void loadFont(String string) throws IOException { + final URL res = this.getClass().getResource(string); + final int[] file = Utils.realBytes(Utils.convertStreamToByteArray(res.openStream(), res.getFile().length())); + final int filelength = file.length; + if (filelength >= 16) { + if (file[0x0] == 114 && file[0x1] == 97 && file[0x2] == 119 && file[0x3] == 0xFF && file[0x8] == 0xFF && file[0xD] == 0xFF) { + charW = file[0x4] << 8 | file[0x5]; + charH = file[0x6] << 8 | file[0x7]; + charS = charW * charH; + charIntCount = (int) Math.ceil(((double) charS) / ((double) intBits)); + minBound = file[0x9] << 24 | file[0xA] << 16 | file[0xB] << 8 | file[0xC]; + maxBound = file[0xE] << 24 | file[0xF] << 16 | file[0x10] << 8 | file[0x11]; + if (maxBound <= minBound) { + maxBound = 9900; //TODO remove it: temp fix + } + rawchars = new boolean[maxBound - minBound][]; + int index = 0x12; + while (index < filelength) { + try { + final int charIndex = file[index] << 8 | file[index + 1]; + final boolean[] rawchar = new boolean[charS]; + int charbytescount = 0; + while (charbytescount * 8 < charS) { + charbytescount += 1; + } + int currentBit = 0; + for (int i = 0; i <= charbytescount; i++) { + for (int bit = 0; bit < 8; bit++) { + if (currentBit >= charS) { + break; + } + rawchar[currentBit] = (((file[index + 2 + i] >> (8 - 1 - bit)) & 0x1) == 1) ? true : false; + currentBit++; + } + } + rawchars[charIndex - minBound] = rawchar; + index += 2 + charbytescount; + } catch (final Exception ex) { + ex.printStackTrace(); + System.out.println(string); + System.exit(-1); + } + } + } else { + throw new IOException(); + } + } else { + throw new IOException(); + } + } + + @SuppressWarnings("unused") + private void saveArray(int[] screen, String coutputpng) { + final BufferedImage bi = new BufferedImage(300, 200, BufferedImage.TYPE_INT_RGB); + final int[] a = ((DataBufferInt) bi.getRaster().getDataBuffer()).getData(); + System.arraycopy(screen, 0, a, 0, screen.length); + try { + ImageIO.write(bi, "PNG", new File(coutputpng)); + } catch (final IOException ex) { + Logger.getLogger(RAWFont.class.getName()).log(Level.SEVERE, null, ex); + } + } + + public int[] getCharIndexes(String txt) { + final int l = txt.length(); + final int[] indexes = new int[l]; + final char[] chars = txt.toCharArray(); + for (int i = 0; i < l; i++) { + indexes[i] = (chars[i] & 0xFFFF) - minBound; + } + return indexes; + } + + @Override + public void initialize(Display d) { + // TODO Auto-generated method stub + + } + + @Override + public void use(Display d) { + ((CPURenderer) d.getRenderer()).currentFont = this; + } + + @Override + public int getStringWidth(String text) { + final int w = (charW + 1) * text.length(); + if (text.length() > 0) { + return w - 1; + } else { + return 0; + } + } + + @Override + public int getCharacterWidth() { + return charW; + } + + @Override + public int getCharacterHeight() { + return charH; + } + +} diff --git a/src/org/warp/picalculator/gui/graphicengine/cpu/CPUSkin.java b/src/org/warp/picalculator/gui/graphicengine/cpu/CPUSkin.java new file mode 100644 index 00000000..711f3482 --- /dev/null +++ b/src/org/warp/picalculator/gui/graphicengine/cpu/CPUSkin.java @@ -0,0 +1,53 @@ +package org.warp.picalculator.gui.graphicengine.cpu; + +import java.awt.image.BufferedImage; +import java.io.IOException; + +import javax.imageio.ImageIO; + +import org.warp.picalculator.Main; +import org.warp.picalculator.gui.graphicengine.Display; +import org.warp.picalculator.gui.graphicengine.RAWSkin; +import org.warp.picalculator.gui.graphicengine.cpu.CPUDisplay.CPURenderer; + +public class CPUSkin implements RAWSkin { + + public int[] skinData; + public int[] skinSize; + + CPUSkin(String file) throws IOException { + load(file); + } + + @Override + public void load(String file) throws IOException { + final BufferedImage img = ImageIO.read(Main.instance.getClass().getResource("/"+file)); + skinData = getMatrixOfImage(img); + skinSize = new int[] { img.getWidth(), img.getHeight() }; + } + + public static int[] getMatrixOfImage(BufferedImage bufferedImage) { + final int width = bufferedImage.getWidth(null); + final int height = bufferedImage.getHeight(null); + final int[] pixels = new int[width * height]; + for (int i = 0; i < width; i++) { + for (int j = 0; j < height; j++) { + pixels[i + j * width] = bufferedImage.getRGB(i, j); + } + } + + return pixels; + } + + @Override + public void initialize(Display d) { + // TODO Auto-generated method stub + + } + + @Override + public void use(Display d) { + ((CPURenderer) d.getRenderer()).currentSkin = this; + } + +} diff --git a/src/org/warp/picalculator/gui/graphicengine/cpu/SwingWindow.java b/src/org/warp/picalculator/gui/graphicengine/cpu/SwingWindow.java index 38a89201..bea8ae12 100644 --- a/src/org/warp/picalculator/gui/graphicengine/cpu/SwingWindow.java +++ b/src/org/warp/picalculator/gui/graphicengine/cpu/SwingWindow.java @@ -18,7 +18,7 @@ import javax.swing.JPanel; import org.warp.picalculator.Utils; import org.warp.picalculator.device.Keyboard; import org.warp.picalculator.device.Keyboard.Key; -import org.warp.picalculator.gui.PIDisplay; +import org.warp.picalculator.gui.DisplayManager; import org.warp.picalculator.gui.graphicengine.Drawable; public class SwingWindow extends JFrame { @@ -26,40 +26,41 @@ public class SwingWindow extends JFrame { public CustomCanvas c; private static Drawable d; public boolean wasResized = false; + private final CPUDisplay display; - public SwingWindow(Drawable d) { + public SwingWindow(CPUDisplay disp, Drawable d) { SwingWindow.d = d; + display = disp; c = new CustomCanvas(); c.setDoubleBuffered(false); this.add(c); // this.setExtendedState(Frame.MAXIMIZED_BOTH); Toolkit.getDefaultToolkit().setDynamicLayout(false); // Transparent 16 x 16 pixel cursor image. - BufferedImage cursorImg = new BufferedImage(16, 16, BufferedImage.TYPE_INT_ARGB); - + final BufferedImage cursorImg = new BufferedImage(16, 16, BufferedImage.TYPE_INT_ARGB); + if (Utils.debugOn) { if (Utils.debugThirdScreen) { this.setLocation(2880, 900); - this.setResizable(false); - this.setAlwaysOnTop(true); + setResizable(false); + setAlwaysOnTop(true); } } else { // Create a new blank cursor. - Cursor blankCursor = Toolkit.getDefaultToolkit().createCustomCursor(cursorImg, new Point(0, 0), "blank cursor"); + final Cursor blankCursor = Toolkit.getDefaultToolkit().createCustomCursor(cursorImg, new Point(0, 0), "blank cursor"); // Set the blank cursor to the JFrame. getContentPane().setCursor(blankCursor); - - this.setResizable(false); + + setResizable(false); } - - this.setTitle("Raspberry PI Calculator by XDrake99 (Andrea Cavalli)"); - - - this.addComponentListener(new ComponentListener() { + + setTitle("Raspberry PI Calculator by XDrake99 (Andrea Cavalli)"); + + addComponentListener(new ComponentListener() { @Override public void componentHidden(ComponentEvent e) { - PIDisplay.display.destroy(); + DisplayManager.display.destroy(); } @Override @@ -73,10 +74,10 @@ public class SwingWindow extends JFrame { @Override public void componentShown(ComponentEvent e) {} }); - this.addKeyListener(new KeyListener() { + addKeyListener(new KeyListener() { @Override public void keyPressed(KeyEvent arg0) { - Keyboard.debugKeyEvent = arg0; + Keyboard.debugKeyCode = arg0.getKeyCode(); } @Override @@ -125,7 +126,7 @@ public class SwingWindow extends JFrame { } int row = 2; int col = 1; - Keyboard.debugKeysDown[row-1][col-1] = false; + Keyboard.debugKeysDown[row - 1][col - 1] = false; break; case KeyEvent.VK_1: if (!Keyboard.shift && !Keyboard.alpha) { @@ -175,12 +176,12 @@ public class SwingWindow extends JFrame { //LEFT row = 2; col = 3; - Keyboard.debugKeysDown[row-1][col-1] = false; + Keyboard.debugKeysDown[row - 1][col - 1] = false; case KeyEvent.VK_RIGHT: //RIGHT row = 2; col = 5; - Keyboard.debugKeysDown[row-1][col-1] = false; + Keyboard.debugKeysDown[row - 1][col - 1] = false; } } @@ -216,7 +217,7 @@ public class SwingWindow extends JFrame { // private static ArrayList mediaValori = new ArrayList(); - public static class CustomCanvas extends JPanel { + public class CustomCanvas extends JPanel { /** * @@ -228,11 +229,11 @@ public class SwingWindow extends JFrame { // long time1 = System.nanoTime(); d.refresh(); - final int[] a = ((DataBufferInt) CPUDisplay.g.getRaster().getDataBuffer()).getData(); + final int[] a = ((DataBufferInt) display.g.getRaster().getDataBuffer()).getData(); // System.arraycopy(canvas2d, 0, a, 0, canvas2d.length); - CPUDisplay.canvas2d = a; - g.clearRect(0, 0, CPUDisplay.size[0], CPUDisplay.size[1]); - g.drawImage(CPUDisplay.g, 0, 0, null); + CPUDisplay.canvas2d = a; + g.clearRect(0, 0, display.size[0], display.size[1]); + g.drawImage(display.g, 0, 0, null); // long time2 = System.nanoTime(); // double timeDelta = ((double)(time2-time1))/1000000000d; // double mediaAttuale = timeDelta; diff --git a/src/org/warp/picalculator/gui/graphicengine/gpu/CalculatorWindow.java b/src/org/warp/picalculator/gui/graphicengine/gpu/CalculatorWindow.java deleted file mode 100644 index 2aaa4b6f..00000000 --- a/src/org/warp/picalculator/gui/graphicengine/gpu/CalculatorWindow.java +++ /dev/null @@ -1,673 +0,0 @@ -/** - * Copyright 2012-2013 JogAmp Community. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, are - * permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this list of - * conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, this list - * of conditions and the following disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND - * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * The views and conclusions contained in the software and documentation are those of the - * authors and should not be interpreted as representing official policies, either expressed - * or implied, of JogAmp Community. - */ - -package org.warp.picalculator.gui.graphicengine.gpu; - -import com.jogamp.opengl.GL; -import com.jogamp.opengl.GL2ES1; -import com.jogamp.opengl.GL2ES2; -import com.jogamp.opengl.GLAutoDrawable; -import com.jogamp.opengl.GLEventListener; -import com.jogamp.opengl.GLException; -import com.jogamp.opengl.GLProfile; -import com.jogamp.opengl.GLCapabilities; -import com.jogamp.newt.opengl.GLWindow; - -import com.jogamp.opengl.util.*; -import com.jogamp.opengl.util.texture.Texture; -import com.jogamp.opengl.util.texture.TextureIO; -import com.jogamp.common.nio.Buffers; - -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.nio.FloatBuffer; - -import javax.imageio.ImageIO; - -import org.warp.picalculator.gui.graphicengine.Display; - -/** - *
- *   __ __|_  ___________________________________________________________________________  ___|__ __
- *  //    /\                                           _                                  /\    \\
- * //____/  \__     __ _____ _____ _____ _____ _____  | |     __ _____ _____ __        __/  \____\\
- *  \    \  / /  __|  |     |   __|  _  |     |  _  | | |  __|  |     |   __|  |      /\ \  /    /
- *   \____\/_/  |  |  |  |  |  |  |     | | | |   __| | | |  |  |  |  |  |  |  |__   "  \_\/____/
- *  /\    \     |_____|_____|_____|__|__|_|_|_|__|    | | |_____|_____|_____|_____|  _  /    /\
- * /  \____\                       http://jogamp.org  |_|                              /____/  \
- * \  /   "' _________________________________________________________________________ `"   \  /
- *  \/____.                                                                             .____\/
- * 
- * - *

- * JOGL2 OpenGL ES 2 demo to expose and learn what the RAW OpenGL ES 2 API looks like. - * - * Compile, run and enjoy: - wget http://jogamp.org/deployment/jogamp-current/archive/jogamp-all-platforms.7z - 7z x jogamp-all-platforms.7z - cd jogamp-all-platforms - mkdir -p demos/es2 - cd demos/es2 - wget https://raw.github.com/xranby/jogl-demos/master/src/demos/es2/RawGL2ES2demo.java - cd ../.. - javac -cp jar/jogl-all.jar:jar/gluegen-rt.jar demos/es2/RawGL2ES2demo.java - java -cp jar/jogl-all.jar:jar/gluegen-rt.jar:. demos.es2.RawGL2ES2demo - *

- * - * - * @author Xerxes Rånby (xranby) - */ - -public class CalculatorWindow implements GLEventListener{ - -/* Introducing the OpenGL ES 2 Vertex shader - * - * The main loop inside the vertex shader gets executed - * one time for each vertex. - * - * vertex -> * uniform data -> mat4 projection = ( 1, 0, 0, 0, - * (0,1,0) / \ 0, 1, 0, 0, - * / . \ <- origo (0,0,0) 0, 0, 1, 0, - * / \ 0, 0,-1, 1 ); - * vertex -> *-------* <- vertex - * (-1,-1,0) (1,-1,0) <- attribute data can be used - * (0, 0,1) for color, position, normals etc. - * - * The vertex shader recive input data in form of - * "uniform" data that are common to all vertex - * and - * "attribute" data that are individual to each vertex. - * One vertex can have several "attribute" data sources enabled. - * - * The vertex shader produce output used by the fragment shader. - * gl_Position are expected to get set to the final vertex position. - * You can also send additional user defined - * "varying" data to the fragment shader. - * - * Model Translate, Scale and Rotate are done here by matrix-multiplying a - * projection matrix against each vertex position. - * - * The whole vertex shader program are a String containing GLSL ES language - * http://www.khronos.org/registry/gles/specs/2.0/GLSL_ES_Specification_1.0.17.pdf - * sent to the GPU driver for compilation. - */ -private String vertexShaderString = -// For GLSL 1 and 1.1 code i highly recomend to not include a -// GLSL ES language #version line, GLSL ES section 3.4 -// Many GPU drivers refuse to compile the shader if #version is different from -// the drivers internal GLSL version. -// -// This demo use GLSL version 1.1 (the implicit version) - -"#if __VERSION__ >= 130\n" + // GLSL 130+ uses in and out -" #define attribute in\n" + // instead of attribute and varying -" #define varying out\n" + // used by OpenGL 3 core and later. -"#endif\n" + - -"#ifdef GL_ES \n" + -"precision mediump float; \n" + // Precision Qualifiers -"precision mediump int; \n" + // GLSL ES section 4.5.2 -"#endif \n" + - -"uniform mat4 uniform_Projection; \n" + // Incomming data used by -"attribute vec4 attribute_Position; \n" + // the vertex shader -"attribute vec4 attribute_Color; \n" + // uniform and attributes -"attribute vec2 a_TexCoordinate; \n" + - -"varying vec2 v_TexCoordinate; \n" + -"varying vec4 varying_Color; \n" + // Outgoing varying data - // sent to the fragment shader -"void main(void) \n" + -"{ \n" + -" varying_Color = attribute_Color; \n" + -" v_TexCoordinate = a_TexCoordinate; \n" + -" gl_Position = uniform_Projection * attribute_Position; \n" + -"} "; - -/* Introducing the OpenGL ES 2 Fragment shader - * - * The main loop of the fragment shader gets executed for each visible - * pixel fragment on the render buffer. - * - * vertex-> * - * (0,1,-1) /f\ - * /ffF\ <- This fragment F gl_FragCoord get interpolated - * /fffff\ to (0.25,0.25,-1) based on the - * vertex-> *fffffff* <-vertex three vertex gl_Position. - * (-1,-1,-1) (1,-1,-1) - * - * - * All incomming "varying" and gl_FragCoord data to the fragment shader - * gets interpolated based on the vertex positions. - * - * The fragment shader produce and store the final color data output into - * gl_FragColor. - * - * Is up to you to set the final colors and calculate lightning here based on - * supplied position, color and normal data. - * - * The whole fragment shader program are a String containing GLSL ES language - * http://www.khronos.org/registry/gles/specs/2.0/GLSL_ES_Specification_1.0.17.pdf - * sent to the GPU driver for compilation. - */ -private String fragmentShaderString = -"#if __VERSION__ >= 130\n" + -" #define varying in\n" + -" out vec4 mgl_FragColor;\n" + -" #define texture2D texture\n" + -" #define gl_FragColor mgl_FragColor\n" + -"#endif\n" + - -"#ifdef GL_ES \n" + -"precision mediump float; \n" + -"precision mediump int; \n" + -"#endif \n" + - -"uniform sampler2D u_Texture; \n" + - -"varying vec2 v_TexCoordinate; \n" + -"varying vec4 varying_Color; \n" + //incomming varying data to the - //frament shader - //sent from the vertex shader -"void main (void) \n" + -"{ \n" + - -" gl_FragColor = (varying_Color * texture2D(u_Texture, v_TexCoordinate));" + -"} "; - - -FloatBuffer fbVertices = Buffers.newDirectFloatBuffer(2000*18); // max 2000 quadrati -FloatBuffer fbColors = Buffers.newDirectFloatBuffer(2000*24); // max 2000 quadrati -FloatBuffer fbTextureCoordinates = Buffers.newDirectFloatBuffer(2000*12); // max 2000 quadrati -final Texture[] texture = new Texture[1]; -final int[] textureHandle = new int[1]; - -private final Display disp; -public CalculatorWindow(Display disp) { - this.disp = disp; -} - - /* Introducing projection matrix helper functions - * - * OpenGL ES 2 vertex projection transformations gets applied inside the - * vertex shader, all you have to do are to calculate and supply a projection matrix. - * - * Its recomended to use the com/jogamp/opengl/util/PMVMatrix.java - * import com.jogamp.opengl.util.PMVMatrix; - * To simplify all your projection model view matrix creation needs. - * - * These helpers here are based on PMVMatrix code and common linear - * algebra for matrix multiplication, translate and rotations. - */ - private void glMultMatrixf(FloatBuffer a, FloatBuffer b, FloatBuffer d) { - final int aP = a.position(); - final int bP = b.position(); - final int dP = d.position(); - for (int i = 0; i < 4; i++) { - final float ai0=a.get(aP+i+0*4), ai1=a.get(aP+i+1*4), ai2=a.get(aP+i+2*4), ai3=a.get(aP+i+3*4); - d.put(dP+i+0*4 , ai0 * b.get(bP+0+0*4) + ai1 * b.get(bP+1+0*4) + ai2 * b.get(bP+2+0*4) + ai3 * b.get(bP+3+0*4) ); - d.put(dP+i+1*4 , ai0 * b.get(bP+0+1*4) + ai1 * b.get(bP+1+1*4) + ai2 * b.get(bP+2+1*4) + ai3 * b.get(bP+3+1*4) ); - d.put(dP+i+2*4 , ai0 * b.get(bP+0+2*4) + ai1 * b.get(bP+1+2*4) + ai2 * b.get(bP+2+2*4) + ai3 * b.get(bP+3+2*4) ); - d.put(dP+i+3*4 , ai0 * b.get(bP+0+3*4) + ai1 * b.get(bP+1+3*4) + ai2 * b.get(bP+2+3*4) + ai3 * b.get(bP+3+3*4) ); - } - } - - private float[] multiply(float[] a,float[] b){ - float[] tmp = new float[16]; - glMultMatrixf(FloatBuffer.wrap(a),FloatBuffer.wrap(b),FloatBuffer.wrap(tmp)); - return tmp; - } - - private float[] translate(float[] m,float x,float y,float z){ - float[] t = { 1.0f, 0.0f, 0.0f, 0.0f, - 0.0f, 1.0f, 0.0f, 0.0f, - 0.0f, 0.0f, 1.0f, 0.0f, - x, y, z, 1.0f }; - return multiply(m, t); - } - - private float[] rotate(float[] m,float a,float x,float y,float z){ - float s, c; - s = (float)Math.sin(Math.toRadians(a)); - c = (float)Math.cos(Math.toRadians(a)); - float[] r = { - x * x * (1.0f - c) + c, y * x * (1.0f - c) + z * s, x * z * (1.0f - c) - y * s, 0.0f, - x * y * (1.0f - c) - z * s, y * y * (1.0f - c) + c, y * z * (1.0f - c) + x * s, 0.0f, - x * z * (1.0f - c) + y * s, y * z * (1.0f - c) - x * s, z * z * (1.0f - c) + c, 0.0f, - 0.0f, 0.0f, 0.0f, 1.0f }; - return multiply(m, r); - } - -/* Introducing the GL2ES2 demo - * - * How to render a triangle using ~500 lines of code using the RAW - * OpenGL ES 2 API. - * The Programmable pipeline in OpenGL ES 2 are both fast and flexible - * yet it do take some extra lines of code to setup. - * - */ - private double t0 = System.currentTimeMillis(); - private double theta; - private double s; - - private static int width=1920; - private static int height=1080; - - private int shaderProgram; - private int vertShader; - private int fragShader; - private int ModelViewProjectionMatrixHandle; - private int mTextureUniformHandle; - private int mTextureCoordinateHandle; - private final int mTextureCoordinateDataSize = 2; - private int mTextureDataHandle; - static final int COLOR_IDX = 0; - static final int VERTICES_IDX = 1; - static final int TEXTURE_IDX = 2; - int[] vboHandles; - - public GLWindow window; - - public void create(){ - /* This demo are based on the GL2ES2 GLProfile that uses common hardware acceleration - * functionality of desktop OpenGL 3, 2 and mobile OpenGL ES 2 devices. - * JogAmp JOGL will probe all the installed libGL.so, libEGL.so and libGLESv2.so librarys on - * the system to find which one provide hardware acceleration for your GPU device. - * Its common to find more than one version of these librarys installed on a system. - * For example on a ARM Linux system JOGL may find - * Hardware accelerated Nvidia tegra GPU drivers in: /usr/lib/nvidia-tegra/libEGL.so - * Software rendered Mesa Gallium driver in: /usr/lib/arm-linux-gnueabi/mesa-egl/libEGL.so.1 - * Software rendered Mesa X11 in: /usr/lib/arm-linux-gnueabi/mesa/libGL.so - * Good news!: JOGL does all this probing for you all you have to do are to ask for - * the GLProfile you want to use. - */ - - GLCapabilities caps = new GLCapabilities(GLProfile.get(GLProfile.GL2ES2)); - // We may at this point tweak the caps and request a translucent drawable - caps.setBackgroundOpaque(false); - GLWindow glWindow = GLWindow.create(caps); - window = glWindow; - - /* You may combine the NEWT GLWindow inside existing Swing and AWT - * applications by encapsulating the glWindow inside a - * com.jogamp.newt.awt.NewtCanvasAWT canvas. - * - * NewtCanvasAWT newtCanvas = new NewtCanvasAWT(glWindow); - * JFrame frame = new JFrame("RAW GL2ES2 Demo inside a JFrame!"); - * frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); - * frame.setSize(width,height); - * frame.add(newtCanvas); - * // add some swing code if you like. - * // javax.swing.JButton b = new javax.swing.JButton(); - * // b.setText("Hi"); - * // frame.add(b); - * frame.setVisible(true); - */ - - // In this demo we prefer to setup and view the GLWindow directly - // this allows the demo to run on -Djava.awt.headless=true systems - glWindow.setTitle("Raw GL2ES2 Demo"); - - // Finally we connect the GLEventListener application code to the NEWT GLWindow. - // GLWindow will call the GLEventListener init, reshape, display and dispose - // functions when needed. - glWindow.addGLEventListener(this /* GLEventListener */); - Animator animator = new Animator(); - animator.add(glWindow); - animator.start(); - } - - public void init(GLAutoDrawable drawable) { - GL2ES2 gl = drawable.getGL().getGL2ES2(); - - System.err.println("Chosen GLCapabilities: " + drawable.getChosenGLCapabilities()); - System.err.println("INIT GL IS: " + gl.getClass().getName()); - System.err.println("GL_VENDOR: " + gl.glGetString(GL.GL_VENDOR)); - System.err.println("GL_RENDERER: " + gl.glGetString(GL.GL_RENDERER)); - System.err.println("GL_VERSION: " + gl.glGetString(GL.GL_VERSION)); - - /* The initialization below will use the OpenGL ES 2 API directly - * to setup the two shader programs that will be run on the GPU. - * - * Its recommended to use the jogamp/opengl/util/glsl/ classes - * import com.jogamp.opengl.util.glsl.ShaderCode; - * import com.jogamp.opengl.util.glsl.ShaderProgram; - * import com.jogamp.opengl.util.glsl.ShaderState; - * to simplify shader customization, compile and loading. - * - * You may also want to look at the JOGL RedSquareES2 demo - * http://jogamp.org/git/?p=jogl.git;a=blob;f=src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/RedSquareES2.java;hb=HEAD#l78 - * to see how the shader customization, compile and loading is done - * using the recommended JogAmp GLSL utility classes. - */ - - // Make the shader strings compatible with OpenGL 3 core if needed - // GL2ES2 also includes the intersection of GL3 core - // The default implicit GLSL version 1.1 is now depricated in GL3 core - // GLSL 1.3 is the minimum version that now has to be explicitly set. - // This allows the shaders to compile using the latest - // desktop OpenGL 3 and 4 drivers. - if(gl.isGL3core()){ - System.out.println("GL3 core detected: explicit add #version 130 to shaders"); - vertexShaderString = "#version 130\n"+vertexShaderString; - fragmentShaderString = "#version 130\n"+fragmentShaderString; - } - - // Create GPU shader handles - // OpenGL ES retuns a index id to be stored for future reference. - vertShader = gl.glCreateShader(GL2ES2.GL_VERTEX_SHADER); - fragShader = gl.glCreateShader(GL2ES2.GL_FRAGMENT_SHADER); - - //Generate textures - gl.glGenTextures(1, textureHandle, 0); - - try { - Texture t = loadTexture("test.png"); - textureHandle[0] = t.getTarget(); - texture[0] = t; - gl.glBindTexture(GL2ES2.GL_TEXTURE_2D, textureHandle[0]); - } catch (GLException | IOException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - - //Compile the vertexShader String into a program. - String[] vlines = new String[] { vertexShaderString }; - int[] vlengths = new int[] { vlines[0].length() }; - gl.glShaderSource(vertShader, vlines.length, vlines, vlengths, 0); - gl.glCompileShader(vertShader); - - //Check compile status. - int[] compiled = new int[1]; - gl.glGetShaderiv(vertShader, GL2ES2.GL_COMPILE_STATUS, compiled,0); - if(compiled[0]!=0){System.out.println("Horray! vertex shader compiled");} - else { - int[] logLength = new int[1]; - gl.glGetShaderiv(vertShader, GL2ES2.GL_INFO_LOG_LENGTH, logLength, 0); - - byte[] log = new byte[logLength[0]]; - gl.glGetShaderInfoLog(vertShader, logLength[0], (int[])null, 0, log, 0); - - System.err.println("Error compiling the vertex shader: " + new String(log)); - System.exit(1); - } - - //Compile the fragmentShader String into a program. - String[] flines = new String[] { fragmentShaderString }; - int[] flengths = new int[] { flines[0].length() }; - gl.glShaderSource(fragShader, flines.length, flines, flengths, 0); - gl.glCompileShader(fragShader); - - //Check compile status. - gl.glGetShaderiv(fragShader, GL2ES2.GL_COMPILE_STATUS, compiled,0); - if(compiled[0]!=0){System.out.println("Horray! fragment shader compiled");} - else { - int[] logLength = new int[1]; - gl.glGetShaderiv(fragShader, GL2ES2.GL_INFO_LOG_LENGTH, logLength, 0); - - byte[] log = new byte[logLength[0]]; - gl.glGetShaderInfoLog(fragShader, logLength[0], (int[])null, 0, log, 0); - - System.err.println("Error compiling the fragment shader: " + new String(log)); - System.exit(1); - } - - //Each shaderProgram must have - //one vertex shader and one fragment shader. - shaderProgram = gl.glCreateProgram(); - gl.glAttachShader(shaderProgram, vertShader); - gl.glAttachShader(shaderProgram, fragShader); - - //Associate attribute ids with the attribute names inside - //the vertex shader. - gl.glBindAttribLocation(shaderProgram, 0, "attribute_Position"); - gl.glBindAttribLocation(shaderProgram, 1, "attribute_Color"); - gl.glBindAttribLocation(shaderProgram, 2, "a_TexCoordinate"); - - gl.glLinkProgram(shaderProgram); - - //Get a id number to the uniform_Projection matrix - //so that we can update it. - ModelViewProjectionMatrixHandle = gl.glGetUniformLocation(shaderProgram, "uniform_Projection"); - mTextureUniformHandle = gl.glGetUniformLocation(shaderProgram, "u_Texture"); - mTextureCoordinateHandle = gl.glGetAttribLocation(shaderProgram, "a_TexCoordinate"); - - /* GL2ES2 also includes the intersection of GL3 core - * GL3 core and later mandates that a "Vector Buffer Object" must - * be created and bound before calls such as gl.glDrawArrays is used. - * The VBO lines in this demo makes the code forward compatible with - * OpenGL 3 and ES 3 core and later where a default - * vector buffer object is deprecated. - * - * Generate two VBO pointers / handles - * VBO is data buffers stored inside the graphics card memory. - */ - vboHandles = new int[3]; - gl.glGenBuffers(3, vboHandles, 0); - - - } - - public void reshape(GLAutoDrawable drawable, int x, int y, int z, int h) { - System.out.println("Window resized to width=" + z + " height=" + h); - width = z; - height = h; - - // Get gl - GL2ES2 gl = drawable.getGL().getGL2ES2(); - - // Optional: Set viewport - // Render to a square at the center of the window. - gl.glViewport((width-height)/2,0,height,height); - } - - public void display(GLAutoDrawable drawable) { - // Update variables used in animation - double t1 = System.currentTimeMillis(); - theta += (t1-t0)*0.005f; - t0 = t1; - s = Math.sin(theta); - - // Get gl - GL2ES2 gl = drawable.getGL().getGL2ES2(); - - // Clear screen - gl.glClearColor(0, 0, 0, 0f); // Purple - gl.glClear(GL2ES2.GL_STENCIL_BUFFER_BIT | - GL2ES2.GL_COLOR_BUFFER_BIT | - GL2ES2.GL_DEPTH_BUFFER_BIT ); - - // Use the shaderProgram that got linked during the init part. - gl.glUseProgram(shaderProgram); - - /* Change a projection matrix - * The matrix multiplications and OpenGL ES2 code below - * basically match this OpenGL ES1 code. - * note that the model_view_projection matrix gets sent to the vertexShader. - * - * gl.glLoadIdentity(); - * gl.glTranslatef(0.0f,0.0f,-0.1f); - * gl.glRotatef((float)30f*(float)s,1.0f,0.0f,1.0f); - * - */ - - // Set the active texture unit to texture unit 0. - gl.glActiveTexture(textureHandle[0]); - - // Bind the texture to this unit. - gl.glBindTexture(GL2ES2.GL_TEXTURE_2D, mTextureDataHandle); - - // Tell the texture uniform sampler to use this texture in the shader by binding to texture unit 0. - gl.glUniform1i(mTextureUniformHandle, 0); - - float[] model_view_projection; - float[] identity_matrix = { - 1.0f, 0.0f, 0.0f, 0.0f, - 0.0f, 1.0f, 0.0f, 0.0f, - 0.0f, 0.0f, 1.0f, 0.0f, - 0.0f, 0.0f, 0.0f, 1.0f, - }; - model_view_projection = identity_matrix; -// model_view_projection = rotate(model_view_projection,30f*(float)s,1.0f,0.0f,1.0f); -// model_view_projection = translate(model_view_projection,-0.5f,-0.5f, 0f); - - // Send the final projection matrix to the vertex shader by - // using the uniform location id obtained during the init part. - gl.glUniformMatrix4fv(ModelViewProjectionMatrixHandle, 1, false, model_view_projection, 0); - - /* - * Render a triangle: - * The OpenGL ES2 code below basically match this OpenGL code. - * - * gl.glBegin(GL_TRIANGLES); // Drawing Using Triangles - * gl.glVertex3f( 0.0f, 1.0f, 0.0f); // Top - * gl.glVertex3f(-1.0f,-1.0f, 0.0f); // Bottom Left - * gl.glVertex3f( 1.0f,-1.0f, 0.0f); // Bottom Right - * gl.glEnd(); // Finished Drawing The Triangle - */ - - fbVertices.clear(); - fbColors.clear(); - fbTextureCoordinates.clear(); - - fbVertices.put(new float[]{ - 0.0f, 0.0f, 0.0f, //Top - 1.0f, 1.0f, 0.0f, //Bottom Left - 0.0f, 1.0f, 0.0f, //Bottom Right - }); - fbColors.put(new float[]{ - 1.0f, 0.0f, 0.0f, 1.0f, //Top color (red) - 0.0f, 0.0f, 0.0f, 1.0f, //Bottom Left color (black) - 1.0f, 1.0f, 0.0f, 1.0f, //Bottom Right color (yellow) - }); - fbTextureCoordinates.put(new float[]{ - 0.0f, 0.0f, - 0.0f, 1.0f, - 1.0f, 0.0f, - }); - fbVertices.put(new float[]{ - 0.0f, 0.0f, 0.0f, - 1.0f, 0.0f, 0.0f, - 1.0f, 1.0f, 0.0f}); - fbColors.put(new float[]{ - 1.0f, 0.0f, 0.0f, 1.0f, - 0.0f, 0.0f, 0.0f, 1.0f, - 1.0f, 1.0f, 1.0f, 1.0f}); - fbTextureCoordinates.put(new float[]{ - 0.0f, 1.0f, - 1.0f, 1.0f, - 1.0f, 0.0f, - }); - fbColors.position(0); - fbVertices.position(0); - fbTextureCoordinates.position(0); - int numTriangles = fbVertices.limit()/9; - - // Select the VBO, GPU memory data, to use for vertices - gl.glBindBuffer(GL2ES2.GL_ARRAY_BUFFER, vboHandles[VERTICES_IDX]); - - // transfer data to VBO, this perform the copy of data from CPU -> GPU memory - int numBytes = numTriangles * 9 * 4; - gl.glBufferData(GL.GL_ARRAY_BUFFER, numBytes, fbVertices, GL.GL_STATIC_DRAW); - - // Associate Vertex attribute 0 with the last bound VBO - gl.glVertexAttribPointer(0 /* the vertex attribute */, 3, - GL2ES2.GL_FLOAT, false /* normalized? */, 0 /* stride */, - 0 /* The bound VBO data offset */); - - // VBO - // gl.glBindBuffer(GL2ES2.GL_ARRAY_BUFFER, 0); // You can unbind the VBO after it have been associated using glVertexAttribPointer - - gl.glEnableVertexAttribArray(0); - - // Select the VBO, GPU memory data, to use for colors - gl.glBindBuffer(GL2ES2.GL_ARRAY_BUFFER, vboHandles[COLOR_IDX]); - - numBytes = numTriangles * 12 * 4; - gl.glBufferData(GL.GL_ARRAY_BUFFER, numBytes, fbColors, GL.GL_STATIC_DRAW); - - // Associate Vertex attribute 1 with the last bound VBO - gl.glVertexAttribPointer(1 /* the color attribute */, 4 /* four possitions used for each vertex */, - GL2ES2.GL_FLOAT, false /* normalized? */, 0 /* stride */, - 0 /* The bound VBO data offset */); - - gl.glEnableVertexAttribArray(1); - - // Select the VBO, GPU memory data, to use for texture - gl.glBindBuffer(GL2ES2.GL_ARRAY_BUFFER, vboHandles[TEXTURE_IDX]); - - numBytes = numTriangles * 6 * 4; - gl.glBufferData(GL.GL_ARRAY_BUFFER, numBytes, fbTextureCoordinates, GL.GL_STATIC_DRAW); - - // Associate Vertex attribute 1 with the last bound VBO - gl.glVertexAttribPointer(mTextureCoordinateHandle /* the texture attribute */, 2 /* two possitions used for each coordinate */, - GL2ES2.GL_FLOAT, false /* normalized? */, 0 /* stride */, - 0 /* The bound VBO data offset */); - - gl.glEnableVertexAttribArray(mTextureCoordinateHandle); - - - gl.glDrawArrays(GL2ES2.GL_TRIANGLES, 0, numTriangles*3); //Draw the vertices as triangle - - gl.glDisableVertexAttribArray(0); // Allow release of vertex position memory - gl.glDisableVertexAttribArray(1); // Allow release of vertex color memory - gl.glDisableVertexAttribArray(mTextureCoordinateHandle); // Allow release of vertex texture memory - -// disp.di - } - - public void drawQuad() { - - } - - public void dispose(GLAutoDrawable drawable){ - System.out.println("cleanup, remember to release shaders"); - GL2ES2 gl = drawable.getGL().getGL2ES2(); - gl.glUseProgram(0); - gl.glDeleteBuffers(3, vboHandles, 0); // Release VBO, color and vertices, buffer GPU memory. - vboHandles = null; - gl.glDetachShader(shaderProgram, vertShader); - gl.glDeleteShader(vertShader); - gl.glDetachShader(shaderProgram, fragShader); - gl.glDeleteShader(fragShader); - gl.glDeleteProgram(shaderProgram); - System.exit(0); - } - - public static Texture loadTexture(String file) throws GLException, IOException - { - ByteArrayOutputStream os = new ByteArrayOutputStream(); - ImageIO.write(ImageIO.read(new File(file)), "png", os); - InputStream fis = new ByteArrayInputStream(os.toByteArray()); - return TextureIO.newTexture(fis, true, TextureIO.PNG); - } - -} \ No newline at end of file diff --git a/src/org/warp/picalculator/gui/graphicengine/gpu/DeallocationHelper.java b/src/org/warp/picalculator/gui/graphicengine/gpu/DeallocationHelper.java new file mode 100644 index 00000000..232f29c4 --- /dev/null +++ b/src/org/warp/picalculator/gui/graphicengine/gpu/DeallocationHelper.java @@ -0,0 +1,706 @@ +/** + * Copyright (c) 2006-2016 Julien Gouesse This program is free software; you can + * redistribute it and/or modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. This program is distributed + * in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even + * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. You should have received + * a copy of the GNU General Public License along with this program; if not, + * write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ +package org.warp.picalculator.gui.graphicengine.gpu; + +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.nio.Buffer; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.nio.CharBuffer; +import java.nio.DoubleBuffer; +import java.nio.FloatBuffer; +import java.nio.IntBuffer; +import java.nio.LongBuffer; +import java.nio.ShortBuffer; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * Helper to deallocate memory on the native heap allocated during the creation + * of a direct byte buffer. It supports numerous virtual machines including + * OpenJDK, Oracle/Sun Java, Android Dalvik Virtual Machine, Apache Harmony and + * GNU Classpath. This class uses the syntax of Java 1.7 but it can work + * correctly with Java 1.4 with a very few minor type changes when using the + * maps and the collections. It relies on lots of implementation details but + * it's robust enough to go on working (except when the implementors + * intentionally use a very general class to store the buffers) despite minor + * naming changes like those that occurred between Java 1.6 and Java 1.7. It + * supports Java 1.9 despite the move of the cleaner from the package sun.misc + * to jdk.internal.ref (in the module java.base). N.B: Releasing the native + * memory of a sliced direct NIO buffer, the one of a direct NIO buffer created + * with JNI or the one of any direct NIO buffer created by the virtual machine + * or by a framework not under your control doesn't prevent the calls to methods + * attempting to access such buffers. Those calls can throw an exception or + * crash the virtual machine depending on the implementations. + * + * @author Julien Gouesse + */ +public class DeallocationHelper { + + /** + * tool responsible for releasing the native memory of a deallocatable byte + * buffer + */ + public static abstract class Deallocator { + + public Deallocator() { + super(); + } + + /** + * releases the native memory of a deallocatable byte buffer + * + * @param directByteBuffer + * deallocatable byte buffer + * + * @return true if the deallocation is successful, + * otherwise false + */ + public abstract boolean run(final ByteBuffer directByteBuffer); + } + + public static class OracleSunOpenJdkDeallocator extends Deallocator { + + private Method directByteBufferCleanerMethod; + + private Method cleanerCleanMethod; + + public OracleSunOpenJdkDeallocator() { + super(); + try { + final Class directByteBufferClass = Class.forName("java.nio.DirectByteBuffer"); + directByteBufferCleanerMethod = directByteBufferClass.getDeclaredMethod("cleaner"); + /** + * The return type is sun.misc.Cleaner in Java <= 1.8, + * jdk.internal.ref.Cleaner in Java >= 1.9. Only the latter + * implements the Runnable interface. + */ + final Class cleanerClass = directByteBufferCleanerMethod.getReturnType(); + if (Runnable.class.isAssignableFrom(cleanerClass)) { + cleanerCleanMethod = Runnable.class.getDeclaredMethod("run"); + } else { + cleanerCleanMethod = cleanerClass.getDeclaredMethod("clean"); + } + } catch (ClassNotFoundException | NoSuchMethodException e) { + logger.log(Level.WARNING, "The initialization of the deallocator for Oracle Java, Sun Java and OpenJDK has failed", e); + } + } + + @Override + public boolean run(final ByteBuffer directByteBuffer) { + boolean success = false; + if (directByteBufferCleanerMethod != null && cleanerCleanMethod != null) { + final boolean directByteBufferCleanerMethodWasAccessible = directByteBufferCleanerMethod.isAccessible(); + final boolean cleanerCleanMethodWasAccessible = cleanerCleanMethod.isAccessible(); + try { + // according to the Java documentation, by default, a reflected object is not accessible + directByteBufferCleanerMethod.setAccessible(true); + final Object cleaner = directByteBufferCleanerMethod.invoke(directByteBuffer); + if (cleaner != null) { + cleanerCleanMethod.setAccessible(true); + cleanerCleanMethod.invoke(cleaner); + success = true; + } + } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { + logger.log(Level.WARNING, "The deallocation of a direct NIO buffer has failed", e); + } finally { + directByteBufferCleanerMethod.setAccessible(directByteBufferCleanerMethodWasAccessible); + cleanerCleanMethod.setAccessible(cleanerCleanMethodWasAccessible); + } + } + return (success); + } + } + + public static class AndroidDeallocator extends Deallocator { + + private Method directByteBufferFreeMethod; + + public AndroidDeallocator() { + super(); + try { + final Class directByteBufferClass = Class.forName("java.nio.DirectByteBuffer"); + directByteBufferFreeMethod = directByteBufferClass.getDeclaredMethod("free"); + } catch (ClassNotFoundException | NoSuchMethodException e) { + logger.log(Level.WARNING, "The initialization of the deallocator for Android has failed", e); + } + } + + @Override + public boolean run(final ByteBuffer directByteBuffer) { + boolean success = false; + if (directByteBufferFreeMethod != null) { + final boolean directByteBufferFreeMethodWasAccessible = directByteBufferFreeMethod.isAccessible(); + try { + directByteBufferFreeMethod.setAccessible(true); + directByteBufferFreeMethod.invoke(directByteBuffer); + success = true; + } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { + logger.log(Level.WARNING, "The deallocation of a direct NIO buffer has failed", e); + } finally { + directByteBufferFreeMethod.setAccessible(directByteBufferFreeMethodWasAccessible); + } + } + return (success); + } + } + + public static class GnuClasspathDeallocator extends Deallocator { + + private Method vmDirectByteBufferFreeMethod; + + private Field bufferAddressField; + + public GnuClasspathDeallocator() { + super(); + try { + final Class vmDirectByteBufferClass = Class.forName("java.nio.VMDirectByteBuffer"); + final Class gnuClasspathPointerClass = Class.forName("gnu.classpath.Pointer"); + vmDirectByteBufferFreeMethod = vmDirectByteBufferClass.getDeclaredMethod("free", gnuClasspathPointerClass); + bufferAddressField = Buffer.class.getDeclaredField("address"); + } catch (ClassNotFoundException | NoSuchMethodException | NoSuchFieldException e) { + logger.log(Level.WARNING, "The initialization of the deallocator for GNU Classpath has failed", e); + } + } + + @Override + public boolean run(final ByteBuffer directByteBuffer) { + boolean success = false; + if (vmDirectByteBufferFreeMethod != null && bufferAddressField != null) { + final boolean bufferAddressFieldWasAccessible = bufferAddressField.isAccessible(); + final boolean vmDirectByteBufferFreeMethodWasAccessible = vmDirectByteBufferFreeMethod.isAccessible(); + try { + bufferAddressField.setAccessible(true); + final Object address = bufferAddressField.get(directByteBuffer); + if (address != null) { + vmDirectByteBufferFreeMethod.setAccessible(true); + vmDirectByteBufferFreeMethod.invoke(null, address); + success = true; + } + } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { + logger.log(Level.WARNING, "The deallocation of a direct NIO buffer has failed", e); + } finally { + bufferAddressField.setAccessible(bufferAddressFieldWasAccessible); + vmDirectByteBufferFreeMethod.setAccessible(vmDirectByteBufferFreeMethodWasAccessible); + } + } + return (success); + } + } + + public static class ApacheHarmonyDeallocator extends Deallocator { + + private Method directByteBufferFreeMethod; + + public ApacheHarmonyDeallocator() { + super(); + try { + final Class directByteBufferClass = Class.forName("java.nio.DirectByteBuffer"); + directByteBufferFreeMethod = directByteBufferClass.getDeclaredMethod("free"); + } catch (ClassNotFoundException | NoSuchMethodException e) { + logger.log(Level.WARNING, "The initialization of the deallocator for Apache Harmony has failed", e); + } + } + + @Override + public boolean run(final ByteBuffer directByteBuffer) { + boolean success = false; + if (directByteBufferFreeMethod != null) { + final boolean directByteBufferFreeMethodWasAccessible = directByteBufferFreeMethod.isAccessible(); + try { + directByteBufferFreeMethod.setAccessible(true); + directByteBufferFreeMethod.invoke(directByteBuffer); + success = true; + } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { + logger.log(Level.WARNING, "The deallocation of a direct NIO buffer has failed", e); + } finally { + directByteBufferFreeMethod.setAccessible(directByteBufferFreeMethodWasAccessible); + } + } + return (success); + } + } + + private static final Logger logger = Logger.getLogger(DeallocationHelper.class.getName()); + + private Map, Field> attachmentOrByteBufferFieldMap; + + private Set> deallocatableBufferClassSet; + + private Deallocator deallocator; + + /** + * Default constructor + */ + public DeallocationHelper() { + this(false); + } + + /** + * Main constructor + * + * @param ignoreClassesAndFieldsHints + * true if the known implementation details should + * be ignored when looking for the classes and the fields used + * for the native memory of the direct buffers (they are then + * fully recomputed at runtime which is slower but safer), + * otherwise false + */ + public DeallocationHelper(final boolean ignoreClassesAndFieldsHints) { + super(); + final List buffersToDelete = new ArrayList<>(); + /** + * builds the map used to determine the names of the fields containing + * the direct byte buffers. The direct read only buffers and the sliced + * buffers and the direct buffers for other primitive types than bytes + * store their data into some direct byte buffers. Those direct byte + * buffers often are the only one accessing directly to the native + * memory. That's why it's necessary to find them when a developer + * passes a direct NIO buffer. The code below relies on numerous + * implementation details found in some classes not available in the + * public APIs, it's used to find the fields faster in most of the + * cases. The class names haven't changed since Java 1.4 unlike a few + * field names. + */ + final Map attachmentOrByteBufferFieldNameMap = new HashMap<>(); + final String javaVendor = System.getProperty("java.vendor"); + final String javaVersion = System.getProperty("java.version"); + if (!ignoreClassesAndFieldsHints) { + if (javaVendor.equals("Sun Microsystems Inc.") || javaVendor.equals("Oracle Corporation")) { + final String java14to16DirectBufferAttachmentFieldName = "viewedBuffer"; + final String java17to19DirectBufferAttachmentFieldName = "att"; + final String byteBufferAsNonByteBufferByteBufferFieldName = "bb"; + final String[] directBufferClassnames = new String[] { "java.nio.DirectByteBuffer", "java.nio.DirectByteBufferR", "java.nio.DirectCharBufferRS", "java.nio.DirectCharBufferRU", "java.nio.DirectCharBufferS", "java.nio.DirectCharBufferU", "java.nio.DirectDoubleBufferRS", "java.nio.DirectDoubleBufferRU", "java.nio.DirectDoubleBufferS", "java.nio.DirectDoubleBufferU", "java.nio.DirectFloatBufferRS", "java.nio.DirectFloatBufferRU", "java.nio.DirectFloatBufferS", "java.nio.DirectFloatBufferU", "java.nio.DirectIntBufferRS", "java.nio.DirectIntBufferRU", "java.nio.DirectIntBufferS", "java.nio.DirectIntBufferU", "java.nio.DirectLongBufferRS", "java.nio.DirectLongBufferRU", "java.nio.DirectLongBufferS", "java.nio.DirectLongBufferU", "java.nio.DirectShortBufferRS", "java.nio.DirectShortBufferRU", "java.nio.DirectShortBufferS", "java.nio.DirectShortBufferU" }; + final String[] byteBufferAsNonByteBufferClassnames = new String[] { "java.nio.ByteBufferAsCharBufferB", "java.nio.ByteBufferAsCharBufferL", "java.nio.ByteBufferAsCharBufferRB", "java.nio.ByteBufferAsCharBufferRL", "java.nio.ByteBufferAsDoubleBufferB", "java.nio.ByteBufferAsDoubleBufferL", "java.nio.ByteBufferAsDoubleBufferRB", "java.nio.ByteBufferAsDoubleBufferRL", "java.nio.ByteBufferAsFloatBufferB", "java.nio.ByteBufferAsFloatBufferL", "java.nio.ByteBufferAsFloatBufferRB", "java.nio.ByteBufferAsFloatBufferRL", "java.nio.ByteBufferAsIntBufferB", "java.nio.ByteBufferAsIntBufferL", "java.nio.ByteBufferAsIntBufferRB", "java.nio.ByteBufferAsIntBufferRL", "java.nio.ByteBufferAsLongBufferB", "java.nio.ByteBufferAsLongBufferL", "java.nio.ByteBufferAsLongBufferRB", "java.nio.ByteBufferAsLongBufferRL", "java.nio.ByteBufferAsShortBufferB", "java.nio.ByteBufferAsShortBufferL", "java.nio.ByteBufferAsShortBufferRB", "java.nio.ByteBufferAsShortBufferRL" }; + final String[] javaVersionElements = System.getProperty("java.version").split("\\."); + final int indexOfEarlyAccessSuffix = javaVersionElements[0].lastIndexOf("-ea"); + if (indexOfEarlyAccessSuffix != -1) { + // drops the "-ea" suffix from the major version number for + // an early access build + javaVersionElements[0] = javaVersionElements[0].substring(0, indexOfEarlyAccessSuffix); + } + final int major, minor; + if (javaVersionElements.length >= 2) { + major = Integer.parseInt(javaVersionElements[0]); + minor = Integer.parseInt(javaVersionElements[1]); + } else { + major = 1; + minor = Integer.parseInt(javaVersionElements[0]); + } + final String directBufferAttachmentFieldName; + if (minor == 1 && major <= 6) { + directBufferAttachmentFieldName = java14to16DirectBufferAttachmentFieldName; + } else { + directBufferAttachmentFieldName = java17to19DirectBufferAttachmentFieldName; + } + for (final String directBufferClassname : directBufferClassnames) { + attachmentOrByteBufferFieldNameMap.put(directBufferClassname, directBufferAttachmentFieldName); + } + for (final String byteBufferAsNonByteBufferClassname : byteBufferAsNonByteBufferClassnames) { + attachmentOrByteBufferFieldNameMap.put(byteBufferAsNonByteBufferClassname, byteBufferAsNonByteBufferByteBufferFieldName); + } + } else if (javaVendor.equals("The Android Project")) { + final String byteBufferAsNonByteBufferByteBufferFieldName = "byteBuffer"; + final String[] byteBufferAsNonByteBufferClassnames = new String[] { "java.nio.ByteBufferAsCharBuffer", "java.nio.ByteBufferAsDoubleBuffer", "java.nio.ByteBufferAsFloatBuffer", "java.nio.ByteBufferAsIntBuffer", "java.nio.ByteBufferAsLongBuffer", "java.nio.ByteBufferAsShortBuffer" }; + for (final String byteBufferAsNonByteBufferClassname : byteBufferAsNonByteBufferClassnames) { + attachmentOrByteBufferFieldNameMap.put(byteBufferAsNonByteBufferClassname, byteBufferAsNonByteBufferByteBufferFieldName); + } + } else if (/* javaVendor.equals("Apple Inc.")|| */javaVendor.equals("Free Software Foundation, Inc.")) { + final String byteBufferAsNonByteBufferByteBufferFieldName = "bb"; + final String[] byteBufferAsNonByteBufferClassnames = new String[] { "java.nio.CharViewBufferImpl", "java.nio.DoubleViewBufferImpl", "java.nio.FloatViewBufferImpl", "java.nio.IntViewBufferImpl", "java.nio.LongViewBufferImpl", "java.nio.ShortViewBufferImpl" }; + for (final String byteBufferAsNonByteBufferClassname : byteBufferAsNonByteBufferClassnames) { + attachmentOrByteBufferFieldNameMap.put(byteBufferAsNonByteBufferClassname, byteBufferAsNonByteBufferByteBufferFieldName); + } + } else if (javaVendor.contains("Apache")) { + final String byteBufferAsNonByteBufferByteBufferFieldName = "byteBuffer"; + final String[] byteBufferAsNonByteBufferClassnames = new String[] { "java.nio.CharToByteBufferAdapter", "java.nio.DoubleToByteBufferAdapter", "java.nio.FloatToByteBufferAdapter", "java.nio.IntToByteBufferAdapter", "java.nio.LongToByteBufferAdapter", "java.nio.ShortToByteBufferAdapter" }; + for (final String byteBufferAsNonByteBufferClassname : byteBufferAsNonByteBufferClassnames) { + attachmentOrByteBufferFieldNameMap.put(byteBufferAsNonByteBufferClassname, byteBufferAsNonByteBufferByteBufferFieldName); + } + } else if (javaVendor.equals("Jeroen Frijters")) {// TODO IKVM + } else if (javaVendor.contains("IBM")) {// TODO J9 + } + } + // checks if these classes are in the class library + if (!attachmentOrByteBufferFieldNameMap.isEmpty()) { + final List classnamesToRemove = new ArrayList<>(); + for (final String classname : attachmentOrByteBufferFieldNameMap.keySet()) { + try { + Class.forName(classname); + } catch (final ClassNotFoundException cnfe) { + classnamesToRemove.add(classname); + } + } + for (final String classnameToRemove : classnamesToRemove) { + attachmentOrByteBufferFieldNameMap.remove(classnameToRemove); + } + } + // builds the map used to determine the fields containing the direct + // byte buffers + attachmentOrByteBufferFieldMap = new HashMap<>(); + if (!attachmentOrByteBufferFieldNameMap.isEmpty()) { + for (final Entry attachmentOrByteBufferFieldNameEntry : attachmentOrByteBufferFieldNameMap.entrySet()) { + final String classname = attachmentOrByteBufferFieldNameEntry.getKey(); + final String fieldname = attachmentOrByteBufferFieldNameEntry.getValue(); + try { + final Class bufferClass = Class.forName(classname); + Field bufferField = null; + Class bufferIntermediaryClass = bufferClass; + final List> intermediaryClassWithoutBufferList = new ArrayList<>(); + while (bufferIntermediaryClass != null) { + try { + bufferField = bufferIntermediaryClass.getDeclaredField(fieldname); + } catch (final NoSuchFieldException nsfe) { + if (!bufferIntermediaryClass.equals(Object.class) && !bufferIntermediaryClass.equals(Buffer.class)) { + intermediaryClassWithoutBufferList.add(bufferIntermediaryClass); + } + } + bufferIntermediaryClass = bufferIntermediaryClass.getSuperclass(); + } + if (bufferField == null) { + final String superClassesMsg; + if (intermediaryClassWithoutBufferList.isEmpty()) { + superClassesMsg = ""; + } else if (intermediaryClassWithoutBufferList.size() == 1) { + superClassesMsg = " and in its super class " + intermediaryClassWithoutBufferList.get(0).getName(); + } else { + final StringBuilder builder = new StringBuilder(); + builder.append(" and in its super classes"); + int classIndex = 0; + for (final Class intermediaryClassWithoutBuffer : intermediaryClassWithoutBufferList) { + builder.append(' '); + builder.append(intermediaryClassWithoutBuffer.getName()); + if (classIndex < intermediaryClassWithoutBufferList.size() - 1) { + builder.append(','); + } + classIndex++; + } + superClassesMsg = builder.toString(); + } + logger.warning("The field " + fieldname + " hasn't been found in the class " + classname + superClassesMsg); + } else {// the field has been found, stores it into the map + attachmentOrByteBufferFieldMap.put(bufferClass, bufferField); + } + } catch (final ClassNotFoundException cnfe) {// TODO The Java version + // isn't very useful + // under + // Android as it is + // always zero, rather + // use + // android.os.Build.VERSION.RELEASE + // to show something + // meaningful supported + // since the API level 1 + final String msg = "The class " + classname + " hasn't been found while initializing the deallocator. Java vendor: " + javaVendor + " Java version: " + javaVersion; + logger.log(Level.WARNING, msg, cnfe); + } + } + } + // if a known implementation has drastically changed or if the current + // implementation is unknown + if (attachmentOrByteBufferFieldNameMap.isEmpty()) {// detects everything + // with the + // reflection API + // creates all + // possible kinds of + // direct NIO buffer + // that can contain + // buffers (sliced + // buffers and views) + final ByteBuffer slicedBigEndianReadOnlyDirectByteBuffer = ((ByteBuffer) ByteBuffer.allocateDirect(2).order(ByteOrder.BIG_ENDIAN).put((byte) 0).put((byte) 0).position(1).limit(2)).slice().asReadOnlyBuffer(); + final ByteBuffer slicedBigEndianReadWriteDirectByteBuffer = ((ByteBuffer) ByteBuffer.allocateDirect(2).order(ByteOrder.BIG_ENDIAN).put((byte) 0).put((byte) 0).position(1).limit(2)).slice(); + final CharBuffer bigEndianReadOnlyDirectCharBuffer = ByteBuffer.allocateDirect(1).order(ByteOrder.BIG_ENDIAN).asReadOnlyBuffer().asCharBuffer(); + final CharBuffer bigEndianReadWriteDirectCharBuffer = ByteBuffer.allocateDirect(1).order(ByteOrder.BIG_ENDIAN).asCharBuffer(); + final DoubleBuffer bigEndianReadOnlyDirectDoubleBuffer = ByteBuffer.allocateDirect(1).order(ByteOrder.BIG_ENDIAN).asReadOnlyBuffer().asDoubleBuffer(); + final DoubleBuffer bigEndianReadWriteDirectDoubleBuffer = ByteBuffer.allocateDirect(1).order(ByteOrder.BIG_ENDIAN).asDoubleBuffer(); + final FloatBuffer bigEndianReadOnlyDirectFloatBuffer = ByteBuffer.allocateDirect(1).order(ByteOrder.BIG_ENDIAN).asReadOnlyBuffer().asFloatBuffer(); + final FloatBuffer bigEndianReadWriteDirectFloatBuffer = ByteBuffer.allocateDirect(1).order(ByteOrder.BIG_ENDIAN).asFloatBuffer(); + final IntBuffer bigEndianReadOnlyDirectIntBuffer = ByteBuffer.allocateDirect(1).order(ByteOrder.BIG_ENDIAN).asReadOnlyBuffer().asIntBuffer(); + final IntBuffer bigEndianReadWriteDirectIntBuffer = ByteBuffer.allocateDirect(1).order(ByteOrder.BIG_ENDIAN).asIntBuffer(); + final LongBuffer bigEndianReadOnlyDirectLongBuffer = ByteBuffer.allocateDirect(1).order(ByteOrder.BIG_ENDIAN).asReadOnlyBuffer().asLongBuffer(); + final LongBuffer bigEndianReadWriteDirectLongBuffer = ByteBuffer.allocateDirect(1).order(ByteOrder.BIG_ENDIAN).asLongBuffer(); + final ShortBuffer bigEndianReadOnlyDirectShortBuffer = ByteBuffer.allocateDirect(1).order(ByteOrder.BIG_ENDIAN).asReadOnlyBuffer().asShortBuffer(); + final ShortBuffer bigEndianReadWriteDirectShortBuffer = ByteBuffer.allocateDirect(1).order(ByteOrder.BIG_ENDIAN).asShortBuffer(); + final ByteBuffer slicedLittleEndianReadOnlyDirectByteBuffer = ((ByteBuffer) ByteBuffer.allocateDirect(2).order(ByteOrder.LITTLE_ENDIAN).put((byte) 0).put((byte) 0).position(1).limit(2)).slice().asReadOnlyBuffer(); + final ByteBuffer slicedLittleEndianReadWriteDirectByteBuffer = ((ByteBuffer) ByteBuffer.allocateDirect(2).order(ByteOrder.LITTLE_ENDIAN).put((byte) 0).put((byte) 0).position(1).limit(2)).slice(); + final CharBuffer littleEndianReadOnlyDirectCharBuffer = ByteBuffer.allocateDirect(1).order(ByteOrder.LITTLE_ENDIAN).asReadOnlyBuffer().asCharBuffer(); + final CharBuffer littleEndianReadWriteDirectCharBuffer = ByteBuffer.allocateDirect(1).order(ByteOrder.LITTLE_ENDIAN).asCharBuffer(); + final DoubleBuffer littleEndianReadOnlyDirectDoubleBuffer = ByteBuffer.allocateDirect(1).order(ByteOrder.LITTLE_ENDIAN).asReadOnlyBuffer().asDoubleBuffer(); + final DoubleBuffer littleEndianReadWriteDirectDoubleBuffer = ByteBuffer.allocateDirect(1).order(ByteOrder.LITTLE_ENDIAN).asDoubleBuffer(); + final FloatBuffer littleEndianReadOnlyDirectFloatBuffer = ByteBuffer.allocateDirect(1).order(ByteOrder.LITTLE_ENDIAN).asReadOnlyBuffer().asFloatBuffer(); + final FloatBuffer littleEndianReadWriteDirectFloatBuffer = ByteBuffer.allocateDirect(1).order(ByteOrder.LITTLE_ENDIAN).asFloatBuffer(); + final IntBuffer littleEndianReadOnlyDirectIntBuffer = ByteBuffer.allocateDirect(1).order(ByteOrder.LITTLE_ENDIAN).asReadOnlyBuffer().asIntBuffer(); + final IntBuffer littleEndianReadWriteDirectIntBuffer = ByteBuffer.allocateDirect(1).order(ByteOrder.LITTLE_ENDIAN).asIntBuffer(); + final LongBuffer littleEndianReadOnlyDirectLongBuffer = ByteBuffer.allocateDirect(1).order(ByteOrder.LITTLE_ENDIAN).asReadOnlyBuffer().asLongBuffer(); + final LongBuffer littleEndianReadWriteDirectLongBuffer = ByteBuffer.allocateDirect(1).order(ByteOrder.LITTLE_ENDIAN).asLongBuffer(); + final ShortBuffer littleEndianReadOnlyDirectShortBuffer = ByteBuffer.allocateDirect(1).order(ByteOrder.LITTLE_ENDIAN).asReadOnlyBuffer().asShortBuffer(); + final ShortBuffer littleEndianReadWriteDirectShortBuffer = ByteBuffer.allocateDirect(1).order(ByteOrder.LITTLE_ENDIAN).asShortBuffer(); + final List buffers = new ArrayList<>(); + buffers.add(slicedBigEndianReadOnlyDirectByteBuffer); + buffers.add(slicedBigEndianReadWriteDirectByteBuffer); + buffers.add(bigEndianReadOnlyDirectCharBuffer); + buffers.add(bigEndianReadWriteDirectCharBuffer); + buffers.add(bigEndianReadOnlyDirectDoubleBuffer); + buffers.add(bigEndianReadWriteDirectDoubleBuffer); + buffers.add(bigEndianReadOnlyDirectFloatBuffer); + buffers.add(bigEndianReadWriteDirectFloatBuffer); + buffers.add(bigEndianReadOnlyDirectIntBuffer); + buffers.add(bigEndianReadWriteDirectIntBuffer); + buffers.add(bigEndianReadOnlyDirectLongBuffer); + buffers.add(bigEndianReadWriteDirectLongBuffer); + buffers.add(bigEndianReadOnlyDirectShortBuffer); + buffers.add(bigEndianReadWriteDirectShortBuffer); + buffers.add(slicedLittleEndianReadOnlyDirectByteBuffer); + buffers.add(slicedLittleEndianReadWriteDirectByteBuffer); + buffers.add(littleEndianReadOnlyDirectCharBuffer); + buffers.add(littleEndianReadWriteDirectCharBuffer); + buffers.add(littleEndianReadOnlyDirectDoubleBuffer); + buffers.add(littleEndianReadWriteDirectDoubleBuffer); + buffers.add(littleEndianReadOnlyDirectFloatBuffer); + buffers.add(littleEndianReadWriteDirectFloatBuffer); + buffers.add(littleEndianReadOnlyDirectIntBuffer); + buffers.add(littleEndianReadWriteDirectIntBuffer); + buffers.add(littleEndianReadOnlyDirectLongBuffer); + buffers.add(littleEndianReadWriteDirectLongBuffer); + buffers.add(littleEndianReadOnlyDirectShortBuffer); + buffers.add(littleEndianReadWriteDirectShortBuffer); + // gets the fields to access the contained buffers + for (final Buffer buffer : buffers) { + final Class bufferClass = buffer.getClass(); + if (!attachmentOrByteBufferFieldMap.containsKey(bufferClass)) { + Field bufferField = null; + Class bufferIntermediaryClass = bufferClass; + while (bufferIntermediaryClass != null && bufferField == null) { + for (final Field field : bufferIntermediaryClass.getDeclaredFields()) { + final boolean fieldWasAccessible = field.isAccessible(); + try { + field.setAccessible(true); + final Object fieldValue = field.get(buffer); + if (fieldValue != null && fieldValue instanceof Buffer) { + bufferField = field; + break; + } + } catch (final IllegalAccessException iae) { + logger.log(Level.WARNING, "Cannot access the field " + field.getName() + " of the class " + bufferIntermediaryClass.getName(), iae); + } finally { + field.setAccessible(fieldWasAccessible); + } + } + bufferIntermediaryClass = bufferIntermediaryClass.getSuperclass(); + } + if (bufferField != null) { + attachmentOrByteBufferFieldMap.put(bufferClass, bufferField); + } + } + } + // cleans the mess + buffersToDelete.addAll(buffers); + } + // builds the set of classes whose instances can be deallocated + deallocatableBufferClassSet = new HashSet<>(); + if (javaVendor.equals("Sun Microsystems Inc.") || javaVendor.equals("Oracle Corporation") || javaVendor.equals("The Android Project")) { + Class directByteBufferClass = null; + final String directByteBufferClassName = "java.nio.DirectByteBuffer"; + try { + directByteBufferClass = Class.forName(directByteBufferClassName); + } catch (final ClassNotFoundException cnfe) { + final String msg = "The class " + directByteBufferClassName + " hasn't been found while initializing the deallocator. Java vendor: " + javaVendor + " Java version: " + javaVersion; + logger.log(Level.WARNING, msg, cnfe); + } + if (directByteBufferClass != null) { + deallocatableBufferClassSet.add(directByteBufferClass); + } + } else if (/* javaVendor.equals("Apple Inc.")|| */javaVendor.equals("Free Software Foundation, Inc.")) { + Class readOnlyDirectByteBufferClass = null; + final String readOnlyDirectByteBufferClassName = "java.nio.DirectByteBufferImpl.ReadOnly"; + try { + readOnlyDirectByteBufferClass = Class.forName(readOnlyDirectByteBufferClassName); + } catch (final ClassNotFoundException cnfe) { + final String msg = "The class " + readOnlyDirectByteBufferClassName + " hasn't been found while initializing the deallocator. Java vendor: " + javaVendor + " Java version: " + javaVersion; + logger.log(Level.WARNING, msg, cnfe); + } + if (readOnlyDirectByteBufferClass != null) { + deallocatableBufferClassSet.add(readOnlyDirectByteBufferClass); + } + Class readWriteDirectByteBufferClass = null; + final String readWriteDirectByteBufferClassName = "java.nio.DirectByteBufferImpl.ReadWrite"; + try { + readWriteDirectByteBufferClass = Class.forName(readWriteDirectByteBufferClassName); + } catch (final ClassNotFoundException cnfe) { + final String msg = "The class " + readWriteDirectByteBufferClassName + " hasn't been found while initializing the deallocator. Java vendor: " + javaVendor + " Java version: " + javaVersion; + logger.log(Level.WARNING, msg, cnfe); + } + if (readWriteDirectByteBufferClass != null) { + deallocatableBufferClassSet.add(readWriteDirectByteBufferClass); + } + } else if (javaVendor.contains("Apache")) { + Class readOnlyDirectByteBufferClass = null; + final String readOnlyDirectByteBufferClassName = "java.nio.ReadOnlyDirectByteBuffer"; + try { + readOnlyDirectByteBufferClass = Class.forName(readOnlyDirectByteBufferClassName); + } catch (final ClassNotFoundException cnfe) { + final String msg = "The class " + readOnlyDirectByteBufferClassName + " hasn't been found while initializing the deallocator. Java vendor: " + javaVendor + " Java version: " + javaVersion; + logger.log(Level.WARNING, msg, cnfe); + } + if (readOnlyDirectByteBufferClass != null) { + deallocatableBufferClassSet.add(readOnlyDirectByteBufferClass); + } + Class readWriteDirectByteBufferClass = null; + final String readWriteDirectByteBufferClassName = "java.nio.ReadWriteDirectByteBuffer"; + try { + readWriteDirectByteBufferClass = Class.forName(readWriteDirectByteBufferClassName); + } catch (final ClassNotFoundException cnfe) { + final String msg = "The class " + readWriteDirectByteBufferClassName + " hasn't been found while initializing the deallocator. Java vendor: " + javaVendor + " Java version: " + javaVersion; + logger.log(Level.WARNING, msg, cnfe); + } + if (readWriteDirectByteBufferClass != null) { + deallocatableBufferClassSet.add(readWriteDirectByteBufferClass); + } + } else if (javaVendor.equals("Jeroen Frijters")) {// TODO IKVM + } else if (javaVendor.contains("IBM")) {// TODO J9 + } + // if there is no known implementation class of the direct byte buffers + if (deallocatableBufferClassSet.isEmpty()) {// creates a read write + // direct byte buffer + final ByteBuffer dummyReadWriteDirectByteBuffer = ByteBuffer.allocateDirect(1); + // gets its class + final Class readWriteDirectByteBufferClass = dummyReadWriteDirectByteBuffer.getClass(); + // stores this class + deallocatableBufferClassSet.add(readWriteDirectByteBufferClass); + // cleans the mess + buffersToDelete.add(dummyReadWriteDirectByteBuffer); + // creates a read only direct byte buffer + final ByteBuffer dummyReadOnlyDirectByteBuffer = ByteBuffer.allocateDirect(1).asReadOnlyBuffer(); + // gets its class + final Class readOnlyDirectByteBufferClass = dummyReadOnlyDirectByteBuffer.getClass(); + // stores this class + deallocatableBufferClassSet.add(readOnlyDirectByteBufferClass); + // cleans the mess + buffersToDelete.add(dummyReadOnlyDirectByteBuffer); + } + // builds the deallocator responsible for releasing the native memory of + // a deallocatable byte buffer + if (javaVendor.equals("Sun Microsystems Inc.") || javaVendor.equals("Oracle Corporation")) { + deallocator = new OracleSunOpenJdkDeallocator(); + } else if (javaVendor.equals("The Android Project")) { + deallocator = new AndroidDeallocator(); + } else if (/* javaVendor.equals("Apple Inc.")|| */javaVendor.equals("Free Software Foundation, Inc.")) { + deallocator = new GnuClasspathDeallocator(); + } else if (javaVendor.contains("Apache")) { + deallocator = new ApacheHarmonyDeallocator(); + } else if (javaVendor.equals("Jeroen Frijters")) {// TODO IKVM + deallocator = null; + } else if (javaVendor.contains("IBM")) {// TODO J9 + deallocator = null; + } else { + deallocator = null; + } + // final cleanup + for (final Buffer bufferToDelete : buffersToDelete) { + deallocate(bufferToDelete); + } + } + + public ByteBuffer findDeallocatableBuffer(Buffer buffer) { + final ByteBuffer deallocatableDirectByteBuffer; + // looks only for the direct buffers + if (buffer != null && buffer.isDirect()) {// looks for any contained + // buffer in the passed buffer + final Class bufferClass = buffer.getClass(); + final Field attachmentOrByteBufferField = attachmentOrByteBufferFieldMap == null ? null : attachmentOrByteBufferFieldMap.get(bufferClass); + final Buffer attachmentBufferOrByteBuffer; + if (attachmentOrByteBufferField == null) { + attachmentBufferOrByteBuffer = null; + } else { + Object attachedObjectOrByteBuffer; + final boolean attachedObjectOrByteBufferFieldWasAccessible = attachmentOrByteBufferField.isAccessible(); + try { + attachmentOrByteBufferField.setAccessible(true); + attachedObjectOrByteBuffer = attachmentOrByteBufferField.get(buffer); + } catch (IllegalArgumentException | IllegalAccessException iae) { + attachedObjectOrByteBuffer = null; + } finally { + attachmentOrByteBufferField.setAccessible(attachedObjectOrByteBufferFieldWasAccessible); + } + if (attachedObjectOrByteBuffer instanceof Buffer) { + attachmentBufferOrByteBuffer = (Buffer) attachedObjectOrByteBuffer; + } else { + attachmentBufferOrByteBuffer = null; + } + } + // if there is no buffer inside the buffer given in input + if (attachmentBufferOrByteBuffer == null) {// if it's a direct byte + // buffer and if it's an + // instance of + // a deallocatable buffer + // class + if (buffer instanceof ByteBuffer && deallocatableBufferClassSet.contains(bufferClass)) { + deallocatableDirectByteBuffer = (ByteBuffer) buffer; + } else {// it's not a byte buffer or it's not a + // deallocatable buffer + deallocatableDirectByteBuffer = null; + final String bufferClassName = bufferClass.getName(); + logger.warning("No deallocatable buffer has been found for an instance of the class " + bufferClassName + " whereas it is a direct NIO buffer"); + } + } else {// the passed buffer contains another buffer, looks for a + // deallocatable buffer inside it + deallocatableDirectByteBuffer = findDeallocatableBuffer(attachmentBufferOrByteBuffer); + } + } else {// there is no need to clean the heap based buffers + deallocatableDirectByteBuffer = null; + } + return deallocatableDirectByteBuffer; + } + + public void deallocate(final Buffer buffer) { + if (deallocator != null) { + final ByteBuffer deallocatableBuffer = findDeallocatableBuffer(buffer); + if (deallocatableBuffer != null) { + deallocator.run(deallocatableBuffer); + } + } + } + + public Deallocator getDeallocator() { + return (deallocator); + } + + public void setDeallocator(Deallocator deallocator) { + this.deallocator = deallocator; + } + + public Map, Field> getAttachmentOrByteBufferFieldMap() { + return (attachmentOrByteBufferFieldMap); + } + + public void setAttachmentOrByteBufferFieldMap(Map, Field> attachmentOrByteBufferFieldMap) { + this.attachmentOrByteBufferFieldMap = attachmentOrByteBufferFieldMap; + } + + public Set> getDeallocatableBufferClassSet() { + return (deallocatableBufferClassSet); + } + + public void setDeallocatableBufferClassSet(Set> deallocatableBufferClassSet) { + this.deallocatableBufferClassSet = deallocatableBufferClassSet; + } +} diff --git a/src/org/warp/picalculator/gui/graphicengine/gpu/GPUDisplay.java b/src/org/warp/picalculator/gui/graphicengine/gpu/GPUDisplay.java index e08b85da..32d1f1a8 100644 --- a/src/org/warp/picalculator/gui/graphicengine/gpu/GPUDisplay.java +++ b/src/org/warp/picalculator/gui/graphicengine/gpu/GPUDisplay.java @@ -1,23 +1,28 @@ package org.warp.picalculator.gui.graphicengine.gpu; -import java.awt.image.BufferedImage; +import java.io.IOException; import org.warp.picalculator.Main; import org.warp.picalculator.Utils; import org.warp.picalculator.gui.graphicengine.Drawable; -import org.warp.picalculator.gui.graphicengine.Renderer; +import org.warp.picalculator.gui.graphicengine.RAWFont; +import org.warp.picalculator.gui.graphicengine.RAWSkin; + +import com.jogamp.opengl.GLProfile; +import com.jogamp.opengl.egl.EGL; public class GPUDisplay implements org.warp.picalculator.gui.graphicengine.Display { - private boolean initialized = false; - private CalculatorWindow wnd; + private volatile boolean initialized = false; + private volatile boolean created = false; + private NEWTWindow wnd; private Drawable d; private GPURenderer r; - + int[] size = new int[]{Main.screenSize[0], Main.screenSize[1]}; + @Override public int[] getSize() { - // TODO Auto-generated method stub - return null; + return size; } @Override @@ -27,8 +32,7 @@ public class GPUDisplay implements org.warp.picalculator.gui.graphicengine.Displ @Override public void setTitle(String title) { - // TODO Auto-generated method stub - + wnd.window.setTitle(title); } @Override @@ -38,59 +42,59 @@ public class GPUDisplay implements org.warp.picalculator.gui.graphicengine.Displ } wnd.window.setResizable(r); wnd.window.setUndecorated(!r); - wnd.window.setPointerVisible(r); + wnd.window.setPointerVisible(r); } @Override public void setDisplayMode(int ww, int wh) { + this.size[0] = ww; + this.size[1] = wh; wnd.window.setSize(ww, wh); } @Override public void create() { + created = true; r = new GPURenderer(); - wnd = new CalculatorWindow(this); + wnd = new NEWTWindow(this); wnd.create(); setDisplayMode(Main.screenSize[0], Main.screenSize[1]); - setResizable(Utils.debugOn&!Utils.debugThirdScreen); + setResizable(Utils.debugOn & !Utils.debugThirdScreen); initialized = true; } @Override public boolean wasResized() { - // TODO Auto-generated method stub - return false; + return Main.screenSize[0] != size[0] | Main.screenSize[1] != size[1]; } @Override public int getWidth() { - // TODO Auto-generated method stub - return 0; + return size[0]; } @Override public int getHeight() { - // TODO Auto-generated method stub - return 0; + return size[1]; } @Override public void destroy() { -// EGL.destroy(); (Automatic) + initialized = false; + created = false; + wnd.window.destroy(); } @Override public void start(Drawable d) { - this.d = d; - wnd.window.setVisible(true); + this.d = d; + wnd.window.setVisible(true); } @Override public void repaint() { - if (d != null) { - r.gl.glClearColor(red, green, blue, alpha); + if (d != null & r != null && r.gl != null) { d.refresh(); - r.glFlush(); } } @@ -99,4 +103,30 @@ public class GPUDisplay implements org.warp.picalculator.gui.graphicengine.Displ return r; } + @Override + public RAWFont loadFont(String file) throws IOException { + return new GPUFont(file); + } + + @Override + public RAWSkin loadSkin(String file) throws IOException { + return new GPUSkin(file); + } + + @Override + public void waitUntilExit() { + try { + do { + Thread.sleep(500); + } while(initialized | created); + } catch (InterruptedException e) { + + } + } + + @Override + public boolean isSupported() { + return GLProfile.isAnyAvailable() == false; + } + } diff --git a/src/org/warp/picalculator/gui/graphicengine/gpu/GPUFont.java b/src/org/warp/picalculator/gui/graphicengine/gpu/GPUFont.java new file mode 100644 index 00000000..a56b2fe4 --- /dev/null +++ b/src/org/warp/picalculator/gui/graphicengine/gpu/GPUFont.java @@ -0,0 +1,140 @@ +package org.warp.picalculator.gui.graphicengine.gpu; + +import java.awt.image.BufferedImage; +import java.io.File; +import java.io.IOException; + +import javax.imageio.ImageIO; + +import org.warp.picalculator.gui.graphicengine.Display; +import org.warp.picalculator.gui.graphicengine.RAWFont; +import org.warp.picalculator.gui.graphicengine.cpu.CPUFont; + +import com.jogamp.opengl.GLException; +import com.jogamp.opengl.util.texture.Texture; + +public class GPUFont implements RAWFont { + + public Texture texture; + public int textureW; + public int textureH; + public int charW; + public int charH; + public int minCharIndex; + public int maxCharIndex; + + public int memoryWidth; + public int memoryHeight; + public int memoryWidthOfEachColumn; + + private boolean initialized = false; + private CPUFont tmpFont; + + GPUFont(String file) throws IOException { + load(file); + } + + @Override + public void load(String file) throws IOException { + CPUFont font = CPUFont.loadTemporaryFont(file); + charW = font.charW; + charH = font.charH; + minCharIndex = font.minBound; + maxCharIndex = font.maxBound; + tmpFont = font; + font = null; + } + + public int[] getCharIndexes(String txt) { + final int l = txt.length(); + final int[] indexes = new int[l]; + final char[] chars = txt.toCharArray(); + for (int i = 0; i < l; i++) { + indexes[i] = (chars[i] & 0xFFFF) - minCharIndex; + } + return indexes; + } + + private void genTexture(boolean[][] chars) { + final double totalChars = maxCharIndex - minCharIndex; + final int w = powerOf2((int) (Math.ceil(Math.sqrt(totalChars) * charW))); + final int h = powerOf2((int) (Math.ceil(Math.sqrt(totalChars) * charH))); + final int maxIndexW = (int) Math.floor(((double) w) / ((double) charW)) - 1; + BufferedImage bfi = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB); + int indexX = 0; + int indexY = 0; + for (int i = 0; i < totalChars; i++) { + boolean[] currentChar = chars[i]; + if (currentChar != null && currentChar.length > 0) { + for (int charY = 0; charY < charH; charY++) { + for (int charX = 0; charX < charW; charX++) { + if (currentChar[charY*charW+charX]) { + bfi.setRGB(indexX * charW + charX, indexY * charH + charY, 0xFFFFFFFF); + } + } + } + } + indexX++; + if (indexX >= maxIndexW) { + indexX = 0; + indexY += 1; + } + currentChar = null; + } + try { + memoryWidth = w; + memoryHeight = h; + memoryWidthOfEachColumn = maxIndexW; + texture = GPURenderer.importTexture(bfi); + textureW = bfi.getWidth(); + textureH = bfi.getHeight(); + bfi.flush(); + bfi = null; + } catch (GLException | IOException e) { + e.printStackTrace(); + } + } + + private int powerOf2(int a) { + return (int) (a == 0 ? 0 : Math.pow(2, 32 - Integer.numberOfLeadingZeros(a - 1))); + } + + @Override + public void initialize(Display d) { + genTexture(tmpFont.rawchars); + tmpFont.chars32 = null; + tmpFont.rawchars = null; + tmpFont = null; + initialized = true; + } + + @Override + public void use(Display d) { + if (!initialized) { + initialize(d); + } + final GPURenderer r = (GPURenderer) d.getRenderer(); + r.currentFont = this; + r.useTexture(texture, textureW, textureH); + } + + @Override + public int getStringWidth(String text) { + final int w = (charW + 1) * text.length(); + if (text.length() > 0) { + return w - 1; + } else { + return 0; + } + } + + @Override + public int getCharacterWidth() { + return charW; + } + + @Override + public int getCharacterHeight() { + return charH; + } +} \ No newline at end of file diff --git a/src/org/warp/picalculator/gui/graphicengine/gpu/GPURenderer.java b/src/org/warp/picalculator/gui/graphicengine/gpu/GPURenderer.java index 9ae6b3eb..48f8ec1a 100644 --- a/src/org/warp/picalculator/gui/graphicengine/gpu/GPURenderer.java +++ b/src/org/warp/picalculator/gui/graphicengine/gpu/GPURenderer.java @@ -2,123 +2,261 @@ package org.warp.picalculator.gui.graphicengine.gpu; import java.awt.FontMetrics; import java.awt.image.BufferedImage; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.nio.Buffer; +import java.nio.FloatBuffer; +import javax.imageio.ImageIO; import org.warp.picalculator.gui.graphicengine.RAWFont; import org.warp.picalculator.gui.graphicengine.Renderer; -import com.jogamp.opengl.GL2ES2; +import com.jogamp.common.nio.Buffers; +import com.jogamp.opengl.GL; +import com.jogamp.opengl.GL2ES1; +import com.jogamp.opengl.GLException; +import com.jogamp.opengl.util.texture.Texture; +import com.jogamp.opengl.util.texture.TextureData; +import com.jogamp.opengl.util.texture.TextureIO; public class GPURenderer implements Renderer { - public GL2ES2 gl; + public GL2ES1 gl; + + private final DeallocationHelper deallocationHelper = new DeallocationHelper(); + FloatBuffer fbVertices; + FloatBuffer txVertices; + FloatBuffer colVertices; + int fbElements; + + float[] currentColor = new float[16]; + float[] currentClearColorARGBf = new float[]{1f, 197f/255f, 194f/255f, 175f/255f}; + boolean currentTexEnabled; + Texture currentTex; + float currentTexWidth; + float currentTexHeight; + + GPUFont currentFont; @Override public void glColor3i(int r, int gg, int b) { - // TODO Auto-generated method stub - + final float red = ((float)r) / 255f; + final float gre = ((float)gg) / 255f; + final float blu = ((float)b) / 255f; + currentColor = new float[] { red, gre, blu, 1.0f, red, gre, blu, 1.0f, red, gre, blu, 1.0f, red, gre, blu, 1.0f, }; } @Override - public void glColor(int c) { - // TODO Auto-generated method stub - + public void glColor3f(float red, float gre, float blu) { + currentColor = new float[] { red, gre, blu, 1.0f, red, gre, blu, 1.0f, red, gre, blu, 1.0f, red, gre, blu, 1.0f, }; + } + + @Override + public void glColor4f(float red, float gre, float blu, float alp) { + currentColor = new float[] { red, gre, blu, alp, red, gre, blu, alp, red, gre, blu, alp, red, gre, blu, alp, }; + } + + @Override + public void glColor(int rgb) { + final int alpha = (rgb >> 24) & 0xFF; + final int red = (rgb >> 16) & 0xFF; + final int green = (rgb >> 8) & 0xFF; + final int blue = rgb & 0xFF; + glColor4i(red, green, blue, alpha); } @Override public int glGetClearColor() { - // TODO Auto-generated method stub - return 0; + return (int)(currentClearColorARGBf[0] * 255) << 24 | (int)(currentClearColorARGBf[1] * 255) << 16 | (int)(currentClearColorARGBf[2] * 255) << 8 | (int)(currentClearColorARGBf[3] * 255); } @Override - public void glClearColor(int c) { - // TODO Auto-generated method stub - + public void glClearColor(int rgb) { + final float alpha = (float)((rgb >> 24) & 0xFF) / 255f; + final float red = (float)((rgb >> 16) & 0xFF) / 255f; + final float green = (float)((rgb >> 8) & 0xFF) / 255f; + final float blue = (float)(rgb & 0xFF) / 255f; + glClearColor4f(red, green, blue, alpha); } @Override - public void glColor4i(int red, int green, int blue, int alpha) { - // TODO Auto-generated method stub - + public void glColor4i(int r, int g, int b, int a) { + final float red = (r) / 255f; + final float gre = (g) / 255f; + final float blu = (b) / 255f; + final float alp = (a) / 255f; + currentColor = new float[] { red, gre, blu, alp, red, gre, blu, alp, red, gre, blu, alp, red, gre, blu, alp, }; } @Override - public void glClearColor(int red, int green, int blue, int alpha) { - // TODO Auto-generated method stub - + public void glClearColor4i(int red, int green, int blue, int alpha) { + final float ros = (red) / 255f; + final float gre = (green) / 255f; + final float blu = (blue) / 255f; + final float alp = (alpha) / 255f; + currentClearColorARGBf = new float[]{alp, ros, gre, blu}; } @Override - public void glClear() { - // TODO Auto-generated method stub - + public void glClearColor4f(float red, float green, float blue, float alpha) { + currentClearColorARGBf = new float[]{alpha, red, green, blue}; } @Override - public void glDrawSkin(int skinwidth, int[] skin, int x0, int y0, int s0, int t0, int s1, int t1, - boolean transparent) { - // TODO Auto-generated method stub - + public void glClear(int screenWidth, int screenHeight) { + glColor(glGetClearColor()); + glFillColor(0, 0, screenWidth, screenHeight); } @Override public void glDrawLine(int x0, int y0, int x1, int y1) { - // TODO Auto-generated method stub - + glFillColor(x0, y0, x1-x0+1, y1-y0+1); } @Override - public void glFillRect(int x0, int y0, int w1, int h1) { - // TODO Auto-generated method stub - + public void glFillRect(int x, int y, int width, int height, float uvX, float uvY, float uvWidth, float uvHeight) { + enableTexture(); + uvWidth/=currentTexWidth; + uvX/=currentTexWidth; + uvHeight/=currentTexHeight; + uvY = 1 - uvY/currentTexHeight - uvHeight; + final float[] vertices = { x, y, 0.0f, x, y + height, 0.0f, x + width, y, 0.0f, x + width, y + height, 0.0f, }; + final float[] tex_vertices = { uvX, uvY + uvHeight, uvX, uvY, uvX + uvWidth, uvY + uvHeight, uvX + uvWidth, uvY, }; + fbElements++; + fbVertices.put(vertices); + txVertices.put(tex_vertices); + colVertices.put(currentColor); } @Override - public int[] getMatrixOfImage(BufferedImage bufferedImage) { - // TODO Auto-generated method stub - return null; + public void glFillColor(int x0, int y0, int w1, int h1) { + disableTexture(); + final float[] vertices = { x0, y0, 0.0f, x0, y0 + h1, 0.0f, x0 + w1, y0, 0.0f, x0 + w1, y0 + h1, 0.0f, }; + final float[] tex_vertices = { 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, 0.0f, }; + fbElements++; + fbVertices.put(vertices); + txVertices.put(tex_vertices); + colVertices.put(currentColor); } @Override public void glDrawStringLeft(int x, int y, String text) { - // TODO Auto-generated method stub - + final int txtLen = text.length(); + int[] txtArray = currentFont.getCharIndexes(text); + int tableIndexX; + int tableIndexY; + for (int currentCharIndex = 0; currentCharIndex < txtLen; currentCharIndex++) { + tableIndexX = txtArray[currentCharIndex] % currentFont.memoryWidthOfEachColumn; + tableIndexY = (txtArray[currentCharIndex] - tableIndexX) / currentFont.memoryWidthOfEachColumn; + glFillRect(x + currentCharIndex * (currentFont.charW + 1), y, currentFont.charW, currentFont.charH, tableIndexX*currentFont.charW, tableIndexY*currentFont.charH, currentFont.charW, currentFont.charH); + } } @Override public void glDrawStringCenter(int x, int y, String text) { - // TODO Auto-generated method stub - + glDrawStringLeft(x - (currentFont.getStringWidth(text) / 2), y, text); } @Override public void glDrawStringRight(int x, int y, String text) { - // TODO Auto-generated method stub - - } - - @Override - public void glSetFont(RAWFont font) { - // TODO Auto-generated method stub - - } - - @Override - public int glGetStringWidth(RAWFont rf, String text) { - // TODO Auto-generated method stub - return 0; - } - - @Override - public int glGetFontWidth(FontMetrics fm, String text) { - // TODO Auto-generated method stub - return 0; + glDrawStringLeft(x - currentFont.getStringWidth(text), y, text); } @Override public RAWFont getCurrentFont() { - // TODO Auto-generated method stub - return null; + return currentFont; } + static Texture importTexture(GL gl, String string) throws IOException { + final FileInputStream f = new FileInputStream("test.png"); + final TextureData tx_dat = TextureIO.newTextureData(gl.getGLProfile(), f, false, TextureIO.PNG); + final Texture tex = new Texture(gl, tx_dat); + tex.setTexParameteri(gl, GL.GL_TEXTURE_MIN_FILTER, GL.GL_LINEAR); + tex.setTexParameteri(gl, GL.GL_TEXTURE_MAG_FILTER, GL.GL_NEAREST); + tex.setTexParameteri(gl, GL.GL_TEXTURE_WRAP_S, GL.GL_CLAMP_TO_EDGE); + tex.setTexParameteri(gl, GL.GL_TEXTURE_WRAP_T, GL.GL_CLAMP_TO_EDGE); + return tex; + } + + static BufferedImage openTexture(String file) throws GLException, IOException { + final ByteArrayOutputStream os = new ByteArrayOutputStream(); + return ImageIO.read(GPURenderer.class.getClassLoader().getResource(file)); + } + + static Texture importTexture(BufferedImage img) throws GLException, IOException { + final ByteArrayOutputStream os = new ByteArrayOutputStream(); + ImageIO.write(img, "png", os); + final InputStream fis = new ByteArrayInputStream(os.toByteArray()); + return TextureIO.newTexture(fis, false, TextureIO.PNG); + } + + @Override + public void glClearSkin() { + if (currentTex != null) { + currentTex = null; + endDrawCycle(); + startDrawCycle(); + } + } + + public void startDrawCycle() { + fbVertices = Buffers.newDirectFloatBuffer(3 * 4); + txVertices = Buffers.newDirectFloatBuffer(2 * 4); + colVertices = Buffers.newDirectFloatBuffer(4 * 4); + fbElements = 0; + } + + public void endDrawCycle() { + fbVertices.rewind(); + txVertices.rewind(); + colVertices.rewind(); + + gl.glColorPointer(4, GL.GL_FLOAT, 0, colVertices); + gl.glTexCoordPointer(2, GL.GL_FLOAT, 0, txVertices); + gl.glVertexPointer(3, GL.GL_FLOAT, 0, fbVertices); + + if (currentTexEnabled) { + gl.glEnable(GL2ES1.GL_TEXTURE_2D); + currentTex.bind(gl); + } else { + gl.glDisable(GL2ES1.GL_TEXTURE_2D); + } + + gl.glDrawArrays(GL.GL_TRIANGLE_STRIP, 0, 4); + + deleteBuffer(fbVertices); + deleteBuffer(txVertices); + deleteBuffer(colVertices); + fbVertices = null; + txVertices = null; + colVertices = null; + } + + public void deleteBuffer(final Buffer realNioBuffer) { + if (deallocationHelper != null) { + deallocationHelper.deallocate(realNioBuffer); + } + } + + void disableTexture() { + endDrawCycle(); + startDrawCycle(); + currentTexEnabled = false; + } + + void enableTexture() { + endDrawCycle(); + startDrawCycle(); + currentTexEnabled = true; + } + + void useTexture(Texture t, float w, float h) { + enableTexture(); + currentTex = t; + currentTexWidth = w; + currentTexHeight = h; + } } diff --git a/src/org/warp/picalculator/gui/graphicengine/gpu/GPUSkin.java b/src/org/warp/picalculator/gui/graphicengine/gpu/GPUSkin.java new file mode 100644 index 00000000..9648de84 --- /dev/null +++ b/src/org/warp/picalculator/gui/graphicengine/gpu/GPUSkin.java @@ -0,0 +1,58 @@ +package org.warp.picalculator.gui.graphicengine.gpu; + +import java.awt.image.BufferedImage; +import java.io.IOException; +import org.warp.picalculator.gui.graphicengine.Display; +import org.warp.picalculator.gui.graphicengine.RAWSkin; + +import com.jogamp.opengl.GL2ES1; +import com.jogamp.opengl.GLException; +import com.jogamp.opengl.util.texture.Texture; + +public class GPUSkin implements RAWSkin { + + public Texture t; + public int w; + public int h; + + private String texturePath; + private boolean initialized = false; + + GPUSkin(String file) throws IOException { + load(file); + } + + @Override + public void load(String file) throws IOException { + if ((this.getClass().getClassLoader().getResource(file)) == null) { + throw new IOException("File '" + file + "' not found!"); + } + texturePath = file; + } + + @Override + public void initialize(Display d) { + try { + BufferedImage i = GPURenderer.openTexture(texturePath); + GL2ES1 gl = ((GPURenderer)d.getRenderer()).gl; + t = GPURenderer.importTexture(i); + w = i.getWidth(); + h = i.getHeight(); + t.setTexParameteri(gl, GL2ES1.GL_TEXTURE_MAG_FILTER, GL2ES1.GL_NEAREST); + initialized = true; + } catch (GLException | IOException e) { + e.printStackTrace(); + System.exit(1); + } + } + + @Override + public void use(Display d) { + if (!initialized) { + initialize(d); + } + final GPURenderer r = (GPURenderer) d.getRenderer(); + r.useTexture(t,w,h); + } + +} diff --git a/src/org/warp/picalculator/gui/graphicengine/gpu/NEWTWindow.java b/src/org/warp/picalculator/gui/graphicengine/gpu/NEWTWindow.java new file mode 100644 index 00000000..84c14239 --- /dev/null +++ b/src/org/warp/picalculator/gui/graphicengine/gpu/NEWTWindow.java @@ -0,0 +1,381 @@ +/** + * Copyright 2012-2013 JogAmp Community. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of JogAmp Community. + */ + +package org.warp.picalculator.gui.graphicengine.gpu; + +import com.jogamp.opengl.GL; +import com.jogamp.opengl.GL2ES1; +import com.jogamp.opengl.GLAutoDrawable; +import com.jogamp.opengl.GLEventListener; +import com.jogamp.opengl.GLProfile; +import com.jogamp.opengl.fixedfunc.GLMatrixFunc; +import com.jogamp.opengl.fixedfunc.GLPointerFunc; +import com.jogamp.opengl.GLCapabilities; +import com.jogamp.newt.event.KeyEvent; +import com.jogamp.newt.event.KeyListener; +import com.jogamp.newt.event.WindowEvent; +import com.jogamp.newt.event.WindowListener; +import com.jogamp.newt.event.WindowUpdateEvent; +import com.jogamp.newt.opengl.GLWindow; + +import com.jogamp.opengl.util.*; + +import java.awt.event.ComponentEvent; +import java.awt.event.ComponentListener; + +import org.warp.picalculator.device.Keyboard; +import org.warp.picalculator.device.Keyboard.Key; +import org.warp.picalculator.gui.DisplayManager; +import org.warp.picalculator.gui.graphicengine.Display; + +/** + *
+ *   __ __|_  ___________________________________________________________________________  ___|__ __
+ *  //    /\                                           _                                  /\    \\
+ * //____/  \__     __ _____ _____ _____ _____ _____  | |     __ _____ _____ __        __/  \____\\
+ *  \    \  / /  __|  |     |   __|  _  |     |  _  | | |  __|  |     |   __|  |      /\ \  /    /
+ *   \____\/_/  |  |  |  |  |  |  |     | | | |   __| | | |  |  |  |  |  |  |  |__   "  \_\/____/
+ *  /\    \     |_____|_____|_____|__|__|_|_|_|__|    | | |_____|_____|_____|_____|  _  /    /\
+ * /  \____\                       http://jogamp.org  |_|                              /____/  \
+ * \  /   "' _________________________________________________________________________ `"   \  /
+ *  \/____.                                                                             .____\/
+ * 
+ * + *

+ * JOGL2 OpenGL ES 2 demo to expose and learn what the RAW OpenGL ES 2 API looks + * like. + * + * Compile, run and enjoy: + * wget + * http://jogamp.org/deployment/jogamp-current/archive/jogamp-all-platforms.7z + * 7z x jogamp-all-platforms.7z + * cd jogamp-all-platforms + * mkdir -p demos/es2 + * cd demos/es2 + * wget + * https://raw.github.com/xranby/jogl-demos/master/src/demos/es2/RawGL2ES1demo.java + * cd ../.. + * javac -cp jar/jogl-all.jar:jar/gluegen-rt.jar demos/es2/RawGL2ES1demo.java + * java -cp jar/jogl-all.jar:jar/gluegen-rt.jar:. demos.es2.RawGL2ES1demo + *

+ * + * + * @author Xerxes Rånby (xranby) + */ + +public class NEWTWindow implements GLEventListener { + + private final GPUDisplay disp; + private final GPURenderer renderer; + + public NEWTWindow(GPUDisplay disp) { + this.disp = disp; + renderer = disp.getRenderer(); + } + + public GLWindow window; + + public void create() { + /* This demo are based on the GL2ES1 GLProfile that uses common hardware acceleration + * functionality of desktop OpenGL 3, 2 and mobile OpenGL ES 2 devices. + * JogAmp JOGL will probe all the installed libGL.so, libEGL.so and libGLESv2.so librarys on + * the system to find which one provide hardware acceleration for your GPU device. + * Its common to find more than one version of these librarys installed on a system. + * For example on a ARM Linux system JOGL may find + * Hardware accelerated Nvidia tegra GPU drivers in: /usr/lib/nvidia-tegra/libEGL.so + * Software rendered Mesa Gallium driver in: /usr/lib/arm-linux-gnueabi/mesa-egl/libEGL.so.1 + * Software rendered Mesa X11 in: /usr/lib/arm-linux-gnueabi/mesa/libGL.so + * Good news!: JOGL does all this probing for you all you have to do are to ask for + * the GLProfile you want to use. + */ + + System.out.println("Loading OpenGL..."); + System.out.println(GLProfile.glAvailabilityToString()); + if (GLProfile.isAnyAvailable()) { + System.err.println("Le OpenGL non sono presenti su questo computer!"); + } + final GLCapabilities caps = new GLCapabilities(GLProfile.get(GLProfile.GL2ES1)); + System.out.println("Loaded OpenGL"); + // We may at this point tweak the caps and request a translucent drawable + caps.setBackgroundOpaque(true); //transparency window + final GLWindow glWindow = GLWindow.create(caps); + window = glWindow; + + glWindow.setTitle("Algebraic Calculator for Raspberry PI by Andrea Cavalli (XDrake99)"); + + glWindow.addWindowListener(new WindowListener() { + + @Override + public void windowDestroyNotify(WindowEvent e) { + // TODO Auto-generated method stub + + } + + @Override + public void windowDestroyed(WindowEvent e) { + DisplayManager.display.destroy(); + } + + @Override + public void windowGainedFocus(WindowEvent e) { + // TODO Auto-generated method stub + + } + + @Override + public void windowLostFocus(WindowEvent e) { + // TODO Auto-generated method stub + + } + + @Override + public void windowMoved(WindowEvent e) { + // TODO Auto-generated method stub + + } + + @Override + public void windowRepaint(WindowUpdateEvent e) { + // TODO Auto-generated method stub + + } + + @Override + public void windowResized(WindowEvent e) { + + } + + }); + glWindow.addKeyListener(new KeyListener() { + @Override + public void keyPressed(KeyEvent arg0) { + Keyboard.debugKeyCode = arg0.getKeyCode(); + } + + @Override + public void keyReleased(KeyEvent arg0) { + switch (arg0.getKeyCode()) { + case KeyEvent.VK_ESCAPE: + Keyboard.keyReleased(Key.POWER); + break; + case KeyEvent.VK_D: + Keyboard.keyReleased(Key.debug_DEG); + break; + case KeyEvent.VK_R: + Keyboard.keyReleased(Key.debug_RAD); + break; + case KeyEvent.VK_G: + Keyboard.keyReleased(Key.debug_GRA); + break; + case KeyEvent.VK_X: + if (Keyboard.alpha) { + Keyboard.keyReleased(Key.LETTER_X); + } else { + Keyboard.keyReleased(Key.NONE); + } + break; + case KeyEvent.VK_P: + if (Keyboard.alpha) { + Keyboard.keyReleased(Key.PI); + } else { + Keyboard.keyReleased(Key.NONE); + } + break; + case KeyEvent.VK_B: + if (Keyboard.shift) { + Keyboard.keyReleased(Key.BRIGHTNESS_CYCLE_REVERSE); + } else if (!Keyboard.shift && !Keyboard.alpha) { + Keyboard.keyReleased(Key.BRIGHTNESS_CYCLE); + } else { + Keyboard.keyReleased(Key.NONE); + } + break; + case KeyEvent.VK_ENTER: + if (!Keyboard.shift && !Keyboard.alpha) { + Keyboard.keyReleased(Key.SOLVE); + } else { + Keyboard.keyReleased(Key.NONE); + } + int row = 2; + int col = 1; + Keyboard.debugKeysDown[row - 1][col - 1] = false; + break; + case KeyEvent.VK_1: + if (!Keyboard.shift && !Keyboard.alpha) { + Keyboard.keyReleased(Key.debug1); + } else { + Keyboard.keyReleased(Key.NONE); + } + break; + case KeyEvent.VK_2: + if (!Keyboard.shift && !Keyboard.alpha) { + Keyboard.keyReleased(Key.debug2); + } else { + Keyboard.keyReleased(Key.NONE); + } + break; + case KeyEvent.VK_3: + if (!Keyboard.shift && !Keyboard.alpha) { + Keyboard.keyReleased(Key.debug3); + } else { + Keyboard.keyReleased(Key.NONE); + } + break; + case KeyEvent.VK_4: + if (!Keyboard.shift && !Keyboard.alpha) { + Keyboard.keyReleased(Key.debug4); + } else { + Keyboard.keyReleased(Key.NONE); + } + break; + case KeyEvent.VK_5: + if (!Keyboard.shift && !Keyboard.alpha) { + Keyboard.keyReleased(Key.debug5); + } else { + Keyboard.keyReleased(Key.NONE); + } + break; + case 0x15: + case KeyEvent.VK_SHIFT: + Keyboard.keyReleased(Key.SHIFT); + break; + case KeyEvent.VK_A: + Keyboard.keyReleased(Key.ALPHA); + break; + case KeyEvent.VK_M: + Keyboard.keyPressed(Key.SURD_MODE); + break; + case KeyEvent.VK_LEFT: + //LEFT + row = 2; + col = 3; + Keyboard.debugKeysDown[row - 1][col - 1] = false; + case KeyEvent.VK_RIGHT: + //RIGHT + row = 2; + col = 5; + Keyboard.debugKeysDown[row - 1][col - 1] = false; + } + } + }); + + glWindow.addGLEventListener(this /* GLEventListener */); + final Animator animator = new Animator(); + animator.add(glWindow); + animator.start(); + } + + @Override + public void init(GLAutoDrawable drawable) { + final GL2ES1 gl = drawable.getGL().getGL2ES1(); + + //Vsync + gl.setSwapInterval(2); + + //Textures + gl.glEnable(GL.GL_TEXTURE_2D); + + //Transparency + gl.glEnable(GL2ES1.GL_BLEND); + gl.glBlendFunc(GL2ES1.GL_SRC_ALPHA, GL2ES1.GL_ONE_MINUS_SRC_ALPHA); + + try { + renderer.currentTex = ((GPUSkin) disp.loadSkin("test.png")).t; + } catch (final Exception e) { + e.printStackTrace(); + } + + System.err.println("Chosen GLCapabilities: " + drawable.getChosenGLCapabilities()); + System.err.println("INIT GL IS: " + gl.getClass().getName()); + System.err.println("GL_VENDOR: " + gl.glGetString(GL.GL_VENDOR)); + System.err.println("GL_RENDERER: " + gl.glGetString(GL.GL_RENDERER)); + System.err.println("GL_VERSION: " + gl.glGetString(GL.GL_VERSION)); + } + + @Override + public void reshape(GLAutoDrawable glad, int x, int y, int width, int height) { + disp.size[0] = width; + disp.size[1] = height; + final GL2ES1 gl = glad.getGL().getGL2ES1(); + float max_wh, min_wh; + if (width == 0) { + width = 1; + } + if (height == 0) { + height = 1; + } + if (width > height) { + max_wh = width; + min_wh = height; + } else { + max_wh = height; + min_wh = width; + } + + gl.glViewport(0, 0, width, height); + + gl.glMatrixMode(GLMatrixFunc.GL_PROJECTION); + gl.glLoadIdentity(); + + gl.glOrtho(0.0, width, height, 0.0, -1, 1); + + gl.glMatrixMode(GLMatrixFunc.GL_MODELVIEW); + gl.glLoadIdentity(); + } + + @Override + public void display(GLAutoDrawable glad) { + final GL2ES1 gl = glad.getGL().getGL2ES1(); + + renderer.gl = gl; + + gl.glEnableClientState(GLPointerFunc.GL_COLOR_ARRAY); + gl.glEnableClientState(GLPointerFunc.GL_VERTEX_ARRAY); + gl.glEnableClientState(GLPointerFunc.GL_TEXTURE_COORD_ARRAY); + + renderer.startDrawCycle(); + + disp.repaint(); + + renderer.endDrawCycle(); + + renderer.gl = null; + + gl.glDisableClientState(GLPointerFunc.GL_COLOR_ARRAY); + gl.glDisableClientState(GLPointerFunc.GL_TEXTURE_COORD_ARRAY); + gl.glDisableClientState(GLPointerFunc.GL_VERTEX_ARRAY); + } + + @Override + public void dispose(GLAutoDrawable drawable) { + System.out.println("cleanup"); + final GL2ES1 gl = drawable.getGL().getGL2ES1(); + System.exit(0); + } + +} \ No newline at end of file diff --git a/src/org/warp/picalculator/gui/screens/ChooseVariableValueScreen.java b/src/org/warp/picalculator/gui/screens/ChooseVariableValueScreen.java index e0bcf95e..3d8d5aee 100644 --- a/src/org/warp/picalculator/gui/screens/ChooseVariableValueScreen.java +++ b/src/org/warp/picalculator/gui/screens/ChooseVariableValueScreen.java @@ -1,44 +1,53 @@ package org.warp.picalculator.gui.screens; import org.warp.picalculator.Main; +import org.warp.picalculator.Utils; import org.warp.picalculator.device.Keyboard.Key; -import org.warp.picalculator.gui.PIDisplay; +import org.warp.picalculator.gui.DisplayManager; import org.warp.picalculator.math.functions.Function; import org.warp.picalculator.math.functions.Variable.VariableValue; public class ChooseVariableValueScreen extends Screen { @SuppressWarnings("unused") - private MathInputScreen es; + private final MathInputScreen es; public Function resultNumberValue; public ChooseVariableValueScreen(MathInputScreen es, VariableValue variableValue) { super(); canBeInHistory = false; - + this.es = es; } - + @Override - public void created() throws InterruptedException { - } + public void created() throws InterruptedException {} @Override public void init() throws InterruptedException {} @Override public void render() { - PIDisplay.renderer.glColor4i(0, 0, 0, 64); - PIDisplay.renderer.glDrawStringCenter(Main.screenSize[0]/2+1, Main.screenSize[1]/4, "WORK IN PROGRESS. THIS SCREEN MUST HAVE A GUI TO SELECT THE VARIABLE TO SOLVE."); - PIDisplay.renderer.glDrawStringCenter(Main.screenSize[0]/2, Main.screenSize[1]/4+1, "WORK IN PROGRESS. THIS SCREEN MUST HAVE A GUI TO SELECT THE VARIABLE TO SOLVE."); - PIDisplay.renderer.glDrawStringCenter(Main.screenSize[0]/2+1, Main.screenSize[1]/4+1, "WORK IN PROGRESS. THIS SCREEN MUST HAVE A GUI TO SELECT THE VARIABLE TO SOLVE."); - PIDisplay.renderer.glColor3i(255, 0, 0); - PIDisplay.renderer.glDrawStringCenter(Main.screenSize[0]/2, Main.screenSize[1]/4, "WORK IN PROGRESS. THIS SCREEN MUST HAVE A GUI TO SELECT THE VARIABLE TO SOLVE."); + Utils.getFont(false, true).use(DisplayManager.display); + DisplayManager.renderer.glColor4i(0, 0, 0, 64); + DisplayManager.renderer.glDrawStringCenter(Main.screenSize[0] / 2 + 1, Main.screenSize[1] / 2 - 20, "WORK IN PROGRESS."); + DisplayManager.renderer.glDrawStringCenter(Main.screenSize[0] / 2, Main.screenSize[1] / 2 - 20 + 1, "WORK IN PROGRESS."); + DisplayManager.renderer.glDrawStringCenter(Main.screenSize[0] / 2 + 1, Main.screenSize[1] / 2 - 20 + 1, "WORK IN PROGRESS."); + DisplayManager.renderer.glColor3i(255, 0, 0); + DisplayManager.renderer.glDrawStringCenter(Main.screenSize[0] / 2, Main.screenSize[1] / 2 - 20, "WORK IN PROGRESS."); + + Utils.getFont(false, false).use(DisplayManager.display); + DisplayManager.renderer.glColor4i(0, 0, 0, 64); + DisplayManager.renderer.glDrawStringCenter(Main.screenSize[0] / 2 + 1, Main.screenSize[1] / 2, "THIS SCREEN MUST HAVE A GUI TO SELECT THE VARIABLE TO SOLVE."); + DisplayManager.renderer.glDrawStringCenter(Main.screenSize[0] / 2, Main.screenSize[1] / 2 + 1, "THIS SCREEN MUST HAVE A GUI TO SELECT THE VARIABLE TO SOLVE."); + DisplayManager.renderer.glDrawStringCenter(Main.screenSize[0] / 2 + 1, Main.screenSize[1] / 2 + 1, "THIS SCREEN MUST HAVE A GUI TO SELECT THE VARIABLE TO SOLVE."); + DisplayManager.renderer.glColor3i(255, 0, 0); + DisplayManager.renderer.glDrawStringCenter(Main.screenSize[0] / 2, Main.screenSize[1] / 2, "THIS SCREEN MUST HAVE A GUI TO SELECT THE VARIABLE TO SOLVE."); } @Override public void beforeRender(float dt) { - + } @Override diff --git a/src/org/warp/picalculator/gui/screens/EmptyScreen.java b/src/org/warp/picalculator/gui/screens/EmptyScreen.java index 0fea5479..46f9b7da 100644 --- a/src/org/warp/picalculator/gui/screens/EmptyScreen.java +++ b/src/org/warp/picalculator/gui/screens/EmptyScreen.java @@ -10,7 +10,7 @@ public class EmptyScreen extends Screen { super(); canBeInHistory = false; } - + @Override public void created() throws InterruptedException { endLoading = 0; @@ -27,7 +27,7 @@ public class EmptyScreen extends Screen { @Override public void beforeRender(float dt) { - + } @Override @@ -37,7 +37,7 @@ public class EmptyScreen extends Screen { @Override public boolean keyPressed(Key k) { - + return false; } diff --git a/src/org/warp/picalculator/gui/screens/KeyboardDebugScreen.java b/src/org/warp/picalculator/gui/screens/KeyboardDebugScreen.java index 49ab8309..ac8627f3 100644 --- a/src/org/warp/picalculator/gui/screens/KeyboardDebugScreen.java +++ b/src/org/warp/picalculator/gui/screens/KeyboardDebugScreen.java @@ -1,12 +1,11 @@ package org.warp.picalculator.gui.screens; -import static org.warp.picalculator.device.graphicengine.cpu.CPUDisplay.Render.*; -import static org.warp.picalculator.gui.PIDisplay.colore; -import static org.warp.picalculator.gui.PIDisplay.fonts; +import static org.warp.picalculator.gui.DisplayManager.fonts; import org.warp.picalculator.Main; import org.warp.picalculator.device.Keyboard.Key; -import org.warp.picalculator.gui.PIDisplay; +import org.warp.picalculator.gui.DisplayManager; +import org.warp.picalculator.gui.graphicengine.Renderer; public class KeyboardDebugScreen extends Screen { @@ -14,169 +13,168 @@ public class KeyboardDebugScreen extends Screen { public String keyevent; public static int keyX; public static int keyY; - public static String[] log = new String[]{"POWER ON","LOADING","LOADED","DONE","---"}; + public static String[] log = new String[] { "POWER ON", "LOADING", "LOADED", "DONE", "---" }; public long beforetime; - + public KeyboardDebugScreen() { super(); canBeInHistory = false; } - - @Override - public void created() throws InterruptedException { - } @Override - public void init() throws InterruptedException { - } + public void created() throws InterruptedException {} + + @Override + public void init() throws InterruptedException {} @Override public void render() { - PIDisplay.renderer.glSetFont(fonts[2]); - colore(0.75f, 0.0f, 0.0f, 1.0f); - PIDisplay.renderer.glDrawStringRight(Main.screenSize[0] - 10, 30, "-" + keyevent.toUpperCase() + "-"); + Renderer renderer = DisplayManager.renderer; + fonts[2].use(DisplayManager.display); + renderer.glColor4f(0.75f, 0.0f, 0.0f, 1.0f); + renderer.glDrawStringRight(Main.screenSize[0] - 10, 30, "-" + keyevent.toUpperCase() + "-"); if (keyevent != "NONE") { - PIDisplay.renderer.glSetFont(fonts[2]); - colore(0.0f, 0.0f, 0.0f, 1.0f); - PIDisplay.renderer.glDrawStringLeft(10, 30, "Key position"); - PIDisplay.renderer.glDrawStringLeft(10, 45, "X: " + keyX + ", Y:" + keyY); - PIDisplay.renderer.glDrawStringLeft(10, 65, "Key value"); - PIDisplay.renderer.glDrawStringLeft(10, 80, key); + fonts[2].use(DisplayManager.display); + renderer.glColor4f(0.0f, 0.0f, 0.0f, 1.0f); + renderer.glDrawStringLeft(10, 30, "Key position"); + renderer.glDrawStringLeft(10, 45, "X: " + keyX + ", Y:" + keyY); + renderer.glDrawStringLeft(10, 65, "Key value"); + renderer.glDrawStringLeft(10, 80, key); } - PIDisplay.renderer.glSetFont(fonts[3]); - colore(0.0f, 0.0f, 0.0f, 1.0f); + fonts[3].use(DisplayManager.display); + renderer.glColor4f(0.0f, 0.0f, 0.0f, 1.0f); for (int i = 0; i < 5; i++) { if (log[i] != null) { - PIDisplay.renderer.glDrawStringLeft(10, 230 + 15*(i+1), log[i].toUpperCase()); + renderer.glDrawStringLeft(10, 230 + 15 * (i + 1), log[i].toUpperCase()); } } //FROM SERIAL - colore(0.0f, 0.0f, 0.0f, 1.0f); - PIDisplay.renderer.glFillRect(-80+100+200, 90, 5, 5); - PIDisplay.renderer.glFillRect(-80+100, 100, 200, 70); - PIDisplay.renderer.glSetFont(fonts[2]); - colore(1.0f, 1.0f, 1.0f, 1.0f); - PIDisplay.renderer.glDrawStringCenter(-80+100+200/2, 100+70/2-(PIDisplay.renderer.getCurrentFont().charH/2), "FROM SERIAL"); - PIDisplay.renderer.glSetFont(fonts[3]); - colore(0.0f, 0.0f, 1.0f, 1.0f); + renderer.glColor4f(0.0f, 0.0f, 0.0f, 1.0f); + renderer.glFillColor(-80 + 100 + 200, 90, 5, 5); + renderer.glFillColor(-80 + 100, 100, 200, 70); + fonts[2].use(DisplayManager.display); + renderer.glColor4f(1.0f, 1.0f, 1.0f, 1.0f); + renderer.glDrawStringCenter(-80 + 100 + 200 / 2, 100 + 70 / 2 - (renderer.getCurrentFont().getCharacterHeight() / 2), "FROM SERIAL"); + fonts[3].use(DisplayManager.display); + renderer.glColor4f(0.0f, 0.0f, 1.0f, 1.0f); for (int i = 0; i < 8; i++) { if (pinsA[i] == 1) { - colore(0.0f, 1.0f, 0.0f, 1.0f); + renderer.glColor4f(0.0f, 1.0f, 0.0f, 1.0f); } else if (pinsA[i] == 2) { - colore(0.5f, 0.5f, 1.0f, 1.0f); + renderer.glColor4f(0.5f, 0.5f, 1.0f, 1.0f); } else if (pinsA[i] == -1) { - colore(0.7f, 0.7f, 0.7f, 1.0f); + renderer.glColor4f(0.7f, 0.7f, 0.7f, 1.0f); } else if (pinsA[i] == 0) { - colore(1.0f, 0.0f, 0.0f, 1.0f); + renderer.glColor4f(1.0f, 0.0f, 0.0f, 1.0f); } - PIDisplay.renderer.glFillRect(-80+103+25*(7-i), 80, 20, 20); - colore(0.0f, 0.0f, 0.0f, 1.0f); - PIDisplay.renderer.glDrawStringCenter(-80+113+25*(7-i), 90-(PIDisplay.renderer.getCurrentFont().charH/2), ""+(i+1)); + renderer.glFillColor(-80 + 103 + 25 * (7 - i), 80, 20, 20); + renderer.glColor4f(0.0f, 0.0f, 0.0f, 1.0f); + renderer.glDrawStringCenter(-80 + 113 + 25 * (7 - i), 90 - (renderer.getCurrentFont().getCharacterHeight() / 2), "" + (i + 1)); } for (int i = 15; i >= 8; i--) { if (pinsA[i] == 1) { - colore(0.0f, 1.0f, 0.0f, 1.0f); + renderer.glColor4f(0.0f, 1.0f, 0.0f, 1.0f); } else if (pinsA[i] == 2) { - colore(0.5f, 0.5f, 1.0f, 1.0f); + renderer.glColor4f(0.5f, 0.5f, 1.0f, 1.0f); } else if (pinsA[i] == -1) { - colore(0.7f, 0.7f, 0.7f, 1.0f); + renderer.glColor4f(0.7f, 0.7f, 0.7f, 1.0f); } else if (pinsA[i] == 0) { - colore(1.0f, 0.0f, 0.0f, 1.0f); + renderer.glColor4f(1.0f, 0.0f, 0.0f, 1.0f); } - PIDisplay.renderer.glFillRect(-80+103+25*(i-8), 170, 20, 20); - colore(0.0f, 0.0f, 0.0f, 1.0f); - PIDisplay.renderer.glDrawStringCenter(-80+113+25*(i-8), 180-(PIDisplay.renderer.getCurrentFont().charH/2), ""+(i+1)); + renderer.glFillColor(-80 + 103 + 25 * (i - 8), 170, 20, 20); + renderer.glColor4f(0.0f, 0.0f, 0.0f, 1.0f); + renderer.glDrawStringCenter(-80 + 113 + 25 * (i - 8), 180 - (renderer.getCurrentFont().getCharacterHeight() / 2), "" + (i + 1)); } for (int i = 0; i < 8; i++) { if (dataA[i]) { - colore(0.0f, 1.0f, 0.0f, 1.0f); + renderer.glColor4f(0.0f, 1.0f, 0.0f, 1.0f); } else { - colore(1.0f, 0.0f, 0.0f, 1.0f); + renderer.glColor4f(1.0f, 0.0f, 0.0f, 1.0f); } - PIDisplay.renderer.glFillRect(-80+160+10*(i), 150, 8, 8); + renderer.glFillColor(-80 + 160 + 10 * (i), 150, 8, 8); } //TO SERIAL - colore(0.0f, 0.0f, 0.0f, 1.0f); - PIDisplay.renderer.glFillRect(150+90, 200, 5, 5); - PIDisplay.renderer.glFillRect(150+100, 100, 200, 70); - PIDisplay.renderer.glSetFont(fonts[2]); - colore(1.0f, 1.0f, 1.0f, 1.0f); - PIDisplay.renderer.glDrawStringCenter(150+100+200/2, 100+70/2-(PIDisplay.renderer.getCurrentFont().charH/2), "TO SERIAL"); - PIDisplay.renderer.glSetFont(fonts[3]); - colore(0.0f, 0.0f, 1.0f, 1.0f); + renderer.glColor4f(0.0f, 0.0f, 0.0f, 1.0f); + renderer.glFillColor(150 + 90, 200, 5, 5); + renderer.glFillColor(150 + 100, 100, 200, 70); + fonts[2].use(DisplayManager.display); + renderer.glColor4f(1.0f, 1.0f, 1.0f, 1.0f); + renderer.glDrawStringCenter(150 + 100 + 200 / 2, 100 + 70 / 2 - (renderer.getCurrentFont().getCharacterHeight() / 2), "TO SERIAL"); + fonts[3].use(DisplayManager.display); + renderer.glColor4f(0.0f, 0.0f, 1.0f, 1.0f); for (int i = 15; i >= 8; i--) { if (pinsB[i] == 1) { - colore(0.0f, 1.0f, 0.0f, 1.0f); + renderer.glColor4f(0.0f, 1.0f, 0.0f, 1.0f); } else if (pinsB[i] == 2) { - colore(0.5f, 0.5f, 1.0f, 1.0f); + renderer.glColor4f(0.5f, 0.5f, 1.0f, 1.0f); } else if (pinsB[i] == -1) { - colore(0.7f, 0.7f, 0.7f, 1.0f); + renderer.glColor4f(0.7f, 0.7f, 0.7f, 1.0f); } else if (pinsB[i] == 0) { - colore(1.0f, 0.0f, 0.0f, 1.0f); + renderer.glColor4f(1.0f, 0.0f, 0.0f, 1.0f); } - PIDisplay.renderer.glFillRect(150+103+25*(15-i), 80, 20, 20); - colore(0.0f, 0.0f, 0.0f, 1.0f); - PIDisplay.renderer.glDrawStringCenter(150+113+25*(15-i), 90-(PIDisplay.renderer.getCurrentFont().charH/2), ""+(i+1)); + renderer.glFillColor(150 + 103 + 25 * (15 - i), 80, 20, 20); + renderer.glColor4f(0.0f, 0.0f, 0.0f, 1.0f); + renderer.glDrawStringCenter(150 + 113 + 25 * (15 - i), 90 - (renderer.getCurrentFont().getCharacterHeight() / 2), "" + (i + 1)); } for (int i = 7; i >= 0; i--) { if (pinsB[i] == 1) { - colore(0.0f, 1.0f, 0.0f, 1.0f); + renderer.glColor4f(0.0f, 1.0f, 0.0f, 1.0f); } else if (pinsB[i] == 2) { - colore(0.5f, 0.5f, 1.0f, 1.0f); + renderer.glColor4f(0.5f, 0.5f, 1.0f, 1.0f); } else if (pinsB[i] == -1) { - colore(0.7f, 0.7f, 0.7f, 1.0f); + renderer.glColor4f(0.7f, 0.7f, 0.7f, 1.0f); } else if (pinsB[i] == 0) { - colore(1.0f, 0.0f, 0.0f, 1.0f); + renderer.glColor4f(1.0f, 0.0f, 0.0f, 1.0f); } - PIDisplay.renderer.glFillRect(150+103+25*(i), 170, 20, 20); - colore(0.0f, 0.0f, 0.0f, 1.0f); - PIDisplay.renderer.glDrawStringCenter(150+113+25*(i), 180-(PIDisplay.renderer.getCurrentFont().charH/2), ""+(i+1)); + renderer.glFillColor(150 + 103 + 25 * (i), 170, 20, 20); + renderer.glColor4f(0.0f, 0.0f, 0.0f, 1.0f); + renderer.glDrawStringCenter(150 + 113 + 25 * (i), 180 - (renderer.getCurrentFont().getCharacterHeight() / 2), "" + (i + 1)); } for (int i = 0; i < 8; i++) { if (dataB[i]) { - colore(0.0f, 1.0f, 0.0f, 1.0f); + renderer.glColor4f(0.0f, 1.0f, 0.0f, 1.0f); } else { - colore(1.0f, 0.0f, 0.0f, 1.0f); + renderer.glColor4f(1.0f, 0.0f, 0.0f, 1.0f); } - PIDisplay.renderer.glFillRect(150+160+10*(i), 150, 8, 8); + renderer.glFillColor(150 + 160 + 10 * (i), 150, 8, 8); } - + //GPIO for (int i = 0; i < 40; i++) { if (gpio[i] == true) { - colore(0.0f, 1.0f, 0.0f, 1.0f); + renderer.glColor4f(0.0f, 1.0f, 0.0f, 1.0f); } else { - colore(1.0f, 0.0f, 0.0f, 1.0f); + renderer.glColor4f(1.0f, 0.0f, 0.0f, 1.0f); } if (i % 2 == 0) { - PIDisplay.renderer.glFillRect(53+15*((i)/2), 50, 5, 5); - colore(0.0f, 0.0f, 0.0f, 1.0f); - PIDisplay.renderer.glDrawStringCenter(55+15*((i)/2), 60, ""+(i+1)); + renderer.glFillColor(53 + 15 * ((i) / 2), 50, 5, 5); + renderer.glColor4f(0.0f, 0.0f, 0.0f, 1.0f); + renderer.glDrawStringCenter(55 + 15 * ((i) / 2), 60, "" + (i + 1)); } else { - PIDisplay.renderer.glFillRect(53+15*((i-1)/2), 40, 5, 5); - colore(0.0f, 0.0f, 0.0f, 1.0f); - PIDisplay.renderer.glDrawStringCenter(55+15*((i-1)/2), 35-PIDisplay.renderer.getCurrentFont().charH, ""+(i+1)); + renderer.glFillColor(53 + 15 * ((i - 1) / 2), 40, 5, 5); + renderer.glColor4f(0.0f, 0.0f, 0.0f, 1.0f); + renderer.glDrawStringCenter(55 + 15 * ((i - 1) / 2), 35 - renderer.getCurrentFont().getCharacterHeight(), "" + (i + 1)); } } - + //KEYS for (int c = 0; c < 8; c++) { for (int r = 0; r < 8; r++) { if (ks[c][r]) { - colore(0.0f, 1.0f, 0.0f, 1.0f); + renderer.glColor4f(0.0f, 1.0f, 0.0f, 1.0f); } else { - colore(1.0f, 0.0f, 0.0f, 1.0f); + renderer.glColor4f(1.0f, 0.0f, 0.0f, 1.0f); } - PIDisplay.renderer.glFillRect(250+6*c, 250+6*r, 5, 5); + renderer.glFillColor(250 + 6 * c, 250 + 6 * r, 5, 5); } } } @Override public void beforeRender(float dt) { - if (System.currentTimeMillis()-beforetime >= 1000) { + if (System.currentTimeMillis() - beforetime >= 1000) { keyevent = "NONE"; keyX = 0; keyY = 0; @@ -208,19 +206,18 @@ public class KeyboardDebugScreen extends Screen { key = k.toString(); return false; } - - public static int[] pinsA = new int[]{2, 2, 2, 2, 2, 2, 2, 1, -1, -1, 0, 0, 0, 0, 2, -1}; - public static int[] pinsB = new int[]{0, 0, 2, 2, 2, 2, -1, 1, 0, -1, 2, 2, 2, 2, 0, -1}; + public static int[] pinsA = new int[] { 2, 2, 2, 2, 2, 2, 2, 1, -1, -1, 0, 0, 0, 0, 2, -1 }; + public static int[] pinsB = new int[] { 0, 0, 2, 2, 2, 2, -1, 1, 0, -1, 2, 2, 2, 2, 0, -1 }; public static boolean[] dataA = new boolean[8]; public static boolean[] dataB = new boolean[8]; public static boolean[][] ks = new boolean[8][8]; public static boolean[] gpio = new boolean[40]; - + public static void log(String str) { - String[] newlog = log; + final String[] newlog = log; for (int i = 1; i < 5; i++) { - newlog[i-1] = newlog[i]; + newlog[i - 1] = newlog[i]; } newlog[4] = "[" + System.currentTimeMillis() + "]" + str; log = newlog; diff --git a/src/org/warp/picalculator/gui/screens/LoadingScreen.java b/src/org/warp/picalculator/gui/screens/LoadingScreen.java index c5014763..ce680bc5 100644 --- a/src/org/warp/picalculator/gui/screens/LoadingScreen.java +++ b/src/org/warp/picalculator/gui/screens/LoadingScreen.java @@ -1,79 +1,74 @@ package org.warp.picalculator.gui.screens; -import static org.warp.picalculator.gui.PIDisplay.colore; -import static org.warp.picalculator.gui.PIDisplay.fonts; +import static org.warp.picalculator.gui.DisplayManager.colore; +import static org.warp.picalculator.gui.DisplayManager.fonts; import org.warp.picalculator.Main; import org.warp.picalculator.device.Keyboard.Key; -import org.warp.picalculator.gui.PIDisplay; +import org.warp.picalculator.gui.DisplayManager; +import org.warp.picalculator.gui.GraphicUtils; public class LoadingScreen extends Screen { public float endLoading; boolean mustRefresh = true; public float loadingTextTranslation = 0.0f; - public boolean loadingTextTranslationTopToBottom = true; private boolean loading; - private static final String titleString = "PICalculator by Andrea Cavalli"; + private static final String titleString = "Andrea Cavalli's Algebraic Calculator"; public LoadingScreen() { super(); canBeInHistory = false; } - + @Override public void created() throws InterruptedException { endLoading = 0; } @Override - public void init() throws InterruptedException { - } - + public void init() throws InterruptedException {} + @Override public void beforeRender(float dt) { - if (loadingTextTranslation >= 10.0f) { - loadingTextTranslation = 10.0f; - loadingTextTranslationTopToBottom = false; - } else if (loadingTextTranslation <= -10.0f) { - loadingTextTranslation = -10.0f; - loadingTextTranslationTopToBottom = true; - } + loadingTextTranslation = GraphicUtils.sinDeg(endLoading * 90f) * 10f; - if (loadingTextTranslationTopToBottom) { - loadingTextTranslation += dt * 15; - } else { - loadingTextTranslation -= dt * 15; - } - endLoading += dt; - if (endLoading >= 2) { + if (endLoading >= 5f) { loading = false; - PIDisplay.INSTANCE.setScreen(new MathInputScreen()); + DisplayManager.INSTANCE.setScreen(new MathInputScreen()); } mustRefresh = true; } @Override public void render() { - PIDisplay.renderer.glSetFont(fonts[2]); - colore(1.0f, 1.0f, 1.0f, 1.0f); - PIDisplay.renderer.glDrawStringCenter((Main.screenSize[0] / 2) - 1,(int) ((Main.screenSize[1]/ 2) - 25 + loadingTextTranslation), titleString); - colore(1.0f, 1.0f, 1.0f, 1.0f); - PIDisplay.renderer.glDrawStringCenter((Main.screenSize[0] / 2) + 1,(int) ((Main.screenSize[1]/ 2) - 25 + loadingTextTranslation), titleString); - colore(1.0f, 1.0f, 1.0f, 1.0f); - PIDisplay.renderer.glDrawStringCenter((Main.screenSize[0] / 2), (int) ((Main.screenSize[1]/ 2) - 25 - 1 + loadingTextTranslation), titleString); - colore(1.0f, 1.0f, 1.0f, 1.0f); - PIDisplay.renderer.glDrawStringCenter((Main.screenSize[0] / 2), (int) ((Main.screenSize[1]/ 2) - 25 + 1 + loadingTextTranslation), titleString); - colore(1.0f, 0.5f, 0.0f, 1.0f); - PIDisplay.renderer.glDrawStringCenter((Main.screenSize[0] / 2), (int) ((Main.screenSize[1]/ 2) - 25 + loadingTextTranslation), titleString); - colore(0.0f, 0.0f, 0.0f, 0.75f); - PIDisplay.renderer.glSetFont(fonts[0]); - PIDisplay.renderer.glDrawStringCenter((Main.screenSize[0] / 2), (Main.screenSize[1]/ 2) + 11, "LOADING"); - PIDisplay.renderer.glSetFont(fonts[1]); - colore(0.0f, 0.0f, 0.0f, 0.5f); - PIDisplay.renderer.glDrawStringCenter((Main.screenSize[0] / 2), (Main.screenSize[1]/ 2) + 22, "PLEASE WAIT..."); - + fonts[2].use(DisplayManager.display); + DisplayManager.renderer.glClearColor(0xFF000000); + DisplayManager.renderer.glClear(DisplayManager.display.getWidth(), DisplayManager.display.getWidth()); + DisplayManager.renderer.glColor3i(230, 33, 23); + DisplayManager.renderer.glDrawStringCenter((Main.screenSize[0] / 2) - 1, (int) ((Main.screenSize[1] / 2) - 25 + loadingTextTranslation), titleString); + DisplayManager.renderer.glDrawStringCenter((Main.screenSize[0] / 2) - 2, (int) ((Main.screenSize[1] / 2) - 25 + loadingTextTranslation), titleString); + DisplayManager.renderer.glDrawStringCenter((Main.screenSize[0] / 2) + 1, (int) ((Main.screenSize[1] / 2) - 25 + loadingTextTranslation), titleString); + DisplayManager.renderer.glDrawStringCenter((Main.screenSize[0] / 2) + 2, (int) ((Main.screenSize[1] / 2) - 25 + loadingTextTranslation), titleString); + DisplayManager.renderer.glDrawStringCenter((Main.screenSize[0] / 2), (int) ((Main.screenSize[1] / 2) - 25 - 1 + loadingTextTranslation), titleString); + DisplayManager.renderer.glDrawStringCenter((Main.screenSize[0] / 2), (int) ((Main.screenSize[1] / 2) - 25 - 2 + loadingTextTranslation), titleString); + DisplayManager.renderer.glDrawStringCenter((Main.screenSize[0] / 2), (int) ((Main.screenSize[1] / 2) - 25 + 1 + loadingTextTranslation), titleString); + DisplayManager.renderer.glDrawStringCenter((Main.screenSize[0] / 2), (int) ((Main.screenSize[1] / 2) - 25 + 2 + loadingTextTranslation), titleString); + + DisplayManager.renderer.glDrawStringCenter((Main.screenSize[0] / 2) + 1, (int) ((Main.screenSize[1] / 2) - 25 + 1 + loadingTextTranslation), titleString); + DisplayManager.renderer.glDrawStringCenter((Main.screenSize[0] / 2) - 1, (int) ((Main.screenSize[1] / 2) - 25 + 1 + loadingTextTranslation), titleString); + DisplayManager.renderer.glDrawStringCenter((Main.screenSize[0] / 2) - 1, (int) ((Main.screenSize[1] / 2) - 25 - 1 + loadingTextTranslation), titleString); + DisplayManager.renderer.glDrawStringCenter((Main.screenSize[0] / 2) + 1, (int) ((Main.screenSize[1] / 2) - 25 - 1 + loadingTextTranslation), titleString); + DisplayManager.renderer.glColor3i(255, 255, 255); + DisplayManager.renderer.glDrawStringCenter((Main.screenSize[0] / 2), (int) ((Main.screenSize[1] / 2) - 25 + loadingTextTranslation), titleString); + DisplayManager.renderer.glColor4f(0.0f, 0.0f, 0.0f, 0.75f); + fonts[0].use(DisplayManager.display); + DisplayManager.renderer.glDrawStringCenter((Main.screenSize[0] / 2), (Main.screenSize[1] / 2) + 11, "LOADING"); + fonts[1].use(DisplayManager.display); + DisplayManager.renderer.glColor4f(0.0f, 0.0f, 0.0f, 0.5f); + DisplayManager.renderer.glDrawStringCenter((Main.screenSize[0] / 2), (Main.screenSize[1] / 2) + 22, "PLEASE WAIT..."); + } @Override diff --git a/src/org/warp/picalculator/gui/screens/MarioScreen.java b/src/org/warp/picalculator/gui/screens/MarioScreen.java index b8957680..80255eb9 100644 --- a/src/org/warp/picalculator/gui/screens/MarioScreen.java +++ b/src/org/warp/picalculator/gui/screens/MarioScreen.java @@ -8,17 +8,16 @@ import javax.imageio.ImageIO; import org.warp.picalculator.Main; import org.warp.picalculator.device.Keyboard; import org.warp.picalculator.device.Keyboard.Key; -import org.warp.picalculator.gui.PIDisplay; +import org.warp.picalculator.gui.DisplayManager; +import org.warp.picalculator.gui.graphicengine.RAWSkin; public class MarioScreen extends Screen { - private int[] skin; - private int[] skinSize; - private int[] ground; - private int[] groundSize; + private RAWSkin skin; + private RAWSkin groundskin; private boolean errored; - public float[] marioPos = new float[]{30,0}; - public float[] marioForces = new float[]{0,0}; + public float[] marioPos = new float[] { 30, 0 }; + public float[] marioForces = new float[] { 0, 0 }; public float walkAnimation = 0; public float jumptime = 0; public boolean walking = false; @@ -26,8 +25,8 @@ public class MarioScreen extends Screen { public boolean jumping = false; public boolean flipped = false; public boolean onGround = true; - public int[] marioSkinPos = new int[]{0,0}; - + public int[] marioSkinPos = new int[] { 0, 0 }; + public MarioScreen() { super(); canBeInHistory = false; @@ -35,25 +34,14 @@ public class MarioScreen extends Screen { @Override public void init() { - BufferedImage img; try { - img = ImageIO.read(Main.instance.getClass().getResource("/marioskin.png")); - skin = PIDisplay.renderer.getMatrixOfImage(img); - skinSize = new int[] { img.getWidth(), img.getHeight() }; + skin = DisplayManager.display.loadSkin("marioskin.png"); + groundskin = DisplayManager.display.loadSkin("marioground.png"); } catch (IOException e) { e.printStackTrace(); - errored = true; - } - try { - img = ImageIO.read(Main.instance.getClass().getResource("/marioground.png")); - ground = PIDisplay.renderer.getMatrixOfImage(img); - groundSize = new int[] { img.getWidth(), img.getHeight() }; - } catch (IOException e) { - e.printStackTrace(); - errored = true; } } - + @Override public void created() throws InterruptedException { if (!errored) { @@ -65,36 +53,36 @@ public class MarioScreen extends Screen { public void beforeRender(float dt) { if (!errored) { walkAnimation += dt; - boolean rightPressed = Keyboard.isKeyDown(2, 5); - boolean leftPressed = Keyboard.isKeyDown(2, 3); - boolean jumpPressed = Keyboard.isKeyDown(2, 1); + final boolean rightPressed = Keyboard.isKeyDown(2, 5); + final boolean leftPressed = Keyboard.isKeyDown(2, 3); + final boolean jumpPressed = Keyboard.isKeyDown(2, 1); if ((leftPressed || rightPressed) == (leftPressed & rightPressed)) { walking = false; walkAnimation = 0; } else { if (rightPressed) { //RIGHT if (marioForces[0] < 500f) { - marioForces[0] += dt*500f; + marioForces[0] += dt * 500f; } walking = true; flipped = false; } if (leftPressed) { //LEFT if (marioForces[0] > -500f) { - marioForces[0] -= dt*500f; + marioForces[0] -= dt * 500f; } walking = true; flipped = true; } } if (jumpPressed) { //JUMP - jumptime+=dt; + jumptime += dt; if (!jumping && onGround) { - marioForces[1] = dt*(4*1569.6f); + marioForces[1] = dt * (4 * 1569.6f); jumping = true; onGround = false; } else if (jumptime <= 0.5f) { - marioForces[1] = dt*(4*1569.6f); + marioForces[1] = dt * (4 * 1569.6f); } } else { jumping = false; @@ -104,7 +92,7 @@ public class MarioScreen extends Screen { marioSkinPos[0] = 0; marioSkinPos[1] = 0; } else if (onGround & walking & !running & !jumping && walkAnimation >= 0.08) { - while(walkAnimation > 0.08) { + while (walkAnimation > 0.08) { walkAnimation -= 0.08; if (marioSkinPos[0] == 1 & marioSkinPos[1] == 0) { marioSkinPos[0] += 2; @@ -121,42 +109,44 @@ public class MarioScreen extends Screen { marioSkinPos[0] = 5; marioSkinPos[1] = 1; } - marioForces[1] -= dt*1569.6; - marioPos[0] += dt*marioForces[0]; + marioForces[1] -= dt * 1569.6; + marioPos[0] += dt * marioForces[0]; if (!onGround) { - marioPos[1] -= dt*marioForces[1]; + marioPos[1] -= dt * marioForces[1]; } marioForces[0] *= 0.75; - PIDisplay.renderer.glClearColor(0xff9290ff); + DisplayManager.renderer.glClearColor(0xff9290ff); } } @Override public void render() { if (errored) { - PIDisplay.renderer.glDrawStringLeft(0, 20, "ERROR"); + DisplayManager.renderer.glDrawStringLeft(0, 20, "ERROR"); } else { - PIDisplay.renderer.glSetFont(PIDisplay.fonts[0]); - PIDisplay.renderer.glDrawSkin(groundSize[0], ground, 0, 25+25, 0, 0, 16, 16, false); - PIDisplay.renderer.glDrawSkin(groundSize[0], ground, 16, 25+25, 0, 0, 16, 16, false); - PIDisplay.renderer.glDrawSkin(groundSize[0], ground, 16*2, 25+25, 0, 0, 16, 16, false); - PIDisplay.renderer.glDrawSkin(groundSize[0], ground, 16*3, 25+25, 0, 0, 16, 16, false); - PIDisplay.renderer.glDrawSkin(groundSize[0], ground, 16*4, 25+25, 0, 0, 16, 16, false); - PIDisplay.renderer.glDrawSkin(groundSize[0], ground, 16*5, 25+25, 0, 0, 16, 16, false); - PIDisplay.renderer.glDrawSkin(groundSize[0], ground, 16*6, 25+25, 0, 0, 16, 16, false); - PIDisplay.renderer.glDrawSkin(groundSize[0], ground, 16*7, 25+25, 0, 0, 16, 16, false); - PIDisplay.renderer.glDrawSkin(groundSize[0], ground, 16*8, 25+25, 0, 0, 16, 16, false); - PIDisplay.renderer.glDrawSkin(groundSize[0], ground, 0, 25+25+16, 0, 0, 16, 16, false); - PIDisplay.renderer.glDrawSkin(groundSize[0], ground, 16, 25+25+16, 0, 0, 16, 16, false); - PIDisplay.renderer.glDrawSkin(groundSize[0], ground, 16*2, 25+25+16, 0, 0, 16, 16, false); - PIDisplay.renderer.glDrawSkin(groundSize[0], ground, 16*3, 25+25+16, 0, 0, 16, 16, false); - PIDisplay.renderer.glDrawSkin(groundSize[0], ground, 16*4, 25+25+16, 0, 0, 16, 16, false); - PIDisplay.renderer.glDrawSkin(groundSize[0], ground, 16*5, 25+25+16, 0, 0, 16, 16, false); - PIDisplay.renderer.glDrawSkin(groundSize[0], ground, 16*6, 25+25+16, 0, 0, 16, 16, false); - PIDisplay.renderer.glDrawSkin(groundSize[0], ground, 16*7, 25+25+16, 0, 0, 16, 16, false); - PIDisplay.renderer.glDrawSkin(groundSize[0], ground, 16*8, 25+25+16, 0, 0, 16, 16, false); - + DisplayManager.fonts[0].use(DisplayManager.display); + groundskin.use(DisplayManager.display); + DisplayManager.renderer.glFillRect(16 * 0, 25 + 25, 16, 16, 0, 0, 16, 16); + DisplayManager.renderer.glFillRect(16 * 1, 25 + 25, 16, 16, 0, 0, 16, 16); + DisplayManager.renderer.glFillRect(16 * 2, 25 + 25, 16, 16, 0, 0, 16, 16); + DisplayManager.renderer.glFillRect(16 * 3, 25 + 25, 16, 16, 0, 0, 16, 16); + DisplayManager.renderer.glFillRect(16 * 4, 25 + 25, 16, 16, 0, 0, 16, 16); + DisplayManager.renderer.glFillRect(16 * 5, 25 + 25, 16, 16, 0, 0, 16, 16); + DisplayManager.renderer.glFillRect(16 * 6, 25 + 25, 16, 16, 0, 0, 16, 16); + DisplayManager.renderer.glFillRect(16 * 7, 25 + 25, 16, 16, 0, 0, 16, 16); + DisplayManager.renderer.glFillRect(16 * 8, 25 + 25, 16, 16, 0, 0, 16, 16); + + DisplayManager.renderer.glFillRect(16 * 0, 25 + 25 + 16 * 1, 16, 16, 0, 0, 16, 16); + DisplayManager.renderer.glFillRect(16 * 1, 25 + 25 + 16 * 1, 16, 16, 0, 0, 16, 16); + DisplayManager.renderer.glFillRect(16 * 2, 25 + 25 + 16 * 1, 16, 16, 0, 0, 16, 16); + DisplayManager.renderer.glFillRect(16 * 3, 25 + 25 + 16 * 1, 16, 16, 0, 0, 16, 16); + DisplayManager.renderer.glFillRect(16 * 4, 25 + 25 + 16 * 1, 16, 16, 0, 0, 16, 16); + DisplayManager.renderer.glFillRect(16 * 5, 25 + 25 + 16 * 1, 16, 16, 0, 0, 16, 16); + DisplayManager.renderer.glFillRect(16 * 6, 25 + 25 + 16 * 1, 16, 16, 0, 0, 16, 16); + DisplayManager.renderer.glFillRect(16 * 7, 25 + 25 + 16 * 1, 16, 16, 0, 0, 16, 16); + DisplayManager.renderer.glFillRect(16 * 8, 25 + 25 + 16 * 1, 16, 16, 0, 0, 16, 16); + // EASTER EGG // glSetFont(PIDisplay.fonts[4]); // glColor(0xFF000000); @@ -173,9 +163,11 @@ public class MarioScreen extends Screen { // glDrawStringRight(0, Main.screenSize[1]-glGetCurrentFontHeight(), "F"); // glColor(0xffede7); // glDrawStringRight(0, Main.screenSize[1]-glGetCurrentFontHeight(), "G"); - + //DRAW MARIO - PIDisplay.renderer.glDrawSkin(skinSize[0], skin, getPosX()-18, 25+getPosY(), 35*(marioSkinPos[0]+(flipped?2:1)), 27*marioSkinPos[1], 35*(marioSkinPos[0]+(flipped?1:2)), 27*(marioSkinPos[1]+1), true); + skin.use(DisplayManager.display); + DisplayManager.renderer.glFillRect(getPosX() - 18, 25 + getPosY(), 35, 27, 35 * (marioSkinPos[0] + 1), 27 * marioSkinPos[1], 35, 27); +// PIDisplay.renderer.glDrawSkin(getPosX() - 18, 25 + getPosY(), 35 * (marioSkinPos[0] + (flipped ? 2 : 1)), 27 * marioSkinPos[1], 35 * (marioSkinPos[0] + (flipped ? 1 : 2)), 27 * (marioSkinPos[1] + 1), true); } } @@ -193,13 +185,13 @@ public class MarioScreen extends Screen { public boolean keyPressed(Key k) { return false; } - + private int getPosX() { - return (int)marioPos[0]; + return (int) marioPos[0]; } - + private int getPosY() { - return (int)marioPos[1]; + return (int) marioPos[1]; } } diff --git a/src/org/warp/picalculator/gui/screens/MathInputScreen.java b/src/org/warp/picalculator/gui/screens/MathInputScreen.java index 538b5b0f..c75b3c12 100644 --- a/src/org/warp/picalculator/gui/screens/MathInputScreen.java +++ b/src/org/warp/picalculator/gui/screens/MathInputScreen.java @@ -15,8 +15,9 @@ import org.warp.picalculator.Main; import org.warp.picalculator.Utils; import org.warp.picalculator.device.Keyboard; import org.warp.picalculator.device.Keyboard.Key; -import org.warp.picalculator.gui.PIDisplay; +import org.warp.picalculator.gui.DisplayManager; import org.warp.picalculator.gui.graphicengine.RAWFont; +import org.warp.picalculator.gui.graphicengine.Renderer; import org.warp.picalculator.math.AngleMode; import org.warp.picalculator.math.Calculator; import org.warp.picalculator.math.MathematicalSymbols; @@ -42,17 +43,17 @@ public class MathInputScreen extends Screen { public int errorLevel = 0; // 0 = nessuno, 1 = risultato, 2 = tutto boolean mustRefresh = true; boolean afterDoNextStep = false; - + public MathInputScreen() { super(); canBeInHistory = true; - + calc = new Calculator(); } - + @Override public void created() throws InterruptedException { - + } @Override @@ -114,14 +115,14 @@ public class MathInputScreen extends Screen { } public void interpreta(boolean temporary) throws Error { - String eqn = nuovaEquazione; + final String eqn = nuovaEquazione; if (!temporary) { equazioneCorrente = eqn; } - + calc.parseInputString(eqn); } - + @Override public void beforeRender(float dt) { showCaretDelta += dt; @@ -134,39 +135,39 @@ public class MathInputScreen extends Screen { caretPos = nuovaEquazione.length(); } - if (PIDisplay.error == null) { - PIDisplay.renderer.glClearColor(0xFFc5c2af); + if (DisplayManager.error == null) { + DisplayManager.renderer.glClearColor(0xFFc5c2af); } else { - PIDisplay.renderer.glClearColor(0xFFDC3C32); + DisplayManager.renderer.glClearColor(0xFFDC3C32); } } private static final RAWFont fontBig = Utils.getFont(false); - + @Override public void renderStatusbar() { - PIDisplay.renderer.glColor3i(0, 0, 0); - int pos = 2; - int spacersNumb = 1; + Renderer renderer = DisplayManager.renderer; + renderer.glColor3f(1, 1, 1); + final int pos = 2; + final int spacersNumb = 1; int skinN = 0; if (calc.exactMode) { skinN = 22; - PIDisplay.drawSkinPart(2 + 18 * pos + 2 * spacersNumb, 2, 16 * skinN, 16 * 0, 16 + 16 * skinN, 16 + 16 * 0); } else { skinN = 21; - PIDisplay.drawSkinPart(2 + 18 * pos + 2 * spacersNumb, 2, 16 * skinN, 16 * 0, 16 + 16 * skinN, 16 + 16 * 0); } + renderer.glFillRect(2 + 18 * pos + 2 * spacersNumb, 2, 16, 16, 16 * skinN, 16 * 0, 16, 16); } - + @Override public void render() { - PIDisplay.renderer.glSetFont(fontBig); + fontBig.use(DisplayManager.display); final int textColor = 0xFF000000; final int padding = 4; - PIDisplay.renderer.glColor(textColor); - final int caretRealPos = MathematicalSymbols.getGraphicRepresentation(nuovaEquazione.substring(0, caretPos)).length()*(fontBig.charW+1); + DisplayManager.renderer.glColor(textColor); + final int caretRealPos = MathematicalSymbols.getGraphicRepresentation(nuovaEquazione.substring(0, caretPos)).length() * (fontBig.getCharacterWidth() + 1); final String inputTextWithoutCaret = MathematicalSymbols.getGraphicRepresentation(nuovaEquazione); - final boolean tooLongI = padding+PIDisplay.renderer.glGetStringWidth(fontBig, nuovaEquazione)+padding >= Main.screenSize[0]; + final boolean tooLongI = padding + fontBig.getStringWidth(nuovaEquazione) + padding >= Main.screenSize[0]; int scrollI = 0; if (tooLongI) { scrollI = -scrollX; @@ -176,23 +177,23 @@ public class MathInputScreen extends Screen { scrollI = 0; } } - PIDisplay.renderer.glDrawStringLeft(padding+scrollI, padding+20, inputTextWithoutCaret); + DisplayManager.renderer.glDrawStringLeft(padding + scrollI, padding + 20, inputTextWithoutCaret); if (showCaret) { - PIDisplay.renderer.glDrawStringLeft(padding+scrollI+caretRealPos, padding+20, "|"); + DisplayManager.renderer.glDrawStringLeft(padding + scrollI + caretRealPos, padding + 20, "|"); } if (tooLongI) { - PIDisplay.renderer.glColor(PIDisplay.renderer.glGetClearColor()); - PIDisplay.renderer.glFillRect(Main.screenSize[0]-16-2, padding+20, fontBig.charH, Main.screenSize[0]); - PIDisplay.renderer.glColor(textColor); - PIDisplay.drawSkinPart(Main.screenSize[0]-16, padding+20+fontBig.charH/2-16/2, 304, 0, 304+16, 16); + DisplayManager.renderer.glColor(DisplayManager.renderer.glGetClearColor()); + DisplayManager.renderer.glFillColor(Main.screenSize[0] - 16 - 2, padding + 20, fontBig.getCharacterHeight(), Main.screenSize[0]); + DisplayManager.renderer.glColor(textColor); + DisplayManager.drawSkinPart(Main.screenSize[0] - 16, padding + 20 + fontBig.getCharacterHeight() / 2 - 16 / 2, 304, 0, 304 + 16, 16); } if (calc.f != null) { int topSpacing = 0; - Iterator iter = calc.f.iterator(); + final Iterator iter = calc.f.iterator(); while (iter.hasNext()) { - Function fnc = iter.next(); + final Function fnc = iter.next(); try { - final boolean tooLong = padding+fnc.getWidth()+padding >= Main.screenSize[0]; + final boolean tooLong = padding + fnc.getWidth() + padding >= Main.screenSize[0]; int scrollA = 0; if (tooLong) { scrollA = -scrollX; @@ -202,15 +203,15 @@ public class MathInputScreen extends Screen { scrollA = 0; } } - final int y = padding+20+padding+fontBig.charH+1+topSpacing; - fnc.draw(padding+scrollA, y); + final int y = padding + 20 + padding + fontBig.getCharacterHeight() + 1 + topSpacing; + fnc.draw(padding + scrollA, y); if (tooLong) { - PIDisplay.renderer.glColor(PIDisplay.renderer.glGetClearColor()); - PIDisplay.renderer.glFillRect(Main.screenSize[0]-16-2, y, fnc.getHeight(), Main.screenSize[0]); - PIDisplay.renderer.glColor(textColor); - PIDisplay.drawSkinPart(Main.screenSize[0]-16, y+fnc.getHeight()/2-16/2, 304, 0, 304+16, 16); + DisplayManager.renderer.glColor(DisplayManager.renderer.glGetClearColor()); + DisplayManager.renderer.glFillColor(Main.screenSize[0] - 16 - 2, y, fnc.getHeight(), Main.screenSize[0]); + DisplayManager.renderer.glColor(textColor); + DisplayManager.drawSkinPart(Main.screenSize[0] - 16, y + fnc.getHeight() / 2 - 16 / 2, 304, 0, 304 + 16, 16); } - } catch (NullPointerException e) { + } catch (final NullPointerException e) { iter.remove(); } topSpacing += fnc.getHeight() + 2; @@ -218,16 +219,16 @@ public class MathInputScreen extends Screen { } if (calc.f2 != null) { int bottomSpacing = 0; - for (Function f : calc.f2) { - bottomSpacing += f.getHeight()+2; - f.draw(PIDisplay.display.getWidth() - 2 - f.getWidth(), PIDisplay.display.getHeight() - bottomSpacing); + for (final Function f : calc.f2) { + bottomSpacing += f.getHeight() + 2; + f.draw(DisplayManager.display.getWidth() - 2 - f.getWidth(), DisplayManager.display.getHeight() - bottomSpacing); } if (calc.resultsCount > 1 && calc.resultsCount != calc.f2.size()) { - String resultsCountText = calc.resultsCount+" total results".toUpperCase(); - PIDisplay.renderer.glColor(0xFF9AAEA0); - PIDisplay.renderer.glSetFont(Utils.getFont(true)); - bottomSpacing += fontBig.charH+2; - PIDisplay.renderer.glDrawStringRight(PIDisplay.display.getWidth() - 2, PIDisplay.display.getHeight() - bottomSpacing, resultsCountText); + final String resultsCountText = calc.resultsCount + " total results".toUpperCase(); + DisplayManager.renderer.glColor(0xFF9AAEA0); + Utils.getFont(true).use(DisplayManager.display); + bottomSpacing += fontBig.getCharacterHeight() + 2; + DisplayManager.renderer.glDrawStringRight(DisplayManager.display.getWidth() - 2, DisplayManager.display.getHeight() - bottomSpacing, resultsCountText); } } } @@ -251,26 +252,24 @@ public class MathInputScreen extends Screen { try { try { interpreta(true); - showVariablesDialog(new Runnable(){ - @Override - public void run() { - equazioneCorrente = nuovaEquazione; - calc.f2 = calc.f; - afterDoNextStep = true; - simplify(MathInputScreen.this); - } + showVariablesDialog(() -> { + equazioneCorrente = nuovaEquazione; + calc.f2 = calc.f; + afterDoNextStep = true; + simplify(MathInputScreen.this); }); - } catch (Exception ex) { - if (Utils.debugOn) + } catch (final Exception ex) { + if (Utils.debugOn) { ex.printStackTrace(); + } throw new Error(Errors.SYNTAX_ERROR); } - } catch (Error e) { - StringWriter sw = new StringWriter(); - PrintWriter pw = new PrintWriter(sw); + } catch (final Error e) { + final StringWriter sw = new StringWriter(); + final PrintWriter pw = new PrintWriter(sw); e.printStackTrace(pw); d.errorStackTrace = sw.toString().toUpperCase().replace("\t", " ").replace("\r", "").split("\n"); - PIDisplay.error = e.id.toString(); + DisplayManager.error = e.id.toString(); System.err.println(e.id); } } else { @@ -279,10 +278,10 @@ public class MathInputScreen extends Screen { } return true; case SOLVE: - if (PIDisplay.error != null) { + if (DisplayManager.error != null) { Utils.debug.println("Resetting after error..."); - PIDisplay.error = null; - this.equazioneCorrente = null; + DisplayManager.error = null; + equazioneCorrente = null; calc.f = null; calc.f2 = null; calc.resultsCount = 0; @@ -296,26 +295,24 @@ public class MathInputScreen extends Screen { if (nuovaEquazione != equazioneCorrente && nuovaEquazione.length() > 0) { changeEquationScreen(); interpreta(true); - showVariablesDialog(new Runnable(){ - @Override - public void run() { - equazioneCorrente = nuovaEquazione; - solve(); - }}); + showVariablesDialog(() -> { + equazioneCorrente = nuovaEquazione; + solve(); + }); } } - } catch (Exception ex) { + } catch (final Exception ex) { if (Utils.debugOn) { ex.printStackTrace(); } throw new Error(Errors.SYNTAX_ERROR); } - } catch (Error e) { - StringWriter sw = new StringWriter(); - PrintWriter pw = new PrintWriter(sw); + } catch (final Error e) { + final StringWriter sw = new StringWriter(); + final PrintWriter pw = new PrintWriter(sw); e.printStackTrace(pw); d.errorStackTrace = sw.toString().toUpperCase().replace("\t", " ").replace("\r", "").split("\n"); - PIDisplay.error = e.id.toString(); + DisplayManager.error = e.id.toString(); System.err.println(e.id); } return true; @@ -384,7 +381,7 @@ public class MathInputScreen extends Screen { typeChar("√"); return true; case POWER_OF_2: - typeChar(MathematicalSymbols.POWER+"2"); + typeChar(MathematicalSymbols.POWER + "2"); return true; case POWER_OF_x: typeChar(MathematicalSymbols.POWER); @@ -419,12 +416,14 @@ public class MathInputScreen extends Screen { case DELETE: if (nuovaEquazione.length() > 0) { if (caretPos > 0) { - caretPos-=1; - nuovaEquazione=nuovaEquazione.substring(0, caretPos)+nuovaEquazione.substring(caretPos+1, nuovaEquazione.length()); + caretPos -= 1; + nuovaEquazione = nuovaEquazione.substring(0, caretPos) + nuovaEquazione.substring(caretPos + 1, nuovaEquazione.length()); } else { nuovaEquazione = nuovaEquazione.substring(1); } - try {interpreta(true);} catch (Error e) {} + try { + interpreta(true); + } catch (final Error e) {} } afterDoNextStep = false; return true; @@ -434,7 +433,7 @@ public class MathInputScreen extends Screen { } else { caretPos = nuovaEquazione.length(); } - scrollX = PIDisplay.renderer.glGetStringWidth(fontBig, nuovaEquazione.substring(0, caretPos)+"|||"); + scrollX = fontBig.getStringWidth(nuovaEquazione.substring(0, caretPos) + "|||"); showCaret = true; showCaretDelta = 0L; return true; @@ -444,27 +443,27 @@ public class MathInputScreen extends Screen { } else { caretPos = 0; } - scrollX = PIDisplay.renderer.glGetStringWidth(fontBig, nuovaEquazione.substring(0, caretPos)+"|||"); + scrollX = fontBig.getStringWidth(nuovaEquazione.substring(0, caretPos) + "|||"); showCaret = true; showCaretDelta = 0L; return true; case RESET: - if (PIDisplay.error != null) { + if (DisplayManager.error != null) { Utils.debug.println("Resetting after error..."); - PIDisplay.error = null; + DisplayManager.error = null; return true; } else { caretPos = 0; - nuovaEquazione=""; + nuovaEquazione = ""; afterDoNextStep = false; if (calc.f != null) { calc.f.clear(); } return true; } - case SURD_MODE: + case SURD_MODE: calc.exactMode = !calc.exactMode; - if (calc.exactMode == false) { + if (calc.exactMode == false) { calc.f2 = solveExpression(calc.f2); } else { equazioneCorrente = ""; @@ -472,27 +471,25 @@ public class MathInputScreen extends Screen { } return true; case debug1: - PIDisplay.INSTANCE.setScreen(new EmptyScreen()); + DisplayManager.INSTANCE.setScreen(new EmptyScreen()); return true; case HISTORY_BACK: - if (PIDisplay.INSTANCE.canGoBack()) { - if (equazioneCorrente != null && equazioneCorrente.length() > 0 & PIDisplay.sessions[PIDisplay.currentSession+1] instanceof MathInputScreen) { + if (DisplayManager.INSTANCE.canGoBack()) { + if (equazioneCorrente != null && equazioneCorrente.length() > 0 & DisplayManager.sessions[DisplayManager.currentSession + 1] instanceof MathInputScreen) { nuovaEquazione = equazioneCorrente; try { interpreta(true); - } catch (Error e) { - } + } catch (final Error e) {} } } return false; case HISTORY_FORWARD: - if (PIDisplay.INSTANCE.canGoForward()) { - if (equazioneCorrente != null && equazioneCorrente.length() > 0 & PIDisplay.sessions[PIDisplay.currentSession-1] instanceof MathInputScreen) { + if (DisplayManager.INSTANCE.canGoForward()) { + if (equazioneCorrente != null && equazioneCorrente.length() > 0 & DisplayManager.sessions[DisplayManager.currentSession - 1] instanceof MathInputScreen) { nuovaEquazione = equazioneCorrente; try { interpreta(true); - } catch (Error e) { - } + } catch (final Error e) {} } } return false; @@ -527,23 +524,23 @@ public class MathInputScreen extends Screen { return false; } } - + private ArrayList solveExpression(ArrayList f22) { try { try { return calc.solveExpression(f22); - } catch (Exception ex) { + } catch (final Exception ex) { if (Utils.debugOn) { ex.printStackTrace(); } throw new Error(Errors.SYNTAX_ERROR); } - } catch (Error e) { - StringWriter sw = new StringWriter(); - PrintWriter pw = new PrintWriter(sw); + } catch (final Error e) { + final StringWriter sw = new StringWriter(); + final PrintWriter pw = new PrintWriter(sw); e.printStackTrace(pw); d.errorStackTrace = sw.toString().toUpperCase().replace("\t", " ").replace("\r", "").split("\n"); - PIDisplay.error = e.id.toString(); + DisplayManager.error = e.id.toString(); System.err.println(e.id); } return null; @@ -554,15 +551,15 @@ public class MathInputScreen extends Screen { try { showVariablesDialog(); ArrayList results = new ArrayList<>(); - ArrayList partialResults = new ArrayList<>(); - for (Function f : calc.f2) { + final ArrayList partialResults = new ArrayList<>(); + for (final Function f : calc.f2) { if (f instanceof Equation) { - PIDisplay.INSTANCE.setScreen(new SolveEquationScreen(this)); + DisplayManager.INSTANCE.setScreen(new SolveEquationScreen(this)); } else { results.add(f); - for (Function itm : results) { + for (final Function itm : results) { if (itm.isSolved() == false) { - List dt = itm.solveOneStep(); + final List dt = itm.solveOneStep(); partialResults.addAll(dt); } else { partialResults.add(itm); @@ -572,34 +569,34 @@ public class MathInputScreen extends Screen { partialResults.clear(); } } - + if (results.size() == 0) { calc.resultsCount = 0; } else { calc.resultsCount = results.size(); Collections.reverse(results); // add elements to al, including duplicates - Set hs = new LinkedHashSet<>(); + final Set hs = new LinkedHashSet<>(); hs.addAll(results); results.clear(); results.addAll(hs); calc.f2 = results; - for (Function rf : calc.f2) { + for (final Function rf : calc.f2) { rf.generateGraphics(); } } - } catch (Exception ex) { + } catch (final Exception ex) { if (Utils.debugOn) { ex.printStackTrace(); } throw new Error(Errors.SYNTAX_ERROR); } - } catch (Error e) { - StringWriter sw = new StringWriter(); - PrintWriter pw = new PrintWriter(sw); + } catch (final Error e) { + final StringWriter sw = new StringWriter(); + final PrintWriter pw = new PrintWriter(sw); e.printStackTrace(pw); d.errorStackTrace = sw.toString().toUpperCase().replace("\t", " ").replace("\r", "").split("\n"); - PIDisplay.error = e.id.toString(); + DisplayManager.error = e.id.toString(); System.err.println(e.id); } } @@ -607,71 +604,72 @@ public class MathInputScreen extends Screen { protected void solve() { try { try { - for (Function f : calc.f) { + for (final Function f : calc.f) { if (f instanceof Equation) { - PIDisplay.INSTANCE.setScreen(new SolveEquationScreen(this)); + DisplayManager.INSTANCE.setScreen(new SolveEquationScreen(this)); return; } } - - ArrayList results = solveExpression(calc.f); + + final ArrayList results = solveExpression(calc.f); if (results.size() == 0) { calc.resultsCount = 0; } else { calc.resultsCount = results.size(); Collections.reverse(results); // add elements to al, including duplicates - Set hs = new LinkedHashSet<>(); + final Set hs = new LinkedHashSet<>(); hs.addAll(results); results.clear(); results.addAll(hs); calc.f2 = results; - for (Function rf : calc.f2) { + for (final Function rf : calc.f2) { rf.generateGraphics(); } } - } catch (Exception ex) { + } catch (final Exception ex) { if (Utils.debugOn) { ex.printStackTrace(); } throw new Error(Errors.SYNTAX_ERROR); } - } catch (Error e) { - StringWriter sw = new StringWriter(); - PrintWriter pw = new PrintWriter(sw); + } catch (final Error e) { + final StringWriter sw = new StringWriter(); + final PrintWriter pw = new PrintWriter(sw); e.printStackTrace(pw); d.errorStackTrace = sw.toString().toUpperCase().replace("\t", " ").replace("\r", "").split("\n"); - PIDisplay.error = e.id.toString(); + DisplayManager.error = e.id.toString(); System.err.println(e.id); } } private void changeEquationScreen() { if (equazioneCorrente != null && equazioneCorrente.length() > 0) { - MathInputScreen cloned = clone(); + final MathInputScreen cloned = clone(); cloned.caretPos = cloned.equazioneCorrente.length(); cloned.nuovaEquazione = cloned.equazioneCorrente; - cloned.scrollX = PIDisplay.renderer.glGetStringWidth(fontBig, cloned.equazioneCorrente); - try {cloned.interpreta(true);} catch (Error e) {} - PIDisplay.INSTANCE.replaceScreen(cloned); - this.initialized = false; - PIDisplay.INSTANCE.setScreen(this); - + cloned.scrollX = fontBig.getStringWidth(cloned.equazioneCorrente); + try { + cloned.interpreta(true); + } catch (final Error e) {} + DisplayManager.INSTANCE.replaceScreen(cloned); + initialized = false; + DisplayManager.INSTANCE.setScreen(this); + } } public void typeChar(String chr) { - int len = chr.length(); - nuovaEquazione=nuovaEquazione.substring(0, caretPos)+chr+nuovaEquazione.substring(caretPos, nuovaEquazione.length()); - caretPos+=len; - scrollX = PIDisplay.renderer.glGetStringWidth(fontBig, nuovaEquazione.substring(0, caretPos)+"|||"); + final int len = chr.length(); + nuovaEquazione = nuovaEquazione.substring(0, caretPos) + chr + nuovaEquazione.substring(caretPos, nuovaEquazione.length()); + caretPos += len; + scrollX = fontBig.getStringWidth(nuovaEquazione.substring(0, caretPos) + "|||"); showCaret = true; showCaretDelta = 0L; afterDoNextStep = false; try { interpreta(true); - } catch (Error e) { - } + } catch (final Error e) {} // f.clear(); //TODO: I removed this line to prevent input blanking when pressing EQUALS button and cloning this screen, but I must see why I created this part of code. } @@ -679,30 +677,30 @@ public class MathInputScreen extends Screen { public boolean keyReleased(Key k) { return false; } - + public void showVariablesDialog() { showVariablesDialog(null); } - + public void showVariablesDialog(final Runnable runnable) { - Thread ct = new Thread(()->{ - ArrayList variablesInFunctions = getVariables(calc.f.toArray(new Function[calc.f.size()])); - for (VariableValue f : calc.variablesValues) { + final Thread ct = new Thread(() -> { + final ArrayList variablesInFunctions = getVariables(calc.f.toArray(new Function[calc.f.size()])); + for (final VariableValue f : calc.variablesValues) { if (variablesInFunctions.contains(f.v)) { variablesInFunctions.remove(f.v); } } - + boolean cancelled = false; - for (Function f : variablesInFunctions) { - ChooseVariableValueScreen cvs = new ChooseVariableValueScreen(this, new VariableValue((Variable) f, new Number(calc, 0))); - PIDisplay.INSTANCE.setScreen(cvs); + for (final Function f : variablesInFunctions) { + final ChooseVariableValueScreen cvs = new ChooseVariableValueScreen(this, new VariableValue((Variable) f, new Number(calc, 0))); + DisplayManager.INSTANCE.setScreen(cvs); try { - while (PIDisplay.screen == cvs) { + while (DisplayManager.screen == cvs) { Utils.debug.println(Thread.currentThread().getName()); Thread.sleep(200); } - } catch (InterruptedException e) {} + } catch (final InterruptedException e) {} if (cvs.resultNumberValue == null) { cancelled = true; break; @@ -716,7 +714,7 @@ public class MathInputScreen extends Screen { calc.variablesValues.add(new VariableValue((Variable) f, (Number) cvs.resultNumberValue)); } } - if (!cancelled) { + if (!cancelled) { if (runnable != null) { runnable.run(); } @@ -728,16 +726,16 @@ public class MathInputScreen extends Screen { ct.setDaemon(true); ct.start(); } - + private ArrayList getVariables(Function[] fncs) { - ArrayList res = new ArrayList<>(); - for (Function f : fncs) { + final ArrayList res = new ArrayList<>(); + for (final Function f : fncs) { if (f instanceof FunctionTwoValues) { - res.addAll(getVariables(new Function[]{((FunctionTwoValues)f).getVariable1(), ((FunctionTwoValues)f).getVariable2()})); + res.addAll(getVariables(new Function[] { ((FunctionTwoValues) f).getVariable1(), ((FunctionTwoValues) f).getVariable2() })); } else if (f instanceof FunctionMultipleValues) { - res.addAll(getVariables(((FunctionMultipleValues)f).getVariables())); + res.addAll(getVariables(((FunctionMultipleValues) f).getVariables())); } else if (f instanceof AnteriorFunction) { - res.addAll(getVariables(new Function[]{((AnteriorFunction)f).getVariable()})); + res.addAll(getVariables(new Function[] { ((AnteriorFunction) f).getVariable() })); } else if (f instanceof Variable) { if (!res.contains(f)) { res.add(f); @@ -746,11 +744,11 @@ public class MathInputScreen extends Screen { } return res; } - + @Override public MathInputScreen clone() { - MathInputScreen es = this; - MathInputScreen es2 = new MathInputScreen(); + final MathInputScreen es = this; + final MathInputScreen es2 = new MathInputScreen(); es2.scrollX = es.scrollX; es2.nuovaEquazione = es.nuovaEquazione; es2.equazioneCorrente = es.equazioneCorrente; diff --git a/src/org/warp/picalculator/gui/screens/Screen.java b/src/org/warp/picalculator/gui/screens/Screen.java index 21ea5a13..59625fad 100644 --- a/src/org/warp/picalculator/gui/screens/Screen.java +++ b/src/org/warp/picalculator/gui/screens/Screen.java @@ -1,10 +1,10 @@ package org.warp.picalculator.gui.screens; import org.warp.picalculator.device.Keyboard.Key; -import org.warp.picalculator.gui.PIDisplay; +import org.warp.picalculator.gui.DisplayManager; public abstract class Screen { - public PIDisplay d; + public DisplayManager d; public boolean created = false; public boolean initialized = false; public boolean canBeInHistory = false; @@ -30,9 +30,9 @@ public abstract class Screen { public abstract void init() throws InterruptedException; public abstract void render(); - + public void renderStatusbar() { - + } public abstract void beforeRender(float dt); @@ -40,6 +40,6 @@ public abstract class Screen { public abstract boolean mustBeRefreshed(); public abstract boolean keyPressed(Key k); - + public abstract boolean keyReleased(Key k); } diff --git a/src/org/warp/picalculator/gui/screens/SolveEquationScreen.java b/src/org/warp/picalculator/gui/screens/SolveEquationScreen.java index e7c35118..d2e51626 100644 --- a/src/org/warp/picalculator/gui/screens/SolveEquationScreen.java +++ b/src/org/warp/picalculator/gui/screens/SolveEquationScreen.java @@ -3,41 +3,40 @@ package org.warp.picalculator.gui.screens; import org.warp.picalculator.Error; import org.warp.picalculator.Main; import org.warp.picalculator.device.Keyboard.Key; -import org.warp.picalculator.gui.PIDisplay; +import org.warp.picalculator.gui.DisplayManager; import org.warp.picalculator.math.Calculator; public class SolveEquationScreen extends Screen { @SuppressWarnings("unused") - private MathInputScreen es; + private final MathInputScreen es; public SolveEquationScreen(MathInputScreen es) { super(); canBeInHistory = false; - + this.es = es; } - + @Override - public void created() throws InterruptedException { - } + public void created() throws InterruptedException {} @Override public void init() throws InterruptedException {} @Override public void render() { - PIDisplay.renderer.glColor4i(0, 0, 0, 64); - PIDisplay.renderer.glDrawStringCenter(Main.screenSize[0]/2+1, Main.screenSize[1]/4, "WORK IN PROGRESS. THIS SCREEN MUST HAVE A GUI TO SELECT THE VARIABLE TO SOLVE."); - PIDisplay.renderer.glDrawStringCenter(Main.screenSize[0]/2, Main.screenSize[1]/4+1, "WORK IN PROGRESS. THIS SCREEN MUST HAVE A GUI TO SELECT THE VARIABLE TO SOLVE."); - PIDisplay.renderer.glDrawStringCenter(Main.screenSize[0]/2+1, Main.screenSize[1]/4+1, "WORK IN PROGRESS. THIS SCREEN MUST HAVE A GUI TO SELECT THE VARIABLE TO SOLVE."); - PIDisplay.renderer.glColor3i(255, 0, 0); - PIDisplay.renderer.glDrawStringCenter(Main.screenSize[0]/2, Main.screenSize[1]/4, "WORK IN PROGRESS. THIS SCREEN MUST HAVE A GUI TO SELECT THE VARIABLE TO SOLVE."); + DisplayManager.renderer.glColor4i(0, 0, 0, 64); + DisplayManager.renderer.glDrawStringCenter(Main.screenSize[0] / 2 + 1, Main.screenSize[1] / 4, "WORK IN PROGRESS. THIS SCREEN MUST HAVE A GUI TO SELECT THE VARIABLE TO SOLVE."); + DisplayManager.renderer.glDrawStringCenter(Main.screenSize[0] / 2, Main.screenSize[1] / 4 + 1, "WORK IN PROGRESS. THIS SCREEN MUST HAVE A GUI TO SELECT THE VARIABLE TO SOLVE."); + DisplayManager.renderer.glDrawStringCenter(Main.screenSize[0] / 2 + 1, Main.screenSize[1] / 4 + 1, "WORK IN PROGRESS. THIS SCREEN MUST HAVE A GUI TO SELECT THE VARIABLE TO SOLVE."); + DisplayManager.renderer.glColor3i(255, 0, 0); + DisplayManager.renderer.glDrawStringCenter(Main.screenSize[0] / 2, Main.screenSize[1] / 4, "WORK IN PROGRESS. THIS SCREEN MUST HAVE A GUI TO SELECT THE VARIABLE TO SOLVE."); } @Override public void beforeRender(float dt) { - + } @Override @@ -49,13 +48,13 @@ public class SolveEquationScreen extends Screen { public boolean keyPressed(Key k) { switch (k) { case LETTER_X: - PIDisplay.INSTANCE.goBack(); + DisplayManager.INSTANCE.goBack(); try { es.calc.solveExpression('X'); - } catch (Error e) { - Screen scr = PIDisplay.INSTANCE.getScreen(); + } catch (final Error e) { + final Screen scr = DisplayManager.INSTANCE.getScreen(); if (scr instanceof MathInputScreen) { - MathInputScreen escr = (MathInputScreen) scr; + final MathInputScreen escr = (MathInputScreen) scr; escr.errorLevel = 1; //escr.err2 = e; //TODO: What is this variable, and why it doesn't exists? } else { diff --git a/src/org/warp/picalculator/math/AngleMode.java b/src/org/warp/picalculator/math/AngleMode.java index 2780b927..e8f01ecb 100644 --- a/src/org/warp/picalculator/math/AngleMode.java +++ b/src/org/warp/picalculator/math/AngleMode.java @@ -1,7 +1,5 @@ package org.warp.picalculator.math; public enum AngleMode { - DEG, - RAD, - GRA + DEG, RAD, GRA } diff --git a/src/org/warp/picalculator/math/Calculator.java b/src/org/warp/picalculator/math/Calculator.java index 316a14e1..c2c0e6a5 100644 --- a/src/org/warp/picalculator/math/Calculator.java +++ b/src/org/warp/picalculator/math/Calculator.java @@ -21,7 +21,7 @@ public class Calculator { public ArrayList f2; public ArrayList variablesValues; public int resultsCount; - + public Calculator() { f = new ArrayList<>(); f2 = new ArrayList<>(); @@ -34,9 +34,9 @@ public class Calculator { if (!string.startsWith("{")) { throw new Error(Errors.SYNTAX_ERROR); } - String[] parts = string.substring(1).split("\\{"); - EquationsSystem s = new EquationsSystem(this); - for (String part : parts) { + final String[] parts = string.substring(1).split("\\{"); + final EquationsSystem s = new EquationsSystem(this); + for (final String part : parts) { s.addFunctionToEnd(parseEquationString(part)); } return s; @@ -46,16 +46,16 @@ public class Calculator { return new Expression(this, string); } } - + public Function parseEquationString(String string) throws Error { - String[] parts = string.split("="); + final String[] parts = string.split("="); if (parts.length == 1) { - Equation e = new Equation(this, null, null); + final Equation e = new Equation(this, null, null); e.setVariable1(new Expression(this, parts[0])); e.setVariable2(new Number(this, BigInteger.ZERO)); return e; } else if (parts.length == 2) { - Equation e = new Equation(this, null, null); + final Equation e = new Equation(this, null, null); e.setVariable1(new Expression(this, parts[0])); e.setVariable2(new Expression(this, parts[1])); return e; @@ -66,19 +66,19 @@ public class Calculator { public ArrayList solveExpression(ArrayList input) throws Error { ArrayList results = new ArrayList<>(); - ArrayList partialResults = new ArrayList<>(); - for (Function f : input) { + final ArrayList partialResults = new ArrayList<>(); + for (final Function f : input) { if (f instanceof Equation) { throw new IllegalArgumentException("Not an expression!"); } else { results.add(f); while (Utils.allSolved(results) == false) { - for (Function itm : results) { + for (final Function itm : results) { if (itm.isSolved() == false) { - long t1 = System.currentTimeMillis(); - List dt = itm.solveOneStep(); - long t2 = System.currentTimeMillis(); - if (t2-t1 >= 3000) { + final long t1 = System.currentTimeMillis(); + final List dt = itm.solveOneStep(); + final long t2 = System.currentTimeMillis(); + if (t2 - t1 >= 3000) { throw new Error(Errors.TIMEOUT); } partialResults.addAll(dt); @@ -108,24 +108,24 @@ public class Calculator { } public void parseInputString(String eqn) throws Error { - ArrayList fncs = new ArrayList<>(); + final ArrayList fncs = new ArrayList<>(); if (eqn.length() > 0) { try { fncs.add(parseString(eqn.replace("sqrt", "Ⓐ").replace("^", "Ⓑ"))); - } catch (Exception ex) { - + } catch (final Exception ex) { + } } f = fncs; - for (Function f : f) { + for (final Function f : f) { try { f.generateGraphics(); - } catch (NullPointerException ex) { + } catch (final NullPointerException ex) { throw new Error(Errors.SYNTAX_ERROR); } } } - + /*public void solve(EquationScreen equationScreen, char letter) throws Error { if (Calculator.currentSession == 0 && Calculator.sessions[0] instanceof EquationScreen) { EquationScreen es = (EquationScreen) Calculator.sessions[0]; diff --git a/src/org/warp/picalculator/math/MathematicalSymbols.java b/src/org/warp/picalculator/math/MathematicalSymbols.java index e6fbd722..1ff4e60a 100644 --- a/src/org/warp/picalculator/math/MathematicalSymbols.java +++ b/src/org/warp/picalculator/math/MathematicalSymbols.java @@ -51,7 +51,7 @@ public class MathematicalSymbols { } public static String[] variables() { - return new String[] { "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "ⓧ", "Ⓨ", "Z", PI}; + return new String[] { "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "ⓧ", "Ⓨ", "Z", PI }; } public static String[] genericSyntax() { @@ -59,13 +59,6 @@ public class MathematicalSymbols { } public static String getGraphicRepresentation(String string) { - return string - .replace("Ⓑ", "^") - .replace("Ⓒ", "SIN") - .replace("Ⓓ", "COS") - .replace("Ⓔ", "TAN") - .replace("Ⓕ", "ASIN") - .replace("Ⓖ", "ACOS") - .replace("Ⓗ", "ATAN"); + return string.replace("Ⓑ", "^").replace("Ⓒ", "SIN").replace("Ⓓ", "COS").replace("Ⓔ", "TAN").replace("Ⓕ", "ASIN").replace("Ⓖ", "ACOS").replace("Ⓗ", "ATAN"); } } diff --git a/src/org/warp/picalculator/math/functions/AnteriorFunction.java b/src/org/warp/picalculator/math/functions/AnteriorFunction.java index 0e61fdbe..2bf7926e 100644 --- a/src/org/warp/picalculator/math/functions/AnteriorFunction.java +++ b/src/org/warp/picalculator/math/functions/AnteriorFunction.java @@ -4,7 +4,7 @@ import java.util.ArrayList; import org.warp.picalculator.Error; import org.warp.picalculator.Utils; -import org.warp.picalculator.gui.PIDisplay; +import org.warp.picalculator.gui.DisplayManager; import org.warp.picalculator.gui.graphicengine.cpu.CPUDisplay; import org.warp.picalculator.math.Calculator; @@ -12,17 +12,17 @@ import com.rits.cloning.Cloner; public abstract class AnteriorFunction implements Function { public AnteriorFunction(Function value) { - this.root = value.getRoot(); + root = value.getRoot(); variable = value; } - + public AnteriorFunction(Calculator root, Function value) { this.root = root; variable = value; } - + protected abstract Function NewInstance(Calculator root, Function value); - + protected final Calculator root; protected Function variable; protected int width; @@ -49,54 +49,54 @@ public abstract class AnteriorFunction implements Function { @Override public final ArrayList solveOneStep() throws Error { final boolean solved = variable.isSolved(); - ArrayList result = solved?solve():null; - + ArrayList result = solved ? solve() : null; + if (result == null || result.isEmpty()) { result = new ArrayList<>(); - - ArrayList l1 = new ArrayList<>(); + + final ArrayList l1 = new ArrayList<>(); if (variable.isSolved()) { l1.add(variable); } else { l1.addAll(variable.solveOneStep()); } - - for (Function f : l1) { - result.add(NewInstance(this.root, f)); + + for (final Function f : l1) { + result.add(NewInstance(root, f)); } } - + return result; } protected abstract ArrayList solve() throws Error; - + @Override public boolean isSolved() { return variable.isSolved() ? !isSolvable() : false; } - + protected abstract boolean isSolvable(); - + @Override public void generateGraphics() { variable.setSmall(small); variable.generateGraphics(); - - width = PIDisplay.renderer.glGetStringWidth(Utils.getFont(small), getSymbol()) + 1 + getVariable().getWidth(); + + width = DisplayManager.renderer.glGetStringWidth(Utils.getFont(small), getSymbol()) + 1 + getVariable().getWidth(); height = variable.getHeight(); line = variable.getLine(); } @Override public void draw(int x, int y) { - float h1 = getVariable().getHeight(); - int wsegno = PIDisplay.renderer.glGetStringWidth(Utils.getFont(small), getSymbol()); - float hsegno = Utils.getFontHeight(small); - float maxh = getHeight(); - PIDisplay.renderer.glSetFont(Utils.getFont(small)); - - PIDisplay.renderer.glDrawStringLeft(x, (int) Math.floor(y + (maxh - hsegno) / 2), getSymbol()); + final float h1 = getVariable().getHeight(); + final int wsegno = DisplayManager.renderer.glGetStringWidth(Utils.getFont(small), getSymbol()); + final float hsegno = Utils.getFontHeight(small); + final float maxh = getHeight(); + DisplayManager.renderer.glSetFont(Utils.getFont(small)); + + DisplayManager.renderer.glDrawStringLeft(x, (int) Math.floor(y + (maxh - hsegno) / 2), getSymbol()); getVariable().draw(x + wsegno + 1, (int) Math.floor(y + (maxh - h1) / 2)); } @@ -123,7 +123,7 @@ public abstract class AnteriorFunction implements Function { if (variable != null) { val1 = variable.toString(); } - return getSymbol()+val1; + return getSymbol() + val1; // } catch (Error e) { // return e.id.toString(); // } @@ -131,20 +131,20 @@ public abstract class AnteriorFunction implements Function { @Override public AnteriorFunction clone() { - Cloner cloner = new Cloner(); + final Cloner cloner = new Cloner(); return cloner.deepClone(this); } - + @Override public void setSmall(boolean small) { this.small = small; } - + @Override public int hashCode() { - return variable.hashCode()+883*getSymbol().hashCode(); + return variable.hashCode() + 883 * getSymbol().hashCode(); } - + @Override public abstract boolean equals(Object o); } diff --git a/src/org/warp/picalculator/math/functions/Division.java b/src/org/warp/picalculator/math/functions/Division.java index 0b69cb67..b30e970c 100644 --- a/src/org/warp/picalculator/math/functions/Division.java +++ b/src/org/warp/picalculator/math/functions/Division.java @@ -4,7 +4,7 @@ import java.util.ArrayList; import org.warp.picalculator.Error; import org.warp.picalculator.Utils; -import org.warp.picalculator.gui.PIDisplay; +import org.warp.picalculator.gui.DisplayManager; import org.warp.picalculator.gui.graphicengine.cpu.CPUDisplay; import org.warp.picalculator.math.Calculator; import org.warp.picalculator.math.MathematicalSymbols; @@ -29,19 +29,26 @@ public class Division extends FunctionTwoValues { return MathematicalSymbols.DIVISION; } - @Override protected boolean isSolvable() { - if (FractionsRule1.compare(this)) return true; - if (FractionsRule2.compare(this)) return true; - if (FractionsRule3.compare(this)) return true; - if (UndefinedRule2.compare(this)) return true; + if (FractionsRule1.compare(this)) { + return true; + } + if (FractionsRule2.compare(this)) { + return true; + } + if (FractionsRule3.compare(this)) { + return true; + } + if (UndefinedRule2.compare(this)) { + return true; + } if (variable1 instanceof Number && variable2 instanceof Number && root.exactMode == false) { return true; - } + } return false; } - + @Override public ArrayList solve() throws Error { ArrayList result = new ArrayList<>(); @@ -52,15 +59,15 @@ public class Division extends FunctionTwoValues { } else if (FractionsRule3.compare(this)) { result = FractionsRule3.execute(this); } else if (UndefinedRule2.compare(this)) { - result = UndefinedRule2.execute(this); + result = UndefinedRule2.execute(this); } else if (variable1 instanceof Number && variable2 instanceof Number && root.exactMode == false) { - result.add(((Number)variable1).divide((Number)variable2)); + result.add(((Number) variable1).divide((Number) variable2)); } return result; } public boolean hasMinus() { - String numerator = variable1.toString(); + final String numerator = variable1.toString(); if (numerator.startsWith("-")) { return true; } @@ -68,7 +75,7 @@ public class Division extends FunctionTwoValues { } public void draw(int x, int y, boolean small, boolean drawMinus) { - boolean beforedrawminus = this.drawMinus; + final boolean beforedrawminus = this.drawMinus; this.drawMinus = drawMinus; draw(x, y); this.drawMinus = beforedrawminus; @@ -79,22 +86,22 @@ public class Division extends FunctionTwoValues { @Override public void generateGraphics() { variable1.generateGraphics(); - + variable2.generateGraphics(); - + width = calcWidth(); height = calcHeight(); line = variable1.getHeight() + 1; } - + @Override public void draw(int x, int y) { // glColor3f(255, 127-50+new Random().nextInt(50), 0); // glFillRect(x,y,width,height); // glColor3f(0, 0, 0); - - Object var1 = variable1; - Object var2 = variable2; + + final Object var1 = variable1; + final Object var2 = variable2; boolean minus = false; int minusw = 0; int minush = 0; @@ -105,15 +112,15 @@ public class Division extends FunctionTwoValues { } int w1 = 0; int h1 = 0; - PIDisplay.renderer.glSetFont(Utils.getFont(small)); + Utils.getFont(small).use(DisplayManager.display); if (minus) { - w1 = PIDisplay.renderer.glGetStringWidth(Utils.getFont(small), numerator); - h1 = Utils.getFont(small).charH; + w1 = Utils.getFont(small).getStringWidth(numerator); + h1 = Utils.getFont(small).getCharacterHeight(); } else { w1 = ((Function) var1).getWidth(); h1 = ((Function) var1).getHeight(); } - int w2 = ((Function) var2).getWidth(); + final int w2 = ((Function) var2).getWidth(); int maxw; if (w1 > w2) { maxw = 1 + w1; @@ -121,22 +128,22 @@ public class Division extends FunctionTwoValues { maxw = 1 + w2; } if (minus && drawMinus) { - minusw = PIDisplay.renderer.glGetStringWidth(Utils.getFont(small), "-") + 1; - minush = Utils.getFont(small).charH; - PIDisplay.renderer.glDrawStringLeft(x+1, y + h1 + 1 + 1 - (minush / 2), "-"); - PIDisplay.renderer.glDrawStringLeft((int) (x+1 + minusw + 1 + (maxw - w1) / 2d), y, numerator); + minusw = Utils.getFont(small).getCharacterWidth() /* Width of minus */ + 1; + minush = Utils.getFont(small).getCharacterHeight(); + DisplayManager.renderer.glDrawStringLeft(x + 1, y + h1 + 1 + 1 - (minush / 2), "-"); + DisplayManager.renderer.glDrawStringLeft((int) (x + 1 + minusw + 1 + (maxw - w1) / 2d), y, numerator); } else { - ((Function) var1).draw((int) (x+1 + minusw + (maxw - w1) / 2d), y); + ((Function) var1).draw((int) (x + 1 + minusw + (maxw - w1) / 2d), y); } - ((Function) var2).draw((int) (x+1 + minusw + (maxw - w2) / 2d), y + h1 + 1 + 1 + 1); - PIDisplay.renderer.glFillRect(x+1+ minusw, y + h1 + 1, maxw, 1); + ((Function) var2).draw((int) (x + 1 + minusw + (maxw - w2) / 2d), y + h1 + 1 + 1 + 1); + DisplayManager.renderer.glFillColor(x + 1 + minusw, y + h1 + 1, maxw, 1); } @Override public int getHeight() { return height; } - + @Override protected int calcHeight() { @@ -152,7 +159,7 @@ public class Division extends FunctionTwoValues { } else { h1 = variable1.getHeight(); } - int h2 = variable2.getHeight(); + final int h2 = variable2.getHeight(); return h1 + 3 + h2; } @@ -160,12 +167,12 @@ public class Division extends FunctionTwoValues { public int getLine() { return line; } - + @Override public int getWidth() { return width; } - + @Override protected int calcWidth() { boolean minus = false; @@ -176,28 +183,28 @@ public class Division extends FunctionTwoValues { } int w1 = 0; if (minus) { - w1 = PIDisplay.renderer.glGetStringWidth(Utils.getFont(small), numerator); + w1 = Utils.getFont(small).getStringWidth(numerator); } else { w1 = variable1.getWidth(); } - int w2 = variable2.getWidth(); + final int w2 = variable2.getWidth(); int maxw = 0; if (w1 > w2) { - maxw = w1+1; + maxw = w1 + 1; } else { - maxw = w2+1; + maxw = w2 + 1; } if (minus && drawMinus) { - return 1 + PIDisplay.renderer.glGetStringWidth(Utils.getFont(small), "-") + 1 + maxw; + return 1 + Utils.getFont(small).getCharacterWidth() /* Width of minus */ + 1 + maxw; } else { return 1 + maxw; } } - + @Override public boolean equals(Object o) { if (o instanceof Division) { - FunctionTwoValues f = (FunctionTwoValues) o; + final FunctionTwoValues f = (FunctionTwoValues) o; return variable1.equals(f.variable1) && variable2.equals(f.variable2); } return false; diff --git a/src/org/warp/picalculator/math/functions/EmptyNumber.java b/src/org/warp/picalculator/math/functions/EmptyNumber.java index 65eeab63..5b437cb8 100644 --- a/src/org/warp/picalculator/math/functions/EmptyNumber.java +++ b/src/org/warp/picalculator/math/functions/EmptyNumber.java @@ -4,7 +4,7 @@ import java.util.List; import org.warp.picalculator.Error; import org.warp.picalculator.Utils; -import org.warp.picalculator.gui.PIDisplay; +import org.warp.picalculator.gui.DisplayManager; import org.warp.picalculator.gui.graphicengine.cpu.CPUDisplay; import org.warp.picalculator.math.Calculator; @@ -13,9 +13,9 @@ public class EmptyNumber implements Function { public EmptyNumber(Calculator root) { this.root = root; } - + private final Calculator root; - + @Override public String getSymbol() { return " "; @@ -39,12 +39,12 @@ public class EmptyNumber implements Function { @Override public void draw(int x, int y) { - PIDisplay.renderer.glDrawStringLeft(x, y, "␀"); + DisplayManager.renderer.glDrawStringLeft(x, y, "␀"); } @Override public int getWidth() { - return PIDisplay.renderer.glGetStringWidth(Utils.getFont(small), "␀"); + return DisplayManager.renderer.glGetStringWidth(Utils.getFont(small), "␀"); } @Override @@ -54,7 +54,7 @@ public class EmptyNumber implements Function { @Override public int getLine() { - return Utils.getFont(small).charH/2; + return Utils.getFont(small).charH / 2; } @Override @@ -63,12 +63,12 @@ public class EmptyNumber implements Function { } private boolean small = false; - + @Override public void setSmall(boolean small) { this.small = small; } - + @Override public boolean equals(Object o) { return o instanceof EmptyNumber; diff --git a/src/org/warp/picalculator/math/functions/Expression.java b/src/org/warp/picalculator/math/functions/Expression.java index 2a0cb0f1..6f5e4eb3 100644 --- a/src/org/warp/picalculator/math/functions/Expression.java +++ b/src/org/warp/picalculator/math/functions/Expression.java @@ -12,7 +12,7 @@ import java.util.regex.Pattern; import org.warp.picalculator.Error; import org.warp.picalculator.Errors; import org.warp.picalculator.Utils; -import org.warp.picalculator.gui.PIDisplay; +import org.warp.picalculator.gui.DisplayManager; import org.warp.picalculator.math.Calculator; import org.warp.picalculator.math.MathematicalSymbols; import org.warp.picalculator.math.functions.trigonometry.ArcCosine; @@ -27,7 +27,7 @@ public class Expression extends FunctionMultipleValues { public Expression(Calculator root) { super(root); } - + public Expression(Calculator root, Function[] values) { super(root, values); } @@ -48,19 +48,19 @@ public class Expression extends FunctionMultipleValues { try { new Number(root, string); isNumber = true; - } catch (NumberFormatException ex) { + } catch (final NumberFormatException ex) { isNumber = false; } - + String processExpression = string; Utils.debug.println(debugSpaces + "•Analyzing expression:" + processExpression); - + isNumber = false; //TODO: rimuovere isNumber, alcune semplificazione come la divisione per zero altrimenti verrebbero saltate. - - if (isNumber){ + + if (isNumber) { // If the expression is already a number: // Se l'espressione è già un numero: - Number t = new Number(root, string); + final Number t = new Number(root, string); setVariables(new Function[] { t }); Utils.debug.println(debugSpaces + "•Result:" + t.toString()); } else { @@ -75,7 +75,7 @@ public class Expression extends FunctionMultipleValues { // Controlla se ci sono più di un uguale (=) int equationsFound = 0; int systemsFound = 0; - for (char c : processExpression.toCharArray()) { + for (final char c : processExpression.toCharArray()) { if (("" + c).equals(MathematicalSymbols.EQUATION)) { equationsFound += 1; } @@ -98,7 +98,7 @@ public class Expression extends FunctionMultipleValues { boolean symbolsChanged = false; while (matcher.find()) { symbolsChanged = true; - String correzione = "+"; + final String correzione = "+"; processExpression = processExpression.substring(0, matcher.start(0)) + correzione + processExpression.substring(matcher.start(0) + matcher.group(0).length(), processExpression.length()); matcher = pattern.matcher(processExpression); } @@ -109,11 +109,11 @@ public class Expression extends FunctionMultipleValues { matcher = pattern.matcher(processExpression); while (matcher.find()) { symbolsChanged = true; - String correzione = "-"; + final String correzione = "-"; processExpression = processExpression.substring(0, matcher.start(0)) + correzione + processExpression.substring(matcher.start(0) + matcher.group(0).length(), processExpression.length()); matcher = pattern.matcher(processExpression); } - + // Rimuovi i segni appena dopo le parentesi if (processExpression.contains("(+")) { symbolsChanged = true; @@ -138,11 +138,11 @@ public class Expression extends FunctionMultipleValues { symbolsChanged = false; while (matcher.find()) { symbolsChanged = true; - String correzione = matcher.group(0).replaceFirst(Matcher.quoteReplacement("+"), ""); + final String correzione = matcher.group(0).replaceFirst(Matcher.quoteReplacement("+"), ""); processExpression = processExpression.substring(0, matcher.start(0) + 1) + correzione + processExpression.substring(matcher.start(0) + matcher.group(0).length(), processExpression.length()); matcher = pattern.matcher(processExpression); } - + // Correggi i segni - in − processExpression = processExpression.replace("-", MathematicalSymbols.SUBTRACTION); @@ -151,11 +151,11 @@ public class Expression extends FunctionMultipleValues { matcher = pattern.matcher(processExpression); while (matcher.find()) { symbolsChanged = true; - String correzione = MathematicalSymbols.MINUS; + final String correzione = MathematicalSymbols.MINUS; processExpression = processExpression.substring(0, matcher.start(0) + 1) + correzione + processExpression.substring(matcher.start(0) + 2, processExpression.length()); matcher = pattern.matcher(processExpression); } - + // Cambia il segno iniziale − in - if (processExpression.startsWith("−")) { symbolsChanged = true; @@ -186,7 +186,7 @@ public class Expression extends FunctionMultipleValues { symbolsChanged = true; // sistema i segni * impliciti prima e dopo l'espressione. String beforeexp = processExpression.substring(0, matcher.start(0)); - String newexp = matcher.group(0).substring(1, matcher.group(0).length() - 1); + final String newexp = matcher.group(0).substring(1, matcher.group(0).length() - 1); String afterexp = processExpression.substring(matcher.start(0) + matcher.group(0).length(), processExpression.length()); if (Pattern.compile("[^\\-" + Utils.ArrayToRegex(Utils.add(concat(MathematicalSymbols.functions(), concat(MathematicalSymbols.signums(true), MathematicalSymbols.genericSyntax())), "(")) + "]$").matcher(beforeexp).find()) { // Se la stringa precedente finisce con un numero @@ -211,13 +211,13 @@ public class Expression extends FunctionMultipleValues { debugSpaces += " "; // Convert the expression to a list of objects - Expression imputRawParenthesis = new Expression(root); + final Expression imputRawParenthesis = new Expression(root); imputRawParenthesis.setVariables(new Function[] {}); String tmp = ""; final String[] functions = concat(concat(concat(concat(MathematicalSymbols.functions(), MathematicalSymbols.parentheses()), MathematicalSymbols.signums(true)), MathematicalSymbols.variables()), MathematicalSymbols.genericSyntax()); for (int i = 0; i < processExpression.length(); i++) { // Per ogni carattere cerca se è un numero o una funzione: - String charI = processExpression.charAt(i) + ""; + final String charI = processExpression.charAt(i) + ""; if (Utils.isInArray(charI, functions)) { // Finds the type of function fron the following list @@ -326,7 +326,7 @@ public class Expression extends FunctionMultipleValues { Utils.debug.println(debugSpaces + "•Added multiplication to expression:" + new Multiplication(root, null, null).getSymbol()); } } else { - Function precedentFunction = imputRawParenthesis.getVariable(imputRawParenthesis.getVariablesLength() - 1); + final Function precedentFunction = imputRawParenthesis.getVariable(imputRawParenthesis.getVariablesLength() - 1); if (tmp.length() > 0) { if (precedentFunction instanceof Number || precedentFunction instanceof Variable) { imputRawParenthesis.addFunctionToEnd(new Multiplication(root, null, null)); @@ -366,7 +366,7 @@ public class Expression extends FunctionMultipleValues { // Se il carattere è un numero intero, un segno // negativo, o un punto tmp += charI; - } catch (Exception exc) { + } catch (final Exception exc) { throw new java.lang.RuntimeException("Il carattere " + tmp + charI + " non è nè un numero nè un espressione presente nella lista completa!\nAggiungerlo ad essa o rimuovere il carattere dall'espressione!"); } } @@ -375,7 +375,7 @@ public class Expression extends FunctionMultipleValues { Utils.debug.println(debugSpaces + "•Added variable to expression:" + tmp); try { imputRawParenthesis.addFunctionToEnd(new Number(root, tmp)); - } catch (NumberFormatException ex) { + } catch (final NumberFormatException ex) { throw new Error(Errors.SYNTAX_ERROR); } tmp = ""; @@ -392,9 +392,9 @@ public class Expression extends FunctionMultipleValues { Utils.debug.println(debugSpaces + "•Removing useless parentheses"); for (int i = 0; i < imputRawParenthesis.functions.length; i++) { if (imputRawParenthesis.functions[i] instanceof Expression) { - Expression par = (Expression) imputRawParenthesis.functions[i]; + final Expression par = (Expression) imputRawParenthesis.functions[i]; if (par.functions.length == 1) { - Function subFunz = par.functions[0]; + final Function subFunz = par.functions[0]; if (subFunz instanceof Expression || subFunz instanceof Number || subFunz instanceof Variable) { imputRawParenthesis.functions[i] = subFunz; Utils.debug.println(debugSpaces + " •Useless parentheses removed"); @@ -402,21 +402,21 @@ public class Expression extends FunctionMultipleValues { } } } - + // Inizia l'affinazione dell'espressione Utils.debug.println(debugSpaces + "•Pushing classes..."); - Function[] oldFunctionsArray = imputRawParenthesis.getVariables(); - ArrayList oldFunctionsList = new ArrayList<>(); + final Function[] oldFunctionsArray = imputRawParenthesis.getVariables(); + final ArrayList oldFunctionsList = new ArrayList<>(); for (int i = 0; i < oldFunctionsArray.length; i++) { Function funzione = oldFunctionsArray[i]; if (funzione != null) { //Affinazione - if (funzione instanceof Root) { - if ((i - 1) >= 0 && oldFunctionsArray[i-1] instanceof Number && ((Number)oldFunctionsArray[i-1]).getTerm().compareTo(new BigDecimal(2)) == 0) { + if (funzione instanceof Root) { + if ((i - 1) >= 0 && oldFunctionsArray[i - 1] instanceof Number && ((Number) oldFunctionsArray[i - 1]).getTerm().compareTo(new BigDecimal(2)) == 0) { oldFunctionsArray[i] = null; - oldFunctionsArray[i-1] = null; - oldFunctionsList.remove(oldFunctionsList.size()-1); + oldFunctionsArray[i - 1] = null; + oldFunctionsList.remove(oldFunctionsList.size() - 1); i -= 1; funzione = new RootSquare(root, null); } @@ -452,64 +452,12 @@ public class Expression extends FunctionMultipleValues { oldFunctionsList.set(0, new Multiplication(root, oldFunctionsList.get(0), oldFunctionsList.remove(1))); } } - Utils.debug.println(debugSpaces + " •Phase: "+step); + Utils.debug.println(debugSpaces + " •Phase: " + step); while (i < oldFunctionsList.size() && change == false && oldFunctionsList.size() > 1) { - Function funzioneTMP = oldFunctionsList.get(i); + final Function funzioneTMP = oldFunctionsList.get(i); if (funzioneTMP instanceof FunctionTwoValues) { if (step != "SN Functions") { - if ( - (step == "sums" && (funzioneTMP instanceof Sum || funzioneTMP instanceof SumSubtraction || funzioneTMP instanceof Subtraction) == true && ((funzioneTMP instanceof AnteriorFunction && ((AnteriorFunction) funzioneTMP).variable == null) || (funzioneTMP instanceof FunctionTwoValues && ((FunctionTwoValues) funzioneTMP).variable1 == null && ((FunctionTwoValues) funzioneTMP).variable2 == null) || (!(funzioneTMP instanceof AnteriorFunction) && !(funzioneTMP instanceof FunctionTwoValues)))) - || - ( - step.equals("multiplications") - && - ( - (funzioneTMP instanceof Multiplication) - || - (funzioneTMP instanceof Division) - ) - && - ((FunctionTwoValues) funzioneTMP).variable1 == null - && - ((FunctionTwoValues) funzioneTMP).variable2 == null - ) - || - ( - step == "NSN Functions" - && - (funzioneTMP instanceof Sum) == false - && - (funzioneTMP instanceof SumSubtraction) == false - && - (funzioneTMP instanceof Subtraction) == false - && - (funzioneTMP instanceof Multiplication) == false - && - (funzioneTMP instanceof Division) == false - && - ( - ( - funzioneTMP instanceof AnteriorFunction - && - ((AnteriorFunction) funzioneTMP).variable == null - ) - || - ( - funzioneTMP instanceof FunctionTwoValues - && - ((FunctionTwoValues) funzioneTMP).variable1 == null - && - ((FunctionTwoValues) funzioneTMP).variable2 == null - ) - || - ( - !(funzioneTMP instanceof AnteriorFunction) - && - !(funzioneTMP instanceof FunctionTwoValues) - ) - ) - ) - ) { + if ((step == "sums" && (funzioneTMP instanceof Sum || funzioneTMP instanceof SumSubtraction || funzioneTMP instanceof Subtraction) == true && ((funzioneTMP instanceof AnteriorFunction && ((AnteriorFunction) funzioneTMP).variable == null) || (funzioneTMP instanceof FunctionTwoValues && ((FunctionTwoValues) funzioneTMP).variable1 == null && ((FunctionTwoValues) funzioneTMP).variable2 == null) || (!(funzioneTMP instanceof AnteriorFunction) && !(funzioneTMP instanceof FunctionTwoValues)))) || (step.equals("multiplications") && ((funzioneTMP instanceof Multiplication) || (funzioneTMP instanceof Division)) && ((FunctionTwoValues) funzioneTMP).variable1 == null && ((FunctionTwoValues) funzioneTMP).variable2 == null) || (step == "NSN Functions" && (funzioneTMP instanceof Sum) == false && (funzioneTMP instanceof SumSubtraction) == false && (funzioneTMP instanceof Subtraction) == false && (funzioneTMP instanceof Multiplication) == false && (funzioneTMP instanceof Division) == false && ((funzioneTMP instanceof AnteriorFunction && ((AnteriorFunction) funzioneTMP).variable == null) || (funzioneTMP instanceof FunctionTwoValues && ((FunctionTwoValues) funzioneTMP).variable1 == null && ((FunctionTwoValues) funzioneTMP).variable2 == null) || (!(funzioneTMP instanceof AnteriorFunction) && !(funzioneTMP instanceof FunctionTwoValues))))) { change = true; if (i + 1 < oldFunctionsList.size() && i - 1 >= 0) { @@ -526,13 +474,13 @@ public class Expression extends FunctionMultipleValues { Utils.debug.println(debugSpaces + " •Set variable to expression:" + funzioneTMP.getSymbol()); try { Utils.debug.println(debugSpaces + " " + "var1=" + ((FunctionTwoValues) funzioneTMP).getVariable1().toString()); - } catch (NullPointerException ex2) {} + } catch (final NullPointerException ex2) {} try { Utils.debug.println(debugSpaces + " " + "var2=" + ((FunctionTwoValues) funzioneTMP).getVariable2().toString()); - } catch (NullPointerException ex2) {} + } catch (final NullPointerException ex2) {} try { Utils.debug.println(debugSpaces + " " + "(result)=" + ((FunctionTwoValues) funzioneTMP).toString()); - } catch (NullPointerException ex2) {} + } catch (final NullPointerException ex2) {} } else { throw new Error(Errors.SYNTAX_ERROR); @@ -542,9 +490,9 @@ public class Expression extends FunctionMultipleValues { } else if (funzioneTMP instanceof AnteriorFunction) { if ((step == "SN Functions" && ((AnteriorFunction) funzioneTMP).variable == null)) { if (i + 1 < oldFunctionsList.size()) { - Function nextFunc = oldFunctionsList.get(i + 1); - if (nextFunc instanceof AnteriorFunction && ((AnteriorFunction)nextFunc).variable == null) { - + final Function nextFunc = oldFunctionsList.get(i + 1); + if (nextFunc instanceof AnteriorFunction && ((AnteriorFunction) nextFunc).variable == null) { + } else { change = true; ((AnteriorFunction) funzioneTMP).setVariable(nextFunc); @@ -556,7 +504,7 @@ public class Expression extends FunctionMultipleValues { oldFunctionsList.remove(i + 1); Utils.debug.println(debugSpaces + " •Set variable to expression:" + funzioneTMP.getSymbol()); - Function var = ((AnteriorFunction) funzioneTMP).getVariable(); + final Function var = ((AnteriorFunction) funzioneTMP).getVariable(); if (var == null) { Utils.debug.println(debugSpaces + " " + "var=null"); } else { @@ -580,8 +528,8 @@ public class Expression extends FunctionMultipleValues { } } while (((oldFunctionsList.size() != before || step != "sums") && oldFunctionsList.size() > 1)); } - if(oldFunctionsList.isEmpty()) { - setVariables(new Function[]{new Number(root, 0)}); + if (oldFunctionsList.isEmpty()) { + setVariables(new Function[] { new Number(root, 0) }); } else { setVariables(oldFunctionsList); } @@ -593,7 +541,7 @@ public class Expression extends FunctionMultipleValues { } Utils.debug.println(debugSpaces + "•Finished correcting classes."); - String result = toString(); + final String result = toString(); Utils.debug.println(debugSpaces + "•Result:" + result); } } @@ -608,7 +556,7 @@ public class Expression extends FunctionMultipleValues { if (functions.length > 1) { return true; } else if (functions.length == 1) { - Function f = functions[0]; + final Function f = functions[0]; if (f.isSolved() == false) { return true; } else { @@ -617,31 +565,31 @@ public class Expression extends FunctionMultipleValues { } return false; } - + @Override public List solveOneStep() throws Error { - List ret = new ArrayList<>(); + final List ret = new ArrayList<>(); if (functions.length == 1) { if (functions[0].isSolved() || !parenthesisNeeded()) { ret.add(functions[0]); return ret; } else { - List l = functions[0].solveOneStep(); - for (Function f : l) { + final List l = functions[0].solveOneStep(); + for (final Function f : l) { if (f instanceof Number || f instanceof Variable) { ret.add(f); } else { - ret.add(new Expression(root, new Function[]{f})); + ret.add(new Expression(root, new Function[] { f })); } } return ret; } } else { - for (Function f : functions) { + for (final Function f : functions) { if (f.isSolved() == false) { - List partial = f.solveOneStep(); - for (Function fnc : partial) { - ret.add(new Expression(root, new Function[]{fnc})); + final List partial = f.solveOneStep(); + for (final Function fnc : partial) { + ret.add(new Expression(root, new Function[] { fnc })); } } } @@ -651,34 +599,32 @@ public class Expression extends FunctionMultipleValues { @Override public void generateGraphics() { - for (Function var : functions) { + for (final Function var : functions) { var.setSmall(small); var.generateGraphics(); } - + width = calcWidth(); height = calcHeight(); line = calcLine(); } - + public boolean parenthesisNeeded() { boolean parenthesisneeded = true; if (initialParenthesis) { parenthesisneeded = false; } else { if (functions.length == 1) { - Function f = functions[0]; - if (f instanceof Number || f instanceof Variable || f instanceof Expression || f instanceof Division || f instanceof Joke - || f instanceof Undefined || f instanceof Power || f instanceof Sine || f instanceof Cosine || f instanceof Tangent - || f instanceof ArcSine || f instanceof ArcCosine || f instanceof ArcTangent) { + final Function f = functions[0]; + if (f instanceof Number || f instanceof Variable || f instanceof Expression || f instanceof Division || f instanceof Joke || f instanceof Undefined || f instanceof Power || f instanceof Sine || f instanceof Cosine || f instanceof Tangent || f instanceof ArcSine || f instanceof ArcCosine || f instanceof ArcTangent) { parenthesisneeded = false; } if (f instanceof Multiplication) { - if (((Multiplication)f).getVariable1() instanceof Number) { - parenthesisneeded = !(((Multiplication)f).getVariable2() instanceof Variable); - } else if (((Multiplication)f).getVariable2() instanceof Number) { - parenthesisneeded = !(((Multiplication)f).getVariable1() instanceof Variable); - } else if (((Multiplication) f).getVariable1() instanceof Variable || ((Multiplication)f).getVariable2() instanceof Variable) { + if (((Multiplication) f).getVariable1() instanceof Number) { + parenthesisneeded = !(((Multiplication) f).getVariable2() instanceof Variable); + } else if (((Multiplication) f).getVariable2() instanceof Number) { + parenthesisneeded = !(((Multiplication) f).getVariable1() instanceof Variable); + } else if (((Multiplication) f).getVariable1() instanceof Variable || ((Multiplication) f).getVariable2() instanceof Variable) { parenthesisneeded = false; } } @@ -686,30 +632,30 @@ public class Expression extends FunctionMultipleValues { } return parenthesisneeded; } - + @Override public void draw(int x, int y) { if (parenthesisNeeded() == false) { - this.functions[0].draw(x, y); + functions[0].draw(x, y); } else { - float miny = y; - float maxy = y + getHeight(); - int h = getHeight(); + final float miny = y; + final float maxy = y + getHeight(); + final int h = getHeight(); x += 1; - PIDisplay.renderer.glDrawLine(x, y + 2, x + 2, y); - PIDisplay.renderer.glDrawLine(x, y + 2, x, y + h - 3); - PIDisplay.renderer.glDrawLine(x, y + h - 3, x + 2, y + h - 1); + DisplayManager.renderer.glDrawLine(x, y + 2, x + 2, y); + DisplayManager.renderer.glDrawLine(x, y + 2, x, y + h - 3); + DisplayManager.renderer.glDrawLine(x, y + h - 3, x + 2, y + h - 1); x += 4; - for (Function f : functions) { - float fheight = f.getHeight(); - float y2 = miny + ((maxy - miny) / 2 - fheight / 2); + for (final Function f : functions) { + final float fheight = f.getHeight(); + final float y2 = miny + ((maxy - miny) / 2 - fheight / 2); f.draw(x, (int) y2); x += f.getWidth(); } x += 2; - PIDisplay.renderer.glDrawLine(x, y, x + 2, y + 2); - PIDisplay.renderer.glDrawLine(x + 2, y + 2, x + 2, y + h - 3); - PIDisplay.renderer.glDrawLine(x, y + h - 1, x + 2, y + h - 3); + DisplayManager.renderer.glDrawLine(x, y, x + 2, y + 2); + DisplayManager.renderer.glDrawLine(x + 2, y + 2, x + 2, y + h - 3); + DisplayManager.renderer.glDrawLine(x, y + h - 1, x + 2, y + h - 3); x += 4; } } @@ -721,28 +667,28 @@ public class Expression extends FunctionMultipleValues { private int calcWidth() { if (parenthesisNeeded() == false) { - return this.functions[0].getWidth(); + return functions[0].getWidth(); } else { int w = 0; - for (Function f : functions) { + for (final Function f : functions) { w += f.getWidth(); } return 1 + 4 + w + 2 + 4; } } - + @Override public int getHeight() { return height; } - + private int calcHeight() { if (initialParenthesis || functions.length == 1) { - return this.functions[0].getHeight(); + return functions[0].getHeight(); } else { Function tmin = null; Function tmax = null; - for (Function t : functions) { + for (final Function t : functions) { if (tmin == null || t.getLine() >= tmin.getLine()) { tmin = t; } @@ -750,8 +696,9 @@ public class Expression extends FunctionMultipleValues { tmax = t; } } - if (tmin == null) + if (tmin == null) { return Utils.getFontHeight(small); + } return tmin.getLine() + tmax.getHeight() - tmax.getLine(); } } @@ -760,23 +707,24 @@ public class Expression extends FunctionMultipleValues { public int getLine() { return line; } - + private int calcLine() { if (initialParenthesis || functions.length == 1) { - return this.functions[0].getLine(); + return functions[0].getLine(); } else { Function tl = null; - for (Function t : functions) { + for (final Function t : functions) { if (tl == null || t.getLine() >= tl.getLine()) { tl = t; } } - if (tl == null) + if (tl == null) { return Utils.getFontHeight(small) / 2; + } return tl.getLine(); } } - + @Override public String toString() { String vars = "null"; @@ -786,7 +734,7 @@ public class Expression extends FunctionMultipleValues { vars = functions[0].toString(); } } else { - for (Function variable : functions) { + for (final Function variable : functions) { if (variable != null) { vars += ", " + variable.toString(); } @@ -794,15 +742,15 @@ public class Expression extends FunctionMultipleValues { vars = vars.substring(2); } } - return "("+vars+")"; + return "(" + vars + ")"; } - + @Override public boolean equals(Object o) { if (o instanceof Expression) { - Expression f = (Expression) o; - Function[] exprFuncs1 = functions; - Function[] exprFuncs2 = f.functions; + final Expression f = (Expression) o; + final Function[] exprFuncs1 = functions; + final Function[] exprFuncs2 = f.functions; if (exprFuncs1.length == exprFuncs2.length) { for (int i = 0; i < exprFuncs1.length; i++) { if (exprFuncs1[i].equals(exprFuncs2[i]) == false) { @@ -812,7 +760,7 @@ public class Expression extends FunctionMultipleValues { return true; } } else if (o != null & getVariablesLength() == 1) { - Function f = (Function) o; + final Function f = (Function) o; return (functions[0].equals(f)); } else if (o == null & getVariablesLength() == 0) { return true; diff --git a/src/org/warp/picalculator/math/functions/Function.java b/src/org/warp/picalculator/math/functions/Function.java index eddf83df..80542913 100644 --- a/src/org/warp/picalculator/math/functions/Function.java +++ b/src/org/warp/picalculator/math/functions/Function.java @@ -21,14 +21,14 @@ public interface Function { public int getHeight(); public int getLine(); - + public Calculator getRoot(); - + public void setSmall(boolean small); - + @Override public int hashCode(); - + @Override public boolean equals(Object o); } diff --git a/src/org/warp/picalculator/math/functions/FunctionMultipleValues.java b/src/org/warp/picalculator/math/functions/FunctionMultipleValues.java index 60dcbe5f..d61ab0e9 100644 --- a/src/org/warp/picalculator/math/functions/FunctionMultipleValues.java +++ b/src/org/warp/picalculator/math/functions/FunctionMultipleValues.java @@ -15,7 +15,7 @@ public abstract class FunctionMultipleValues implements Function { public FunctionMultipleValues(Function[] values) { if (values.length > 0) { - this.root = values[0].getRoot(); + root = values[0].getRoot(); } else { throw new NullPointerException("Nessun elemento nell'array. Impossibile ricavare il nodo root"); } @@ -39,8 +39,8 @@ public abstract class FunctionMultipleValues implements Function { } public void setVariables(final List value) { - int vsize = value.size(); - Function[] tmp = new Function[vsize]; + final int vsize = value.size(); + final Function[] tmp = new Function[vsize]; for (int i = 0; i < vsize; i++) { tmp[i] = value.get(i); } @@ -60,7 +60,7 @@ public abstract class FunctionMultipleValues implements Function { } public void addFunctionToEnd(Function value) { - int index = functions.length; + final int index = functions.length; setVariablesLength(index + 1); functions[index] = value; } @@ -75,32 +75,32 @@ public abstract class FunctionMultipleValues implements Function { @Override public abstract String getSymbol(); - + @Override public boolean isSolved() { - for (Function variable : functions) { + for (final Function variable : functions) { if (!variable.isSolved()) { return false; } } return !isSolvable(); } - + protected abstract boolean isSolvable(); @Override public Calculator getRoot() { return root; } - + @Override public abstract void generateGraphics(); - + @Override public String toString() { // try { // return solve().toString(); - return "TODO: fare una nuova alternativa a solve().toString()"; + return "TODO: fare una nuova alternativa a solve().toString()"; // } catch (Error e) { // return e.id.toString(); // } @@ -108,20 +108,20 @@ public abstract class FunctionMultipleValues implements Function { @Override public Function clone() { - Cloner cloner = new Cloner(); + final Cloner cloner = new Cloner(); return cloner.deepClone(this); } - + @Override public void setSmall(boolean small) { this.small = small; } - + @Override public int hashCode() { - return functions.hashCode()+883*getSymbol().hashCode(); + return functions.hashCode() + 883 * getSymbol().hashCode(); } - + @Override public boolean equals(Object o) { return false; diff --git a/src/org/warp/picalculator/math/functions/FunctionTwoValues.java b/src/org/warp/picalculator/math/functions/FunctionTwoValues.java index 944e61ac..7d9aaeca 100644 --- a/src/org/warp/picalculator/math/functions/FunctionTwoValues.java +++ b/src/org/warp/picalculator/math/functions/FunctionTwoValues.java @@ -4,7 +4,7 @@ import java.util.ArrayList; import org.warp.picalculator.Error; import org.warp.picalculator.Utils; -import org.warp.picalculator.gui.PIDisplay; +import org.warp.picalculator.gui.DisplayManager; import org.warp.picalculator.gui.graphicengine.cpu.CPUDisplay; import org.warp.picalculator.math.Calculator; @@ -16,11 +16,11 @@ public abstract class FunctionTwoValues implements Function { variable1 = value1; variable2 = value2; } - + protected abstract Function NewInstance(Calculator root, Function value1, Function value2); protected final Calculator root; - + protected Function variable1 = null; protected Function variable2 = null; protected int width; @@ -40,7 +40,7 @@ public abstract class FunctionTwoValues implements Function { public Calculator getRoot() { return root; } - + public Function getVariable2() { return variable2; } @@ -51,24 +51,24 @@ public abstract class FunctionTwoValues implements Function { @Override public abstract String getSymbol(); - + @Override public boolean isSolved() { return (variable1.isSolved() & variable2.isSolved()) ? !isSolvable() : false; } - + protected abstract boolean isSolvable(); - + @Override public final ArrayList solveOneStep() throws Error { final boolean solved = variable1.isSolved() & variable2.isSolved(); - ArrayList result = solved?solve():null;; - + ArrayList result = solved ? solve() : null;; + if (result == null || result.isEmpty()) { result = new ArrayList<>(); - - ArrayList l1 = new ArrayList<>(); - ArrayList l2 = new ArrayList<>(); + + final ArrayList l1 = new ArrayList<>(); + final ArrayList l2 = new ArrayList<>(); if (variable1.isSolved()) { l1.add(variable1); } else { @@ -79,27 +79,27 @@ public abstract class FunctionTwoValues implements Function { } else { l2.addAll(variable2.solveOneStep()); } - - Function[][] results = Utils.joinFunctionsResults(l1, l2); - - for (Function[] f : results) { - result.add(NewInstance(this.root, f[0], f[1])); + + final Function[][] results = Utils.joinFunctionsResults(l1, l2); + + for (final Function[] f : results) { + result.add(NewInstance(root, f[0], f[1])); } } - + return result; } - + protected abstract ArrayList solve() throws Error; - + @Override public void generateGraphics() { variable1.setSmall(small); variable1.generateGraphics(); - + variable2.setSmall(small); variable2.generateGraphics(); - + width = calcWidth(); height = calcHeight(); line = calcLine(); @@ -107,14 +107,14 @@ public abstract class FunctionTwoValues implements Function { @Override public void draw(int x, int y) { - int ln = getLine(); + final int ln = getLine(); int dx = 0; variable1.draw(dx + x, ln - variable1.getLine() + y); - dx += 1+variable1.getWidth(); + dx += 1 + variable1.getWidth(); if (drawSignum()) { - PIDisplay.renderer.glSetFont(Utils.getFont(small)); - PIDisplay.renderer.glDrawStringLeft(dx + x, ln - Utils.getFontHeight(small) / 2 + y, getSymbol()); - dx += PIDisplay.renderer.glGetStringWidth(Utils.getFont(small), getSymbol()); + Utils.getFont(small).use(DisplayManager.display); + DisplayManager.renderer.glDrawStringLeft(dx + x, ln - Utils.getFontHeight(small) / 2 + y, getSymbol()); + dx += Utils.getFont(small).getStringWidth(getSymbol()); } variable2.draw(dx + x, ln - variable2.getLine() + y); } @@ -144,28 +144,28 @@ public abstract class FunctionTwoValues implements Function { if (variable2 != null) { val2 = variable2.toString(); } - return val1+getSymbol()+val2; + return val1 + getSymbol() + val2; } @Override public FunctionTwoValues clone() { - Cloner cloner = new Cloner(); + final Cloner cloner = new Cloner(); return cloner.deepClone(this); } public boolean drawSignum() { return true; } - + @Override public void setSmall(boolean small) { this.small = small; - } + } protected int calcWidth() { - return variable1.getWidth() + 1 + (drawSignum() ? PIDisplay.renderer.glGetStringWidth(Utils.getFont(small), getSymbol()) : 0) + variable2.getWidth(); + return variable1.getWidth() + 1 + (drawSignum() ? Utils.getFont(small).getStringWidth(getSymbol()) : 0) + variable2.getWidth(); } - + protected int calcHeight() { Function tmin = variable1; @@ -178,7 +178,7 @@ public abstract class FunctionTwoValues implements Function { } return tmin.getLine() + tmax.getHeight() - tmax.getLine(); } - + protected int calcLine() { Function tl = variable1; if (tl == null || variable2.getLine() >= tl.getLine()) { @@ -186,12 +186,12 @@ public abstract class FunctionTwoValues implements Function { } return tl.getLine(); } - + @Override public int hashCode() { - return variable1.hashCode()+7*variable2.hashCode()+883*getSymbol().hashCode(); + return variable1.hashCode() + 7 * variable2.hashCode() + 883 * getSymbol().hashCode(); } - + @Override public abstract boolean equals(Object o); } diff --git a/src/org/warp/picalculator/math/functions/Joke.java b/src/org/warp/picalculator/math/functions/Joke.java index 582cc2f7..3e425ddb 100644 --- a/src/org/warp/picalculator/math/functions/Joke.java +++ b/src/org/warp/picalculator/math/functions/Joke.java @@ -4,7 +4,7 @@ import java.util.List; import org.warp.picalculator.Error; import org.warp.picalculator.Utils; -import org.warp.picalculator.gui.PIDisplay; +import org.warp.picalculator.gui.DisplayManager; import org.warp.picalculator.gui.graphicengine.RAWFont; import org.warp.picalculator.gui.graphicengine.cpu.CPUDisplay; import org.warp.picalculator.math.Calculator; @@ -14,16 +14,16 @@ public class Joke implements Function { public static final byte FISH = 0; public static final byte TORNADO = 1; public static final byte SHARKNADO = 2; - private static final String[] jokes = new String[]{"♓", "TORNADO", "SHARKNADO"}; - private static final int[] jokesFont = new int[]{4, -1, -1}; + private static final String[] jokes = new String[] { "♓", "TORNADO", "SHARKNADO" }; + private static final int[] jokesFont = new int[] { 4, -1, -1 }; private final byte joke; private final Calculator root; - + public Joke(Calculator root, byte joke) { this.root = root; this.joke = joke; } - + @Override public String getSymbol() { return "joke"; @@ -41,34 +41,34 @@ public class Joke implements Function { @Override public void generateGraphics() { - + } @Override public void draw(int x, int y) { - RAWFont rf = PIDisplay.renderer.getCurrentFont(); + final RAWFont rf = DisplayManager.renderer.getCurrentFont(); if (jokesFont[joke] >= 0) { - PIDisplay.renderer.glSetFont(PIDisplay.fonts[jokesFont[joke]]); + DisplayManager.renderer.glSetFont(DisplayManager.fonts[jokesFont[joke]]); } - PIDisplay.renderer.glDrawStringLeft(x, y, jokes[joke]); + DisplayManager.renderer.glDrawStringLeft(x, y, jokes[joke]); if (jokesFont[joke] >= 0) { - PIDisplay.renderer.glSetFont(rf); + DisplayManager.renderer.glSetFont(rf); } } @Override public int getWidth() { if (jokesFont[joke] >= 0) { - return PIDisplay.renderer.glGetStringWidth(PIDisplay.fonts[jokesFont[joke]], jokes[joke]); + return DisplayManager.renderer.glGetStringWidth(DisplayManager.fonts[jokesFont[joke]], jokes[joke]); } else { - return PIDisplay.renderer.glGetStringWidth(Utils.getFont(small), jokes[joke]); + return DisplayManager.renderer.glGetStringWidth(Utils.getFont(small), jokes[joke]); } } @Override public int getHeight() { if (jokesFont[joke] >= 0) { - return PIDisplay.fonts[jokesFont[joke]].charH; + return DisplayManager.fonts[jokesFont[joke]].charH; } else { return Utils.getFont(small).charH; } @@ -76,7 +76,7 @@ public class Joke implements Function { @Override public int getLine() { - return getHeight()/2; + return getHeight() / 2; } @Override @@ -85,7 +85,7 @@ public class Joke implements Function { } private boolean small = false; - + @Override public void setSmall(boolean small) { this.small = small; diff --git a/src/org/warp/picalculator/math/functions/Multiplication.java b/src/org/warp/picalculator/math/functions/Multiplication.java index 57fc82c1..0611e4d4 100644 --- a/src/org/warp/picalculator/math/functions/Multiplication.java +++ b/src/org/warp/picalculator/math/functions/Multiplication.java @@ -21,7 +21,7 @@ public class Multiplication extends FunctionTwoValues { variable2 = value1; } } - + @Override protected Function NewInstance(Calculator root, Function value1, Function value2) { return new Multiplication(root, value1, value2); @@ -37,12 +37,24 @@ public class Multiplication extends FunctionTwoValues { if (variable1 instanceof Number & variable2 instanceof Number) { return true; } - if (SyntaxRule1.compare(this)) return true; - if (NumberRule1.compare(this)) return true; - if (NumberRule2.compare(this)) return true; - if (NumberRule6.compare(this)) return true; - if (ExponentRule15.compare(this)) return true; - if (MultiplicationMethod1.compare(this)) return true; + if (SyntaxRule1.compare(this)) { + return true; + } + if (NumberRule1.compare(this)) { + return true; + } + if (NumberRule2.compare(this)) { + return true; + } + if (NumberRule6.compare(this)) { + return true; + } + if (ExponentRule15.compare(this)) { + return true; + } + if (MultiplicationMethod1.compare(this)) { + return true; + } return false; } @@ -62,15 +74,15 @@ public class Multiplication extends FunctionTwoValues { } else if (MultiplicationMethod1.compare(this)) { result = MultiplicationMethod1.execute(this); } else if (variable1.isSolved() & variable2.isSolved()) { - result.add(((Number)variable1).multiply((Number)variable2)); + result.add(((Number) variable1).multiply((Number) variable2)); } return result; } @Override public boolean drawSignum() { - Function[] tmpVar = new Function[] { variable1, variable2 }; - boolean[] ok = new boolean[] { false, false }; + final Function[] tmpVar = new Function[] { variable1, variable2 }; + final boolean[] ok = new boolean[] { false, false }; for (int val = 0; val < 2; val++) { while (!ok[val]) { if (tmpVar[val] instanceof Division) { @@ -132,11 +144,11 @@ public class Multiplication extends FunctionTwoValues { return true; } } - + @Override public boolean equals(Object o) { if (o instanceof Multiplication) { - FunctionTwoValues f = (FunctionTwoValues) o; + final FunctionTwoValues f = (FunctionTwoValues) o; if (variable1.equals(f.variable1) && variable2.equals(f.variable2)) { return true; } else if (variable1.equals(f.variable2) && variable2.equals(f.variable1)) { diff --git a/src/org/warp/picalculator/math/functions/Negative.java b/src/org/warp/picalculator/math/functions/Negative.java index 5e44c8cb..bbecd7a4 100644 --- a/src/org/warp/picalculator/math/functions/Negative.java +++ b/src/org/warp/picalculator/math/functions/Negative.java @@ -5,7 +5,7 @@ import java.util.ArrayList; import org.warp.picalculator.Error; import org.warp.picalculator.Errors; import org.warp.picalculator.Utils; -import org.warp.picalculator.gui.PIDisplay; +import org.warp.picalculator.gui.DisplayManager; import org.warp.picalculator.gui.graphicengine.cpu.CPUDisplay; import org.warp.picalculator.math.Calculator; import org.warp.picalculator.math.MathematicalSymbols; @@ -27,25 +27,31 @@ public class Negative extends AnteriorFunction { public String getSymbol() { return MathematicalSymbols.MINUS; } - + @Override public void generateGraphics() { variable.setSmall(small); variable.generateGraphics(); - + height = getVariable().getHeight(); - width = PIDisplay.renderer.glGetStringWidth(Utils.getFont(small), "-") + getVariable().getWidth(); + width = DisplayManager.renderer.glGetStringWidth(Utils.getFont(small), "-") + getVariable().getWidth(); line = getVariable().getLine(); } @Override protected boolean isSolvable() { - if (variable instanceof Number) return true; - if (ExpandRule1.compare(this)) return true; - if (ExpandRule5.compare(this)) return true; + if (variable instanceof Number) { + return true; + } + if (ExpandRule1.compare(this)) { + return true; + } + if (ExpandRule5.compare(this)) { + return true; + } return false; } - + @Override public ArrayList solve() throws Error { if (variable == null) { @@ -58,24 +64,24 @@ public class Negative extends AnteriorFunction { result = ExpandRule5.execute(this); } else if (variable.isSolved()) { try { - Number var = (Number) getVariable(); + final Number var = (Number) getVariable(); result.add(var.multiply(new Number(root, "-1"))); - } catch(NullPointerException ex) { + } catch (final NullPointerException ex) { throw new Error(Errors.ERROR); - } catch(NumberFormatException ex) { + } catch (final NumberFormatException ex) { throw new Error(Errors.SYNTAX_ERROR); - } catch(ArithmeticException ex) { + } catch (final ArithmeticException ex) { throw new Error(Errors.NUMBER_TOO_SMALL); } } else { - ArrayList l1 = new ArrayList<>(); + final ArrayList l1 = new ArrayList<>(); if (variable.isSolved()) { l1.add(variable); } else { l1.addAll(variable.solveOneStep()); } - - for (Function f : l1) { + + for (final Function f : l1) { result.add(new Negative(root, f)); } } @@ -96,11 +102,11 @@ public class Negative extends AnteriorFunction { public int getLine() { return line; } - + @Override public boolean equals(Object o) { if (o instanceof Negative) { - return ((Negative)o).variable.equals(variable); + return ((Negative) o).variable.equals(variable); } return false; } diff --git a/src/org/warp/picalculator/math/functions/Number.java b/src/org/warp/picalculator/math/functions/Number.java index f3a2f25b..06a4d733 100644 --- a/src/org/warp/picalculator/math/functions/Number.java +++ b/src/org/warp/picalculator/math/functions/Number.java @@ -9,9 +9,8 @@ import java.util.List; import org.nevec.rjm.BigDecimalMath; import org.warp.picalculator.Error; import org.warp.picalculator.Utils; -import org.warp.picalculator.gui.PIDisplay; +import org.warp.picalculator.gui.DisplayManager; import org.warp.picalculator.gui.graphicengine.RAWFont; -import org.warp.picalculator.gui.graphicengine.cpu.CPUDisplay; import org.warp.picalculator.math.Calculator; import com.rits.cloning.Cloner; @@ -29,7 +28,7 @@ public class Number implements Function { this.root = root; term = new BigDecimal(val).setScale(Utils.scale, Utils.scaleMode2); } - + public Number(Calculator root, BigDecimal val) { this.root = root; term = val.setScale(Utils.scale, Utils.scaleMode2); @@ -72,26 +71,26 @@ public class Number implements Function { } public Number add(Number f) { - Number ret = new Number(this.root, getTerm().add(f.getTerm())); + final Number ret = new Number(root, getTerm().add(f.getTerm())); return ret; } public Number multiply(Number f) { - Number ret = new Number(this.root, getTerm().multiply(f.getTerm())); + final Number ret = new Number(root, getTerm().multiply(f.getTerm())); return ret; } public Number divide(Number f) throws Error { - Number ret = new Number(this.root, BigDecimalMath.divideRound(getTerm(), f.getTerm())); + final Number ret = new Number(root, BigDecimalMath.divideRound(getTerm(), f.getTerm())); return ret; } - + public Number pow(Number f) throws Error { - Number ret = new Number(this.root, BigDecimal.ONE); + Number ret = new Number(root, BigDecimal.ONE); if (Utils.isIntegerValue(f.term)) { final BigInteger bi = f.term.toBigInteger(); for (BigInteger i = BigInteger.ZERO; i.compareTo(bi) < 0; i = i.add(BigInteger.ONE)) { - ret = ret.multiply(new Number(this.root, getTerm())); + ret = ret.multiply(new Number(root, getTerm())); } } else { ret.term = BigDecimalMath.pow(term, f.term); @@ -101,20 +100,20 @@ public class Number implements Function { @Override public String toString() { - String sWith0 = getTerm().setScale(Utils.displayScale, Utils.scaleMode2).toPlainString(); - String sExtendedWith0 = getTerm().toPlainString(); + final String sWith0 = getTerm().setScale(Utils.displayScale, Utils.scaleMode2).toPlainString(); + final String sExtendedWith0 = getTerm().toPlainString(); //Remove trailing zeroes. Thanks to Kent, http://stackoverflow.com/questions/14984664/remove-trailing-zero-in-java String s = sWith0.indexOf(".") < 0 ? sWith0 : sWith0.replaceAll("0*$", "").replaceAll("\\.$", ""); - String sExtended = sExtendedWith0.indexOf(".") < 0 ? sExtendedWith0 : sExtendedWith0.replaceAll("0*$", "").replaceAll("\\.$", ""); - + final String sExtended = sExtendedWith0.indexOf(".") < 0 ? sExtendedWith0 : sExtendedWith0.replaceAll("0*$", "").replaceAll("\\.$", ""); + if (sExtended.length() > s.length()) { - s = s+"…"; + s = s + "…"; } - + if (root.exactMode == false) { - String cuttedNumber = s.split("\\.")[0]; + final String cuttedNumber = s.split("\\.")[0]; if (cuttedNumber.length() > 8) { - return cuttedNumber.substring(0, 1)+","+cuttedNumber.substring(1, 8)+"ℯ℮"+(cuttedNumber.length()-1); + return cuttedNumber.substring(0, 1) + "," + cuttedNumber.substring(1, 8) + "ℯ℮" + (cuttedNumber.length() - 1); } } return s; @@ -131,7 +130,7 @@ public class Number implements Function { @Override public void draw(int x, int y) { - PIDisplay.renderer.glSetFont(Utils.getFont(small)); + Utils.getFont(small).use(DisplayManager.display); String t = toString(); if (t.startsWith("-")) { @@ -144,20 +143,20 @@ public class Number implements Function { if (t.contains("ℯ℮")) { final RAWFont defaultf = Utils.getFont(small); final RAWFont smallf = Utils.getFont(true); - String s = t.substring(0, t.indexOf("ℯ℮")+2); - int sw = PIDisplay.renderer.glGetStringWidth(defaultf, s); - PIDisplay.renderer.glDrawStringLeft(x+1, y+smallf.charH-2, s); - PIDisplay.renderer.glSetFont(smallf); - PIDisplay.renderer.glDrawStringLeft(x+1+sw-3, y, t.substring(t.indexOf("ℯ℮")+2)); + final String s = t.substring(0, t.indexOf("ℯ℮") + 2); + final int sw = defaultf.getStringWidth(s); + DisplayManager.renderer.glDrawStringLeft(x + 1, y + smallf.getCharacterHeight() - 2, s); + smallf.use(DisplayManager.display); + DisplayManager.renderer.glDrawStringLeft(x + 1 + sw - 3, y, t.substring(t.indexOf("ℯ℮") + 2)); } else { - PIDisplay.renderer.glDrawStringLeft(x+1, y, t); + DisplayManager.renderer.glDrawStringLeft(x + 1, y, t); } } public int getHeight(boolean drawMinus) { - boolean beforedrawminus = this.drawMinus; + final boolean beforedrawminus = this.drawMinus; this.drawMinus = drawMinus; - int h = getHeight(); + final int h = getHeight(); this.drawMinus = beforedrawminus; return h; } @@ -166,21 +165,22 @@ public class Number implements Function { public int getHeight() { return height; } - + private int calcHeight() { - String t = toString(); + final String t = toString(); if (t.contains("ℯ℮")) { - return Utils.getFontHeight(small)-2+Utils.getFontHeight(true); + return Utils.getFontHeight(small) - 2 + Utils.getFontHeight(true); } else { - int h1 = Utils.getFontHeight(small); + final int h1 = Utils.getFontHeight(small); return h1; } } + @Override public int getWidth() { return width; } - + public int calcWidth() { String t = toString(); if (t.startsWith("-")) { @@ -193,23 +193,23 @@ public class Number implements Function { if (t.contains("ℯ℮")) { final RAWFont defaultf = Utils.getFont(small); final RAWFont smallf = Utils.getFont(true); - String s = t.substring(0, t.indexOf("ℯ℮")+2); - int sw = PIDisplay.renderer.glGetStringWidth(defaultf, s); - return 1+sw-3+PIDisplay.renderer.glGetStringWidth(smallf, t.substring(t.indexOf("ℯ℮")+2)); + final String s = t.substring(0, t.indexOf("ℯ℮") + 2); + final int sw = defaultf.getStringWidth(s); + return 1 + sw - 3 + smallf.getStringWidth(t.substring(t.indexOf("ℯ℮") + 2)); } else { - return PIDisplay.renderer.glGetStringWidth(Utils.getFont(small), t)+1; + return Utils.getFont(small).getStringWidth(t) + 1; } } - + @Override public int getLine() { return line; } - + private int calcLine() { - String t = toString(); + final String t = toString(); if (t.contains("ℯ℮")) { - return (Utils.getFontHeight(small) / 2)-2+Utils.getFontHeight(true); + return (Utils.getFontHeight(small) / 2) - 2 + Utils.getFontHeight(true); } else { return Utils.getFontHeight(small) / 2; } @@ -217,10 +217,10 @@ public class Number implements Function { @Override public Number clone() { - Cloner cloner = new Cloner(); + final Cloner cloner = new Cloner(); return cloner.deepClone(this); } - + @Override public void setSmall(boolean small) { this.small = small; @@ -233,23 +233,23 @@ public class Number implements Function { @Override public List solveOneStep() throws Error { - List result = new ArrayList<>(); + final List result = new ArrayList<>(); result.add(this); return result; } - + @Override public int hashCode() { return toString().hashCode(); } - + @Override public boolean equals(Object o) { if (o != null & term != null) { if (o instanceof Number) { - BigDecimal nav = ((Number) o).getTerm(); - boolean na1 = term.compareTo(BigDecimal.ZERO) == 0; - boolean na2 = nav.compareTo(BigDecimal.ZERO) == 0; + final BigDecimal nav = ((Number) o).getTerm(); + final boolean na1 = term.compareTo(BigDecimal.ZERO) == 0; + final boolean na2 = nav.compareTo(BigDecimal.ZERO) == 0; if (na1 == na2) { if (na1 == true) { return true; @@ -283,49 +283,41 @@ public class Number implements Function { * return 6*toString().length()-1; * } */ - + public boolean canBeFactorized() { if (Utils.isIntegerValue(getTerm())) { return getTerm().toBigIntegerExact().compareTo(BigInteger.valueOf(1)) > 1; } return false; } - - public LinkedList getFactors() - { + + public LinkedList getFactors() { BigInteger n = getTerm().toBigIntegerExact(); - BigInteger two = BigInteger.valueOf(2); - LinkedList fs = new LinkedList<>(); + final BigInteger two = BigInteger.valueOf(2); + final LinkedList fs = new LinkedList<>(); - if (n.compareTo(two) < 0) - { - throw new IllegalArgumentException("must be greater than one"); - } + if (n.compareTo(two) < 0) { + throw new IllegalArgumentException("must be greater than one"); + } - while (n.mod(two).equals(BigInteger.ZERO)) - { - fs.add(two); - n = n.divide(two); - } + while (n.mod(two).equals(BigInteger.ZERO)) { + fs.add(two); + n = n.divide(two); + } - if (n.compareTo(BigInteger.ONE) > 0) - { - BigInteger f = BigInteger.valueOf(3); - while (f.multiply(f).compareTo(n) <= 0) - { - if (n.mod(f).equals(BigInteger.ZERO)) - { - fs.add(f); - n = n.divide(f); - } - else - { - f = f.add(two); - } - } - fs.add(n); - } + if (n.compareTo(BigInteger.ONE) > 0) { + BigInteger f = BigInteger.valueOf(3); + while (f.multiply(f).compareTo(n) <= 0) { + if (n.mod(f).equals(BigInteger.ZERO)) { + fs.add(f); + n = n.divide(f); + } else { + f = f.add(two); + } + } + fs.add(n); + } - return fs; + return fs; } } diff --git a/src/org/warp/picalculator/math/functions/Power.java b/src/org/warp/picalculator/math/functions/Power.java index 720cdb16..ddec0efa 100644 --- a/src/org/warp/picalculator/math/functions/Power.java +++ b/src/org/warp/picalculator/math/functions/Power.java @@ -14,11 +14,11 @@ import org.warp.picalculator.math.rules.FractionsRule5; import org.warp.picalculator.math.rules.UndefinedRule1; public class Power extends FunctionTwoValues { - + public Power(Calculator root, Function value1, Function value2) { super(root, value1, value2); } - + @Override protected Function NewInstance(Calculator root, Function value1, Function value2) { return new Power(root, value1, value2); @@ -34,32 +34,46 @@ public class Power extends FunctionTwoValues { if (variable1 instanceof Number & variable2 instanceof Number) { return true; } - if (UndefinedRule1.compare(this)) return true; - if (ExponentRule1.compare(this)) return true; - if (ExponentRule2.compare(this)) return true; - if (ExponentRule3.compare(this)) return true; - if (ExponentRule4.compare(this)) return true; - if (FractionsRule4.compare(this)) return true; - if (FractionsRule5.compare(this)) return true; + if (UndefinedRule1.compare(this)) { + return true; + } + if (ExponentRule1.compare(this)) { + return true; + } + if (ExponentRule2.compare(this)) { + return true; + } + if (ExponentRule3.compare(this)) { + return true; + } + if (ExponentRule4.compare(this)) { + return true; + } + if (FractionsRule4.compare(this)) { + return true; + } + if (FractionsRule5.compare(this)) { + return true; + } return false; } - + @Override public void generateGraphics() { variable1.setSmall(small); variable1.generateGraphics(); - + variable2.setSmall(true); variable2.generateGraphics(); - + height = variable1.getHeight() + variable2.getHeight() - 4; line = variable2.getHeight() - 4 + variable1.getLine(); - width = getVariable1().getWidth() + getVariable2().getWidth()+1; + width = getVariable1().getWidth() + getVariable2().getWidth() + 1; } @Override public ArrayList solve() throws Error { - ArrayList result = new ArrayList<>(); + final ArrayList result = new ArrayList<>(); if (UndefinedRule1.compare(this)) { result.addAll(UndefinedRule1.execute(this)); } else if (ExponentRule1.compare(this)) { @@ -75,17 +89,17 @@ public class Power extends FunctionTwoValues { } else if (FractionsRule5.compare(this)) { result.addAll(FractionsRule5.execute(this)); } else if (variable1 instanceof Number & variable2 instanceof Number) { - result.add(((Number)variable1).pow((Number)variable2)); + result.add(((Number) variable1).pow((Number) variable2)); } return result; } - + @Override public void draw(int x, int y) { // glColor3f(0, 127-50+new Random().nextInt(50), 0); // glFillRect(x,y,width,height); // glColor3f(0, 0, 0); - + int dx = 0; variable1.draw(dx + x, getHeight() - variable1.getHeight() + y); dx += variable1.getWidth(); @@ -106,11 +120,11 @@ public class Power extends FunctionTwoValues { public int getWidth() { return width; } - + @Override public boolean equals(Object o) { if (o instanceof Power) { - FunctionTwoValues f = (FunctionTwoValues) o; + final FunctionTwoValues f = (FunctionTwoValues) o; return variable1.equals(f.variable1) && variable2.equals(f.variable2); } return false; diff --git a/src/org/warp/picalculator/math/functions/Root.java b/src/org/warp/picalculator/math/functions/Root.java index 1a65cd47..7f97cf45 100644 --- a/src/org/warp/picalculator/math/functions/Root.java +++ b/src/org/warp/picalculator/math/functions/Root.java @@ -5,7 +5,7 @@ import java.math.BigInteger; import java.util.ArrayList; import org.warp.picalculator.Error; -import org.warp.picalculator.gui.PIDisplay; +import org.warp.picalculator.gui.DisplayManager; import org.warp.picalculator.math.Calculator; import org.warp.picalculator.math.MathematicalSymbols; @@ -14,12 +14,12 @@ public class Root extends FunctionTwoValues { public Root(Calculator root, Function value1, Function value2) { super(root, value1, value2); } - + @Override protected Function NewInstance(Calculator root, Function value1, Function value2) { return new Root(root, value1, value2); } - + @Override public String getSymbol() { return MathematicalSymbols.NTH_ROOT; @@ -29,10 +29,10 @@ public class Root extends FunctionTwoValues { public void generateGraphics() { variable1.setSmall(true); variable1.generateGraphics(); - + variable2.setSmall(small); variable2.generateGraphics(); - + width = 1 + variable1.getWidth() + 2 + variable2.getWidth() + 2; height = variable1.getHeight() + variable2.getHeight() - 2; line = variable1.getHeight() + variable2.getLine() - 2; @@ -47,36 +47,36 @@ public class Root extends FunctionTwoValues { try { Number exponent = new Number(root, BigDecimal.ONE); exponent = exponent.divide((Number) variable1); - Number resultVal = ((Number)variable2).pow(exponent); - Number originalVariable = resultVal.pow(new Number(root, 2)); + final Number resultVal = ((Number) variable2).pow(exponent); + final Number originalVariable = resultVal.pow(new Number(root, 2)); if (originalVariable.equals(variable2)) { return true; - } + } } catch (Exception | Error ex) { ex.printStackTrace(); } } - if (variable1 instanceof Number && ((Number)variable1).equals(new Number(root, 2))) { + if (variable1 instanceof Number && ((Number) variable1).equals(new Number(root, 2))) { return true; } return false; } - + @Override public ArrayList solve() throws Error { - ArrayList result = new ArrayList<>(); + final ArrayList result = new ArrayList<>(); if (root.exactMode) { - if (variable1 instanceof Number && ((Number)variable1).equals(new Number(root, 2))) { + if (variable1 instanceof Number && ((Number) variable1).equals(new Number(root, 2))) { result.add(new RootSquare(root, variable2)); } else { Number exponent = new Number(root, BigInteger.ONE); exponent = exponent.divide((Number) variable1); - result.add(((Number)variable2).pow(exponent)); + result.add(((Number) variable2).pow(exponent)); } } else { - Number exp = (Number) variable1; - Number numb = (Number) variable2; - + final Number exp = (Number) variable1; + final Number numb = (Number) variable2; + result.add(numb.pow(new Number(root, 1).divide(exp))); } return result; @@ -87,21 +87,21 @@ public class Root extends FunctionTwoValues { // glColor3f(0, 255, 0); // glFillRect(x,y,width,height); // glColor3f(0, 0, 0); - - int w1 = getVariable2().getWidth(); - int h1 = getVariable2().getHeight(); - int w2 = getVariable1().getWidth(); - int h2 = getVariable1().getHeight(); - int height = getHeight(); - int hh = (int) Math.ceil((double) h1 / 2); + + final int w1 = getVariable2().getWidth(); + final int h1 = getVariable2().getHeight(); + final int w2 = getVariable1().getWidth(); + final int h2 = getVariable1().getHeight(); + final int height = getHeight(); + final int hh = (int) Math.ceil((double) h1 / 2); getVariable1().draw(x + 1, y); getVariable2().draw(x + 1 + w2 + 2, y + h2 - 2); - PIDisplay.renderer.glDrawLine(x + 1 + w2 - 2, y + height - 3, x + 1 + w2, y + height); - PIDisplay.renderer.glDrawLine(x + 1 + w2, y + height - 1 - hh, x + 1 + w2, y + height - 1); - PIDisplay.renderer.glDrawLine(x + 1 + w2 + 1, y + height - 2 - h1, x + 1 + w2 + 1, y + height - 1 - hh - 1); - PIDisplay.renderer.glDrawLine(x + 1 + w2 + 1, y + height - h1 - 2, x + 1 + w2 + 2 + w1 + 1, y + height - h1 - 2); + DisplayManager.renderer.glDrawLine(x + 1 + w2 - 2, y + height - 3, x + 1 + w2, y + height); + DisplayManager.renderer.glDrawLine(x + 1 + w2, y + height - 1 - hh, x + 1 + w2, y + height - 1); + DisplayManager.renderer.glDrawLine(x + 1 + w2 + 1, y + height - 2 - h1, x + 1 + w2 + 1, y + height - 1 - hh - 1); + DisplayManager.renderer.glDrawLine(x + 1 + w2 + 1, y + height - h1 - 2, x + 1 + w2 + 2 + w1 + 1, y + height - h1 - 2); } @Override @@ -118,11 +118,11 @@ public class Root extends FunctionTwoValues { public int getLine() { return line; } - + @Override public boolean equals(Object o) { if (o instanceof Root) { - FunctionTwoValues f = (FunctionTwoValues) o; + final FunctionTwoValues f = (FunctionTwoValues) o; return variable1.equals(f.variable1) && variable2.equals(f.variable2); } return false; diff --git a/src/org/warp/picalculator/math/functions/RootSquare.java b/src/org/warp/picalculator/math/functions/RootSquare.java index 7fe74908..5df55fc0 100644 --- a/src/org/warp/picalculator/math/functions/RootSquare.java +++ b/src/org/warp/picalculator/math/functions/RootSquare.java @@ -18,17 +18,17 @@ public class RootSquare extends AnteriorFunction { public Function NewInstance(Calculator root, Function value) { return new RootSquare(root, value); } - + @Override public String getSymbol() { return MathematicalSymbols.SQUARE_ROOT; } - + @Override public void generateGraphics() { variable.setSmall(small); variable.generateGraphics(); - + height = getVariable().getHeight() + 2; width = 1 + 4 + getVariable().getWidth() + 1; line = getVariable().getLine() + 2; @@ -43,29 +43,29 @@ public class RootSquare extends AnteriorFunction { try { Number exponent = new Number(root, BigInteger.ONE); exponent = exponent.divide(new Number(root, 2)); - Number resultVal = ((Number)variable).pow(exponent); - Number originalVariable = resultVal.pow(new Number(root, 2)); + final Number resultVal = ((Number) variable).pow(exponent); + final Number originalVariable = resultVal.pow(new Number(root, 2)); if (originalVariable.equals(variable)) { return true; } } catch (Exception | Error ex) { - + } } return false; } - + @Override public ArrayList solve() throws Error { - ArrayList result = new ArrayList<>(); + final ArrayList result = new ArrayList<>(); if (root.exactMode) { Number exponent = new Number(root, BigInteger.ONE); exponent = exponent.divide(new Number(root, 2)); - result.add(((Number)variable).pow(exponent)); + result.add(((Number) variable).pow(exponent)); } else { - Number exp = new Number(root, 2); - Number numb = (Number) variable; - + final Number exp = new Number(root, 2); + final Number numb = (Number) variable; + result.add(numb.pow(new Number(root, 1).divide(exp))); } return result; @@ -76,7 +76,7 @@ public class RootSquare extends AnteriorFunction { // glColor3f(0, 255, 0); // glFillRect(x,y,width,height); // glColor3f(0, 0, 0); - + Utils.writeSquareRoot(getVariable(), x, y, small); } @@ -94,7 +94,7 @@ public class RootSquare extends AnteriorFunction { public int getLine() { return line; } - + @Override public boolean equals(Object o) { if (o instanceof RootSquare) { diff --git a/src/org/warp/picalculator/math/functions/Subtraction.java b/src/org/warp/picalculator/math/functions/Subtraction.java index 99ce1393..490e4ce4 100644 --- a/src/org/warp/picalculator/math/functions/Subtraction.java +++ b/src/org/warp/picalculator/math/functions/Subtraction.java @@ -19,12 +19,12 @@ public class Subtraction extends FunctionTwoValues { public Subtraction(Calculator root, Function value1, Function value2) { super(root, value1, value2); } - + @Override protected Function NewInstance(Calculator root, Function value1, Function value2) { return new Subtraction(root, value1, value2); } - + @Override public String getSymbol() { return MathematicalSymbols.SUBTRACTION; @@ -35,17 +35,33 @@ public class Subtraction extends FunctionTwoValues { if (variable1 instanceof Number & variable2 instanceof Number) { return true; } - if (VariableRule1.compare(this)) return true; - if (VariableRule2.compare(this)) return true; - if (VariableRule3.compare(this)) return true; - if (NumberRule3.compare(this)) return true; - if (ExpandRule1.compare(this)) return true; - if (ExpandRule5.compare(this)) return true; - if (NumberRule5.compare(this)) return true; - if (SumMethod1.compare(this)) return true; + if (VariableRule1.compare(this)) { + return true; + } + if (VariableRule2.compare(this)) { + return true; + } + if (VariableRule3.compare(this)) { + return true; + } + if (NumberRule3.compare(this)) { + return true; + } + if (ExpandRule1.compare(this)) { + return true; + } + if (ExpandRule5.compare(this)) { + return true; + } + if (NumberRule5.compare(this)) { + return true; + } + if (SumMethod1.compare(this)) { + return true; + } return false; } - + @Override public ArrayList solve() throws Error { ArrayList result = new ArrayList<>(); @@ -66,15 +82,15 @@ public class Subtraction extends FunctionTwoValues { } else if (SumMethod1.compare(this)) { result = SumMethod1.execute(this); } else if (variable1.isSolved() & variable2.isSolved()) { - result.add(((Number)variable1).add(((Number)variable2).multiply(new Number(root, "-1")))); + result.add(((Number) variable1).add(((Number) variable2).multiply(new Number(root, "-1")))); } return result; } - + @Override public boolean equals(Object o) { if (o instanceof Subtraction) { - FunctionTwoValues f = (FunctionTwoValues) o; + final FunctionTwoValues f = (FunctionTwoValues) o; return variable1.equals(f.variable1) && variable2.equals(f.variable2); } return false; diff --git a/src/org/warp/picalculator/math/functions/Sum.java b/src/org/warp/picalculator/math/functions/Sum.java index d28f1e78..8887f333 100644 --- a/src/org/warp/picalculator/math/functions/Sum.java +++ b/src/org/warp/picalculator/math/functions/Sum.java @@ -6,7 +6,7 @@ import java.util.ArrayList; import org.warp.picalculator.Error; import org.warp.picalculator.Errors; import org.warp.picalculator.Utils; -import org.warp.picalculator.gui.PIDisplay; +import org.warp.picalculator.gui.DisplayManager; import org.warp.picalculator.math.Calculator; import org.warp.picalculator.math.MathematicalSymbols; import org.warp.picalculator.math.rules.NumberRule3; @@ -28,25 +28,41 @@ public class Sum extends FunctionTwoValues { protected Function NewInstance(Calculator root, Function value1, Function value2) { return new Sum(root, value1, value2); } - + @Override public String getSymbol() { return MathematicalSymbols.SUM; } - + @Override protected boolean isSolvable() { if (variable1 instanceof Number & variable2 instanceof Number) { return true; } - if (SyntaxRule2.compare(this)) return true; - if (VariableRule1.compare(this)) return true; - if (VariableRule2.compare(this)) return true; - if (VariableRule3.compare(this)) return true; - if (NumberRule3.compare(this)) return true; - if (NumberRule5.compare(this)) return true; - if (NumberRule7.compare(this)) return true; - if (SumMethod1.compare(this)) return true; + if (SyntaxRule2.compare(this)) { + return true; + } + if (VariableRule1.compare(this)) { + return true; + } + if (VariableRule2.compare(this)) { + return true; + } + if (VariableRule3.compare(this)) { + return true; + } + if (NumberRule3.compare(this)) { + return true; + } + if (NumberRule5.compare(this)) { + return true; + } + if (NumberRule7.compare(this)) { + return true; + } + if (SumMethod1.compare(this)) { + return true; + } return false; } @@ -74,18 +90,18 @@ public class Sum extends FunctionTwoValues { result = SumMethod1.execute(this); } else if (variable1.isSolved() & variable2.isSolved()) { if ((root.getChild().equals(this))) { - if (((Number)variable1).term.compareTo(new BigDecimal(2)) == 0 && ((Number)variable2).term.compareTo(new BigDecimal(2)) == 0) { + if (((Number) variable1).term.compareTo(new BigDecimal(2)) == 0 && ((Number) variable2).term.compareTo(new BigDecimal(2)) == 0) { result.add(new Joke(root, Joke.FISH)); return result; - } else if (((Number)variable1).term.compareTo(new BigDecimal(20)) == 0 && ((Number)variable2).term.compareTo(new BigDecimal(20)) == 0) { + } else if (((Number) variable1).term.compareTo(new BigDecimal(20)) == 0 && ((Number) variable2).term.compareTo(new BigDecimal(20)) == 0) { result.add(new Joke(root, Joke.TORNADO)); return result; - } else if (((Number)variable1).term.compareTo(new BigDecimal(29)) == 0 && ((Number)variable2).term.compareTo(new BigDecimal(29)) == 0) { + } else if (((Number) variable1).term.compareTo(new BigDecimal(29)) == 0 && ((Number) variable2).term.compareTo(new BigDecimal(29)) == 0) { result.add(new Joke(root, Joke.SHARKNADO)); return result; } } - result.add(((Number)variable1).add((Number)variable2)); + result.add(((Number) variable1).add((Number) variable2)); } return result; } @@ -94,10 +110,10 @@ public class Sum extends FunctionTwoValues { public void generateGraphics() { variable1.setSmall(small); variable1.generateGraphics(); - + variable2.setSmall(small); variable2.generateGraphics(); - + width = calcWidth(); height = calcHeight(); line = calcLine(); @@ -107,20 +123,20 @@ public class Sum extends FunctionTwoValues { public int getWidth() { return width; } - + @Override protected int calcWidth() { int dx = 0; dx += variable1.getWidth(); dx += 1; - dx += PIDisplay.renderer.glGetStringWidth(Utils.getFont(small), getSymbol()); + dx += DisplayManager.renderer.glGetStringWidth(Utils.getFont(small), getSymbol()); return dx += variable2.getWidth(); } - + @Override public boolean equals(Object o) { if (o instanceof Sum) { - FunctionTwoValues f = (FunctionTwoValues) o; + final FunctionTwoValues f = (FunctionTwoValues) o; if (variable1.equals(f.variable1) && variable2.equals(f.variable2)) { return true; } else if (variable1.equals(f.variable2) && variable2.equals(f.variable1)) { diff --git a/src/org/warp/picalculator/math/functions/SumSubtraction.java b/src/org/warp/picalculator/math/functions/SumSubtraction.java index d90f3148..cda7a25b 100644 --- a/src/org/warp/picalculator/math/functions/SumSubtraction.java +++ b/src/org/warp/picalculator/math/functions/SumSubtraction.java @@ -5,7 +5,7 @@ import java.util.ArrayList; import org.warp.picalculator.Error; import org.warp.picalculator.Errors; import org.warp.picalculator.Utils; -import org.warp.picalculator.gui.PIDisplay; +import org.warp.picalculator.gui.DisplayManager; import org.warp.picalculator.gui.graphicengine.cpu.CPUDisplay; import org.warp.picalculator.math.Calculator; import org.warp.picalculator.math.MathematicalSymbols; @@ -19,7 +19,7 @@ public class SumSubtraction extends FunctionTwoValues { public SumSubtraction(Calculator root, Function value1, Function value2) { super(root, value1, value2); } - + @Override protected Function NewInstance(Calculator root, Function value1, Function value2) { return new SumSubtraction(root, value1, value2); @@ -35,13 +35,21 @@ public class SumSubtraction extends FunctionTwoValues { if (variable1 instanceof Number & variable2 instanceof Number) { return true; } - if (NumberRule3.compare(this)) return true; - if (ExpandRule1.compare(this)) return true; - if (NumberRule4.compare(this)) return true; - if (NumberRule5.compare(this)) return true; + if (NumberRule3.compare(this)) { + return true; + } + if (ExpandRule1.compare(this)) { + return true; + } + if (NumberRule4.compare(this)) { + return true; + } + if (NumberRule5.compare(this)) { + return true; + } return false; } - + @Override public ArrayList solve() throws Error { if (variable1 == null || variable2 == null) { @@ -57,8 +65,8 @@ public class SumSubtraction extends FunctionTwoValues { } else if (NumberRule5.compare(this)) { result = NumberRule5.execute(this); } else if (variable1.isSolved() & variable2.isSolved()) { - result.add(((Number)variable1).add((Number)variable2)); - result.add(((Number)variable1).add(((Number)variable2).multiply(new Number(root, "-1")))); + result.add(((Number) variable1).add((Number) variable2)); + result.add(((Number) variable1).add(((Number) variable2).multiply(new Number(root, "-1")))); } return result; } @@ -67,29 +75,29 @@ public class SumSubtraction extends FunctionTwoValues { public void generateGraphics() { variable1.setSmall(small); variable1.generateGraphics(); - + variable2.setSmall(small); variable2.generateGraphics(); - + width = calcWidth(); height = calcHeight(); line = calcLine(); } - + @Override public void draw(int x, int y) { // glColor3f(127, 127-50+new Random().nextInt(50), 255); // glFillRect(x,y,width,height); // glColor3f(0, 0, 0); - - int ln = getLine(); + + final int ln = getLine(); int dx = 0; variable1.draw(dx + x, ln - variable1.getLine() + y); dx += variable1.getWidth(); - PIDisplay.renderer.glSetFont(Utils.getFont(small)); + DisplayManager.renderer.glSetFont(Utils.getFont(small)); dx += 1; - PIDisplay.renderer.glDrawStringLeft(dx + x, ln - Utils.getFontHeight(small) / 2 + y, getSymbol()); - dx += PIDisplay.renderer.glGetStringWidth(Utils.getFont(small), getSymbol()); + DisplayManager.renderer.glDrawStringLeft(dx + x, ln - Utils.getFontHeight(small) / 2 + y, getSymbol()); + dx += DisplayManager.renderer.glGetStringWidth(Utils.getFont(small), getSymbol()); variable2.draw(dx + x, ln - variable2.getLine() + y); } @@ -97,20 +105,20 @@ public class SumSubtraction extends FunctionTwoValues { public int getWidth() { return width; } - + @Override protected int calcWidth() { int dx = 0; dx += variable1.getWidth(); dx += 1; - dx += PIDisplay.renderer.glGetStringWidth(Utils.getFont(small), getSymbol()); + dx += DisplayManager.renderer.glGetStringWidth(Utils.getFont(small), getSymbol()); return dx += variable2.getWidth(); } - + @Override public boolean equals(Object o) { if (o instanceof SumSubtraction) { - FunctionTwoValues f = (FunctionTwoValues) o; + final FunctionTwoValues f = (FunctionTwoValues) o; return variable1.equals(f.variable1) && variable2.equals(f.variable2); } return false; diff --git a/src/org/warp/picalculator/math/functions/Undefined.java b/src/org/warp/picalculator/math/functions/Undefined.java index d73a9cd7..8b2c96d5 100644 --- a/src/org/warp/picalculator/math/functions/Undefined.java +++ b/src/org/warp/picalculator/math/functions/Undefined.java @@ -4,12 +4,12 @@ import java.util.List; import org.warp.picalculator.Error; import org.warp.picalculator.Utils; -import org.warp.picalculator.gui.PIDisplay; +import org.warp.picalculator.gui.DisplayManager; import org.warp.picalculator.gui.graphicengine.cpu.CPUDisplay; import org.warp.picalculator.math.Calculator; public class Undefined implements Function { - + protected final Calculator root; public Undefined(Calculator root) { @@ -33,18 +33,18 @@ public class Undefined implements Function { private int width, height, line; private boolean small; - + @Override public void generateGraphics() { - width = PIDisplay.renderer.glGetStringWidth(Utils.getFont(small), "UNDEFINED"); + width = DisplayManager.renderer.glGetStringWidth(Utils.getFont(small), "UNDEFINED"); height = Utils.getFontHeight(small); - line = height/2; + line = height / 2; } @Override public void draw(int x, int y) { - PIDisplay.renderer.glSetFont(Utils.getFont(small)); - PIDisplay.renderer.glDrawStringLeft(x, y, "UNDEFINED"); + DisplayManager.renderer.glSetFont(Utils.getFont(small)); + DisplayManager.renderer.glDrawStringLeft(x, y, "UNDEFINED"); } @Override @@ -71,7 +71,7 @@ public class Undefined implements Function { public void setSmall(boolean small) { this.small = small; } - + @Override public boolean equals(Object o) { if (o instanceof Undefined) { diff --git a/src/org/warp/picalculator/math/functions/Variable.java b/src/org/warp/picalculator/math/functions/Variable.java index d5b5096c..e9b83976 100644 --- a/src/org/warp/picalculator/math/functions/Variable.java +++ b/src/org/warp/picalculator/math/functions/Variable.java @@ -5,7 +5,7 @@ import java.util.List; import org.warp.picalculator.Error; import org.warp.picalculator.Utils; -import org.warp.picalculator.gui.PIDisplay; +import org.warp.picalculator.gui.DisplayManager; import org.warp.picalculator.math.Calculator; import com.rits.cloning.Cloner; @@ -18,7 +18,7 @@ public class Variable implements Function { protected int line; protected boolean small; protected final Calculator root; - + public Variable(Calculator root, char val) { this.root = root; var = val; @@ -50,7 +50,7 @@ public class Variable implements Function { @Override public String toString() { - return ""+getChar(); + return "" + getChar(); } // public void draw(int x, int y, PIDisplay g, boolean small, boolean drawMinus) { @@ -62,42 +62,42 @@ public class Variable implements Function { @Override public void draw(int x, int y) { - PIDisplay.renderer.glSetFont(Utils.getFont(small)); - PIDisplay.renderer.glDrawStringLeft(x+1, y, toString()); + Utils.getFont(small).use(DisplayManager.display); + DisplayManager.renderer.glDrawStringLeft(x + 1, y, toString()); } @Override public int getHeight() { return height; } - + private int calcHeight() { - int h1 = Utils.getFontHeight(small); + final int h1 = Utils.getFontHeight(small); return h1; } - + @Override public int getWidth() { return width; } - + public int calcWidth() { - return PIDisplay.renderer.glGetStringWidth(Utils.getFont(small), toString())+1; + return Utils.getFont(small).getStringWidth(toString()) + 1; } - + @Override public int getLine() { return line; } - + private int calcLine() { return Utils.getFontHeight(small) / 2; } - + public static class VariableValue { public final Variable v; public final Number n; - + public VariableValue(Variable v, Number n) { this.v = v; this.n = n; @@ -106,10 +106,10 @@ public class Variable implements Function { @Override public Variable clone() { - Cloner cloner = new Cloner(); + final Cloner cloner = new Cloner(); return cloner.deepClone(this); } - + @Override public void setSmall(boolean small) { this.small = small; @@ -122,16 +122,16 @@ public class Variable implements Function { @Override public List solveOneStep() throws Error { - List result = new ArrayList<>(); + final List result = new ArrayList<>(); result.add(this); return result; } - + @Override public int hashCode() { return toString().hashCode(); } - + @Override public boolean equals(Object o) { if (o instanceof Variable) { diff --git a/src/org/warp/picalculator/math/functions/equations/Equation.java b/src/org/warp/picalculator/math/functions/equations/Equation.java index 870a177f..df01cf6c 100644 --- a/src/org/warp/picalculator/math/functions/equations/Equation.java +++ b/src/org/warp/picalculator/math/functions/equations/Equation.java @@ -21,7 +21,7 @@ import com.rits.cloning.Cloner; public class Equation extends FunctionTwoValues { public Equation(Calculator root, Function value1, Function value2) { - super(root, value1,value2); + super(root, value1, value2); } @Override @@ -33,7 +33,7 @@ public class Equation extends FunctionTwoValues { public String getSymbol() { return MathematicalSymbols.EQUATION; } - + @Override protected boolean isSolvable() { if (variable1 instanceof Number & variable2 instanceof Number) { @@ -41,45 +41,45 @@ public class Equation extends FunctionTwoValues { } return false; } - + @Override public ArrayList solve() throws Error { if (variable1 == null || variable2 == null) { throw new Error(Errors.SYNTAX_ERROR); } - ArrayList result = new ArrayList<>(); - if (variable1.isSolved() & variable2.isSolved()) { - if (((Number)variable2).getTerm().compareTo(new BigDecimal(0)) == 0) { + final ArrayList result = new ArrayList<>(); + if (variable1.isSolved() & variable2.isSolved()) { + if (((Number) variable2).getTerm().compareTo(new BigDecimal(0)) == 0) { result.add(this); } else { - Equation e = new Equation(root, null, null); + final Equation e = new Equation(root, null, null); e.setVariable1(new Subtraction(root, variable1, variable2)); e.setVariable2(new Number(root, "0")); - result.add(e); + result.add(e); } } return result; } - + public List solve(char variableCharacter) { @SuppressWarnings("unused") - ArrayList e; + final ArrayList e; //TODO: WORK IN PROGRESS. //TODO: Finire. Fare in modo che risolva i passaggi fino a che non ce ne sono più return null; } - + //WORK IN PROGRESS public ArrayList solveStep(char charIncognita) { ArrayList result = new ArrayList<>(); - result.add(this.clone()); - for (SolveMethod t : SolveMethod.techniques) { - ArrayList newResults = new ArrayList<>(); + result.add(clone()); + for (final SolveMethod t : SolveMethod.techniques) { + final ArrayList newResults = new ArrayList<>(); final int sz = result.size(); for (int n = 0; n < sz; n++) { newResults.addAll(t.solve(result.get(n))); } - Set hs = new HashSet<>(); + final Set hs = new HashSet<>(); hs.addAll(newResults); newResults.clear(); newResults.addAll(hs); @@ -91,8 +91,14 @@ public class Equation extends FunctionTwoValues { @Override public Equation clone() { - Cloner cloner = new Cloner(); + final Cloner cloner = new Cloner(); return cloner.deepClone(this); } + @Override + public boolean equals(Object o) { + // TODO Auto-generated method stub + return false; + } + } \ No newline at end of file diff --git a/src/org/warp/picalculator/math/functions/equations/EquationsSystem.java b/src/org/warp/picalculator/math/functions/equations/EquationsSystem.java index 04ddb820..cead9005 100644 --- a/src/org/warp/picalculator/math/functions/equations/EquationsSystem.java +++ b/src/org/warp/picalculator/math/functions/equations/EquationsSystem.java @@ -4,7 +4,7 @@ import java.util.ArrayList; import java.util.List; import org.warp.picalculator.Error; -import org.warp.picalculator.gui.PIDisplay; +import org.warp.picalculator.gui.DisplayManager; import org.warp.picalculator.math.Calculator; import org.warp.picalculator.math.functions.Expression; import org.warp.picalculator.math.functions.Function; @@ -17,11 +17,11 @@ public class EquationsSystem extends FunctionMultipleValues { public EquationsSystem(Calculator root) { super(root); } - + public EquationsSystem(Calculator root, Function value) { - super(root, new Function[]{value}); + super(root, new Function[] { value }); } - + public EquationsSystem(Calculator root, Function[] value) { super(root, value); } @@ -38,31 +38,31 @@ public class EquationsSystem extends FunctionMultipleValues { } return false; } - + @Override public List solveOneStep() throws Error { - List ret = new ArrayList<>(); + final List ret = new ArrayList<>(); if (functions.length == 1) { if (functions[0].isSolved()) { ret.add(functions[0]); return ret; } else { - List l = functions[0].solveOneStep(); - for (Function f : l) { + final List l = functions[0].solveOneStep(); + for (final Function f : l) { if (f instanceof Number) { ret.add(f); } else { - ret.add(new Expression(this.root, new Function[]{f})); + ret.add(new Expression(root, new Function[] { f })); } } return ret; } } else { - for (Function f : functions) { + for (final Function f : functions) { if (f.isSolved() == false) { - List partial = f.solveOneStep(); - for (Function fnc : partial) { - ret.add(new Expression(this.root, new Function[]{fnc})); + final List partial = f.solveOneStep(); + for (final Function fnc : partial) { + ret.add(new Expression(root, new Function[] { fnc })); } } } @@ -72,49 +72,48 @@ public class EquationsSystem extends FunctionMultipleValues { @Override public void generateGraphics() { - for (Function f : functions) { + for (final Function f : functions) { f.setSmall(false); f.generateGraphics(); } - + width = 0; - for (Function f : functions) { + for (final Function f : functions) { if (f.getWidth() > width) { width = f.getWidth(); } } width += 5; - + height = 3; - for (Function f : functions) { - height += f.getHeight()+spacing; + for (final Function f : functions) { + height += f.getHeight() + spacing; } height = height - spacing + 2; - - line = height/2; + + line = height / 2; } - + @Override public void draw(int x, int y) { - final int h = this.getHeight() - 1; + final int h = getHeight() - 1; final int marginTop = 3; final int marginBottom = (h - 3 - 2) / 2 + marginTop; final int spazioSopra = h - marginBottom; int dy = marginTop; - for (Function f : functions) { + for (final Function f : functions) { f.draw(x + 5, y + dy); - dy+=f.getHeight()+spacing; + dy += f.getHeight() + spacing; } - - - PIDisplay.renderer.glDrawLine(x + 2, y + 0, x + 3, y + 0); - PIDisplay.renderer.glDrawLine(x + 1, y + 1, x + 1, y + marginBottom / 2); - PIDisplay.renderer.glDrawLine(x + 2, y + marginBottom / 2 + 1, x + 2, y + marginBottom - 1); - PIDisplay.renderer.glDrawLine(x + 0, y + marginBottom, x + 1, y + marginBottom); - PIDisplay.renderer.glDrawLine(x + 2, y + marginBottom + 1, x + 2, y + marginBottom + spazioSopra / 2 - 1); - PIDisplay.renderer.glDrawLine(x + 1, y + marginBottom + spazioSopra / 2, x + 1, y + h - 1); - PIDisplay.renderer.glDrawLine(x + 2, y + h, x + 3, y + h); + + DisplayManager.renderer.glDrawLine(x + 2, y + 0, x + 3, y + 0); + DisplayManager.renderer.glDrawLine(x + 1, y + 1, x + 1, y + marginBottom / 2); + DisplayManager.renderer.glDrawLine(x + 2, y + marginBottom / 2 + 1, x + 2, y + marginBottom - 1); + DisplayManager.renderer.glDrawLine(x + 0, y + marginBottom, x + 1, y + marginBottom); + DisplayManager.renderer.glDrawLine(x + 2, y + marginBottom + 1, x + 2, y + marginBottom + spazioSopra / 2 - 1); + DisplayManager.renderer.glDrawLine(x + 1, y + marginBottom + spazioSopra / 2, x + 1, y + h - 1); + DisplayManager.renderer.glDrawLine(x + 2, y + h, x + 3, y + h); } @Override diff --git a/src/org/warp/picalculator/math/functions/equations/EquationsSystemPart.java b/src/org/warp/picalculator/math/functions/equations/EquationsSystemPart.java index 15538b56..a9a2bc9c 100644 --- a/src/org/warp/picalculator/math/functions/equations/EquationsSystemPart.java +++ b/src/org/warp/picalculator/math/functions/equations/EquationsSystemPart.java @@ -1,7 +1,5 @@ package org.warp.picalculator.math.functions.equations; -import static org.warp.picalculator.gui.graphicengine.cpu.CPUDisplay.Render.glDrawLine; - import java.util.ArrayList; import java.util.List; @@ -21,7 +19,7 @@ public class EquationsSystemPart extends AnteriorFunction { protected Function NewInstance(Calculator root, Function value) { return new EquationsSystemPart(root, value); } - + @Override public String getSymbol() { return MathematicalSymbols.SYSTEM; @@ -31,15 +29,15 @@ public class EquationsSystemPart extends AnteriorFunction { public void generateGraphics() { variable.setSmall(false); variable.generateGraphics(); - + width = 5 + getVariable().getWidth(); height = 3 + getVariable().getHeight() + 2; line = 3 + getVariable().getLine(); } - + @Override public void draw(int x, int y) { - final int h = this.getHeight() - 1; + final int h = getHeight() - 1; final int paddingTop = 3; final int spazioSotto = (h - 3 - 2) / 2 + paddingTop; final int spazioSopra = h - spazioSotto; @@ -67,4 +65,22 @@ public class EquationsSystemPart extends AnteriorFunction { public int getLine() { return line; } + + @Override + protected ArrayList solve() throws Error { + // TODO Auto-generated method stub + return null; + } + + @Override + protected boolean isSolvable() { + // TODO Auto-generated method stub + return false; + } + + @Override + public boolean equals(Object o) { + // TODO Auto-generated method stub + return false; + } } diff --git a/src/org/warp/picalculator/math/functions/trigonometry/ArcCosine.java b/src/org/warp/picalculator/math/functions/trigonometry/ArcCosine.java index d1697784..4945a4e0 100644 --- a/src/org/warp/picalculator/math/functions/trigonometry/ArcCosine.java +++ b/src/org/warp/picalculator/math/functions/trigonometry/ArcCosine.java @@ -9,16 +9,16 @@ import org.warp.picalculator.math.functions.AnteriorFunction; import org.warp.picalculator.math.functions.Function; public class ArcCosine extends AnteriorFunction { - + public ArcCosine(Calculator root, Function value) { super(root, value); } - + @Override public Function NewInstance(Calculator root, Function value) { return new ArcCosine(root, value); } - + @Override public String getSymbol() { return MathematicalSymbols.getGraphicRepresentation(MathematicalSymbols.ARC_COSINE); diff --git a/src/org/warp/picalculator/math/functions/trigonometry/ArcSine.java b/src/org/warp/picalculator/math/functions/trigonometry/ArcSine.java index ad00e7c4..03ec67da 100644 --- a/src/org/warp/picalculator/math/functions/trigonometry/ArcSine.java +++ b/src/org/warp/picalculator/math/functions/trigonometry/ArcSine.java @@ -9,16 +9,16 @@ import org.warp.picalculator.math.functions.AnteriorFunction; import org.warp.picalculator.math.functions.Function; public class ArcSine extends AnteriorFunction { - + public ArcSine(Calculator root, Function value) { super(root, value); } - + @Override public Function NewInstance(Calculator root, Function value) { return new ArcSine(root, value); } - + @Override public String getSymbol() { return MathematicalSymbols.getGraphicRepresentation(MathematicalSymbols.ARC_SINE); diff --git a/src/org/warp/picalculator/math/functions/trigonometry/ArcTangent.java b/src/org/warp/picalculator/math/functions/trigonometry/ArcTangent.java index 65496150..3130014e 100644 --- a/src/org/warp/picalculator/math/functions/trigonometry/ArcTangent.java +++ b/src/org/warp/picalculator/math/functions/trigonometry/ArcTangent.java @@ -9,16 +9,16 @@ import org.warp.picalculator.math.functions.AnteriorFunction; import org.warp.picalculator.math.functions.Function; public class ArcTangent extends AnteriorFunction { - + public ArcTangent(Calculator root, Function value) { super(root, value); } - + @Override public Function NewInstance(Calculator root, Function value) { return new ArcTangent(root, value); } - + @Override public String getSymbol() { return MathematicalSymbols.getGraphicRepresentation(MathematicalSymbols.ARC_TANGENT); diff --git a/src/org/warp/picalculator/math/functions/trigonometry/Cosine.java b/src/org/warp/picalculator/math/functions/trigonometry/Cosine.java index a89435d7..9ff4c11a 100644 --- a/src/org/warp/picalculator/math/functions/trigonometry/Cosine.java +++ b/src/org/warp/picalculator/math/functions/trigonometry/Cosine.java @@ -9,16 +9,16 @@ import org.warp.picalculator.math.functions.AnteriorFunction; import org.warp.picalculator.math.functions.Function; public class Cosine extends AnteriorFunction { - + public Cosine(Calculator root, Function value) { super(root, value); } - + @Override public Function NewInstance(Calculator root, Function value) { return new Cosine(root, value); } - + @Override public String getSymbol() { return MathematicalSymbols.getGraphicRepresentation(MathematicalSymbols.COSINE); diff --git a/src/org/warp/picalculator/math/functions/trigonometry/Sine.java b/src/org/warp/picalculator/math/functions/trigonometry/Sine.java index 66da00f5..29310a1d 100644 --- a/src/org/warp/picalculator/math/functions/trigonometry/Sine.java +++ b/src/org/warp/picalculator/math/functions/trigonometry/Sine.java @@ -12,16 +12,16 @@ import org.warp.picalculator.math.functions.Function; import org.warp.picalculator.math.functions.Number; public class Sine extends AnteriorFunction { - + public Sine(Calculator root, Function value) { super(root, value); } - + @Override public Function NewInstance(Calculator root, Function value) { return new Sine(root, value); } - + @Override public String getSymbol() { return MathematicalSymbols.getGraphicRepresentation(MathematicalSymbols.SINE); @@ -35,14 +35,14 @@ public class Sine extends AnteriorFunction { } } if (root.angleMode == AngleMode.DEG) { - Function[] solvableValues = new Function[]{new Number(root, 0), new Number(root, 30), new Number(root, 90), }; + final Function[] solvableValues = new Function[] { new Number(root, 0), new Number(root, 30), new Number(root, 90), }; } return false; } @Override public ArrayList solve() throws Error { - ArrayList results = new ArrayList<>(); + final ArrayList results = new ArrayList<>(); if (variable instanceof Number) { if (root.exactMode == false) { results.add(new Number(root, BigDecimalMath.sin(((Number) variable).getTerm()))); @@ -54,7 +54,7 @@ public class Sine extends AnteriorFunction { @Override public boolean equals(Object o) { if (o instanceof Sine) { - AnteriorFunction f = (AnteriorFunction) o; + final AnteriorFunction f = (AnteriorFunction) o; if (variable.equals(f.getVariable())) { return true; } diff --git a/src/org/warp/picalculator/math/functions/trigonometry/Tangent.java b/src/org/warp/picalculator/math/functions/trigonometry/Tangent.java index 5b2002f0..1d327041 100644 --- a/src/org/warp/picalculator/math/functions/trigonometry/Tangent.java +++ b/src/org/warp/picalculator/math/functions/trigonometry/Tangent.java @@ -9,16 +9,16 @@ import org.warp.picalculator.math.functions.AnteriorFunction; import org.warp.picalculator.math.functions.Function; public class Tangent extends AnteriorFunction { - + public Tangent(Calculator root, Function value) { super(root, value); } - + @Override public Function NewInstance(Calculator root, Function value) { return new Tangent(root, value); } - + @Override public String getSymbol() { return MathematicalSymbols.getGraphicRepresentation(MathematicalSymbols.TANGENT); diff --git a/src/org/warp/picalculator/math/rules/ExpandRule1.java b/src/org/warp/picalculator/math/rules/ExpandRule1.java index c5ed15d0..d4ed3b2c 100644 --- a/src/org/warp/picalculator/math/rules/ExpandRule1.java +++ b/src/org/warp/picalculator/math/rules/ExpandRule1.java @@ -16,6 +16,7 @@ import org.warp.picalculator.math.functions.SumSubtraction; * Expand rule
* -(+a+b) = -a-b
* -(+a-b) = -a+b + * * @author Andrea Cavalli * */ @@ -23,9 +24,9 @@ public class ExpandRule1 { public static boolean compare(Function f) { if (f instanceof Negative) { - Negative fnc = (Negative) f; + final Negative fnc = (Negative) f; if (fnc.getVariable() instanceof Expression) { - Expression expr = (Expression) fnc.getVariable(); + final Expression expr = (Expression) fnc.getVariable(); if (expr.getVariablesLength() == 1) { if (expr.getVariable(0) instanceof Sum) { return true; @@ -37,9 +38,9 @@ public class ExpandRule1 { } } } else if (f instanceof Subtraction || f instanceof SumSubtraction) { - FunctionTwoValues fnc = (FunctionTwoValues) f; + final FunctionTwoValues fnc = (FunctionTwoValues) f; if (fnc.getVariable2() instanceof Expression) { - Expression expr = (Expression) fnc.getVariable2(); + final Expression expr = (Expression) fnc.getVariable2(); if (expr.getVariablesLength() == 1) { if (expr.getVariable(0) instanceof Sum) { return true; @@ -55,68 +56,68 @@ public class ExpandRule1 { } public static ArrayList execute(Function f) throws Error { - ArrayList result = new ArrayList<>(); - Calculator root = f.getRoot(); - + final ArrayList result = new ArrayList<>(); + final Calculator root = f.getRoot(); + Expression expr = null; int fromSubtraction = 0; FunctionTwoValues subtraction = null; if (f instanceof Negative) { - expr = ((Expression)((Negative) f).getVariable()); + expr = ((Expression) ((Negative) f).getVariable()); } else if (f instanceof Subtraction || f instanceof SumSubtraction) { - expr = ((Expression)((FunctionTwoValues) f).getVariable2()); + expr = ((Expression) ((FunctionTwoValues) f).getVariable2()); if (f instanceof Subtraction) { fromSubtraction = 1; } else { fromSubtraction = 2; } } - + if (f instanceof SumSubtraction) { - + } - Function fnc = expr.getVariable(0); + final Function fnc = expr.getVariable(0); if (fnc instanceof Sum) { - Function a = ((Sum) fnc).getVariable1(); - Function b = ((Sum) fnc).getVariable2(); - Subtraction fnc2 = new Subtraction(root, null, b); + final Function a = ((Sum) fnc).getVariable1(); + final Function b = ((Sum) fnc).getVariable2(); + final Subtraction fnc2 = new Subtraction(root, null, b); fnc2.setVariable1(new Negative(root, a)); if (fromSubtraction > 0) { subtraction = new Subtraction(root, null, null); - subtraction.setVariable1(((FunctionTwoValues)f).getVariable1()); + subtraction.setVariable1(((FunctionTwoValues) f).getVariable1()); subtraction.setVariable2(fnc2); result.add(subtraction); } else { result.add(fnc2); } } else if (fnc instanceof Subtraction) { - Function a = ((Subtraction) fnc).getVariable1(); - Function b = ((Subtraction) fnc).getVariable2(); - Sum fnc2 = new Sum(root, null, b); + final Function a = ((Subtraction) fnc).getVariable1(); + final Function b = ((Subtraction) fnc).getVariable2(); + final Sum fnc2 = new Sum(root, null, b); fnc2.setVariable1(new Negative(root, a)); if (fromSubtraction > 0) { subtraction = new Subtraction(root, null, null); - subtraction.setVariable1(((FunctionTwoValues)f).getVariable1()); + subtraction.setVariable1(((FunctionTwoValues) f).getVariable1()); subtraction.setVariable2(fnc2); result.add(subtraction); } else { result.add(fnc2); } } else if (fnc instanceof SumSubtraction) { - Function a = ((SumSubtraction) fnc).getVariable1(); - Function b = ((SumSubtraction) fnc).getVariable2(); - Sum fnc2 = new Sum(root, null, b); + final Function a = ((SumSubtraction) fnc).getVariable1(); + final Function b = ((SumSubtraction) fnc).getVariable2(); + final Sum fnc2 = new Sum(root, null, b); fnc2.setVariable1(new Negative(root, a)); - Subtraction fnc3 = new Subtraction(root, null, b); + final Subtraction fnc3 = new Subtraction(root, null, b); fnc3.setVariable1(new Negative(root, a)); if (fromSubtraction > 0) { subtraction = new SumSubtraction(root, null, null); - subtraction.setVariable1(((FunctionTwoValues)f).getVariable1()); + subtraction.setVariable1(((FunctionTwoValues) f).getVariable1()); subtraction.setVariable2(fnc2); result.add(subtraction); subtraction = new SumSubtraction(root, null, null); - subtraction.setVariable1(((FunctionTwoValues)f).getVariable1()); + subtraction.setVariable1(((FunctionTwoValues) f).getVariable1()); subtraction.setVariable2(fnc3); result.add(subtraction); result.add(subtraction); diff --git a/src/org/warp/picalculator/math/rules/ExpandRule5.java b/src/org/warp/picalculator/math/rules/ExpandRule5.java index 6b1546d3..52fba71f 100644 --- a/src/org/warp/picalculator/math/rules/ExpandRule5.java +++ b/src/org/warp/picalculator/math/rules/ExpandRule5.java @@ -3,7 +3,6 @@ package org.warp.picalculator.math.rules; import java.util.ArrayList; import org.warp.picalculator.Error; -import org.warp.picalculator.math.Calculator; import org.warp.picalculator.math.functions.Expression; import org.warp.picalculator.math.functions.Function; import org.warp.picalculator.math.functions.Negative; @@ -12,6 +11,7 @@ import org.warp.picalculator.math.functions.Subtraction; /** * Expand rule
* -(-a) = a + * * @author Andrea Cavalli * */ @@ -19,15 +19,15 @@ public class ExpandRule5 { public static boolean compare(Function f) { if (f instanceof Negative) { - Negative fnc = (Negative) f; + final Negative fnc = (Negative) f; if (fnc.getVariable() instanceof Expression) { - Expression e = (Expression)fnc.getVariable(); + final Expression e = (Expression) fnc.getVariable(); return e.getVariablesLength() == 1 && e.getVariable(0) instanceof Negative; } } else if (f instanceof Subtraction) { - Subtraction fnc = (Subtraction) f; + final Subtraction fnc = (Subtraction) f; if (fnc.getVariable2() instanceof Expression) { - Expression e = (Expression)fnc.getVariable2(); + final Expression e = (Expression) fnc.getVariable2(); return e.getVariablesLength() == 1 && e.getVariable(0) instanceof Negative; } } @@ -35,15 +35,15 @@ public class ExpandRule5 { } public static ArrayList execute(Function f) throws Error { - ArrayList result = new ArrayList<>(); - Function a = null; + final ArrayList result = new ArrayList<>(); + final Function a = null; if (f instanceof Negative) { - Negative fnc = (Negative) f; - result.add(((Negative)((Expression)fnc.getVariable()).getVariable(0)).getVariable()); + final Negative fnc = (Negative) f; + result.add(((Negative) ((Expression) fnc.getVariable()).getVariable(0)).getVariable()); } else if (f instanceof Subtraction) { - Subtraction fnc = (Subtraction) f; - result.add(((Negative)((Expression)fnc.getVariable2()).getVariable(0)).getVariable()); + final Subtraction fnc = (Subtraction) f; + result.add(((Negative) ((Expression) fnc.getVariable2()).getVariable(0)).getVariable()); } return result; } diff --git a/src/org/warp/picalculator/math/rules/ExponentRule1.java b/src/org/warp/picalculator/math/rules/ExponentRule1.java index ff883fc7..cd94a8f5 100644 --- a/src/org/warp/picalculator/math/rules/ExponentRule1.java +++ b/src/org/warp/picalculator/math/rules/ExponentRule1.java @@ -11,14 +11,15 @@ import org.warp.picalculator.math.functions.Power; /** * Exponent rule
* 1^a=1 + * * @author Andrea Cavalli * */ public class ExponentRule1 { public static boolean compare(Function f) { - Power fnc = (Power) f; - Calculator root = f.getRoot(); + final Power fnc = (Power) f; + final Calculator root = f.getRoot(); if (fnc.getVariable1().equals(new Number(root, 1))) { return true; } @@ -26,8 +27,8 @@ public class ExponentRule1 { } public static ArrayList execute(Function f) throws Error { - Calculator root = f.getRoot(); - ArrayList result = new ArrayList<>(); + final Calculator root = f.getRoot(); + final ArrayList result = new ArrayList<>(); result.add(new Number(root, 1)); return result; } diff --git a/src/org/warp/picalculator/math/rules/ExponentRule15.java b/src/org/warp/picalculator/math/rules/ExponentRule15.java index 475f1208..bdbac082 100644 --- a/src/org/warp/picalculator/math/rules/ExponentRule15.java +++ b/src/org/warp/picalculator/math/rules/ExponentRule15.java @@ -13,13 +13,14 @@ import org.warp.picalculator.math.functions.Power; /** * Exponent rule
* a*a=a^2 + * * @author Andrea Cavalli * */ public class ExponentRule15 { public static boolean compare(Function f) { - Multiplication fnc = (Multiplication) f; + final Multiplication fnc = (Multiplication) f; if (fnc.getVariable1().equals(fnc.getVariable2())) { return true; } @@ -27,14 +28,14 @@ public class ExponentRule15 { } public static ArrayList execute(Function f) throws Error { - Calculator root = f.getRoot(); - ArrayList result = new ArrayList<>(); - Multiplication fnc = (Multiplication) f; - Power p = new Power(root, null, null); - Expression expr = new Expression(root); - Function a = fnc.getVariable1(); + final Calculator root = f.getRoot(); + final ArrayList result = new ArrayList<>(); + final Multiplication fnc = (Multiplication) f; + final Power p = new Power(root, null, null); + final Expression expr = new Expression(root); + final Function a = fnc.getVariable1(); expr.addFunctionToEnd(a); - Number two = new Number(root, 2); + final Number two = new Number(root, 2); p.setVariable1(expr); p.setVariable2(two); result.add(p); diff --git a/src/org/warp/picalculator/math/rules/ExponentRule16.java b/src/org/warp/picalculator/math/rules/ExponentRule16.java index 30187fc5..3ddaa7ad 100644 --- a/src/org/warp/picalculator/math/rules/ExponentRule16.java +++ b/src/org/warp/picalculator/math/rules/ExponentRule16.java @@ -14,6 +14,7 @@ import org.warp.picalculator.math.functions.Root; /** * Exponent rule
* a√x=x^1/a + * * @author Andrea Cavalli * */ @@ -21,7 +22,7 @@ public class ExponentRule16 { public static boolean compare(Function f) { if (f instanceof Root) { - Root fnc = (Root) f; + final Root fnc = (Root) f; if (fnc.getVariable1().equals(fnc.getVariable2())) { return true; } @@ -30,14 +31,14 @@ public class ExponentRule16 { } public static ArrayList execute(Function f) throws Error { - Calculator root = f.getRoot(); - ArrayList result = new ArrayList<>(); - Multiplication fnc = (Multiplication) f; - Power p = new Power(fnc.getRoot(), null, null); - Expression expr = new Expression(root); - Function a = fnc.getVariable1(); + final Calculator root = f.getRoot(); + final ArrayList result = new ArrayList<>(); + final Multiplication fnc = (Multiplication) f; + final Power p = new Power(fnc.getRoot(), null, null); + final Expression expr = new Expression(root); + final Function a = fnc.getVariable1(); expr.addFunctionToEnd(a); - Number two = new Number(root, 2); + final Number two = new Number(root, 2); p.setVariable1(expr); p.setVariable2(two); result.add(p); diff --git a/src/org/warp/picalculator/math/rules/ExponentRule2.java b/src/org/warp/picalculator/math/rules/ExponentRule2.java index 3ca5c3cd..755fc5ff 100644 --- a/src/org/warp/picalculator/math/rules/ExponentRule2.java +++ b/src/org/warp/picalculator/math/rules/ExponentRule2.java @@ -10,13 +10,14 @@ import org.warp.picalculator.math.functions.Power; /** * Exponent rule
* a^1=a + * * @author Andrea Cavalli * */ public class ExponentRule2 { public static boolean compare(Function f) { - Power fnc = (Power) f; + final Power fnc = (Power) f; if (fnc.getVariable2().equals(new Number(f.getRoot(), 1))) { return true; } @@ -24,8 +25,8 @@ public class ExponentRule2 { } public static ArrayList execute(Function f) throws Error { - ArrayList result = new ArrayList<>(); - result.add(((Power)f).getVariable1()); + final ArrayList result = new ArrayList<>(); + result.add(((Power) f).getVariable1()); return result; } diff --git a/src/org/warp/picalculator/math/rules/ExponentRule3.java b/src/org/warp/picalculator/math/rules/ExponentRule3.java index 59652a1f..50c640d5 100644 --- a/src/org/warp/picalculator/math/rules/ExponentRule3.java +++ b/src/org/warp/picalculator/math/rules/ExponentRule3.java @@ -10,13 +10,14 @@ import org.warp.picalculator.math.functions.Power; /** * Exponent rule
* a^0=1 + * * @author Andrea Cavalli * */ public class ExponentRule3 { public static boolean compare(Function f) { - Power fnc = (Power) f; + final Power fnc = (Power) f; if (fnc.getVariable2().equals(new Number(f.getRoot(), 0))) { return true; } @@ -24,7 +25,7 @@ public class ExponentRule3 { } public static ArrayList execute(Function f) throws Error { - ArrayList result = new ArrayList<>(); + final ArrayList result = new ArrayList<>(); result.add(new Number(f.getRoot(), 1)); return result; } diff --git a/src/org/warp/picalculator/math/rules/ExponentRule4.java b/src/org/warp/picalculator/math/rules/ExponentRule4.java index 73d07bb2..c2200403 100644 --- a/src/org/warp/picalculator/math/rules/ExponentRule4.java +++ b/src/org/warp/picalculator/math/rules/ExponentRule4.java @@ -13,13 +13,14 @@ import org.warp.picalculator.math.functions.Power; /** * Exponent rule
* (a*b)^n=a^n*b^n + * * @author Andrea Cavalli * */ public class ExponentRule4 { public static boolean compare(Function f) { - Power fnc = (Power) f; + final Power fnc = (Power) f; if (fnc.getVariable1() instanceof Expression && ((Expression) fnc.getVariable1()).getVariablesLength() == 1 && ((Expression) fnc.getVariable1()).getVariable(0) instanceof Multiplication && fnc.getVariable2() instanceof Number) { return true; } @@ -27,22 +28,22 @@ public class ExponentRule4 { } public static ArrayList execute(Function f) throws Error { - Calculator root = f.getRoot(); - ArrayList result = new ArrayList<>(); - Power fnc = (Power) f; - Expression expr = (Expression) fnc.getVariable1(); - Multiplication mult = (Multiplication) expr.getVariable(0); - Function a = mult.getVariable1(); - Function b = mult.getVariable2(); - Number n = (Number) fnc.getVariable2(); - Multiplication retMult = new Multiplication(root, null, null); - Power p1 = new Power(root, null, null); - Expression e1 = new Expression(root); + final Calculator root = f.getRoot(); + final ArrayList result = new ArrayList<>(); + final Power fnc = (Power) f; + final Expression expr = (Expression) fnc.getVariable1(); + final Multiplication mult = (Multiplication) expr.getVariable(0); + final Function a = mult.getVariable1(); + final Function b = mult.getVariable2(); + final Number n = (Number) fnc.getVariable2(); + final Multiplication retMult = new Multiplication(root, null, null); + final Power p1 = new Power(root, null, null); + final Expression e1 = new Expression(root); e1.addFunctionToEnd(a); p1.setVariable1(e1); p1.setVariable2(n); - Power p2 = new Power(root, null, null); - Expression e2 = new Expression(root); + final Power p2 = new Power(root, null, null); + final Expression e2 = new Expression(root); e2.addFunctionToEnd(b); p2.setVariable1(e2); p2.setVariable2(n); diff --git a/src/org/warp/picalculator/math/rules/FractionsRule1.java b/src/org/warp/picalculator/math/rules/FractionsRule1.java index f8b80fdc..5dac1a13 100644 --- a/src/org/warp/picalculator/math/rules/FractionsRule1.java +++ b/src/org/warp/picalculator/math/rules/FractionsRule1.java @@ -11,19 +11,20 @@ import org.warp.picalculator.math.functions.Number; /** * Fractions rule
* 0 / a = 0 + * * @author Andrea Cavalli * */ public class FractionsRule1 { public static boolean compare(Function f) { - Calculator root = f.getRoot(); - Division fnc = (Division) f; + final Calculator root = f.getRoot(); + final Division fnc = (Division) f; if (fnc.getVariable1() instanceof Number) { - Number numb1 = (Number) fnc.getVariable1(); + final Number numb1 = (Number) fnc.getVariable1(); if (numb1.equals(new Number(root, 0))) { if (fnc.getVariable2() instanceof Number) { - Number numb2 = (Number) fnc.getVariable2(); + final Number numb2 = (Number) fnc.getVariable2(); if (numb2.equals(new Number(root, 0))) { return false; } @@ -35,7 +36,7 @@ public class FractionsRule1 { } public static ArrayList execute(Function f) throws Error { - ArrayList result = new ArrayList<>(); + final ArrayList result = new ArrayList<>(); result.add(new Number(f.getRoot(), 0)); return result; } diff --git a/src/org/warp/picalculator/math/rules/FractionsRule2.java b/src/org/warp/picalculator/math/rules/FractionsRule2.java index 4c110be7..586a720e 100644 --- a/src/org/warp/picalculator/math/rules/FractionsRule2.java +++ b/src/org/warp/picalculator/math/rules/FractionsRule2.java @@ -10,15 +10,16 @@ import org.warp.picalculator.math.functions.Number; /** * Fractions rule
* a / 1 = a + * * @author Andrea Cavalli * */ public class FractionsRule2 { public static boolean compare(Function f) { - Division fnc = (Division) f; + final Division fnc = (Division) f; if (fnc.getVariable2() instanceof Number) { - Number numb = (Number) fnc.getVariable2(); + final Number numb = (Number) fnc.getVariable2(); if (numb.equals(new Number(f.getRoot(), 1))) { return true; } @@ -27,8 +28,8 @@ public class FractionsRule2 { } public static ArrayList execute(Function f) throws Error { - ArrayList result = new ArrayList<>(); - Division fnc = (Division) f; + final ArrayList result = new ArrayList<>(); + final Division fnc = (Division) f; result.add(fnc.getVariable1()); return result; } diff --git a/src/org/warp/picalculator/math/rules/FractionsRule3.java b/src/org/warp/picalculator/math/rules/FractionsRule3.java index 8dd20916..46d9283a 100644 --- a/src/org/warp/picalculator/math/rules/FractionsRule3.java +++ b/src/org/warp/picalculator/math/rules/FractionsRule3.java @@ -10,13 +10,14 @@ import org.warp.picalculator.math.functions.Number; /** * Fractions rule
* a / a = 1 + * * @author Andrea Cavalli * */ public class FractionsRule3 { public static boolean compare(Function f) { - Division fnc = (Division) f; + final Division fnc = (Division) f; if (fnc.getVariable1().equals(fnc.getVariable2())) { return true; } @@ -24,7 +25,7 @@ public class FractionsRule3 { } public static ArrayList execute(Function f) throws Error { - ArrayList result = new ArrayList<>(); + final ArrayList result = new ArrayList<>(); result.add(new Number(f.getRoot(), 1)); return result; } diff --git a/src/org/warp/picalculator/math/rules/FractionsRule4.java b/src/org/warp/picalculator/math/rules/FractionsRule4.java index 04be9cbd..d411e7f9 100644 --- a/src/org/warp/picalculator/math/rules/FractionsRule4.java +++ b/src/org/warp/picalculator/math/rules/FractionsRule4.java @@ -11,15 +11,16 @@ import org.warp.picalculator.math.functions.Power; /** * Fractions rule
* (a / b) ^ -1 = b / a + * * @author Andrea Cavalli * */ public class FractionsRule4 { public static boolean compare(Function f) { - Power fnc = (Power) f; + final Power fnc = (Power) f; if (fnc.getVariable1() instanceof Division && fnc.getVariable2() instanceof Number) { - Number n2 = (Number) fnc.getVariable2(); + final Number n2 = (Number) fnc.getVariable2(); if (n2.equals(new Number(f.getRoot(), -1))) { return true; } @@ -28,11 +29,11 @@ public class FractionsRule4 { } public static ArrayList execute(Function f) throws Error { - ArrayList result = new ArrayList<>(); - Power fnc = (Power) f; - Function a = ((Division)fnc.getVariable1()).getVariable1(); - Function b = ((Division)fnc.getVariable1()).getVariable2(); - Division res = new Division(f.getRoot(), b, a); + final ArrayList result = new ArrayList<>(); + final Power fnc = (Power) f; + final Function a = ((Division) fnc.getVariable1()).getVariable1(); + final Function b = ((Division) fnc.getVariable1()).getVariable2(); + final Division res = new Division(f.getRoot(), b, a); result.add(res); return result; } diff --git a/src/org/warp/picalculator/math/rules/FractionsRule5.java b/src/org/warp/picalculator/math/rules/FractionsRule5.java index f7092df0..f9a9a0bc 100644 --- a/src/org/warp/picalculator/math/rules/FractionsRule5.java +++ b/src/org/warp/picalculator/math/rules/FractionsRule5.java @@ -1,4 +1,5 @@ package org.warp.picalculator.math.rules; + import java.math.BigDecimal; import java.util.ArrayList; @@ -12,15 +13,16 @@ import org.warp.picalculator.math.functions.Power; /** * Fractions rule
* (a / b) ^ -c = (b / a) ^ c + * * @author Andrea Cavalli * */ public class FractionsRule5 { public static boolean compare(Function f) { - Power fnc = (Power) f; + final Power fnc = (Power) f; if (fnc.getVariable1() instanceof Division && fnc.getVariable2() instanceof Number) { - Number n2 = (Number) fnc.getVariable2(); + final Number n2 = (Number) fnc.getVariable2(); if (n2.getTerm().compareTo(BigDecimal.ZERO) < 0) { return true; } @@ -29,14 +31,14 @@ public class FractionsRule5 { } public static ArrayList execute(Function f) throws Error { - Calculator root = f.getRoot(); - ArrayList result = new ArrayList<>(); - Power fnc = (Power) f; - Function a = ((Division)fnc.getVariable1()).getVariable1(); - Function b = ((Division)fnc.getVariable1()).getVariable2(); - Function c = ((Number)fnc.getVariable2()).multiply(new Number(root, "-1")); - Division dv = new Division(root, b, a); - Power pow = new Power(root, dv, c); + final Calculator root = f.getRoot(); + final ArrayList result = new ArrayList<>(); + final Power fnc = (Power) f; + final Function a = ((Division) fnc.getVariable1()).getVariable1(); + final Function b = ((Division) fnc.getVariable1()).getVariable2(); + final Function c = ((Number) fnc.getVariable2()).multiply(new Number(root, "-1")); + final Division dv = new Division(root, b, a); + final Power pow = new Power(root, dv, c); result.add(pow); return result; } diff --git a/src/org/warp/picalculator/math/rules/NumberRule1.java b/src/org/warp/picalculator/math/rules/NumberRule1.java index 9e3e00ff..79ef49b2 100644 --- a/src/org/warp/picalculator/math/rules/NumberRule1.java +++ b/src/org/warp/picalculator/math/rules/NumberRule1.java @@ -11,22 +11,23 @@ import org.warp.picalculator.math.functions.Number; /** * Number rule
* a * 0 = 0 + * * @author Andrea Cavalli * */ public class NumberRule1 { public static boolean compare(Function f) { - Calculator root = f.getRoot(); - Multiplication mult = (Multiplication) f; + final Calculator root = f.getRoot(); + final Multiplication mult = (Multiplication) f; if (mult.getVariable1() instanceof Number) { - Number numb = (Number) mult.getVariable1(); + final Number numb = (Number) mult.getVariable1(); if (numb.equals(new Number(root, 0))) { return true; } } if (mult.getVariable2() instanceof Number) { - Number numb = (Number) mult.getVariable2(); + final Number numb = (Number) mult.getVariable2(); if (numb.equals(new Number(root, 0))) { return true; } @@ -35,7 +36,7 @@ public class NumberRule1 { } public static ArrayList execute(Function f) throws Error { - ArrayList result = new ArrayList<>(); + final ArrayList result = new ArrayList<>(); result.add(new Number(f.getRoot(), "0")); return result; } diff --git a/src/org/warp/picalculator/math/rules/NumberRule2.java b/src/org/warp/picalculator/math/rules/NumberRule2.java index bec01ff1..8438ceb6 100644 --- a/src/org/warp/picalculator/math/rules/NumberRule2.java +++ b/src/org/warp/picalculator/math/rules/NumberRule2.java @@ -11,22 +11,23 @@ import org.warp.picalculator.math.functions.Number; /** * Number rule
* a * 1 = a + * * @author Andrea Cavalli * */ public class NumberRule2 { public static boolean compare(Function f) { - Calculator root = f.getRoot(); - Multiplication mult = (Multiplication) f; + final Calculator root = f.getRoot(); + final Multiplication mult = (Multiplication) f; if (mult.getVariable1() instanceof Number) { - Number numb = (Number) mult.getVariable1(); + final Number numb = (Number) mult.getVariable1(); if (numb.equals(new Number(root, 1))) { return true; } } if (mult.getVariable2() instanceof Number) { - Number numb = (Number) mult.getVariable2(); + final Number numb = (Number) mult.getVariable2(); if (numb.equals(new Number(root, 1))) { return true; } @@ -35,26 +36,26 @@ public class NumberRule2 { } public static ArrayList execute(Function f) throws Error { - Calculator root = f.getRoot(); - ArrayList result = new ArrayList<>(); + final Calculator root = f.getRoot(); + final ArrayList result = new ArrayList<>(); Function a = null; boolean aFound = false; - Multiplication mult = (Multiplication) f; + final Multiplication mult = (Multiplication) f; if (aFound == false & mult.getVariable1() instanceof Number) { - Number numb = (Number) mult.getVariable1(); + final Number numb = (Number) mult.getVariable1(); if (numb.equals(new Number(root, 1))) { a = mult.getVariable2(); aFound = true; } } if (aFound == false && mult.getVariable2() instanceof Number) { - Number numb = (Number) mult.getVariable2(); + final Number numb = (Number) mult.getVariable2(); if (numb.equals(new Number(root, 1))) { a = mult.getVariable1(); aFound = true; } } - + result.add(a); return result; } diff --git a/src/org/warp/picalculator/math/rules/NumberRule3.java b/src/org/warp/picalculator/math/rules/NumberRule3.java index e69d18bf..2556e1b5 100644 --- a/src/org/warp/picalculator/math/rules/NumberRule3.java +++ b/src/org/warp/picalculator/math/rules/NumberRule3.java @@ -17,6 +17,7 @@ import org.warp.picalculator.math.functions.SumSubtraction; * a - a = 0
* -a + a = 0
* a ± a = {0, 2a} + * * @author Andrea Cavalli * */ @@ -24,20 +25,20 @@ public class NumberRule3 { public static boolean compare(Function f) { if (f instanceof Subtraction) { - Subtraction sub = (Subtraction) f; + final Subtraction sub = (Subtraction) f; if (sub.getVariable1().equals(sub.getVariable2())) { return true; } } else if (f instanceof Sum) { - Sum sub = (Sum) f; + final Sum sub = (Sum) f; if (sub.getVariable1() instanceof Negative) { - Negative neg = (Negative) sub.getVariable1(); + final Negative neg = (Negative) sub.getVariable1(); if (neg.getVariable().equals(sub.getVariable2())) { return true; } } } else if (f instanceof SumSubtraction) { - SumSubtraction sub = (SumSubtraction) f; + final SumSubtraction sub = (SumSubtraction) f; if (sub.getVariable1().equals(sub.getVariable2())) { return true; } @@ -46,10 +47,10 @@ public class NumberRule3 { } public static ArrayList execute(Function f) throws Error { - Calculator root = f.getRoot(); - ArrayList result = new ArrayList<>(); + final Calculator root = f.getRoot(); + final ArrayList result = new ArrayList<>(); if (f instanceof SumSubtraction) { - Multiplication mul = new Multiplication(root, null, null); + final Multiplication mul = new Multiplication(root, null, null); mul.setVariable1(new Number(root, 2)); mul.setVariable2(f); result.add(mul); diff --git a/src/org/warp/picalculator/math/rules/NumberRule4.java b/src/org/warp/picalculator/math/rules/NumberRule4.java index 9e9e9bf4..40f6c406 100644 --- a/src/org/warp/picalculator/math/rules/NumberRule4.java +++ b/src/org/warp/picalculator/math/rules/NumberRule4.java @@ -12,6 +12,7 @@ import org.warp.picalculator.math.functions.SumSubtraction; /** * Number rule
* a ± b = {a+b, a-b} + * * @author Andrea Cavalli * */ @@ -25,9 +26,9 @@ public class NumberRule4 { } public static ArrayList execute(Function f) throws Error { - Calculator root = f.getRoot(); - ArrayList result = new ArrayList<>(); - SumSubtraction ss = (SumSubtraction) f; + final Calculator root = f.getRoot(); + final ArrayList result = new ArrayList<>(); + final SumSubtraction ss = (SumSubtraction) f; result.add(new Sum(root, ss.getVariable1(), ss.getVariable2())); result.add(new Subtraction(root, ss.getVariable1(), ss.getVariable2())); return result; diff --git a/src/org/warp/picalculator/math/rules/NumberRule5.java b/src/org/warp/picalculator/math/rules/NumberRule5.java index 9bdf90a7..3de422f3 100644 --- a/src/org/warp/picalculator/math/rules/NumberRule5.java +++ b/src/org/warp/picalculator/math/rules/NumberRule5.java @@ -16,14 +16,15 @@ import org.warp.picalculator.math.functions.Number; * 0 - a = a
* a ± 0 = a
* 0 ± a = a + * * @author Andrea Cavalli * */ public class NumberRule5 { public static boolean compare(Function f) { - Calculator root = f.getRoot(); - FunctionTwoValues fnc = (FunctionTwoValues) f; + final Calculator root = f.getRoot(); + final FunctionTwoValues fnc = (FunctionTwoValues) f; if (fnc.getVariable1().equals(new Number(root, 0)) || fnc.getVariable2().equals(new Number(root, 0))) { return true; } @@ -31,9 +32,9 @@ public class NumberRule5 { } public static ArrayList execute(Function f) throws Error { - Calculator root = f.getRoot(); - ArrayList result = new ArrayList<>(); - FunctionTwoValues fnc = (FunctionTwoValues) f; + final Calculator root = f.getRoot(); + final ArrayList result = new ArrayList<>(); + final FunctionTwoValues fnc = (FunctionTwoValues) f; Function a = fnc.getVariable1(); if (a.equals(new Number(root, 0))) { a = fnc.getVariable2(); diff --git a/src/org/warp/picalculator/math/rules/NumberRule6.java b/src/org/warp/picalculator/math/rules/NumberRule6.java index 998e4546..7e451277 100644 --- a/src/org/warp/picalculator/math/rules/NumberRule6.java +++ b/src/org/warp/picalculator/math/rules/NumberRule6.java @@ -12,22 +12,23 @@ import org.warp.picalculator.math.functions.Number; /** * Number rule
* a * -1 = -a + * * @author Andrea Cavalli * */ public class NumberRule6 { public static boolean compare(Function f) { - Calculator root = f.getRoot(); - Multiplication mult = (Multiplication) f; + final Calculator root = f.getRoot(); + final Multiplication mult = (Multiplication) f; if (mult.getVariable1() instanceof Number) { - Number numb = (Number) mult.getVariable1(); + final Number numb = (Number) mult.getVariable1(); if (numb.equals(new Number(root, -1))) { return true; } } if (mult.getVariable2() instanceof Number) { - Number numb = (Number) mult.getVariable2(); + final Number numb = (Number) mult.getVariable2(); if (numb.equals(new Number(root, -1))) { return true; } @@ -36,29 +37,29 @@ public class NumberRule6 { } public static ArrayList execute(Function f) throws Error { - Calculator root = f.getRoot(); - ArrayList result = new ArrayList<>(); + final Calculator root = f.getRoot(); + final ArrayList result = new ArrayList<>(); Function a = null; boolean aFound = false; - Multiplication mult = (Multiplication) f; + final Multiplication mult = (Multiplication) f; if (aFound == false & mult.getVariable1() instanceof Number) { - Number numb = (Number) mult.getVariable1(); + final Number numb = (Number) mult.getVariable1(); if (numb.equals(new Number(root, -1))) { a = mult.getVariable2(); aFound = true; } } if (aFound == false && mult.getVariable2() instanceof Number) { - Number numb = (Number) mult.getVariable2(); + final Number numb = (Number) mult.getVariable2(); if (numb.equals(new Number(root, -1))) { a = mult.getVariable1(); aFound = true; } } - - Negative minus = new Negative(root, null); + + final Negative minus = new Negative(root, null); minus.setVariable(a); - + result.add(minus); return result; } diff --git a/src/org/warp/picalculator/math/rules/NumberRule7.java b/src/org/warp/picalculator/math/rules/NumberRule7.java index 0c4f6663..301fe896 100644 --- a/src/org/warp/picalculator/math/rules/NumberRule7.java +++ b/src/org/warp/picalculator/math/rules/NumberRule7.java @@ -12,6 +12,7 @@ import org.warp.picalculator.math.functions.Sum; /** * Number rule
* a + a = 2a + * * @author Andrea Cavalli * */ @@ -22,9 +23,9 @@ public class NumberRule7 { } public static ArrayList execute(Sum f) throws Error { - Calculator root = f.getRoot(); - ArrayList result = new ArrayList<>(); - Multiplication mult = new Multiplication(root, null, null); + final Calculator root = f.getRoot(); + final ArrayList result = new ArrayList<>(); + final Multiplication mult = new Multiplication(root, null, null); mult.setVariable1(new Number(root, 2)); mult.setVariable2(f.getVariable1()); result.add(mult); diff --git a/src/org/warp/picalculator/math/rules/SyntaxRule1.java b/src/org/warp/picalculator/math/rules/SyntaxRule1.java index 86ddbd47..16147f29 100644 --- a/src/org/warp/picalculator/math/rules/SyntaxRule1.java +++ b/src/org/warp/picalculator/math/rules/SyntaxRule1.java @@ -12,13 +12,14 @@ import org.warp.picalculator.math.functions.Sum; /** * Syntax rule
* (a*b)*c=a*(b*c) + * * @author Andrea Cavalli * */ public class SyntaxRule1 { public static boolean compare(Function f) { - FunctionTwoValues m = (FunctionTwoValues) f; + final FunctionTwoValues m = (FunctionTwoValues) f; if (m instanceof Multiplication & m.getVariable1() instanceof Multiplication) { return true; } else if (m instanceof Sum & m.getVariable1() instanceof Sum) { @@ -28,12 +29,12 @@ public class SyntaxRule1 { } public static ArrayList execute(Function f) throws Error { - Calculator root = f.getRoot(); - ArrayList result = new ArrayList<>(); - FunctionTwoValues mOut = (FunctionTwoValues) f; - Function a = ((FunctionTwoValues)mOut.getVariable1()).getVariable1(); - Function b = ((FunctionTwoValues)mOut.getVariable1()).getVariable2(); - Function c = mOut.getVariable2(); + final Calculator root = f.getRoot(); + final ArrayList result = new ArrayList<>(); + final FunctionTwoValues mOut = (FunctionTwoValues) f; + final Function a = ((FunctionTwoValues) mOut.getVariable1()).getVariable1(); + final Function b = ((FunctionTwoValues) mOut.getVariable1()).getVariable2(); + final Function c = mOut.getVariable2(); FunctionTwoValues mIn; if (f instanceof Multiplication) { mIn = new Multiplication(root, null, null); diff --git a/src/org/warp/picalculator/math/rules/SyntaxRule2.java b/src/org/warp/picalculator/math/rules/SyntaxRule2.java index 2e5266f5..75e43289 100644 --- a/src/org/warp/picalculator/math/rules/SyntaxRule2.java +++ b/src/org/warp/picalculator/math/rules/SyntaxRule2.java @@ -11,6 +11,7 @@ import org.warp.picalculator.math.functions.Sum; /** * Syntax rule
* a+(b+c)=(a+b)+c + * * @author Andrea Cavalli * */ @@ -21,7 +22,7 @@ public class SyntaxRule2 { return true; } if (f.getVariable2() instanceof Expression) { - Expression e = (Expression) f.getVariable2(); + final Expression e = (Expression) f.getVariable2(); if (e.getVariablesLength() == 1 && e.getVariable(0) instanceof Sum) { return true; } @@ -30,18 +31,18 @@ public class SyntaxRule2 { } public static ArrayList execute(Sum f) throws Error { - Calculator root = f.getRoot(); - ArrayList result = new ArrayList<>(); - Function a = f.getVariable1(); + final Calculator root = f.getRoot(); + final ArrayList result = new ArrayList<>(); + final Function a = f.getVariable1(); Function b, c; if (f.getVariable2() instanceof Sum) { - b = ((Sum)f.getVariable2()).getVariable1(); - c = ((Sum)f.getVariable2()).getVariable2(); + b = ((Sum) f.getVariable2()).getVariable1(); + c = ((Sum) f.getVariable2()).getVariable2(); } else { - b = ((Sum)((Expression)f.getVariable2()).getVariable(0)).getVariable1(); - c = ((Sum)((Expression)f.getVariable2()).getVariable(0)).getVariable2(); + b = ((Sum) ((Expression) f.getVariable2()).getVariable(0)).getVariable1(); + c = ((Sum) ((Expression) f.getVariable2()).getVariable(0)).getVariable2(); } - Sum mIn = new Sum(root, null, null); + final Sum mIn = new Sum(root, null, null); f.setVariable1(mIn); mIn.setVariable1(a); mIn.setVariable2(b); diff --git a/src/org/warp/picalculator/math/rules/UndefinedRule1.java b/src/org/warp/picalculator/math/rules/UndefinedRule1.java index 31e102ef..b5cecfa4 100644 --- a/src/org/warp/picalculator/math/rules/UndefinedRule1.java +++ b/src/org/warp/picalculator/math/rules/UndefinedRule1.java @@ -12,14 +12,15 @@ import org.warp.picalculator.math.functions.Undefined; /** * Undefined rule
* 0^0=undefined + * * @author Andrea Cavalli * */ public class UndefinedRule1 { public static boolean compare(Function f) { - Calculator root = f.getRoot(); - Power fnc = (Power) f; + final Calculator root = f.getRoot(); + final Power fnc = (Power) f; if (fnc.getVariable1().equals(new Number(root, 0)) && fnc.getVariable2().equals(new Number(root, 0))) { return true; } @@ -27,8 +28,8 @@ public class UndefinedRule1 { } public static ArrayList execute(Function f) throws Error { - Calculator root = f.getRoot(); - ArrayList result = new ArrayList<>(); + final Calculator root = f.getRoot(); + final ArrayList result = new ArrayList<>(); result.add(new Undefined(root)); return result; } diff --git a/src/org/warp/picalculator/math/rules/UndefinedRule2.java b/src/org/warp/picalculator/math/rules/UndefinedRule2.java index b202a23f..2e818b1c 100644 --- a/src/org/warp/picalculator/math/rules/UndefinedRule2.java +++ b/src/org/warp/picalculator/math/rules/UndefinedRule2.java @@ -12,16 +12,17 @@ import org.warp.picalculator.math.functions.Undefined; /** * Undefined rule
* a / 0 = undefined + * * @author Andrea Cavalli * */ public class UndefinedRule2 { public static boolean compare(Function f) { - Calculator root = f.getRoot(); - Division fnc = (Division) f; + final Calculator root = f.getRoot(); + final Division fnc = (Division) f; if (fnc.getVariable2() instanceof Number) { - Number numb = (Number) fnc.getVariable2(); + final Number numb = (Number) fnc.getVariable2(); if (numb.equals(new Number(root, 0))) { return true; } @@ -30,8 +31,8 @@ public class UndefinedRule2 { } public static ArrayList execute(Function f) throws Error { - Calculator root = f.getRoot(); - ArrayList result = new ArrayList<>(); + final Calculator root = f.getRoot(); + final ArrayList result = new ArrayList<>(); result.add(new Undefined(root)); return result; } diff --git a/src/org/warp/picalculator/math/rules/VariableRule1.java b/src/org/warp/picalculator/math/rules/VariableRule1.java index d1c324af..61c4efd1 100644 --- a/src/org/warp/picalculator/math/rules/VariableRule1.java +++ b/src/org/warp/picalculator/math/rules/VariableRule1.java @@ -14,6 +14,7 @@ import org.warp.picalculator.math.functions.Sum; /** * Variable rule
* ax+bx=(a+b)*x (a,b NUMBER; x VARIABLE|MULTIPLICATION) + * * @author Andrea Cavalli * */ @@ -21,8 +22,8 @@ public class VariableRule1 { public static boolean compare(FunctionTwoValues fnc) { if (fnc.getVariable1() instanceof Multiplication & fnc.getVariable2() instanceof Multiplication) { - Multiplication m1 = (Multiplication) fnc.getVariable1(); - Multiplication m2 = (Multiplication) fnc.getVariable2(); + final Multiplication m1 = (Multiplication) fnc.getVariable1(); + final Multiplication m2 = (Multiplication) fnc.getVariable2(); if (m1.getVariable2().equals(m2.getVariable2())) { return true; } @@ -31,18 +32,18 @@ public class VariableRule1 { } public static ArrayList execute(FunctionTwoValues fnc) throws Error { - Calculator root = fnc.getRoot(); - ArrayList result = new ArrayList<>(); - Multiplication m1 = (Multiplication) fnc.getVariable1(); - Multiplication m2 = (Multiplication) fnc.getVariable2(); - Function a = m1.getVariable1(); - Function b = m2.getVariable1(); - Function x = m1.getVariable2(); - - Multiplication retm = new Multiplication(root, null, null); - Expression rete = new Expression(root); + final Calculator root = fnc.getRoot(); + final ArrayList result = new ArrayList<>(); + final Multiplication m1 = (Multiplication) fnc.getVariable1(); + final Multiplication m2 = (Multiplication) fnc.getVariable2(); + final Function a = m1.getVariable1(); + final Function b = m2.getVariable1(); + final Function x = m1.getVariable2(); + + final Multiplication retm = new Multiplication(root, null, null); + final Expression rete = new Expression(root); FunctionTwoValues rets; - if (fnc instanceof Sum){ + if (fnc instanceof Sum) { rets = new Sum(root, null, null); } else { rets = new Subtraction(root, null, null); diff --git a/src/org/warp/picalculator/math/rules/VariableRule2.java b/src/org/warp/picalculator/math/rules/VariableRule2.java index b0a8df7c..c3c5ed8d 100644 --- a/src/org/warp/picalculator/math/rules/VariableRule2.java +++ b/src/org/warp/picalculator/math/rules/VariableRule2.java @@ -15,6 +15,7 @@ import org.warp.picalculator.math.functions.Sum; /** * Variable rule
* ax+x=(a+1)*x (a,b NUMBER; x VARIABLES) + * * @author Andrea Cavalli * */ @@ -22,7 +23,7 @@ public class VariableRule2 { public static boolean compare(FunctionTwoValues fnc) { if (fnc.getVariable1() instanceof Multiplication) { - Multiplication m1 = (Multiplication) fnc.getVariable1(); + final Multiplication m1 = (Multiplication) fnc.getVariable1(); if (m1.getVariable2().equals(fnc.getVariable2())) { return true; } @@ -31,15 +32,15 @@ public class VariableRule2 { } public static ArrayList execute(FunctionTwoValues fnc) throws Error { - Calculator root = fnc.getRoot(); - ArrayList result = new ArrayList<>(); - Multiplication m1 = (Multiplication) fnc.getVariable1(); - Function a = m1.getVariable1(); - Function x = fnc.getVariable2(); - - Multiplication retm = new Multiplication(root, null, null); - Expression rete = new Expression(root); - + final Calculator root = fnc.getRoot(); + final ArrayList result = new ArrayList<>(); + final Multiplication m1 = (Multiplication) fnc.getVariable1(); + final Function a = m1.getVariable1(); + final Function x = fnc.getVariable2(); + + final Multiplication retm = new Multiplication(root, null, null); + final Expression rete = new Expression(root); + FunctionTwoValues rets; if (fnc instanceof Sum) { rets = new Sum(root, null, null); diff --git a/src/org/warp/picalculator/math/rules/VariableRule3.java b/src/org/warp/picalculator/math/rules/VariableRule3.java index 6ea0a3cd..08b84fd2 100644 --- a/src/org/warp/picalculator/math/rules/VariableRule3.java +++ b/src/org/warp/picalculator/math/rules/VariableRule3.java @@ -15,6 +15,7 @@ import org.warp.picalculator.math.functions.Sum; /** * Variable rule
* x+ax=(a+1)*x (a,b NUMBER; x VARIABLES) + * * @author Andrea Cavalli * */ @@ -22,7 +23,7 @@ public class VariableRule3 { public static boolean compare(FunctionTwoValues fnc) { if (fnc.getVariable2() instanceof Multiplication) { - Multiplication m2 = (Multiplication) fnc.getVariable2(); + final Multiplication m2 = (Multiplication) fnc.getVariable2(); if (m2.getVariable2().equals(fnc.getVariable1())) { return true; } @@ -31,14 +32,14 @@ public class VariableRule3 { } public static ArrayList execute(FunctionTwoValues fnc) throws Error { - Calculator root = fnc.getRoot(); - ArrayList result = new ArrayList<>(); - Multiplication m2 = (Multiplication) fnc.getVariable2(); - Function a = m2.getVariable1(); - Function x = fnc.getVariable1(); - - Multiplication retm = new Multiplication(root, null, null); - Expression rete = new Expression(root); + final Calculator root = fnc.getRoot(); + final ArrayList result = new ArrayList<>(); + final Multiplication m2 = (Multiplication) fnc.getVariable2(); + final Function a = m2.getVariable1(); + final Function x = fnc.getVariable1(); + + final Multiplication retm = new Multiplication(root, null, null); + final Expression rete = new Expression(root); FunctionTwoValues rets; if (fnc instanceof Sum) { rets = new Sum(root, null, null); diff --git a/src/org/warp/picalculator/math/rules/methods/DivisionRule1.java b/src/org/warp/picalculator/math/rules/methods/DivisionRule1.java index 8c64f5c4..73f079f7 100644 --- a/src/org/warp/picalculator/math/rules/methods/DivisionRule1.java +++ b/src/org/warp/picalculator/math/rules/methods/DivisionRule1.java @@ -12,6 +12,7 @@ import org.warp.picalculator.math.functions.Number; /** * Division method
* Example: (XY)/(YZ) = X/Z + * * @author Andrea Cavalli * */ @@ -22,32 +23,32 @@ public class DivisionRule1 { } public static ArrayList execute(Division f) throws Error { - Calculator root = f.getRoot(); + final Calculator root = f.getRoot(); Function result; - ArrayList elements = getDivisionElements(f); - int[] workingElementCouple = getFirstWorkingDivisionCouple(elements); - Function elem1 = elements.get(workingElementCouple[0]); - Function elem2 = elements.get(workingElementCouple[1]); - + final ArrayList elements = getDivisionElements(f); + final int[] workingElementCouple = getFirstWorkingDivisionCouple(elements); + final Function elem1 = elements.get(workingElementCouple[0]); + final Function elem2 = elements.get(workingElementCouple[1]); + final int size = elements.size(); Function prec = new Multiplication(root, elem1, elem2); - for (int i = size-1; i >= 0; i--) { + for (int i = size - 1; i >= 0; i--) { if (i != workingElementCouple[0] & i != workingElementCouple[1]) { - Function a = prec; - Function b = elements.get(i); + final Function a = prec; + final Function b = elements.get(i); prec = new Multiplication(root, a, b); } } - + result = prec; - - ArrayList results = new ArrayList<>(); + + final ArrayList results = new ArrayList<>(); results.add(result); return results; } - + private static ArrayList getDivisionElements(Division division) { - ArrayList elementsNumerator = new ArrayList<>(); + final ArrayList elementsNumerator = new ArrayList<>(); Function numMult = division.getVariable1(); while (numMult instanceof Multiplication) { elementsNumerator.add(((Multiplication) numMult).getVariable1()); @@ -55,18 +56,17 @@ public class DivisionRule1 { } elementsNumerator.add(numMult); - ArrayList elementsDenominator = new ArrayList<>(); + final ArrayList elementsDenominator = new ArrayList<>(); Function denomMult = division.getVariable1(); while (denomMult instanceof Multiplication) { elementsDenominator.add(((Multiplication) denomMult).getVariable1()); denomMult = ((Multiplication) denomMult).getVariable2(); } elementsDenominator.add(denomMult); - - + return elements; } - + private static int[] getFirstWorkingDivisionCouple(ArrayList elements) { final int size = elements.size(); Function a; @@ -82,7 +82,7 @@ public class DivisionRule1 { Function testFunc; testFunc = new Multiplication(root, a, b); if (!testFunc.isSolved()) { - return new int[]{i, j}; + return new int[] { i, j }; } } } diff --git a/src/org/warp/picalculator/math/rules/methods/MultiplicationMethod1.java b/src/org/warp/picalculator/math/rules/methods/MultiplicationMethod1.java index 79596c0c..46f25a09 100644 --- a/src/org/warp/picalculator/math/rules/methods/MultiplicationMethod1.java +++ b/src/org/warp/picalculator/math/rules/methods/MultiplicationMethod1.java @@ -11,42 +11,43 @@ import org.warp.picalculator.math.functions.Number; /** * Multiplication method
* Example: X*3*X*2 = 6*X^2 + * * @author Andrea Cavalli * */ public class MultiplicationMethod1 { public static boolean compare(Function f) { - return ((Multiplication)f).getVariable1().isSolved() && ((Multiplication)f).getVariable2().isSolved() && !(((Multiplication)f).getVariable1() instanceof Number && ((Multiplication)f).getVariable2() instanceof Number) && getFirstWorkingMultiplicationCouple(getMultiplicationElements(f)) != null; + return ((Multiplication) f).getVariable1().isSolved() && ((Multiplication) f).getVariable2().isSolved() && !(((Multiplication) f).getVariable1() instanceof Number && ((Multiplication) f).getVariable2() instanceof Number) && getFirstWorkingMultiplicationCouple(getMultiplicationElements(f)) != null; } public static ArrayList execute(Function f) throws Error { Function result; - Calculator root = f.getRoot(); - ArrayList elements = getMultiplicationElements(f); - int[] workingElementCouple = getFirstWorkingMultiplicationCouple(elements); - Function elem1 = elements.get(workingElementCouple[0]); - Function elem2 = elements.get(workingElementCouple[1]); - + final Calculator root = f.getRoot(); + final ArrayList elements = getMultiplicationElements(f); + final int[] workingElementCouple = getFirstWorkingMultiplicationCouple(elements); + final Function elem1 = elements.get(workingElementCouple[0]); + final Function elem2 = elements.get(workingElementCouple[1]); + final int size = elements.size(); Function prec = new Multiplication(root, elem1, elem2); - for (int i = size-1; i >= 0; i--) { + for (int i = size - 1; i >= 0; i--) { if (i != workingElementCouple[0] & i != workingElementCouple[1]) { - Function a = prec; - Function b = elements.get(i); + final Function a = prec; + final Function b = elements.get(i); prec = new Multiplication(root, a, b); } } - + result = prec; - - ArrayList results = new ArrayList<>(); + + final ArrayList results = new ArrayList<>(); results.add(result); return results; } - + private static ArrayList getMultiplicationElements(Function mult) { - ArrayList elements = new ArrayList<>(); + final ArrayList elements = new ArrayList<>(); while (mult instanceof Multiplication) { elements.add(((Multiplication) mult).getVariable1()); mult = ((Multiplication) mult).getVariable2(); @@ -54,7 +55,7 @@ public class MultiplicationMethod1 { elements.add(mult); return elements; } - + private static int[] getFirstWorkingMultiplicationCouple(ArrayList elements) { final int size = elements.size(); Function a; @@ -65,7 +66,7 @@ public class MultiplicationMethod1 { if (elements.size() == 2) { return null; } - Calculator root = elements.get(0).getRoot(); + final Calculator root = elements.get(0).getRoot(); for (int i = 0; i < size; i++) { a = elements.get(i); for (int j = 0; j < size; j++) { @@ -74,7 +75,7 @@ public class MultiplicationMethod1 { Function testFunc; testFunc = new Multiplication(root, a, b); if (!testFunc.isSolved()) { - return new int[]{i, j}; + return new int[] { i, j }; } } } diff --git a/src/org/warp/picalculator/math/rules/methods/SumMethod1.java b/src/org/warp/picalculator/math/rules/methods/SumMethod1.java index 6f5466a4..4999ac61 100644 --- a/src/org/warp/picalculator/math/rules/methods/SumMethod1.java +++ b/src/org/warp/picalculator/math/rules/methods/SumMethod1.java @@ -15,52 +15,53 @@ import org.warp.picalculator.math.functions.Sum; /** * Sum method
* 13+sqrt(2)+5X+1 = 14+sqrt(2)+5X + * * @author Andrea Cavalli * */ public class SumMethod1 { public static boolean compare(Function f) { - Calculator root = f.getRoot(); - return (f instanceof Sum || f instanceof Subtraction) && ((FunctionTwoValues)f).getVariable1().isSolved() && ((FunctionTwoValues)f).getVariable2().isSolved() && !(((FunctionTwoValues)f).getVariable1() instanceof Number && ((FunctionTwoValues)f).getVariable2() instanceof Number) && getFirstWorkingSumCouple(root, getSumElements(f)) != null; + final Calculator root = f.getRoot(); + return (f instanceof Sum || f instanceof Subtraction) && ((FunctionTwoValues) f).getVariable1().isSolved() && ((FunctionTwoValues) f).getVariable2().isSolved() && !(((FunctionTwoValues) f).getVariable1() instanceof Number && ((FunctionTwoValues) f).getVariable2() instanceof Number) && getFirstWorkingSumCouple(root, getSumElements(f)) != null; } public static ArrayList execute(Function f) throws Error { Function result; - Calculator root = f.getRoot(); - ArrayList elements = getSumElements(f); - int[] workingElementCouple = getFirstWorkingSumCouple(root, elements); - Function elem1 = elements.get(workingElementCouple[0]); - Function elem2 = elements.get(workingElementCouple[1]); - + final Calculator root = f.getRoot(); + final ArrayList elements = getSumElements(f); + final int[] workingElementCouple = getFirstWorkingSumCouple(root, elements); + final Function elem1 = elements.get(workingElementCouple[0]); + final Function elem2 = elements.get(workingElementCouple[1]); + final int size = elements.size(); Function prec = new Sum(root, elem1, elem2); - for (int i = size-1; i >= 0; i--) { + for (int i = size - 1; i >= 0; i--) { if (i != workingElementCouple[0] & i != workingElementCouple[1]) { - Function a = prec; - Function b = elements.get(i); + final Function a = prec; + final Function b = elements.get(i); if (b instanceof Negative) { - prec = new Subtraction(root, a, ((Negative)b).getVariable()); - ((FunctionTwoValues)prec).getVariable2(); + prec = new Subtraction(root, a, ((Negative) b).getVariable()); + ((FunctionTwoValues) prec).getVariable2(); } else if (b instanceof Number && ((Number) b).getTerm().compareTo(BigDecimal.ZERO) < 0) { - prec = new Subtraction(root, a, ((Number)b).multiply(new Number(root, -1))); - ((FunctionTwoValues)prec).getVariable2(); + prec = new Subtraction(root, a, ((Number) b).multiply(new Number(root, -1))); + ((FunctionTwoValues) prec).getVariable2(); } else { prec = new Sum(root, a, b); } } } - + result = prec; - - ArrayList results = new ArrayList<>(); + + final ArrayList results = new ArrayList<>(); results.add(result); return results; } - + private static ArrayList getSumElements(Function sum) { - Calculator root = sum.getRoot(); - ArrayList elements = new ArrayList<>(); + final Calculator root = sum.getRoot(); + final ArrayList elements = new ArrayList<>(); while (sum instanceof Sum || sum instanceof Subtraction) { if (sum instanceof Sum) { elements.add(((FunctionTwoValues) sum).getVariable2()); @@ -72,7 +73,7 @@ public class SumMethod1 { elements.add(sum); return elements; } - + private static int[] getFirstWorkingSumCouple(Calculator root, ArrayList elements) { final int size = elements.size(); Function a; @@ -87,18 +88,18 @@ public class SumMethod1 { if (i != j) { Function testFunc; if (b instanceof Negative) { - testFunc = new Subtraction(root, a, ((Negative)b).getVariable()); + testFunc = new Subtraction(root, a, ((Negative) b).getVariable()); } else if (b instanceof Number && ((Number) b).getTerm().compareTo(BigDecimal.ZERO) < 0) { - testFunc = new Subtraction(root, a, ((Number)b).multiply(new Number(root, -1))); + testFunc = new Subtraction(root, a, ((Number) b).multiply(new Number(root, -1))); } else if (a instanceof Negative) { - testFunc = new Subtraction(root, b, ((Negative)a).getVariable()); + testFunc = new Subtraction(root, b, ((Negative) a).getVariable()); } else if (a instanceof Number && ((Number) a).getTerm().compareTo(BigDecimal.ZERO) < 0) { - testFunc = new Subtraction(root, b, ((Number)a).multiply(new Number(root, -1))); + testFunc = new Subtraction(root, b, ((Number) a).multiply(new Number(root, -1))); } else { testFunc = new Sum(root, a, b); } if (!testFunc.isSolved()) { - return new int[]{i, j}; + return new int[] { i, j }; } } } diff --git a/test.png b/test.png deleted file mode 100644 index 703116f83f2fb7f059220f693949cf93511913d5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 200550 zcmZ6yWmsFm7A}kxic?&IyBBwNEmGWyYmwk?#S6tXKq(FdiWA%k?(PsYSaFJ7&OP5f zKfd+j&AZ=BCeN%r&&=9uuZhu6SHMIgMT3Kb!&Fj~)q;aV1j4}~xV%SvQ&9QwXx;=k z4b{(bXz!3;|F5M)vb}xcD5!mxr=N&nR#%|~E{Tt4X=P7v8 zy^*<6nm7EPO&?V1(qq3}PE8Rf6qOJ%GQaUe=Kpjx`RDr^YPKcvGZ{#a8sk5gmw*u1}zj9z_`@cPF zwYB`W&Eg)cHpc#qkH%Uxt>^z&tYoBg)%wqGqhnk?>ngg${eS=U!&U9;SM87QPzNES zyr1N2yd;v4bl;l&E;mTf<$WWUW}CD zxuH!P=c&K-|Es*=`HwdJg04m4=u?+60{#Dt?tjKLeD%gr%AroB1OF5Mf8^ZfKMs5| z|Mpd;!X@{a|BUXqK;Oa6;z`l2xX^#AgSES9B(5@dtm$rgMfUXC~MqWM1)=708` z#ORIxd;a%dg9;I21xCQx|8%M6M){I3Zo4Wo2k>FAOB2AQ3~ z!BN2}$x40p0X5{R*^wEv-o2B~HY|&e87_&?`KG}SzLrjA|H!i47cz#aUxs$AiN)QK zh|As@vqn%fKt|@DYNKD!O{04|mf^a0 z`cd=%^e@>;Bny0g)L?1UWTA31`}!IHI`Cp$Dhw=6Cg-;GB8&GKZD`32SGT>Sazw>9M2Y~*gj+3*e-X!BH z(Pp42!;zIRIePb%)Z(bVD!y2@C4Gas0*ub1NpxBCaS(cOrE`M+aQv4{r|@3R@&4~( ze_$A-2LU?xJ!M$>bF#d#DnIbyR*wtieV`Cf z(l|M2@}Zj^LnnRjNoCN8n}O`fe%^R)`}pI2G}FPPBv#P+D?8Nc0RWZGU6=s5pPrn! z7X9|_J-_$g&do)=BkIb@gdjh#uY$u|mXmj`gU5Cnrh5anLZ!5%cwIkF`r_FV8SuC-_-glUkP8ae zDjZd9YD>vLhEkOcb4wd``yB1p@lLYZ42K{I{!Dx-N6DX6?PP{3n%yM^fk|(Ip#GBpQs#o`br83Hb>nn0KJc1C{*cV>xYW zNV4E};~@s7YZsbDp&u<43OY=kfBRl>Mx}jTwcXqnr$;Qb8WRmgkmj z#_5sOsVZ%?S8oQ4z-Ao+`!30+^!k@AWWbV{p6TZ6DWTLso z;o4kihpOO7u_i!XeI8kEBJv_E4f{rVVrWnU<$Nsypk&L)Ai72GCI?7u1W?KX=zjGT z!PWzf&%;K~C#9Uhy@#kka`2MrL}t3yHBOD5{ta(VX}ljdrH_C$&0RG0U3gxcc9E*3 zBHy@Iw$ALEONNUQ>QI#xlH6BDvsy@ord=3Dz>rgCtmRRY;XfSq&(Nh+f%xJrb^xsI z+hir$+)Yu*sHv8eN;nMy@ZB;)^+bz5+E_uy2|RsiynZwd3Jp=OH||@2@i1`qMsC7GrM=%Xv5Ge@5CoGDs#HlXq&hkamXAz58w1o*{ zAJ)}*GNrAHZT{jlW(ZM?*S?mId{{Nz4`Y5cOmj0NCl~@JS!QY;9_P%NGQi>yY22U* zkF9p3D%ddzFj7(Mj=by;fj0BPfzv(hhKw)Vv!*q7eN{$`jEn|xf>c!#iIuCjm+!g> zS;Iy`Cy@r?P6A6H)Y=ChiL^!s@*<3D%M@1lU_$ z>Zfc_yB8?y&qw7n5s~2J#WahbnN4igrXMg!^mM&ga^3Pe==`SNA!jBAlYpH*d5QB@ zcu=@eC##Px9}Y(5fT?$;v|7bMIVxjW5S@%ycRJvh7L9oE-}0QA_u8$EjU$)K{qPhN zKTz1{LkKt42+nz+#2%+BtURI8I_gO`fKqgG8)m#!d)*|7JfhmuVrKV?j3~P*(9maL zDU8941^EFtRBK)!mcLSchL{5dXZB;bFn^LK&Qr%S1Q|A6tFG~3rgX_B$zN~ zE+2x%X$#Dl?x4gXYbgv&@a(GsA-Zd~^PP19A#30yKtF-K{&J_wP*%%#47`JWoGze6 zRLt75x3KZ{OR+hWO+_i%+ri;!emqAz%$id{x>=Q-KCPJ$x4F6bc|tm2Wz;l(cr7s2 zm_xBnNSz3-!D-f7Wc-ucti6RPosMVLs88aQY^(t{oPSn$4ZOP{5RQ=%!Is8$b=1U} zGv&=wH+}4`1G0jZp9au z&6+yaN|Z)tH4Z~)OaGZNuKJHp`^g%h8$gC*?BG*UYf{xeyHN@7FXRRgm>CDZ+}{54 zGhV536wBsSWoVr0?ikMgrc22Kc+Hnhpiyw6_=jR8gV-xwQYy;*F^)#$r~8r$tABas zr;i-pW8Y`0(l7ve?z+N_nf81&S_&E#w1UDlqNlMU z#!ytpM5fiQViTC%Gnc&Skl8@t zKFm%F{%fXZVI6dgj7CNo;!}KWjh;a1?g@LAl26igNRS)p3&7Qh^^!kEe=Z!bK0~kDXLs zP@gAyk**wHyH8?DBZ+c5L)UYiM$KCLD;GT*4;-O77!)v3IlK%RUXF?RmRq&9Of0nq zN;9^P**RumJbM|O8)ve)Cj{Z>s7A=B2<_2Vk=GK=7Itlju9{{WD9IwSL+}LfZI6>7vMHQ^_)@J}()s&FD&@!41{bJ7XaJndvOmO4&VsWfS3-U0g zp3$xAxs z-X#D63F!y?Vc`PXl4l@nxY&4<$%aHQA1$3#zBE@V@fS3)W5t{@UfjO&# zg?9ikjkG9;jsOI*142OiL{a5v zb$Llsy5ZG)7V-A7T(wXv|V#icy&B;{++#sUcOaw^U zYC3$!W_nLG>*uVoyU;iv((e%qVWZ;J*FD+t6{yuot~g$Fv^AXi6iIe~2u-Aa>t zoR|%j$I9VcGX+TB4ZKnS`|ci-sodc4T5!0wP+5BO;S}TTIjzxK6M^u~{N4_3Em#y4 zfgga&djc*S#{QOELo;c%7J75mctY_Y1E!0fc;$q%ReQ|kF%@;G zJnB8=lpbih5NttH>WC`E*t14DnLL#(sFwA6df{zP9jpx6=hb|RJAVu7#(ZHI7%|<^ zmNyf0lqUL;DaMth-JeEKE~ z|HeT!Q{@paXs_^N1XeNlgP^fINslzsb2b~?Pnpf1uiIE{rJ9%BmsK>W#-i~|z8~_L zK|>LRc+)z5IUGhC2Lsri|5h1AH9L<}_@h&{s_nB#Y`Wpv3KUVff8m6E;WX2LN|O$@ z(aKKf7eNL@(u+?uW~B>J|&>DZA7`*%#lk zVmfhTfXrDBgJ?Ru3~EuBVn5!*& zT5S&JX}k2FK;|uNL06H|IYk8V$d?_ImMgs3nQWsjR7@&t{h-B16Xn-7Ue*jdrJTJn zzb&d1^YLShQDc(n|H@syx*L;fwToZRaKT;C!^xF78dY3VBhl5-)k(bGyNI48hK^l@8&es8C=XAX zxb?o@!kxb3s6CxN=Xgcwdmah8yx5Zx`Q9LcL%0THZFu8OJZn*=duEl)J z&*-M!$x%@#c{`zA7(Jp&x@V}Bk~Dy9)+Tdp_zs*7anpV?U{UMgq47d?hW)Lu5*_0; z59L|OjcYt@I0bIXB!7i~D2gFcOr@cZux{9v^HMhpd^^P*{-2E1@dSozi9gpi!vCtl zN~_)CJW&2Sr=5>UzEL!H_!OYh_a=XP4koutJO*(M5P)1A5$Rf9Gy>_x=~^Z9B06(e z$6B=sxVb104Ah@2luqaTQ~Lj8zh)RJ;|Tsq#TVSI{)Yb-fEG1j<Lv6Df2 z&n3zI$&|7RH{1^?uaY{#qJh8Sy-hpz{C%Z017PqsCTaXdrsja3o`zuKTMf(dlB>ER zhAC6RoKD;QATa9}c}Kny{)H9|MNJ zglZf4W4LTL*PqqCp`WSxFY}zz%T=GtP9)Nq-Aiev_tFURshZ#7-={U@3?#B0Bbek} zoXt-Dbkj$B9jjRo!P*gLWCmXU+9+C9(de`N@FA$=gNl{XE9=HEqviT_W(3ITdod#; z-fstV3#M{7yh9Z+Fq!ZYvH_xTbMv$(aVo#=8L8#3>3XJG3n5d{QkWTy zbA#f@eT9QQc^caS|L)g}j_>pY7E(x*jaMUMb==y%FHa9os>)nR==Kz|n@ekrMZx4? z(|>)VW*hpj?1(kwGEh8#bHuz8h~$<8?njcVZsg+HS%?!c8}||lstpR#Dk{aMa;Tc zRoj`=bR=+31 z3QzB;SGr|cn?f+i_dairWBb+di7`1KDgHvf#ZsJ-A87S0L5_ieVM^q{=+21NB}gDq zhMLMKDg$0H$!LW97v66iKu>t_m#v&n5H8m=46w2_gMj#aZzl()@k|rHfYj*vsy~Vv z8y>NEewp61{&6d=7CpFd@v{LZY0kyJ$t261&4z@m8_DAEC;?}pp(Y7iKy9t*_ffQlYM4TatdSU8q&F1d z$;XDXjiYb`SI0YJV>IkP>hbqWWYBN_SWRt2toDk3B^DOzY-u4@ZAoHvRbf`4zHq$g z8^JYHj@~ByY0kPuIyAz{UfaH|IJ$DSpICg-fN>j^#H%UolI6r0HT+L_XJSTBO&j5Q zB1te_4_x0g_jgkS|4%fYbxVy#N$V?MF`&3rx8QvI^B&H6K8p~IuMv@T+l_1ov4FAe z5-8Bu=YD_ua&I)FLp!+D#*1hAtD6YjXpMRg+Fqm=?nmggsN$6Yqza45o6@W_nBx3V z)Og41+x6)8KlO;6BB`o_bvPeK%Bg^U zp;lXr&yF<;K{OaIb2(doP))MzNS4yNTJqn#Plq$*lGIl6t{%)4(R&8>#0y~v(QnJE ze{Y3Zo1%j$8Z*2nYcq0K+=x}Ua$L%?d$`jF!WEHDicch~8GTiu(xu`n{tsEq>$4)K zn?(7qFSAcO=w~dePIt!?H6&9f)}897)~sA~?(`>BZd4h3A03l5tg^fL=a6r{Kd?DJ zIffKt)U0(lHqcE^HE5Sx8jYBYYLWgbxI}@M5n^%YjpLpXW#~cxCv}Go+Q$<9yi1#m z@>utqsYATwrmVYW!MsaTkWgxjuO;li>oHaLwu_a;SCC{Jd1V1Q_}R162YeMu8Mdm| zt0|9ODfF+*%Z-V_d_V4U_8Lqg1a$F~e*b$S%iP$}eEV2>uvx}}OLNk4sJT<#U>7n_ zd#1*2UD$rt8gb9}iOUkT?%;}#*+1Giy-W_#sH<2*7u6Hr#}DR@Tk`2WtMvi?yCghv zM714VGkW$3b|KrM-|!S#cmS22_#kG`Cs|>2NMzLbh2M70Hhucy(xY;S5S?-=)G* zvV@$5&UCtnyYA>8>6J&poz_&$f)A)9~s;3b3Ww?Ub2-F&y8 z7(ih7Z8Eju#XE(Y?-mnhv?;75!lz<0rqa~V2`P3)_i=6<4H%I^)%@SPKrG`j9{LIxPpj(q=$o3ammBvLRy$& zzP)cuAKJi`{Ot!gzpMl8*9G_QYrn^?Yk)U#ql%&r3zBf~N({(6b#(PFx5`}hnYW84 zDLmQpx^;!oyAhA77#TI5s)3SzUA2OyF}lRz+$R%L;`+6~i&dtYizjNo+XNQwg8$hE zKO?sxWmW#Z`coZjYiq2Jy_wZT8#CeSjM2sdxe z43VY|uq7~Ul_jbJqwS}*X&!#Ny5$i&K9*yrNY3yeyaUP^9g}huBrbu87FaRuPQ8fk z$va*57Gjm;Q#TLQjJ1Xf`Xry6SX=$&cd&4HFBG0|ii@OL4~g}eDyzgLe+-f9k1UDM z``#A0kUXWSWC4cwF=zGWl47ZlWVd?y_&COPU4YD)x`J{G-F#C7<6{9&wV9T;+*B|Q zm8{`p4>ny~?&V`qyjEWpSDdj)o`1@%+tL#wzldLPfrf4q(j5Mr9aasGe^5?>Sb2e%w5CvnED-y5F*R(#~1lF+Bh#pgCfty5@>_IJTL?D&BT-Fvx zct`1^Dpb;gKfkqcYl4Ed`s=u&Z=mJ#!)o&tOdzu{)rw5Wf%#}iKF)9?Ai8-(5~tL2 zO6yoK9*)8!+?ILU%xNiI%Qi#rF5`UV^gQS&JMXx%`Tcjp8_p>~X#r5!%S^3w)68&1 z7Jn#uQ|_lEIN8ti(sji85BU-Tr+e-8oNlKmVue|SB+uCa)L+%jP-$#wN-0XSYONl( z{#;mMUeAz^70>n)Vda<+VVyT*Xn|t9{UG3U>{>w&b)p#Qim<~1B6t{WNBDYe~)_7A(Pi< zWE+Ox>0l=HIUj;HlyH8~Onr`ZJSSsK(0jU_m~Y%ms-BU?`bj3Ku4CVUaYFwrjw8(z zXwlgof#InNKn!$UQjt{0(Nec0AyA&({a5Y4J8hcY=lZuo&^LZ%^t7bxyAjE#omy%f zc}w1wZiPop@I9G$VlWwxBU1W|TYRO&7s@FFl2qLPR|{Z*To&{A2x9=&y`^$Tq(2Kt z>pLS&M$Zb4li=c4=nmoVmFs=}`^$MwU_Bi-NKBI}g+aS3NL2Lc9+sN+yAbk}1Bq`) z0IAJ!k{ji4293A=l`RXr1`&*qtzI$Y|&&#jN* z(0^h%?B6E_W+@z1@}U6T$-H*y2z#s;-T9;xFA_N3_h%Z6HKl|~=Itx#3h-}Wt_9>9 zk5jn?VUvGRG9H}SHK#AQ$B150J$gn^vL>u9S#W~d38FCI5>&VEWL-=@4d3Q<@EZ)` zazyZQ>*0AK7KL_l{;ah^REsVviZ{e+ey354hrdpz2zfV->gyyCnj#o*i<}hhLL!?` zNX0bQs}ISd4U(4UEb{Vk1Ffn&FYU4ic%=8b5F`wI$09uYGH~ZnPr-kURf%h-1sgah z@oxG`GFqkbj=TY+?g4|exEr_r70?&3&>h5$DsE_Auvy^#yqmW(p%b}wFo~_I=0P3x zoF@H?fsERL*$sm#0A=+$q{@Uy7BDaDm~H71q) zVnG5x$tL|=R2pDcEofMkd3Tr%V5VlSLQpVFry(SX0m6H4I7(!?e6baRhqWpdXHQOZ zx7e0TsMDHVeMFJVLLqmCw(6EWdQ@j&C)EkhQHpLbu*;N?0l2yZxd9@D7~CzC+}Kfo zYZs_|q$N2J1DQtsL2#M7zfu97nO_8UGl*o=h_a+UN|?N7@$eh1xg3YLl?T0YjR1oU znqEgVfG-{AmY`o3Q=^=~%~_fiVA}J{%aVK1u2%{kv3lIwd0AbBy~fmQ>bodkGRvKj ztp07fp9%#T(waIjTg#j(ddwo)0Zu#in?Ar0aC(Mw5ruzgPZVx9uvw#+YT1433xYWY zQ@I5TCbe}NnL3FnPzxNg!g5>4>mgJg=ZKivRm$m2i4zPR;G#P0Eq#qsfcr7yQO!T9$* zsnT~gGnsac*`90=YA0*qYpe?-=uTYlv-!K9DvQEo*_mEc3IfS^YRZWq1)2p#Jn2J0 z8~>j%nXy)7>_>}QOe<}wx9F2Ll1fHE06+t4qmqFc`yrf>g z+!}G?Z#N$adL22~|C-5Y+L^BjE)|Enc*9Z!(Oa-^N*(00&Ks*7sUWLw=|Eyqm+z%r zb$6r$LN#h@UAdAZ1jF=M%e3G34%?1C^s7OJ)A!hi-Q-)cEmn1`pEtVVjN{~- zde%zS@0aT@vWG!bsf3gWXnz*M*jMyWUCmMOC2ds4)EY=x#Z}Fm5rM8zLVnG8J~tyf zo593*jq0|ReKBjK7kfv=~=SlqoO8WMXC6)Bil47K-i?rc2_n0oo=xaSwP= zjO5m=?@VAt4;jdyexZ|MC!H=X%`79(!wbJwDjGn0gL~NtwD`WP*jOM*dwy!PS#;2S zRmIP?kyBb-2h$`2F;oGgT+(S?HlgY1tjCFuY~Cc}9vFXdCpe(#y~_$qV{oXS0G*x#eV6Fqe*(ey_mHA}nQpouMQ z5+1_2zpOm4_+htRU5N2U%4&V%BIE-r``;OAMX*@68q$cQ1deY_-(G-MtcoCli%Psb z*au^1S1u5a9c=8WrksbgdI0SUC!5HJHetn1{FPs{##OUjBf?b@siUTzJ#sb;YftI% z#yQ{beOAMnGo3^@*2Jvd`X0YlsGz=bh&y}2+0xxVHeV?{3@~=075MN)Ed4A^Uw`M} z$5m2gqU~h=&+}!T{N(H`1EbMtJ>npvw0reC^*}r39@W^@kToR!LRrZ>QD^8#>cy8u7WZ{MiRR#- z`C?ftywWd3{{Ie{u!HBM;&&m#CFQEkmIfcSqu1gG(4?EYA{`_7{KW*=_x_dMuapje z9@c(!fGF!S%%VZM9#S{a4lB}wp9K%Tx|11nTJ^rDr>6H@9X-`2#Jk$`Ey4lkUD7*= z!6Vt6G>wRk#jY*jLrJUvTNOw1Rw$pBH#~4@X6@TjwK0t~t>(>RINOKg0wV-hmm{;+ zAfglN@e%!(pFZ3R``T|y#|zPVG_Bz+?iNqd>>QWUJm@VHd9G4D8e^|O=CWi9rE|a# zDy;&@Rx8#~HdRyjcTCTnD8-yUKDZhSzX&GO&wOgKX%luByE!vuoC3WT;yjJ?~S)E;Z%j2^tp!D`KHRH>|m?^$-XV=rl#=oJy5*y5Fs0yLX zgRs|&NbAh;`xLk4V$TNkzNS>sUcBIsyqb>PCfHO%xX2u!RiaV_`2eZON1mrR34i~> zL>07D!DvW`&{PW&_X5e6i8(>~e9nhEsY)gw9Qlfh?%xtwgY?U0W9y(!t?^;qNAIl* zb~O{>`V6-0HVr5e(P#HNeH>e_+!p76JBXDnZTHOU?BmboxR-4=>6idJeBj^4SL1&c zP?n%Q>rP(Uok+5}LrG_b=%UlApIJ!dDPc4?&0ufC3giJTg3`P%wUcIlFMNFog4_Q! zcfI7RqpT6?fk9UoI798CXPmWmr7^dXc#J^S;dXQ(i8e}Qmtk3TEp8*>NjkI)v_QFZ z0s)}IN(`vzx*3bpw^q$*g)DxfZoy|H=lE_&st>FAm+}LdPs^g~M@>!ieCLI@=`ep^ zIdKT6_|w+VoOC3qmXY6V_C>o#xQ$X1pg&jq3B7FX^%E864OB^><=AQ+l&^Z3c#Sgh-H5yE_r^0o|V|rSPZ9s~_Iyv;FaFrk$2S zb5gqW$z&|ci4KfvH)S@0(z#5CoBwbVZ0XIxTNpK%-8@d*rID8s>-)Kr1aG%mX*4d8 zRzbb&Y|}mJtNISZ#&YN17x`A?epH?~M;J_RA<{Pcd%_;BtNF`8qkAHcqYKzozdzos zXG@hJ5j`sZL6!`xjDw<^9>^P0*KFG_)@c)Xj-SeIm#?i?-Y=$GXjNg@ak=>V(1U}g zm2J&tUq0@OtQgy@U9$B0l6*!wG?t`I*LPT+Z0J=6%BN(F%E1bgiZy1xaf9`%ZlDik zV09Sky8YnrqG9yz*2)X%z43JM$YutC#r?FIYeG&f8I3Y3;+liIo+WtL{Fxt2yEcwm zlko1pkwzM$Tga-hFZ_8du~{D7AZTw$zxcOixfj||7!~~R`1;%xTmTU&NG#l7{Dj6; z6RK&Pn}87((x6u=!?L}r=D>Vf*HUY-Mn9A3<%hzC5g?j7Ur6ZSA(+Y_UCaK^l)rkJVjff|%2BtM4^LlLwf>C*1-p+HG3V_$ zeW}eE&bFsPK2movspJK2g%S;XSbAzf%@qK>(n>0KvjpR6LldJ`{%^+2wP+AAdo|f` z)dNMQ{(mgCTGW3HT1dZ(I#y%SFm8kNt7;j|Gw52ByAXwh^CvASoRpi9Bvlnot>Xw# zE1c+xmz7Aqb8_j~i;VreGOlc32I8ztrRa|Jf)2BD!+b`8x-n=QWdx&g9nzt5NaLOp z@y5JKtjAf)Rh1^^KB=-lRGhb%JT8VY;Qf!pvJ8S(#n-xO2N*;J8f>)ZS{Xd`|Na0G zZkN_4hUeEYsjxgjF3O20@;U%WJf-BB3Il4qNSiR5*(fer6Iqug;qi;xP$W*&F?~WVIkQwNa@aKX z``imvZxW|{f$`lRp)LP-E(Pe$nz>Mb)XcEwhat*f5D4^ikOBiv=AreM(oek}>f1Oo z*RmxL87n&4Yf<4OHV_UUu4a;;ZlZ#<2*lpEP@Q&YORnhH79O>>1>7<{4%$@B}{>fLML6RK#e6#8GqRLRpU2?Hsn`CPRRn3~4jW>_P5nj5K@FU!jHk6V z7_k=>zVT7q9=qB0A;rgO15TX=X!)uK)ic{`N+bP{{3ml5;IGXN(r;|27tX2fc4-`A}f|V>(BoW}MrAlIyce!13G5746-J z9$YDk4{xO*gGVPCf;OCZ>Uvp~8p;=4o1A-y;gG8H9EiF6K-ks8oxZ6X_1khH;wa$w zBn@rYA^JCBzH|2J{ZBWFx$PscCd5E2Jz-Mb#T1L%MX8i+C|3c!KRkwUu}khy)qgnC zGDlm9ExmAh9mz){cCBf0=pPF?L`Xrr?_B&N=eaiDqNaQB^W&ztP80*rV|X?uh>aGQ zUE(jw0j=Yv8j7wb>-1sn39r}Qaz-Lag1LMR6i`_jJ^AY$Wn>~dal{&jYaCpW_v{R- zAYv;{NC)1sZMlw9WF)YPb_LT{5gpApEsAPLt=G{hw+l-_FIwss>i_%*=?IwWEs&Hm zNU=uT^8a}!-A%)^Uccy%O(Ci_qyF}Ur+6XE78GW!#)Dn%xBWK12VX`g4aTdUxpQ1- z9m8i00qI()_a{48YWWS@43Zo!expxc_!|U(aBnA5;x)hlKM3XgWFXt7nC$yAf=y2T z_6hje`L*5ye&g7LjCaW zM@x|}G`PNr6y?BS4JQ5;B7#hRxsE+ZA4#Qb@Flynw}d88QbCV7A3LlV1b6i?S=2kj z*rJ1yIXk7VTUCULsIJ=H%R^*xbr~{{pqy@!lJ!tKFe=pp4~j8HaMvIN`h-V-8ejWZ zvhi@Q^}=LrAOz~BozUUOs*DUYnYU8FFU;CwT4>Lo_t{jAjHhR0`0s)rTv>He{#bS` zvtrQ@Y0+1aB$U-XNzZlbkm6F9U_!+Zq0*5b!g6SnP8aPsS95a8+-myN@ZnP4>J02> zwM=UmQ;dv$IxjMMR&v`;FTicsIr19A7Y^DQqf=%m>x1Tu68S=u7QCt@?qu6>(Wf!BI!pDQtL3Z9oetkAZF3cvkK+LO0 z0Sf8p7SE%W!UfoP03-qwsU5h7Q=h>p`}0!?{-u6(*#aH&=ed5u`V7Hp_~^JV@7ADI zv(yOnsTr>gU9Ufy|8xewz8wEx+z2sxE9*-Vh%r)bm1u-aTzFDNc@L|nlFYPFNJLaS zL8WO|I;0g1(oulFWOkkWmp`cKDbdz%VuMk|$b@hcr4F6hCY+v$P8~T& zXhSTy*3b7jF0)u3^pbca#KQ%RWBzcq`@#bq9V;sr^r+mwA$;V~I@+OMZ^-B`_HeW! zVB5QKp`17D0jT7+pQY}+06a_GGK#;et4(A<46ZI+i%_W)W;28CtZYVg3@z=5fy!zw zS&%FNDqw}0u^PTZcH<+Q$~GZzB5m3P5)q4_KcbRe-0)Ml9j=wH1yGH|DHeWy#i_W5_8R=j#)E!k9ldoQtb z@bm4Ri_7G0vA}D^1>M^*g&o}zo{q9&sNS3+R9Kffz*Q3(0&caZMM+C2v6rW^b^hmO zqh22Z>WxM}D%1_jFG;b?aVsls#}R6&XY;+sk*FuWgU}9QXIDZ_=wsJKHRV}zD^Mo* z(%s!(i~85eXh!6nsrOQZ4``cPx`>;}OODvh zOo?EkV+{PCcr=(ebAlXAFtY!V23Vsu{P8C}?~r^-!d5sDhih7gs6sU@A8E(nS+! z@ajx#Bm7%d{Rg(;hzauD!n|t7TnP1Pw=x>3x?RxSwsVBh_zUF_{u(Me zf9JoPCzc?bh!>5c$Um20%BX06Kf%DR$nZiDng(|ALW$3DXC`hSZAOf)wHaXXseZge`T{*gQ(yyJ69M*2iMV zuwvF2DlSTl<=_kh7TccYSSW}P@?Cx+#oCPOpiW`9D34$=Nl1s5=TWrH_wkXn@Yr1t zZed`pLqTTDL_+vS%VSI(;VP*)Tdr8T0HFy)GnZ`g@BJ~rAN(#;%_po_i; zD!h3=l!b&LG$pk2VO!#!xgALXm-*=li`pN;X3gx$X62-^yb%UhaRF5_hanWV=?IPi zHZPCIOpyT)Yi#VcZQ+Ei%D-BIOQWZVGU?!2t5dyfQ`X4Xq*@J>`V8}N2r|M&czG4@ z$0_0ADTDtFo9_B01MohR5Lcwc34SBRWG1Z`9 zIz!`LO4yY?Plr12n(ovY?g^F*Z+X@BPofDt?rCqkd`tUD;t2R{cGcpG6(-^Ribk03 zKst}6VO;!`p{jy9%7X6nmD&{_%=jr`qB$c_0ej}F1eMqbpfj|k1`rSOrIJdf5Xz`Avd6Dq*l=EqVm!|(FrHzFV06pWjtZZ9 zJ9#(ao>A;UMHHvAZ4e+BvbH<4QMM!L+>|&kU!(z*wI658+U$G=#G%qArW_hj7%1=o zjMxOcK2-+0A1odF2SY z>z}X%kP>M3aNg})5ek@967A{n^-b_w`v`o$4rW0)-yIggXib6~y%m|uydCT5AnAbB zrAn+o#C(CkgpRe=&p!FmQ0G8FhFNE5`-ZawZBw2z!)WLH&Nu!32LUZsz;ySz*u~G5 zo|~{EyyfUE8$?Wt4%Ww4Papq|IYo<7I=CTHMp*o>NCOqGz2_L31HLA3@AUH)&A66u z(k^=kZ6cW(Xk8}VD$41Pgr^tb`(1lM-(=1i$sf|Tggs*4a7yI4e3=ppdjOR~r`Y<+ zj6ir^+5S*~c=-=XiM)Vf+pka?+qN&9>&lFdMRk)gZO>vZkrWXi@n`^&`%Zs_JC~lX z3t!G6ii1;3K*)~*5V0G_-v`LL+09{w%gQbAl+9nMKcX_D+NAPxE?N}pq4|Kzs@6`e zm@N(CQLA;);>gc75r5Rai@k;2ajLB9%R!NvIhhQe}r z&C_Qh*4~~NTpeMLyLSK~{S90(%IN2#ZSG3!+fnu zId3OHXLTg8GL6Y{AlW4OT71mYX3I>86 zAJ0qww!re6p$&*a`c5UK*39F%$hVQY0>I?YyNn#t4K%EEYHR&%g~3?6eQ*v#NCHMN z^^>%nIN(RCtkfWQ|K+<>B!`a*t14adFUI68p)`koQnj_UHMb_>0T67NYKA&?cxi>3 zEy)z+d8g=xXzjy4*fErmMM*Qu5YILPkuLlH1L8m(za0bOIUhMe7{7$g%U*bAl%*U% zj@rv%;11uufA2)@)~#a)a?#`QY0t4y-#rj_9(~)s9@&vv9qjc|Tg~w6us5BK(o_aV z4t`C!x*|yONqNpcX4Y#L!aa_w?A2U0@_>8TQ`WztFXdJW*Ox{Z^@6YY6pQEaUoEDNr@!%lNuaLX! zpd7lro7dhXFFcaeS3bcGt0^xcM=d3e5mR-zoSexM>!f-oa(1`Z=yk?<0uJPocJ?Ic zc*l`Hp$Btf*_{CZ03ZNKL_t(=dX$m2l8Ib!{`r1|WJ6~nmw_ja!~&T`coj;f{fBRF zKVOc0ynJ~WIfRa2#YF*2InNdD`~CIxA>>qXV_<042H~G*O*{b>{y8jjt63{Z&FjON zlCzL=_E?TWZmk*=0XWd@e%y@dz5=<*veir32TMt?VRIC6qG%$A*-JzY2b$!nDU`~r z6_pu1etM|Jk;6l-N+XdgM56`!BZ{0-Q#vl>1ne`mR8ACFYu9*Rm_F`1ETx;bAAdZ_ zK6x?#-J$)pls8z%3(Fr&-h`+in#lEqe)e#ykZvdIEjAr{N5$~0+%X`Y%1&IveYsW%?^HeTa>OX#b z6JpcH{ZfesSVM`Fvyih3->pfoX(c>7d=zrDXUjw`=i$h)d3no0A#Eb3gm5FA6FKb5 z4BF7y$fdi0T%qegjz@wH5~4_lecxJW$2ql?i@=F-;IY(Z+bk3^0fj^G1$3|*6>5Rz;?ehhZ9$dGGE8r+mm z-}pNc_ggOzGcBdnVq!d*oGi@DjC%`sTC_I`3McBCoivbLzEU!VkyH6$*Q1atYErqr z+dGdp_J^f2?Fxd)Tb<3+qeld!1F%8?9oz;3&Ou#*r%p`&x0X^yA*W;(^09R3PYOkj z%8gS((V`Lb|Va zyMsyxmhz)1aqpLxKHS1c@M9_Sp?%l|a6hnx<446x1 zOqc$mXlPPVA`wk$&@p)raisH&{{zpgIRtz-r5u4=XXNx{&%~2e-JxCA zA350>9xnm*@*<@hjoiBhQ^dq5wUo!k*zx4!KFwYdmeFwA%TdTxmg8m&cX{$YAeYNk zM=6;eCXwhxhQg(F(u9qz6r`{h_y0*pJ(o)8=U5Z?G`r7-Y_qjKJ{3*o_78kz%{u{D1Jq5@qh};pe zfGebfyzo8mN}3EKH;TA9GBL6I-SmVVrhR+eiOz_1p}lk?2fmeVsY_I^;%ap4&EE->U;Jy0tRFFsT_Rq{R9 zOZFO?7m16ChT&_54^;J;7^)vgcoyp2g>SyeQ%l(z*a>$)sHLQPu=~Prvs2A*P4Q8O zkn<=bePswOCC!e)Kig|G8fP34XOhQu`QR4vB(IDo&7;PXc_57cWNGW*H{!6DJX^^^ zF0My5a%mykoh=}8*{Q=nRhE{?o9BN_)3e26sqZr-|C`&XDV!A=Xe(LSwv>Jr7|xHd zly2l!M-cZ&+}J5yCL0@xgvrsp>kPUfS81&a?Bzx*@8~|6=w>O;iTLvSia*FLrFRmM zd)0m1hpT#e3WEjPUY>!RZ7FxAsG5yJ4nD__yFqt)bL6~JUc!;H8X`^Pj4}i$V`{Nn zHjx9bx|FhqfC*IPve|UE&-_`x`|`wr98%{%E=q{kVJw9YRse@g6;9f2OPSV5w~!6q z{egJk)@r~6S?K3kMur1Kuic$lP*v>JR_OSKRG%1@Z+pzl(A(CF5}m&Han1t zj^LA0Q&_o#%ke-GU%aS4>okmV1K?~2^6mO=2q8Pr+*?l%TGUcLeg(f!O;vk?$nm3A zYX;Uc6|1Sxf!wIplaQhDS$uUmpYOE1A*ttubQXCGGHc7&y>{!@U;lXXM{cI_h9Q>>;CPhz=Wk2dY$mJd=60-;3|dNF z78qeEUC3!0gQJ({=I&4U=H>u7e1FG;?$N#Ey^*fcegME;4(|pxmwS%o+{6Y`Iq;4o zI*9^TFpMz+kTb@{XvQ)gB(L1|lJ!6O*(LAc^2aTur@zV#^In~O;zEuuxb(6a^5NF8L*=IJME@{y zCu!~U0esp6pk?spEd0}+w8LIfjmcI&%$T5Y_l>D1Md!?+Yr@1W{Ns{LH5vG^nQw^fv3g1B#i!$5oakW8?JHC=&$k@_2_^#{B5!LI{Hu zmDlNLTHH34>JW0Oq#e{Zsio{O;8=TfsMzBqxwhnRZ<#dZ&IXRDUmAo>=d(kdCj^+x zS;WmVOX)-oEG46;KmyroAFutf_3N*{dJ>6*On;0(X$^>*Uwj_Sq`S7IluQ2k5p_7m z8LgwcGnRuj0-ymimK?dcxp$Ufyng)*SLsl?Gwr2Y<;;}`mioxsWa07g7)o4sENzUL zMS`5*g(rBL+sk;4jYkQV41*^pb6nuSGgvX(DCFiMk^2<6rB93hedVD?0OZg;Y9fv0 zMk0qP1s8I-<1|=ZuJD?937ed==>nm^P4;c%g2Etj!XaScLe3jK6S;n^ytjwQDI}G7 zPmwDvXG-0IteEx^ko%KmDf_0Sr0W{#JCV!koyLJd^$PyK)3Ve4xM`KdR02M|5YqN^8Zqy&P&p8M!NbRpgd3JI0ZleD&CCAqPs=r}i?(?IrV)%iq1N@*XX# z@O>U~_mQ|)47rEv>-+z>krOys6uE>*Mj%J`dKZgQ%|Z@K2_C+$&R=EYsSADl1tz1U zG;JXlA2@kOR!Da1c z>4h)hMSFR4n6WM8tZ6Afe!TpP?mh8{B#HwwyInyCH)?=DnaDk8@wp{+91L{uqV<9m zxxpX8+h-b%cU6nKb*X3)$G*9-a^=4cfB(lPpLn2Op4J_kb3&mZh0}Q$7BE!)s#TO^ z&4B1E*^u;*=4w4D8s>Os&^c>r%1TGX^XbfgCN%Q0OImM}&OhiS^#J=>#Gyq9->?IM z^xO$Y4jU>9A54xuWUqa{?5Vhr6TV*#E^_3KtfUF4@S!QgmeSsbu;@gtsA}Sl*?xi@ z%q@0Mqg4=hAU7fHUW6Pkjwg=aCCJ7F$gL)9OKBnpmv5RPhhyNYroH^tw3m#$H*dI| zq*7P%PEC!Uha9ZP95a^F57!?quK#yVpeaR$oTzED(GkeeCtNjnSBb!TEJ0cQI6H-O z8FIqpV~99Y%MRq|YeC6{Tr}Igw6%3O&DK>Mf3lTM@eInslDE+2meMG*L-7!~Y#JWV zv<%3>-=UiH;@RiV5uXC~@`Ud!@QzO(+Q5Ark7gkbB-tngEEwOzOZJZiji*2w;1Ev@ zM+;Z4_sl~lJa3}PQRGgso2sE6)NJH-wMJvRTw468z4ebpVi?mpan7p>#Ria5REv** zGA5bVST95$u0Xx)M2=d@o@FVmL42Box7t&V2OCn(dF2n-A}5o<(}XE=bV%%T+fs7m zYBYv3m%RLbIjvLV{xFe~mtWnC`e*iMX689^;6MEKBff4_CLw6G+so`>ATM0Ao_$^zw$t6X6$i|G^pawd~m zrsIEd(_Uxx(uG`(0v9diL^pEoy4?LpWR4lj+{5+MLqrbYQ7q(s{`n+&26C*$GFwZS zZOv#eXR1V@$aTHZ$-YopE&|r(N0+v46$I~z(^8hYCqFXez*in0OBBZ(CdVr}h8-=_j}@4-8p#Z?xZTs@q z%oZo@6nDCUr1Amj47rX`X5*c?r7WA4lKM{Bo?LK#CdGM0=5^avDkF&FCr~Y0di3cx zj$GFP+-!E?eJMQ)$bJ0d&3~B4B?H;$<5%$+5ITmOBFylKLT6gaT<+n+#bM-%k}gk7 zkZWWDBC&Ua`IH?eaxY%IINiJey4}z_KyKkUGlZO@`(#yTtzBR#Z#t3dj=h?E+%JJn z8Hi{`-rmGcm1_X!xwSIk)c_HccPA}5gCZ}7s#kxQg! zPu$2Uh9n)B#Np=vInf&9fUR5T#ARiLlh1>dQ7+Th5UtIi5vjRa;dea#na{v;v?AD4|?>3};?uzIaBn7vQ@x*P*# z8bHqNEOr0x-nOlCY?@qN)=szaJaOwxf;_d9yVO$JNfWS?8dys1ISq$>9d*eiM|~7S z%+%rBi5t0`$;Fl2{tP>aKIiTtSy&KG0J;4)Z=PE!mrTA4kkb3xZ)S37ZYkMhljpbp zYb0*jL&j3pYuH^vK29Sd8{jc1bnMN4?yY8C2qH^Z5+RSzm#!x zU%GlM!BXBt;9iY^rv&6CyNFz24CA6#eK3(hvAo-pOa80KTm^_Cyck5+?9C~DoD%{^ z;%k*b;Q6OfSf8BvbixQA!3u5Zf8a~a;4?v z<&;<|=?M~`$Yn))qdB#g@F~3yDmTuMqiGF_oY(vED9YQsKFIotb=30S-koQdK9Q1$ zTsPY>I);&YUqarP()pBr>Ls<5FH>4{ido7Zsf4;z4vb~1ES{b=Y}Mk>p}lP2R6L03 zxV?l}&XCH88^&_G4K`t+B}prqiCm8%C&SCk$Y4$`U0G{5nUief+D_!unq?_Bhb<+G z@*D>C;(`HR;sqkd+D>>n<6)fkLssJt2a%i2D#x>c+<*MXf4uoaG+2*iGA}D}f65O* zPx>TVU9)>B&#;v6FO5X5raz*+CH<+7eS~BKJ?0$Erp%$&bb-^l1M9_$?X#5*h-=HK z@2)PS1~#FB${oe%ga&RYF^U@lBMHcj(O7OQi*b?Wi3fFqZqrIC)vF9S&^2l=*}8Re ziZ8H~aV#JVA%`u>!3sm}$$bks@^Jn3{{VH1{)g+8hl~IC?I9pXk<#7B(YvwMCz(tn`k!PP^*+BHC*x+Z{9ws1iiXM&f7YR3Vg(xe6XA_;3@=B}IVbnc% z5eDSQT}3AXDMvg+Jva~vI!n~KXP+Z2?@60k%GqeATw|7UYZy5&mg0(7K0Vz&XzUKG zWPMxUC*+{L+)N^JS_=zt6uI4l1KjZ~YAY*0l&JmsBr)XV#mbxYH8aj~MRM^QH?HhD zy`_YW&I8CvI$Fy5rdjyjHYZ=UR6CU^J11g|PN1}%ITX6mNEQE4MoAna?jf_3ah_>> z4odeMLr&3kM??q6{ZW1M2T2RG;R~*gLVVtz+n-+}rI~%RmvS&^Vp&Q+ek5|L#+$iT zOTS$1qs~pd6I(o+B8nUCjRK;K%sqW@roBYs(v{_fg?9rx46ImgwZ$#vv5nlTG$IF< zQYeWrk}EfOj4uV3mpO8{=hR#!!8|Fz!)tb+A{S){PNg+Q;}Tj$)!>2eFmO(z;j#(M)NgV8OnMD012DeU>!U=Dg(Eob>I$itb4hS4xU z0&*1`SX?=?d6_HRC-$$8L{6%iJXbuhERFJAB^7@5q7x$T zOJROSM|dN8iCan|wL~pt!6XhS<0{uJn8s4S3&^bia;JmPH6FAudGXES%*>VI?tu|8 z=owYJc=9kC+J!SsL}RRFsB-Yrr=ZI6h^fW-@7izIuW;j+57;6n51?(>2b{ojl~0a{jrQ{6KVaSwt?m?MY=%oX9PY z)7Ir|n!bPq=PSAR+H(uIGcBb!0y&=RCHJhBWn`{DVQSt-GDr=s9K49hubI7kF{E^y zxc~T%;LtZtAaZGuWhsx1tQ)z>?qgbg3+iH>C)DV^NF%uHcOyqnE&%4%s-uv*|B4}p zTY-WjkOR+$X-;Y{D~nv^XhY;E$=^~lBXiCNRVTrFXI-3OK<+=^Hz3SH*mX~sJ=BJxG zmvba9hY^Io(olm>$(s{>8laX=N9g$GM&a_(5~!)9%8;|XIkdX>_Qs8oWMSK`Ez?e6 ziA@_^HwC%XMN)bp_f6hh0)Zz-pNiNOxomPNnI#+Jo?D#+GdoE@Zs^4e@#A$t*GWWD zFBS*Isq40GfqZB@L?z{fE0yk$l-A=pkn<74Z3JzNIhZ-BEgwBPe08xKayM=)J}~8_ z2XP<3=X6@RU@#azh=o~{vZ-RX&57LazY9^64Q10?H5yD?hN`6M`l-*29KPy9w>$ihA{Szn&OVw7H<3f3Uaa{-L|&T0l7%6=Bd78;AaP#@a#6jW3y7(ylvIzY zwt_EG9!A9_l&L64rM?`LgnWXYR+y0TdECh&WB~CIEA&vUZEh?_K>tNjC6Dr zy%-)Ieo@QiVnbL`YAKMEx45LlK8AXSEI+N>sjKS@ImIC?wXj&E@XWa_9U!;WyY!)6 znMkHrm!E0W#aqU{++M9mBcK*VlZ8DCIdTPYb>Q?%gK=&1=tP2+^p3e$$^}) zT&GJ`wY@HqvgJ(5eXE(n8VZ&u(%4C)yOD!E0@)i$3LTl!OmcK9YEu;fxtoJrUg}fd zWwKKl%e~9XXk>!7=bSAmp?krNoTN(FlZ)GtGqq)@{pw<0+zUAb-{bOw%X?g2R;?ce z5Etm(pO~F}{-Z5HFjfkV_V?>yfzHtIYOU%C`_|hb zU+07kMvWqOT?}He13vlJIY+fPb3u{PB*Y{Bh0zv z<l|OnLAbo7b&D?B)+qBUoo2BnTN5ZPUI2@ zdvb?Q9POt}Teb%-_6eTVl0ozqkV{{FKmsXtc?rbTbE%s%6B9c-Bc_=fE3NhS_se1* zDeYpsnaEvGkFXEd_v+{W6n#>xzM5zx5^Ov$xDtj7x%r-HAv2kpOks25AuPur=gpAI z7TavXmkl|{Wc$Xk=ED{>luVwDTr)2(n3MH7)_`#228ud@xh~;)q8=6%TUj%HsQF$b zNDMg=Fag15Avap5$O(l)4aNnCsbWMo;yyqQ;v~a*PPu*i_Ji9!UmcRNuVzZhO64_n z5u2|ua$-(u5-aBrmKw|!f+8w%hV1eZ@&;+XE~{S0$gQ$mIgyupV$G=8_P^~h6eJR3 zPtH@%1h(Q)=9DyC5zFg^t?DYQY+tXpPO)ThA~#(y6^uxyrnn`gNALt5rgbKBx#Gy| zyk+D(!^xEVY!w}-n{$aCNWmo6v9UBzdwDPoVu3pZ}4e=I(@f$iLj z+UdU^pHg{ARHafko_~N%T}6rCKX}|fddwxIY(q}^-M>o`-%;pzMA}|K66*Cht@`64 z--#SHT;k-*>#3_Vn7Iz*9+Fy0id@#$=N~YUyY!G%pV&1YSi1Ws7&*ZkId#q7R9$O8 z;(7;iuuG6sd&iX5^_WjrVDpZ^z9$j|g(GJQOAq9oeU}+69s_tWpE62u2qme7D|3DI*TN0J;9h8TN`agosyCv zcj1DBC8gh&`}yZrQK&?~?}&;iDM{^551L=JMJz)jBcaU4nWA|8>4##-1Gz`T!w*SU zIEvD|9Y^lcunjp=Qo<>?kt3F{3v&T=5h5BRaK#6@hbw70 z^9_bvET$H*N4J9|r36VgirmEWn;$-4d8uV?&WtEBf@CXLIAw6r0&b#r@-RqauV^_(L(|(3!$gYorj(7p3smBVWxz zZt}`?god9z6R$Aj2K449swnZXBS*p~&1EZXLdvxZ8n?4hdZMIm9+|Fc~+ozmil@hNL0&-oT}$ysI zxnRvKXP&+IYLxJekbm|3jTt4qUm1 zL|FDYklP)5WKC-}_g#_bM(;dpI^dShL{4os+rPhR`?;Y5D@UgYbt3mFsz|w9ScnP% zVG0TDW5mXXIgrboW#xJVQumkjUB4nW#K`oX2w86!$#s1)GdYEZb&A}@AKFwPv2QuOSs|%&{E<1+#yL5l5Mm#F~gNk5+XibM*dkV&XXNq@90!SG5+f6ZE4xv+dbJ3H~yhaCvj zDJ)8fCFR67MJat~p0)9OsnF*~kz0Yw_aupZIX!2l2!ggjU&V{B1~;uw51pOf!C?|M zS^nen#p8STw#5HV%nzjog~ti`I&tDci36ohA}R@N=h{?K<}X|@9LP1Xh4brU@W4Jg zf}2$$H1?Qn7Y9IrJbi_fe2H3;ZEejCUU@>q=_OJxyM!MDnssO z1q!hAz0-A4Tg`x5k2E5M?!>v1as}&a9n3LFNe%>0be10M8ar9x$o+oFuaHGp2^(^= z<2w^SUdL8sX4XWGOUmxRaY-p=*^`;MTj5U-kjsuQlJ&)lSrk(P2Q`MAeVU~UIakRS zlvxhFF}9btx7J@^M^Pp}dVHKm9h-N~ ziCAiL8buCG3e(eus30(Mn|td+;;)&vC)tq^A$sKlmXxDB@tuz_Jt-rxNrfds`S|eP zuO;5S*lbf_c^vw6GI!kK;E$gRGod4J6?#-Az;rjRj(n z3VUZEN0?KMp?|Nw`1j+jn}FPpmCEWiMUD`DdKxK%q?{HF3Q++`Ube0iIcqwRt@JA} z^4?5lKZjr;%@BCjGZW&J#UvniSBBvkm;8FbiQMz+p?T8$#*w3vvP&%`wr+5^q!fKu zY0}|C#d?P7%1L&1hxD+{e7KU*WhtkxQ9mx&9l5c%8@VAE>mPyg+ZS6Rn)-;5n<)N0 zF#8iAHz9E1a($Qn_51J8F(4c8iy-$ik(8I(;3Ssf+E#0|u}b=-ST(u0hu?(7KGHX^ zi(J0k?CktXC>6^|lcDkKh*$N=?j=v;F758R)_`z%DP}`c+|<#6NGShOrMylHuXlxh zI=IVR1F~SRu|%Juux&&MYf4xaQTr1XB7RjyT21dj?o44h*ApVKvq>S+)6?^8xaY;t z&`_=CP2=S4Noa9rr?>6L-^QBOP;XAx7;<)B4h;|g{mIzyW}6Dj=E<+W-oO9ruUU%= zhrA>{-PSro&R~D+t+x`1`j@4p`{9vf^3RudbE|1CFFA7490l8V<}s9e%P)rSEq{ER zxY-XQO-PxsxOGbA@J^`|&kq+cCF>~>;Gmvu)PdFT|WmmGsg`wr`d&{e*je;f)WuEs= zx28ToMvnS%6uE!>3nXRUh8)eq`5^-lEH}15#we?_Uy4*B+`cefi?@Ndivt7y`FVhB z1hFF*x?Jp0i{j$t#^M<@mL14(U#>ppR47{VsybR<&qrLIq% zVBnrVzufjW`|miA6Qc|{_5q~A5u3?Ok^2P5!NJIBjfTeMrR0>C(~iELEn{yBU)Hgu zrH$PEWKzz6yi728$s>vBJul=Kb3@z9*yq@OoLI)dEfXu3RtyaGYHn+NJyPS6(x4wi zj7UT>&PL8<1?f_dT=qtCgcXrIA2*ScylTCOk&}4i8zA?uTc0l?H*zx{XRc3$06FMH z>7Ag3m~P-sPI{-NuHIy4W-3Hul~`l$d|>8nV`qsVM{VRy?%UOKs!Tg<9LSZ0Vm#O# zxko`Un{CX6RAol^6#Hu|FI5ZV@|kW;oQ- z$WeKjBgoyr(A}JYwE|=$`Z>Xqn1x(rA0o{zCvxDrl5v) z0$%V=p@4`N1hMd;`*=|-2e|a`* zgd?E~dste&8M^mkXfE^qdC#)cYbP$T}P*tE_D;+oF`LxU~kuV)?m3%aX}0 z7fFjM$qE2+Lt+T&$T!aV3ZO;x{lJ+KOBZssH6U5GlYk`0r>2;VBgnx_6By#G9|+eG z*}O9!8V?B`$N_YfPshz@9$}LR7dsgWttsE+%e|nC^`wf#%_N^Z8}={ig`Vl@;hG~k9+?K>GRb6N zB)OFP9?Q#@-&b?;>a<4ka(f=Z69;ofL%>!p5(%{aFlAtrz1YXDyU8x5wfusbPMxvBrm`O?~?J^}Lekbbt*^OLC;K*fZlN=!TCTwITg-mFXw$FvmKyHxj z3LmqOTTp7An|Bml9G^#uOovnIyKR(8p$K;Qd?s=sXnr%Hvm=MqWnK{a^Lk|zx=%&2 zZDc|DCSge?D`4cVPYsEa#bKCjGK}U&ve^+TDVH3`9m~2d9n?2lnQ$^0m`o-&HkOwD zY-O0d%(b>^1c>Q9>SA>uN15~0d>FY^SS7h&_OHVHW(RWIM=R(E?xsr|!E;8*;gv4n1-QWSYsx3~N9IAI?3~1iN_@xVq~Yc47I&M2=0N+~@b- zz{usOY^-g1ZQ$vceZrMx2{Y%*uJ~TuySKdkM@@Wj?=d*c_4=|!Ts>?<&d6W76pfFO zD5VxoSfj9~`P{-R45}OWj~%)3-udhl zIe#Atxrgcz6f{6i7ddiPavUifIT78Sx~(fn&rBkY92;QEljbhuqJu}T^HBnvuF#2n z$~OtiuXKh`&m>0fYVpO_XG7Zf&iwe!4wIA)>$zzq5~h z6F`v5OT#QZ=_HOar`H;%+uJXuHO(?{nx<$<+O~`UxnRoa^v_OL?p)+Z4*}7Y5f9=B za(u(1134LxlU2nWc`~>--piT=JW9KOILzFKikrA@$gu;y-Iw~yrKKGUxl+7m(`yHh zd-lmA=nR0P!?ZA8eCYAL?d|Q;$IM?gnZv}bQek;X^~06{9;MU@t47!yh0P^pJjhl$ z7WsgaQ96in3UTD-Fe^Wl0R8$z*gD4WB`z5ihfCZ&5KH(1Q_(Xo$AVQJgEqt$$T z^Ny_`k|Bp+yn?2SQ<;pYWVo;-Ax&N$=0+~?8U}Z@b%E4iE;u&toFy#3Qs#PM6uIHr z;>ga({ER6n9mok#VX#`AHsIkEid^c}rz1fnz&O)LN7^?fbCMz%jfSS!*Mwl#4Jncf zIh)bTapXGUm0ikIT*#%nWeDt^oE^D=Vq4H(A84{QdV!3|>zeou?GWc~zXQ0lkb64A zh=ZGL$UQ0r#h!9G7#xGK&DX9yc`_CxgPYwWOdgfkDdT@g9NWO5dr&=o&&eDR_XkBz zy>RLG-+!i(Qjfq?Cn*exZ!Rex7-AeA1JU&!S%J#Se@y~#Q#R!00lJZtk{TJASA@`F zYUKU<-tmwNxrYxaa)Xf5vzA?P(nMJ^8SerzX!Y3XdpiMozb*MH4sG6*7;DAn7` z7K+bI@{4n{ zDMd~W6GaYhS4i|RUk+9l|Fq9`5@6&81WQ`m8k|LML)4RU91jjTd!5 zPDG(unn_qB@j))JZlcb)tc}KS)hwQ>Knu@9fx!0*rpHgK=#Pyt&V&b;{AjlC(SxY|wN$J?G!X;&j&p9`jSoNZ85nH-{9XXN1aFMh)$jezO zDambw0fyY#@Ytg@K+fl0>1ZLRDBQ|vO3jWOvLok%;EC`0YzY6cGrmAl;R4ELZS(Sq z0%Z;xFddL<6Bo{o96KKUa(exfUx)F{{q_A@xAK|V@YkLstSH*@08)@l+$eLJd zks1l4FzCW^Ql_DlKS5qTO{`+m2TzVfFEvlzEaoo%IrG!Z(rpVlRcqzaTFVIJ!Udfp z7pBDJ!bTTe*{vAUL~g}u+wqu*?$nhOIn)N=tW_RZQWn{Wg^4aRO;%u?#S$m(rTyK_Ao`)N828wq;|&}bI*^y*%F0P(?vLedm?~H}-Tq@6 zko*020SnahlNynf5Hv}U+Ey+pYndy2R+ohwtW50t`PS>}Q&XW=CUPO)BB}ZZOGhPT zHoM4D;S9M;564(nxEs0MhZb_w0v(c=qOWuF4z+R@2T?JD-_#JAU2L1xC)mhr{4+6B6grV}H18mPf8~}c0CaS_KwIk(H=l`1$+y`gJr;7wq&WO+h#)6I zV3Eyzg-sq?HSx$=bM<*3C15G(7&jElD*bu+7Lc(h_|QLdce}vBBDm3 zmv(sxCyZ6)_lbH1zmtct(!}rESY9Hw64jeIHMz47lfW#8PE~S+0@B3*{=;W2Hy|5O zV|>G@yNRGnR?dYS>Y9`zMov%#Icy;(WMn&VZ1VDi=R!vI7{ncBs*;I*@BvKZWPKbr{rlqu?qYrVT17 z9TrY&h^0sI@#|MRkppijJFxq&EA5Lv+mM4!0&j{v zntni=2Fs1KZ4@?Cniz(0p+#&P1N4yJ(y6wHShV=;NVm$Uao>uOp`{ zNVd&8@Upm(6D9?0MMEQ@thivSv840zdP91%J953__I+0#!V=N#1Xx}oDlcK_RYn{h z{`zb)>p*TLJ4|xr1i4Xl?g4|&l$X^#O(4YS7`QukV$PieJbZ$YG!okUNvQpf8IGEp&Ts`(8qbrLm2}H{yHL7WSsoASssy8fSka1E1iPdRH zN+)t-V`HUY@$Yt!(^}yUo(4=qyu)X%}lRj3w4!-0+J*ML-+)Kg%833{lEM5%4b?{=|&Di7x#%i7Qh^G z_;lE*8wrmjXF*;l@={UQW~{$k(Y@R4S^1bXC$t7&sI* z6cf2tA&vR7GuL%qgB>}!TOOPc2aTt*y@;TeH@&z6m5ogy8&H?Lfa7EG=w8OVb*2xO zmiFy{bwO@}*gqmeNtlJG(u96s^$CmxkB|FDKM5c#MgM63=y9pD*6S?lFmq6nGW749 z2C7mt_ULw%R*q~};gZrG3ytsoN1)72jg#%c`D~`hmYF5a^h^(WI;8reh5H^1J z?@yJVZvL0Fil;qD0a0l7u{z}?7&+(`&&}e?X@6;Ha$hiGFTa?`eSvT#*P-|>lv1nu1Wa5%KA+lCgRfroO`+XU z{Mm6A=DI)!opf2fEP|>GYIIDVD@y53t{?9H%$V!thad-O?(yr_Nk@%iKst(Ku3Wh? zsnt3sd_5XAk@Jy?$WG*3nvWvq+`L1P8xVwni?DZnV&^6lPzgfx*l$nZoq-(6&W~_^ zlx+bto%LVS@B77-?(XjHbadBT?&kDkuIfcNayI3Mi4eyKpLsXNsRS8C6T)#_uy^F+<10XRht=c4(t)6LtxzVNu@TCHB3a;wlt z9ngTQ7)3W(UMc+pBKp-|1fNwx>ciPo{!2M5FbBX?N3MIx9byE!i0xDW4`pQEi9~WN zX*>EkJH^6)lD!v3M-oXc*0>n!y{gv9$(AP8{zWA;HFUUCD+l!9@|6mc84d4+{TaZk z&5%+HtehV=A%6O)f6~A^-*P!ZE}CHb1s@w^pn`tzQxbRpbk-_)1NhGYP9UuZW!FAv z!v47;%+yYc9~vfpevj#MNc!yB0{=7XEAA5)r(%#bLcq!|v4F%v$j~x;_sn!>WX8qt(55fj%56kJ&DHOz?giXF>3t+wQ~-d^PUh>x0;5L))Z5*Rfv@L~tS;`jiHRm< z(6pmty5^$`8zs{oGo;qm?zXbBD`XZ&wDjkP^2R`1U}xDbr?;nPc=0>}b+Vx1(yTbI zBBwbB;B8gYtqs>u5T4~H)Kx#6YNF=;PZkh?aCi^z;zA_s2G4C{H@*kDn@p>101eVF z7M0uwQ2|An_+0wDx4|uEx4<8NfcvJ<=DXmlssi_j73bA;Z=bV-d zfq@?ngAYW6cKl))qwQWVd;|jT(%&#q#v{N0`k_5Vfl*;YxTSWs>!fNAHlTK`HlH^x zuzyx~kK@bCP1tdcOkCZgExMkgOu`RfI$Q$&N(UD@j=_el@(@X<;O;|Nq<8-D#jMA2 zpSn3b*oenNv9R2&A|bm>%-La$gpDzlpnuU-WC;76LQuV1`EJ1bFh61OqL3d=X$2;u z$R>NgvgNjS?(Lh#`8q`wm;K>B%QQp^b)nHoG)Kp@Thz>HB!k83yj0LC`J)F3xX_?n zbm(GWnctSC!dK-vxgTAN`GLRFC&pXVAKo^2wiTk8n?gnNI4|b8(i6!HLGFi2ML<*V zkw$Aa-bB`?53f3na6!M*bG~zrW@J0$cWp%G)j#}x_|21*UG@t=#6-?xuckHF&?D$a zZugp+RlVl>l_$-F`XE;h4BZu`sWjO~@P#0PY+~B?XQm&#PhDHG(+qGYBE=d*nOh)^ z)J~6|<;VccU6}rL6{2bozG`lTVDD` zd^*N|bx!-BGSMJWv!i{1on-ap({23K-G?v3AveHi0I%Xdo-@=Z9Kvwug6 zr0<$}b*=C0%*q_=y@F$ubS}Dr;jVdv|8#8d{A@Gfh3qwwDSgq{-B`fS9crbNdd>Y6|6T2Jtp}T=7d^}dEVj4c zd;p)>+J2<&Y#^_j=5T6k$*@6V>~jC_LP!=LS0(;YMNJB?@Z0tbx3gZ@7k&s06xdwIIQKA&(V4x!EL<@Y(|9kZN!=GX$<7H^GTxoruySKTM7+a^sO)Fh~L zzk_STi7p85V){>#zOi}3Ltqv6Bf-L8ZgG3Tcps+y(F>g!L`+l|is}a4uBQZ86%BQM zDo$!^+$(U5pWdLc2fh-)Z#d~5A&1EM!v?#2eW;{BvO^H4S(5!7`FNk+LNYZD%Dy!A z{(O;GQszqk6@t!t+q&0NVh6e;pKmCsD;C|}e$;{^=UVN}(6#(bQ+y2ti%*kjHA;-U zV@gAy(d{_eH~ZEjJ5WnrYi3UF&e2pb$?C|cCE&wkCpADCe0LJkd)DMRcA7RHyOG_Q zyX41uJ4_4xapD+MUx=elP}Isv$oM5C<~C4cx|B1Sb{Gq{$SBGEdX8Y*dag!qQ4HXk zp5gO41r;#Yeh_?fLY)`m=eT9t=7#}Zwe@-RAhY`M@nS-dmpO(tdn)lW8vUAQ-R%Xp z(k`a(6+Z4i z`^)zjxv6QIzc?rG&Py?D;fPw}Y!gy`6sxGPnT`H?b(|H5VR25^g#OO#Q8UEhCkTyS zP*cPGofnHg>mi+&S4CM1B)`gEJ$a*RD}t^y;lK0?vJbvT67atHRRp3P;<$ssa+PrW z%htYoJPmDOUmCm;MdyaI5M2AySewI6-<5Yysg13_WJYp*eGn4d{3id}S9Kb*51*+Y zbLh9XvIzie2E1ezo8cHqzDy)bEFeO_4m0(rFvuGrSS^nQpXdU}>0K12iL=Uj`Dftl zhv?^w_m`u0)(u?9!<(j9M*g51>1=!Y^@apqZiX=ecStJBU*#5gE1;02yT(S2#N-G~ zt)fq>>2k+DKTd@{tBeFushuZ%jxP4~llrf6H@w#V$?MYu@a*hR%7&FL>n%4$R)jeI z`fuGmAN$P;5qQU_8ZSf|^5eH0>y`kLtkErl3Pn=6WMrp#^ms&p9ALCg569`D?_@2f ze>#G7@<-&o9+`-I#C-Aq=W=%ct>!MX-k}fpYj8n%GBfP8m7}K3gjlm!S({mdN>d9} zgHV(D(8wgduO=1Dr0^Gn!*>MtpsAV2&*G9VX(lq7zRM(N#$#DIo5Y}AeI1d1U{#Rs z-!;ft!x6+Ziqj)A$mu5W5o-b%!Mc3KnCcfU(+FO%jVjxyH?lW#Pb)+V>q!p}`zrCC z$sxWHuc}Mig~CTwNUfV6|##v z;QNlE$;Zedvdex0D=3voeFQ#7tF1eut~4tiJW84ge z@2P24T{ZW9@0A}(w1fPnCXt;q_6K#8m}%qSTvLp|>SG>g6@o^wPVL8j21CvuQ=}c` zwj;sE?FdT+e@!h+pJCbewo`qc*F2#{=4LO9?U&Bb{p4+OaTh zR=1&52^C2PTS27X8HAC7+o*#C;5_fN$L`ZM9o0|q0`H^O#aUQ4TmJsAxM+&rV>v#~ zD9s{64XyU|8IWtz)KYV*4f@~;ZKE)R!z`Kcex1aNV9BC=io&^y9ZXvNj}xpP9bq^t zubW6q*ZJ}JM&bQGu_1{wzIY>0nwK)O3kW2*1Lv}pUMsV^zyiaBXUj;TG3e4@^C?%c z+xNe`$_B1mf!Ph-6;a_o^Xo4Ie^&ly6RgsUh6{}NlUdtqY?B3|XXPxGXa$oPRA)+e z`W}nUi|2Q-vEH>^Db&);Ar$!hRO9Xs^QAr+i+#0UYk-1Z8wgBacGz~WRD&0abkYm)Lr!eql+PW~jl zFb{R(VVRl^^qDfQccsTbSja-KSB$1bc9c5NQ@$Vb;^dJa7Qh~)8alcrQ zOhMmk@%XV5)&Kn9C91?Fh8ETD=;co&Dpvk2caqwQjU7NM`0lxB0J1J(O3p#t>Z8N? z_b}k&!6H}@3ua|@l}2C8Ot0;>E=i12txLbq|Yq6e4C zzy8KDyxjJFTNGUAJcnt=U-Hwz!i}C6J?#xtEc4Fg@c3^dX?H#ly7r_$V0vb;v-j@4 ztR@28(xz`(Aci}-a7cTDE2EKsBI`yuPy;AQc9NM3Ta7`yM=lrkwbc1+g}`M>2-`Vk z!6X#YpyLHDZ!`}3dF`aise_X7`rqB( zD!R(%fD{^7b>O@cQ$6B(-3r*7*MG}`U2Zrs|T3zzdRBl7?Pp4Nl5CfMN_`US23^ z$l*f&dgYfNDB*{H|Q#kHktiDIT~G0eB&Z$WEGmV8Th4_ikc zAA$*+H6wOL3_T7&?vH9=eZ0hL4%XAg?PC*&EM?HzVC89gQ_VaaPu@v?Utv07N$VyA z-V@WoSK?yiR8fb#dCp(+y8QafL;z8)uELZ!W013aa47>64_-8>jIt!2V{~+l^U-Hz z3o((hAu3Bd<~|T>Lbcf)(8wGHXMJ)P{gZL@bE-`6{!%5PZ_1=+v{+ad>~&*+c)-wH$?JN~uDr4$`r;a+Fc($eY`x%+61Z>`MutFpFcTO`#ywH%a^=wlbP zz3P!w{-ajl%08|mtzLYrMjuve@&+uBJvBIdsdP#wKP@RgKtsSI(KfAoiW_lKeZLG8 zfSzf_IaVl?>6l?^T~FWTjOzu;5?t6l*lj3bbRJr33~g8K=US%6?| z5QDqBz{>MK&vYh}pxaaHOCnLu(1j-6*p1;-_zAo0k_`2zA)W!8+AOn4W09{omkQL+|L*?o*3Y~*GtFUY z|J~+eWFP_$f?@R_Uukgt>|=iS>zZ)OTJg;!z|R{?TfeH_Iqw7`%`W%`TX#y3!IuI8;O$41nCFmg={h-oLplS-!JMhLdUexw8q zfneBRuS9gQ-Amun5al;qQI>|`LT|_HFAR{JRGZvovDkvmY?mVgfv@%#?avOr)LsAj zIUDNE@s6P9ed;&{HE%ftElf9rhq*ANa2l+ie?^E~U9UFR&wwBuj;>7|{nMM3f}6a6&hj_x84lmQZzTvR-(z#)vGk5o?LH*BV5}gHUU?dq--B`{X~V2jgx1!O=JfQ( zia9u2JRkPf&sBhqkAJ0MGj3Ha(h}3B{H435r3bSbwf5fqvIlW=1m^Yp@13quZC=(0 z+R_-`D!-vY2_JpU^45!{pe)a@=BE=*vQUTY?3NYy?kMt_i83F5jYrR2rb64h3if)r zoJq>QZ5OkD-wmMw!swgr~u4Ay1o=)P#avS5=BYEIPo<`BY zI_kp54Mx71>q3KJWje`{J}Myd(21WPbZwRA{{mCnfLgQiJ@+6|05L14Ej;;hs-oh0mw6Een_fdQ~|Y5;{iI!vF#wfO;O?b`{x5u(VW!^ZhB<&ZeaQ0bq*%rK6b0 znet|udO2esPqcFCF)>9uutWJx<$Tzty46M*y6foL(HFAwH?I|@nfXG&d|ELMOhoLk z1a)d19)(&bZ7S=&Yw{HJ!rj=5*6Z)k3!+uX8p|h`5O#8(4JKF^O`J#B6`e)xRIcgk zkKo%n9ptxh^iONw-xHeyL=yJ4rkyAzGhyNrOt3`={h@A0_Q>X@OMe~A8MA^|94ge+ z*2ype3=P)W%6VYR_<-q*q&LQ&p*F3=LOXnLdw`u;r-!1hX21TJRq7EoeQGxQx@kdy zjXMXIwj}s1&>&Ikm!;p&Ex`;MrJ{3gJ?^wMZBTM^RH|r%aznR1CEKqrQ8lS6@*mf& z)4;6Xcxwd8ha=sOvr&(mUqxgDOabzijVFOvM#6}a&A;*!hvfZ;t&ZkOa zE~;2A6fl%fT5|hsOUm~8C$SqW8|=Mhc8x;mw$`7q>MLN81=r5iZ0TaVrQ|hfX>i}_ zIJQck67SvPJBYGR%Eo1GepZ=GxQ8S2?Y!q_M{)hC>CUE2_Clr1tRO24hYuP|!JM z!YX^@J2zyTQ+*RU%O7sPZsLCbpAAV1;qzM|Eaya!&_HAiUB7$3CF)LXC@VOzWVx)> zpO6uZtG=hZEzdm0$k&Y;s2OIC2ms`O-uN)ZZMY~r-iPrC&Pg(18rN}%yi2z4L#Do9 zY4Z(iHb8$Of^Bu2Dl~vL*eEM%b}kIFH(Q+LIGETVPa$zim|%EpjCEOjM$kt=HWkbWCvw_T1E_n9zVcQjbOjoJmm!n5s+}f-Q{l%?GIl z)IGSsisIXxf+p7Xw6|oarxiR}2a^Y5tFT=C@%)N1Z8#N}obl1^3-Q7U2Re>ZgpW>EwBz%!U-SEm0SGT8n$ z6(LZP{6-hax_l4I)$|hz;P5s{hBqeH}4Wu54-}&gOmSs`+zZNzXEU zG;4`jW%jTbbSO8l^AVj}VwZCvB~z?MFih&pG4HbQ5; z;|Yl|rmcSO=|-|JKXR-6k(!sW9WQ6^vp{J zf5x`QkNeTZJtPrHD>*N%oGxI=rwo`3yeDOKdZ7CO_TOqsM}L&y@&cDL zes4H9$I&i@ey)$gSRGnh@YK+9X~G!x@D1(EI!vYuG$8x2634su_d`9dy+@9#+1nD& zkR{jp-bhOc6_fK7_VUlYKu)l+^VsL9$e+D34vk0$=*=dqS{nt>H4vnWjdq2$jmcOT zSKvB65r8!NjU0*fIFh?&U5~W*<;NOybbS*zyI-jyKj~v{Figv$7@E^V$w_RQ^o^c3Q7LPpmWCj$=`^`%DE;pISos_U~q`Yd2|wD%FFQ#D^XG2=d%6}=|MJ7V}F3ibVVM1epx8GsQ6%PG76_)iAM`#&;Gj2$Ij z6h+<1loCI&=X2fii_>BP7X>UZV|``IHNWc~7WgON7)KtQCoKtnKd5x-cJn-9MUywq zaBG56(`Cz&-SzownW+Xn?d+$6<8LPIyzO-HctouTyl!Qt>{2Kxu-q_w-Y%JTM~%Sw zt}2ZzIp&20+!>CPMnkpAXOau-d??$!D$r|lnrEdU%~Or`EeAJmWeN7KhM+^}e7?wC zDp^iO$UmhqeP*i~aj`!rXO-V`B!v^WrO7}yyVO%w*SmVMhJ+!HD~;nwH*AD94rDU3PG1p=>Z=w1a;^D%fevgB$M{DXGC@EGI0z3McJH`{lU>;nu@m$yQ&`00YL#rK3V{DhXfY-fEthvo0Vrd97KM zTN+Zk&haLs+UUIp0q3+x#8zYhoQ^-WIfrzbb2^reqUwWm*xi9X(RW1~v8)`HW1JKZ z1Wt+R!uvn$z6cYO_Gkil1J0x)hvBD5-|N3b#2+PWQSXu4NASD`Q>`wHyum;NJLpg2bM5oE*b;%5pt zn&=19LsE&##l&>tQti~33e|wpqGNANrDIOm;ul7jQlJe(P73*L%$V(osq8fW?*-^6 zj@nfc5bgE4H6ewjKhWxFMp~?9vysvw*z9iB3~I)rX1oMV1Y%*Xj^MoxXV*(W_v)*Nwo{hX^g8%0{P*o5}ZqjIAMRrpH&i!4= zRKre)pOa!l4__U-oH5j8E-h&x2;dii@-SfJM!6N2%ShtN8FgbBOfl^%OFO;(xDbax ztcM~e5Lk@WW93W&N4wyQJUXayK*-^^!{z+)I#Yx>!Nb`SaNRx0FFj=jB)y_^CZK%S zcgqpui}xakPbw7-tcnR1R=O+FL-%Gyrz+FPQgk>00g0~g5;|b&)u5_-R)%CvPP@Kpl>-HWueYa)q(Mn@bt5sPaUgm>hA}dS(?;W$hb>3@Q zuw!O|?v@X=cfp$?qjOv2SbeR)XEH-B-`5!O=BIj!HY6R)qCP#mVfaO}Ve7H{S4081 z&0%c87+qk-&uHJ9MbXss#SV=u!VGM%-5}z(aHM4j4X$Rut%an(R~mk_NRqG4!>G`T zaH%NHU$E+a@gG|)OA-hNPS2;Oo?jpd%lLM*SzVORi%{78j#r~4__GMDU4!x}wpyKv zi-3z*4$3dG$t`>ou#33*U9=ehkA7z2&uK~N^LVDBLGYms0>fjo6EUOEu29rKWT=s0 z;Ha-vHny^d-gk!`ZYh1l_?eMm#2Iu-2QNUm9G^?wgz5YmfjoU!&g^Q~XXMQ_eW_fO zuX4ilpDMG);|@z$ZlAyS5LX75I29AA6z8z&1kVEzVO_R%0>6pfU=CBUufGh(I>7wk zC^qHmC!`FGSKJ2LqZre=1^w}t*w{tBB<>xcU&99J-#VM_z1SKq@HJ85>RNJG$(63( zuFHD^mc|OMbtp0h4XP>7Sk)o4ILYX7T;NpSZ=%-bAV63_it>vPM_{1rPQnKDXiUNB zbb27NKG0(S~;+Uk%0{N4a( z=ce}ZmgR2emAwD^p>qC7<0Z}X&CEGyI*tk~CFAsO|t6!Aji$x4}TXvc7m5Xa4x~-I$!3}_A<@YU8JP{ ziXRqG_*7CFTdfz!vGuM5+WGWUgqGr^48B_GapR28EzMv|BhpSdBvBN|{%?)J!U$84 zWXBQ~>LW5*=YNxr3QcRFAx11DM(gxiGXxLYKDsocpmNpTR6aUuc zOG!$~qy|?C=}OFL8QqGRHsFZ+*IHC^fd3u8q(BUb+++orvsx#-w}rs2wkKpR*g1qT z&p6-~AcK&t9g488%W@t4e{hD(rTCRHVV%bjRFGwY%f#0mqO9QBG#Uq(6}u)1D0TiF zK#d;#T^q*YO#Q!-ngZS9vGRSO)TEMH)9Y+wT~#HYjIx2lU3hiFV+gVG?P?MoGf$@0 zYA)-`yK)n`ds$z`HOx~(X@Bs#55f{g-r8ceruxIC9mil`cztP!n|V4%`SY7goBH*w zSKG==r}4!5Zojd>C9&-6O_;h0&Oj-3-EkWeu551?pc9CIR_z_w*~tmR$6#y1=gbHe%Ybtd*X`^Engmsa&7%E#F)XX7ru*BulXL&e#rXnz>bsWaS zx5e2jnu;38?L%POAo*27{W7g!sTm05L{1MoX=E^V+Yfe%#6}I^(Ek<+oF?joz*LAS{>{&zyuwzAS&>E8;v`{pAGY_zoGHflS6Y516SEI6Z*IxUKr@O5as z+UI#$Q6d!m$lyf3oR0n5z++Vz;#E_otD50yeGD3X9<%$X=Hc=)= zk@Q?V7L!VlE72*~H7bUCVHT!29fUG1Gzkiw;BtO8h z9Ox`*E2iP^U*i|SbbzMw$Y>y^{C2HWbJJgkmj~MFl)^Zx`*2G?;-lO%Tc8v3tuf)# zV6x?B-=Z~J4hxI58q$tKXM@Ougvz-+0 zyqn|tS43pbJUW0L8$#HTii||F{n%Gajj}EeAON>*YYxY3Jik-c#W(cORoR<6%-7Za zj&Fl&!e0838_aU!qLnWz1b%RFgV<8&+3Xld-BaPZm$of`sHUvJo-e@Z29Fe2{}uXo zD6=60F`VdcY;^e;Wqs5d2TAp;n)K`0@(S4_;c-2z(AYM>en2{5Fu@2HmqQVC0*Q*8 zq1RgdO_9B5FSY%4!Rr2IwtEb9-!pf=X`82HClIg;XDG*ITEwb0*76s|>OIc+Eo@O> z{6T6)?3|wsTqSYrU5xjl|xa8yZqnv@6Oz|9{znB z(bD}7gBEaflQD!#EaJk?jJQ*?8&nu2U`xLINDi&wadl6Y4T>X_kcx{u^N=XM*Om5T z-WQE4#a%rKsPPX2h0pQqUdjMYRS0l@Mv3HRRFddTv(yFE?Y zD1e!nu15!0G-2anw$yy+r4sOp?Dp)x57QseAQq)_6J5PY|70LYja!ZoC#OgHgQX}1 z6;f41)hP|t5Y9bW!+2LWBZ!11P%_ALd?$RaL~dx`J@1ciZiSga-6?&NQPHz_R}ygh zg<>mdWmF-ur(5;=1O_h+%%giU-|{l8j)Ui$bPPzg_x2d5-uEq3_{l|Fy3*~CPr1G? zPsKvUP4$%R4XIRgfN`iXEqs-k-z32rl(x_UJhfRBT_&?PqyWEWdT4gpw^dRA2fq&d zXu6Q~3v7&l7jrcCDeLX)E5{Rjjd7*lVr}Y>g$b5dw;m9R94LeF3nFdaM9tUEShffu^P{tdtm&;ra;X&sFXf7 z32yEs1$ghFz<}QbgUv>)!@2?j0^TdT|8CG;*f0e#2xRc@L^>SYJ1SojL{xmaC;q&l ze7@FDUVCVb2&o>^yiiC}Dar0<683hj`gMNO?dE!L?yPG5U1Oat2Pu(}`A*6Oiesgb zFp^m(h1nopq28KD{>^GcYxC6jPtkN_v5IJ_?}QYg#FPq?B?1ZWbu#&bH;+r=(xKg6 zx69;N81k?8o=1}{dlM{I1h|pCKy;rB3~=Mb9ZDBc2KS{s?xtJ3e9`$*1vEdS8E|qZ zCQ_t~`sQaYlnG&1mr*KhLZa%Q{opr6U_VzFAd0Q8Af_N4U}5HsxPI;2f)BepobZE_ z)N~u_&i#^k2=eH5Vh+D{416z0fm=kt9HTXk_;)0Mks@^Kx?o%9LnUl=?65Lino1l* z`T13DF}>M;^uo!_2nR}d#{KOUzS3xifP2$=8obvhD}kjI=vMo>k+xq1*sJ0{$c zz&LKKh2MnV0UoX~Zp-DP#D*xyIU>v4g!~AqNU9xGVch&zHRL>M#-c9Mp{Be{56hig ztmo?1DeU&$zm`LgRAC zNnC>PdlB?We(Ji5=p%G23xkPD=k&y7J_Zb*$Aa&wv~jYW+0AlEFw+bgSu1(eYy=}y zOWmsb)%zJeWMRI4`Rgag?1pgLl4n|KhGp1#ddCHEkwiIAJmY43 znH@yM=BEOq0LJt)1Y~;5Og{u^S!s(d#`t!2NJ_SN@5kCw`mX6Xx1p=Qp~XBB>wqG& z#H(D?yc9u~u>U$eL+X$JJx%vM>Pw$pcJ&^%%&q0*T#j9LKhMnI&I7G~l4r5jKX>8A zEh2DK1^F}K2t||i*M~Q{C;_ZzoXVAv3{7O-`nuQ1T5y*qsh;k9+v=e`)3Cc&u;0It zsFlQ4V~oy;z(OHfJYp?MU8U1NT6kE1D;*PE5hQudX#!Ex_<+ z{1({}J)qPhBp~3KCUBJifcG0S>ef%-6QAmTWP<966N;C2+sdS1Yy6Wb>2K_>oQk+s zHTdvLAWjtjNmf+<@N>@9`x80SZD~s}P0c!#N;=qlT)XtMu@Q^B5{*&dr}j@pT|*T^ z<2}RII)Go&7_6?i6E=^+-9fGW#e-ub&;}`~(2$S~Km7Ra^jBNZRt22nhTl6)a0T-v zbO>G^0c9S62isPY^AzR+Kg^9cr!&pLs{U`=Tg#iZ+z!Q>8!+UO%=G#E4fVlOz!|2A zX`Pr!Uig`(kr}PPB8PjnmLz9}Rxs`|HB^_KGvMdAIg_rYJ4T_y*k?VuzHMdQ-%~mP zpGQAZ10*F^umSSk{*SQ!z~=&;{LQqtdVa4?>y2t|=H0?3JvIzT-!iIcj+JDn4?fLt zg<}p}ytlVs$;t@Z1ND}TSCwDY zopH>SOYrl5<9tk#e!3wEt=z!hk=7{Svx*`)S$Cv9=c1*ApJSe#gNLSKVfs9l8*Eg) z=xXTC#VZ!xBAtr=blP z7zPE48`6>sI}F4ig!u8FFZKQX!ouWSzKib7o5$@He)mdGqD?a`j`_^HZSX{)%KaLk zy{tt5);47bFLE+#odZw;8022Vw@=#HVCJb0bx2a(-Kcy;-US$h8`pOzjt$8VI^Ukk z$0V$fT50N4D4>`M)Rh^v&z;P{?fX=lPXJDgev;95+`Afm$%h5z9!D3Pq!?qg%}y5o zIrc3p19-i?0gg+pw6EGc(pOmwYTwNjn;1wq1E0+1Sj?!~BPQyCi0Et~-d1Gjom zAlc5>K7r2vCW;KrC#MF{XNud%1kc_K*+^}87v0rSriZvFbS}(18veL@WU8?Ud#94C ziK+*}V3ae{6&%5n2d7aG#2t&rTD~cIXC6uTJ&!#BgGK!vccsx=CU_e4m|}9y@fS>a zkLMo!ub=x92?1w2J9?ke2m!!9DVX+F)nnSGJJ;n$IO+mpAtM5$l=+{hr>0t&Zi_^j zC>2eRL`am6r=Rzb1%<1x0WF?X<=?_Ho4;}U{V5Emo7?hn_shxzKvOS;DV;9TMB^Om zDzMrb%5bz96tUxaXaL-^(a+eh)lWlu3Idfu3F*PX?JEV;Gkk*H11;?A7&;0DYEHxe zWOex5Oy4%MrWROTX20$`|Bo2olTU+y?wo{)i#H0Rk5}SCNzXk`YYA9B0whsP@^8 z?XVJjfDZaEsE2Oa!r*&dZm#|Ef*ag$aodUhK(e(gEw{i(!<0cIeB)UD-3#~jIli4- z={Lix`8dl7T@*`UZXx*ON(o+=Gmo3F4L8@_q|a+eaBaMw*<~f(fvJjn9Xi1J)U9M{ z_!Lk~$pCNqPRbYau|=^?TYtP(qfaQ=KhCLc> zb6Xt6k_$~C?+=TNEi$ZN3klDaH=g@GaIL~rmvLoe5p)>Tte@vY~ka z4sL9ynfnf%=Kc7KT|zIo#lfMF5Uea%XGsXW5%^hxRv+J*vH!`2K>wg(yt(tRKG8Kb zTL(5ALSHj6dh7liwyL*r(Y%{N0A4F;#)wXA%38rQ=eDMqlT-1$W4 zmiw8r>gf+-`1AKf*T{0aJxh2_Ss9z<_c{ylg_YvJ?+kHuz5!I%Bp=KPVB^!U;bDp$ z*F8QhR>@Z_G*ItvGQ)OzCtnfNsdoE>>j6*tQs@9l>D!GIOR`Vp0gE=J z_noZV>ao-wPfzOF21|sSU&nZhUW5LQ@ZU4FvqCb0*l*xtr0ZXE#GRHo$?+1tEkP^9 zIU7PR=2HqNuI5@T#RT4gI+m}-wj(|joUC@C*5h)zSCcfm@b#Cy_9Fab$~dK-yW-6w zyC3Rx)+Y`Q-xxqlF!4>){slAhSN=8}U#Q$!u=~$1-0~~UOfCt}r-CuH(L8dcy0qL} zZ8nmD$B*Ktt0kB#TY7ZMOWJ4mJj+NDo#o-g{p=42E% zh}~p4e<#-47Vqf|0nKwX{$3P7g8oaKNBry<4EluTm$rS+co!(Q*uOC#i6)GYpOR({ zNh9I2_(%_tPE?C{Q&fi5bQ<(gpr->-?+}tZp^hju|Gaac*OAP7F?VPQx~aS)+Yd5z zOZ*dzC}#weW5+oBy~syzyicFjW_|4>5Fl}8beALJBqyaT(9uFxb^#w&&C3|2lUe@K z(;G4M<~xjh{J!Z6NIlT(I9O_}`Dqx9rlliZwZnis0v6s2AU9``$%$j>Q8RYqu9@j=)O$LBH9@LH4cD(iwBYyfNPAe;-zDXq zj)}s|+h>foB6i~&Mo+Mq%T}Kt)*f@v!tKYDvVUGokeVtEWq}6rnS?oeky2ep5fUOv zJ_o#wO@1yl$;X!GF6sHPajR}#J@Bs#nN(bowDloU(D@*E%_s+_@?_&ai~1tQwdsE;PgQ#8V*6)zGzAcx zG5spUdO2Jw1yRNqzzK($mWf^Efg>paW27yX$or1_dFpZK_p5YLNbv7_5e0&XPdB%> z(nHt-&_vXc}NurCLnl_vD}VJYg_)LfRAq@8DWjzuCXIIww)G3e%GH677S^)Bx1 zSuE~=Tlqrk-UogG!F-6zDscm)3-hTg%k81r`M7dVpt=gYAyOH0hl2NHA5=`Oe=wmR zge+w58tTUZ3jWyS=!zqxJS55N$THL2D~L*1`~I;pWjP6-%W`Ei@cCb8EkSiv>u_ zXzw9_5{9mSsqL=U+_&l*J1CNmLsBGkpXV*D50$5RxpBX8T1_Mf(+K{D3jN;Uk zd5+#I2{50OX5OF6G@laqlQ&#&>nh(63;WCEK!;ELQtalsGWi#?bBCzC(R{PxVSlsq zRp$I@tHqQd9>%KFw;=YAmNq}w4MC)n3E?N5DfeBpLP{th<5aKs<zYt5f!2QoNmA5NZ`uya#<0f291>tL z53<$JbckV28K2hMPjCK@rmyg8`v1O{7En-9x?^<1Na+UY8r>l=Iuz-W8iUdJCZ#(@ zNi$ldVIZ-ANQ0E1eE0i39-n{VK3=cqz4x4R&-tGgK%7pBWZuGq@3?-fSePdn#TxwL ztt-m6l2B{XelkKmv*+JW#F-b3F4Cj0KzOgeZ%2}TZ>OWC*DAGffJ^c{V_J|(+Og2< zP>aT_(5Qf$q$vF5>nR9@w-V9}#F4JE3i~PnIn(ZZv{GpGhdOQh!w=6uJY@OuJ=vE2r<_@Vre2;)!WK_ zin8-3or?y-W16-t{#2+x%H&;#;XIxz&&K?#19z}Lu;RIWNad?u69a7`!JiqgG%Sq39p@>~7NqB#naGKn%1{W9XtIm#?v_KWlN%||AQ7eV@B>}=T6fd87~ z3M8?BN${ZUCdM2Co1DX|UUr+_S9c=jysyZXkeE8w4ROqqehiGUl7weyus>5GDe4It z0tfuQMYek`x14!wu11`#bVokQhw$=g(R|{rsC3}nhzfDv8LWu;5)ZnhktN8`T}_p_ zu{oRg2_=v;>|<&SW6P1wf=X*lQhDA*9ZVh{lTgj}zupD@E7B(_UO}iT=bk7>Fw%A8 zt$VyVNfoP_D=1q4dE`JVz#`y)e{M@zRm{QT2}u9_|GE*XeTa%MZH`IA+qV;Zs-N;e zhKw^y>i=(snl{;Grl=+*(8-OV?P(r#;O-~~MKvNreus6D%@!qteBJe12C92(UvY-Q zXVGYT8&9Q%VA+aj1*ghfEc)e~;=*a0wXX)WMQY;Bf;D-Oc$=6ho^*5jSbX-DKHqe2q9 zG_pd5MR|+4N@rz3N0%n8qx@--YUC*<#mz&{Bc+htiAe?_uFD&`wVL@$eYW4?f_Wbx zX&}wA{A7b@I$LXz|Fu9I1QN~pv)_JOM7hCRTgz73u0qqQUujRGtNekS1C7wA2%qsz zktGB|V1}w+=9cZxN7D}v1M4erTpxDTC9VG{63WBBef!=Q8M&+Z)kY;6@r_3RV^4Y#ohC9DjY6GQMmDe2+&!)=rkD^@><)xqu?Y$RitW>(%l6x3_}ol`;* z2rikMn{(Z*hzcDYiEdO~f=f48x7%LTx;BILRJ91`g8z%h%PGomoT(Q8?;9AZ{aM>E zVp2ZYP3lM~u_3a#E=~h6kCYtZuEOIP6cuGE)vRWa)dmiA6`~|?l zNd0cahJZl}>lQ1QM?GSq!o&T>uC{ye3H1aopiG@j0?Y<7Z19p|q^D#vlMC|3T=48~ zm@#Ssk^FHRdMKj|;+>t2$-DcsUfJ?M^PH@4d5w3pKC_VFZ#fOjR`m?(H?G)?jKE zxwlMou)3&hFes(tQrlu-bOx?V|339ksOosM`1)lgxXX;jz&*Fyk&sAj80lS1frWO?yr5puo@`@}K| zzW3=K$G}ku3KF?|pT0O=3%GA*;xq zN5?>&xg{h0eD>9YrEXWG?T|(R05pCSg*zl-fBGd?3>vDWH_;|``ewH5=|F;ju8s~! zT=z0!ufT_lMzxv4`RDf-ub)u~@I-aGLHt zW;g$xqs}YM#SR2;pG5ft<{{40q*}&zoQkkmG)0j#g??(YTFci1KojUXI4V-i;^!cPbrH`f_5E+;=~$)Mss?e(xXG$tTne6Wc}?jtj%M|qkSl!(SWGE z_jfl$vnza2WUMg}sp!%MSIyot;4O$W{(_}0290Lw7f;t-r%Y7^WI6qn*MI0d1cMkx zsZ3nZxWmRH$5|O{M_w2B>imVhy^KRPaHEWv$H>rg9OmW0p?7kAiy^0knm}17-q&#u zxynne#ymEZ*y(^ADfr+T5$FA*KlGk+Gm_VEPG9kaRE0!c4#$tjeey$cNTAY*QQ5-J ziXrIc*pW|1Iek#Z@R~DK1#;yR)7TiV)^NMM_h>fsOH{dWHOpWM=*SC!cQZ{?KWypP z6UtY(sBGGxut^2Cp)724oVJf?9zF;=Edjx!DJRDV(XPUJNN#>8*(`@U*3-8?2<^42 z6QuIpqj%$N$iSl&Pg!p2qSQ_~%tfs~6;n=&W%T08bXIN8x&qohIL{EXOw+gtfZ2sE z@7lwFpc4K=2dq&SYlw&a1jHs?WxJN^IGZ|agPl*ik7?SVq$$?5nZ9tP*Qf~h`=0pi zD$MgWGMMG}PUQ?Cm1f9`{IfN}t;C_m{z*B<43Vl|jkBp%lFiIBh-%bE&|9 z5UcRU<&dWB{YExN<2# z#WeA|Dz+Oc4i2lmC~`h)lxzc1UqKkPwL3nre#!KBN1t){$zXecOF!KtY%VXubA@BX zw>_qa*lqJu#gLIdJ&*?wMD%8jP4e9Ca_#M$kgN|B1Ik$Scqw4tBc8naVTTz=(@aT{ z=6N>m+UQBj$_rDMfZ(h59}V~X>#(jG_Q%gB2Ys?dJG+0upq2Ab=3mS&6n|x>r+HX1 zXJ~r3IyAhhqxg!5YU0~p)r(;@wSMoB0GeEvvO75y3?UXI1bXj20U8*zn60M4YsZR} zL0|LSm6We?a-xOhWF$IbA&|fCbRiLl>R+t79nS>Fz)%?76c5Yv{PvJ^z^@PoS$h0d zn5`8~Uq^@OQ%@ddvy@4Q_``Y`%>p#<=`U@J3)=EP&gXpd<`*oy!7q|V*+bqc%tf|Z zb!Pz|F`*teUmiDZp;|UqeYYiCD{%VO5Hni20e3E>CDSMr*O}M~Kj8O`6XWY` zlZPti{Ui3K)jt*8o0om+_ey1+G6trSG>~x4xPbJt5_7UCm^D`D z-MKL;I`a+p%E!XcZ)$pYo*W=KNg#Q5*xb{#5q_X(>`_!xjQ|cfJPlUm;h}iW7W^SR zMbQ_G8o<=E*zB1Ugy@3I2rs`#w5ctkA7pErlyC`Vfa)t_8+j3O-uBp0mL(iAktKaj zrB6!}Z@w^OL8;9h?;Cfqx8zM=)jhXb=XO*NpX?R;_B);~|MpbUZd*byPHiKxBEy8U zL3gYeS4|F)+VP>8zb4Q%Z#?Y%*v7x}(>WIT!HYXm1tdHMk)(hfHpldMN!kzW#e5bU zx4`P$@~grzuB$24MgI3_qYr*VifI?PDWCa5-?sWnppJ@g89NHGwH3g+R>m7~Bc&N@ z*pqdj*Dpr0GUnM`E0a<{kqTN`M^uUHY*ZQIT&i1c+86s>fZFfMz=UcJ-Hc_5rM zxm}CLbu}i%u-fT@V&{5VJY-wZbZj|Y3jEaCx0@f_A}MY+_iTp?vxv)GGFLfp_;Tas zcqhH2er77W>L)Kv#m>SU?42|<3%df#r=P~lqdv65!t+Ui%4Vv{WCpe#B;edvT!I26 zb5+erCTU9p7bY$S;nB{azyEy0fB3gvrY-+XH z%n%XiNdz3E7ZEBtRi8C9#Ndn$H1^aOC;u&5FUky;v5b*aqYc#{S9dlwyW1fVfZaz> zdSh8cKHNT(%xy30D|{Aw-@Uts{`V~w^kbw#oBUl`<~`3&O%)bxr;x1sSV?#$T`Lav zIeo<*=AGiAepi!S5cXPz&`bZh=o&-D<&t!3YPFrgt`ruw-Ehv!H`#A9jf_=hQKGtP zX}=gzX&Q!%ndNN-*q@J7-#@<9gTCD!8+REbhBU$iXPN{bX{}KgNF+^Fd)mD(2 z`GzY#`1Tc^Zu;{w$27Z^tT8Xc|DoQ|W~5mEW+TWEpp)i;i1Q2ZYi^>Xl=bRff*to& zBmkrY`3r|sv)*ScuIVjpnWA%a&7-QS|A`2dRkjpHp(rZM!SC>%ciIRp{BGl%!$uAV z+bRrY<^)Ie+K;LUh>G5&rXt%5B)@!-&ipH&Y>=h&@8NXIFv7dTFNBcWgS*rq<=5bE zHxWSX1SU311r=6t%g%vexF%(o*fK|De~<y zfl;ReeF1)7^^tq0Uwqc4-})4#?usrG=-U^?Z2hCdGvCYEd?` zcPARNWH=;dwCZ^EJWroD1w~yWDt_jPcNbw?uF{(VIM5rERWB1>`RDc=+Rw59C}-4W zPXw#ZCRk4BF4=;khr|Nq*J=JOYTa@3!AInJ4YA%$?7&X$+HO#4;XgNjm~Zm_$spIE zliuba>--J&lSrBH`<6i8QOt_5v&}x!ev|H0K13#jvl6JL_f2Qwjf$q~yFBB%r|(CuyOkkOi^UdO)z|pLf∾$2-U?~CPq{x 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