From 445eb8f1c388c8be4da9127790a7c6273f45ae1b Mon Sep 17 00:00:00 2001 From: josch Date: Wed, 28 Sep 2011 22:56:50 +0200 Subject: [PATCH] Initial commit --- build.xml | 74 + nbproject/build-impl.xml | 1041 +++++++++ nbproject/private/config.properties | 0 nbproject/private/private.properties | 1 + nbproject/project.properties | 62 + src/deepZoom/Main.java | 9 + src/deepZoom/MandelAnimator.java | 334 +++ src/deepZoom/animation/Animation.java | 32 + src/deepZoom/animation/ZoomAnimation.java | 69 + src/deepZoom/calculator/Calculator.java | 15 + .../calculator/ParallelCalculator.java | 93 + src/deepZoom/colorings/Coloring.java | 22 + src/deepZoom/colorings/GradientColoring.java | 26 + .../SmoothIterationsColoringBad.java | 37 + src/deepZoom/fractals/Fractal.java | 29 + src/deepZoom/fractals/Mandel.java | 119 ++ src/deepZoom/fractals/MandelPrecision.java | 151 ++ src/deepZoom/parameters/Animation.java | 30 + src/deepZoom/parameters/Parameters.java | 57 + src/deepZoom/parameters/ZoomAnimation.java | 55 + src/deepZoom/renderer/Layer.java | 28 + src/deepZoom/renderer/PointInfo.java | 21 + src/deepZoom/renderer/Scene.java | 221 ++ src/deepZoom/schedulers/AngularScheduler.java | 32 + src/deepZoom/schedulers/CRTScheduler.java | 24 + src/deepZoom/schedulers/ClockScheduler.java | 24 + src/deepZoom/schedulers/DitherScheduler.java | 25 + src/deepZoom/schedulers/FlowerScheduler.java | 36 + src/deepZoom/schedulers/ModScheduler.java | 22 + src/deepZoom/schedulers/PriorityPoint.java | 32 + .../schedulers/PythagorasScheduler.java | 23 + src/deepZoom/schedulers/RadialScheduler.java | 26 + src/deepZoom/schedulers/RandomScheduler.java | 45 + src/deepZoom/schedulers/Scheduler.java | 43 + src/deepZoom/schedulers/SimpleScheduler.java | 23 + src/deepZoom/schedulers/SpiralScheduler.java | 33 + src/deepZoom/schedulers/SplitScheduler.java | 23 + .../schedulers/SquareSpiralScheduler.java | 37 + src/deepZoom/schedulers/XorScheduler.java | 25 + src/deepZoom/viewports/Viewport.java | 73 + src/digisoft/custom/NumberFunctions.java | 224 ++ src/digisoft/custom/awt/Color3f.java | 534 +++++ src/digisoft/custom/awt/Color3fConst.java | 184 ++ src/digisoft/custom/math/NumberConstants.java | 58 + .../custom/swing/GraphicsFunctions.java | 87 + src/digisoft/custom/swing/ImageFunctions.java | 100 + .../custom/swing/RefreshListener.java | 11 + src/digisoft/custom/swing/RefreshThread.java | 39 + .../custom/swing/gradient/Gradient.java | 19 + .../custom/swing/gradient/OpaqueGradient.java | 108 + .../custom/swing/window/CanvasWindow.java | 165 ++ .../custom/swing/window/PixelWindow.java | 96 + .../swing/window/canvas/GraphicsCanvas.java | 131 ++ .../canvas/MemoryImageSourceCanvas.java | 69 + .../custom/util/geom/DoubleDouble.java | 1892 +++++++++++++++++ 55 files changed, 6789 insertions(+) create mode 100644 build.xml create mode 100644 nbproject/build-impl.xml create mode 100644 nbproject/private/config.properties create mode 100644 nbproject/private/private.properties create mode 100644 nbproject/project.properties create mode 100644 src/deepZoom/Main.java create mode 100644 src/deepZoom/MandelAnimator.java create mode 100644 src/deepZoom/animation/Animation.java create mode 100644 src/deepZoom/animation/ZoomAnimation.java create mode 100644 src/deepZoom/calculator/Calculator.java create mode 100644 src/deepZoom/calculator/ParallelCalculator.java create mode 100644 src/deepZoom/colorings/Coloring.java create mode 100644 src/deepZoom/colorings/GradientColoring.java create mode 100644 src/deepZoom/colorings/SmoothIterationsColoringBad.java create mode 100644 src/deepZoom/fractals/Fractal.java create mode 100644 src/deepZoom/fractals/Mandel.java create mode 100644 src/deepZoom/fractals/MandelPrecision.java create mode 100644 src/deepZoom/parameters/Animation.java create mode 100644 src/deepZoom/parameters/Parameters.java create mode 100644 src/deepZoom/parameters/ZoomAnimation.java create mode 100644 src/deepZoom/renderer/Layer.java create mode 100644 src/deepZoom/renderer/PointInfo.java create mode 100644 src/deepZoom/renderer/Scene.java create mode 100644 src/deepZoom/schedulers/AngularScheduler.java create mode 100644 src/deepZoom/schedulers/CRTScheduler.java create mode 100644 src/deepZoom/schedulers/ClockScheduler.java create mode 100644 src/deepZoom/schedulers/DitherScheduler.java create mode 100644 src/deepZoom/schedulers/FlowerScheduler.java create mode 100644 src/deepZoom/schedulers/ModScheduler.java create mode 100644 src/deepZoom/schedulers/PriorityPoint.java create mode 100644 src/deepZoom/schedulers/PythagorasScheduler.java create mode 100644 src/deepZoom/schedulers/RadialScheduler.java create mode 100644 src/deepZoom/schedulers/RandomScheduler.java create mode 100644 src/deepZoom/schedulers/Scheduler.java create mode 100644 src/deepZoom/schedulers/SimpleScheduler.java create mode 100644 src/deepZoom/schedulers/SpiralScheduler.java create mode 100644 src/deepZoom/schedulers/SplitScheduler.java create mode 100644 src/deepZoom/schedulers/SquareSpiralScheduler.java create mode 100644 src/deepZoom/schedulers/XorScheduler.java create mode 100644 src/deepZoom/viewports/Viewport.java create mode 100644 src/digisoft/custom/NumberFunctions.java create mode 100644 src/digisoft/custom/awt/Color3f.java create mode 100644 src/digisoft/custom/awt/Color3fConst.java create mode 100644 src/digisoft/custom/math/NumberConstants.java create mode 100644 src/digisoft/custom/swing/GraphicsFunctions.java create mode 100644 src/digisoft/custom/swing/ImageFunctions.java create mode 100644 src/digisoft/custom/swing/RefreshListener.java create mode 100644 src/digisoft/custom/swing/RefreshThread.java create mode 100644 src/digisoft/custom/swing/gradient/Gradient.java create mode 100644 src/digisoft/custom/swing/gradient/OpaqueGradient.java create mode 100644 src/digisoft/custom/swing/window/CanvasWindow.java create mode 100644 src/digisoft/custom/swing/window/PixelWindow.java create mode 100644 src/digisoft/custom/swing/window/canvas/GraphicsCanvas.java create mode 100644 src/digisoft/custom/swing/window/canvas/MemoryImageSourceCanvas.java create mode 100644 src/digisoft/custom/util/geom/DoubleDouble.java diff --git a/build.xml b/build.xml new file mode 100644 index 0000000..531aa84 --- /dev/null +++ b/build.xml @@ -0,0 +1,74 @@ + + + + + + + + + + + Builds, tests, and runs the project ZomBDeepZoom. + + + diff --git a/nbproject/build-impl.xml b/nbproject/build-impl.xml new file mode 100644 index 0000000..8940165 --- /dev/null +++ b/nbproject/build-impl.xml @@ -0,0 +1,1041 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Must set src.dir + Must set test.src.dir + Must set build.dir + Must set dist.dir + Must set build.classes.dir + Must set dist.javadoc.dir + Must set build.test.classes.dir + Must set build.test.results.dir + Must set build.classes.excludes + Must set dist.jar + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Must set javac.includes + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Must set JVM to use for profiling in profiler.info.jvm + Must set profiler agent JVM arguments in profiler.info.jvmargs.agent + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Must select some files in the IDE or set javac.includes + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + To run this application from the command line without Ant, try: + + + + + + + java -cp "${run.classpath.with.dist.jar}" ${main.class} + + + + + + + + + + + + + + + + + + + + + + + + + To run this application from the command line without Ant, try: + + java -jar "${dist.jar.resolved}" + + + + + + + + + + + + + + + + + + + + + + + + + Must select one file in the IDE or set run.class + + + + Must select one file in the IDE or set run.class + + + + + + + + + + + + + + + + + + + + + + + Must select one file in the IDE or set debug.class + + + + + Must select one file in the IDE or set debug.class + + + + + Must set fix.includes + + + + + + + + + + + + + + + + + Must select one file in the IDE or set profile.class + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Must select some files in the IDE or set javac.includes + + + + + + + + + + + + + + + + + + + + Some tests failed; see details above. + + + + + + + + + Must select some files in the IDE or set test.includes + + + + Some tests failed; see details above. + + + + + Must select one file in the IDE or set test.class + + + + + + + + + + + + + + + + + + + + + + + + + + + Must select one file in the IDE or set applet.url + + + + + + + + + Must select one file in the IDE or set applet.url + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/nbproject/private/config.properties b/nbproject/private/config.properties new file mode 100644 index 0000000..e69de29 diff --git a/nbproject/private/private.properties b/nbproject/private/private.properties new file mode 100644 index 0000000..0857e3a --- /dev/null +++ b/nbproject/private/private.properties @@ -0,0 +1 @@ +user.properties.file=C:\\Users\\Yukari Yakumo\\.netbeans\\7.0\\build.properties diff --git a/nbproject/project.properties b/nbproject/project.properties new file mode 100644 index 0000000..a7c2e0e --- /dev/null +++ b/nbproject/project.properties @@ -0,0 +1,62 @@ +application.title=ZomBDeepZoom +application.vendor=Administrator +build.classes.dir=${build.dir}/classes +build.classes.excludes=**/*.java,**/*.form +# This directory is removed when the project is cleaned: +build.dir=build +build.generated.dir=${build.dir}/generated +build.generated.sources.dir=${build.dir}/generated-sources +# Only compile against the classpath explicitly listed here: +build.sysclasspath=ignore +build.test.classes.dir=${build.dir}/test/classes +build.test.results.dir=${build.dir}/test/results +debug.classpath=\ + ${run.classpath} +debug.test.classpath=\ + ${run.test.classpath} +# This directory is removed when the project is cleaned: +dist.dir=dist +dist.jar=${dist.dir}/ZomBDeepZoom.jar +dist.javadoc.dir=${dist.dir}/javadoc +excludes= +includes=** +jar.compress=false +javac.classpath= +# Space-separated list of extra javac options +javac.compilerargs= +javac.deprecation=false +javac.source=1.5 +javac.target=1.5 +javac.test.classpath=\ + ${javac.classpath}:\ + ${build.classes.dir}:\ + ${libs.junit.classpath}:\ + ${libs.junit_4.classpath} +javadoc.additionalparam= +javadoc.author=false +javadoc.encoding=${source.encoding} +javadoc.noindex=false +javadoc.nonavbar=false +javadoc.notree=false +javadoc.private=false +javadoc.splitindex=true +javadoc.use=true +javadoc.version=false +javadoc.windowtitle= +main.class=deepZoom.MandelAnimator +manifest.file=manifest.mf +meta.inf.dir=${src.dir}/META-INF +platform.active=default_platform +run.classpath=\ + ${javac.classpath}:\ + ${build.classes.dir} +# Space-separated list of JVM arguments used when running the project +# (you may also define separate properties like run-sys-prop.name=value instead of -Dname=value +# or test-sys-prop.name=value to set system properties for unit tests): +run.jvmargs= +run.test.classpath=\ + ${javac.test.classpath}:\ + ${build.test.classes.dir} +source.encoding=UTF-8 +src.dir=src +test.src.dir=test diff --git a/src/deepZoom/Main.java b/src/deepZoom/Main.java new file mode 100644 index 0000000..35b7759 --- /dev/null +++ b/src/deepZoom/Main.java @@ -0,0 +1,9 @@ +package deepZoom; + +public class Main { + + public static void main(String[] args) { + //new MandelAnimator(); + + } +} \ No newline at end of file diff --git a/src/deepZoom/MandelAnimator.java b/src/deepZoom/MandelAnimator.java new file mode 100644 index 0000000..949950d --- /dev/null +++ b/src/deepZoom/MandelAnimator.java @@ -0,0 +1,334 @@ +package deepZoom; + +import java.awt.event.InputEvent; +import java.awt.event.MouseEvent; +import java.awt.event.MouseListener; +import java.io.IOException; + +import deepZoom.calculator.Calculator; +import deepZoom.calculator.ParallelCalculator; +import deepZoom.colorings.Coloring; +import deepZoom.colorings.SmoothIterationsColoringBad; +import deepZoom.fractals.Fractal; +import deepZoom.fractals.Mandel; +import deepZoom.fractals.MandelPrecision; +import deepZoom.parameters.ZoomAnimation; +import deepZoom.renderer.Layer; +import deepZoom.renderer.Scene; +import deepZoom.schedulers.AngularScheduler; +import deepZoom.schedulers.CRTScheduler; +import deepZoom.schedulers.ClockScheduler; +import deepZoom.schedulers.DitherScheduler; +import deepZoom.schedulers.FlowerScheduler; +import deepZoom.schedulers.ModScheduler; +import deepZoom.schedulers.PythagorasScheduler; +import deepZoom.schedulers.RadialScheduler; +import deepZoom.schedulers.RandomScheduler; +import deepZoom.schedulers.Scheduler; +import deepZoom.schedulers.SimpleScheduler; +import deepZoom.schedulers.SpiralScheduler; +import deepZoom.schedulers.SplitScheduler; +import deepZoom.schedulers.SquareSpiralScheduler; +import deepZoom.schedulers.XorScheduler; +import deepZoom.viewports.Viewport; + +import digisoft.custom.NumberFunctions; +import digisoft.custom.awt.Color3f; +import digisoft.custom.swing.ImageFunctions; +import digisoft.custom.swing.RefreshListener; +import digisoft.custom.swing.RefreshThread; +import digisoft.custom.swing.gradient.Gradient; +import digisoft.custom.swing.gradient.OpaqueGradient; +import digisoft.custom.swing.window.PixelWindow; +import digisoft.custom.util.geom.DoubleDouble; +import java.io.File; + +/** + * @author Zom-B + * @since 1.0 + * @see date 2006/10/20 + */ +public class MandelAnimator implements RefreshListener, Calculator, MouseListener { + + private static final String SAVEPATH = "C:/Animation golden/"; + private static final int WIDTH = (int) (1024); + private static final int HEIGHT = (int) (576); + private static int FRAME_START = 1; + private static final int FRAME_END = 3600; + private static final int FRAME_STEP = 1; + private static final boolean DO_ANTIALIAS = true; + //Traditional Wikipedia + private DoubleDouble centerX = new DoubleDouble(-0.7436438870371587, -3.628952515063387E-17); + private DoubleDouble centerY = new DoubleDouble(0.13182590420531198, -1.2892807754956678E-17); + //Line and cross + //private DoubleDouble centerX = new DoubleDouble(-0.743646040973709, -4.790419761500457E-18); + //private DoubleDouble centerY = new DoubleDouble(0.13182426946026354, 1.9785505600065397E-18); + private static final double MIN_ZOOM = 1; + private static final double MAX_ZOOM = 1e30; + private static final int NUM_FRAMES = 3600; + + public static void main(String[] args) { + new MandelAnimator(); + } + private static final int NUM_CPUS = Runtime.getRuntime().availableProcessors(); + private PixelWindow aaWindow = new PixelWindow(10, 10, MandelAnimator.WIDTH, MandelAnimator.HEIGHT); + private PixelWindow iterWindow = new PixelWindow(10, 10, MandelAnimator.WIDTH, MandelAnimator.HEIGHT); + private PixelWindow fractalWindow = new PixelWindow(10, 10, MandelAnimator.WIDTH, MandelAnimator.HEIGHT); + private Viewport viewport = new Viewport(); + private Layer layer = new Layer(); + private ZoomAnimation animation = new ZoomAnimation(); + private Fractal fractal = new Mandel(); + private Coloring coloring = new SmoothIterationsColoringBad(makeGradient()); + private Scheduler[] schedulers = {new SpiralScheduler(10)}; + private int scheduler; + private Scene scene = new Scene(); + private int frameNr; + private boolean antialiasStep = false; + private long runTime; + private long frameTime; + + public MandelAnimator() { + File dirFile = new File(SAVEPATH); + dirFile.mkdir(); + + int newSave = 0; + for (int i = MandelAnimator.FRAME_START; i <= MandelAnimator.FRAME_END; i++) { + File test = new File(MandelAnimator.SAVEPATH + + NumberFunctions.toStringFixedLength(i, 4) + ".png"); + if (!test.isFile()) { + newSave = i; + break; + } + } + MandelAnimator.FRAME_START = newSave; + + fractalWindow.addMouseListener(this); + iterWindow.setTitle("Iter"); + aaWindow.setTitle("AA"); + + animation.setWidth(MandelAnimator.WIDTH); + animation.setNumFrames(MandelAnimator.NUM_FRAMES); + animation.setCenterX(centerX); + animation.setCenterY(centerY); + animation.setMagnStart(MandelAnimator.MIN_ZOOM); + animation.setMagnEnd(MandelAnimator.MAX_ZOOM); + animation.setBailout(128); + animation.init(); + viewport.setSize(MandelAnimator.WIDTH, MandelAnimator.HEIGHT); + viewport.setParameters(animation); + fractal.setParameters(animation); + coloring.setParameters(animation); + + for (Scheduler s : schedulers) { + s.setViewport(viewport); + } + + scene.setViewport(viewport); + scene.setColorPixels(fractalWindow.pixels); + scene.setIterMap(iterWindow.pixels); + scene.setEdgeMap(aaWindow.pixels); + scene.setNumCPUs(MandelAnimator.NUM_CPUS); + + { + layer.setFractal(fractal); + layer.setColoring(coloring); + scene.addLayer(layer); + } + + frameNr = MandelAnimator.FRAME_START; + + runTime = frameTime = System.currentTimeMillis(); + ParallelCalculator.createCalculators(this, MandelAnimator.NUM_CPUS); + new RefreshThread(this, 30).start(); + } + + public static Gradient makeGradient() { + final Color3f[] c = { + new Color3f(14, 11, 82), + new Color3f(14, 60, 165), + new Color3f(78, 154, 220), + new Color3f(176, 229, 255), + new Color3f(249, 253, 239), + new Color3f(249, 229, 96), + new Color3f(249, 181, 15), + new Color3f(217, 108, 3), + new Color3f(134, 32, 13), + new Color3f(57, 4, 35), + new Color3f(14, 11, 82)}; + final float[] f = new float[c.length]; + for (int i = 0; i < c.length; i++) { + f[i] = i / (float) (c.length - 1); + f[i] = (float) StrictMath.sqrt(f[i]); + } + + return new OpaqueGradient(f, c); + } + + /* + public static Gradient makeGradient() { + final Color3f[] c = {new Color3f(0, 0, 0f), // + new Color3f(1, 0, 0f), // + new Color3f(1, 1, 1f), // Red + new Color3f(1, 0, 0f), // + new Color3f(0, 0, 0f), // + new Color3f(1, 0.4f, 0f), // + new Color3f(1, 1, 1f), // Orange + new Color3f(1, 0.4f, 0f), // + new Color3f(0, 0, 0f), // + new Color3f(1, 1, 0f), // + new Color3f(1, 1, 1f), // Yellow + new Color3f(1, 1, 0f), // + new Color3f(0, 0, 0f), // + new Color3f(0, 1, 0f), // + new Color3f(1, 1, 1f), // Green + new Color3f(0, 1, 0f), // + new Color3f(0, 0, 0f), // + new Color3f(0, 1, 1f), // + new Color3f(1, 1, 1f), // Cyan + new Color3f(0, 1, 1f), // + new Color3f(0, 0, 0f), // + new Color3f(0, 0, 1f), // + new Color3f(1, 1, 1f), // Blue + new Color3f(0, 0, 1f), // + new Color3f(0, 0, 0f)}; + final float[] f = new float[c.length]; + for (int i = 0; i < c.length; i++) { + f[i] = i / (float) (c.length - 1); + f[i] = (float) StrictMath.sqrt(f[i]); + } + + return new OpaqueGradient(f, c); + } */ + + private void saveFrame() { + try { + ImageFunctions.savePNG(MandelAnimator.SAVEPATH + NumberFunctions.toStringFixedLength(frameNr, 4) + ".png", fractalWindow.pixels, + MandelAnimator.WIDTH, MandelAnimator.HEIGHT); + } catch (IOException e) { + e.printStackTrace(); + } + } + + private void destroyImage() { + System.gc(); + fractalWindow.clear(0); + iterWindow.clear(0); + aaWindow.clear(0); + } + + private void nextFrame() { + frameNr += MandelAnimator.FRAME_STEP; + if (frameNr > MandelAnimator.FRAME_END) { + // System.exit(0); + while (true) { + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + } + } + + @Override + public void prepareCalculation() { + scheduler = NumberFunctions.RND.nextInt(schedulers.length); + scene.setScheduler(schedulers[scheduler]); + + if (!antialiasStep) { + fractalWindow.setTitle(Integer.toString(frameNr) + " First pass"); + + animation.setFrame(frameNr); + + System.out.println("Rough: " + frameNr + " magn=" + animation.getMagn() + " maxiter=" + animation.getMaxiter()); + + destroyImage(); + scene.initFrame(); + } else { + fractalWindow.setTitle(Integer.toString(frameNr) + " Antialiasing"); + + animation.setFrame(frameNr); + animation.setMaxiter(animation.getMaxiter() << 2); + + System.out.println("AA: " + frameNr + " magn=" + animation.getMagn() + " maxiter=" + animation.getMaxiter()); + + scene.calcAntialiasMask(); + } + + schedulers[scheduler].init(); + } + + @Override + public void calculate(int cpu) { + if (!antialiasStep) { + scene.render(cpu); + } else { + scene.renderAntialias(cpu); + } + } + + @Override + public void calculationCompleted() { + if (!antialiasStep && MandelAnimator.DO_ANTIALIAS) { + antialiasStep = true; + } else { + antialiasStep = false; + + fractalWindow.repaintNow(); + iterWindow.repaintNow(); + saveFrame(); + + long time = System.currentTimeMillis(); + System.out.println("Time elapsed: " + (time - runTime) / 1e3 + " / " + (time - frameTime) / 1e3); + if (time - frameTime < 2000) { + try { + Thread.sleep(2000 - time + frameTime); + } catch (InterruptedException e) { + } + } + frameTime = System.currentTimeMillis(); + + nextFrame(); + } + } + + @Override + public void refreshing() { + fractalWindow.repaintNow(); + iterWindow.repaintNow(); + aaWindow.repaintNow(); + if (antialiasStep) { + aaWindow.setTitle("AA " + (int) (schedulers[scheduler].getProgress() * 1000) / 10f + "%"); + } else { + iterWindow.setTitle("Iter " + (int) (schedulers[scheduler].getProgress() * 1000) / 10f + "%"); + } + } + + @Override + public void mouseClicked(MouseEvent e) { + } + + @Override + public void mouseEntered(MouseEvent e) { + } + + @Override + public void mouseExited(MouseEvent e) { + } + + @Override + public void mousePressed(MouseEvent e) { + if ((e.getModifiers() & InputEvent.BUTTON1_MASK) != 0) { + centerX = viewport.getPX(e.getX(), e.getY()); + centerY = viewport.getPY(e.getX(), e.getY()); + + System.out.println("/tprivate DoubleDouble/t/t/tcenterX/t/t/t= new DoubleDouble(" + centerX.hi + ", " + centerX.lo + ");"); + System.out.println("/tprivate DoubleDouble/t/t/tcenterY/t/t/t= new DoubleDouble(" + centerY.hi + ", " + centerY.lo + ");"); + } else if ((e.getModifiers() & InputEvent.BUTTON3_MASK) != 0) { + } + } + + @Override + public void mouseReleased(MouseEvent e) { + } +} diff --git a/src/deepZoom/animation/Animation.java b/src/deepZoom/animation/Animation.java new file mode 100644 index 0000000..5279504 --- /dev/null +++ b/src/deepZoom/animation/Animation.java @@ -0,0 +1,32 @@ +package deepZoom.animation; + +import deepZoom.parameters.Parameters; + +/** + * Generic animation for fractals. Implementations define which parameters are + * animated, though animation for the following quantities is supported: center, + * magnitude, maxiter and bailout. Before the animation can be calculated, the + * number of frames need also be known beforehand. After changing animation + * parameters or number of frames, the animation needs to be initialized by + * calling init(). + * + * @author Zom-B + * @since 1.0 + * @date May 2, 2009 + */ +public abstract class Animation extends Parameters { + + protected int numFrames; + + public void setNumFrames(int numFrames) { + this.numFrames = numFrames; + } + + /** + * Initialize the animation sequence. Call after each change to + * initial/final parameters or number of frames. + */ + public abstract void init(); + + public abstract void setFrame(int frameNr); +} diff --git a/src/deepZoom/animation/ZoomAnimation.java b/src/deepZoom/animation/ZoomAnimation.java new file mode 100644 index 0000000..4121f38 --- /dev/null +++ b/src/deepZoom/animation/ZoomAnimation.java @@ -0,0 +1,69 @@ +package deepZoom.animation; + +import digisoft.custom.util.geom.DoubleDouble; + +/** + * Animation that just zooms. The center parameters and bailout are not + * animated, and the zooming position is the center of the fractal. ie. set the + * center of the fractal to the center of thezoomed frame. The maxiter is also + * animated to account for constant detail with maximum speed throughout the + * animation. For this, the width of the frame in pixels is also required. + * Bailout is also not animated. + * + * @author Zom-B + * @since 1.0 + * @date May 2, 2009 + */ +public class ZoomAnimation extends Animation { + + private int width; + private double magnStart; + private double magnEnd; + private double factorMagn; + + public void setWidth(int width) { + this.width = width; + } + + @Override + public void setNumFrames(int numFrames) { + this.numFrames = numFrames; + } + + @Override + public void setCenterX(DoubleDouble centerX) { + this.centerX = centerX; + } + + @Override + public void setCenterY(DoubleDouble centerY) { + this.centerY = centerY; + } + + public void setMagnStart(double magnStart) { + this.magnStart = magnStart; + } + + public void setMagnEnd(double magnEnd) { + this.magnEnd = magnEnd; + } + + @Override + public void setBailout(double bailout) { + this.bailout = bailout; + } + + @Override + public void init() { + factorMagn = StrictMath.pow(magnEnd / magnStart, 1.0 / (numFrames - 1)); + } + + @Override + public void setFrame(int frameNr) { + magn = magnStart * StrictMath.pow(factorMagn, frameNr - 1); + + maxiter = (long) (width * StrictMath.pow(magn, -0.5)); + + System.out.println(magn); + } +} diff --git a/src/deepZoom/calculator/Calculator.java b/src/deepZoom/calculator/Calculator.java new file mode 100644 index 0000000..205844d --- /dev/null +++ b/src/deepZoom/calculator/Calculator.java @@ -0,0 +1,15 @@ +package deepZoom.calculator; + +/** + * @author Zom-B + * @since 1.0 + * @date Apr 19, 2009 + */ +public interface Calculator { + + public void prepareCalculation(); + + public void calculate(int cpu); + + public void calculationCompleted(); +} diff --git a/src/deepZoom/calculator/ParallelCalculator.java b/src/deepZoom/calculator/ParallelCalculator.java new file mode 100644 index 0000000..441d747 --- /dev/null +++ b/src/deepZoom/calculator/ParallelCalculator.java @@ -0,0 +1,93 @@ +package deepZoom.calculator; + +import java.util.Arrays; + +/** + * @author Zom-B + * @since 1.0 + * @date Apr 19, 2009 + */ +public class ParallelCalculator implements Runnable { + + private static int NUM_CPUS; + private static boolean[] WAIT; + private static boolean[] GO; + + public static void createCalculators(Calculator calculator, int numCPUs) { + ParallelCalculator.NUM_CPUS = numCPUs; + + ParallelCalculator.WAIT = new boolean[numCPUs]; + ParallelCalculator.GO = new boolean[numCPUs]; + + for (int i = 0; i < numCPUs; i++) { + new ParallelCalculator(calculator, i); + } + } + private int cpu; + private Calculator calculator; + + private ParallelCalculator(Calculator calculator, int cpu) { + this.calculator = calculator; + this.cpu = cpu; + + System.out.println("Starting core " + cpu); + + prepare(); + new Thread(this).start(); + } + + public void run() { + while (true) { + calculator.calculate(cpu); + syncWithOthers(); + } + } + + private void prepare() { + if (cpu == 0) { + Arrays.fill(ParallelCalculator.WAIT, true); + Arrays.fill(ParallelCalculator.GO, true); + + calculator.prepareCalculation(); + } + } + + private void syncWithOthers() { + ParallelCalculator.WAIT[cpu] = false; + + if (cpu == 0) { + while (true) { + boolean done = true; + for (int i = ParallelCalculator.NUM_CPUS - 1; i >= 0; i--) { + if (ParallelCalculator.WAIT[i]) { + done = false; + break; + } + } + if (done) { + break; + } + + Thread.yield(); + } + + // All threads done. + + calculator.calculationCompleted(); + prepare(); + + Arrays.fill(ParallelCalculator.WAIT, true); + Arrays.fill(ParallelCalculator.GO, true); + } else { + while (!ParallelCalculator.GO[cpu]) { + try { + Thread.sleep(1); + } catch (InterruptedException e) { + Thread.yield(); + } + } + } + + ParallelCalculator.GO[cpu] = false; + } +} \ No newline at end of file diff --git a/src/deepZoom/colorings/Coloring.java b/src/deepZoom/colorings/Coloring.java new file mode 100644 index 0000000..272d188 --- /dev/null +++ b/src/deepZoom/colorings/Coloring.java @@ -0,0 +1,22 @@ +package deepZoom.colorings; + +import deepZoom.parameters.Parameters; +import deepZoom.renderer.PointInfo; + +/** + * @author Zom-B + * @since 1.0 + * @date May 1, 2009 + */ +public abstract class Coloring { + + protected Parameters parameters; + + public void setParameters(Parameters parameters) { + this.parameters = parameters; + } + + public abstract void initParameters(); + + public abstract int getColor(PointInfo resultSet); +} diff --git a/src/deepZoom/colorings/GradientColoring.java b/src/deepZoom/colorings/GradientColoring.java new file mode 100644 index 0000000..b8d10e1 --- /dev/null +++ b/src/deepZoom/colorings/GradientColoring.java @@ -0,0 +1,26 @@ +package deepZoom.colorings; + +import deepZoom.renderer.PointInfo; + +import digisoft.custom.swing.gradient.Gradient; + +/** + * @author Zom-B + * @since 1.0 + * @date May 2, 2009 + */ +public abstract class GradientColoring extends Coloring { + + protected Gradient gradient; + + public GradientColoring(Gradient gradient) { + this.gradient = gradient; + } + + @Override + public int getColor(PointInfo resultSet) { + return gradient.get(getIndex(resultSet) % 1); + } + + public abstract float getIndex(PointInfo resultSet); +} diff --git a/src/deepZoom/colorings/SmoothIterationsColoringBad.java b/src/deepZoom/colorings/SmoothIterationsColoringBad.java new file mode 100644 index 0000000..e3cf24d --- /dev/null +++ b/src/deepZoom/colorings/SmoothIterationsColoringBad.java @@ -0,0 +1,37 @@ +package deepZoom.colorings; + +import deepZoom.renderer.PointInfo; + +import digisoft.custom.math.NumberConstants; +import digisoft.custom.swing.gradient.Gradient; +import digisoft.custom.util.geom.DoubleDouble; + +/** + * @author Zom-B + * @since 1.0 + * @date May 1, 2009 + */ +public class SmoothIterationsColoringBad extends GradientColoring { + + private double logLogBailout; + + public SmoothIterationsColoringBad(Gradient gradient) { + super(gradient); + } + + @Override + public void initParameters() { + logLogBailout = StrictMath.log(StrictMath.log(parameters.getBailout())); + } + + @Override + public float getIndex(PointInfo resultSet) { + long i = resultSet.lastIter; + DoubleDouble zx = resultSet.lastZX; + DoubleDouble zy = resultSet.lastZY; + + double r = StrictMath.sqrt(zx.hi * zx.hi + zy.hi * zy.hi); + double c = i - 1.28 + (logLogBailout - StrictMath.log(StrictMath.log(r))) * NumberConstants.Q1LOG2; + return (float) (StrictMath.log(c / 64 + 1) / NumberConstants.LOG2 + 0.45); + } +} diff --git a/src/deepZoom/fractals/Fractal.java b/src/deepZoom/fractals/Fractal.java new file mode 100644 index 0000000..bf006d6 --- /dev/null +++ b/src/deepZoom/fractals/Fractal.java @@ -0,0 +1,29 @@ +package deepZoom.fractals; + +import deepZoom.parameters.Parameters; +import deepZoom.renderer.PointInfo; + +/** + * @author Zom-B + * @since 1.0 + * @date 2009/05/01 + */ +public abstract class Fractal { + + protected Parameters parameters; + + public void setParameters(Parameters parameters) { + this.parameters = parameters; + } + + public abstract void initFrame(); + + /** + * + * @param x + * @param y + * @param result + * float array with {gradient index, last iter} + */ + public abstract void calcPoint(PointInfo pointInfo); +} diff --git a/src/deepZoom/fractals/Mandel.java b/src/deepZoom/fractals/Mandel.java new file mode 100644 index 0000000..d81bb9b --- /dev/null +++ b/src/deepZoom/fractals/Mandel.java @@ -0,0 +1,119 @@ +package deepZoom.fractals; + +import deepZoom.renderer.PointInfo; + +/** + * @author Zom-B + * @since 1.0 + * @date 2009/07/09 + */ +public class Mandel extends Fractal { + + private static final double PRIODICITY_EPS = 1e-17; + + @Override + public void initFrame() { + } + + @Override + public void calcPoint(PointInfo pointInfo) { + double zx; + double zy; + double xx; + double yy; + + double bailout = parameters.getBailout(); + long maxiter = parameters.getMaxiter(); + + // Calculate viewport. + double px = pointInfo.px.hi; + double py = pointInfo.py.hi; + + // Main bulb check. + zx = 4 * (px * px + py * py); + xx = 2 * px; + zy = zx + 4 * xx; + if (zy < -3.75) { + pointInfo.inside = true; + pointInfo.lastIter = maxiter; + pointInfo.lastZX.hi = px; + pointInfo.lastZY.hi = py; + return; + } + + // Cardoid check. + zy = zx - xx + 0.25; + xx = xx + zy - 0.5; + xx *= xx; + if (zy > xx) { + pointInfo.inside = true; + pointInfo.lastIter = maxiter; + pointInfo.lastZX.hi = px; + pointInfo.lastZY.hi = py; + return; + } + + zx = px; + zy = py; + + // Initial maximum period to detect. + int check = 3; + // Maximum period doubles every iterations: + int whenupdate = 10; + // Period history registers. + double hx = 0; + double hy = 0; + + // long int because maxiter goes above 2**31 bits + for (long i = 1; i <= 50000; i++) { + // Precalculate squares. + xx = zx * zx; + yy = zy * zy; + + // Check bailout. + if (xx + yy > bailout) { + pointInfo.inside = false; + pointInfo.lastIter = i; + pointInfo.lastZX.hi = zx; + pointInfo.lastZY.hi = zy; + return; + } + + // Iterate + zy = 2 * zx * zy + py; + zx = xx - yy + px; + + // Periodicity check. + double d = zx - hx; + if (d > 0.0 ? d < Mandel.PRIODICITY_EPS : d > -Mandel.PRIODICITY_EPS) { + d = zy - hy; + if (d > 0.0 ? d < Mandel.PRIODICITY_EPS : d > -Mandel.PRIODICITY_EPS) { + // Period found. + + pointInfo.inside = true; + pointInfo.lastIter = i; // & check + pointInfo.lastZX.hi = zx; + pointInfo.lastZY.hi = zy; + return; + } + } + if ((i & check) == 0) { + if (--whenupdate == 0) { + whenupdate = 10; + check <<= 1; + check++; + } + // period = 0; + hx = zx; + hy = zy; + } + } + + // Maxiter reached. + pointInfo.inside = true; + pointInfo.lastIter = maxiter; + pointInfo.lastZX.hi = zx; + pointInfo.lastZY.hi = zy; + return; + } +} \ No newline at end of file diff --git a/src/deepZoom/fractals/MandelPrecision.java b/src/deepZoom/fractals/MandelPrecision.java new file mode 100644 index 0000000..a6bcd28 --- /dev/null +++ b/src/deepZoom/fractals/MandelPrecision.java @@ -0,0 +1,151 @@ +package deepZoom.fractals; + +import deepZoom.renderer.PointInfo; + +import digisoft.custom.util.geom.DoubleDouble; + +/** + * @author Zom-B + * @since 1.0 + * @date 2009/07/09 + */ +public class MandelPrecision extends Fractal { + + private static final double PRIODICITY_EPS = 1e-17; + + @Override + public void initFrame() { + } + + @Override + public void calcPoint(PointInfo pointInfo) { + DoubleDouble zx = new DoubleDouble(); + DoubleDouble zy = new DoubleDouble(); + DoubleDouble xx = new DoubleDouble(); + DoubleDouble yy = new DoubleDouble(); + DoubleDouble temp = new DoubleDouble(); + + double bailout = parameters.getBailout(); + long maxiter = parameters.getMaxiter(); + + // Calculate viewport. + // DoubleDouble px = this.viewport.getPX(x, y); + // DoubleDouble py = this.viewport.getPY(x, y); + DoubleDouble px = pointInfo.px; + DoubleDouble py = pointInfo.py; + + // Main bulb check. + // zx = 4 * (px * px + py * py); + zy.set(py); + zy.sqrSelf(); + zx.set(px); + zx.sqrSelf(); + zx.addSelf(zy); + zx.mulSelf(4); + // temp = 2 * px + xx.set(px); + xx.mulSelf(2); + // zy = zx + 4 * temp + zy.set(xx); + zy.mulSelf(4); + zy.addSelf(zx); + if (zy.hi < -3.75) { + pointInfo.inside = true; + pointInfo.lastIter = maxiter; + pointInfo.lastZX = px; + pointInfo.lastZY = py; + return; + } + + // Cardoid check. + // zy = zx - temp + 0.25; + zy.set(zx); + zy.subSelf(xx); + zy.addSelf(0.25); + // temp = (temp + zy - 0.5)**2; + xx.addSelf(zy); + xx.addSelf(-0.5); + xx.sqrSelf(); + // if (zy > temp) + if (zy.hi > xx.hi) { + pointInfo.inside = true; + pointInfo.lastIter = maxiter; + pointInfo.lastZX = px; + pointInfo.lastZY = py; + return; + } + + zx.set(px); + zy.set(py); + + // Initial maximum period to detect. + int check = 3; + // Maximum period doubles every iterations: + int whenupdate = 10; + // Period history registers. + double hx = 0; + double hy = 0; + + // long int because maxiter goes above 2**31 bits + for (long i = 1; i <= 50000; i++) { + // Precalculate squares. + xx.set(zx); + xx.sqrSelf(); + yy.set(zy); + yy.sqrSelf(); + + // Check bailout. + temp.set(xx); + temp.addSelf(yy); + if (temp.hi > bailout) { + pointInfo.inside = false; + pointInfo.lastIter = i; + pointInfo.lastZX = zx; + pointInfo.lastZY = zy; + return; + } + + // Iterate + // y' = y * x * 2 + cy + zy.mulSelf(zx); + zy.addSelf(zy); + zy.addSelf(py); + // x' = xx - yy + px + xx.subSelf(yy); + zx.set(xx); + zx.addSelf(px); + + // Periodicity check. + double d = zx.hi - hx; + if (d > 0.0 ? d < MandelPrecision.PRIODICITY_EPS : d > -MandelPrecision.PRIODICITY_EPS) { + d = zy.hi - hy; + if (d > 0.0 ? d < MandelPrecision.PRIODICITY_EPS : d > -MandelPrecision.PRIODICITY_EPS) { + // Period found. + + pointInfo.inside = true; + pointInfo.lastIter = i; // & check + pointInfo.lastZX = zx; + pointInfo.lastZY = zy; + return; + } + } + if ((i & check) == 0) { + if (--whenupdate == 0) { + whenupdate = 10; + check <<= 1; + check++; + } + // period = 0; + hx = zx.hi; + hy = zy.hi; + } + } + + // Maxiter reached. + pointInfo.inside = true; + pointInfo.lastIter = maxiter; + pointInfo.lastZX = zx; + pointInfo.lastZY = zy; + return; + } +} \ No newline at end of file diff --git a/src/deepZoom/parameters/Animation.java b/src/deepZoom/parameters/Animation.java new file mode 100644 index 0000000..5b50b02 --- /dev/null +++ b/src/deepZoom/parameters/Animation.java @@ -0,0 +1,30 @@ +package deepZoom.parameters; + +/** + * Generic animation for fractals. Implementations define which parameters are + * animated, though animation for the following quantities is supported: center, + * magnitude, maxiter and bailout. Before the animation can be calculated, the + * number of frames need also be known beforehand. After changing animation + * parameters or number of frames, the animation needs to be initialized by + * calling init(). + * + * @author Zom-B + * @since 1.0 + * @date May 2, 2009 + */ +public abstract class Animation extends Parameters { + + protected int numFrames; + + public void setNumFrames(int numFrames) { + this.numFrames = numFrames; + } + + /** + * Initialize the animation sequence. Call after each change to + * initial/final parameters or number of frames. + */ + public abstract void init(); + + public abstract void setFrame(int frameNr); +} diff --git a/src/deepZoom/parameters/Parameters.java b/src/deepZoom/parameters/Parameters.java new file mode 100644 index 0000000..939fc4b --- /dev/null +++ b/src/deepZoom/parameters/Parameters.java @@ -0,0 +1,57 @@ +package deepZoom.parameters; + +import digisoft.custom.util.geom.DoubleDouble; + +/** + * @author Zom-B + * @since 1.0 + * @date May 2, 2009 + */ +public class Parameters { + + protected DoubleDouble centerX = new DoubleDouble(); + protected DoubleDouble centerY = new DoubleDouble(); + protected double magn; + protected long maxiter; + protected double bailout; + + public void setCenterX(DoubleDouble centerX) { + this.centerX = centerX; + } + + public DoubleDouble getCenterX() { + return centerX; + } + + public void setCenterY(DoubleDouble centerY) { + this.centerY = centerY; + } + + public DoubleDouble getCenterY() { + return centerY; + } + + public void setMagn(double magn) { + this.magn = magn; + } + + public double getMagn() { + return magn; + } + + public void setMaxiter(long maxiter) { + this.maxiter = maxiter; + } + + public long getMaxiter() { + return maxiter; + } + + public void setBailout(double bailout) { + this.bailout = bailout; + } + + public double getBailout() { + return bailout; + } +} diff --git a/src/deepZoom/parameters/ZoomAnimation.java b/src/deepZoom/parameters/ZoomAnimation.java new file mode 100644 index 0000000..cce050c --- /dev/null +++ b/src/deepZoom/parameters/ZoomAnimation.java @@ -0,0 +1,55 @@ +package deepZoom.parameters; + +/** + * Animation that just zooms. The center parameters and bailout are not + * animated, and the zooming position is the center of the fractal. ie. set the + * center of the fractal to the center of thezoomed frame. The maxiter is also + * animated to account for constant detail with maximum speed throughout the + * animation. For this, the width of the frame in pixels is also required. + * Bailout is also not animated. + * + * @author Zom-B + * @since 1.0 + * @date May 2, 2009 + */ +public class ZoomAnimation extends Animation { + + private int width; + private double magnStart; + private double magnEnd; + private double factorMagn; + + public void setWidth(int width) { + this.width = width; + } + + @Override + public void setNumFrames(int numFrames) { + this.numFrames = numFrames; + } + + public void setMagnStart(double magnStart) { + this.magnStart = magnStart; + } + + public void setMagnEnd(double magnEnd) { + this.magnEnd = magnEnd; + } + + @Override + public void setBailout(double bailout) { + this.bailout = bailout; + } + + @Override + public void init() { + factorMagn = StrictMath.pow(magnEnd / magnStart, 1.0 / (numFrames - 1)); + } + + @Override + public void setFrame(int frameNr) { + magn = magnStart * StrictMath.pow(factorMagn, frameNr - 1); + + maxiter = (long) (width * StrictMath.sqrt(magn)); + } +} diff --git a/src/deepZoom/renderer/Layer.java b/src/deepZoom/renderer/Layer.java new file mode 100644 index 0000000..ea623d9 --- /dev/null +++ b/src/deepZoom/renderer/Layer.java @@ -0,0 +1,28 @@ +package deepZoom.renderer; + +import deepZoom.colorings.Coloring; +import deepZoom.fractals.Fractal; + +/** + * @author Zom-B + * @since 1.0 + * @date May 3, 2009 + */ +public class Layer { + + protected Fractal fractal; + protected Coloring coloring; + + public void setFractal(Fractal fractal) { + this.fractal = fractal; + } + + public void setColoring(Coloring coloring) { + this.coloring = coloring; + } + + public void initFrame() { + fractal.initFrame(); + coloring.initParameters(); + } +} diff --git a/src/deepZoom/renderer/PointInfo.java b/src/deepZoom/renderer/PointInfo.java new file mode 100644 index 0000000..e3ca811 --- /dev/null +++ b/src/deepZoom/renderer/PointInfo.java @@ -0,0 +1,21 @@ +package deepZoom.renderer; + +import digisoft.custom.util.geom.DoubleDouble; + +/** + * @author Zom-B + * @since 1.0 + * @date May 2, 2009 + */ +public class PointInfo { + + public DoubleDouble px; + public DoubleDouble py; + public boolean inside; + public long lastIter; + public DoubleDouble lastZX = new DoubleDouble(); + public DoubleDouble lastZY = new DoubleDouble(); + protected int antialiasFactor; + protected int antialiasReach; + protected int antialiasArea; +} diff --git a/src/deepZoom/renderer/Scene.java b/src/deepZoom/renderer/Scene.java new file mode 100644 index 0000000..1b5a402 --- /dev/null +++ b/src/deepZoom/renderer/Scene.java @@ -0,0 +1,221 @@ +package deepZoom.renderer; + +import deepZoom.schedulers.PriorityPoint; +import deepZoom.schedulers.Scheduler; +import deepZoom.viewports.Viewport; + +import digisoft.custom.awt.Color3f; +import digisoft.custom.awt.Color3fConst; + +/** + * @author Zom-B + * @since 1.0 + * @date May 2, 2009 + */ +public class Scene { + + private Viewport viewport; + private Scheduler scheduler; + private int[] pixels; + private int[] iterMap; + private int[] edgeMap; + private Color3f[] colors; + private int[] mask; + // Multiple layer support unfinished! + private Layer layer; + private int width; + private int height; + private int area = -1; + + public void setViewport(Viewport viewport) { + this.viewport = viewport; + } + + public void setScheduler(Scheduler scheduler) { + this.scheduler = scheduler; + } + + public void setColorPixels(int[] pixels) { + this.pixels = pixels; + } + + public void setIterMap(int[] iterMap) { + this.iterMap = iterMap; + } + + public void setEdgeMap(int[] edgeMap) { + this.edgeMap = edgeMap; + } + + public void addLayer(Layer layer) { + this.layer = layer; + } + + public void initFrame() { + viewport.initParameters(); + layer.initFrame(); + + width = viewport.width; + height = viewport.height; + + if (area != width * height) { + area = width * height; + + colors = new Color3f[area]; + mask = new int[area]; + + for (int i = 0; i < area; i++) { + colors[i] = new Color3f(); + } + } + + for (int i = 0; i < area; i++) { + colors[i].set(0, 0, 0); + } + } + + public void render(PointInfo pointInfo, PriorityPoint point) { + int p = point.x + point.y * width; + + viewport.getPoint(point.x, point.y, pointInfo); + layer.fractal.calcPoint(pointInfo); + int iter = (int) pointInfo.lastIter; + boolean inside = pointInfo.inside; + + iterMap[p] = iter; + edgeMap[p] = inside ? 0 : iter; + + if (!inside) { + colors[p].addSelf(layer.coloring.getColor(pointInfo)); + } + + pixels[p] = colors[p].getRGB(); + } + + public void calcAntialiasMask() { + int p = -1; + for (int y = 0; y < height; y++) { + search: + for (int x = 0; x < width; x++) { + if (x == 0 || y == 0 || x + 1 == width || y + 1 == height) { + mask[++p] = 1; + continue; + } + + mask[++p] = 0; + + int iters = edgeMap[p]; + + for (int v = y - 1; v <= y + 1; v++) { + for (int u = x - 1; u <= x + 1; u++) { + if (u >= 0 && v >= 0 && u < width && v < height) { + int i = StrictMath.abs(edgeMap[u + v * width]); + if (i != iters) { + mask[p] = 1; + continue search; + } + } + } + } + } + } + + p = 0; + for (int y = 0; y < height; y++) { + for (int x = 0; x < width; x++) { + if (mask[p] != 0) { + int i = 0; + for (int v = y - 1; v <= y + 1; v++) { + for (int u = x - 1; u <= x + 1; u++) { + if (u >= 0 && v >= 0 && u < width && v < height) { + int iters = StrictMath.abs(iterMap[u + v * width]); + if (i < iters) { + i = iters; + } + } + } + } + double d = 32 / StrictMath.log(i); + mask[p] = StrictMath.min((int) (d * d), 15); + } + p++; + } + } + + p = 0; + for (int y = 0; y < height; y++) { + for (int x = 0; x < width; x++) { + edgeMap[p] = Color3fConst.DOS_PALETTE[mask[p++] & 0xFF]; + } + } + } + + public void renderAntialias(PointInfo pointInfo, PriorityPoint point) { + int p = point.x + point.y * width; + + if (mask[p] != 0) { + pointInfo.antialiasFactor = 5; + pointInfo.antialiasReach = pointInfo.antialiasFactor / 2; + pointInfo.antialiasArea = pointInfo.antialiasFactor * pointInfo.antialiasFactor; + + calcAntialiasPixel(pointInfo, p, point); + edgeMap[p] = (edgeMap[p] & 0xFCFCFC) >> 2; + + colors[p].scaleSelf(1f / pointInfo.antialiasArea); + pixels[p] = colors[p].getRGB(); + } + } + + private void calcAntialiasPixel(PointInfo pointInfo, int p, PriorityPoint point) { + int reach = pointInfo.antialiasReach; + double factor = 1.0 / pointInfo.antialiasFactor; + for (int x = -reach; x <= reach; x++) { + double dx = x * factor; + for (int y = -reach; y <= reach; y++) { + double dy = y * factor; + + if ((x | y) != 0) { + viewport.getPoint(point.x + dx, point.y + dy, pointInfo); + layer.fractal.calcPoint(pointInfo); + boolean inside = pointInfo.inside; + + if (!inside) { + colors[p].addSelf(layer.coloring.getColor(pointInfo)); + } + } + } + } + } + private PointInfo[] pointInfos; + + public void setNumCPUs(int numCPUs) { + if (pointInfos == null || pointInfos.length != numCPUs) { + pointInfos = new PointInfo[numCPUs]; + for (int cpu = 0; cpu < numCPUs; cpu++) { + pointInfos[cpu] = new PointInfo(); + } + } + } + + public void render(int cpu) { + while (true) { + PriorityPoint point = scheduler.poll(); + if (point == null) { + return; + } + + this.render(pointInfos[cpu], point); + } + } + + public void renderAntialias(int cpu) { + while (true) { + PriorityPoint point = scheduler.poll(); + if (point == null) { + return; + } + + this.renderAntialias(pointInfos[cpu], point); + } + } +} diff --git a/src/deepZoom/schedulers/AngularScheduler.java b/src/deepZoom/schedulers/AngularScheduler.java new file mode 100644 index 0000000..38a6617 --- /dev/null +++ b/src/deepZoom/schedulers/AngularScheduler.java @@ -0,0 +1,32 @@ +package deepZoom.schedulers; + +/** + * @author Zom-B + * @since 1.0 + * @date 2009/05/02 + */ +public class AngularScheduler extends Scheduler { + + private int bands; + + public AngularScheduler(int bands) { + this.bands = bands; + } + + @Override + protected void initImpl() { + super.clear(); + + for (int i = 0; i < numLayers; i++) { + for (int y = 0; y < height; y++) { + double dy = y - (height - 0.875) * 0.5; + for (int x = 0; x < width; x++) { + double dx = x - (width - 0.75) * 0.5; + + double a = StrictMath.abs((StrictMath.atan2(dy, -dx) / (2 * StrictMath.PI) + 0.5) * bands % 1 - 0.5); + add(new PriorityPoint(i, x, y, -a)); + } + } + } + } +} diff --git a/src/deepZoom/schedulers/CRTScheduler.java b/src/deepZoom/schedulers/CRTScheduler.java new file mode 100644 index 0000000..ac53bd0 --- /dev/null +++ b/src/deepZoom/schedulers/CRTScheduler.java @@ -0,0 +1,24 @@ +package deepZoom.schedulers; + +/** + * @author Zom-B + * @since 1.0 + * @date 2009/05/05 + */ +public class CRTScheduler extends Scheduler { + + @Override + protected void initImpl() { + super.clear(); + + for (int i = 0; i < numLayers; i++) { + for (int y = 0; y < height; y++) { + int dy = height - y; + for (int x = 0; x < width; x++) { + int dx = width - x; + add(new PriorityPoint(i, x, y, -x * y * dx * dy)); + } + } + } + } +} diff --git a/src/deepZoom/schedulers/ClockScheduler.java b/src/deepZoom/schedulers/ClockScheduler.java new file mode 100644 index 0000000..e80141c --- /dev/null +++ b/src/deepZoom/schedulers/ClockScheduler.java @@ -0,0 +1,24 @@ +package deepZoom.schedulers; + +/** + * @author Zom-B + * @since 1.0 + * @date 2009/05/02 + */ +public class ClockScheduler extends Scheduler { + + @Override + protected void initImpl() { + super.clear(); + + for (int i = 0; i < numLayers; i++) { + for (int y = 0; y < height; y++) { + double dy = y - (height - 0.875) * 0.5; + for (int x = 0; x < width; x++) { + double dx = x - (width - 0.75) * 0.5; + add(new PriorityPoint(i, x, y, Math.atan2(-dy, -dx))); + } + } + } + } +} diff --git a/src/deepZoom/schedulers/DitherScheduler.java b/src/deepZoom/schedulers/DitherScheduler.java new file mode 100644 index 0000000..e6a1e38 --- /dev/null +++ b/src/deepZoom/schedulers/DitherScheduler.java @@ -0,0 +1,25 @@ +package deepZoom.schedulers; + +/** + * @author Zom-B + * @since 1.0 + * @date 2009/05/03 + */ +public class DitherScheduler extends Scheduler { + + @Override + protected void initImpl() { + super.clear(); + + for (int i = 0; i < numLayers; i++) { + for (int y = 0; y < height; y++) { + int dy = Integer.reverse(y) >>> 16; + for (int x = 0; x < width; x++) { + int dx = Integer.reverse(x) >>> 16; + + add(new PriorityPoint(i, x, y, dx + dy)); + } + } + } + } +} diff --git a/src/deepZoom/schedulers/FlowerScheduler.java b/src/deepZoom/schedulers/FlowerScheduler.java new file mode 100644 index 0000000..66049e3 --- /dev/null +++ b/src/deepZoom/schedulers/FlowerScheduler.java @@ -0,0 +1,36 @@ +package deepZoom.schedulers; + +/** + * @author Zom-B + * @since 1.0 + * @date 2009/05/03 + */ +public class FlowerScheduler extends Scheduler { + + private int petals; + private double petalSize; + + public FlowerScheduler(int petals, double petalSize) { + this.petals = petals; + this.petalSize = 4 / petalSize + 1; + } + + @Override + protected void initImpl() { + super.clear(); + + for (int i = 0; i < numLayers; i++) { + for (int y = 0; y < height; y++) { + double dy = y - (height - 0.875) * 0.5; + for (int x = 0; x < width; x++) { + double dx = x - (width - 0.75) * 0.5; + + double a = StrictMath.atan2(dy, -dx) * petals; + double r = StrictMath.sqrt(dx * dx + dy * dy); + dx = r * (StrictMath.cos(a) + petalSize); + add(new PriorityPoint(i, x, y, dx)); + } + } + } + } +} diff --git a/src/deepZoom/schedulers/ModScheduler.java b/src/deepZoom/schedulers/ModScheduler.java new file mode 100644 index 0000000..fa06d8e --- /dev/null +++ b/src/deepZoom/schedulers/ModScheduler.java @@ -0,0 +1,22 @@ +package deepZoom.schedulers; + +/** + * @author Zom-B + * @since 1.0 + * @date 2009/05/05 + */ +public class ModScheduler extends Scheduler { + + @Override + protected void initImpl() { + super.clear(); + + for (int i = 0; i < numLayers; i++) { + for (int y = 0; y < height; y++) { + for (int x = 0; x < width; x++) { + add(new PriorityPoint(i, x, y, x % (y + 1))); + } + } + } + } +} diff --git a/src/deepZoom/schedulers/PriorityPoint.java b/src/deepZoom/schedulers/PriorityPoint.java new file mode 100644 index 0000000..29a40cc --- /dev/null +++ b/src/deepZoom/schedulers/PriorityPoint.java @@ -0,0 +1,32 @@ +package deepZoom.schedulers; + +/** + * @author Zom-B + * @since 1.0 + * @date 2009/04/17 + */ +public class PriorityPoint implements Comparable { + + public int layer; + public int x; + public int y; + private double priority; + + public PriorityPoint(int layer, int x, int y, double priority) { + this.layer = layer; + this.x = x; + this.y = y; + this.priority = priority; + } + + @Override + public int compareTo(PriorityPoint other) { + double d = priority - other.priority; + return d < 0 ? -1 : d > 0 ? 1 : 0; + } + + @Override + public String toString() { + return this.getClass().getSimpleName() + "[layer " + layer + ", (" + x + ", " + y + ")]"; + } +} diff --git a/src/deepZoom/schedulers/PythagorasScheduler.java b/src/deepZoom/schedulers/PythagorasScheduler.java new file mode 100644 index 0000000..0dbbea5 --- /dev/null +++ b/src/deepZoom/schedulers/PythagorasScheduler.java @@ -0,0 +1,23 @@ +package deepZoom.schedulers; + +/** + * @author Zom-B + * @since 1.0 + * @date 2009/05/03 + */ +public class PythagorasScheduler extends Scheduler { + + @Override + protected void initImpl() { + super.clear(); + + for (int i = 0; i < numLayers; i++) { + for (int y = 0; y < height; y++) { + for (int x = 0; x < width; x++) { + + add(new PriorityPoint(i, x, y, x & y)); + } + } + } + } +} diff --git a/src/deepZoom/schedulers/RadialScheduler.java b/src/deepZoom/schedulers/RadialScheduler.java new file mode 100644 index 0000000..21169b7 --- /dev/null +++ b/src/deepZoom/schedulers/RadialScheduler.java @@ -0,0 +1,26 @@ +package deepZoom.schedulers; + +/** + * @author Zom-B + * @since 1.0 + * @date 2009/04/17 + */ +public class RadialScheduler extends Scheduler { + + @Override + protected void initImpl() { + super.clear(); + + for (int i = 0; i < numLayers; i++) { + for (int y = 0; y < height; y++) { + double dy = y - (height - 0.875) * 0.5; + dy *= dy; + for (int x = 0; x < width; x++) { + double dx = x - (width - 0.75) * 0.5; + + add(new PriorityPoint(i, x, y, dx * dx + dy)); + } + } + } + } +} diff --git a/src/deepZoom/schedulers/RandomScheduler.java b/src/deepZoom/schedulers/RandomScheduler.java new file mode 100644 index 0000000..8579de7 --- /dev/null +++ b/src/deepZoom/schedulers/RandomScheduler.java @@ -0,0 +1,45 @@ +package deepZoom.schedulers; + +import digisoft.custom.NumberFunctions; + +/** + * @author Zom-B + * @since 1.0 + * @date 2009/05/02 + */ +public class RandomScheduler extends Scheduler { + + private int area = -1; + private double[] order; + private int position = 0; + + @Override + protected void initImpl() { + if (area != width * height) { + area = width * height; + + order = new double[area]; + for (int i = 0; i < area; i++) { + order[i] = NumberFunctions.RND.nextDouble(); + } + } + + super.clear(); + + int p = position; + for (int y = 0; y < height; y++) { + for (int x = 0; x < width; x++) { + for (int i = 0; i < numLayers; i++) { + add(new PriorityPoint(i, x, y, order[p])); + } + p = (p + 1) % area; + } + } + } + + @Override + public PriorityPoint poll() { + position = (position + area - 1) % area; + return super.poll(); + } +} diff --git a/src/deepZoom/schedulers/Scheduler.java b/src/deepZoom/schedulers/Scheduler.java new file mode 100644 index 0000000..a0095f7 --- /dev/null +++ b/src/deepZoom/schedulers/Scheduler.java @@ -0,0 +1,43 @@ +package deepZoom.schedulers; + +import java.util.concurrent.PriorityBlockingQueue; + +import deepZoom.viewports.Viewport; +import java.util.PriorityQueue; + +/** + * @author Zom-B + * @since 1.0 + * @date 2009/04/17 + */ +public abstract class Scheduler extends PriorityBlockingQueue { + + protected int numLayers = 1; + protected int width; + protected int height; + private int total; + private Viewport viewport; + + public void setNumLayers(int numLayers) { + this.numLayers = numLayers; + } + + public void setViewport(Viewport viewport) { + this.viewport = viewport; + } + + public void init() { + width = viewport.width; + height = viewport.height; + + initImpl(); + + total = super.size(); + } + + protected abstract void initImpl(); + + public double getProgress() { + return (total - super.size()) / (double) total; + } +} diff --git a/src/deepZoom/schedulers/SimpleScheduler.java b/src/deepZoom/schedulers/SimpleScheduler.java new file mode 100644 index 0000000..30e5232 --- /dev/null +++ b/src/deepZoom/schedulers/SimpleScheduler.java @@ -0,0 +1,23 @@ +package deepZoom.schedulers; + +/** + * @author Zom-B + * @since 1.0 + * @date 2009/05/03 + */ +public class SimpleScheduler extends Scheduler { + + @Override + protected void initImpl() { + super.clear(); + + for (int i = 0; i < numLayers; i++) { + for (int y = 0; y < height; y++) { + int dy = y * width; + for (int x = 0; x < width; x++) { + add(new PriorityPoint(i, x, y, dy + x)); + } + } + } + } +} diff --git a/src/deepZoom/schedulers/SpiralScheduler.java b/src/deepZoom/schedulers/SpiralScheduler.java new file mode 100644 index 0000000..347a828 --- /dev/null +++ b/src/deepZoom/schedulers/SpiralScheduler.java @@ -0,0 +1,33 @@ +package deepZoom.schedulers; + +/** + * @author Zom-B + * @since 1.0 + * @date 2009/05/02 + */ +public class SpiralScheduler extends Scheduler { + + private double thickness; + + public SpiralScheduler(double thickness) { + this.thickness = thickness; + } + + @Override + protected void initImpl() { + super.clear(); + + for (int i = 0; i < numLayers; i++) { + for (int y = 0; y < height; y++) { + double dy = y - (height - 0.875) * 0.5; + for (int x = 0; x < width; x++) { + double dx = x - (width - 0.75) * 0.5; + + double a = StrictMath.atan2(dy, -dx) / (2 * StrictMath.PI); + dx = (int) (a + StrictMath.sqrt(dx * dx + dy * dy) / thickness) * thickness - a; + add(new PriorityPoint(i, x, y, dx)); + } + } + } + } +} diff --git a/src/deepZoom/schedulers/SplitScheduler.java b/src/deepZoom/schedulers/SplitScheduler.java new file mode 100644 index 0000000..b0a00e3 --- /dev/null +++ b/src/deepZoom/schedulers/SplitScheduler.java @@ -0,0 +1,23 @@ +package deepZoom.schedulers; + +/** + * @author Zom-B + * @since 1.0 + * @date 2009/05/03 + */ +public class SplitScheduler extends Scheduler { + + @Override + protected void initImpl() { + super.clear(); + + for (int i = 0; i < numLayers; i++) { + for (int y = 0; y < height; y++) { + int dy = StrictMath.abs(y - (height >> 1)) * width; + for (int x = 0; x < width; x++) { + add(new PriorityPoint(i, x, y, dy + x)); + } + } + } + } +} diff --git a/src/deepZoom/schedulers/SquareSpiralScheduler.java b/src/deepZoom/schedulers/SquareSpiralScheduler.java new file mode 100644 index 0000000..1766dca --- /dev/null +++ b/src/deepZoom/schedulers/SquareSpiralScheduler.java @@ -0,0 +1,37 @@ +package deepZoom.schedulers; + +/** + * @author Zom-B + * @since 1.0 + * @date 2009/05/04 + */ +public class SquareSpiralScheduler extends Scheduler { + + @Override + protected void initImpl() { + super.clear(); + + for (int i = 0; i < numLayers; i++) { + for (int y = 0; y < height; y++) { + int dy = y - (height >> 1); + for (int x = 0; x < width; x++) { + int dx = x - (width >> 1); + + if (dx > dy) { + if (dx < -dy) { + dx = 4 * dy * dy + 7 * dy + 3 + dx; + } else { + dx = 4 * dx * dx + 3 * dx + 1 + dy; + } + } else if (dx < -dy) { + dx = 4 * dx * dx + 1 * dx - 1 - dy; + } else { + dx = 4 * dy * dy + 5 * dy + 1 - dx; + } + + add(new PriorityPoint(i, x, y, dx)); + } + } + } + } +} diff --git a/src/deepZoom/schedulers/XorScheduler.java b/src/deepZoom/schedulers/XorScheduler.java new file mode 100644 index 0000000..eb491b5 --- /dev/null +++ b/src/deepZoom/schedulers/XorScheduler.java @@ -0,0 +1,25 @@ +package deepZoom.schedulers; + +/** + * @author Zom-B + * @since 1.0 + * @date 2009/05/03 + */ +public class XorScheduler extends Scheduler { + + @Override + protected void initImpl() { + super.clear(); + + for (int i = 0; i < numLayers; i++) { + for (int y = 0; y < height; y++) { + int dy = StrictMath.abs(y - (height >> 1)); + for (int x = 0; x < width; x++) { + int dx = StrictMath.abs(x - (width >> 1)); + + add(new PriorityPoint(i, x, y, dx ^ dy)); + } + } + } + } +} diff --git a/src/deepZoom/viewports/Viewport.java b/src/deepZoom/viewports/Viewport.java new file mode 100644 index 0000000..5b9d51d --- /dev/null +++ b/src/deepZoom/viewports/Viewport.java @@ -0,0 +1,73 @@ +package deepZoom.viewports; + +import deepZoom.parameters.Parameters; +import deepZoom.renderer.PointInfo; + +import digisoft.custom.util.geom.DoubleDouble; + +/** + * Mapping from (sub)pixel coordinates to coordinates in the complex plane. + * Don't forget to call init() after changing the input or output configuration. + * + * @author Zom-B + * @since 1.0 + * @date 2009/04/19 + */ +public class Viewport { + // Input configuration. + + public int width; + public int height; + // Output configuration. + private Parameters parameters; + // Internally used values. + private transient DoubleDouble x0d = new DoubleDouble(0); + private transient DoubleDouble x2 = new DoubleDouble(0); + private transient DoubleDouble y1d = new DoubleDouble(0); + private transient DoubleDouble y2 = new DoubleDouble(0); + + public void setSize(int width, int height) { + this.width = width; + this.height = height; + } + + public void setParameters(Parameters parameters) { + this.parameters = parameters; + } + + /** Call each time the viewport or parameters change. */ + public void initParameters() { + x0d.set(4, 0); + x0d.divSelf(parameters.getMagn()); + x0d.divSelf(width); + + x2.set(-2 / parameters.getMagn(), 0); + x2.addSelf(parameters.getCenterX()); + + y1d.set(-4, 0); + y1d.divSelf(parameters.getMagn()); + y1d.divSelf(width); + + y2.set(2 / parameters.getMagn() * height / width, 0); + y2.addSelf(parameters.getCenterY()); + } + + public DoubleDouble getPX(double x, double y) { + DoubleDouble px = new DoubleDouble(x); + px.mulSelf(x0d); + px.addSelf(x2); + return px; + } + + public DoubleDouble getPY(double x, double y) { + DoubleDouble py = new DoubleDouble(y); + py.mulSelf(y1d); + py.addSelf(y2); + return py; + } + + public void getPoint(double x, double y, PointInfo pointInfo) { + pointInfo.px = getPX(x, y); + pointInfo.py = getPY(x, y); + } +} diff --git a/src/digisoft/custom/NumberFunctions.java b/src/digisoft/custom/NumberFunctions.java new file mode 100644 index 0000000..96fb478 --- /dev/null +++ b/src/digisoft/custom/NumberFunctions.java @@ -0,0 +1,224 @@ +package digisoft.custom; + +import java.security.SecureRandom; +import java.text.DecimalFormat; +import java.util.Arrays; +import java.util.Random; + +/** + * @author Zom-B + * @since 1.0 + * @date 2007/11/16 + */ +public class NumberFunctions { + + private static final String ZEROES = "0000000000000000000000000000000000000000000000000000000000000000"; + private static SecureRandom secureRnd = null; + public static final Random RND = new Random(); + public static final DecimalFormat COMMA_NUMBER = new DecimalFormat("#,###"); + + public static String toStringFixedLength(int i, int len) { + String out = Integer.toString(i); + return NumberFunctions.ZEROES.substring(out.length(), len) + out; + } + + public static String toStringFixedLength(long i, int len) { + String out = Long.toString(i); + return NumberFunctions.ZEROES.substring(out.length(), len) + out; + } + + public static String toStringFixedLength(int i, int base, int len) { + String out = Long.toString(i & 0xFFFFFFFFL, base); + + if (base > 10) { + return NumberFunctions.ZEROES.substring(out.length(), len) + out.toUpperCase(); + } + return NumberFunctions.ZEROES.substring(out.length(), len) + out; + } + + public static String toStringFixedLength(long i, int base, int len) { + String out = Long.toString(i, base); + + if (base > 10) { + return NumberFunctions.ZEROES.substring(out.length(), len) + out.toUpperCase(); + } + return NumberFunctions.ZEROES.substring(out.length(), len) + out; + } + + public static Random getSecureRandom() { + if (NumberFunctions.secureRnd == null) { + NumberFunctions.secureRnd = new SecureRandom(); + } + return NumberFunctions.secureRnd; + } + + /** + * Find primes by recording a list with some proven non-prime numbers + * (NPNs). If the NPNs are chosen carefully, the gaps between the non-prime + * numbers will be prime numbers.
+ * The NPNs are chosen by calculating rectangles with an area which is an + * odd number. The length is stepped through every odd number in the range [ + * 3, sqrt(guess)]. For every length, the height is + * stepped through such numbers (also odd numbers) so the area will stay + * within the range [guess-gapSize, guess). When the + * largest gap between any two successive successive prime numbers p1 and p2 + * (gap=|p2-p1|) lower than guess is smaller or equal to + * gapSize, the result will be a prime number deterministically.
+ *
+ * Warning: Do not use this routine as-is for finding a random prime number + * pn for any guess with equal distribution of n. The difference + * in gaps between successive prime numbers causes the distribution to bias + * greatly. Use findRandomPrime instead. + * + * @param guess + * an initial guess + * @return the largest prime smaller than or equal to guess + * @since 1.0 + * @see NumberFunctions#findRandomPrime(int, int) + * @see http://www.trnicely.net/ + */ + public static int findPrimeNear(int guess) { + // Make it an odd number. + if ((guess & 1) == 0) { + guess--; + } + + // Find largest gap + int maxGap; + if (guess <= 523) { + // Minimum gap for <7 bits. (closest was 9.030667136 bits) + maxGap = 14; + } else if (guess <= 155921) { + // Minimum gap for <15 bits. (closest was 17.25045573 bits) + maxGap = 72; + } else if (guess <= 2147437599) // Magic number? see else block. + { + // Minimum gap for <31 bits. (closest was 31.09957781 bits) + maxGap = 292; + } else { + throw new IllegalArgumentException("guess+floor(sqrt(guess))-292 should be below 2^31-1, so guess should be below 2147437600"); + } + int halfGap = maxGap >> 1; + + // The list is compressed and reversed. (ie. index 0 is the guess, 1 is + // guess-2, etc.) + boolean[] primes = new boolean[halfGap]; + Arrays.fill(primes, true); + + int halfway = (int) StrictMath.sqrt(guess); + int minGap = guess - maxGap; + + // fill the array with nonprimes + for (int i = 3; i <= halfway; i += 2) { + int max = guess / i; + int min = (minGap + i) / i; + if ((min & 1) == 0) { + min++; + } + for (int j = min; j <= max; j += 2) { + int nonPrime = j * i; + int index = guess - nonPrime >> 1; + if (index >= 0) { + primes[index] = false; + } + } + } + + // Find the highest prime number in the list. + for (int a = 0; a < halfGap; a++) { + if (primes[a]) { + return guess - (a << 1); + } + } + throw new IllegalStateException("gap too small"); + } + + /** + * Find primes by recording a list with some proven non-prime numbers + * (NPNs). If the NPNs are chosen carefully, the gaps between the non-prime + * numbers will be prime numbers.
+ * The NPNs are chosen by calculating rectangles with an area which is an + * odd number. The length is stepped through every odd number in the range [ + * 3, sqrt(guess)]. For every length, the height is + * stepped through such numbers (also odd numbers) so the area will stay + * within the range [guess-gapSize, guess). When the + * largest gap between any two successive successive prime numbers p1 and p2 + * (gap=|p2-p1|) lower than guess is smaller or equal to + * gapSize, the result will be a prime number deterministically.
+ *
+ * Warning: Do not use this routine as-is for finding a random prime number + * pn for any guess with equal distribution of n. The difference + * in gaps between successive prime numbers causes the distribution to bias + * greatly. Use findRandomPrime instead. + * + * @param guess + * an initial guess + * @return the largest prime smaller than or equal to guess + * @since 1.0 + * @see NumberFunctions#findRandomPrime(int, int) + * @see http://www.trnicely.net/ + */ + public static long findPrimeNear(long guess) { + // Make it an odd number. + if ((guess & 1) == 0) { + guess--; + } + + // Find largest gap + int maxGap; + if (guess <= 2147437600) {// Delegate to a faster function. + return NumberFunctions.findPrimeNear((int) guess); + } else if (guess <= 2300942549L) { + // Minimum gap for <31 bits. (closest was 31.10 bits) + maxGap = 292; + } else if (guess <= 9223372033817776756L) // Magic number? see else block. + { + // There is known gap yet for <63 bits, so I'm using the next known + // gap (85.90 bits) + maxGap = 1448; + } else { + throw new IllegalArgumentException("guess+floor(sqrt(guess))-1448 should be below 2^63-1, so guess should be below 9223372033817776757"); + } + int halfGap = maxGap >> 1; + + // The list is compressed and reversed. (ie. index 0 is the guess, 1 is + // guess-2, etc.) + boolean[] primes = new boolean[halfGap]; + Arrays.fill(primes, true); + + long halfway = (long) StrictMath.sqrt(guess); + long minGap = guess - maxGap; + + // fill the array with nonprimes + for (long i = 3; i <= halfway; i += 2) { + long max = guess / i; + long min = (minGap + i) / i; + if ((min & 1) == 0) { + min++; + } + for (long j = min; j <= max; j += 2) { + long nonPrime = j * i; + int index = (int) (guess - nonPrime) >> 1; + if (index >= 0) { + primes[index] = false; + } + } + } + + // Find the highest prime number in the list. + for (int a = 0; a < halfGap; a++) { + if (primes[a]) { + return guess - (a << 1); + } + } + throw new IllegalStateException("gap too small"); + } + + public static int factorial(int v) { + int out = 1; + for (int i = 2; i <= v; i++) { + out *= i; + } + return out; + } +} diff --git a/src/digisoft/custom/awt/Color3f.java b/src/digisoft/custom/awt/Color3f.java new file mode 100644 index 0000000..13c5cf6 --- /dev/null +++ b/src/digisoft/custom/awt/Color3f.java @@ -0,0 +1,534 @@ +package digisoft.custom.awt; + +import java.awt.Color; + +/** + * @author Zom-B + * @since 1.0 + * @date 2005/10/03 + */ +public class Color3f { + + private static final float MIN_CLIP_LEVEL = -0.003921568627450980392156862745098f; + private static final float MAX_CLIP_LEVEL = 1.003921568627450980392156862745098f; + public float r; + public float g; + public float b; + + /** + * Create the color opaque black + */ + public Color3f() { + this(0f, 0f, 0f); + } + + /** + * Create an opaque color from packed RGB triple + * + * @param i + * @since 1.0 + */ + public Color3f(int i) { + b = (i & 0xFF) / 255f; + g = ((i >>= 8) & 0xFF) / 255f; + r = (i >> 8 & 0xFF) / 255f; + } + + /** + * Create an opaque color defined gray shade + * + * @param i + * @since 1.0 + */ + public Color3f(float i) { + this(i, i, i); + } + + /** + * Create an opaque defined color + * + * @param r + * @param g + * @param b + */ + public Color3f(float r, float g, float b) { + this.r = r; + this.g = g; + this.b = b; + } + + /** + * Create an opaque defined color + * + * @param r + * @param g + * @param b + */ + public Color3f(int r, int g, int b) { + this.r = r / 255f; + this.g = g / 255f; + this.b = b / 255f; + } + + /** + * @param color + * @since 1.0 + */ + public Color3f(Color color) { + r = color.getRed() / 255f; + g = color.getGreen() / 255f; + b = color.getBlue() / 255f; + } + + /** + * @param color + * @since 1.0 + */ + public Color3f(Color3f color) { + r = color.r; + g = color.g; + b = color.b; + } + + public void set(Color3f c) { + r = c.r; + g = c.g; + b = c.b; + } + + public void set(int r, int g, int b) { + this.r = r; + this.g = g; + this.b = b; + } + + public float getGrayValue() { + return 0.299f * r + 0.587f * g + 0.114f * b; + } + + public void addSelf(int i) { + b += (i & 0xFF) / 255f; + g += ((i >>= 8) & 0xFF) / 255f; + r += (i >> 8 & 0xFF) / 255f; + } + + public Color3f scale(float f) { + return new Color3f(r * f, g * f, b * f); + } + + public void scaleSelf(float f) { + r *= f; + g *= f; + b *= f; + } + + public Color3f interpolateLinear(Color3f c, float f) { + return new Color3f( // + r + (c.r - r) * f, // + g + (c.g - g) * f, // + b + (c.b - b) * f); + } + + public void interpolateLinearSelf(Color3f c, float f) { + r = r + (c.r - r) * f; + g = g + (c.g - g) * f; + b = b + (c.b - b) * f; + } + + public Color3f gamma(float gammaFactor) { + return new Color3f( // + (float) Math.pow(r, gammaFactor), // + (float) Math.pow(g, gammaFactor), // + (float) Math.pow(b, gammaFactor)); + } + + /** + * Converts the components of this color, as specified by the HSB model, to + * an equivalent set of values for the default RGB model. + *

