--- /dev/null
+/**
+ *
+ */
+package de.republib.gui;
+
+import java.awt.Color;
+import java.awt.Graphics;
+import java.util.LinkedList;
+import java.util.List;
+
+import de.republib.util.DoublePair;
+import de.republib.util.IPairData;
+import de.republib.util.PairData;
+
+/**
+ * Manages a set of curves as part of a <i>MultiChannelSheet</i>.
+ *
+ * A channel is an area in a diagram with its own real world coordinates. The
+ * channels are ordered vertically in the sheet.
+ *
+ * @author hm
+ *
+ */
+public class Channel {
+ private static final Color colorLegend = Color.BLACK;
+ private final int index;
+ private final MultiChannelSheet parent;
+ private double realX0 = 0.0;
+ private double realWidth = 1.0;
+ private double realY0 = 0.0;
+ private double realHeight = 1.0;
+ private int x0 = 0;
+ private int width = 800;
+ private int y0 = 0;
+ private int height = 600;
+ private final List<IPairData> curves = new LinkedList<IPairData>();
+
+ private final Color[] colorData = { Color.BLUE, Color.RED, Color.CYAN, Color.GREEN, Color.MAGENTA, Color.DARK_GRAY,
+ Color.ORANGE, Color.PINK };
+
+ /**
+ * Constructor.
+ *
+ * @param index
+ * the index in the list of the parent
+ * @param parent
+ * the multi channel sheet
+ */
+ public Channel(int index, MultiChannelSheet parent) {
+ this.index = index;
+ this.parent = parent;
+ }
+
+ /**
+ * @return the data
+ */
+ public List<IPairData> getCurves() {
+ return this.curves;
+ }
+
+ /**
+ * @return the height
+ */
+ public int getHeight() {
+ return this.height;
+ }
+
+ /**
+ * @return the index
+ */
+ public int getIndex() {
+ return this.index;
+ }
+
+ /**
+ * @return the parent
+ */
+ public MultiChannelSheet getParent() {
+ return this.parent;
+ }
+
+ /**
+ * @return the realHeight
+ */
+ public double getRealHeight() {
+ return this.realHeight;
+ }
+
+ /**
+ * @return the realWidth
+ */
+ public double getRealWidth() {
+ return this.realWidth;
+ }
+
+ /**
+ * @return the realX0
+ */
+ public double getRealX0() {
+ return this.realX0;
+ }
+
+ /**
+ * @return the realY0
+ */
+ public double getRealY0() {
+ return this.realY0;
+ }
+
+ /**
+ * @return the width
+ */
+ public int getWidth() {
+ return this.width;
+ }
+
+ /**
+ * @return the x0
+ */
+ public int getX0() {
+ return this.x0;
+ }
+
+ /**
+ * @return the y0
+ */
+ public int getY0() {
+ return this.y0;
+ }
+
+ /**
+ * Draw the channel.
+ *
+ * @param graphics
+ * the graphical properties
+ */
+ public void paint(Graphics graphics) {
+ int no = -1;
+ for (final IPairData curve : this.curves) {
+ graphics.setColor(this.colorData[++no % this.colorData.length]);
+ final DoublePair minMax = PairData.minMaxY(curve, null);
+ this.realX0 = curve.getX(0);
+ this.realWidth = curve.getX(curve.getSteps() - 1) - this.realX0;
+ this.realY0 = minMax.getValue1();
+ final int steps = curve.getSteps();
+ final double maxY = minMax.getValue2();
+ this.realHeight = maxY + (maxY - this.realY0) / steps;
+ int lastX = 0, lastY = 0;
+ for (int ix = 0; ix < curve.getSteps(); ix++) {
+ final int x = transformX(curve.getX(ix));
+ final int y = transformY(curve.getY(ix));
+ if (ix > 0) {
+ graphics.drawLine(lastX, lastY, x, y);
+ }
+ lastX = x;
+ lastY = y;
+ }
+ }
+ paintLegend(graphics);
+ }
+
+ /**
+ * Paints the scale data, title...
+ *
+ * @param graphics
+ * the graphical properties
+ */
+ private void paintLegend(Graphics graphics) {
+ graphics.setFont(this.parent.getFont());
+ graphics.setColor(Channel.colorLegend);
+ final int x = this.x0 + this.width / 2;
+ final int y = this.y0 + this.parent.getFontSizeLegend() + 5;
+ final IPairData data = this.curves.get(0);
+ graphics.drawString(data.getName(), x, y);
+ String text = String.format("(%.1g, %.1g)", data.getX(0), data.getY(0));
+ graphics.drawString(text, this.x0 + 5, this.y0 + this.getHeight() - this.parent.getFontSizeLegend());
+ final int lastIx = data.getSteps() - 1;
+ text = String.format("(%.1g, %.1g)", data.getX(lastIx), data.getY(lastIx));
+ final int width = graphics.getFontMetrics().stringWidth(text);
+ graphics.drawString(text, this.x0 + this.width - width - 5, y);
+ }
+
+ /**
+ * @param height
+ * the height to set
+ */
+ public void setHeight(int height) {
+ this.height = height;
+ }
+
+ /**
+ * @param realHeight
+ * the realHeight to set
+ */
+ public void setRealHeight(double realHeight) {
+ this.realHeight = realHeight;
+ }
+
+ /**
+ * @param realWidth
+ * the realWidth to set
+ */
+ public void setRealWidth(double realWidth) {
+ this.realWidth = realWidth;
+ }
+
+ /**
+ * @param realX0
+ * the realX0 to set
+ */
+ public void setRealX0(double realX0) {
+ this.realX0 = realX0;
+ }
+
+ /**
+ * @param realY0
+ * the realY0 to set
+ */
+ public void setRealY0(double realY0) {
+ this.realY0 = realY0;
+ }
+
+ /**
+ * @param width
+ * the width to set
+ */
+ public void setWidth(int width) {
+ this.width = width;
+ }
+
+ /**
+ * @param x0
+ * the x0 to set
+ */
+ public void setX0(int x0) {
+ this.x0 = x0;
+ }
+
+ /**
+ * @param y0
+ * the y0 to set
+ */
+ public void setY0(int y0) {
+ this.y0 = y0;
+ }
+
+ /**
+ * 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()) / (this.realWidth);
+ int rc;
+ if (xPixel < 0) {
+ rc = 0;
+ } else if (xPixel > getWidth()) {
+ rc = getWidth();
+ } else {
+ rc = (int) Math.round(xPixel);
+ }
+ return this.x0 + 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()) / this.realHeight;
+ int rc;
+ if (yPixel < 0) {
+ rc = getHeight();
+ } else if (yPixel > getHeight()) {
+ rc = -1;
+ } else {
+ rc = getHeight() - (int) Math.round(yPixel);
+ }
+ return this.y0 + rc;
+ }
+}
--- /dev/null
+/**
+ *
+ */
+package de.republib.gui;
+
+import java.awt.BasicStroke;
+import java.awt.Color;
+import java.awt.Font;
+import java.awt.Graphics;
+import java.awt.Graphics2D;
+import java.util.LinkedList;
+import java.util.List;
+
+import javax.swing.JPanel;
+
+import de.republib.util.DoublePair;
+import de.republib.util.IPairData;
+import de.republib.util.PairData;
+
+/**
+ * A diagram sheet.
+ *
+ * <pre>
+ * ----------------------------
+ * |<-- vertic. scale
+ * |
+ * |
+ * |
+ * | v-- horiz. scale
+ * |__________________________
+ * -----------------------------
+ * </pre>
+ *
+ * @author hm
+ *
+ */
+public class CurveSheet extends JPanel {
+ /**
+ *
+ */
+ private static final long serialVersionUID = 1L;
+ private double realX0 = 0.0;
+ private double realY0 = 0.0;
+ private double realWidth = 1.0;
+ private double realHeight = 1.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 widthLine = 3;
+ private final Color colorScale = Color.DARK_GRAY;
+ // private final Color colorSheet = Color.WHITE;
+ private final int fontSizeLegend = 16;
+ private final List<IPairData> data = new LinkedList<IPairData>();
+ private final Color[] colorData = { Color.BLUE, Color.RED, Color.CYAN, Color.GREEN, Color.MAGENTA, Color.DARK_GRAY,
+ Color.ORANGE, Color.PINK };
+ private Font font = null;
+
+ /**
+ * Appends a data package for drawing one line.
+ *
+ * @param data
+ * the pair data for one line
+ * @return the instance (for chaining)
+ */
+ public CurveSheet addData(IPairData data) {
+ this.data.add(data);
+ return this;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see javax.swing.JComponent#paintComponent(java.awt.Graphics)
+ */
+ @Override
+ protected void paintComponent(Graphics graphics) {
+ super.paintComponent(graphics);
+ paintScale(graphics);
+ paintData(graphics);
+ paintLegend(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;
+ if (this.font == null) {
+ this.font = new Font(graphics.getFont().getName(), graphics.getFont().getStyle(), this.fontSizeLegend);
+
+ }
+ final Graphics2D graphics2 = (Graphics2D) graphics;
+ graphics2.setStroke(new BasicStroke(this.widthLine));
+ int no = -1;
+ for (final IPairData data : this.data) {
+ graphics.setColor(this.colorData[++no % this.colorData.length]);
+ final DoublePair minMax = PairData.minMaxY(data, null);
+ this.realX0 = data.getX(0);
+ this.realWidth = data.getX(data.getSteps() - 1) - this.realX0;
+ this.realY0 = minMax.getValue1();
+ final int steps = data.getSteps();
+ final double maxY = minMax.getValue2();
+ this.realHeight = maxY + (maxY - this.realY0) / steps;
+ 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 data as lines in the sheet.
+ *
+ * @param graphics
+ * the graphic environment
+ */
+ protected void paintLegend(Graphics graphics) {
+ int no = 1;
+ final int x = getWidth() / 2;
+ graphics.setFont(this.font);
+ for (final IPairData data : this.data) {
+ final int y = (no + no / 4) * this.fontSizeLegend;
+ graphics.setColor(this.colorData[(no - 1) % this.colorData.length]);
+ graphics.drawString(data.getName(), x, y);
+ graphics.drawLine(x - 20, y, x - 5, y);
+ ++no;
+ }
+ }
+
+ /**
+ * Paints the scales.
+ *
+ * @param graphics
+ * the graphic environment
+ */
+ protected void paintScale(Graphics graphics) {
+ graphics.setColor(this.colorScale);
+ final int y0 = this.getHeight() - this.vScaleDistance;
+ final int y1 = this.vScaleDistance;
+ final int x0 = this.hScaleDistance;
+ final int x1 = this.getWidth() - this.hScaleDistance;
+ // vertical scale:
+ // graphics.drawLine(x0, y0, x0, y1);
+ // horizontal scale:
+ // graphics.drawLine(x0, y0, x1, y0);
+ int no = 1;
+ final int x = getWidth() / 2;
+ graphics.setFont(this.font);
+ final int textWidth = 75;
+ for (final IPairData data : this.data) {
+ final int yBottom = (no + no / 4) * this.fontSizeLegend;
+ graphics.setColor(this.colorData[(no - 1) % this.colorData.length]);
+ // bottom left to-top: xMin
+ String text = String.format("x0: %.1g", data.getX(0));
+ graphics.drawString(text, 2, y0 - this.fontSizeLegend / 2);
+ // bottom left to-right: yMin
+ text = String.format("y0: %.1g", data.getY(0));
+ graphics.drawString(text, textWidth * no, y0 - this.fontSizeLegend / 2);
+ // top left: to-right: yMax
+ text = String.format("y1: %.1g", data.getY(data.getSteps() - 1));
+ graphics.drawString(text, textWidth * no + textWidth * no / 8, 3 * this.fontSizeLegend / 2);
+ // top right: to-bottom: xMax
+ text = String.format("x1: %.1g", data.getX(data.getSteps() - 1));
+ graphics.drawString(text, this.getWidth() - textWidth,
+ no * this.fontSizeLegend + no * this.fontSizeLegend / 8);
+ ++no;
+ }
+ }
+
+ /**
+ * 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) / (this.realWidth);
+ 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) / this.realHeight;
+ int rc;
+ if (yPixel < 0) {
+ rc = getHeight();
+ } else if (yPixel > getHeight()) {
+ rc = -1;
+ } else {
+ rc = getHeight() - (int) Math.round(yPixel);
+ }
+ return rc;
+ }
+}
+++ /dev/null
-/**
- *
- */
-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.DoublePair;
-import de.republib.util.IPairData;
-import de.republib.util.PairData;
-
-/**
- * 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)
- */
- public 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) {
- final DoublePair minMax = PairData.minMaxY(data, null);
- this.realX0 = data.getX(0);
- this.realWidth = data.getX(data.getSteps() - 1) - this.realX0;
- this.realY0 = minMax.getValue1();
- final int steps = data.getSteps();
- final double maxY = minMax.getValue2();
- this.realHeight = maxY + (maxY - this.realY0) / steps;
- 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);
- final int y0 = this.getHeight() - this.vScaleDistance;
- final int y1 = this.vScaleDistance;
- final int x0 = this.hScaleDistance;
- final int x1 = this.getWidth() - this.hScaleDistance;
- // vertical scale:
- graphics.drawLine(x0, y0, x0, y1);
- // horizontal scale:
- graphics.drawLine(x0, y0, x1, y0);
-
- }
-
- /**
- * 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 = getHeight();
- } else if (yPixel > getHeight()) {
- rc = -1;
- } else {
- rc = getHeight() - (int) Math.round(yPixel);
- }
- return rc;
- }
-}
--- /dev/null
+/**
+ *
+ */
+package de.republib.gui;
+
+import java.awt.Color;
+import java.awt.Font;
+import java.awt.Graphics;
+import java.awt.event.ComponentAdapter;
+import java.awt.event.ComponentEvent;
+import java.util.ArrayList;
+
+import javax.swing.JPanel;
+
+import de.republib.util.IPairData;
+
+/**
+ * Manages a diagram with multiple <strong>channels</strong>.
+ *
+ * A channel is an area in a diagram with its own real world coordinates. The
+ * channels are ordered in a grid.<br>
+ * <br>
+ * Screen coordinates:<br>
+ * All channels of a column have the same width. Column widths can be different.
+ * Channel height can be different.
+ *
+ * <pre>
+ * __________________________
+ * | channel0 : channel3
+ * --------------------------
+ * | channel1 : channel4
+ * --------------------------
+ * | channel2 :
+ * __________________________
+ * </pre>
+ *
+ * @author hm
+ *
+ */
+public class MultiChannelSheet extends JPanel {
+ /**
+ * Serialization UnifiedId.
+ */
+ private static final long serialVersionUID = 1L;
+
+ private final int columnCount = 2;
+ private final int rowCount = 4;
+ private final ArrayList<Channel> channels = new ArrayList<>();
+ private final int widthGridLine = 1;
+ private final Color colorGridLine = Color.BLACK;
+ private Font font = null;
+ private final int fontSizeLegend = 14;
+
+ /**
+ * Constructor.
+ */
+ public MultiChannelSheet() {
+ addComponentListener(new ResizeListener(this));
+ }
+
+ /**
+ * Adds a channel to the sheet.
+ *
+ * @param channel
+ * the channel to add
+ * @return the instance (for chaining)
+ */
+ public MultiChannelSheet addChannel(IPairData data) {
+ final Channel channel = new Channel(this.channels.size(), this);
+ this.channels.add(channel);
+ channel.getCurves().add(data);
+ return this;
+ }
+
+ /**
+ * Returns the n-th channel.
+ *
+ * @param index
+ * index of the wanted channel.
+ * @return <i>null</i>: wrong index<br>
+ * otherwise: the index-th channel
+ */
+ Channel getChannel(int index) {
+ return index >= 0 && index < this.channels.size() ? this.channels.get(index) : null;
+ }
+
+ /**
+ * @return the channelCount
+ */
+ public int getChannelCount() {
+ return this.channels.size();
+ }
+
+ /**
+ * @return the font
+ */
+ @Override
+ public Font getFont() {
+ return this.font;
+ }
+
+ /**
+ * @return the fontSizeLegend
+ */
+ public int getFontSizeLegend() {
+ return this.fontSizeLegend;
+ }
+
+ /**
+ * Handles a resize event.
+ */
+ public void onResize() {
+ resizeChannels();
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see javax.swing.JComponent#paintComponent(java.awt.Graphics)
+ */
+ @Override
+ protected void paintComponent(Graphics graphics) {
+ if (this.font == null) {
+ this.font = new Font(graphics.getFont().getName(), graphics.getFont().getStyle(), this.fontSizeLegend);
+ }
+ super.paintComponent(graphics);
+ paintGrid(graphics);
+ final int count = getChannelCount();
+ for (int index = 0; index < count; index++) {
+ final Channel channel = this.channels.get(index);
+ channel.paint(graphics);
+ }
+ }
+
+ /**
+ * Paints the grid lines separating the channel areas.
+ *
+ * @param graphics
+ * the graphics properties
+ */
+ protected void paintGrid(Graphics graphics) {
+ graphics.setColor(this.colorGridLine);
+ final int x1 = this.getWidth();
+ final int y1 = this.getHeight();
+ final int height = y1 / this.rowCount;
+ final int width = x1 / this.columnCount;
+ // vertical lines:
+ for (int ix = 1; ix < this.columnCount; ix++) {
+ final int x = ix * width;
+ graphics.drawLine(x, 0, x, y1);
+ }
+ // horizontal lines:
+ for (int ix = 1; ix < this.rowCount; ix++) {
+ final int y = ix * height;
+ graphics.drawLine(0, y, x1, y);
+ }
+ }
+
+ /**
+ * Divides the current sheet to the current channels.
+ */
+ private void resizeChannels() {
+ final int count = getChannelCount();
+ int lastY = 0;
+ int lastX = 0;
+ final int height = getHeight() / this.rowCount;
+ int width = getWidth() / this.columnCount;
+ for (int index = 0; index < count; index++) {
+ final Channel channel = this.channels.get(index);
+ final int col = index / this.rowCount;
+ final int row = index % this.rowCount;
+ channel.setY0(lastY);
+ channel.setX0(lastX);
+ channel.setWidth(width - this.widthGridLine);
+ if (row % this.rowCount == this.rowCount - 1) {
+ channel.setHeight(getHeight() - lastY);
+ lastY = 0;
+ lastX += width;
+ if (col == this.columnCount - 1) {
+ width = getWidth() - lastX;
+ }
+ } else {
+ channel.setHeight(height - this.widthGridLine);
+ lastY += height;
+ }
+ }
+ }
+
+ /**
+ * @param channelCount
+ * the channelCount to set
+ */
+ public void setChannelCount(int channelCount) {
+ boolean changed = false;
+ while (this.channels.size() > channelCount) {
+ this.channels.remove(this.channels.size() - 1);
+ changed = true;
+ }
+ while (this.channels.size() < channelCount) {
+ this.channels.add(new Channel(this.channels.size(), this));
+ changed = true;
+ }
+ if (changed) {
+ resizeChannels();
+ }
+ }
+
+ /**
+ * @param font
+ * the font to set
+ */
+ @Override
+ public void setFont(Font font) {
+ this.font = font;
+ }
+}
+
+class ResizeListener extends ComponentAdapter {
+ MultiChannelSheet sheet;
+
+ ResizeListener(MultiChannelSheet sheet) {
+ this.sheet = sheet;
+ }
+
+ @Override
+ public void componentResized(ComponentEvent e) {
+ this.sheet.onResize();
+ }
+}
import javax.swing.JTabbedPane;
import javax.swing.JTextField;
-import de.republib.gui.Diagram;
+import de.republib.gui.MultiChannelSheet;
import de.republib.util.FunctionPairData;
import de.republib.util.I18N;
import de.republib.util.MathFunction;
private JPanel panelOutput;
private JPanel panelLog;
private JLabel labelStatusLine;
- private Diagram panelData;
+ private MultiChannelSheet panelData;
private JPanel panelHead;
private JTextField textFieldServer;
private JTextField textFieldPort;
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("Diagram"), this.panelData = new MultiChannelSheet());
FunctionPairData function = new FunctionPairData(MathFunction.X, 0.0, 10.0, 790);
function.setFactor(9.0);
function.setOffset(1.0);
- this.panelData.addData(function);
+ this.panelData.addChannel(function);
function = new FunctionPairData(MathFunction.SIN, 0.0, 10.0, 790);
function.setFactor(4.0);
function.setOffset(5.0);
- this.panelData.addData(function);
+ this.panelData.addChannel(function);
+ function = new FunctionPairData(MathFunction.COS, 0.0, 10.0, 790);
+ function.setFactor(4.0);
+ function.setOffset(5.0);
+ this.panelData.addChannel(function);
+ function = new FunctionPairData(MathFunction.LOG, 0.01, 10.0, 790);
+ this.panelData.addChannel(function);
+ function = new FunctionPairData(MathFunction.EXP, -5.0, 5.0, 790);
+ this.panelData.addChannel(function);
+ function = new FunctionPairData(MathFunction.X2, -1, 2, 790);
+ this.panelData.addChannel(function);
+ function = new FunctionPairData(MathFunction.TAN, 0.0, 1.0, 790);
+ this.panelData.addChannel(function);
this.tabbedPane.addTab(I18N.tr("Log"), this.panelLog = new JPanel());
}
private final int dataWidth;
+ private String name;
+
/**
* Constructor.
*
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);
+ BytePairData.logger.error("getY(): illegal data width: %d", dataWidth);
dataWidth = 1;
}
+ this.name = String.format("%d bit data", 8 * dataWidth);
this.minX = minX;
this.maxX = maxX;
this.dataWidth = dataWidth;
return this.minX;
}
+ /**
+ * @return the name
+ */
+ @Override
+ public String getName() {
+ return this.name;
+ }
+
/*
* (non-Javadoc)
*
return y;
}
+ /**
+ * @param name
+ * the name to set
+ */
+ public void setName(String name) {
+ this.name = name;
+ }
+
}
private final int steps;
+ private String name;
+
public FunctionPairData(MathFunction function, double xMin, double xMax, int steps) {
this.function = function;
+ this.name = this.function.name();
this.xMax = xMax;
this.xMin = xMin;
this.steps = steps;
return this.function;
}
+ /**
+ * @return the name
+ */
+ @Override
+ public String getName() {
+ return this.name;
+ }
+
/**
* @return the offset
*/
default:
break;
}
- return y * this.factor + this.offset;
+ y = y * this.factor + this.offset;
+ return y;
}
/**
this.factor2 = factor2;
}
+ /**
+ * @param name
+ * the name to set
+ */
+ public void setName(String name) {
+ this.name = name;
+ }
+
/**
* @param offset
* the offset to set
*/
public interface IPairData {
+ /**
+ * Gets a name for the legend.
+ *
+ * @return a name of the data
+ */
+ String getName();
+
/**
* Returns the number of (x, y) pairs.
*
* @return the <i>index</i>-th x value
*/
double getY(int index);
+
+ /**
+ * Sets the name for the legend.
+ *
+ * @param name
+ * the name to set
+ */
+ void setName(String name);
}
--- /dev/null
+package de.republib.util;
+
+/**
+ * Helper class for strings.
+ *
+ * @author hm
+ *
+ */
+public class StringUtils {
+ /**
+ * Formats a double value.
+ *
+ * Wanted: a short string as possible.
+ *
+ * @param value
+ * value to format
+ * @param precision
+ * number of "valid digits": 0.034 and 1.2E99 have 2 valid
+ * digits<br>
+ * <i>precision</i> in [1, 3]
+ * @return the formatted strings
+ */
+ public static String formatFloat(double value, int precision) {
+ String rc = null;
+ if (precision <= 0) {
+ precision = 1;
+ }
+ if (value >= 1E6) {
+ rc = String.format("%.g", precision - 1, value);
+ } else if (value > 1.0) {
+ double limit;
+ int prec = 0;
+ switch (precision) {
+ case 1:
+ limit = 10.0;
+ prec = 0;
+ break;
+ case 2:
+ limit = 100.0;
+ prec = 1;
+ break;
+ case 3:
+ limit = 1000.0;
+ prec = 2;
+ break;
+ default:
+ limit = 1000.0;
+ break;
+ }
+ if (value >= limit) {
+ rc = String.format("%d", (int) Math.round(value));
+ } else {
+ rc = String.format("%.*g", prec, value);
+ }
+ } else if (value >= 1E-5) {
+ final double limit;
+ int prec;
+ switch (precision) {
+ case 1:
+ limit = 1E-4;
+ prec = 5;
+ break;
+ case 2:
+ limit = 1E-3;
+ prec = 4;
+ break;
+ case 3:
+ limit = 1E-2;
+ prec = 3;
+ break;
+ default:
+ limit = 1E-2;
+ prec = 3;
+ break;
+ }
+ if (value < limit) {
+
+ } else {
+ rc = String.format("%.*f", prec, value);
+ }
+ } else {
+ rc = String.format("%.*g", precision - 1, value);
+ }
+ return rc;
+ }
+}
--- /dev/null
+package de.republib.util;
+
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+public class StringUtilsTest {
+
+ private void checkPrec1() {
+ final double value = 1234567.77;
+ Assert.assertEquals(StringUtils.formatFloat(value, 3), "123E6");
+ Assert.assertEquals(StringUtils.formatFloat(123456.77, 3), "123456");
+ Assert.assertEquals(StringUtils.formatFloat(12345.77, 3), "123456");
+ Assert.assertEquals(StringUtils.formatFloat(1234.77, 3), "12345");
+ Assert.assertEquals(StringUtils.formatFloat(123.77, 3), "123");
+ Assert.assertEquals(StringUtils.formatFloat(12.77, 3), "12.7");
+ Assert.assertEquals(StringUtils.formatFloat(1.77, 3), "1.77");
+
+ }
+
+ private void checkPrec2() {
+
+ }
+
+ private void checkPrec3() {
+
+ }
+
+ @Test
+ public void formatFloat() {
+ checkPrec1();
+ checkPrec2();
+ checkPrec3();
+ }
+}