]> gitweb.hamatoma.de Git - jpinet/commitdiff
Diagram, PairData...
authorhama <hama@siduction.net>
Wed, 6 Jul 2016 22:13:40 +0000 (00:13 +0200)
committerhama <hama@siduction.net>
Wed, 6 Jul 2016 22:13:40 +0000 (00:13 +0200)
13 files changed:
src/main/java/de/republib/gui/Diagram.java [new file with mode: 0644]
src/main/java/de/republib/pinet/Client.java
src/main/java/de/republib/pinet/gui/ControlCenter.java [new file with mode: 0644]
src/main/java/de/republib/util/BytePairData.java [new file with mode: 0644]
src/main/java/de/republib/util/DynBytes.java
src/main/java/de/republib/util/FunctionPairData.java [new file with mode: 0644]
src/main/java/de/republib/util/I18N.java [new file with mode: 0644]
src/main/java/de/republib/util/IPairData.java [new file with mode: 0644]
src/main/java/de/republib/util/MathFunction.java [new file with mode: 0644]
src/main/java/de/republib/util/PairData.java [new file with mode: 0644]
src/test/java/de/republib/util/BytePairDataTest.java [new file with mode: 0644]
src/test/java/de/republib/util/DynBytesTest.java
src/test/java/de/republib/util/FunctionPairDataTest.java [new file with mode: 0644]