+ * The saturation and brightness components should + * be floating-point values between zero and one (numbers in the range + * 0.0-1.0). The hue component can be any floating-point + * number. The floor of this number is subtracted from it to create a + * fraction between 0 and 1. This fractional number is then virtually + * multiplied by 360 to produce the hue angle in the HSB color model. + *

+ * + * @param hsb + * the Color3f containing the components hue, saturation, + * brightness and alpha in the fields of red, green, blue and + * alpha, respectively + * @return the Color3f with the RGB value of the color with the indicated + * hue, saturation, brightness and alpha. + * + * @see java.awt.Color#HSB2RGB(float, float, float) + * @see java.awt.Color#getRGB() + * @see java.awt.Color#Color(int) + * @see java.awt.image.ColorModel#getRGBdefault() + * @since 1.0 + */ + public Color3f hsb2Rgb() { + if (g == 0) { + return new Color3f(b, b, b); + } + Color3f out = new Color3f(0, 0, 0); + float hue6 = (r - (float) Math.floor(r)) * 6; + float hue_f = hue6 - (float) java.lang.Math.floor(hue6); + float p = b * (1 - g); + switch ((int) hue6) { + case 0: + case 6: { + out.r = b; + out.g = b * (1 - g * (1 - hue_f)); + out.b = p; + break; + } + case 1: { + out.r = b * (1 - g * hue_f); + out.g = b; + out.b = p; + break; + } + case 2: { + out.r = p; + out.g = b; + out.b = b * (1 - g * (1 - hue_f)); + break; + } + case 3: { + out.r = p; + out.g = b * (1 - g * hue_f); + out.b = b; + } + break; + case 4: { + out.r = b * (1 - g * (1 - hue_f)); + out.g = p; + out.b = b; + break; + } + case 5: { + out.r = b; + out.g = p; + out.b = b * (1 - g * hue_f); + } + } + return out; + } + + /** + * Converts the components of this color, as specified by the default RGB + * model, to an equivalent set of values for hue, saturation, and brightness + * that are the three components of the HSB model. + * + * @see java.awt.Color#RGB2HSB(int, int, int, float[]) + * @see java.awt.Color#getRGB() + * @see java.awt.Color#Color(int) + * @see java.awt.image.ColorModel#getRGBdefault() + * @since JDK1.0 + */ + public Color3f rgb2Hsb() { + float cmax = r > g ? r : g; + if (b > cmax) { + cmax = b; + } + float cmin = r < g ? r : g; + if (b < cmin) { + cmin = b; + } + float dist = cmax - cmin; + + Color3f out = new Color3f(0f, 0f, 0f); + + out.b = cmax; + out.g = cmax != 0 ? dist / cmax : 0; + + if (out.g == 0) { + out.r = 0; + } else { + if (r == cmax) { + if (g >= b) { + out.r = (g - b) / dist; + } else { + out.r = 6.0f + (g - b) / dist; + } + } else if (g == cmax) { + out.r = 2.0f + (b - r) / dist; + } else { + out.r = 4.0f + (r - g) / dist; + } + out.r /= 6.0f; + } + return out; + } + + /** + * Converts the components of this color, as specified by the default RGB + * model, to an equivalent set of values for hue, saturation, and brightness + * that are the three components of the HSB model. + * + * @see java.awt.Color#RGB2HSB(int, int, int, float[]) + * @see java.awt.Color#getRGB() + * @see java.awt.Color#Color(int) + * @see java.awt.image.ColorModel#getRGBdefault() + * @since JDK1.0 + */ + public void rgb2HsbSelf() { + float cmax = r > g ? r : g; + if (b > cmax) { + cmax = b; + } + float cmin = r < g ? r : g; + if (b < cmin) { + cmin = b; + } + float dist = cmax - cmin; + + float g = cmax != 0 ? dist / cmax : 0; + + if (g == 0) { + r = 0; + } else { + if (r == cmax) { + if (this.g >= b) { + r = (this.g - b) / dist; + } else { + r = 6.0f + (this.g - b) / dist; + } + } else if (this.g == cmax) { + r = 2.0f + (b - r) / dist; + } else { + r = 4.0f + (r - this.g) / dist; + } + r /= 6.0f; + } + b = cmax; + this.g = g; + } + + /** + * Convert RGB to YPbPr (the floating point version of YCbCr). + * + * @return R=Y in [0, 1]; G=Pb in [-0.5 0.5]; B=Pr in [-0.5 0.5] + * @since 1.0 + */ + public Color3f rgb2YPbPr() { + return new Color3f( // + +0.29900000000000000000f * r + 0.58700000000000000000f * g + 0.114000000000000000000f * b, // + -0.16873589164785553047f * r - 0.33126410835214446952f * g + 0.500000000000000000000f * b, // + +0.50000000000000000000f * r - 0.41868758915834522111f * g - 0.081312410841654778888f * b); + } + + /** + * Convert RGB to YPbPr (the floating point version of YCbCr). + * + * @return R=Y in [0, 1]; G=Pb in [-0.5 0.5]; B=Pr in [-0.5 0.5] + * @since 1.0 + */ + public void rgb2YPbPrSelf() { + float r = +0.29900000000000000000f * this.r + 0.58700000000000000000f * g + 0.114000000000000000000f * b; + float g = -0.16873589164785553047f * this.r - 0.33126410835214446952f * this.g + 0.500000000000000000000f * b; + b = +0.50000000000000000000f * this.r - 0.41868758915834522111f * this.g - 0.081312410841654778888f * b; + this.r = r; + this.g = g; + } + + /** + * Convert YPbPr (the floating point version of YCbCr) to RGB. Inputs: R=Y + * in [0 1]; G=Pb in [-0.5 0.5]; B=Pr in [-0.5 0.5] + * + * @return RGB colors + * @since 1.0 + */ + public Color3f tPbPr2Rgb() { + return new Color3f( // + r /* ***************************** */ + 1.40200000000000000000f * b, // + r - 0.34413628620102214650f * g - 0.71413628620102214645f * b, // + r + 1.77200000000000000000f * g /* + * ********************** + * ****** + */); + } + + /** + * Convert RGB to YUV (the colorspace used by PAL TV). + * + * @return R=Y in [0, 1]; G=U in [-0.5 0.5]; B=V in [-0.5 0.5] + * @since 1.0 + */ + public Color3f rgb2Yuv() { + return new Color3f( // + +0.29900000000000000000f * r + 0.58700000000000000000f * g + 0.11400000000000000000f * b, // + -0.14713769751693002257f * r - 0.28886230248306997742f * g + 0.43600000000000000000f * b, // + +0.61500000000000000000f * r - 0.51498573466476462197f * g - 0.10001426533523537803f * b); + } + + /** + * Convert YUV (the colorspace used in PAL TV) to RGB. Inputs: R=Y in [0 1]; + * G=U in [-0.5 0.5]; B=V in [-0.5 0.5] + * + * @return RGB colors + * @since 1.0 + */ + public Color3f yuv2Rgb() { + return new Color3f( // + r /* ***************************** */ + 1.13983739837398373980f * b, // + r - 0.39465170435897035149f * g - 0.58059860666749768007f * b, // + r + 2.03211009174311926600f * g /* + * ********************** + * ****** + */); + } + + /** + * Convert RGB to YUV (the colorspace used by PAL TV). + * + * @return R=Y in [0, 1]; G=U in [-0.5 0.5]; B=V in [-0.5 0.5] + * @since 1.0 + */ + public Color3f rgb2YiQ() { + return new Color3f( // + +0.29900000000000000000f * r + 0.58700000000000000000f * g + 0.11400000000000000000f * b, // + +0.59571613491277455268f * r - 0.27445283783925646357f * g - 0.32126329707351808911f * b, // + +0.21145640212011786639f * r - 0.52259104529161116836f * g + 0.31113464317149330198f * b); + } + + /** + * Convert YIQ (the colorspace used in NTSC TV) to RGB. Inputs: R=Y in [0 + * 1]; G=I in [-0.5 0.5]; B=Q in [-0.5 0.5] + * + * @return RGB colors + * @since 1.0 + */ + public Color3f yiq2Rgb() { + return new Color3f( // + r + 0.95629483232089399045f * g + 0.62102512544472871408f * b, // + r - 0.27212147408397731948f * g - 0.64738095351761572226f * b, // + r - 1.10698990856712821590f * g + 1.70461497549882932850f * b); + } + + /** + * Convert RGB to XYZ (the CIE 1931 color space). + * + * @return R=Y in [0, 1]; G=U in [0 1]; B=V in [0 1] + * @since 1.0 + */ + public Color3f rgb2Xyz() { + return new Color3f( // + +0.43030294260923249074f * r + 0.34163640134469669562f * g + 0.17822777850125160973f * b, // + +0.22187495478288550304f * r + 0.70683393381661385301f * g + 0.071291111400500643890f * b, // + +0.020170450434807773004f * r + 0.12958622119971253972f * g + 0.93866630010659181124f * b); + } + + /** + * Convert XYZ (the CIE 1931 color space) to RGB. Inputs: R=X in [0 1]; G=Y + * in [0 1]; B=z in [0 1] + * + * @return RGB colors + * @since 1.0 + */ + public Color3f xyz2Rgb() { + return new Color3f( // + +2.0608465608465608465f * r - 0.93738977072310405639f * g - 0.32010582010582010580f * b, // + -1.1415343915343915346f * r + 2.2094356261022927693f * g + 0.048941798941798941806f * b, // + +0.080687830687830687828f * r - 0.27204585537918871252f * g + 1.2711640211640211641f * b); + } + + public Color3f clip() { + float ra = r; + float ga = g; + float ba = b; + + if (ra < 0) { + ra = 0; + } else if (ra > 1) { + ra = 1; + } + if (ga < 0) { + ga = 0; + } else if (ga > 1) { + ga = 1; + } + if (ba < 0) { + ba = 0; + } else if (ba > 1) { + ba = 1; + } + + return new Color3f(ra, ga, ba); + } + + public Color3f showClip() { + if (r < Color3f.MIN_CLIP_LEVEL || r > Color3f.MAX_CLIP_LEVEL || g < Color3f.MIN_CLIP_LEVEL || g > Color3f.MAX_CLIP_LEVEL || b < Color3f.MIN_CLIP_LEVEL + || b > Color3f.MAX_CLIP_LEVEL) { + return new Color3f(0.5f, 0.5f, 0.5f); + } + return this; + } + + public boolean isClipping() { + return r < Color3f.MIN_CLIP_LEVEL || r > Color3f.MAX_CLIP_LEVEL || g < Color3f.MIN_CLIP_LEVEL || g > Color3f.MAX_CLIP_LEVEL + || b < Color3f.MIN_CLIP_LEVEL || b > Color3f.MAX_CLIP_LEVEL; + } + + /** + * Converts this color to a color understood by the java.awt package. + * + * @return an instance of java.awt.Color with the color attributes clamped + * to {black,white} + * @see java.awt.Color + * @since 1.0 + */ + public Color toColor() { + float ra = r; + float ga = g; + float ba = b; + + if (ra < 0) { + ra = 0; + } else if (ra > 1) { + ra = 1; + } + if (ga < 0) { + ga = 0; + } else if (ga > 1) { + ga = 1; + } + if (ba < 0) { + ba = 0; + } else if (ba > 1) { + ba = 1; + } + + return new java.awt.Color(ra, ga, ba); + } + + public int getRGB() { + int ra = (int) (r * 255 + 0.5); + int ga = (int) (g * 255 + 0.5); + int ba = (int) (b * 255 + 0.5); + + if (ra < 0) { + ra = 0; + } else if (ra > 255) { + ra = 255; + } + if (ga < 0) { + ga = 0; + } else if (ga > 255) { + ga = 255; + } + if (ba < 0) { + ba = 0; + } else if (ba > 255) { + ba = 255; + } + + return ba + (ga + (ra << 8) << 8); + } + + @Override + public String toString() { + return super.getClass().getSimpleName() + "[" + r + ", " + g + ", " + b + "]"; + } +} diff --git a/src/digisoft/custom/awt/Color3fConst.java b/src/digisoft/custom/awt/Color3fConst.java new file mode 100644 index 0000000..37ae8af --- /dev/null +++ b/src/digisoft/custom/awt/Color3fConst.java @@ -0,0 +1,184 @@ +package digisoft.custom.awt; + +import digisoft.custom.NumberFunctions; + +/** + * @author Zom-B + * @since 1.0 + * @date 2009/04/16 + */ +public class Color3fConst { + + public static void main(String[] args) { + int p = 0; + for (int i = 0; i < 32; i++) { + for (int j = 0; j < 8; j++) { + Color3f c = new Color3f(Color3fConst.DOS_PALETTE[p++]); + System.out.print("0x" + NumberFunctions.toStringFixedLength(c.getRGB(), 16, 6) + ", "); + } + System.out.println(" //"); + } + } + public static final int[] DOS_PALETTE = {0x000000, 0x0000AA, 0x00AA00, 0x00AAAA, 0xAA0000, 0xAA00AA, 0xAA5500, 0xAAAAAA, // + 0x555555, 0x5555FF, 0x55FF55, 0x55FFFF, 0xFF5555, 0xFF55FF, 0xFFFF55, 0xFFFFFF, // + 0x000000, 0x141414, 0x202020, 0x2C2C2C, 0x383838, 0x454545, 0x515151, 0x616161, // + 0x717171, 0x828282, 0x929292, 0xA2A2A2, 0xB6B6B6, 0xCBCBCB, 0xE3E3E3, 0xFFFFFF, // + 0x0000FF, 0x4100FF, 0x7D00FF, 0xBE00FF, 0xFF00FF, 0xFF00BE, 0xFF007D, 0xFF0041, // + 0xFF0000, 0xFF4100, 0xFF7D00, 0xFFBE00, 0xFFFF00, 0xBEFF00, 0x7DFF00, 0x41FF00, // + 0x00FF00, 0x00FF41, 0x00FF7D, 0x00FFBE, 0x00FFFF, 0x00BEFF, 0x007DFF, 0x0041FF, // + 0x7D7DFF, 0x9E7DFF, 0xBE7DFF, 0xDF7DFF, 0xFF7DFF, 0xFF7DDF, 0xFF7DBE, 0xFF7D9E, // + 0xFF7D7D, 0xFF9E7D, 0xFFBE7D, 0xFFDF7D, 0xFFFF7D, 0xDFFF7D, 0xBEFF7D, 0x9EFF7D, // + 0x7DFF7D, 0x7DFF9E, 0x7DFFBE, 0x7DFFDF, 0x7DFFFF, 0x7DDFFF, 0x7DBEFF, 0x7D9EFF, // + 0xB6B6FF, 0xC7B6FF, 0xDBB6FF, 0xEBB6FF, 0xFFB6FF, 0xFFB6EB, 0xFFB6DB, 0xFFB6C7, // + 0xFFB6B6, 0xFFC7B6, 0xFFDBB6, 0xFFEBB6, 0xFFFFB6, 0xEBFFB6, 0xDBFFB6, 0xC7FFB6, // + 0xB6FFB6, 0xB6FFC7, 0xB6FFDB, 0xB6FFEB, 0xB6FFFF, 0xB6EBFF, 0xB6DBFF, 0xB6C7FF, // + 0x000071, 0x1C0071, 0x380071, 0x550071, 0x710071, 0x710055, 0x710038, 0x71001C, // + 0x710000, 0x711C00, 0x713800, 0x715500, 0x717100, 0x557100, 0x387100, 0x1C7100, // + 0x007100, 0x00711C, 0x007138, 0x007155, 0x007171, 0x005571, 0x003871, 0x001C71, // + 0x383871, 0x453871, 0x553871, 0x613871, 0x713871, 0x713861, 0x713855, 0x713845, // + 0x713838, 0x714538, 0x715538, 0x716138, 0x717138, 0x617138, 0x557138, 0x457138, // + 0x387138, 0x387145, 0x387155, 0x387161, 0x387171, 0x386171, 0x385571, 0x384571, // + 0x515171, 0x595171, 0x615171, 0x695171, 0x715171, 0x715169, 0x715161, 0x715159, // + 0x715151, 0x715951, 0x716151, 0x716951, 0x717151, 0x697151, 0x617151, 0x597151, // + 0x517151, 0x517159, 0x517161, 0x517169, 0x517171, 0x516971, 0x516171, 0x515971, // + 0x000041, 0x100041, 0x200041, 0x300041, 0x410041, 0x410030, 0x410020, 0x410010, // + 0x410000, 0x411000, 0x412000, 0x413000, 0x414100, 0x304100, 0x204100, 0x104100, // + 0x004100, 0x004110, 0x004120, 0x004130, 0x004141, 0x003041, 0x002041, 0x001041, // + 0x202041, 0x282041, 0x302041, 0x382041, 0x412041, 0x412038, 0x412030, 0x412028, // + 0x412020, 0x412820, 0x413020, 0x413820, 0x414120, 0x384120, 0x304120, 0x284120, // + 0x204120, 0x204128, 0x204130, 0x204138, 0x204141, 0x203841, 0x203041, 0x202841, // + 0x2C2C41, 0x302C41, 0x342C41, 0x3C2C41, 0x412C41, 0x412C3C, 0x412C34, 0x412C30, // + 0x412C2C, 0x41302C, 0x41342C, 0x413C2C, 0x41412C, 0x3C412C, 0x34412C, 0x30412C, // + 0x2C412C, 0x2C4130, 0x2C4134, 0x2C413C, 0x2C4141, 0x2C3C41, 0x2C3441, 0x2C3041, // + 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, // + 0x000000}; + public static final Color3f[] DOS_COLORS = {new Color3f(0.0f, 0.0f, 0.0f), new Color3f(0.0f, 0.0f, 0.6666667f), // + new Color3f(0.0f, 0.6666667f, 0.0f), new Color3f(0.0f, 0.6666667f, 0.6666667f), // + new Color3f(0.6666667f, 0.0f, 0.0f), new Color3f(0.6666667f, 0.0f, 0.6666667f), // + new Color3f(0.6666667f, 0.33333334f, 0.0f), new Color3f(0.6666667f, 0.6666667f, 0.6666667f), // + new Color3f(0.33333334f, 0.33333334f, 0.33333334f), new Color3f(0.33333334f, 0.33333334f, 1.0f), // + new Color3f(0.33333334f, 1.0f, 0.33333334f), new Color3f(0.33333334f, 1.0f, 1.0f), // + new Color3f(1.0f, 0.33333334f, 0.33333334f), new Color3f(1.0f, 0.33333334f, 1.0f), // + new Color3f(1.0f, 1.0f, 0.33333334f), new Color3f(1.0f, 1.0f, 1.0f), // + new Color3f(0.0f, 0.0f, 0.0f), new Color3f(0.078431375f, 0.078431375f, 0.078431375f), // + new Color3f(0.1254902f, 0.1254902f, 0.1254902f), new Color3f(0.17254902f, 0.17254902f, 0.17254902f), // + new Color3f(0.21960784f, 0.21960784f, 0.21960784f), new Color3f(0.27058825f, 0.27058825f, 0.27058825f), // + new Color3f(0.31764707f, 0.31764707f, 0.31764707f), new Color3f(0.38039216f, 0.38039216f, 0.38039216f), // + new Color3f(0.44313726f, 0.44313726f, 0.44313726f), new Color3f(0.50980395f, 0.50980395f, 0.50980395f), // + new Color3f(0.57254905f, 0.57254905f, 0.57254905f), new Color3f(0.63529414f, 0.63529414f, 0.63529414f), // + new Color3f(0.7137255f, 0.7137255f, 0.7137255f), new Color3f(0.79607844f, 0.79607844f, 0.79607844f), // + new Color3f(0.8901961f, 0.8901961f, 0.8901961f), new Color3f(1.0f, 1.0f, 1.0f), // + new Color3f(0.0f, 0.0f, 1.0f), new Color3f(0.25490198f, 0.0f, 1.0f), // + new Color3f(0.49019608f, 0.0f, 1.0f), new Color3f(0.74509805f, 0.0f, 1.0f), // + new Color3f(1.0f, 0.0f, 1.0f), new Color3f(1.0f, 0.0f, 0.74509805f), // + new Color3f(1.0f, 0.0f, 0.49019608f), new Color3f(1.0f, 0.0f, 0.25490198f), // + new Color3f(1.0f, 0.0f, 0.0f), new Color3f(1.0f, 0.25490198f, 0.0f), // + new Color3f(1.0f, 0.49019608f, 0.0f), new Color3f(1.0f, 0.74509805f, 0.0f), // + new Color3f(1.0f, 1.0f, 0.0f), new Color3f(0.74509805f, 1.0f, 0.0f), // + new Color3f(0.49019608f, 1.0f, 0.0f), new Color3f(0.25490198f, 1.0f, 0.0f), // + new Color3f(0.0f, 1.0f, 0.0f), new Color3f(0.0f, 1.0f, 0.25490198f), // + new Color3f(0.0f, 1.0f, 0.49019608f), new Color3f(0.0f, 1.0f, 0.74509805f), // + new Color3f(0.0f, 1.0f, 1.0f), new Color3f(0.0f, 0.74509805f, 1.0f), // + new Color3f(0.0f, 0.49019608f, 1.0f), new Color3f(0.0f, 0.25490198f, 1.0f), // + new Color3f(0.49019608f, 0.49019608f, 1.0f), new Color3f(0.61960787f, 0.49019608f, 1.0f), // + new Color3f(0.74509805f, 0.49019608f, 1.0f), new Color3f(0.8745098f, 0.49019608f, 1.0f), // + new Color3f(1.0f, 0.49019608f, 1.0f), new Color3f(1.0f, 0.49019608f, 0.8745098f), // + new Color3f(1.0f, 0.49019608f, 0.74509805f), new Color3f(1.0f, 0.49019608f, 0.61960787f), // + new Color3f(1.0f, 0.49019608f, 0.49019608f), new Color3f(1.0f, 0.61960787f, 0.49019608f), // + new Color3f(1.0f, 0.74509805f, 0.49019608f), new Color3f(1.0f, 0.8745098f, 0.49019608f), // + new Color3f(1.0f, 1.0f, 0.49019608f), new Color3f(0.8745098f, 1.0f, 0.49019608f), // + new Color3f(0.74509805f, 1.0f, 0.49019608f), new Color3f(0.61960787f, 1.0f, 0.49019608f), // + new Color3f(0.49019608f, 1.0f, 0.49019608f), new Color3f(0.49019608f, 1.0f, 0.61960787f), // + new Color3f(0.49019608f, 1.0f, 0.74509805f), new Color3f(0.49019608f, 1.0f, 0.8745098f), // + new Color3f(0.49019608f, 1.0f, 1.0f), new Color3f(0.49019608f, 0.8745098f, 1.0f), // + new Color3f(0.49019608f, 0.74509805f, 1.0f), new Color3f(0.49019608f, 0.61960787f, 1.0f), // + new Color3f(0.7137255f, 0.7137255f, 1.0f), new Color3f(0.78039217f, 0.7137255f, 1.0f), // + new Color3f(0.85882354f, 0.7137255f, 1.0f), new Color3f(0.92156863f, 0.7137255f, 1.0f), // + new Color3f(1.0f, 0.7137255f, 1.0f), new Color3f(1.0f, 0.7137255f, 0.92156863f), // + new Color3f(1.0f, 0.7137255f, 0.85882354f), new Color3f(1.0f, 0.7137255f, 0.78039217f), // + new Color3f(1.0f, 0.7137255f, 0.7137255f), new Color3f(1.0f, 0.78039217f, 0.7137255f), // + new Color3f(1.0f, 0.85882354f, 0.7137255f), new Color3f(1.0f, 0.92156863f, 0.7137255f), // + new Color3f(1.0f, 1.0f, 0.7137255f), new Color3f(0.92156863f, 1.0f, 0.7137255f), // + new Color3f(0.85882354f, 1.0f, 0.7137255f), new Color3f(0.78039217f, 1.0f, 0.7137255f), // + new Color3f(0.7137255f, 1.0f, 0.7137255f), new Color3f(0.7137255f, 1.0f, 0.78039217f), // + new Color3f(0.7137255f, 1.0f, 0.85882354f), new Color3f(0.7137255f, 1.0f, 0.92156863f), // + new Color3f(0.7137255f, 1.0f, 1.0f), new Color3f(0.7137255f, 0.92156863f, 1.0f), // + new Color3f(0.7137255f, 0.85882354f, 1.0f), new Color3f(0.7137255f, 0.78039217f, 1.0f), // + new Color3f(0.0f, 0.0f, 0.44313726f), new Color3f(0.10980392f, 0.0f, 0.44313726f), // + new Color3f(0.21960784f, 0.0f, 0.44313726f), new Color3f(0.33333334f, 0.0f, 0.44313726f), // + new Color3f(0.44313726f, 0.0f, 0.44313726f), new Color3f(0.44313726f, 0.0f, 0.33333334f), // + new Color3f(0.44313726f, 0.0f, 0.21960784f), new Color3f(0.44313726f, 0.0f, 0.10980392f), // + new Color3f(0.44313726f, 0.0f, 0.0f), new Color3f(0.44313726f, 0.10980392f, 0.0f), // + new Color3f(0.44313726f, 0.21960784f, 0.0f), new Color3f(0.44313726f, 0.33333334f, 0.0f), // + new Color3f(0.44313726f, 0.44313726f, 0.0f), new Color3f(0.33333334f, 0.44313726f, 0.0f), // + new Color3f(0.21960784f, 0.44313726f, 0.0f), new Color3f(0.10980392f, 0.44313726f, 0.0f), // + new Color3f(0.0f, 0.44313726f, 0.0f), new Color3f(0.0f, 0.44313726f, 0.10980392f), // + new Color3f(0.0f, 0.44313726f, 0.21960784f), new Color3f(0.0f, 0.44313726f, 0.33333334f), // + new Color3f(0.0f, 0.44313726f, 0.44313726f), new Color3f(0.0f, 0.33333334f, 0.44313726f), // + new Color3f(0.0f, 0.21960784f, 0.44313726f), new Color3f(0.0f, 0.10980392f, 0.44313726f), // + new Color3f(0.21960784f, 0.21960784f, 0.44313726f), new Color3f(0.27058825f, 0.21960784f, 0.44313726f), // + new Color3f(0.33333334f, 0.21960784f, 0.44313726f), new Color3f(0.38039216f, 0.21960784f, 0.44313726f), // + new Color3f(0.44313726f, 0.21960784f, 0.44313726f), new Color3f(0.44313726f, 0.21960784f, 0.38039216f), // + new Color3f(0.44313726f, 0.21960784f, 0.33333334f), new Color3f(0.44313726f, 0.21960784f, 0.27058825f), // + new Color3f(0.44313726f, 0.21960784f, 0.21960784f), new Color3f(0.44313726f, 0.27058825f, 0.21960784f), // + new Color3f(0.44313726f, 0.33333334f, 0.21960784f), new Color3f(0.44313726f, 0.38039216f, 0.21960784f), // + new Color3f(0.44313726f, 0.44313726f, 0.21960784f), new Color3f(0.38039216f, 0.44313726f, 0.21960784f), // + new Color3f(0.33333334f, 0.44313726f, 0.21960784f), new Color3f(0.27058825f, 0.44313726f, 0.21960784f), // + new Color3f(0.21960784f, 0.44313726f, 0.21960784f), new Color3f(0.21960784f, 0.44313726f, 0.27058825f), // + new Color3f(0.21960784f, 0.44313726f, 0.33333334f), new Color3f(0.21960784f, 0.44313726f, 0.38039216f), // + new Color3f(0.21960784f, 0.44313726f, 0.44313726f), new Color3f(0.21960784f, 0.38039216f, 0.44313726f), // + new Color3f(0.21960784f, 0.33333334f, 0.44313726f), new Color3f(0.21960784f, 0.27058825f, 0.44313726f), // + new Color3f(0.31764707f, 0.31764707f, 0.44313726f), new Color3f(0.34901962f, 0.31764707f, 0.44313726f), // + new Color3f(0.38039216f, 0.31764707f, 0.44313726f), new Color3f(0.4117647f, 0.31764707f, 0.44313726f), // + new Color3f(0.44313726f, 0.31764707f, 0.44313726f), new Color3f(0.44313726f, 0.31764707f, 0.4117647f), // + new Color3f(0.44313726f, 0.31764707f, 0.38039216f), new Color3f(0.44313726f, 0.31764707f, 0.34901962f), // + new Color3f(0.44313726f, 0.31764707f, 0.31764707f), new Color3f(0.44313726f, 0.34901962f, 0.31764707f), // + new Color3f(0.44313726f, 0.38039216f, 0.31764707f), new Color3f(0.44313726f, 0.4117647f, 0.31764707f), // + new Color3f(0.44313726f, 0.44313726f, 0.31764707f), new Color3f(0.4117647f, 0.44313726f, 0.31764707f), // + new Color3f(0.38039216f, 0.44313726f, 0.31764707f), new Color3f(0.34901962f, 0.44313726f, 0.31764707f), // + new Color3f(0.31764707f, 0.44313726f, 0.31764707f), new Color3f(0.31764707f, 0.44313726f, 0.34901962f), // + new Color3f(0.31764707f, 0.44313726f, 0.38039216f), new Color3f(0.31764707f, 0.44313726f, 0.4117647f), // + new Color3f(0.31764707f, 0.44313726f, 0.44313726f), new Color3f(0.31764707f, 0.4117647f, 0.44313726f), // + new Color3f(0.31764707f, 0.38039216f, 0.44313726f), new Color3f(0.31764707f, 0.34901962f, 0.44313726f), // + new Color3f(0.0f, 0.0f, 0.25490198f), new Color3f(0.0627451f, 0.0f, 0.25490198f), // + new Color3f(0.1254902f, 0.0f, 0.25490198f), new Color3f(0.1882353f, 0.0f, 0.25490198f), // + new Color3f(0.25490198f, 0.0f, 0.25490198f), new Color3f(0.25490198f, 0.0f, 0.1882353f), // + new Color3f(0.25490198f, 0.0f, 0.1254902f), new Color3f(0.25490198f, 0.0f, 0.0627451f), // + new Color3f(0.25490198f, 0.0f, 0.0f), new Color3f(0.25490198f, 0.0627451f, 0.0f), // + new Color3f(0.25490198f, 0.1254902f, 0.0f), new Color3f(0.25490198f, 0.1882353f, 0.0f), // + new Color3f(0.25490198f, 0.25490198f, 0.0f), new Color3f(0.1882353f, 0.25490198f, 0.0f), // + new Color3f(0.1254902f, 0.25490198f, 0.0f), new Color3f(0.0627451f, 0.25490198f, 0.0f), // + new Color3f(0.0f, 0.25490198f, 0.0f), new Color3f(0.0f, 0.25490198f, 0.0627451f), // + new Color3f(0.0f, 0.25490198f, 0.1254902f), new Color3f(0.0f, 0.25490198f, 0.1882353f), // + new Color3f(0.0f, 0.25490198f, 0.25490198f), new Color3f(0.0f, 0.1882353f, 0.25490198f), // + new Color3f(0.0f, 0.1254902f, 0.25490198f), new Color3f(0.0f, 0.0627451f, 0.25490198f), // + new Color3f(0.1254902f, 0.1254902f, 0.25490198f), new Color3f(0.15686275f, 0.1254902f, 0.25490198f), // + new Color3f(0.1882353f, 0.1254902f, 0.25490198f), new Color3f(0.21960784f, 0.1254902f, 0.25490198f), // + new Color3f(0.25490198f, 0.1254902f, 0.25490198f), new Color3f(0.25490198f, 0.1254902f, 0.21960784f), // + new Color3f(0.25490198f, 0.1254902f, 0.1882353f), new Color3f(0.25490198f, 0.1254902f, 0.15686275f), // + new Color3f(0.25490198f, 0.1254902f, 0.1254902f), new Color3f(0.25490198f, 0.15686275f, 0.1254902f), // + new Color3f(0.25490198f, 0.1882353f, 0.1254902f), new Color3f(0.25490198f, 0.21960784f, 0.1254902f), // + new Color3f(0.25490198f, 0.25490198f, 0.1254902f), new Color3f(0.21960784f, 0.25490198f, 0.1254902f), // + new Color3f(0.1882353f, 0.25490198f, 0.1254902f), new Color3f(0.15686275f, 0.25490198f, 0.1254902f), // + new Color3f(0.1254902f, 0.25490198f, 0.1254902f), new Color3f(0.1254902f, 0.25490198f, 0.15686275f), // + new Color3f(0.1254902f, 0.25490198f, 0.1882353f), new Color3f(0.1254902f, 0.25490198f, 0.21960784f), // + new Color3f(0.1254902f, 0.25490198f, 0.25490198f), new Color3f(0.1254902f, 0.21960784f, 0.25490198f), // + new Color3f(0.1254902f, 0.1882353f, 0.25490198f), new Color3f(0.1254902f, 0.15686275f, 0.25490198f), // + new Color3f(0.17254902f, 0.17254902f, 0.25490198f), new Color3f(0.1882353f, 0.17254902f, 0.25490198f), // + new Color3f(0.20392157f, 0.17254902f, 0.25490198f), new Color3f(0.23529412f, 0.17254902f, 0.25490198f), // + new Color3f(0.25490198f, 0.17254902f, 0.25490198f), new Color3f(0.25490198f, 0.17254902f, 0.23529412f), // + new Color3f(0.25490198f, 0.17254902f, 0.20392157f), new Color3f(0.25490198f, 0.17254902f, 0.1882353f), // + new Color3f(0.25490198f, 0.17254902f, 0.17254902f), new Color3f(0.25490198f, 0.1882353f, 0.17254902f), // + new Color3f(0.25490198f, 0.20392157f, 0.17254902f), new Color3f(0.25490198f, 0.23529412f, 0.17254902f), // + new Color3f(0.25490198f, 0.25490198f, 0.17254902f), new Color3f(0.23529412f, 0.25490198f, 0.17254902f), // + new Color3f(0.20392157f, 0.25490198f, 0.17254902f), new Color3f(0.1882353f, 0.25490198f, 0.17254902f), // + new Color3f(0.17254902f, 0.25490198f, 0.17254902f), new Color3f(0.17254902f, 0.25490198f, 0.1882353f), // + new Color3f(0.17254902f, 0.25490198f, 0.20392157f), new Color3f(0.17254902f, 0.25490198f, 0.23529412f), // + new Color3f(0.17254902f, 0.25490198f, 0.25490198f), new Color3f(0.17254902f, 0.23529412f, 0.25490198f), // + new Color3f(0.17254902f, 0.20392157f, 0.25490198f), new Color3f(0.17254902f, 0.1882353f, 0.25490198f), // + new Color3f(0.0f, 0.0f, 0.0f), new Color3f(0.0f, 0.0f, 0.0f), // + new Color3f(0.0f, 0.0f, 0.0f), new Color3f(0.0f, 0.0f, 0.0f), // + new Color3f(0.0f, 0.0f, 0.0f), new Color3f(0.0f, 0.0f, 0.0f), // + new Color3f(0.0f, 0.0f, 0.0f), new Color3f(0.0f, 0.0f, 0.0f), // + new Color3f(0.0f, 0.0f, 0.0f)}; +} diff --git a/src/digisoft/custom/math/NumberConstants.java b/src/digisoft/custom/math/NumberConstants.java new file mode 100644 index 0000000..46b2ea5 --- /dev/null +++ b/src/digisoft/custom/math/NumberConstants.java @@ -0,0 +1,58 @@ +package digisoft.custom.math; + +/** + * @author Zom-B + * @since 1.0 + * @date 2009/04/26 + */ +public interface NumberConstants { + + public static final double COS1 = 0.54030230586813971740093660744297660373231042061792; // Knuth31 + public static final double CUBERT2 = 1.25992104989487316476721060727822835057025146470151; // Knuth05 + public static final double CUBERT3 = 1.44224957030740838232163831078010958839186925349935; // Knuth06 + public static final double DEG_TO_RAD = 0.01745329251994329576923690768488612713442871888542; // Knuth18 + public static final double E = 2.71828182845904523536028747135266249775724709369996; // Knuth24 + public static final double EULERGAMMA = 0.57721566490153286060651209008240243104215933593992; // Knuth27 + public static final double EXP_EULERGAMMA = 1.7810724179901979852365041031071795491696452143034; // Knuth28 + public static final double EXP_PI025 = 2.19328005073801545655976965927873822346163764199427; // Knuth29 + public static final double E_SQR = 7.38905609893065022723042746057500781318031557055185; // Knuth26 + public static final double GAMMA033 = 2.6789385347077476336556929409746776441286893779573; // Knuth22 + public static final double GAMMA05 = 1.7724538509055160272981674833411451827975494561224; // Knuth21 + public static final double GAMMA067 = 1.3541179394264004169452880281545137855193272660568; // Knuth23 + public static final double LOG10 = 2.30258509299404568401799145468436420760110148862877; // Knuth11 + public static final double LOG2 = 0.69314718055994530941723212145817656807550013436026; // Knuth09 + public static final double LOG3 = 1.09861228866810969139524523692252570464749055782275; // Knuth10 + public static final double LOGPHI = 0.48121182505960344749775891342436842313518433438566; // Knuth13 + public static final double LOGPI = 1.14472988584940017414342735135305871164729481291531; // Knuth12 + public static final double LOGR10 = 0.43429448190325182765112891891660508229439700580367; + public static final double LOGR2 = 1.44269504088896340735992468100189213742664595415299; + public static final double NLOGLOG2 = 0.36651292058166432701243915823266946945426344783711; // Knuth33 + public static final double PHI = 1.61803398874989484820458683436563811772030917980576; // Knuth08 + public static final double PI = 3.14159265358979323846264338327950288419716939937511; // Knuth17 + public static final double PI05 = 1.57079632679489661923132169163975144209858469968755; + public static final double PI2 = 6.28318530717958647692528676655900576839433879875021; + public static final double PI_SQR = 9.86960440108935861883449099987615113531369940724079; // Knuth20 + public static final double Q05LOG10 = 0.21714724095162591382556445945830254114719850290183; + public static final double Q05LOG2 = 0.72134752044448170367996234050094606871332297707649; + public static final double Q05PI = 0.15915494309189533576888376337251436203445964574046; + public static final double Q1_3 = 0.33333333333333333333333333333333333333333333333333; + public static final double Q1_6 = 0.16666666666666666666666666666666666666666666666667; + public static final double Q1E = 0.36787944117144232159552377016146086744581113103177; // Knuth25 + public static final double Q1LOG10 = 0.43429448190325182765112891891660508229439700580367; // Knuth15 + public static final double Q1LOG2 = 1.44269504088896340735992468100189213742664595415299; // Knuth14 + public static final double Q1LOGPHI = 2.07808692123502753760132260611779576774219226778328; // Knuth16 + public static final double Q1PI = 0.31830988618379067153776752674502872406891929148091; // Knuth19 + public static final double Q2PI = 0.63661977236758134307553505349005744813783858296183; // + public static final double Q2POW025 = 1.18920711500272106671749997056047591529297209246382; // Knuth07 + public static final double Q2SQRT5 = 0.89442719099991587856366946749251049417624734384461; + public static final double RAD_TO_DEG = 57.2957795130823208767981548141051703324054724665643; + public static final double SIN1 = 0.84147098480789650665250232163029899962256306079837; // Knuth30 + public static final double SQRT02 = 0.44721359549995793928183473374625524708812367192231; + public static final double SQRT05 = 0.70710678118654752440084436210484903928483593768847; + public static final double SQRT075 = 0.86602540378443864676372317075293618347140262690519; + public static final double SQRT10 = 3.16227766016837933199889354443271853371955513932522; // Knuth04 + public static final double SQRT2 = 1.41421356237309504880168872420969807856967187537695; // Knuth01 + public static final double SQRT3 = 1.73205080756887729352744634150587236694280525381038; // Knuth02 + public static final double SQRT5 = 2.23606797749978969640917366873127623544061835961153; // Knuth03 + public static final double ZETA3 = 1.2020569031595942853997381615114499907649862923405; // Knuth32 +} diff --git a/src/digisoft/custom/swing/GraphicsFunctions.java b/src/digisoft/custom/swing/GraphicsFunctions.java new file mode 100644 index 0000000..6b06c34 --- /dev/null +++ b/src/digisoft/custom/swing/GraphicsFunctions.java @@ -0,0 +1,87 @@ +package digisoft.custom.swing; + +import java.awt.BasicStroke; +import java.awt.DisplayMode; +import java.awt.Graphics2D; +import java.awt.GraphicsDevice; +import java.awt.GraphicsEnvironment; +import java.awt.RenderingHints; + +import javax.swing.UIManager; + +/** + * @author Zom-B + * @since 1.0 + * @date 2007/12/01 + */ +public class GraphicsFunctions { + + public static final BasicStroke DEFAULT_SQUARE_STROKE = new BasicStroke(1, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER); + public static final BasicStroke DEFAULT_ROUND_STROKE = new BasicStroke(1, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND); + + public static void setNiceLookAndFeel() { + try { + UIManager.setLookAndFeel("com.sun.java.swing.plaf.nimbus.NimbusLookAndFeel"); + } catch (Exception e) { + } + } + + public static void setAntialiased(Graphics2D g, boolean antialiased) { + if (antialiased && g.getRenderingHint(RenderingHints.KEY_ANTIALIASING) != RenderingHints.VALUE_ANTIALIAS_ON) { + g.translate(0.5, 0.5); + g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); + g.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY); + g.setRenderingHint(RenderingHints.KEY_DITHERING, RenderingHints.VALUE_DITHER_ENABLE); + g.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON); + g.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON); + g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC); + g.setRenderingHint(RenderingHints.KEY_ALPHA_INTERPOLATION, RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY); + g.setRenderingHint(RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_QUALITY); + g.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE); + } + if (!antialiased && g.getRenderingHint(RenderingHints.KEY_ANTIALIASING) == RenderingHints.VALUE_ANTIALIAS_ON) { + g.translate(-0.5, -0.5); + g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_DEFAULT); + g.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_DEFAULT); + g.setRenderingHint(RenderingHints.KEY_DITHERING, RenderingHints.VALUE_DITHER_DEFAULT); + g.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_DEFAULT); + g.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_DEFAULT); + g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC); + g.setRenderingHint(RenderingHints.KEY_ALPHA_INTERPOLATION, RenderingHints.VALUE_ALPHA_INTERPOLATION_DEFAULT); + g.setRenderingHint(RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_DEFAULT); + g.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_DEFAULT); + } + } + + public static GraphicsDevice getDisplayDevice() { + return GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice(); + } + + public static DisplayMode getDisplayMode(int width, int height) { + DisplayMode currentMode = GraphicsFunctions.getDisplayDevice().getDisplayMode(); + DisplayMode[] modes = GraphicsFunctions.getDisplayDevice().getDisplayModes(); + + int bitDepth = currentMode.getBitDepth(); + int refreshRate = currentMode.getRefreshRate(); + + for (DisplayMode mode : modes) { + if (mode.getHeight() == height && mode.getWidth() == width && mode.getBitDepth() == bitDepth && mode.getRefreshRate() == refreshRate) { + return mode; + } + } + + refreshRate = Integer.MAX_VALUE; + int index = -1; + for (int i = modes.length - 1; i >= 0; i--) { + DisplayMode mode = modes[i]; + if (mode.getHeight() == height && mode.getWidth() == width && mode.getBitDepth() == bitDepth) { + if (refreshRate > mode.getRefreshRate()) { + refreshRate = mode.getRefreshRate(); + index = i; + } + } + } + + return index < 0 ? null : modes[index]; + } +} diff --git a/src/digisoft/custom/swing/ImageFunctions.java b/src/digisoft/custom/swing/ImageFunctions.java new file mode 100644 index 0000000..ecde036 --- /dev/null +++ b/src/digisoft/custom/swing/ImageFunctions.java @@ -0,0 +1,100 @@ +package digisoft.custom.swing; + +import java.awt.Image; +import java.awt.image.BufferedImage; +import java.io.BufferedOutputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.OutputStream; + +import javax.imageio.ImageIO; +import javax.swing.ImageIcon; + +import com.sun.image.codec.jpeg.JPEGCodec; +import com.sun.image.codec.jpeg.JPEGEncodeParam; +import com.sun.image.codec.jpeg.JPEGImageEncoder; + +/** + * @author Zom-B + * @since 1.0 + * @date 2009/04/28 + */ +public class ImageFunctions { + + public static final int SCALE_HINT_ALWAYS = 0; + public static final int SCALE_HINT_FIT_INSIDE = 1; + public static final int SCALE_HINT_WHEN_NECESSARY = 2; + + public static ImageIcon scaleImage(ImageIcon imageIcon, int width, int height, int scalingHint) { + switch (scalingHint) { + case SCALE_HINT_WHEN_NECESSARY: { + if (imageIcon.getIconWidth() <= width && imageIcon.getIconHeight() <= height) { + return imageIcon; + } + // Fall through. + } + case SCALE_HINT_ALWAYS: { + return ImageFunctions.scaleImage(imageIcon, width, height); + } + case SCALE_HINT_FIT_INSIDE: { + Image image = imageIcon.getImage(); + + double wf = (double) width / image.getWidth(null); + double hf = (double) height / image.getHeight(null); + + if (wf > hf) { + height = (int) (wf * image.getHeight(null) + 0.5); + } else if (hf > wf) { + width = (int) (hf * image.getWidth(null) + 0.5); + } + + // imageIcon.setImage(image.getScaledInstance(width, height, + // Image.SCALE_AREA_AVERAGING)); + // return imageIcon; + return new ImageIcon(image.getScaledInstance(width, height, Image.SCALE_AREA_AVERAGING)); + } + } + throw new IllegalArgumentException("Illegal scalingHint. Must be one of SCALE_HINT_ALWAYS, SCALE_HINT_FIT_INSIDE, SCALE_HINT_WHEN_NECESSARY"); + } + + public static ImageIcon scaleImage(ImageIcon imageIcon, int width, int height) { + Image image = imageIcon.getImage(); + + double wf = (double) width / image.getWidth(null); + double hf = (double) height / image.getHeight(null); + + if (wf < hf) { + height = (int) (wf * image.getHeight(null) + 0.5); + } else if (hf < wf) { + width = (int) (hf * image.getWidth(null) + 0.5); + } + + // imageIcon.setImage(image.getScaledInstance(width, height, + // Image.SCALE_AREA_AVERAGING)); + // return imageIcon; + return new ImageIcon(image.getScaledInstance(width, height, Image.SCALE_AREA_AVERAGING)); + } + + public static void saveJPEG(String filename, int[] pixels, int width, int height) throws IOException { + BufferedImage saveImage = new BufferedImage(width, height, BufferedImage.TYPE_BYTE_GRAY); + saveImage.setRGB(0, 0, width, height, pixels, 0, width); + + OutputStream out = new BufferedOutputStream(new FileOutputStream(filename)); + JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(out); + JPEGEncodeParam param = encoder.getDefaultJPEGEncodeParam(saveImage); + param.setQuality(0.95f, false); + encoder.setJPEGEncodeParam(param); + encoder.encode(saveImage); + out.close(); + } + + public static void savePNG(String filename, int[] pixels, int width, int height) throws IOException { + BufferedImage saveImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); + saveImage.setRGB(0, 0, width, height, pixels, 0, width); + + OutputStream out = new BufferedOutputStream(new FileOutputStream(filename)); + ImageIO.write(saveImage, "png", out); + + out.close(); + } +} \ No newline at end of file diff --git a/src/digisoft/custom/swing/RefreshListener.java b/src/digisoft/custom/swing/RefreshListener.java new file mode 100644 index 0000000..499b93f --- /dev/null +++ b/src/digisoft/custom/swing/RefreshListener.java @@ -0,0 +1,11 @@ +package digisoft.custom.swing; + +/** + * @author Zom-B + * @since 1.0 + * @date 2008/12/27 + */ +public interface RefreshListener { + + public void refreshing(); +} diff --git a/src/digisoft/custom/swing/RefreshThread.java b/src/digisoft/custom/swing/RefreshThread.java new file mode 100644 index 0000000..8c4ab9b --- /dev/null +++ b/src/digisoft/custom/swing/RefreshThread.java @@ -0,0 +1,39 @@ +package digisoft.custom.swing; + +/** + * @author Zom-B + * @since 1.0 + * @date 2009/04/16 + */ +public class RefreshThread extends Thread { + + private double delay; + private RefreshListener runnable; + + public RefreshThread(RefreshListener refreshListener, int fps) { + super(); + + runnable = refreshListener; + delay = 1e9 / fps; + } + + @Override + public void run() { + try { + double t = System.nanoTime(); + while (true) { + runnable.refreshing(); + + t += delay; + + long sleepTime = (long) ((t - System.nanoTime()) / 1e6); + + if (sleepTime > 0) { + Thread.sleep(sleepTime); + } + } + } catch (InterruptedException e) { + e.printStackTrace(); + } + } +} diff --git a/src/digisoft/custom/swing/gradient/Gradient.java b/src/digisoft/custom/swing/gradient/Gradient.java new file mode 100644 index 0000000..bb3220a --- /dev/null +++ b/src/digisoft/custom/swing/gradient/Gradient.java @@ -0,0 +1,19 @@ +package digisoft.custom.swing.gradient; + +/** + * @author Zom-B + * @since 1.0 + * @date 2009/04/19 + */ +public interface Gradient { + + public boolean hasTransparency(); + + public int getLength(); + + public int get(int index); + + public int get(double position); + + public int getOverflow(); +} diff --git a/src/digisoft/custom/swing/gradient/OpaqueGradient.java b/src/digisoft/custom/swing/gradient/OpaqueGradient.java new file mode 100644 index 0000000..1d1dc87 --- /dev/null +++ b/src/digisoft/custom/swing/gradient/OpaqueGradient.java @@ -0,0 +1,108 @@ +package digisoft.custom.swing.gradient; + +import digisoft.custom.awt.Color3f; + +/** + * @author Zom-B + * @since 1.0 + * @date 2009/04/05 + */ +public class OpaqueGradient implements Gradient { + + private static final int MAX_GRADIENT_ARRAY_SIZE = 5000; + private static final int GRADIENT_SIZE = 256; + private float[] fractions; + private int gradientOverflow; + private float[] intervals; + private int gradientLength; + private int[] gradient; + + public OpaqueGradient(float[] fractions, Color3f[] colors) { + this.fractions = fractions; + + gradientOverflow = colors[colors.length - 1].getRGB(); + + intervals = new float[fractions.length - 1]; + for (int i = 0; i < intervals.length; i++) { + intervals[i] = fractions[i + 1] - fractions[i]; + } + + calculateGradientFractions(colors); + } + + private void calculateGradientFractions(Color3f[] colors) { + int n = intervals.length; + + // Find smallest interval + float Imin = 1; + for (int i = 0; i < n; i++) { + if (Imin > intervals[i]) { + Imin = intervals[i]; + } + } + + calculateSingleArrayGradient(colors, Imin); + + } + + private void calculateSingleArrayGradient(Color3f[] colors, float Imin) { + + gradientLength = (int) (OpaqueGradient.GRADIENT_SIZE / Imin + 0.5); + if (gradientLength > OpaqueGradient.MAX_GRADIENT_ARRAY_SIZE) { + gradientLength = OpaqueGradient.MAX_GRADIENT_ARRAY_SIZE; + } + + gradient = new int[gradientLength + 1]; + int part = 0; + for (int i = 0; i <= gradientLength; i++) { + // Fraction of the gradient. + float f = (float) i / gradientLength; + + // Select interval. + while (f > fractions[part + 1]) { + part++; + } + + // Fraction of the current interval. + float p = (f - fractions[part]) / intervals[part]; + + // 2 colors to interpolate + Color3f c1 = colors[part]; + Color3f c2 = colors[part + 1]; + + gradient[i] = interpolate(c1, c2, p); + } + } + + private int interpolate(Color3f c1, Color3f c2, float p) { + return 0xFF000000 // + | (int) ((c1.r + (c2.r - c1.r) * p) * 255 + .5) << 16 // + | (int) ((c1.g + (c2.g - c1.g) * p) * 255 + .5) << 8// + | (int) ((c1.b + (c2.b - c1.b) * p) * 255 + .5); + } + + @Override + public boolean hasTransparency() { + return false; + } + + @Override + public int getLength() { + return gradientLength; + } + + @Override + public int get(int index) { + return gradient[index]; + } + + @Override + public int get(double position) { + return gradient[(int) (position * gradientLength + 0.5)]; + } + + @Override + public int getOverflow() { + return gradientOverflow; + } +} diff --git a/src/digisoft/custom/swing/window/CanvasWindow.java b/src/digisoft/custom/swing/window/CanvasWindow.java new file mode 100644 index 0000000..7db3f6e --- /dev/null +++ b/src/digisoft/custom/swing/window/CanvasWindow.java @@ -0,0 +1,165 @@ +package digisoft.custom.swing.window; + +import java.awt.DisplayMode; +import java.awt.GraphicsDevice; +import java.awt.Rectangle; +import java.util.logging.Level; +import java.util.logging.Logger; + +import javax.swing.JFrame; + +import digisoft.custom.swing.GraphicsFunctions; +import digisoft.custom.swing.window.canvas.GraphicsCanvas; + +/** + * @author Zom-B + * @since 1.0 + * @date 2009/03/22 + */ +public class CanvasWindow extends JFrame { + + /** + * Creates a fullscreen CanvasWindow using a given GraphicsCanvas + * + * + * @param canvas + * the GraphicsCanvas defining the drawing method + * @param x + * the x-position of the upper-left corner of the window + * @param y + * the y-position of the upper-left corner of the window + * @param width + * the width of the drawable area of the window + * @param height + * the height of the drawable area of the window + */ + public CanvasWindow(GraphicsCanvas canvas, int x, int y, int width, int height) { + super(); + + this.setup(canvas, width, height); + + super.setResizable(false); + super.pack(); + super.setLocation(x, y); + super.setVisible(true); + + try { + Thread.sleep(10); + } catch (InterruptedException ex) { + Logger.getLogger(CanvasWindow.class.getName()).log(Level.SEVERE, null, ex); + } + + canvas.requestFocus(); + } + + /** + * Creates a fullscreen CanvasWindow using a given GraphicsCanvas + * + * + * @param canvas + * the GraphicsCanvas defining the drawing method + * @param width + * the width of the drawable area of the window + * @param height + * the height of the drawable area of the window + */ + public CanvasWindow(GraphicsCanvas canvas, int width, int height) { + super(); + + this.setup(canvas, width, height); + + super.setResizable(false); + super.pack(); + super.setLocationRelativeTo(null); + super.setVisible(true); + + try { + Thread.sleep(10); + } catch (InterruptedException ex) { + Logger.getLogger(CanvasWindow.class.getName()).log(Level.SEVERE, null, ex); + } + + canvas.requestFocus(); + } + + /** + * Creates a fullscreen CanvasWindow using a given GraphicsCanvas + * + * @param canvas + * the GraphicsCanvas defining the drawing method + * @param exclusive + * when this is set, the window becomes fullscreen, otherwise, it + * will stretch to fit the screen. + */ + public CanvasWindow(GraphicsCanvas canvas, boolean exclusive) { + super(); + + GraphicsDevice displayDevice = GraphicsFunctions.getDisplayDevice(); + DisplayMode mode = displayDevice.getDisplayMode(); + int width = mode.getWidth(); + int height = mode.getHeight(); + + this.setup(canvas, width, height); + + super.invalidate(); + super.setUndecorated(true); + + super.setResizable(false); + super.pack(); + super.setLocationRelativeTo(null); + + if (exclusive) { + displayDevice.setFullScreenWindow(this); + } else { + super.setBounds(new Rectangle(0, 0, width, height)); + super.setVisible(true); + } + + canvas.requestFocus(); + } + + public CanvasWindow(GraphicsCanvas canvas, DisplayMode mode) { + super(); + + GraphicsDevice displayDevice = GraphicsFunctions.getDisplayDevice(); + int width = mode.getWidth(); + int height = mode.getHeight(); + + this.setup(canvas, width, height); + + super.invalidate(); + super.setUndecorated(true); + + super.setResizable(false); + super.pack(); + super.setLocationRelativeTo(null); + + displayDevice.setFullScreenWindow(this); + displayDevice.setDisplayMode(mode); + + canvas.requestFocus(); + } + + private void setup(GraphicsCanvas canvas, int width, int height) { + super.setName(this.getClass().getSimpleName()); + super.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + super.setLayout(null); + + { + canvas.init(width, height, false); + + super.setContentPane(canvas); + } + } + + public void setExclusive(boolean b) { + GraphicsFunctions.getDisplayDevice().setFullScreenWindow(b ? this : null); + + GraphicsCanvas canvas = (GraphicsCanvas) this.getContentPane(); + if (b) { + super.setBounds(new Rectangle(0, 0, canvas.width, canvas.height)); + } else { + super.pack(); + } + } +} diff --git a/src/digisoft/custom/swing/window/PixelWindow.java b/src/digisoft/custom/swing/window/PixelWindow.java new file mode 100644 index 0000000..ad1f001 --- /dev/null +++ b/src/digisoft/custom/swing/window/PixelWindow.java @@ -0,0 +1,96 @@ +package digisoft.custom.swing.window; + +import java.awt.DisplayMode; + +import digisoft.custom.swing.GraphicsFunctions; +import digisoft.custom.swing.window.canvas.MemoryImageSourceCanvas; + +/** + * @author Zom-B + * @since 1.0 + * @date 2009/04/04 + */ +public class PixelWindow extends MemoryImageSourceCanvas { + + private CanvasWindow window; + private DisplayMode backupMode = null; + + /** + * Creates a fullscreen CanvasWindow using a given GraphicsCanvas + * + * + * @param x + * the x-position of the upper-left corner of the window + * @param y + * the y-position of the upper-left corner of the window + * @param width + * the width of the drawable area of the window + * @param height + * the height of the drawable area of the window + */ + public PixelWindow(int x, int y, int width, int height) { + super(); + + window = new CanvasWindow(this, x, y, width, height); + } + + /** + * Creates a fullscreen CanvasWindow using a given GraphicsCanvas + * + * + * @param width + * the width of the drawable area of the window + * @param height + * the height of the drawable area of the window + */ + public PixelWindow(int width, int height) { + super(); + + window = new CanvasWindow(this, width, height); + } + + /** + * Creates a fullscreen CanvasWindow using a given GraphicsCanvas + * + * @param exclusive + * when this is set, the window becomes fullscreen, otherwise, it + * will stretch to fit the screen. + */ + public PixelWindow(boolean exclusive) { + super(); + + window = new CanvasWindow(this, exclusive); + } + + public PixelWindow(DisplayMode mode) { + super(); + + backupMode = GraphicsFunctions.getDisplayDevice().getDisplayMode(); + + window = new CanvasWindow(this, mode); + + while (pixels == null) { + Thread.yield(); + } + } + + public void setExclusive(boolean b) { + window.setExclusive(b); + } + + public void setFullscreen(DisplayMode mode) { + if (backupMode == null) { + window.setExclusive(true); + backupMode = GraphicsFunctions.getDisplayDevice().getDisplayMode(); + GraphicsFunctions.getDisplayDevice().setDisplayMode(mode); + } else { + GraphicsFunctions.getDisplayDevice().setDisplayMode(backupMode); + window.setExclusive(false); + backupMode = null; + } + } + + public void setTitle(String name) { + window.setTitle(name); + } +} diff --git a/src/digisoft/custom/swing/window/canvas/GraphicsCanvas.java b/src/digisoft/custom/swing/window/canvas/GraphicsCanvas.java new file mode 100644 index 0000000..418b364 --- /dev/null +++ b/src/digisoft/custom/swing/window/canvas/GraphicsCanvas.java @@ -0,0 +1,131 @@ +package digisoft.custom.swing.window.canvas; + +import java.awt.Dimension; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.Paint; +import java.awt.event.ComponentEvent; +import java.awt.event.ComponentListener; + +import javax.swing.JPanel; + +/** + * @author Zom-B + * @since 1.0 + * @date 2009/03/22 + */ +public abstract class GraphicsCanvas extends JPanel implements ComponentListener { + + public int width; + public int height; + public int halfWidth; + public int halfHeight; + private volatile boolean resizeRequest; + protected Graphics pg = null; + + // //////////////////////////////////////////////////////////// + public GraphicsCanvas() { + addComponentListener(this); + } + + public void init(int width, int height, boolean painting) { + if (this.width != width || this.height != height) { + setPreferredSize(new Dimension(width, height)); + + initImpl(width, height); + + this.width = width; + this.height = height; + + halfWidth = width >> 1; + halfHeight = height >> 1; + + g = null; + + if (painting) { + resized(); + } + } + } + + // //////////////////////////////////////////////////////////// + public void clear(Paint paint) { + throw new Error("Engine " + this.getClass().getSimpleName() + " has no clear(Paint paint)"); + } + + public void clear(int rgb) { + throw new Error("Engine " + this.getClass().getSimpleName() + " has no clear(int rgb)"); + } + + public void clear(int rgba, boolean hasAlpha) { + throw new Error("Engine " + this.getClass().getSimpleName() + " has no clear(int rgba, boolean hasAlpha)"); + } + + public void pset(int x, int y, int rgb) { + throw new Error("Engine " + this.getClass().getSimpleName() + " has no pset(int x, int y, int rgb)"); + } + + public int pget(int x, int y) { + throw new Error("Engine " + this.getClass().getSimpleName() + " has no pget(int x, int y)"); + } + + public Graphics2D graphics() { + throw new Error("Engine " + this.getClass().getSimpleName() + " has no 2D graphics. Only pixel access supported."); + } + + public void setAntialiased(boolean b) { + throw new Error("Engine " + this.getClass().getSimpleName() + " has no 2D graphics. No antialiasing supported."); + } + + protected abstract void initImpl(int width, int height); + + protected abstract void paintImpl(Graphics g); + + public boolean ready() { + return true; + } + + // //////////////////////////////////////////////////////////// + public void resized() { + } + + // //////////////////////////////////////////////////////////// + @Override + public void paint(Graphics g) { + if (resizeRequest) { + init(super.getWidth(), super.getHeight(), true); + resizeRequest = false; + } else { + paintImpl(g); + } + } + private Graphics2D g = null; + + public void repaintNow() { + if (g == null) { + g = (Graphics2D) getGraphics(); + } + paint(g); + } + + @Override + public void componentResized(ComponentEvent e) { + System.out.println("componentResized " + width + "\t" + height); + if (width != super.getWidth() || height != super.getHeight()) { + resizeRequest = true; + } + super.repaint(); + } + + @Override + public void componentHidden(ComponentEvent arg0) { + } + + @Override + public void componentMoved(ComponentEvent arg0) { + } + + @Override + public void componentShown(ComponentEvent arg0) { + } +} diff --git a/src/digisoft/custom/swing/window/canvas/MemoryImageSourceCanvas.java b/src/digisoft/custom/swing/window/canvas/MemoryImageSourceCanvas.java new file mode 100644 index 0000000..5208994 --- /dev/null +++ b/src/digisoft/custom/swing/window/canvas/MemoryImageSourceCanvas.java @@ -0,0 +1,69 @@ +package digisoft.custom.swing.window.canvas; + +import java.awt.Graphics; +import java.awt.Image; +import java.awt.Toolkit; +import java.awt.image.ColorModel; +import java.awt.image.DirectColorModel; +import java.awt.image.MemoryImageSource; +import java.util.Arrays; + +/** + * @author Zom-B + * @since 1.0 + * @date 2009/03/22 + */ +public class MemoryImageSourceCanvas extends GraphicsCanvas { + + private Image image; + public int[] pixels; + public int pixelCount; + private ColorModel cm; + private MemoryImageSource source; + + // //////////////////////////////////////////////////////////// + @Override + public void clear(int backgroundColor) { + Arrays.fill(pixels, backgroundColor); + } + + @Override + public void pset(int x, int y, int rgb) { + pixels[y * width + x] = rgb; + } + + @Override + public int pget(int x, int y) { + return pixels[y * width + x]; + } + + // //////////////////////////////////////////////////////////// + @Override + protected void initImpl(int width, int height) { + pixelCount = width * height; + + if (pixels == null || pixels.length < pixelCount) { + pixels = new int[pixelCount]; + } + + cm = new DirectColorModel(32, 0x00ff0000, 0x0000ff00, 0x000000ff); + source = new MemoryImageSource(width, height, pixels, 0, width); + source.setFullBufferUpdates(true); + source.setAnimated(true); + image = Toolkit.getDefaultToolkit().createImage(source); + } + + @Override + public void paintImpl(Graphics g) { + if (source != null) { + source.newPixels(pixels, cm, 0, width); + } + + if (image != null) { + g.drawImage(image, 0, 0, null); + + // force repaint now (proper method) + // Toolkit.getDefaultToolkit().sync(); + } + } +} diff --git a/src/digisoft/custom/util/geom/DoubleDouble.java b/src/digisoft/custom/util/geom/DoubleDouble.java new file mode 100644 index 0000000..f328deb --- /dev/null +++ b/src/digisoft/custom/util/geom/DoubleDouble.java @@ -0,0 +1,1892 @@ +package digisoft.custom.util.geom; + +import java.util.Arrays; +import java.util.Random; + +/** + * double: 53 bits DoubleDouble: >106 bits + * + * @author Zom-B + * @since 1.0 + * @see http://crd.lbl.gov/~dhbailey/mpdist/index.html + * @date 2006/10/22 + */ +public strictfp class DoubleDouble { + + public static final char[] BASE_36_TABLE = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', // + 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', // + 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', // + 'U', 'V', 'W', 'X', 'Y', 'Z'}; + public static final char[] ZEROES = { // + '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', // + '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', // + '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', // + '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', // + '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', // + '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', // + '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', // + '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', // + '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', // + '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', // + '0', '0', '0', '0', '0'}; + // public static final double MUL_SPLIT = 0x08000001; + public static final double POSITIVE_INFINITY = Double.MAX_VALUE / 0x08000001; + public static final double NEGATIVE_INFINITY = -DoubleDouble.POSITIVE_INFINITY; + public static final double HALF_EPSILON = 1.1102230246251565E-16; + public static final double EPSILON = 1.232595164407831E-32; + public static final DoubleDouble PI = new DoubleDouble(3.141592653589793, 1.2246467991473532E-16); + public static final DoubleDouble E = new DoubleDouble(2.718281828459045, 1.4456468917292502E-16); + public static final DoubleDouble LOG2 = new DoubleDouble(0.6931471805599453, 2.3190468138462996E-17); + public static final DoubleDouble INV_LOG2 = new DoubleDouble(1.4426950408889634, 2.0355273740931033E-17); + public double hi; + public double lo; + + // ***********************************************************************// + // ************************ Creation functions ***************************// + // ***********************************************************************// + public DoubleDouble() { + hi = 0; + lo = 0; + } + + public DoubleDouble(double d) { + hi = d; + lo = 0; + } + + public DoubleDouble(double hi, double lo) { + this.hi = hi; + this.lo = lo; + } + + public DoubleDouble(DoubleDouble dd) { + hi = dd.hi; + lo = dd.lo; + } + + public void set(double hi) { + this.hi = hi; + lo = 0; + } + + public void set(double hi, double lo) { + this.hi = hi; + this.lo = lo; + } + + public void set(DoubleDouble dd) { + hi = dd.hi; + lo = dd.lo; + } + + public static DoubleDouble random(Random r) { + return new DoubleDouble(r.nextDouble(), r.nextDouble() * DoubleDouble.HALF_EPSILON).normalize(); + } + + public static DoubleDouble randomDynamic(Random r) { + DoubleDouble x = new DoubleDouble(r.nextDouble(), r.nextDouble() / (1L << (r.nextInt(11) + 52))); + x.mulSelf(DoubleDouble.powOf2(r.nextInt(129) - 64)); + x.normalizeSelf(); + if (r.nextBoolean()) { + x.negSelf(); + } + return x; + } + + // ***********************************************************************// + // ************************** Other functions ****************************// + // ***********************************************************************// + @Override + public String toString() { + if (hi != hi) { + return "NaN"; + } + if (hi >= DoubleDouble.POSITIVE_INFINITY) { + return "Infinity"; + } + if (hi <= DoubleDouble.NEGATIVE_INFINITY) { + return "-Infinity"; + } + return DoubleDouble.toString(this, 10); + } + + /** + * Format a string in an easily readable format. The number is represented + * as scientific form on the following conditions:

  1. (for big + * numbers) When the first digit right of the decimal point would not be + * within the first minPrecision positions of the string,
  2. (for + * small numbers) When the most significant digit would not be within the + * first minPrecision positions of the string

