diff --git a/.gitmodules b/.gitmodules
index 6b558787..612f980c 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -1,3 +1,6 @@
[submodule "Flow"]
path = Flow
url = https://github.com/Cavallium/Flow
+[submodule "bigdecimal-math"]
+ path = bigdecimal-math
+ url = https://github.com/Cavallium/bigdecimal-math
diff --git a/Flow b/Flow
index 4ec16b0e..59b89e9d 160000
--- a/Flow
+++ b/Flow
@@ -1 +1 @@
-Subproject commit 4ec16b0e2d49da9771503e713604f5641ef6c414
+Subproject commit 59b89e9d165c3fc615ca44aa742b531caf13fcb6
diff --git a/LICENSE b/LICENSE
index 753842b6..c59b79ea 100644
--- a/LICENSE
+++ b/LICENSE
@@ -186,7 +186,7 @@
same "printed page" as the copyright notice for easier
identification within third-party archives.
- Copyright [yyyy] [name of copyright owner]
+ Copyright 2018 Andrea Cavalli
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
diff --git a/MmapByteBuffer.java b/MmapByteBuffer.java
deleted file mode 100644
index 5573e989..00000000
--- a/MmapByteBuffer.java
+++ /dev/null
@@ -1,33 +0,0 @@
-package it.cavallium.warppi;
-
-import java.nio.ByteBuffer;
-
-public class MmapByteBuffer {
- private int fd;
- private int address;
- private int length;
- private ByteBuffer buffer;
-
- public MmapByteBuffer(int fd, int address, int length, ByteBuffer buffer) {
- this.fd = fd;
- this.address = address;
- this.length = length;
- this.buffer = buffer;
- }
-
- public int getFd() {
- return fd;
- }
-
- public int getAddress() {
- return address;
- }
-
- public int getLength() {
- return length;
- }
-
- public ByteBuffer getBuffer() {
- return buffer;
- }
-}
\ No newline at end of file
diff --git a/README.md b/README.md
index 71ff635e..1f76a5a2 100644
--- a/README.md
+++ b/README.md
@@ -1,8 +1,8 @@
# WarpPI Calculator
Step-by-step algebra calculator for Raspberry PI.
-**This project is experimental and strictly related to my calculator, designed to run on an embedded hardware.
-It works but many fundamental features aren't complete.**
+**This project is experimental and strictly related to my calculator, designed to run on a raspberry PI Zero.**
+**Many fundamental features are missing, this project is still in its infancy.**
**If you really want to build and test it on your computer take account of that.**
diff --git a/bigdecimal-math b/bigdecimal-math
new file mode 160000
index 00000000..b08a4a6a
--- /dev/null
+++ b/bigdecimal-math
@@ -0,0 +1 @@
+Subproject commit b08a4a6aca41fbc6bf0c4bd252f716d518d368a5
diff --git a/core/pom.xml b/core/pom.xml
index d163a214..39c3ca38 100644
--- a/core/pom.xml
+++ b/core/pom.xml
@@ -6,10 +6,9 @@
it.cavalliumwarppi
- ${project.version}
+ 0.9.0a3warppi-core
- bundleWarpPI Calculator CoreWarpPI Calculator core project
@@ -18,7 +17,17 @@
it.cavalliumwarppi-flow
- ${project.version}
+ 0.9.0a3
+
+
+ it.cavallium
+ warppi-util
+ 0.9.0a3
+
+
+ it.cavallium
+ bigdecimal-math
+ 0.9.0a3it.unimi.dsi
@@ -46,16 +55,8 @@
- org.apache.felix
- maven-bundle-plugin
- true
-
-
- *
- it.cavallium.warppi.*
- warppi-core
-
-
+ org.apache.maven.plugins
+ maven-compiler-pluginorg.apache.maven.plugins
diff --git a/core/src/main/java/it/cavallium/warppi/Engine.java b/core/src/main/java/it/cavallium/warppi/Engine.java
index 39cb380c..ef863750 100644
--- a/core/src/main/java/it/cavallium/warppi/Engine.java
+++ b/core/src/main/java/it/cavallium/warppi/Engine.java
@@ -89,12 +89,17 @@ public class Engine {
}
Engine.platform.getConsoleUtils().out().println(ConsoleUtils.OUTPUTLEVEL_DEBUG_MIN, args);
checkDeviceType();
- if (Engine.getPlatform().isRunningOnRaspberry() && args.isRaspberryModeAllowed()) {
+ if (args.isRaspberryModeAllowed() == false) {
+ Engine.getPlatform().setRunningOnRaspberry(false);
+ }
+ if (Engine.getPlatform().isRunningOnRaspberry()) {
Engine.getPlatform().getGpio().wiringPiSetupPhys();
Engine.getPlatform().getGpio().pinMode(12, Engine.getPlatform().getGpio().valuePwmOutput());
} else {
StaticVars.screenPos = new int[] { 0, 0 };
- Engine.getPlatform().getSettings().setDebugEnabled(true);
+ if (Engine.getPlatform().isJavascript() == false) {
+ Engine.getPlatform().getSettings().setDebugEnabled(true);
+ }
}
}
diff --git a/core/src/main/java/it/cavallium/warppi/Platform.java b/core/src/main/java/it/cavallium/warppi/Platform.java
index bf762917..47a4c906 100644
--- a/core/src/main/java/it/cavallium/warppi/Platform.java
+++ b/core/src/main/java/it/cavallium/warppi/Platform.java
@@ -20,7 +20,7 @@ public interface Platform {
StorageUtils getStorageUtils();
- PngUtils getPngUtils();
+ ImageUtils getImageUtils();
Settings getSettings();
@@ -36,6 +36,8 @@ public interface Platform {
boolean isJavascript();
+ void setRunningOnRaspberry(boolean b);
+
boolean isRunningOnRaspberry();
String getOsName();
@@ -169,19 +171,17 @@ public interface Platform {
void close() throws IOException;
}
-
- public interface PngUtils {
-
- PngReader load(InputStream resourceStream);
-
- public interface PngReader {
-
+
+ public interface ImageUtils {
+
+ ImageReader load(InputStream resourceStream) throws IOException;
+
+ public interface ImageReader {
+
int[] getImageMatrix();
int[] getSize();
-
}
-
}
public interface Settings {
diff --git a/core/src/main/java/it/cavallium/warppi/device/Keyboard.java b/core/src/main/java/it/cavallium/warppi/device/Keyboard.java
index f55af5ee..a949d5d1 100644
--- a/core/src/main/java/it/cavallium/warppi/device/Keyboard.java
+++ b/core/src/main/java/it/cavallium/warppi/device/Keyboard.java
@@ -1,7 +1,5 @@
package it.cavallium.warppi.device;
-import java.awt.event.KeyEvent;
-
import it.cavallium.warppi.Engine;
import it.cavallium.warppi.Platform.ConsoleUtils;
import it.cavallium.warppi.StaticVars;
@@ -12,6 +10,7 @@ import it.cavallium.warppi.event.KeyPressedEvent;
import it.cavallium.warppi.event.KeyReleasedEvent;
import it.cavallium.warppi.event.KeyboardEventListener;
import it.cavallium.warppi.extra.mario.MarioScreen;
+import it.cavallium.warppi.extra.tetris.TetrisScreen;
import it.cavallium.warppi.gui.GUIErrorMessage;
import it.cavallium.warppi.gui.screens.KeyboardDebugScreen;
import it.cavallium.warppi.gui.screens.Screen;
@@ -41,15 +40,15 @@ public class Keyboard {
public synchronized void startKeyboard() {
final Thread kt = new Thread(() -> {
- if (Engine.getPlatform().getSettings().isDebugEnabled()) {
+ if (Engine.getPlatform().isRunningOnRaspberry() == false) {
try {
while (true) {
if (Keyboard.debugKeyCode != -1) {
- Keyboard.debugKeyPressed(Keyboard.debugKeyCode);
+ Keyboard.debugKey(Keyboard.debugKeyCode, false);
Keyboard.debugKeyCode = -1;
}
if (Keyboard.debugKeyCodeRelease != -1) {
- Keyboard.debugKeyReleased(Keyboard.debugKeyCodeRelease);
+ Keyboard.debugKey(Keyboard.debugKeyCodeRelease, true);
Keyboard.debugKeyCodeRelease = -1;
}
Thread.sleep(50);
@@ -88,9 +87,9 @@ public class Keyboard {
if (data[row] == true && Keyboard.precedentStates[row][col] == false) {
// System.out.println("Pressed button at " + (row + 1) + ", " + (col + 1));
// KeyboardDebugScreen.log("Pressed button at " + (row + 1) + ", " + (col + 1));
- Keyboard.keyPressedRaw(row, col);
+ Keyboard.keyRaw(row, col, false);
} else if (data[row] == false && Keyboard.precedentStates[row][col] == true) {
- Keyboard.keyReleasedRaw(row, col);
+ Keyboard.keyRaw(row, col, true);
}
// KeyboardDebugScreen.log("Released button at " + (row + 1) + ", " + (col + 1));
Keyboard.precedentStates[row][col] = data[row];
@@ -105,306 +104,324 @@ public class Keyboard {
kt.start();
}
- public static void debugKeyPressed(final int keyCode) {
+ /**
+ *
+ * @param k
+ * @param released true: released, false: pressed
+ */
+ private static void debugKey(Key k, boolean released) {
+ if (released) {
+ Keyboard.keyReleased(k);
+ } else {
+ Keyboard.keyPressed(k);
+ }
+ }
+
+ /**
+ *
+ * @param keyCode
+ * @param released true: released, false: pressed
+ */
+ public static void debugKey(final int keyCode, boolean released) {
switch (keyCode) {
- case KeyEvent.VK_ESCAPE:
- Keyboard.keyPressed(Key.BACK);
+ case KeyboardAWTValues.VK_ESCAPE:
+ debugKey(Key.BACK, released);
break;
- case KeyEvent.VK_S:
+ case KeyboardAWTValues.VK_S:
if (Keyboard.shift) {
- Keyboard.keyPressed(Key.ARCSINE);
+ debugKey(Key.ARCSINE, released);
} else if (Keyboard.alpha) {
- Keyboard.keyPressed(Key.LETTER_S);
+ debugKey(Key.LETTER_S, released);
} else {
- Keyboard.keyPressed(Key.SINE);
+ debugKey(Key.SINE, released);
}
break;
- case KeyEvent.VK_C:
+ case KeyboardAWTValues.VK_C:
if (Keyboard.shift) {
- Keyboard.keyPressed(Key.ARCCOSINE);
+ debugKey(Key.ARCCOSINE, released);
} else if (Keyboard.alpha) {
- Keyboard.keyPressed(Key.LETTER_C);
+ debugKey(Key.LETTER_C, released);
} else {
- Keyboard.keyPressed(Key.COSINE);
+ debugKey(Key.COSINE, released);
}
break;
- case KeyEvent.VK_T:
+ case KeyboardAWTValues.VK_T:
if (Keyboard.shift) {
- Keyboard.keyPressed(Key.ARCTANGENT);
+ debugKey(Key.ARCTANGENT, released);
} else if (Keyboard.alpha) {
- Keyboard.keyPressed(Key.LETTER_T);
+ debugKey(Key.LETTER_T, released);
} else {
- Keyboard.keyPressed(Key.TANGENT);
+ debugKey(Key.TANGENT, released);
}
break;
- case KeyEvent.VK_D:
+ case KeyboardAWTValues.VK_D:
if (!Keyboard.shift && !Keyboard.alpha) {
- Keyboard.keyPressed(Key.debug_DEG);
+ debugKey(Key.debug_DEG, released);
} else if (Keyboard.alpha) {
- Keyboard.keyPressed(Key.LETTER_D);
+ debugKey(Key.LETTER_D, released);
} else {
- Keyboard.keyPressed(Key.NONE);
+ debugKey(Key.NONE, released);
}
break;
- case KeyEvent.VK_R:
+ case KeyboardAWTValues.VK_R:
if (!Keyboard.shift && !Keyboard.alpha) {
- Keyboard.keyPressed(Key.debug_RAD);
+ debugKey(Key.debug_RAD, released);
} else if (Keyboard.alpha) {
- Keyboard.keyPressed(Key.LETTER_R);
+ debugKey(Key.LETTER_R, released);
} else {
- Keyboard.keyPressed(Key.NONE);
+ debugKey(Key.NONE, released);
}
break;
- case KeyEvent.VK_G:
+ case KeyboardAWTValues.VK_G:
if (!Keyboard.shift && !Keyboard.alpha) {
- Keyboard.keyPressed(Key.debug_GRA);
+ debugKey(Key.debug_GRA, released);
} else if (Keyboard.alpha) {
- Keyboard.keyPressed(Key.LETTER_G);
+ debugKey(Key.LETTER_G, released);
} else {
- Keyboard.keyPressed(Key.NONE);
+ debugKey(Key.NONE, released);
}
break;
- case KeyEvent.VK_X:
+ case KeyboardAWTValues.VK_X:
if (Keyboard.alpha) {
- Keyboard.keyPressed(Key.LETTER_X);
+ debugKey(Key.LETTER_X, released);
} else {
- Keyboard.keyPressed(Key.NONE);
+ debugKey(Key.NONE, released);
}
break;
- case KeyEvent.VK_P:
+ case KeyboardAWTValues.VK_P:
if (Keyboard.shift) {
- Keyboard.keyPressed(Key.NONE);
+ debugKey(Key.NONE, released);
} else if (Keyboard.alpha) {
- Keyboard.keyPressed(Key.LETTER_P);
+ debugKey(Key.LETTER_P, released);
} else {
- Keyboard.keyPressed(Key.PI);
+ debugKey(Key.PI, released);
}
break;
- case KeyEvent.VK_E:
+ case KeyboardAWTValues.VK_E:
if (Keyboard.shift) {
- Keyboard.keyPressed(Key.NONE);
+ debugKey(Key.NONE, released);
} else if (Keyboard.alpha) {
- Keyboard.keyPressed(Key.LETTER_E);
+ debugKey(Key.LETTER_E, released);
} else {
- Keyboard.keyPressed(Key.EULER_NUMBER);
+ debugKey(Key.EULER_NUMBER, released);
}
break;
- case KeyEvent.VK_Y:
+ case KeyboardAWTValues.VK_Y:
if (Keyboard.alpha) {
- Keyboard.keyPressed(Key.LETTER_Y);
+ debugKey(Key.LETTER_Y, released);
} else {
- Keyboard.keyPressed(Key.NONE);
+ debugKey(Key.NONE, released);
}
break;
- case KeyEvent.VK_B:
+ case KeyboardAWTValues.VK_B:
if (Keyboard.shift) {
- Keyboard.keyPressed(Key.BRIGHTNESS_CYCLE_REVERSE);
+ debugKey(Key.BRIGHTNESS_CYCLE_REVERSE, released);
} else if (!Keyboard.shift && !Keyboard.alpha) {
- Keyboard.keyPressed(Key.BRIGHTNESS_CYCLE);
+ debugKey(Key.BRIGHTNESS_CYCLE, released);
} else {
- Keyboard.keyPressed(Key.LETTER_B);
+ debugKey(Key.LETTER_B, released);
}
break;
- case KeyEvent.VK_L:
+ case KeyboardAWTValues.VK_L:
if (Keyboard.shift) {
- Keyboard.keyPressed(Key.LOGARITHM);
+ debugKey(Key.LOGARITHM, released);
} else if (Keyboard.alpha) {
- Keyboard.keyPressed(Key.LETTER_L);
+ debugKey(Key.LETTER_L, released);
} else {
- Keyboard.keyPressed(Key.LOGARITHM);
+ debugKey(Key.LOGARITHM, released);
}
break;
case KeyboardJogampValues.VK_ENTER:
- case KeyEvent.VK_ENTER:
+ case KeyboardAWTValues.VK_ENTER:
if (Keyboard.shift) {
- Keyboard.keyPressed(Key.STEP);
+ debugKey(Key.STEP, released);
} else if (!Keyboard.shift && !Keyboard.alpha) {
- Keyboard.keyPressed(Key.SIMPLIFY);
+ debugKey(Key.SIMPLIFY, released);
} else {
- Keyboard.keyPressed(Key.NONE);
+ debugKey(Key.NONE, released);
}
int row = 2;
int col = 1;
Keyboard.debugKeysDown[row - 1][col - 1] = true;
break;
- case KeyEvent.VK_1:
+ case KeyboardAWTValues.VK_1:
if (!Keyboard.shift && !Keyboard.alpha) {
- Keyboard.keyPressed(Key.NUM1);
+ debugKey(Key.NUM1, released);
} else {
- Keyboard.keyPressed(Key.NONE);
+ debugKey(Key.NONE, released);
}
break;
- case KeyEvent.VK_2:
+ case KeyboardAWTValues.VK_2:
if (!Keyboard.shift && !Keyboard.alpha) {
- Keyboard.keyPressed(Key.NUM2);
+ debugKey(Key.NUM2, released);
} else {
- Keyboard.keyPressed(Key.NONE);
+ debugKey(Key.NONE, released);
}
break;
- case KeyEvent.VK_3:
+ case KeyboardAWTValues.VK_3:
if (!Keyboard.shift && !Keyboard.alpha) {
- Keyboard.keyPressed(Key.NUM3);
+ debugKey(Key.NUM3, released);
} else {
- Keyboard.keyPressed(Key.NONE);
+ debugKey(Key.NONE, released);
}
break;
- case KeyEvent.VK_4:
+ case KeyboardAWTValues.VK_4:
if (!Keyboard.shift && !Keyboard.alpha) {
- Keyboard.keyPressed(Key.NUM4);
+ debugKey(Key.NUM4, released);
} else {
- Keyboard.keyPressed(Key.NONE);
+ debugKey(Key.NONE, released);
}
break;
- case KeyEvent.VK_5:
+ case KeyboardAWTValues.VK_5:
if (!Keyboard.shift && !Keyboard.alpha) {
- Keyboard.keyPressed(Key.NUM5);
+ debugKey(Key.NUM5, released);
} else {
- Keyboard.keyPressed(Key.NONE);
+ debugKey(Key.NONE, released);
}
break;
- case KeyEvent.VK_6:
+ case KeyboardAWTValues.VK_6:
if (!Keyboard.shift && !Keyboard.alpha) {
- Keyboard.keyPressed(Key.NUM6);
+ debugKey(Key.NUM6, released);
} else {
- Keyboard.keyPressed(Key.NONE);
+ debugKey(Key.NONE, released);
}
break;
- case KeyEvent.VK_7:
+ case KeyboardAWTValues.VK_7:
if (!Keyboard.shift && !Keyboard.alpha) {
- Keyboard.keyPressed(Key.NUM7);
+ debugKey(Key.NUM7, released);
} else if (Keyboard.shift) {
- if (Engine.getPlatform().getSettings().isDebugEnabled()) {
- Keyboard.keyPressed(Key.DIVIDE);
+ if (Engine.getPlatform().isRunningOnRaspberry() == false) {
+ debugKey(Key.DIVIDE, released);
}
}
break;
- case KeyEvent.VK_8:
+ case KeyboardAWTValues.VK_8:
if (!Keyboard.shift && !Keyboard.alpha) {
- Keyboard.keyPressed(Key.NUM8);
+ debugKey(Key.NUM8, released);
} else if (Keyboard.shift) {
- Keyboard.keyPressed(Key.PARENTHESIS_OPEN);
+ debugKey(Key.PARENTHESIS_OPEN, released);
} else {
- Keyboard.keyPressed(Key.NONE);
+ debugKey(Key.NONE, released);
}
break;
- case KeyEvent.VK_9:
+ case KeyboardAWTValues.VK_9:
if (!Keyboard.shift && !Keyboard.alpha) {
- Keyboard.keyPressed(Key.NUM9);
+ debugKey(Key.NUM9, released);
} else if (Keyboard.shift) {
- Keyboard.keyPressed(Key.PARENTHESIS_CLOSE);
+ debugKey(Key.PARENTHESIS_CLOSE, released);
} else {
- Keyboard.keyPressed(Key.NONE);
+ debugKey(Key.NONE, released);
}
break;
- case KeyEvent.VK_0:
+ case KeyboardAWTValues.VK_0:
if (!Keyboard.shift && !Keyboard.alpha) {
- Keyboard.keyPressed(Key.NUM0);
+ debugKey(Key.NUM0, released);
} else if (Keyboard.shift) {
- Keyboard.keyPressed(Key.EQUAL);
+ debugKey(Key.EQUAL, released);
} else {
- Keyboard.keyPressed(Key.NONE);
+ debugKey(Key.NONE, released);
}
break;
- case KeyEvent.VK_M:
+ case KeyboardAWTValues.VK_M:
if (!Keyboard.shift && !Keyboard.alpha) {
- Keyboard.keyPressed(Key.SURD_MODE);
+ debugKey(Key.SURD_MODE, released);
} else if (Keyboard.shift) {
- Keyboard.keyPressed(Key.NONE);
+ debugKey(Key.NONE, released);
} else {
- Keyboard.keyPressed(Key.LETTER_M);
+ debugKey(Key.LETTER_M, released);
}
break;
case KeyboardJogampValues.VK_ADD:
- case KeyEvent.VK_ADD:
+ case KeyboardAWTValues.VK_ADD:
if (!Keyboard.shift && !Keyboard.alpha) {
- Keyboard.keyPressed(Key.PLUS);
+ debugKey(Key.PLUS, released);
} else if (Keyboard.shift) {
- Keyboard.keyPressed(Key.PLUS_MINUS);
+ debugKey(Key.PLUS_MINUS, released);
} else {
- Keyboard.keyPressed(Key.NONE);
+ debugKey(Key.NONE, released);
}
break;
case KeyboardJogampValues.VK_SUBTRACT:
- case KeyEvent.VK_SUBTRACT:
+ case KeyboardAWTValues.VK_SUBTRACT:
if (!Keyboard.shift && !Keyboard.alpha) {
- Keyboard.keyPressed(Key.MINUS);
+ debugKey(Key.MINUS, released);
} else {
- Keyboard.keyPressed(Key.NONE);
+ debugKey(Key.NONE, released);
}
break;
case KeyboardJogampValues.VK_MULTIPLY:
- case KeyEvent.VK_MULTIPLY:
+ case KeyboardAWTValues.VK_MULTIPLY:
if (!Keyboard.shift && !Keyboard.alpha) {
- Keyboard.keyPressed(Key.MULTIPLY);
+ debugKey(Key.MULTIPLY, released);
} else {
- Keyboard.keyPressed(Key.NONE);
+ debugKey(Key.NONE, released);
}
break;
case KeyboardJogampValues.VK_DIVIDE:
- case KeyEvent.VK_DIVIDE:
+ case KeyboardAWTValues.VK_DIVIDE:
if (!Keyboard.shift && !Keyboard.alpha) {
- Keyboard.keyPressed(Key.DIVIDE);
+ debugKey(Key.DIVIDE, released);
} else {
- Keyboard.keyPressed(Key.NONE);
+ debugKey(Key.NONE, released);
}
break;
- case KeyEvent.VK_BACK_SPACE:
- Keyboard.keyPressed(Key.DELETE);
+ case KeyboardAWTValues.VK_BACK_SPACE:
+ debugKey(Key.DELETE, released);
break;
case KeyboardJogampValues.VK_DELETE:
- case KeyEvent.VK_DELETE:
+ case KeyboardAWTValues.VK_DELETE:
if (!Keyboard.shift && !Keyboard.alpha) {
- Keyboard.keyPressed(Key.RESET);
+ debugKey(Key.RESET, released);
} else {
- Keyboard.keyPressed(Key.NONE);
+ debugKey(Key.NONE, released);
}
break;
case KeyboardJogampValues.VK_LEFT:
- case KeyEvent.VK_LEFT:
+ case KeyboardAWTValues.VK_LEFT:
//LEFT
row = 2;
col = 3;
Keyboard.debugKeysDown[row - 1][col - 1] = true;
if (!Keyboard.shift && !Keyboard.alpha) {
- Keyboard.keyPressed(Key.LEFT);
+ debugKey(Key.LEFT, released);
} else {
- Keyboard.keyPressed(Key.NONE);
+ debugKey(Key.NONE, released);
}
break;
case KeyboardJogampValues.VK_RIGHT:
- case KeyEvent.VK_RIGHT:
+ case KeyboardAWTValues.VK_RIGHT:
//RIGHT
row = 2;
col = 5;
Keyboard.debugKeysDown[row - 1][col - 1] = true;
if (!Keyboard.shift && !Keyboard.alpha) {
- Keyboard.keyPressed(Key.RIGHT);
+ debugKey(Key.RIGHT, released);
} else {
- Keyboard.keyPressed(Key.NONE);
+ debugKey(Key.NONE, released);
}
break;
case KeyboardJogampValues.VK_UP:
- case KeyEvent.VK_UP:
+ case KeyboardAWTValues.VK_UP:
//UP
row = 1;
col = 4;
Keyboard.debugKeysDown[row - 1][col - 1] = true;
if (!Keyboard.shift && !Keyboard.alpha) {
- Keyboard.keyPressed(Key.UP);
+ debugKey(Key.UP, released);
} else {
- Keyboard.keyPressed(Key.NONE);
+ debugKey(Key.NONE, released);
}
break;
case KeyboardJogampValues.VK_DOWN:
- case KeyEvent.VK_DOWN:
+ case KeyboardAWTValues.VK_DOWN:
//DOWN
row = 3;
col = 4;
Keyboard.debugKeysDown[row - 1][col - 1] = true;
if (!Keyboard.shift && !Keyboard.alpha) {
- Keyboard.keyPressed(Key.DOWN);
+ debugKey(Key.DOWN, released);
} else {
- Keyboard.keyPressed(Key.NONE);
+ debugKey(Key.NONE, released);
}
break;
case (short) 12:
@@ -413,219 +430,219 @@ public class Keyboard {
col = 4;
Keyboard.debugKeysDown[row - 1][col - 1] = true;
if (!Keyboard.shift && !Keyboard.alpha) {
- Keyboard.keyPressed(Key.OK);
+ debugKey(Key.OK, released);
} else {
- Keyboard.keyPressed(Key.NONE);
+ debugKey(Key.NONE, released);
}
break;
case KeyboardJogampValues.VK_NUMPAD4:
- case KeyEvent.VK_NUMPAD4:
+ case KeyboardAWTValues.VK_NUMPAD4:
if (!Keyboard.shift && !Keyboard.alpha) {
- Keyboard.keyPressed(Key.HISTORY_BACK);
+ debugKey(Key.HISTORY_BACK, released);
} else {
- Keyboard.keyPressed(Key.NONE);
+ debugKey(Key.NONE, released);
}
break;
case KeyboardJogampValues.VK_NUMPAD6:
- case KeyEvent.VK_NUMPAD6:
+ case KeyboardAWTValues.VK_NUMPAD6:
if (!Keyboard.shift && !Keyboard.alpha) {
- Keyboard.keyPressed(Key.HISTORY_FORWARD);
+ debugKey(Key.HISTORY_FORWARD, released);
} else {
- Keyboard.keyPressed(Key.NONE);
+ debugKey(Key.NONE, released);
}
break;
- case KeyEvent.VK_PERIOD:
+ case KeyboardAWTValues.VK_PERIOD:
if (!Keyboard.shift && !Keyboard.alpha) {
- Keyboard.keyPressed(Key.DOT);
+ debugKey(Key.DOT, released);
} else {
- Keyboard.keyPressed(Key.NONE);
+ debugKey(Key.NONE, released);
}
break;
- case KeyEvent.VK_A:
+ case KeyboardAWTValues.VK_A:
if (!Keyboard.shift && !Keyboard.alpha) {
- Keyboard.keyPressed(Key.NONE);
+ debugKey(Key.NONE, released);
} else if (Keyboard.alpha && !Keyboard.shift) {
- Keyboard.keyPressed(Key.LETTER_A);
+ debugKey(Key.LETTER_A, released);
} else if (Keyboard.shift && !Keyboard.alpha) {
- Keyboard.keyPressed(Key.NONE);
+ debugKey(Key.NONE, released);
} else {
- Keyboard.keyPressed(Key.NONE);
+ debugKey(Key.NONE, released);
}
break;
- case KeyEvent.VK_F:
+ case KeyboardAWTValues.VK_F:
if (!Keyboard.shift && !Keyboard.alpha) {
- Keyboard.keyPressed(Key.NONE);
+ debugKey(Key.NONE, released);
} else if (Keyboard.alpha && !Keyboard.shift) {
- Keyboard.keyPressed(Key.LETTER_F);
+ debugKey(Key.LETTER_F, released);
} else if (Keyboard.shift && !Keyboard.alpha) {
- Keyboard.keyPressed(Key.NONE);
+ debugKey(Key.NONE, released);
} else {
- Keyboard.keyPressed(Key.NONE);
+ debugKey(Key.NONE, released);
}
break;
- case KeyEvent.VK_H:
+ case KeyboardAWTValues.VK_H:
if (!Keyboard.shift && !Keyboard.alpha) {
- Keyboard.keyPressed(Key.NONE);
+ debugKey(Key.NONE, released);
} else if (Keyboard.alpha && !Keyboard.shift) {
- Keyboard.keyPressed(Key.LETTER_H);
+ debugKey(Key.LETTER_H, released);
} else if (Keyboard.shift && !Keyboard.alpha) {
- Keyboard.keyPressed(Key.NONE);
+ debugKey(Key.NONE, released);
} else {
- Keyboard.keyPressed(Key.NONE);
+ debugKey(Key.NONE, released);
}
break;
- case KeyEvent.VK_I:
+ case KeyboardAWTValues.VK_I:
if (!Keyboard.shift && !Keyboard.alpha) {
- Keyboard.keyPressed(Key.NONE);
+ debugKey(Key.NONE, released);
} else if (Keyboard.alpha && !Keyboard.shift) {
- Keyboard.keyPressed(Key.LETTER_I);
+ debugKey(Key.LETTER_I, released);
} else if (Keyboard.shift && !Keyboard.alpha) {
- Keyboard.keyPressed(Key.NONE);
+ debugKey(Key.NONE, released);
} else {
- Keyboard.keyPressed(Key.NONE);
+ debugKey(Key.NONE, released);
}
break;
- case KeyEvent.VK_J:
+ case KeyboardAWTValues.VK_J:
if (!Keyboard.shift && !Keyboard.alpha) {
- Keyboard.keyPressed(Key.NONE);
+ debugKey(Key.NONE, released);
} else if (Keyboard.alpha && !Keyboard.shift) {
- Keyboard.keyPressed(Key.LETTER_J);
+ debugKey(Key.LETTER_J, released);
} else if (Keyboard.shift && !Keyboard.alpha) {
- Keyboard.keyPressed(Key.NONE);
+ debugKey(Key.NONE, released);
} else {
- Keyboard.keyPressed(Key.NONE);
+ debugKey(Key.NONE, released);
}
break;
- case KeyEvent.VK_K:
+ case KeyboardAWTValues.VK_K:
if (!Keyboard.shift && !Keyboard.alpha) {
- Keyboard.keyPressed(Key.NONE);
+ debugKey(Key.NONE, released);
} else if (Keyboard.alpha && !Keyboard.shift) {
- Keyboard.keyPressed(Key.LETTER_K);
+ debugKey(Key.LETTER_K, released);
} else if (Keyboard.shift && !Keyboard.alpha) {
- Keyboard.keyPressed(Key.NONE);
+ debugKey(Key.NONE, released);
} else {
- Keyboard.keyPressed(Key.NONE);
+ debugKey(Key.NONE, released);
}
break;
- case KeyEvent.VK_N:
+ case KeyboardAWTValues.VK_N:
if (!Keyboard.shift && !Keyboard.alpha) {
- Keyboard.keyPressed(Key.NONE);
+ debugKey(Key.NONE, released);
} else if (Keyboard.alpha && !Keyboard.shift) {
- Keyboard.keyPressed(Key.LETTER_N);
+ debugKey(Key.LETTER_N, released);
} else if (Keyboard.shift && !Keyboard.alpha) {
- Keyboard.keyPressed(Key.NONE);
+ debugKey(Key.NONE, released);
} else {
- Keyboard.keyPressed(Key.NONE);
+ debugKey(Key.NONE, released);
}
break;
- case KeyEvent.VK_O:
+ case KeyboardAWTValues.VK_O:
if (!Keyboard.shift && !Keyboard.alpha) {
- Keyboard.keyPressed(Key.NONE);
+ debugKey(Key.NONE, released);
} else if (Keyboard.alpha && !Keyboard.shift) {
- Keyboard.keyPressed(Key.LETTER_O);
+ debugKey(Key.LETTER_O, released);
} else if (Keyboard.shift && !Keyboard.alpha) {
- Keyboard.keyPressed(Key.NONE);
+ debugKey(Key.NONE, released);
} else {
- Keyboard.keyPressed(Key.NONE);
+ debugKey(Key.NONE, released);
}
break;
- case KeyEvent.VK_Q:
+ case KeyboardAWTValues.VK_Q:
if (!Keyboard.shift && !Keyboard.alpha) {
- Keyboard.keyPressed(Key.NONE);
+ debugKey(Key.NONE, released);
} else if (Keyboard.alpha && !Keyboard.shift) {
- Keyboard.keyPressed(Key.LETTER_Q);
+ debugKey(Key.LETTER_Q, released);
} else if (Keyboard.shift && !Keyboard.alpha) {
- Keyboard.keyPressed(Key.NONE);
+ debugKey(Key.NONE, released);
} else {
- Keyboard.keyPressed(Key.NONE);
+ debugKey(Key.NONE, released);
}
break;
- case KeyEvent.VK_U:
+ case KeyboardAWTValues.VK_U:
if (!Keyboard.shift && !Keyboard.alpha) {
- Keyboard.keyPressed(Key.NONE);
+ debugKey(Key.NONE, released);
} else if (Keyboard.alpha && !Keyboard.shift) {
- Keyboard.keyPressed(Key.LETTER_U);
+ debugKey(Key.LETTER_U, released);
} else if (Keyboard.shift && !Keyboard.alpha) {
- Keyboard.keyPressed(Key.NONE);
+ debugKey(Key.NONE, released);
} else {
- Keyboard.keyPressed(Key.NONE);
+ debugKey(Key.NONE, released);
}
break;
- case KeyEvent.VK_V:
+ case KeyboardAWTValues.VK_V:
if (!Keyboard.shift && !Keyboard.alpha) {
- Keyboard.keyPressed(Key.NONE);
+ debugKey(Key.NONE, released);
} else if (Keyboard.alpha && !Keyboard.shift) {
- Keyboard.keyPressed(Key.LETTER_V);
+ debugKey(Key.LETTER_V, released);
} else if (Keyboard.shift && !Keyboard.alpha) {
- Keyboard.keyPressed(Key.NONE);
+ debugKey(Key.NONE, released);
} else {
- Keyboard.keyPressed(Key.NONE);
+ debugKey(Key.NONE, released);
}
break;
- case KeyEvent.VK_W:
+ case KeyboardAWTValues.VK_W:
if (!Keyboard.shift && !Keyboard.alpha) {
- Keyboard.keyPressed(Key.NONE);
+ debugKey(Key.NONE, released);
} else if (Keyboard.alpha && !Keyboard.shift) {
- Keyboard.keyPressed(Key.LETTER_W);
+ debugKey(Key.LETTER_W, released);
} else if (Keyboard.shift && !Keyboard.alpha) {
- Keyboard.keyPressed(Key.NONE);
+ debugKey(Key.NONE, released);
} else {
- Keyboard.keyPressed(Key.NONE);
+ debugKey(Key.NONE, released);
}
break;
- case KeyEvent.VK_Z:
+ case KeyboardAWTValues.VK_Z:
if (!Keyboard.shift && !Keyboard.alpha) {
- Keyboard.keyPressed(Key.NONE);
+ debugKey(Key.NONE, released);
} else if (Keyboard.alpha && !Keyboard.shift) {
- Keyboard.keyPressed(Key.LETTER_Z);
+ debugKey(Key.LETTER_Z, released);
} else if (Keyboard.shift && !Keyboard.alpha) {
- Keyboard.keyPressed(Key.ZOOM_MODE);
+ debugKey(Key.ZOOM_MODE, released);
} else {
- Keyboard.keyPressed(Key.NONE);
+ debugKey(Key.NONE, released);
}
break;
case KeyboardJogampValues.VK_SHIFT:
- case KeyEvent.VK_SHIFT:
- Keyboard.keyPressed(Key.SHIFT);
+ case KeyboardAWTValues.VK_SHIFT:
+ debugKey(Key.SHIFT, released);
break;
- case KeyEvent.VK_CONTROL:
- Keyboard.keyPressed(Key.ALPHA);
+ case KeyboardAWTValues.VK_CONTROL:
+ debugKey(Key.ALPHA, released);
break;
case KeyboardJogampValues.VK_NUMPAD1:
- case KeyEvent.VK_NUMPAD1:
- Keyboard.keyPressed(Key.SQRT);
+ case KeyboardAWTValues.VK_NUMPAD1:
+ debugKey(Key.SQRT, released);
break;
case KeyboardJogampValues.VK_NUMPAD2:
- case KeyEvent.VK_NUMPAD2:
- Keyboard.keyPressed(Key.ROOT);
+ case KeyboardAWTValues.VK_NUMPAD2:
+ debugKey(Key.ROOT, released);
break;
case KeyboardJogampValues.VK_NUMPAD3:
- case KeyEvent.VK_NUMPAD3:
- Keyboard.keyPressed(Key.POWER_OF_2);
+ case KeyboardAWTValues.VK_NUMPAD3:
+ debugKey(Key.POWER_OF_2, released);
break;
case KeyboardJogampValues.VK_NUMPAD5:
- case KeyEvent.VK_NUMPAD5:
- Keyboard.keyPressed(Key.POWER_OF_x);
+ case KeyboardAWTValues.VK_NUMPAD5:
+ debugKey(Key.POWER_OF_x, released);
break;
}
}
private synchronized static void debugKeyReleased(final int keyCode) {
switch (keyCode) {
- case KeyEvent.VK_ENTER:
+ case KeyboardAWTValues.VK_ENTER:
int row = 2;
int col = 1;
Keyboard.debugKeysDown[row - 1][col - 1] = false;
break;
case KeyboardJogampValues.VK_LEFT:
- case KeyEvent.VK_LEFT:
+ case KeyboardAWTValues.VK_LEFT:
//LEFT
row = 2;
col = 3;
Keyboard.debugKeysDown[row - 1][col - 1] = false;
break;
case KeyboardJogampValues.VK_RIGHT:
- case KeyEvent.VK_RIGHT:
+ case KeyboardAWTValues.VK_RIGHT:
//RIGHT
row = 2;
col = 5;
@@ -633,14 +650,14 @@ public class Keyboard {
System.out.println("RELEASE");
break;
case KeyboardJogampValues.VK_UP:
- case KeyEvent.VK_UP:
+ case KeyboardAWTValues.VK_UP:
//UP
row = 1;
col = 4;
Keyboard.debugKeysDown[row - 1][col - 1] = false;
break;
case KeyboardJogampValues.VK_DOWN:
- case KeyEvent.VK_DOWN:
+ case KeyboardAWTValues.VK_DOWN:
//DOWN
row = 3;
col = 4;
@@ -655,22 +672,21 @@ public class Keyboard {
}
}
+ /**
+ *
+ * @param row
+ * @param col
+ * @return
+ */
+ @Deprecated
public static boolean isKeyDown(final int row, final int col) {
- if (Engine.getPlatform().getSettings().isDebugEnabled() == false) {
+ if (Engine.getPlatform().isRunningOnRaspberry()) {
return Keyboard.precedentStates[row - 1][col - 1];
} else {
return Keyboard.debugKeysDown[row - 1][col - 1];
}
}
- public synchronized static void keyReleasedRaw(final int row, final int col) {
-// KeyboardDebugScreen.keyX = row;
-// KeyboardDebugScreen.keyY = col;
- if (row == 1 && col == 1) {
- //keyReleased(Key.BRIGHTNESS_CYCLE);
- }
- }
-
static final String[][][] KeyLabelsMap = /* [ROW, COLUMN, (0:normal 1:shift 2:alpha)] */
{ { /* ROW 0 */
{ "⇪", "⇪", null }, /* 0,0 */
@@ -687,8 +703,8 @@ public class Keyboard {
{ "⇦", null, null }, /* 1,2 */
{ "OK", null, null }, /* 1,3 */
{ "⇨", null, null }, /* 1,4 */
- { "↤", null, null }, /* 1,5 */
- { "↦", null, null }, /* 1,6 */
+ { "≪", null, null }, /* 1,5 */
+ { "≫", null, null }, /* 1,6 */
{ "", null, null } /* 1,7 */
}, { /* ROW 2 */
{ "", null, null }, /* 2,0 */
@@ -751,7 +767,7 @@ public class Keyboard {
{ Key.SHIFT, Key.SHIFT, Key.SHIFT }, /* 0,0 */
{ Key.ALPHA, Key.ALPHA, Key.ALPHA }, /* 0,1 */
{ Key.NONE, Key.NONE, Key.NONE }, /* 0,2 */
- { Key.NONE, Key.NONE, Key.NONE }, /* 0,3 */
+ { Key.UP, Key.NONE, Key.NONE }, /* 0,3 */
{ Key.NONE, Key.NONE, Key.NONE }, /* 0,4 */
{ Key.SETTINGS, Key.NONE, Key.NONE }, /* 0,5 */
{ Key.BRIGHTNESS_CYCLE, Key.BRIGHTNESS_CYCLE_REVERSE, Key.ZOOM_MODE }, /* 0,6 */
@@ -850,19 +866,33 @@ public class Keyboard {
}
}
- public static synchronized void keyPressedRaw(final int row, final int col) {
+ /**
+ *
+ * @param row
+ * @param col
+ * @param released true: released, false: pressed
+ */
+ public static synchronized void keyRaw(final int row, final int col, final boolean released) {
// KeyboardDebugScreen.keyX = row;
// KeyboardDebugScreen.keyY = col;
final Key k = Keyboard.keyMap[row][col][Keyboard.shift ? 1 : Keyboard.alpha ? 2 : 0];
if (k != null) {
- Keyboard.keyPressed(k);
+ if (released) {
+ Keyboard.keyReleased(k);
+ } else {
+ Keyboard.keyPressed(k);
+ }
} else {
- Keyboard.keyPressed(Key.NONE);
+ if (released) {
+ Keyboard.keyReleased(Key.NONE);
+ } else {
+ Keyboard.keyPressed(Key.NONE);
+ }
}
}
public static void stopKeyboard() {
- if (Engine.getPlatform().getSettings().isDebugEnabled() == false) {
+ if (Engine.getPlatform().isRunningOnRaspberry()) {
Engine.getPlatform().getGpio().digitalWrite(33, false);
Engine.getPlatform().getGpio().digitalWrite(35, false);
Engine.getPlatform().getGpio().digitalWrite(36, false);
@@ -900,6 +930,7 @@ public class Keyboard {
case NONE:
break;
case BRIGHTNESS_CYCLE:
+ Engine.INSTANCE.getHardwareDevice().getDisplayManager().setScreen(new TetrisScreen()); //TODO: rimuovere: prova
Engine.INSTANCE.getHardwareDevice().getDisplayManager().cycleBrightness(false);
refresh = true;
break;
diff --git a/core/src/main/java/it/cavallium/warppi/device/KeyboardAWTValues.java b/core/src/main/java/it/cavallium/warppi/device/KeyboardAWTValues.java
new file mode 100644
index 00000000..083d0531
--- /dev/null
+++ b/core/src/main/java/it/cavallium/warppi/device/KeyboardAWTValues.java
@@ -0,0 +1,700 @@
+package it.cavallium.warppi.device;
+
+public interface KeyboardAWTValues {
+
+ /**
+ * The first number in the range of ids used for key events.
+ */
+ int KEY_FIRST = 400;
+
+ /**
+ * The last number in the range of ids used for key events.
+ */
+ int KEY_LAST = 402;
+
+ /**
+ * The "key typed" event. This event is generated when a character is
+ * entered. In the simplest case, it is produced by a single key press.
+ * Often, however, characters are produced by series of key presses, and
+ * the mapping from key pressed events to key typed events may be
+ * many-to-one or many-to-many.
+ */
+ int KEY_TYPED = KEY_FIRST;
+
+ /**
+ * The "key pressed" event. This event is generated when a key
+ * is pushed down.
+ */
+ int KEY_PRESSED = 1 + KEY_FIRST; //Event.KEY_PRESS
+
+ /**
+ * The "key released" event. This event is generated when a key
+ * is let up.
+ */
+ int KEY_RELEASED = 2 + KEY_FIRST; //Event.KEY_RELEASE
+
+ /* Virtual key codes. */
+
+ int VK_ENTER = '\n';
+ int VK_BACK_SPACE = '\b';
+ int VK_TAB = '\t';
+ int VK_CANCEL = 0x03;
+ int VK_CLEAR = 0x0C;
+ int VK_SHIFT = 0x10;
+ int VK_CONTROL = 0x11;
+ int VK_ALT = 0x12;
+ int VK_PAUSE = 0x13;
+ int VK_CAPS_LOCK = 0x14;
+ int VK_ESCAPE = 0x1B;
+ int VK_SPACE = 0x20;
+ int VK_PAGE_UP = 0x21;
+ int VK_PAGE_DOWN = 0x22;
+ int VK_END = 0x23;
+ int VK_HOME = 0x24;
+
+ /**
+ * Constant for the non-numpad left arrow key.
+ * @see #VK_KP_LEFT
+ */
+ int VK_LEFT = 0x25;
+
+ /**
+ * Constant for the non-numpad up arrow key.
+ * @see #VK_KP_UP
+ */
+ int VK_UP = 0x26;
+
+ /**
+ * Constant for the non-numpad right arrow key.
+ * @see #VK_KP_RIGHT
+ */
+ int VK_RIGHT = 0x27;
+
+ /**
+ * Constant for the non-numpad down arrow key.
+ * @see #VK_KP_DOWN
+ */
+ int VK_DOWN = 0x28;
+
+ /**
+ * Constant for the comma key, ","
+ */
+ int VK_COMMA = 0x2C;
+
+ /**
+ * Constant for the minus key, "-"
+ * @since 1.2
+ */
+ int VK_MINUS = 0x2D;
+
+ /**
+ * Constant for the period key, "."
+ */
+ int VK_PERIOD = 0x2E;
+
+ /**
+ * Constant for the forward slash key, "/"
+ */
+ int VK_SLASH = 0x2F;
+
+ /** VK_0 thru VK_9 are the same as ASCII '0' thru '9' (0x30 - 0x39) */
+ int VK_0 = 0x30;
+ int VK_1 = 0x31;
+ int VK_2 = 0x32;
+ int VK_3 = 0x33;
+ int VK_4 = 0x34;
+ int VK_5 = 0x35;
+ int VK_6 = 0x36;
+ int VK_7 = 0x37;
+ int VK_8 = 0x38;
+ int VK_9 = 0x39;
+
+ /**
+ * Constant for the semicolon key, ";"
+ */
+ int VK_SEMICOLON = 0x3B;
+
+ /**
+ * Constant for the equals key, "="
+ */
+ int VK_EQUALS = 0x3D;
+
+ /** VK_A thru VK_Z are the same as ASCII 'A' thru 'Z' (0x41 - 0x5A) */
+ int VK_A = 0x41;
+ int VK_B = 0x42;
+ int VK_C = 0x43;
+ int VK_D = 0x44;
+ int VK_E = 0x45;
+ int VK_F = 0x46;
+ int VK_G = 0x47;
+ int VK_H = 0x48;
+ int VK_I = 0x49;
+ int VK_J = 0x4A;
+ int VK_K = 0x4B;
+ int VK_L = 0x4C;
+ int VK_M = 0x4D;
+ int VK_N = 0x4E;
+ int VK_O = 0x4F;
+ int VK_P = 0x50;
+ int VK_Q = 0x51;
+ int VK_R = 0x52;
+ int VK_S = 0x53;
+ int VK_T = 0x54;
+ int VK_U = 0x55;
+ int VK_V = 0x56;
+ int VK_W = 0x57;
+ int VK_X = 0x58;
+ int VK_Y = 0x59;
+ int VK_Z = 0x5A;
+
+ /**
+ * Constant for the open bracket key, "["
+ */
+ int VK_OPEN_BRACKET = 0x5B;
+
+ /**
+ * Constant for the back slash key, "\"
+ */
+ int VK_BACK_SLASH = 0x5C;
+
+ /**
+ * Constant for the close bracket key, "]"
+ */
+ int VK_CLOSE_BRACKET = 0x5D;
+
+ int VK_NUMPAD0 = 0x60;
+ int VK_NUMPAD1 = 0x61;
+ int VK_NUMPAD2 = 0x62;
+ int VK_NUMPAD3 = 0x63;
+ int VK_NUMPAD4 = 0x64;
+ int VK_NUMPAD5 = 0x65;
+ int VK_NUMPAD6 = 0x66;
+ int VK_NUMPAD7 = 0x67;
+ int VK_NUMPAD8 = 0x68;
+ int VK_NUMPAD9 = 0x69;
+ int VK_MULTIPLY = 0x6A;
+ int VK_ADD = 0x6B;
+
+ /**
+ * This constant is obsolete, and is included only for backwards
+ * compatibility.
+ * @see #VK_SEPARATOR
+ */
+ int VK_SEPARATER = 0x6C;
+
+ /**
+ * Constant for the Numpad Separator key.
+ * @since 1.4
+ */
+ int VK_SEPARATOR = VK_SEPARATER;
+
+ int VK_SUBTRACT = 0x6D;
+ int VK_DECIMAL = 0x6E;
+ int VK_DIVIDE = 0x6F;
+ int VK_DELETE = 0x7F; /* ASCII DEL */
+ int VK_NUM_LOCK = 0x90;
+ int VK_SCROLL_LOCK = 0x91;
+
+ /** Constant for the F1 function key. */
+ int VK_F1 = 0x70;
+
+ /** Constant for the F2 function key. */
+ int VK_F2 = 0x71;
+
+ /** Constant for the F3 function key. */
+ int VK_F3 = 0x72;
+
+ /** Constant for the F4 function key. */
+ int VK_F4 = 0x73;
+
+ /** Constant for the F5 function key. */
+ int VK_F5 = 0x74;
+
+ /** Constant for the F6 function key. */
+ int VK_F6 = 0x75;
+
+ /** Constant for the F7 function key. */
+ int VK_F7 = 0x76;
+
+ /** Constant for the F8 function key. */
+ int VK_F8 = 0x77;
+
+ /** Constant for the F9 function key. */
+ int VK_F9 = 0x78;
+
+ /** Constant for the F10 function key. */
+ int VK_F10 = 0x79;
+
+ /** Constant for the F11 function key. */
+ int VK_F11 = 0x7A;
+
+ /** Constant for the F12 function key. */
+ int VK_F12 = 0x7B;
+
+ /**
+ * Constant for the F13 function key.
+ * @since 1.2
+ */
+ /* F13 - F24 are used on IBM 3270 keyboard; use random range for constants. */
+ int VK_F13 = 0xF000;
+
+ /**
+ * Constant for the F14 function key.
+ * @since 1.2
+ */
+ int VK_F14 = 0xF001;
+
+ /**
+ * Constant for the F15 function key.
+ * @since 1.2
+ */
+ int VK_F15 = 0xF002;
+
+ /**
+ * Constant for the F16 function key.
+ * @since 1.2
+ */
+ int VK_F16 = 0xF003;
+
+ /**
+ * Constant for the F17 function key.
+ * @since 1.2
+ */
+ int VK_F17 = 0xF004;
+
+ /**
+ * Constant for the F18 function key.
+ * @since 1.2
+ */
+ int VK_F18 = 0xF005;
+
+ /**
+ * Constant for the F19 function key.
+ * @since 1.2
+ */
+ int VK_F19 = 0xF006;
+
+ /**
+ * Constant for the F20 function key.
+ * @since 1.2
+ */
+ int VK_F20 = 0xF007;
+
+ /**
+ * Constant for the F21 function key.
+ * @since 1.2
+ */
+ int VK_F21 = 0xF008;
+
+ /**
+ * Constant for the F22 function key.
+ * @since 1.2
+ */
+ int VK_F22 = 0xF009;
+
+ /**
+ * Constant for the F23 function key.
+ * @since 1.2
+ */
+ int VK_F23 = 0xF00A;
+
+ /**
+ * Constant for the F24 function key.
+ * @since 1.2
+ */
+ int VK_F24 = 0xF00B;
+
+ int VK_PRINTSCREEN = 0x9A;
+ int VK_INSERT = 0x9B;
+ int VK_HELP = 0x9C;
+ int VK_META = 0x9D;
+
+ int VK_BACK_QUOTE = 0xC0;
+ int VK_QUOTE = 0xDE;
+
+ /**
+ * Constant for the numeric keypad up arrow key.
+ * @see #VK_UP
+ * @since 1.2
+ */
+ int VK_KP_UP = 0xE0;
+
+ /**
+ * Constant for the numeric keypad down arrow key.
+ * @see #VK_DOWN
+ * @since 1.2
+ */
+ int VK_KP_DOWN = 0xE1;
+
+ /**
+ * Constant for the numeric keypad left arrow key.
+ * @see #VK_LEFT
+ * @since 1.2
+ */
+ int VK_KP_LEFT = 0xE2;
+
+ /**
+ * Constant for the numeric keypad right arrow key.
+ * @see #VK_RIGHT
+ * @since 1.2
+ */
+ int VK_KP_RIGHT = 0xE3;
+
+ /* For European keyboards */
+ /** @since 1.2 */
+ int VK_DEAD_GRAVE = 0x80;
+ /** @since 1.2 */
+ int VK_DEAD_ACUTE = 0x81;
+ /** @since 1.2 */
+ int VK_DEAD_CIRCUMFLEX = 0x82;
+ /** @since 1.2 */
+ int VK_DEAD_TILDE = 0x83;
+ /** @since 1.2 */
+ int VK_DEAD_MACRON = 0x84;
+ /** @since 1.2 */
+ int VK_DEAD_BREVE = 0x85;
+ /** @since 1.2 */
+ int VK_DEAD_ABOVEDOT = 0x86;
+ /** @since 1.2 */
+ int VK_DEAD_DIAERESIS = 0x87;
+ /** @since 1.2 */
+ int VK_DEAD_ABOVERING = 0x88;
+ /** @since 1.2 */
+ int VK_DEAD_DOUBLEACUTE = 0x89;
+ /** @since 1.2 */
+ int VK_DEAD_CARON = 0x8a;
+ /** @since 1.2 */
+ int VK_DEAD_CEDILLA = 0x8b;
+ /** @since 1.2 */
+ int VK_DEAD_OGONEK = 0x8c;
+ /** @since 1.2 */
+ int VK_DEAD_IOTA = 0x8d;
+ /** @since 1.2 */
+ int VK_DEAD_VOICED_SOUND = 0x8e;
+ /** @since 1.2 */
+ int VK_DEAD_SEMIVOICED_SOUND = 0x8f;
+
+ /** @since 1.2 */
+ int VK_AMPERSAND = 0x96;
+ /** @since 1.2 */
+ int VK_ASTERISK = 0x97;
+ /** @since 1.2 */
+ int VK_QUOTEDBL = 0x98;
+ /** @since 1.2 */
+ int VK_LESS = 0x99;
+
+ /** @since 1.2 */
+ int VK_GREATER = 0xa0;
+ /** @since 1.2 */
+ int VK_BRACELEFT = 0xa1;
+ /** @since 1.2 */
+ int VK_BRACERIGHT = 0xa2;
+
+ /**
+ * Constant for the "@" key.
+ * @since 1.2
+ */
+ int VK_AT = 0x0200;
+
+ /**
+ * Constant for the ":" key.
+ * @since 1.2
+ */
+ int VK_COLON = 0x0201;
+
+ /**
+ * Constant for the "^" key.
+ * @since 1.2
+ */
+ int VK_CIRCUMFLEX = 0x0202;
+
+ /**
+ * Constant for the "$" key.
+ * @since 1.2
+ */
+ int VK_DOLLAR = 0x0203;
+
+ /**
+ * Constant for the Euro currency sign key.
+ * @since 1.2
+ */
+ int VK_EURO_SIGN = 0x0204;
+
+ /**
+ * Constant for the "!" key.
+ * @since 1.2
+ */
+ int VK_EXCLAMATION_MARK = 0x0205;
+
+ /**
+ * Constant for the inverted exclamation mark key.
+ * @since 1.2
+ */
+ int VK_INVERTED_EXCLAMATION_MARK = 0x0206;
+
+ /**
+ * Constant for the "(" key.
+ * @since 1.2
+ */
+ int VK_LEFT_PARENTHESIS = 0x0207;
+
+ /**
+ * Constant for the "#" key.
+ * @since 1.2
+ */
+ int VK_NUMBER_SIGN = 0x0208;
+
+ /**
+ * Constant for the "+" key.
+ * @since 1.2
+ */
+ int VK_PLUS = 0x0209;
+
+ /**
+ * Constant for the ")" key.
+ * @since 1.2
+ */
+ int VK_RIGHT_PARENTHESIS = 0x020A;
+
+ /**
+ * Constant for the "_" key.
+ * @since 1.2
+ */
+ int VK_UNDERSCORE = 0x020B;
+
+ /**
+ * Constant for the Microsoft Windows "Windows" key.
+ * It is used for both the left and right version of the key.
+ * @see #getKeyLocation()
+ * @since 1.5
+ */
+ int VK_WINDOWS = 0x020C;
+
+ /**
+ * Constant for the Microsoft Windows Context Menu key.
+ * @since 1.5
+ */
+ int VK_CONTEXT_MENU = 0x020D;
+
+ /* for input method support on Asian Keyboards */
+
+ /* not clear what this means - listed in Microsoft Windows API */
+ int VK_FINAL = 0x0018;
+
+ /** Constant for the Convert function key. */
+ /* Japanese PC 106 keyboard, Japanese Solaris keyboard: henkan */
+ int VK_CONVERT = 0x001C;
+
+ /** Constant for the Don't Convert function key. */
+ /* Japanese PC 106 keyboard: muhenkan */
+ int VK_NONCONVERT = 0x001D;
+
+ /** Constant for the Accept or Commit function key. */
+ /* Japanese Solaris keyboard: kakutei */
+ int VK_ACCEPT = 0x001E;
+
+ /* not clear what this means - listed in Microsoft Windows API */
+ int VK_MODECHANGE = 0x001F;
+
+ /* replaced by VK_KANA_LOCK for Microsoft Windows and Solaris;
+ might still be used on other platforms */
+ int VK_KANA = 0x0015;
+
+ /* replaced by VK_INPUT_METHOD_ON_OFF for Microsoft Windows and Solaris;
+ might still be used for other platforms */
+ int VK_KANJI = 0x0019;
+
+ /**
+ * Constant for the Alphanumeric function key.
+ * @since 1.2
+ */
+ /* Japanese PC 106 keyboard: eisuu */
+ int VK_ALPHANUMERIC = 0x00F0;
+
+ /**
+ * Constant for the Katakana function key.
+ * @since 1.2
+ */
+ /* Japanese PC 106 keyboard: katakana */
+ int VK_KATAKANA = 0x00F1;
+
+ /**
+ * Constant for the Hiragana function key.
+ * @since 1.2
+ */
+ /* Japanese PC 106 keyboard: hiragana */
+ int VK_HIRAGANA = 0x00F2;
+
+ /**
+ * Constant for the Full-Width Characters function key.
+ * @since 1.2
+ */
+ /* Japanese PC 106 keyboard: zenkaku */
+ int VK_FULL_WIDTH = 0x00F3;
+
+ /**
+ * Constant for the Half-Width Characters function key.
+ * @since 1.2
+ */
+ /* Japanese PC 106 keyboard: hankaku */
+ int VK_HALF_WIDTH = 0x00F4;
+
+ /**
+ * Constant for the Roman Characters function key.
+ * @since 1.2
+ */
+ /* Japanese PC 106 keyboard: roumaji */
+ int VK_ROMAN_CHARACTERS = 0x00F5;
+
+ /**
+ * Constant for the All Candidates function key.
+ * @since 1.2
+ */
+ /* Japanese PC 106 keyboard - VK_CONVERT + ALT: zenkouho */
+ int VK_ALL_CANDIDATES = 0x0100;
+
+ /**
+ * Constant for the Previous Candidate function key.
+ * @since 1.2
+ */
+ /* Japanese PC 106 keyboard - VK_CONVERT + SHIFT: maekouho */
+ int VK_PREVIOUS_CANDIDATE = 0x0101;
+
+ /**
+ * Constant for the Code Input function key.
+ * @since 1.2
+ */
+ /* Japanese PC 106 keyboard - VK_ALPHANUMERIC + ALT: kanji bangou */
+ int VK_CODE_INPUT = 0x0102;
+
+ /**
+ * Constant for the Japanese-Katakana function key.
+ * This key switches to a Japanese input method and selects its Katakana input mode.
+ * @since 1.2
+ */
+ /* Japanese Macintosh keyboard - VK_JAPANESE_HIRAGANA + SHIFT */
+ int VK_JAPANESE_KATAKANA = 0x0103;
+
+ /**
+ * Constant for the Japanese-Hiragana function key.
+ * This key switches to a Japanese input method and selects its Hiragana input mode.
+ * @since 1.2
+ */
+ /* Japanese Macintosh keyboard */
+ int VK_JAPANESE_HIRAGANA = 0x0104;
+
+ /**
+ * Constant for the Japanese-Roman function key.
+ * This key switches to a Japanese input method and selects its Roman-Direct input mode.
+ * @since 1.2
+ */
+ /* Japanese Macintosh keyboard */
+ int VK_JAPANESE_ROMAN = 0x0105;
+
+ /**
+ * Constant for the locking Kana function key.
+ * This key locks the keyboard into a Kana layout.
+ * @since 1.3
+ */
+ /* Japanese PC 106 keyboard with special Windows driver - eisuu + Control; Japanese Solaris keyboard: kana */
+ int VK_KANA_LOCK = 0x0106;
+
+ /**
+ * Constant for the input method on/off key.
+ * @since 1.3
+ */
+ /* Japanese PC 106 keyboard: kanji. Japanese Solaris keyboard: nihongo */
+ int VK_INPUT_METHOD_ON_OFF = 0x0107;
+
+ /* for Sun keyboards */
+ /** @since 1.2 */
+ int VK_CUT = 0xFFD1;
+ /** @since 1.2 */
+ int VK_COPY = 0xFFCD;
+ /** @since 1.2 */
+ int VK_PASTE = 0xFFCF;
+ /** @since 1.2 */
+ int VK_UNDO = 0xFFCB;
+ /** @since 1.2 */
+ int VK_AGAIN = 0xFFC9;
+ /** @since 1.2 */
+ int VK_FIND = 0xFFD0;
+ /** @since 1.2 */
+ int VK_PROPS = 0xFFCA;
+ /** @since 1.2 */
+ int VK_STOP = 0xFFC8;
+
+ /**
+ * Constant for the Compose function key.
+ * @since 1.2
+ */
+ int VK_COMPOSE = 0xFF20;
+
+ /**
+ * Constant for the AltGraph function key.
+ * @since 1.2
+ */
+ int VK_ALT_GRAPH = 0xFF7E;
+
+ /**
+ * Constant for the Begin key.
+ * @since 1.5
+ */
+ int VK_BEGIN = 0xFF58;
+
+ /**
+ * This value is used to indicate that the keyCode is unknown.
+ * KEY_TYPED events do not have a keyCode value; this value
+ * is used instead.
+ */
+ int VK_UNDEFINED = 0x0;
+
+ /**
+ * KEY_PRESSED and KEY_RELEASED events which do not map to a
+ * valid Unicode character use this for the keyChar value.
+ */
+ char CHAR_UNDEFINED = 0xFFFF;
+
+ /**
+ * A constant indicating that the keyLocation is indeterminate
+ * or not relevant.
+ * KEY_TYPED events do not have a keyLocation; this value
+ * is used instead.
+ * @since 1.4
+ */
+ int KEY_LOCATION_UNKNOWN = 0;
+
+ /**
+ * A constant indicating that the key pressed or released
+ * is not distinguished as the left or right version of a key,
+ * and did not originate on the numeric keypad (or did not
+ * originate with a virtual key corresponding to the numeric
+ * keypad).
+ * @since 1.4
+ */
+ int KEY_LOCATION_STANDARD = 1;
+
+ /**
+ * A constant indicating that the key pressed or released is in
+ * the left key location (there is more than one possible location
+ * for this key). Example: the left shift key.
+ * @since 1.4
+ */
+ int KEY_LOCATION_LEFT = 2;
+
+ /**
+ * A constant indicating that the key pressed or released is in
+ * the right key location (there is more than one possible location
+ * for this key). Example: the right shift key.
+ * @since 1.4
+ */
+ int KEY_LOCATION_RIGHT = 3;
+
+ /**
+ * A constant indicating that the key event originated on the
+ * numeric keypad or with a virtual key corresponding to the
+ * numeric keypad.
+ * @since 1.4
+ */
+ int KEY_LOCATION_NUMPAD = 4;
+}
diff --git a/core/src/main/java/it/cavallium/warppi/device/PIHardwareDisplay.java b/core/src/main/java/it/cavallium/warppi/device/PIHardwareDisplay.java
index 8a506681..f652581e 100644
--- a/core/src/main/java/it/cavallium/warppi/device/PIHardwareDisplay.java
+++ b/core/src/main/java/it/cavallium/warppi/device/PIHardwareDisplay.java
@@ -13,7 +13,7 @@ public class PIHardwareDisplay implements HardwareDisplay {
@Override
public void setBrightness(final double value) {
- if (Engine.getPlatform().getSettings().isDebugEnabled() == false) {
+ if (Engine.getPlatform().isRunningOnRaspberry()) {
Engine.getPlatform().getGpio().pwmWrite(12, (int) Math.ceil(value * 1024f));
// SoftPwm.softPwmWrite(12, (int)(Math.ceil(brightness*10)));
} else {
diff --git a/core/src/main/java/it/cavallium/warppi/device/graphicengine/RAWFont.java b/core/src/main/java/it/cavallium/warppi/device/graphicengine/RAWFont.java
index 1be75b02..d344d79a 100644
--- a/core/src/main/java/it/cavallium/warppi/device/graphicengine/RAWFont.java
+++ b/core/src/main/java/it/cavallium/warppi/device/graphicengine/RAWFont.java
@@ -1,7 +1,5 @@
package it.cavallium.warppi.device.graphicengine;
-import java.awt.image.BufferedImage;
-import java.awt.image.DataBufferInt;
import java.io.File;
import java.io.IOException;
import java.lang.ref.WeakReference;
@@ -9,8 +7,6 @@ import java.net.URL;
import java.util.logging.Level;
import java.util.logging.Logger;
-import javax.imageio.ImageIO;
-
import it.cavallium.warppi.Engine;
import it.cavallium.warppi.util.ClassUtils;
import it.cavallium.warppi.util.Utils;
@@ -135,18 +131,6 @@ public class RAWFont {
return indexes;
}
- @SuppressWarnings("unused")
- private void saveArray(final int[] screen, final 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 void drawText(final int[] screen, final int[] screenSize, final int x, final int y, final int[] text,
final int color) {
final int screenLength = screen.length;
diff --git a/core/src/main/java/it/cavallium/warppi/extra/mario/MarioScreen.java b/core/src/main/java/it/cavallium/warppi/extra/mario/MarioScreen.java
index 70f9a000..a7a310f1 100644
--- a/core/src/main/java/it/cavallium/warppi/extra/mario/MarioScreen.java
+++ b/core/src/main/java/it/cavallium/warppi/extra/mario/MarioScreen.java
@@ -7,6 +7,7 @@ import it.cavallium.warppi.StaticVars;
import it.cavallium.warppi.Platform.ConsoleUtils;
import it.cavallium.warppi.device.Keyboard;
import it.cavallium.warppi.event.KeyPressedEvent;
+import it.cavallium.warppi.event.KeyReleasedEvent;
import it.cavallium.warppi.gui.HistoryBehavior;
import it.cavallium.warppi.gui.graphicengine.BinaryFont;
import it.cavallium.warppi.gui.graphicengine.Skin;
@@ -43,6 +44,43 @@ public class MarioScreen extends Screen {
historyBehavior = HistoryBehavior.ALWAYS_KEEP_IN_HISTORY;
}
+ @Override
+ public void graphicInitialized() {
+ try {
+ if (MarioScreen.skin == null) {
+ MarioScreen.skin = Engine.INSTANCE.getHardwareDevice().getDisplayManager().engine.loadSkin("/marioskin.png");
+ }
+ if (MarioScreen.groundskin == null) {
+ MarioScreen.groundskin = Engine.INSTANCE.getHardwareDevice().getDisplayManager().engine.loadSkin("/marioground.png");
+ }
+ if (MarioScreen.gpuTest2 == null) {
+ try {
+ MarioScreen.gpuTest2 = Engine.INSTANCE.getHardwareDevice().getDisplayManager().engine.loadFont("N:\\gputest\\gputest2");
+ } catch (final Exception ex) {}
+ }
+ if (MarioScreen.gpuTest1 == null) {
+ try {
+ MarioScreen.gpuTest1 = Engine.INSTANCE.getHardwareDevice().getDisplayManager().engine.loadFont("N:\\gputest\\gputest12");
+ MarioScreen.gpuTest12 = true;
+ } catch (final Exception ex) {
+ MarioScreen.gpuTest12 = false;
+ try {
+ MarioScreen.gpuTest1 = Engine.INSTANCE.getHardwareDevice().getDisplayManager().engine.loadFont("N:\\gputest\\gputest1");
+ } catch (final Exception ex2) {}
+ }
+ }
+ if (MarioScreen.gpuTest3 == null) {
+ try {
+ MarioScreen.gpuTest3 = Engine.INSTANCE.getHardwareDevice().getDisplayManager().engine.loadSkin("N:\\gputest\\font_gputest3.png");
+ } catch (final Exception ex) {
+ ex.printStackTrace();
+ }
+ }
+ } catch (final IOException e) {
+ e.printStackTrace();
+ }
+ }
+
@Override
public void initialized() {
try {
@@ -87,12 +125,49 @@ public class MarioScreen extends Screen {
}
}
+ boolean rightPressed, leftPressed, jumpPressed;
+
+ @Override
+ public boolean onKeyPressed(KeyPressedEvent k) {
+ switch(k.getKey()) {
+ case OK:
+ case SIMPLIFY:
+ case STEP:
+ jumpPressed = true;
+ return true;
+ case LEFT:
+ leftPressed = true;
+ return true;
+ case RIGHT:
+ rightPressed = true;
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ @Override
+ public boolean onKeyReleased(KeyReleasedEvent k) {
+ switch(k.getKey()) {
+ case OK:
+ case SIMPLIFY:
+ case STEP:
+ jumpPressed = false;
+ return true;
+ case LEFT:
+ leftPressed = false;
+ return true;
+ case RIGHT:
+ rightPressed = false;
+ return true;
+ default:
+ return false;
+ }
+ }
+
@Override
public void beforeRender(final float dt) {
if (!errored) {
- final boolean rightPressed = Keyboard.isKeyDown(2, 5);
- final boolean leftPressed = Keyboard.isKeyDown(2, 3);
- final boolean jumpPressed = Keyboard.isKeyDown(2, 1);
final boolean upPressed = false, downPressed = false, runPressed = false;
g.gameTick(dt, upPressed, downPressed, leftPressed, rightPressed, jumpPressed, runPressed);
diff --git a/core/src/main/java/it/cavallium/warppi/extra/tetris/BlockType.java b/core/src/main/java/it/cavallium/warppi/extra/tetris/BlockColor.java
similarity index 62%
rename from core/src/main/java/it/cavallium/warppi/extra/tetris/BlockType.java
rename to core/src/main/java/it/cavallium/warppi/extra/tetris/BlockColor.java
index c359f9dd..cc784d60 100644
--- a/core/src/main/java/it/cavallium/warppi/extra/tetris/BlockType.java
+++ b/core/src/main/java/it/cavallium/warppi/extra/tetris/BlockColor.java
@@ -1,10 +1,11 @@
-package it.cavallium.warppi.extra.tetris;
-
-public enum BlockType {
- RED,
- GREEN,
- YELLOW,
- BLUE,
- ORANGE,
- VIOLET
-}
+package it.cavallium.warppi.extra.tetris;
+
+public enum BlockColor {
+ RED,
+ GREEN,
+ BLUE,
+ YELLOW,
+ ORANGE,
+ PURPLE,
+ CYAN
+}
diff --git a/core/src/main/java/it/cavallium/warppi/extra/tetris/ButtonInfo.java b/core/src/main/java/it/cavallium/warppi/extra/tetris/ButtonInfo.java
new file mode 100644
index 00000000..33ec0ddc
--- /dev/null
+++ b/core/src/main/java/it/cavallium/warppi/extra/tetris/ButtonInfo.java
@@ -0,0 +1,38 @@
+package it.cavallium.warppi.extra.tetris;
+
+public class ButtonInfo {
+
+ public volatile int pressedCount = 0;
+ public volatile int releasedCount = 0;
+ public volatile int unreadCount = 0;
+
+ public ButtonInfo() {
+
+ }
+
+ public void press() {
+ if (pressedCount <= releasedCount) {
+ pressedCount = releasedCount + 1;
+ unreadCount++;
+ }
+ }
+
+ public void release() {
+ releasedCount++;
+ pressedCount = releasedCount;
+ }
+
+ public int readPressed() {
+ int val = unreadCount;
+ unreadCount = 0;
+ return val;
+ }
+
+ public boolean hasUnreadData() {
+ return unreadCount > 0;
+ }
+
+ public boolean isPressedNow() {
+ return pressedCount > releasedCount;
+ }
+}
diff --git a/core/src/main/java/it/cavallium/warppi/extra/tetris/MarioBlock.java b/core/src/main/java/it/cavallium/warppi/extra/tetris/MarioBlock.java
deleted file mode 100644
index d463e236..00000000
--- a/core/src/main/java/it/cavallium/warppi/extra/tetris/MarioBlock.java
+++ /dev/null
@@ -1,33 +0,0 @@
-package it.cavallium.warppi.extra.tetris;
-
-public class MarioBlock {
- private final int x;
- private final int y;
- private final byte id;
-
- public MarioBlock(final int x, final int y, final byte b) {
- this.x = x;
- this.y = y;
- id = b;
- }
-
- public boolean isSolid() {
- return MarioBlock.isSolid(id);
- }
-
- public byte getID() {
- return id;
- }
-
- public int getX() {
- return x;
- }
-
- public int getY() {
- return y;
- }
-
- public static boolean isSolid(final byte id) {
- return id != 0b0;
- }
-}
diff --git a/core/src/main/java/it/cavallium/warppi/extra/tetris/MarioEnemy.java b/core/src/main/java/it/cavallium/warppi/extra/tetris/MarioEnemy.java
deleted file mode 100644
index e6b5c120..00000000
--- a/core/src/main/java/it/cavallium/warppi/extra/tetris/MarioEnemy.java
+++ /dev/null
@@ -1,9 +0,0 @@
-package it.cavallium.warppi.extra.tetris;
-
-public class MarioEnemy extends MarioEntity {
-
- public MarioEnemy(final double x, final double y, final double forceX, final double forceY, final boolean onGround, final boolean subjectToGravity) {
- super(x, y, forceX, forceY, onGround, subjectToGravity);
- }
-
-}
diff --git a/core/src/main/java/it/cavallium/warppi/extra/tetris/MarioEntity.java b/core/src/main/java/it/cavallium/warppi/extra/tetris/MarioEntity.java
deleted file mode 100644
index c563449f..00000000
--- a/core/src/main/java/it/cavallium/warppi/extra/tetris/MarioEntity.java
+++ /dev/null
@@ -1,85 +0,0 @@
-package it.cavallium.warppi.extra.tetris;
-
-public class MarioEntity {
- protected double x;
- protected double y;
- public double forceX;
- public double forceY;
- public boolean collisionUp;
- public boolean collisionDown;
- public boolean collisionLeft;
- public boolean collisionRight;
- public boolean subjectToGravity;
-
- public MarioEntity(final double x, final double y, final double forceX, final double forceY, final boolean onGround, final boolean subjectToGravity) {
- this.x = x;
- this.y = y;
- this.forceX = forceX;
- this.forceY = forceY;
- collisionDown = onGround;
- this.subjectToGravity = subjectToGravity;
- }
-
- public void setPosition(final double x, final double y) {
- this.x = x;
- this.y = y;
- }
-
- public void setPosition(final double x, final double y, final boolean onGround) {
- this.x = x;
- this.y = y;
- collisionDown = onGround;
- }
-
- public double getX() {
- return x;
- }
-
- public double getY() {
- return y;
- }
-
- public boolean isOnGround() {
- return collisionDown;
- }
-
- public void setOnGround(final boolean onGround) {
- collisionDown = onGround;
- }
-
- public void gameTick(final double dt) {
- x = computeFutureDX(dt);
- y = computeFutureDY(dt);
- forceX = computeFutureForceDX(dt);
- forceY = computeFutureForceDY(dt);
- }
-
- public double computeFutureDX(final double dt) {
- return x + dt * forceX - x;
- }
-
- public double computeFutureDY(final double dt) {
- final double forceY = this.forceY;
- double y = this.y;
- if (!collisionDown) {
- y += dt * forceY;
- }
- return y - this.y;
- }
-
- public double computeFutureForceDX(final double dt) {
- double forceX = this.forceX;
- forceX *= 0.75;
- return forceX - this.forceX;
- }
-
- public double computeFutureForceDY(final double dt) {
- double forceY = this.forceY;
- if (subjectToGravity && !collisionDown) {
- forceY -= dt * 1569.6 / 16f;
- } else {
- forceY *= 0.75;
- }
- return forceY - this.forceY;
- }
-}
diff --git a/core/src/main/java/it/cavallium/warppi/extra/tetris/MarioEvent.java b/core/src/main/java/it/cavallium/warppi/extra/tetris/MarioEvent.java
deleted file mode 100644
index 9a2023c5..00000000
--- a/core/src/main/java/it/cavallium/warppi/extra/tetris/MarioEvent.java
+++ /dev/null
@@ -1,5 +0,0 @@
-package it.cavallium.warppi.extra.tetris;
-
-public class MarioEvent {
-
-}
diff --git a/core/src/main/java/it/cavallium/warppi/extra/tetris/MarioWorld.java b/core/src/main/java/it/cavallium/warppi/extra/tetris/MarioWorld.java
deleted file mode 100644
index 5166e236..00000000
--- a/core/src/main/java/it/cavallium/warppi/extra/tetris/MarioWorld.java
+++ /dev/null
@@ -1,69 +0,0 @@
-package it.cavallium.warppi.extra.tetris;
-
-public class MarioWorld {
-
- private final int[] spawnPoint;
- private final int width;
- private final int height;
- private final byte[][] data;
- @SuppressWarnings("unused")
- private final MarioEvent[] events;
- private final MarioEntity[] entities;
-
- /**
- * @param width
- * @param height
- * @param data
- * @param events
- * @param marioEnemies
- */
- public MarioWorld(final int[] spawnPoint, final int width, final int height, final byte[][] data, final MarioEvent[] events, final MarioEntity[] entities) {
- this.spawnPoint = spawnPoint;
- this.width = width;
- this.height = height;
- this.data = data;
- this.events = events;
- this.entities = entities;
- }
-
- public byte getBlockIdAt(final int x, final int y) {
- final int idy = height - 1 - y;
- if (idy < 0 || idy >= data.length) {
- return 0b0;
- }
- final int idx = x;
- if (idx < 0 || idx >= data[0].length) {
- return 0b0;
- }
- return data[idy][idx];
- }
-
- public MarioBlock getBlockAt(final int x, final int y) {
- return new MarioBlock(x, y, getBlockIdAt(x, y));
- }
-
- public int getWidth() {
- return width;
- }
-
- public int getHeight() {
- return height;
- }
-
- public void reset() {
-
- }
-
- public double getSpawnPointX() {
- return spawnPoint[0];
- }
-
- public double getSpawnPointY() {
- return spawnPoint[1];
- }
-
- public MarioEntity[] getEntities() {
- return entities;
- }
-
-}
diff --git a/core/src/main/java/it/cavallium/warppi/extra/tetris/PlayerEntity.java b/core/src/main/java/it/cavallium/warppi/extra/tetris/PlayerEntity.java
deleted file mode 100644
index e74655b1..00000000
--- a/core/src/main/java/it/cavallium/warppi/extra/tetris/PlayerEntity.java
+++ /dev/null
@@ -1,138 +0,0 @@
-package it.cavallium.warppi.extra.tetris;
-
-public class PlayerEntity extends MarioEntity {
-
- @SuppressWarnings("unused")
- private final int life;
- public float walkAnimation = 0;
- public float jumptime = 0;
- public boolean walking = false;
- public boolean running = false;
- public boolean jumping = false;
- public boolean flipped = false;
- public int[] marioSkinPos = new int[] { 0, 0 };
- private double controllerDX;
- private double controllerDY;
-
- public PlayerEntity(final double x, final double y, final int life) {
- super(x, y, 0, 0, true, true);
- this.life = life;
- }
-
- @Override
- public void gameTick(final double dt) {
- walkAnimation += dt;
- x += computeFutureDX(dt);
- y += computeFutureDY(dt);
- forceX += computeFutureForceDX(dt);
- forceY += computeFutureForceDY(dt);
- if (controllerDX == 0) {
- walking = false;
- walkAnimation = 0;
- } else {
- if (controllerDX > 0) { //RIGHT
- walking = true;
- flipped = false;
- }
- if (controllerDX < 0) { //LEFT
- walking = true;
- flipped = true;
- }
- }
- if (controllerDY > 0) { //JUMP
- if (collisionUp) {
- jumptime = Float.MAX_VALUE;
- jumping = false;
- }
- jumptime += dt;
- if (jumptime <= 0.5f && !jumping && collisionDown) {
- jumping = true;
- collisionDown = false;
- } else if (jumptime <= 0.5f) {} else {
- jumping = false;
- }
- } else {
- jumping = false;
- if (collisionDown) {
- jumptime = 0;
- } else {
- jumptime = Float.MAX_VALUE;
- }
- }
- if (!walking & !running & !jumping) {
- marioSkinPos[0] = 0;
- marioSkinPos[1] = 0;
- } else if (collisionDown & walking & !running & !jumping && walkAnimation >= 0.08) {
- while (walkAnimation > 0.08) {
- walkAnimation -= 0.08;
- if (marioSkinPos[0] == 1 & marioSkinPos[1] == 0) {
- marioSkinPos[0] += 2;
- } else if (marioSkinPos[0] == 3 & marioSkinPos[1] == 0) {
- marioSkinPos[0] -= 1;
- } else if (marioSkinPos[0] == 2 & marioSkinPos[1] == 0) {
- marioSkinPos[0] -= 1;
- } else {
- marioSkinPos[0] = 1;
- marioSkinPos[1] = 0;
- }
- }
- } else if (jumping) {
- marioSkinPos[0] = 5;
- marioSkinPos[1] = 1;
- }
- }
-
- @Override
- public double computeFutureDX(final double dt) {
- return super.computeFutureDX(dt);
- }
-
- public double computeFuturedDY(final double dt) {
- return super.computeFutureDY(dt);
- }
-
- @Override
- public double computeFutureForceDX(final double dt) {
- double forceX = this.forceX;
- if (controllerDX == 0) {} else {
- if (controllerDX > 0) {
- if (forceX < 500f / 16f) {
- forceX += dt * 500f / 16f;
- }
- }
- if (controllerDX < 0) {
- if (forceX > -500f / 16f) {
- forceX -= dt * 500f / 16f;
- }
- }
- }
-
- return forceX + super.computeFutureForceDX(dt) - this.forceX;
- }
-
- @Override
- public double computeFutureForceDY(final double dt) {
- float jumptime = this.jumptime;
- double forceY = this.forceY;
- if (controllerDY > 0) { //JUMP
- if (collisionUp) {
- jumptime = Float.MAX_VALUE;
- }
- jumptime += dt;
- if (jumptime <= 0.5f && !jumping && collisionDown) {
- forceY = dt * (4 * 1569.6f) / 16f;
- } else if (jumptime <= 0.5f) {
- forceY = dt * (4 * 1569.6f) / 16f;
- }
- }
- return forceY + super.computeFutureForceDY(dt) - this.forceY;
- }
-
- public void move(final float dt, final double dX, final double dY) {
- walkAnimation += dt;
-
- controllerDX = dX;
- controllerDY = dY;
- }
-
-}
diff --git a/core/src/main/java/it/cavallium/warppi/extra/tetris/PositionEvent.java b/core/src/main/java/it/cavallium/warppi/extra/tetris/PositionEvent.java
deleted file mode 100644
index ad8ebd03..00000000
--- a/core/src/main/java/it/cavallium/warppi/extra/tetris/PositionEvent.java
+++ /dev/null
@@ -1,5 +0,0 @@
-package it.cavallium.warppi.extra.tetris;
-
-public class PositionEvent extends MarioEvent {
-
-}
diff --git a/core/src/main/java/it/cavallium/warppi/extra/tetris/TetrisGame.java b/core/src/main/java/it/cavallium/warppi/extra/tetris/TetrisGame.java
index 3a3bc5a9..505d71c2 100644
--- a/core/src/main/java/it/cavallium/warppi/extra/tetris/TetrisGame.java
+++ b/core/src/main/java/it/cavallium/warppi/extra/tetris/TetrisGame.java
@@ -1,21 +1,234 @@
package it.cavallium.warppi.extra.tetris;
+import java.util.Arrays;
+
public class TetrisGame {
- private static final int WIDTH = 10, HEIGHT = 22;
- private BlockType[] grid;
- private BlockType[] hovergrid;
- private GameStatus gameStatus = GameStatus.INITIAL;
- private int score = 0;
-
+ public static final int WIDTH = 10, HEIGHT = 22;
+ public static final double TICK_TIME = 0.25, DOWN_TIME = 0.10, MOVE_TIMER = 0.125;
+ private double tickTimer, downTimer, leftTimer, rightTimer, upTimer;
+ private BlockColor[] grid;
+ private BlockColor[] hovergrid;
+ private volatile BlockColor[] renderedGrid;
+ private GameStatus gameStatus;
+ private int score;
+ private double currentTime;
+ private Tetromino currentTetromino;
+ private Tetromino nextTetromino;
+
public TetrisGame() {
-
+ resetVariables();
}
- private void playAgain() {
- grid = new BlockType[WIDTH * HEIGHT];
- hovergrid = new BlockType[WIDTH * HEIGHT];
- score = 0;
+ void playAgain() {
+ resetVariables();
gameStatus = GameStatus.PLAYING;
+ placeNextTetromino();
+ }
+
+ private void resetVariables() {
+ grid = new BlockColor[WIDTH * HEIGHT];
+ hovergrid = new BlockColor[WIDTH * HEIGHT];
+ renderedGrid = new BlockColor[WIDTH * HEIGHT];
+ score = 0;
+ currentTime = 0;
+ tickTimer = 0;
+ gameStatus = GameStatus.INITIAL;
+ currentTetromino = null;
+ nextTetromino = generateRandomTetromino();
+ nextTetromino.fixInitialPosition();
+ }
+
+ public void update(float dt, ButtonInfo leftPressed, ButtonInfo rightPressed, ButtonInfo downPressed,
+ ButtonInfo upPressed, ButtonInfo okPressed, ButtonInfo backPressed) {
+ currentTime += dt;
+ tickTimer += dt;
+ leftTimer += dt;
+ rightTimer += dt;
+ downTimer += dt;
+ upTimer += dt;
+ if (leftPressed.hasUnreadData()) {
+ for (int i = leftPressed.readPressed(); i > 0; i--) {
+ move(this.currentTetromino, -1, 0, 0);
+ }
+ leftTimer = -MOVE_TIMER;
+ } else if (leftPressed.isPressedNow()) {
+ while (leftTimer >= MOVE_TIMER) {
+ leftTimer -= MOVE_TIMER;
+ move(this.currentTetromino, -1, 0, 0);
+ }
+ } else {
+ leftTimer = 0;
+ }
+ if (rightPressed.hasUnreadData()) {
+ for (int i = rightPressed.readPressed(); i > 0; i--) {
+ move(this.currentTetromino, 1, 0, 0);
+ }
+ rightTimer = -MOVE_TIMER;
+ } else if (rightPressed.isPressedNow()) {
+ while (rightTimer >= MOVE_TIMER) {
+ rightTimer -= MOVE_TIMER;
+ move(this.currentTetromino, 1, 0, 0);
+ }
+ } else {
+ rightTimer = 0;
+ }
+ if (upPressed.hasUnreadData()) {
+ for (int i = upPressed.readPressed(); i > 0; i--) {
+ move(this.currentTetromino, 0, 0, 1);
+ }
+ upTimer = -MOVE_TIMER;
+ } else if (upPressed.isPressedNow()) {
+ while (upTimer >= MOVE_TIMER) {
+ upTimer -= MOVE_TIMER;
+ move(this.currentTetromino, 0, 0, 1);
+ }
+ } else {
+ upTimer = 0;
+ }
+ if (downPressed.isPressedNow()) {
+ downPressed.readPressed();
+ while (downTimer >= DOWN_TIME) {
+ downTimer -= DOWN_TIME;
+ move(this.currentTetromino, 0, 1, 0);
+ }
+ } else {
+ downTimer = 0;
+ }
+ while (tickTimer >= TICK_TIME) {
+ tickTimer -= TICK_TIME;
+ gameTick(leftPressed, rightPressed, downPressed, okPressed, backPressed);
+ }
+ if (gameStatus == GameStatus.INITIAL) {
+ playAgain();
+ } else {
+
+ }
+ renderGrid();
+ }
+
+ public void gameTick(ButtonInfo leftPressed, ButtonInfo rightPressed, ButtonInfo downPressed, ButtonInfo okPressed,
+ ButtonInfo backPressed) {
+ if (move(this.currentTetromino, 0, 1, 0)) {
+
+ } else {
+ // Spawn new tetromino and write the old to the permanent grid
+ drawCurrentTetromino(grid);
+ checkLines();
+ placeNextTetromino();
+ if (move(this.currentTetromino, 0, 0, 0) == false) {
+ // Lose
+ this.gameStatus = GameStatus.LOST;
+ playAgain();
+ }
+ }
+ }
+
+ private void checkLines() {
+ for (int i = HEIGHT - 1; i >= 0; i--) {
+ boolean scored = true;
+ while (scored) {
+ for (int x = 0; x < WIDTH; x++) {
+ if (this.grid[x + i * WIDTH] == null) {
+ scored = false;
+ break;
+ }
+ }
+ if (scored) {
+ this.score += WIDTH;
+ for (int x = 0; x < WIDTH; x++) {
+ int y = i;
+ while (y > 0) {
+ this.grid[x + (y) * WIDTH] = this.grid[x + (y - 1) * WIDTH];
+ y--;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ private boolean move(Tetromino t, int dX, int dY, int dRotation) {
+ byte rot = (byte) ((t.getRotation() + dRotation) % 4);
+ boolean[] block = t.getRenderedBlock(rot);
+ int blockSize = t.getTetrominoGridSize();
+ int half1 = (int) Math.floor(((double) t.getTetrominoGridSize()) / 2d);
+ int half2 = blockSize - half1;
+ byte aX = (byte) (t.getX() + dX), aY = (byte) (t.getY() + dY);
+ int blockX = 0, blockY = 0;
+ for (int x = aX - half1; x < aX + half2; x++) {
+ for (int y = aY - half1; y < aY + half2; y++) {
+ if (block[blockX + blockY * blockSize] == true) {
+ if (x >= 0 & y >= 0 & x < WIDTH & (x + y * WIDTH) < this.grid.length) {
+ if (this.grid[x + y * WIDTH] != null) {
+ return false;
+ }
+ } else {
+ return false;
+ }
+ }
+ blockY++;
+ }
+ blockY = 0;
+ blockX++;
+ }
+ t.setRotation(rot);
+ t.setX(aX);
+ t.setY(aY);
+ return true;
+ }
+
+ public void renderGrid() {
+ this.renderedGrid = Arrays.copyOf(grid, grid.length);
+ drawCurrentTetromino(this.renderedGrid);
+ for (int y = 0; y < HEIGHT; y++) {
+ for (int x = 0; x < WIDTH; x++) {
+ final int offset = x + y * WIDTH;
+ renderedGrid[offset] = hovergrid[offset] != null ? hovergrid[offset] : renderedGrid[offset];
+ }
+ }
+ }
+
+ private void placeNextTetromino() {
+ currentTetromino = nextTetromino;
+ nextTetromino = generateRandomTetromino();
+ nextTetromino.fixInitialPosition();
+ }
+
+ private Tetromino generateRandomTetromino() {
+ int s = (int) (Math.random() * 7);
+ final byte middleX = (byte) ((WIDTH - 1) / 2), middleY = 0, rotation = (byte) (Math.random() * 4);
+ switch (s) {
+ case 0:
+ return new TetrominoICyan(middleX, middleY, rotation);
+ case 1:
+ return new TetrominoJBlue(middleX, middleY, rotation);
+ case 2:
+ return new TetrominoLOrange(middleX, middleY, rotation);
+ case 3:
+ return new TetrominoOYellow(middleX, middleY, rotation);
+ case 4:
+ return new TetrominoSGreen(middleX, middleY, rotation);
+ case 5:
+ return new TetrominoTPurple(middleX, middleY, rotation);
+ default:
+ return new TetrominoZRed(middleX, middleY, rotation);
+ }
+ }
+
+ public Tetromino getNextTetromino() {
+ return this.nextTetromino;
+ }
+
+ private void drawCurrentTetromino(BlockColor[] grid) {
+ currentTetromino.draw(grid, WIDTH);
+ }
+
+ public BlockColor[] getRenderedGrid() {
+ return renderedGrid;
+ }
+
+ public int getScore() {
+ return this.score;
}
}
diff --git a/core/src/main/java/it/cavallium/warppi/extra/tetris/TetrisScreen.java b/core/src/main/java/it/cavallium/warppi/extra/tetris/TetrisScreen.java
index 23dae466..64e954d2 100644
--- a/core/src/main/java/it/cavallium/warppi/extra/tetris/TetrisScreen.java
+++ b/core/src/main/java/it/cavallium/warppi/extra/tetris/TetrisScreen.java
@@ -5,8 +5,12 @@ import java.io.IOException;
import it.cavallium.warppi.Engine;
import it.cavallium.warppi.StaticVars;
import it.cavallium.warppi.device.Keyboard;
+import it.cavallium.warppi.event.KeyPressedEvent;
+import it.cavallium.warppi.event.KeyReleasedEvent;
import it.cavallium.warppi.gui.HistoryBehavior;
import it.cavallium.warppi.gui.graphicengine.BinaryFont;
+import it.cavallium.warppi.gui.graphicengine.GraphicEngine;
+import it.cavallium.warppi.gui.graphicengine.Renderer;
import it.cavallium.warppi.gui.graphicengine.Skin;
import it.cavallium.warppi.gui.screens.Screen;
@@ -14,6 +18,22 @@ public class TetrisScreen extends Screen {
private TetrisGame g;
+ private ButtonInfo leftPressed = new ButtonInfo();
+
+ private ButtonInfo rightPressed = new ButtonInfo();
+
+ private ButtonInfo upPressed = new ButtonInfo();
+
+ private ButtonInfo downPressed = new ButtonInfo();
+
+ private ButtonInfo okPressed = new ButtonInfo();
+
+ private ButtonInfo backPressed = new ButtonInfo();
+
+ private GraphicEngine e;
+
+ private Renderer r;
+
private static Skin skin;
public TetrisScreen() {
@@ -23,155 +43,143 @@ public class TetrisScreen extends Screen {
@Override
public void initialized() {
-// try {
-// if (TetrisScreen.skin == null) {
-// TetrisScreen.skin = Engine.INSTANCE.getHardwareDevice().getDisplayManager().engine.loadSkin("/marioskin.png");
-// }
-// if (TetrisScreen.groundskin == null) {
-// TetrisScreen.groundskin = Engine.INSTANCE.getHardwareDevice().getDisplayManager().engine.loadSkin("/marioground.png");
-// }
-// if (TetrisScreen.gpuTest2 == null) {
-// try {
-// TetrisScreen.gpuTest2 = Engine.INSTANCE.getHardwareDevice().getDisplayManager().engine.loadFont("N:\\gputest\\gputest2");
-// } catch (final Exception ex) {}
-// }
-// if (TetrisScreen.gpuTest1 == null) {
-// try {
-// TetrisScreen.gpuTest1 = Engine.INSTANCE.getHardwareDevice().getDisplayManager().engine.loadFont("N:\\gputest\\gputest12");
-// TetrisScreen.gpuTest12 = true;
-// } catch (final Exception ex) {
-// TetrisScreen.gpuTest12 = false;
-// try {
-// TetrisScreen.gpuTest1 = Engine.INSTANCE.getHardwareDevice().getDisplayManager().engine.loadFont("N:\\gputest\\gputest1");
-// } catch (final Exception ex2) {}
-// }
-// }
-// if (TetrisScreen.gpuTest3 == null) {
-// try {
-// TetrisScreen.gpuTest3 = Engine.INSTANCE.getHardwareDevice().getDisplayManager().engine.loadSkin("N:\\gputest\\font_gputest3.png");
-// } catch (final Exception ex) {
-// ex.printStackTrace();
-// }
-// }
-// } catch (final IOException e) {
-// e.printStackTrace();
-// }
+ StaticVars.windowZoom.onNext(2f);
+ }
+
+ @Override
+ public void graphicInitialized() {
+ try {
+ e = d.engine;
+ r = d.renderer;
+ if (TetrisScreen.skin == null) {
+ TetrisScreen.skin = Engine.INSTANCE.getHardwareDevice().getDisplayManager().engine.loadSkin("/tetrisskin.png");
+ }
+ } catch (final IOException e) {
+ e.printStackTrace();
+ }
}
@Override
public void created() throws InterruptedException {
-// if (!errored) {
-// g = new MarioGame();
-// }
+ g = new TetrisGame();
}
@Override
public void beforeRender(final float dt) {
-// if (!errored) {
-// final boolean rightPressed = Keyboard.isKeyDown(2, 5);
-// final boolean leftPressed = Keyboard.isKeyDown(2, 3);
-// final boolean jumpPressed = Keyboard.isKeyDown(2, 1);
-// final boolean upPressed = false, downPressed = false, runPressed = false;
-// g.gameTick(dt, upPressed, downPressed, leftPressed, rightPressed, jumpPressed, runPressed);
-//
-// gpuTestElapsed += dt;
-// while (gpuTestElapsed >= 0.04) {
-// gpuTestNum = (gpuTestNum + 1) % gpuTestMax;
-// gpuTestElapsed -= 0.04;
-// }
-// gpuCharTestt1Elapsed += dt;
-// while (gpuCharTestt1Elapsed >= 1.5) {
-// gpuCharTest1Num = (gpuCharTest1Num + 1) % gpuCharTest1.length;
-// gpuCharTestt1Elapsed -= 1.5;
-// }
-//
-// Engine.INSTANCE.getHardwareDevice().getDisplayManager().renderer.glClearColor(0xff000000);
-// }
+ Engine.INSTANCE.getHardwareDevice().getDisplayManager().renderer.glClearColor(0xff000000);
+ g.update(dt, leftPressed, rightPressed, downPressed, upPressed, okPressed, backPressed);
}
@Override
public void render() {
-// if (errored) {
-// Engine.INSTANCE.getHardwareDevice().getDisplayManager().renderer.glDrawStringLeft(0, 20, "ERROR");
-// } else {
-// if (TetrisScreen.groundskin != null) {
-// final double playerX = g.getPlayer().getX();
-// final double playerY = g.getPlayer().getY();
-// TetrisScreen.groundskin.use(Engine.INSTANCE.getHardwareDevice().getDisplayManager().engine);
-// final MarioWorld w = g.getCurrentWorld();
-// final int width = w.getWidth();
-// final int height = w.getHeight();
-// final float screenX = Engine.INSTANCE.getHardwareDevice().getDisplayManager().engine.getWidth() / 2f - 8f;
-// final float screenY = Engine.INSTANCE.getHardwareDevice().getDisplayManager().engine.getHeight() / 2f - 8f;
-// final float shiftX = -8 + 16 * (float) playerX;
-// final float shiftY = -8 + 16 * (height - (float) playerY);
-// int blue = -1;
-// for (int ix = 0; ix < width; ix++) {
-// for (int iy = 0; iy < height; iy++) {
-// final double distX = Math.abs(playerX - ix);
-// final double distY = Math.abs(playerY - iy - 1.5d);
-// if (distX * distX + distY * distY / 2d < 25d) {
-// final byte b = w.getBlockIdAt(ix, iy);
-// if (b == 0) {
-// if (blue != 1) {
-// blue = 1;
-// Engine.INSTANCE.getHardwareDevice().getDisplayManager().renderer.glColor(0xff9290ff);
-// }
-// Engine.INSTANCE.getHardwareDevice().getDisplayManager().renderer.glFillColor(screenX - shiftX + 16 * ix, screenY - shiftY + 16 * (height - iy), 16, 16);
-// } else {
-// if (blue != 0) {
-// blue = 0;
-// Engine.INSTANCE.getHardwareDevice().getDisplayManager().renderer.glColor(0xffffffff);
-// }
-// Engine.INSTANCE.getHardwareDevice().getDisplayManager().renderer.glFillRect(screenX - shiftX + 16 * ix, screenY - shiftY + 16 * (height - iy), 16, 16, 0, 0, 16, 16);
-// }
-// }
-// }
-// }
-// if (blue != 0) {
-// blue = 0;
-// Engine.INSTANCE.getHardwareDevice().getDisplayManager().renderer.glColor(0xffffffff);
-// }
-//
-// //DRAW MARIO
-// TetrisScreen.skin.use(Engine.INSTANCE.getHardwareDevice().getDisplayManager().engine);
-// Engine.INSTANCE.getHardwareDevice().getDisplayManager().renderer.glFillRect(screenX - (g.getPlayer().flipped ? 3 : 0), screenY, 35, 27, 35 * (g.getPlayer().marioSkinPos[0] + (g.getPlayer().flipped ? 2 : 1)), 27 * g.getPlayer().marioSkinPos[1], 35 * (g.getPlayer().flipped ? -1 : 1), 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);
-// }
-//
-//// GPU PERFORMANCE TEST
-// if (TetrisScreen.gpuTest1 != null) {
-// Engine.INSTANCE.getHardwareDevice().getDisplayManager().renderer.glColor3f(1, 1, 1);
-// Engine.INSTANCE.getHardwareDevice().getDisplayManager().renderer.glFillColor(Engine.INSTANCE.getHardwareDevice().getDisplayManager().engine.getWidth() - (TetrisScreen.gpuTest12 ? 512 : 256), Engine.INSTANCE.getHardwareDevice().getDisplayManager().engine.getHeight() / 2 - (TetrisScreen.gpuTest12 ? 256 : 128), TetrisScreen.gpuTest12 ? 512 : 256, TetrisScreen.gpuTest12 ? 512 : 256);
-// TetrisScreen.gpuTest1.use(Engine.INSTANCE.getHardwareDevice().getDisplayManager().engine);
-// Engine.INSTANCE.getHardwareDevice().getDisplayManager().renderer.glColor3f(0, 0, 0);
-// Engine.INSTANCE.getHardwareDevice().getDisplayManager().renderer.glDrawStringRight(Engine.INSTANCE.getHardwareDevice().getDisplayManager().engine.getWidth(), Engine.INSTANCE.getHardwareDevice().getDisplayManager().engine.getHeight() / 2 - (TetrisScreen.gpuTest12 ? 256 : 128), gpuCharTest1[gpuCharTest1Num]);
-// }
-// if (TetrisScreen.gpuTest3 != null) {
-// TetrisScreen.gpuTest3.use(Engine.INSTANCE.getHardwareDevice().getDisplayManager().engine);
-// Engine.INSTANCE.getHardwareDevice().getDisplayManager().renderer.glColor4f(1, 1, 1, 0.7f);
-// Engine.INSTANCE.getHardwareDevice().getDisplayManager().renderer.glFillRect(0, StaticVars.screenSize[1] - 128, 224, 128, gpuTestNum * 224, 0, 224, 128);
-// }
-// if (TetrisScreen.gpuTest2 != null) {
-// TetrisScreen.gpuTest2.use(Engine.INSTANCE.getHardwareDevice().getDisplayManager().engine);
-// Engine.INSTANCE.getHardwareDevice().getDisplayManager().renderer.glColor(0xFF000000);
-// Engine.INSTANCE.getHardwareDevice().getDisplayManager().renderer.glDrawStringRight(StaticVars.screenSize[0], Engine.INSTANCE.getHardwareDevice().getDisplayManager().engine.getHeight() - TetrisScreen.gpuTest2.getCharacterHeight(), "A");
-// Engine.INSTANCE.getHardwareDevice().getDisplayManager().renderer.glColor(0xFF800000);
-// Engine.INSTANCE.getHardwareDevice().getDisplayManager().renderer.glDrawStringRight(StaticVars.screenSize[0], Engine.INSTANCE.getHardwareDevice().getDisplayManager().engine.getHeight() - TetrisScreen.gpuTest2.getCharacterHeight(), "B");
-// Engine.INSTANCE.getHardwareDevice().getDisplayManager().renderer.glColor(0xFFeea28e);
-// Engine.INSTANCE.getHardwareDevice().getDisplayManager().renderer.glDrawStringRight(StaticVars.screenSize[0], Engine.INSTANCE.getHardwareDevice().getDisplayManager().engine.getHeight() - TetrisScreen.gpuTest2.getCharacterHeight(), "C");
-// Engine.INSTANCE.getHardwareDevice().getDisplayManager().renderer.glColor(0xFFee7255);
-// Engine.INSTANCE.getHardwareDevice().getDisplayManager().renderer.glDrawStringRight(StaticVars.screenSize[0], Engine.INSTANCE.getHardwareDevice().getDisplayManager().engine.getHeight() - TetrisScreen.gpuTest2.getCharacterHeight(), "D");
-// Engine.INSTANCE.getHardwareDevice().getDisplayManager().renderer.glColor(0xFFeac0b0);
-// Engine.INSTANCE.getHardwareDevice().getDisplayManager().renderer.glDrawStringRight(StaticVars.screenSize[0], Engine.INSTANCE.getHardwareDevice().getDisplayManager().engine.getHeight() - TetrisScreen.gpuTest2.getCharacterHeight(), "E");
-// Engine.INSTANCE.getHardwareDevice().getDisplayManager().renderer.glColor(0xFFf3d8ce);
-// Engine.INSTANCE.getHardwareDevice().getDisplayManager().renderer.glDrawStringRight(StaticVars.screenSize[0], Engine.INSTANCE.getHardwareDevice().getDisplayManager().engine.getHeight() - TetrisScreen.gpuTest2.getCharacterHeight(), "F");
-// Engine.INSTANCE.getHardwareDevice().getDisplayManager().renderer.glColor(0xFFffede7);
-// Engine.INSTANCE.getHardwareDevice().getDisplayManager().renderer.glDrawStringRight(StaticVars.screenSize[0], Engine.INSTANCE.getHardwareDevice().getDisplayManager().engine.getHeight() - TetrisScreen.gpuTest2.getCharacterHeight(), "G");
-// }
-// }
+ if (TetrisScreen.skin != null) {
+ TetrisScreen.skin.use(e);
+ }
+ r.glColor3f(1, 1, 1);
+ BlockColor[] renderedGrid = g.getRenderedGrid();
+ int centerScreen = StaticVars.screenSize[0]/2;
+ int centerGrid = TetrisGame.WIDTH*6/2-1;
+ final int leftOffset = centerScreen - centerGrid;
+ final int topOffset = StaticVars.screenSize[1] - TetrisGame.HEIGHT*6-1;
+ for (int y = 0; y < TetrisGame.HEIGHT; y++) {
+ for (int x = 0; x < TetrisGame.WIDTH; x++) {
+ final int offset = x+y*TetrisGame.WIDTH;
+ final BlockColor type = renderedGrid[offset];
+ if (type != null) {
+ r.glFillRect(leftOffset + x * 5, topOffset + (y+3) * 5, 5, 5, renderedGrid[offset].ordinal() * 5, 0, 5, 5);
+ } else {
+ r.glFillRect(leftOffset + x * 5, topOffset + (y+3) * 5, 5, 5, 7 * 5, 0, 5, 5);
+ }
+ }
+ }
+
+
+ Tetromino nextTetromino = g.getNextTetromino();
+ if (nextTetromino != null) {
+ r.glColor3f(0.25f, 0.25f, 0.25f);
+ r.glFillColor(leftOffset + (TetrisGame.WIDTH + 3) * 5, topOffset + 3 * 5, 5*4, 5*4);
+ r.glColor3f(1,1,1);
+ boolean[] renderedNextTetromino = nextTetromino.getRenderedBlock();
+ final BlockColor type = nextTetromino.getColor();
+ int nextTetrominoGridSize = nextTetromino.getTetrominoGridSize();
+ int nextGridOffset = 4*5/2 - nextTetrominoGridSize*5/2;
+ for (int y = 0; y < nextTetrominoGridSize; y++) {
+ for (int x = 0; x < nextTetrominoGridSize; x++) {
+ final int offset = x+y*nextTetrominoGridSize;
+ if (renderedNextTetromino[offset]) {
+ if (type != null) {
+ r.glFillRect(leftOffset + nextGridOffset + (TetrisGame.WIDTH + 3 + x) * 5, topOffset + nextGridOffset + (3 + y) * 5, 5, 5, type.ordinal() * 5, 0, 5, 5);
+ }
+ }
+ }
+ }
+ }
+ r.glColor3f(1,1,1);
+ r.glDrawStringLeft(leftOffset + (TetrisGame.WIDTH + 3) * 5, topOffset + (3+5) * 5, "SCORE:"+g.getScore());
}
-
+
+ @Override
+ public boolean onKeyPressed(KeyPressedEvent k) {
+ switch (k.getKey()) {
+ case LEFT: {
+ leftPressed.press();
+ return true;
+ }
+ case RIGHT: {
+ rightPressed.press();
+ return true;
+ }
+ case UP: {
+ upPressed.press();
+ return true;
+ }
+ case DOWN: {
+ downPressed.press();
+ return true;
+ }
+ case OK: {
+ okPressed.press();
+ g.playAgain();
+ return true;
+ }
+ case BACK: {
+ backPressed.press();
+ return true;
+ }
+ default: return false;
+ }
+ }
+
+ @Override
+ public boolean onKeyReleased(KeyReleasedEvent k) {
+ switch (k.getKey()) {
+ case LEFT: {
+ leftPressed.release();
+ return true;
+ }
+ case RIGHT: {
+ rightPressed.release();
+ return true;
+ }
+ case UP: {
+ upPressed.release();
+ return true;
+ }
+ case DOWN: {
+ downPressed.release();
+ return true;
+ }
+ case OK: {
+ okPressed.release();
+ return true;
+ }
+ case BACK: {
+ backPressed.release();
+ return true;
+ }
+ default: return false;
+ }
+ }
@Override
public boolean mustBeRefreshed() {
return true;
@@ -179,7 +187,6 @@ public class TetrisScreen extends Screen {
@Override
public String getSessionTitle() {
- return "Absolutely not Super Mario";
+ return "Tetris";
}
-
}
diff --git a/core/src/main/java/it/cavallium/warppi/extra/tetris/Tetromino.java b/core/src/main/java/it/cavallium/warppi/extra/tetris/Tetromino.java
new file mode 100644
index 00000000..ebadf3b2
--- /dev/null
+++ b/core/src/main/java/it/cavallium/warppi/extra/tetris/Tetromino.java
@@ -0,0 +1,130 @@
+package it.cavallium.warppi.extra.tetris;
+
+public abstract class Tetromino {
+ private byte x, y, rotation;
+ private final TetrominoType type;
+ public final boolean o = false, w = true;
+
+ public Tetromino(byte x, byte y, byte rotation, TetrominoType type) {
+ super();
+ this.x = x;
+ this.y = y;
+ this.rotation = rotation;
+ this.type = type;
+ }
+
+ public byte getX() {
+ return x;
+ }
+
+ public void setX(byte x) {
+ this.x = x;
+ }
+
+ public byte getY() {
+ return y;
+ }
+
+ public void setY(byte y) {
+ this.y = y;
+ }
+
+ public byte getRotation() {
+ return rotation;
+ }
+
+ public void setRotation(byte rotation) {
+ this.rotation = rotation;
+ }
+
+ public TetrominoType getType() {
+ return type;
+ }
+
+ public BlockColor getColor() {
+ switch(type) {
+ case I_CYAN:
+ return BlockColor.CYAN;
+ case J_BLUE:
+ return BlockColor.BLUE;
+ case L_ORANGE:
+ return BlockColor.ORANGE;
+ case O_YELLOW:
+ return BlockColor.YELLOW;
+ case S_GREEN:
+ return BlockColor.GREEN;
+ case T_PURPLE:
+ return BlockColor.PURPLE;
+ case Z_RED:
+ return BlockColor.RED;
+ default:
+ return BlockColor.RED;
+ }
+ }
+
+ public void draw(BlockColor[] grid, final int WIDTH) {
+ boolean[] blockGrid = getRenderedBlock();
+ final int tetrominoGridSize = getTetrominoGridSize();
+ final int centerOffset = (int) Math.floor((double)tetrominoGridSize/2d);
+ final BlockColor type = getColor();
+ for (int bx = 0; bx < tetrominoGridSize; bx++) {
+ for (int by = 0; by < tetrominoGridSize; by++) {
+ if (blockGrid[bx+by*tetrominoGridSize] == w) {
+ final int index = x+bx-centerOffset + (y+by-centerOffset) * WIDTH;
+ if (index < grid.length && index >= 0) {
+ grid[index] = type;
+ }
+ }
+ }
+ }
+ }
+
+ public void fixInitialPosition() {
+ this.y += (byte) (this.getTetrominoGridSize()/2);
+ }
+
+ public abstract int getTetrominoGridSize();
+ protected abstract boolean[] getRenderedBlock(byte dRotation);
+ protected boolean[] getRenderedBlock() {
+ return getRenderedBlock(this.rotation);
+ }
+
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + rotation;
+ result = prime * result + ((type == null) ? 0 : type.hashCode());
+ result = prime * result + x;
+ result = prime * result + y;
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ Tetromino other = (Tetromino) obj;
+ if (rotation != other.rotation)
+ return false;
+ if (type != other.type)
+ return false;
+ if (x != other.x)
+ return false;
+ if (y != other.y)
+ return false;
+ return true;
+ }
+
+ @Override
+ public String toString() {
+ return "Tetromino = {\n\t\"x\": \"" + x + "\",\n\ty\": \"" + y + "\",\n\trotation\": \"" + rotation + "\",\n\ttype\": \"" + type + "\"\n}";
+ }
+
+
+}
diff --git a/core/src/main/java/it/cavallium/warppi/extra/tetris/TetrominoICyan.java b/core/src/main/java/it/cavallium/warppi/extra/tetris/TetrominoICyan.java
new file mode 100644
index 00000000..d15a2d7e
--- /dev/null
+++ b/core/src/main/java/it/cavallium/warppi/extra/tetris/TetrominoICyan.java
@@ -0,0 +1,48 @@
+package it.cavallium.warppi.extra.tetris;
+
+public class TetrominoICyan extends Tetromino {
+ public TetrominoICyan(byte x, byte y, byte rotation) {
+ super(x, y, rotation, TetrominoType.I_CYAN);
+ }
+
+ @Override
+ public int getTetrominoGridSize() {
+ return 4;
+ }
+
+ @Override
+ public boolean[] getRenderedBlock(final byte rotation) {
+ switch(rotation) {
+ case 0:
+ return new boolean[] {
+ o,o,o,o,
+ w,w,w,w,
+ o,o,o,o,
+ o,o,o,o
+ };
+ case 1:
+ return new boolean[] {
+ o,o,w,o,
+ o,o,w,o,
+ o,o,w,o,
+ o,o,w,o
+ };
+ case 2:
+ return new boolean[] {
+ o,o,o,o,
+ o,o,o,o,
+ w,w,w,w,
+ o,o,o,o
+ };
+ case 3:
+ return new boolean[] {
+ o,w,o,o,
+ o,w,o,o,
+ o,w,o,o,
+ o,w,o,o
+ };
+ default:
+ throw new NullPointerException();
+ }
+ }
+}
diff --git a/core/src/main/java/it/cavallium/warppi/extra/tetris/TetrominoJBlue.java b/core/src/main/java/it/cavallium/warppi/extra/tetris/TetrominoJBlue.java
new file mode 100644
index 00000000..eae5698d
--- /dev/null
+++ b/core/src/main/java/it/cavallium/warppi/extra/tetris/TetrominoJBlue.java
@@ -0,0 +1,44 @@
+package it.cavallium.warppi.extra.tetris;
+
+public class TetrominoJBlue extends Tetromino {
+ public TetrominoJBlue(byte x, byte y, byte rotation) {
+ super(x, y, rotation, TetrominoType.J_BLUE);
+ }
+
+ @Override
+ public int getTetrominoGridSize() {
+ return 3;
+ }
+
+ @Override
+ public boolean[] getRenderedBlock(final byte rotation) {
+ switch(rotation) {
+ case 0:
+ return new boolean[] {
+ w,o,o,
+ w,w,w,
+ o,o,o
+ };
+ case 1:
+ return new boolean[] {
+ o,w,w,
+ o,w,o,
+ o,w,o
+ };
+ case 2:
+ return new boolean[] {
+ o,o,o,
+ w,w,w,
+ o,o,w
+ };
+ case 3:
+ return new boolean[] {
+ o,w,o,
+ o,w,o,
+ w,w,o
+ };
+ default:
+ throw new NullPointerException();
+ }
+ }
+}
diff --git a/core/src/main/java/it/cavallium/warppi/extra/tetris/TetrominoLOrange.java b/core/src/main/java/it/cavallium/warppi/extra/tetris/TetrominoLOrange.java
new file mode 100644
index 00000000..09d5d384
--- /dev/null
+++ b/core/src/main/java/it/cavallium/warppi/extra/tetris/TetrominoLOrange.java
@@ -0,0 +1,44 @@
+package it.cavallium.warppi.extra.tetris;
+
+public class TetrominoLOrange extends Tetromino {
+ public TetrominoLOrange(byte x, byte y, byte rotation) {
+ super(x, y, rotation, TetrominoType.L_ORANGE);
+ }
+
+ @Override
+ public int getTetrominoGridSize() {
+ return 3;
+ }
+
+ @Override
+ public boolean[] getRenderedBlock(final byte rotation) {
+ switch(rotation) {
+ case 0:
+ return new boolean[] {
+ o,o,w,
+ w,w,w,
+ o,o,o
+ };
+ case 1:
+ return new boolean[] {
+ o,w,o,
+ o,w,o,
+ o,w,w
+ };
+ case 2:
+ return new boolean[] {
+ o,o,o,
+ w,w,w,
+ w,o,o
+ };
+ case 3:
+ return new boolean[] {
+ w,w,o,
+ o,w,o,
+ o,w,o
+ };
+ default:
+ throw new NullPointerException();
+ }
+ }
+}
diff --git a/core/src/main/java/it/cavallium/warppi/extra/tetris/TetrominoOYellow.java b/core/src/main/java/it/cavallium/warppi/extra/tetris/TetrominoOYellow.java
new file mode 100644
index 00000000..7425a75d
--- /dev/null
+++ b/core/src/main/java/it/cavallium/warppi/extra/tetris/TetrominoOYellow.java
@@ -0,0 +1,19 @@
+package it.cavallium.warppi.extra.tetris;
+
+public class TetrominoOYellow extends Tetromino {
+ public TetrominoOYellow(byte x, byte y, byte rotation) {
+ super(x, y, rotation, TetrominoType.O_YELLOW);
+ }
+ @Override
+ public int getTetrominoGridSize() {
+ return 2;
+ }
+
+ @Override
+ public boolean[] getRenderedBlock(byte rotation) {
+ return new boolean[] {
+ w,w,
+ w,w,
+ };
+ }
+}
diff --git a/core/src/main/java/it/cavallium/warppi/extra/tetris/TetrominoSGreen.java b/core/src/main/java/it/cavallium/warppi/extra/tetris/TetrominoSGreen.java
new file mode 100644
index 00000000..1bb35053
--- /dev/null
+++ b/core/src/main/java/it/cavallium/warppi/extra/tetris/TetrominoSGreen.java
@@ -0,0 +1,44 @@
+package it.cavallium.warppi.extra.tetris;
+
+public class TetrominoSGreen extends Tetromino {
+ public TetrominoSGreen(byte x, byte y, byte rotation) {
+ super(x, y, rotation, TetrominoType.S_GREEN);
+ }
+
+ @Override
+ public int getTetrominoGridSize() {
+ return 3;
+ }
+
+ @Override
+ public boolean[] getRenderedBlock(final byte rotation) {
+ switch(rotation) {
+ case 0:
+ return new boolean[] {
+ o,w,w,
+ w,w,o,
+ o,o,o
+ };
+ case 1:
+ return new boolean[] {
+ o,w,o,
+ o,w,w,
+ o,o,w
+ };
+ case 2:
+ return new boolean[] {
+ o,o,o,
+ o,w,w,
+ w,w,o
+ };
+ case 3:
+ return new boolean[] {
+ w,o,o,
+ w,w,o,
+ o,w,o
+ };
+ default:
+ throw new NullPointerException();
+ }
+ }
+}
diff --git a/core/src/main/java/it/cavallium/warppi/extra/tetris/TetrominoTPurple.java b/core/src/main/java/it/cavallium/warppi/extra/tetris/TetrominoTPurple.java
new file mode 100644
index 00000000..4b187f3d
--- /dev/null
+++ b/core/src/main/java/it/cavallium/warppi/extra/tetris/TetrominoTPurple.java
@@ -0,0 +1,44 @@
+package it.cavallium.warppi.extra.tetris;
+
+public class TetrominoTPurple extends Tetromino {
+ public TetrominoTPurple(byte x, byte y, byte rotation) {
+ super(x, y, rotation, TetrominoType.T_PURPLE);
+ }
+
+ @Override
+ public int getTetrominoGridSize() {
+ return 3;
+ }
+
+ @Override
+ public boolean[] getRenderedBlock(byte rotation) {
+ switch(rotation) {
+ case 0:
+ return new boolean[] {
+ o,w,o,
+ w,w,w,
+ o,o,o
+ };
+ case 1:
+ return new boolean[] {
+ o,w,o,
+ o,w,w,
+ o,w,o
+ };
+ case 2:
+ return new boolean[] {
+ o,o,o,
+ w,w,w,
+ o,w,o
+ };
+ case 3:
+ return new boolean[] {
+ o,w,o,
+ w,w,o,
+ o,w,o
+ };
+ default:
+ throw new NullPointerException();
+ }
+ }
+}
diff --git a/core/src/main/java/it/cavallium/warppi/extra/tetris/TetrominoType.java b/core/src/main/java/it/cavallium/warppi/extra/tetris/TetrominoType.java
new file mode 100644
index 00000000..794fa4b9
--- /dev/null
+++ b/core/src/main/java/it/cavallium/warppi/extra/tetris/TetrominoType.java
@@ -0,0 +1,11 @@
+package it.cavallium.warppi.extra.tetris;
+
+public enum TetrominoType {
+ I_CYAN,
+ O_YELLOW,
+ T_PURPLE,
+ S_GREEN,
+ Z_RED,
+ J_BLUE,
+ L_ORANGE
+}
diff --git a/core/src/main/java/it/cavallium/warppi/extra/tetris/TetrominoZRed.java b/core/src/main/java/it/cavallium/warppi/extra/tetris/TetrominoZRed.java
new file mode 100644
index 00000000..5f99f83d
--- /dev/null
+++ b/core/src/main/java/it/cavallium/warppi/extra/tetris/TetrominoZRed.java
@@ -0,0 +1,44 @@
+package it.cavallium.warppi.extra.tetris;
+
+public class TetrominoZRed extends Tetromino {
+ public TetrominoZRed(byte x, byte y, byte rotation) {
+ super(x, y, rotation, TetrominoType.Z_RED);
+ }
+
+ @Override
+ public int getTetrominoGridSize() {
+ return 3;
+ }
+
+ @Override
+ public boolean[] getRenderedBlock(final byte rotation) {
+ switch(rotation) {
+ case 0:
+ return new boolean[] {
+ w,w,o,
+ o,w,w,
+ o,o,o
+ };
+ case 1:
+ return new boolean[] {
+ o,o,w,
+ o,w,w,
+ o,w,o
+ };
+ case 2:
+ return new boolean[] {
+ o,o,o,
+ w,w,o,
+ o,w,w
+ };
+ case 3:
+ return new boolean[] {
+ o,w,o,
+ w,w,o,
+ w,o,o
+ };
+ default:
+ throw new NullPointerException();
+ }
+ }
+}
diff --git a/core/src/main/java/it/cavallium/warppi/gui/CalculatorHUD.java b/core/src/main/java/it/cavallium/warppi/gui/CalculatorHUD.java
index a86fac78..921c32ce 100644
--- a/core/src/main/java/it/cavallium/warppi/gui/CalculatorHUD.java
+++ b/core/src/main/java/it/cavallium/warppi/gui/CalculatorHUD.java
@@ -24,6 +24,12 @@ public class CalculatorHUD extends HUD {
}
+ @Override
+ public void graphicInitialized() throws InterruptedException {
+ // TODO Auto-generated method stub
+
+ }
+
@Override
public void render() {
// TODO Auto-generated method stub
diff --git a/core/src/main/java/it/cavallium/warppi/gui/DisplayManager.java b/core/src/main/java/it/cavallium/warppi/gui/DisplayManager.java
index faa26d33..cf913787 100644
--- a/core/src/main/java/it/cavallium/warppi/gui/DisplayManager.java
+++ b/core/src/main/java/it/cavallium/warppi/gui/DisplayManager.java
@@ -5,14 +5,13 @@ import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
-import org.apache.commons.lang3.tuple.Pair;
-
import it.cavallium.warppi.Engine;
import it.cavallium.warppi.Platform.ConsoleUtils;
import it.cavallium.warppi.Platform.Semaphore;
import it.cavallium.warppi.StaticVars;
import it.cavallium.warppi.device.Keyboard;
import it.cavallium.warppi.flow.Observable;
+import it.cavallium.warppi.flow.Pair;
import it.cavallium.warppi.gui.graphicengine.BinaryFont;
import it.cavallium.warppi.gui.graphicengine.GraphicEngine;
import it.cavallium.warppi.gui.graphicengine.Renderer;
@@ -243,10 +242,10 @@ public final class DisplayManager implements RenderingLoop {
screen.create();
}
this.screen = screen;
- screenChange.release();
if (screen.initialized == false) {
screen.initialize();
}
+ screenChange.release();
} catch (final Exception e) {
e.printStackTrace();
Engine.getPlatform().exit(0);
@@ -268,10 +267,10 @@ public final class DisplayManager implements RenderingLoop {
try {
screen.create();
this.screen = screen;
- screenChange.release();
if (screen.initialized == false) {
screen.initialize();
}
+ screenChange.release();
} catch (final Exception e) {
e.printStackTrace();
Engine.getPlatform().exit(0);
@@ -373,6 +372,13 @@ public final class DisplayManager implements RenderingLoop {
}
}
}
+ if (!screen.graphicInitialized) {
+ try {
+ screen.initializeGraphic();
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ }
renderer.glClear(engine.getWidth(), engine.getHeight());
}
@@ -440,7 +446,6 @@ public final class DisplayManager implements RenderingLoop {
setScreen(initialScreen);
initialScreen = null;
}
- screen.initialize();
} catch (final Exception e) {
e.printStackTrace();
Engine.getPlatform().exit(0);
diff --git a/core/src/main/java/it/cavallium/warppi/gui/GraphicalInterface.java b/core/src/main/java/it/cavallium/warppi/gui/GraphicalInterface.java
index 9617df37..f1ee5694 100644
--- a/core/src/main/java/it/cavallium/warppi/gui/GraphicalInterface.java
+++ b/core/src/main/java/it/cavallium/warppi/gui/GraphicalInterface.java
@@ -2,8 +2,10 @@ package it.cavallium.warppi.gui;
public interface GraphicalInterface {
void create() throws InterruptedException;
-
+
void initialize() throws InterruptedException;
+
+ void initializeGraphic() throws InterruptedException;
void render();
diff --git a/core/src/main/java/it/cavallium/warppi/gui/HUD.java b/core/src/main/java/it/cavallium/warppi/gui/HUD.java
index 06e13a26..79436fe9 100644
--- a/core/src/main/java/it/cavallium/warppi/gui/HUD.java
+++ b/core/src/main/java/it/cavallium/warppi/gui/HUD.java
@@ -3,6 +3,7 @@ package it.cavallium.warppi.gui;
public abstract class HUD implements GraphicalInterface {
public DisplayManager d;
public boolean created = false;
+ public boolean graphicInitialized = false;
public boolean initialized = false;
public boolean visible = true;
@@ -16,6 +17,14 @@ public abstract class HUD implements GraphicalInterface {
}
}
+ @Override
+ public void initializeGraphic() throws InterruptedException {
+ if (!graphicInitialized) {
+ graphicInitialized = true;
+ graphicInitialized();
+ }
+ }
+
@Override
public void create() throws InterruptedException {
if (!created) {
@@ -26,6 +35,8 @@ public abstract class HUD implements GraphicalInterface {
public abstract void created() throws InterruptedException;
+ public abstract void graphicInitialized() throws InterruptedException;
+
public abstract void initialized() throws InterruptedException;
public abstract void renderBackground();
diff --git a/core/src/main/java/it/cavallium/warppi/gui/expression/ExtraMenu.java b/core/src/main/java/it/cavallium/warppi/gui/expression/ExtraMenu.java
index e28d6c5c..5c8b2f56 100644
--- a/core/src/main/java/it/cavallium/warppi/gui/expression/ExtraMenu.java
+++ b/core/src/main/java/it/cavallium/warppi/gui/expression/ExtraMenu.java
@@ -5,6 +5,7 @@ import java.util.Arrays;
import it.cavallium.warppi.event.KeyboardEventListener;
import it.cavallium.warppi.gui.expression.blocks.Block;
import it.cavallium.warppi.gui.expression.blocks.BlockVariable;
+import it.cavallium.warppi.gui.expression.blocks.TreeContainer;
import it.cavallium.warppi.gui.graphicengine.GraphicEngine;
import it.cavallium.warppi.gui.graphicengine.Renderer;
@@ -45,7 +46,7 @@ public abstract class ExtraMenu implements KeyboardEventListene
return false;
}
- public abstract ExtraMenu clone(InputContext ic);
+ public abstract ExtraMenu clone(final TreeContainer parent, InputContext ic);
public abstract ExtraMenu clone(T newBlockVariable);
diff --git a/core/src/main/java/it/cavallium/warppi/gui/expression/blocks/Block.java b/core/src/main/java/it/cavallium/warppi/gui/expression/blocks/Block.java
index 6dda310c..638c596d 100644
--- a/core/src/main/java/it/cavallium/warppi/gui/expression/blocks/Block.java
+++ b/core/src/main/java/it/cavallium/warppi/gui/expression/blocks/Block.java
@@ -18,6 +18,22 @@ public abstract class Block implements TreeBlock, GraphicalElement {
protected int height;
protected int line;
protected TreeContainer parent;
+
+ public Block() {
+
+ }
+
+ /**
+ * Copy
+ * @param b
+ */
+ public Block(TreeContainer parent, Block b) {
+ this.small = b.small;
+ this.width = b.width;
+ this.height = b.height;
+ this.line = b.line;
+ this.parent = parent;
+ }
/**
*
@@ -95,5 +111,5 @@ public abstract class Block implements TreeBlock, GraphicalElement {
this.parent = parent;
}
- public abstract Block clone(InputContext ic);
+ public abstract Block clone(TreeContainer parent, InputContext ic);
}
diff --git a/core/src/main/java/it/cavallium/warppi/gui/expression/blocks/BlockChar.java b/core/src/main/java/it/cavallium/warppi/gui/expression/blocks/BlockChar.java
index b4a1a2cb..e9db9436 100644
--- a/core/src/main/java/it/cavallium/warppi/gui/expression/blocks/BlockChar.java
+++ b/core/src/main/java/it/cavallium/warppi/gui/expression/blocks/BlockChar.java
@@ -18,9 +18,14 @@ public class BlockChar extends Block {
recomputeDimensions();
}
- public BlockChar(final char ch, InputContext ic) {
- this.ch = ch;
- recomputeDimensions();
+ /**
+ * Copy
+ * @param b
+ * @param ic
+ */
+ protected BlockChar(final TreeContainer parent, final BlockChar b, InputContext ic) {
+ super(parent, b);
+ this.ch = b.ch;
}
@Override
@@ -83,8 +88,8 @@ public class BlockChar extends Block {
}
@Override
- public BlockChar clone(InputContext ic) {
- return new BlockChar(ch, ic);
+ public BlockChar clone(final TreeContainer parent, InputContext ic) {
+ return new BlockChar(parent, this, ic);
}
}
diff --git a/core/src/main/java/it/cavallium/warppi/gui/expression/blocks/BlockContainer.java b/core/src/main/java/it/cavallium/warppi/gui/expression/blocks/BlockContainer.java
index 5554fdfa..96abf8ce 100644
--- a/core/src/main/java/it/cavallium/warppi/gui/expression/blocks/BlockContainer.java
+++ b/core/src/main/java/it/cavallium/warppi/gui/expression/blocks/BlockContainer.java
@@ -79,24 +79,25 @@ public class BlockContainer implements TreeContainer, GraphicalElement {
recomputeDimensions();
}
- private BlockContainer(BlockContainer old, InputContext ic) {
+ private BlockContainer(final TreeBlock parent, BlockContainer old, InputContext ic) {
this.autoMinimums = old.autoMinimums;
this.content = new ObjectArrayList<>();
for (Block b : old.content) {
- this.content.add(b.clone(ic));
+ this.content.add(b.clone(this, ic));
}
+
this.height = old.height;
this.line = old.line;
this.minHeight = old.minHeight;
this.minWidth = old.minWidth;
- this.parent = old.parent;
+ this.parent = parent;
this.small = old.small;
this.width = old.width;
this.withBorder = old.withBorder;
}
- public BlockContainer clone(InputContext ic) {
- return new BlockContainer(this, ic);
+ public BlockContainer clone(final TreeBlock parent, InputContext ic) {
+ return new BlockContainer(parent, this, ic);
}
@Override
@@ -261,18 +262,21 @@ public class BlockContainer implements TreeContainer, GraphicalElement {
innerContainersBeforeCaret++;
}
}
- removeAt(pos - 1);
- if (blocks != null) {
- ObjectListIterator blocksIterator = blocks.iterator();
- int blockNum = 0;
- while (blocksIterator.hasNext()) {
- Block block = blocksIterator.next();
- addBlockUnsafe(pos - 1 + blockNum, block);
- blockNum++;
+ // If the caret is at the end of a block with inner containers don't delete anything and enter into that block.
+ if (innerContainers == null || (innerContainers.size() - innerContainersBeforeCaret != 0)) {
+ removeAt(pos - 1);
+ if (blocks != null) {
+ ObjectListIterator blocksIterator = blocks.iterator();
+ int blockNum = 0;
+ while (blocksIterator.hasNext()) {
+ Block block = blocksIterator.next();
+ addBlockUnsafe(pos - 1 + blockNum, block);
+ blockNum++;
+ }
}
+ caret.setPosition(caretOldPos - innerContainersBeforeCaret);
+ removed = true;
}
- caret.setPosition(caretOldPos - innerContainersBeforeCaret);
- removed = true;
}
}
caret.skip(1);
diff --git a/core/src/main/java/it/cavallium/warppi/gui/expression/blocks/BlockDivision.java b/core/src/main/java/it/cavallium/warppi/gui/expression/blocks/BlockDivision.java
index f3774d06..3702cec5 100644
--- a/core/src/main/java/it/cavallium/warppi/gui/expression/blocks/BlockDivision.java
+++ b/core/src/main/java/it/cavallium/warppi/gui/expression/blocks/BlockDivision.java
@@ -27,10 +27,14 @@ public class BlockDivision extends Block {
recomputeDimensions();
}
- private BlockDivision(BlockDivision old, InputContext ic) {
- containerUp = old.containerUp.clone(ic);
- containerDown = old.containerDown.clone(ic);
- recomputeDimensions();
+ private BlockDivision(final TreeContainer parent, BlockDivision old, InputContext ic) {
+ super(parent, old);
+ containerUp = old.containerUp.clone(this, ic);
+ containerDown = old.containerDown.clone(this, ic);
+ paddingLeftLower = old.paddingLeftLower;
+ paddingLeftUpper = old.paddingLeftUpper;
+ h1 = old.h1;
+ System.out.println(String.join(",", ""+h1, ""+old.h1, ""+line, ""+old.line));
}
@Override
@@ -144,7 +148,7 @@ public class BlockDivision extends Block {
}
@Override
- public BlockDivision clone(InputContext ic) {
- return new BlockDivision(this, ic);
+ public BlockDivision clone(final TreeContainer parent, InputContext ic) {
+ return new BlockDivision(parent, this, ic);
}
}
diff --git a/core/src/main/java/it/cavallium/warppi/gui/expression/blocks/BlockExponentialNotation.java b/core/src/main/java/it/cavallium/warppi/gui/expression/blocks/BlockExponentialNotation.java
index d19d4074..cdb25f9d 100644
--- a/core/src/main/java/it/cavallium/warppi/gui/expression/blocks/BlockExponentialNotation.java
+++ b/core/src/main/java/it/cavallium/warppi/gui/expression/blocks/BlockExponentialNotation.java
@@ -1,6 +1,7 @@
package it.cavallium.warppi.gui.expression.blocks;
import it.cavallium.warppi.gui.expression.Caret;
+import it.cavallium.warppi.gui.expression.InputContext;
import it.cavallium.warppi.gui.graphicengine.GraphicEngine;
import it.cavallium.warppi.gui.graphicengine.Renderer;
@@ -8,6 +9,21 @@ public class BlockExponentialNotation extends BlockPower {
private int bw;
private int bh;
+ public BlockExponentialNotation() {
+ super();
+ }
+
+ /**
+ * Copy
+ * @param old
+ * @param ic
+ */
+ private BlockExponentialNotation(final TreeContainer parent, BlockExponentialNotation old, InputContext ic) {
+ super(parent, old, ic);
+ this.bw = old.bw;
+ this.bh = old.bh;
+ }
+
@Override
public void draw(final GraphicEngine ge, final Renderer r, final int x, final int y, final Caret caret) {
BlockContainer.getDefaultFont(small).use(ge);
@@ -23,4 +39,9 @@ public class BlockExponentialNotation extends BlockPower {
bh = BlockContainer.getDefaultCharHeight(small);
width += bw;
}
+
+ @Override
+ public BlockExponentialNotation clone(final TreeContainer parent, InputContext ic) {
+ return new BlockExponentialNotation(parent, this, ic);
+ }
}
diff --git a/core/src/main/java/it/cavallium/warppi/gui/expression/blocks/BlockLogarithm.java b/core/src/main/java/it/cavallium/warppi/gui/expression/blocks/BlockLogarithm.java
index feba80af..8699ed4d 100644
--- a/core/src/main/java/it/cavallium/warppi/gui/expression/blocks/BlockLogarithm.java
+++ b/core/src/main/java/it/cavallium/warppi/gui/expression/blocks/BlockLogarithm.java
@@ -40,10 +40,19 @@ public class BlockLogarithm extends Block implements IParenthesis {
recomputeDimensions();
}
- private BlockLogarithm(BlockLogarithm old, InputContext ic) {
- containerBase = old.containerBase.clone(ic);
- containerNumber = old.containerNumber.clone(ic);
- recomputeDimensions();
+ private BlockLogarithm(final TreeContainer parent, BlockLogarithm old, InputContext ic) {
+ super(parent, old);
+ containerBase = old.containerBase.clone(this, ic);
+ containerNumber = old.containerNumber.clone(this, ic);
+ this.prw = old.prw;
+ this.bw = old.bw;
+ this.bh = old.bh;
+ this.bl = old.bl;
+ this.chw = old.chw;
+ this.chh = old.chh;
+ this.schh = old.schh;
+ this.nmbh = old.nmbh;
+ this.toph = old.toph;
}
@Override
@@ -183,8 +192,8 @@ public class BlockLogarithm extends Block implements IParenthesis {
}
@Override
- public BlockLogarithm clone(InputContext ic) {
- return new BlockLogarithm(this, ic);
+ public BlockLogarithm clone(final TreeContainer parent, InputContext ic) {
+ return new BlockLogarithm(parent, this, ic);
}
}
diff --git a/core/src/main/java/it/cavallium/warppi/gui/expression/blocks/BlockNumericChar.java b/core/src/main/java/it/cavallium/warppi/gui/expression/blocks/BlockNumericChar.java
index 7976c2af..ed44c709 100644
--- a/core/src/main/java/it/cavallium/warppi/gui/expression/blocks/BlockNumericChar.java
+++ b/core/src/main/java/it/cavallium/warppi/gui/expression/blocks/BlockNumericChar.java
@@ -1,9 +1,19 @@
package it.cavallium.warppi.gui.expression.blocks;
+import it.cavallium.warppi.gui.expression.InputContext;
+
public class BlockNumericChar extends BlockChar {
public BlockNumericChar(final char ch) {
super(ch);
}
+ private BlockNumericChar(final TreeContainer parent, BlockNumericChar old, InputContext ic) {
+ super(parent, old, ic);
+ }
+
+ @Override
+ public BlockNumericChar clone(final TreeContainer parent, InputContext ic) {
+ return new BlockNumericChar(parent, this, ic);
+ }
}
diff --git a/core/src/main/java/it/cavallium/warppi/gui/expression/blocks/BlockParenthesis.java b/core/src/main/java/it/cavallium/warppi/gui/expression/blocks/BlockParenthesis.java
index 395021a7..e4cfd2cf 100644
--- a/core/src/main/java/it/cavallium/warppi/gui/expression/blocks/BlockParenthesis.java
+++ b/core/src/main/java/it/cavallium/warppi/gui/expression/blocks/BlockParenthesis.java
@@ -15,8 +15,8 @@ public class BlockParenthesis extends BlockParenthesisAbstract {
super(blocks);
}
- private BlockParenthesis(BlockParenthesis old, InputContext ic) {
- super(old, ic);
+ private BlockParenthesis(final TreeContainer parent, BlockParenthesis old, InputContext ic) {
+ super(parent, old, ic);
}
@Override
@@ -38,8 +38,8 @@ public class BlockParenthesis extends BlockParenthesisAbstract {
}
@Override
- public BlockParenthesis clone(InputContext ic) {
- return new BlockParenthesis(this, ic);
+ public BlockParenthesis clone(final TreeContainer parent, InputContext ic) {
+ return new BlockParenthesis(parent, this, ic);
}
}
diff --git a/core/src/main/java/it/cavallium/warppi/gui/expression/blocks/BlockParenthesisAbstract.java b/core/src/main/java/it/cavallium/warppi/gui/expression/blocks/BlockParenthesisAbstract.java
index eefe3b39..bfff55c8 100644
--- a/core/src/main/java/it/cavallium/warppi/gui/expression/blocks/BlockParenthesisAbstract.java
+++ b/core/src/main/java/it/cavallium/warppi/gui/expression/blocks/BlockParenthesisAbstract.java
@@ -31,10 +31,18 @@ public abstract class BlockParenthesisAbstract extends Block implements IParenth
recomputeDimensions();
}
- BlockParenthesisAbstract(BlockParenthesisAbstract old, InputContext ic) {
- containerNumber = old.containerNumber.clone(ic);
- prefix = old.prefix == null ? null : new String(old.prefix);
- recomputeDimensions();
+ /**
+ * Copy
+ * @param old
+ * @param ic
+ */
+ BlockParenthesisAbstract(final TreeContainer parent, BlockParenthesisAbstract old, InputContext ic) {
+ super(parent, old);
+ containerNumber = old.containerNumber.clone(this, ic);
+ prefix = old.prefix;
+ prw = old.prw;
+ chw = old.chw;
+ chh = old.chh;
}
public BlockParenthesisAbstract(final ObjectArrayList blocks) {
diff --git a/core/src/main/java/it/cavallium/warppi/gui/expression/blocks/BlockPower.java b/core/src/main/java/it/cavallium/warppi/gui/expression/blocks/BlockPower.java
index 7530d25a..a665fa6d 100644
--- a/core/src/main/java/it/cavallium/warppi/gui/expression/blocks/BlockPower.java
+++ b/core/src/main/java/it/cavallium/warppi/gui/expression/blocks/BlockPower.java
@@ -20,8 +20,9 @@ public class BlockPower extends Block {
recomputeDimensions();
}
- private BlockPower(BlockPower old, InputContext ic) {
- this.containerExponent = old.containerExponent.clone(ic);
+ protected BlockPower(final TreeContainer parent, BlockPower old, InputContext ic) {
+ super(parent, old);
+ this.containerExponent = old.containerExponent.clone(this, ic);
}
@Override
@@ -100,7 +101,7 @@ public class BlockPower extends Block {
}
@Override
- public BlockPower clone(InputContext ic) {
- return new BlockPower(this, ic);
+ public BlockPower clone(final TreeContainer parent, InputContext ic) {
+ return new BlockPower(parent, this, ic);
}
}
diff --git a/core/src/main/java/it/cavallium/warppi/gui/expression/blocks/BlockPower2.java b/core/src/main/java/it/cavallium/warppi/gui/expression/blocks/BlockPower2.java
index bc152ab4..e586a463 100644
--- a/core/src/main/java/it/cavallium/warppi/gui/expression/blocks/BlockPower2.java
+++ b/core/src/main/java/it/cavallium/warppi/gui/expression/blocks/BlockPower2.java
@@ -21,8 +21,9 @@ public class BlockPower2 extends Block {
recomputeDimensions();
}
- private BlockPower2(BlockPower2 old, InputContext ic) {
- this.containerExponent = old.containerExponent.clone(ic);
+ private BlockPower2(final TreeContainer parent, BlockPower2 old, InputContext ic) {
+ super(parent, old);
+ this.containerExponent = old.containerExponent.clone(this, ic);
}
@Override
@@ -106,7 +107,7 @@ public class BlockPower2 extends Block {
}
@Override
- public BlockPower2 clone(InputContext ic) {
- return new BlockPower2(this, ic);
+ public BlockPower2 clone(final TreeContainer parent, InputContext ic) {
+ return new BlockPower2(parent, this, ic);
}
}
diff --git a/core/src/main/java/it/cavallium/warppi/gui/expression/blocks/BlockSine.java b/core/src/main/java/it/cavallium/warppi/gui/expression/blocks/BlockSine.java
index 468e6736..08998ba9 100644
--- a/core/src/main/java/it/cavallium/warppi/gui/expression/blocks/BlockSine.java
+++ b/core/src/main/java/it/cavallium/warppi/gui/expression/blocks/BlockSine.java
@@ -13,8 +13,8 @@ public class BlockSine extends BlockParenthesisAbstract {
super("SIN");
}
- private BlockSine(BlockSine old, InputContext ic) {
- super(old, ic);
+ private BlockSine(final TreeContainer parent, BlockSine old, InputContext ic) {
+ super(parent, old, ic);
}
@Override
@@ -24,7 +24,7 @@ public class BlockSine extends BlockParenthesisAbstract {
}
@Override
- public Block clone(InputContext ic) {
- return new BlockSine(this, ic);
+ public BlockSine clone(final TreeContainer parent, InputContext ic) {
+ return new BlockSine(parent, this, ic);
}
}
diff --git a/core/src/main/java/it/cavallium/warppi/gui/expression/blocks/BlockSquareRoot.java b/core/src/main/java/it/cavallium/warppi/gui/expression/blocks/BlockSquareRoot.java
index 004d06bd..4bdfe9ea 100644
--- a/core/src/main/java/it/cavallium/warppi/gui/expression/blocks/BlockSquareRoot.java
+++ b/core/src/main/java/it/cavallium/warppi/gui/expression/blocks/BlockSquareRoot.java
@@ -22,9 +22,10 @@ public class BlockSquareRoot extends Block {
recomputeDimensions();
}
- private BlockSquareRoot(BlockSquareRoot old, InputContext ic) {
- this.containerNumber = old.containerNumber.clone(ic);
- recomputeDimensions();
+ private BlockSquareRoot(final TreeContainer parent, BlockSquareRoot old, InputContext ic) {
+ super(parent, old);
+ this.containerNumber = old.containerNumber.clone(this, ic);
+ this.h1 = old.h1;
}
@Override
@@ -118,7 +119,7 @@ public class BlockSquareRoot extends Block {
}
@Override
- public BlockSquareRoot clone(InputContext ic) {
- return new BlockSquareRoot(this, ic);
+ public BlockSquareRoot clone(final TreeContainer parent, InputContext ic) {
+ return new BlockSquareRoot(parent, this, ic);
}
}
diff --git a/core/src/main/java/it/cavallium/warppi/gui/expression/blocks/BlockUndefined.java b/core/src/main/java/it/cavallium/warppi/gui/expression/blocks/BlockUndefined.java
index 67ee0877..46289191 100644
--- a/core/src/main/java/it/cavallium/warppi/gui/expression/blocks/BlockUndefined.java
+++ b/core/src/main/java/it/cavallium/warppi/gui/expression/blocks/BlockUndefined.java
@@ -16,8 +16,8 @@ public class BlockUndefined extends Block {
recomputeDimensions();
}
- private BlockUndefined(BlockUndefined old, InputContext ic) {
- recomputeDimensions();
+ private BlockUndefined(final TreeContainer parent, BlockUndefined old, InputContext ic) {
+ super(parent, old);
}
@Override
@@ -76,8 +76,8 @@ public class BlockUndefined extends Block {
}
@Override
- public BlockUndefined clone(InputContext ic) {
- return new BlockUndefined(this, ic);
+ public BlockUndefined clone(final TreeContainer parent, InputContext ic) {
+ return new BlockUndefined(parent, this, ic);
}
}
diff --git a/core/src/main/java/it/cavallium/warppi/gui/expression/blocks/BlockVariable.java b/core/src/main/java/it/cavallium/warppi/gui/expression/blocks/BlockVariable.java
index 412b4d33..aa59d8ee 100644
--- a/core/src/main/java/it/cavallium/warppi/gui/expression/blocks/BlockVariable.java
+++ b/core/src/main/java/it/cavallium/warppi/gui/expression/blocks/BlockVariable.java
@@ -45,7 +45,8 @@ public class BlockVariable extends Block {
recomputeDimensions();
}
- private BlockVariable(BlockVariable old, InputContext ic) {
+ private BlockVariable(final TreeContainer parent, BlockVariable old, InputContext ic) {
+ super(parent, old);
this.ic = ic;
this.ch = old.ch;
type = old.type;
@@ -53,8 +54,7 @@ public class BlockVariable extends Block {
typeDirtyID = old.typeDirtyID;
this.typeLocked = old.typeLocked;
menu = old.menu == null ? null : new VariableMenu(old.menu, this);
- retrieveValue();
- recomputeDimensions();
+ mustRefresh = old.mustRefresh;
}
private void retrieveValue() {
@@ -273,8 +273,8 @@ public class BlockVariable extends Block {
}
@Override
- public VariableMenu clone(InputContext ic) {
- return new VariableMenu(this, block.clone(ic));
+ public VariableMenu clone(final TreeContainer parent, InputContext ic) {
+ return new VariableMenu(this, block.clone(parent, ic));
}
}
@@ -295,7 +295,7 @@ public class BlockVariable extends Block {
}
@Override
- public BlockVariable clone(InputContext ic) {
- return new BlockVariable(this, ic);
+ public BlockVariable clone(final TreeContainer parent, InputContext ic) {
+ return new BlockVariable(parent, this, ic);
}
}
diff --git a/core/src/main/java/it/cavallium/warppi/gui/expression/containers/InputContainer.java b/core/src/main/java/it/cavallium/warppi/gui/expression/containers/InputContainer.java
index 72a88e35..f31b413e 100644
--- a/core/src/main/java/it/cavallium/warppi/gui/expression/containers/InputContainer.java
+++ b/core/src/main/java/it/cavallium/warppi/gui/expression/containers/InputContainer.java
@@ -18,7 +18,6 @@ import it.cavallium.warppi.util.Error;
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
public abstract class InputContainer implements GraphicalElement, InputLayout {
- private static final long serialVersionUID = 923589369317765667L;
protected BlockContainer root;
protected Caret caret;
private static final float CARET_DURATION = 0.5f;
@@ -61,11 +60,11 @@ public abstract class InputContainer implements GraphicalElement, InputLayout {
*/
protected InputContainer(InputContainer old, InputContext ic) {
this.caretTime = old.caretTime;
- this.extra = old.extra == null ? null : old.extra.clone(ic);
+ this.extra = old.extra == null ? null : old.extra.clone(null, ic);
this.maxPosition = old.maxPosition;
this.caret = old.caret == null ? null : new Caret(old.caret);
this.inputContext = ic;
- this.root = old.root == null ? null : old.root.clone(ic);
+ this.root = old.root == null ? null : old.root.clone(null, ic);
this.parsed = old.parsed;
}
diff --git a/core/src/main/java/it/cavallium/warppi/gui/expression/containers/NormalInputContainer.java b/core/src/main/java/it/cavallium/warppi/gui/expression/containers/NormalInputContainer.java
index 1de13251..fa3d6ad5 100644
--- a/core/src/main/java/it/cavallium/warppi/gui/expression/containers/NormalInputContainer.java
+++ b/core/src/main/java/it/cavallium/warppi/gui/expression/containers/NormalInputContainer.java
@@ -46,7 +46,6 @@ public class NormalInputContainer extends InputContainer {
* @param userInput
* @param ic
*/
- @SuppressWarnings("deprecation")
public NormalInputContainer(InputContainer old, InputContext ic) {
super(old, ic);
}
diff --git a/core/src/main/java/it/cavallium/warppi/gui/graphicengine/Skin.java b/core/src/main/java/it/cavallium/warppi/gui/graphicengine/Skin.java
index 5469dbdd..80c24b71 100644
--- a/core/src/main/java/it/cavallium/warppi/gui/graphicengine/Skin.java
+++ b/core/src/main/java/it/cavallium/warppi/gui/graphicengine/Skin.java
@@ -13,7 +13,15 @@ public interface Skin {
void use(GraphicEngine d);
+ /**
+ * May not be available before initialization
+ * @return skin width
+ */
int getSkinWidth();
+ /**
+ * May not be available before initialization
+ * @return skin height
+ */
int getSkinHeight();
}
diff --git a/core/src/main/java/it/cavallium/warppi/gui/graphicengine/impl/common/PngSkin.java b/core/src/main/java/it/cavallium/warppi/gui/graphicengine/impl/common/PngSkin.java
index c90c8504..78a4fba0 100644
--- a/core/src/main/java/it/cavallium/warppi/gui/graphicengine/impl/common/PngSkin.java
+++ b/core/src/main/java/it/cavallium/warppi/gui/graphicengine/impl/common/PngSkin.java
@@ -1,14 +1,10 @@
package it.cavallium.warppi.gui.graphicengine.impl.common;
-import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
-import java.net.URISyntaxException;
-
-import javax.imageio.ImageIO;
import it.cavallium.warppi.Engine;
-import it.cavallium.warppi.Platform.PngUtils.PngReader;
+import it.cavallium.warppi.Platform.ImageUtils.ImageReader;
import it.cavallium.warppi.gui.graphicengine.GraphicEngine;
import it.cavallium.warppi.gui.graphicengine.Skin;
@@ -29,14 +25,7 @@ public abstract class PngSkin implements Skin {
if (!file.startsWith("/")) {
file = "/" + file;
}
- if (!file.endsWith(".png")) {
- final File f = File.createTempFile("picalculator-png", ".png");
- f.deleteOnExit();
- final BufferedImage img = ImageIO.read(Engine.getPlatform().getStorageUtils().getResourceStream(file));
- ImageIO.write(img, "PNG", f);
- file = f.toString();
- }
- final PngReader r = Engine.getPlatform().getPngUtils().load(Engine.getPlatform().getStorageUtils().getResourceStream(file));
+ final ImageReader r = Engine.getPlatform().getImageUtils().load(Engine.getPlatform().getStorageUtils().getResourceStream(file));
if (r == null) {
skinData = new int[0];
skinSize = new int[] { 0, 0 };
diff --git a/core/src/main/java/it/cavallium/warppi/gui/graphicengine/impl/common/RFTFont.java b/core/src/main/java/it/cavallium/warppi/gui/graphicengine/impl/common/RFTFont.java
index 1e7ea476..a2baae3a 100644
--- a/core/src/main/java/it/cavallium/warppi/gui/graphicengine/impl/common/RFTFont.java
+++ b/core/src/main/java/it/cavallium/warppi/gui/graphicengine/impl/common/RFTFont.java
@@ -1,7 +1,5 @@
package it.cavallium.warppi.gui.graphicengine.impl.common;
-import java.awt.image.BufferedImage;
-import java.awt.image.DataBufferInt;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
@@ -10,8 +8,6 @@ import java.util.LinkedList;
import java.util.logging.Level;
import java.util.logging.Logger;
-import javax.imageio.ImageIO;
-
import it.cavallium.warppi.Engine;
import it.cavallium.warppi.Platform.ConsoleUtils;
import it.cavallium.warppi.gui.graphicengine.BinaryFont;
@@ -19,7 +15,7 @@ import it.cavallium.warppi.gui.graphicengine.GraphicEngine;
import it.cavallium.warppi.util.Utils;
public abstract class RFTFont implements BinaryFont {
-
+
public boolean[][] rawchars;
public int[] chars32;
public int minBound = 10;
@@ -223,18 +219,6 @@ public abstract class RFTFont implements BinaryFont {
}
}
- @SuppressWarnings("unused")
- private void saveArray(final int[] screen, final int w, final int h, final String coutputpng) {
- final BufferedImage bi = new BufferedImage(w, h, 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(BinaryFont.class.getName()).log(Level.SEVERE, null, ex);
- }
- }
-
public int[] getCharIndexes(final String txt) {
final int l = txt.length();
final int[] indexes = new int[l];
diff --git a/core/src/main/java/it/cavallium/warppi/gui/screens/ChooseVariableValueScreen.java b/core/src/main/java/it/cavallium/warppi/gui/screens/ChooseVariableValueScreen.java
index 0a7b92bc..0c8a7ca7 100644
--- a/core/src/main/java/it/cavallium/warppi/gui/screens/ChooseVariableValueScreen.java
+++ b/core/src/main/java/it/cavallium/warppi/gui/screens/ChooseVariableValueScreen.java
@@ -27,6 +27,9 @@ public class ChooseVariableValueScreen extends Screen {
@Override
public void initialized() throws InterruptedException {}
+ @Override
+ public void graphicInitialized() throws InterruptedException {}
+
@Override
public void render() {
Utils.getFont(false, true).use(Engine.INSTANCE.getHardwareDevice().getDisplayManager().engine);
diff --git a/core/src/main/java/it/cavallium/warppi/gui/screens/EmptyScreen.java b/core/src/main/java/it/cavallium/warppi/gui/screens/EmptyScreen.java
index 7502376e..e60210b0 100644
--- a/core/src/main/java/it/cavallium/warppi/gui/screens/EmptyScreen.java
+++ b/core/src/main/java/it/cavallium/warppi/gui/screens/EmptyScreen.java
@@ -19,6 +19,9 @@ public class EmptyScreen extends Screen {
@Override
public void initialized() throws InterruptedException {}
+ @Override
+ public void graphicInitialized() throws InterruptedException {}
+
@Override
public void render() {
// TODO Auto-generated method stub
diff --git a/core/src/main/java/it/cavallium/warppi/gui/screens/KeyboardDebugScreen.java b/core/src/main/java/it/cavallium/warppi/gui/screens/KeyboardDebugScreen.java
index 10302b19..412a08e7 100644
--- a/core/src/main/java/it/cavallium/warppi/gui/screens/KeyboardDebugScreen.java
+++ b/core/src/main/java/it/cavallium/warppi/gui/screens/KeyboardDebugScreen.java
@@ -27,6 +27,9 @@ public class KeyboardDebugScreen extends Screen {
@Override
public void initialized() throws InterruptedException {}
+ @Override
+ public void graphicInitialized() throws InterruptedException {}
+
@Override
public void render() {
final Renderer renderer = Engine.INSTANCE.getHardwareDevice().getDisplayManager().renderer;
diff --git a/core/src/main/java/it/cavallium/warppi/gui/screens/LoadingScreen.java b/core/src/main/java/it/cavallium/warppi/gui/screens/LoadingScreen.java
index ed4af2f2..db078d4e 100644
--- a/core/src/main/java/it/cavallium/warppi/gui/screens/LoadingScreen.java
+++ b/core/src/main/java/it/cavallium/warppi/gui/screens/LoadingScreen.java
@@ -33,6 +33,9 @@ public class LoadingScreen extends Screen {
Engine.INSTANCE.getHardwareDevice().getDisplayManager().getHUD().hide();
StaticVars.windowZoom.onNext(1f);
}
+
+ @Override
+ public void graphicInitialized() throws InterruptedException {}
@Override
public void beforeRender(final float dt) {
diff --git a/core/src/main/java/it/cavallium/warppi/gui/screens/MathInputScreen.java b/core/src/main/java/it/cavallium/warppi/gui/screens/MathInputScreen.java
index d783556c..396c4eb3 100644
--- a/core/src/main/java/it/cavallium/warppi/gui/screens/MathInputScreen.java
+++ b/core/src/main/java/it/cavallium/warppi/gui/screens/MathInputScreen.java
@@ -105,6 +105,11 @@ public class MathInputScreen extends Screen {
/* Fine caricamento */
}
+ @Override
+ public void graphicInitialized() throws InterruptedException {
+ /* Fine caricamento */
+ }
+
@Override
public void beforeRender(final float dt) {
if (Engine.INSTANCE.getHardwareDevice().getDisplayManager().error == null) {
diff --git a/core/src/main/java/it/cavallium/warppi/gui/screens/Screen.java b/core/src/main/java/it/cavallium/warppi/gui/screens/Screen.java
index ec6dbb27..5c07dd1e 100644
--- a/core/src/main/java/it/cavallium/warppi/gui/screens/Screen.java
+++ b/core/src/main/java/it/cavallium/warppi/gui/screens/Screen.java
@@ -10,6 +10,7 @@ public abstract class Screen implements KeyboardEventListener, TouchEventListene
public DisplayManager d;
public boolean created = false;
public boolean initialized = false;
+ public boolean graphicInitialized = false;
public HistoryBehavior historyBehavior = HistoryBehavior.NORMAL;
public static long lastDebugScreenID = 1;
@@ -19,6 +20,14 @@ public abstract class Screen implements KeyboardEventListener, TouchEventListene
debugScreenID = lastDebugScreenID++;
}
+ @Override
+ public void initializeGraphic() throws InterruptedException {
+ if (!graphicInitialized) {
+ graphicInitialized = true;
+ graphicInitialized();
+ }
+ }
+
@Override
public void initialize() throws InterruptedException {
if (!initialized) {
@@ -35,10 +44,30 @@ public abstract class Screen implements KeyboardEventListener, TouchEventListene
}
}
+ /**
+ * Called when creating the screen
+ * Called before initialized()
+ * Called before graphicInitialized()
+ * @throws InterruptedException
+ */
public abstract void created() throws InterruptedException;
+ /**
+ * Load everything except skins, etc...
+ * Called after created()
+ * Called after graphicInitialized()
+ * @throws InterruptedException
+ */
public abstract void initialized() throws InterruptedException;
+ /**
+ * Load skins, etc...
+ * Called after created()
+ * Called before initialized()
+ * @throws InterruptedException
+ */
+ public abstract void graphicInitialized() throws InterruptedException;
+
@Override
public abstract void render();
diff --git a/core/src/main/java/it/cavallium/warppi/gui/screens/SolveForXScreen.java b/core/src/main/java/it/cavallium/warppi/gui/screens/SolveForXScreen.java
index 6890dd18..c9a06249 100644
--- a/core/src/main/java/it/cavallium/warppi/gui/screens/SolveForXScreen.java
+++ b/core/src/main/java/it/cavallium/warppi/gui/screens/SolveForXScreen.java
@@ -23,6 +23,9 @@ public class SolveForXScreen extends Screen {
@Override
public void initialized() throws InterruptedException {}
+ @Override
+ public void graphicInitialized() throws InterruptedException {}
+
@Override
public void render() {
Engine.INSTANCE.getHardwareDevice().getDisplayManager().renderer.glColor4i(0, 0, 0, 64);
diff --git a/core/src/main/java/it/cavallium/warppi/math/Function.java b/core/src/main/java/it/cavallium/warppi/math/Function.java
index 9a72fb64..24494324 100644
--- a/core/src/main/java/it/cavallium/warppi/math/Function.java
+++ b/core/src/main/java/it/cavallium/warppi/math/Function.java
@@ -71,7 +71,7 @@ public interface Function {
* @throws InterruptedException
*/
ObjectArrayList simplify(Rule rule) throws Error, InterruptedException;
-
+
/**
*
* @param context
diff --git a/core/src/main/java/it/cavallium/warppi/math/FunctionDynamic.java b/core/src/main/java/it/cavallium/warppi/math/FunctionDynamic.java
index 5c0bbd24..5c959bc0 100644
--- a/core/src/main/java/it/cavallium/warppi/math/FunctionDynamic.java
+++ b/core/src/main/java/it/cavallium/warppi/math/FunctionDynamic.java
@@ -9,6 +9,8 @@ import it.cavallium.warppi.util.Utils;
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
public abstract class FunctionDynamic implements Function {
+ private boolean simplified;
+
public FunctionDynamic(final MathContext root) {
this.root = root;
functions = new Function[] {};
@@ -131,7 +133,7 @@ public abstract class FunctionDynamic implements Function {
@Override
public abstract FunctionDynamic clone();
-
+
@Override
public int hashCode() {
return functions.hashCode() + 883 * super.hashCode();
diff --git a/core/src/main/java/it/cavallium/warppi/math/FunctionOperator.java b/core/src/main/java/it/cavallium/warppi/math/FunctionOperator.java
index 91d79819..c43de8b2 100644
--- a/core/src/main/java/it/cavallium/warppi/math/FunctionOperator.java
+++ b/core/src/main/java/it/cavallium/warppi/math/FunctionOperator.java
@@ -7,7 +7,7 @@ import it.cavallium.warppi.util.Utils;
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
public abstract class FunctionOperator implements Function {
-
+
/**
* Create a new instance of FunctionOperator. The Math Context will be the
* same of value1's.
diff --git a/core/src/main/java/it/cavallium/warppi/math/FunctionSingle.java b/core/src/main/java/it/cavallium/warppi/math/FunctionSingle.java
index 1f7ee462..9f17d25f 100644
--- a/core/src/main/java/it/cavallium/warppi/math/FunctionSingle.java
+++ b/core/src/main/java/it/cavallium/warppi/math/FunctionSingle.java
@@ -6,6 +6,8 @@ import it.unimi.dsi.fastutil.objects.ObjectArrayList;
public abstract class FunctionSingle implements Function {
+ private boolean simplified;
+
/**
* Create a new instance of FunctionSingle. The Math Context will be the
* same of value's.
diff --git a/core/src/main/java/it/cavallium/warppi/math/functions/EmptyNumber.java b/core/src/main/java/it/cavallium/warppi/math/functions/EmptyNumber.java
deleted file mode 100644
index bbdefc25..00000000
--- a/core/src/main/java/it/cavallium/warppi/math/functions/EmptyNumber.java
+++ /dev/null
@@ -1,65 +0,0 @@
-package it.cavallium.warppi.math.functions;
-
-import it.cavallium.warppi.gui.expression.blocks.Block;
-import it.cavallium.warppi.math.Function;
-import it.cavallium.warppi.math.FunctionVisitor;
-import it.cavallium.warppi.math.MathContext;
-import it.cavallium.warppi.math.rules.Rule;
-import it.cavallium.warppi.util.Error;
-import it.unimi.dsi.fastutil.objects.ObjectArrayList;
-
-public class EmptyNumber implements Function {
-
- public EmptyNumber(final MathContext root) {
- this.root = root;
- }
-
- private final MathContext root;
-
- @Override
- public ObjectArrayList simplify(final Rule rule) throws Error, InterruptedException {
- return rule.execute(this);
- }
-
- @Override
- public MathContext getMathContext() {
- return root;
- }
-
- @Override
- public boolean equals(final Object o) {
- return o instanceof EmptyNumber;
- }
-
- @Override
- public Function clone() {
- return new EmptyNumber(root);
- }
-
- @Override
- public Function clone(MathContext c) {
- return new EmptyNumber(c);
- }
-
- @Override
- public Function setParameter(final int index, final Function var) throws IndexOutOfBoundsException {
- throw new IndexOutOfBoundsException();
- }
-
- @Override
- public Function getParameter(final int index) throws IndexOutOfBoundsException {
- throw new IndexOutOfBoundsException();
- }
-
- @Override
- public ObjectArrayList toBlock(final MathContext context) {
- // TODO Auto-generated method stub
- return null;
- }
-
- @Override
- public T accept(final FunctionVisitor visitor) {
- return visitor.visit(this);
- }
-
-}
diff --git a/core/src/main/java/it/cavallium/warppi/math/functions/Variable.java b/core/src/main/java/it/cavallium/warppi/math/functions/Variable.java
index 6baf6792..da2041d8 100644
--- a/core/src/main/java/it/cavallium/warppi/math/functions/Variable.java
+++ b/core/src/main/java/it/cavallium/warppi/math/functions/Variable.java
@@ -14,6 +14,7 @@ public class Variable implements Function {
protected char var;
protected final MathContext root;
protected V_TYPE type = V_TYPE.CONSTANT;
+ private boolean simplified;
public Variable(final MathContext root, final char val, final V_TYPE type) {
this.root = root;
diff --git a/core/src/main/java/it/cavallium/warppi/math/solver/MathSolver.java b/core/src/main/java/it/cavallium/warppi/math/solver/MathSolver.java
index 30ca1fb1..8394621e 100644
--- a/core/src/main/java/it/cavallium/warppi/math/solver/MathSolver.java
+++ b/core/src/main/java/it/cavallium/warppi/math/solver/MathSolver.java
@@ -1,6 +1,7 @@
package it.cavallium.warppi.math.solver;
import java.util.List;
+import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
import it.cavallium.warppi.Engine;
@@ -9,6 +10,9 @@ import it.cavallium.warppi.math.Function;
import it.cavallium.warppi.math.rules.Rule;
import it.cavallium.warppi.math.rules.RuleType;
import it.cavallium.warppi.util.Error;
+import it.unimi.dsi.fastutil.objects.Object2ObjectMaps;
+import it.unimi.dsi.fastutil.objects.Object2ObjectOpenCustomHashMap;
+import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
public class MathSolver {
@@ -17,6 +21,7 @@ public class MathSolver {
private final AtomicInteger stepState = new AtomicInteger(0);
private int stepStateRepetitions = 0;
private int consecutiveNullSteps = 0;
+ private final Object2ObjectOpenHashMap> simplificationCache;
private enum StepState {
_1_CALCULATION, _2_EXPANSION, _3_CALCULATION, _4_REDUCTION
@@ -28,6 +33,7 @@ public class MathSolver {
public MathSolver(final Function initialFunction) {
this.initialFunction = initialFunction;
+ this.simplificationCache = new Object2ObjectOpenHashMap>();
}
@SuppressWarnings("unchecked")
@@ -214,15 +220,18 @@ public class MathSolver {
for (final Function fnc : fncs) {
boolean didSomething = false;
for (final Rule rule : rules) {
- final List ruleResults = fnc.simplify(rule);
- if (ruleResults != null && !ruleResults.isEmpty()) {
- if (results == null) {
- results = new ObjectArrayList<>();
+ if (isSimplified(fnc, rule) == false) {
+ final List ruleResults = fnc.simplify(rule);
+ if (ruleResults != null && !ruleResults.isEmpty()) {
+ if (results == null) {
+ results = new ObjectArrayList<>();
+ }
+ results.addAll(ruleResults);
+ appliedRules.add(rule);
+ setSimplified(fnc, rule);
+ didSomething = true;
+ break;
}
- results.addAll(ruleResults);
- appliedRules.add(rule);
- didSomething = true;
- break;
}
}
if (!didSomething && fncs.size() > 1) {
@@ -248,4 +257,30 @@ public class MathSolver {
}
return results;
}
+
+ private boolean isSimplified(Function fnc, Rule rule) {
+ if (simplificationCache.containsKey(fnc)) {
+ List alreadySimplifiedRules = simplificationCache.get(fnc);
+ if (alreadySimplifiedRules.contains(rule)) {
+ return true;
+ } else {
+ return false;
+ }
+ } else {
+ simplificationCache.put(fnc, new ObjectArrayList());
+ }
+ return false;
+ }
+
+ private void setSimplified(Function fnc, Rule rule) {
+ ObjectArrayList oar;
+ if (simplificationCache.containsKey(fnc)) {
+ oar = new ObjectArrayList<>();
+ simplificationCache.put(fnc, oar);
+ } else {
+ oar = simplificationCache.get(fnc);
+ if (oar.contains(rule)) return;
+ }
+ oar.add(rule);
+ }
}
diff --git a/core/src/main/java/it/cavallium/warppi/util/Utils.java b/core/src/main/java/it/cavallium/warppi/util/Utils.java
index c1d195a6..0336f252 100644
--- a/core/src/main/java/it/cavallium/warppi/util/Utils.java
+++ b/core/src/main/java/it/cavallium/warppi/util/Utils.java
@@ -4,15 +4,10 @@ import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
-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;
import java.net.URISyntaxException;
-import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
@@ -571,55 +566,6 @@ public class Utils {
return sdata;
}
- public static void printSystemResourcesUsage() {
- System.out.println("============");
- final OperatingSystemMXBean operatingSystemMXBean = ManagementFactory.getOperatingSystemMXBean();
- for (final 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 (final Exception e) {
- value = e;
- } // try
- boolean percent = false;
- boolean mb = false;
- final String displayName = method.getName();
- final String displayValue = value.toString();
- if (displayName.endsWith("CpuLoad")) {
- percent = true;
- }
- if (displayName.endsWith("MemorySize")) {
- mb = true;
- }
- final List 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 (final Exception ex) {
- System.out.println(displayName + " = " + displayValue);
- }
- } else if (mb) {
- try {
- System.out.println(displayName + " = " + Long.parseLong(displayValue) / 1024L / 1024L + " MB");
- } catch (final Exception ex) {
- System.out.println(displayName + " = " + displayValue);
- }
- } else {
- System.out.println(displayName + " = " + displayValue);
- }
- }
- } // if
- } // for
- System.out.println("============");
- }
-
public static boolean isWindows() {
return Engine.getPlatform().getOsName().indexOf("win") >= 0;
}
diff --git a/core/src/main/java/org/nevec/rjm/Bernoulli.java b/core/src/main/java/org/nevec/rjm/Bernoulli.java
deleted file mode 100644
index d4834db0..00000000
--- a/core/src/main/java/org/nevec/rjm/Bernoulli.java
+++ /dev/null
@@ -1,102 +0,0 @@
-package org.nevec.rjm;
-
-import java.math.BigInteger;
-import java.util.Vector;
-
-import it.cavallium.warppi.util.Error;
-
-/**
- * Bernoulli numbers.
- *
- * @since 2006-06-25
- * @author Richard J. Mathar
- */
-public class Bernoulli {
- /*
- * The list of all Bernoulli numbers as a vector, n=0,2,4,....
- */
- static Vector a = new Vector<>();
-
- public Bernoulli() {
- if (Bernoulli.a.size() == 0) {
- Bernoulli.a.add(Rational.ONE);
- Bernoulli.a.add(new Rational(1, 6));
- }
- }
-
- /**
- * Set a coefficient in the internal table.
- *
- * @param n
- * the zero-based index of the coefficient. n=0 for the constant
- * term.
- * @param value
- * the new value of the coefficient.
- */
- protected void set(final int n, final Rational value) {
- final int nindx = n / 2;
- if (nindx < Bernoulli.a.size()) {
- Bernoulli.a.set(nindx, value);
- } else {
- while (Bernoulli.a.size() < nindx) {
- Bernoulli.a.add(Rational.ZERO);
- }
- Bernoulli.a.add(value);
- }
- }
-
- /**
- * The Bernoulli number at the index provided.
- *
- * @param n
- * the index, non-negative.
- * @return the B_0=1 for n=0, B_1=-1/2 for n=1, B_2=1/6 for n=2 etc
- * @throws Error
- */
- public Rational at(final int n) throws Error {
- if (n == 1) {
- return new Rational(-1, 2);
- } else if (n % 2 != 0) {
- return Rational.ZERO;
- } else {
- final int nindx = n / 2;
- if (Bernoulli.a.size() <= nindx) {
- for (int i = 2 * Bernoulli.a.size(); i <= n; i += 2) {
- set(i, doubleSum(i));
- }
- }
- return Bernoulli.a.elementAt(nindx);
- }
- }
-
- /*
- * Generate a new B_n by a standard double sum.
- *
- * @param n The index of the Bernoulli number.
- *
- * @return The Bernoulli number at n.
- */
- private Rational doubleSum(final int n) throws Error {
- Rational resul = Rational.ZERO;
- for (int k = 0; k <= n; k++) {
- Rational jsum = Rational.ZERO;
- BigInteger bin = BigInteger.ONE;
- for (int j = 0; j <= k; j++) {
- final BigInteger jpown = new BigInteger("" + j).pow(n);
- if (j % 2 == 0) {
- jsum = jsum.add(bin.multiply(jpown));
- } else {
- jsum = jsum.subtract(bin.multiply(jpown));
- }
-
- /*
- * update binomial(k,j) recursively
- */
- bin = bin.multiply(new BigInteger("" + (k - j))).divide(new BigInteger("" + (j + 1)));
- }
- resul = resul.add(jsum.divide(new BigInteger("" + (k + 1))));
- }
- return resul;
- }
-
-} /* Bernoulli */
diff --git a/core/src/main/java/org/nevec/rjm/BigComplex.java b/core/src/main/java/org/nevec/rjm/BigComplex.java
deleted file mode 100644
index 636e53a4..00000000
--- a/core/src/main/java/org/nevec/rjm/BigComplex.java
+++ /dev/null
@@ -1,220 +0,0 @@
-package org.nevec.rjm;
-
-import java.math.BigDecimal;
-import java.math.MathContext;
-
-/**
- * Complex numbers with BigDecimal real and imaginary components
- *
- * @since 2008-10-26
- * @author Richard J. Mathar
- */
-public class BigComplex {
- /**
- * real part
- */
- BigDecimal re;
-
- /**
- * imaginary part
- */
- BigDecimal im;
-
- /**
- * The constant that equals zero
- */
- final static BigComplex ZERO = new BigComplex(BigDecimal.ZERO, BigDecimal.ZERO);
-
- /**
- * Default ctor equivalent to zero.
- */
- public BigComplex() {
- re = BigDecimal.ZERO;
- im = BigDecimal.ZERO;
- }
-
- /**
- * ctor with real and imaginary parts
- *
- * @param x
- * real part
- * @param y
- * imaginary part
- */
- public BigComplex(final BigDecimal x, final BigDecimal y) {
- re = x;
- im = y;
- }
-
- /**
- * ctor with real part.
- *
- * @param x
- * real part.
- * The imaginary part is set to zero.
- */
- public BigComplex(final BigDecimal x) {
- re = x;
- im = BigDecimal.ZERO;
- }
-
- /**
- * ctor with real and imaginary parts
- *
- * @param x
- * real part
- * @param y
- * imaginary part
- */
- public BigComplex(final double x, final double y) {
- re = new BigDecimal(x);
- im = new BigDecimal(y);
- }
-
- /**
- * Multiply with another BigComplex
- *
- * @param oth
- * The BigComplex which is a factor in the product
- * @param mc
- * Defining precision and rounding mode
- * @return This multiplied by oth
- * @since 2010-07-19 implemented with 3 multiplications and 5
- * additions/subtractions
- */
- BigComplex multiply(final BigComplex oth, final MathContext mc) {
- final BigDecimal a = re.add(im).multiply(oth.re);
- final BigDecimal b = oth.re.add(oth.im).multiply(im);
- final BigDecimal c = oth.im.subtract(oth.re).multiply(re);
- final BigDecimal x = a.subtract(b, mc);
- final BigDecimal y = a.add(c, mc);
- return new BigComplex(x, y);
- }
-
- /**
- * Add a BigDecimal
- *
- * @param oth
- * the value to be added to the real part.
- * @return this added to oth
- */
- BigComplex add(final BigDecimal oth) {
- final BigDecimal x = re.add(oth);
- return new BigComplex(x, im);
- }
-
- /**
- * Subtract another BigComplex
- *
- * @param oth
- * the value to be subtracted from this.
- * @return this minus oth
- */
- BigComplex subtract(final BigComplex oth) {
- final BigDecimal x = re.subtract(oth.re);
- final BigDecimal y = im.subtract(oth.im);
- return new BigComplex(x, y);
- }
-
- /**
- * Complex-conjugation
- *
- * @return the complex conjugate of this.
- */
- BigComplex conj() {
- return new BigComplex(re, im.negate());
- }
-
- /**
- * The absolute value squared.
- *
- * @return The sum of the squares of real and imaginary parts.
- * This is the square of BigComplex.abs() .
- */
- BigDecimal norm() {
- return re.multiply(re).add(im.multiply(im));
- }
-
- /**
- * The absolute value.
- *
- * @return the square root of the sum of the squares of real and imaginary
- * parts.
- * @since 2008-10-27
- */
- BigDecimal abs(final MathContext mc) {
- return BigDecimalMath.sqrt(norm(), mc);
- }
-
- /**
- * The square root.
- *
- * @return the square root of the this.
- * The branch is chosen such that the imaginary part of the result
- * has the
- * same sign as the imaginary part of this.
- * @see Tim Ahrendt, Fast
- * High-precision computation of complex square roots,
- * ISSAC 1996 p142-149.
- * @since 2008-10-27
- */
- BigComplex sqrt(final MathContext mc) {
- final BigDecimal half = new BigDecimal("2");
- /*
- * compute l=sqrt(re^2+im^2), then u=sqrt((l+re)/2)
- * and v= +- sqrt((l-re)/2 as the new real and imaginary parts.
- */
- final BigDecimal l = abs(mc);
- 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) {
- return new BigComplex(u, v);
- } else {
- return new BigComplex(u, v.negate());
- }
- }
-
- /**
- * The inverse of this.
- *
- * @return 1/this
- */
- BigComplex inverse(final MathContext mc) {
- final BigDecimal hyp = norm();
- /* 1/(x+iy)= (x-iy)/(x^2+y^2 */
- return new BigComplex(re.divide(hyp, mc), im.divide(hyp, mc).negate());
- }
-
- /**
- * Divide through another BigComplex number.
- *
- * @return this/oth
- */
- BigComplex divide(final BigComplex oth, final MathContext mc) {
- /* lazy implementation: (x+iy)/(a+ib)= (x+iy)* 1/(a+ib) */
- return multiply(oth.inverse(mc), mc);
- }
-
- /**
- * Human-readable Fortran-type display
- *
- * @return real and imaginary part in parenthesis, divided by a comma.
- */
- @Override
- public String toString() {
- return "(" + re.toString() + "," + im.toString() + ")";
- }
-
- /**
- * Human-readable Fortran-type display
- *
- * @return real and imaginary part in parenthesis, divided by a comma.
- */
- public String toString(final MathContext mc) {
- return "(" + re.round(mc).toString() + "," + im.round(mc).toString() + ")";
- }
-
-} /* BigComplex */
diff --git a/core/src/main/java/org/nevec/rjm/BigDecimalMath.java b/core/src/main/java/org/nevec/rjm/BigDecimalMath.java
deleted file mode 100644
index 926f1ded..00000000
--- a/core/src/main/java/org/nevec/rjm/BigDecimalMath.java
+++ /dev/null
@@ -1,3038 +0,0 @@
-package org.nevec.rjm;
-
-import java.math.BigDecimal;
-import java.math.BigInteger;
-import java.math.MathContext;
-import java.security.ProviderException;
-
-import it.cavallium.warppi.util.Error;
-
-/**
- * BigDecimal special functions.
- * A Java Math.BigDecimal
- * Implementation of Core Mathematical Functions
- *
- * @since 2009-05-22
- * @author Richard J. Mathar
- * @see apfloat
- * @see dfp
- * @see JScience
- */
-public class BigDecimalMath {
-
- /**
- * The base of the natural logarithm in a predefined accuracy.
- * http://www.cs.arizona.edu/icon/oddsends/e.htm
- * The precision of the predefined constant is one less than
- * the string's length, taking into account the decimal dot.
- * static int E_PRECISION = E.length()-1 ;
- */
- static BigDecimal E = new BigDecimal("2.71828182845904523536028747135266249775724709369995957496696762772407663035354" + "759457138217852516642742746639193200305992181741359662904357290033429526059563" + "073813232862794349076323382988075319525101901157383418793070215408914993488416" + "750924476146066808226480016847741185374234544243710753907774499206955170276183" + "860626133138458300075204493382656029760673711320070932870912744374704723069697" + "720931014169283681902551510865746377211125238978442505695369677078544996996794" + "686445490598793163688923009879312773617821542499922957635148220826989519366803" + "318252886939849646510582093923982948879332036250944311730123819706841614039701" + "983767932068328237646480429531180232878250981945581530175671736133206981125099" + "618188159304169035159888851934580727386673858942287922849989208680582574927961" + "048419844436346324496848756023362482704197862320900216099023530436994184914631" + "409343173814364054625315209618369088870701676839642437814059271456354906130310" + "720851038375051011574770417189861068739696552126715468895703503540212340784981" + "933432106817012100562788023519303322474501585390473041995777709350366041699732" + "972508868769664035557071622684471625607988265178713419512466520103059212366771" + "943252786753985589448969709640975459185695638023637016211204774272283648961342" + "251644507818244235294863637214174023889344124796357437026375529444833799801612" + "549227850925778256209262264832627793338656648162772516401910590049164499828931");
-
- /**
- * Euler's constant Pi.
- * http://www.cs.arizona.edu/icon/oddsends/pi.htm
- */
- static BigDecimal PI = new BigDecimal("3.14159265358979323846264338327950288419716939937510582097494459230781640628620" + "899862803482534211706798214808651328230664709384460955058223172535940812848111" + "745028410270193852110555964462294895493038196442881097566593344612847564823378" + "678316527120190914564856692346034861045432664821339360726024914127372458700660" + "631558817488152092096282925409171536436789259036001133053054882046652138414695" + "194151160943305727036575959195309218611738193261179310511854807446237996274956" + "735188575272489122793818301194912983367336244065664308602139494639522473719070" + "217986094370277053921717629317675238467481846766940513200056812714526356082778" + "577134275778960917363717872146844090122495343014654958537105079227968925892354" + "201995611212902196086403441815981362977477130996051870721134999999837297804995" + "105973173281609631859502445945534690830264252230825334468503526193118817101000" + "313783875288658753320838142061717766914730359825349042875546873115956286388235" + "378759375195778185778053217122680661300192787661119590921642019893809525720106" + "548586327886593615338182796823030195203530185296899577362259941389124972177528" + "347913151557485724245415069595082953311686172785588907509838175463746493931925" + "506040092770167113900984882401285836160356370766010471018194295559619894676783" + "744944825537977472684710404753464620804668425906949129331367702898915210475216" + "205696602405803815019351125338243003558764024749647326391419927260426992279678" + "235478163600934172164121992458631503028618297455570674983850549458858692699569" + "092721079750930295532116534498720275596023648066549911988183479775356636980742" + "654252786255181841757467289097777279380008164706001614524919217321721477235014");
-
- /**
- * Euler-Mascheroni constant lower-case gamma.
- * http://www.worldwideschool.org/library/books/sci/math/
- * MiscellaneousMathematicalConstants/chap35.html
- */
- static BigDecimal GAMMA = new BigDecimal("0.577215664901532860606512090082402431" + "0421593359399235988057672348848677267776646709369470632917467495146314472498070" + "8248096050401448654283622417399764492353625350033374293733773767394279259525824" + "7094916008735203948165670853233151776611528621199501507984793745085705740029921" + "3547861466940296043254215190587755352673313992540129674205137541395491116851028" + "0798423487758720503843109399736137255306088933126760017247953783675927135157722" + "6102734929139407984301034177717780881549570661075010161916633401522789358679654" + "9725203621287922655595366962817638879272680132431010476505963703947394957638906" + "5729679296010090151251959509222435014093498712282479497471956469763185066761290" + "6381105182419744486783638086174945516989279230187739107294578155431600500218284" + "4096053772434203285478367015177394398700302370339518328690001558193988042707411" + "5422278197165230110735658339673487176504919418123000406546931429992977795693031" + "0050308630341856980323108369164002589297089098548682577736428825395492587362959" + "6133298574739302373438847070370284412920166417850248733379080562754998434590761" + "6431671031467107223700218107450444186647591348036690255324586254422253451813879" + "1243457350136129778227828814894590986384600629316947188714958752549236649352047" + "3243641097268276160877595088095126208404544477992299157248292516251278427659657" + "0832146102982146179519579590959227042089896279712553632179488737642106606070659" + "8256199010288075612519913751167821764361905705844078357350158005607745793421314" + "49885007864151716151945");
-
- /**
- * Natural logarithm of 2.
- * http://www.worldwideschool.org/library/books/sci/math/
- * MiscellaneousMathematicalConstants/chap58.html
- */
- static BigDecimal LOG2 = new BigDecimal("0.693147180559945309417232121458176568075" + "50013436025525412068000949339362196969471560586332699641868754200148102057068573" + "368552023575813055703267075163507596193072757082837143519030703862389167347112335" + "011536449795523912047517268157493206515552473413952588295045300709532636664265410" + "423915781495204374043038550080194417064167151864471283996817178454695702627163106" + "454615025720740248163777338963855069526066834113727387372292895649354702576265209" + "885969320196505855476470330679365443254763274495125040606943814710468994650622016" + "772042452452961268794654619316517468139267250410380254625965686914419287160829380" + "317271436778265487756648508567407764845146443994046142260319309673540257444607030" + "809608504748663852313818167675143866747664789088143714198549423151997354880375165" + "861275352916610007105355824987941472950929311389715599820565439287170007218085761" + "025236889213244971389320378439353088774825970171559107088236836275898425891853530" + "243634214367061189236789192372314672321720534016492568727477823445353476481149418" + "642386776774406069562657379600867076257199184734022651462837904883062033061144630" + "073719489002743643965002580936519443041191150608094879306786515887090060520346842" + "973619384128965255653968602219412292420757432175748909770675268711581705113700915" + "894266547859596489065305846025866838294002283300538207400567705304678700184162404" + "418833232798386349001563121889560650553151272199398332030751408426091479001265168" + "243443893572472788205486271552741877243002489794540196187233980860831664811490930" + "667519339312890431641370681397776498176974868903887789991296503619270710889264105" + "230924783917373501229842420499568935992206602204654941510613");
-
- /**
- * Euler's constant.
- *
- * @param mc
- * The required precision of the result.
- * @return 3.14159...
- * @throws Error
- * @since 2009-05-29
- */
- static public BigDecimal pi(final MathContext mc) throws Error {
- /* look it up if possible */
- if (mc.getPrecision() < BigDecimalMath.PI.precision()) {
- return BigDecimalMath.PI.round(mc);
- } else {
- /*
- * Broadhurst arXiv:math/9803067
- */
- final int[] a = { 1, 0, 0, -1, -1, -1, 0, 0 };
- final BigDecimal S = BigDecimalMath.broadhurstBBP(1, 1, a, mc);
- return BigDecimalMath.multiplyRound(S, 8);
- }
- } /* BigDecimalMath.pi */
-
- /**
- * Euler-Mascheroni constant.
- *
- * @param mc
- * The required precision of the result.
- * @return 0.577...
- * @throws Error
- * @since 2009-08-13
- */
- static public BigDecimal gamma(final MathContext mc) throws Error {
- /* look it up if possible */
- if (mc.getPrecision() < BigDecimalMath.GAMMA.precision()) {
- return BigDecimalMath.GAMMA.round(mc);
- } else {
- final double eps = BigDecimalMath.prec2err(0.577, mc.getPrecision());
-
- /*
- * Euler-Stieltjes as shown in Dilcher, Aequat Math 48 (1) (1994)
- * 55-85
- */
- MathContext mcloc = SafeMathContext.newMathContext(2 + mc.getPrecision());
- BigDecimal resul = BigDecimal.ONE;
- resul = resul.add(BigDecimalMath.log(2, mcloc));
- resul = resul.subtract(BigDecimalMath.log(3, mcloc));
-
- /*
- * how many terms: zeta-1 falls as 1/2^(2n+1), so the
- * terms drop faster than 1/2^(4n+2). Set 1/2^(4kmax+2) < eps.
- * Leading term zeta(3)/(4^1*3) is 0.017. Leading zeta(3) is 1.2.
- * Log(2) is 0.7
- */
- final int kmax = (int) ((Math.log(eps / 0.7) - 2.) / 4.);
- mcloc = SafeMathContext.newMathContext(1 + BigDecimalMath.err2prec(1.2, eps / kmax));
- for (int n = 1;; n++) {
- /*
- * zeta is close to 1. Division of zeta-1 through
- * 4^n*(2n+1) means divion through roughly 2^(2n+1)
- */
- BigDecimal c = BigDecimalMath.zeta(2 * n + 1, mcloc).subtract(BigDecimal.ONE);
- BigInteger fourn = new BigInteger("" + (2 * n + 1));
- fourn = fourn.shiftLeft(2 * n);
- c = BigDecimalMath.divideRound(c, fourn);
- resul = resul.subtract(c);
- if (c.doubleValue() < 0.1 * eps) {
- break;
- }
- }
- return resul.round(mc);
- }
-
- } /* BigDecimalMath.gamma */
-
- /**
- * The square root.
- *
- * @param x
- * the non-negative argument.
- * @param mc
- * @return the square root of the BigDecimal.
- * @since 2008-10-27
- */
- static public BigDecimal sqrt(final BigDecimal x, final MathContext mc) {
- 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) {
- 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 */
- final MathContext locmc = SafeMathContext.newMathContext(mc.getPrecision() + 2, mc.getRoundingMode());
-
- /*
- * relative accuracy requested is 10^(-precision)
- */
- final double eps = Math.pow(10.0, -mc.getPrecision());
- for (;;) {
- /*
- * s = s -(s/2-x/2s); test correction s-x/s for being
- * smaller than the precision requested. The relative correction is
- * 1-x/s^2,
- * (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) {
- break;
- }
- s = s.add(x.divide(s, locmc)).divide(half, locmc);
- /* debugging */
- // System.out.println("itr "+x.round(locmc).toString() + " " +
- // s.round(locmc).toString()) ;
- }
- return s;
- } /* BigDecimalMath.sqrt */
-
- /**
- * The square root.
- *
- * @param x
- * the non-negative argument.
- * @return the square root of the BigDecimal rounded to the precision
- * implied by x.
- * @since 2009-06-25
- */
- static public BigDecimal sqrt(final BigDecimal x) {
- if (x.compareTo(BigDecimal.ZERO) < 0) {
- throw new ArithmeticException("negative argument " + x.toString() + " of square root");
- }
-
- return BigDecimalMath.root(2, x);
- } /* BigDecimalMath.sqrt */
-
- /**
- * The cube root.
- *
- * @param x
- * The argument.
- * @return The cubic root of the BigDecimal rounded to the precision implied
- * by x.
- * The sign of the result is the sign of the argument.
- * @since 2009-08-16
- */
- static public BigDecimal cbrt(final BigDecimal x) {
- if (x.compareTo(BigDecimal.ZERO) < 0) {
- return BigDecimalMath.root(3, x.negate()).negate();
- } else {
- return BigDecimalMath.root(3, x);
- }
- } /* BigDecimalMath.cbrt */
-
- /**
- * The integer root.
- *
- * @param n
- * the positive argument.
- * @param x
- * the non-negative argument.
- * @return The n-th root of the BigDecimal rounded to the precision implied
- * by x, x^(1/n).
- * @since 2009-07-30
- */
- static public BigDecimal root(final int n, final BigDecimal x) {
- if (x.compareTo(BigDecimal.ZERO) < 0) {
- throw new ArithmeticException("negative argument " + x.toString() + " of root");
- }
- if (n <= 0) {
- throw new ArithmeticException("negative power " + n + " of root");
- }
-
- if (n == 1) {
- return x;
- }
-
- /* start the computation from a double precision estimate */
- BigDecimal s = new BigDecimal(Math.pow(x.doubleValue(), 1.0 / n));
-
- /*
- * this creates nth with nominal precision of 1 digit
- */
- final BigDecimal nth = new BigDecimal(n);
-
- /*
- * Specify an internal accuracy within the loop which is
- * slightly larger than what is demanded by 'eps' below.
- */
- final BigDecimal xhighpr = BigDecimalMath.scalePrec(x, 2);
- final MathContext mc = SafeMathContext.newMathContext(2 + x.precision());
-
- /*
- * Relative accuracy of the result is eps.
- */
- final double eps = x.ulp().doubleValue() / (2 * n * x.doubleValue());
- for (;;) {
- /*
- * s = s -(s/n-x/n/s^(n-1)) = s-(s-x/s^(n-1))/n; test correction
- * s/n-x/s for being
- * smaller than the precision requested. The relative correction is
- * (1-x/s^n)/n,
- */
- BigDecimal c = xhighpr.divide(s.pow(n - 1), mc);
- c = s.subtract(c);
- final MathContext locmc = SafeMathContext.newMathContext(c.precision());
- c = c.divide(nth, locmc);
- s = s.subtract(c);
- if (Math.abs(c.doubleValue() / s.doubleValue()) < eps) {
- break;
- }
- }
- return s.round(SafeMathContext.newMathContext(BigDecimalMath.err2prec(eps)));
- } /* BigDecimalMath.root */
-
- /**
- * The hypotenuse.
- *
- * @param x
- * the first argument.
- * @param y
- * the second argument.
- * @return the square root of the sum of the squares of the two arguments,
- * sqrt(x^2+y^2).
- * @since 2009-06-25
- */
- static public BigDecimal hypot(final BigDecimal x, final BigDecimal y) {
- /*
- * compute x^2+y^2
- */
- BigDecimal z = x.pow(2).add(y.pow(2));
-
- /*
- * truncate to the precision set by x and y. Absolute error =
- * 2*x*xerr+2*y*yerr,
- * where the two errors are 1/2 of the ulp's. Two intermediate protectio
- * digits.
- */
- final BigDecimal zerr = x.abs().multiply(x.ulp()).add(y.abs().multiply(y.ulp()));
- MathContext mc = SafeMathContext.newMathContext(2 + BigDecimalMath.err2prec(z, zerr));
-
- /* Pull square root */
- z = BigDecimalMath.sqrt(z.round(mc));
-
- /*
- * Final rounding. Absolute error in the square root is
- * (y*yerr+x*xerr)/z, where zerr holds 2*(x*xerr+y*yerr).
- */
- mc = SafeMathContext.newMathContext(BigDecimalMath.err2prec(z.doubleValue(), 0.5 * zerr.doubleValue() / z.doubleValue()));
- return z.round(mc);
- } /* BigDecimalMath.hypot */
-
- /**
- * The hypotenuse.
- *
- * @param n
- * the first argument.
- * @param x
- * the second argument.
- * @return the square root of the sum of the squares of the two arguments,
- * sqrt(n^2+x^2).
- * @since 2009-08-05
- */
- static public BigDecimal hypot(final int n, final BigDecimal x) {
- /*
- * compute n^2+x^2 in infinite precision
- */
- BigDecimal z = new BigDecimal(n).pow(2).add(x.pow(2));
-
- /*
- * Truncate to the precision set by x. Absolute error = in z (square of
- * the result) is |2*x*xerr|,
- * where the error is 1/2 of the ulp. Two intermediate protection
- * digits.
- * zerr is a signed value, but used only in conjunction with err2prec(),
- * so this feature does not harm.
- */
- final double zerr = x.doubleValue() * x.ulp().doubleValue();
- MathContext mc = SafeMathContext.newMathContext(2 + BigDecimalMath.err2prec(z.doubleValue(), zerr));
-
- /* Pull square root */
- z = BigDecimalMath.sqrt(z.round(mc));
-
- /*
- * Final rounding. Absolute error in the square root is x*xerr/z, where
- * zerr holds 2*x*xerr.
- */
- mc = SafeMathContext.newMathContext(BigDecimalMath.err2prec(z.doubleValue(), 0.5 * zerr / z.doubleValue()));
- return z.round(mc);
- } /* BigDecimalMath.hypot */
-
- /**
- * A suggestion for the maximum numter of terms in the Taylor expansion of
- * the exponential.
- */
- static private int TAYLOR_NTERM = 8;
-
- /**
- * The exponential function.
- *
- * @param x
- * the argument.
- * @return exp(x).
- * The precision of the result is implicitly defined by the
- * precision in the argument.
- * In particular this means that "Invalid Operation" errors are
- * thrown if catastrophic
- * cancellation of digits causes the result to have no valid digits
- * left.
- * @since 2009-05-29
- * @author Richard J. Mathar
- */
- static public BigDecimal exp(final BigDecimal x) {
- /*
- * To calculate the value if x is negative, use exp(-x) = 1/exp(x)
- */
- if (x.compareTo(BigDecimal.ZERO) < 0) {
- final BigDecimal invx = BigDecimalMath.exp(x.negate());
- /*
- * Relative error in inverse of invx is the same as the relative
- * errror in invx.
- * This is used to define the precision of the result.
- */
- final MathContext mc = SafeMathContext.newMathContext(invx.precision());
- return BigDecimal.ONE.divide(invx, mc);
- } else if (x.compareTo(BigDecimal.ZERO) == 0) {
- /*
- * recover the valid number of digits from x.ulp(), if x hits the
- * zero. The x.precision() is 1 then, and does not provide this
- * information.
- */
- return BigDecimalMath.scalePrec(BigDecimal.ONE, -(int) Math.log10(x.ulp().doubleValue()));
- } else {
- /*
- * Push the number in the Taylor expansion down to a small
- * value where TAYLOR_NTERM terms will do. If x<1, the n-th term is
- * of the order
- * x^n/n!, and equal to both the absolute and relative error of the
- * result
- * since the result is close to 1. The x.ulp() sets the relative and
- * absolute error
- * of the result, as estimated from the first Taylor term.
- * We want x^TAYLOR_NTERM/TAYLOR_NTERM! < x.ulp, which is guaranteed
- * if
- * x^TAYLOR_NTERM < TAYLOR_NTERM*(TAYLOR_NTERM-1)*...*x.ulp.
- */
- final double xDbl = x.doubleValue();
- final double xUlpDbl = x.ulp().doubleValue();
- if (Math.pow(xDbl, BigDecimalMath.TAYLOR_NTERM) < BigDecimalMath.TAYLOR_NTERM * (BigDecimalMath.TAYLOR_NTERM - 1.0) * (BigDecimalMath.TAYLOR_NTERM - 2.0) * xUlpDbl) {
- /*
- * Add TAYLOR_NTERM terms of the Taylor expansion (Euler's sum
- * formula)
- */
- BigDecimal resul = BigDecimal.ONE;
-
- /* x^i */
- BigDecimal xpowi = BigDecimal.ONE;
-
- /* i factorial */
- BigInteger ifac = BigInteger.ONE;
-
- /*
- * TAYLOR_NTERM terms to be added means we move x.ulp() to the
- * right
- * for each power of 10 in TAYLOR_NTERM, so the addition won't
- * add noise beyond
- * what's already in x.
- */
- final MathContext mcTay = SafeMathContext.newMathContext(BigDecimalMath.err2prec(1., xUlpDbl / BigDecimalMath.TAYLOR_NTERM));
- for (int i = 1; i <= BigDecimalMath.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) {
- 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.
- */
- final MathContext mc = SafeMathContext.newMathContext(BigDecimalMath.err2prec(xUlpDbl / 2.));
- return resul.round(mc);
- } else {
- /*
- * Compute exp(x) = (exp(0.1*x))^10. Division by 10 does not
- * lead
- * to loss of accuracy.
- */
- int exSc = (int) (1.0 - Math.log10(BigDecimalMath.TAYLOR_NTERM * (BigDecimalMath.TAYLOR_NTERM - 1.0) * (BigDecimalMath.TAYLOR_NTERM - 2.0) * xUlpDbl / Math.pow(xDbl, BigDecimalMath.TAYLOR_NTERM)) / (BigDecimalMath.TAYLOR_NTERM - 1.0));
- final BigDecimal xby10 = x.scaleByPowerOfTen(-exSc);
- BigDecimal expxby10 = BigDecimalMath.exp(xby10);
-
- /*
- * Final powering by 10 means that the relative error of the
- * result
- * is 10 times the relative error of the base (First order
- * binomial expansion).
- * This looses one digit.
- */
- final MathContext mc = SafeMathContext.newMathContext(expxby10.precision() - exSc);
- /*
- * Rescaling the powers of 10 is done in chunks of a maximum of
- * 8 to avoid an invalid operation
- * response by the BigDecimal.pow library or integer overflow.
- */
- while (exSc > 0) {
- int exsub = Math.min(8, exSc);
- exSc -= exsub;
- final MathContext mctmp = SafeMathContext.newMathContext(expxby10.precision() - exsub + 2);
- int pex = 1;
- while (exsub-- > 0) {
- pex *= 10;
- }
- expxby10 = expxby10.pow(pex, mctmp);
- }
- return expxby10.round(mc);
- }
- }
- } /* BigDecimalMath.exp */
-
- /**
- * The base of the natural logarithm.
- *
- * @param mc
- * the required precision of the result
- * @return exp(1) = 2.71828....
- * @since 2009-05-29
- */
- static public BigDecimal exp(final MathContext mc) {
- /* look it up if possible */
- if (mc.getPrecision() < BigDecimalMath.E.precision()) {
- return BigDecimalMath.E.round(mc);
- } else {
- /*
- * Instantiate a 1.0 with the requested pseudo-accuracy
- * and delegate the computation to the public method above.
- */
- final BigDecimal uni = BigDecimalMath.scalePrec(BigDecimal.ONE, mc.getPrecision());
- return BigDecimalMath.exp(uni);
- }
- } /* BigDecimalMath.exp */
-
- /**
- * The natural logarithm.
- *
- * @param x
- * the argument.
- * @return ln(x).
- * The precision of the result is implicitly defined by the
- * precision in the argument.
- * @since 2009-05-29
- * @author Richard J. Mathar
- */
- static public BigDecimal log(final BigDecimal x) {
- /*
- * the value is undefined if x is negative.
- */
- if (x.compareTo(BigDecimal.ZERO) < 0) {
- throw new ArithmeticException("Cannot take log of negative " + x.toString());
- } else if (x.compareTo(BigDecimal.ONE) == 0) {
- /* log 1. = 0. */
- return BigDecimalMath.scalePrec(BigDecimal.ZERO, x.precision() - 1);
- } else if (Math.abs(x.doubleValue() - 1.0) <= 0.3) {
- /*
- * The standard Taylor series around x=1, z=0, z=x-1.
- * Abramowitz-Stegun 4.124.
- * The absolute error is err(z)/(1+z) = err(x)/x.
- */
- final BigDecimal z = BigDecimalMath.scalePrec(x.subtract(BigDecimal.ONE), 2);
- BigDecimal zpown = z;
- final double eps = 0.5 * x.ulp().doubleValue() / Math.abs(x.doubleValue());
- BigDecimal resul = z;
- for (int k = 2;; k++) {
- zpown = BigDecimalMath.multiplyRound(zpown, z);
- final BigDecimal c = BigDecimalMath.divideRound(zpown, k);
- if (k % 2 == 0) {
- resul = resul.subtract(c);
- } else {
- resul = resul.add(c);
- }
- if (Math.abs(c.doubleValue()) < eps) {
- break;
- }
- }
- final MathContext mc = SafeMathContext.newMathContext(BigDecimalMath.err2prec(resul.doubleValue(), eps));
- return resul.round(mc);
- } else {
- final double xDbl = x.doubleValue();
- final double xUlpDbl = x.ulp().doubleValue();
-
- /*
- * Map log(x) = log root[r](x)^r = r*log( root[r](x)) with the aim
- * to move roor[r](x) near to 1.2 (that is, below the 0.3 appearing
- * above), where log(1.2) is roughly 0.2.
- */
- int r = (int) (Math.log(xDbl) / 0.2);
-
- /*
- * Since the actual requirement is a function of the value 0.3
- * appearing above,
- * we avoid the hypothetical case of endless recurrence by ensuring
- * that r >= 2.
- */
- r = Math.max(2, r);
-
- /*
- * Compute r-th root with 2 additional digits of precision
- */
- final BigDecimal xhighpr = BigDecimalMath.scalePrec(x, 2);
- BigDecimal resul = BigDecimalMath.root(r, xhighpr);
- resul = BigDecimalMath.log(resul).multiply(new BigDecimal(r));
-
- /*
- * error propagation: log(x+errx) = log(x)+errx/x, so the absolute
- * error
- * in the result equals the relative error in the input,
- * xUlpDbl/xDbl .
- */
- final MathContext mc = SafeMathContext.newMathContext(BigDecimalMath.err2prec(resul.doubleValue(), xUlpDbl / xDbl));
- return resul.round(mc);
- }
- } /* BigDecimalMath.log */
-
- /**
- * The natural logarithm.
- *
- * @param n
- * The main argument, a strictly positive integer.
- * @param mc
- * The requirements on the precision.
- * @return ln(n).
- * @since 2009-08-08
- * @author Richard J. Mathar
- * @throws Error
- */
- static public BigDecimal log(final int n, final MathContext mc) throws Error {
- /*
- * the value is undefined if x is negative.
- */
- if (n <= 0) {
- throw new ArithmeticException("Cannot take log of negative " + n);
- } else if (n == 1) {
- return BigDecimal.ZERO;
- } else if (n == 2) {
- if (mc.getPrecision() < BigDecimalMath.LOG2.precision()) {
- return BigDecimalMath.LOG2.round(mc);
- } else {
- /*
- * Broadhurst arXiv:math/9803067
- * a>
- * Error propagation: the error in log(2) is twice the error in
- * S(2,-5,...).
- */
- final int[] a = { 2, -5, -2, -7, -2, -5, 2, -3 };
- BigDecimal S = BigDecimalMath.broadhurstBBP(2, 1, a, SafeMathContext.newMathContext(1 + mc.getPrecision()));
- S = S.multiply(new BigDecimal(8));
- S = BigDecimalMath.sqrt(BigDecimalMath.divideRound(S, 3));
- return S.round(mc);
- }
- } else if (n == 3) {
- /*
- * summation of a series roughly proportional to (7/500)^k. Estimate
- * count
- * of terms to estimate the precision (drop the favorable additional
- * 1/k here): 0.013^k <= 10^(-precision), so k*log10(0.013) <=
- * -precision
- * so k>= precision/1.87.
- */
- final int kmax = (int) (mc.getPrecision() / 1.87);
- MathContext mcloc = SafeMathContext.newMathContext(mc.getPrecision() + 1 + (int) Math.log10(kmax * 0.693 / 1.098));
- BigDecimal log3 = BigDecimalMath.multiplyRound(BigDecimalMath.log(2, mcloc), 19);
-
- /*
- * log3 is roughly 1, so absolute and relative error are the same.
- * The
- * result will be divided by 12, so a conservative error is the one
- * already found in mc
- */
- final double eps = BigDecimalMath.prec2err(1.098, mc.getPrecision()) / kmax;
- final Rational r = new Rational(7153, 524288);
- Rational pk = new Rational(7153, 524288);
- for (int k = 1;; k++) {
- final Rational tmp = pk.divide(k);
- if (tmp.doubleValue() < eps) {
- break;
- }
-
- /*
- * how many digits of tmp do we need in the sum?
- */
- mcloc = SafeMathContext.newMathContext(BigDecimalMath.err2prec(tmp.doubleValue(), eps));
- final BigDecimal c = pk.divide(k).BigDecimalValue(mcloc);
- if (k % 2 != 0) {
- log3 = log3.add(c);
- } else {
- log3 = log3.subtract(c);
- }
- pk = pk.multiply(r);
- }
- log3 = BigDecimalMath.divideRound(log3, 12);
- return log3.round(mc);
- } else if (n == 5) {
- /*
- * summation of a series roughly proportional to (7/160)^k. Estimate
- * count
- * of terms to estimate the precision (drop the favorable additional
- * 1/k here): 0.046^k <= 10^(-precision), so k*log10(0.046) <=
- * -precision
- * so k>= precision/1.33.
- */
- final int kmax = (int) (mc.getPrecision() / 1.33);
- MathContext mcloc = SafeMathContext.newMathContext(mc.getPrecision() + 1 + (int) Math.log10(kmax * 0.693 / 1.609));
- BigDecimal log5 = BigDecimalMath.multiplyRound(BigDecimalMath.log(2, mcloc), 14);
-
- /*
- * log5 is roughly 1.6, so absolute and relative error are the same.
- * The
- * result will be divided by 6, so a conservative error is the one
- * already found in mc
- */
- final double eps = BigDecimalMath.prec2err(1.6, mc.getPrecision()) / kmax;
- final Rational r = new Rational(759, 16384);
- Rational pk = new Rational(759, 16384);
- for (int k = 1;; k++) {
- final Rational tmp = pk.divide(k);
- if (tmp.doubleValue() < eps) {
- break;
- }
-
- /*
- * how many digits of tmp do we need in the sum?
- */
- mcloc = SafeMathContext.newMathContext(BigDecimalMath.err2prec(tmp.doubleValue(), eps));
- final BigDecimal c = pk.divide(k).BigDecimalValue(mcloc);
- log5 = log5.subtract(c);
- pk = pk.multiply(r);
- }
- log5 = BigDecimalMath.divideRound(log5, 6);
- return log5.round(mc);
- } else if (n == 7) {
- /*
- * summation of a series roughly proportional to (1/8)^k. Estimate
- * count
- * of terms to estimate the precision (drop the favorable additional
- * 1/k here): 0.125^k <= 10^(-precision), so k*log10(0.125) <=
- * -precision
- * so k>= precision/0.903.
- */
- final int kmax = (int) (mc.getPrecision() / 0.903);
- MathContext mcloc = SafeMathContext.newMathContext(mc.getPrecision() + 1 + (int) Math.log10(kmax * 3 * 0.693 / 1.098));
- BigDecimal log7 = BigDecimalMath.multiplyRound(BigDecimalMath.log(2, mcloc), 3);
-
- /*
- * log7 is roughly 1.9, so absolute and relative error are the same.
- */
- final double eps = BigDecimalMath.prec2err(1.9, mc.getPrecision()) / kmax;
- final Rational r = new Rational(1, 8);
- Rational pk = new Rational(1, 8);
- for (int k = 1;; k++) {
- final Rational tmp = pk.divide(k);
- if (tmp.doubleValue() < eps) {
- break;
- }
-
- /*
- * how many digits of tmp do we need in the sum?
- */
- mcloc = SafeMathContext.newMathContext(BigDecimalMath.err2prec(tmp.doubleValue(), eps));
- final BigDecimal c = pk.divide(k).BigDecimalValue(mcloc);
- log7 = log7.subtract(c);
- pk = pk.multiply(r);
- }
- return log7.round(mc);
-
- }
-
- else {
- /*
- * At this point one could either forward to the log(BigDecimal)
- * signature (implemented)
- * or decompose n into Ifactors and use an implemenation of all the
- * prime bases.
- * Estimate of the result; convert the mc argument to an absolute
- * error eps
- * log(n+errn) = log(n)+errn/n = log(n)+eps
- */
- final double res = Math.log(n);
- double eps = BigDecimalMath.prec2err(res, mc.getPrecision());
- /*
- * errn = eps*n, convert absolute error in result to requirement on
- * absolute error in input
- */
- eps *= n;
- /*
- * Convert this absolute requirement of error in n to a relative
- * error in n
- */
- final MathContext mcloc = SafeMathContext.newMathContext(1 + BigDecimalMath.err2prec(n, eps));
- /*
- * Padd n with a number of zeros to trigger the required accuracy in
- * the standard signature method
- */
- final BigDecimal nb = BigDecimalMath.scalePrec(new BigDecimal(n), mcloc);
- return BigDecimalMath.log(nb);
- }
- } /* log */
-
- /**
- * The natural logarithm.
- *
- * @param r
- * The main argument, a strictly positive value.
- * @param mc
- * The requirements on the precision.
- * @return ln(r).
- * @since 2009-08-09
- * @author Richard J. Mathar
- */
- static public BigDecimal log(final Rational r, final MathContext mc) {
- /*
- * the value is undefined if x is negative.
- */
- if (r.compareTo(Rational.ZERO) <= 0) {
- throw new ArithmeticException("Cannot take log of negative " + r.toString());
- } else if (r.compareTo(Rational.ONE) == 0) {
- return BigDecimal.ZERO;
- } 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.
- */
- final double eps = BigDecimalMath.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.
- */
- final MathContext mcloc = SafeMathContext.newMathContext(1 + BigDecimalMath.err2prec(eps));
-
- final BigDecimal resul = BigDecimalMath.log(r.BigDecimalValue(mcloc));
-
- return resul.round(mc);
- }
- } /* log */
-
- /**
- * Power function.
- *
- * @param x
- * Base of the power.
- * @param y
- * Exponent of the power.
- * @return x^y.
- * The estimation of the relative error in the result is
- * |log(x)*err(y)|+|y*err(x)/x|
- * @since 2009-06-01
- */
- static public BigDecimal pow(final BigDecimal x, final BigDecimal y) {
- if (x.compareTo(BigDecimal.ZERO) < 0) {
- throw new ArithmeticException("Cannot power negative " + x.toString());
- } else if (x.compareTo(BigDecimal.ZERO) == 0) {
- return BigDecimal.ZERO;
- } else {
- /*
- * return x^y = exp(y*log(x)) ;
- */
- final BigDecimal logx = BigDecimalMath.log(x);
- final BigDecimal ylogx = y.multiply(logx);
- final BigDecimal resul = BigDecimalMath.exp(ylogx);
-
- /*
- * The estimation of the relative error in the result is
- * |log(x)*err(y)|+|y*err(x)/x|
- */
- final double errR = Math.abs(logx.doubleValue() * y.ulp().doubleValue() / 2.) + Math.abs(y.doubleValue() * x.ulp().doubleValue() / 2. / x.doubleValue());
- final MathContext mcR = SafeMathContext.newMathContext(BigDecimalMath.err2prec(1.0, errR));
- return resul.round(mcR);
- }
- } /* BigDecimalMath.pow */
-
- /**
- * Raise to an integer power and round.
- *
- * @param x
- * The base.
- * @param n
- * The exponent.
- * @return x^n.
- * @since 2009-08-13
- * @since 2010-05-26 handle also n<0 cases.
- */
- static public BigDecimal powRound(final BigDecimal x, final int n) {
- /**
- * Special cases: x^1=x and x^0 = 1
- */
- if (n == 1) {
- return x;
- } else if (n == 0) {
- return BigDecimal.ONE;
- } else {
- /*
- * The relative error in the result is n times the relative error in
- * the input.
- * The estimation is slightly optimistic due to the integer rounding
- * of the logarithm.
- * Since the standard BigDecimal.pow can only handle positive n, we
- * split the algorithm.
- */
- final MathContext mc = SafeMathContext.newMathContext(x.precision() - (int) Math.log10(Math.abs(n)));
- if (n > 0) {
- return x.pow(n, mc);
- } else {
- return BigDecimal.ONE.divide(x.pow(-n), mc);
- }
- }
- } /* BigDecimalMath.powRound */
-
- /**
- * Raise to an integer power and round.
- *
- * @param x
- * The base.
- * @param n
- * The exponent.
- * The current implementation allows n only in the interval of
- * the standard int values.
- * @return x^n.
- * @since 2010-05-26
- */
- static public BigDecimal powRound(final BigDecimal x, final BigInteger n) {
- /**
- * For now, the implementation forwards to the cases where n
- * is in the range of the standard integers. This might, however, be
- * implemented to decompose larger powers into cascaded calls to smaller
- * ones.
- */
- if (n.compareTo(Rational.MAX_INT) > 0 || n.compareTo(Rational.MIN_INT) < 0) {
- throw new ProviderException("Not implemented: big power " + n.toString());
- } else {
- return BigDecimalMath.powRound(x, n.intValue());
- }
- } /* BigDecimalMath.powRound */
-
- /**
- * Raise to a fractional power and round.
- *
- * @param x
- * The base.
- * Generally enforced to be positive, with the exception of
- * integer exponents where
- * the sign is carried over according to the parity of the
- * exponent.
- * @param q
- * The exponent.
- * @return x^q.
- * @since 2010-05-26
- */
- static public BigDecimal powRound(final BigDecimal x, final Rational q) {
- /**
- * Special cases: x^1=x and x^0 = 1
- */
- if (q.compareTo(BigInteger.ONE) == 0) {
- return x;
- } else if (q.signum() == 0) {
- return BigDecimal.ONE;
- } else if (q.isInteger()) {
- /*
- * We are sure that the denominator is positive here, because
- * normalize() has been
- * called during constrution etc.
- */
- return BigDecimalMath.powRound(x, q.a);
- } else if (x.compareTo(BigDecimal.ZERO) < 0) {
- throw new ArithmeticException("Cannot power negative " + x.toString());
- } else if (q.isIntegerFrac()) {
- /*
- * Newton method with first estimate in double precision.
- * The disadvantage of this first line here is that the result
- * must fit in the
- * standard range of double precision numbers exponents.
- */
- final double estim = Math.pow(x.doubleValue(), q.doubleValue());
- BigDecimal res = new BigDecimal(estim);
-
- /*
- * The error in x^q is q*x^(q-1)*Delta(x).
- * The relative error is q*Delta(x)/x, q times the relative
- * error of x.
- */
- 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.
- */
- final int qa = q.a.intValue();
- final int qb = q.b.intValue();
-
- /* Newton iterations. */
- final BigDecimal xpowa = BigDecimalMath.powRound(x, qa);
- for (;;) {
- /*
- * numerator and denominator of the Newton term. The major
- * disadvantage of this implementation is that the updates
- * of the powers
- * of the new estimate are done in full precision calling
- * BigDecimal.pow(),
- * which becomes slow if the denominator of q is large.
- */
- final BigDecimal nu = res.pow(qb).subtract(xpowa);
- final BigDecimal de = BigDecimalMath.multiplyRound(res.pow(qb - 1), q.b);
-
- /* estimated correction */
- BigDecimal eps = nu.divide(de, MathContext.DECIMAL64);
-
- final BigDecimal err = res.multiply(reserr, MathContext.DECIMAL64);
- final int precDiv = 2 + BigDecimalMath.err2prec(eps, err);
- if (precDiv <= 0) {
- /*
- * The case when the precision is already reached and
- * any precision
- * will do.
- */
- eps = nu.divide(de, MathContext.DECIMAL32);
- } else {
- final MathContext mc = SafeMathContext.newMathContext(precDiv);
- eps = nu.divide(de, mc);
- }
-
- res = BigDecimalMath.subtractRound(res, eps);
- /*
- * reached final precision if the relative error fell below
- * reserr,
- * |eps/res| < reserr
- */
- if (eps.divide(res, MathContext.DECIMAL64).abs().compareTo(reserr) < 0) {
- /*
- * delete the bits of extra precision kept in this
- * working copy.
- */
- final MathContext mc = SafeMathContext.newMathContext(BigDecimalMath.err2prec(reserr.doubleValue()));
- return res.round(mc);
- }
- }
- } else {
- /*
- * The error in x^q is q*x^(q-1)*Delta(x) + Delta(q)*x^q*log(x).
- * The relative error is q/x*Delta(x) + Delta(q)*log(x). Convert
- * q to a floating point
- * number such that its relative error becomes negligible:
- * Delta(q)/q << Delta(x)/x/log(x) .
- */
- final int precq = 3 + BigDecimalMath.err2prec(x.ulp().divide(x, MathContext.DECIMAL64).doubleValue() / Math.log(x.doubleValue()));
- final MathContext mc = SafeMathContext.newMathContext(precq);
-
- /*
- * Perform the actual calculation as exponentiation of two
- * floating point numbers.
- */
- return BigDecimalMath.pow(x, q.BigDecimalValue(mc));
- }
- } /* BigDecimalMath.powRound */
-
- /**
- * Trigonometric sine.
- *
- * @param x
- * The argument in radians.
- * @return sin(x) in the range -1 to 1.
- * @throws Error
- * @since 2009-06-01
- */
- static public BigDecimal sin(final BigDecimal x) throws Error {
- if (x.compareTo(BigDecimal.ZERO) < 0) {
- return BigDecimalMath.sin(x.negate()).negate();
- } else if (x.compareTo(BigDecimal.ZERO) == 0) {
- return BigDecimal.ZERO;
- } else {
- /*
- * reduce modulo 2pi
- */
- final BigDecimal res = BigDecimalMath.mod2pi(x);
- final double errpi = 0.5 * Math.abs(x.ulp().doubleValue());
- MathContext mc = SafeMathContext.newMathContext(2 + BigDecimalMath.err2prec(3.14159, errpi));
- final BigDecimal p = BigDecimalMath.pi(mc);
- mc = SafeMathContext.newMathContext(x.precision());
- if (res.compareTo(p) > 0) {
- /*
- * pi 0) {
- /*
- * pi/2 0) {
- /*
- * x>pi/4: sin(x) = cos(pi/2-x)
- */
- return BigDecimalMath.cos(BigDecimalMath.subtractRound(p.divide(new BigDecimal("2")), res));
- } else {
- /*
- * Simple Taylor expansion, sum_{i=1..infinity}
- * (-1)^(..)res^(2i+1)/(2i+1)!
- */
- BigDecimal resul = res;
-
- /* x^i */
- BigDecimal xpowi = res;
-
- /* 2i+1 factorial */
- BigInteger ifac = BigInteger.ONE;
-
- /*
- * The error in the result is set by the error in x itself.
- */
- final double xUlpDbl = res.ulp().doubleValue();
-
- /*
- * The error in the result is set by the error in x itself.
- * We need at most k terms to squeeze x^(2k+1)/(2k+1)! below
- * this value.
- * x^(2k+1) < x.ulp; (2k+1)*log10(x) < -x.precision;
- * 2k*log10(x)< -x.precision;
- * 2k*(-log10(x)) > x.precision; 2k*log10(1/x) > x.precision
- */
- final int k = (int) (res.precision() / Math.log10(1.0 / res.doubleValue())) / 2;
- final MathContext mcTay = SafeMathContext.newMathContext(BigDecimalMath.err2prec(res.doubleValue(), xUlpDbl / k));
- for (int i = 1;; i++) {
- /*
- * TBD: at which precision will 2*i or 2*i+1 overflow?
- */
- ifac = ifac.multiply(new BigInteger("" + 2 * i));
- ifac = ifac.multiply(new BigInteger("" + (2 * i + 1)));
- xpowi = xpowi.multiply(res).multiply(res).negate();
- final BigDecimal corr = xpowi.divide(new BigDecimal(ifac), mcTay);
- resul = resul.add(corr);
- if (corr.abs().doubleValue() < 0.5 * xUlpDbl) {
- break;
- }
- }
- /*
- * The error in the result is set by the error in x itself.
- */
- mc = SafeMathContext.newMathContext(res.precision());
- return resul.round(mc);
- }
- }
- } /* sin */
-
- /**
- * Trigonometric cosine.
- *
- * @param x
- * The argument in radians.
- * @return cos(x) in the range -1 to 1.
- * @throws Error
- * @since 2009-06-01
- */
- static public BigDecimal cos(final BigDecimal x) throws Error {
- if (x.compareTo(BigDecimal.ZERO) < 0) {
- return BigDecimalMath.cos(x.negate());
- } else if (x.compareTo(BigDecimal.ZERO) == 0) {
- return BigDecimal.ONE;
- } else {
- /*
- * reduce modulo 2pi
- */
- final BigDecimal res = BigDecimalMath.mod2pi(x);
- final double errpi = 0.5 * Math.abs(x.ulp().doubleValue());
- MathContext mc = SafeMathContext.newMathContext(2 + BigDecimalMath.err2prec(3.14159, errpi));
- final BigDecimal p = BigDecimalMath.pi(mc);
- mc = SafeMathContext.newMathContext(x.precision());
- if (res.compareTo(p) > 0) {
- /*
- * pi 0) {
- /*
- * pi/2 0) {
- /*
- * x>pi/4: cos(x) = sin(pi/2-x)
- */
- return BigDecimalMath.sin(BigDecimalMath.subtractRound(p.divide(new BigDecimal("2")), res));
- } else {
- /*
- * Simple Taylor expansion, sum_{i=0..infinity}
- * (-1)^(..)res^(2i)/(2i)!
- */
- BigDecimal resul = BigDecimal.ONE;
-
- /* x^i */
- BigDecimal xpowi = BigDecimal.ONE;
-
- /* 2i factorial */
- BigInteger ifac = BigInteger.ONE;
-
- /*
- * The absolute error in the result is the error in x^2/2
- * which is x times the error in x.
- */
- final double xUlpDbl = 0.5 * res.ulp().doubleValue() * res.doubleValue();
-
- /*
- * The error in the result is set by the error in x^2/2
- * itself, xUlpDbl.
- * We need at most k terms to push x^(2k+1)/(2k+1)! below
- * this value.
- * x^(2k) < xUlpDbl; (2k)*log(x) < log(xUlpDbl);
- */
- final int k = (int) (Math.log(xUlpDbl) / Math.log(res.doubleValue())) / 2;
- final MathContext mcTay = SafeMathContext.newMathContext(BigDecimalMath.err2prec(1., xUlpDbl / k));
- for (int i = 1;; i++) {
- /*
- * TBD: at which precision will 2*i-1 or 2*i overflow?
- */
- ifac = ifac.multiply(new BigInteger("" + (2 * i - 1)));
- ifac = ifac.multiply(new BigInteger("" + 2 * i));
- xpowi = xpowi.multiply(res).multiply(res).negate();
- final BigDecimal corr = xpowi.divide(new BigDecimal(ifac), mcTay);
- resul = resul.add(corr);
- if (corr.abs().doubleValue() < 0.5 * xUlpDbl) {
- break;
- }
- }
- /*
- * The error in the result is governed by the error in x
- * itself.
- */
- mc = SafeMathContext.newMathContext(BigDecimalMath.err2prec(resul.doubleValue(), xUlpDbl));
- return resul.round(mc);
- }
- }
- } /* BigDecimalMath.cos */
-
- /**
- * The trigonometric tangent.
- *
- * @param x
- * the argument in radians.
- * @return the tan(x)
- * @throws Error
- */
- static public BigDecimal tan(final BigDecimal x) throws Error {
- if (x.compareTo(BigDecimal.ZERO) == 0) {
- return BigDecimal.ZERO;
- } else if (x.compareTo(BigDecimal.ZERO) < 0) {
- return BigDecimalMath.tan(x.negate()).negate();
- } else {
- /*
- * reduce modulo pi
- */
- final BigDecimal res = BigDecimalMath.modpi(x);
-
- /*
- * absolute error in the result is err(x)/cos^2(x) to lowest order
- */
- final double xDbl = res.doubleValue();
- final double xUlpDbl = x.ulp().doubleValue() / 2.;
- final double eps = xUlpDbl / 2. / Math.pow(Math.cos(xDbl), 2.);
-
- if (xDbl > 0.8) {
- /* tan(x) = 1/cot(x) */
- final BigDecimal co = BigDecimalMath.cot(x);
- final MathContext mc = SafeMathContext.newMathContext(BigDecimalMath.err2prec(1. / co.doubleValue(), eps));
- return BigDecimal.ONE.divide(co, mc);
- } else {
- final BigDecimal xhighpr = BigDecimalMath.scalePrec(res, 2);
- final BigDecimal xhighprSq = BigDecimalMath.multiplyRound(xhighpr, xhighpr);
-
- BigDecimal resul = xhighpr.plus();
-
- /* x^(2i+1) */
- BigDecimal xpowi = xhighpr;
-
- final Bernoulli b = new Bernoulli();
-
- /* 2^(2i) */
- BigInteger fourn = new BigInteger("4");
- /* (2i)! */
- BigInteger fac = new BigInteger("2");
-
- for (int i = 2;; i++) {
- Rational f = b.at(2 * i).abs();
- fourn = fourn.shiftLeft(2);
- 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 = BigDecimalMath.multiplyRound(xpowi, xhighprSq);
- final BigDecimal c = BigDecimalMath.multiplyRound(xpowi, f);
- resul = resul.add(c);
- if (Math.abs(c.doubleValue()) < 0.1 * eps) {
- break;
- }
- }
- final MathContext mc = SafeMathContext.newMathContext(BigDecimalMath.err2prec(resul.doubleValue(), eps));
- return resul.round(mc);
- }
- }
- } /* BigDecimalMath.tan */
-
- /**
- * The trigonometric co-tangent.
- *
- * @param x
- * the argument in radians.
- * @return the cot(x)
- * @throws Error
- * @since 2009-07-31
- */
- static public BigDecimal cot(final BigDecimal x) throws Error {
- if (x.compareTo(BigDecimal.ZERO) == 0) {
- throw new ArithmeticException("Cannot take cot of zero " + x.toString());
- } else if (x.compareTo(BigDecimal.ZERO) < 0) {
- return BigDecimalMath.cot(x.negate()).negate();
- } else {
- /*
- * reduce modulo pi
- */
- final BigDecimal res = BigDecimalMath.modpi(x);
-
- /*
- * absolute error in the result is err(x)/sin^2(x) to lowest order
- */
- final double xDbl = res.doubleValue();
- final double xUlpDbl = x.ulp().doubleValue() / 2.;
- final double eps = xUlpDbl / 2. / Math.pow(Math.sin(xDbl), 2.);
-
- final BigDecimal xhighpr = BigDecimalMath.scalePrec(res, 2);
- final BigDecimal xhighprSq = BigDecimalMath.multiplyRound(xhighpr, xhighpr);
-
- MathContext mc = SafeMathContext.newMathContext(BigDecimalMath.err2prec(xhighpr.doubleValue(), eps));
- BigDecimal resul = BigDecimal.ONE.divide(xhighpr, mc);
-
- /* x^(2i-1) */
- BigDecimal xpowi = xhighpr;
-
- final Bernoulli b = new Bernoulli();
-
- /* 2^(2i) */
- BigInteger fourn = new BigInteger("4");
- /* (2i)! */
- BigInteger fac = BigInteger.ONE;
-
- for (int i = 1;; i++) {
- 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);
- final BigDecimal c = BigDecimalMath.multiplyRound(xpowi, f);
- if (i % 2 == 0) {
- resul = resul.add(c);
- } else {
- resul = resul.subtract(c);
- }
- if (Math.abs(c.doubleValue()) < 0.1 * eps) {
- break;
- }
-
- fourn = fourn.shiftLeft(2);
- xpowi = BigDecimalMath.multiplyRound(xpowi, xhighprSq);
- }
- mc = SafeMathContext.newMathContext(BigDecimalMath.err2prec(resul.doubleValue(), eps));
- return resul.round(mc);
- }
- } /* BigDecimalMath.cot */
-
- /**
- * The inverse trigonometric sine.
- *
- * @param x
- * the argument.
- * @return the arcsin(x) in radians.
- * @throws Error
- */
- 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) {
- return BigDecimal.ZERO;
- } else if (x.compareTo(BigDecimal.ONE) == 0) {
- /*
- * arcsin(1) = pi/2
- */
- final double errpi = Math.sqrt(x.ulp().doubleValue());
- final MathContext mc = SafeMathContext.newMathContext(BigDecimalMath.err2prec(3.14159, errpi));
- return BigDecimalMath.pi(mc).divide(new BigDecimal(2));
- } else if (x.compareTo(BigDecimal.ZERO) < 0) {
- return BigDecimalMath.asin(x.negate()).negate();
- } else if (x.doubleValue() > 0.7) {
- final BigDecimal xCompl = BigDecimal.ONE.subtract(x);
- final double xDbl = x.doubleValue();
- final double xUlpDbl = x.ulp().doubleValue() / 2.;
- final double eps = xUlpDbl / 2. / Math.sqrt(1. - Math.pow(xDbl, 2.));
-
- final BigDecimal xhighpr = BigDecimalMath.scalePrec(xCompl, 3);
- final BigDecimal xhighprV = BigDecimalMath.divideRound(xhighpr, 4);
-
- BigDecimal resul = BigDecimal.ONE;
-
- /* x^(2i+1) */
- BigDecimal xpowi = BigDecimal.ONE;
-
- /* i factorial */
- BigInteger ifacN = BigInteger.ONE;
- BigInteger ifacD = BigInteger.ONE;
-
- for (int i = 1;; i++) {
- ifacN = ifacN.multiply(new BigInteger("" + (2 * i - 1)));
- ifacD = ifacD.multiply(new BigInteger("" + i));
- if (i == 1) {
- xpowi = xhighprV;
- } else {
- xpowi = BigDecimalMath.multiplyRound(xpowi, xhighprV);
- }
- final BigDecimal c = BigDecimalMath.divideRound(BigDecimalMath.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.) {
- break;
- }
- }
- /*
- * sqrt(2*z)*(1+...)
- */
- xpowi = BigDecimalMath.sqrt(xhighpr.multiply(new BigDecimal(2)));
- resul = BigDecimalMath.multiplyRound(xpowi, resul);
-
- MathContext mc = SafeMathContext.newMathContext(resul.precision());
- final BigDecimal pihalf = BigDecimalMath.pi(mc).divide(new BigDecimal(2));
-
- mc = SafeMathContext.newMathContext(BigDecimalMath.err2prec(resul.doubleValue(), eps));
- return pihalf.subtract(resul, mc);
- } else {
- /*
- * absolute error in the result is err(x)/sqrt(1-x^2) to lowest
- * order
- */
- final double xDbl = x.doubleValue();
- final double xUlpDbl = x.ulp().doubleValue() / 2.;
- final double eps = xUlpDbl / 2. / Math.sqrt(1. - Math.pow(xDbl, 2.));
-
- final BigDecimal xhighpr = BigDecimalMath.scalePrec(x, 2);
- final BigDecimal xhighprSq = BigDecimalMath.multiplyRound(xhighpr, xhighpr);
-
- BigDecimal resul = xhighpr.plus();
-
- /* x^(2i+1) */
- BigDecimal xpowi = xhighpr;
-
- /* i factorial */
- BigInteger ifacN = BigInteger.ONE;
- BigInteger ifacD = BigInteger.ONE;
-
- for (int i = 1;; i++) {
- ifacN = ifacN.multiply(new BigInteger("" + (2 * i - 1)));
- ifacD = ifacD.multiply(new BigInteger("" + 2 * i));
- xpowi = BigDecimalMath.multiplyRound(xpowi, xhighprSq);
- final BigDecimal c = BigDecimalMath.divideRound(BigDecimalMath.multiplyRound(xpowi, ifacN), ifacD.multiply(new BigInteger("" + (2 * i + 1))));
- resul = resul.add(c);
- if (Math.abs(c.doubleValue()) < 0.1 * eps) {
- break;
- }
- }
- final MathContext mc = SafeMathContext.newMathContext(BigDecimalMath.err2prec(resul.doubleValue(), eps));
- return resul.round(mc);
- }
- } /* BigDecimalMath.asin */
-
- /**
- * The inverse trigonometric cosine.
- *
- * @param x
- * the argument.
- * @return the arccos(x) in radians.
- * @throws Error
- * @since 2009-09-29
- */
- static public BigDecimal acos(final BigDecimal x) throws Error {
- /*
- * Essentially forwarded to pi/2 - asin(x)
- */
- final BigDecimal xhighpr = BigDecimalMath.scalePrec(x, 2);
- BigDecimal resul = BigDecimalMath.asin(xhighpr);
- double eps = resul.ulp().doubleValue() / 2.;
-
- MathContext mc = SafeMathContext.newMathContext(BigDecimalMath.err2prec(3.14159, eps));
- final BigDecimal pihalf = BigDecimalMath.pi(mc).divide(new BigDecimal(2));
- resul = pihalf.subtract(resul);
-
- /*
- * absolute error in the result is err(x)/sqrt(1-x^2) to lowest order
- */
- final double xDbl = x.doubleValue();
- final double xUlpDbl = x.ulp().doubleValue() / 2.;
- eps = xUlpDbl / 2. / Math.sqrt(1. - Math.pow(xDbl, 2.));
-
- mc = SafeMathContext.newMathContext(BigDecimalMath.err2prec(resul.doubleValue(), eps));
- return resul.round(mc);
-
- } /* BigDecimalMath.acos */
-
- /**
- * The inverse trigonometric tangent.
- *
- * @param x
- * the argument.
- * @return the principal value of arctan(x) in radians in the range -pi/2 to
- * +pi/2.
- * @throws Error
- * @since 2009-08-03
- */
- static public BigDecimal atan(final BigDecimal x) throws Error {
- if (x.compareTo(BigDecimal.ZERO) < 0) {
- return BigDecimalMath.atan(x.negate()).negate();
- } else if (x.compareTo(BigDecimal.ZERO) == 0) {
- return BigDecimal.ZERO;
- } 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.
- */
- final BigDecimal y = BigDecimalMath.scalePrec(x, 2);
- final BigDecimal newx = BigDecimalMath.divideRound(BigDecimalMath.hypot(1, y).subtract(BigDecimal.ONE), y);
-
- /* intermediate result with too optimistic error estimate */
- final BigDecimal resul = BigDecimalMath.multiplyRound(BigDecimalMath.atan(newx), 2);
-
- /*
- * absolute error in the result is errx/(1+x^2), where errx = half
- * of the ulp.
- */
- final double eps = x.ulp().doubleValue() / (2.0 * Math.hypot(1.0, x.doubleValue()));
- final MathContext mc = SafeMathContext.newMathContext(BigDecimalMath.err2prec(resul.doubleValue(), eps));
- return resul.round(mc);
- } else if (x.doubleValue() < 0.71) {
- /* Taylor expansion around x=0; Abramowitz-Stegun 4.4.42 */
-
- final BigDecimal xhighpr = BigDecimalMath.scalePrec(x, 2);
- final BigDecimal xhighprSq = BigDecimalMath.multiplyRound(xhighpr, xhighpr).negate();
-
- BigDecimal resul = xhighpr.plus();
-
- /* signed x^(2i+1) */
- BigDecimal xpowi = xhighpr;
-
- /*
- * absolute error in the result is errx/(1+x^2), where errx = half
- * of the ulp.
- */
- final double eps = x.ulp().doubleValue() / (2.0 * Math.hypot(1.0, x.doubleValue()));
-
- for (int i = 1;; i++) {
- xpowi = BigDecimalMath.multiplyRound(xpowi, xhighprSq);
- final BigDecimal c = BigDecimalMath.divideRound(xpowi, 2 * i + 1);
-
- resul = resul.add(c);
- if (Math.abs(c.doubleValue()) < 0.1 * eps) {
- break;
- }
- }
- final MathContext mc = SafeMathContext.newMathContext(BigDecimalMath.err2prec(resul.doubleValue(), eps));
- return resul.round(mc);
- } else {
- /* Taylor expansion around x=infinity; Abramowitz-Stegun 4.4.42 */
-
- /*
- * absolute error in the result is errx/(1+x^2), where errx = half
- * of the ulp.
- */
- 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 = SafeMathContext.newMathContext(2 + BigDecimalMath.err2prec(3.1416, eps));
- final BigDecimal onepi = BigDecimalMath.pi(mc);
- BigDecimal resul = onepi.divide(new BigDecimal(2));
-
- final BigDecimal xhighpr = BigDecimalMath.divideRound(-1, BigDecimalMath.scalePrec(x, 2));
- final BigDecimal xhighprSq = BigDecimalMath.multiplyRound(xhighpr, xhighpr).negate();
-
- /* signed x^(2i+1) */
- BigDecimal xpowi = xhighpr;
-
- for (int i = 0;; i++) {
- final BigDecimal c = BigDecimalMath.divideRound(xpowi, 2 * i + 1);
-
- resul = resul.add(c);
- if (Math.abs(c.doubleValue()) < 0.1 * eps) {
- break;
- }
- xpowi = BigDecimalMath.multiplyRound(xpowi, xhighprSq);
- }
- mc = SafeMathContext.newMathContext(BigDecimalMath.err2prec(resul.doubleValue(), eps));
- return resul.round(mc);
- }
- } /* BigDecimalMath.atan */
-
- /**
- * The hyperbolic cosine.
- *
- * @param x
- * The argument.
- * @return The cosh(x) = (exp(x)+exp(-x))/2 .
- * @author Richard J. Mathar
- * @throws Error
- * @since 2009-08-19
- */
- static public BigDecimal cosh(final BigDecimal x) throws Error {
- if (x.compareTo(BigDecimal.ZERO) < 0) {
- return BigDecimalMath.cos(x.negate());
- } else if (x.compareTo(BigDecimal.ZERO) == 0) {
- return BigDecimal.ONE;
- } else if (x.doubleValue() > 1.5) {
- /*
- * cosh^2(x) = 1+ sinh^2(x).
- */
- return BigDecimalMath.hypot(1, BigDecimalMath.sinh(x));
- } else {
- final BigDecimal xhighpr = BigDecimalMath.scalePrec(x, 2);
- /* Simple Taylor expansion, sum_{0=1..infinity} x^(2i)/(2i)! */
- BigDecimal resul = BigDecimal.ONE;
-
- /* x^i */
- BigDecimal xpowi = BigDecimal.ONE;
-
- /* 2i factorial */
- BigInteger ifac = BigInteger.ONE;
-
- /*
- * The absolute error in the result is the error in x^2/2 which
- * is x times the error in x.
- */
- 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,
- * xUlpDbl.
- * We need at most k terms to push x^(2k)/(2k)! below this
- * value.
- * x^(2k) < xUlpDbl; (2k)*log(x) < log(xUlpDbl);
- */
- final int k = (int) (Math.log(xUlpDbl) / Math.log(x.doubleValue())) / 2;
-
- /*
- * The individual terms are all smaller than 1, so an estimate
- * of 1.0 for
- * the absolute value will give a safe relative error estimate
- * for the indivdual terms
- */
- final MathContext mcTay = SafeMathContext.newMathContext(BigDecimalMath.err2prec(1., xUlpDbl / k));
- for (int i = 1;; i++) {
- /*
- * TBD: at which precision will 2*i-1 or 2*i overflow?
- */
- ifac = ifac.multiply(new BigInteger("" + (2 * i - 1)));
- ifac = ifac.multiply(new BigInteger("" + 2 * i));
- xpowi = xpowi.multiply(xhighpr).multiply(xhighpr);
- final BigDecimal corr = xpowi.divide(new BigDecimal(ifac), mcTay);
- resul = resul.add(corr);
- if (corr.abs().doubleValue() < 0.5 * xUlpDbl) {
- break;
- }
- }
- /*
- * The error in the result is governed by the error in x itself.
- */
- final MathContext mc = SafeMathContext.newMathContext(BigDecimalMath.err2prec(resul.doubleValue(), xUlpDbl));
- return resul.round(mc);
- }
- } /* BigDecimalMath.cosh */
-
- /**
- * The hyperbolic sine.
- *
- * @param x
- * the argument.
- * @return the sinh(x) = (exp(x)-exp(-x))/2 .
- * @author Richard J. Mathar
- * @throws Error
- * @since 2009-08-19
- */
- static public BigDecimal sinh(final BigDecimal x) throws Error {
- if (x.compareTo(BigDecimal.ZERO) < 0) {
- return BigDecimalMath.sinh(x.negate()).negate();
- } else if (x.compareTo(BigDecimal.ZERO) == 0) {
- return BigDecimal.ZERO;
- } else if (x.doubleValue() > 2.4) {
- /*
- * Move closer to zero with sinh(2x)= 2*sinh(x)*cosh(x).
- */
- final BigDecimal two = new BigDecimal(2);
- final BigDecimal xhalf = x.divide(two);
- final BigDecimal resul = BigDecimalMath.sinh(xhalf).multiply(BigDecimalMath.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
- * error
- * in the result is cosh(x)*errx, and the relative error is
- * coth(x)*errx = errx/tanh(x)
- */
- final double eps = Math.tanh(x.doubleValue());
- final MathContext mc = SafeMathContext.newMathContext(BigDecimalMath.err2prec(0.5 * x.ulp().doubleValue() / eps));
- return resul.round(mc);
- } else {
- final BigDecimal xhighpr = BigDecimalMath.scalePrec(x, 2);
- /*
- * Simple Taylor expansion, sum_{i=0..infinity} x^(2i+1)/(2i+1)!
- */
- BigDecimal resul = xhighpr;
-
- /* x^i */
- BigDecimal xpowi = xhighpr;
-
- /* 2i+1 factorial */
- BigInteger ifac = BigInteger.ONE;
-
- /*
- * The error in the result is set by the error in x itself.
- */
- final double xUlpDbl = x.ulp().doubleValue();
-
- /*
- * The error in the result is set by the error in x itself.
- * We need at most k terms to squeeze x^(2k+1)/(2k+1)! below
- * this value.
- * x^(2k+1) < x.ulp; (2k+1)*log10(x) < -x.precision;
- * 2k*log10(x)< -x.precision;
- * 2k*(-log10(x)) > x.precision; 2k*log10(1/x) > x.precision
- */
- final int k = (int) (x.precision() / Math.log10(1.0 / xhighpr.doubleValue())) / 2;
- final MathContext mcTay = SafeMathContext.newMathContext(BigDecimalMath.err2prec(x.doubleValue(), xUlpDbl / k));
- for (int i = 1;; i++) {
- /*
- * TBD: at which precision will 2*i or 2*i+1 overflow?
- */
- ifac = ifac.multiply(new BigInteger("" + 2 * i));
- ifac = ifac.multiply(new BigInteger("" + (2 * i + 1)));
- xpowi = xpowi.multiply(xhighpr).multiply(xhighpr);
- final BigDecimal corr = xpowi.divide(new BigDecimal(ifac), mcTay);
- resul = resul.add(corr);
- if (corr.abs().doubleValue() < 0.5 * xUlpDbl) {
- break;
- }
- }
- /*
- * The error in the result is set by the error in x itself.
- */
- final MathContext mc = SafeMathContext.newMathContext(x.precision());
- return resul.round(mc);
- }
- } /* BigDecimalMath.sinh */
-
- /**
- * The hyperbolic tangent.
- *
- * @param x
- * The argument.
- * @return The tanh(x) = sinh(x)/cosh(x).
- * @author Richard J. Mathar
- * @since 2009-08-20
- */
- static public BigDecimal tanh(final BigDecimal x) {
- if (x.compareTo(BigDecimal.ZERO) < 0) {
- return BigDecimalMath.tanh(x.negate()).negate();
- } else if (x.compareTo(BigDecimal.ZERO) == 0) {
- return BigDecimal.ZERO;
- } else {
- final BigDecimal xhighpr = BigDecimalMath.scalePrec(x, 2);
-
- /*
- * tanh(x) = (1-e^(-2x))/(1+e^(-2x)) .
- */
- final BigDecimal exp2x = BigDecimalMath.exp(xhighpr.multiply(new BigDecimal(-2)));
-
- /*
- * The error in tanh x is err(x)/cosh^2(x).
- */
- final double eps = 0.5 * x.ulp().doubleValue() / Math.pow(Math.cosh(x.doubleValue()), 2.0);
- final MathContext mc = SafeMathContext.newMathContext(BigDecimalMath.err2prec(Math.tanh(x.doubleValue()), eps));
- return BigDecimal.ONE.subtract(exp2x).divide(BigDecimal.ONE.add(exp2x), mc);
- }
- } /* BigDecimalMath.tanh */
-
- /**
- * The inverse hyperbolic sine.
- *
- * @param x
- * The argument.
- * @return The arcsinh(x) .
- * @author Richard J. Mathar
- * @since 2009-08-20
- */
- static public BigDecimal asinh(final BigDecimal x) {
- if (x.compareTo(BigDecimal.ZERO) == 0) {
- return BigDecimal.ZERO;
- } else {
- final BigDecimal xhighpr = BigDecimalMath.scalePrec(x, 2);
-
- /*
- * arcsinh(x) = log(x+hypot(1,x))
- */
- final BigDecimal logx = BigDecimalMath.log(BigDecimalMath.hypot(1, xhighpr).add(xhighpr));
-
- /*
- * The absolute error in arcsinh x is err(x)/sqrt(1+x^2)
- */
- final double xDbl = x.doubleValue();
- final double eps = 0.5 * x.ulp().doubleValue() / Math.hypot(1., xDbl);
- final MathContext mc = SafeMathContext.newMathContext(BigDecimalMath.err2prec(logx.doubleValue(), eps));
- return logx.round(mc);
- }
- } /* BigDecimalMath.asinh */
-
- /**
- * The inverse hyperbolic cosine.
- *
- * @param x
- * The argument.
- * @return The arccosh(x) .
- * @author Richard J. Mathar
- * @since 2009-08-20
- */
- static public BigDecimal acosh(final BigDecimal x) {
- if (x.compareTo(BigDecimal.ONE) < 0) {
- throw new ArithmeticException("Out of range argument cosh " + x.toString());
- } else if (x.compareTo(BigDecimal.ONE) == 0) {
- return BigDecimal.ZERO;
- } else {
- final BigDecimal xhighpr = BigDecimalMath.scalePrec(x, 2);
-
- /*
- * arccosh(x) = log(x+sqrt(x^2-1))
- */
- final BigDecimal logx = BigDecimalMath.log(BigDecimalMath.sqrt(xhighpr.pow(2).subtract(BigDecimal.ONE)).add(xhighpr));
-
- /*
- * The absolute error in arcsinh x is err(x)/sqrt(x^2-1)
- */
- final double xDbl = x.doubleValue();
- final double eps = 0.5 * x.ulp().doubleValue() / Math.sqrt(xDbl * xDbl - 1.);
- final MathContext mc = SafeMathContext.newMathContext(BigDecimalMath.err2prec(logx.doubleValue(), eps));
- return logx.round(mc);
- }
- } /* BigDecimalMath.acosh */
-
- /**
- * The Gamma function.
- *
- * @param x
- * The argument.
- * @return Gamma(x).
- * @throws Error
- * @since 2009-08-06
- */
- static public BigDecimal Gamma(final BigDecimal x) throws Error {
- /*
- * reduce to interval near 1.0 with the functional relation,
- * Abramowitz-Stegun 6.1.33
- */
- if (x.compareTo(BigDecimal.ZERO) < 0) {
- return BigDecimalMath.divideRound(BigDecimalMath.Gamma(x.add(BigDecimal.ONE)), x);
- } else if (x.doubleValue() > 1.5) {
- /*
- * Gamma(x) = Gamma(xmin+n) = Gamma(xmin)*Pochhammer(xmin,n).
- */
- final int n = (int) (x.doubleValue() - 0.5);
- final BigDecimal xmin1 = x.subtract(new BigDecimal(n));
- return BigDecimalMath.multiplyRound(BigDecimalMath.Gamma(xmin1), BigDecimalMath.pochhammer(xmin1, n));
- } else {
- /*
- * apply Abramowitz-Stegun 6.1.33
- */
- BigDecimal z = x.subtract(BigDecimal.ONE);
-
- /*
- * add intermediately 2 digits to the partial sum accumulation
- */
- z = BigDecimalMath.scalePrec(z, 2);
- MathContext mcloc = SafeMathContext.newMathContext(z.precision());
-
- /*
- * measure of the absolute error is the relative error in the first,
- * logarithmic term
- */
- double eps = x.ulp().doubleValue() / x.doubleValue();
-
- BigDecimal resul = BigDecimalMath.log(BigDecimalMath.scalePrec(x, 2)).negate();
-
- if (x.compareTo(BigDecimal.ONE) != 0) {
-
- final BigDecimal gammCompl = BigDecimal.ONE.subtract(BigDecimalMath.gamma(mcloc));
- resul = resul.add(BigDecimalMath.multiplyRound(z, gammCompl));
- for (int n = 2;; n++) {
- /*
- * multiplying z^n/n by zeta(n-1) means that the two
- * relative errors add.
- * so the requirement in the relative error of zeta(n)-1 is
- * that this is somewhat
- * smaller than the relative error in z^n/n (the absolute
- * error of thelatter is the
- * absolute error in z)
- */
- BigDecimal c = BigDecimalMath.divideRound(z.pow(n, mcloc), n);
- MathContext m = SafeMathContext.newMathContext(BigDecimalMath.err2prec(n * z.ulp().doubleValue() / 2. / z.doubleValue()));
- c = c.round(m);
-
- /*
- * At larger n, zeta(n)-1 is roughly 1/2^n. The product is
- * c/2^n.
- * The relative error in c is c.ulp/2/c . The error in the
- * product should be small versus eps/10.
- * Error from 1/2^n is c*err(sigma-1).
- * We need a relative error of zeta-1 of the order of
- * c.ulp/50/c. This is an absolute
- * error in zeta-1 of c.ulp/50/c/2^n, and also the absolute
- * error in zeta, because zeta is
- * of the order of 1.
- */
- if (eps / 100. / c.doubleValue() < 0.01) {
- m = SafeMathContext.newMathContext(BigDecimalMath.err2prec(eps / 100. / c.doubleValue()));
- } else {
- m = SafeMathContext.newMathContext(2);
- }
- /* zeta(n) -1 */
- final BigDecimal zetm1 = BigDecimalMath.zeta(n, m).subtract(BigDecimal.ONE);
- c = BigDecimalMath.multiplyRound(c, zetm1);
-
- if (n % 2 == 0) {
- resul = resul.add(c);
- } else {
- resul = resul.subtract(c);
- }
-
- /*
- * alternating sum, so truncating as eps is reached suffices
- */
- if (Math.abs(c.doubleValue()) < eps) {
- break;
- }
- }
- }
-
- /*
- * The relative error in the result is the absolute error in the
- * input variable times the digamma (psi) value at that point.
- */
- final double zdbl = z.doubleValue();
- eps = BigDecimalMath.psi(zdbl) * x.ulp().doubleValue() / 2.;
- mcloc = SafeMathContext.newMathContext(BigDecimalMath.err2prec(eps));
- return BigDecimalMath.exp(resul).round(mcloc);
- }
- } /* BigDecimalMath.gamma */
-
- /**
- * The Gamma function.
- *
- * @param q
- * The argument.
- * @param mc
- * The required accuracy in the result.
- * @return Gamma(x).
- * @throws Error
- * @since 2010-05-26
- */
- static public BigDecimal Gamma(final Rational q, final MathContext mc) throws Error {
- if (q.isBigInteger()) {
- if (q.compareTo(Rational.ZERO) <= 0) {
- throw new ArithmeticException("Gamma at " + q.toString());
- } else {
- /* Gamma(n) = (n-1)! */
- final Factorial f = new Factorial();
- final BigInteger g = f.at(q.trunc().intValue() - 1);
- return BigDecimalMath.scalePrec(new BigDecimal(g), mc);
- }
- } else if (q.b.intValue() == 2) {
- /*
- * half integer cases which are related to sqrt(pi)
- */
- final BigDecimal p = BigDecimalMath.sqrt(BigDecimalMath.pi(mc));
- if (q.compareTo(Rational.ZERO) >= 0) {
- Rational pro = Rational.ONE;
- Rational f = q.subtract(1);
- while (f.compareTo(Rational.ZERO) > 0) {
- pro = pro.multiply(f);
- f = f.subtract(1);
- }
- return BigDecimalMath.multiplyRound(p, pro);
- } else {
- Rational pro = Rational.ONE;
- Rational f = q;
- while (f.compareTo(Rational.ZERO) < 0) {
- pro = pro.divide(f);
- f = f.add(1);
- }
- return BigDecimalMath.multiplyRound(p, pro);
- }
- } else {
- /*
- * The relative error of the result is psi(x)*Delta(x). Tune
- * Delta(x) such
- * that this is equivalent to mc: Delta(x) = precision/psi(x).
- */
- final double qdbl = q.doubleValue();
- final double deltx = 5. * Math.pow(10., -mc.getPrecision()) / BigDecimalMath.psi(qdbl);
-
- final MathContext mcx = SafeMathContext.newMathContext(BigDecimalMath.err2prec(qdbl, deltx));
- final BigDecimal x = q.BigDecimalValue(mcx);
-
- /* forward calculation to the general floating point case */
- return BigDecimalMath.Gamma(x);
- }
- } /* BigDecimalMath.Gamma */
-
- /**
- * Pochhammer's function.
- *
- * @param x
- * The main argument.
- * @param n
- * The non-negative index.
- * @return (x)_n = x(x+1)(x+2)*...*(x+n-1).
- * @since 2009-08-19
- */
- static public BigDecimal pochhammer(final BigDecimal x, final int n) {
- /*
- * reduce to interval near 1.0 with the functional relation,
- * Abramowitz-Stegun 6.1.33
- */
- if (n < 0) {
- throw new ProviderException("Not implemented: pochhammer with negative index " + n);
- } else if (n == 0) {
- return BigDecimal.ONE;
- } else {
- /*
- * internally two safety digits
- */
- final BigDecimal xhighpr = BigDecimalMath.scalePrec(x, 2);
- BigDecimal resul = xhighpr;
-
- 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
- */
- double eps = 0.5 * xUlpDbl / Math.abs(xDbl);
- for (int i = 1; i < n; i++) {
- eps += 0.5 * xUlpDbl / Math.abs(xDbl + i);
- resul = resul.multiply(xhighpr.add(new BigDecimal(i)));
- final MathContext mcloc = SafeMathContext.newMathContext(4 + BigDecimalMath.err2prec(eps));
- resul = resul.round(mcloc);
- }
- return resul.round(SafeMathContext.newMathContext(BigDecimalMath.err2prec(eps)));
- }
- } /* BigDecimalMath.pochhammer */
-
- /**
- * Reduce value to the interval [0,2*Pi].
- *
- * @param x
- * the original value
- * @return the value modulo 2*pi in the interval from 0 to 2*pi.
- * @throws Error
- * @since 2009-06-01
- */
- static public BigDecimal mod2pi(final BigDecimal x) throws Error {
- /*
- * write x= 2*pi*k+r with the precision in r defined by the precision of
- * x and not
- * compromised by the precision of 2*pi, so the ulp of 2*pi*k should
- * match the ulp of x.
- * First get a guess of k to figure out how many digits of 2*pi are
- * needed.
- */
- 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) {
- err2pi = 0.25 * Math.abs(x.ulp().doubleValue() / k);
- } else {
- err2pi = 0.5 * Math.abs(x.ulp().doubleValue());
- }
- MathContext mc = SafeMathContext.newMathContext(2 + BigDecimalMath.err2prec(6.283, err2pi));
- final BigDecimal twopi = BigDecimalMath.pi(mc).multiply(new BigDecimal(2));
-
- /*
- * Delegate the actual operation to the BigDecimal class, which may
- * return
- * a negative value of x was negative .
- */
- BigDecimal res = x.remainder(twopi);
- if (res.compareTo(BigDecimal.ZERO) < 0) {
- res = res.add(twopi);
- }
-
- /*
- * The actual precision is set by the input value, its absolute value of
- * x.ulp()/2.
- */
- mc = SafeMathContext.newMathContext(BigDecimalMath.err2prec(res.doubleValue(), x.ulp().doubleValue() / 2.));
- return res.round(mc);
- } /* mod2pi */
-
- /**
- * Reduce value to the interval [-Pi/2,Pi/2].
- *
- * @param x
- * The original value
- * @return The value modulo pi, shifted to the interval from -Pi/2 to Pi/2.
- * @throws Error
- * @since 2009-07-31
- */
- static public BigDecimal modpi(final BigDecimal x) throws Error {
- /*
- * write x= pi*k+r with the precision in r defined by the precision of x
- * and not
- * compromised by the precision of pi, so the ulp of pi*k should match
- * the ulp of x.
- * First get a guess of k to figure out how many digits of pi are
- * needed.
- */
- 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) {
- errpi = 0.5 * Math.abs(x.ulp().doubleValue() / k);
- } else {
- errpi = 0.5 * Math.abs(x.ulp().doubleValue());
- }
- MathContext mc = SafeMathContext.newMathContext(2 + BigDecimalMath.err2prec(3.1416, errpi));
- final BigDecimal onepi = BigDecimalMath.pi(mc);
- final BigDecimal pihalf = onepi.divide(new BigDecimal(2));
-
- /*
- * Delegate the actual operation to the BigDecimal class, which may
- * return
- * a negative value of x was negative .
- */
- BigDecimal res = x.remainder(onepi);
- if (res.compareTo(pihalf) > 0) {
- res = res.subtract(onepi);
- } else if (res.compareTo(pihalf.negate()) < 0) {
- res = res.add(onepi);
- }
-
- /*
- * The actual precision is set by the input value, its absolute value of
- * x.ulp()/2.
- */
- mc = SafeMathContext.newMathContext(BigDecimalMath.err2prec(res.doubleValue(), x.ulp().doubleValue() / 2.));
- return res.round(mc);
- } /* modpi */
-
- /**
- * Riemann zeta function.
- *
- * @param n
- * The positive integer argument.
- * @param mc
- * Specification of the accuracy of the result.
- * @return zeta(n).
- * @throws Error
- * @since 2009-08-05
- */
- static public BigDecimal zeta(final int n, final MathContext mc) throws Error {
- if (n <= 0) {
- throw new ProviderException("Not implemented: zeta at negative argument " + n);
- }
- if (n == 1) {
- throw new ArithmeticException("Pole at zeta(1) ");
- }
-
- if (n % 2 == 0) {
- /*
- * Even indices. Abramowitz-Stegun 23.2.16. Start with
- * 2^(n-1)*B(n)/n!
- */
- Rational b = new Bernoulli().at(n).abs();
- b = b.divide(new Factorial().at(n));
- b = b.multiply(BigInteger.ONE.shiftLeft(n - 1));
-
- /*
- * to be multiplied by pi^n. Absolute error in the result of pi^n is
- * n times
- * error in pi times pi^(n-1). Relative error is n*error(pi)/pi,
- * requested by mc.
- * Need one more digit in pi if n=10, two digits if n=100 etc, and
- * add one extra digit.
- */
- final MathContext mcpi = SafeMathContext.newMathContext(mc.getPrecision() + (int) Math.log10(10.0 * n));
- final BigDecimal piton = BigDecimalMath.pi(mcpi).pow(n, mc);
- return BigDecimalMath.multiplyRound(piton, b);
- } else if (n == 3) {
- /*
- * Broadhurst BBP arXiv:math/9803067
- * Error propagation: S31 is roughly 0.087, S33 roughly 0.131
- */
- final int[] a31 = { 1, -7, -1, 10, -1, -7, 1, 0 };
- final int[] a33 = { 1, 1, -1, -2, -1, 1, 1, 0 };
- BigDecimal S31 = BigDecimalMath.broadhurstBBP(3, 1, a31, mc);
- BigDecimal S33 = BigDecimalMath.broadhurstBBP(3, 3, a33, mc);
- S31 = S31.multiply(new BigDecimal(48));
- S33 = S33.multiply(new BigDecimal(32));
- return S31.add(S33).divide(new BigDecimal(7), mc);
- } else if (n == 5) {
- /*
- * Broadhurst BBP arXiv:math/9803067
- * Error propagation: S51 is roughly -11.15, S53 roughly 22.165, S55
- * is roughly 0.031
- * 9*2048*S51/6265 = -3.28. 7*2038*S53/61651= 5.07.
- * 738*2048*S55/61651= 0.747.
- * The result is of the order 1.03, so we add 2 digits to S51 and
- * S52 and one digit to S55.
- */
- 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 = BigDecimalMath.broadhurstBBP(5, 1, a51, SafeMathContext.newMathContext(2 + mc.getPrecision()));
- BigDecimal S53 = BigDecimalMath.broadhurstBBP(5, 3, a53, SafeMathContext.newMathContext(2 + mc.getPrecision()));
- BigDecimal S55 = BigDecimalMath.broadhurstBBP(5, 5, a55, SafeMathContext.newMathContext(1 + mc.getPrecision()));
- S51 = S51.multiply(new BigDecimal(18432));
- S53 = S53.multiply(new BigDecimal(14336));
- S55 = S55.multiply(new BigDecimal(1511424));
- return S51.add(S53).subtract(S55).divide(new BigDecimal(62651), mc);
- } else {
- /*
- * Cohen et al Exp Math 1 (1) (1992) 25
- */
- Rational betsum = new Rational();
- 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) {
- betsum = betsum.add(b);
- } else {
- betsum = betsum.subtract(b);
- }
- }
- betsum = betsum.divide(n - 1);
- /*
- * The first term, including the facor (2pi)^n, is essentially most
- * of the result, near one. The second term below is roughly in the
- * range 0.003 to 0.009.
- * So the precision here is matching the precisionn requested by mc,
- * and the precision
- * requested for 2*pi is in absolute terms adjusted.
- */
- final MathContext mcloc = SafeMathContext.newMathContext(2 + mc.getPrecision() + (int) Math.log10(n));
- BigDecimal ftrm = BigDecimalMath.pi(mcloc).multiply(new BigDecimal(2));
- ftrm = ftrm.pow(n);
- ftrm = BigDecimalMath.multiplyRound(ftrm, betsum.BigDecimalValue(mcloc));
- BigDecimal exps = new BigDecimal(0);
-
- /*
- * the basic accuracy of the accumulated terms before multiplication
- * with 2
- */
- double eps = Math.pow(10., -mc.getPrecision());
-
- if (n % 4 == 3) {
- /*
- * since the argument n is at least 7 here, the drop
- * of the terms is at rather constant pace at least 10^-3, for
- * example
- * 0.0018, 0.2e-7, 0.29e-11, 0.74e-15 etc for npr=1,2,3.... We
- * want 2 times these terms
- * fall below eps/10.
- */
- final int kmax = mc.getPrecision() / 3;
- eps /= kmax;
- /*
- * need an error of eps for 2/(exp(2pi)-1) = 0.0037
- * The absolute error is
- * 4*exp(2pi)*err(pi)/(exp(2pi)-1)^2=0.0075*err(pi)
- */
- BigDecimal exp2p = BigDecimalMath.pi(SafeMathContext.newMathContext(3 + BigDecimalMath.err2prec(3.14, eps / 0.0075)));
- exp2p = BigDecimalMath.exp(exp2p.multiply(new BigDecimal(2)));
- BigDecimal c = exp2p.subtract(BigDecimal.ONE);
- exps = BigDecimalMath.divideRound(1, c);
- for (int npr = 2; npr <= kmax; npr++) {
- /*
- * the error estimate above for npr=1 is the worst case of
- * the absolute error created by an error in 2pi. So we can
- * safely re-use the exp2p value computed above without
- * reassessment of its error.
- */
- c = BigDecimalMath.powRound(exp2p, npr).subtract(BigDecimal.ONE);
- c = BigDecimalMath.multiplyRound(c, new BigInteger("" + npr).pow(n));
- c = BigDecimalMath.divideRound(1, c);
- exps = exps.add(c);
- }
- } else {
- /*
- * since the argument n is at least 9 here, the drop
- * of the terms is at rather constant pace at least 10^-3, for
- * example
- * 0.0096, 0.5e-7, 0.3e-11, 0.6e-15 etc. We want these terms
- * fall below eps/10.
- */
- final int kmax = (1 + mc.getPrecision()) / 3;
- eps /= kmax;
- /*
- * need an error of eps for
- * 2/(exp(2pi)-1)*(1+4*Pi/8/(1-exp(-2pi)) = 0.0096
- * at k=7 or = 0.00766 at k=13 for example.
- * The absolute error is 0.017*err(pi) at k=9, 0.013*err(pi) at
- * k=13, 0.012 at k=17
- */
- BigDecimal twop = BigDecimalMath.pi(SafeMathContext.newMathContext(3 + BigDecimalMath.err2prec(3.14, eps / 0.017)));
- twop = twop.multiply(new BigDecimal(2));
- final BigDecimal exp2p = BigDecimalMath.exp(twop);
- BigDecimal c = exp2p.subtract(BigDecimal.ONE);
- exps = BigDecimalMath.divideRound(1, c);
- c = BigDecimal.ONE.subtract(BigDecimalMath.divideRound(1, exp2p));
- c = BigDecimalMath.divideRound(twop, c).multiply(new BigDecimal(2));
- c = BigDecimalMath.divideRound(c, n - 1).add(BigDecimal.ONE);
- exps = BigDecimalMath.multiplyRound(exps, c);
- for (int npr = 2; npr <= kmax; npr++) {
- c = BigDecimalMath.powRound(exp2p, npr).subtract(BigDecimal.ONE);
- c = BigDecimalMath.multiplyRound(c, new BigInteger("" + npr).pow(n));
-
- BigDecimal d = BigDecimalMath.divideRound(1, exp2p.pow(npr));
- d = BigDecimal.ONE.subtract(d);
- d = BigDecimalMath.divideRound(twop, d).multiply(new BigDecimal(2 * npr));
- d = BigDecimalMath.divideRound(d, n - 1).add(BigDecimal.ONE);
-
- d = BigDecimalMath.divideRound(d, c);
-
- exps = exps.add(d);
- }
- }
- exps = exps.multiply(new BigDecimal(2));
- return ftrm.subtract(exps, mc);
- }
- } /* zeta */
-
- /**
- * Riemann zeta function.
- *
- * @param n
- * The positive integer argument.
- * @return zeta(n)-1.
- * @throws Error
- * @since 2009-08-20
- */
- static public double zeta1(final int n) throws Error {
- /*
- * 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) {
- throw new ProviderException("Not implemented: zeta at negative argument " + n);
- }
- if (n == 1) {
- throw new ArithmeticException("Pole at zeta(1) ");
- }
-
- if (n < zmin1.length) {
- /* look it up if available */
- return zmin1[n];
- } 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.
- */
- final double eps = 1.e-18 * Math.pow(2., -n);
- final MathContext mc = SafeMathContext.newMathContext(BigDecimalMath.err2prec(eps));
- return BigDecimalMath.zeta(n, mc).subtract(BigDecimal.ONE).doubleValue();
- }
- } /* zeta */
-
- /**
- * trigonometric cot.
- *
- * @param x
- * The argument.
- * @return cot(x) = 1/tan(x).
- */
- static public double cot(final double x) {
- return 1. / Math.tan(x);
- }
-
- /**
- * Digamma function.
- *
- * @param x
- * The main argument.
- * @return psi(x).
- * The error is sometimes up to 10 ulp, where AS 6.3.15 suffers from
- * cancellation of digits and psi=0
- * @throws Error
- * @since 2009-08-26
- */
- static public double psi(final double x) throws Error {
- /*
- * the single positive zero of psi(x)
- */
- final double psi0 = 1.46163214496836234126265954232572132846819;
- if (x > 2.0) {
- /*
- * Reduce to a value near x=1 with the standard recurrence formula.
- * Abramowitz-Stegun 6.3.5
- */
- final int m = (int) (x - 0.5);
- final double xmin1 = x - m;
- double resul = 0.;
- for (int i = 1; i <= m; i++) {
- resul += 1. / (x - i);
- }
- return resul + BigDecimalMath.psi(xmin1);
- } else if (Math.abs(x - psi0) < 0.55) {
- /*
- * Taylor approximation around the local zero
- */
- 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--) {
- resul = resul * xdiff + psiT0[i];
- }
- return resul * xdiff;
- } else if (x < 0.) {
- /* Reflection formula */
- final double xmin = 1. - x;
- return BigDecimalMath.psi(xmin) + Math.PI / Math.tan(Math.PI * xmin);
- } else {
- final double xmin1 = x - 1;
- double resul = 0.;
- for (int k = 26; k >= 1; k--) {
- resul -= BigDecimalMath.zeta1(2 * k + 1);
- resul *= xmin1 * xmin1;
- }
- /* 0.422... = 1 -gamma */
- return resul + 0.422784335098467139393487909917597568 + 0.5 / xmin1 - 1. / (1 - xmin1 * xmin1) - Math.PI / (2. * Math.tan(Math.PI * xmin1));
- }
- } /* psi */
-
- /**
- * Broadhurst ladder sequence.
- *
- * @param a
- * The vector of 8 integer arguments
- * @param mc
- * Specification of the accuracy of the result
- * @return S_(n,p)(a)
- * @throws Error
- * @since 2009-08-09
- * @see arXiv:math/9803067
- */
- static protected BigDecimal broadhurstBBP(final int n, final int p, final int a[], final MathContext mc)
- throws Error {
- /*
- * Explore the actual magnitude of the result first with a quick
- * estimate.
- */
- double x = 0.0;
- 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
- * absolute precision.
- */
- double eps = BigDecimalMath.prec2err(x, mc.getPrecision());
-
- /*
- * Divide this through the number of terms in the sum to account for
- * error accumulation
- * The divisor 2^(p(k+1)/2) means that on the average each 8th term in k
- * has shrunk by
- * relative to the 8th predecessor by 1/2^(4p). 1/2^(4pc) =
- * 10^(-precision) with c the 8term
- * cycles yields c=log_2( 10^precision)/4p = 3.3*precision/4p with k=8c
- */
- final int kmax = (int) (6.6 * mc.getPrecision() / p);
-
- /* Now eps is the absolute error in each term */
- eps /= kmax;
- BigDecimal res = BigDecimal.ZERO;
- for (int c = 0;; c++) {
- Rational r = new Rational();
- for (int k = 0; k < 8; k++) {
- Rational tmp = new Rational(new BigInteger("" + a[k]), new BigInteger("" + (1 + 8 * c + k)).pow(n));
- /*
- * floor( (pk+p)/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) {
- break;
- }
- final MathContext mcloc = SafeMathContext.newMathContext(1 + BigDecimalMath.err2prec(r.doubleValue(), eps));
- res = res.add(r.BigDecimalValue(mcloc));
- }
- return res.round(mc);
- } /* broadhurstBBP */
-
- /**
- * Add a BigDecimal and a BigInteger.
- *
- * @param x
- * The left summand
- * @param y
- * The right summand
- * @return The sum x+y.
- * @since 2012-03-02
- */
- static public BigDecimal add(final BigDecimal x, final BigInteger y) {
- return x.add(new BigDecimal(y));
- } /* add */
-
- /**
- * Add and round according to the larger of the two ulp's.
- *
- * @param x
- * The left summand
- * @param y
- * The right summand
- * @return The sum x+y.
- * @since 2009-07-30
- */
- static public BigDecimal addRound(final BigDecimal x, final BigDecimal y) {
- final BigDecimal resul = x.add(y);
- /*
- * The estimation of the absolute error in the result is
- * |err(y)|+|err(x)|
- */
- final double errR = Math.abs(y.ulp().doubleValue() / 2.) + Math.abs(x.ulp().doubleValue() / 2.);
- int err2prec = BigDecimalMath.err2prec(resul.doubleValue(), errR);
- if (err2prec < 0) {
- err2prec = 0;
- }
- final MathContext mc = SafeMathContext.newMathContext(err2prec);
- return resul.round(mc);
- } /* addRound */
-
- /**
- * Add and round according to the larger of the two ulp's.
- *
- * @param x
- * The left summand
- * @param y
- * The right summand
- * @return The sum x+y.
- * @since 2010-07-19
- */
- static public BigComplex addRound(final BigComplex x, final BigDecimal y) {
- final BigDecimal R = BigDecimalMath.addRound(x.re, y);
- return new BigComplex(R, x.im);
- } /* addRound */
-
- /**
- * Add and round according to the larger of the two ulp's.
- *
- * @param x
- * The left summand
- * @param y
- * The right summand
- * @return The sum x+y.
- * @since 2010-07-19
- */
- static public BigComplex addRound(final BigComplex x, final BigComplex y) {
- final BigDecimal R = BigDecimalMath.addRound(x.re, y.re);
- final BigDecimal I = BigDecimalMath.addRound(x.im, y.im);
- return new BigComplex(R, I);
- } /* addRound */
-
- /**
- * Subtract and round according to the larger of the two ulp's.
- *
- * @param x
- * The left term.
- * @param y
- * The right term.
- * @return The difference x-y.
- * @since 2009-07-30
- */
- static public BigDecimal subtractRound(final BigDecimal x, final BigDecimal y) {
- final BigDecimal resul = x.subtract(y);
- /*
- * The estimation of the absolute error in the result is
- * |err(y)|+|err(x)|
- */
- final double errR = Math.abs(y.ulp().doubleValue() / 2.) + Math.abs(x.ulp().doubleValue() / 2.);
- final MathContext mc = SafeMathContext.newMathContext(BigDecimalMath.err2prec(resul.doubleValue(), errR));
- return resul.round(mc);
- } /* subtractRound */
-
- /**
- * Subtract and round according to the larger of the two ulp's.
- *
- * @param x
- * The left summand
- * @param y
- * The right summand
- * @return The difference x-y.
- * @since 2010-07-19
- */
- static public BigComplex subtractRound(final BigComplex x, final BigComplex y) {
- final BigDecimal R = BigDecimalMath.subtractRound(x.re, y.re);
- final BigDecimal I = BigDecimalMath.subtractRound(x.im, y.im);
- return new BigComplex(R, I);
- } /* subtractRound */
-
- /**
- * Multiply and round.
- *
- * @param x
- * The left factor.
- * @param y
- * The right factor.
- * @return The product x*y.
- * @since 2009-07-30
- */
- static public BigDecimal multiplyRound(final BigDecimal x, final BigDecimal 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|
- */
- final MathContext mc = SafeMathContext.newMathContext(Math.min(x.precision(), y.precision()));
- return resul.round(mc);
- } /* multiplyRound */
-
- /**
- * Multiply and round.
- *
- * @param x
- * The left factor.
- * @param y
- * The right factor.
- * @return The product x*y.
- * @since 2010-07-19
- */
- static public BigComplex multiplyRound(final BigComplex x, final BigDecimal y) {
- final BigDecimal R = BigDecimalMath.multiplyRound(x.re, y);
- final BigDecimal I = BigDecimalMath.multiplyRound(x.im, y);
- return new BigComplex(R, I);
- } /* multiplyRound */
-
- /**
- * Multiply and round.
- *
- * @param x
- * The left factor.
- * @param y
- * The right factor.
- * @return The product x*y.
- * @since 2010-07-19
- */
- static public BigComplex multiplyRound(final BigComplex x, final BigComplex y) {
- final BigDecimal R = BigDecimalMath.subtractRound(BigDecimalMath.multiplyRound(x.re, y.re), BigDecimalMath.multiplyRound(x.im, y.im));
- final BigDecimal I = BigDecimalMath.addRound(BigDecimalMath.multiplyRound(x.re, y.im), BigDecimalMath.multiplyRound(x.im, y.re));
- return new BigComplex(R, I);
- } /* multiplyRound */
-
- /**
- * Multiply and round.
- *
- * @param x
- * The left factor.
- * @param f
- * The right factor.
- * @return The product x*f.
- * @since 2009-07-30
- */
- static public BigDecimal multiplyRound(final BigDecimal x, final Rational f) {
- if (f.compareTo(BigInteger.ZERO) == 0) {
- return BigDecimal.ZERO;
- } else {
- /*
- * Convert the rational value with two digits of extra precision
- */
- final MathContext mc = SafeMathContext.newMathContext(2 + x.precision());
- final BigDecimal fbd = f.BigDecimalValue(mc);
-
- /*
- * and the precision of the product is then dominated by the
- * precision in x
- */
- return BigDecimalMath.multiplyRound(x, fbd);
- }
- }
-
- /**
- * Multiply and round.
- *
- * @param x
- * The left factor.
- * @param n
- * The right factor.
- * @return The product x*n.
- * @since 2009-07-30
- */
- static public BigDecimal multiplyRound(final BigDecimal x, final int n) {
- final BigDecimal resul = x.multiply(new BigDecimal(n));
- /*
- * The estimation of the absolute error in the result is |n*err(x)|
- */
- final MathContext mc = SafeMathContext.newMathContext(n != 0 ? x.precision() : 0);
- return resul.round(mc);
- }
-
- /**
- * Multiply and round.
- *
- * @param x
- * The left factor.
- * @param n
- * The right factor.
- * @return the product x*n
- * @since 2009-07-30
- */
- static public BigDecimal multiplyRound(final BigDecimal x, final BigInteger n) {
- final BigDecimal resul = x.multiply(new BigDecimal(n));
- /*
- * The estimation of the absolute error in the result is |n*err(x)|
- */
- final MathContext mc = SafeMathContext.newMathContext(n.compareTo(BigInteger.ZERO) != 0 ? x.precision() : 0);
- return resul.round(mc);
- }
-
- /**
- * Divide and round.
- *
- * @param x
- * The numerator
- * @param y
- * The denominator
- * @return the divided x/y
- * @since 2009-07-30
- */
- static public BigDecimal divideRound(final BigDecimal x, final BigDecimal y) {
- /*
- * The estimation of the relative error in the result is
- * |err(y)/y|+|err(x)/x|
- */
- final MathContext mc = SafeMathContext.newMathContext(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
- * a smaller apparent accuracy than starte... add missing trailing zeros
- * now.
- */
- return BigDecimalMath.scalePrec(resul, mc);
- }
-
- /**
- * Build the inverse and maintain the approximate accuracy.
- *
- * @param z
- * The denominator
- * @return The divided 1/z = [Re(z)-i*Im(z)]/ [Re^2 z + Im^2 z]
- * @since 2010-07-19
- */
- static public BigComplex invertRound(final BigComplex z) {
- if (z.im.compareTo(BigDecimal.ZERO) == 0) {
- /*
- * In this case with vanishing Im(x), the result is simply 1/Re z.
- */
- final MathContext mc = SafeMathContext.newMathContext(z.re.precision());
- return new BigComplex(BigDecimal.ONE.divide(z.re, mc));
- } else if (z.re.compareTo(BigDecimal.ZERO) == 0) {
- /*
- * In this case with vanishing Re(z), the result is simply -i/Im z
- */
- final MathContext mc = SafeMathContext.newMathContext(z.im.precision());
- return new BigComplex(BigDecimal.ZERO, BigDecimal.ONE.divide(z.im, mc).negate());
- } else {
- /*
- * 1/(x.re+I*x.im) = 1/(x.re+x.im^2/x.re) - I /(x.im +x.re^2/x.im)
- */
- BigDecimal R = BigDecimalMath.addRound(z.re, BigDecimalMath.divideRound(BigDecimalMath.multiplyRound(z.im, z.im), z.re));
- BigDecimal I = BigDecimalMath.addRound(z.im, BigDecimalMath.divideRound(BigDecimalMath.multiplyRound(z.re, z.re), z.im));
- MathContext mc = SafeMathContext.newMathContext(1 + R.precision());
- R = BigDecimal.ONE.divide(R, mc);
- mc = SafeMathContext.newMathContext(1 + I.precision());
- I = BigDecimal.ONE.divide(I, mc);
- return new BigComplex(R, I.negate());
- }
- }
-
- /**
- * Divide and round.
- *
- * @param x
- * The numerator
- * @param y
- * The denominator
- * @return the divided x/y
- * @since 2010-07-19
- */
- static public BigComplex divideRound(final BigComplex x, final BigComplex y) {
- return BigDecimalMath.multiplyRound(x, BigDecimalMath.invertRound(y));
- }
-
- /**
- * Divide and round.
- *
- * @param x
- * The numerator
- * @param n
- * The denominator
- * @return the divided x/n
- * @since 2009-07-30
- */
- static public BigDecimal divideRound(final BigDecimal x, final int n) {
- /*
- * The estimation of the relative error in the result is |err(x)/x|
- */
- final MathContext mc = SafeMathContext.newMathContext(x.precision());
- return x.divide(new BigDecimal(n), mc);
- }
-
- /**
- * Divide and round.
- *
- * @param x
- * The numerator
- * @param n
- * The denominator
- * @return the divided x/n
- * @since 2009-07-30
- */
- static public BigDecimal divideRound(final BigDecimal x, final BigInteger n) {
- /*
- * The estimation of the relative error in the result is |err(x)/x|
- */
- final MathContext mc = SafeMathContext.newMathContext(x.precision());
- return x.divide(new BigDecimal(n), mc);
- } /* divideRound */
-
- /**
- * Divide and round.
- *
- * @param n
- * The numerator
- * @param x
- * The denominator
- * @return the divided n/x
- * @since 2009-08-05
- */
- static public BigDecimal divideRound(final BigInteger n, final BigDecimal x) {
- /*
- * The estimation of the relative error in the result is |err(x)/x|
- */
- final MathContext mc = SafeMathContext.newMathContext(x.precision());
- return new BigDecimal(n).divide(x, mc);
- } /* divideRound */
-
- /**
- * Divide and round.
- *
- * @param n
- * The numerator
- * @param x
- * The denominator
- * @return the divided n/x
- * @since 2012-03-01
- */
- static public BigComplex divideRound(final BigInteger n, final BigComplex x) {
- /*
- * catch case of real-valued denominator first
- */
- if (x.im.compareTo(BigDecimal.ZERO) == 0) {
- return new BigComplex(BigDecimalMath.divideRound(n, x.re), BigDecimal.ZERO);
- } else if (x.re.compareTo(BigDecimal.ZERO) == 0) {
- return new BigComplex(BigDecimal.ZERO, BigDecimalMath.divideRound(n, x.im).negate());
- }
-
- final BigComplex z = BigDecimalMath.invertRound(x);
- /*
- * n/(x+iy) = nx/(x^2+y^2) -nyi/(x^2+y^2)
- */
- final BigDecimal repart = BigDecimalMath.multiplyRound(z.re, n);
- final BigDecimal impart = BigDecimalMath.multiplyRound(z.im, n);
- return new BigComplex(repart, impart);
- } /* divideRound */
-
- /**
- * Divide and round.
- *
- * @param n
- * The numerator.
- * @param x
- * The denominator.
- * @return the divided n/x.
- * @since 2009-08-05
- */
- static public BigDecimal divideRound(final int n, final BigDecimal x) {
- /*
- * The estimation of the relative error in the result is |err(x)/x|
- */
- final MathContext mc = SafeMathContext.newMathContext(x.precision());
- return new BigDecimal(n).divide(x, mc);
- }
-
- /**
- * Append decimal zeros to the value. This returns a value which appears to
- * have
- * a higher precision than the input.
- *
- * @param x
- * The input value
- * @param d
- * The (positive) value of zeros to be added as least significant
- * digits.
- * @return The same value as the input but with increased (pseudo)
- * precision.
- */
- static public BigDecimal scalePrec(final BigDecimal x, final int d) {
- return x.setScale(d + x.scale());
- }
-
- /**
- * Append decimal zeros to the value. This returns a value which appears to
- * have
- * a higher precision than the input.
- *
- * @param x
- * The input value
- * @param d
- * The (positive) value of zeros to be added as least significant
- * digits.
- * @return The same value as the input but with increased (pseudo)
- * precision.
- */
- static public BigComplex scalePrec(final BigComplex x, final int d) {
- return new BigComplex(BigDecimalMath.scalePrec(x.re, d), BigDecimalMath.scalePrec(x.im, d));
- }
-
- /**
- * Boost the precision by appending decimal zeros to the value. This returns
- * a value which appears to have
- * a higher precision than the input.
- *
- * @param x
- * The input value
- * @param mc
- * The requirement on the minimum precision on return.
- * @return The same value as the input but with increased (pseudo)
- * precision.
- */
- static public BigDecimal scalePrec(final BigDecimal x, final MathContext mc) {
- final int diffPr = mc.getPrecision() - x.precision();
- if (diffPr > 0) {
- return BigDecimalMath.scalePrec(x, diffPr);
- } else {
- return x;
- }
- } /* BigDecimalMath.scalePrec */
-
- /**
- * Convert an absolute error to a precision.
- *
- * @param x
- * The value of the variable
- * @param xerr
- * The absolute error in the variable
- * @return The number of valid digits in x.
- * The value is rounded down, and on the pessimistic side for that
- * reason.
- * @since 2009-06-25
- */
- static public int err2prec(final BigDecimal x, final BigDecimal xerr) {
- return BigDecimalMath.err2prec(xerr.divide(x, MathContext.DECIMAL64).doubleValue());
- }
-
- /**
- * Convert an absolute error to a precision.
- *
- * @param x
- * The value of the variable
- * The value returned depends only on the absolute value, not on
- * the sign.
- * @param xerr
- * The absolute error in the variable
- * The value returned depends only on the absolute value, not on
- * the sign.
- * @return The number of valid digits in x.
- * Derived from the representation x+- xerr, as if the error was
- * represented
- * in a "half width" (half of the error bar) form.
- * The value is rounded down, and on the pessimistic side for that
- * reason.
- * @since 2009-05-30
- */
- static public int err2prec(final double x, final double xerr) {
- /*
- * Example: an error of xerr=+-0.5 at x=100 represents 100+-0.5 with
- * a precision = 3 (digits).
- */
- return 1 + (int) Math.log10(Math.abs(0.5 * x / xerr));
- }
-
- /**
- * Convert a relative error to a precision.
- *
- * @param xerr
- * The relative error in the variable.
- * The value returned depends only on the absolute value, not on
- * the sign.
- * @return The number of valid digits in x.
- * The value is rounded down, and on the pessimistic side for that
- * reason.
- * @since 2009-08-05
- */
- static public int err2prec(final double xerr) {
- /*
- * Example: an error of xerr=+-0.5 a precision of 1 (digit), an error of
- * +-0.05 a precision of 2 (digits)
- */
- return 1 + (int) Math.log10(Math.abs(0.5 / xerr));
- }
-
- /**
- * Convert a precision (relative error) to an absolute error.
- * The is the inverse functionality of err2prec().
- *
- * @param x
- * The value of the variable
- * The value returned depends only on the absolute value, not on
- * the sign.
- * @param prec
- * The number of valid digits of the variable.
- * @return the absolute error in x.
- * Derived from the an accuracy of one half of the ulp.
- * @since 2009-08-09
- */
- static public double prec2err(final double x, final int prec) {
- return 5. * Math.abs(x) * Math.pow(10., -prec);
- }
-
-} /* BigDecimalMath */
diff --git a/core/src/main/java/org/nevec/rjm/BigIntegerMath.java b/core/src/main/java/org/nevec/rjm/BigIntegerMath.java
deleted file mode 100644
index 7c2893f2..00000000
--- a/core/src/main/java/org/nevec/rjm/BigIntegerMath.java
+++ /dev/null
@@ -1,644 +0,0 @@
-package org.nevec.rjm;
-
-import java.math.BigInteger;
-import java.util.Vector;
-
-import it.cavallium.warppi.util.Error;
-
-/**
- * BigInteger special functions and Number theory.
- *
- * @since 2009-08-06
- * @author Richard J. Mathar
- */
-public class BigIntegerMath {
-
- /**
- * Evaluate binomial(n,k).
- *
- * @param n
- * The upper index
- * @param k
- * The lower index
- * @return The binomial coefficient
- */
- static public BigInteger binomial(final int n, final int k) {
- if (k == 0) {
- return BigInteger.ONE;
- }
- BigInteger bin = new BigInteger("" + n);
- 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)) {
- bin = bin.divide(i);
- }
- return bin;
- } /* binomial */
-
- /**
- * Evaluate binomial(n,k).
- *
- * @param n
- * The upper index
- * @param k
- * The lower index
- * @return The binomial coefficient
- * @since 2008-10-15
- */
- static public BigInteger binomial(final BigInteger n, final BigInteger k) {
- /*
- * binomial(n,0) =1
- */
- if (k.compareTo(BigInteger.ZERO) == 0) {
- return BigInteger.ONE;
- }
-
- BigInteger bin = new BigInteger("" + n);
-
- /*
- * the following version first calculates n(n-1)(n-2)..(n-k+1)
- * in the first loop, and divides this product through k(k-1)(k-2)....2
- * in the second loop. This is rather slow and replaced by a faster
- * version
- * below
- * BigInteger n2 = bin ;
- * BigInteger i= k.subtract(BigInteger.ONE) ;
- * for( ; i.compareTo(BigInteger.ONE) >= 0 ; i =
- * i.subtract(BigInteger.ONE) )
- * bin = bin.multiply(n2.subtract(i)) ;
- * i= new BigInteger(""+k) ;
- * for( ; i.compareTo(BigInteger.ONE) == 1 ; i =
- * i.subtract(BigInteger.ONE) )
- * bin = bin.divide(i) ;
- */
-
- /*
- * calculate n then n(n-1)/2 then n(n-1)(n-2)(2*3) etc up to
- * n(n-1)..(n-k+1)/(2*3*..k)
- * This is roughly the best way to keep the individual intermediate
- * products small
- * and in the integer domain. First replace C(n,k) by C(n,n-k) if n-k
- * Deprecated: This function is extremely slow and inefficient!
- *
- * @param n
- * The integer of which the divisors are to be found.
- * @return The sorted list of positive divisors.
- * @since 2010-08-27
- * @author Richard J. Mathar
- */
- @Deprecated
- static public Vector divisors(final BigInteger n) {
- return new Ifactor(n.abs()).divisors();
- }
-
- /**
- * Evaluate sigma(n).
- *
- * @param n
- * the argument for which divisors will be searched.
- * @return the sigma function. Sum of the divisors of the argument.
- * @since 2006-08-14
- * @author Richard J. Mathar
- */
- static public BigInteger sigma(final BigInteger n) {
- return new Ifactor(n.abs()).sigma().n;
- }
-
- /**
- * Evaluate floor(sqrt(n)).
- *
- * @param n
- * The non-negative argument.
- * @return The integer square root. The square root rounded down.
- * @since 2010-08-27
- * @author Richard J. Mathar
- */
- static public int isqrt(final int n) {
- if (n < 0) {
- throw new ArithmeticException("Negative argument " + n);
- }
- final double resul = Math.sqrt(n);
- return (int) Math.round(resul);
- }
-
- /**
- * Evaluate floor(sqrt(n)).
- *
- * @param n
- * The non-negative argument.
- * Arguments less than zero throw an ArithmeticException.
- * @return The integer square root, the square root rounded down.
- * @since 2010-08-27
- * @author Richard J. Mathar
- */
- static public long isqrt(final long n) {
- if (n < 0) {
- throw new ArithmeticException("Negative argument " + n);
- }
- final double resul = Math.sqrt(n);
- return Math.round(resul);
- }
-
- /**
- * Evaluate floor(sqrt(n)).
- *
- * @param n
- * The non-negative argument.
- * Arguments less than zero throw an ArithmeticException.
- * @return The integer square root, the square root rounded down.
- * @since 2011-02-12
- * @author Richard J. Mathar
- */
- static public BigInteger isqrt(final BigInteger n) {
- if (n.compareTo(BigInteger.ZERO) < 0) {
- throw new ArithmeticException("Negative argument " + n.toString());
- }
- /*
- * Start with an estimate from a floating point reduction.
- */
- BigInteger x;
- final int bl = n.bitLength();
- if (bl > 120) {
- x = n.shiftRight(bl / 2 - 1);
- } else {
- final double resul = Math.sqrt(n.doubleValue());
- x = new BigInteger("" + Math.round(resul));
- }
-
- final BigInteger two = new BigInteger("2");
- while (true) {
- /*
- * check whether the result is accurate, x^2 =n
- */
- final BigInteger x2 = x.pow(2);
- BigInteger xplus2 = x.add(BigInteger.ONE).pow(2);
- 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) {
- return x.subtract(BigInteger.ONE);
- }
- /*
- * Newton algorithm. This correction is on the
- * low side caused by the integer divisions. So the value required
- * may end up by one unit too large by the bare algorithm, and this
- * is caught above by comparing x^2, (x+-1)^2 with n.
- */
- xplus2 = x2.subtract(n).divide(x).divide(two);
- x = x.subtract(xplus2);
- }
- }
-
- /**
- * Evaluate core(n).
- * Returns the smallest positive integer m such that n/m is a perfect
- * square.
- *
- * @param n
- * The non-negative argument.
- * @return The square-free part of n.
- * @since 2011-02-12
- * @author Richard J. Mathar
- */
- static public BigInteger core(final BigInteger n) {
- if (n.compareTo(BigInteger.ZERO) < 0) {
- throw new ArithmeticException("Negative argument " + n);
- }
- final Ifactor i = new Ifactor(n);
- return i.core();
- }
-
- /**
- * Minor of an integer matrix.
- *
- * @param A
- * The matrix.
- * @param r
- * The row index of the row to be removed (0-based).
- * An exception is thrown if this is outside the range 0 to the
- * upper row index of A.
- * @param c
- * The column index of the column to be removed (0-based).
- * An exception is thrown if this is outside the range 0 to the
- * upper column index of A.
- * @return The depleted matrix. This is not a deep copy but contains
- * references to the original.
- * @since 2010-08-27
- * @author Richard J. Mathar
- */
- 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) {
- throw new ArithmeticException("zero row count in matrix");
- }
- 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) {
- throw new ArithmeticException("zero column count in matrix");
- }
- if (c < 0 || c >= cL) {
- throw new ArithmeticException("column number " + c + " out of range 0.." + (cL - 1));
- }
- final BigInteger M[][] = new BigInteger[rL - 1][cL - 1];
- int imrow = 0;
- for (int row = 0; row < rL; row++) {
- if (row != r) {
- int imcol = 0;
- for (int col = 0; col < cL; col++) {
- if (col != c) {
- M[imrow][imcol] = A[row][col];
- imcol++;
- }
- }
- imrow++;
- }
- }
- return M;
- }
-
- /**
- * Replace column of a matrix with a column vector.
- *
- * @param A
- * The matrix.
- * @param c
- * The column index of the column to be substituted (0-based).
- * @param v
- * The column vector to be inserted.
- * With the current implementation, it must be at least as long
- * as the row count, and
- * its elements that exceed that count are ignored.
- * @return The modified matrix. This is not a deep copy but contains
- * references to the original.
- * @since 2010-08-27
- * @author Richard J. Mathar
- */
- @SuppressWarnings("unused")
- static private BigInteger[][] colSubs(final BigInteger[][] A, final int c, final BigInteger[] v)
- throws ArithmeticException {
- /* original row count */
- final int rL = A.length;
- if (rL == 0) {
- throw new ArithmeticException("zero row count in matrix");
- }
- /* original column count */
- final int cL = A[0].length;
- if (cL == 0) {
- throw new ArithmeticException("zero column count in matrix");
- }
- if (c < 0 || c >= cL) {
- throw new ArithmeticException("column number " + c + " out of range 0.." + (cL - 1));
- }
- final BigInteger M[][] = new BigInteger[rL][cL];
- for (int row = 0; row < rL; row++) {
- for (int col = 0; col < cL; col++) {
- /*
- * currently, v may just be longer than the row count, and
- * surplus
- * elements will be ignored. Shorter v lead to an exception.
- */
- if (col != c) {
- M[row][col] = A[row][col];
- } else {
- M[row][col] = v[row];
- }
- }
- }
- return M;
- }
-
- /**
- * Determinant of an integer square matrix.
- *
- * @param A
- * The square matrix.
- * If column and row dimensions are unequal, an
- * ArithmeticException is thrown.
- * @return The determinant.
- * @since 2010-08-27
- * @author Richard J. Mathar
- */
- static public BigInteger det(final BigInteger[][] A) throws ArithmeticException {
- BigInteger d = BigInteger.ZERO;
- /* row size */
- final int rL = A.length;
- if (rL == 0) {
- throw new ArithmeticException("zero row count in matrix");
- }
- /* column size */
- final int cL = A[0].length;
- if (cL != rL) {
- throw new ArithmeticException("Non-square matrix dim " + rL + " by " + cL);
- }
-
- /*
- * Compute the low-order cases directly.
- */
- if (rL == 1) {
- return A[0][0];
- } else if (rL == 2) {
- d = A[0][0].multiply(A[1][1]);
- return d.subtract(A[0][1].multiply(A[1][0]));
- } else {
- /* Work arbitrarily along the first column of the matrix */
- for (int r = 0; r < rL; r++) {
- /*
- * Do not consider minors that do no contribute anyway
- */
- if (A[r][0].compareTo(BigInteger.ZERO) != 0) {
- final BigInteger M[][] = BigIntegerMath.minor(A, r, 0);
- final BigInteger m = A[r][0].multiply(BigIntegerMath.det(M));
- /* recursive call */
- if (r % 2 == 0) {
- d = d.add(m);
- } else {
- d = d.subtract(m);
- }
- }
- }
- }
- return d;
- }
-
- /**
- * Solve a linear system of equations.
- *
- * @param A
- * The square matrix.
- * If it is not of full rank, an ArithmeticException is thrown.
- * @param rhs
- * The right hand side. The length of this vector must match the
- * matrix size;
- * else an ArithmeticException is thrown.
- * @return The vector of x in A*x=rhs.
- * @since 2010-08-28
- * @author Richard J. Mathar
- * @throws Error
- */
- static public Rational[] solve(final BigInteger[][] A, final BigInteger[] rhs) throws ArithmeticException, Error {
-
- final int rL = A.length;
- if (rL == 0) {
- throw new ArithmeticException("zero row count in matrix");
- }
-
- /* column size */
- final int cL = A[0].length;
- if (cL != rL) {
- throw new ArithmeticException("Non-square matrix dim " + rL + " by " + cL);
- }
- if (rhs.length != rL) {
- throw new ArithmeticException("Right hand side dim " + rhs.length + " unequal matrix dim " + rL);
- }
-
- /*
- * Gauss elimination
- */
- final Rational x[] = new Rational[rL];
-
- /*
- * copy of r.h.s ito a mutable Rationalright hand side
- */
- 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
- * row r.
- */
- for (int c = 0; c < cL - 1; c++) {
- /*
- * zero on the diagonal? swap with a non-zero row, searched with
- * index r
- */
- if (A[c][c].compareTo(BigInteger.ZERO) == 0) {
- boolean swpd = false;
- for (int r = c + 1; r < rL; r++) {
- if (A[r][c].compareTo(BigInteger.ZERO) != 0) {
- for (int cpr = c; cpr < cL; cpr++) {
- final BigInteger tmp = A[c][cpr];
- A[c][cpr] = A[r][cpr];
- A[r][cpr] = tmp;
- }
- final Rational tmp = x[c];
- x[c] = x[r];
- x[r] = tmp;
- swpd = true;
- break;
- }
- }
- /*
- * not swapped with a non-zero row: determinant zero and no
- * solution
- */
- 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++) {
- /*
- * skip the cpr=c which actually sets the zero: this element is
- * not visited again
- */
- for (int cpr = c + 1; cpr < cL; cpr++) {
- final BigInteger tmp = A[c][c].multiply(A[r][cpr]).subtract(A[c][cpr].multiply(A[r][c]));
- A[r][cpr] = tmp;
- }
- 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) {
- 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--) {
- x[rpr] = x[rpr].subtract(x[r].multiply(A[rpr][r]));
- }
- }
-
- return x;
- }
-
- /**
- * The lowest common multiple
- *
- * @param a
- * The first argument
- * @param b
- * The second argument
- * @return lcm(|a|,|b|)
- * @since 2010-08-27
- * @author Richard J. Mathar
- */
- static public BigInteger lcm(final BigInteger a, final BigInteger b) {
- final BigInteger g = a.gcd(b);
- return a.multiply(b).abs().divide(g);
- }
-
- /**
- * Evaluate the value of an integer polynomial at some integer argument.
- *
- * @param c
- * Represents the coefficients c[0]+c[1]*x+c[2]*x^2+.. of the
- * polynomial
- * @param x
- * The abscissa point of the evaluation
- * @return The polynomial value.
- * @since 2010-08-27
- * @author Richard J. Mathar
- */
- static public BigInteger valueOf(final Vector c, final BigInteger x) {
- if (c.size() == 0) {
- return BigInteger.ZERO;
- }
- BigInteger res = c.lastElement();
- for (int i = c.size() - 2; i >= 0; i--) {
- res = res.multiply(x).add(c.elementAt(i));
- }
- return res;
- }
-
- /**
- * The central factorial number t(n,k) number at the indices provided.
- *
- * @param n
- * the first parameter, non-negative.
- * @param k
- * the second index, non-negative.
- * @return t(n,k)
- * @since 2009-08-06
- * @author Richard J. Mathar
- * @throws Error
- * @see P. L. Butzer
- * et al, Num. Funct. Anal. Opt. 10 (5)( 1989) 419-488
- */
- static public Rational centrlFactNumt(final int n, final int k) throws Error {
- if (k > n || k < 0 || k % 2 != n % 2) {
- return Rational.ZERO;
- } else if (k == n) {
- return Rational.ONE;
- } else {
- /* Proposition 6.2.6 */
- final Factorial f = new Factorial();
- Rational jsum = new Rational(0, 1);
- 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(BigIntegerMath.binomial(j, nu));
- if (nu % 2 != 0) {
- nusum = nusum.subtract(t);
- } else {
- nusum = nusum.add(t);
- }
- }
- nusum = nusum.divide(f.at(j)).divide(n + j);
- nusum = nusum.multiply(BigIntegerMath.binomial(2 * kprime, kprime - j));
- if (j % 2 != 0) {
- jsum = jsum.subtract(nusum);
- } else {
- jsum = jsum.add(nusum);
- }
- }
- return jsum.multiply(k).multiply(BigIntegerMath.binomial(n + kprime, k));
- }
- } /* CentralFactNumt */
-
- /**
- * The central factorial number T(n,k) number at the indices provided.
- *
- * @param n
- * the first parameter, non-negative.
- * @param k
- * the second index, non-negative.
- * @return T(n,k)
- * @since 2009-08-06
- * @author Richard J. Mathar
- * @see P. L. Butzer
- * et al, Num. Funct. Anal. Opt. 10 (5)( 1989) 419-488
- */
- static public Rational centrlFactNumT(final int n, final int k) {
- if (k > n || k < 0 || k % 2 != n % 2) {
- return Rational.ZERO;
- } else if (k == n) {
- return Rational.ONE;
- } else {
- /* Proposition 2.1 */
- return BigIntegerMath.centrlFactNumT(n - 2, k - 2).add(BigIntegerMath.centrlFactNumT(n - 2, k).multiply(new Rational(k * k, 4)));
- }
- } /* CentralFactNumT */
-
-} /* BigIntegerMath */
diff --git a/core/src/main/java/org/nevec/rjm/BigIntegerPoly.java b/core/src/main/java/org/nevec/rjm/BigIntegerPoly.java
deleted file mode 100644
index 0818c02e..00000000
--- a/core/src/main/java/org/nevec/rjm/BigIntegerPoly.java
+++ /dev/null
@@ -1,764 +0,0 @@
-package org.nevec.rjm;
-
-import java.math.BigDecimal;
-import java.math.BigInteger;
-import java.util.Scanner;
-import java.util.Vector;
-
-import it.cavallium.warppi.util.Error;
-
-/**
- * Polynomial with integer coefficients.
- * Alternatively to be interpreted as a sequence which has the polynomial as an
- * (approximate)
- * generating function.
- *
- * @since 2010-08-27
- * @author Richard J. Mathar
- */
-public class BigIntegerPoly implements Cloneable {
- /**
- * The list of all coefficients, starting with a0, then a1, as in
- * poly=a0+a1*x+a2*x^2+a3*x^3+...
- */
- Vector a;
-
- /**
- * Default ctor.
- * Creates the polynomial p(x)=0.
- */
- public BigIntegerPoly() {
- a = new Vector<>();
- }
-
- /**
- * Ctor with a comma-separated list as the list of coefficients.
- *
- * @param L
- * the string of the form a0,a1,a2,a3 with the coefficients
- */
- public BigIntegerPoly(final String L) throws NumberFormatException {
- a = new Vector<>();
- final Scanner sc = new Scanner(L);
- sc.useDelimiter(",");
- while (sc.hasNextBigInteger()) {
- a.add(sc.nextBigInteger());
- }
- simplify();
- sc.close();
- } /* ctor */
-
- /**
- * Ctor with a list of coefficients.
- *
- * @param c
- * The coefficients a0, a1, a2 etc in a0+a1*x+a2*x^2+...
- */
- @SuppressWarnings("unchecked")
- public BigIntegerPoly(final Vector c) {
- a = (Vector) c.clone();
- simplify();
- } /* ctor */
-
- /**
- * Ctor with a list of coefficients.
- *
- * @param c
- * The coefficients a0, a1, a2 etc in a0+a1*x+a2*x^2+...
- */
- public BigIntegerPoly(final BigInteger[] c) {
- for (final BigInteger element : c) {
- a.add(element.add(BigInteger.ZERO));
- }
- simplify();
- } /* ctor */
-
- /**
- * Create a copy of this.
- *
- * @since 2010-08-27
- */
- @Override
- public BigIntegerPoly clone() {
- return new BigIntegerPoly(a);
- } /* clone */
-
- /**
- * Translate into a RatPoly copy.
- *
- * @since 2012-03-02
- */
- public RatPoly toRatPoly() {
- final RatPoly bd = new RatPoly();
- for (int i = 0; i < a.size(); i++) {
- bd.set(i, a.elementAt(i));
- }
- return bd;
- } /* toRatPoly */
-
- /**
- * Retrieve a polynomial coefficient.
- *
- * @param n
- * the zero-based index of the coefficient. n=0 for the constant
- * term.
- * @return the polynomial coefficient in front of x^n.
- */
- public BigInteger at(final int n) {
- if (n < a.size()) {
- return a.elementAt(n);
- } else {
- return BigInteger.ZERO;
- }
- } /* at */
-
- /**
- * Evaluate at some integer argument.
- *
- * @param x
- * The abscissa point of the evaluation
- * @return The polynomial value.
- * @since 2010-08-27
- * @author Richard J. Mathar
- */
- public BigInteger valueOf(final BigInteger x) {
- if (a.size() == 0) {
- return BigInteger.ZERO;
- }
- BigInteger res = a.lastElement();
- /*
- * Heron casted form
- */
- for (int i = a.size() - 2; i >= 0; i--) {
- res = res.multiply(x).add(a.elementAt(i));
- }
- return res;
- } /* valueOf */
-
- /**
- * Horner scheme to find the function value at the argument x
- *
- * @param x
- * The argument x.
- * @return Value of the polynomial at x.
- * @since 2008-11-13
- */
- public BigInteger valueOf(final int x) {
- return valueOf(new BigInteger("" + x));
- } /* valueOf */
-
- /**
- * Set a polynomial coefficient.
- *
- * @param n
- * the zero-based index of the coefficient. n=0 for the constant
- * term.
- * If the polynomial has not yet the degree to need this
- * coefficient,
- * the intermediate coefficients are set to zero.
- * @param value
- * the new value of the coefficient.
- */
- public void set(final int n, final BigInteger value) {
- if (n < a.size()) {
- a.set(n, value);
- } else {
- /*
- * fill intermediate powers with coefficients of zero
- */
- while (a.size() < n) {
- a.add(BigInteger.ZERO);
- }
- a.add(value);
- }
- } /* set */
-
- /**
- * Set a polynomial coefficient.
- *
- * @param n
- * the zero-based index of the coefficient. n=0 for the constant
- * term.
- * If the polynomial has not yet the degree to need this
- * coefficient,
- * the intermediate coefficients are implicitly set to zero.
- * @param value
- * the new value of the coefficient.
- */
- public void set(final int n, final int value) {
- final BigInteger val2 = new BigInteger("" + value);
- set(n, val2);
- } /* set */
-
- /**
- * Count of coefficients.
- *
- * @return the number of polynomial coefficients.
- * Differs from the polynomial degree by one.
- */
- public int size() {
- return a.size();
- } /* size */
-
- /**
- * Polynomial degree.
- *
- * @return the polynomial degree.
- */
- public int degree() {
- return a.size() - 1;
- } /* degree */
-
- /**
- * Polynomial lower degree.
- *
- * @return power of the smallest non-zero coefficient.
- * 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) {
- return n;
- }
- }
- return 0;
- } /* ldegree */
-
- /**
- * Multiply by a constant factor.
- *
- * @param val
- * the factor
- * @return the product of this with the factor.
- * All coefficients of this have been multiplied individually by the
- * factor.
- * @since 2010-08-27
- */
- public BigIntegerPoly multiply(final BigInteger val) {
- 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 */
-
- /**
- * Multiply by another polynomial
- *
- * @param val
- * the other polynomial
- * @return the product of this with the other polynomial
- */
- public BigIntegerPoly multiply(final BigIntegerPoly val) {
- 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++) {
- coef = coef.add(at(nleft).multiply(val.at(n - nleft)));
- }
- resul.set(n, coef);
- }
- resul.simplify();
- return resul;
- } /* multiply */
-
- /**
- * Raise to a positive power.
- *
- * @param n
- * the exponent of the power
- * @return the n-th power of this.
- */
- public BigIntegerPoly pow(final int n) throws ArithmeticException {
- BigIntegerPoly resul = new BigIntegerPoly("1");
- if (n < 0) {
- throw new ArithmeticException("negative polynomial power " + n);
- } else {
- for (int i = 1; i <= n; i++) {
- resul = resul.multiply(this);
- }
- resul.simplify();
- return resul;
- }
- } /* pow */
-
- /**
- * Add another polynomial
- *
- * @param val
- * the other polynomial
- * @return the sum of this with the other polynomial
- * @since 2010-08-27
- */
- public BigIntegerPoly add(final BigIntegerPoly val) {
- 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++) {
- final BigInteger coef = at(n).add(val.at(n));
- resul.set(n, coef);
- }
- resul.simplify();
- return resul;
- } /* add */
-
- /**
- * Subtract another polynomial
- *
- * @param val
- * the other polynomial
- * @return the difference between this and the other polynomial
- * @since 2008-10-25
- */
- public BigIntegerPoly subtract(final BigIntegerPoly val) {
- 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++) {
- final BigInteger coef = at(n).subtract(val.at(n));
- resul.set(n, coef);
- }
- resul.simplify();
- return resul;
- } /* subtract */
-
- /**
- * Divide by another polynomial.
- *
- * @param val
- * the other polynomial
- * @return A vector with [0] containg the polynomial of degree which is the
- * difference of the degree of this and the degree of val. [1] the
- * remainder polynomial.
- * This = returnvalue[0] + returnvalue[1]/val .
- * @since 2012-03-01
- */
- public BigIntegerPoly[] divideAndRemainder(final BigIntegerPoly val) {
- final BigIntegerPoly[] ret = new BigIntegerPoly[2];
- /*
- * remove any high-order zeros. note that the clone() operation calls
- * simplify().
- */
- 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) {
- throw new ArithmeticException("Division through zero polynomial");
- }
- /*
- * degree of this smaller than degree of val: remainder is this
- */
- if (thisSimpl.degree() < valSimpl.degree()) {
- /*
- * leading polynomial equals zero
- */
- ret[0] = new BigIntegerPoly();
- ret[1] = thisSimpl;
- } else {
- /*
- * long division. Highest degree by dividing the highest degree
- * of this thru val. At this point an exception is thrown if the
- * polynomial division cannot be done with integer coefficients.
- */
- ret[0] = new BigIntegerPoly();
- 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]);
-
- /*
- * recurrences: build this - val*(1-termresult) and feed this
- * into another round of division. Have intermediate
- * ret[0]+ret[1]/val.
- */
- ret[1] = thisSimpl.subtract(ret[0].multiply(valSimpl));
-
- /*
- * any remainder left ?
- */
- if (ret[1].degree() < valSimpl.degree()) {
- ;
- } else {
- final BigIntegerPoly rem[] = ret[1].divideAndRemainder(val);
- ret[0] = ret[0].add(rem[0]);
- ret[1] = rem[1];
- }
- }
- return ret;
- } /* divideAndRemainder */
-
- /**
- * Print as a comma-separated list of coefficients.
- *
- * @return the representation a0,a1,a2,a3,...
- * @since 2010-08-27
- */
- @Override
- public String toString() {
- String str = new String();
- for (int n = 0; n < a.size(); n++) {
- if (n == 0) {
- str += a.elementAt(n).toString();
- } else {
- str += "," + a.elementAt(n).toString();
- }
- }
- if (str.length() == 0) {
- str = "0";
- }
- return str;
- } /* toString */
-
- /**
- * Print as a polyomial in x.
- *
- * @return The representation a0+a1*x+a2*x^2+...
- * The terms with zero coefficients are not mentioned.
- * @since 2008-10-26
- */
- public String toPString() {
- String str = new String();
- for (int n = 0; n < a.size(); n++) {
- final BigInteger num = a.elementAt(n);
- if (num.compareTo(BigInteger.ZERO) != 0) {
- str += " ";
- if (num.compareTo(BigInteger.ZERO) > 0 && n > 0) {
- str += "+";
- }
- str += a.elementAt(n).toString();
- if (n > 0) {
- str += "*x";
- if (n > 1) {
- str += "^" + n;
- }
- }
- }
- }
- if (str.length() == 0) {
- str = "0";
- }
- return str;
- } /* toPString */
-
- /**
- * Simplify the representation.
- * Trailing values with zero coefficients (at high powers) are deleted.
- */
- protected void simplify() {
- int n = a.size() - 1;
- if (n >= 0) {
- while (a.elementAt(n).compareTo(BigInteger.ZERO) == 0) {
- a.removeElementAt(n);
- if (--n < 0) {
- break;
- }
- }
- }
- } /* simplify */
-
- /**
- * First derivative.
- *
- * @return The first derivative with respect to the indeterminate variable.
- * @since 2008-10-26
- */
- public BigIntegerPoly derive() {
- if (a.size() <= 1) {
- /*
- * derivative of the constant is just zero
- */
- return new BigIntegerPoly();
- } else {
- 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);
- }
- return d;
- }
- } /* derive */
-
- /**
- * Truncate polynomial degree.
- *
- * @return The polynomial with all coefficients beyond deg set to zero.
- * @since 2010-08-27
- */
- public BigIntegerPoly trunc(final int newdeg) {
- final BigIntegerPoly t = new BigIntegerPoly();
- for (int i = 0; i <= newdeg; i++) {
- t.set(i, at(i));
- }
- t.simplify();
- return t;
- } /* trunc */
-
- /**
- * Inverse Binomial transform.
- *
- * @param maxdeg
- * the maximum polynomial degree of the result
- * @return the sequence of coefficients is the inverse binomial transform of
- * the original sequence.
- * @since 2010-08-29
- */
- public BigIntegerPoly binomialTInv(final int maxdeg) {
- 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) {
- c = c.subtract(a.elementAt(j).multiply(BigIntegerMath.binomial(i, j)));
- } else {
- c = c.add(a.elementAt(j).multiply(BigIntegerMath.binomial(i, j)));
- }
- }
- r.set(i, c);
- }
- r.simplify();
- return r;
- } /* binomialTInv */
-
- /**
- * Compute the order of the root r.
- *
- * @return 1 for simple roots, 2 for order 2 etc., 0 if not a root
- * @since 2010-08-27
- */
- public int rootDeg(final BigInteger r) {
- int o = 0;
- BigIntegerPoly d = clone();
- BigInteger roo = d.valueOf(r);
- while (roo.compareTo(BigInteger.ZERO) == 0) {
- o++;
- d = d.derive();
- roo = d.valueOf(r);
- }
- return o;
- } /* rootDeg */
-
- /**
- * Generate the integer roots of the polynomial.
- *
- * @return The vector of integer roots, without their multiplicity.
- * @since 2010-08-27
- */
- public Vector iroots() {
- /* The vector of the roots */
- final Vector res = new Vector<>();
-
- /*
- * collect the zero
- */
- if (a.firstElement().compareTo(BigInteger.ZERO) == 0) {
- res.add(BigInteger.ZERO);
- }
-
- /*
- * collect the divisors of the constant element (or the reduced
- * polynomial)
- */
- final int l = ldegree();
- if (a.elementAt(l).compareTo(BigInteger.ZERO) != 0) {
- @SuppressWarnings("deprecation")
- 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) {
- /* found a root cand[i] */
- res.add(cand.elementAt(i));
- }
- roo = valueOf(cand.elementAt(i).negate());
- if (roo.compareTo(BigInteger.ZERO) == 0) {
- res.add(cand.elementAt(i).negate());
- }
- }
- }
- return res;
- } /* iroots */
-
- /**
- * Generate the factors which are 2nd degree polynomials.
- *
- * @return A (potentially empty) vector of factors, without multiplicity.
- * Only factors with non-zero absolute coefficient are generated.
- * This means the factors are of the form x^2+a*x+b=0 with nonzero
- * b.
- * @throws Error
- * @since 2012-03-01
- */
- protected Vector i2roots() throws Error {
- /*
- * The vector of the factors to be returned
- */
- final Vector res = new Vector<>();
-
- if (degree() < 2) {
- return res;
- }
-
- final BigInteger bsco = a.firstElement().abs();
- @SuppressWarnings("deprecation")
- final Vector b = BigIntegerMath.divisors(bsco);
- final BigInteger csco = a.lastElement().abs();
- @SuppressWarnings("deprecation")
- final Vector c = BigIntegerMath.divisors(csco);
-
- /*
- * Generate the floating point values of roots. To have some reasonable
- * accuracy in the results, add zeros to the integer coefficients,
- * scaled
- * by the expected division with values of b (which are all <=
- * a.firstele).
- * Number of decimal digits in bsco by using a log2->log10 rough
- * estimate
- * and adding 6 safety digits
- */
- final RatPoly thisDec = toRatPoly();
- final Vector roo = thisDec.roots(6 + (int) (0.3 * bsco.bitCount()));
-
- final BigDecimal half = new BigDecimal("0.5");
-
- /*
- * for each of the roots z try to see whether c*z^2+a*z+b=0 with integer
- * a, b and c
- * where b is restricted to a signed divisor of the constant
- * coefficient.
- * Solve z*(c*z+a)=-b or c*z+a = -b/z or -b/z-c*z = some integer a.
- */
- 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
- * this
- * case is already covered by using iroots().
- */
- if (bco.signum() != 0) {
- for (int sig = -1; sig <= 1; sig += 2) {
- 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)
- */
- BigDecimal negA = BigDecimalMath.add(BigDecimalMath.divideRound(bcosig, z.norm()), cco);
- negA = negA.multiply(z.re);
- /*
- * convert to a with round-to-nearest
- */
- final BigInteger a = negA.negate().add(half).toBigInteger();
-
- /*
- * test the polynomial remainder. if zero, add the
- * term
- * to the results.
- */
- final BigIntegerPoly dtst = new BigIntegerPoly("" + bcosig + "," + a + "," + cco);
- try {
- final BigIntegerPoly[] rm = divideAndRemainder(dtst);
- if (rm[1].isZero()) {
- res.add(dtst);
- }
- } catch (final ArithmeticException ex) {}
- }
- }
- }
- }
- }
-
- return res;
- } /* i2roots */
-
- /**
- * Test whether this polynomial value is zero.
- *
- * @return If this is a polynomial p(x)=0 for all x.
- */
- public boolean isZero() {
- simplify();
- return a.size() == 0;
- }
-
- /**
- * Factorization into integer polynomials.
- * The current factorization detects only factors which are polynomials of
- * order up to 2.
- *
- * @return The vector of factors. Factors with higher multiplicity are
- * represented by repetition.
- * @throws Error
- * @since 2012-03-01
- */
- public Vector ifactor() throws Error {
- /*
- * this ought be entirely rewritten in terms of the LLL algorithm
- */
- final Vector fac = new Vector<>();
-
- /* collect integer roots (polynomial factors of degree 1) */
- final Vector r = iroots();
- BigIntegerPoly[] res = new BigIntegerPoly[2];
- res[0] = this;
- for (final BigInteger i : r) {
- final int deg = rootDeg(i);
- /* construct the factor x-i */
- final BigIntegerPoly f = new BigIntegerPoly("" + i.negate() + ",1");
- for (int mu = 0; mu < deg; mu++) {
- fac.add(f);
- res = res[0].divideAndRemainder(f);
- }
- }
-
- /*
- * collect factors which are polynomials of degree 2
- */
- 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 {
- final BigIntegerPoly[] dtst = res[0].divideAndRemainder(i);
- if (dtst[1].isZero()) {
- fac.add(i);
- res = dtst;
- } else {
- break;
- }
- } catch (final ArithmeticException ex) {
- break;
- }
- }
- }
-
- /*
- * add remaining factor, if not equal to 1
- */
- if (res[0].degree() > 0 || res[0].a.firstElement().compareTo(BigInteger.ONE) != 0) {
- fac.add(res[0]);
- }
- return fac;
- } /* ifactor */
-
-} /* BigIntegerPoly */
diff --git a/core/src/main/java/org/nevec/rjm/BigSurd.java b/core/src/main/java/org/nevec/rjm/BigSurd.java
deleted file mode 100644
index 7e60fa57..00000000
--- a/core/src/main/java/org/nevec/rjm/BigSurd.java
+++ /dev/null
@@ -1,567 +0,0 @@
-package org.nevec.rjm;
-
-import java.math.BigDecimal;
-import java.math.BigInteger;
-import java.math.MathContext;
-import java.security.ProviderException;
-
-import it.cavallium.warppi.util.Error;
-import it.cavallium.warppi.util.Utils;
-
-/**
- * Square roots on the real line.
- * These represent numbers which are a product of a (signed) fraction by
- * a square root of a non-negative fraction.
- * This might be extended to values on the imaginary axis by allowing negative
- * values underneath the square root, but this is not yet implemented.
- *
- * @since 2011-02-12
- * @author Richard J. Mathar
- */
-public class BigSurd implements Cloneable, Comparable {
- /**
- * The value of zero.
- */
- static public BigSurd ZERO = new BigSurd();
-
- /**
- * The value of one.
- */
- static public BigSurd ONE = new BigSurd(Rational.ONE, Rational.ONE);
- /**
- * Prefactor
- */
- Rational pref;
-
- /**
- * The number underneath the square root, always non-negative.
- * The mathematical object has the value pref*sqrt(disc).
- */
- Rational disc;
-
- /**
- * Default ctor, which represents the zero.
- *
- * @since 2011-02-12
- */
- public BigSurd() {
- pref = Rational.ZERO;
- disc = Rational.ZERO;
- }
-
- /**
- * ctor given the prefactor and the basis of the root.
- * This creates an object of value a*sqrt(b).
- *
- * @param a
- * the prefactor.
- * @param b
- * the discriminant.
- * @since 2011-02-12
- */
- public BigSurd(final Rational a, final Rational b) {
- pref = a;
- /*
- * reject attempts to use a negative b
- */
- if (b.signum() < 0) {
- throw new ProviderException("Not implemented: imaginary surds");
- }
- disc = b;
- try {
- normalize();
- normalizeG();
- } catch (final Error e) {
- e.printStackTrace();
- }
- }
-
- /**
- * ctor given the numerator and denominator of the root.
- * This creates an object of value sqrt(a/b).
- *
- * @param a
- * the numerator
- * @param b
- * the denominator.
- * @since 2011-02-12
- */
- public BigSurd(final int a, final int b) {
- this(Rational.ONE, new Rational(a, b));
- }
-
- /**
- * ctor given the value under the root.
- * This creates an object of value sqrt(a).
- *
- * @param a
- * the discriminant.
- * @since 2011-02-12
- */
- public BigSurd(final BigInteger a) {
- this(Rational.ONE, new Rational(a, BigInteger.ONE));
- }
-
- public BigSurd(final Rational a) {
- this(Rational.ONE, a);
- }
-
- /**
- * Create a deep copy.
- *
- * @since 2011-02-12
- */
- @Override
- public BigSurd clone() {
- final Rational fclon = pref.clone();
- final Rational dclon = disc.clone();
- /*
- * the main intent here is to bypass any attempt to reduce the
- * discriminant
- * by figuring out the square-free part in normalize(), which has
- * already done
- * in the current copy of the number.
- */
- final BigSurd cl = new BigSurd();
- cl.pref = fclon;
- cl.disc = dclon;
- return cl;
- } /* BigSurd.clone */
-
- /**
- * Add two surds of compatible discriminant.
- *
- * @param val
- * The value to be added to this.
- */
-
- public BigSurdVec add(final BigSurd val) {
- // zero plus somethings yields something
- if (signum() == 0) {
- return new BigSurdVec(val);
- } else if (val.signum() == 0) {
- return new BigSurdVec(this);
- } else {
- // let the ctor of BigSurdVec to the work
- return new BigSurdVec(this, val);
- }
- } /* BigSurd.add */
-
- /**
- * Multiply by another square root.
- *
- * @param val
- * a second number of this type.
- * @return the product of this with the val.
- * @since 2011-02-12
- */
- public BigSurd multiply(final BigSurd val) {
- return new BigSurd(pref.multiply(val.pref), disc.multiply(val.disc));
- } /* BigSurd.multiply */
-
- /**
- * Multiply by a rational number.
- *
- * @param val
- * the factor.
- * @return the product of this with the val.
- * @since 2011-02-15
- */
- public BigSurd multiply(final Rational val) {
- return new BigSurd(pref.multiply(val), disc);
- } /* BigSurd.multiply */
-
- /**
- * Multiply by a BigInteger.
- *
- * @param val
- * a second number.
- * @return the product of this with the value.
- * @since 2011-02-12
- */
- public BigSurd multiply(final BigInteger val) {
- return new BigSurd(pref.multiply(val), disc);
- } /* BigSurd.multiply */
-
- /**
- * Multiply by an integer.
- *
- * @param val
- * a second number.
- * @return the product of this with the value.
- * @since 2011-02-12
- */
- public BigSurd multiply(final int val) {
- final BigInteger tmp = new BigInteger("" + val);
- return multiply(tmp);
- } /* BigSurd.multiply */
-
- /**
- * Compute the square.
- *
- * @return this value squared.
- * @since 2011-02-12
- */
- public Rational sqr() {
- Rational res = pref.pow(2);
- res = res.multiply(disc);
- return res;
- } /* BigSurd.sqr */
-
- /**
- * Divide by another square root.
- *
- * @param val
- * A second number of this type.
- * @return The value of this/val
- * @throws Error
- * @since 2011-02-12
- */
- public BigSurd divide(final BigSurd val) throws Error {
- 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() {
- final BigSurd bs = this;
- final BigInteger denominator = pref.b;
- String s = "";
- if (denominator.compareTo(BigInteger.ONE) != 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 {
- final BigInteger numerator = bs.pref.a;
- if (numerator.compareTo(BigInteger.ONE) != 0) {
- s += numerator.toString();
- s += "*";
- s += "(";
- }
- s += "2√";
- if (bs.disc.isInteger()) {
- s += bs.disc.toString();
- } else {
- s += "(" + bs.disc.toString() + ")";
- }
- if (numerator.compareTo(BigInteger.ONE) != 0) {
- s += ")";
- }
- }
- return s;
- }
-
- /**
- * Divide by an integer.
- *
- * @param val
- * a second number.
- * @return the value of this/val
- * @throws Error
- * @since 2011-02-12
- */
- public BigSurd divide(final BigInteger val) throws Error {
- if (val.signum() == 0) {
- throw new ArithmeticException("Dividing " + toFancyString() + " through zero.");
- }
- return new BigSurd(pref.divide(val), disc);
- } /* BigSurd.divide */
-
- /**
- * Divide by an integer.
- *
- * @param val
- * A second number.
- * @return The value of this/val
- * @throws Error
- * @since 2011-02-12
- */
- public BigSurd divide(final int val) throws Error {
- if (val == 0) {
- throw new ArithmeticException("Dividing " + toFancyString() + " through zero.");
- }
- return new BigSurd(pref.divide(val), disc);
- } /* BigSurd.divide */
-
- /**
- * Compute the negative.
- *
- * @return -this.
- * @since 2011-02-12
- */
- public BigSurd negate() {
- /*
- * This is trying to be quick, avoiding normalize(), by toggling
- * the sign in a clone()
- */
- final BigSurd n = clone();
- n.pref = n.pref.negate();
- return n;
- } /* BigSurd.negate */
-
- /**
- * Absolute value.
- *
- * @return The absolute (non-negative) value of this.
- * @since 2011-02-12
- */
- public BigSurd abs() {
- return new BigSurd(pref.abs(), disc);
- }
-
- /**
- * Compares the value of this with another constant.
- *
- * @param val
- * the other constant to compare with
- * @return -1, 0 or 1 if this number is numerically less than, equal to,
- * or greater than val.
- * @since 2011-02-12
- */
- @Override
- public int compareTo(final BigSurd val) {
- /*
- * Since we keep the discriminant positive, the rough estimate
- * comes from comparing the signs of the prefactors.
- */
- final int sig = signum();
- final int sigv = val.signum();
- if (sig < 0 && sigv >= 0) {
- return -1;
- }
- if (sig > 0 && sigv <= 0) {
- return 1;
- }
- if (sig == 0 && sigv == 0) {
- return 0;
- }
- if (sig == 0 && sigv > 0) {
- return -1;
- }
- if (sig == 0 && sigv < 0) {
- return 1;
- }
-
- /*
- * Work out the cases of equal sign. Compare absolute values by
- * comparison
- * of the squares which is forwarded to the comparison of the Rational
- * class.
- */
- final Rational this2 = sqr();
- final Rational val2 = val.sqr();
- final int c = this2.compareTo(val2);
- if (c == 0) {
- return 0;
- } else if (sig > 0 && c > 0 || sig < 0 && c < 0) {
- return 1;
- } else {
- return -1;
- }
- } /* BigSurd.compareTo */
-
- /**
- * Return a string in the format (number/denom)*()^(1/2).
- * If the discriminant equals 1, print just the prefactor.
- *
- * @return the human-readable version in base 10
- * @since 2011-02-12
- */
- @Override
- public String toString() {
- if (disc.compareTo(Rational.ONE) != 0 && disc.compareTo(Rational.ZERO) != 0) {
- return "(" + pref.toString() + ")*(" + disc.toString() + ")^(1/2)";
- } else {
- return pref.toString();
- }
- } /* BigSurd.toString */
-
- /**
- * Return a double value representation.
- *
- * @return The value with double precision.
- * @since 2011-02-12
- */
- public double doubleValue() {
- /*
- * First compute the square to prevent overflows if the two pieces of
- * the prefactor and the discriminant are of very different magnitude.
- */
- final Rational p2 = pref.pow(2).multiply(disc);
- System.out.println("dv sq " + p2.toString());
- final double res = p2.doubleValue();
- System.out.println("dv sq " + res);
- return pref.signum() >= 0 ? Math.sqrt(res) : -Math.sqrt(res);
- } /* BigSurd.doubleValue */
-
- /**
- * Return a float value representation.
- *
- * @return The value with single precision.
- * @since 2011-02-12
- */
- public float floatValue() {
- return (float) doubleValue();
- } /* BigSurd.floatValue */
-
- /**
- * True if the value is integer.
- * Equivalent to the indication whether a conversion to an integer
- * can be exact.
- *
- * @since 2011-02-12
- */
- public boolean isBigInteger() {
- return pref.isBigInteger() && (disc.signum() == 0 || disc.compareTo(Rational.ONE) == 0);
- } /* BigSurd.isBigInteger */
-
- /**
- * True if the value is rational.
- * Equivalent to the indication whether a conversion to a Rational can be
- * exact.
- *
- * @since 2011-02-12
- */
- public boolean isRational() {
- return disc.signum() == 0 || disc.compareTo(Rational.ONE) == 0;
- } /* BigSurd.isRational */
-
- /**
- * Convert to a rational value if possible
- *
- * @since 2012-02-15
- */
- public Rational toRational() {
- if (isRational()) {
- return pref;
- } else {
- throw new ArithmeticException("Undefined conversion " + toFancyString() + " to Rational.");
- }
- } /* BigSurd.toRational */
-
- /**
- * The sign: 1 if the number is >0, 0 if ==0, -1 if <0
- *
- * @return the signum of the value.
- * @since 2011-02-12
- */
- public int signum() {
- /*
- * Since the disc is kept positive, this is the same
- * as the sign of the prefactor. This works because a zero discriminant
- * is always copied over to the prefactor, not hidden.
- */
- return pref.signum();
- } /* BigSurd.signum */
-
- /**
- * Normalize to squarefree discriminant.
- *
- * @throws Error
- * @since 2011-02-12
- */
- protected void normalize() throws Error {
- /*
- * Move squares out of the numerator and denominator of the discriminant
- */
- if (disc.signum() != 0) {
- /*
- * square-free part of the numerator: numer = numC*some^2
- */
- final BigInteger numC = BigIntegerMath.core(disc.numer());
- /*
- * extract the perfect square of the numerator
- */
- BigInteger sq = disc.numer().divide(numC);
- /*
- * extract the associated square root
- */
- BigInteger sqf = BigIntegerMath.isqrt(sq);
-
- /*
- * move sqf over to the pre-factor
- */
- pref = pref.multiply(sqf);
-
- 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 {
- pref = Rational.ZERO;
- }
- } /* BigSurd.normalize */
-
- /**
- * Normalize to coprime numerator and denominator in prefactor and
- * discriminant
- *
- * @throws Error
- * @since 2011-02-12
- */
- protected void normalizeG() throws Error {
- /*
- * Is there a common factor between the numerator of the prefactor
- * and the denominator of the discriminant ?
- */
- BigInteger d = pref.numer().abs().gcd(disc.denom());
- if (d.compareTo(BigInteger.ONE) > 0) {
- pref = pref.divide(d);
- /*
- * instead of multiplying with the square of d, using two steps
- * offers a change to recognize the common factor..
- */
- disc = disc.multiply(d);
- disc = disc.multiply(d);
- }
- /*
- * Is there a common factor between the denominator of the prefactor
- * and the numerator of the discriminant ?
- */
- d = pref.denom().gcd(disc.numer());
- if (d.compareTo(BigInteger.ONE) > 0) {
- pref = pref.multiply(d);
- /*
- * instead of dividing through the square of d, using two steps
- * offers a change to recognize the common factor..
- */
- disc = disc.divide(d);
- disc = disc.divide(d);
- }
- } /* BigSurd.normalizeG */
-
- /**
- * Return the approximate floating point representation.
- *
- * @param mc
- * Description of the accuracy needed.
- * @return A representation with digits valid as described by mc
- * @since 2012-02-15
- */
- public BigDecimal BigDecimalValue(final MathContext mc) {
- /*
- * the relative error of the result equals the relative error of the
- * prefactor plus half of the relative error of the discriminant.
- * So adding 3 digits temporarily is sufficient.
- */
- final MathContext locmc = new MathContext(mc.getPrecision() + 3, mc.getRoundingMode());
- /*
- * first the square root of the discriminant
- */
- 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.
- */
- final BigDecimal res = sqrdis.multiply(pref.BigDecimalValue(mc));
- return BigDecimalMath.scalePrec(res, mc);
- } /* BigDecimalValue */
-
-} /* BigSurd */
diff --git a/core/src/main/java/org/nevec/rjm/BigSurdVec.java b/core/src/main/java/org/nevec/rjm/BigSurdVec.java
deleted file mode 100644
index ff7c7be0..00000000
--- a/core/src/main/java/org/nevec/rjm/BigSurdVec.java
+++ /dev/null
@@ -1,650 +0,0 @@
-package org.nevec.rjm;
-
-import java.math.BigDecimal;
-import java.math.BigInteger;
-import java.math.MathContext;
-import java.util.Vector;
-
-import it.cavallium.warppi.util.Error;
-import it.cavallium.warppi.util.Utils;
-
-/**
- * A BigSurdVec represents an algebraic sum or differences of values which each
- * term an instance of BigSurd. This mainly means that sums or differences of
- * two BigSurd (or two BigSurdVec) can be represented (exactly) as a BigSurdVec.
- *
- * @since 2012-02-15
- * @author Richard J. Mathar
- */
-public class BigSurdVec implements Comparable {
- /**
- * The value of zero.
- */
- static public BigSurdVec ZERO = new BigSurdVec();
-
- /**
- * The value of one.
- */
- static public BigSurdVec ONE = new BigSurdVec(BigSurd.ONE);
-
- /**
- * Internal representation: Each term as a single BigSurd. The value zero is
- * represented by an empty vector.
- */
- Vector terms;
-
- /**
- * Default ctor, which represents the zero.
- *
- * @since 2012-02-15
- */
- public BigSurdVec() {
- terms = new Vector<>();
- } /* ctor */
-
- /**
- * ctor given the value of a BigSurd.
- *
- * @param a
- * The value to be represented by this vector.
- * @since 2012-02-15
- */
- public BigSurdVec(final BigSurd a) {
- terms = new Vector<>(1);
- terms.add(a);
- } /* ctor */
-
- /**
- * ctor given two values, which (when added) represent this number a+b.
- *
- * @param a
- * The value to be represented by the first term of the vector.
- * @param b
- * The value to be represented by the second term of the vector.
- * @since 2012-02-15
- */
- public BigSurdVec(final BigSurd a, final BigSurd b) {
- terms = new Vector<>(2);
- terms.add(a);
- terms.add(b);
- try {
- normalize();
- } catch (final Error e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- } /* ctor */
-
- /**
- * Combine terms that can be written as a single surd. This unites for
- * example the terms sqrt(90) and sqrt(10) to 4*sqrt(10).
- *
- * @throws Error
- *
- * @since 2012-02-15
- */
- protected void normalize() throws Error {
- /*
- * nothing to be done if at most one term
- */
- if (terms.size() <= 1) {
- return;
- }
-
- 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++) {
- final BigSurd todo = terms.elementAt(j);
- boolean merged = false;
- for (int ex = 0; ex < newter.size(); ex++) {
- BigSurd v = newter.elementAt(ex);
- /*
- * try to merge terms[j] and newter[ex]. todo = r * v with r a
- * rational number is needed. Replaces v with v+todo = v*(1+r)
- * if this reduction works.
- */
- final BigSurd r = todo.divide(v);
- if (r.isRational()) {
- /* compute r+1 */
- final Rational newpref = r.toRational().add(1);
- /*
- * eliminate accidental zeros; overwrite with v*(1+r).
- */
- if (newpref.compareTo(Rational.ZERO) == 0) {
- newter.removeElementAt(ex);
- } else {
- v = v.multiply(newpref);
- newter.setElementAt(v, ex);
- }
- merged = true;
- break;
- }
- }
- /*
- * append if none of the existing elements matched
- */
- if (!merged) {
- newter.add(todo);
- }
- }
-
- /* overwrite old version */
- terms = newter;
- } /* normalize */
-
- /**
- * Compare algebraic value with oth. Returns -1, 0 or +1 depending on
- * whether this is smaller, equal to or larger than oth.
- *
- * @param oth
- * The value with which this is to be compared.
- * @return 0 or +-1.
- * @since 2012-02-15
- */
- @Override
- public int compareTo(final BigSurdVec oth) {
- BigSurdVec diff;
- try {
- diff = this.subtract(oth);
- return diff.signum();
- } catch (final Error e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- return 0;
- }
- } /* compareTo */
-
- /**
- * Sign function. Returns -1, 0 or +1 depending on whether this is smaller,
- * equal to or larger than zero.
- *
- * @return 0 or +-1.
- * @throws Error
- * @since 2012-02-15
- */
- public int signum() throws Error {
- /*
- * 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) {
- return 0;
- }
-
- /*
- * if there is one term: forward to the signum function of BigSurd
- */
- 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].
- */
- final int sig0 = terms.elementAt(0).signum();
- int offsig = 1;
- for (; offsig < terms.size(); offsig++) {
- if (terms.elementAt(offsig).signum() != sig0) {
- break;
- }
- }
- 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) {
- return terms.elementAt(0).compareTo(terms.elementAt(1).negate());
- }
-
- /*
- * if there are three terms, move the one with the offending sign to the
- * other side and square both sides (which looses the sign) to remove
- * all but one surds. The difference of the squared sides contains at
- * most two terms, which reduces to the case above. t(0)+t(offbar) <>
- * -t(offs)
- */
- if (terms.size() == 3) {
- BigSurdVec lhs;
- if (offsig == 2) {
- lhs = new BigSurdVec(terms.elementAt(0), terms.elementAt(1));
- } 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
- * code!
- *
- *
- *
- * BigSurd rhs = new BigSurd(terms.elementAt(offsig).sqr(),
- * Rational.ONE);
- *
- *
- *
- */
- if (lhs.compareTo(lhs) > 0) {
- /*
- * dominating sign was t(0)+t(offbar)
- */
- return terms.elementAt(0).signum();
- } else {
- return terms.elementAt(offsig).signum();
- }
- }
-
- /*
- * for a larger number of terms: take a floating point representation
- * with a small but correct number of digits, and resume with the sign
- * of that one.
- */
- return floatValue() > 0. ? 1 : -1;
-
- } /* signum */
-
- /**
- * Construct an approximate floating point representation
- *
- * @param mc
- * The intended accuracy of the result.
- * @return A truncated version with the precision described by mc
- */
- public BigDecimal BigDecimalValue(final MathContext mc) {
- /*
- * simple cases with one term forwarded to the BigSurd class
- */
- if (terms.size() == 0) {
- return BigDecimal.ZERO;
- } else if (terms.size() == 1) {
- return terms.firstElement().BigDecimalValue(mc);
- }
-
- /*
- * To reduce cancellation errors, loop over increasing local precision
- * 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].
- */
- final BigDecimal[] res = new BigDecimal[2];
- res[0] = BigDecimal.ZERO;
- for (int addpr = 1;; addpr += 3) {
- final MathContext locmc = new MathContext(mc.getPrecision() + addpr, mc.getRoundingMode());
- res[1] = BigDecimal.ZERO;
- for (final BigSurd j : terms) {
- res[1] = BigDecimalMath.addRound(res[1], j.BigDecimalValue(locmc));
- }
- if (addpr > 1) {
- 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];
- }
- return BigDecimalMath.scalePrec(res[1], mc);
-
- } /* BigDecimalValue */
-
- /**
- * Construct an approximate floating point representation
- *
- * @return A truncated version with the precision described by mc
- */
- public double doubleValue() {
- final BigDecimal bd = BigDecimalValue(MathContext.DECIMAL128);
- return bd.doubleValue();
- } /* doubleValue */
-
- /**
- * Construct an approximate floating point representation
- *
- * @return A truncated version with the precision described by mc
- */
- public double floatValue() {
- final BigDecimal bd = BigDecimalValue(MathContext.DECIMAL64);
- return bd.floatValue();
- } /* floatValue */
-
- /**
- * Add two vectors algebraically.
- *
- * @param val
- * The value to be added to this.
- * @return The new value representing this+val.
- * @throws Error
- */
- public BigSurdVec add(final BigSurdVec val) throws Error {
- final BigSurdVec sum = new BigSurdVec();
- /*
- * concatenate the vectors and eliminate common overlaps
- */
- for (final BigSurd term : terms) {
- if (term.compareTo(BigSurd.ZERO) != 0) {
- sum.terms.add(term);
- }
- }
- for (final BigSurd term : val.terms) {
- if (term.compareTo(BigSurd.ZERO) != 0) {
- sum.terms.add(term);
- }
- }
- sum.normalize();
- return sum;
- } /* add */
-
- /**
- * Add two vectors algebraically.
- *
- * @param val
- * The value to be added to this.
- * @return The new value representing this+val.
- * @throws Error
- */
- public BigSurdVec add(final BigSurd val) throws Error {
- final BigSurdVec sum = new BigSurdVec();
- /*
- * concatenate the vectors and eliminate common overlaps
- */
- sum.terms.addAll(terms);
- sum.terms.add(val);
- sum.normalize();
- return sum;
- } /* add */
-
- /**
- * Subtract another number.
- *
- * @param val
- * The value to be subtracted from this.
- * @return The new value representing this-val.
- * @throws Error
- */
- public BigSurdVec subtract(final BigSurdVec val) throws Error {
- final BigSurdVec sum = new BigSurdVec();
- /*
- * concatenate the vectors and eliminate common overlaps
- */
- sum.terms.addAll(terms);
- for (final BigSurd s : val.terms) {
- sum.terms.add(s.negate());
- }
- sum.normalize();
- return sum;
- } /* subtract */
-
- /**
- * Subtract another number.
- *
- * @param val
- * The value to be subtracted from this.
- * @return The new value representing this-val.
- * @throws Error
- */
- public BigSurdVec subtract(final BigSurd val) throws Error {
- final BigSurdVec sum = new BigSurdVec();
- /*
- * concatenate the vectors and eliminate common overlaps
- */
- sum.terms.addAll(terms);
- sum.terms.add(val.negate());
- sum.normalize();
- return sum;
- } /* subtract */
-
- /**
- * Compute the negative.
- *
- * @return -this.
- * @since 2012-02-15
- */
- public BigSurdVec negate() {
- /*
- * accumulate the negated elements of term one by one
- */
- 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
- */
- return resul;
- } /* negate */
-
- /**
- * Compute the square.
- *
- * @return this value squared.
- * @throws Error
- * @since 2012-02-15
- */
- public BigSurdVec sqr() throws Error {
- /*
- * Binomial expansion. First the sum of the terms squared, then 2 times
- * the mixed products.
- */
- 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++) {
- resul.terms.add(terms.elementAt(i).multiply(terms.elementAt(j)).multiply(2));
- }
- }
- resul.normalize();
- return resul;
- } /* sqr */
-
- /**
- * Multiply by another square root.
- *
- * @param val
- * a second number of this type.
- * @return the product of this with the val.
- * @throws Error
- * @since 2011-02-12
- */
- public BigSurdVec multiply(final BigSurd val) throws Error {
- 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 (final BigSurd s : terms) {
- resul.terms.add(s);
- }
- for (final BigSurd s : val.terms) {
- resul = resul.multiply(s);
- }
- return resul;
- } /* multiply */
-
- public BigSurdVec divide(final BigSurd val) throws Error {
- final BigSurdVec resul = new BigSurdVec();
- for (final BigSurd s : terms) {
- resul.terms.add(s.divide(val));
- }
- resul.normalize();
- return resul;
- } /* multiply */
-
- public BigSurdVec divide(final BigSurdVec val) throws Error {
- BigSurdVec resul = new BigSurdVec();
- resul.terms = terms;
- for (final BigSurd s : val.terms) {
- resul = resul.divide(s);
- }
- return resul;
- } /* divide */
-
- /**
- * True if the value is rational. Equivalent to the indication whether a
- * conversion to a Rational can be exact.
- *
- * @since 2011-02-12
- */
- public boolean isRational() {
- boolean val = false;
- for (final BigSurd s : terms) {
- val = s.isRational();
- if (val == false) {
- break;
- }
- }
- return val;
- } /* BigSurdVec.isRational */
-
- /**
- * True if the value is BigInteger. Equivalent to the indication whether a
- * conversion to a BigInteger can be exact.
- *
- * @since 2011-02-12
- */
- public boolean isBigInteger() {
- boolean val = false;
- for (final BigSurd s : terms) {
- val = s.isBigInteger();
- if (val == false) {
- break;
- }
- }
- return val;
- } /* BigSurdVec.isRational */
-
- /**
- * Convert to a rational value if possible
- *
- * @since 2012-02-15
- */
- public Rational toRational() {
- Rational rat = Rational.ZERO;
- if (isRational() == false) {
- throw new ArithmeticException("Undefined conversion " + toString() + " to Rational.");
- }
- for (final BigSurd s : terms) {
- rat = rat.add(s.pref);
- }
- return rat;
- } /* BigSurd.toRational */
-
- /**
- * Convert to a BigInteger value if possible
- *
- * @since 2012-02-15
- */
- public BigInteger toBigInteger() {
- BigDecimal tmp = BigDecimal.ZERO.setScale(Utils.scale, Utils.scaleMode);
- if (isBigInteger() == false) {
- throw new ArithmeticException("Undefined conversion " + toString() + " to Rational.");
- }
- for (final BigSurd s : terms) {
- tmp = BigDecimalMath.addRound(tmp, s.pref.BigDecimalValue(new MathContext(Utils.scale, Utils.scaleMode2)));
- }
- return tmp.toBigInteger();
- } /* BigSurd.toRational */
-
- /**
- * Convert to a BigDecimal value if possible
- *
- * @since 2012-02-15
- */
- public BigDecimal toBigDecimal() {
- BigDecimal tmp = BigDecimal.ZERO.setScale(Utils.scale, Utils.scaleMode);
- for (final BigSurd s : terms) {
- tmp = BigDecimalMath.addRound(tmp, s.BigDecimalValue(new MathContext(Utils.scale, Utils.scaleMode2)));
- }
- return tmp;
- } /* BigSurd.toBigDecimal */
-
- /**
- * Return a string in the format (number/denom)*()^(1/2). If the
- * discriminant equals 1, print just the prefactor.
- *
- * @return the human-readable version in base 10
- * @since 2012-02-16
- */
- @Override
- public String toString() {
- /*
- * simple cases with one term forwarded to the BigSurd class
- */
- if (terms.size() == 0) {
- return new String("0");
- } else {
- String s = new String();
- for (int t = 0; t < terms.size(); t++) {
- final BigSurd bs = terms.elementAt(t);
- if (bs.signum() > 0) {
- s += "+";
- }
- s += bs.toString();
- }
- return s;
- }
- } /* toString */
-
- public String toFancyString() {
- if (terms.size() == 0) {
- return new String("0");
- } else {
- BigInteger denominator = BigInteger.ONE;
- for (int i = 0; i < terms.size(); i++) {
- denominator = denominator.multiply(terms.elementAt(i).pref.b);
- }
- String s = "";
- if (denominator.compareTo(BigInteger.ONE) != 0) {
- s += "(";
- }
- for (int t = 0; t < terms.size(); t++) {
- 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 {
- final BigInteger numerator = bs.pref.multiply(denominator).numer();
- if (numerator.compareTo(BigInteger.ONE) != 0) {
- s += numerator.toString();
- s += "*";
- // s += "("; Radice quadrata. non servono le parentesi.
- }
- s += "Ⓐ";
- if (bs.disc.isInteger()) {
- s += bs.disc.toString();
- } else {
- s += "(" + bs.disc.toString() + ")";
- }
- if (numerator.compareTo(BigInteger.ONE) != 0) {
- // s += ")"; Radice quadrata. non servono le parentesi.
- }
- }
- }
- if (denominator.compareTo(BigInteger.ONE) != 0) {
- s += ")";
- s += "/";
- s += denominator;
- }
- return s;
- }
- }
-
-} /* BigSurdVec */
diff --git a/core/src/main/java/org/nevec/rjm/Euler.java b/core/src/main/java/org/nevec/rjm/Euler.java
deleted file mode 100644
index c29a09cb..00000000
--- a/core/src/main/java/org/nevec/rjm/Euler.java
+++ /dev/null
@@ -1,73 +0,0 @@
-package org.nevec.rjm;
-
-import java.math.BigInteger;
-import java.util.Vector;
-
-/**
- * Euler numbers
- *
- * @see A000364 in the OEIS.
- * @since 2008-10-30
- * @author Richard J. Mathar
- */
-public class Euler {
- /*
- * The list of all Euler numbers as a vector, n=0,2,4,....
- */
- static protected Vector a = new Vector<>();
-
- /**
- * Ctor(). Fill the hash list initially with E_0 to E_3.
- */
- public Euler() {
- if (Euler.a.size() == 0) {
- Euler.a.add(BigInteger.ONE);
- Euler.a.add(BigInteger.ONE);
- Euler.a.add(new BigInteger("5"));
- Euler.a.add(new BigInteger("61"));
- }
- }
-
- /**
- * Compute a coefficient in the internal table.
- *
- * @param n
- * the zero-based index of the coefficient. n=0 for the E_0 term.
- */
- protected void set(final int n) {
- while (n >= Euler.a.size()) {
- BigInteger val = BigInteger.ZERO;
- boolean sigPos = true;
- final int thisn = Euler.a.size();
- for (int i = thisn - 1; i > 0; i--) {
- BigInteger f = new BigInteger("" + Euler.a.elementAt(i).toString());
- f = f.multiply(BigIntegerMath.binomial(2 * thisn, 2 * i));
- if (sigPos) {
- val = val.add(f);
- } else {
- val = val.subtract(f);
- }
- sigPos = !sigPos;
- }
- if (thisn % 2 == 0) {
- val = val.subtract(BigInteger.ONE);
- } else {
- val = val.add(BigInteger.ONE);
- }
- Euler.a.add(val);
- }
- }
-
- /**
- * The Euler number at the index provided.
- *
- * @param n
- * the index, non-negative.
- * @return the E_0=E_1=1 , E_2=5, E_3=61 etc
- */
- public BigInteger at(final int n) {
- set(n);
- return Euler.a.elementAt(n);
- }
-
-} /* Euler */
diff --git a/core/src/main/java/org/nevec/rjm/EulerPhi.java b/core/src/main/java/org/nevec/rjm/EulerPhi.java
deleted file mode 100644
index 639b34b1..00000000
--- a/core/src/main/java/org/nevec/rjm/EulerPhi.java
+++ /dev/null
@@ -1,66 +0,0 @@
-package org.nevec.rjm;
-
-import java.math.BigInteger;
-
-/**
- * Euler totient function.
- *
- * @see A000010 in the OEIS.
- * @since 2008-10-14
- * @since 2012-03-04 Adapted to new Ifactor representation.
- * @author Richard J. Mathar
- */
-public class EulerPhi {
- /**
- * Default constructor.
- * Does nothing().
- */
- public EulerPhi() {}
-
- /**
- * Compute phi(n).
- *
- * @param n
- * The positive argument of the function.
- * @return phi(n)
- */
- public BigInteger at(final int n) {
- return at(new BigInteger("" + n));
- } /* at */
-
- /**
- * Compute phi(n).
- *
- * @param n
- * The positive argument of the function.
- * @return phi(n)
- */
- public BigInteger at(final BigInteger n) {
- if (n.compareTo(BigInteger.ZERO) <= 0) {
- throw new ArithmeticException("negative argument " + n + " of EulerPhi");
- }
- final Ifactor prFact = new Ifactor(n);
- BigInteger phi = n;
- if (n.compareTo(BigInteger.ONE) > 0) {
- for (int i = 0; i < prFact.primeexp.size(); i += 2) {
- 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 */
-
- /**
- * Test program.
- * It takes one argument n and prints the value phi(n).
- * java -cp . org.nevec.rjm.EulerPhi n
- *
- * @since 2006-08-14
- */
- public static void main(final String[] args) throws ArithmeticException {
- 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/core/src/main/java/org/nevec/rjm/Factorial.java b/core/src/main/java/org/nevec/rjm/Factorial.java
deleted file mode 100644
index 175bab0b..00000000
--- a/core/src/main/java/org/nevec/rjm/Factorial.java
+++ /dev/null
@@ -1,79 +0,0 @@
-package org.nevec.rjm;
-
-import java.math.BigInteger;
-import java.util.Vector;
-
-/**
- * Factorials.
- *
- * @since 2006-06-25
- * @since 2012-02-15 Storage of the values based on Ifactor, not BigInteger.
- * @author Richard J. Mathar
- */
-public class Factorial {
- /**
- * The list of all factorials as a vector.
- */
- static Vector a = new Vector<>();
-
- /**
- * ctor().
- * Initialize the vector of the factorials with 0!=1 and 1!=1.
- */
- public Factorial() {
- if (Factorial.a.size() == 0) {
- Factorial.a.add(Ifactor.ONE);
- Factorial.a.add(Ifactor.ONE);
- }
- } /* ctor */
-
- /**
- * Compute the factorial of the non-negative integer.
- *
- * @param n
- * the argument to the factorial, non-negative.
- * @return the factorial of n.
- */
- public BigInteger at(final int n) {
- /*
- * extend the internal list if needed.
- */
- growto(n);
- return Factorial.a.elementAt(n).n;
- } /* at */
-
- /**
- * Compute the factorial of the non-negative integer.
- *
- * @param n
- * the argument to the factorial, non-negative.
- * @return the factorial of n.
- */
- public Ifactor toIfactor(final int n) {
- /*
- * extend the internal list if needed.
- */
- growto(n);
- return Factorial.a.elementAt(n);
- } /* at */
-
- /**
- * Extend the internal table to cover up to n!
- *
- * @param n
- * The maximum factorial to be supported.
- * @since 2012-02-15
- */
- private void growto(final int n) {
- /*
- * extend the internal list if needed. Size to be 2 for n<=1, 3 for n<=2
- * etc.
- */
- while (Factorial.a.size() <= n) {
- final int lastn = Factorial.a.size() - 1;
- final Ifactor nextn = new Ifactor(lastn + 1);
- Factorial.a.add(Factorial.a.elementAt(lastn).multiply(nextn));
- }
- } /* growto */
-
-} /* Factorial */
diff --git a/core/src/main/java/org/nevec/rjm/Harmonic.java b/core/src/main/java/org/nevec/rjm/Harmonic.java
deleted file mode 100644
index 5058c3a2..00000000
--- a/core/src/main/java/org/nevec/rjm/Harmonic.java
+++ /dev/null
@@ -1,43 +0,0 @@
-package org.nevec.rjm;
-
-/**
- * Harmonic numbers.
- * H(n) is the sum of the inverses of the integers from 1 to n.
- *
- * @since 2008-10-19
- * @author Richard J. Mathar
- */
-public class Harmonic {
- /**
- * ctor()
- * Does nothing.
- */
- public Harmonic() {}
-
- /**
- * The Harmonic number at the index specified
- *
- * @param n
- * the index, non-negative.
- * @return the H_1=1 for n=1, H_2=3/2 for n=2 etc.
- * For values of n less than 1, zero is returned.
- */
- public Rational at(final int n) {
- if (n < 1) {
- return new Rational(0, 1);
- } else {
- /*
- * start with 1 as the result
- */
- Rational a = new Rational(1, 1);
-
- /*
- * add 1/i for i=2..n
- */
- for (int i = 2; i <= n; i++) {
- a = a.add(new Rational(1, i));
- }
- return a;
- }
- }
-} /* Harmonic */
diff --git a/core/src/main/java/org/nevec/rjm/Ifactor.java b/core/src/main/java/org/nevec/rjm/Ifactor.java
deleted file mode 100644
index fe9948e3..00000000
--- a/core/src/main/java/org/nevec/rjm/Ifactor.java
+++ /dev/null
@@ -1,835 +0,0 @@
-package org.nevec.rjm;
-
-import java.math.BigInteger;
-import java.util.Collections;
-import java.util.Vector;
-
-import it.cavallium.warppi.util.Error;
-
-/**
- * Factored integers.
- * This class contains a non-negative integer with the prime factor
- * decomposition attached.
- *
- * @since 2006-08-14
- * @since 2012-02-14 The internal representation contains the bases, and becomes
- * sparser if few
- * prime factors are present.
- * @author Richard J. Mathar
- */
-public class Ifactor implements Cloneable, Comparable {
- /**
- * The standard representation of the number
- */
- public BigInteger n;
-
- /*
- * The bases and powers of the prime factorization.
- * representation n = primeexp[0]^primeexp[1]*primeexp[2]^primeexp[3]*...
- * The value 0 is represented by an empty vector, the value 1 by a vector of
- * length 1
- * with a single power of 0.
- */
- public Vector primeexp;
-
- final public static Ifactor ONE = new Ifactor(1);
-
- final public static Ifactor ZERO = new Ifactor(0);
-
- /**
- * Constructor given an integer.
- * constructor with an ordinary integer
- *
- * @param number
- * the standard representation of the integer
- */
- public Ifactor(int number) {
- n = new BigInteger("" + number);
- primeexp = new Vector<>();
- if (number > 1) {
- int primindx = 0;
- final Prime primes = new Prime();
- /*
- * Test division against all primes.
- */
- while (number > 1) {
- int ex = 0;
- /*
- * primindx=0 refers to 2, =1 to 3, =2 to 5, =3 to 7 etc
- */
- final int p = primes.at(primindx).intValue();
- while (number % p == 0) {
- ex++;
- number /= p;
- if (number == 1) {
- break;
- }
- }
- if (ex > 0) {
- primeexp.add(new Integer(p));
- primeexp.add(new Integer(ex));
- }
- primindx++;
- }
- } else if (number == 1) {
- primeexp.add(new Integer(1));
- primeexp.add(new Integer(0));
- }
- } /* Ifactor */
-
- /**
- * Constructor given a BigInteger .
- * Constructor with an ordinary integer, calling a prime factor
- * decomposition.
- *
- * @param number
- * the BigInteger representation of the integer
- */
- public Ifactor(BigInteger number) {
- n = number;
- primeexp = new Vector<>();
- if (number.compareTo(BigInteger.ONE) == 0) {
- primeexp.add(new Integer(1));
- primeexp.add(new Integer(0));
- } else {
- int primindx = 0;
- final Prime primes = new Prime();
- /*
- * Test for division against all primes.
- */
- while (number.compareTo(BigInteger.ONE) == 1) {
- int ex = 0;
- 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) {
- break;
- }
- }
- if (ex > 0) {
- primeexp.add(new Integer(p.intValue()));
- primeexp.add(new Integer(ex));
- }
- primindx++;
- }
- }
- } /* Ifactor */
-
- /**
- * Constructor given a list of exponents of the prime factor decomposition.
- *
- * @param pows
- * the vector with the sorted list of exponents.
- * pows[0] is the exponent of 2, pows[1] the exponent of 3,
- * pows[2] the exponent of 5 etc.
- * Note that this list does not include the primes, but assumes a
- * continuous prime-smooth basis.
- */
- public Ifactor(final Vector pows) {
- primeexp = new Vector<>(2 * pows.size());
- if (pows.size() > 0) {
- n = BigInteger.ONE;
- 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++) {
- 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 {
- n = BigInteger.ZERO;
- }
- } /* Ifactor */
-
- /**
- * Copy constructor.
- *
- * @param oth
- * the value to be copied
- */
- public Ifactor(final Ifactor oth) {
- n = oth.n;
- primeexp = oth.primeexp;
- } /* Ifactor */
-
- /**
- * Deep copy.
- *
- * @since 2009-08-14
- */
- @Override
- public Ifactor clone() {
- /*
- * Line not used:
- *
- * Vector p = (Vector)primeexp.clone();
- *
- */
- final Ifactor cl = new Ifactor(0);
- cl.n = new BigInteger("" + n);
- return cl;
- } /* Ifactor.clone */
-
- /**
- * Comparison of two numbers.
- * The value of this method is in allowing the Vector<>.contains() calls
- * that use the value,
- * not the reference for comparison.
- *
- * @param oth
- * the number to compare this with.
- * @return true if both are the same numbers, false otherwise.
- */
- public boolean equals(final Ifactor oth) {
- return n.compareTo(oth.n) == 0;
- } /* Ifactor.equals */
-
- /**
- * Multiply with another positive integer.
- *
- * @param oth
- * the second factor.
- * @return the product of both numbers.
- */
- public Ifactor multiply(final BigInteger oth) {
- /*
- * the optimization is to factorize oth _before_ multiplying
- */
- return multiply(new Ifactor(oth));
- } /* Ifactor.multiply */
-
- /**
- * Multiply with another positive integer.
- *
- * @param oth
- * the second factor.
- * @return the product of both numbers.
- */
- public Ifactor multiply(final int oth) {
- /*
- * the optimization is to factorize oth _before_ multiplying
- */
- return multiply(new Ifactor(oth));
- } /* Ifactor.multiply */
-
- /**
- * Multiply with another positive integer.
- *
- * @param oth
- * the second factor.
- * @return the product of both numbers.
- */
- public Ifactor multiply(final Ifactor oth) {
- /*
- * This might be done similar to the lcm() implementation by adding
- * the powers of the components and calling the constructor with the
- * list of exponents. This here is the simplest implementation, but slow
- * because
- * it calls another prime factorization of the product:
- * return( new Ifactor(n.multiply(oth.n))) ;
- */
- return multGcdLcm(oth, 0);
- }
-
- /**
- * Lowest common multiple of this with oth.
- *
- * @param oth
- * the second parameter of lcm(this,oth)
- * @return the lowest common multiple of both numbers. Returns zero
- * if any of both arguments is zero.
- */
- public Ifactor lcm(final Ifactor oth) {
- return multGcdLcm(oth, 2);
- }
-
- /**
- * Greatest common divisor of this and oth.
- *
- * @param oth
- * the second parameter of gcd(this,oth)
- * @return the lowest common multiple of both numbers. Returns zero
- * if any of both arguments is zero.
- */
- public Ifactor gcd(final Ifactor oth) {
- return multGcdLcm(oth, 1);
- }
-
- /**
- * Multiply with another positive integer.
- *
- * @param oth
- * the second factor.
- * @param type
- * 0 to multiply, 1 for gcd, 2 for lcm
- * @return the product, gcd or lcm of both numbers.
- */
- protected Ifactor multGcdLcm(final Ifactor oth, final int type) {
- final Ifactor prod = new Ifactor(0);
- /*
- * skip the case where 0*something =0, falling thru to the empty
- * representation for 0
- */
- if (primeexp.size() != 0 && oth.primeexp.size() != 0) {
- /*
- * Cases of 1 times something return something.
- * Cases of lcm(1, something) return something.
- * Cases of gcd(1, something) return 1.
- */
- if (primeexp.firstElement().intValue() == 1 && type == 0) {
- return oth;
- } else if (primeexp.firstElement().intValue() == 1 && type == 2) {
- return oth;
- } else if (primeexp.firstElement().intValue() == 1 && type == 1) {
- return this;
- } else if (oth.primeexp.firstElement().intValue() == 1 && type == 0) {
- return this;
- } else if (oth.primeexp.firstElement().intValue() == 1 && type == 2) {
- return this;
- } else if (oth.primeexp.firstElement().intValue() == 1 && type == 1) {
- return oth;
- } else {
- int idxThis = 0;
- int idxOth = 0;
- switch (type) {
- case 0:
- prod.n = n.multiply(oth.n);
- break;
- case 1:
- prod.n = n.gcd(oth.n);
- break;
- case 2:
- /*
- * the awkward way, lcm = product divided by gcd
- */
- prod.n = n.multiply(oth.n).divide(n.gcd(oth.n));
- break;
- }
-
- /*
- * scan both representations left to right, increasing prime
- * powers
- */
- while (idxOth < oth.primeexp.size() || idxThis < primeexp.size()) {
- if (idxOth >= oth.primeexp.size()) {
- /*
- * exhausted the list in oth.primeexp; copy over the
- * remaining 'this'
- * if multiplying or lcm, discard if gcd.
- */
- if (type == 0 || type == 2) {
- prod.primeexp.add(primeexp.elementAt(idxThis));
- prod.primeexp.add(primeexp.elementAt(idxThis + 1));
- }
- idxThis += 2;
- } else if (idxThis >= primeexp.size()) {
- /*
- * exhausted the list in primeexp; copy over the
- * remaining 'oth'
- */
- if (type == 0 || type == 2) {
- prod.primeexp.add(oth.primeexp.elementAt(idxOth));
- prod.primeexp.add(oth.primeexp.elementAt(idxOth + 1));
- }
- idxOth += 2;
- } else {
- Integer p;
- int ex;
- switch (primeexp.elementAt(idxThis).compareTo(oth.primeexp.elementAt(idxOth))) {
- case 0:
- /* same prime bases p in both factors */
- p = primeexp.elementAt(idxThis);
- switch (type) {
- case 0:
- /* product means adding exponents */
- ex = primeexp.elementAt(idxThis + 1).intValue() + oth.primeexp.elementAt(idxOth + 1).intValue();
- break;
- case 1:
- /* gcd means minimum of exponents */
- ex = Math.min(primeexp.elementAt(idxThis + 1).intValue(), oth.primeexp.elementAt(idxOth + 1).intValue());
- break;
- default:
- /* lcm means maximum of exponents */
- ex = Math.max(primeexp.elementAt(idxThis + 1).intValue(), oth.primeexp.elementAt(idxOth + 1).intValue());
- break;
- }
- prod.primeexp.add(p);
- prod.primeexp.add(new Integer(ex));
- idxOth += 2;
- idxThis += 2;
- break;
- case 1:
- /*
- * this prime base bigger than the other and
- * taken later
- */
- if (type == 0 || type == 2) {
- prod.primeexp.add(oth.primeexp.elementAt(idxOth));
- prod.primeexp.add(oth.primeexp.elementAt(idxOth + 1));
- }
- idxOth += 2;
- break;
- default:
- /*
- * this prime base smaller than the other and
- * taken now
- */
- if (type == 0 || type == 2) {
- prod.primeexp.add(primeexp.elementAt(idxThis));
- prod.primeexp.add(primeexp.elementAt(idxThis + 1));
- }
- idxThis += 2;
- }
- }
- }
- }
- }
- return prod;
- } /* Ifactor.multGcdLcm */
-
- /**
- * Integer division through another positive integer.
- *
- * @param oth
- * the denominator.
- * @return the division of this through the oth, discarding the remainder.
- */
- public Ifactor divide(final Ifactor oth) {
- /*
- * todo: it'd probably be faster to cancel the gcd(this,oth) first in
- * the prime power
- * representation, which would avoid a more strenous factorization of
- * the integer ratio
- */
- return new Ifactor(n.divide(oth.n));
- } /* Ifactor.divide */
-
- /**
- * Summation with another positive integer
- *
- * @param oth
- * the other term.
- * @return the sum of both numbers
- */
- public Ifactor add(final BigInteger oth) {
- /*
- * avoid refactorization if oth is zero...
- */
- if (oth.compareTo(BigInteger.ZERO) != 0) {
- return new Ifactor(n.add(oth));
- } else {
- return this;
- }
- } /* Ifactor.add */
-
- /**
- * Exponentiation with a positive integer.
- *
- * @param exponent
- * the non-negative exponent
- * @return n^exponent. If exponent=0, the result is 1.
- */
- public Ifactor pow(final int exponent) throws ArithmeticException {
- /*
- * three simple cases first
- */
- if (exponent < 0) {
- throw new ArithmeticException("Cannot raise " + toString() + " to negative " + exponent);
- } else if (exponent == 0) {
- return new Ifactor(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.
- */
- final Ifactor pows = new Ifactor(0);
- for (int i = 0; i < primeexp.size(); i += 2) {
- 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));
- }
- return pows;
- } /* Ifactor.pow */
-
- /**
- * Pulling the r-th root.
- *
- * @param r
- * the positive or negative (nonzero) root.
- * @return n^(1/r).
- * The return value falls into the Ifactor class if r is positive,
- * but if r is negative
- * a Rational type is needed.
- * @throws Error
- * @since 2009-05-18
- */
- public Rational root(final int r) throws ArithmeticException, Error {
- if (r == 0) {
- throw new ArithmeticException("Cannot pull zeroth root of " + toString());
- } else if (r < 0) {
- /*
- * a^(-1/b)= 1/(a^(1/b))
- */
- final Rational invRoot = root(-r);
- return Rational.ONE.divide(invRoot);
- } else {
- 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).
- */
- 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));
- }
- /*
- * convert result to a Rational; unfortunately this will loose the
- * prime factorization
- */
- return new Rational(pows);
- }
- } /* Ifactor.root */
-
- /**
- * The set of positive divisors.
- *
- * @return the vector of divisors of the absolute value, sorted.
- * @since 2010-08-27
- */
- public Vector divisors() {
- /*
- * Recursive approach: the divisors of p1^e1*p2^e2*..*py^ey*pz^ez are
- * the divisors that don't contain the factor pz, and the
- * the divisors that contain any power of pz between 1 and up to ez
- * multiplied
- * by 1 or by a product that contains the factors p1..py.
- */
- 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) */
- final Ifactor dp = dropPrime();
-
- /* get ez */
- final int ez = primeexp.lastElement().intValue();
-
- final Vector partd = dp.divisors();
-
- /* obtain pz by lookup in the prime list */
- final BigInteger pz = new BigInteger(primeexp.elementAt(primeexp.size() - 2).toString());
-
- /*
- * 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++) {
- 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++) {
- d.add(partd.elementAt(i).multiply(pzez));
- }
- }
- }
- Collections.sort(d);
- return d;
- } /* Ifactor.divisors */
-
- /**
- * Sum of the divisors of the number.
- *
- * @return the sum of all divisors of the number, 1+....+n.
- */
- public Ifactor sigma() {
- return sigma(1);
- } /* Ifactor.sigma */
-
- /**
- * Sum of the k-th powers of divisors of the number.
- *
- * @return the sum of all divisors of the number, 1^k+....+n^k.
- */
- public Ifactor sigma(final int k) {
- /*
- * 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) {
- return Ifactor.ONE;
- } else if (n.compareTo(BigInteger.ZERO) == 0) {
- return Ifactor.ZERO;
- } 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) {
- final int ex = primeexp.elementAt(i + 1).intValue();
- if (k == 0) {
- resul = resul.multiply(ex + 1);
- } 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.
- */
- final Ifactor f = new Ifactor(num.divide(deno));
- resul = resul.multiply(f);
- }
- }
- return resul;
- }
- } /* Ifactor.sigma */
-
- /**
- * Divide through the highest possible power of the highest prime.
- * If the current number is the prime factor product p1^e1 * p2*e2*
- * p3^e3*...*py^ey * pz^ez,
- * the value returned has the final factor pz^ez eliminated, which gives
- * p1^e1 * p2*e2* p3^e3*...*py^ey.
- *
- * @return the new integer obtained by removing the highest prime power.
- * If this here represents 0 or 1, it is returned without change.
- * @since 2006-08-20
- */
- public Ifactor dropPrime() {
- /*
- * the cases n==1 or n ==0
- */
- if (n.compareTo(BigInteger.ONE) <= 0) {
- return this;
- }
-
- /*
- * The cases n>1
- * Start empty. Copy all but the last factor over to the result
- * the vector with the new prime factor powers, which contain the
- * old prime factor powers up to but not including the last one.
- */
- 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));
- 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;
- } /* Ifactor.dropPrime */
-
- /**
- * Test whether this is a square of an integer (perfect square).
- *
- * @return true if this is an integer squared (including 0), else false
- */
- public boolean issquare() {
- /*
- * 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) {
- return false;
- }
- }
- return true;
- } /* Ifactor.issquare */
-
- /**
- * The sum of the prime factor exponents, with multiplicity.
- *
- * @return the sum over the primeexp numbers
- */
- public int bigomega() {
- int resul = 0;
- for (int i = 1; i < primeexp.size(); i += 2) {
- resul += primeexp.elementAt(i).intValue();
- }
- return resul;
- } /* Ifactor.bigomega */
-
- /**
- * The sum of the prime factor exponents, without multiplicity.
- *
- * @return the number of distinct prime factors.
- * @since 2008-10-16
- */
- public int omega() {
- return primeexp.size() / 2;
- } /* Ifactor.omega */
-
- /**
- * The square-free part.
- *
- * @return the minimum m such that m times this number is a square.
- * @since 2008-10-16
- */
- public BigInteger core() {
- BigInteger resul = BigInteger.ONE;
- 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 */
-
- /**
- * The Moebius function.
- * 1 if n=1, else, if k is the number of distinct prime factors, return
- * (-1)^k,
- * else, if k has repeated prime factors, return 0.
- *
- * @return the moebius function.
- */
- public int moebius() {
- 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) {
- return 0;
- } else if (e == 1) {
- /* accumulates (-1)^k */
- k *= -1;
- }
-
- }
- return k;
- } /* Ifactor.moebius */
-
- /**
- * Maximum of two values.
- *
- * @param oth
- * the number to compare this with.
- * @return the larger of the two values.
- */
- public Ifactor max(final Ifactor oth) {
- if (n.compareTo(oth.n) >= 0) {
- return this;
- } else {
- return oth;
- }
- } /* Ifactor.max */
-
- /**
- * Minimum of two values.
- *
- * @param oth
- * the number to compare this with.
- * @return the smaller of the two values.
- */
- public Ifactor min(final Ifactor oth) {
- if (n.compareTo(oth.n) <= 0) {
- return this;
- } else {
- return oth;
- }
- } /* Ifactor.min */
-
- /**
- * Maximum of a list of values.
- *
- * @param set
- * list of numbers.
- * @return the largest in the list.
- */
- public static Ifactor max(final Vector set) {
- Ifactor resul = set.elementAt(0);
- for (int i = 1; i < set.size(); i++) {
- resul = resul.max(set.elementAt(i));
- }
- return resul;
- } /* Ifactor.max */
-
- /**
- * Minimum of a list of values.
- *
- * @param set
- * list of numbers.
- * @return the smallest in the list.
- */
- public static Ifactor min(final Vector set) {
- Ifactor resul = set.elementAt(0);
- for (int i = 1; i < set.size(); i++) {
- resul = resul.min(set.elementAt(i));
- }
- return resul;
- } /* Ifactor.min */
-
- /**
- * Compare value against another Ifactor
- *
- * @param oth
- * The value to be compared agains.
- * @return 1, 0 or -1 according to being larger, equal to or smaller than
- * oth.
- * @since 2012-02-15
- */
- @Override
- public int compareTo(final Ifactor oth) {
- return n.compareTo(oth.n);
- } /* compareTo */
-
- /**
- * Convert to printable format
- *
- * @return a string of the form n:prime^pow*prime^pow*prime^pow...
- */
- @Override
- public String toString() {
- String resul = new String(n.toString() + ":");
- if (n.compareTo(BigInteger.ONE) == 0) {
- resul += "1";
- } else {
- boolean firstMul = true;
- for (int i = 0; i < primeexp.size(); i += 2) {
- if (!firstMul) {
- resul += "*";
- }
- if (primeexp.elementAt(i + 1).intValue() > 1) {
- resul += primeexp.elementAt(i).toString() + "^" + primeexp.elementAt(i + 1).toString();
- } else {
- resul += primeexp.elementAt(i).toString();
- }
- firstMul = false;
- }
- }
- return resul;
- } /* Ifactor.toString */
-
- /**
- * Test program.
- * It takes a single argument n and prints the integer factorizaton.
- * java -cp . org.nevec.rjm.Ifactor n
- */
- public static void main(final String[] args) throws Exception {
- final BigInteger n = new BigInteger(args[0]);
- System.out.println(new Ifactor(n));
- } /* Ifactor.main */
-} /* Ifactor */
diff --git a/core/src/main/java/org/nevec/rjm/PartitionsP.java b/core/src/main/java/org/nevec/rjm/PartitionsP.java
deleted file mode 100644
index 1af7559e..00000000
--- a/core/src/main/java/org/nevec/rjm/PartitionsP.java
+++ /dev/null
@@ -1,88 +0,0 @@
-package org.nevec.rjm;
-
-import java.math.BigInteger;
-import java.util.Vector;
-
-/**
- * Number of partitions.
- *
- * @since 2008-10-15
- * @author Richard J. Mathar
- */
-public class PartitionsP {
- /**
- * The list of all partitions as a vector.
- */
- static protected Vector a = new Vector<>();
-
- /**
- * The maximum integer covered by the high end of the list.
- */
- static protected BigInteger nMax = new BigInteger("-1");
-
- /**
- * Default constructor initializing a list of partitions up to 7.
- */
- public PartitionsP() {
- if (PartitionsP.a.size() == 0) {
- PartitionsP.a.add(new BigInteger("" + 1));
- PartitionsP.a.add(new BigInteger("" + 1));
- PartitionsP.a.add(new BigInteger("" + 2));
- PartitionsP.a.add(new BigInteger("" + 3));
- PartitionsP.a.add(new BigInteger("" + 5));
- PartitionsP.a.add(new BigInteger("" + 7));
- }
- PartitionsP.nMax = new BigInteger("" + (PartitionsP.a.size() - 1));
- } /* ctor */
-
- /**
- * return the number of partitions of i
- *
- * @param i
- * the zero-based index into the list of partitions
- * @return the ith partition number. This is 1 if i=0 or 1, 2 if i=2 and so
- * forth.
- */
- public BigInteger at(final int i) {
- /*
- * If the current list is too small, increase in intervals
- * of 3 until the list has at least i elements.
- */
- while (i > PartitionsP.nMax.intValue()) {
- growto(PartitionsP.nMax.add(new BigInteger("" + 3)));
- }
- return PartitionsP.a.elementAt(i);
- } /* at */
-
- /**
- * extend the list of known partitions up to n
- *
- * @param n
- * the maximum integer hashed after the call.
- */
- private void growto(final BigInteger n) {
- while (PartitionsP.a.size() <= n.intValue()) {
- BigInteger per = new BigInteger("0");
- final BigInteger cursiz = new BigInteger("" + PartitionsP.a.size());
- for (int k = 0; k < PartitionsP.a.size(); k++) {
- final BigInteger tmp = PartitionsP.a.elementAt(k).multiply(BigIntegerMath.sigma(PartitionsP.a.size() - k));
- per = per.add(tmp);
- }
- PartitionsP.a.add(per.divide(cursiz));
- }
- PartitionsP.nMax = new BigInteger("" + (PartitionsP.a.size() - 1));
- } /* growto */
-
- /**
- * Test program.
- * It takes one integer argument n and prints P(n).
- * java -cp . org.nevec.rjm.PartitionsP n
- *
- * @since 2008-10-15
- */
- public static void main(final String[] args) throws Exception {
- final PartitionsP a = new PartitionsP();
- final int n = new Integer(args[0]).intValue();
- System.out.println("P(" + n + ")=" + a.at(n));
- }
-}
diff --git a/core/src/main/java/org/nevec/rjm/Prime.java b/core/src/main/java/org/nevec/rjm/Prime.java
deleted file mode 100644
index 2b1111a9..00000000
--- a/core/src/main/java/org/nevec/rjm/Prime.java
+++ /dev/null
@@ -1,321 +0,0 @@
-package org.nevec.rjm;
-
-import java.math.BigInteger;
-import java.util.Vector;
-
-/**
- * Prime numbers.
- * The implementation is a very basic computation of the set of all primes
- * on demand, growing infinitely without any defined upper limit.
- * The effects of such scheme are (i) the lookup-times become shorter after
- * a while as more and more primes have been used and stored. The applications
- * appear to become faster. (ii) Using the implementation for factorizations
- * may easily require all available memory and stall finally, because indeed
- * a dense list of primes with growing upper bound is kept without any hashing
- * or lagging scheme.
- *
- * @since 2006-08-11
- * @author Richard J. Mathar
- */
-public class Prime {
- /**
- * The list of all numbers as a vector.
- */
- static Vector a = new Vector<>();
-
- /**
- * The maximum integer covered by the high end of the list.
- */
- static protected BigInteger nMax = new BigInteger("-1");
-
- /**
- * Default constructor initializing a list of primes up to 17.
- * 17 is enough to call the Miller-Rabin tests on the first 7 primes without
- * further
- * action.
- */
- public Prime() {
- if (Prime.a.size() == 0) {
- Prime.a.add(new BigInteger("" + 2));
- Prime.a.add(new BigInteger("" + 3));
- Prime.a.add(new BigInteger("" + 5));
- Prime.a.add(new BigInteger("" + 7));
- Prime.a.add(new BigInteger("" + 11));
- Prime.a.add(new BigInteger("" + 13));
- Prime.a.add(new BigInteger("" + 17));
- }
- Prime.nMax = Prime.a.lastElement();
- }
-
- /**
- * Test if a number is a prime.
- *
- * @param n
- * the integer to be tested for primality
- * @return true if prime, false if not
- */
- public boolean contains(final BigInteger n) {
- /*
- * not documented
- * return ( n.isProbablePrime() ) ;
- */
- switch (millerRabin(n)) {
- case -1:
- return false;
- case 1:
- return true;
- }
- growto(n);
- return Prime.a.contains(n);
- }
-
- /**
- * Test whether a number n is a strong pseudoprime to base a.
- *
- * @param n
- * the integer to be tested for primality
- * @param a
- * the base
- * @return true if the test is passed, so n may be a prime.
- * false if the test is not passed, so n is not a prime.
- * @since 2010-02-25
- */
- public boolean isSPP(final BigInteger n, final BigInteger a) {
- final BigInteger two = new BigInteger("" + 2);
-
- /*
- * numbers less than 2 are not prime
- */
- if (n.compareTo(two) == -1) {
- return false;
- } else if (n.compareTo(two) == 0) {
- return true;
- } else if (n.remainder(two).compareTo(BigInteger.ZERO) == 0) {
- return false;
- } else {
- /*
- * q= n- 1 = d *2^s with d odd
- */
- final BigInteger q = n.subtract(BigInteger.ONE);
- 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) {
- return true;
- }
-
- /*
- * test whether a^(d*2^r) = -1 (mod n), 0<=r= Prime.a.size()) {
- growto(Prime.nMax.add(new BigInteger("" + 5)));
- }
- return Prime.a.elementAt(i);
- }
-
- /**
- * return the count of primes <= n
- *
- * @param n
- * the upper limit of the scan
- * @return the ith prime. This is 2 if i=0, 3 if i=1 and so forth.
- */
- public BigInteger pi(final BigInteger n) {
- /*
- * If the current list is too small, increase in intervals
- * of 5 until the list has at least i elements.
- */
- growto(n);
- BigInteger r = new BigInteger("0");
- for (int i = 0; i < Prime.a.size(); i++) {
- if (Prime.a.elementAt(i).compareTo(n) <= 0) {
- r = r.add(BigInteger.ONE);
- }
- }
- return r;
- }
-
- /**
- * return the smallest prime larger than n
- *
- * @param n
- * lower limit of the search
- * @return the next larger prime.
- * @since 2008-10-16
- */
- public BigInteger nextprime(final BigInteger n) {
- /* if n <=1, return 2 */
- if (n.compareTo(BigInteger.ONE) <= 0) {
- return Prime.a.elementAt(0);
- }
-
- /*
- * If the currently largest element in the list is too small, increase
- * in intervals
- * of 5 until the list has at least i elements.
- */
- while (Prime.a.lastElement().compareTo(n) <= 0) {
- growto(Prime.nMax.add(new BigInteger("" + 5)));
- }
- for (int i = 0; i < Prime.a.size(); i++) {
- if (Prime.a.elementAt(i).compareTo(n) == 1) {
- return Prime.a.elementAt(i);
- }
- }
- return Prime.a.lastElement();
- }
-
- /**
- * return the largest prime smaller than n
- *
- * @param n
- * upper limit of the search
- * @return the next smaller prime.
- * @since 2008-10-17
- */
- public BigInteger prevprime(final BigInteger n) {
- /* if n <=2, return 0 */
- if (n.compareTo(BigInteger.ONE) <= 0) {
- return BigInteger.ZERO;
- }
-
- /*
- * If the currently largest element in the list is too small, increase
- * in intervals
- * of 5 until the list has at least i elements.
- */
- while (Prime.a.lastElement().compareTo(n) < 0) {
- growto(Prime.nMax.add(new BigInteger("" + 5)));
- }
-
- for (int i = 0; i < Prime.a.size(); i++) {
- if (Prime.a.elementAt(i).compareTo(n) >= 0) {
- return Prime.a.elementAt(i - 1);
- }
- }
- return Prime.a.lastElement();
- }
-
- /**
- * extend the list of known primes up to n
- *
- * @param n
- * the maximum integer known to be prime or not prime after the
- * call.
- */
- protected void growto(final BigInteger n) {
- while (Prime.nMax.compareTo(n) == -1) {
- Prime.nMax = Prime.nMax.add(BigInteger.ONE);
- boolean isp = true;
- for (int p = 0; p < Prime.a.size(); p++) {
- /*
- * Test the list of known primes only up to sqrt(n)
- */
- if (Prime.a.get(p).multiply(Prime.a.get(p)).compareTo(Prime.nMax) == 1) {
- break;
- }
-
- /*
- * The next case means that the p'th number in the list of known
- * primes divides
- * nMax and nMax cannot be a prime.
- */
- if (Prime.nMax.remainder(Prime.a.get(p)).compareTo(BigInteger.ZERO) == 0) {
- isp = false;
- break;
- }
- }
- if (isp) {
- Prime.a.add(Prime.nMax);
- }
- }
- }
-
- /**
- * Test program.
- * Usage: java -cp . org.nevec.rjm.Prime n
- * This takes a single argument (n) and prints prime(n), the previous and
- * next prime, and pi(n).
- *
- * @since 2006-08-14
- */
- public static void main(final String[] args) throws Exception {
- final Prime a = new Prime();
- final int n = new Integer(args[0]).intValue();
- if (n >= 1) {
- 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)));
- }
- }
-} /* Prime */
diff --git a/core/src/main/java/org/nevec/rjm/RatPoly.java b/core/src/main/java/org/nevec/rjm/RatPoly.java
deleted file mode 100644
index 6bb27552..00000000
--- a/core/src/main/java/org/nevec/rjm/RatPoly.java
+++ /dev/null
@@ -1,1045 +0,0 @@
-package org.nevec.rjm;
-
-import java.math.BigInteger;
-import java.math.MathContext;
-import java.math.RoundingMode;
-import java.util.Random;
-import java.util.Scanner;
-import java.util.Vector;
-
-import it.cavallium.warppi.util.Error;
-
-/**
- * A one-parameter polynomial with rational coefficients.
- * Alternatively to be interpreted as a sequence which has the polynomial as an
- * (approximate)
- * generating function.
- *
- * @since 2006-06-25
- * @author Richard J. Mathar
- */
-class RatPoly {
- /**
- * The list of all coefficients, ascending exponents. Starting with a0, then
- * a1, representing
- * a value a0+a1*x+a2*x^2+a3*x^3+...
- */
- protected Vector a;
-
- /**
- * Default ctor.
- * Initializes the zero-valued polynomial x=0.
- */
- public RatPoly() {
- a = new Vector<>();
- } /* ctor */
-
- /**
- * Constructor with an explicit list of coefficients.
- *
- * @param L
- * the coefficients a0, a1, a2, a3,.., A deep copy of the these
- * is created.
- */
- public RatPoly(final Vector L) {
- a = new Vector<>();
- for (int i = 0; i < L.size(); i++) {
- a.add(L.elementAt(i).clone());
- }
- simplify();
- } /* ctor */
-
- /**
- * Constructor with a comma-separated list as the list of coefficients.
- *
- * @param L
- * the string of the form a0,a1,a2,a3 with the coefficients
- */
- public RatPoly(final String L) throws NumberFormatException {
- a = new Vector<>();
- final Scanner sc = new Scanner(L);
- sc.useDelimiter(",");
- while (sc.hasNext()) {
- final String tok = sc.next();
- a.add(new Rational(tok));
- }
- simplify();
- sc.close();
- } /* ctor */
-
- /**
- * Constructor from a hypergeometric series.
- *
- * @param A
- * the list of values in the numerator of AFB
- * @param B
- * the list of values in the denominator of AFB
- * @param nmax
- * the order of the truncated polynomial representation
- * @throws Error
- * @since 2008-11-13
- */
- public RatPoly(final Vector A, final Vector B, final int nmax) throws Error {
- /*
- * To allow common initialization with the signature below,
- * the main body is assembled in a separate function.
- */
- init(A, B, nmax);
- }
-
- /**
- * Constructor from a hypergeometric series.
- *
- * @param A
- * the list of values in the numerator of AFB.
- * At least one of these values must be a negative integer, which
- * implicitly determines
- * the order of the new polynomial.
- * @param B
- * the list of values in the denominator of AFB
- * @throws Error
- * @since 2009-08-05
- */
- public RatPoly(final Vector A, final Vector B) throws Error {
- 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) {
- Nmax = A.elementAt(j).negate();
- } else {
- Nmax = Nmax.min(A.elementAt(j).negate());
- }
- }
- }
- if (Nmax.compareTo(BigInteger.ZERO) < 0) {
- throw new ArithmeticException("Infinite Number of Terms in Series " + Nmax.toString());
- }
-
- final int nmax = Nmax.intValue() - 1;
- init(A, B, nmax);
- } /* ctor */
-
- /**
- * Constructor from a hypergeometric series.
- *
- * @param A
- * the list of values in the numerator of AFB
- * @param B
- * the list of values in the denominator of AFB
- * @param nmax
- * the order of the truncated polynomial representation
- * @throws Error
- * @since 2008-11-13
- */
- protected void init(final Vector A, final Vector B, final int nmax) throws Error {
- a = new Vector<>();
- 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++) {
- final Rational aEl = new Rational(A.elementAt(j));
- c = c.multiply(aEl.Pochhammer(n));
- }
- for (int j = 0; j < B.size(); j++) {
- final Rational bEl = new Rational(B.elementAt(j));
- c = c.divide(bEl.Pochhammer(n));
- }
- c = c.divide(f.at(n));
- a.add(c);
- }
- simplify();
- } /* init */
-
- /**
- * Create a copy of this.
- *
- * @since 2008-11-07
- */
- @Override
- @SuppressWarnings("unchecked")
- public RatPoly clone() {
- final RatPoly clo = new RatPoly();
- clo.a = (Vector) a.clone();
- return clo;
- } /* clone */
-
- /**
- * Retrieve a polynomial coefficient.
- *
- * @param n
- * the zero-based index of the coefficient. n=0 for the constant
- * term.
- * @return the polynomial coefficient in front of x^n.
- */
- public Rational at(final int n) {
- if (n < a.size()) {
- return a.elementAt(n);
- } else {
- return new Rational(0, 1);
- }
- } /* at */
-
- /**
- * Horner scheme to find the function value at the argument x
- *
- * @param x
- * The argument of the polynomial
- * @param mc
- * The context determining the precision of the value returned.
- * @since 2008-10-26
- */
- public BigComplex valueOf(final BigComplex x, final MathContext mc) {
- /* result is initialized to zero */
- BigComplex f = new BigComplex();
- for (int i = degree(); i >= 0; i--) {
- f = f.multiply(x, mc).add(a.elementAt(i).BigDecimalValue(mc));
- }
- return f;
- } /* valueOf */
-
- /**
- * Horner scheme to find the function value at the argument x
- *
- * @param x
- * The argument of the polynomial
- * @since 2008-11-13
- */
- public Rational valueOf(final Rational x) {
- /* result is initialized to zero */
- Rational f = new Rational(0, 1);
- for (int i = degree(); i >= 0; i--) {
- f = f.multiply(x).add(a.elementAt(i));
- }
- return f;
- } /* valueOf */
-
- /**
- * Horner scheme to find the function value at the argument x
- *
- * @param x
- * The argument of the polynomial
- * @since 2008-11-13
- */
- public Rational valueOf(final int x) {
- return valueOf(new Rational(x, 1));
- } /* valueOf */
-
- /**
- * Horner scheme to evaluate the function at the argument x
- *
- * @param x
- * The argument of the polynomial
- * @since 2010-08-27
- */
- public Rational valueOf(final BigInteger x) {
- return valueOf(new Rational(x));
- } /* valueOf */
-
- /*
- * Set a polynomial coefficient.
- *
- * @param n the zero-based index of the coefficient. n=0 for the constant
- * term.
- * If the polynomial has not yet the degree to need this coefficient,
- * the intermediate coefficients are implicitly set to zero.
- *
- * @param value the new value of the coefficient.
- */
- public void set(final int n, final Rational value) {
- if (n < a.size()) {
- a.set(n, value);
- } else {
- /*
- * fill intermediate powers with coefficients of zero
- */
- while (a.size() < n) {
- a.add(new Rational(0, 1));
- }
- a.add(value);
- }
- } /* set */
-
- /**
- * Set a polynomial coefficient.
- *
- * @param n
- * the zero-based index of the coefficient. n=0 for the constant
- * term.
- * If the polynomial has not yet the degree to need this
- * coefficient,
- * the intermediate coefficients are implicitly set to zero.
- * @param value
- * the new value of the coefficient.
- */
- public void set(final int n, final BigInteger value) {
- final Rational val2 = new Rational(value, BigInteger.ONE);
- set(n, val2);
- } /* set */
-
- /**
- * Set a polynomial coefficient.
- *
- * @param n
- * the zero-based index of the coefficient. n=0 for the constant
- * term.
- * If the polynomial has not yet the degree to need this
- * coefficient,
- * the intermediate coefficients are implicitly set to zero.
- * @param value
- * the new value of the coefficient.
- */
- public void set(final int n, final int value) {
- final Rational val2 = new Rational(value, 1);
- set(n, val2);
- } /* set */
-
- /*
- * Set to the taylor series of exp(x) up to degree nmax.
- *
- * @param nmax the maximum polynomial degree
- */
- public void setExp(final int nmax) {
- a.clear();
- final Factorial factorial = new Factorial();
- for (int n = 0; n <= nmax; n++) {
- set(n, new Rational(BigInteger.ONE, factorial.at(n)));
- }
- } /* setExp */
-
- /**
- * Set to the taylor series representing 0+x.
- */
- public void setx() {
- a.clear();
- /* coefficient 0/1=0 */
- a.add(new Rational(0, 1));
- /* coefficient 1/1=1 */
- a.add(new Rational(1, 1));
- } /* setx */
-
- /**
- * Count of coefficients. One more than the degree of the polynomial.
- *
- * @return the number of polynomial coefficients.
- */
- public int size() {
- return a.size();
- } /* size */
-
- /**
- * Polynomial degree.
- *
- * @return the polynomial degree.
- */
- public int degree() {
- return a.size() - 1;
- } /* degree */
-
- /**
- * Lower Polynomial degree.
- *
- * @return The smallest exponent n such that [x^n] of the polynomial is
- * nonzero.
- * If the polynmial is identical zero, the result is (still) 0.
- * @since 2010-08-27
- */
- public int ldegree() {
- for (int n = 0; n < a.size(); n++) {
- if (a.elementAt(n).compareTo(BigInteger.ZERO) != 0) {
- return n;
- }
- }
- return 0;
- } /* ldegree */
-
- /**
- * Multiply by a constant factor.
- *
- * @param val
- * the factor
- * @return the product of this with the factor.
- * All coefficients of this have been multiplied individually by the
- * factor.
- */
- public RatPoly multiply(final Rational val) {
- 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 */
-
- /**
- * Multiply by a constant factor.
- *
- * @param val
- * the factor
- * @return the product of this with the factor.
- * All coefficients of this have been multiplied individually by the
- * factor.
- * @since 2010-08-27
- */
- public RatPoly multiply(final BigInteger val) {
- 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 */
-
- /**
- * Multiply by another polynomial
- *
- * @param val
- * the other polynomial
- * @return the product of this with the other polynomial
- */
- public RatPoly multiply(final RatPoly val) {
- final RatPoly resul = new RatPoly();
- /*
- * 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++) {
- Rational coef = new Rational(0, 1);
- for (int nleft = 0; nleft <= n; nleft++) {
- coef = coef.add(at(nleft).multiply(val.at(n - nleft)));
- }
- resul.set(n, coef);
- }
- resul.simplify();
- return resul;
- } /* multiply */
-
- /**
- * Raise to a positive power.
- *
- * @param n
- * The non-negative exponent of the power
- * @return The n-th power of this.
- */
- public RatPoly pow(final int n) throws ArithmeticException {
- RatPoly resul = new RatPoly("1");
- if (n < 0) {
- throw new ArithmeticException("negative polynomial power " + n);
- } 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++) {
- resul = resul.multiply(this);
- }
- resul.simplify();
- return resul;
- }
- } /* pow */
-
- /**
- * Raise to a rational power.
- * The result is the taylor expansion of this, truncated at the first
- * term that remains undetermined based on the current number of
- * coefficients.
- *
- * @param r
- * the exponent of the power
- * @return This^r .
- * @throws Error
- * @since 2009-05-18
- */
- public RatPoly pow(final Rational r) throws ArithmeticException, Error {
- /*
- * split (a0+a1*x+a2*x^2+...)^r = a0^r*(1+a1/a0*r+a2/a0*r^2+..)^r
- */
- Rational f = at(0);
- f = f.pow(r);
-
- /*
- * scale the polynomial by division through the expansion coefficient of
- * the absolute term
- */
- final RatPoly red = divide(a.elementAt(0));
-
- /*
- * and remove the leading term (now equal to 1)
- */
- red.set(0, 0);
-
- /*
- * Binomial expansion of the rest. sum_{l=0..infinity}
- * binomial(r,l)*red^l
- */
- RatPoly resul = new RatPoly("1");
-
- final int d = degree();
- for (int l = 1; l <= d; l++) {
- final Rational b = Rational.binomial(r, l);
- resul = resul.add(red.pow(l).multiply(b));
- }
- return resul.multiply(f);
- } /* pow */
-
- /**
- * Add another polynomial
- *
- * @param val
- * The other polynomial
- * @return The sum of this and the other polynomial
- * @since 2008-10-25
- */
- public RatPoly add(final RatPoly val) {
- 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++) {
- final Rational coef = at(n).add(val.at(n));
- resul.set(n, coef);
- }
- resul.simplify();
- return resul;
- } /* add */
-
- /**
- * Subtract another polynomial
- *
- * @param val
- * The other polynomial
- * @return The difference between this and the other polynomial
- * @since 2008-10-25
- */
- public RatPoly subtract(final RatPoly val) {
- 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++) {
- final Rational coef = at(n).subtract(val.at(n));
- resul.set(n, coef);
- }
- resul.simplify();
- return resul;
- } /* subtract */
-
- /**
- * Divide by a constant.
- *
- * @param val
- * the constant through which the coefficients will be divided.
- * @return the Taylor expansion of this/val .
- * @throws Error
- * @since 2009-05-18
- */
- public RatPoly divide(final Rational val) throws Error {
- if (val.compareTo(Rational.ZERO) != 0) {
- final RatPoly resul = new RatPoly();
- for (int n = 0; n < a.size(); n++) {
- resul.set(n, a.elementAt(n).divide(val));
- }
- return resul;
- } else {
- throw new ArithmeticException("Cannot divide " + toPString() + " through zero.");
- }
- } /* divide */
-
- /**
- * Divide by another polynomial.
- *
- * @param val
- * the other polynomial
- * @param nmax
- * the maximum degree of the Taylor expansion of the result.
- * @return the Taylor expansion of this/val up to degree nmax.
- * @throws Error
- */
- public RatPoly divide(final RatPoly val, final int nmax) throws Error {
- final RatPoly num = this;
- final RatPoly denom = val;
-
- /*
- * divide by a common smallest power/degree
- */
- 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) {
- break;
- }
- }
-
- final RatPoly resul = new RatPoly();
- /*
- * todo: If the polynomial division is exact, we could leave
- * the loop earlier, indeed
- */
- for (int n = 0; n <= nmax; n++) {
- Rational coef = num.at(n);
- for (int nres = 0; nres < n; nres++) {
- coef = coef.subtract(resul.at(nres).multiply(denom.at(n - nres)));
- }
- coef = coef.divide(denom.at(0));
- resul.set(n, coef);
- }
- resul.simplify();
- return resul;
- } /* divide */
-
- /**
- * Divide by another polynomial.
- *
- * @param val
- * the other polynomial
- * @return A vector with [0] containg the polynomial of degree which is the
- * difference of thisdegree and the degree of val. [1] the remainder
- * polynomial.
- * This = returnvalue[0] + returnvalue[1]/val .
- * @throws Error
- * @since 2012-03-01
- */
- public RatPoly[] divideAndRemainder(final RatPoly val) throws Error {
- final RatPoly[] ret = new RatPoly[2];
- /*
- * remove any high-order zeros
- */
- final RatPoly valSimpl = val.clone();
- valSimpl.simplify();
- 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) {
- throw new ArithmeticException("Division through zero polynomial");
- }
- /*
- * degree of this smaller than degree of val: remainder is this
- */
- if (thisSimpl.degree() < valSimpl.degree()) {
- /*
- * leading polynomial equals zero
- */
- ret[0] = new RatPoly();
- ret[1] = thisSimpl;
- } else {
- /*
- * long division. Highest degree by dividing the highest degree
- * of this thru val.
- */
- ret[0] = new RatPoly();
- ret[0].set(thisSimpl.degree() - valSimpl.degree(), thisSimpl.a.lastElement().divide(valSimpl.a.lastElement()));
-
- /*
- * recurrences: build this - val*(1-termresult) and feed this
- * into another round of division. Have intermediate
- * ret[0]+ret[1]/val.
- */
- ret[1] = thisSimpl.subtract(ret[0].multiply(valSimpl));
-
- /*
- * any remainder left ?
- */
- if (ret[1].degree() < valSimpl.degree()) {
- ;
- } else {
- final RatPoly rem[] = ret[1].divideAndRemainder(val);
- ret[0] = ret[0].add(rem[0]);
- ret[1] = rem[1];
- }
- }
- return ret;
- } /* divideAndRemainder */
-
- /**
- * Print as a comma-separated list of coefficients.
- *
- * @return The representation a0,a1,a2,a3,...
- * This is a sort of opposite of the ctor that takes a string as an
- * argument.
- * @since 2008-10-25
- */
- @Override
- public String toString() {
- String str = new String();
- for (int n = 0; n < a.size(); n++) {
- if (n == 0) {
- str += a.elementAt(n).toString();
- } else {
- str += "," + a.elementAt(n).toString();
- }
- }
- /*
- * print at least a sole zero
- */
- if (str.length() == 0) {
- str = "0";
- }
- return str;
- } /* toString */
-
- /**
- * Print as a polyomial in x.
- *
- * @return To representation a0+a1*x+a2*x^2+...
- * This does not print the terms with coefficients equal to zero.
- * @since 2008-10-26
- */
- public String toPString() {
- String str = new String();
- for (int n = 0; n < a.size(); n++) {
- final BigInteger num = a.elementAt(n).a;
- if (num.compareTo(BigInteger.ZERO) != 0) {
- str += " ";
- if (num.compareTo(BigInteger.ZERO) > 0) {
- str += "+";
- }
- str += a.elementAt(n).toString();
- if (n > 0) {
- str += "*x";
- if (n > 1) {
- str += "^" + n;
- }
- }
- }
- }
- /*
- * print at least a sole zero
- */
- if (str.length() == 0) {
- str = "0";
- }
- return str;
- } /* toPString */
-
- /**
- * Simplify the representation.
- * Trailing values with zero coefficients (at high powers) are deleted.
- * This modifies the polynomial on the stop (does not return another
- * instance)
- */
- private void simplify() {
- int n = a.size() - 1;
- if (n >= 0) {
- while (a.elementAt(n).compareTo(BigInteger.ZERO) == 0) {
- a.remove(n);
- if (--n < 0) {
- break;
- }
- }
- }
- } /* simplify */
-
- /**
- * First derivative.
- *
- * @return The first derivative with respect to the indeterminate variable.
- * @since 2008-10-26
- */
- public RatPoly derive() {
- if (a.size() <= 1) {
- /*
- * derivative of the constant is just zero
- */
- return 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);
- }
- return d;
- }
- } /* derive */
-
- /**
- * Scale coefficients such that the coefficient in front of the maximum
- * degree is unity.
- *
- * @return The scaled polynomial
- * @throws Error
- * @since 2008-10-26
- */
- public RatPoly monic() throws Error {
- 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));
- m.set(i, c);
- }
- return m;
- } /* monic */
-
- /**
- * Mobius transform.
- *
- * @param maxdeg
- * the maximum polynomial degree of the result
- * @return the sequence of coefficients is the Mobius transform of the
- * original sequence.
- * @since 2008-12-02
- */
- public RatPoly mobiusT(final int maxdeg) {
- /*
- * Start with the polynomial 0
- */
- 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) {
- final Ifactor m = new Ifactor(i / d);
- c = c.add(a.elementAt(d).multiply(m.moebius()));
- }
- }
- r.set(i, c);
- }
- r.simplify();
- return r;
- } /* mobiusT */
-
- /**
- * Inverse Mobius transform.
- *
- * @param maxdeg
- * the maximum polynomial degree of the result
- * @return the sequence of coefficients is the inverse Mobius transform of
- * the original sequence.
- * @since 2008-12-02
- */
- public RatPoly mobiusTInv(final int maxdeg) {
- /*
- * Start with the polynomial 0
- */
- 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) {
- c = c.add(a.elementAt(d));
- }
- }
- r.set(i, c);
- }
- r.simplify();
- return r;
- } /* mobiusTInv */
-
- /**
- * Binomial transform.
- *
- * @param maxdeg
- * the maximum polynomial degree of the result
- * @return the sequence of coefficients is the binomial transform of the
- * original sequence.
- * @since 2008-10-26
- */
- public RatPoly binomialT(final int maxdeg) {
- 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++) {
- c = c.add(a.elementAt(j).multiply(BigIntegerMath.binomial(i, j)));
- }
- r.set(i, c);
- }
- r.simplify();
- return r;
- } /* binomialT */
-
- /**
- * Inverse Binomial transform.
- *
- * @param maxdeg
- * the maximum polynomial degree of the result
- * @return the sequence of coefficients is the inverse binomial transform of
- * the original sequence.
- * @since 2008-10-26
- */
- public RatPoly binomialTInv(final int maxdeg) {
- 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) {
- c = c.subtract(a.elementAt(j).multiply(BigIntegerMath.binomial(i, j)));
- } else {
- c = c.add(a.elementAt(j).multiply(BigIntegerMath.binomial(i, j)));
- }
- }
- r.set(i, c);
- }
- r.simplify();
- return r;
- } /* binomialTInv */
-
- /**
- * Truncate polynomial degree.
- *
- * @param newdeg
- * The maximum degree of the result.
- * @return The polynomial with all coefficients beyond deg set to zero.
- * If newdeg =3, for example the polynomial returned has at most
- * degree 3.
- * If newdeg is larger than the degree of this, zeros (at the higher
- * orders of x)
- * are appended. That polynomial would have formal degree larger
- * than this.
- * @since 2008-10-26
- */
- public RatPoly trunc(final int newdeg) {
- final RatPoly t = new RatPoly();
- for (int i = 0; i <= newdeg; i++) {
- t.set(i, at(i));
- }
- t.simplify();
- return t;
- } /* trunc */
-
- /**
- * Generate the roots of the polynomial in floating point arithmetic.
- *
- * @see Durand
- * Kerner method
- * @param the
- * number of floating point digits
- * @throws Error
- * @since 2008-10-26
- */
- public Vector roots(final int digits) throws Error {
- final RatPoly mon = monic();
-
- final Random rand = new Random();
- final MathContext mc = new MathContext(digits + 3, RoundingMode.DOWN);
-
- Vector res = new Vector<>();
-
- final int d = mon.degree();
- double randRad = 0.;
- for (int i = 0; i <= d; i++) {
- /* scale coefficient at maximum degree */
- final double absi = Math.abs(mon.at(i).doubleValue());
- if (absi > randRad) {
- randRad = absi;
- }
- }
- randRad += 1.0;
-
- /*
- * initial values randomly in radius 1+randRad
- */
- for (int i = 0; i < d; i++) {
- 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)));
- }
-
- /*
- * iterate until convr indicates that all values changed by less than
- * the digits
- * precision indicates.
- */
- boolean convr = false;
- for (; !convr;)// ORIGINAL LINE: for(int itr =0 ; ! convr ; itr++)
- {
- convr = true;
- final Vector resPlus = new Vector<>();
- for (int v = 0; v < d; v++) {
- /*
- * evaluate f(x)/(x-root1)/(x-root2)/... (x-rootdegr), Newton
- * method
- */
- BigComplex thisx = res.elementAt(v);
- BigComplex nv = mon.valueOf(thisx, mc);
- for (int j = 0; j < d; j++) {
- 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)) {
- convr = false;
- }
-
- thisx = thisx.subtract(nv);
-
- /* If unstable, start over */
- if (thisx.abs(MathContext.DECIMAL32).doubleValue() > randRad) {
- return roots(digits);
- }
-
- resPlus.add(thisx);
- }
- res = resPlus;
-
- }
- return res;
- } /* roots */
-
- /**
- * Generate the integer roots of the polynomial.
- *
- * @return The vector of integer roots, with multiplicity.
- * The shows alternatingly first a root then its multiplicty, then
- * another root and multiplicty etc.
- * @since 2008-10-26
- */
- public Vector iroots() {
- /* The vector of the roots */
- final Vector res = new Vector<>();
-
- final int lowd = ldegree();
- if (lowd == 0 && a.elementAt(0).compareTo(BigInteger.ZERO) == 0) {
- /*
- * Case of polynomial identical to zero:
- * reported as a simple root of value 0.
- */
- res.add(BigInteger.ZERO);
- res.add(BigInteger.ONE);
- return res;
- }
-
- /*
- * multiply all coefs with the lcm() to get an integer polynomial
- * start with denominator of first non-zero coefficient.
- */
- BigInteger lcmDeno = a.elementAt(lowd).b;
- 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
- */
- final Vector ipo = new Vector<>();
- for (int i = 0; i < a.size(); i++) {
- final BigInteger d = a.elementAt(i).a.multiply(lcmDeno).divide(a.elementAt(i).b);
- ipo.add(d);
- }
-
- 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.
- */
- final Vector cand = p.iroots();
- for (int i = 0; i < cand.size(); i++) {
- final BigInteger r = cand.elementAt(i);
- final int deg = p.rootDeg(r);
- res.add(r);
- res.add(new BigInteger("" + deg));
- }
-
- return res;
- } /* iroots */
-
-} /* RatPoly */
diff --git a/core/src/main/java/org/nevec/rjm/Rational.java b/core/src/main/java/org/nevec/rjm/Rational.java
deleted file mode 100644
index f11574a8..00000000
--- a/core/src/main/java/org/nevec/rjm/Rational.java
+++ /dev/null
@@ -1,900 +0,0 @@
-package org.nevec.rjm;
-
-import java.math.BigDecimal;
-import java.math.BigInteger;
-import java.math.MathContext;
-import java.math.RoundingMode;
-
-import it.cavallium.warppi.util.Error;
-import it.cavallium.warppi.util.Errors;
-
-/**
- * Fractions (rational numbers). They are divisions of two BigInteger numbers,
- * reduced to coprime numerator and denominator.
- *
- * @since 2006-06-25
- * @author Richard J. Mathar
- */
-public class Rational implements Cloneable, Comparable {
- /**
- * numerator
- */
- BigInteger a;
-
- /**
- * denominator, always larger than zero.
- */
- BigInteger b;
-
- /**
- * The maximum and minimum value of a standard Java integer, 2^31.
- *
- * @since 2009-05-18
- */
- static public BigInteger MAX_INT = new BigInteger("2147483647");
- static public BigInteger MIN_INT = new BigInteger("-2147483648");
-
- /**
- * The constant 1.
- */
- public static Rational ONE = new Rational(1, 1);
- /**
- * The constant 0.
- */
- static public Rational ZERO = new Rational();
-
- /**
- * The constant 1/2
- *
- * @since 2010-05-25
- */
- static public Rational HALF = new Rational(1, 2);
-
- /**
- * Default ctor, which represents the zero.
- *
- * @since 2007-11-17
- */
- public Rational() {
- a = BigInteger.ZERO;
- b = BigInteger.ONE;
- }
-
- /**
- * ctor from a numerator and denominator.
- *
- * @param a
- * the numerator.
- * @param b
- * the denominator.
- */
- public Rational(final BigInteger a, final BigInteger b) {
- this.a = a;
- this.b = b;
- normalize();
- }
-
- /**
- * ctor from a numerator.
- *
- * @param a
- * the BigInteger.
- */
- public Rational(final BigInteger a) {
- this.a = a;
- b = new BigInteger("1");
- }
-
- /**
- * ctor from a numerator and denominator.
- *
- * @param a
- * the numerator.
- * @param b
- * the denominator.
- */
- public Rational(final int a, final int b) {
- this(new BigInteger("" + a), new BigInteger("" + b));
- }
-
- /**
- * ctor from an integer.
- *
- * @param n
- * the integer to be represented by the new instance.
- * @since 2010-07-18
- */
- public Rational(final int n) {
- this(n, 1);
- }
-
- /**
- * ctor from a string representation.
- *
- * @param str
- * the string. This either has a slash in it, separating two
- * integers, or, if there is no slash, is representing the
- * numerator with implicit denominator equal to 1. Warning: this
- * does not yet test for a denominator equal to zero
- */
- public Rational(final String str) {
- this(str, 10);
- }
-
- /**
- * ctor from a string representation in a specified base.
- *
- * @param str
- * the string. This either has a slash in it, separating two
- * integers, or, if there is no slash, is just representing the
- * numerator.
- * @param radix
- * the number base for numerator and denominator Warning: this
- * does not yet test for a denominator equal to zero
- */
- public Rational(final String str, final int radix) {
- final int hasslah = str.indexOf("/");
- if (hasslah == -1) {
- a = new BigInteger(str, radix);
- b = new BigInteger("1", radix);
- /* no normalization necessary here */
- } else {
- /*
- * create numerator and denominator separately
- */
- a = new BigInteger(str.substring(0, hasslah), radix);
- b = new BigInteger(str.substring(hasslah + 1), radix);
- normalize();
- }
- }
-
- /**
- * Create a copy.
- *
- * @since 2008-11-07
- */
- @Override
- public Rational clone() {
- /*
- * protected access means this does not work return new
- * Rational(a.clone(), b.clone()) ;
- */
- final BigInteger aclon = new BigInteger("" + a);
- final BigInteger bclon = new BigInteger("" + b);
- return new Rational(aclon, bclon);
- } /* Rational.clone */
-
- /**
- * Multiply by another fraction.
- *
- * @param val
- * a second rational number.
- * @return the product of this with the val.
- */
- public Rational multiply(final Rational val) {
- 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.
- */
- return new Rational(num, deno);
- } /* Rational.multiply */
-
- /**
- * Multiply by a BigInteger.
- *
- * @param val
- * a second number.
- * @return the product of this with the value.
- */
- public Rational multiply(final BigInteger val) {
- final Rational val2 = new Rational(val, BigInteger.ONE);
- return multiply(val2);
- } /* Rational.multiply */
-
- /**
- * Multiply by an integer.
- *
- * @param val
- * a second number.
- * @return the product of this with the value.
- */
- public Rational multiply(final int val) {
- final BigInteger tmp = new BigInteger("" + val);
- return multiply(tmp);
- } /* Rational.multiply */
-
- /**
- * Power to an integer.
- *
- * @param exponent
- * the exponent.
- * @return this value raised to the power given by the exponent. If the
- * exponent is 0, the value 1 is returned.
- */
- public Rational pow(final int exponent) {
- if (exponent == 0) {
- return new Rational(1, 1);
- }
-
- 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 {
- return new Rational(deno, num);
- }
- } /* Rational.pow */
-
- /**
- * Power to an integer.
- *
- * @param exponent
- * the exponent.
- * @return this value raised to the power given by the exponent. If the
- * exponent is 0, the value 1 is returned.
- * @throws Error
- * @since 2009-05-18
- */
- public Rational pow(final BigInteger exponent) throws Error {
- /* test for overflow */
- if (exponent.compareTo(Rational.MAX_INT) == 1) {
- throw new Error(Errors.NUMBER_TOO_LARGE);
- }
- if (exponent.compareTo(Rational.MIN_INT) == -1) {
- throw new Error(Errors.NUMBER_TOO_SMALL);
- }
-
- /* promote to the simpler interface above */
- return pow(exponent.intValue());
- } /* Rational.pow */
-
- /**
- * r-th root.
- *
- * @param r
- * the inverse of the exponent. 2 for the square root, 3 for the
- * third root etc
- * @return this value raised to the inverse power given by the root
- * argument, this^(1/r).
- * @throws Error
- * @since 2009-05-18
- */
- public Rational root(final BigInteger r) throws Error {
- /* test for overflow */
- if (r.compareTo(Rational.MAX_INT) == 1) {
- throw new Error(Errors.NUMBER_TOO_LARGE);
- }
- if (r.compareTo(Rational.MIN_INT) == -1) {
- throw new Error(Errors.NUMBER_TOO_SMALL);
- }
-
- final int rthroot = r.intValue();
- /* cannot pull root of a negative value with even-valued root */
- if (compareTo(Rational.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
- * sign
- */
- final boolean flipsign = compareTo(Rational.ZERO) == -1 && rthroot % 2 != 0 ? true : false;
-
- /*
- * delegate the main work to ifactor#root()
- */
- 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) {
- return resul.negate();
- } else {
- return resul;
- }
- } /* Rational.root */
-
- /**
- * Raise to a rational power.
- *
- * @param exponent
- * The exponent.
- * @return This value raised to the power given by the exponent. If the
- * exponent is 0, the value 1 is returned.
- * @throws Error
- * @since 2009-05-18
- */
- public Rational pow(final Rational exponent) throws Error {
- 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)
- */
- final Rational tmp = pow(exponent.a);
- return tmp.root(exponent.b);
- } /* Rational.pow */
-
- /**
- * Divide by another fraction.
- *
- * @param val
- * A second rational number.
- * @return The value of this/val
- * @throws Error
- */
- public Rational divide(final Rational val) throws Error {
- if (val.compareTo(Rational.ZERO) == 0) {
- throw new Error(Errors.DIVISION_BY_ZERO);
- }
- 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.
- */
- return new Rational(num, deno);
- } /* Rational.divide */
-
- /**
- * Divide by an integer.
- *
- * @param val
- * a second number.
- * @return the value of this/val
- * @throws Error
- */
- public Rational divide(final BigInteger val) throws Error {
- if (val.compareTo(BigInteger.ZERO) == 0) {
- throw new Error(Errors.DIVISION_BY_ZERO);
- }
- final Rational val2 = new Rational(val, BigInteger.ONE);
- return divide(val2);
- } /* Rational.divide */
-
- /**
- * Divide by an integer.
- *
- * @param val
- * A second number.
- * @return The value of this/val
- * @throws Error
- */
- public Rational divide(final int val) throws Error {
- if (val == 0) {
- throw new Error(Errors.DIVISION_BY_ZERO);
- }
- final Rational val2 = new Rational(val, 1);
- return divide(val2);
- } /* Rational.divide */
-
- /**
- * Add another fraction.
- *
- * @param val
- * The number to be added
- * @return this+val.
- */
- public Rational add(final Rational val) {
- 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 */
-
- /**
- * Add another integer.
- *
- * @param val
- * The number to be added
- * @return this+val.
- */
- public Rational add(final BigInteger val) {
- final Rational val2 = new Rational(val, BigInteger.ONE);
- return add(val2);
- } /* Rational.add */
-
- /**
- * Add another integer.
- *
- * @param val
- * The number to be added
- * @return this+val.
- * @since May 26 2010
- */
- public Rational add(final int val) {
- final BigInteger val2 = a.add(b.multiply(new BigInteger("" + val)));
- return new Rational(val2, b);
- } /* Rational.add */
-
- /**
- * Compute the negative.
- *
- * @return -this.
- */
- public Rational negate() {
- return new Rational(a.negate(), b);
- } /* Rational.negate */
-
- /**
- * Subtract another fraction.
- *
- * @param val
- * the number to be subtracted from this
- * @return this - val.
- */
- public Rational subtract(final Rational val) {
- final Rational val2 = val.negate();
- return add(val2);
- } /* Rational.subtract */
-
- /**
- * Subtract an integer.
- *
- * @param val
- * the number to be subtracted from this
- * @return this - val.
- */
- public Rational subtract(final BigInteger val) {
- final Rational val2 = new Rational(val, BigInteger.ONE);
- return subtract(val2);
- } /* Rational.subtract */
-
- /**
- * Subtract an integer.
- *
- * @param val
- * the number to be subtracted from this
- * @return this - val.
- */
- public Rational subtract(final int val) {
- final Rational val2 = new Rational(val, 1);
- return subtract(val2);
- } /* Rational.subtract */
-
- /**
- * binomial (n choose m).
- *
- * @param n
- * the numerator. Equals the size of the set to choose from.
- * @param m
- * the denominator. Equals the number of elements to select.
- * @return the binomial coefficient.
- * @since 2006-06-27
- * @author Richard J. Mathar
- * @throws Error
- */
- public static Rational binomial(final Rational n, final BigInteger m) throws Error {
- 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);
- }
- return bin;
- } /* Rational.binomial */
-
- /**
- * binomial (n choose m).
- *
- * @param n
- * the numerator. Equals the size of the set to choose from.
- * @param m
- * the denominator. Equals the number of elements to select.
- * @return the binomial coefficient.
- * @since 2009-05-19
- * @author Richard J. Mathar
- * @throws Error
- */
- public static Rational binomial(final Rational n, final int m) throws Error {
- 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);
- }
- return bin;
- } /* Rational.binomial */
-
- /**
- * Hankel's symbol (n,k)
- *
- * @param n
- * the first parameter.
- * @param k
- * the second parameter, greater or equal to 0.
- * @return Gamma(n+k+1/2)/k!/GAMMA(n-k+1/2)
- * @since 2010-07-18
- * @author Richard J. Mathar
- * @throws Error
- */
- public static Rational hankelSymb(final Rational n, final int k) throws Error {
- if (k == 0) {
- return Rational.ONE;
- } else if (k < 0) {
- throw new Error(Errors.NEGATIVE_PARAMETER);
- }
- Rational nkhalf = n.subtract(k).add(Rational.HALF);
- nkhalf = nkhalf.Pochhammer(2 * k);
- final Factorial f = new Factorial();
- return nkhalf.divide(f.at(k));
- } /* Rational.binomial */
-
- /**
- * Get the numerator.
- *
- * @return The numerator of the reduced fraction.
- */
- public BigInteger numer() {
- return a;
- }
-
- /**
- * Get the denominator.
- *
- * @return The denominator of the reduced fraction.
- */
- public BigInteger denom() {
- return b;
- }
-
- /**
- * Absolute value.
- *
- * @return The absolute (non-negative) value of this.
- */
- public Rational abs() {
- return new Rational(a.abs(), b.abs());
- }
-
- /**
- * floor(): the nearest integer not greater than this.
- *
- * @return The integer rounded towards negative infinity.
- */
- public BigInteger floor() {
- /*
- * is already integer: return the numerator
- */
- if (b.compareTo(BigInteger.ONE) == 0) {
- return a;
- } else if (a.compareTo(BigInteger.ZERO) > 0) {
- return a.divide(b);
- } else {
- return a.divide(b).subtract(BigInteger.ONE);
- }
- } /* Rational.floor */
-
- /**
- * ceil(): the nearest integer not smaller than this.
- *
- * @return The integer rounded towards positive infinity.
- * @since 2010-05-26
- */
- public BigInteger ceil() {
- /*
- * is already integer: return the numerator
- */
- if (b.compareTo(BigInteger.ONE) == 0) {
- return a;
- } else if (a.compareTo(BigInteger.ZERO) > 0) {
- return a.divide(b).add(BigInteger.ONE);
- } else {
- return a.divide(b);
- }
- } /* Rational.ceil */
-
- /**
- * Remove the fractional part.
- *
- * @return The integer rounded towards zero.
- */
- public BigInteger trunc() {
- /*
- * is already integer: return the numerator
- */
- if (b.compareTo(BigInteger.ONE) == 0) {
- return a;
- } else {
- return a.divide(b);
- }
- } /* Rational.trunc */
-
- /**
- * Compares the value of this with another constant.
- *
- * @param val
- * the other constant to compare with
- * @return -1, 0 or 1 if this number is numerically less than, equal to, or
- * greater than val.
- */
- @Override
- public int compareTo(final Rational val) {
- /*
- * Since we have always kept the denominators positive, simple
- * cross-multiplying works without changing the sign.
- */
- final BigInteger left = a.multiply(val.b);
- final BigInteger right = val.a.multiply(b);
- return left.compareTo(right);
- } /* Rational.compareTo */
-
- /**
- * Compares the value of this with another constant.
- *
- * @param val
- * the other constant to compare with
- * @return -1, 0 or 1 if this number is numerically less than, equal to, or
- * greater than val.
- */
- public int compareTo(final BigInteger val) {
- final Rational val2 = new Rational(val, BigInteger.ONE);
- return compareTo(val2);
- } /* Rational.compareTo */
-
- /**
- * Return a string in the format number/denom. If the denominator equals 1,
- * print just the numerator without a slash.
- *
- * @return the human-readable version in base 10
- */
- @Override
- public String toString() {
- if (b.compareTo(BigInteger.ONE) != 0) {
- return a.toString() + "/" + b.toString();
- } else {
- return a.toString();
- }
- } /* Rational.toString */
-
- /**
- * Return a double value representation.
- *
- * @return The value with double precision.
- * @since 2008-10-26
- */
- public double doubleValue() {
- /*
- * To meet the risk of individual overflows of the exponents of a
- * separate invocation a.doubleValue() or b.doubleValue(), we divide
- * first in a BigDecimal environment and convert the result.
- */
- final BigDecimal adivb = new BigDecimal(a).divide(new BigDecimal(b), MathContext.DECIMAL128);
- return adivb.doubleValue();
- } /* Rational.doubleValue */
-
- /**
- * Return a float value representation.
- *
- * @return The value with single precision.
- * @since 2009-08-06
- */
- public float floatValue() {
- final BigDecimal adivb = new BigDecimal(a).divide(new BigDecimal(b), MathContext.DECIMAL128);
- return adivb.floatValue();
- } /* Rational.floatValue */
-
- /**
- * Return a representation as BigDecimal.
- *
- * @param mc
- * the mathematical context which determines precision, rounding
- * mode etc
- * @return A representation as a BigDecimal floating point number.
- * @since 2008-10-26
- */
- public BigDecimal BigDecimalValue(final MathContext mc) {
- /*
- * numerator and denominator individually rephrased
- */
- 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
- * truncated representation. 1/4 will appear as 0.25, independent of mc
- */
- return BigDecimalMath.scalePrec(n.divide(d, mc), mc);
- } /* Rational.BigDecimalValue */
-
- /**
- * Return a string in floating point format.
- *
- * @param digits
- * The precision (number of digits)
- * @return The human-readable version in base 10.
- * @since 2008-10-25
- */
- public String toFString(final int digits) {
- if (b.compareTo(BigInteger.ONE) != 0) {
- final MathContext mc = new MathContext(digits, RoundingMode.DOWN);
- final BigDecimal f = new BigDecimal(a).divide(new BigDecimal(b), mc);
- return f.toString();
- } else {
- return a.toString();
- }
- } /* Rational.toFString */
-
- /**
- * Compares the value of this with another constant.
- *
- * @param val
- * The other constant to compare with
- * @return The arithmetic maximum of this and val.
- * @since 2008-10-19
- */
- public Rational max(final Rational val) {
- if (compareTo(val) > 0) {
- return this;
- } else {
- return val;
- }
- } /* Rational.max */
-
- /**
- * Compares the value of this with another constant.
- *
- * @param val
- * The other constant to compare with
- * @return The arithmetic minimum of this and val.
- * @since 2008-10-19
- */
- public Rational min(final Rational val) {
- if (compareTo(val) < 0) {
- return this;
- } else {
- return val;
- }
- } /* Rational.min */
-
- /**
- * Compute Pochhammer's symbol (this)_n.
- *
- * @param n
- * The number of product terms in the evaluation.
- * @return Gamma(this+n)/Gamma(this) = this*(this+1)*...*(this+n-1).
- * @since 2008-10-25
- */
- public Rational Pochhammer(final BigInteger n) {
- if (n.compareTo(BigInteger.ZERO) < 0) {
- return null;
- } else if (n.compareTo(BigInteger.ZERO) == 0) {
- return Rational.ONE;
- } 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)) {
- res = res.multiply(add(i));
- }
- return res;
- }
- } /* Rational.pochhammer */
-
- /**
- * Compute pochhammer's symbol (this)_n.
- *
- * @param n
- * The number of product terms in the evaluation.
- * @return Gamma(this+n)/GAMMA(this).
- * @since 2008-11-13
- */
- public Rational Pochhammer(final int n) {
- return Pochhammer(new BigInteger("" + n));
- } /* Rational.pochhammer */
-
- /**
- * True if the value is integer. Equivalent to the indication whether a
- * conversion to an integer can be exact.
- *
- * @since 2010-05-26
- */
- public boolean isBigInteger() {
- return b.abs().compareTo(BigInteger.ONE) == 0;
- } /* Rational.isBigInteger */
-
- /**
- * True if the value is integer and in the range of the standard integer.
- * Equivalent to the indication whether a conversion to an integer can be
- * exact.
- *
- * @since 2010-05-26
- */
- public boolean isInteger() {
- if (!isBigInteger()) {
- return false;
- }
- return a.compareTo(Rational.MAX_INT) <= 0 && a.compareTo(Rational.MIN_INT) >= 0;
- } /* Rational.isInteger */
-
- /**
- * Conversion to an integer value, if this can be done exactly.
- *
- * @throws Error
- *
- * @since 2011-02-13
- */
- int intValue() throws Error {
- if (!isInteger()) {
- throw new Error(Errors.CONVERSION_ERROR);
- }
- return a.intValue();
- }
-
- /**
- * Conversion to a BigInteger value, if this can be done exactly.
- *
- * @throws Error
- *
- * @since 2012-03-02
- */
- BigInteger BigIntegerValue() throws Error {
- if (!isBigInteger()) {
- throw new Error(Errors.CONVERSION_ERROR);
- }
- return a;
- }
-
- /**
- * True if the value is a fraction of two integers in the range of the
- * standard integer.
- *
- * @since 2010-05-26
- */
- public boolean isIntegerFrac() {
- return a.compareTo(Rational.MAX_INT) <= 0 && a.compareTo(Rational.MIN_INT) >= 0 && b.compareTo(Rational.MAX_INT) <= 0 && b.compareTo(Rational.MIN_INT) >= 0;
- } /* Rational.isIntegerFrac */
-
- /**
- * The sign: 1 if the number is >0, 0 if ==0, -1 if <0
- *
- * @return the signum of the value.
- * @since 2010-05-26
- */
- public int signum() {
- return b.signum() * a.signum();
- } /* Rational.signum */
-
- /**
- * Common lcm of the denominators of a set of rational values.
- *
- * @param vals
- * The list/set of the rational values.
- * @return LCM(denom of first, denom of second, ..,denom of last)
- * @since 2012-03-02
- */
- static public BigInteger lcmDenom(final Rational[] vals) {
- BigInteger l = BigInteger.ONE;
- for (final Rational val : vals) {
- l = BigIntegerMath.lcm(l, val.b);
- }
- return l;
- } /* Rational.lcmDenom */
-
- /**
- * Normalize to coprime numerator and denominator. Also copy a negative sign
- * of the denominator to the numerator.
- *
- * @since 2008-10-19
- */
- protected void normalize() {
- /*
- * compute greatest common divisor of numerator and denominator
- */
- final BigInteger g = a.gcd(b);
- if (g.compareTo(BigInteger.ONE) > 0) {
- a = a.divide(g);
- b = b.divide(g);
- }
- if (b.compareTo(BigInteger.ZERO) == -1) {
- a = a.negate();
- b = b.negate();
- }
- } /* Rational.normalize */
-} /* Rational */
diff --git a/core/src/main/java/org/nevec/rjm/SafeMathContext.java b/core/src/main/java/org/nevec/rjm/SafeMathContext.java
deleted file mode 100644
index 95dd90e0..00000000
--- a/core/src/main/java/org/nevec/rjm/SafeMathContext.java
+++ /dev/null
@@ -1,27 +0,0 @@
-package org.nevec.rjm;
-
-import java.math.MathContext;
-import java.math.RoundingMode;
-
-import it.cavallium.warppi.Engine;
-import it.cavallium.warppi.Platform.ConsoleUtils;
-
-public final class SafeMathContext {
-
- public static MathContext newMathContext(int precision) {
- if (precision <= 0) {
- Engine.getPlatform().getConsoleUtils().out().print(ConsoleUtils.OUTPUTLEVEL_DEBUG_MIN, "Warning! MathContext precision is <= 0 (" + precision + ")");
- precision = 1;
- }
- return new MathContext(precision);
- }
-
- public static MathContext newMathContext(int precision, final RoundingMode roundingMode) {
- if (precision <= 0) {
- Engine.getPlatform().getConsoleUtils().out().print(ConsoleUtils.OUTPUTLEVEL_DEBUG_MIN, "Warning! MathContext precision is <= 0 (" + precision + ")");
- precision = 1;
- }
- return new MathContext(precision, roundingMode);
- }
-
-}
diff --git a/core/src/main/java/org/nevec/rjm/Wigner3j.java b/core/src/main/java/org/nevec/rjm/Wigner3j.java
deleted file mode 100644
index 114ddfa3..00000000
--- a/core/src/main/java/org/nevec/rjm/Wigner3j.java
+++ /dev/null
@@ -1,628 +0,0 @@
-package org.nevec.rjm;
-
-import java.math.BigInteger;
-import java.util.Scanner;
-
-import it.cavallium.warppi.util.Error;
-
-/**
- * Exact representations of Wigner 3jm and 3nj values of half-integer arguments.
- *
- * @see R. J. Mathar, Corrigendum to
- * "Universal factorzation fo 3n-j (j>2) symbols ..[J. Phys. A: Math. Gen.37 (2004) 3259]"
- *
- * @see R. J. Mathar, Symmetries in
- * Wigner 18-j and 21-j Symbols
- * @since 2011-02-15
- * @author Richard J. Mathar
- */
-public class Wigner3j {
- /**
- * Test programs. This supports three types of direct evaluations:
- * java -cp . org.nevec.rjm.Wigner3j 3jm 2j1+1 2j2+1 2j3+1 2m1+1 2m2+1 2m3+1
- *
- * java -cp . org.nevec.rjm.Wigner3j 6j 2j1+1 2j2+2 .. 2j6+1
- * java -cp . org.nevec.rjm.Wigner3j 9j 2j1+1 2j2+2 .. 2j9+1
- * The first command line argument is one of the three tags which determine
- * whether a 3jm, a 6j or a 9j symbol will be computed. The other arguments
- * are 6 or 9 integer values, which are the physical (half-integer) values
- * multplied by 2 and augmented by 1. The order of the 6 or 9 values is as
- * reading the corresponding standard symbol as first row, then second row
- * (and for the 9j symbol) third row.
- *
- * @since 2011-02-15
- * @author Richard J. Mathar
- * @throws Error
- */
- static public void main(final String args[]) throws Error {
- if (args[0].compareTo("6j") == 0) {
- try {
- 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++) {
- j += args[i] + " ";
- }
- final BigSurdVec w = Wigner3j.wigner3j(m1, t1, t2, j);
- System.out.println(w.toString());
- } catch (final Exception e) {
- System.out.println(e.getMessage());
- }
- } else if (args[0].compareTo("9j") == 0) {
- try {
- 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++) {
- j += args[i] + " ";
- }
- final BigSurdVec w = Wigner3j.wigner3j(m1, t1, t2, j);
- System.out.println(w.toString());
- } catch (final Exception e) {
- System.out.println(e.getMessage());
- }
- } else if (args[0].compareTo("3jm") == 0) {
- 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 = Wigner3j.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 (final Exception e) {
- System.out.println(e.getMessage());
- }
- } else {
- System.out.println("usage:");
- System.out.println(args[0] + " 6j 2j1+1 2j2+1 2j3+1 2j4+1 2j5+1 2j6+1");
- System.out.println(args[0] + " 9j 2j1+1 2j2+1 2j3+1 2j4+1 2j5+1 2j6+1.. 2j9+1 ");
- System.out.println(args[0] + " 3jm 2j1+1 2j2+1 2j3+1 2m1+1 2m2+1 2m3+1 ");
- }
- } /* Wigner3j.main */
-
- /**
- * The Wigner 3jm symbol (j1,j2,j3,m1,m2,m3). All arguments of the function
- * are the actual parameters multiplied by 2, so they all allow an integer
- * representation.
- *
- * @param j1
- * integer representing 2*j1
- * @param j2
- * integer representing 2*j2
- * @param j3
- * integer representing 2*j3
- * @param m1
- * integer representing 2*m1
- * @param m2
- * integer representing 2*m2
- * @param m3
- * integer representing 2*m3
- * @return The value of the symbol. Zero if any of the triangular
- * inequalities is violated or some parameters are out of range.
- * @since 2011-02-13
- * @author Richard J. Mathar
- * @throws Error
- */
- static public BigSurd wigner3jm(final int j1, final int j2, final int j3, final int m1, final int m2, final int m3)
- throws Error {
- 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 Wigner3j.wigner3jm(J1, J2, J3, M1, M2, M3);
- } /* wigner3jm */
-
- /**
- * Wigner 3jn symbol. For the 6j symbol, the input of the 3 lines is
- * "1 2 3 1 5 6", "4 5 3 4 2 6" "2j1+1 2j2+1 2j3+1 2l1+1 2l2+1 2l3+1"
- *
- * @param m1
- * The information on the number of angular momenta.
- * @param t1
- * The list of one half of the triads, indexing j, whitespace
- * separated
- * @param t2
- * The list of the second half of the triads, indexing j,
- * whitespace separated
- * @param j
- * The list of the integer values of the angular momenta. They
- * are actually the doubled j-values plus 1, whitespace
- * separated. Only as many as announced by the m1 parameter are
- * used; trailing numbers are ignored.
- * @see A. Bar-Shalom and M. Klapisch,
- * NJGRAF...
- * , Comp. Phys Comm. 50 (3) (1988) 375
- * @since 2011-02-13
- * @since 2012-02-15 Upgraded return value to BigSurdVec
- * @author Richard J. Mathar
- * @throws Error
- */
- static public BigSurdVec wigner3j(final String m1, final String t1, final String t2, final String j) throws Error {
- /*
- * The first number in the line "m" is the number of angular momenta.
- * The rest of the line is ignored.
- */
- Scanner s = new Scanner(m1);
- final int m = s.nextInt();
- if (m % 3 != 0) {
- s.close();
- throw new IllegalArgumentException("Angular momenta " + m + " not a multiple of three.");
- }
-
- /*
- * Scan the numbers in the line "j". Excess numbers beyond what has been
- * announced in the "m" line are ignored.
- */
- final int[] jvec = new int[m];
- final int[] tvec = new int[2 * m];
-
- s.close();
-
- /*
- * the third row contains positive 2j+1.
- */
- s = new Scanner(j);
- int ji = 0;
- while (s.hasNextInt() && ji < m) {
- jvec[ji++] = s.nextInt();
- if (jvec[ji - 1] < 1) {
- s.close();
- throw new IllegalArgumentException("Illegal value " + jvec[ji - 1] + " for 2j+1.");
- }
- }
-
- s.close();
-
- /*
- * the first two rows contain signed values of indices into the j list
- */
- s = new Scanner(t1);
- int ti = 0;
- while (s.hasNextInt()) {
- tvec[ti++] = s.nextInt();
- }
-
- s.close();
-
- s = new Scanner(t2);
- while (s.hasNextInt()) {
- tvec[ti++] = s.nextInt();
- }
-
- /*
- * Basic sanity checks. All indices in the first two lines address a
- * number in the third line, and each index occurs exactly twice.
- */
- if (ji % 3 != 0) {
- s.close();
- throw new IllegalArgumentException("j-count " + ji + " not a multiple of three.");
- }
- if (ti != 2 * ji) {
- s.close();
- throw new IllegalArgumentException("triad-count " + ti + " not twice j-count " + 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.
- */
- final int[][] jhash = new int[m][2];
-
- for (ti = 0; ti < 2 * m; 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");
- }
- if (jfreq[Math.abs(t) - 1] >= 2) {
- s.close();
- throw new IllegalArgumentException("Node " + t + " referenced more than twice");
- }
- jhash[Math.abs(t) - 1][jfreq[Math.abs(t) - 1]] = ti;
- jfreq[Math.abs(t) - 1]++;
- }
-
- /*
- * Move on from the 2j+1 values of the input to the j-values. Subtract
- * one and divide through 2.
- */
- final Rational[] J = new Rational[jvec.length];
- for (ji = 0; ji < jvec.length; ji++) {
- J[ji] = new Rational(jvec[ji] - 1, 2);
- }
-
- /*
- * Convert the 1-based indices to 0-based indices, loosing the sign
- * information.
- */
- 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.
- */
- final Rational[] M = new Rational[J.length];
- s.close();
- return Wigner3j.wigner3j(tvec, J, M, triadidx);
- } /* wigner3j */
-
- /**
- * Wigner 3jn symbol. Computes sum_{mi} (-1)^(j1-m1+j2-m2+...)
- * triad(triadidx[0..2])*triad(triadidx[3..5])*... where each factor is a
- * Wigner-3jm symbol with each sign of m_i occurring once at the
- * corresponding l-value.
- *
- * @param triadidx
- * 0-based indices into the list of J
- * @param J
- * The list of J-values
- * @param M
- * The list of M-values associated with the J. This contains null
- * where the parameter has not yet been set by an outer loop.
- * @since 2011-02-13
- * @since 2012-02-15 Upgraded to return BigSurdVec
- * @author Richard J. Mathar
- * @throws Error
- */
- static private BigSurdVec wigner3j(final int[] tvec, final Rational[] J, final Rational[] M, final int[] triadidx)
- throws Error {
- /*
- * The result of the computation. The sum over all m-combinations of the
- * triads.
- */
- BigSurdVec res = new BigSurdVec();
-
- /*
- * First step is to monitor the triangular conditions on the J. If at
- * least one is violated, the result is zero. Loop over the triads.
- */
- 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) {
- return res;
- }
- if (J[triadidx[t]].add(J[triadidx[t + 1]]).compareTo(J[triadidx[t + 2]]) < 0) {
- return res;
- }
- }
-
- /*
- * the index of the preferred member of the triad list. Preference given
- * to those dangling in triads where alreaday two others are fixed, then
- * to members where at least one is fixed, then to smallest associated
- * J-values.
- */
- int freeM = -1;
- int freeMrank = -1;
- for (int i = 0; i < triadidx.length; i++) {
- /*
- * found an m-value which has not yet been summed over.
- */
- if (M[triadidx[i]] == null) {
- /*
- * 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.
- */
- 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
- */
- 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
- * set.
- */
- if (M[triadidx[nei1]] != null && M[triadidx[nei2]] != null) {
- freeM = i;
- break;
- } else {
- /*
- * rough work load estimator: basically (2J1+1)*(2J2+1)
- */
- Rational wt = J[triadidx[i]].multiply(2).add(1);
- if (M[triadidx[nei1]] == null) {
- wt = wt.multiply(J[triadidx[nei1]].multiply(2).add(1));
- }
- if (M[triadidx[nei2]] == null) {
- wt = wt.multiply(J[triadidx[nei2]].multiply(2).add(1));
- }
- final int thiswt = wt.intValue();
- if (freeM < 0 || thiswt < freeMrank) {
- freeM = i;
- freeMrank = thiswt;
- }
- }
- }
- }
-
- if (freeM >= 0) {
- /*
- * found an m-value which has not yet been summed over.
- */
- if (M[triadidx[freeM]] == 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.
- */
- 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
- */
- 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,
- * the allowed range.
- */
- Rational newm = J[triadidx[freeM]].negate();
- while (newm.compareTo(J[triadidx[freeM]]) <= 0) {
- childM[triadidx[freeM]] = tvec[freeM] > 0 ? newm : newm.negate();
- res = res.add(Wigner3j.wigner3j(tvec, J, childM, triadidx));
- newm = newm.add(Rational.ONE);
- }
- } else {
- /*
- * Set its value and the value at its companion j-value. Sum
- * of the three m-values in the triad is to be zero for a
- * non-zero contribution.
- */
- Rational m1 = M[triadidx[nei1]];
- Rational m2 = M[triadidx[nei2]];
- /*
- * negate if these are the second occurrences of the J in
- * the triads
- */
- if (tvec[nei1] < 0) {
- m1 = m1.negate();
- }
- if (tvec[nei2] < 0) {
- m2 = m2.negate();
- }
- /* m3 = -(m1+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
- * associated J-value. One could essentially remove this
- * branching and let wigner3j() decide on this, but this is
- * inefficient.
- */
- if (newm.abs().compareTo(J[triadidx[freeM]]) <= 0) {
- childM[triadidx[freeM]] = newm;
- res = res.add(Wigner3j.wigner3j(tvec, J, childM, triadidx));
- }
- /*
- * zero contribution if this m-value cannot be set to any
- * value compatible with the triangular conditions.
- */
- }
- return res;
- }
- }
-
- /*
- * reached the bottom of the loop where all M-values are assigned. Build
- * the product over all Wigner-3jm values and the associated sign.
- */
- res = BigSurdVec.ONE;
- for (int ji = 0; ji < triadidx.length; ji += 3) {
- Rational m1 = M[triadidx[ji]];
- Rational m2 = M[triadidx[ji + 1]];
- Rational m3 = M[triadidx[ji + 2]];
- /*
- * negate if these are associated with in-flowing vectors in the
- * triads
- */
- if (tvec[ji] < 0) {
- m1 = m1.negate();
- }
- if (tvec[ji + 1] < 0) {
- m2 = m2.negate();
- }
- if (tvec[ji + 2] < 0) {
- m3 = m3.negate();
- }
- res = res.multiply(Wigner3j.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) {
- 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++) {
- 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)) {
- res = res.negate();
- }
- return res;
- } /* wigner3j */
-
- /**
- * The Wigner 3jm symbol (j1,j2,j3,m1,m2,m3). Warning: there is no check
- * that each argument is indeed half-integer.
- *
- * @param j1
- * integer or half-integer j1
- * @param j2
- * integer or half-integer j2
- * @param j3
- * integer or half-integer j3
- * @param m1
- * integer or half-integer m1
- * @param m2
- * integer or half-integer m2
- * @param m3
- * integer or half-integer m3
- * @return The value of the symbol. Zero if any of the triangular
- * inequalities is violated or some parameters are out of range.
- * @since 2011-02-13
- * @author Richard J. Mathar
- * @throws Error
- */
- static protected BigSurd wigner3jm(final Rational j1, final Rational j2, final Rational j3, final Rational m1,
- final Rational m2, final Rational m3) throws Error {
- /*
- * Check that m1+m2+m3 = 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) {
- return BigSurd.ZERO;
- }
-
- /*
- * Check that |j1-j2|<=j3 <= |j1+j2|
- */
- final Rational j1m2 = j1.subtract(j2);
- if (j1m2.abs().compareTo(j3) > 0) {
- return BigSurd.ZERO;
- }
- 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) {
- return BigSurd.ZERO;
- }
-
- /*
- * Check that m_i-j_i are integer.
- */
- 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)!
- * (j1+j2-j3)! /(j1+j2+j3+1)!
- * *(j3-m)!*(j3+m)!(j1-m1)!*(j1+m1)!*(j2-m2)!*(j2+m2)!] *sum_k
- * (-1)^k/[k!(j1+j2-j3-k)!(j1-m1-k)!(j2+m2-k)!(j3-j2+m1+k)!)*(j3-j1-m2+k
- * )!]
- */
-
- /*
- * It is tacitly assumed that all the major j_i, m_i values are in the
- * integer range. This is implicitly plausible since otherwise the
- * execution times of the following loop over the k-values would be
- * immense.
- */
- int j1j2jk = j1p2.subtract(j3).intValue();
- int j1m1k = j1.subtract(m1).intValue();
- int j2m2k = j2.add(m2).intValue();
- int jj2m1k = j3.subtract(j2).add(m1).intValue();
- int jj1m2k = j3.subtract(j1).subtract(m2).intValue();
-
- int k = Math.max(0, -jj2m1k);
- k = Math.max(k, -jj1m2k);
- if (k > 0) {
- j1j2jk -= k;
- j1m1k -= k;
- j2m2k -= k;
- jj2m1k += k;
- jj1m2k += k;
- }
-
- final Factorial f = new Factorial();
- Rational sumk = new Rational();
- while (true) {
- 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 {
- sumk = sumk.subtract(new Rational(BigInteger.ONE, d));
- }
- j1j2jk--;
- j1m1k--;
- j2m2k--;
- jj2m1k++;
- jj1m2k++;
- if (j1j2jk < 0 || j1m1k < 0 || j2m2k < 0) {
- break;
- }
- k++;
- }
- /*
- * sign factor (-1)^(j1-j2-m3)
- */
- if (j1m2.subtract(m3).intValue() % 2 != 0) {
- sumk = sumk.negate();
- }
-
- k = j1m2.add(j3).intValue();
- BigInteger s = f.at(k);
- k = j3.subtract(j1m2).intValue();
- s = s.multiply(f.at(k));
- k = j1p2.subtract(j3).intValue();
- s = s.multiply(f.at(k));
- k = j3.add(m3).intValue();
- s = s.multiply(f.at(k));
- k = j3.subtract(m3).intValue();
- s = s.multiply(f.at(k));
- k = j1.add(m1).intValue();
- s = s.multiply(f.at(k));
- k = j1.subtract(m1).intValue();
- s = s.multiply(f.at(k));
- k = j2.add(m2).intValue();
- s = s.multiply(f.at(k));
- k = j2.subtract(m2).intValue();
- s = s.multiply(f.at(k));
- k = j1p2.add(j3).intValue();
- k++;
- final Rational disc = new Rational(s, f.at(k));
- return new BigSurd(sumk, disc);
- } /* wigner3jm */
-
-} /* Wigner3j */
diff --git a/core/src/main/java/org/nevec/rjm/Wigner3jGUI.java b/core/src/main/java/org/nevec/rjm/Wigner3jGUI.java
deleted file mode 100644
index 8cffd15f..00000000
--- a/core/src/main/java/org/nevec/rjm/Wigner3jGUI.java
+++ /dev/null
@@ -1,335 +0,0 @@
-package org.nevec.rjm;
-
-import java.awt.Color;
-import java.awt.Font;
-import java.awt.GridBagConstraints;
-import java.awt.GridBagLayout;
-import java.awt.Label;
-import java.awt.TextArea;
-import java.awt.event.ActionEvent;
-import java.awt.event.ActionListener;
-import java.util.Scanner;
-
-import javax.swing.JButton;
-import javax.swing.JFrame;
-import javax.swing.JList;
-import javax.swing.event.ListSelectionEvent;
-import javax.swing.event.ListSelectionListener;
-
-import it.cavallium.warppi.util.Error;
-
-/**
- * An interactive interface to the Wigner3j class. The GUI allows to preselect
- * one of the symbols if the number of j-terms is small (6j up to 15j), or to
- * enter any other connectivity for the triads of j-values. The actual j-values
- * are entered as integers (2j+1) and the computation of one value (in exact
- * square root representation) is started manually.
- *
- * @since 2011-02-15
- */
-public class Wigner3jGUI implements ActionListener, ListSelectionListener {
- /**
- * The master window of the session
- */
- JFrame fram;
-
- /*
- * global labels
- */
- Label Lbl0;
- Label Lbl1;
-
- JButton sear;
- JList> searJ;
- String[] searOpt = { "6j", "9j", "12j 1st", "12j 2nd (not symm)", "15j 1st", "15j 2nd", "15j 3rd", "15j 4th", "15j 5th" };
-
- /**
- * Field with the triads inputs
- */
- TextArea inpGtria;
-
- /**
- * Field with the J-value inputs
- */
- TextArea inpGjval;
-
- /**
- * Field of the outputs.
- */
- TextArea outG;
-
- GridBagLayout gridbag;
- GridBagConstraints gridconstr;
-
- /**
- * @since 2011-02-15
- */
- public void init() {
- fram = new JFrame("Wigner3jGUI");
-
- Lbl0 = new Label("Input: (Triads upper area, values 2J+1 second area");
- Lbl1 = new Label("Output:");
-
- sear = new JButton("Compute");
- sear.setActionCommand("compute");
- sear.addActionListener(this);
- sear.setToolTipText("Compute a general 3jn value");
-
- searJ = new JList
- *
- * Concrete classes should extend {@link PngChunkSingle} or
- * {@link PngChunkMultiple}
- *
- * Note that some methods/fields are type-specific (getOrderingConstraint(),
- * allowsMultiple()),
- * some are 'almost' type-specific (id,crit,pub,safe; the exception is
- * PngUKNOWN),
- * and the rest are instance-specific
- */
-public abstract class PngChunk {
-
- /**
- * Chunk-id: 4 letters
- */
- public final String id;
- /**
- * Autocomputed at creation time
- */
- public final boolean crit, pub, safe;
-
- protected final ImageInfo imgInfo;
-
- protected ChunkRaw raw;
-
- private boolean priority = false; // For writing. Queued chunks with high priority will be written
- // as soon as
- // possible
-
- protected int chunkGroup = -1; // chunk group where it was read or writen
-
- /**
- * Possible ordering constraint for a PngChunk type -only relevant for
- * ancillary chunks. Theoretically, there could be
- * more general constraints, but these cover the constraints for standard
- * chunks.
- */
- public enum ChunkOrderingConstraint {
- /**
- * no ordering constraint
- */
- NONE,
- /**
- * Must go before PLTE (and hence, also before IDAT)
- */
- BEFORE_PLTE_AND_IDAT,
- /**
- * Must go after PLTE (if exists) but before IDAT
- */
- AFTER_PLTE_BEFORE_IDAT,
- /**
- * Must go after PLTE (and it must exist) but before IDAT
- */
- AFTER_PLTE_BEFORE_IDAT_PLTE_REQUIRED,
- /**
- * Must before IDAT (before or after PLTE)
- */
- BEFORE_IDAT,
- /**
- * After IDAT (this restriction does not apply to the standard PNG
- * chunks)
- */
- AFTER_IDAT,
- /**
- * Does not apply
- */
- NA;
-
- public boolean mustGoBeforePLTE() {
- return this == BEFORE_PLTE_AND_IDAT;
- }
-
- public boolean mustGoBeforeIDAT() {
- return this == BEFORE_IDAT || this == BEFORE_PLTE_AND_IDAT || this == AFTER_PLTE_BEFORE_IDAT;
- }
-
- /**
- * after pallete, if exists
- */
- public boolean mustGoAfterPLTE() {
- return this == AFTER_PLTE_BEFORE_IDAT || this == AFTER_PLTE_BEFORE_IDAT_PLTE_REQUIRED;
- }
-
- public boolean mustGoAfterIDAT() {
- return this == AFTER_IDAT;
- }
-
- public boolean isOk(final int currentChunkGroup, final boolean hasplte) {
- if (this == NONE)
- return true;
- else if (this == BEFORE_IDAT)
- return currentChunkGroup < ChunksList.CHUNK_GROUP_4_IDAT;
- else if (this == BEFORE_PLTE_AND_IDAT)
- return currentChunkGroup < ChunksList.CHUNK_GROUP_2_PLTE;
- else if (this == AFTER_PLTE_BEFORE_IDAT)
- return hasplte ? currentChunkGroup < ChunksList.CHUNK_GROUP_4_IDAT : currentChunkGroup < ChunksList.CHUNK_GROUP_4_IDAT && currentChunkGroup > ChunksList.CHUNK_GROUP_2_PLTE;
- else if (this == AFTER_IDAT)
- return currentChunkGroup > ChunksList.CHUNK_GROUP_4_IDAT;
- return false;
- }
- }
-
- public PngChunk(final String id, final ImageInfo imgInfo) {
- this.id = id;
- this.imgInfo = imgInfo;
- crit = ChunkHelper.isCritical(id);
- pub = ChunkHelper.isPublic(id);
- safe = ChunkHelper.isSafeToCopy(id);
- }
-
- protected final ChunkRaw createEmptyChunk(final int len, final boolean alloc) {
- final ChunkRaw c = new ChunkRaw(len, ChunkHelper.toBytes(id), alloc);
- return c;
- }
-
- /**
- * In which "chunkGroup" (see {@link ChunksList}for definition) this chunks
- * instance was read or written.
- *
- * -1 if not read or written (eg, queued)
- */
- final public int getChunkGroup() {
- return chunkGroup;
- }
-
- /**
- * @see #getChunkGroup()
- */
- final void setChunkGroup(final int chunkGroup) {
- this.chunkGroup = chunkGroup;
- }
-
- public boolean hasPriority() {
- return priority;
- }
-
- public void setPriority(final boolean priority) {
- this.priority = priority;
- }
-
- final void write(final OutputStream os) {
- if (raw == null || raw.data == null)
- raw = createRawChunk();
- if (raw == null)
- throw new PngjExceptionInternal("null chunk ! creation failed for " + this);
- raw.writeChunk(os);
- }
-
- /**
- * Creates the physical chunk. This is used when writing (serialization).
- * Each particular chunk class implements its
- * own logic.
- *
- * @return A newly allocated and filled raw chunk
- */
- public abstract ChunkRaw createRawChunk();
-
- /**
- * Parses raw chunk and fill inside data. This is used when reading
- * (deserialization). Each particular chunk class
- * implements its own logic.
- */
- protected abstract void parseFromRaw(ChunkRaw c);
-
- /**
- * See {@link PngChunkMultiple} and {@link PngChunkSingle}
- *
- * @return true if PNG accepts multiple chunks of this class
- */
- protected abstract boolean allowsMultiple();
-
- public ChunkRaw getRaw() {
- return raw;
- }
-
- void setRaw(final ChunkRaw raw) {
- this.raw = raw;
- }
-
- /**
- * @see ChunkRaw#len
- */
- public int getLen() {
- return raw != null ? raw.len : -1;
- }
-
- /**
- * @see ChunkRaw#getOffset()
- */
- public long getOffset() {
- return raw != null ? raw.getOffset() : -1;
- }
-
- /**
- * This signals that the raw chunk (serialized data) as invalid, so that
- * it's regenerated on write. This should be
- * called for the (infrequent) case of chunks that were copied from a
- * PngReader and we want to manually modify it.
- */
- public void invalidateRawData() {
- raw = null;
- }
-
- /**
- * see {@link ChunkOrderingConstraint}
- */
- public abstract ChunkOrderingConstraint getOrderingConstraint();
-
- @Override
- public String toString() {
- return "chunk id= " + id + " (len=" + getLen() + " offset=" + getOffset() + ")";
- }
-
-}
diff --git a/teavm/src/main/java/ar/com/hjg/pngj/chunks/PngChunkACTL.java b/teavm/src/main/java/ar/com/hjg/pngj/chunks/PngChunkACTL.java
deleted file mode 100644
index 3d179f06..00000000
--- a/teavm/src/main/java/ar/com/hjg/pngj/chunks/PngChunkACTL.java
+++ /dev/null
@@ -1,57 +0,0 @@
-package ar.com.hjg.pngj.chunks;
-
-import ar.com.hjg.pngj.ImageInfo;
-import ar.com.hjg.pngj.PngHelperInternal;
-
-/**
- * acTL chunk. For APGN, not PGN standard
- *
- * see
- * https://wiki.mozilla.org/APNG_Specification#.60acTL.60:_The_Animation_Control_Chunk
- *
- */
-public class PngChunkACTL extends PngChunkSingle {
- public final static String ID = "acTL";
- private int numFrames;
- private int numPlays;
-
- public PngChunkACTL(final ImageInfo info) {
- super(PngChunkACTL.ID, info);
- }
-
- @Override
- public ChunkOrderingConstraint getOrderingConstraint() {
- return ChunkOrderingConstraint.BEFORE_IDAT;
- }
-
- @Override
- public ChunkRaw createRawChunk() {
- final ChunkRaw c = createEmptyChunk(8, true);
- PngHelperInternal.writeInt4tobytes(numFrames, c.data, 0);
- PngHelperInternal.writeInt4tobytes(numPlays, c.data, 4);
- return c;
- }
-
- @Override
- public void parseFromRaw(final ChunkRaw chunk) {
- numFrames = PngHelperInternal.readInt4fromBytes(chunk.data, 0);
- numPlays = PngHelperInternal.readInt4fromBytes(chunk.data, 4);
- }
-
- public int getNumFrames() {
- return numFrames;
- }
-
- public void setNumFrames(final int numFrames) {
- this.numFrames = numFrames;
- }
-
- public int getNumPlays() {
- return numPlays;
- }
-
- public void setNumPlays(final int numPlays) {
- this.numPlays = numPlays;
- }
-
-}
diff --git a/teavm/src/main/java/ar/com/hjg/pngj/chunks/PngChunkBKGD.java b/teavm/src/main/java/ar/com/hjg/pngj/chunks/PngChunkBKGD.java
deleted file mode 100644
index 6486c189..00000000
--- a/teavm/src/main/java/ar/com/hjg/pngj/chunks/PngChunkBKGD.java
+++ /dev/null
@@ -1,112 +0,0 @@
-package ar.com.hjg.pngj.chunks;
-
-import ar.com.hjg.pngj.ImageInfo;
-import ar.com.hjg.pngj.PngHelperInternal;
-import ar.com.hjg.pngj.PngjException;
-
-/**
- * bKGD Chunk.
- *
- * see {@link http://www.w3.org/TR/PNG/#11bKGD}
- *
- * This chunk structure depends on the image type
- */
-public class PngChunkBKGD extends PngChunkSingle {
- public final static String ID = ChunkHelper.bKGD;
- // only one of these is meaningful
- private int gray;
- private int red, green, blue;
- private int paletteIndex;
-
- public PngChunkBKGD(final ImageInfo info) {
- super(ChunkHelper.bKGD, info);
- }
-
- @Override
- public ChunkOrderingConstraint getOrderingConstraint() {
- return ChunkOrderingConstraint.AFTER_PLTE_BEFORE_IDAT;
- }
-
- @Override
- public ChunkRaw createRawChunk() {
- ChunkRaw c = null;
- if (imgInfo.greyscale) {
- c = createEmptyChunk(2, true);
- PngHelperInternal.writeInt2tobytes(gray, c.data, 0);
- } else if (imgInfo.indexed) {
- c = createEmptyChunk(1, true);
- c.data[0] = (byte) paletteIndex;
- } else {
- c = createEmptyChunk(6, true);
- PngHelperInternal.writeInt2tobytes(red, c.data, 0);
- PngHelperInternal.writeInt2tobytes(green, c.data, 0);
- PngHelperInternal.writeInt2tobytes(blue, c.data, 0);
- }
- return c;
- }
-
- @Override
- public void parseFromRaw(final ChunkRaw c) {
- if (imgInfo.greyscale)
- gray = PngHelperInternal.readInt2fromBytes(c.data, 0);
- else if (imgInfo.indexed)
- paletteIndex = c.data[0] & 0xff;
- else {
- red = PngHelperInternal.readInt2fromBytes(c.data, 0);
- green = PngHelperInternal.readInt2fromBytes(c.data, 2);
- blue = PngHelperInternal.readInt2fromBytes(c.data, 4);
- }
- }
-
- /**
- * Set gray value (0-255 if bitdept=8)
- *
- * @param gray
- */
- public void setGray(final int gray) {
- if (!imgInfo.greyscale)
- throw new PngjException("only gray images support this");
- this.gray = gray;
- }
-
- public int getGray() {
- if (!imgInfo.greyscale)
- throw new PngjException("only gray images support this");
- return gray;
- }
-
- /**
- * Set pallette index
- *
- */
- public void setPaletteIndex(final int i) {
- if (!imgInfo.indexed)
- throw new PngjException("only indexed (pallete) images support this");
- paletteIndex = i;
- }
-
- public int getPaletteIndex() {
- if (!imgInfo.indexed)
- throw new PngjException("only indexed (pallete) images support this");
- return paletteIndex;
- }
-
- /**
- * Set rgb values
- *
- */
- public void setRGB(final int r, final int g, final int b) {
- if (imgInfo.greyscale || imgInfo.indexed)
- throw new PngjException("only rgb or rgba images support this");
- red = r;
- green = g;
- blue = b;
- }
-
- public int[] getRGB() {
- if (imgInfo.greyscale || imgInfo.indexed)
- throw new PngjException("only rgb or rgba images support this");
- return new int[] { red, green, blue };
- }
-
-}
diff --git a/teavm/src/main/java/ar/com/hjg/pngj/chunks/PngChunkCHRM.java b/teavm/src/main/java/ar/com/hjg/pngj/chunks/PngChunkCHRM.java
deleted file mode 100644
index 6086a7a2..00000000
--- a/teavm/src/main/java/ar/com/hjg/pngj/chunks/PngChunkCHRM.java
+++ /dev/null
@@ -1,75 +0,0 @@
-package ar.com.hjg.pngj.chunks;
-
-import ar.com.hjg.pngj.ImageInfo;
-import ar.com.hjg.pngj.PngHelperInternal;
-import ar.com.hjg.pngj.PngjException;
-
-/**
- * cHRM chunk.
- *
- * see
- * https://wiki.mozilla.org/APNG_Specification#.60fcTL.60:_The_Frame_Control_Chunk
- *
- */
-public class PngChunkFCTL extends PngChunkMultiple {
- public final static String ID = "fcTL";
-
- public final static byte APNG_DISPOSE_OP_NONE = 0;
- public final static byte APNG_DISPOSE_OP_BACKGROUND = 1;
- public final static byte APNG_DISPOSE_OP_PREVIOUS = 2;
- public final static byte APNG_BLEND_OP_SOURCE = 0;
- public final static byte APNG_BLEND_OP_OVER = 1;
-
- private int seqNum;
- private int width, height, xOff, yOff;
- private int delayNum, delayDen;
- private byte disposeOp, blendOp;
-
- public PngChunkFCTL(final ImageInfo info) {
- super(PngChunkFCTL.ID, info);
- }
-
- public ImageInfo getEquivImageInfo() {
- return new ImageInfo(width, height, imgInfo.bitDepth, imgInfo.alpha, imgInfo.greyscale, imgInfo.indexed);
- }
-
- @Override
- public ChunkOrderingConstraint getOrderingConstraint() {
- return ChunkOrderingConstraint.NONE;
- }
-
- @Override
- public ChunkRaw createRawChunk() {
- final ChunkRaw c = createEmptyChunk(8, true);
- int off = 0;
- PngHelperInternal.writeInt4tobytes(seqNum, c.data, off);
- off += 4;
- PngHelperInternal.writeInt4tobytes(width, c.data, off);
- off += 4;
- PngHelperInternal.writeInt4tobytes(height, c.data, off);
- off += 4;
- PngHelperInternal.writeInt4tobytes(xOff, c.data, off);
- off += 4;
- PngHelperInternal.writeInt4tobytes(yOff, c.data, off);
- off += 4;
- PngHelperInternal.writeInt2tobytes(delayNum, c.data, off);
- off += 2;
- PngHelperInternal.writeInt2tobytes(delayDen, c.data, off);
- off += 2;
- c.data[off] = disposeOp;
- off += 1;
- c.data[off] = blendOp;
- return c;
- }
-
- @Override
- public void parseFromRaw(final ChunkRaw chunk) {
- int off = 0;
- seqNum = PngHelperInternal.readInt4fromBytes(chunk.data, off);
- off += 4;
- width = PngHelperInternal.readInt4fromBytes(chunk.data, off);
- off += 4;
- height = PngHelperInternal.readInt4fromBytes(chunk.data, off);
- off += 4;
- xOff = PngHelperInternal.readInt4fromBytes(chunk.data, off);
- off += 4;
- yOff = PngHelperInternal.readInt4fromBytes(chunk.data, off);
- off += 4;
- delayNum = PngHelperInternal.readInt2fromBytes(chunk.data, off);
- off += 2;
- delayDen = PngHelperInternal.readInt2fromBytes(chunk.data, off);
- off += 2;
- disposeOp = chunk.data[off];
- off += 1;
- blendOp = chunk.data[off];
- }
-
- public int getSeqNum() {
- return seqNum;
- }
-
- public void setSeqNum(final int seqNum) {
- this.seqNum = seqNum;
- }
-
- public int getWidth() {
- return width;
- }
-
- public void setWidth(final int width) {
- this.width = width;
- }
-
- public int getHeight() {
- return height;
- }
-
- public void setHeight(final int height) {
- this.height = height;
- }
-
- public int getxOff() {
- return xOff;
- }
-
- public void setxOff(final int xOff) {
- this.xOff = xOff;
- }
-
- public int getyOff() {
- return yOff;
- }
-
- public void setyOff(final int yOff) {
- this.yOff = yOff;
- }
-
- public int getDelayNum() {
- return delayNum;
- }
-
- public void setDelayNum(final int delayNum) {
- this.delayNum = delayNum;
- }
-
- public int getDelayDen() {
- return delayDen;
- }
-
- public void setDelayDen(final int delayDen) {
- this.delayDen = delayDen;
- }
-
- public byte getDisposeOp() {
- return disposeOp;
- }
-
- public void setDisposeOp(final byte disposeOp) {
- this.disposeOp = disposeOp;
- }
-
- public byte getBlendOp() {
- return blendOp;
- }
-
- public void setBlendOp(final byte blendOp) {
- this.blendOp = blendOp;
- }
-
-}
diff --git a/teavm/src/main/java/ar/com/hjg/pngj/chunks/PngChunkFDAT.java b/teavm/src/main/java/ar/com/hjg/pngj/chunks/PngChunkFDAT.java
deleted file mode 100644
index 47449a00..00000000
--- a/teavm/src/main/java/ar/com/hjg/pngj/chunks/PngChunkFDAT.java
+++ /dev/null
@@ -1,72 +0,0 @@
-package ar.com.hjg.pngj.chunks;
-
-import ar.com.hjg.pngj.ImageInfo;
-import ar.com.hjg.pngj.PngHelperInternal;
-import ar.com.hjg.pngj.PngjException;
-
-/**
- * fdAT chunk. For APGN, not PGN standard
- *
- * see
- * https://wiki.mozilla.org/APNG_Specification#.60fdAT.60:_The_Frame_Data_Chunk
- *
- * This implementation does not support buffering, this should be not managed
- * similar to a IDAT chunk
- *
- */
-public class PngChunkFDAT extends PngChunkMultiple {
- public final static String ID = "fdAT";
- private int seqNum;
- private byte[] buffer; // normally not allocated - if so, it's the raw data, so it includes the 4bytes seqNum
- int datalen; // length of idat data, excluding seqNUm (= chunk.len-4)
-
- public PngChunkFDAT(final ImageInfo info) {
- super(PngChunkFDAT.ID, info);
- }
-
- @Override
- public ChunkOrderingConstraint getOrderingConstraint() {
- return ChunkOrderingConstraint.AFTER_IDAT;
- }
-
- @Override
- public ChunkRaw createRawChunk() {
- if (buffer == null)
- throw new PngjException("not buffered");
- final ChunkRaw c = createEmptyChunk(datalen + 4, false);
- c.data = buffer; // shallow copy!
- return c;
- }
-
- @Override
- public void parseFromRaw(final ChunkRaw chunk) {
- seqNum = PngHelperInternal.readInt4fromBytes(chunk.data, 0);
- datalen = chunk.len - 4;
- buffer = chunk.data;
- }
-
- public int getSeqNum() {
- return seqNum;
- }
-
- public void setSeqNum(final int seqNum) {
- this.seqNum = seqNum;
- }
-
- public byte[] getBuffer() {
- return buffer;
- }
-
- public void setBuffer(final byte[] buffer) {
- this.buffer = buffer;
- }
-
- public int getDatalen() {
- return datalen;
- }
-
- public void setDatalen(final int datalen) {
- this.datalen = datalen;
- }
-
-}
diff --git a/teavm/src/main/java/ar/com/hjg/pngj/chunks/PngChunkGAMA.java b/teavm/src/main/java/ar/com/hjg/pngj/chunks/PngChunkGAMA.java
deleted file mode 100644
index 3b70654b..00000000
--- a/teavm/src/main/java/ar/com/hjg/pngj/chunks/PngChunkGAMA.java
+++ /dev/null
@@ -1,51 +0,0 @@
-package ar.com.hjg.pngj.chunks;
-
-import ar.com.hjg.pngj.ImageInfo;
-import ar.com.hjg.pngj.PngHelperInternal;
-import ar.com.hjg.pngj.PngjException;
-
-/**
- * gAMA chunk.
- *
- * see http://www.w3.org/TR/PNG/#11gAMA
- */
-public class PngChunkGAMA extends PngChunkSingle {
- public final static String ID = ChunkHelper.gAMA;
-
- // http://www.w3.org/TR/PNG/#11gAMA
- private double gamma;
-
- public PngChunkGAMA(final ImageInfo info) {
- super(PngChunkGAMA.ID, info);
- }
-
- @Override
- public ChunkOrderingConstraint getOrderingConstraint() {
- return ChunkOrderingConstraint.BEFORE_PLTE_AND_IDAT;
- }
-
- @Override
- public ChunkRaw createRawChunk() {
- final ChunkRaw c = createEmptyChunk(4, true);
- final int g = (int) (gamma * 100000 + 0.5);
- PngHelperInternal.writeInt4tobytes(g, c.data, 0);
- return c;
- }
-
- @Override
- public void parseFromRaw(final ChunkRaw chunk) {
- if (chunk.len != 4)
- throw new PngjException("bad chunk " + chunk);
- final int g = PngHelperInternal.readInt4fromBytes(chunk.data, 0);
- gamma = g / 100000.0;
- }
-
- public double getGamma() {
- return gamma;
- }
-
- public void setGamma(final double gamma) {
- this.gamma = gamma;
- }
-
-}
diff --git a/teavm/src/main/java/ar/com/hjg/pngj/chunks/PngChunkHIST.java b/teavm/src/main/java/ar/com/hjg/pngj/chunks/PngChunkHIST.java
deleted file mode 100644
index 7d84aed8..00000000
--- a/teavm/src/main/java/ar/com/hjg/pngj/chunks/PngChunkHIST.java
+++ /dev/null
@@ -1,56 +0,0 @@
-package ar.com.hjg.pngj.chunks;
-
-import ar.com.hjg.pngj.ImageInfo;
-import ar.com.hjg.pngj.PngHelperInternal;
-import ar.com.hjg.pngj.PngjException;
-
-/**
- * hIST chunk.
- *
- * see http://www.w3.org/TR/PNG/#11hIST
- * only for palette images
- */
-public class PngChunkHIST extends PngChunkSingle {
- public final static String ID = ChunkHelper.hIST;
-
- private int[] hist = new int[0]; // should have same lenght as palette
-
- public PngChunkHIST(final ImageInfo info) {
- super(PngChunkHIST.ID, info);
- }
-
- @Override
- public ChunkOrderingConstraint getOrderingConstraint() {
- return ChunkOrderingConstraint.AFTER_PLTE_BEFORE_IDAT;
- }
-
- @Override
- public void parseFromRaw(final ChunkRaw c) {
- if (!imgInfo.indexed)
- throw new PngjException("only indexed images accept a HIST chunk");
- final int nentries = c.data.length / 2;
- hist = new int[nentries];
- for (int i = 0; i < hist.length; i++)
- hist[i] = PngHelperInternal.readInt2fromBytes(c.data, i * 2);
- }
-
- @Override
- public ChunkRaw createRawChunk() {
- if (!imgInfo.indexed)
- throw new PngjException("only indexed images accept a HIST chunk");
- ChunkRaw c = null;
- c = createEmptyChunk(hist.length * 2, true);
- for (int i = 0; i < hist.length; i++)
- PngHelperInternal.writeInt2tobytes(hist[i], c.data, i * 2);
- return c;
- }
-
- public int[] getHist() {
- return hist;
- }
-
- public void setHist(final int[] hist) {
- this.hist = hist;
- }
-
-}
diff --git a/teavm/src/main/java/ar/com/hjg/pngj/chunks/PngChunkICCP.java b/teavm/src/main/java/ar/com/hjg/pngj/chunks/PngChunkICCP.java
deleted file mode 100644
index caa2de2a..00000000
--- a/teavm/src/main/java/ar/com/hjg/pngj/chunks/PngChunkICCP.java
+++ /dev/null
@@ -1,76 +0,0 @@
-package ar.com.hjg.pngj.chunks;
-
-import ar.com.hjg.pngj.ImageInfo;
-import ar.com.hjg.pngj.PngjException;
-
-/**
- * iCCP chunk.
- *
- * See {@link http://www.w3.org/TR/PNG/#11iCCP}
- */
-public class PngChunkICCP extends PngChunkSingle {
- public final static String ID = ChunkHelper.iCCP;
-
- // http://www.w3.org/TR/PNG/#11iCCP
- private String profileName;
- private byte[] compressedProfile; // copmression/decopmresion is done in getter/setter
-
- public PngChunkICCP(final ImageInfo info) {
- super(PngChunkICCP.ID, info);
- }
-
- @Override
- public ChunkOrderingConstraint getOrderingConstraint() {
- return ChunkOrderingConstraint.BEFORE_PLTE_AND_IDAT;
- }
-
- @Override
- public ChunkRaw createRawChunk() {
- final ChunkRaw c = createEmptyChunk(profileName.length() + compressedProfile.length + 2, true);
- System.arraycopy(ChunkHelper.toBytes(profileName), 0, c.data, 0, profileName.length());
- c.data[profileName.length()] = 0;
- c.data[profileName.length() + 1] = 0;
- System.arraycopy(compressedProfile, 0, c.data, profileName.length() + 2, compressedProfile.length);
- return c;
- }
-
- @Override
- public void parseFromRaw(final ChunkRaw chunk) {
- final int pos0 = ChunkHelper.posNullByte(chunk.data);
- profileName = ChunkHelper.toString(chunk.data, 0, pos0);
- final int comp = chunk.data[pos0 + 1] & 0xff;
- if (comp != 0)
- throw new PngjException("bad compression for ChunkTypeICCP");
- final int compdatasize = chunk.data.length - (pos0 + 2);
- compressedProfile = new byte[compdatasize];
- System.arraycopy(chunk.data, pos0 + 2, compressedProfile, 0, compdatasize);
- }
-
- /**
- * The profile should be uncompressed bytes
- */
- public void setProfileNameAndContent(final String name, final byte[] profile) {
- profileName = name;
- compressedProfile = ChunkHelper.compressBytes(profile, true);
- }
-
- public void setProfileNameAndContent(final String name, final String profile) {
- setProfileNameAndContent(name, ChunkHelper.toBytes(profile));
- }
-
- public String getProfileName() {
- return profileName;
- }
-
- /**
- * uncompressed
- **/
- public byte[] getProfile() {
- return ChunkHelper.compressBytes(compressedProfile, false);
- }
-
- public String getProfileAsString() {
- return ChunkHelper.toString(getProfile());
- }
-
-}
diff --git a/teavm/src/main/java/ar/com/hjg/pngj/chunks/PngChunkIDAT.java b/teavm/src/main/java/ar/com/hjg/pngj/chunks/PngChunkIDAT.java
deleted file mode 100644
index febd1469..00000000
--- a/teavm/src/main/java/ar/com/hjg/pngj/chunks/PngChunkIDAT.java
+++ /dev/null
@@ -1,35 +0,0 @@
-package ar.com.hjg.pngj.chunks;
-
-import ar.com.hjg.pngj.ImageInfo;
-
-/**
- * IDAT chunk.
- *
- * see http://www.w3.org/TR/PNG/#11IDAT
- *
- * This is dummy placeholder - we write/read this chunk (actually several) by
- * special code.
- */
-public class PngChunkIDAT extends PngChunkMultiple {
- public final static String ID = ChunkHelper.IDAT;
-
- // http://www.w3.org/TR/PNG/#11IDAT
- public PngChunkIDAT(final ImageInfo i) {
- super(PngChunkIDAT.ID, i);
- }
-
- @Override
- public ChunkOrderingConstraint getOrderingConstraint() {
- return ChunkOrderingConstraint.NA;
- }
-
- @Override
- public ChunkRaw createRawChunk() {// does nothing
- return null;
- }
-
- @Override
- public void parseFromRaw(final ChunkRaw c) { // does nothing
- }
-
-}
diff --git a/teavm/src/main/java/ar/com/hjg/pngj/chunks/PngChunkIEND.java b/teavm/src/main/java/ar/com/hjg/pngj/chunks/PngChunkIEND.java
deleted file mode 100644
index 01fb6259..00000000
--- a/teavm/src/main/java/ar/com/hjg/pngj/chunks/PngChunkIEND.java
+++ /dev/null
@@ -1,35 +0,0 @@
-package ar.com.hjg.pngj.chunks;
-
-import ar.com.hjg.pngj.ImageInfo;
-
-/**
- * IEND chunk.
- *
- * see http://www.w3.org/TR/PNG/#11IEND
- */
-public class PngChunkIEND extends PngChunkSingle {
- public final static String ID = ChunkHelper.IEND;
-
- // http://www.w3.org/TR/PNG/#11IEND
- // this is a dummy placeholder
- public PngChunkIEND(final ImageInfo info) {
- super(PngChunkIEND.ID, info);
- }
-
- @Override
- public ChunkOrderingConstraint getOrderingConstraint() {
- return ChunkOrderingConstraint.NA;
- }
-
- @Override
- public ChunkRaw createRawChunk() {
- final ChunkRaw c = new ChunkRaw(0, ChunkHelper.b_IEND, false);
- return c;
- }
-
- @Override
- public void parseFromRaw(final ChunkRaw c) {
- // this is not used
- }
-
-}
diff --git a/teavm/src/main/java/ar/com/hjg/pngj/chunks/PngChunkIHDR.java b/teavm/src/main/java/ar/com/hjg/pngj/chunks/PngChunkIHDR.java
deleted file mode 100644
index ddcbd5ec..00000000
--- a/teavm/src/main/java/ar/com/hjg/pngj/chunks/PngChunkIHDR.java
+++ /dev/null
@@ -1,184 +0,0 @@
-package ar.com.hjg.pngj.chunks;
-
-import java.io.ByteArrayInputStream;
-
-import ar.com.hjg.pngj.ImageInfo;
-import ar.com.hjg.pngj.PngHelperInternal;
-import ar.com.hjg.pngj.PngjException;
-import ar.com.hjg.pngj.PngjInputException;
-
-/**
- * IHDR chunk.
- *
- * see http://www.w3.org/TR/PNG/#11IHDR
- *
- * This is a special critical Chunk.
- */
-public class PngChunkIHDR extends PngChunkSingle {
- public final static String ID = ChunkHelper.IHDR;
-
- private int cols;
- private int rows;
- private int bitspc;
- private int colormodel;
- private int compmeth;
- private int filmeth;
- private int interlaced;
-
- // http://www.w3.org/TR/PNG/#11IHDR
- //
- public PngChunkIHDR(final ImageInfo info) { // argument is normally null here, if not null is used to fill the fields
- super(PngChunkIHDR.ID, info);
- if (info != null)
- fillFromInfo(info);
- }
-
- @Override
- public ChunkOrderingConstraint getOrderingConstraint() {
- return ChunkOrderingConstraint.NA;
- }
-
- @Override
- public ChunkRaw createRawChunk() {
- final ChunkRaw c = new ChunkRaw(13, ChunkHelper.b_IHDR, true);
- int offset = 0;
- PngHelperInternal.writeInt4tobytes(cols, c.data, offset);
- offset += 4;
- PngHelperInternal.writeInt4tobytes(rows, c.data, offset);
- offset += 4;
- c.data[offset++] = (byte) bitspc;
- c.data[offset++] = (byte) colormodel;
- c.data[offset++] = (byte) compmeth;
- c.data[offset++] = (byte) filmeth;
- c.data[offset++] = (byte) interlaced;
- return c;
- }
-
- @Override
- public void parseFromRaw(final ChunkRaw c) {
- if (c.len != 13)
- throw new PngjException("Bad IDHR len " + c.len);
- final ByteArrayInputStream st = c.getAsByteStream();
- cols = PngHelperInternal.readInt4(st);
- rows = PngHelperInternal.readInt4(st);
- // bit depth: number of bits per channel
- bitspc = PngHelperInternal.readByte(st);
- colormodel = PngHelperInternal.readByte(st);
- compmeth = PngHelperInternal.readByte(st);
- filmeth = PngHelperInternal.readByte(st);
- interlaced = PngHelperInternal.readByte(st);
- }
-
- public int getCols() {
- return cols;
- }
-
- public void setCols(final int cols) {
- this.cols = cols;
- }
-
- public int getRows() {
- return rows;
- }
-
- public void setRows(final int rows) {
- this.rows = rows;
- }
-
- public int getBitspc() {
- return bitspc;
- }
-
- public void setBitspc(final int bitspc) {
- this.bitspc = bitspc;
- }
-
- public int getColormodel() {
- return colormodel;
- }
-
- public void setColormodel(final int colormodel) {
- this.colormodel = colormodel;
- }
-
- public int getCompmeth() {
- return compmeth;
- }
-
- public void setCompmeth(final int compmeth) {
- this.compmeth = compmeth;
- }
-
- public int getFilmeth() {
- return filmeth;
- }
-
- public void setFilmeth(final int filmeth) {
- this.filmeth = filmeth;
- }
-
- public int getInterlaced() {
- return interlaced;
- }
-
- public void setInterlaced(final int interlaced) {
- this.interlaced = interlaced;
- }
-
- public boolean isInterlaced() {
- return getInterlaced() == 1;
- }
-
- public void fillFromInfo(final ImageInfo info) {
- setCols(imgInfo.cols);
- setRows(imgInfo.rows);
- setBitspc(imgInfo.bitDepth);
- int colormodel = 0;
- if (imgInfo.alpha)
- colormodel += 0x04;
- if (imgInfo.indexed)
- colormodel += 0x01;
- if (!imgInfo.greyscale)
- colormodel += 0x02;
- setColormodel(colormodel);
- setCompmeth(0); // compression method 0=deflate
- setFilmeth(0); // filter method (0)
- setInterlaced(0); // we never interlace
- }
-
- /** throws PngInputException if unexpected values */
- public ImageInfo createImageInfo() {
- check();
- final boolean alpha = (getColormodel() & 0x04) != 0;
- final boolean palette = (getColormodel() & 0x01) != 0;
- final boolean grayscale = getColormodel() == 0 || getColormodel() == 4;
- // creates ImgInfo and imgLine, and allocates buffers
- return new ImageInfo(getCols(), getRows(), getBitspc(), alpha, grayscale, palette);
- }
-
- public void check() {
- if (cols < 1 || rows < 1 || compmeth != 0 || filmeth != 0)
- throw new PngjInputException("bad IHDR: col/row/compmethod/filmethod invalid");
- if (bitspc != 1 && bitspc != 2 && bitspc != 4 && bitspc != 8 && bitspc != 16)
- throw new PngjInputException("bad IHDR: bitdepth invalid");
- if (interlaced < 0 || interlaced > 1)
- throw new PngjInputException("bad IHDR: interlace invalid");
- switch (colormodel) {
- case 0:
- break;
- case 3:
- if (bitspc == 16)
- throw new PngjInputException("bad IHDR: bitdepth invalid");
- break;
- case 2:
- case 4:
- case 6:
- if (bitspc != 8 && bitspc != 16)
- throw new PngjInputException("bad IHDR: bitdepth invalid");
- break;
- default:
- throw new PngjInputException("bad IHDR: invalid colormodel");
- }
- }
-
-}
diff --git a/teavm/src/main/java/ar/com/hjg/pngj/chunks/PngChunkITXT.java b/teavm/src/main/java/ar/com/hjg/pngj/chunks/PngChunkITXT.java
deleted file mode 100644
index d9d1bb83..00000000
--- a/teavm/src/main/java/ar/com/hjg/pngj/chunks/PngChunkITXT.java
+++ /dev/null
@@ -1,108 +0,0 @@
-package ar.com.hjg.pngj.chunks;
-
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-
-import ar.com.hjg.pngj.ImageInfo;
-import ar.com.hjg.pngj.PngjException;
-
-/**
- * iTXt chunk.
- *
- * see http://www.w3.org/TR/PNG/#11iTXt
- */
-public class PngChunkITXT extends PngChunkTextVar {
- public final static String ID = ChunkHelper.iTXt;
-
- private boolean compressed = false;
- private String langTag = "";
- private String translatedTag = "";
-
- // http://www.w3.org/TR/PNG/#11iTXt
- public PngChunkITXT(final ImageInfo info) {
- super(PngChunkITXT.ID, info);
- }
-
- @Override
- public ChunkRaw createRawChunk() {
- if (key == null || key.trim().length() == 0)
- throw new PngjException("Text chunk key must be non empty");
- try {
- final ByteArrayOutputStream ba = new ByteArrayOutputStream();
- ba.write(ChunkHelper.toBytes(key));
- ba.write(0); // separator
- ba.write(compressed ? 1 : 0);
- ba.write(0); // compression method (always 0)
- ba.write(ChunkHelper.toBytes(langTag));
- ba.write(0); // separator
- ba.write(ChunkHelper.toBytesUTF8(translatedTag));
- ba.write(0); // separator
- byte[] textbytes = ChunkHelper.toBytesUTF8(val);
- if (compressed)
- textbytes = ChunkHelper.compressBytes(textbytes, true);
- ba.write(textbytes);
- final byte[] b = ba.toByteArray();
- final ChunkRaw chunk = createEmptyChunk(b.length, false);
- chunk.data = b;
- return chunk;
- } catch (final IOException e) {
- throw new PngjException(e);
- }
- }
-
- @Override
- public void parseFromRaw(final ChunkRaw c) {
- int nullsFound = 0;
- final int[] nullsIdx = new int[3];
- for (int i = 0; i < c.data.length; i++) {
- if (c.data[i] != 0)
- continue;
- nullsIdx[nullsFound] = i;
- nullsFound++;
- if (nullsFound == 1)
- i += 2;
- if (nullsFound == 3)
- break;
- }
- if (nullsFound != 3)
- throw new PngjException("Bad formed PngChunkITXT chunk");
- key = ChunkHelper.toString(c.data, 0, nullsIdx[0]);
- int i = nullsIdx[0] + 1;
- compressed = c.data[i] == 0 ? false : true;
- i++;
- if (compressed && c.data[i] != 0)
- throw new PngjException("Bad formed PngChunkITXT chunk - bad compression method ");
- langTag = ChunkHelper.toString(c.data, i, nullsIdx[1] - i);
- translatedTag = ChunkHelper.toStringUTF8(c.data, nullsIdx[1] + 1, nullsIdx[2] - nullsIdx[1] - 1);
- i = nullsIdx[2] + 1;
- if (compressed) {
- final byte[] bytes = ChunkHelper.compressBytes(c.data, i, c.data.length - i, false);
- val = ChunkHelper.toStringUTF8(bytes);
- } else
- val = ChunkHelper.toStringUTF8(c.data, i, c.data.length - i);
- }
-
- public boolean isCompressed() {
- return compressed;
- }
-
- public void setCompressed(final boolean compressed) {
- this.compressed = compressed;
- }
-
- public String getLangtag() {
- return langTag;
- }
-
- public void setLangtag(final String langtag) {
- langTag = langtag;
- }
-
- public String getTranslatedTag() {
- return translatedTag;
- }
-
- public void setTranslatedTag(final String translatedTag) {
- this.translatedTag = translatedTag;
- }
-}
diff --git a/teavm/src/main/java/ar/com/hjg/pngj/chunks/PngChunkMultiple.java b/teavm/src/main/java/ar/com/hjg/pngj/chunks/PngChunkMultiple.java
deleted file mode 100644
index 0f822d24..00000000
--- a/teavm/src/main/java/ar/com/hjg/pngj/chunks/PngChunkMultiple.java
+++ /dev/null
@@ -1,28 +0,0 @@
-package ar.com.hjg.pngj.chunks;
-
-import ar.com.hjg.pngj.ImageInfo;
-
-/**
- * PNG chunk type (abstract) that allows multiple instances in same image.
- */
-public abstract class PngChunkMultiple extends PngChunk {
-
- protected PngChunkMultiple(final String id, final ImageInfo imgInfo) {
- super(id, imgInfo);
- }
-
- @Override
- public final boolean allowsMultiple() {
- return true;
- }
-
- /**
- * NOTE: this chunk uses the default Object's equals() hashCode()
- * implementation.
- *
- * This is the right thing to do, normally.
- *
- * This is important, eg see ChunkList.removeFromList()
- */
-
-}
diff --git a/teavm/src/main/java/ar/com/hjg/pngj/chunks/PngChunkOFFS.java b/teavm/src/main/java/ar/com/hjg/pngj/chunks/PngChunkOFFS.java
deleted file mode 100644
index 2f762a6c..00000000
--- a/teavm/src/main/java/ar/com/hjg/pngj/chunks/PngChunkOFFS.java
+++ /dev/null
@@ -1,81 +0,0 @@
-package ar.com.hjg.pngj.chunks;
-
-import ar.com.hjg.pngj.ImageInfo;
-import ar.com.hjg.pngj.PngHelperInternal;
-import ar.com.hjg.pngj.PngjException;
-
-/**
- * oFFs chunk.
- *
- * see http://www.libpng.org/pub/png/spec/register/pngext-1.3.0-pdg.html#C.oFFs
- */
-public class PngChunkOFFS extends PngChunkSingle {
- public final static String ID = "oFFs";
-
- // http://www.libpng.org/pub/png/spec/register/pngext-1.3.0-pdg.html#C.oFFs
- private long posX;
- private long posY;
- private int units; // 0: pixel 1:micrometer
-
- public PngChunkOFFS(final ImageInfo info) {
- super(PngChunkOFFS.ID, info);
- }
-
- @Override
- public ChunkOrderingConstraint getOrderingConstraint() {
- return ChunkOrderingConstraint.BEFORE_IDAT;
- }
-
- @Override
- public ChunkRaw createRawChunk() {
- final ChunkRaw c = createEmptyChunk(9, true);
- PngHelperInternal.writeInt4tobytes((int) posX, c.data, 0);
- PngHelperInternal.writeInt4tobytes((int) posY, c.data, 4);
- c.data[8] = (byte) units;
- return c;
- }
-
- @Override
- public void parseFromRaw(final ChunkRaw chunk) {
- if (chunk.len != 9)
- throw new PngjException("bad chunk length " + chunk);
- posX = PngHelperInternal.readInt4fromBytes(chunk.data, 0);
- if (posX < 0)
- posX += 0x100000000L;
- posY = PngHelperInternal.readInt4fromBytes(chunk.data, 4);
- if (posY < 0)
- posY += 0x100000000L;
- units = PngHelperInternal.readInt1fromByte(chunk.data, 8);
- }
-
- /**
- * 0: pixel, 1:micrometer
- */
- public int getUnits() {
- return units;
- }
-
- /**
- * 0: pixel, 1:micrometer
- */
- public void setUnits(final int units) {
- this.units = units;
- }
-
- public long getPosX() {
- return posX;
- }
-
- public void setPosX(final long posX) {
- this.posX = posX;
- }
-
- public long getPosY() {
- return posY;
- }
-
- public void setPosY(final long posY) {
- this.posY = posY;
- }
-
-}
diff --git a/teavm/src/main/java/ar/com/hjg/pngj/chunks/PngChunkPHYS.java b/teavm/src/main/java/ar/com/hjg/pngj/chunks/PngChunkPHYS.java
deleted file mode 100644
index acce8ed3..00000000
--- a/teavm/src/main/java/ar/com/hjg/pngj/chunks/PngChunkPHYS.java
+++ /dev/null
@@ -1,107 +0,0 @@
-package ar.com.hjg.pngj.chunks;
-
-import ar.com.hjg.pngj.ImageInfo;
-import ar.com.hjg.pngj.PngHelperInternal;
-import ar.com.hjg.pngj.PngjException;
-
-/**
- * pHYs chunk.
- *
- * see http://www.w3.org/TR/PNG/#11pHYs
- */
-public class PngChunkPHYS extends PngChunkSingle {
- public final static String ID = ChunkHelper.pHYs;
-
- // http://www.w3.org/TR/PNG/#11pHYs
- private long pixelsxUnitX;
- private long pixelsxUnitY;
- private int units; // 0: unknown 1:metre
-
- public PngChunkPHYS(final ImageInfo info) {
- super(PngChunkPHYS.ID, info);
- }
-
- @Override
- public ChunkOrderingConstraint getOrderingConstraint() {
- return ChunkOrderingConstraint.BEFORE_IDAT;
- }
-
- @Override
- public ChunkRaw createRawChunk() {
- final ChunkRaw c = createEmptyChunk(9, true);
- PngHelperInternal.writeInt4tobytes((int) pixelsxUnitX, c.data, 0);
- PngHelperInternal.writeInt4tobytes((int) pixelsxUnitY, c.data, 4);
- c.data[8] = (byte) units;
- return c;
- }
-
- @Override
- public void parseFromRaw(final ChunkRaw chunk) {
- if (chunk.len != 9)
- throw new PngjException("bad chunk length " + chunk);
- pixelsxUnitX = PngHelperInternal.readInt4fromBytes(chunk.data, 0);
- if (pixelsxUnitX < 0)
- pixelsxUnitX += 0x100000000L;
- pixelsxUnitY = PngHelperInternal.readInt4fromBytes(chunk.data, 4);
- if (pixelsxUnitY < 0)
- pixelsxUnitY += 0x100000000L;
- units = PngHelperInternal.readInt1fromByte(chunk.data, 8);
- }
-
- public long getPixelsxUnitX() {
- return pixelsxUnitX;
- }
-
- public void setPixelsxUnitX(final long pixelsxUnitX) {
- this.pixelsxUnitX = pixelsxUnitX;
- }
-
- public long getPixelsxUnitY() {
- return pixelsxUnitY;
- }
-
- public void setPixelsxUnitY(final long pixelsxUnitY) {
- this.pixelsxUnitY = pixelsxUnitY;
- }
-
- public int getUnits() {
- return units;
- }
-
- public void setUnits(final int units) {
- this.units = units;
- }
-
- // special getters / setters
-
- /**
- * returns -1 if the physicial unit is unknown, or X-Y are not equal
- */
- public double getAsDpi() {
- if (units != 1 || pixelsxUnitX != pixelsxUnitY)
- return -1;
- return pixelsxUnitX * 0.0254;
- }
-
- /**
- * returns -1 if the physicial unit is unknown
- */
- public double[] getAsDpi2() {
- if (units != 1)
- return new double[] { -1, -1 };
- return new double[] { pixelsxUnitX * 0.0254, pixelsxUnitY * 0.0254 };
- }
-
- public void setAsDpi(final double dpi) {
- units = 1;
- pixelsxUnitX = (long) (dpi / 0.0254 + 0.5);
- pixelsxUnitY = pixelsxUnitX;
- }
-
- public void setAsDpi2(final double dpix, final double dpiy) {
- units = 1;
- pixelsxUnitX = (long) (dpix / 0.0254 + 0.5);
- pixelsxUnitY = (long) (dpiy / 0.0254 + 0.5);
- }
-
-}
diff --git a/teavm/src/main/java/ar/com/hjg/pngj/chunks/PngChunkPLTE.java b/teavm/src/main/java/ar/com/hjg/pngj/chunks/PngChunkPLTE.java
deleted file mode 100644
index a0cfe734..00000000
--- a/teavm/src/main/java/ar/com/hjg/pngj/chunks/PngChunkPLTE.java
+++ /dev/null
@@ -1,95 +0,0 @@
-package ar.com.hjg.pngj.chunks;
-
-import ar.com.hjg.pngj.ImageInfo;
-import ar.com.hjg.pngj.PngjException;
-
-/**
- * PLTE chunk.
- *
- * see http://www.w3.org/TR/PNG/#11PLTE
- *
- * Critical chunk
- */
-public class PngChunkPLTE extends PngChunkSingle {
- public final static String ID = ChunkHelper.PLTE;
-
- // http://www.w3.org/TR/PNG/#11PLTE
- private int nentries = 0;
- /**
- * RGB8 packed in one integer
- */
- private int[] entries;
-
- public PngChunkPLTE(final ImageInfo info) {
- super(PngChunkPLTE.ID, info);
- }
-
- @Override
- public ChunkOrderingConstraint getOrderingConstraint() {
- return ChunkOrderingConstraint.NA;
- }
-
- @Override
- public ChunkRaw createRawChunk() {
- final int len = 3 * nentries;
- final int[] rgb = new int[3];
- final ChunkRaw c = createEmptyChunk(len, true);
- for (int n = 0, i = 0; n < nentries; n++) {
- getEntryRgb(n, rgb);
- c.data[i++] = (byte) rgb[0];
- c.data[i++] = (byte) rgb[1];
- c.data[i++] = (byte) rgb[2];
- }
- return c;
- }
-
- @Override
- public void parseFromRaw(final ChunkRaw chunk) {
- setNentries(chunk.len / 3);
- for (int n = 0, i = 0; n < nentries; n++)
- setEntry(n, chunk.data[i++] & 0xff, chunk.data[i++] & 0xff, chunk.data[i++] & 0xff);
- }
-
- public void setNentries(final int n) {
- nentries = n;
- if (nentries < 1 || nentries > 256)
- throw new PngjException("invalid pallette - nentries=" + nentries);
- if (entries == null || entries.length != nentries)
- entries = new int[nentries];
- }
-
- public int getNentries() {
- return nentries;
- }
-
- public void setEntry(final int n, final int r, final int g, final int b) {
- entries[n] = r << 16 | g << 8 | b;
- }
-
- public int getEntry(final int n) {
- return entries[n];
- }
-
- public void getEntryRgb(final int n, final int[] rgb) {
- getEntryRgb(n, rgb, 0);
- }
-
- public void getEntryRgb(final int n, final int[] rgb, final int offset) {
- final int v = entries[n];
- rgb[offset + 0] = (v & 0xff0000) >> 16;
- rgb[offset + 1] = (v & 0xff00) >> 8;
- rgb[offset + 2] = v & 0xff;
- }
-
- public int minBitDepth() {
- if (nentries <= 2)
- return 1;
- else if (nentries <= 4)
- return 2;
- else if (nentries <= 16)
- return 4;
- else
- return 8;
- }
-
-}
diff --git a/teavm/src/main/java/ar/com/hjg/pngj/chunks/PngChunkSBIT.java b/teavm/src/main/java/ar/com/hjg/pngj/chunks/PngChunkSBIT.java
deleted file mode 100644
index f782b0ea..00000000
--- a/teavm/src/main/java/ar/com/hjg/pngj/chunks/PngChunkSBIT.java
+++ /dev/null
@@ -1,114 +0,0 @@
-package ar.com.hjg.pngj.chunks;
-
-import ar.com.hjg.pngj.ImageInfo;
-import ar.com.hjg.pngj.PngHelperInternal;
-import ar.com.hjg.pngj.PngjException;
-
-/**
- * sBIT chunk.
- *
- * see http://www.w3.org/TR/PNG/#11sBIT
- *
- * this chunk structure depends on the image type
- */
-public class PngChunkSBIT extends PngChunkSingle {
- public final static String ID = ChunkHelper.sBIT;
- // http://www.w3.org/TR/PNG/#11sBIT
-
- // significant bits
- private int graysb, alphasb;
- private int redsb, greensb, bluesb;
-
- public PngChunkSBIT(final ImageInfo info) {
- super(PngChunkSBIT.ID, info);
- }
-
- @Override
- public ChunkOrderingConstraint getOrderingConstraint() {
- return ChunkOrderingConstraint.BEFORE_PLTE_AND_IDAT;
- }
-
- private int getCLen() {
- int len = imgInfo.greyscale ? 1 : 3;
- if (imgInfo.alpha)
- len += 1;
- return len;
- }
-
- @Override
- public void parseFromRaw(final ChunkRaw c) {
- if (c.len != getCLen())
- throw new PngjException("bad chunk length " + c);
- if (imgInfo.greyscale) {
- graysb = PngHelperInternal.readInt1fromByte(c.data, 0);
- if (imgInfo.alpha)
- alphasb = PngHelperInternal.readInt1fromByte(c.data, 1);
- } else {
- redsb = PngHelperInternal.readInt1fromByte(c.data, 0);
- greensb = PngHelperInternal.readInt1fromByte(c.data, 1);
- bluesb = PngHelperInternal.readInt1fromByte(c.data, 2);
- if (imgInfo.alpha)
- alphasb = PngHelperInternal.readInt1fromByte(c.data, 3);
- }
- }
-
- @Override
- public ChunkRaw createRawChunk() {
- ChunkRaw c = null;
- c = createEmptyChunk(getCLen(), true);
- if (imgInfo.greyscale) {
- c.data[0] = (byte) graysb;
- if (imgInfo.alpha)
- c.data[1] = (byte) alphasb;
- } else {
- c.data[0] = (byte) redsb;
- c.data[1] = (byte) greensb;
- c.data[2] = (byte) bluesb;
- if (imgInfo.alpha)
- c.data[3] = (byte) alphasb;
- }
- return c;
- }
-
- public void setGraysb(final int gray) {
- if (!imgInfo.greyscale)
- throw new PngjException("only greyscale images support this");
- graysb = gray;
- }
-
- public int getGraysb() {
- if (!imgInfo.greyscale)
- throw new PngjException("only greyscale images support this");
- return graysb;
- }
-
- public void setAlphasb(final int a) {
- if (!imgInfo.alpha)
- throw new PngjException("only images with alpha support this");
- alphasb = a;
- }
-
- public int getAlphasb() {
- if (!imgInfo.alpha)
- throw new PngjException("only images with alpha support this");
- return alphasb;
- }
-
- /**
- * Set rgb values
- *
- */
- public void setRGB(final int r, final int g, final int b) {
- if (imgInfo.greyscale || imgInfo.indexed)
- throw new PngjException("only rgb or rgba images support this");
- redsb = r;
- greensb = g;
- bluesb = b;
- }
-
- public int[] getRGB() {
- if (imgInfo.greyscale || imgInfo.indexed)
- throw new PngjException("only rgb or rgba images support this");
- return new int[] { redsb, greensb, bluesb };
- }
-}
diff --git a/teavm/src/main/java/ar/com/hjg/pngj/chunks/PngChunkSPLT.java b/teavm/src/main/java/ar/com/hjg/pngj/chunks/PngChunkSPLT.java
deleted file mode 100644
index 423b41ff..00000000
--- a/teavm/src/main/java/ar/com/hjg/pngj/chunks/PngChunkSPLT.java
+++ /dev/null
@@ -1,129 +0,0 @@
-package ar.com.hjg.pngj.chunks;
-
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-
-import ar.com.hjg.pngj.ImageInfo;
-import ar.com.hjg.pngj.PngHelperInternal;
-import ar.com.hjg.pngj.PngjException;
-
-/**
- * sPLT chunk.
- *
- * see http://www.w3.org/TR/PNG/#11sPLT
- */
-public class PngChunkSPLT extends PngChunkMultiple {
- public final static String ID = ChunkHelper.sPLT;
-
- // http://www.w3.org/TR/PNG/#11sPLT
-
- private String palName;
- private int sampledepth; // 8/16
- private int[] palette; // 5 elements per entry
-
- public PngChunkSPLT(final ImageInfo info) {
- super(PngChunkSPLT.ID, info);
- }
-
- @Override
- public ChunkOrderingConstraint getOrderingConstraint() {
- return ChunkOrderingConstraint.BEFORE_IDAT;
- }
-
- @Override
- public ChunkRaw createRawChunk() {
- try {
- final ByteArrayOutputStream ba = new ByteArrayOutputStream();
- ba.write(ChunkHelper.toBytes(palName));
- ba.write(0); // separator
- ba.write((byte) sampledepth);
- final int nentries = getNentries();
- for (int n = 0; n < nentries; n++) {
- for (int i = 0; i < 4; i++)
- if (sampledepth == 8)
- PngHelperInternal.writeByte(ba, (byte) palette[n * 5 + i]);
- else
- PngHelperInternal.writeInt2(ba, palette[n * 5 + i]);
- PngHelperInternal.writeInt2(ba, palette[n * 5 + 4]);
- }
- final byte[] b = ba.toByteArray();
- final ChunkRaw chunk = createEmptyChunk(b.length, false);
- chunk.data = b;
- return chunk;
- } catch (final IOException e) {
- throw new PngjException(e);
- }
- }
-
- @Override
- public void parseFromRaw(final ChunkRaw c) {
- int t = -1;
- for (int i = 0; i < c.data.length; i++)
- if (c.data[i] == 0) {
- t = i;
- break;
- }
- if (t <= 0 || t > c.data.length - 2)
- throw new PngjException("bad sPLT chunk: no separator found");
- palName = ChunkHelper.toString(c.data, 0, t);
- sampledepth = PngHelperInternal.readInt1fromByte(c.data, t + 1);
- t += 2;
- final int nentries = (c.data.length - t) / (sampledepth == 8 ? 6 : 10);
- palette = new int[nentries * 5];
- int r, g, b, a, f, ne;
- ne = 0;
- for (int i = 0; i < nentries; i++) {
- if (sampledepth == 8) {
- r = PngHelperInternal.readInt1fromByte(c.data, t++);
- g = PngHelperInternal.readInt1fromByte(c.data, t++);
- b = PngHelperInternal.readInt1fromByte(c.data, t++);
- a = PngHelperInternal.readInt1fromByte(c.data, t++);
- } else {
- r = PngHelperInternal.readInt2fromBytes(c.data, t);
- t += 2;
- g = PngHelperInternal.readInt2fromBytes(c.data, t);
- t += 2;
- b = PngHelperInternal.readInt2fromBytes(c.data, t);
- t += 2;
- a = PngHelperInternal.readInt2fromBytes(c.data, t);
- t += 2;
- }
- f = PngHelperInternal.readInt2fromBytes(c.data, t);
- t += 2;
- palette[ne++] = r;
- palette[ne++] = g;
- palette[ne++] = b;
- palette[ne++] = a;
- palette[ne++] = f;
- }
- }
-
- public int getNentries() {
- return palette.length / 5;
- }
-
- public String getPalName() {
- return palName;
- }
-
- public void setPalName(final String palName) {
- this.palName = palName;
- }
-
- public int getSampledepth() {
- return sampledepth;
- }
-
- public void setSampledepth(final int sampledepth) {
- this.sampledepth = sampledepth;
- }
-
- public int[] getPalette() {
- return palette;
- }
-
- public void setPalette(final int[] palette) {
- this.palette = palette;
- }
-
-}
diff --git a/teavm/src/main/java/ar/com/hjg/pngj/chunks/PngChunkSRGB.java b/teavm/src/main/java/ar/com/hjg/pngj/chunks/PngChunkSRGB.java
deleted file mode 100644
index de261e79..00000000
--- a/teavm/src/main/java/ar/com/hjg/pngj/chunks/PngChunkSRGB.java
+++ /dev/null
@@ -1,55 +0,0 @@
-package ar.com.hjg.pngj.chunks;
-
-import ar.com.hjg.pngj.ImageInfo;
-import ar.com.hjg.pngj.PngHelperInternal;
-import ar.com.hjg.pngj.PngjException;
-
-/**
- * sRGB chunk.
- *
- * see http://www.w3.org/TR/PNG/#11sRGB
- */
-public class PngChunkSRGB extends PngChunkSingle {
- public final static String ID = ChunkHelper.sRGB;
-
- // http://www.w3.org/TR/PNG/#11sRGB
-
- public static final int RENDER_INTENT_Perceptual = 0;
- public static final int RENDER_INTENT_Relative_colorimetric = 1;
- public static final int RENDER_INTENT_Saturation = 2;
- public static final int RENDER_INTENT_Absolute_colorimetric = 3;
-
- private int intent;
-
- public PngChunkSRGB(final ImageInfo info) {
- super(PngChunkSRGB.ID, info);
- }
-
- @Override
- public ChunkOrderingConstraint getOrderingConstraint() {
- return ChunkOrderingConstraint.BEFORE_PLTE_AND_IDAT;
- }
-
- @Override
- public void parseFromRaw(final ChunkRaw c) {
- if (c.len != 1)
- throw new PngjException("bad chunk length " + c);
- intent = PngHelperInternal.readInt1fromByte(c.data, 0);
- }
-
- @Override
- public ChunkRaw createRawChunk() {
- ChunkRaw c = null;
- c = createEmptyChunk(1, true);
- c.data[0] = (byte) intent;
- return c;
- }
-
- public int getIntent() {
- return intent;
- }
-
- public void setIntent(final int intent) {
- this.intent = intent;
- }
-}
diff --git a/teavm/src/main/java/ar/com/hjg/pngj/chunks/PngChunkSTER.java b/teavm/src/main/java/ar/com/hjg/pngj/chunks/PngChunkSTER.java
deleted file mode 100644
index fe135767..00000000
--- a/teavm/src/main/java/ar/com/hjg/pngj/chunks/PngChunkSTER.java
+++ /dev/null
@@ -1,54 +0,0 @@
-package ar.com.hjg.pngj.chunks;
-
-import ar.com.hjg.pngj.ImageInfo;
-import ar.com.hjg.pngj.PngjException;
-
-/**
- * sTER chunk.
- *
- * see http://www.libpng.org/pub/png/spec/register/pngext-1.3.0-pdg.html#C.sTER
- */
-public class PngChunkSTER extends PngChunkSingle {
- public final static String ID = "sTER";
-
- // http://www.libpng.org/pub/png/spec/register/pngext-1.3.0-pdg.html#C.sTER
- private byte mode; // 0: cross-fuse layout 1: diverging-fuse layout
-
- public PngChunkSTER(final ImageInfo info) {
- super(PngChunkSTER.ID, info);
- }
-
- @Override
- public ChunkOrderingConstraint getOrderingConstraint() {
- return ChunkOrderingConstraint.BEFORE_IDAT;
- }
-
- @Override
- public ChunkRaw createRawChunk() {
- final ChunkRaw c = createEmptyChunk(1, true);
- c.data[0] = mode;
- return c;
- }
-
- @Override
- public void parseFromRaw(final ChunkRaw chunk) {
- if (chunk.len != 1)
- throw new PngjException("bad chunk length " + chunk);
- mode = chunk.data[0];
- }
-
- /**
- * 0: cross-fuse layout 1: diverging-fuse layout
- */
- public byte getMode() {
- return mode;
- }
-
- /**
- * 0: cross-fuse layout 1: diverging-fuse layout
- */
- public void setMode(final byte mode) {
- this.mode = mode;
- }
-
-}
diff --git a/teavm/src/main/java/ar/com/hjg/pngj/chunks/PngChunkSingle.java b/teavm/src/main/java/ar/com/hjg/pngj/chunks/PngChunkSingle.java
deleted file mode 100644
index a98df4e8..00000000
--- a/teavm/src/main/java/ar/com/hjg/pngj/chunks/PngChunkSingle.java
+++ /dev/null
@@ -1,45 +0,0 @@
-package ar.com.hjg.pngj.chunks;
-
-import ar.com.hjg.pngj.ImageInfo;
-
-/**
- * PNG chunk type (abstract) that does not allow multiple instances in same
- * image.
- */
-public abstract class PngChunkSingle extends PngChunk {
-
- protected PngChunkSingle(final String id, final ImageInfo imgInfo) {
- super(id, imgInfo);
- }
-
- @Override
- public final boolean allowsMultiple() {
- return false;
- }
-
- @Override
- public int hashCode() {
- final int prime = 31;
- int result = 1;
- result = prime * result + (id == null ? 0 : id.hashCode());
- return result;
- }
-
- @Override
- public boolean equals(final Object obj) {
- if (this == obj)
- return true;
- if (obj == null)
- return false;
- if (getClass() != obj.getClass())
- return false;
- final PngChunkSingle other = (PngChunkSingle) obj;
- if (id == null) {
- if (other.id != null)
- return false;
- } else if (!id.equals(other.id))
- return false;
- return true;
- }
-
-}
diff --git a/teavm/src/main/java/ar/com/hjg/pngj/chunks/PngChunkTEXT.java b/teavm/src/main/java/ar/com/hjg/pngj/chunks/PngChunkTEXT.java
deleted file mode 100644
index efaa62d4..00000000
--- a/teavm/src/main/java/ar/com/hjg/pngj/chunks/PngChunkTEXT.java
+++ /dev/null
@@ -1,44 +0,0 @@
-package ar.com.hjg.pngj.chunks;
-
-import ar.com.hjg.pngj.ImageInfo;
-import ar.com.hjg.pngj.PngjException;
-
-/**
- * tEXt chunk.
- *
- * see http://www.w3.org/TR/PNG/#11tEXt
- */
-public class PngChunkTEXT extends PngChunkTextVar {
- public final static String ID = ChunkHelper.tEXt;
-
- public PngChunkTEXT(final ImageInfo info) {
- super(PngChunkTEXT.ID, info);
- }
-
- public PngChunkTEXT(final ImageInfo info, final String key, final String val) {
- super(PngChunkTEXT.ID, info);
- setKeyVal(key, val);
- }
-
- @Override
- public ChunkRaw createRawChunk() {
- if (key == null || key.trim().length() == 0)
- throw new PngjException("Text chunk key must be non empty");
- final byte[] b = ChunkHelper.toBytes(key + "\0" + val);
- final ChunkRaw chunk = createEmptyChunk(b.length, false);
- chunk.data = b;
- return chunk;
- }
-
- @Override
- public void parseFromRaw(final ChunkRaw c) {
- int i;
- for (i = 0; i < c.data.length; i++)
- if (c.data[i] == 0)
- break;
- key = ChunkHelper.toString(c.data, 0, i);
- i++;
- val = i < c.data.length ? ChunkHelper.toString(c.data, i, c.data.length - i) : "";
- }
-
-}
diff --git a/teavm/src/main/java/ar/com/hjg/pngj/chunks/PngChunkTIME.java b/teavm/src/main/java/ar/com/hjg/pngj/chunks/PngChunkTIME.java
deleted file mode 100644
index 37fab915..00000000
--- a/teavm/src/main/java/ar/com/hjg/pngj/chunks/PngChunkTIME.java
+++ /dev/null
@@ -1,83 +0,0 @@
-package ar.com.hjg.pngj.chunks;
-
-import java.util.Calendar;
-
-import ar.com.hjg.pngj.ImageInfo;
-import ar.com.hjg.pngj.PngHelperInternal;
-import ar.com.hjg.pngj.PngjException;
-
-/**
- * tIME chunk.
- *
- * see http://www.w3.org/TR/PNG/#11tIME
- */
-public class PngChunkTIME extends PngChunkSingle {
- public final static String ID = ChunkHelper.tIME;
-
- // http://www.w3.org/TR/PNG/#11tIME
- private int year, mon, day, hour, min, sec;
-
- public PngChunkTIME(final ImageInfo info) {
- super(PngChunkTIME.ID, info);
- }
-
- @Override
- public ChunkOrderingConstraint getOrderingConstraint() {
- return ChunkOrderingConstraint.NONE;
- }
-
- @Override
- public ChunkRaw createRawChunk() {
- final ChunkRaw c = createEmptyChunk(7, true);
- PngHelperInternal.writeInt2tobytes(year, c.data, 0);
- c.data[2] = (byte) mon;
- c.data[3] = (byte) day;
- c.data[4] = (byte) hour;
- c.data[5] = (byte) min;
- c.data[6] = (byte) sec;
- return c;
- }
-
- @Override
- public void parseFromRaw(final ChunkRaw chunk) {
- if (chunk.len != 7)
- throw new PngjException("bad chunk " + chunk);
- year = PngHelperInternal.readInt2fromBytes(chunk.data, 0);
- mon = PngHelperInternal.readInt1fromByte(chunk.data, 2);
- day = PngHelperInternal.readInt1fromByte(chunk.data, 3);
- hour = PngHelperInternal.readInt1fromByte(chunk.data, 4);
- min = PngHelperInternal.readInt1fromByte(chunk.data, 5);
- sec = PngHelperInternal.readInt1fromByte(chunk.data, 6);
- }
-
- public void setNow(final int secsAgo) {
- final Calendar d = Calendar.getInstance();
- d.setTimeInMillis(System.currentTimeMillis() - 1000 * (long) secsAgo);
- year = d.get(Calendar.YEAR);
- mon = d.get(Calendar.MONTH) + 1;
- day = d.get(Calendar.DAY_OF_MONTH);
- hour = d.get(Calendar.HOUR_OF_DAY);
- min = d.get(Calendar.MINUTE);
- sec = d.get(Calendar.SECOND);
- }
-
- public void setYMDHMS(final int yearx, final int monx, final int dayx, final int hourx, final int minx,
- final int secx) {
- year = yearx;
- mon = monx;
- day = dayx;
- hour = hourx;
- min = minx;
- sec = secx;
- }
-
- public int[] getYMDHMS() {
- return new int[] { year, mon, day, hour, min, sec };
- }
-
- /** format YYYY/MM/DD HH:mm:SS */
- public String getAsString() {
- return String.format("%04d/%02d/%02d %02d:%02d:%02d", year, mon, day, hour, min, sec);
- }
-
-}
diff --git a/teavm/src/main/java/ar/com/hjg/pngj/chunks/PngChunkTRNS.java b/teavm/src/main/java/ar/com/hjg/pngj/chunks/PngChunkTRNS.java
deleted file mode 100644
index dd507304..00000000
--- a/teavm/src/main/java/ar/com/hjg/pngj/chunks/PngChunkTRNS.java
+++ /dev/null
@@ -1,150 +0,0 @@
-package ar.com.hjg.pngj.chunks;
-
-import ar.com.hjg.pngj.ImageInfo;
-import ar.com.hjg.pngj.PngHelperInternal;
-import ar.com.hjg.pngj.PngjException;
-
-/**
- * tRNS chunk.
- *
- * see http://www.w3.org/TR/PNG/#11tRNS
- *
- * this chunk structure depends on the image type
- */
-public class PngChunkTRNS extends PngChunkSingle {
- public final static String ID = ChunkHelper.tRNS;
-
- // http://www.w3.org/TR/PNG/#11tRNS
-
- // only one of these is meaningful, depending on the image type
- private int gray;
- private int red, green, blue;
- private int[] paletteAlpha = new int[] {};
-
- public PngChunkTRNS(final ImageInfo info) {
- super(PngChunkTRNS.ID, info);
- }
-
- @Override
- public ChunkOrderingConstraint getOrderingConstraint() {
- return ChunkOrderingConstraint.AFTER_PLTE_BEFORE_IDAT;
- }
-
- @Override
- public ChunkRaw createRawChunk() {
- ChunkRaw c = null;
- if (imgInfo.greyscale) {
- c = createEmptyChunk(2, true);
- PngHelperInternal.writeInt2tobytes(gray, c.data, 0);
- } else if (imgInfo.indexed) {
- c = createEmptyChunk(paletteAlpha.length, true);
- for (int n = 0; n < c.len; n++)
- c.data[n] = (byte) paletteAlpha[n];
- } else {
- c = createEmptyChunk(6, true);
- PngHelperInternal.writeInt2tobytes(red, c.data, 0);
- PngHelperInternal.writeInt2tobytes(green, c.data, 0);
- PngHelperInternal.writeInt2tobytes(blue, c.data, 0);
- }
- return c;
- }
-
- @Override
- public void parseFromRaw(final ChunkRaw c) {
- if (imgInfo.greyscale)
- gray = PngHelperInternal.readInt2fromBytes(c.data, 0);
- else if (imgInfo.indexed) {
- final int nentries = c.data.length;
- paletteAlpha = new int[nentries];
- for (int n = 0; n < nentries; n++)
- paletteAlpha[n] = c.data[n] & 0xff;
- } else {
- red = PngHelperInternal.readInt2fromBytes(c.data, 0);
- green = PngHelperInternal.readInt2fromBytes(c.data, 2);
- blue = PngHelperInternal.readInt2fromBytes(c.data, 4);
- }
- }
-
- /**
- * Set rgb values
- *
- */
- public void setRGB(final int r, final int g, final int b) {
- if (imgInfo.greyscale || imgInfo.indexed)
- throw new PngjException("only rgb or rgba images support this");
- red = r;
- green = g;
- blue = b;
- }
-
- public int[] getRGB() {
- if (imgInfo.greyscale || imgInfo.indexed)
- throw new PngjException("only rgb or rgba images support this");
- return new int[] { red, green, blue };
- }
-
- public int getRGB888() {
- if (imgInfo.greyscale || imgInfo.indexed)
- throw new PngjException("only rgb or rgba images support this");
- return red << 16 | green << 8 | blue;
- }
-
- public void setGray(final int g) {
- if (!imgInfo.greyscale)
- throw new PngjException("only grayscale images support this");
- gray = g;
- }
-
- public int getGray() {
- if (!imgInfo.greyscale)
- throw new PngjException("only grayscale images support this");
- return gray;
- }
-
- /**
- * Sets the length of the palette alpha. This should be followed by
- * #setNentriesPalAlpha
- *
- * @param idx
- * index inside the table
- * @param val
- * alpha value (0-255)
- */
- public void setEntryPalAlpha(final int idx, final int val) {
- paletteAlpha[idx] = val;
- }
-
- public void setNentriesPalAlpha(final int len) {
- paletteAlpha = new int[len];
- }
-
- /**
- * WARNING: non deep copy. See also {@link #setNentriesPalAlpha(int)}
- * {@link #setEntryPalAlpha(int, int)}
- */
- public void setPalAlpha(final int[] palAlpha) {
- if (!imgInfo.indexed)
- throw new PngjException("only indexed images support this");
- paletteAlpha = palAlpha;
- }
-
- /**
- * WARNING: non deep copy
- */
- public int[] getPalletteAlpha() {
- return paletteAlpha;
- }
-
- /**
- * to use when only one pallete index is set as totally transparent
- */
- public void setIndexEntryAsTransparent(final int palAlphaIndex) {
- if (!imgInfo.indexed)
- throw new PngjException("only indexed images support this");
- paletteAlpha = new int[] { palAlphaIndex + 1 };
- for (int i = 0; i < palAlphaIndex; i++)
- paletteAlpha[i] = 255;
- paletteAlpha[palAlphaIndex] = 0;
- }
-
-}
diff --git a/teavm/src/main/java/ar/com/hjg/pngj/chunks/PngChunkTextVar.java b/teavm/src/main/java/ar/com/hjg/pngj/chunks/PngChunkTextVar.java
deleted file mode 100644
index 1591011a..00000000
--- a/teavm/src/main/java/ar/com/hjg/pngj/chunks/PngChunkTextVar.java
+++ /dev/null
@@ -1,60 +0,0 @@
-package ar.com.hjg.pngj.chunks;
-
-import ar.com.hjg.pngj.ImageInfo;
-
-/**
- * Superclass (abstract) for three textual chunks (TEXT, ITXT, ZTXT)
- */
-public abstract class PngChunkTextVar extends PngChunkMultiple {
- protected String key; // key/val: only for tEXt. lazy computed
- protected String val;
-
- // http://www.w3.org/TR/PNG/#11keywords
- public final static String KEY_Title = "Title"; // Short (one line) title or caption for image
- public final static String KEY_Author = "Author"; // Name of image's creator
- public final static String KEY_Description = "Description"; // Description of image (possibly
- // long)
- public final static String KEY_Copyright = "Copyright"; // Copyright notice
- public final static String KEY_Creation_Time = "Creation Time"; // Time of original image creation
- public final static String KEY_Software = "Software"; // Software used to create the image
- public final static String KEY_Disclaimer = "Disclaimer"; // Legal disclaimer
- public final static String KEY_Warning = "Warning"; // Warning of nature of content
- public final static String KEY_Source = "Source"; // Device used to create the image
- public final static String KEY_Comment = "Comment"; // Miscellaneous comment
-
- protected PngChunkTextVar(final String id, final ImageInfo info) {
- super(id, info);
- }
-
- @Override
- public ChunkOrderingConstraint getOrderingConstraint() {
- return ChunkOrderingConstraint.NONE;
- }
-
- public static class PngTxtInfo {
- public String title;
- public String author;
- public String description;
- public String creation_time;// = (new Date()).toString();
- public String software;
- public String disclaimer;
- public String warning;
- public String source;
- public String comment;
-
- }
-
- public String getKey() {
- return key;
- }
-
- public String getVal() {
- return val;
- }
-
- public void setKeyVal(final String key, final String val) {
- this.key = key;
- this.val = val;
- }
-
-}
diff --git a/teavm/src/main/java/ar/com/hjg/pngj/chunks/PngChunkUNKNOWN.java b/teavm/src/main/java/ar/com/hjg/pngj/chunks/PngChunkUNKNOWN.java
deleted file mode 100644
index dbc8ad08..00000000
--- a/teavm/src/main/java/ar/com/hjg/pngj/chunks/PngChunkUNKNOWN.java
+++ /dev/null
@@ -1,40 +0,0 @@
-package ar.com.hjg.pngj.chunks;
-
-import ar.com.hjg.pngj.ImageInfo;
-
-/**
- * Placeholder for UNKNOWN (custom or not) chunks.
- *
- * For PngReader, a chunk is unknown if it's not registered in the chunk factory
- */
-public class PngChunkUNKNOWN extends PngChunkMultiple { // unkown, custom or not
-
- public PngChunkUNKNOWN(final String id, final ImageInfo info) {
- super(id, info);
- }
-
- @Override
- public ChunkOrderingConstraint getOrderingConstraint() {
- return ChunkOrderingConstraint.NONE;
- }
-
- @Override
- public ChunkRaw createRawChunk() {
- return raw;
- }
-
- @Override
- public void parseFromRaw(final ChunkRaw c) {
-
- }
-
- /* does not do deep copy! */
- public byte[] getData() {
- return raw.data;
- }
-
- /* does not do deep copy! */
- public void setData(final byte[] data) {
- raw.data = data;
- }
-}
diff --git a/teavm/src/main/java/ar/com/hjg/pngj/chunks/PngChunkZTXT.java b/teavm/src/main/java/ar/com/hjg/pngj/chunks/PngChunkZTXT.java
deleted file mode 100644
index 7ad9e69b..00000000
--- a/teavm/src/main/java/ar/com/hjg/pngj/chunks/PngChunkZTXT.java
+++ /dev/null
@@ -1,61 +0,0 @@
-package ar.com.hjg.pngj.chunks;
-
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-
-import ar.com.hjg.pngj.ImageInfo;
-import ar.com.hjg.pngj.PngjException;
-
-/**
- * zTXt chunk.
- *
- * see http://www.w3.org/TR/PNG/#11zTXt
- */
-public class PngChunkZTXT extends PngChunkTextVar {
- public final static String ID = ChunkHelper.zTXt;
-
- // http://www.w3.org/TR/PNG/#11zTXt
- public PngChunkZTXT(final ImageInfo info) {
- super(PngChunkZTXT.ID, info);
- }
-
- @Override
- public ChunkRaw createRawChunk() {
- if (key == null || key.trim().length() == 0)
- throw new PngjException("Text chunk key must be non empty");
- try {
- final ByteArrayOutputStream ba = new ByteArrayOutputStream();
- ba.write(ChunkHelper.toBytes(key));
- ba.write(0); // separator
- ba.write(0); // compression method: 0
- final byte[] textbytes = ChunkHelper.compressBytes(ChunkHelper.toBytes(val), true);
- ba.write(textbytes);
- final byte[] b = ba.toByteArray();
- final ChunkRaw chunk = createEmptyChunk(b.length, false);
- chunk.data = b;
- return chunk;
- } catch (final IOException e) {
- throw new PngjException(e);
- }
- }
-
- @Override
- public void parseFromRaw(final ChunkRaw c) {
- int nullsep = -1;
- for (int i = 0; i < c.data.length; i++) { // look for first zero
- if (c.data[i] != 0)
- continue;
- nullsep = i;
- break;
- }
- if (nullsep < 0 || nullsep > c.data.length - 2)
- throw new PngjException("bad zTXt chunk: no separator found");
- key = ChunkHelper.toString(c.data, 0, nullsep);
- final int compmet = c.data[nullsep + 1];
- if (compmet != 0)
- throw new PngjException("bad zTXt chunk: unknown compression method");
- final byte[] uncomp = ChunkHelper.compressBytes(c.data, nullsep + 2, c.data.length - nullsep - 2, false); // uncompress
- val = ChunkHelper.toString(uncomp);
- }
-
-}
diff --git a/teavm/src/main/java/ar/com/hjg/pngj/chunks/PngMetadata.java b/teavm/src/main/java/ar/com/hjg/pngj/chunks/PngMetadata.java
deleted file mode 100644
index 46c30c92..00000000
--- a/teavm/src/main/java/ar/com/hjg/pngj/chunks/PngMetadata.java
+++ /dev/null
@@ -1,235 +0,0 @@
-package ar.com.hjg.pngj.chunks;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import ar.com.hjg.pngj.PngjException;
-
-/**
- * We consider "image metadata" every info inside the image except for the most
- * basic image info (IHDR chunk - ImageInfo
- * class) and the pixels values.
- *
- * This includes the palette (if present) and all the ancillary chunks
- *
- * This class provides a wrapper over the collection of chunks of a image (read
- * or to write) and provides some high
- * level methods to access them
- */
-public class PngMetadata {
- private final ChunksList chunkList;
- private final boolean readonly;
-
- public PngMetadata(final ChunksList chunks) {
- chunkList = chunks;
- if (chunks instanceof ChunksListForWrite)
- readonly = false;
- else
- readonly = true;
- }
-
- /**
- * Queues the chunk at the writer
- *
- * lazyOverwrite: if true, checks if there is a queued "equivalent" chunk
- * and if so, overwrites it. However if that
- * not check for already written chunks.
- */
- public void queueChunk(final PngChunk c, final boolean lazyOverwrite) {
- final ChunksListForWrite cl = getChunkListW();
- if (readonly)
- throw new PngjException("cannot set chunk : readonly metadata");
- if (lazyOverwrite)
- ChunkHelper.trimList(cl.getQueuedChunks(), c2 -> ChunkHelper.equivalent(c, c2));
- cl.queue(c);
- }
-
- public void queueChunk(final PngChunk c) {
- queueChunk(c, true);
- }
-
- private ChunksListForWrite getChunkListW() {
- return (ChunksListForWrite) chunkList;
- }
-
- // ///// high level utility methods follow ////////////
-
- // //////////// DPI
-
- /**
- * returns -1 if not found or dimension unknown
- */
- public double[] getDpi() {
- final PngChunk c = chunkList.getById1(ChunkHelper.pHYs, true);
- if (c == null)
- return new double[] { -1, -1 };
- else
- return ((PngChunkPHYS) c).getAsDpi2();
- }
-
- public void setDpi(final double x) {
- setDpi(x, x);
- }
-
- public void setDpi(final double x, final double y) {
- final PngChunkPHYS c = new PngChunkPHYS(chunkList.imageInfo);
- c.setAsDpi2(x, y);
- queueChunk(c);
- }
-
- // //////////// TIME
-
- /**
- * Creates a time chunk with current time, less secsAgo seconds
- *
- *
- * @return Returns the created-queued chunk, just in case you want to
- * examine or modify it
- */
- public PngChunkTIME setTimeNow(final int secsAgo) {
- final PngChunkTIME c = new PngChunkTIME(chunkList.imageInfo);
- c.setNow(secsAgo);
- queueChunk(c);
- return c;
- }
-
- public PngChunkTIME setTimeNow() {
- return setTimeNow(0);
- }
-
- /**
- * Creates a time chunk with diven date-time
- *
- *
- * @return Returns the created-queued chunk, just in case you want to
- * examine or modify it
- */
- public PngChunkTIME setTimeYMDHMS(final int yearx, final int monx, final int dayx, final int hourx, final int minx,
- final int secx) {
- final PngChunkTIME c = new PngChunkTIME(chunkList.imageInfo);
- c.setYMDHMS(yearx, monx, dayx, hourx, minx, secx);
- queueChunk(c, true);
- return c;
- }
-
- /**
- * null if not found
- */
- public PngChunkTIME getTime() {
- return (PngChunkTIME) chunkList.getById1(ChunkHelper.tIME);
- }
-
- public String getTimeAsString() {
- final PngChunkTIME c = getTime();
- return c == null ? "" : c.getAsString();
- }
-
- // //////////// TEXT
-
- /**
- * Creates a text chunk and queue it.
- *
- *
- * @param k
- * : key (latin1)
- * @param val
- * (arbitrary, should be latin1 if useLatin1)
- * @param useLatin1
- * @param compress
- * @return Returns the created-queued chunks, just in case you want to
- * examine, touch it
- */
- public PngChunkTextVar setText(final String k, final String val, final boolean useLatin1, final boolean compress) {
- if (compress && !useLatin1)
- throw new PngjException("cannot compress non latin text");
- PngChunkTextVar c;
- if (useLatin1) {
- if (compress)
- c = new PngChunkZTXT(chunkList.imageInfo);
- else
- c = new PngChunkTEXT(chunkList.imageInfo);
- } else {
- c = new PngChunkITXT(chunkList.imageInfo);
- ((PngChunkITXT) c).setLangtag(k); // we use the same orig tag (this is not quite right)
- }
- c.setKeyVal(k, val);
- queueChunk(c, true);
- return c;
- }
-
- public PngChunkTextVar setText(final String k, final String val) {
- return setText(k, val, false, false);
- }
-
- /**
- * gets all text chunks with a given key
- *
- * returns null if not found
- *
- * Warning: this does not check the "lang" key of iTxt
- */
- @SuppressWarnings("unchecked")
- public List extends PngChunkTextVar> getTxtsForKey(final String k) {
- @SuppressWarnings("rawtypes")
- final List c = new ArrayList();
- c.addAll(chunkList.getById(ChunkHelper.tEXt, k));
- c.addAll(chunkList.getById(ChunkHelper.zTXt, k));
- c.addAll(chunkList.getById(ChunkHelper.iTXt, k));
- return c;
- }
-
- /**
- * Returns empty if not found, concatenated (with newlines) if multiple! -
- * and trimmed
- *
- * Use getTxtsForKey() if you don't want this behaviour
- */
- public String getTxtForKey(final String k) {
- final List extends PngChunkTextVar> li = getTxtsForKey(k);
- if (li.isEmpty())
- return "";
- final StringBuilder t = new StringBuilder();
- for (final PngChunkTextVar c : li)
- t.append(c.getVal()).append("\n");
- return t.toString().trim();
- }
-
- /**
- * Returns the palette chunk, if present
- *
- * @return null if not present
- */
- public PngChunkPLTE getPLTE() {
- return (PngChunkPLTE) chunkList.getById1(PngChunkPLTE.ID);
- }
-
- /**
- * Creates a new empty palette chunk, queues it for write and return it to
- * the caller, who should fill its entries
- */
- public PngChunkPLTE createPLTEChunk() {
- final PngChunkPLTE plte = new PngChunkPLTE(chunkList.imageInfo);
- queueChunk(plte);
- return plte;
- }
-
- /**
- * Returns the TRNS chunk, if present
- *
- * @return null if not present
- */
- public PngChunkTRNS getTRNS() {
- return (PngChunkTRNS) chunkList.getById1(PngChunkTRNS.ID);
- }
-
- /**
- * Creates a new empty TRNS chunk, queues it for write and return it to the
- * caller, who should fill its entries
- */
- public PngChunkTRNS createTRNSChunk() {
- final PngChunkTRNS trns = new PngChunkTRNS(chunkList.imageInfo);
- queueChunk(trns);
- return trns;
- }
-
-}
diff --git a/teavm/src/main/java/ar/com/hjg/pngj/chunks/package.html b/teavm/src/main/java/ar/com/hjg/pngj/chunks/package.html
deleted file mode 100644
index 13740669..00000000
--- a/teavm/src/main/java/ar/com/hjg/pngj/chunks/package.html
+++ /dev/null
@@ -1,9 +0,0 @@
-
-
-
-Contains the code related to chunk management for the PNGJ library.
-
-Only needed by client code if some special chunk handling is required.
-
-Users of this library should rarely need more than the public members of this package.
-Newcomers: start with PngReader and PngWriter.
-
-
-Example of use: this code reads a true colour PNG image (RGB8 or RGBA8)
-and reduces the red channel by half, increasing the green by 20.
-It copies all the "safe" metadata from the original image, and adds a textual metadata.
-
-
- public static void convert(String origFilename, String destFilename) {
- // you can also use PngReader (esentially the same) or PngReaderByte
- PngReaderInt pngr = new PngReaderInt(new File(origFilename));
- System.out.println(pngr.toString());
- int channels = pngr.imgInfo.channels;
- if (channels < 3 || pngr.imgInfo.bitDepth != 8)
- throw new RuntimeException("For simplicity this supports only RGB8/RGBA8 images");
- // writer with same image properties as original
- PngWriter pngw = new PngWriter(new File(destFilename), pngr.imgInfo, true);
- // instruct the writer to grab all ancillary chunks from the original
- pngw.copyChunksFrom(pngr.getChunksList(), ChunkCopyBehaviour.COPY_ALL_SAFE);
- // add a textual chunk to writer
- pngw.getMetadata().setText(PngChunkTextVar.KEY_Description, "Decreased red and increased green");
- // also: while(pngr.hasMoreRows())
- for (int row = 0; row < pngr.imgInfo.rows; row++) {
- ImageLineInt l1 = pngr.readRowInt(); // each element is a sample
- int[] scanline = l1.getScanline(); // to save typing
- for (int j = 0; j < pngr.imgInfo.cols; j++) {
- scanline[j * channels] /= 2;
- scanline[j * channels + 1] = ImageLineHelper.clampTo_0_255(scanline[j * channels + 1] + 20);
- }
- pngw.writeRow(l1);
- }
- pngr.end(); // it's recommended to end the reader first, in case there are trailing chunks to read
- pngw.end();
- }
-
-
-
-For more examples, see the tests and samples.
-
-
-
-
diff --git a/teavm/src/main/java/ar/com/hjg/pngj/pixels/CompressorStream.java b/teavm/src/main/java/ar/com/hjg/pngj/pixels/CompressorStream.java
deleted file mode 100644
index 7c7425af..00000000
--- a/teavm/src/main/java/ar/com/hjg/pngj/pixels/CompressorStream.java
+++ /dev/null
@@ -1,168 +0,0 @@
-package ar.com.hjg.pngj.pixels;
-
-import java.io.OutputStream;
-
-import ar.com.hjg.pngj.IDatChunkWriter;
-
-/**
- * This is an OutputStream that compresses (via Deflater or a deflater-like
- * object), and optionally passes the
- * compressed stream to another output stream.
- *
- * It allows to compute in/out/ratio stats.
- *
- * It works as a stream (similar to DeflaterOutputStream), but it's peculiar in
- * that it expects that each writes has a
- * fixed length (other lenghts are accepted, but it's less efficient) and that
- * the total amount of bytes is known (so it
- * can close itself, but it can also be closed on demand) In PNGJ use, the block
- * is typically a row (including filter
- * byte).
- *
- * We use this to do the real compression (with Deflate) but also to compute
- * tentative estimators
- *
- * If not closed, it can be recicled via reset()
- *
- *
- */
-public abstract class CompressorStream extends OutputStream {
-
- protected IDatChunkWriter idatChunkWriter;
- public final int blockLen;
- public final long totalbytes;
-
- boolean closed = false;
- protected boolean done = false;
- protected long bytesIn = 0;
- protected long bytesOut = 0;
- protected int block = -1;
-
- /** optionally stores the first byte of each block (row) */
- private byte[] firstBytes;
- protected boolean storeFirstByte = false;
-
- /**
- *
- * @param idatCw
- * Can be null (if we are only interested in compute compression
- * ratio)
- * @param blockLen
- * Estimated maximum block length. If unknown, use -1.
- * @param totalbytes
- * Expected total bytes to be fed. If unknown, use -1.
- */
- public CompressorStream(final IDatChunkWriter idatCw, int blockLen, long totalbytes) {
- idatChunkWriter = idatCw;
- if (blockLen < 0)
- blockLen = 4096;
- if (totalbytes < 0)
- totalbytes = Long.MAX_VALUE;
- if (blockLen < 1 || totalbytes < 1)
- throw new RuntimeException(" maxBlockLen or totalLen invalid");
- this.blockLen = blockLen;
- this.totalbytes = totalbytes;
- }
-
- /** Releases resources. Idempotent. */
- @Override
- public void close() {
- done();
- if (idatChunkWriter != null)
- idatChunkWriter.close();
- closed = true;
- }
-
- /**
- * Will be called automatically when the number of bytes reaches the total
- * expected Can be also be called from
- * outside. This should set the flag done=true
- */
- public abstract void done();
-
- @Override
- public final void write(final byte[] data) {
- write(data, 0, data.length);
- }
-
- @Override
- public final void write(final byte[] data, int off, int len) {
- block++;
- if (len <= blockLen) { // normal case
- mywrite(data, off, len);
- if (storeFirstByte && block < firstBytes.length)
- firstBytes[block] = data[off]; // only makes sense in this case
- } else
- while (len > 0) {
- mywrite(data, off, blockLen);
- off += blockLen;
- len -= blockLen;
- }
- if (bytesIn >= totalbytes)
- done();
-
- }
-
- /**
- * same as write, but guarantedd to not exceed blockLen The implementation
- * should update bytesOut and bytesInt but not
- * check for totalBytes
- */
- public abstract void mywrite(byte[] data, int off, int len);
-
- /**
- * compressed/raw. This should be called only when done
- */
- public final double getCompressionRatio() {
- return bytesOut == 0 ? 1.0 : bytesOut / (double) bytesIn;
- }
-
- /**
- * raw (input) bytes. This should be called only when done
- */
- public final long getBytesRaw() {
- return bytesIn;
- }
-
- /**
- * compressed (out) bytes. This should be called only when done
- */
- public final long getBytesCompressed() {
- return bytesOut;
- }
-
- public boolean isClosed() {
- return closed;
- }
-
- public boolean isDone() {
- return done;
- }
-
- public byte[] getFirstBytes() {
- return firstBytes;
- }
-
- public void setStoreFirstByte(final boolean storeFirstByte, final int nblocks) {
- this.storeFirstByte = storeFirstByte;
- if (this.storeFirstByte) {
- if (firstBytes == null || firstBytes.length < nblocks)
- firstBytes = new byte[nblocks];
- } else
- firstBytes = null;
- }
-
- public void reset() {
- done();
- bytesIn = 0;
- bytesOut = 0;
- block = -1;
- done = false;
- }
-
- @Override
- public void write(final int i) { // should not be used
- write(new byte[] { (byte) i });
- }
-
-}
diff --git a/teavm/src/main/java/ar/com/hjg/pngj/pixels/CompressorStreamDeflater.java b/teavm/src/main/java/ar/com/hjg/pngj/pixels/CompressorStreamDeflater.java
deleted file mode 100644
index 291bf4d6..00000000
--- a/teavm/src/main/java/ar/com/hjg/pngj/pixels/CompressorStreamDeflater.java
+++ /dev/null
@@ -1,105 +0,0 @@
-package ar.com.hjg.pngj.pixels;
-
-import java.util.zip.Deflater;
-
-import ar.com.hjg.pngj.IDatChunkWriter;
-import ar.com.hjg.pngj.PngjOutputException;
-
-/**
- * CompressorStream backed by a Deflater.
- *
- * Note that the Deflater is not disposed after done, you should either recycle
- * this with reset() or dispose it with
- * close()
- *
- */
-public class CompressorStreamDeflater extends CompressorStream {
-
- protected Deflater deflater;
- protected byte[] buf1; // temporary storage of compressed bytes: only used if idatWriter is null
- protected boolean deflaterIsOwn = true;
-
- /**
- * if a deflater is passed, it must be already reset. It will not be
- * released on close
- */
- public CompressorStreamDeflater(final IDatChunkWriter idatCw, final int maxBlockLen, final long totalLen, final Deflater def) {
- super(idatCw, maxBlockLen, totalLen);
- deflater = def == null ? new Deflater() : def;
- deflaterIsOwn = def == null;
- }
-
- public CompressorStreamDeflater(final IDatChunkWriter idatCw, final int maxBlockLen, final long totalLen) {
- this(idatCw, maxBlockLen, totalLen, null);
- }
-
- public CompressorStreamDeflater(final IDatChunkWriter idatCw, final int maxBlockLen, final long totalLen, final int deflaterCompLevel, final int deflaterStrategy) {
- this(idatCw, maxBlockLen, totalLen, new Deflater(deflaterCompLevel));
- deflaterIsOwn = true;
- deflater.setStrategy(deflaterStrategy);
- }
-
- @Override
- public void mywrite(final byte[] data, final int off, final int len) {
- if (deflater.finished() || done || closed)
- throw new PngjOutputException("write beyond end of stream");
- deflater.setInput(data, off, len);
- bytesIn += len;
- while (!deflater.needsInput())
- deflate();
- }
-
- protected void deflate() {
- byte[] buf;
- int off, n;
- if (idatChunkWriter != null) {
- buf = idatChunkWriter.getBuf();
- off = idatChunkWriter.getOffset();
- n = idatChunkWriter.getAvailLen();
- } else {
- if (buf1 == null)
- buf1 = new byte[4096];
- buf = buf1;
- off = 0;
- n = buf1.length;
- }
- final int len = deflater.deflate(buf, off, n);
- if (len > 0) {
- if (idatChunkWriter != null)
- idatChunkWriter.incrementOffset(len);
- bytesOut += len;
- }
- }
-
- /** automatically called when done */
- @Override
- public void done() {
- if (done)
- return;
- if (!deflater.finished()) {
- deflater.finish();
- while (!deflater.finished())
- deflate();
- }
- done = true;
- if (idatChunkWriter != null)
- idatChunkWriter.close();
- }
-
- @Override
- public void close() {
- done();
- try {
- if (deflaterIsOwn)
- deflater.end();
- } catch (final Exception e) {}
- super.close();
- }
-
- @Override
- public void reset() {
- deflater.reset();
- super.reset();
- }
-
-}
diff --git a/teavm/src/main/java/ar/com/hjg/pngj/pixels/CompressorStreamLz4.java b/teavm/src/main/java/ar/com/hjg/pngj/pixels/CompressorStreamLz4.java
deleted file mode 100644
index 318918f2..00000000
--- a/teavm/src/main/java/ar/com/hjg/pngj/pixels/CompressorStreamLz4.java
+++ /dev/null
@@ -1,94 +0,0 @@
-package ar.com.hjg.pngj.pixels;
-
-import java.util.zip.Deflater;
-
-import ar.com.hjg.pngj.IDatChunkWriter;
-import ar.com.hjg.pngj.PngjOutputException;
-
-/**
- * This class uses a quick compressor to get a rough estimate of deflate
- * compression ratio.
- *
- * This just ignores the outputStream, and the deflater related parameters
- */
-public class CompressorStreamLz4 extends CompressorStream {
-
- private final DeflaterEstimatorLz4 lz4;
-
- private byte[] buf; // lazily allocated, only if needed
- private final int buffer_size;
- // bufpos=bytes in buffer yet not compressed (bytesIn include this)
- private int inbuf = 0;
-
- private static final int MAX_BUFFER_SIZE = 16000;
-
- public CompressorStreamLz4(final IDatChunkWriter os, final int maxBlockLen, final long totalLen) {
- super(os, maxBlockLen, totalLen);
- lz4 = new DeflaterEstimatorLz4();
- buffer_size = (int) (totalLen > CompressorStreamLz4.MAX_BUFFER_SIZE ? CompressorStreamLz4.MAX_BUFFER_SIZE : totalLen);
- }
-
- public CompressorStreamLz4(final IDatChunkWriter os, final int maxBlockLen, final long totalLen, final Deflater def) {
- this(os, maxBlockLen, totalLen);// edlfater ignored
- }
-
- public CompressorStreamLz4(final IDatChunkWriter os, final int maxBlockLen, final long totalLen, final int deflaterCompLevel, final int deflaterStrategy) {
- this(os, maxBlockLen, totalLen); // paramters ignored
- }
-
- @Override
- public void mywrite(final byte[] b, int off, int len) {
- if (len == 0)
- return;
- if (done || closed)
- throw new PngjOutputException("write beyond end of stream");
- bytesIn += len;
- while (len > 0)
- if (inbuf == 0 && (len >= CompressorStreamLz4.MAX_BUFFER_SIZE || bytesIn == totalbytes)) {
- // direct copy (buffer might be null or empty)
- bytesOut += lz4.compressEstim(b, off, len);
- len = 0;
- } else {
- if (buf == null)
- buf = new byte[buffer_size];
- final int len1 = inbuf + len <= buffer_size ? len : buffer_size - inbuf; // to copy
- if (len1 > 0)
- System.arraycopy(b, off, buf, inbuf, len1);
- inbuf += len1;
- len -= len1;
- off += len1;
- if (inbuf == buffer_size)
- compressFromBuffer();
- }
- }
-
- void compressFromBuffer() {
- if (inbuf > 0) {
- bytesOut += lz4.compressEstim(buf, 0, inbuf);
- inbuf = 0;
- }
- }
-
- @Override
- public void done() {
- if (!done) {
- compressFromBuffer();
- done = true;
- }
- }
-
- @Override
- public void close() {
- done();
- if (!closed) {
- super.close();
- buf = null;
- }
- }
-
- @Override
- public void reset() {
- super.reset();
- }
-
-}
diff --git a/teavm/src/main/java/ar/com/hjg/pngj/pixels/DeflaterEstimatorHjg.java b/teavm/src/main/java/ar/com/hjg/pngj/pixels/DeflaterEstimatorHjg.java
deleted file mode 100644
index 4f8fab67..00000000
--- a/teavm/src/main/java/ar/com/hjg/pngj/pixels/DeflaterEstimatorHjg.java
+++ /dev/null
@@ -1,248 +0,0 @@
-package ar.com.hjg.pngj.pixels;
-
-final public class DeflaterEstimatorHjg {
-
- /**
- * This object is stateless, it's thread safe and can be reused
- */
- public DeflaterEstimatorHjg() {}
-
- /**
- * Estimates the length of the compressed bytes, as compressed by Lz4
- * WARNING: if larger than LZ4_64K_LIMIT it cuts it
- * in fragments
- *
- * WARNING: if some part of the input is discarded, this should return the
- * proportional (so that
- * returnValue/srcLen=compressionRatio)
- *
- * @param src
- * @param srcOff
- * @param srcLen
- * @return length of the compressed bytes
- */
- public int compressEstim(final byte[] src, int srcOff, final int srcLen) {
- if (srcLen < 10)
- return srcLen; // too small
- int stride = DeflaterEstimatorHjg.LZ4_64K_LIMIT - 1;
- final int segments = (srcLen + stride - 1) / stride;
- stride = srcLen / segments;
- if (stride >= DeflaterEstimatorHjg.LZ4_64K_LIMIT - 1 || stride * segments > srcLen || segments < 1 || stride < 1)
- throw new RuntimeException("?? " + srcLen);
- int bytesIn = 0;
- int bytesOut = 0;
- int len = srcLen;
- while (len > 0) {
- if (len > stride)
- len = stride;
- bytesOut += DeflaterEstimatorHjg.compress64k(src, srcOff, len);
- srcOff += len;
- bytesIn += len;
- len = srcLen - bytesIn;
- }
- final double ratio = bytesOut / (double) bytesIn;
- return bytesIn == srcLen ? bytesOut : (int) (ratio * srcLen + 0.5);
- }
-
- public int compressEstim(final byte[] src) {
- return compressEstim(src, 0, src.length);
- }
-
- static final int MEMORY_USAGE = 14;
- static final int NOT_COMPRESSIBLE_DETECTION_LEVEL = 6; // see SKIP_STRENGTH
-
- static final int MIN_MATCH = 4;
-
- static final int HASH_LOG = DeflaterEstimatorHjg.MEMORY_USAGE - 2;
- static final int HASH_TABLE_SIZE = 1 << DeflaterEstimatorHjg.HASH_LOG;
-
- static final int SKIP_STRENGTH = Math.max(DeflaterEstimatorHjg.NOT_COMPRESSIBLE_DETECTION_LEVEL, 2); // 6 findMatchAttempts =
- // 2^SKIP_STRENGTH+3
- static final int COPY_LENGTH = 8;
- static final int LAST_LITERALS = 5;
- static final int MF_LIMIT = DeflaterEstimatorHjg.COPY_LENGTH + DeflaterEstimatorHjg.MIN_MATCH;
- static final int MIN_LENGTH = DeflaterEstimatorHjg.MF_LIMIT + 1;
-
- static final int MAX_DISTANCE = 1 << 16;
-
- static final int ML_BITS = 4;
- static final int ML_MASK = (1 << DeflaterEstimatorHjg.ML_BITS) - 1;
- static final int RUN_BITS = 8 - DeflaterEstimatorHjg.ML_BITS;
- static final int RUN_MASK = (1 << DeflaterEstimatorHjg.RUN_BITS) - 1;
-
- static final int LZ4_64K_LIMIT = (1 << 16) + DeflaterEstimatorHjg.MF_LIMIT - 1;
- static final int HASH_LOG_64K = DeflaterEstimatorHjg.HASH_LOG + 1;
- static final int HASH_TABLE_SIZE_64K = 1 << DeflaterEstimatorHjg.HASH_LOG_64K;
-
- static final int HASH_LOG_HC = 15;
- static final int HASH_TABLE_SIZE_HC = 1 << DeflaterEstimatorHjg.HASH_LOG_HC;
- static final int OPTIMAL_ML = DeflaterEstimatorHjg.ML_MASK - 1 + DeflaterEstimatorHjg.MIN_MATCH;
-
- static int compress64k(final byte[] src, final int srcOff, final int srcLen) {
- final int srcEnd = srcOff + srcLen;
- final int srcLimit = srcEnd - DeflaterEstimatorHjg.LAST_LITERALS;
- final int mflimit = srcEnd - DeflaterEstimatorHjg.MF_LIMIT;
-
- int sOff = srcOff, dOff = 0;
-
- int anchor = sOff;
-
- if (srcLen >= DeflaterEstimatorHjg.MIN_LENGTH) {
-
- final short[] hashTable = new short[DeflaterEstimatorHjg.HASH_TABLE_SIZE_64K];
-
- ++sOff;
-
- main: while (true) {
-
- // find a match
- int forwardOff = sOff;
-
- int ref;
- int findMatchAttempts1 = (1 << DeflaterEstimatorHjg.SKIP_STRENGTH) + 3; // 64+3=67
- do {
- sOff = forwardOff;
- forwardOff += findMatchAttempts1++ >>> DeflaterEstimatorHjg.SKIP_STRENGTH;
-
- if (forwardOff > mflimit)
- break main; // ends all
-
- final int h = DeflaterEstimatorHjg.hash64k(DeflaterEstimatorHjg.readInt(src, sOff));
- ref = srcOff + DeflaterEstimatorHjg.readShort(hashTable, h);
- DeflaterEstimatorHjg.writeShort(hashTable, h, sOff - srcOff);
- } while (!DeflaterEstimatorHjg.readIntEquals(src, ref, sOff));
-
- // catch up
- final int excess = DeflaterEstimatorHjg.commonBytesBackward(src, ref, sOff, srcOff, anchor);
- sOff -= excess;
- ref -= excess;
- // sequence == refsequence
- final int runLen = sOff - anchor;
- dOff++;
-
- if (runLen >= DeflaterEstimatorHjg.RUN_MASK) {
- if (runLen > DeflaterEstimatorHjg.RUN_MASK)
- dOff += (runLen - DeflaterEstimatorHjg.RUN_MASK) / 0xFF;
- dOff++;
- }
- dOff += runLen;
- while (true) {
- // encode offset
- dOff += 2;
- // count nb matches
- sOff += DeflaterEstimatorHjg.MIN_MATCH;
- ref += DeflaterEstimatorHjg.MIN_MATCH;
- final int matchLen = DeflaterEstimatorHjg.commonBytes(src, ref, sOff, srcLimit);
- sOff += matchLen;
- // encode match len
- if (matchLen >= DeflaterEstimatorHjg.ML_MASK) {
- if (matchLen >= DeflaterEstimatorHjg.ML_MASK + 0xFF)
- dOff += (matchLen - DeflaterEstimatorHjg.ML_MASK) / 0xFF;
- dOff++;
- }
- // test end of chunk
- if (sOff > mflimit) {
- anchor = sOff;
- break main;
- }
- // fill table
- DeflaterEstimatorHjg.writeShort(hashTable, DeflaterEstimatorHjg.hash64k(DeflaterEstimatorHjg.readInt(src, sOff - 2)), sOff - 2 - srcOff);
- // test next position
- final int h = DeflaterEstimatorHjg.hash64k(DeflaterEstimatorHjg.readInt(src, sOff));
- ref = srcOff + DeflaterEstimatorHjg.readShort(hashTable, h);
- DeflaterEstimatorHjg.writeShort(hashTable, h, sOff - srcOff);
- if (!DeflaterEstimatorHjg.readIntEquals(src, sOff, ref))
- break;
- dOff++;
- }
- // prepare next loop
- anchor = sOff++;
- }
- }
- final int runLen = srcEnd - anchor;
- if (runLen >= DeflaterEstimatorHjg.RUN_MASK + 0xFF)
- dOff += (runLen - DeflaterEstimatorHjg.RUN_MASK) / 0xFF;
- dOff++;
- dOff += runLen;
- return dOff;
- }
-
- static int maxCompressedLength(final int length) {
- if (length < 0)
- throw new IllegalArgumentException("length must be >= 0, got " + length);
- return length + length / 255 + 16;
- }
-
- static int hash(final int i) {
- return i * -1640531535 >>> DeflaterEstimatorHjg.MIN_MATCH * 8 - DeflaterEstimatorHjg.HASH_LOG;
- }
-
- static int hash64k(final int i) {
- return i * -1640531535 >>> DeflaterEstimatorHjg.MIN_MATCH * 8 - DeflaterEstimatorHjg.HASH_LOG_64K;
- }
-
- static int readShortLittleEndian(final byte[] buf, final int i) {
- return buf[i] & 0xFF | (buf[i + 1] & 0xFF) << 8;
- }
-
- static boolean readIntEquals(final byte[] buf, final int i, final int j) {
- return buf[i] == buf[j] && buf[i + 1] == buf[j + 1] && buf[i + 2] == buf[j + 2] && buf[i + 3] == buf[j + 3];
- }
-
- static int commonBytes(final byte[] b, int o1, int o2, final int limit) {
- int count = 0;
- while (o2 < limit && b[o1++] == b[o2++])
- ++count;
- return count;
- }
-
- static int commonBytesBackward(final byte[] b, int o1, int o2, final int l1, final int l2) {
- int count = 0;
- while (o1 > l1 && o2 > l2 && b[--o1] == b[--o2])
- ++count;
- return count;
- }
-
- static int readShort(final short[] buf, final int off) {
- return buf[off] & 0xFFFF;
- }
-
- static byte readByte(final byte[] buf, final int i) {
- return buf[i];
- }
-
- static void checkRange(final byte[] buf, final int off) {
- if (off < 0 || off >= buf.length)
- throw new ArrayIndexOutOfBoundsException(off);
- }
-
- static void checkRange(final byte[] buf, final int off, final int len) {
- DeflaterEstimatorHjg.checkLength(len);
- if (len > 0) {
- DeflaterEstimatorHjg.checkRange(buf, off);
- DeflaterEstimatorHjg.checkRange(buf, off + len - 1);
- }
- }
-
- static void checkLength(final int len) {
- if (len < 0)
- throw new IllegalArgumentException("lengths must be >= 0");
- }
-
- static int readIntBE(final byte[] buf, final int i) {
- return (buf[i] & 0xFF) << 24 | (buf[i + 1] & 0xFF) << 16 | (buf[i + 2] & 0xFF) << 8 | buf[i + 3] & 0xFF;
- }
-
- static int readIntLE(final byte[] buf, final int i) {
- return buf[i] & 0xFF | (buf[i + 1] & 0xFF) << 8 | (buf[i + 2] & 0xFF) << 16 | (buf[i + 3] & 0xFF) << 24;
- }
-
- static int readInt(final byte[] buf, final int i) {
- return DeflaterEstimatorHjg.readIntBE(buf, i);
- }
-
- static void writeShort(final short[] buf, final int off, final int v) {
- buf[off] = (short) v;
- }
-
-}
diff --git a/teavm/src/main/java/ar/com/hjg/pngj/pixels/DeflaterEstimatorLz4.java b/teavm/src/main/java/ar/com/hjg/pngj/pixels/DeflaterEstimatorLz4.java
deleted file mode 100644
index 74d544c6..00000000
--- a/teavm/src/main/java/ar/com/hjg/pngj/pixels/DeflaterEstimatorLz4.java
+++ /dev/null
@@ -1,265 +0,0 @@
-package ar.com.hjg.pngj.pixels;
-
-import java.nio.ByteOrder;
-
-/**
- * This estimator actually uses the LZ4 compression algorithm, and hopes that
- * it's well correlated with Deflater. It's
- * about 3 to 4 times faster than Deflater.
- *
- * This is a modified heavily trimmed version of the
- * net.jpountz.lz4.LZ4JavaSafeCompressor class plus some methods from
- * other classes from LZ4 Java library: https://github.com/jpountz/lz4-java ,
- * originally licensed under the Apache
- * License 2.0
- */
-final public class DeflaterEstimatorLz4 {
-
- /**
- * This object is stateless, it's thread safe and can be reused
- */
- public DeflaterEstimatorLz4() {}
-
- /**
- * Estimates the length of the compressed bytes, as compressed by Lz4
- * WARNING: if larger than LZ4_64K_LIMIT it cuts it
- * in fragments
- *
- * WARNING: if some part of the input is discarded, this should return the
- * proportional (so that
- * returnValue/srcLen=compressionRatio)
- *
- * @param src
- * @param srcOff
- * @param srcLen
- * @return length of the compressed bytes
- */
- public int compressEstim(final byte[] src, int srcOff, final int srcLen) {
- if (srcLen < 10)
- return srcLen; // too small
- int stride = DeflaterEstimatorLz4.LZ4_64K_LIMIT - 1;
- final int segments = (srcLen + stride - 1) / stride;
- stride = srcLen / segments;
- if (stride >= DeflaterEstimatorLz4.LZ4_64K_LIMIT - 1 || stride * segments > srcLen || segments < 1 || stride < 1)
- throw new RuntimeException("?? " + srcLen);
- int bytesIn = 0;
- int bytesOut = 0;
- int len = srcLen;
- while (len > 0) {
- if (len > stride)
- len = stride;
- bytesOut += DeflaterEstimatorLz4.compress64k(src, srcOff, len);
- srcOff += len;
- bytesIn += len;
- len = srcLen - bytesIn;
- }
- final double ratio = bytesOut / (double) bytesIn;
- return bytesIn == srcLen ? bytesOut : (int) (ratio * srcLen + 0.5);
- }
-
- public int compressEstim(final byte[] src) {
- return compressEstim(src, 0, src.length);
- }
-
- static final ByteOrder NATIVE_BYTE_ORDER = ByteOrder.nativeOrder();
-
- static final int MEMORY_USAGE = 14;
- static final int NOT_COMPRESSIBLE_DETECTION_LEVEL = 6;
-
- static final int MIN_MATCH = 4;
-
- static final int HASH_LOG = DeflaterEstimatorLz4.MEMORY_USAGE - 2;
- static final int HASH_TABLE_SIZE = 1 << DeflaterEstimatorLz4.HASH_LOG;
-
- static final int SKIP_STRENGTH = Math.max(DeflaterEstimatorLz4.NOT_COMPRESSIBLE_DETECTION_LEVEL, 2);
- static final int COPY_LENGTH = 8;
- static final int LAST_LITERALS = 5;
- static final int MF_LIMIT = DeflaterEstimatorLz4.COPY_LENGTH + DeflaterEstimatorLz4.MIN_MATCH;
- static final int MIN_LENGTH = DeflaterEstimatorLz4.MF_LIMIT + 1;
-
- static final int MAX_DISTANCE = 1 << 16;
-
- static final int ML_BITS = 4;
- static final int ML_MASK = (1 << DeflaterEstimatorLz4.ML_BITS) - 1;
- static final int RUN_BITS = 8 - DeflaterEstimatorLz4.ML_BITS;
- static final int RUN_MASK = (1 << DeflaterEstimatorLz4.RUN_BITS) - 1;
-
- static final int LZ4_64K_LIMIT = (1 << 16) + DeflaterEstimatorLz4.MF_LIMIT - 1;
- static final int HASH_LOG_64K = DeflaterEstimatorLz4.HASH_LOG + 1;
- static final int HASH_TABLE_SIZE_64K = 1 << DeflaterEstimatorLz4.HASH_LOG_64K;
-
- static final int HASH_LOG_HC = 15;
- static final int HASH_TABLE_SIZE_HC = 1 << DeflaterEstimatorLz4.HASH_LOG_HC;
- static final int OPTIMAL_ML = DeflaterEstimatorLz4.ML_MASK - 1 + DeflaterEstimatorLz4.MIN_MATCH;
-
- static int compress64k(final byte[] src, final int srcOff, final int srcLen) {
- final int srcEnd = srcOff + srcLen;
- final int srcLimit = srcEnd - DeflaterEstimatorLz4.LAST_LITERALS;
- final int mflimit = srcEnd - DeflaterEstimatorLz4.MF_LIMIT;
-
- int sOff = srcOff, dOff = 0;
-
- int anchor = sOff;
-
- if (srcLen >= DeflaterEstimatorLz4.MIN_LENGTH) {
-
- final short[] hashTable = new short[DeflaterEstimatorLz4.HASH_TABLE_SIZE_64K];
-
- ++sOff;
-
- main: while (true) {
-
- // find a match
- int forwardOff = sOff;
-
- int ref;
- int findMatchAttempts = (1 << DeflaterEstimatorLz4.SKIP_STRENGTH) + 3;
- do {
- sOff = forwardOff;
- forwardOff += findMatchAttempts++ >>> DeflaterEstimatorLz4.SKIP_STRENGTH;
-
- if (forwardOff > mflimit)
- break main;
-
- final int h = DeflaterEstimatorLz4.hash64k(DeflaterEstimatorLz4.readInt(src, sOff));
- ref = srcOff + DeflaterEstimatorLz4.readShort(hashTable, h);
- DeflaterEstimatorLz4.writeShort(hashTable, h, sOff - srcOff);
- } while (!DeflaterEstimatorLz4.readIntEquals(src, ref, sOff));
-
- // catch up
- final int excess = DeflaterEstimatorLz4.commonBytesBackward(src, ref, sOff, srcOff, anchor);
- sOff -= excess;
- ref -= excess;
- // sequence == refsequence
- final int runLen = sOff - anchor;
- dOff++;
-
- if (runLen >= DeflaterEstimatorLz4.RUN_MASK) {
- if (runLen > DeflaterEstimatorLz4.RUN_MASK)
- dOff += (runLen - DeflaterEstimatorLz4.RUN_MASK) / 0xFF;
- dOff++;
- }
- dOff += runLen;
- while (true) {
- // encode offset
- dOff += 2;
- // count nb matches
- sOff += DeflaterEstimatorLz4.MIN_MATCH;
- ref += DeflaterEstimatorLz4.MIN_MATCH;
- final int matchLen = DeflaterEstimatorLz4.commonBytes(src, ref, sOff, srcLimit);
- sOff += matchLen;
- // encode match len
- if (matchLen >= DeflaterEstimatorLz4.ML_MASK) {
- if (matchLen >= DeflaterEstimatorLz4.ML_MASK + 0xFF)
- dOff += (matchLen - DeflaterEstimatorLz4.ML_MASK) / 0xFF;
- dOff++;
- }
- // test end of chunk
- if (sOff > mflimit) {
- anchor = sOff;
- break main;
- }
- // fill table
- DeflaterEstimatorLz4.writeShort(hashTable, DeflaterEstimatorLz4.hash64k(DeflaterEstimatorLz4.readInt(src, sOff - 2)), sOff - 2 - srcOff);
- // test next position
- final int h = DeflaterEstimatorLz4.hash64k(DeflaterEstimatorLz4.readInt(src, sOff));
- ref = srcOff + DeflaterEstimatorLz4.readShort(hashTable, h);
- DeflaterEstimatorLz4.writeShort(hashTable, h, sOff - srcOff);
- if (!DeflaterEstimatorLz4.readIntEquals(src, sOff, ref))
- break;
- dOff++;
- }
- // prepare next loop
- anchor = sOff++;
- }
- }
- final int runLen = srcEnd - anchor;
- if (runLen >= DeflaterEstimatorLz4.RUN_MASK + 0xFF)
- dOff += (runLen - DeflaterEstimatorLz4.RUN_MASK) / 0xFF;
- dOff++;
- dOff += runLen;
- return dOff;
- }
-
- static int maxCompressedLength(final int length) {
- if (length < 0)
- throw new IllegalArgumentException("length must be >= 0, got " + length);
- return length + length / 255 + 16;
- }
-
- static int hash(final int i) {
- return i * -1640531535 >>> DeflaterEstimatorLz4.MIN_MATCH * 8 - DeflaterEstimatorLz4.HASH_LOG;
- }
-
- static int hash64k(final int i) {
- return i * -1640531535 >>> DeflaterEstimatorLz4.MIN_MATCH * 8 - DeflaterEstimatorLz4.HASH_LOG_64K;
- }
-
- static int readShortLittleEndian(final byte[] buf, final int i) {
- return buf[i] & 0xFF | (buf[i + 1] & 0xFF) << 8;
- }
-
- static boolean readIntEquals(final byte[] buf, final int i, final int j) {
- return buf[i] == buf[j] && buf[i + 1] == buf[j + 1] && buf[i + 2] == buf[j + 2] && buf[i + 3] == buf[j + 3];
- }
-
- static int commonBytes(final byte[] b, int o1, int o2, final int limit) {
- int count = 0;
- while (o2 < limit && b[o1++] == b[o2++])
- ++count;
- return count;
- }
-
- static int commonBytesBackward(final byte[] b, int o1, int o2, final int l1, final int l2) {
- int count = 0;
- while (o1 > l1 && o2 > l2 && b[--o1] == b[--o2])
- ++count;
- return count;
- }
-
- static int readShort(final short[] buf, final int off) {
- return buf[off] & 0xFFFF;
- }
-
- static byte readByte(final byte[] buf, final int i) {
- return buf[i];
- }
-
- static void checkRange(final byte[] buf, final int off) {
- if (off < 0 || off >= buf.length)
- throw new ArrayIndexOutOfBoundsException(off);
- }
-
- static void checkRange(final byte[] buf, final int off, final int len) {
- DeflaterEstimatorLz4.checkLength(len);
- if (len > 0) {
- DeflaterEstimatorLz4.checkRange(buf, off);
- DeflaterEstimatorLz4.checkRange(buf, off + len - 1);
- }
- }
-
- static void checkLength(final int len) {
- if (len < 0)
- throw new IllegalArgumentException("lengths must be >= 0");
- }
-
- static int readIntBE(final byte[] buf, final int i) {
- return (buf[i] & 0xFF) << 24 | (buf[i + 1] & 0xFF) << 16 | (buf[i + 2] & 0xFF) << 8 | buf[i + 3] & 0xFF;
- }
-
- static int readIntLE(final byte[] buf, final int i) {
- return buf[i] & 0xFF | (buf[i + 1] & 0xFF) << 8 | (buf[i + 2] & 0xFF) << 16 | (buf[i + 3] & 0xFF) << 24;
- }
-
- static int readInt(final byte[] buf, final int i) {
- if (DeflaterEstimatorLz4.NATIVE_BYTE_ORDER == ByteOrder.BIG_ENDIAN)
- return DeflaterEstimatorLz4.readIntBE(buf, i);
- else
- return DeflaterEstimatorLz4.readIntLE(buf, i);
- }
-
- static void writeShort(final short[] buf, final int off, final int v) {
- buf[off] = (short) v;
- }
-
-}
diff --git a/teavm/src/main/java/ar/com/hjg/pngj/pixels/FiltersPerformance.java b/teavm/src/main/java/ar/com/hjg/pngj/pixels/FiltersPerformance.java
deleted file mode 100644
index bf35aa42..00000000
--- a/teavm/src/main/java/ar/com/hjg/pngj/pixels/FiltersPerformance.java
+++ /dev/null
@@ -1,208 +0,0 @@
-package ar.com.hjg.pngj.pixels;
-
-import java.util.Arrays;
-
-import ar.com.hjg.pngj.FilterType;
-import ar.com.hjg.pngj.ImageInfo;
-import ar.com.hjg.pngj.PngHelperInternal;
-import ar.com.hjg.pngj.PngjExceptionInternal;
-
-/** for use in adaptative strategy */
-public class FiltersPerformance {
-
- private final ImageInfo iminfo;
- private double memoryA = 0.7; // empirical (not very critical: 0.72)
- private int lastrow = -1;
- private final double[] absum = new double[5];// depending on the strategy not all values might be
- // computed for all
- private final double[] entropy = new double[5];
- private final double[] cost = new double[5];
- private final int[] histog = new int[256]; // temporary, not normalized
- private int lastprefered = -1;
- private boolean initdone = false;
- private double preferenceForNone = 1.0; // higher gives more preference to NONE
-
- // this values are empirical (montecarlo), for RGB8 images with entropy estimator for NONE and
- // memory=0.7
- // DONT MODIFY THIS
- public static final double[] FILTER_WEIGHTS_DEFAULT = { 0.73, 1.03, 0.97, 1.11, 1.22 }; // lower is
- // better!
-
- private final double[] filter_weights = new double[] { -1, -1, -1, -1, -1 };
-
- private final static double LOG2NI = -1.0 / Math.log(2.0);
-
- public FiltersPerformance(final ImageInfo imgInfo) {
- iminfo = imgInfo;
- }
-
- private void init() {
- if (filter_weights[0] < 0) {// has not been set from outside
- System.arraycopy(FiltersPerformance.FILTER_WEIGHTS_DEFAULT, 0, filter_weights, 0, 5);
- double wNone = filter_weights[0];
- if (iminfo.bitDepth == 16)
- wNone = 1.2;
- else if (iminfo.alpha)
- wNone = 0.8;
- else if (iminfo.indexed || iminfo.bitDepth < 8)
- wNone = 0.4; // we prefer NONE strongly
- wNone /= preferenceForNone;
- filter_weights[0] = wNone;
- }
- Arrays.fill(cost, 1.0);
- initdone = true;
- }
-
- public void updateFromFiltered(final FilterType ftype, final byte[] rowff, final int rown) {
- updateFromRawOrFiltered(ftype, rowff, null, null, rown);
- }
-
- /** alternative: computes statistic without filtering */
- public void updateFromRaw(final FilterType ftype, final byte[] rowb, final byte[] rowbprev, final int rown) {
- updateFromRawOrFiltered(ftype, null, rowb, rowbprev, rown);
- }
-
- private void updateFromRawOrFiltered(final FilterType ftype, final byte[] rowff, final byte[] rowb,
- final byte[] rowbprev, final int rown) {
- if (!initdone)
- init();
- if (rown != lastrow) {
- Arrays.fill(absum, Double.NaN);
- Arrays.fill(entropy, Double.NaN);
- }
- lastrow = rown;
- if (rowff != null)
- computeHistogram(rowff);
- else
- computeHistogramForFilter(ftype, rowb, rowbprev);
- if (ftype == FilterType.FILTER_NONE)
- entropy[ftype.val] = computeEntropyFromHistogram();
- else
- absum[ftype.val] = computeAbsFromHistogram();
- }
-
- /* WARNING: this is not idempotent, call it just once per cycle (sigh) */
- public FilterType getPreferred() {
- int fi = 0;
- double vali = Double.MAX_VALUE, val = 0; // lower wins
- for (int i = 0; i < 5; i++) {
- if (!Double.isNaN(absum[i]))
- val = absum[i];
- else if (!Double.isNaN(entropy[i]))
- val = (Math.pow(2.0, entropy[i]) - 1.0) * 0.5;
- else
- continue;
- val *= filter_weights[i];
- val = cost[i] * memoryA + (1 - memoryA) * val;
- cost[i] = val;
- if (val < vali) {
- vali = val;
- fi = i;
- }
- }
- lastprefered = fi;
- return FilterType.getByVal(lastprefered);
- }
-
- public final void computeHistogramForFilter(final FilterType filterType, final byte[] rowb, final byte[] rowbprev) {
- Arrays.fill(histog, 0);
- int i, j;
- final int imax = iminfo.bytesPerRow;
- switch (filterType) {
- case FILTER_NONE:
- for (i = 1; i <= imax; i++)
- histog[rowb[i] & 0xFF]++;
- break;
- case FILTER_PAETH:
- for (i = 1; i <= imax; i++)
- histog[PngHelperInternal.filterRowPaeth(rowb[i], 0, rowbprev[i] & 0xFF, 0)]++;
- for (j = 1, i = iminfo.bytesPixel + 1; i <= imax; i++, j++)
- histog[PngHelperInternal.filterRowPaeth(rowb[i], rowb[j] & 0xFF, rowbprev[i] & 0xFF, rowbprev[j] & 0xFF)]++;
- break;
- case FILTER_SUB:
- for (i = 1; i <= iminfo.bytesPixel; i++)
- histog[rowb[i] & 0xFF]++;
- for (j = 1, i = iminfo.bytesPixel + 1; i <= imax; i++, j++)
- histog[rowb[i] - rowb[j] & 0xFF]++;
- break;
- case FILTER_UP:
- for (i = 1; i <= iminfo.bytesPerRow; i++)
- histog[rowb[i] - rowbprev[i] & 0xFF]++;
- break;
- case FILTER_AVERAGE:
- for (i = 1; i <= iminfo.bytesPixel; i++)
- histog[(rowb[i] & 0xFF) - (rowbprev[i] & 0xFF) / 2 & 0xFF]++;
- for (j = 1, i = iminfo.bytesPixel + 1; i <= imax; i++, j++)
- histog[(rowb[i] & 0xFF) - ((rowbprev[i] & 0xFF) + (rowb[j] & 0xFF)) / 2 & 0xFF]++;
- break;
- default:
- throw new PngjExceptionInternal("Bad filter:" + filterType);
- }
- }
-
- public void computeHistogram(final byte[] rowff) {
- Arrays.fill(histog, 0);
- for (int i = 1; i < iminfo.bytesPerRow; i++)
- histog[rowff[i] & 0xFF]++;
- }
-
- public double computeAbsFromHistogram() {
- int s = 0;
- for (int i = 1; i < 128; i++)
- s += histog[i] * i;
- for (int i = 128, j = 128; j > 0; i++, j--)
- s += histog[i] * j;
- return s / (double) iminfo.bytesPerRow;
- }
-
- public final double computeEntropyFromHistogram() {
- final double s = 1.0 / iminfo.bytesPerRow;
- final double ls = Math.log(s);
-
- double h = 0;
- for (final int x : histog)
- if (x > 0)
- h += (Math.log(x) + ls) * x;
- h *= s * FiltersPerformance.LOG2NI;
- if (h < 0.0)
- h = 0.0;
- return h;
- }
-
- /**
- * If larger than 1.0, NONE will be more prefered. This must be called
- * before init
- *
- * @param preferenceForNone
- * around 1.0 (default: 1.0)
- */
- public void setPreferenceForNone(final double preferenceForNone) {
- this.preferenceForNone = preferenceForNone;
- }
-
- /**
- * Values greater than 1.0 (towards infinite) increase the memory towards 1.
- * Values smaller than 1.0 (towards zero)
- * decreases the memory .
- *
- */
- public void tuneMemory(final double m) {
- if (m == 0)
- memoryA = 0.0;
- else
- memoryA = Math.pow(memoryA, 1.0 / m);
- }
-
- /**
- * To set manually the filter weights. This is not recommended, unless you
- * know what you are doing. Setting this
- * ignores preferenceForNone and omits some heuristics
- *
- * @param weights
- * Five doubles around 1.0, one for each filter type. Lower is
- * preferered
- */
- public void setFilterWeights(final double[] weights) {
- System.arraycopy(weights, 0, filter_weights, 0, 5);
- }
-}
diff --git a/teavm/src/main/java/ar/com/hjg/pngj/pixels/PixelsWriter.java b/teavm/src/main/java/ar/com/hjg/pngj/pixels/PixelsWriter.java
deleted file mode 100644
index 9ab95115..00000000
--- a/teavm/src/main/java/ar/com/hjg/pngj/pixels/PixelsWriter.java
+++ /dev/null
@@ -1,272 +0,0 @@
-package ar.com.hjg.pngj.pixels;
-
-import java.io.OutputStream;
-import java.util.zip.Deflater;
-
-import ar.com.hjg.pngj.FilterType;
-import ar.com.hjg.pngj.IDatChunkWriter;
-import ar.com.hjg.pngj.ImageInfo;
-import ar.com.hjg.pngj.PngHelperInternal;
-import ar.com.hjg.pngj.PngjOutputException;
-
-/**
- * Encodes a set of rows (pixels) as a continuous deflated stream (does not know
- * about IDAT chunk segmentation).
- *
- * This includes the filter selection strategy, plus the filtering itself and
- * the deflating. Only supports fixed length
- * rows (no interlaced writing).
- *
- * Typically an instance of this is hold by a PngWriter - but more instances
- * could be used (for APGN)
- */
-public abstract class PixelsWriter {
-
- private static final int IDAT_MAX_SIZE_DEFAULT = 32000;
-
- protected final ImageInfo imgInfo;
- /**
- * row buffer length, including filter byte (imgInfo.bytesPerRow + 1)
- */
- protected final int buflen;
-
- protected final int bytesPixel;
- protected final int bytesRow;
-
- private CompressorStream compressorStream; // to compress the idat stream
-
- protected int deflaterCompLevel = 6;
- protected int deflaterStrategy = Deflater.DEFAULT_STRATEGY;
-
- protected boolean initdone = false;
-
- /**
- * This is the globally configured filter type - it can be a concrete type
- * or a pseudo type (hint or strategy)
- */
- protected FilterType filterType;
-
- // counts the filters used - just for stats
- private final int[] filtersUsed = new int[5];
-
- // this is the raw underlying os (shared with the PngWriter)
- private OutputStream os;
-
- private int idatMaxSize = PixelsWriter.IDAT_MAX_SIZE_DEFAULT;
-
- /**
- * row being processed, couting from zero
- */
- protected int currentRow;
-
- public PixelsWriter(final ImageInfo imgInfo) {
- this.imgInfo = imgInfo;
- bytesRow = imgInfo.bytesPerRow;
- buflen = bytesRow + 1;
- bytesPixel = imgInfo.bytesPixel;
- currentRow = -1;
- filterType = FilterType.FILTER_DEFAULT;
- }
-
- /**
- * main internal point for external call. It does the lazy initializion if
- * necessary, sets current row, and call
- * {@link #filterAndWrite(byte[])}
- */
- public final void processRow(final byte[] rowb) {
- if (!initdone)
- init();
- currentRow++;
- filterAndWrite(rowb);
- }
-
- protected void sendToCompressedStream(final byte[] rowf) {
- compressorStream.write(rowf, 0, rowf.length);
- filtersUsed[rowf[0]]++;
- }
-
- /**
- * This does the filtering and send to stream. Typically should decide the
- * filtering, call
- * {@link #filterRowWithFilterType(FilterType, byte[], byte[], byte[])} and
- * and
- * {@link #sendToCompressedStream(byte[])}
- *
- * @param rowb
- */
- protected abstract void filterAndWrite(final byte[] rowb);
-
- /**
- * Does the real filtering. This must be called with the real (standard)
- * filterType. This should rarely be overriden.
- *
- * WARNING: look out the contract
- *
- * @param _filterType
- * @param _rowb
- * current row (the first byte might be modified)
- * @param _rowbprev
- * previous row (should be all zero the first time)
- * @param _rowf
- * tentative buffer to store the filtered bytes. might not be
- * used!
- * @return normally _rowf, but eventually _rowb. This MUST NOT BE MODIFIED
- * nor reused by caller
- */
- final protected byte[] filterRowWithFilterType(final FilterType _filterType, final byte[] _rowb,
- final byte[] _rowbprev, byte[] _rowf) {
- // warning: some filters rely on: "previous row" (rowbprev) it must be initialized to 0 the
- // first time
- if (_filterType == FilterType.FILTER_NONE)
- _rowf = _rowb;
- _rowf[0] = (byte) _filterType.val;
- int i, j;
- switch (_filterType) {
- case FILTER_NONE:
- // we return the same original (be careful!)
- break;
- case FILTER_PAETH:
- for (i = 1; i <= bytesPixel; i++)
- _rowf[i] = (byte) PngHelperInternal.filterRowPaeth(_rowb[i], 0, _rowbprev[i] & 0xFF, 0);
- for (j = 1, i = bytesPixel + 1; i <= bytesRow; i++, j++)
- _rowf[i] = (byte) PngHelperInternal.filterRowPaeth(_rowb[i], _rowb[j] & 0xFF, _rowbprev[i] & 0xFF, _rowbprev[j] & 0xFF);
- break;
- case FILTER_SUB:
- for (i = 1; i <= bytesPixel; i++)
- _rowf[i] = _rowb[i];
- for (j = 1, i = bytesPixel + 1; i <= bytesRow; i++, j++)
- _rowf[i] = (byte) (_rowb[i] - _rowb[j]);
- break;
- case FILTER_AVERAGE:
- for (i = 1; i <= bytesPixel; i++)
- _rowf[i] = (byte) (_rowb[i] - (_rowbprev[i] & 0xFF) / 2);
- for (j = 1, i = bytesPixel + 1; i <= bytesRow; i++, j++)
- _rowf[i] = (byte) (_rowb[i] - ((_rowbprev[i] & 0xFF) + (_rowb[j] & 0xFF)) / 2);
- break;
- case FILTER_UP:
- for (i = 1; i <= bytesRow; i++)
- _rowf[i] = (byte) (_rowb[i] - _rowbprev[i]);
- break;
- default:
- throw new PngjOutputException("Filter type not recognized: " + _filterType);
- }
- return _rowf;
- }
-
- /**
- * This will be called by the PngWrite to fill the raw pixels for each row.
- * This can change from call to call.
- * Warning: this can be called before the object is init, implementations
- * should call init() to be sure
- */
- public abstract byte[] getRowb();
-
- /**
- * This will be called lazily just before writing row 0. Idempotent.
- */
- protected final void init() {
- if (!initdone) {
- initParams();
- initdone = true;
- }
- }
-
- /**
- * called by init(); override (calling this first) to do additional
- * initialization
- */
- protected void initParams() {
- final IDatChunkWriter idatWriter = new IDatChunkWriter(os, idatMaxSize);
- if (compressorStream == null)
- compressorStream = new CompressorStreamDeflater(idatWriter, buflen, imgInfo.getTotalRawBytes(), deflaterCompLevel, deflaterStrategy);
- }
-
- /** cleanup. This should be called explicitly. Idempotent and secure */
- public void close() {
- if (compressorStream != null)
- compressorStream.close();
- }
-
- /**
- * Deflater (ZLIB) strategy. You should rarely change this from the default
- * (Deflater.DEFAULT_STRATEGY) to
- * Deflater.FILTERED (Deflater.HUFFMAN_ONLY is fast but compress poorly)
- */
- public void setDeflaterStrategy(final Integer deflaterStrategy) {
- this.deflaterStrategy = deflaterStrategy;
- }
-
- /**
- * Deflater (ZLIB) compression level, between 0 (no compression) and 9
- */
- public void setDeflaterCompLevel(final Integer deflaterCompLevel) {
- this.deflaterCompLevel = deflaterCompLevel;
- }
-
- public Integer getDeflaterCompLevel() {
- return deflaterCompLevel;
- }
-
- public final void setOs(final OutputStream datStream) {
- os = datStream;
- }
-
- public OutputStream getOs() {
- return os;
- }
-
- /** @see #filterType */
- final public FilterType getFilterType() {
- return filterType;
- }
-
- /** @see #filterType */
- final public void setFilterType(final FilterType filterType) {
- this.filterType = filterType;
- }
-
- /* out/in This should be called only after end() to get reliable results */
- public double getCompression() {
- return compressorStream.isDone() ? compressorStream.getCompressionRatio() : 1.0;
- }
-
- public void setCompressorStream(final CompressorStream compressorStream) {
- this.compressorStream = compressorStream;
- }
-
- public long getTotalBytesToWrite() {
- return imgInfo.getTotalRawBytes();
- }
-
- public boolean isDone() {
- return currentRow == imgInfo.rows - 1;
- }
-
- /**
- * computed default fixed filter type to use, if specified DEFAULT; wilde
- * guess based on image properties
- *
- * @return One of the five concrete filter types
- */
- protected FilterType getDefaultFilter() {
- if (imgInfo.indexed || imgInfo.bitDepth < 8)
- return FilterType.FILTER_NONE;
- else if (imgInfo.getTotalPixels() < 1024)
- return FilterType.FILTER_NONE;
- else if (imgInfo.rows == 1)
- return FilterType.FILTER_SUB;
- else if (imgInfo.cols == 1)
- return FilterType.FILTER_UP;
- else
- return FilterType.FILTER_PAETH;
- }
-
- /** informational stats : filter used, in percentages */
- final public String getFiltersUsed() {
- return String.format("%d,%d,%d,%d,%d", (int) (filtersUsed[0] * 100.0 / imgInfo.rows + 0.5), (int) (filtersUsed[1] * 100.0 / imgInfo.rows + 0.5), (int) (filtersUsed[2] * 100.0 / imgInfo.rows + 0.5), (int) (filtersUsed[3] * 100.0 / imgInfo.rows + 0.5), (int) (filtersUsed[4] * 100.0 / imgInfo.rows + 0.5));
- }
-
- public void setIdatMaxSize(final int idatMaxSize) {
- this.idatMaxSize = idatMaxSize;
- }
-}
diff --git a/teavm/src/main/java/ar/com/hjg/pngj/pixels/PixelsWriterDefault.java b/teavm/src/main/java/ar/com/hjg/pngj/pixels/PixelsWriterDefault.java
deleted file mode 100644
index 00ffcec9..00000000
--- a/teavm/src/main/java/ar/com/hjg/pngj/pixels/PixelsWriterDefault.java
+++ /dev/null
@@ -1,158 +0,0 @@
-package ar.com.hjg.pngj.pixels;
-
-import java.util.Arrays;
-
-import ar.com.hjg.pngj.FilterType;
-import ar.com.hjg.pngj.ImageInfo;
-import ar.com.hjg.pngj.PngjOutputException;
-
-/**
- * Default implementation of PixelsWriter, with fixed filters and also adaptive
- * strategies.
- */
-public class PixelsWriterDefault extends PixelsWriter {
- /** current raw row */
- protected byte[] rowb;
- /** previous raw row */
- protected byte[] rowbprev;
- /** buffer for filtered row */
- protected byte[] rowbfilter;
-
- /** evaluates different filters, for adaptive strategy */
- protected FiltersPerformance filtersPerformance;
-
- /** currently concrete selected filter type */
- protected FilterType curfilterType;
-
- /** parameters for adaptive strategy */
- protected int adaptMaxSkip; // set in initParams, does not change
- protected int adaptSkipIncreaseSinceRow; // set in initParams, does not change
- protected double adaptSkipIncreaseFactor; // set in initParams, does not change
- protected int adaptNextRow = 0;
-
- public PixelsWriterDefault(final ImageInfo imgInfo) {
- super(imgInfo);
- filtersPerformance = new FiltersPerformance(imgInfo);
- }
-
- @Override
- protected void initParams() {
- super.initParams();
-
- if (rowb == null || rowb.length < buflen)
- rowb = new byte[buflen];
- if (rowbfilter == null || rowbfilter.length < buflen)
- rowbfilter = new byte[buflen];
- if (rowbprev == null || rowbprev.length < buflen)
- rowbprev = new byte[buflen];
- else
- Arrays.fill(rowbprev, (byte) 0);
-
- // if adaptative but too few rows or columns, use default
- if (imgInfo.cols < 3 && !FilterType.isValidStandard(filterType))
- filterType = FilterType.FILTER_DEFAULT;
- if (imgInfo.rows < 3 && !FilterType.isValidStandard(filterType))
- filterType = FilterType.FILTER_DEFAULT;
-
- if (imgInfo.getTotalPixels() <= 1024 && !FilterType.isValidStandard(filterType))
- filterType = getDefaultFilter();
-
- if (FilterType.isAdaptive(filterType)) {
- // adaptCurSkip = 0;
- adaptNextRow = 0;
- if (filterType == FilterType.FILTER_ADAPTIVE_FAST) {
- adaptMaxSkip = 200;
- adaptSkipIncreaseSinceRow = 3;
- adaptSkipIncreaseFactor = 1 / 4.0; // skip ~ row/3
- } else if (filterType == FilterType.FILTER_ADAPTIVE_MEDIUM) {
- adaptMaxSkip = 8;
- adaptSkipIncreaseSinceRow = 32;
- adaptSkipIncreaseFactor = 1 / 80.0;
- } else if (filterType == FilterType.FILTER_ADAPTIVE_FULL) {
- adaptMaxSkip = 0;
- adaptSkipIncreaseSinceRow = 128;
- adaptSkipIncreaseFactor = 1 / 120.0;
- } else
- throw new PngjOutputException("bad filter " + filterType);
- }
- }
-
- @Override
- protected void filterAndWrite(final byte[] rowb) {
- if (rowb != this.rowb)
- throw new RuntimeException("??"); // we rely on this
- decideCurFilterType();
- final byte[] filtered = filterRowWithFilterType(curfilterType, rowb, rowbprev, rowbfilter);
- sendToCompressedStream(filtered);
- // swap rowb <-> rowbprev
- final byte[] aux = this.rowb;
- this.rowb = rowbprev;
- rowbprev = aux;
- }
-
- protected void decideCurFilterType() {
- // decide the real filter and store in curfilterType
- if (FilterType.isValidStandard(getFilterType()))
- curfilterType = getFilterType();
- else if (getFilterType() == FilterType.FILTER_PRESERVE)
- curfilterType = FilterType.getByVal(rowb[0]);
- else if (getFilterType() == FilterType.FILTER_CYCLIC)
- curfilterType = FilterType.getByVal(currentRow % 5);
- else if (getFilterType() == FilterType.FILTER_DEFAULT) {
- setFilterType(getDefaultFilter());
- curfilterType = getFilterType(); // this could be done once
- } else if (FilterType.isAdaptive(getFilterType())) {// adaptive
- if (currentRow == adaptNextRow) {
- for (final FilterType ftype : FilterType.getAllStandard())
- filtersPerformance.updateFromRaw(ftype, rowb, rowbprev, currentRow);
- curfilterType = filtersPerformance.getPreferred();
- int skip = currentRow >= adaptSkipIncreaseSinceRow ? (int) Math.round((currentRow - adaptSkipIncreaseSinceRow) * adaptSkipIncreaseFactor) : 0;
- if (skip > adaptMaxSkip)
- skip = adaptMaxSkip;
- if (currentRow == 0)
- skip = 0;
- adaptNextRow = currentRow + 1 + skip;
- }
- } else
- throw new PngjOutputException("not implemented filter: " + getFilterType());
- if (currentRow == 0 && curfilterType != FilterType.FILTER_NONE && curfilterType != FilterType.FILTER_SUB)
- curfilterType = FilterType.FILTER_SUB; // first row should always be none or sub
- }
-
- @Override
- public byte[] getRowb() {
- if (!initdone)
- init();
- return rowb;
- }
-
- @Override
- public void close() {
- super.close();
- }
-
- /**
- * Only for adaptive strategies. See
- * {@link FiltersPerformance#setPreferenceForNone(double)}
- */
- public void setPreferenceForNone(final double preferenceForNone) {
- filtersPerformance.setPreferenceForNone(preferenceForNone);
- }
-
- /**
- * Only for adaptive strategies. See
- * {@link FiltersPerformance#tuneMemory(double)}
- */
- public void tuneMemory(final double m) {
- filtersPerformance.tuneMemory(m);
- }
-
- /**
- * Only for adaptive strategies. See
- * {@link FiltersPerformance#setFilterWeights(double[])}
- */
- public void setFilterWeights(final double[] weights) {
- filtersPerformance.setFilterWeights(weights);
- }
-
-}
diff --git a/teavm/src/main/java/ar/com/hjg/pngj/pixels/PixelsWriterMultiple.java b/teavm/src/main/java/ar/com/hjg/pngj/pixels/PixelsWriterMultiple.java
deleted file mode 100644
index bf36c12b..00000000
--- a/teavm/src/main/java/ar/com/hjg/pngj/pixels/PixelsWriterMultiple.java
+++ /dev/null
@@ -1,230 +0,0 @@
-package ar.com.hjg.pngj.pixels;
-
-import java.util.LinkedList;
-import java.util.zip.Deflater;
-
-import ar.com.hjg.pngj.FilterType;
-import ar.com.hjg.pngj.ImageInfo;
-
-/** Special pixels writer for experimental super adaptive strategy */
-public class PixelsWriterMultiple extends PixelsWriter {
- /**
- * unfiltered rowsperband elements, 0 is the current (rowb). This should
- * include all rows of current band, plus one
- */
- protected LinkedList rows;
-
- /**
- * bank of compressor estimators, one for each filter and (perhaps) an
- * adaptive strategy
- */
- protected CompressorStream[] filterBank = new CompressorStream[6];
- /**
- * stored filtered rows, one for each filter (0=none is not allocated but
- * linked)
- */
- protected byte[][] filteredRows = new byte[5][];
- protected byte[] filteredRowTmp; //
-
- protected FiltersPerformance filtersPerf;
- protected int rowsPerBand = 0; // This is a 'nominal' size
- protected int rowsPerBandCurrent = 0; // lastRowInThisBand-firstRowInThisBand +1 : might be
- // smaller than rowsPerBand
- protected int rowInBand = -1;
- protected int bandNum = -1;
- protected int firstRowInThisBand, lastRowInThisBand;
- private boolean tryAdaptive = true;
-
- protected static final int HINT_MEMORY_DEFAULT_KB = 100;
- // we will consume about (not more than) this memory (in buffers, not counting the compressors)
- protected int hintMemoryKb = PixelsWriterMultiple.HINT_MEMORY_DEFAULT_KB;
-
- private int hintRowsPerBand = 1000; // default: very large number, can be changed
-
- private boolean useLz4 = true;
-
- public PixelsWriterMultiple(final ImageInfo imgInfo) {
- super(imgInfo);
- filtersPerf = new FiltersPerformance(imgInfo);
- rows = new LinkedList<>();
- for (int i = 0; i < 2; i++)
- rows.add(new byte[buflen]); // we preallocate 2 rows (rowb and rowbprev)
- filteredRowTmp = new byte[buflen];
- }
-
- @Override
- protected void filterAndWrite(final byte[] rowb) {
- if (!initdone)
- init();
- if (rowb != rows.get(0))
- throw new RuntimeException("?");
- setBandFromNewRown();
- final byte[] rowbprev = rows.get(1);
- for (final FilterType ftype : FilterType.getAllStandardNoneLast()) {
- // this has a special behaviour for NONE: filteredRows[0] is null, and the returned value is
- // rowb
- if (currentRow == 0 && ftype != FilterType.FILTER_NONE && ftype != FilterType.FILTER_SUB)
- continue;
- final byte[] filtered = filterRowWithFilterType(ftype, rowb, rowbprev, filteredRows[ftype.val]);
- filterBank[ftype.val].write(filtered);
- if (currentRow == 0 && ftype == FilterType.FILTER_SUB) { // litle lie, only for first row
- filterBank[FilterType.FILTER_PAETH.val].write(filtered);
- filterBank[FilterType.FILTER_AVERAGE.val].write(filtered);
- filterBank[FilterType.FILTER_UP.val].write(filtered);
- }
- // adptive: report each filterted
- if (tryAdaptive)
- filtersPerf.updateFromFiltered(ftype, filtered, currentRow);
- }
- filteredRows[0] = rowb;
- if (tryAdaptive) {
- final FilterType preferredAdaptive = filtersPerf.getPreferred();
- filterBank[5].write(filteredRows[preferredAdaptive.val]);
- }
- if (currentRow == lastRowInThisBand) {
- final int best = getBestCompressor();
- // PngHelperInternal.debug("won: " + best + " (rows: " + firstRowInThisBand + ":" + lastRowInThisBand + ")");
- // if(currentRow>90&¤tRow<100)
- // PngHelperInternal.debug(String.format("row=%d ft=%s",currentRow,FilterType.getByVal(best)));
- final byte[] filtersAdapt = filterBank[best].getFirstBytes();
- for (int r = firstRowInThisBand, i = 0, j = lastRowInThisBand - firstRowInThisBand; r <= lastRowInThisBand; r++, j--, i++) {
- final int fti = filtersAdapt[i];
- byte[] filtered = null;
- if (r != lastRowInThisBand)
- filtered = filterRowWithFilterType(FilterType.getByVal(fti), rows.get(j), rows.get(j + 1), filteredRowTmp);
- else
- filtered = filteredRows[fti];
- sendToCompressedStream(filtered);
- }
- }
- // rotate
- if (rows.size() > rowsPerBandCurrent)
- rows.addFirst(rows.removeLast());
- else
- rows.addFirst(new byte[buflen]);
- }
-
- @Override
- public byte[] getRowb() {
- return rows.get(0);
- }
-
- private void setBandFromNewRown() {
- final boolean newBand = currentRow == 0 || currentRow > lastRowInThisBand;
- if (currentRow == 0)
- bandNum = -1;
- if (newBand) {
- bandNum++;
- rowInBand = 0;
- } else
- rowInBand++;
- if (newBand) {
- firstRowInThisBand = currentRow;
- lastRowInThisBand = firstRowInThisBand + rowsPerBand - 1;
- final int lastRowInNextBand = firstRowInThisBand + 2 * rowsPerBand - 1;
- if (lastRowInNextBand >= imgInfo.rows) // hack:make this band bigger, so we don't have a small
- // last band
- lastRowInThisBand = imgInfo.rows - 1;
- rowsPerBandCurrent = 1 + lastRowInThisBand - firstRowInThisBand;
- tryAdaptive = rowsPerBandCurrent <= 3 || rowsPerBandCurrent < 10 && imgInfo.bytesPerRow < 64 ? false : true;
- // rebuild bank
- rebuildFiltersBank();
- }
- }
-
- private void rebuildFiltersBank() {
- final long bytesPerBandCurrent = rowsPerBandCurrent * (long) buflen;
- final int DEFLATER_COMP_LEVEL = 4;
- for (int i = 0; i <= 5; i++) {// one for each filter plus one adaptive
- CompressorStream cp = filterBank[i];
- if (cp == null || cp.totalbytes != bytesPerBandCurrent) {
- if (cp != null)
- cp.close();
- if (useLz4)
- cp = new CompressorStreamLz4(null, buflen, bytesPerBandCurrent);
- else
- cp = new CompressorStreamDeflater(null, buflen, bytesPerBandCurrent, DEFLATER_COMP_LEVEL, Deflater.DEFAULT_STRATEGY);
- filterBank[i] = cp;
- } else
- cp.reset();
- cp.setStoreFirstByte(true, rowsPerBandCurrent); // TODO: only for adaptive?
- }
- }
-
- private int computeInitialRowsPerBand() {
- // memory (only buffers) ~ (r+1+5) * bytesPerRow
- int r = (int) (hintMemoryKb * 1024.0 / (imgInfo.bytesPerRow + 1) - 5);
- if (r < 1)
- r = 1;
- if (hintRowsPerBand > 0 && r > hintRowsPerBand)
- r = hintRowsPerBand;
- if (r > imgInfo.rows)
- r = imgInfo.rows;
- if (r > 2 && r > imgInfo.rows / 8) { // redistribute more evenly
- final int k = (imgInfo.rows + r - 1) / r;
- r = (imgInfo.rows + k / 2) / k;
- }
- // PngHelperInternal.debug("rows :" + r + "/" + imgInfo.rows);
- return r;
- }
-
- private int getBestCompressor() {
- double bestcr = Double.MAX_VALUE;
- int bestb = -1;
- for (int i = tryAdaptive ? 5 : 4; i >= 0; i--) {
- final CompressorStream fb = filterBank[i];
- final double cr = fb.getCompressionRatio();
- if (cr <= bestcr) { // dirty trick, here the equality gains for row 0, so that SUB is prefered
- // over PAETH, UP, AVE...
- bestb = i;
- bestcr = cr;
- }
- }
- return bestb;
- }
-
- @Override
- protected void initParams() {
- super.initParams();
- // if adaptative but too few rows or columns, use default
- if (imgInfo.cols < 3 && !FilterType.isValidStandard(filterType))
- filterType = FilterType.FILTER_DEFAULT;
- if (imgInfo.rows < 3 && !FilterType.isValidStandard(filterType))
- filterType = FilterType.FILTER_DEFAULT;
- for (int i = 1; i <= 4; i++)
- if (filteredRows[i] == null || filteredRows[i].length < buflen)
- filteredRows[i] = new byte[buflen];
- if (rowsPerBand == 0)
- rowsPerBand = computeInitialRowsPerBand();
- }
-
- @Override
- public void close() {
- super.close();
- rows.clear();
- for (final CompressorStream f : filterBank)
- f.close();
- }
-
- public void setHintMemoryKb(final int hintMemoryKb) {
- this.hintMemoryKb = hintMemoryKb <= 0 ? PixelsWriterMultiple.HINT_MEMORY_DEFAULT_KB : hintMemoryKb > 10000 ? 10000 : hintMemoryKb;
- }
-
- public void setHintRowsPerBand(final int hintRowsPerBand) {
- this.hintRowsPerBand = hintRowsPerBand;
- }
-
- public void setUseLz4(final boolean lz4) {
- useLz4 = lz4;
- }
-
- /** for tuning memory or other parameters */
- public FiltersPerformance getFiltersPerf() {
- return filtersPerf;
- }
-
- public void setTryAdaptive(final boolean tryAdaptive) {
- this.tryAdaptive = tryAdaptive;
- }
-
-}
diff --git a/teavm/src/main/java/ar/com/hjg/pngj/pixels/package.html b/teavm/src/main/java/ar/com/hjg/pngj/pixels/package.html
deleted file mode 100644
index 85bd6a02..00000000
--- a/teavm/src/main/java/ar/com/hjg/pngj/pixels/package.html
+++ /dev/null
@@ -1,14 +0,0 @@
-
-
-
-Mostly related with logic specific to reading/writing pixels.
-
-
-Includes ImageLine related classes, and rows filtering
-
-
-Some classes like ImageLineInt should belong here, but we keep them in the main package for backward compatibility.
-
-
-
-
diff --git a/teavm/src/main/java/it/cavallium/warppi/gui/graphicengine/html/HtmlEngine.java b/teavm/src/main/java/it/cavallium/warppi/gui/graphicengine/html/HtmlEngine.java
index e9f8d0fa..10b18814 100644
--- a/teavm/src/main/java/it/cavallium/warppi/gui/graphicengine/html/HtmlEngine.java
+++ b/teavm/src/main/java/it/cavallium/warppi/gui/graphicengine/html/HtmlEngine.java
@@ -24,6 +24,7 @@ import it.cavallium.warppi.flow.BehaviorSubject;
import it.cavallium.warppi.flow.Observable;
import it.cavallium.warppi.gui.graphicengine.GraphicEngine;
import it.cavallium.warppi.gui.graphicengine.RenderingLoop;
+import it.unimi.dsi.fastutil.objects.Object2IntArrayMap;
public class HtmlEngine implements GraphicEngine {
@@ -70,15 +71,19 @@ public class HtmlEngine implements GraphicEngine {
}
private String previousValue = "";
+ private static final Object2IntArrayMap keyNames = new Object2IntArrayMap<>();
- @JSBody(params = { "ctx", "enabled" }, script = ""
- + "ctx.mozImageSmoothingEnabled = enabled;"
- + "ctx.oImageSmoothingEnabled = enabled;"
- + "ctx.webkitImageSmoothingEnabled = enabled;"
- + "ctx.msImageSmoothingEnabled = enabled;"
- + "ctx.imageSmoothingEnabled = enabled;")
+ static {
+ keyNames.put(" ", 32);
+ keyNames.put("ArrowUp", 38);
+ keyNames.put("ArrowDown", 40);
+ keyNames.put("ArrowLeft", 37);
+ keyNames.put("ArrowRight", 39);
+ }
+
+ @JSBody(params = { "ctx", "enabled" }, script = "" + "ctx.mozImageSmoothingEnabled = enabled;" + "ctx.oImageSmoothingEnabled = enabled;" + "ctx.webkitImageSmoothingEnabled = enabled;" + "ctx.msImageSmoothingEnabled = enabled;" + "ctx.imageSmoothingEnabled = enabled;")
public static native void setImageSmoothingEnabled(CanvasRenderingContext2D ctx, boolean enabled);
-
+
@Override
public void create(final Runnable onInitialized) {
exitSemaphore = Engine.getPlatform().newSemaphore(0);
@@ -93,14 +98,14 @@ public class HtmlEngine implements GraphicEngine {
onZoom.subscribe((windowZoom) -> {
if (windowZoom != 0) {
if (suppportsZoom()) {
- canvas.setWidth((int)(480 / 1));
- canvas.setHeight((int)(320 / 1));
+ canvas.setWidth((int) (480 / 1));
+ canvas.setHeight((int) (320 / 1));
canvas.getStyle().setProperty("zoom", "" + (1 + 1));
} else {
- canvas.setWidth((int)(480 * 2));
- canvas.setHeight((int)(320 * 2));
+ canvas.setWidth((int) (480 * 2));
+ canvas.setHeight((int) (320 * 2));
}
- canvas.getStyle().setProperty("max-height", (int)(44 / (1+1)) + "vh");
+ canvas.getStyle().setProperty("max-height", (int) (44 / (1 + 1)) + "vh");
width = 480 / windowZoom.intValue();
height = 320 / windowZoom.intValue();
this.mult = windowZoom.intValue();
@@ -114,13 +119,17 @@ public class HtmlEngine implements GraphicEngine {
HtmlEngine.document.getElementById("container").appendChild(canvas);
HtmlEngine.document.getBody().appendChild(keyInput);
keyInput.setTabIndex(0);
- keyInput.addEventListener("keydown", (final KeyboardEvent evt) -> {
+ keyInput.setValue("");
+ HtmlEngine.document.addEventListener("keydown", (final KeyboardEvent evt) -> {
evt.preventDefault();
new Thread(() -> {
- previousValue = keyInput.getValue();
- Keyboard.debugKeyPressed(evt.getKeyCode());
- System.out.println(evt.getKeyCode());
- System.out.println("" + (int) evt.getKey().charAt(0));
+ Keyboard.debugKey(keyNames .getOrDefault(evt.getKey(), evt.getKeyCode()), false);
+ }).start();
+ });
+ HtmlEngine.document.addEventListener("keyup", (final KeyboardEvent evt) -> {
+ evt.preventDefault();
+ new Thread(() -> {
+ Keyboard.debugKey(keyNames .getOrDefault(evt.getKey(), evt.getKeyCode()), true);
}).start();
});
keyInput.addEventListener("input", (final Event evt) -> {
@@ -133,14 +142,17 @@ public class HtmlEngine implements GraphicEngine {
new Thread(() -> {
if (newLen == prevLen) {
- } else if (newLen - prevLen == 1)
- Keyboard.debugKeyPressed(newValue.toUpperCase().charAt(newLen - 1));
+ } else if (newLen - prevLen == 1) {
+ Keyboard.debugKey(newValue.toUpperCase().charAt(newLen - 1), false);
+ Keyboard.debugKey(newValue.toUpperCase().charAt(newLen - 1), true);}
else if (newLen - prevLen > 1)
- for (int i = 0; i < newLen - prevLen; i++)
- Keyboard.debugKeyPressed(newValue.toUpperCase().charAt(prevLen + i));
+ for (int i = 0; i < newLen - prevLen; i++) {
+ Keyboard.debugKey(newValue.toUpperCase().charAt(prevLen + i), false);
+ Keyboard.debugKey(newValue.toUpperCase().charAt(prevLen + i), true);}
else if (newLen - prevLen < 1)
- for (int i = 0; i < prevLen - newLen; i++)
- Keyboard.debugKeyPressed(8);
+ for (int i = 0; i < prevLen - newLen; i++) {
+ Keyboard.debugKey(8, false);
+ Keyboard.debugKey(8, true);}
}).start();
});
canvas.addEventListener("click", (final Event evt) -> {
@@ -151,59 +163,73 @@ public class HtmlEngine implements GraphicEngine {
});
final NodeList extends HTMLElement> buttons = HtmlEngine.document.getBody().getElementsByTagName("button");
for (int i = 0; i < buttons.getLength(); i++)
- if (buttons.item(i).hasAttribute("keycode"))
- buttons.item(i).addEventListener("click", (final Event evt) -> {
- evt.preventDefault();
- final EventTarget target = evt.getCurrentTarget();
- final HTMLButtonElement button = target.cast();
- new Thread(() -> {
- try {
- if (button.hasAttribute("keycode") && button.getAttribute("keycode").contains(",")) {
- final String code = button.getAttribute("keycode");
- final String[] coordinates = code.split(",", 2);
- final boolean removeshift = Keyboard.shift && Integer.parseInt(coordinates[0]) != 0 && Integer.parseInt(coordinates[1]) != 0;
- final boolean removealpha = Keyboard.alpha && Integer.parseInt(coordinates[0]) != 0 && Integer.parseInt(coordinates[1]) != 1;
- Keyboard.keyPressedRaw(Integer.parseInt(coordinates[0]), Integer.parseInt(coordinates[1]));
- if (removeshift)
- Keyboard.keyPressedRaw(0, 0);
- if (removealpha)
- Keyboard.keyPressedRaw(0, 1);
- Thread.sleep(100);
- Keyboard.keyReleasedRaw(Integer.parseInt(coordinates[0]), Integer.parseInt(coordinates[1]));
- if (removeshift)
- Keyboard.keyReleasedRaw(0, 0);
- if (removealpha)
- Keyboard.keyReleasedRaw(0, 1);
- } else if (Keyboard.alpha && !Keyboard.shift) {
- if (button.hasAttribute("keycodea"))
- Keyboard.debugKeyPressed(Integer.parseInt(button.getAttribute("keycodea")));
- else
- Keyboard.debugKeyPressed(Integer.parseInt(button.getAttribute("keycode")));
- } else if (!Keyboard.alpha && Keyboard.shift) {
- if (button.hasAttribute("keycodes"))
- Keyboard.debugKeyPressed(Integer.parseInt(button.getAttribute("keycodes")));
- else
- Keyboard.debugKeyPressed(Integer.parseInt(button.getAttribute("keycode")));
- } else if (Keyboard.alpha && Keyboard.shift) {
- if (button.hasAttribute("keycodesa"))
- Keyboard.debugKeyPressed(Integer.parseInt(button.getAttribute("keycodesa")));
- else if (button.hasAttribute("keycodes"))
- Keyboard.debugKeyPressed(Integer.parseInt(button.getAttribute("keycodes")));
- else
- Keyboard.debugKeyPressed(Integer.parseInt(button.getAttribute("keycode")));
- } else
- Keyboard.debugKeyPressed(Integer.parseInt(button.getAttribute("keycode")));
- } catch (final Exception ex) {
- ex.printStackTrace();
- }
- }).start();
+ if (buttons.item(i).hasAttribute("keycode")) {
+ buttons.item(i).addEventListener("touchstart", (final Event evt) -> {
+ buttonEvent(evt, false);
});
+ buttons.item(i).addEventListener("touchend", (final Event evt) -> {
+ buttonEvent(evt, true);
+ });
+ buttons.item(i).addEventListener("mousedown", (final Event evt) -> {
+ buttonEvent(evt, false);
+ });
+ buttons.item(i).addEventListener("mouseup", (final Event evt) -> {
+ buttonEvent(evt, true);
+ });
+ }
renderer = new HtmlRenderer(this, g);
initialized = true;
if (onInitialized != null)
onInitialized.run();
}
+ private void buttonEvent(Event evt, boolean released) {
+ evt.preventDefault();
+ final EventTarget target = evt.getCurrentTarget();
+ final HTMLButtonElement button = target.cast();
+ new Thread(() -> {
+ try {
+ if (button.hasAttribute("keycode") && button.getAttribute("keycode").contains(",")) {
+ final String code = button.getAttribute("keycode");
+ final String[] coordinates = code.split(",", 2);
+ final boolean removeshift = Keyboard.shift && Integer.parseInt(coordinates[0]) != 0 && Integer.parseInt(coordinates[1]) != 0;
+ final boolean removealpha = Keyboard.alpha && Integer.parseInt(coordinates[0]) != 0 && Integer.parseInt(coordinates[1]) != 1;
+ Keyboard.keyRaw(Integer.parseInt(coordinates[0]), Integer.parseInt(coordinates[1]), released);
+ if (released) {
+ if (removeshift)
+ Keyboard.keyRaw(0, 0, false);
+ if (removealpha)
+ Keyboard.keyRaw(0, 1, false);
+ }
+ } else if (Keyboard.alpha && !Keyboard.shift) {
+ if (button.hasAttribute("keycodea")) {
+ Keyboard.debugKey(Integer.parseInt(button.getAttribute("keycodea")), released);
+ } else {
+ Keyboard.debugKey(Integer.parseInt(button.getAttribute("keycode")), released);
+ }
+ } else if (!Keyboard.alpha && Keyboard.shift) {
+ if (button.hasAttribute("keycodes")) {
+ Keyboard.debugKey(Integer.parseInt(button.getAttribute("keycodes")), released);
+ } else {
+ Keyboard.debugKey(Integer.parseInt(button.getAttribute("keycode")), released);
+ }
+ } else if (Keyboard.alpha && Keyboard.shift) {
+ if (button.hasAttribute("keycodesa")) {
+ Keyboard.debugKey(Integer.parseInt(button.getAttribute("keycodesa")), released);
+ } else if (button.hasAttribute("keycodes")) {
+ Keyboard.debugKey(Integer.parseInt(button.getAttribute("keycodes")), released);
+ } else {
+ Keyboard.debugKey(Integer.parseInt(button.getAttribute("keycode")), released);
+ }
+ } else {
+ Keyboard.debugKey(Integer.parseInt(button.getAttribute("keycode")), released);
+ }
+ } catch (final Exception ex) {
+ ex.printStackTrace();
+ }
+ }).start();
+ }
+
@JSBody(params = {}, script = "return CSS.supports(\"zoom:2\")")
private static native boolean suppportsZoom();
diff --git a/teavm/src/main/java/it/cavallium/warppi/gui/graphicengine/html/HtmlRenderer.java b/teavm/src/main/java/it/cavallium/warppi/gui/graphicengine/html/HtmlRenderer.java
index cf42b542..5c124516 100644
--- a/teavm/src/main/java/it/cavallium/warppi/gui/graphicengine/html/HtmlRenderer.java
+++ b/teavm/src/main/java/it/cavallium/warppi/gui/graphicengine/html/HtmlRenderer.java
@@ -7,7 +7,7 @@ import it.cavallium.warppi.gui.graphicengine.Renderer;
public class HtmlRenderer implements Renderer {
private String currentColor = "#000000ff";
- private String clearColor = "#000000ff";
+ private String clearColor = "#c5c2afff";
HtmlFont f = null;
HtmlSkin currentSkin = null;
private final CanvasRenderingContext2D g;
diff --git a/teavm/src/main/java/it/cavallium/warppi/gui/graphicengine/html/HtmlSkin.java b/teavm/src/main/java/it/cavallium/warppi/gui/graphicengine/html/HtmlSkin.java
index 19b291fe..39090002 100644
--- a/teavm/src/main/java/it/cavallium/warppi/gui/graphicengine/html/HtmlSkin.java
+++ b/teavm/src/main/java/it/cavallium/warppi/gui/graphicengine/html/HtmlSkin.java
@@ -2,14 +2,19 @@ package it.cavallium.warppi.gui.graphicengine.html;
import java.io.IOException;
import java.io.InputStream;
-import java.net.URISyntaxException;
+import org.apache.commons.lang3.ArrayUtils;
import org.teavm.jso.browser.Window;
+import org.teavm.jso.dom.events.Event;
import org.teavm.jso.dom.html.HTMLDocument;
import org.teavm.jso.dom.html.HTMLImageElement;
-import ar.com.hjg.pngj.PngReader;
import it.cavallium.warppi.Engine;
+import it.cavallium.warppi.Platform.Semaphore;
+import it.cavallium.warppi.flow.BehaviorSubject;
+import it.cavallium.warppi.flow.SimpleSubject;
+import it.cavallium.warppi.flow.Subject;
+import it.cavallium.warppi.flow.ValueReference;
import it.cavallium.warppi.gui.graphicengine.GraphicEngine;
import it.cavallium.warppi.gui.graphicengine.Skin;
@@ -38,22 +43,22 @@ public class HtmlSkin implements Skin {
@Override
public void load(String file) throws IOException {
- if (!file.startsWith("/"))
- file = "/" + file;
- url = Engine.getPlatform().getStorageUtils().getBasePath() + file;
- final InputStream stream = Engine.getPlatform().getStorageUtils().getResourceStream(file);
- final PngReader r = new PngReader(stream);
- skinSize = new int[] { r.imgInfo.cols, r.imgInfo.rows };
- r.close();
+ url = Engine.getPlatform().getStorageUtils().getBasePath() + (!file.startsWith("/") ? "/" : "") + file;
}
@Override
public void initialize(final GraphicEngine d) {
final HTMLDocument doc = Window.current().getDocument();
+ ValueReference done = new ValueReference(false);
imgEl = doc.createElement("img").cast();
+ imgEl.addEventListener("load", (Event e) -> {
+ done.value = true;
+ });
imgEl.setSrc(url);
- imgEl.setClassName("hidden");
- doc.getBody().appendChild(imgEl);
+ while (!done.value) {
+ try {Thread.sleep(15);} catch (Exception e) {}
+ }
+ skinSize = new int[] { imgEl.getNaturalWidth(), imgEl.getNaturalHeight() };
initd = true;
}
diff --git a/teavm/src/main/java/it/cavallium/warppi/teavm/TeaVMImageReader.java b/teavm/src/main/java/it/cavallium/warppi/teavm/TeaVMImageReader.java
new file mode 100644
index 00000000..20c46018
--- /dev/null
+++ b/teavm/src/main/java/it/cavallium/warppi/teavm/TeaVMImageReader.java
@@ -0,0 +1,23 @@
+package it.cavallium.warppi.teavm;
+
+import java.io.InputStream;
+
+import it.cavallium.warppi.Platform.ImageUtils.ImageReader;
+
+public class TeaVMImageReader implements ImageReader {
+
+ public TeaVMImageReader(final InputStream resourceStream) {
+ throw new RuntimeException("Not supported by this platform");
+ }
+
+ @Override
+ public int[] getImageMatrix() {
+ throw new RuntimeException("Not supported by this platform");
+ }
+
+ @Override
+ public int[] getSize() {
+ throw new RuntimeException("Not supported by this platform");
+ }
+
+}
diff --git a/teavm/src/main/java/it/cavallium/warppi/teavm/TeaVMImageUtils.java b/teavm/src/main/java/it/cavallium/warppi/teavm/TeaVMImageUtils.java
new file mode 100644
index 00000000..9b0b493b
--- /dev/null
+++ b/teavm/src/main/java/it/cavallium/warppi/teavm/TeaVMImageUtils.java
@@ -0,0 +1,14 @@
+package it.cavallium.warppi.teavm;
+
+import java.io.InputStream;
+
+import it.cavallium.warppi.Platform.ImageUtils;
+
+public class TeaVMImageUtils implements ImageUtils {
+
+ @Override
+ public ImageReader load(final InputStream resourceStream) {
+ return new TeaVMImageReader(resourceStream);
+ }
+
+}
diff --git a/teavm/src/main/java/it/cavallium/warppi/teavm/TeaVMPlatform.java b/teavm/src/main/java/it/cavallium/warppi/teavm/TeaVMPlatform.java
index a053be53..b60fc0ff 100644
--- a/teavm/src/main/java/it/cavallium/warppi/teavm/TeaVMPlatform.java
+++ b/teavm/src/main/java/it/cavallium/warppi/teavm/TeaVMPlatform.java
@@ -21,14 +21,15 @@ public class TeaVMPlatform implements Platform {
private final TeaVMStorageUtils su;
private final String on;
private final Map el;
- private final TeaVMPngUtils pu;
+ private final TeaVMImageUtils pu;
private final TeaVMSettings settings;
+ private Boolean runningOnRaspberryOverride = null;
public TeaVMPlatform() {
cu = new TeaVMConsoleUtils();
gi = new TeaVMGpio();
su = new TeaVMStorageUtils();
- pu = new TeaVMPngUtils();
+ pu = new TeaVMImageUtils();
on = "JavaScript";
el = new HashMap<>();
el.put("HTML5 engine", new HtmlEngine());
@@ -51,7 +52,7 @@ public class TeaVMPlatform implements Platform {
}
@Override
- public PngUtils getPngUtils() {
+ public ImageUtils getImageUtils() {
return pu;
}
@@ -208,6 +209,10 @@ public class TeaVMPlatform implements Platform {
throw new java.lang.UnsupportedOperationException("Not implemented.");
}
+ @Override
+ public void setRunningOnRaspberry(boolean b) {
+ }
+
@Override
public boolean isRunningOnRaspberry() {
return false;
diff --git a/teavm/src/main/java/it/cavallium/warppi/teavm/TeaVMPngReader.java b/teavm/src/main/java/it/cavallium/warppi/teavm/TeaVMPngReader.java
deleted file mode 100644
index 2c21fce7..00000000
--- a/teavm/src/main/java/it/cavallium/warppi/teavm/TeaVMPngReader.java
+++ /dev/null
@@ -1,60 +0,0 @@
-package it.cavallium.warppi.teavm;
-
-import java.io.InputStream;
-
-import ar.com.hjg.pngj.ImageLineInt;
-import it.cavallium.warppi.Platform.PngUtils.PngReader;
-
-public class TeaVMPngReader implements PngReader {
-
- private final ar.com.hjg.pngj.PngReader r;
-
- public TeaVMPngReader(final InputStream resourceStream) {
- r = new ar.com.hjg.pngj.PngReader(resourceStream);
- }
-
- @Override
- public int[] getImageMatrix() {
- final int width = r.imgInfo.cols;
- final int height = r.imgInfo.rows;
- final int channels = r.imgInfo.channels;
- final int[] pixels = new int[width * height];
- int pi = 0;
- ImageLineInt lint;
- while (r.hasMoreRows()) {
- lint = (ImageLineInt) r.readRow();
- final int[] scanLine = lint.getScanline();
-
- for (int i = 0; i < width; i++) {
- final int offset = i * channels;
-
- // Adjust the following code depending on your source image.
- // I need the to set the alpha channel to 0xFF000000 since my destination image
- // is TRANSLUCENT : BufferedImage bi = CONFIG.createCompatibleImage( width, height, Transparency.TRANSLUCENT );
- // my source was 3 channels RGB without transparency
- int nextPixel;
- if (channels == 4)
- nextPixel = scanLine[offset] << 16 | scanLine[offset + 1] << 8 | scanLine[offset + 2] | scanLine[offset + 3] << 24;
- else if (channels == 3)
- nextPixel = scanLine[offset] << 16 | scanLine[offset + 1] << 8 | scanLine[offset + 2] | 0xFF << 24;
- else if (channels == 2)
- nextPixel = scanLine[offset] << 16 | scanLine[offset + 1] << 8 | 0xFF | 0xFF << 24;
- else
- nextPixel = scanLine[offset] << 16 | scanLine[offset] << 8 | scanLine[offset] | 0xFF << 24;
-
- // I'm placing the pixels on a memory mapped file
- pixels[pi] = nextPixel;
- pi++;
- }
-
- }
-
- return pixels;
- }
-
- @Override
- public int[] getSize() {
- return new int[] { r.imgInfo.cols, r.imgInfo.rows };
- }
-
-}
diff --git a/teavm/src/main/java/it/cavallium/warppi/teavm/TeaVMPngUtils.java b/teavm/src/main/java/it/cavallium/warppi/teavm/TeaVMPngUtils.java
deleted file mode 100644
index 6378dc2d..00000000
--- a/teavm/src/main/java/it/cavallium/warppi/teavm/TeaVMPngUtils.java
+++ /dev/null
@@ -1,14 +0,0 @@
-package it.cavallium.warppi.teavm;
-
-import java.io.InputStream;
-
-import it.cavallium.warppi.Platform.PngUtils;
-
-public class TeaVMPngUtils implements PngUtils {
-
- @Override
- public PngReader load(final InputStream resourceStream) {
- return new TeaVMPngReader(resourceStream);
- }
-
-}
diff --git a/teavm/src/main/java/it/cavallium/warppi/teavm/TeaVMSemaphore.java b/teavm/src/main/java/it/cavallium/warppi/teavm/TeaVMSemaphore.java
index ae8f3327..517dee8d 100644
--- a/teavm/src/main/java/it/cavallium/warppi/teavm/TeaVMSemaphore.java
+++ b/teavm/src/main/java/it/cavallium/warppi/teavm/TeaVMSemaphore.java
@@ -5,9 +5,9 @@ import java.util.Queue;
public class TeaVMSemaphore implements it.cavallium.warppi.Platform.Semaphore {
- private final Queue