From: hama Date: Sat, 11 Oct 2014 12:18:57 +0000 (+0200) Subject: Collision detection, refactoring X-Git-Url: https://gitweb.hamatoma.de/?a=commitdiff_plain;h=f3a11682e57b7765d37e8403d2a836f537d29dca;p=robosim Collision detection, refactoring * movables stop when arriving the destination * movables stop when touching any other thing * Bar renamed to Barrier * RobotModelTest renamed to ModelTest --- diff --git a/src/jlection/robotic/Robot.java b/src/jlection/robotic/Robot.java index f3bd9c5..0952358 100644 --- a/src/jlection/robotic/Robot.java +++ b/src/jlection/robotic/Robot.java @@ -18,4 +18,15 @@ public class Robot extends Movable { super(widget); } + /** + * Evaluate exactly one simulation step. + * + * This method is normally overwritten. + * + * Note: if the current time is necessary, use Model.getNow(). + */ + @Override + public void simulationStep() { + + } } diff --git a/src/jlection/robotic/RobotModel.java b/src/jlection/robotic/RobotModel.java index a91e975..d939329 100644 --- a/src/jlection/robotic/RobotModel.java +++ b/src/jlection/robotic/RobotModel.java @@ -3,7 +3,7 @@ */ package jlection.robotic; -import jlecture.simulation.Bar; +import jlecture.simulation.Barrier; import jlecture.simulation.DimensionRW; import jlecture.simulation.Model; import jlecture.simulation.Movable; @@ -35,29 +35,29 @@ public class RobotModel extends Model { */ @Override public void createModel() { - this.things.add(new Bar(this.sheet.createRectangle( - new PointRW(500, 100), new DimensionRW(600, 50), false, this))); - this.things.add(new Bar(this.sheet.createRectangle( - new PointRW(500, 400), new DimensionRW(600, 50), false, this))); - this.things.add(new Bar(this.sheet.createRectangle( - new PointRW(500, 700), new DimensionRW(600, 50), false, this))); + this.things.add(new Barrier(this.sheet.createRectangle(new PointRW(500, + 100), new DimensionRW(600, 50), false, this))); + this.things.add(new Barrier(this.sheet.createRectangle(new PointRW(500, + 400), new DimensionRW(600, 50), false, this))); + this.things.add(new Barrier(this.sheet.createRectangle(new PointRW(500, + 700), new DimensionRW(600, 50), false, this))); + this.firstIndexMovables = this.things.size(); PointRW destination = new PointRW(0, 0); for (int ix = 0; ix < 20; ix++) { - Movable robot = new Movable(this.sheet.createRectangle(new PointRW( - 500, 500), new DimensionRW(10, 10), true, this)); - robot.getWidget().setCenter(openPosition()); - destination.x = robot.getWidget().getCenter().x; - destination.y = robot.getWidget().getCenter().y; + Movable movable = new Movable(this.sheet.createRectangle( + new PointRW(500, 500), new DimensionRW(10, 10), true, this)); + movable.getWidget().setCenter(openPosition()); + destination.x = movable.getWidget().getCenter().x; + destination.y = movable.getWidget().getCenter().y; randomDestination(destination); double minSecondsForWidth = 25; double velocity = 1 / minSecondsForWidth * this.region.width * 0.5 * (1 + this.random.nextDouble()); - robot.setMove(destination, velocity); - this.things.add(robot); + movable.setMove(destination, velocity); + this.things.add(movable); } this.isReady = true; - log("model completed"); } } diff --git a/src/jlecture/simulation/Bar.java b/src/jlecture/simulation/Bar.java deleted file mode 100644 index c0b7898..0000000 --- a/src/jlecture/simulation/Bar.java +++ /dev/null @@ -1,23 +0,0 @@ -/** - * - */ -package jlecture.simulation; - -/** - * Implements a stationary bar in the model. - * - * @author hm - * - */ -public class Bar extends ThingRW { - /** - * Constructor. - * - * @param widget - * the widget in the model view - */ - public Bar(IWidget widget) { - super(widget); - } - -} diff --git a/src/jlecture/simulation/Barrier.java b/src/jlecture/simulation/Barrier.java new file mode 100644 index 0000000..8330dd4 --- /dev/null +++ b/src/jlecture/simulation/Barrier.java @@ -0,0 +1,47 @@ +/** + * + */ +package jlecture.simulation; + +/** + * Implements a stationary element in the model. + * + * Barriers are objects which can not be passed traversed. Movables must go + * arround barriers. + * + * @author hm + * + */ +public class Barrier extends ThingRW { + /** + * Constructor. + * + * @param widget + * the widget in the model view + */ + public Barrier(IWidget widget) { + super(widget); + } + + @Override + public boolean clashes(RectangleRW rectangle) { + boolean rc = false; + if (this.widget.getWidgetType() == WidgetType.RECTANGLE + || this.widget.getWidgetType() == WidgetType.XCROSS) + rc = rectangle.intersects(this.widget.getContour()); + else + assert false; + return rc; + } + + @Override + public boolean clashes(ThingRW thing) { + boolean rc = false; + if (this.widget instanceof RectangleRW) + rc = thing.clashes((RectangleRW) this.widget); + else + assert false; + return rc; + } + +} diff --git a/src/jlecture/simulation/IWidget.java b/src/jlecture/simulation/IWidget.java index 0a8bc7b..24e44b1 100644 --- a/src/jlecture/simulation/IWidget.java +++ b/src/jlecture/simulation/IWidget.java @@ -29,10 +29,16 @@ public interface IWidget { */ public Model getModel(); + /** + * Returns the widget type, e.g. RECTANGLE. + * + * @return the widget type + */ + public WidgetType getWidgetType(); + /** * @param center * the center to set */ public void setCenter(PointRW center); - } diff --git a/src/jlecture/simulation/Model.java b/src/jlecture/simulation/Model.java index 9edabf5..b358e00 100644 --- a/src/jlecture/simulation/Model.java +++ b/src/jlecture/simulation/Model.java @@ -38,6 +38,10 @@ public abstract class Model { * The list of things which are relevant to the simulation. */ protected ArrayList things = new ArrayList(); + /** + * The lower indices are used for bars. + */ + protected int firstIndexMovables = 0; /** * The drawing area (graphical view). */ @@ -52,11 +56,10 @@ public abstract class Model { */ protected Random random = new Random(0x4711); - private long sumTime = 0; - - private long count = 0; - - private long max = 0; + /** + * The current timepoint. Is constant for one simulation step. + */ + protected long now; /** * Constructor. @@ -68,12 +71,35 @@ public abstract class Model { this.region = region; } + /** + * Checks whether a given object collides with one of the other simulated + * objects. + * + * If a collision is detected the object will be stopped (velocity = 0). + * + * @param movable + * the object to test + * @param lastIndex + * we check only the things prior to this index. The other things + * can change their position later + */ + protected void checkCollision(Movable movable, int lastIndex) { + // we use the contour of the assigned widget: + for (int ix = 0; ix < lastIndex; ix++) { + ThingRW thing = this.things.get(ix); + if (movable.clashes(thing)) { + movable.setMove(null, 0); + break; + } + } + } + /** * Builds the elements of the simulator. * * Creates the simulated things and put it into the variable - * things. For the movable things it will initialize the - * velocity and destination. + * things. Each movable thing should be initialized the + * velocity and the destination. */ public abstract void createModel(); @@ -86,6 +112,13 @@ public abstract class Model { return this.widgets; } + /** + * @return the now + */ + public long getNow() { + return this.now; + } + /** * Returns the sheet. * @@ -130,8 +163,8 @@ public abstract class Model { if (current != exclude) { 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; } @@ -139,37 +172,6 @@ public abstract class Model { return rc; } - /** - * Executes one simulator step. - * - * Will be called every 100 milliseconds and calculates the changes which - * are necessary for one simulation step. - */ - public void onTimer() { - if (this.isReady) { - long start = System.currentTimeMillis(); - // count++; - // for (int n = 0; n < 1; n++) - { - for (ThingRW thing : this.things) - if (thing instanceof Movable) { - Movable robot = (Movable) thing; - PointRW center = robot.getWidget().getCenter(); - // moves to the position belonging to the current move: - robot.currentPosition(center, start); - robot.getWidget().setCenter(center); - } - } - // long diff = System.currentTimeMillis() - start; - // sumTime += diff; - // if (max < diff) - // max = diff; - // if (count % 1 == 0) - // log(String.format("Count: %d Duration: %f Max: %d", count, - // (double) sumTime / count, max)); - } - } - /** * Returns a position not occupied by another model thing. * @@ -180,7 +182,7 @@ public abstract class Model { do { 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); return rc; } @@ -218,6 +220,44 @@ public abstract class Model { this.sheet = sheet; } + /** + * Executes one simulation step. + * + * Will be called every 100 milliseconds. + * + * Two actions will be done: + * + * First all movable objects will be moved depending on its prior position + * and its velocity. + * + * After that each simulated object do its own simulation step. + */ + public void simulationStep() { + if (this.isReady) { + this.now = System.currentTimeMillis(); + // do the moves + for (int ix = this.firstIndexMovables; ix < this.things.size(); ix++) { + ThingRW thing = this.things.get(ix); + if (thing instanceof Movable) { + Movable movable = (Movable) thing; + PointRW center = movable.getWidget().getCenter(); + // moves to the position belonging to the current move: + movable.currentPosition(center, this.now); + movable.getWidget().setCenter(center); + checkCollision(movable, ix); + } + } + // each simulated object can do its own simulation step: + for (int ix = this.firstIndexMovables; ix < this.things.size(); ix++) { + ThingRW thing = this.things.get(ix); + if (thing instanceof Movable) { + Movable movable = (Movable) thing; + movable.simulationStep(); + } + } + } + } + /** * Transforms a real world rectangle to a native rectangle. * diff --git a/src/jlecture/simulation/Movable.java b/src/jlecture/simulation/Movable.java index 3cd14c6..f15a156 100644 --- a/src/jlecture/simulation/Movable.java +++ b/src/jlecture/simulation/Movable.java @@ -31,10 +31,12 @@ public class Movable extends ThingRW { * The destination of the currrent move. */ private PointRW destination = new PointRW(0, 0); + /** * The start time of the current move (in msec). */ private long startTime = 0L; + protected Model model = null; /** @@ -48,6 +50,28 @@ public class Movable extends ThingRW { this.model = widget.getModel(); } + @Override + public boolean clashes(RectangleRW rectangle) { + boolean rc = false; + if (this.widget.getWidgetType() == WidgetType.RECTANGLE + || this.widget.getWidgetType() == WidgetType.XCROSS) + rc = this.widget.getContour().intersects(rectangle); + else + assert false; + return rc; + } + + @Override + public boolean clashes(ThingRW thing) { + boolean rc = false; + if (this.widget.getWidgetType() == WidgetType.RECTANGLE + || this.widget.getWidgetType() == WidgetType.XCROSS) + rc = thing.clashes(this.widget.getContour()); + else + assert false; + return rc; + } + /** * Calculates the position (for the current move). * @@ -58,7 +82,7 @@ public class Movable extends ThingRW { * otherwise: the current time in milliseconds */ public void currentPosition(PointRW point, long currentTime) { - if (this.velocity == 0.0) { + if (this.getVelocity() == 0.0) { point.x = this.widget.getCenter().x; point.y = this.widget.getCenter().y; } else { @@ -66,7 +90,7 @@ public class Movable extends ThingRW { currentTime = this.startTime - currentTime; // v = s / t => s = v * t double time = (currentTime - this.startTime) / 1000.0; - double distance = this.velocity * time; + double distance = this.getVelocity() * time; // hypotenuse: // c = sqrt(x_target _ x_start)**2 + (y_target _ y_start)**2) // Theory of intersecting lines: @@ -82,18 +106,28 @@ public class Movable extends ThingRW { // Stop if the destination has reached: if (Math.abs(x_diff2) > Math.abs(x_diff)) { point.x = this.destination.x; - this.velocity = 0; + this.setVelocity(0); } if (Math.abs(y_diff2) > Math.abs(y_diff)) { point.y = this.destination.y; - this.velocity = 0; + this.setVelocity(0); } } } + /** + * Returns the velocity. + * + * @return the velocity + */ + public double getVelocity() { + return this.velocity; + } + /** * @return the widget of the robot */ + @Override public IWidget getWidget() { return this.widget; } @@ -111,8 +145,19 @@ public class Movable extends ThingRW { */ public void setMove(PointRW destination, double velocity) { this.start.clone(this.widget.getCenter()); - this.destination.clone(destination); - this.startTime = System.currentTimeMillis(); + if (destination != null) + this.destination.clone(destination); + this.startTime = this.model.getNow(); + this.setVelocity(velocity); + } + + /** + * Sets the velocity. + * + * @param velocity + * the velocity to set + */ + public void setVelocity(double velocity) { this.velocity = velocity; } @@ -123,4 +168,15 @@ public class Movable extends ThingRW { public void setWidget(IWidget widget) { this.widget = widget; } + + /** + * Evaluate exactly one simulation step. + * + * This method is normally overridden. + * + * Note: if the current time is necessary, use Model.getNow(). + */ + public void simulationStep() { + // nothing to do + } } diff --git a/src/jlecture/simulation/RectangleRW.java b/src/jlecture/simulation/RectangleRW.java index 1e16e2e..fe14156 100644 --- a/src/jlecture/simulation/RectangleRW.java +++ b/src/jlecture/simulation/RectangleRW.java @@ -7,10 +7,13 @@ package jlecture.simulation; * Implements a rectangle with real world coordinates containing x, y, width and * height. * + * The point (x, y) is the left lower edge of the rectangle. + * * @author hm * */ public class RectangleRW { + static final double NEAR_1 = 1 - 1E-13; /** * x coordinate (horizontal) of the left lower corner */ @@ -60,4 +63,59 @@ public class RectangleRW { this.height = source.height; } + /** + * Tests whether a given point is inside the instance. + * + * @param x + * the x coordinate of the point to test + * @param y + * the y coordinate of the point to test + * @return true: the rectangle is completely + * inside the instance
+ * false: the point is outside + */ + public boolean inside(double x, double y) { + boolean rc = x >= this.x && x < this.x + this.width && y >= this.y + && y < this.y + this.height; + return rc; + } + + /** + * Tests whether a given point is inside the instance. + * + * @param point + * the point to test + * @return true: the rectangle is completely + * inside the instance
+ * false: the point is outside + */ + public boolean inside(PointRW point) { + boolean rc = point.x >= this.x && point.x < this.x + this.width + && point.y >= this.y && point.y < this.y + this.height; + return rc; + } + + /** + * Tests whether a given rectangle overlaps the instance. + * + * @param rectangle + * the rectangle to test + * @return true: the rectangle intersects the + * instance
+ * false: otherwise + */ + public boolean intersects(RectangleRW rectangle) { + // the rectangle overlaps if at least one edge of the rectangle is + // inside of the + // instance: + boolean rc = inside(rectangle.x, rectangle.y) + || inside(rectangle.x + RectangleRW.NEAR_1 * rectangle.width, + rectangle.y) + || inside(rectangle.x, rectangle.y + RectangleRW.NEAR_1 + * rectangle.height) + || inside(rectangle.x + RectangleRW.NEAR_1 * rectangle.width, + rectangle.y + RectangleRW.NEAR_1 * rectangle.height); + return rc; + } + } diff --git a/src/jlecture/simulation/ThingRW.java b/src/jlecture/simulation/ThingRW.java index 9bb928e..80c7ca9 100644 --- a/src/jlecture/simulation/ThingRW.java +++ b/src/jlecture/simulation/ThingRW.java @@ -8,7 +8,7 @@ package jlecture.simulation; * * @author hm */ -public class ThingRW { +public abstract class ThingRW { protected IWidget widget; /** @@ -21,4 +21,33 @@ public class ThingRW { this.widget = widget; widget.getModel().getWidgets().add(widget); } + + /** + * Tests whether a given thing has a common point with the instance. + * + * @param rectangle + * the rectangle to test + * @return true: at least one corner is inside the widget
+ * false: otherwise + */ + public abstract boolean clashes(RectangleRW rectangle); + + /** + * Tests whether a given thing has a common point with the instance. + * + * @param thing + * the thing to test + * @return true: thing has at least one common + * point with the instance
+ * false: otherwise + */ + public abstract boolean clashes(ThingRW thing); + + /** + * @return the widget + */ + public IWidget getWidget() { + return this.widget; + } + } diff --git a/src/jlecture/simulation/WidgetType.java b/src/jlecture/simulation/WidgetType.java new file mode 100644 index 0000000..7aa0d2b --- /dev/null +++ b/src/jlecture/simulation/WidgetType.java @@ -0,0 +1,14 @@ +/** + * + */ +package jlecture.simulation; + +/** + * Defines the basic geometric forms. + * + * @author hm + * + */ +public enum WidgetType { + UNDEF, RECTANGLE, XCROSS, LINE, POINT +} diff --git a/src/jlecture/swing/LineSwing.java b/src/jlecture/swing/LineSwing.java index a7f303c..0f5d2ef 100644 --- a/src/jlecture/swing/LineSwing.java +++ b/src/jlecture/swing/LineSwing.java @@ -7,6 +7,7 @@ import java.awt.Graphics2D; import jlecture.simulation.Model; import jlecture.simulation.PointRW; +import jlecture.simulation.WidgetType; /** * Implements a line in Swing. @@ -54,8 +55,13 @@ public class LineSwing extends WidgetSwing { public void draw(Graphics2D graphics) { graphics.drawLine(this.contourSwing.x, this.contourSwing.y, this.contourSwing.x + this.contourSwing.width, this.contourSwing.y - + this.contourSwing.height); + + this.contourSwing.height); } + @Override + public WidgetType getWidgetType() { + return WidgetType.LINE; + } + } diff --git a/src/jlecture/swing/RectangleSwing.java b/src/jlecture/swing/RectangleSwing.java index f603be0..ad5195f 100644 --- a/src/jlecture/swing/RectangleSwing.java +++ b/src/jlecture/swing/RectangleSwing.java @@ -8,6 +8,7 @@ import java.awt.Graphics2D; import jlecture.simulation.DimensionRW; import jlecture.simulation.Model; import jlecture.simulation.PointRW; +import jlecture.simulation.WidgetType; /** * Implements a rectangle with real world coordinates. @@ -62,4 +63,9 @@ public class RectangleSwing extends WidgetSwing { graphics.drawRect(this.contourSwing.x, this.contourSwing.y, this.contourSwing.width, this.contourSwing.height); } + + @Override + public WidgetType getWidgetType() { + return WidgetType.RECTANGLE; + } } diff --git a/src/jlecture/swing/SheetSwing.java b/src/jlecture/swing/SheetSwing.java index e040caf..0835de9 100644 --- a/src/jlecture/swing/SheetSwing.java +++ b/src/jlecture/swing/SheetSwing.java @@ -59,9 +59,8 @@ public class SheetSwing extends JFrame implements ISheet, ActionListener { @Override public void actionPerformed(ActionEvent e) { - // if (e.getActionCommand().equals("")) - { - this.model.onTimer(); + if (e.getSource() instanceof Timer) { + this.model.simulationStep(); repaint(); } } diff --git a/src/jlecture/swing/XCrossSwing.java b/src/jlecture/swing/XCrossSwing.java index b43e598..10dc8d9 100644 --- a/src/jlecture/swing/XCrossSwing.java +++ b/src/jlecture/swing/XCrossSwing.java @@ -9,6 +9,7 @@ import jlecture.simulation.DimensionRW; import jlecture.simulation.Model; import jlecture.simulation.PointRW; import jlecture.simulation.RectangleRW; +import jlecture.simulation.WidgetType; /** * Implements a cross similar to a 'X' for SWT. These are the diagonals of a @@ -57,9 +58,14 @@ public class XCrossSwing extends WidgetSwing { this.model.transform(this.contour, this.contourSwing); graphics.drawLine(this.contourSwing.x, this.contourSwing.y, this.contourSwing.x + this.contourSwing.width, this.contourSwing.y - + this.contourSwing.height); + + this.contourSwing.height); graphics.drawLine(this.contourSwing.x + this.contourSwing.width, this.contourSwing.y, this.contourSwing.x, this.contourSwing.y - + this.contourSwing.height); + + this.contourSwing.height); + } + + @Override + public WidgetType getWidgetType() { + return WidgetType.XCROSS; } } diff --git a/test/jlecture/junit/ModelTest.java b/test/jlecture/junit/ModelTest.java new file mode 100644 index 0000000..d27ccc3 --- /dev/null +++ b/test/jlecture/junit/ModelTest.java @@ -0,0 +1,162 @@ +package jlecture.junit; + +import java.awt.Dimension; +import java.awt.Point; +import java.awt.Rectangle; + +import jlecture.simulation.Barrier; +import jlecture.simulation.DimensionRW; +import jlecture.simulation.ISheet; +import jlecture.simulation.IWidget; +import jlecture.simulation.Model; +import jlecture.simulation.Movable; +import jlecture.simulation.PointRW; +import jlecture.simulation.RectangleRW; +import jlecture.simulation.ThingRW; +import jlecture.swing.SheetSwing; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +public class ModelTest extends Model { + static final double SPEED = 0.01; + + static ISheet sheet = null; + + public ModelTest() { + super(new RectangleRW(0, 0, 1000, 800)); + } + + private void checkCollision(int ixCandidate, boolean shouldClash) { + Movable movable = (Movable) this.things.get(ixCandidate); + checkCollision(movable, ixCandidate - 1); + double expected = shouldClash ? 0.0 : ModelTest.SPEED; + if (movable.getVelocity() != expected) + Assert.assertEquals(expected, movable.getVelocity(), 0.0001); + } + + @Override + public void createModel() { + this.things.clear(); + // Rectangle: (x=200, y=50, w=600, h=100) + this.things.add(new Barrier(ModelTest.sheet.createRectangle( + new PointRW(500, 100), new DimensionRW(600, 50), false, this))); + // in front of + this.things.add(getMovable(190, 60)); + // behind + this.things.add(getMovable(800, 60)); + // clashes with barrier + this.things.add(getMovable(200, 60)); + // clashes with first movable: + this.things.add(getMovable(190, 55)); + } + + private Movable getMovable(double x, double y) { + Movable movable = new Movable(ModelTest.sheet.createRectangle( + new PointRW(x, y), new DimensionRW(10, 10), true, this)); + movable.setMove(new PointRW(0, y), ModelTest.SPEED); + return movable; + } + + @Before + public void prepare() { + ModelTest.sheet = new SheetSwing(new Point(0, 0), new Dimension(1000, + 800), "test", this); + setSheet(ModelTest.sheet); + } + + @Test + public void testcheckCollision() { + createModel(); + checkCollision(1, false); + checkCollision(2, false); + checkCollision(3, false); + checkCollision(4, true); + } + + @Test + public void testMove() { + ISheet sheet = new SheetSwing(new Point(0, 0), + new Dimension(1000, 800), "test", this); + IWidget rectangle = sheet.createRectangle(new PointRW(100, 100), + new DimensionRW(20, 20), true, this); + Movable robot = new Movable(rectangle); + robot.setMove(new PointRW(0, 100), 20.0); + PointRW point = new PointRW(0, 0); + robot.currentPosition(point, -100); + Assert.assertEquals(98.0, point.x, ModelTest.SPEED); + Assert.assertEquals(100.0, point.y, ModelTest.SPEED); + robot.currentPosition(point, -200); + Assert.assertEquals(96.0, point.x, ModelTest.SPEED); + Assert.assertEquals(100.0, point.y, ModelTest.SPEED); + + robot.setMove(new PointRW(200, 100), 20.0); + robot.currentPosition(point, -100); + Assert.assertEquals(102.0, point.x, ModelTest.SPEED); + Assert.assertEquals(100.0, point.y, ModelTest.SPEED); + robot.currentPosition(point, -200); + Assert.assertEquals(104.0, point.x, ModelTest.SPEED); + Assert.assertEquals(100.0, point.y, ModelTest.SPEED); + + robot.setMove(new PointRW(100, 0), 20.0); + robot.currentPosition(point, -100); + Assert.assertEquals(100.0, point.x, ModelTest.SPEED); + Assert.assertEquals(98.0, point.y, ModelTest.SPEED); + robot.currentPosition(point, -200); + Assert.assertEquals(100.0, point.x, ModelTest.SPEED); + Assert.assertEquals(96.0, point.y, ModelTest.SPEED); + + robot.setMove(new PointRW(100, 200), 20.0); + robot.currentPosition(point, -100); + Assert.assertEquals(100.0, point.x, ModelTest.SPEED); + Assert.assertEquals(102.0, point.y, ModelTest.SPEED); + robot.currentPosition(point, -200); + Assert.assertEquals(100.0, point.x, ModelTest.SPEED); + Assert.assertEquals(104.0, point.y, ModelTest.SPEED); + } + + @Test + public void testOccupied() { + ISheet sheet = new SheetSwing(new Point(0, 0), new Dimension(200, 100), + "test", this); + IWidget rectangle = sheet.createRectangle(new PointRW(100, 100), + new DimensionRW(20, 20), true, this); + Barrier bar = new Barrier(rectangle); + this.things.add(bar); + Assert.assertNull(this.occupied(new PointRW(89.9, 89.9), null)); + Assert.assertNull(this.occupied(new PointRW(110.1, 110.1), null)); + Assert.assertNotNull(this.occupied(new PointRW(91, 91), null)); + Assert.assertNotNull(this.occupied(new PointRW(91, 109), null)); + Assert.assertTrue(rectangle == this.widgets.get(0)); + ThingRW thing = this.things.get(0); + Assert.assertTrue(bar == thing); + } + + @Test + public void testOpenPosition() { + ISheet sheet = new SheetSwing(new Point(0, 0), new Dimension(200, 100), + "test", this); + IWidget rectangle = sheet.createRectangle(new PointRW(100, 100), + new DimensionRW(20, 20), true, this); + Barrier bar = new Barrier(rectangle); + this.things.add(bar); + for (int ix = 0; ix < 1000; ix++) { + PointRW p = openPosition(); + Assert.assertNull(this.occupied(p, null)); + } + } + + @Test + public void testOpenTransform() { + ISheet sheet = new SheetSwing(new Point(0, 0), new Dimension(200, 100), + "test", this); + setSheet(sheet); + Rectangle rect = new Rectangle(0, 0, 0, 0); + transform(new RectangleRW(1, 2, 3, 4), rect); + Assert.assertEquals(1, rect.x); + Assert.assertEquals(2, rect.y); + Assert.assertEquals(3, rect.width); + Assert.assertEquals(4, rect.height); + } +} diff --git a/test/jlecture/junit/RobotModelTest.java b/test/jlecture/junit/RobotModelTest.java deleted file mode 100644 index aaba9a2..0000000 --- a/test/jlecture/junit/RobotModelTest.java +++ /dev/null @@ -1,109 +0,0 @@ -package jlecture.junit; - -import java.awt.Dimension; -import java.awt.Point; -import java.awt.Rectangle; - -import jlection.robotic.RobotModel; -import jlecture.simulation.Bar; -import jlecture.simulation.DimensionRW; -import jlecture.simulation.ISheet; -import jlecture.simulation.IWidget; -import jlecture.simulation.Movable; -import jlecture.simulation.PointRW; -import jlecture.simulation.RectangleRW; -import jlecture.simulation.ThingRW; -import jlecture.swing.SheetSwing; - -import org.junit.Assert; -import org.junit.Test; - -public class RobotModelTest extends RobotModel { - public RobotModelTest() { - super(new RectangleRW(0, 0, 1000, 800)); - } - - @Test - public void testMove() { - ISheet sheet = new SheetSwing(new Point(0, 0), - new Dimension(1000, 800), "test", this); - IWidget rectangle = sheet.createRectangle(new PointRW(100, 100), - new DimensionRW(20, 20), true, this); - Movable robot = new Movable(rectangle); - robot.setMove(new PointRW(0, 100), 20.0); - PointRW point = new PointRW(0, 0); - robot.currentPosition(point, -100); - Assert.assertEquals(98.0, point.x, 0.01); - Assert.assertEquals(100.0, point.y, 0.01); - robot.currentPosition(point, -200); - Assert.assertEquals(96.0, point.x, 0.01); - Assert.assertEquals(100.0, point.y, 0.01); - - robot.setMove(new PointRW(200, 100), 20.0); - robot.currentPosition(point, -100); - Assert.assertEquals(102.0, point.x, 0.01); - Assert.assertEquals(100.0, point.y, 0.01); - robot.currentPosition(point, -200); - Assert.assertEquals(104.0, point.x, 0.01); - Assert.assertEquals(100.0, point.y, 0.01); - - robot.setMove(new PointRW(100, 0), 20.0); - robot.currentPosition(point, -100); - Assert.assertEquals(100.0, point.x, 0.01); - Assert.assertEquals(98.0, point.y, 0.01); - robot.currentPosition(point, -200); - Assert.assertEquals(100.0, point.x, 0.01); - Assert.assertEquals(96.0, point.y, 0.01); - - robot.setMove(new PointRW(100, 200), 20.0); - robot.currentPosition(point, -100); - Assert.assertEquals(100.0, point.x, 0.01); - Assert.assertEquals(102.0, point.y, 0.01); - robot.currentPosition(point, -200); - Assert.assertEquals(100.0, point.x, 0.01); - Assert.assertEquals(104.0, point.y, 0.01); - } - - @Test - public void testOccupied() { - ISheet sheet = new SheetSwing(new Point(0, 0), new Dimension(200, 100), - "test", this); - IWidget rectangle = sheet.createRectangle(new PointRW(100, 100), - new DimensionRW(20, 20), true, this); - Bar bar = new Bar(rectangle); - this.things.add(bar); - Assert.assertNull(this.occupied(new PointRW(89.9, 89.9), null)); - Assert.assertNull(this.occupied(new PointRW(110.1, 110.1), null)); - Assert.assertNotNull(this.occupied(new PointRW(91, 91), null)); - Assert.assertNotNull(this.occupied(new PointRW(91, 109), null)); - Assert.assertTrue(rectangle == this.widgets.get(0)); - ThingRW thing = this.things.get(0); - Assert.assertTrue(bar == thing); - } - - @Test - public void testOpenPosition() { - ISheet sheet = new SheetSwing(new Point(0, 0), new Dimension(200, 100), - "test", this); - IWidget rectangle = sheet.createRectangle(new PointRW(100, 100), - new DimensionRW(20, 20), true, this); - Bar bar = new Bar(rectangle); - this.things.add(bar); - for (int ix = 0; ix < 1000; ix++) { - PointRW p = openPosition(); - Assert.assertNull(this.occupied(p, null)); - } - } - - @Test - public void testOpenTransform() { - ISheet sheet = new SheetSwing(new Point(0, 0), new Dimension(200, 100), - "test", this); - Rectangle rect = new Rectangle(0, 0, 0, 0); - transform(new RectangleRW(1, 2, 3, 4), rect); - Assert.assertEquals(1, rect.x); - Assert.assertEquals(2, rect.y); - Assert.assertEquals(3, rect.width); - Assert.assertEquals(4, rect.height); - } -} diff --git a/test/jlecture/junit/WidgetTest.java b/test/jlecture/junit/WidgetTest.java index 31ce8f1..49dba7a 100644 --- a/test/jlecture/junit/WidgetTest.java +++ b/test/jlecture/junit/WidgetTest.java @@ -7,7 +7,7 @@ import java.awt.Dimension; import java.awt.Point; import jlection.robotic.RobotModel; -import jlecture.simulation.Bar; +import jlecture.simulation.Barrier; import jlecture.simulation.DimensionRW; import jlecture.simulation.ISheet; import jlecture.simulation.IWidget; @@ -20,6 +20,8 @@ import org.junit.Assert; import org.junit.Test; /** + * Tests the low level classes of the package jlecture.simulation. + * * @author hm * */ @@ -35,7 +37,7 @@ public class WidgetTest extends RobotModel { "test", this); IWidget rectangle = sheet.createRectangle(new PointRW(100, 50), new DimensionRW(20, 20), true, this); - Bar bar = new Bar(rectangle); + Barrier bar = new Barrier(rectangle); this.things.add(bar); Assert.assertTrue(rectangle == this.widgets.get(0)); ThingRW thing = this.things.get(0); @@ -45,23 +47,276 @@ public class WidgetTest extends RobotModel { @Test public void testDimensionRW() { DimensionRW dim = new DimensionRW(10, 20); - Assert.assertEquals(dim.width, 10, 0); - Assert.assertEquals(dim.height, 20, 0); + Assert.assertEquals(10, dim.width, 0); + Assert.assertEquals(20, dim.height, 0); } @Test public void testPointRW() { PointRW p = new PointRW(10, 20); - Assert.assertEquals(p.x, 10, 0); - Assert.assertEquals(p.y, 20, 0); + Assert.assertEquals(10, p.x, 0); + Assert.assertEquals(20, p.y, 0); + } + + @Test + public void testRectangleInside() { + // adopt the coordinates are integer (discrete). + + RectangleRW r = new RectangleRW(10, 20, 30, 40); + // touching nearly one corner only: + /** + * Legend: '|' '-' and '_' are borders of the instance, X are the test + * rectangles. + * + *
+         * X_____X
+         *  |   |
+         *  |___|
+         * X     X
+         * 
+ */ + // left lower corner: + Assert.assertFalse(r.inside(9, 19)); + // left upper corner: + Assert.assertFalse(r.inside(9, 60)); + // right upper corner: + Assert.assertFalse(r.inside(39, 60)); + // right lower corner: + Assert.assertFalse(r.inside(39, 19)); + + // touching nearly one border + /** + *
+         *  __X__
+         *  |   |
+         * X|   |X
+         *  |___|
+         *    X
+         * 
+ */ + // lower border + Assert.assertFalse(r.inside(9, 25)); + // right border + Assert.assertFalse(r.inside(40, 25)); + // upper border + Assert.assertFalse(r.inside(15, 60)); + // left border + Assert.assertFalse(r.inside(9, 25)); + + // Test the corners: + /** + *
+         *
+         *  X--X
+         *  |  |
+         *  X--X
+         * 
+ */ + // left lower corner: + Assert.assertTrue(r.inside(10, 20)); + // left upper corner: + Assert.assertTrue(r.inside(10, 59)); + // right upper corner: + Assert.assertTrue(r.inside(39, 59)); + // right lower corner: + Assert.assertTrue(r.inside(39, 20)); + + // touching minimal one border + /** + *
+         *  --X--
+         *  |   |
+         *  X   X
+         *  |   |
+         *  --X--
+         * 
+ */ + // lower border + Assert.assertTrue(r.inside(10, 25)); + // right border + Assert.assertTrue(r.inside(39, 25)); + // upper border + Assert.assertTrue(r.inside(15, 59)); + // left border + Assert.assertTrue(r.inside(10, 25)); + } + + @Test + public void testRectangleInsidePoint() { + // adopt the coordinates are integer (discrete). + + RectangleRW r = new RectangleRW(10, 20, 30, 40); + // touching nearly one corner only: + /** + * Legend: '|' '-' and '_' are borders of the instance, X are the test + * rectangles. + * + *
+         * X_____X
+         *  |   |
+         *  |___|
+         * X     X
+         * 
+ */ + // left lower corner: + Assert.assertFalse(r.inside(new PointRW(9, 19))); + // left upper corner: + Assert.assertFalse(r.inside(new PointRW(9, 60))); + // right upper corner: + Assert.assertFalse(r.inside(new PointRW(39, 60))); + // right lower corner: + Assert.assertFalse(r.inside(new PointRW(39, 19))); + + // touching nearly one border + /** + *
+         *  __X__
+         *  |   |
+         * X|   |X
+         *  |___|
+         *    X
+         * 
+ */ + // lower border + Assert.assertFalse(r.inside(new PointRW(9, 25))); + // right border + Assert.assertFalse(r.inside(new PointRW(40, 25))); + // upper border + Assert.assertFalse(r.inside(new PointRW(15, 60))); + // left border + Assert.assertFalse(r.inside(new PointRW(9, 25))); + + // touching minimal one corner only: + /** + *
+         *
+         *  X--X
+         *  |  |
+         *  X--X
+         * 
+ */ + // left lower corner: + Assert.assertTrue(r.inside(new PointRW(10, 20))); + // left upper corner: + Assert.assertTrue(r.inside(new PointRW(10, 59))); + // right upper corner: + Assert.assertTrue(r.inside(new PointRW(39, 59))); + // right lower corner: + Assert.assertTrue(r.inside(new PointRW(39, 20))); + + // touching minimal one border + /** + *
+         *  --X--
+         *  |   |
+         *  X   X
+         *  |   |
+         *  --X--
+         * 
+ */ + // lower border + Assert.assertTrue(r.inside(new PointRW(10, 25))); + // right border + Assert.assertTrue(r.inside(new PointRW(39, 25))); + // upper border + Assert.assertTrue(r.inside(new PointRW(15, 51))); + // left border + Assert.assertTrue(r.inside(new PointRW(10, 25))); + } + + @Test + public void testRectangleIntersects() { + // adopt the coordinates are integer (discrete). + + RectangleRW r = new RectangleRW(10, 20, 30, 40); + // touching nearly one corner only: + /** + * Legend: '|' '-' and '_' are borders of the instance, X are the test + * rectangles. + * + *
+         * X_____X
+         *  |   |
+         *  |___|
+         * X     X
+         * 
+ */ + // left lower corner: + Assert.assertFalse(r.intersects(new RectangleRW(9, 19, 1, 1))); + // left upper corner: + Assert.assertFalse(r.intersects(new RectangleRW(9, 60, 1, 1))); + // right upper corner: + Assert.assertFalse(r.intersects(new RectangleRW(39, 60, 1, 1))); + // right lower corner: + Assert.assertFalse(r.intersects(new RectangleRW(39, 19, 1, 1))); + + // touching nearly one border + /** + *
+         *  __X__
+         *  |   |
+         * X|   |X
+         *  |___|
+         *    X
+         * 
+ */ + // lower border + Assert.assertFalse(r.intersects(new RectangleRW(9, 25, 1, 3))); + // right border + Assert.assertFalse(r.intersects(new RectangleRW(40, 25, 1, 3))); + // upper border + Assert.assertFalse(r.intersects(new RectangleRW(15, 60, 3, 3))); + // left border + Assert.assertFalse(r.intersects(new RectangleRW(9, 25, 1, 3))); + + // touching minimal one corner only: + /** + *
+         *
+         *  X--X
+         *  |  |
+         *  X--X
+         * 
+ */ + // left lower corner: + Assert.assertTrue(r.intersects(new RectangleRW(9, 19, 2, 2))); + Assert.assertTrue(r.intersects(new RectangleRW(10, 20, 1, 1))); + // left upper corner: + Assert.assertTrue(r.intersects(new RectangleRW(9, 59, 2, 1))); + Assert.assertTrue(r.intersects(new RectangleRW(10, 59, 1, 1))); + // right upper corner: + Assert.assertTrue(r.intersects(new RectangleRW(39, 59, 1, 1))); + // right lower corner: + Assert.assertTrue(r.intersects(new RectangleRW(39, 19, 1, 2))); + Assert.assertTrue(r.intersects(new RectangleRW(39, 20, 1, 1))); + + // touching minimal one border + /** + *
+         *  --X--
+         *  |   |
+         *  X   X
+         *  |   |
+         *  --X--
+         * 
+ */ + // lower border + Assert.assertTrue(r.intersects(new RectangleRW(9, 25, 2, 3))); + // right border + Assert.assertTrue(r.intersects(new RectangleRW(39, 25, 1, 3))); + // upper border + Assert.assertTrue(r.intersects(new RectangleRW(15, 51, 3, 1))); + // left border + Assert.assertTrue(r.intersects(new RectangleRW(9, 25, 2, 3))); + Assert.assertTrue(r.intersects(new RectangleRW(10, 25, 1, 3))); } @Test public void testRectangleRW() { RectangleRW r = new RectangleRW(10, 20, 30, 40); - Assert.assertEquals(r.x, 10, 0); - Assert.assertEquals(r.y, 20, 0); - Assert.assertEquals(r.width, 30, 0); - Assert.assertEquals(r.height, 40, 0); + Assert.assertEquals(10, r.x, 0); + Assert.assertEquals(20, r.y, 0); + Assert.assertEquals(30, r.width, 0); + Assert.assertEquals(40, r.height, 0); } }