Where: + * minPrecision = floor(105 / log2(base) + 1) + */ + public static String toString(DoubleDouble dd, int base) { + double digitsPerBit = StrictMath.log(2) / StrictMath.log(base); + int minPrecision = (int) StrictMath.floor(105.0 * digitsPerBit + 2); + + // Get the precision. (The minimum number of significant digits required + // for an accurate representation of this number) + int expHi = (int) ((Double.doubleToRawLongBits(dd.hi) & 0x7FF0000000000000L) >> 52); + int expLo = dd.lo == 0 ? expHi - 53 : (int) ((Double.doubleToRawLongBits(dd.lo) & 0x7FF0000000000000L) >> 52); + int precision = (int) StrictMath.ceil((expHi - expLo + 53) * digitsPerBit); + precision = StrictMath.max(minPrecision, precision); + + // Get the raw digit representation. + char[] chars = new char[precision + 1]; + int exp = DoubleDouble.to_digits(dd, chars, precision, base) + 1; + + // Get some properties. + int left = StrictMath.max(0, -exp); + int right = StrictMath.max(0, exp); + if (chars[precision - 1] == 0) { + precision--; + } + boolean sci = -exp >= minPrecision || exp >= minPrecision; + + // Allocate exactly the right size string. + StringBuilder out = new StringBuilder(precision + (sci ? 3 : left) + (exp > 0 ? 1 : 2)); + + // Build the string. + if (dd.hi < 0) { + out.append('-'); + } + if (sci) { + out.append(chars, 0, 1); + out.append('.'); + out.append(chars, 1, precision - 1); + out.append('e'); + out.append(exp - 1); + } else { + if (exp <= 0) { + out.append('0'); + } + if (right > 0) { + out.append(chars, 0, right); + } + out.append('.'); + if (left > 0) { + if (DoubleDouble.ZEROES.length < left) { + System.err.println(left); + } else { + out.append(DoubleDouble.ZEROES, 0, left); + } + } + out.append(chars, right, precision - right); + } + return out.toString(); + } + + private static int to_digits(DoubleDouble dd, char[] s, int precision, int base) { + int halfBase = (base + 1) >> 1; + + if (dd.hi == 0.0) { + // Assume dd.lo == 0. + Arrays.fill(s, 0, precision, '0'); + return 0; + } + + // First determine the (approximate) exponent. + DoubleDouble temp = dd.abs(); + int exp = (int) StrictMath.floor(StrictMath.log(temp.hi) / StrictMath.log(base)); + + DoubleDouble p = new DoubleDouble(base); + if (exp < -300) { + temp.mulSelf(p.pow(150)); + p.powSelf(-exp - 150); + temp.mulSelf(p); + } else { + p.powSelf(-exp); + temp.mulSelf(p); + } + + // Fix roundoff errors. (eg. floor(log10(1e9))=floor(8.9999~)=8) + if (temp.hi >= base) { + exp++; + temp.hi /= base; + temp.lo /= base; + } else if (temp.hi < 1) { + exp--; + temp.hi *= base; + temp.lo *= base; + } + + if (temp.hi >= base || temp.hi < 1) { + throw new RuntimeException("Can't compute exponent."); + } + + // Handle one digit more. Used afterwards for rounding. + int numDigits = precision + 1; + // Extract the digits. + for (int i = 0; i < numDigits; i++) { + int val = (int) temp.hi; + temp = temp.sub(val); + temp = temp.mul(base); + + s[i] = (char) val; + } + + if (s[0] <= 0) { + throw new RuntimeException("Negative leading digit."); + } + + // Fix negative digits due to roundoff error in exponent. + for (int i = numDigits - 1; i > 0; i--) { + if (s[i] >= 32768) { + s[i - 1]--; + s[i] += base; + } + } + + // Round, handle carry. + if (s[precision] >= halfBase) { + s[precision - 1]++; + + int i = precision - 1; + while (i > 0 && s[i] >= base) { + s[i] -= base; + s[--i]++; + } + } + s[precision] = 0; + + // If first digit became too high, shift right. + if (s[0] >= base) { + exp++; + for (int i = precision; i >= 1;) { + s[i] = s[--i]; + } + } + + // Convert to ASCII. + for (int i = 0; i < precision; i++) { + s[i] = DoubleDouble.BASE_36_TABLE[s[i]]; + } + + // If first digit became zero, and exp > 0, shift left. + if (s[0] == '0' && exp < 32768) { + exp--; + for (int i = 0; i < precision;) { + s[i] = s[++i]; + } + } + + return exp; + } + + // ***********************************************************************// + // ************************ Temporary functions **************************// + // ***********************************************************************// + @Override + public DoubleDouble clone() { + return new DoubleDouble(hi, lo); + } + + public DoubleDouble normalize() { + double s = hi + lo; + return new DoubleDouble(s, lo + (hi - s)); + } + + public void normalizeSelf() { + double a = hi; + hi = a + lo; + lo = lo + (a - hi); + } + + public int intValue() { + int rhi = (int) StrictMath.round(hi); + + if (hi == rhi) { + return rhi + (int) StrictMath.round(lo); + } + if (StrictMath.abs(rhi - hi) == 0.5 && lo < 0.0) { + return rhi - 1; + } + return rhi; + } + + public long longValue() { + long rhi = StrictMath.round(hi); + + if (hi == rhi) { + return rhi + StrictMath.round(lo); + } + if (StrictMath.abs(rhi - hi) == 0.5 && lo < 0.0) { + return rhi - 1; + } + return rhi; + } + + public static DoubleDouble min(DoubleDouble x, DoubleDouble y) { + if (x.hi < y.hi || (x.hi == y.hi && x.lo < y.lo)) { + return x; + } + return y; + } + + public static DoubleDouble max(DoubleDouble x, DoubleDouble y) { + if (x.hi > y.hi || (x.hi == y.hi && x.lo > y.lo)) { + return x; + } + return y; + } + + public static int sgn(double x) { + if (x > 0) { + return 1; + } + if (x < 0) { + return -1; + } + return 0; + } + + // ***********************************************************************// + // ************************* Simple functions ****************************// + // ***********************************************************************// + public DoubleDouble round() { + DoubleDouble out = new DoubleDouble(); + + double rhi = StrictMath.round(hi); + + if (hi == rhi) { + double rlo = StrictMath.round(lo); + out.hi = rhi + rlo; + out.lo = rlo + (rhi - out.hi); + } else { + if (StrictMath.abs(rhi - hi) == 0.5 && lo < 0.0) { + rhi--; + } + out.hi = rhi; + } + return out; + } + + public void roundSelf() { + double rhi = StrictMath.round(hi); + + if (hi == rhi) { + double rlo = StrictMath.round(lo); + hi = rhi + rlo; + lo = rlo + (rhi - hi); + } else { + if (StrictMath.abs(rhi - hi) == 0.5 && lo < 0.0) { + rhi--; + } + hi = rhi; + lo = 0; + } + } + + public DoubleDouble floor() { + DoubleDouble out = new DoubleDouble(); + + double rhi = StrictMath.floor(hi); + + if (hi == rhi) { + double rlo = StrictMath.floor(lo); + out.hi = rhi + rlo; + out.lo = rlo + (rhi - out.hi); + } else { + out.hi = rhi; + } + return out; + } + + public void floorSelf() { + double rhi = StrictMath.floor(hi); + + if (hi == rhi) { + double rlo = StrictMath.floor(lo); + hi = rhi + rlo; + lo = rlo + (rhi - hi); + } else { + hi = rhi; + lo = 0; + } + } + + public DoubleDouble ceil() { + DoubleDouble out = new DoubleDouble(); + + double rhi = StrictMath.ceil(hi); + + if (hi == rhi) { + double rlo = StrictMath.ceil(lo); + out.hi = rhi + rlo; + out.lo = rlo + (rhi - out.hi); + } else { + out.hi = rhi; + } + return out; + } + + public void ceilSelf() { + double rhi = StrictMath.ceil(hi); + + if (hi == rhi) { + double rlo = StrictMath.ceil(lo); + hi = rhi + rlo; + lo = rlo + (rhi - hi); + } else { + hi = rhi; + lo = 0; + } + } + + public DoubleDouble trunc() { + DoubleDouble out = new DoubleDouble(); + + double rhi = (long) (hi); + + if (hi == rhi) { + double rlo = (long) (lo); + out.hi = rhi + rlo; + out.lo = rlo + (rhi - out.hi); + } else { + out.hi = rhi; + } + return out; + } + + public void truncSelf() { + double rhi = (long) (hi); + + if (hi == rhi) { + double rlo = (long) (lo); + hi = rhi + rlo; + lo = rlo + (rhi - hi); + } else { + hi = rhi; + lo = 0; + } + } + + // ***********************************************************************// + // *********************** Calculation functions *************************// + // ***********************************************************************// + public DoubleDouble neg() { + return new DoubleDouble(-hi, -lo); + } + + public void negSelf() { + hi = -hi; + lo = -lo; + } + + public DoubleDouble abs() { + if (hi < 0) { + return new DoubleDouble(-hi, -lo); + } + return new DoubleDouble(hi, lo); + } + + public void absSelf() { + if (hi < 0) { + hi = -hi; + lo = -lo; + } + } + + public DoubleDouble add(double y) { + double a, b, c; + b = hi + y; + a = hi - b; + c = ((hi - (b + a)) + (y + a)) + lo; + a = b + c; + return new DoubleDouble(a, c + (b - a)); + } + + public void addSelf(double y) { + double a, b; + b = hi + y; + a = hi - b; + lo = ((hi - (b + a)) + (y + a)) + lo; + hi = b + lo; + lo += b - hi; + } + + public DoubleDouble add(DoubleDouble y) { + double a, b, c, d, e, f; + e = hi + y.hi; + d = hi - e; + a = lo + y.lo; + f = lo - a; + d = ((hi - (d + e)) + (d + y.hi)) + a; + b = e + d; + c = ((lo - (f + a)) + (f + y.lo)) + (d + (e - b)); + a = b + c; + return new DoubleDouble(a, c + (b - a)); + } + + public void addSelf(DoubleDouble y) { + double a, b, c, d, e; + a = hi + y.hi; + b = hi - a; + c = lo + y.lo; + d = lo - c; + b = ((hi - (b + a)) + (b + y.hi)) + c; + e = a + b; + lo = ((lo - (d + c)) + (d + y.lo)) + (b + (a - e)); + hi = e + lo; + lo += e - hi; + } + + public DoubleDouble addFast(DoubleDouble y) { + double a, b, c; + b = hi + y.hi; + a = hi - b; + c = ((hi - (a + b)) + (a + y.hi)) + (lo + y.lo); + a = b + c; + return new DoubleDouble(a, c + (b - a)); + } + + public void addSelfFast(DoubleDouble y) { + double a, b; + b = hi + y.hi; + a = hi - b; + lo = ((hi - (a + b)) + (a + y.hi)) + (lo + y.lo); + hi = b + lo; + lo += b - hi; + } + + public DoubleDouble sub(double y) { + double a, b, c; + b = hi - y; + a = hi - b; + c = ((hi - (a + b)) + (a - y)) + lo; + a = b + c; + return new DoubleDouble(a, c + (b - a)); + } + + public DoubleDouble subR(double x) { + double a, b, c; + b = x - hi; + a = x - b; + c = ((x - (a + b)) + (a - hi)) - lo; + a = b + c; + return new DoubleDouble(a, c + (b - a)); + } + + public void subSelf(double y) { + double a, b; + b = hi - y; + a = hi - b; + lo = ((hi - (a + b)) + (a - y)) + lo; + hi = b + lo; + lo += b - hi; + } + + public void subRSelf(double x) { + double a, b; + b = x - hi; + a = x - b; + lo = ((x - (a + b)) + (a - hi)) - lo; + hi = b + lo; + lo += b - hi; + } + + public DoubleDouble sub(DoubleDouble y) { + double a, b, c, d, e, f, g; + g = lo - y.lo; + f = lo - g; + e = hi - y.hi; + d = hi - e; + d = ((hi - (d + e)) + (d - y.hi)) + g; + b = e + d; + c = (d + (e - b)) + ((lo - (f + g)) + (f - y.lo)); + a = b + c; + return new DoubleDouble(a, c + (b - a)); + } + + public void subSelf(DoubleDouble y) { + double a, b, c, d, e; + c = lo - y.lo; + a = lo - c; + e = hi - y.hi; + d = hi - e; + d = ((hi - (d + e)) + (d - y.hi)) + c; + b = e + d; + lo = (d + (e - b)) + ((lo - (a + c)) + (a - y.lo)); + hi = b + lo; + lo += b - hi; + } + + public DoubleDouble subR(DoubleDouble y) { + double a, b, c, d, e, f, g; + g = y.lo - lo; + f = y.lo - g; + e = y.hi - hi; + d = y.hi - e; + d = ((y.hi - (d + e)) + (d - hi)) + g; + b = e + d; + c = (d + (e - b)) + ((y.lo - (f + g)) + (f - lo)); + a = b + c; + return new DoubleDouble(a, c + (b - a)); + } + + public void subRSelf(DoubleDouble y) { + double b, d, e, f, g; + g = y.lo - lo; + f = y.lo - g; + e = y.hi - hi; + d = y.hi - e; + d = ((y.hi - (d + e)) + (d - hi)) + g; + b = e + d; + lo = (d + (e - b)) + ((y.lo - (f + g)) + (f - lo)); + hi = b + lo; + lo = lo + (b - hi); + } + + public DoubleDouble subFast(DoubleDouble y) { + double a, b, c; + b = hi - y.hi; + a = hi - b; + c = (((hi - (a + b)) + (a - y.hi)) + lo) - y.lo; + a = b + c; + return new DoubleDouble(a, c + (b - a)); + } + + public void subSelfFast(DoubleDouble y) { + double a, b; + b = hi - y.hi; + a = hi - b; + lo = (((hi - (a + b)) + (a - y.hi)) + lo) - y.lo; + hi = b + lo; + lo += b - hi; + } + + public DoubleDouble mulPwrOf2(double y) { + return new DoubleDouble(hi * y, lo * y); + } + + public void mulSelfPwrOf2(double y) { + hi *= y; + lo *= y; + } + + public DoubleDouble mul(double y) { + double a, b, c, d, e; + a = 0x08000001 * hi; + a += hi - a; + b = hi - a; + c = 0x08000001 * y; + c += y - c; + d = y - c; + e = hi * y; + c = (((a * c - e) + (a * d + b * c)) + b * d) + lo * y; + a = e + c; + return new DoubleDouble(a, c + (e - a)); + } + + public void mulSelf(double y) { + double a, b, c, d, e; + a = 0x08000001 * hi; + a += hi - a; + b = hi - a; + c = 0x08000001 * y; + c += y - c; + d = y - c; + e = hi * y; + lo = (((a * c - e) + (a * d + b * c)) + b * d) + lo * y; + hi = e + lo; + lo += e - hi; + } + + public DoubleDouble mul(DoubleDouble y) { + double a, b, c, d, e; + a = 0x08000001 * hi; + a += hi - a; + b = hi - a; + c = 0x08000001 * y.hi; + c += y.hi - c; + d = y.hi - c; + e = hi * y.hi; + c = (((a * c - e) + (a * d + b * c)) + b * d) + (lo * y.hi + hi * y.lo); + a = e + c; + return new DoubleDouble(a, c + (e - a)); + } + + public void mulSelf(DoubleDouble y) { + double a, b, c, d, e; + a = 0x08000001 * hi; + a += hi - a; + b = hi - a; + c = 0x08000001 * y.hi; + c += y.hi - c; + d = y.hi - c; + e = hi * y.hi; + lo = (((a * c - e) + (a * d + b * c)) + b * d) + (lo * y.hi + hi * y.lo); + hi = e + lo; + lo += e - hi; + } + + public DoubleDouble divPwrOf2(double y) { + return new DoubleDouble(hi / y, lo / y); + } + + public void divSelfPwrOf2(double y) { + hi /= y; + lo /= y; + } + + public DoubleDouble div(double y) { + double a, b, c, d, e, f, g, h; + f = hi / y; + a = 0x08000001 * f; + a += f - a; + b = f - a; + c = 0x08000001 * y; + c += y - c; + d = y - c; + e = f * y; + g = hi - e; + h = hi - g; + b = (g + ((((hi - (h + g)) + (h - e)) + lo) - (((a * c - e) + (a * d + b * c)) + b * d))) / y; + a = f + b; + return new DoubleDouble(a, b + (f - a)); + } + + public void divSelf(double y) { + double a, b, c, d, e, f, g, h; + f = hi / y; + a = 0x08000001 * f; + a += f - a; + b = f - a; + c = 0x08000001 * y; + c += y - c; + d = y - c; + e = f * y; + g = hi - e; + h = hi - g; + lo = (g + ((((hi - (h + g)) + (h - e)) + lo) - (((a * c - e) + (a * d + b * c)) + b * d))) / y; + hi = f + lo; + lo += f - hi; + } + + public DoubleDouble divr(double y) { + double a, b, c, d, e, f; + f = y / hi; + a = 0x08000001 * hi; + a += hi - a; + b = hi - a; + c = 0x08000001 * f; + c += f - c; + d = f - c; + e = hi * f; + b = ((y - e) - ((((a * c - e) + (a * d + b * c)) + b * d) + lo * f)) / hi; + a = f + b; + return new DoubleDouble(a, b + (f - a)); + } + + public void divrSelf(double y) { + double a, b, c, d, e, f; + f = y / hi; + a = 0x08000001 * hi; + a += hi - a; + b = hi - a; + c = 0x08000001 * f; + c += f - c; + d = f - c; + e = hi * f; + lo = ((y - e) - ((((a * c - e) + (a * d + b * c)) + b * d) + lo * f)) / hi; + hi = f + lo; + lo += f - hi; + } + + public DoubleDouble div(DoubleDouble y) { + double a, b, c, d, e, f, g; + f = hi / y.hi; + a = 0x08000001 * y.hi; + a += y.hi - a; + b = y.hi - a; + c = 0x08000001 * f; + c += f - c; + d = f - c; + e = y.hi * f; + c = (((a * c - e) + (a * d + b * c)) + b * d) + y.lo * f; + b = lo - c; + d = lo - b; + a = hi - e; + e = (hi - ((hi - a) + a)) + b; + g = a + e; + e += (a - g) + ((lo - (d + b)) + (d - c)); + a = g + e; + b = a / y.hi; + f += (e + (g - a)) / y.hi; + a = f + b; + return new DoubleDouble(a, b + (f - a)); + } + + public void divSelf(DoubleDouble y) { + double a, b, c, d, e, f, g; + f = hi / y.hi; + a = 0x08000001 * y.hi; + a += y.hi - a; + b = y.hi - a; + c = 0x08000001 * f; + c += f - c; + d = f - c; + e = y.hi * f; + c = (((a * c - e) + (a * d + b * c)) + b * d) + y.lo * f; + b = lo - c; + d = lo - b; + a = hi - e; + e = (hi - ((hi - a) + a)) + b; + g = a + e; + e += (a - g) + ((lo - (d + b)) + (d - c)); + a = g + e; + lo = a / y.hi; + f += (e + (g - a)) / y.hi; + hi = f + lo; + lo += f - hi; + } + + public DoubleDouble divFast(DoubleDouble y) { + double a, b, c, d, e, f, g; + f = hi / y.hi; + a = 0x08000001 * y.hi; + a += y.hi - a; + b = y.hi - a; + c = 0x08000001 * f; + c += f - c; + d = f - c; + e = y.hi * f; + b = (((a * c - e) + (a * d + b * c)) + b * d) + y.lo * f; + a = e + b; + c = hi - a; + g = (c + ((((hi - c) - a) - ((e - a) + b)) + lo)) / y.hi; + a = f + g; + return new DoubleDouble(a, g + (f - a)); + } + + public void divSelfFast(DoubleDouble y) { + double a, b, c, d, e, f; + f = hi / y.hi; + a = 0x08000001 * y.hi; + a += y.hi - a; + b = y.hi - a; + c = 0x08000001 * f; + c += f - c; + d = f - c; + e = y.hi * f; + b = (((a * c - e) + (a * d + b * c)) + b * d) + y.lo * f; + a = e + b; + c = hi - a; + lo = (c + ((((hi - c) - a) - ((e - a) + b)) + lo)) / y.hi; + hi = f + lo; + lo += f - hi; + } + + public DoubleDouble recip() { + double a, b, c, d, e, f; + f = 1 / hi; + a = 0x08000001 * hi; + a += hi - a; + b = hi - a; + c = 0x08000001 * f; + c += f - c; + d = f - c; + e = hi * f; + b = ((1 - e) - ((((a * c - e) + (a * d + b * c)) + b * d) + lo * f)) / hi; + a = f + b; + return new DoubleDouble(a, b + (f - a)); + } + + public void recipSelf() { + double a, b, c, d, e, f; + f = 1 / hi; + a = 0x08000001 * hi; + a += hi - a; + b = hi - a; + c = 0x08000001 * f; + c += f - c; + d = f - c; + e = hi * f; + lo = ((1 - e) - ((((a * c - e) + (a * d + b * c)) + b * d) + lo * f)) / hi; + hi = f + lo; + lo += f - hi; + } + + public DoubleDouble sqr() { + double a, b, c; + a = 0x08000001 * hi; + a += hi - a; + b = hi - a; + c = hi * hi; + b = ((((a * a - c) + a * b * 2) + b * b) + hi * lo * 2) + lo * lo; + a = b + c; + return new DoubleDouble(a, b + (c - a)); + } + + public void sqrSelf() { + double a, b, c; + a = 0x08000001 * hi; + a += hi - a; + b = hi - a; + c = hi * hi; + lo = ((((a * a - c) + a * b * 2) + b * b) + hi * lo * 2) + lo * lo; + hi = c + lo; + lo += c - hi; + } + + public DoubleDouble sqrt() { + if (hi == 0 && lo == 0) { + return new DoubleDouble(); + } + + double a, b, c, d, e, f, g, h; + g = 1 / StrictMath.sqrt(hi); + h = hi * g; + g *= 0.5; + a = 0x08000001 * h; + a += h - a; + b = h - a; + c = h * h; + b = ((a * a - c) + a * b * 2) + b * b; + a = lo - b; + f = lo - a; + e = hi - c; + d = hi - e; + d = ((hi - (d + e)) + (d - c)) + a; + c = e + d; + b = (d + (e - c)) + ((lo - (f + a)) + (f - b)); + a = c + b; + b += (c - a); + c = 0x08000001 * a; + c += a - c; + d = a - c; + e = 0x08000001 * g; + e += g - e; + f = g - e; + a = a * g; + e = ((c * e - a) + (c * f + d * e)) + d * f; + e += b * g; + b = a + e; + e += a - b; + f = b + h; + c = b - f; + return new DoubleDouble(f, e + ((b - (f + c)) + (h + c))); + } + + public void sqrtSelf() { + if (hi == 0 && lo == 0) { + return; + } + + double a, b, c, d, e, f, g, h; + g = 1 / StrictMath.sqrt(hi); + h = hi * g; + g *= 0.5; + a = 0x08000001 * h; + a += h - a; + b = h - a; + c = h * h; + b = ((a * a - c) + a * b * 2) + b * b; + a = lo - b; + f = lo - a; + e = hi - c; + d = hi - e; + d = ((hi - (d + e)) + (d - c)) + a; + c = e + d; + b = (d + (e - c)) + ((lo - (f + a)) + (f - b)); + a = c + b; + b += (c - a); + c = 0x08000001 * a; + c += a - c; + d = a - c; + e = 0x08000001 * g; + e += g - e; + f = g - e; + a = a * g; + e = ((c * e - a) + (c * f + d * e)) + d * f; + e += b * g; + b = a + e; + e += a - b; + hi = b + h; + c = b - hi; + lo = e + ((b - (hi + c)) + (h + c)); + } + + public DoubleDouble sqrtFast() { + if (hi == 0 && lo == 0) { + return new DoubleDouble(); + } + + double a, b, c, d, e; + d = 1 / StrictMath.sqrt(hi); + e = hi * d; + a = 0x08000001 * e; + a += e - a; + b = e - a; + c = e * e; + b = ((a * a - c) + a * b * 2) + b * b; + a = hi - c; + c = hi - a; + c = (a + ((((hi - (c + a)) + (c - c)) + lo) - b)) * d * 0.5; + a = e + c; + b = e - a; + return new DoubleDouble(a, (e - (b + a)) + (b + c)); + } + + public void sqrtSelfFast() { + if (hi == 0 && lo == 0) { + return; + } + + double a, b, c, d, e; + d = 1 / StrictMath.sqrt(hi); + e = hi * d; + a = 0x08000001 * e; + a += e - a; + b = e - a; + c = e * e; + b = ((a * a - c) + a * b * 2) + b * b; + a = hi - c; + c = hi - a; + c = (a + ((((hi - (c + a)) + (c - c)) + lo) - b)) * d * 0.5; + hi = e + c; + b = e - hi; + lo = (e - (b + hi)) + (b + c); + } + + // Devil's values: + // 0.693147180559945309417232121458174 + // 1.03972077083991796412584818218727 + // 1.03972077083991796312584818218727 + public DoubleDouble exp() { + if (hi > 691.067739) { + return new DoubleDouble(Double.POSITIVE_INFINITY); + } + + double a, b, c, d, e, f, g = 0.5, h = 0, i, j, k, l, m, n, o, p, q = 2, r = 1; + int s; + + a = 0x08000001 * hi; + a += hi - a; + b = a - hi; + c = hi * 1.4426950408889634; + b = (((a * 1.4426950514316559 - c) - (b * 1.4426950514316559 + a * 1.0542692496784412E-8)) + b * 1.0542692496784412E-8) + + (lo * 1.4426950408889634 + hi * 2.0355273740931033E-17); + s = (int) StrictMath.round(c); + if (c == s) { + s += (int) StrictMath.round(b); + } else if (StrictMath.abs(s - c) == 0.5 && b < 0.0) { + s--; + } + e = 0.6931471805599453 * s; + c = ((s * 0.6931471824645996 - e) - (s * 1.904654323148236E-9)) + 2.3190468138462996E-17 * s; + b = lo - c; + d = lo - b; + e = hi - e; + a = e + b; + b = ((lo - (d + b)) + (d - c)) + (b + (e - a)); + e = a + 1; + c = a - e; + d = ((a - (e + c)) + (1 + c)) + b; + c = e + d; + d += e - c; + e = 0x08000001 * a; + e += a - e; + f = a - e; + i = a * a; + f = ((e * e - i) + e * f * 2) + f * f; + f += a * b * 2; + f += b * b; + e = f + i; + f += i - e; + i = e * g; + j = f * g; + do { + k = d + j; + l = d - k; + m = c + i; + n = c - m; + n = ((c - (n + m)) + (n + i)) + k; + o = m + n; + d = (n + (m - o)) + ((d - (l + k)) + (l + j)); + c = o + d; + d += o - c; + k = 0x08000001 * e; + k += e - k; + l = e - k; + m = 0x08000001 * a; + m += a - m; + n = a - m; + o = e * a; + f = (((k * m - o) + (k * n + l * m)) + l * n) + (f * a + e * b); + e = o + f; + f += o - e; + n = g / ++q; + k = 0x08000001 * n; + k += n - k; + l = n - k; + m = n * q; + o = g - m; + p = g - o; + h = (o + ((((g - (p + o)) + (p - m)) + h) - (((k * q - m) + l * q)))) / q; + g = n; + i = 0x08000001 * e; + i += e - i; + k = e - i; + j = 0x08000001 * g; + j += g - j; + l = g - j; + m = e * g; + j = (((i * j - m) + (i * l + k * j)) + k * l) + (f * g + e * h); + i = m + j; + j += m - i; + } while (i > 1e-40 || i < -1e-40); + if (s < 0) { + s = -s; + a = 0.5; + } else { + a = 2; + } + while (s > 0) { + if ((s & 1) > 0) { + r *= a; + } + a *= a; + s >>= 1; + } + a = d + j; + b = d - a; + e = c + i; + f = c - e; + f = ((c - (f + e)) + (f + i)) + a; + c = e + f; + d = (f + (e - c)) + ((d - (b + a)) + (b + j)); + return new DoubleDouble(c * r, d * r); + } + + public void expSelf() { + if (hi > 691.067739) { + hi = Double.POSITIVE_INFINITY; + return; + } + + double a, b, c, d, e, f, g = 0.5, h = 0, i, j, k, l, m, n, o, p, q = 2, r = 1; + int s; + + a = 0x08000001 * hi; + a += hi - a; + b = a - hi; + c = hi * 1.4426950408889634; + b = (((a * 1.4426950514316559 - c) - (b * 1.4426950514316559 + a * 1.0542692496784412E-8)) + b * 1.0542692496784412E-8) + + (lo * 1.4426950408889634 + hi * 2.0355273740931033E-17); + s = (int) StrictMath.round(c); + if (c == s) { + s += (int) StrictMath.round(b); + } else if (StrictMath.abs(s - c) == 0.5 && b < 0.0) { + s--; + } + e = 0.6931471805599453 * s; + c = ((s * 0.6931471824645996 - e) - (s * 1.904654323148236E-9)) + 2.3190468138462996E-17 * s; + b = lo - c; + d = lo - b; + e = hi - e; + a = e + b; + b = ((b + (e - a)) + ((lo - (d + b)) + (d - c))); + e = a + 1; + c = a - e; + d = ((a - (e + c)) + (1 + c)) + b; + c = e + d; + d += e - c; + e = 0x08000001 * a; + e += a - e; + f = a - e; + i = a * a; + f = ((e * e - i) + e * f * 2) + f * f; + f += a * b * 2; + f += b * b; + e = f + i; + f += i - e; + i = e * g; + j = f * g; + do { + k = d + j; + l = d - k; + m = c + i; + n = c - m; + n = ((c - (n + m)) + (n + i)) + k; + o = m + n; + d = (n + (m - o)) + ((d - (l + k)) + (l + j)); + c = o + d; + d += o - c; + k = 0x08000001 * e; + k += e - k; + l = e - k; + m = 0x08000001 * a; + m += a - m; + n = a - m; + o = e * a; + f = (((k * m - o) + (k * n + l * m)) + l * n) + (f * a + e * b); + e = o + f; + f += o - e; + n = g / ++q; + k = 0x08000001 * n; + k += n - k; + l = n - k; + m = n * q; + o = g - m; + p = g - o; + h = (o + ((((g - (p + o)) + (p - m)) + h) - (((k * q - m) + l * q)))) / q; + g = n; + i = 0x08000001 * e; + i += e - i; + k = e - i; + j = 0x08000001 * g; + j += g - j; + l = g - j; + m = e * g; + j = (((i * j - m) + (i * l + k * j)) + k * l) + (f * g + e * h); + i = m + j; + j += m - i; + } while (i > 1e-40 || i < -1e-40); + if (s < 0) { + s = -s; + a = 0.5; + } else { + a = 2; + } + while (s > 0) { + if ((s & 1) > 0) { + r *= a; + } + a *= a; + s >>= 1; + } + a = d + j; + b = d - a; + e = c + i; + f = c - e; + f = ((c - (f + e)) + (f + i)) + a; + hi = e + f; + lo = ((f + (e - hi)) + ((d - (b + a)) + (b + j))) * r; + hi *= r; + } + + public DoubleDouble log() { + if (hi <= 0.0) { + return new DoubleDouble(Double.NaN); + } + + double a, b, c, d, e, f, g = 0.5, h = 0, i, j, k, l, m, n, o, p, q = 2, r = 1, s; + int t; + + s = StrictMath.log(hi); + + a = 0x08000001 * s; + a += s + a; + b = s - a; + c = s * -1.4426950408889634; + b = (((a * -1.4426950514316559 - c) + (a * 1.0542692496784412E-8 - b * 1.4426950514316559)) + b * 1.0542692496784412E-8) - (s * 2.0355273740931033E-17); + t = (int) StrictMath.round(c); + if (a == t) { + t += (int) StrictMath.round(b); + } else if (StrictMath.abs(t - a) == 0.5 && b < 0.0) { + t--; + } + e = 0.6931471805599453 * t; + c = ((t * 0.6931471824645996 - e) - (t * 1.904654323148236E-9)) + 2.3190468138462996E-17 * t; + e += s; + a = e + c; + b = (a - e) - c; + e = 1 - a; + d = ((1 - e) - a) + b; + c = e + d; + d += e - c; + e = 0x08000001 * -a; + e -= a + e; + f = a + e; + i = a * a; + f = ((e * e - i) - e * f * 2) + f * f; + f += -a * b * 2; + a = -a; + f += b * b; + e = f + i; + f += i - e; + l = 0x08000001 * e; + l += e - l; + k = e - l; + i = e * g; + j = f * g; + do { + k = d + j; + l = d - k; + m = c + i; + n = c - m; + n = ((c - (n + m)) + (n + i)) + k; + o = m + n; + d = (n + (m - o)) + ((d - (l + k)) + (l + j)); + c = o + d; + d += o - c; + k = 0x08000001 * e; + k += e - k; + l = e - k; + m = 0x08000001 * a; + m += a - m; + n = a - m; + o = e * a; + f = (((k * m - o) + (k * n + l * m)) + l * n) + (f * a + e * b); + e = o + f; + f += o - e; + n = g / ++q; + k = 0x08000001 * n; + k += n - k; + l = n - k; + m = n * q; + o = g - m; + p = g - o; + h = (o + ((((g - (p + o)) + (p - m)) + h) - (((k * q - m) + l * q)))) / q; + g = n; + i = 0x08000001 * e; + i += e - i; + k = e - i; + j = 0x08000001 * g; + j += g - j; + l = g - j; + m = e * g; + j = (((i * j - m) + (i * l + k * j)) + k * l) + (f * g + e * h); + i = m + j; + j += m - i; + } while (i > 1e-40 || i < -1e-40); + if (t < 0) { + t = -t; + k = 0.5; + } else { + k = 2; + } + while (t > 0) { + if ((t & 1) > 0) { + r *= k; + } + k *= k; + t >>= 1; + } + a = d + j; + b = d - a; + e = c + i; + f = c - e; + f = ((c - (f + e)) + (f + i)) + a; + g = e + f; + h = ((f + (e - g)) + ((d - (b + a)) + (b + j))) * r; + g *= r; + a = 0x08000001 * hi; + a += hi - a; + c = hi - a; + b = 0x08000001 * g; + b += g - b; + d = g - b; + e = hi * g; + b = (((a * b - e) + (a * d + c * b)) + c * d) + (lo * g + hi * h); + a = --e + b; + b += e - a; + c = a + s; + d = a - c; + b += ((a - (c + d)) + (s + d)); + a = c + b; + return new DoubleDouble(a, b + (c - a)); + } + + public void logSelf() { + if (hi <= 0.0) { + hi = Double.NaN; + return; + } + + double a, b, c, d, e, f, g = 0.5, h = 0, i, j, k, l, m, n, o, p, q = 2, r = 1, s; + int t; + + s = StrictMath.log(hi); + + a = 0x08000001 * s; + a += s + a; + b = s - a; + c = s * -1.4426950408889634; + b = (((a * -1.4426950514316559 - c) + (a * 1.0542692496784412E-8 - b * 1.4426950514316559)) + b * 1.0542692496784412E-8) - (s * 2.0355273740931033E-17); + t = (int) StrictMath.round(c); + if (c == t) { + t += (int) StrictMath.round(b); + } else if (StrictMath.abs(t + c) == 0.5 && b < 0.0) { + t--; + } + e = 0.6931471805599453 * t; + c = ((t * 0.6931471824645996 - e) - (t * 1.904654323148236E-9)) + 2.3190468138462996E-17 * t; + e += s; + a = e + c; + b = (a - e) - c; + e = 1 - a; + d = ((1 - e) - a) + b; + c = e + d; + d += e - c; + e = 0x08000001 * -a; + e -= a + e; + f = a + e; + i = a * a; + f = ((e * e - i) - e * f * 2) + f * f; + f += -a * b * 2; + a = -a; + f += b * b; + e = f + i; + f += i - e; + l = 0x08000001 * e; + l += e - l; + k = e - l; + i = e * g; + j = f * g; + do { + k = d + j; + l = d - k; + m = c + i; + n = c - m; + n = ((c - (n + m)) + (n + i)) + k; + o = m + n; + d = (n + (m - o)) + ((d - (l + k)) + (l + j)); + c = o + d; + d += o - c; + k = 0x08000001 * e; + k += e - k; + l = e - k; + m = 0x08000001 * a; + m += a - m; + n = a - m; + o = e * a; + f = (((k * m - o) + (k * n + l * m)) + l * n) + (f * a + e * b); + e = o + f; + f += o - e; + n = g / ++q; + k = 0x08000001 * n; + k += n - k; + l = n - k; + m = n * q; + o = g - m; + p = g - o; + h = (o + ((((g - (p + o)) + (p - m)) + h) - (((k * q - m) + l * q)))) / q; + g = n; + i = 0x08000001 * e; + i += e - i; + k = e - i; + j = 0x08000001 * g; + j += g - j; + l = g - j; + m = e * g; + j = (((i * j - m) + (i * l + k * j)) + k * l) + (f * g + e * h); + i = m + j; + j += m - i; + } while (i > 1e-40 || i < -1e-40); + if (t < 0) { + t = -t; + k = 0.5; + } else { + k = 2; + } + while (t > 0) { + if ((t & 1) > 0) { + r *= k; + } + k *= k; + t >>= 1; + } + a = d + j; + b = d - a; + e = c + i; + f = c - e; + f = ((c - (f + e)) + (f + i)) + a; + g = e + f; + h = ((f + (e - g)) + ((d - (b + a)) + (b + j))) * r; + g *= r; + a = 0x08000001 * hi; + a += hi - a; + c = hi - a; + b = 0x08000001 * g; + b += g - b; + d = g - b; + e = hi * g; + lo = (((a * b - e) + (a * d + c * b)) + c * d) + (lo * g + hi * h); + a = --e + lo; + lo += e - a; + c = a + s; + d = a - c; + lo += ((a - (c + d)) + (s + d)); + hi = c + lo; + lo += c - hi; + } + + public static double powOf2(int y) { + return ((long) y + 0xFF) << 52; + } + + public DoubleDouble pow(int y) { + DoubleDouble temp; + int e = y; + if (e < 0) { + e = -y; + } + temp = new DoubleDouble(hi, lo); + DoubleDouble prod = new DoubleDouble(1); + while (e > 0) { + if ((e & 1) > 0) { + prod.mulSelf(temp); + } + temp.sqrSelf(); + e >>= 1; + } + if (y < 0) { + return prod.recip(); + } + return prod; + } + + public void powSelf(int y) { + DoubleDouble temp; + int e = y; + if (e < 0) { + e = -y; + } + temp = new DoubleDouble(hi, lo); + hi = 1; + lo = 0; + while (e > 0) { + if ((e & 1) > 0) { + this.mulSelf(temp); + } + temp.sqrSelf(); + e >>= 1; + } + if (y < 0) { + recipSelf(); + } + } + + public DoubleDouble pow(double y) { + return log().mul(y).exp(); + } + + public void powSelf(double y) { + logSelf(); + this.mulSelf(y); + expSelf(); + } + + public DoubleDouble pow(DoubleDouble y) { + return log().mul(y).exp(); + } + + public void powSelf(DoubleDouble y) { + logSelf(); + this.mulSelf(y); + expSelf(); + } + + public DoubleDouble root(int y) { + if (hi == 0 && lo == 0) { + return new DoubleDouble(); + } + if (hi < 0.0 && ((y & 1) == 0)) { + return new DoubleDouble(Double.NaN); + } + + if (y == 1) { + return this; + } + if (y == 2) { + double a, b, c, d, e, f, g, h; + g = 1 / StrictMath.sqrt(hi); + h = hi * g; + g *= 0.5; + a = 0x08000001 * h; + a += h - a; + b = h - a; + c = h * h; + b = ((a * a - c) + a * b * 2) + b * b; + a = lo - b; + f = lo - a; + e = hi - c; + d = hi - e; + d = ((hi - (d + e)) + (d - c)) + a; + c = e + d; + b = (d + (e - c)) + ((lo - (f + a)) + (f - b)); + a = c + b; + b += (c - a); + c = 0x08000001 * a; + c += a - c; + d = a - c; + e = 0x08000001 * g; + e += g - e; + f = g - e; + a = a * g; + e = ((c * e - a) + (c * f + d * e)) + d * f; + e += b * g; + b = a + e; + e += a - b; + f = b + h; + c = b - f; + return new DoubleDouble(f, e + ((b - (f + c)) + (h + c))); + } + + double a, b, c, d, e, f, g, h, i, j, k, l, m; + int z; + + if (hi < 0) { + b = -hi; + c = -lo; + } else { + b = hi; + c = lo; + } + + a = StrictMath.exp(StrictMath.log(b) / (-y)); + + z = y; + k = a; + l = 0; + g = 1; + h = 0; + while (z > 0) { + if ((z & 1) > 0) { + d = 0x08000001 * g; + d += g - d; + e = g - d; + f = 0x08000001 * k; + f += k - f; + i = k - f; + j = g * k; + h = (((d * f - j) + (d * i + e * f)) + e * i) + (h * k + g * l); + g = j + h; + h += j - g; + } + f = 0x08000001 * k; + f = f + (k - f); + i = k - f; + j = k * k; + i = ((f * f - j) + f * i * 2) + i * i; + i += k * l * 2; + i += l * l; + k = i + j; + l = i + (j - k); + z >>= 1; + } + + l = 0x08000001 * b; + l += b - l; + m = b - l; + d = 0x08000001 * g; + d += g - d; + e = g - d; + f = b * g; + d = (((l * d - f) + (l * e + m * d)) + m * e) + (c * g + b * h); + e = 1 - f; + l = e - d; + m = (e - l) - d; + d = 0x08000001 * l; + d += l - d; + e = l - d; + f = 0x08000001 * a; + f += a - f; + g = a - f; + l *= a; + m *= a; + m += (((d * f - l) + (d * g + e * f)) + e * g); + d = l / y; + e = 0x08000001 * d; + e += d - e; + f = d - e; + g = 0x08000001 * y; + g += y - g; + h = y - g; + i = d * y; + j = l - i; + k = l - j; + m = (j + ((((l - (k + j)) + (k - i)) + m) - (((e * g - i) + (e * h + f * g)) + f * h))) / y; + e = d + a; + l = d - e; + m += (d - (e + l)) + (a + l); + if (hi < 0.0) { + e = -e; + m = -m; + } + i = 1 / e; + l = 0x08000001 * e; + l += e - l; + d = e - l; + f = 0x08000001 * i; + f += i - f; + g = i - f; + h = e * i; + m = ((1 - h) - ((((l * f - h) + (l * g + d * f)) + d * g) + m * i)) / e; + l = i + m; + return new DoubleDouble(l, m + (i - l)); + } + + public void rootSelf(int y) { + if (hi == 0 && lo == 0) { + return; + } + if (hi < 0.0 && ((y & 1) == 0)) { + hi = Double.NaN; + return; + } + + if (y == 1) { + return; + } + if (y == 2) { + double a, b, c, d, e, f, g, h; + g = 1 / StrictMath.sqrt(hi); + h = hi * g; + g *= 0.5; + a = 0x08000001 * h; + a += h - a; + b = h - a; + c = h * h; + b = ((a * a - c) + a * b * 2) + b * b; + a = lo - b; + f = lo - a; + e = hi - c; + d = hi - e; + d = ((hi - (d + e)) + (d - c)) + a; + c = e + d; + b = (d + (e - c)) + ((lo - (f + a)) + (f - b)); + a = c + b; + b += (c - a); + c = 0x08000001 * a; + c += a - c; + d = a - c; + e = 0x08000001 * g; + e += g - e; + f = g - e; + a = a * g; + e = ((c * e - a) + (c * f + d * e)) + d * f; + e += b * g; + b = a + e; + e += a - b; + hi = b + h; + c = b - hi; + lo = e + ((b - (hi + c)) + (h + c)); + return; + } + + double a, b, c, d, e, f, g, h, i, j, k, l, m; + int z; + + if (hi < 0) { + b = -hi; + c = -lo; + } else { + b = hi; + c = lo; + } + + a = StrictMath.exp(StrictMath.log(b) / (-y)); + + z = y; + k = a; + l = 0; + g = 1; + h = 0; + while (z > 0) { + if ((z & 1) > 0) { + d = 0x08000001 * g; + d += g - d; + e = g - d; + f = 0x08000001 * k; + f += k - f; + i = k - f; + j = g * k; + h = (((d * f - j) + (d * i + e * f)) + e * i) + (h * k + g * l); + g = j + h; + h += j - g; + } + f = 0x08000001 * k; + f = f + (k - f); + i = k - f; + j = k * k; + i = ((f * f - j) + f * i * 2) + i * i; + i += k * l * 2; + i += l * l; + k = i + j; + l = i + (j - k); + z >>= 1; + } + + l = 0x08000001 * b; + l += b - l; + m = b - l; + d = 0x08000001 * g; + d += g - d; + e = g - d; + f = b * g; + d = (((l * d - f) + (l * e + m * d)) + m * e) + (c * g + b * h); + e = 1 - f; + l = e - d; + m = (e - l) - d; + d = 0x08000001 * l; + d += l - d; + e = l - d; + f = 0x08000001 * a; + f += a - f; + g = a - f; + l *= a; + m *= a; + m += (((d * f - l) + (d * g + e * f)) + e * g); + d = l / y; + e = 0x08000001 * d; + e += d - e; + f = d - e; + g = 0x08000001 * y; + g += y - g; + h = y - g; + i = d * y; + j = l - i; + k = l - j; + m = (j + ((((l - (k + j)) + (k - i)) + m) - (((e * g - i) + (e * h + f * g)) + f * h))) / y; + e = d + a; + l = d - e; + m += (d - (e + l)) + (a + l); + if (hi < 0.0) { + e = -e; + m = -m; + } + i = 1 / e; + l = 0x08000001 * e; + l += e - l; + d = e - l; + f = 0x08000001 * i; + f += i - f; + g = i - f; + h = e * i; + m = ((1 - h) - ((((l * f - h) + (l * g + d * f)) + d * g) + m * i)) / e; + l = i + m; + hi = l; + lo = m + (i - l); + } + + public DoubleDouble root(double y) { + return log().div(y).exp(); + } + + public void rootSelf(double y) { + logSelf(); + this.divSelf(y); + expSelf(); + } + + public DoubleDouble rootr(double y) { + return divr(StrictMath.log(y)).exp(); + } + + public void rootrSelf(double y) { + divrSelf(StrictMath.log(y)); + expSelf(); + } + + public DoubleDouble root(DoubleDouble y) { + return log().div(y).exp(); + } + + public void rootSelf(DoubleDouble y) { + logSelf(); + this.divSelf(y); + expSelf(); + } +}