diff --git a/src/main/java/de/republib/gui/Diagram.java b/src/main/java/de/republib/gui/Diagram.java
new file mode 100644 (file)
index 0000000..9e2f0f2
--- /dev/null
@@ -0,0 +1,153 @@
+/**
+ *
+ */
+package de.republib.gui;
+
+import java.awt.Color;
+import java.awt.Graphics;
+import java.util.LinkedList;
+import java.util.List;
+
+import javax.swing.JPanel;
+
+import de.republib.util.IPairData;
+
+/**
+ * A diagram sheet.
+ *
+ * <pre>
+ * ----------------------------
+ * |<-- vertic. scale
+ * |
+ * |
+ * |
+ * |          v-- horiz. scale
+ * |__________________________
+ * -----------------------------
+ * </pre>
+ *
+ * @author hm
+ *
+ */
+public class Diagram extends JPanel {
+       private double realX0 = 0.0;
+       private double realY0 = 0.0;
+       private double realWidth = 1.0;
+       private double realHeight = 1.0;
+       /// 0.0: no fix ration. Otherwise: width / height
+       private final double ratio = 800.0 / 600.0;
+       /// distance horizontal scale to left border
+       private final int hScaleDistance = 5;
+       /// distance vertical scale to bottom
+       private final int vScaleDistance = 5;
+       private final int scaleWidth = 1;
+       private final Color colorScale = Color.DARK_GRAY;
+       private final Color colorScaleFont = Color.BLACK;
+       private final Color colorSheet = Color.WHITE;
+       private final List<IPairData> data = new LinkedList<IPairData>();
+
+       /**
+        * Appends a data package for drawing one line.
+        *
+        * @param data
+        *            the pair data for one line
+        * @return the instance (for chaining)
+        */
+       Diagram addData(IPairData data) {
+               this.data.add(data);
+               return this;
+       }
+
+       @Override
+       protected void paintComponent(Graphics graphics) {
+               super.paintComponent(graphics);
+               paintScale(graphics);
+               paintData(graphics);
+       }
+
+       /**
+        * Paints the data as lines in the sheet.
+        *
+        * @param graphics
+        *            the graphic environment
+        */
+       protected void paintData(Graphics graphics) {
+               final double x0 = this.realX0;
+               final double realWidth = this.realWidth;
+               final double y0 = this.realY0;
+               final double realHeight = this.realHeight;
+               for (final IPairData data : this.data) {
+                       this.realX0 = data.getX(0);
+                       this.realWidth = data.getX(data.getSteps() - 1) - this.realX0;
+                       int lastX = 0, lastY = 0;
+                       for (int ix = 0; ix < data.getSteps(); ix++) {
+                               final int x = transformX(data.getX(ix));
+                               final int y = transformY(data.getY(ix));
+                               if (ix > 0) {
+                                       graphics.drawLine(lastX, lastY, x, y);
+                               }
+                               lastX = x;
+                               lastY = y;
+                       }
+               }
+               this.realX0 = x0;
+               this.realWidth = realWidth;
+               this.realY0 = y0;
+               this.realHeight = realHeight;
+       }
+
+       /**
+        * Paints the scales.
+        *
+        * @param graphics
+        *            the graphic environment
+        */
+       protected void paintScale(Graphics graphics) {
+               graphics.setColor(this.colorScale);
+               graphics.drawLine(this.hScaleDistance, this.vScaleDistance, this.getWidth() - this.hScaleDistance,
+                               this.vScaleDistance);
+               graphics.drawLine(this.hScaleDistance, this.vScaleDistance, this.hScaleDistance,
+                               this.getHeight() - this.vScaleDistance);
+
+       }
+
+       /**
+        * Calculates the x position in pixel from a real x coordinate.
+        *
+        * @param x
+        *            the x coordinate in the real world
+        * @return the x value in pixel coordinate
+        */
+       public int transformX(double x) {
+               final double xPixel = (x - this.realX0) * (getWidth() - 2 * this.hScaleDistance);
+               int rc;
+               if (xPixel < 0) {
+                       rc = 0;
+               } else if (xPixel > getWidth()) {
+                       rc = getWidth();
+               } else {
+                       rc = (int) Math.round(xPixel);
+               }
+               return rc;
+       }
+
+       /**
+        * Calculates the y position in pixel from a real y coordinate.
+        *
+        * @param y
+        *            the y coordinate in the real world
+        * @return the y value in pixel coordinate
+        */
+       public int transformY(double y) {
+               final double yPixel = (y - this.realY0) * (getHeight() - 2 * this.vScaleDistance);
+               int rc;
+               if (yPixel < 0) {
+                       rc = -1;
+               } else if (yPixel > getHeight()) {
+                       rc = getHeight();
+               } else {
+                       rc = (int) Math.round(yPixel);
+               }
+               return rc;
+       }
+}
index 12456d1f35c67de802c159c432717bcc79411c81..0dbfea726f7c93e864fdb26354a39e5d2988f9e7 100644 (file)
@@ -3,12 +3,25 @@ package de.republib.pinet;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import de.republib.pinet.gui.ControlCenter;
+
 /**
  * A TCP client to use services from a GPIO server.
  */
 public class Client {
        static Logger logger = LoggerFactory.getLogger(Client.class);
 
+       public static void client(String host, int port) {
+               final GpioClient client = new GpioClient(host, port);
+               client.blink(PinNumber.PIN_RPi2_12, 10, 500, 500);
+       }
+
+       public static void gui() {
+               final ControlCenter center = new ControlCenter();
+               center.populate();
+               center.run();
+       }
+
        /**
         * Evaluates the options and start the program.
         *
@@ -27,7 +40,7 @@ public class Client {
                                port = Integer.parseInt(arg);
                        }
                }
-               final GpioClient client = new GpioClient(host, port);
-               client.blink(PinNumber.PIN_RPi2_12, 10, 500, 500);
+               Client.gui();
+               // Client.client(host, port);
        }
 }
diff --git a/src/main/java/de/republib/pinet/gui/ControlCenter.java b/src/main/java/de/republib/pinet/gui/ControlCenter.java
new file mode 100644 (file)
index 0000000..18dfd5b
--- /dev/null
@@ -0,0 +1,59 @@
+package de.republib.pinet.gui;
+
+import java.awt.BorderLayout;
+import java.awt.Dimension;
+import java.awt.FlowLayout;
+import java.awt.GridLayout;
+
+import javax.swing.JFrame;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.JTabbedPane;
+import javax.swing.JTextField;
+
+import de.republib.gui.Diagram;
+import de.republib.util.I18N;
+
+/**
+ * Created by hm on 03.07.16.
+ */
+public class ControlCenter {
+       private JFrame frame;
+       private JPanel panelCenter;
+       private JPanel panelOutput;
+       private JPanel panelLog;
+       private JLabel labelStatusLine;
+       private JPanel panelData;
+       private JPanel panelHead;
+       private JTextField textFieldServer;
+       private JTextField textFieldPort;
+       private JTabbedPane tabbedPane;
+
+       public void populate() {
+               this.frame = new JFrame(I18N.tr("Pinet Control Center"));
+               this.frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+
+               this.frame.setMinimumSize(new Dimension(800, 600));
+
+               // Add content to the window.
+               this.frame.add(this.panelCenter = new JPanel(new GridLayout(1, 1)), BorderLayout.CENTER);
+               this.frame.add(this.panelHead = new JPanel(new FlowLayout()), BorderLayout.NORTH);
+               this.frame.add(this.labelStatusLine = new JLabel(I18N.tr("welcome")), BorderLayout.SOUTH);
+
+               this.panelHead.add(new JLabel(I18N.tr("Server:")));
+               this.panelHead.add(this.textFieldServer = new JTextField("localhost"));
+               this.panelHead.add(new JLabel(I18N.tr("Port:")));
+               this.panelHead.add(this.textFieldPort = new JTextField("15000"));
+
+               this.panelCenter.add(this.tabbedPane = new JTabbedPane());
+               this.tabbedPane.addTab(I18N.tr("Output"), this.panelOutput = new JPanel());
+               this.tabbedPane.addTab(I18N.tr("Diagram"), this.panelData = new Diagram());
+               this.tabbedPane.addTab(I18N.tr("Log"), this.panelLog = new JPanel());
+       }
+
+       public void run() {
+               // Display the window.
+               this.frame.pack();
+               this.frame.setVisible(true);
+       }
+}
diff --git a/src/main/java/de/republib/util/BytePairData.java b/src/main/java/de/republib/util/BytePairData.java
new file mode 100644 (file)
index 0000000..06c10e6
--- /dev/null
@@ -0,0 +1,122 @@
+/**
+ *
+ */
+package de.republib.util;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * @author hm
+ *
+ */
+public class BytePairData extends DynBytes implements IPairData {
+       static Logger logger = LoggerFactory.getLogger(BytePairData.class);
+       private final double minX;
+
+       private final double maxX;
+
+       private final int dataWidth;
+
+       /**
+        * Constructor.
+        *
+        * @param capacity
+        * @param blocksize
+        * @param minX
+        * @param maxX
+        * @param dataWidth
+        */
+       public BytePairData(int capacity, int blocksize, double minX, double maxX, int dataWidth) {
+               super(capacity, blocksize);
+               if (dataWidth < 0 || dataWidth > 8) {
+                       BytePairData.logger.error("getY(): illegal data width: {:d}", dataWidth);
+                       dataWidth = 1;
+               }
+               this.minX = minX;
+               this.maxX = maxX;
+               this.dataWidth = dataWidth;
+       }
+
+       /**
+        * @return the dataWidth
+        */
+       public int getDataWidth() {
+               return this.dataWidth;
+       }
+
+       /**
+        * @return the maxX
+        */
+       public double getMaxX() {
+               return this.maxX;
+       }
+
+       /**
+        * @return the minX
+        */
+       public double getMinX() {
+               return this.minX;
+       }
+
+       /*
+        * (non-Javadoc)
+        *
+        * @see de.republib.util.IData2D#getSteps()
+        */
+       @Override
+       public int getSteps() {
+               return this.length / this.dataWidth;
+       }
+
+       /*
+        * (non-Javadoc)
+        *
+        * @see de.republib.util.IData2D#getX(int)
+        */
+       @Override
+       public double getX(int index) {
+               double x = this.minX;
+               if (index < 0 || index >= this.length / this.dataWidth) {
+                       BytePairData.logger.error("getX(): wrong index: {:d} / {:d}", index, this.length / this.dataWidth);
+               } else {
+                       x = this.minX + index * (this.maxX - this.minX) / (this.length / this.dataWidth);
+               }
+               return x;
+       }
+
+       /*
+        * (non-Javadoc)
+        *
+        * @see de.republib.util.IData2D#getY(int)
+        */
+       @Override
+       public double getY(int index) {
+               double y = 0.0;
+               if (index < 0 || index >= this.length / this.dataWidth) {
+                       BytePairData.logger.error("getY(): wrong index: {:d} / {:d}", index, this.length / this.dataWidth);
+               } else {
+                       switch (this.dataWidth) {
+                       case 1:
+                               y = this.buffer[index];
+                               break;
+                       case 2:
+                       case 3:
+                       case 4:
+                               y = this.intAsLittleEndian(index * this.dataWidth, this.dataWidth, 0);
+                               break;
+                       case 5:
+                       case 6:
+                       case 7:
+                       case 8:
+                               y = this.longAsLittleEndian(index * this.dataWidth, this.dataWidth, 0);
+                               break;
+                       default:
+                               BytePairData.logger.error("getY(): illegal data width: {:d}", index, this.dataWidth);
+                               break;
+                       }
+               }
+               return y;
+       }
+
+}
index 2ab43a57bb0c9fffb85b4e95e71e09d1cd0a6f6b..d01cfaafe86260189d14814ca08610e14014f454 100644 (file)
@@ -163,7 +163,9 @@ public class DynBytes {
         * @return the instance (for chaining)
         */
        public DynBytes appendLittleEndian(int number, int width) {
-               if (width >= 1 && width <= 4) {
+               if (width < 1 || width > 4) {
+                       DynBytes.logger.debug("appendLitleEndian(%d, %d); wrong width", number, width);
+               } else {
                        ensureSize(this.length + width);
                        for (int ix = 0; ix < width; ix++) {
                                this.buffer[this.length++] = (byte) (number & 0xff);
@@ -301,6 +303,10 @@ public class DynBytes {
                        for (int ii = width - 1; ii >= 0; ii--) {
                                rc = (rc << 8) | ((this.buffer[index + ii]) & 0xff);
                        }
+                       // first bit == 1?
+                       if (width < 4 && rc >> (width * 8 - 1) != 0) {
+                               rc = rc - (1 << width * 8);
+                       }
                }
                return rc;
        }
@@ -321,6 +327,10 @@ public class DynBytes {
                        for (int ii = width - 1; ii >= 0; ii--) {
                                rc = (rc << 8) | ((this.buffer[index + ii]) & 0xff);
                        }
+                       // first bit == 1?
+                       if (width < 8 && rc >> (width * 8 - 1) != 0) {
+                               rc = rc - (1L << width * 8);
+                       }
                }
                return rc;
        }
diff --git a/src/main/java/de/republib/util/FunctionPairData.java b/src/main/java/de/republib/util/FunctionPairData.java
new file mode 100644 (file)
index 0000000..a4cf5d1
--- /dev/null
@@ -0,0 +1,158 @@
+/**
+ *
+ */
+package de.republib.util;
+
+/**
+ * Generate mathematical functions as (x, y) pairs.
+ *
+ * @author hm
+ *
+ */
+public class FunctionPairData implements IPairData {
+       private final MathFunction function;
+
+       private final double xMin;
+
+       private final double xMax;
+
+       private double factor = 1.0;
+
+       private double factor2 = 1.0;
+
+       private double offset = 0.0;
+
+       private final int steps;
+
+       public FunctionPairData(MathFunction function, double xMin, double xMax, int steps) {
+               this.function = function;
+               this.xMax = xMax;
+               this.xMin = xMin;
+               this.steps = steps;
+       }
+
+       /**
+        * @return the factor
+        */
+       public double getFactor() {
+               return this.factor;
+       }
+
+       /**
+        * @return the factor2
+        */
+       public double getFactor2() {
+               return this.factor2;
+       }
+
+       /**
+        * @return the function
+        */
+       public MathFunction getFunction() {
+               return this.function;
+       }
+
+       /**
+        * @return the offset
+        */
+       public double getOffset() {
+               return this.offset;
+       }
+
+       /*
+        * (non-Javadoc)
+        *
+        * @see de.republib.util.IPairData#getCount()
+        */
+       @Override
+       public int getSteps() {
+               return this.steps;
+       }
+
+       /*
+        * (non-Javadoc)
+        *
+        * @see de.republib.util.IPairData#getX(int)
+        */
+       @Override
+       public double getX(int index) {
+               return this.xMin + (this.xMax - this.xMin) * index / this.steps;
+       }
+
+       /**
+        * @return the xMax
+        */
+       public double getxMax() {
+               return this.xMax;
+       }
+
+       /**
+        * @return the xMin
+        */
+       public double getxMin() {
+               return this.xMin;
+       }
+
+       /*
+        * (non-Javadoc)
+        *
+        * @see de.republib.util.IPairData#getY(int)
+        */
+       @Override
+       public double getY(int index) {
+               double y = 0.0;
+               final double x = getX(index);
+               switch (this.function) {
+               case COS:
+                       y = Math.cos(x);
+                       break;
+               case SIN:
+                       y = Math.sin(x);
+                       break;
+               case TAN:
+                       y = Math.tan(x);
+                       break;
+               case EXP:
+                       y = Math.exp(x);
+                       break;
+               case X:
+                       y = x;
+                       break;
+               case LOG:
+                       if (x > 0) {
+                               y = Math.log(x);
+                       }
+                       break;
+               case X2:
+                       y = x * x + this.factor2 / this.factor * x;
+                       break;
+               default:
+                       break;
+               }
+               return y * this.factor + this.offset;
+       }
+
+       /**
+        * @param factor
+        *            the factor to set
+        */
+       public void setFactor(double factor) {
+               this.factor = factor;
+       }
+
+       /**
+        * @param factor2
+        *            the factor2 to set
+        */
+       public void setFactor2(double factor2) {
+               this.factor2 = factor2;
+       }
+
+       /**
+        * @param offset
+        *            the offset to set
+        */
+       public void setOffset(double offset) {
+               this.offset = offset;
+       }
+}
diff --git a/src/main/java/de/republib/util/I18N.java b/src/main/java/de/republib/util/I18N.java
new file mode 100644 (file)
index 0000000..b8932ae
--- /dev/null
@@ -0,0 +1,23 @@
+/**
+ *
+ */
+package de.republib.util;
+
+/**
+ * Internationalization.
+ *
+ * @author hm
+ *
+ */
+public class I18N {
+       /**
+        * Translate a string.
+        *
+        * @param text
+        *            text to translate
+        * @return the translated text
+        */
+       public static String tr(final String key) {
+               return key;
+       }
+}
diff --git a/src/main/java/de/republib/util/IPairData.java b/src/main/java/de/republib/util/IPairData.java
new file mode 100644 (file)
index 0000000..257abca
--- /dev/null
@@ -0,0 +1,38 @@
+/**
+ *
+ */
+package de.republib.util;
+
+/**
+ * Interface of a data storage for (x, y) pairs.
+ *
+ * @author hm
+ *
+ */
+public interface IPairData {
+
+       /**
+        * Returns the number of (x, y) pairs.
+        *
+        * @return the number of pairs.
+        */
+       int getSteps();
+
+       /**
+        * Returns the n-th x value.
+        *
+        * @param index
+        *            index of the x value: 0..getCount() - 1
+        * @return the <i>index</i>-th x value
+        */
+       double getX(int index);
+
+       /**
+        * Returns the n-th y value.
+        *
+        * @param index
+        *            index of the x value: 0..getCount() - 1
+        * @return the <i>index</i>-th x value
+        */
+       double getY(int index);
+}
diff --git a/src/main/java/de/republib/util/MathFunction.java b/src/main/java/de/republib/util/MathFunction.java
new file mode 100644 (file)
index 0000000..af8a1ce
--- /dev/null
@@ -0,0 +1,12 @@
+/**
+ *
+ */
+package de.republib.util;
+
+/**
+ * @author hm
+ *
+ */
+public enum MathFunction {
+       UNDEF, SIN, COS, TAN, X, X2, EXP, LOG
+}
diff --git a/src/main/java/de/republib/util/PairData.java b/src/main/java/de/republib/util/PairData.java
new file mode 100644 (file)
index 0000000..6d3c517
--- /dev/null
@@ -0,0 +1,32 @@
+/**
+ *
+ */
+package de.republib.util;
+
+/**
+ * @author hm
+ *
+ */
+public class PairData {
+       public static double maxY(IPairData data) {
+               double rc = data.getY(0);
+               for (int ix = data.getSteps() - 1; ix > 0; ix--) {
+                       final double current = data.getY(ix);
+                       if (current > rc) {
+                               rc = current;
+                       }
+               }
+               return rc;
+       }
+
+       public static double minY(IPairData data) {
+               double rc = data.getY(0);
+               for (int ix = data.getSteps() - 1; ix > 0; ix--) {
+                       final double current = data.getY(ix);
+                       if (current > rc) {
+                               rc = current;
+                       }
+               }
+               return rc;
+       }
+}
diff --git a/src/test/java/de/republib/util/BytePairDataTest.java b/src/test/java/de/republib/util/BytePairDataTest.java
new file mode 100644 (file)
index 0000000..b547273
--- /dev/null
@@ -0,0 +1,90 @@
+package de.republib.util;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+/**
+ * Tests the class BytePairData.
+ *
+ * @author hm
+ *
+ */
+public class BytePairDataTest {
+       static Logger logger = LoggerFactory.getLogger(BytePairDataTest.class);
+
+       @Test
+       public void BytePairData() {
+               for (int width = 1; width <= 8; width++) {
+                       for (int count = 256; count < width * 256; count++) {
+                               testOne(count, width);
+                       }
+               }
+       }
+
+       @Test
+       public void getSteps() {
+               testOne(1024, 3);
+               testOne(1024 * 64, 5);
+               testOne(1024 * 128, 8);
+               final BytePairData data = new BytePairData(133, 16, -44.0, 2.55, 2);
+               Assert.assertEquals(data.getLength(), 0);
+
+               Assert.assertEquals(data.getSteps(), 0);
+               Assert.assertEquals(data.getMinX(), -44.0);
+               Assert.assertEquals(data.getMaxX(), 2.55);
+       }
+
+       @Test
+       public void getX() {
+               final BytePairData data = new BytePairData(133, 16, -1000.0, 1000.0, 4);
+               Assert.assertEquals(data.getLength(), 0);
+               for (int ix = 0; ix < 1000; ix++) {
+                       data.appendLittleEndian(ix * 314, 4);
+               }
+               Assert.assertEquals(data.getSteps(), 1000);
+               for (int ix = 0; ix < 1000; ix++) {
+                       Assert.assertEquals(data.getX(ix), (-1000.0 + ix * 2));
+                       Assert.assertEquals(data.getY(ix), 314.0 * ix);
+               }
+       }
+
+       @Test
+       public void getY() {
+               final BytePairData data = new BytePairData(133, 16, -50.0, 50, 8);
+               Assert.assertEquals(data.getLength(), 0);
+               for (int ix = 0; ix < 1000; ix++) {
+                       data.appendLittleEndian((long) ix * ix, 8);
+               }
+               Assert.assertEquals(data.getSteps(), 1000);
+               for (int ix = 0; ix < 1000; ix++) {
+                       Assert.assertEquals(data.getX(ix), (-50.0 + ix / 10.0));
+                       Assert.assertEquals(data.getY(ix), (double) ix * ix);
+               }
+       }
+
+       private void testOne(int count, int dataWidth) {
+               // BytePairDataTest.logger.info(String.format("count: %d width: %d",
+               // count, dataWidth));
+               // capacity should be incremented:
+               final BytePairData data = new BytePairData(count * dataWidth - 16, 16, 0.0, count, dataWidth);
+               for (int ix = 0; ix < count; ix++) {
+                       data.appendLittleEndian((long) (ix % 128 - 128), dataWidth);
+               }
+               if (data.getCapacity() < count * dataWidth) {
+                       Assert.assertTrue(data.getCapacity() >= count * dataWidth);
+               }
+               Assert.assertEquals(data.getBlocksize(), 16);
+               Assert.assertEquals(data.getLength(), count * dataWidth);
+
+               Assert.assertEquals(data.getSteps(), count);
+               Assert.assertEquals(data.getMinX(), 0.0);
+               Assert.assertEquals(data.getMaxX(), (double) count);
+               Assert.assertEquals(data.getSteps(), count);
+               for (int ix = 0; ix < count; ix++) {
+                       Assert.assertEquals(data.getX(ix), (double) ix);
+                       Assert.assertEquals(data.getY(ix), (double) (ix % 128 - 128));
+               }
+       }
+}
index 194ccfb3c504574b0d204a53ed079b6c61d7e495..4e6e3f8fc131fa05b7abc7ad8a607ba1a1b4a7d2 100644 (file)
@@ -137,8 +137,8 @@ public class DynBytesTest {
        public void testIntAsLittleEndian() {
                final DynBytes buffer = new DynBytes(16, 2);
                buffer.appendLittleEndian(0x1234567890abcdefL, 8);
-               Assert.assertEquals(buffer.intAsLittleEndian(0, 1, -1), 0xef);
-               Assert.assertEquals(buffer.intAsLittleEndian(0, 3, -1), 0xabcdef);
+               Assert.assertEquals(buffer.intAsLittleEndian(0, 1, -1), -17 /* 0xef */);
+               Assert.assertEquals(buffer.intAsLittleEndian(0, 3, -1), -5517841 /* 0xabcdef */);
                Assert.assertEquals(buffer.intAsLittleEndian(1, 4, -1), 0x7890abcd);
                Assert.assertEquals(buffer.intAsLittleEndian(6, 2, -1), 0x1234);
 
@@ -150,14 +150,24 @@ public class DynBytesTest {
                // wrong width:
                Assert.assertEquals(buffer.intAsLittleEndian(0, 0, -5), -5);
                Assert.assertEquals(buffer.intAsLittleEndian(0, 5, -6), -6);
+
+               // negative values:
+               buffer.setLength(0).appendLittleEndian(-128, 1);
+               Assert.assertEquals(buffer.intAsLittleEndian(0, 1, -5), -128);
+               buffer.setLength(0).appendLittleEndian(-32000, 2);
+               Assert.assertEquals(buffer.intAsLittleEndian(0, 2, -5), -32000);
+               buffer.setLength(0).appendLittleEndian(-1, 3);
+               Assert.assertEquals(buffer.intAsLittleEndian(0, 3, -5), -1);
+               buffer.setLength(0).appendLittleEndian(-1, 4);
+               Assert.assertEquals(buffer.intAsLittleEndian(0, 4, -5), -1);
        }
 
        @org.testng.annotations.Test
        public void testLongAsLittleEndian() {
                final DynBytes buffer = new DynBytes(16, 2);
                buffer.appendLittleEndian(0x1234567890abcdefL, 8);
-               Assert.assertEquals(buffer.longAsLittleEndian(0, 1, -1), 0xefL);
-               Assert.assertEquals(buffer.longAsLittleEndian(0, 3, -1), 0xabcdefL);
+               Assert.assertEquals(buffer.longAsLittleEndian(0, 1, -1), -17L /* 0xef */);
+               Assert.assertEquals(buffer.longAsLittleEndian(0, 3, -1), -5517841L /* 0xabcdef */);
                Assert.assertEquals(buffer.longAsLittleEndian(1, 4, -1), 0x7890abcdL);
                Assert.assertEquals(buffer.longAsLittleEndian(6, 2, -1), 0x1234L);
 
@@ -169,6 +179,22 @@ public class DynBytesTest {
                // wrong width:
                Assert.assertEquals(buffer.intAsLittleEndian(0, 0, -5), -5);
                Assert.assertEquals(buffer.intAsLittleEndian(0, 5, -6), -6);
+
+               // negative values:
+               for (int width = 1; width <= 8; width++) {
+                       buffer.setLength(0).appendLittleEndian(-1L, width);
+                       Assert.assertEquals(buffer.longAsLittleEndian(0, width, -5), -1);
+                       buffer.setLength(0).appendLittleEndian(-128L, width);
+                       Assert.assertEquals(buffer.longAsLittleEndian(0, width, -5), -128L);
+               }
+               buffer.setLength(0).appendLittleEndian(-128, 1);
+               Assert.assertEquals(buffer.longAsLittleEndian(0, 1, -5), -128);
+               buffer.setLength(0).appendLittleEndian(-32000, 2);
+               Assert.assertEquals(buffer.longAsLittleEndian(0, 2, -5), -32000);
+               buffer.setLength(0).appendLittleEndian(-1, 3);
+               Assert.assertEquals(buffer.longAsLittleEndian(0, 3, -5), -1);
+               buffer.setLength(0).appendLittleEndian(-1, 4);
+               Assert.assertEquals(buffer.longAsLittleEndian(0, 4, -5), -1);
        }
 
        @org.testng.annotations.Test
diff --git a/src/test/java/de/republib/util/FunctionPairDataTest.java b/src/test/java/de/republib/util/FunctionPairDataTest.java
new file mode 100644 (file)
index 0000000..3fc2b2c
--- /dev/null
@@ -0,0 +1,131 @@
+package de.republib.util;
+
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+public class FunctionPairDataTest {
+
+       void checkFunctionCos() {
+               final FunctionPairData data = new FunctionPairData(MathFunction.COS, 0.0, 4 * Math.PI / 4, 4);
+               data.setFactor(2);
+               data.setOffset(-15);
+               Assert.assertEquals(data.getSteps(), 4);
+               Assert.assertEquals(data.getY(0), -15.0 + 2 * Math.cos(0.0));
+               Assert.assertEquals(data.getY(1), -15 + 2 * Math.cos(Math.PI / 4));
+               Assert.assertEquals(data.getY(2), -15 + 2 * Math.cos(Math.PI / 2));
+               Assert.assertEquals(data.getY(3), -15 + 2 * Math.cos(3 * Math.PI / 4));
+       }
+
+       void checkFunctionExp() {
+               final FunctionPairData data = new FunctionPairData(MathFunction.EXP, 0.0, 4.0, 4);
+               data.setFactor(10);
+               data.setOffset(3);
+               Assert.assertEquals(data.getSteps(), 4);
+               Assert.assertEquals(data.getY(0), 13.0);
+               Assert.assertEquals(data.getY(1), 3 + 10 * Math.exp(1.0));
+               Assert.assertEquals(data.getY(2), 3 + 10 * Math.exp(2.0));
+               Assert.assertEquals(data.getY(3), 3 + 10 * Math.exp(3.0));
+       }
+
+       void checkFunctionLog() {
+               final FunctionPairData data = new FunctionPairData(MathFunction.LOG, 1.0, 5.0, 4);
+               data.setFactor(7);
+               data.setOffset(5);
+               Assert.assertEquals(data.getSteps(), 4);
+               Assert.assertEquals(data.getY(0), 5.0 + 7 * Math.log(1));
+               Assert.assertEquals(data.getY(1), 5.0 + 7 * Math.log(2.0));
+               Assert.assertEquals(data.getY(2), 5.0 + 7 * Math.log(3.0));
+               Assert.assertEquals(data.getY(3), 5.0 + 7 * Math.log(4.0));
+       }
+
+       void checkFunctionSin() {
+               final FunctionPairData data = new FunctionPairData(MathFunction.SIN, 0.0, 4 * Math.PI / 4, 4);
+               data.setFactor(2);
+               data.setOffset(-15);
+               Assert.assertEquals(data.getSteps(), 4);
+               Assert.assertEquals(data.getY(0), -15.0);
+               Assert.assertEquals(data.getY(1), -15 + 2 * Math.sin(Math.PI / 4));
+               Assert.assertEquals(data.getY(2), -15 + 2 * Math.sin(Math.PI / 2));
+               Assert.assertEquals(data.getY(3), -15 + 2 * Math.sin(3 * Math.PI / 4));
+       }
+
+       void checkFunctionTan() {
+               final FunctionPairData data = new FunctionPairData(MathFunction.TAN, 0.0, 4 * Math.PI / 4, 4);
+               data.setFactor(2);
+               data.setOffset(-3);
+               Assert.assertEquals(data.getSteps(), 4);
+               Assert.assertEquals(data.getY(0), -3.0);
+               Assert.assertEquals(data.getY(1), -3 + 2 * Math.tan(Math.PI / 4));
+               Assert.assertEquals(data.getY(2), -3 + 2 * Math.tan(Math.PI / 2));
+               Assert.assertEquals(data.getY(3), -3 + 2 * Math.tan(3 * Math.PI / 4));
+       }
+
+       void checkFunctionX() {
+               final FunctionPairData data = new FunctionPairData(MathFunction.X, 0.0, 100.0, 10);
+               data.setFactor(2.0);
+               data.setOffset(-5.0);
+               Assert.assertEquals(data.getSteps(), 10);
+               Assert.assertEquals(data.getY(0), -5.0);
+               Assert.assertEquals(data.getY(9), -5.0 + (100.0 - 10) * 2);
+       }
+
+       void checkFunctionX2() {
+               final FunctionPairData data = new FunctionPairData(MathFunction.X2, 0.0, 2.0, 2);
+               data.setFactor(0.5);
+               data.setFactor2(3.0);
+               data.setOffset(-10.0);
+               Assert.assertEquals(data.getSteps(), 2);
+               Assert.assertEquals(data.getY(0), -10.0);
+               Assert.assertEquals(data.getY(2), -10.0 + 0.5 * 2.0 * 2.0 + 2.0 * 3);
+       }
+
+       @Test
+       public void FunctionPairData() {
+               final FunctionPairData data = new FunctionPairData(MathFunction.X, 0.0, 100.0, 10);
+               Assert.assertEquals(data.getSteps(), 10);
+       }
+
+       @Test
+       public void getSteps() {
+               final FunctionPairData data = new FunctionPairData(MathFunction.X2, 0.0, 100.0, 432);
+               Assert.assertEquals(data.getSteps(), 432);
+       }
+
+       @Test
+       public void getX() {
+               final FunctionPairData data = new FunctionPairData(MathFunction.SIN, 0.0, 100.0, 432);
+               Assert.assertEquals(data.getSteps(), 432);
+       }
+
+       @Test
+       public void getY() {
+               checkFunctionX();
+               checkFunctionX2();
+               checkFunctionSin();
+               checkFunctionCos();
+               checkFunctionTan();
+               checkFunctionExp();
+               checkFunctionLog();
+       }
+
+       @Test
+       public void setFactor() {
+               final FunctionPairData data = new FunctionPairData(MathFunction.SIN, 0.0, 100.0, 432);
+               data.setFactor(44.33);
+               Assert.assertEquals(data.getFactor(), 44.33);
+       }
+
+       @Test
+       public void setFactor2() {
+               final FunctionPairData data = new FunctionPairData(MathFunction.SIN, 0.0, 100.0, 432);
+               data.setFactor2(88.33);
+               Assert.assertEquals(data.getFactor2(), 88.33);
+       }
+
+       @Test
+       public void setOffset() {
+               final FunctionPairData data = new FunctionPairData(MathFunction.SIN, 0.0, 100.0, 432);
+               data.setOffset(-32.44);
+               Assert.assertEquals(data.getOffset(), -32.44);
+       }
+}