From 7267c7758eba5863ca28072a063e6064374f1e0b Mon Sep 17 00:00:00 2001 From: hama Date: Sat, 8 Nov 2014 08:48:18 +0100 Subject: [PATCH] Text widget, status line --- src/jlection/robotic/RobotModel.java | 5 +- src/jlecture/simulation/Alignment.java | 14 ++ src/jlecture/simulation/ISheet.java | 24 +++- src/jlecture/simulation/ITextWidget.java | 27 ++++ src/jlecture/simulation/Model.java | 122 ++++++++++++++++- src/jlecture/simulation/WidgetType.java | 2 +- src/jlecture/swing/PanelSwing.java | 7 +- src/jlecture/swing/SheetSwing.java | 12 +- src/jlecture/swing/TextSwing.java | 159 +++++++++++++++++++++++ 9 files changed, 356 insertions(+), 16 deletions(-) create mode 100644 src/jlecture/simulation/Alignment.java create mode 100644 src/jlecture/simulation/ITextWidget.java create mode 100644 src/jlecture/swing/TextSwing.java diff --git a/src/jlection/robotic/RobotModel.java b/src/jlection/robotic/RobotModel.java index 6968c55..14bbc0c 100644 --- a/src/jlection/robotic/RobotModel.java +++ b/src/jlection/robotic/RobotModel.java @@ -38,9 +38,10 @@ public class RobotModel extends Model { public void createModel() { final int count = 1000; final int width = 3; + addStatusSegment(this.positionStep, ""); + Barrier barrier = new Barrier(this.sheet.createRectangle(new PointRW( - 500, - 100), new DimensionRW(600, 100), false, this)); + 500, 100), new DimensionRW(600, 100), false, this)); barrier.getWidget().setColorBackground(Color.gray); this.things.add(barrier); barrier = new Barrier(this.sheet.createRectangle(new PointRW(500, 400), diff --git a/src/jlecture/simulation/Alignment.java b/src/jlecture/simulation/Alignment.java new file mode 100644 index 0000000..2f57405 --- /dev/null +++ b/src/jlecture/simulation/Alignment.java @@ -0,0 +1,14 @@ +/** + * + */ +package jlecture.simulation; + +/** + * Defines some names for horizontal and vertical alignment. + * + * @author hm + * + */ +public enum Alignment { + UNDEF, LEFT, RIGHT, CENTER, TOP, MIDDLE, BOTTOM +} diff --git a/src/jlecture/simulation/ISheet.java b/src/jlecture/simulation/ISheet.java index ed8232c..7e3336c 100644 --- a/src/jlecture/simulation/ISheet.java +++ b/src/jlecture/simulation/ISheet.java @@ -24,9 +24,28 @@ public interface ISheet { * the simulator model * @return a X cross widget */ - IWidget createRectangle(PointRW center, DimensionRW dimension, + public IWidget createRectangle(PointRW center, DimensionRW dimension, boolean filled, Model model); + /** + * Creates a piece of text. + * + * @param text + * the text to show + * @param size + * the font size (in dots) + * @param center + * the position of the text. See the following alignments + * @param horizontalAlignment + * LEFT: the text is left of the center... + * @param verticalAlignment + * TOP: the text is on the center + * @return the created text + */ + public IWidget createText(final String text, final int size, + final PointRW center, final Alignment horizontalAlignment, + final Alignment verticalAlignment); + /** * Creates a X cross widget. * @@ -38,7 +57,8 @@ public interface ISheet { * the simulator model * @return a X cross widget */ - IWidget createXCross(PointRW center, DimensionRW dimension, Model model); + public IWidget createXCross(PointRW center, DimensionRW dimension, + Model model); /** * Returns the width and height of the sheet. diff --git a/src/jlecture/simulation/ITextWidget.java b/src/jlecture/simulation/ITextWidget.java new file mode 100644 index 0000000..86199aa --- /dev/null +++ b/src/jlecture/simulation/ITextWidget.java @@ -0,0 +1,27 @@ +/** + * + */ +package jlecture.simulation; + +/** + * Defines a text widget. + * + * @author hm + * + */ +public interface ITextWidget extends IWidget { + /** + * Returns the text of the widget. + * + * @return the current text + */ + String getText(); + + /** + * Sets the text of the widget. + * + * @param text + * the new text + */ + void setText(String text); +} diff --git a/src/jlecture/simulation/Model.java b/src/jlecture/simulation/Model.java index f50a862..4acf834 100644 --- a/src/jlecture/simulation/Model.java +++ b/src/jlecture/simulation/Model.java @@ -3,9 +3,12 @@ */ package jlecture.simulation; +import java.awt.Color; import java.awt.Dimension; +import java.awt.Point; import java.awt.Rectangle; import java.util.ArrayList; +import java.util.Hashtable; import java.util.List; import java.util.Random; @@ -66,6 +69,40 @@ public abstract class Model { * Counts the number of collisions inside openPosition(). */ public int openPositionCollisions = 0; + /** + * current number of the simulation step. + */ + protected int step = 0; + /** + * The position of the status line segment displaying the step (in % of the + * width) + */ + protected Double positionStep = 0.0; + + /** + * Text color of a normal text in the status line. + */ + protected Color colorStatusNormal = Color.black; + + /** + * Text color of a warning in the status line. + */ + protected Color colorStatusWarning = Color.cyan; + + /** + * Text color of an error message in the status line. + */ + protected Color colorStatusError = Color.red; + + /** + * The start time of the simulation (in millisec from 1.1.1970) + */ + private long startTime = 0; + + /** + * The status line segments. Allows to change texts. + */ + private final Hashtable statusSegments = new Hashtable(); /** * Constructor. @@ -77,6 +114,26 @@ public abstract class Model { this.region = region; } + /** + * Shows a text in the status line + * + * @param xRelative + * start position in % from the width + * @param text + * text to display + */ + public void addStatusSegment(final Double xRelative, final String text) { + + final double x = this.region.x + xRelative / 100.0 * this.region.width; + final double y = -this.region.height / 100.0 * 2; + + if (this.statusSegments.contains(xRelative)) + log(String.format("status segment already exists: %.0f", xRelative)); + else + this.statusSegments.put(xRelative, this.sheet.createText(text, 12, + new PointRW(x, y), Alignment.LEFT, Alignment.TOP)); + } + /** * Checks whether a given object collides with one of the other simulated * objects. @@ -179,8 +236,8 @@ public abstract class Model { if (current != exclude) { final RectangleRW contour = current.widget.getContour(); if (point.x >= contour.x && point.y >= contour.y - && point.x < contour.x + contour.width - && point.y < contour.y + contour.height) { + && point.x < contour.x + contour.width + && point.y < contour.y + contour.height) { rc = current; break; } @@ -200,7 +257,7 @@ public abstract class Model { count++; rc.x = this.region.x + this.random.nextDouble() * this.region.width; rc.y = this.region.x + this.random.nextDouble() - * this.region.height; + * this.region.height; } while (occupied(rc, null) != null); this.openPositionCollisions += count - 1; return rc; @@ -239,6 +296,28 @@ public abstract class Model { this.sheet = sheet; } + /** + * Change the text of a status line segment. + * + * @param xRelative + * identifier of the segment (start position in % of the width) + * @param text + * the new text + * @param color + * the new color + */ + public void setStatusSegmentText(final Double xRelative, final String text, + final Color color) { + final IWidget widget = this.statusSegments.get(xRelative); + if (widget == null) + log(String.format("status segment does not exist: %.0f", xRelative)); + else { + final ITextWidget textWidget = (ITextWidget) widget; + textWidget.setText(text); + textWidget.setColor(color); + } + } + /** * Executes one simulation step. * @@ -254,6 +333,14 @@ public abstract class Model { public void simulationStep() { if (this.isReady) { this.now = System.currentTimeMillis(); + if (this.step++ == 0) + this.startTime = this.now; + else if (this.step % 5 == 0) { + final long duration = (this.now - this.startTime) / 1000L; + setStatusSegmentText(this.positionStep, String.format( + "step %d time: %d sec (%.1f/sec)", this.step, duration, + (double) this.step / duration), this.colorStatusNormal); + } // do the moves for (int ix = this.firstIndexMovables; ix < this.things.size(); ix++) { final ThingRW thing = this.things.get(ix); @@ -290,6 +377,29 @@ public abstract class Model { } } + /** + * Transforms a real world point to a pixel point. + * + *
+     * deltaX = x - xMin
+     * wRW / wPx = deltaXRW / deltaXPx => deltaPx = deltaXRW * wPx / wRW
+     * xPx = xMinPx + deltaXPx, xMinPx = 0
+     * xPx = deltaPx = deltaXRW * wPx / wRW
+     * xPx = (xRW - xMinRW) * (xMaxRW - xMinRW) / xMaxPx
+     * 
+ * + * @param pointRW + * the point to convert + * @param point + * OUT: the calculated point + */ + public void transform(final PointRW pointRW, final Point point) { + final Dimension dimension = this.sheet.getDimension(); + point.x = (int) ((pointRW.x - this.region.x) * this.region.width / dimension.width); + point.y = dimension.height + - (int) ((pointRW.y - this.region.y) * this.region.height / dimension.height); + } + /** * Transforms a real world rectangle to a native rectangle. * @@ -311,9 +421,9 @@ public abstract class Model { final Dimension dimension = this.sheet.getDimension(); rectangle.x = (int) ((rectangleRW.x - this.region.x) - * this.region.width / dimension.width); - rectangle.y = (int) ((rectangleRW.y - this.region.y) - * this.region.height / dimension.height); + * this.region.width / dimension.width); + rectangle.y = dimension.height + - (int) ((rectangleRW.y - this.region.y) * this.region.height / dimension.height); rectangle.width = (int) (rectangleRW.width * dimension.width / this.region.width); rectangle.height = (int) (rectangleRW.height * dimension.height / this.region.height); } diff --git a/src/jlecture/simulation/WidgetType.java b/src/jlecture/simulation/WidgetType.java index 7aa0d2b..8e3e7a3 100644 --- a/src/jlecture/simulation/WidgetType.java +++ b/src/jlecture/simulation/WidgetType.java @@ -10,5 +10,5 @@ package jlecture.simulation; * */ public enum WidgetType { - UNDEF, RECTANGLE, XCROSS, LINE, POINT + UNDEF, RECTANGLE, XCROSS, LINE, POINT, TEXT } diff --git a/src/jlecture/swing/PanelSwing.java b/src/jlecture/swing/PanelSwing.java index f350940..3f94f2f 100644 --- a/src/jlecture/swing/PanelSwing.java +++ b/src/jlecture/swing/PanelSwing.java @@ -35,7 +35,7 @@ class PanelSwing extends JPanel { * @param model * the simulator model */ - public PanelSwing(Model model) { + public PanelSwing(final Model model) { this.model = model; } @@ -45,12 +45,11 @@ class PanelSwing extends JPanel { * @param graphics * the drawing parameter like pencil */ - private void doDrawing(Graphics graphics) { + private void doDrawing(final Graphics graphics) { final Graphics2D g2d = (Graphics2D) graphics; g2d.setColor(this.foreground); g2d.setBackground(this.background); - for (final IWidget item : this.model.getItems()) { final WidgetSwing item2 = (WidgetSwing) item; item2.draw(g2d); @@ -58,7 +57,7 @@ class PanelSwing extends JPanel { } @Override - public void paintComponent(Graphics graphics) { + public void paintComponent(final Graphics graphics) { super.paintComponent(graphics); doDrawing(graphics); } diff --git a/src/jlecture/swing/SheetSwing.java b/src/jlecture/swing/SheetSwing.java index a2a89bb..28aba6a 100644 --- a/src/jlecture/swing/SheetSwing.java +++ b/src/jlecture/swing/SheetSwing.java @@ -8,6 +8,7 @@ import java.awt.event.ActionListener; import javax.swing.JFrame; import javax.swing.Timer; +import jlecture.simulation.Alignment; import jlecture.simulation.DimensionRW; import jlecture.simulation.ISheet; import jlecture.simulation.IWidget; @@ -73,6 +74,15 @@ public class SheetSwing extends JFrame implements ISheet, ActionListener { return new RectangleSwing(center, dimension, filled, model); } + @Override + public IWidget createText(final String text, final int size, + final PointRW center, final Alignment horizontalAlignment, + final Alignment verticalAlignment) { + final TextSwing rc = new TextSwing(text, size, center, + horizontalAlignment, verticalAlignment, this.model); + return rc; + } + @Override public IWidget createXCross(final PointRW center, final DimensionRW dimension, final Model model) { @@ -94,7 +104,7 @@ public class SheetSwing extends JFrame implements ISheet, ActionListener { add(new PanelSwing(this.model)); - setSize(this.dimension.width, this.dimension.height); + setSize(this.dimension.width, this.dimension.height * 120 / 100); if (this.position == null) // build the window in the center: diff --git a/src/jlecture/swing/TextSwing.java b/src/jlecture/swing/TextSwing.java new file mode 100644 index 0000000..12d4062 --- /dev/null +++ b/src/jlecture/swing/TextSwing.java @@ -0,0 +1,159 @@ +/** + * + */ +package jlecture.swing; + +import java.awt.Color; +import java.awt.Font; +import java.awt.FontMetrics; +import java.awt.Graphics2D; +import java.awt.Point; + +import jlecture.simulation.Alignment; +import jlecture.simulation.ITextWidget; +import jlecture.simulation.Model; +import jlecture.simulation.PointRW; +import jlecture.simulation.WidgetType; + +/** + * @author hm + * + */ +public class TextSwing extends WidgetSwing implements ITextWidget { + /** + * font size in dots. + */ + private final int size; + /** + * Text which will be shown. + */ + private String text; + /** + * The width of the text in pixel. + */ + private int textWidth = 0; + /** + * The height of the text in pixel. + */ + private int textHeight = 0; + /** + * the text will be drawn with this font. + */ + Font font = null; + /** + * Helper to calculate width and height. Will be initialized when a + * Graphics is available. + */ + FontMetrics fontMetrics = null; + Point nativeCenter = new Point(0, 0); + Alignment horizontalAlignment; + Alignment verticalAlignment; + + /** + * Contructor. + * + * @param text + * the text to show + * @param size + * the font size in dots + * @param center + * the text will be centered around this point + * @param model + * the simulation model + */ + public TextSwing(final String text, final int size, final PointRW center, + final Alignment horizontalAlignment, final Alignment verticalAlignment, + final Model model) { + super(center, model); + this.size = size; + this.text = text; + this.font = new Font("Helvetica", Font.PLAIN, this.size); + this.horizontalAlignment = horizontalAlignment; + this.verticalAlignment = verticalAlignment; + } + + /* + * (non-Javadoc) + * + * @see jlecture.swing.WidgetSwing#calculateContour() + */ + @Override + protected void calculateContour() { + // TODO Auto-generated method stub + } + + /* + * (non-Javadoc) + * + * @see jlecture.swing.WidgetSwing#draw(java.awt.Graphics2D) + */ + @Override + public void draw(final Graphics2D graphics) { + if (this.font == null) { + this.fontMetrics = graphics.getFontMetrics(this.font); + this.textWidth = this.fontMetrics.stringWidth(this.text); + this.textHeight = this.fontMetrics.getHeight(); + } + final Color safeColor = graphics.getColor(); + graphics.setColor(this.color); + this.model.transform(this.center, this.nativeCenter); + int x, y; + switch (this.horizontalAlignment) { + case LEFT: + x = this.nativeCenter.x; + break; + case RIGHT: + x = this.nativeCenter.x - this.textWidth; + break; + default: + x = this.nativeCenter.x - this.textWidth / 2; + break; + } + switch (this.verticalAlignment) { + case TOP: + y = this.nativeCenter.y + this.textHeight; + break; + case BOTTOM: + y = this.nativeCenter.y; + break; + default: + y = this.nativeCenter.y - this.textHeight / 2; + break; + } + graphics.drawString(this.text, x, y); + graphics.setColor(safeColor); + } + + /* + * (non-Javadoc) + * + * @see jlecture.simulation.IWidget#getMaxDimension() + */ + @Override + public double getMaxDimension() { + // TODO Auto-generated method stub + return 0; + } + + @Override + public String getText() { + return this.text; + } + + /* + * (non-Javadoc) + * + * @see jlecture.simulation.IWidget#getWidgetType() + */ + @Override + public WidgetType getWidgetType() { + return WidgetType.TEXT; + } + + @Override + public void setText(final String text) { + this.text = text; + + } + +} -- 2.39.5