]> gitweb.hamatoma.de Git - robosim/commitdiff
Collision detection, refactoring
authorhama <hama@siduction.net>
Sat, 11 Oct 2014 12:18:57 +0000 (14:18 +0200)
committerhama <hama@siduction.net>
Sat, 11 Oct 2014 12:18:57 +0000 (14:18 +0200)
* movables stop when arriving the destination
* movables stop when touching any other thing
* Bar renamed to Barrier
* RobotModelTest renamed to ModelTest

17 files changed:
src/jlection/robotic/Robot.java
src/jlection/robotic/RobotModel.java
src/jlecture/simulation/Bar.java [deleted file]
src/jlecture/simulation/Barrier.java [new file with mode: 0644]
src/jlecture/simulation/IWidget.java
src/jlecture/simulation/Model.java
src/jlecture/simulation/Movable.java
src/jlecture/simulation/RectangleRW.java
src/jlecture/simulation/ThingRW.java
src/jlecture/simulation/WidgetType.java [new file with mode: 0644]
src/jlecture/swing/LineSwing.java
src/jlecture/swing/RectangleSwing.java
src/jlecture/swing/SheetSwing.java
src/jlecture/swing/XCrossSwing.java
test/jlecture/junit/ModelTest.java [new file with mode: 0644]
test/jlecture/junit/RobotModelTest.java [deleted file]
test/jlecture/junit/WidgetTest.java

index f3bd9c5787952f044b38ba697a496ab6731da59f..095235830181748777fd0914cbeb7bd21eb89c96 100644 (file)
@@ -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() {
+
+    }
 }
index a91e97541b89ebbb9779fdb3b6510c63b697ad70..d93932940137a26233c69f957067d010afc16a5a 100644 (file)
@@ -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 (file)
index c0b7898..0000000
+++ /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 (file)
index 0000000..8330dd4
--- /dev/null
@@ -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;
+    }
+
+}
index 0a8bc7b6f33faaee62826cdc4f40a6f0d1a8ee96..24e44b153e070477abe3dc3639e1d5f0ea4f9c34 100644 (file)
@@ -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);
-
 }
index 9edabf5a3bf79d4e43f3d47f5b9810cde931e240..b358e00e4bd100637268ffb28a8bc38ea29fff23 100644 (file)
@@ -38,6 +38,10 @@ public abstract class Model {
      * The list of things which are relevant to the simulation.
      */
     protected ArrayList<ThingRW> things = new ArrayList<ThingRW>();
+    /**
+     * 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
-     * <code>things</code>. For the movable things it will initialize the
-     * velocity and destination.
+     * <code>things</code>. 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.
      *
index 3cd14c640f30134d3e66ad60657af9d764a84149..f15a156539a89db165f9733cb62d3b65659a7c66 100644 (file)
@@ -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
+    }
 }
index 1e16e2ebe14772773274aa6cc236db315e7c4a94..fe141565f7af9286183b5bb9bf1cf2cda407db0a 100644 (file)
@@ -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 <code>true</code>: the <code>rectangle</code> is completely
+     *         inside the instance<br>
+     *         <code>false</code>: 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 <code>true</code>: the <code>rectangle</code> is completely
+     *         inside the instance<br>
+     *         <code>false</code>: 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 <code>true</code>: the <code>rectangle</code> intersects the
+     *         instance<br>
+     *         <code>false</code>: 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;
+    }
+
 }
index 9bb928eefcbb6ef172a5d37331e50e0cac2d3e61..80c7ca9bda29563839d1c999d4728b0494a9a0e4 100644 (file)
@@ -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 <code>true</code>: at least one corner is inside the widget<br>
+     *         <code>false</code>: 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 <code>true</code>: <code>thing</code> has at least one common
+     *         point with the instance<br>
+     *         <code>false</code>: 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 (file)
index 0000000..7aa0d2b
--- /dev/null
@@ -0,0 +1,14 @@
+/**
+ *
+ */
+package jlecture.simulation;
+
+/**
+ * Defines the basic geometric forms.
+ *
+ * @author hm
+ *
+ */
+public enum WidgetType {
+    UNDEF, RECTANGLE, XCROSS, LINE, POINT
+}
index a7f303ceb3065bba87edae91b0a894a0ee039ed8..0f5d2ef3053568a3b55685c49f606e72624aebce 100644 (file)
@@ -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;
+    }
+
 }
index f603be07ac8633cf6ec716083f1eb8f6fa043ed3..ad5195f5583ec620c82b2ac770478b92be19b471 100644 (file)
@@ -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;
+    }
 }
index e040caff8f9124c2a24cad8cac6aaf239647a81a..0835de927a4c0862bada656aed5e0b006268bef7 100644 (file)
@@ -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();
         }
     }
index b43e598646430f78a000d5c4982d90ead7866f08..10dc8d940e079b35e8502d338953dc6f4a69e00a 100644 (file)
@@ -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 (file)
index 0000000..d27ccc3
--- /dev/null
@@ -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 (file)
index aaba9a2..0000000
+++ /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);
-    }
-}
index 31ce8f1d471b6e803f1fd74abda3171ce9ba0161..49dba7a8d256b56da6eb84670a69d436ccdcb6ab 100644 (file)
@@ -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.
+         *
+         * <pre>
+         * X_____X
+         *  |   |
+         *  |___|
+         * X     X
+         * </pre>
+         */
+        // 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
+        /**
+         * <pre>
+         *  __X__
+         *  |   |
+         * X|   |X
+         *  |___|
+         *    X
+         * </pre>
+         */
+        // 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:
+        /**
+         * <pre>
+         *
+         *  X--X
+         *  |  |
+         *  X--X
+         * </pre>
+         */
+        // 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
+        /**
+         * <pre>
+         *  --X--
+         *  |   |
+         *  X   X
+         *  |   |
+         *  --X--
+         * </pre>
+         */
+        // 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.
+         *
+         * <pre>
+         * X_____X
+         *  |   |
+         *  |___|
+         * X     X
+         * </pre>
+         */
+        // 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
+        /**
+         * <pre>
+         *  __X__
+         *  |   |
+         * X|   |X
+         *  |___|
+         *    X
+         * </pre>
+         */
+        // 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:
+        /**
+         * <pre>
+         *
+         *  X--X
+         *  |  |
+         *  X--X
+         * </pre>
+         */
+        // 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
+        /**
+         * <pre>
+         *  --X--
+         *  |   |
+         *  X   X
+         *  |   |
+         *  --X--
+         * </pre>
+         */
+        // 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.
+         *
+         * <pre>
+         * X_____X
+         *  |   |
+         *  |___|
+         * X     X
+         * </pre>
+         */
+        // 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
+        /**
+         * <pre>
+         *  __X__
+         *  |   |
+         * X|   |X
+         *  |___|
+         *    X
+         * </pre>
+         */
+        // 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:
+        /**
+         * <pre>
+         *
+         *  X--X
+         *  |  |
+         *  X--X
+         * </pre>
+         */
+        // 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
+        /**
+         * <pre>
+         *  --X--
+         *  |   |
+         *  X   X
+         *  |   |
+         *  --X--
+         * </pre>
+         */
+        // 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);
     }
 }