Commit 8b4c313d authored by Benedikt Zoennchen's avatar Benedikt Zoennchen
Browse files

adapt LinkedCellGrid such that an element can be updated if it moves from one position to another.

parent 1cb60daf
......@@ -65,13 +65,11 @@ public class OfflineTopographyController {
protected void recomputeCells() {
this.topography.getSpatialMap(Pedestrian.class).clear();
for (Pedestrian pedestrian : this.topography.getElements(Pedestrian.class)) {
this.topography.getSpatialMap(Pedestrian.class).addObject(pedestrian,
pedestrian.getPosition());
this.topography.getSpatialMap(Pedestrian.class).addObject(pedestrian);
}
this.topography.getSpatialMap(Car.class).clear();
for (Car car : this.topography.getElements(Car.class)) {
this.topography.getSpatialMap(Car.class).addObject(car,
car.getPosition());
this.topography.getSpatialMap(Car.class).addObject(car);
}
}
}
......@@ -104,16 +104,16 @@ public class PedestrianOSM extends Pedestrian {
switch (updateType) {
case EVENT_DRIVEN:
result = new UpdateSchemeEventDriven(pedestrian);
result = new UpdateSchemeEventDriven(pedestrian, pedestrian.topography);
break;
case PARALLEL:
result = new UpdateSchemeParallel(pedestrian);
break;
case SEQUENTIAL:
result = new UpdateSchemeSequential(pedestrian);
result = new UpdateSchemeSequential(pedestrian, pedestrian.topography);
break;
default:
result = new UpdateSchemeSequential(pedestrian);
result = new UpdateSchemeSequential(pedestrian, pedestrian.topography);
}
return result;
......
package org.vadere.simulator.models.osm.updateScheme;
import org.vadere.simulator.models.osm.PedestrianOSM;
import org.vadere.state.scenario.Topography;
import org.vadere.util.geometry.shapes.VPoint;
public class UpdateSchemeEventDriven implements UpdateSchemeOSM {
private final PedestrianOSM pedestrian;
private final Topography topography;
public UpdateSchemeEventDriven(PedestrianOSM pedestrian) {
public UpdateSchemeEventDriven(PedestrianOSM pedestrian, Topography topography) {
this.pedestrian = pedestrian;
this.topography = topography;
}
@Override
public void update(double timeStepInSec, double currentTimeInSec, CallMethod callMethod) {
VPoint oldPosition = pedestrian.getPosition();
// for the first step after creation, timeOfNextStep has to be initialized
if (pedestrian.getTimeOfNextStep() == 0) {
pedestrian.setTimeOfNextStep(currentTimeInSec);
......@@ -22,6 +28,8 @@ public class UpdateSchemeEventDriven implements UpdateSchemeOSM {
pedestrian.updateNextPosition();
pedestrian.makeStep(pedestrian.getDurationNextStep());
pedestrian.setTimeOfNextStep(pedestrian.getTimeOfNextStep() + pedestrian.getDurationNextStep());
topography.moveElement(pedestrian, oldPosition);
}
}
package org.vadere.simulator.models.osm.updateScheme;
import org.vadere.simulator.models.osm.PedestrianOSM;
import org.vadere.state.scenario.Topography;
import org.vadere.util.geometry.shapes.VPoint;
public class UpdateSchemeSequential implements UpdateSchemeOSM {
private final PedestrianOSM pedestrian;
private final Topography topography;
public UpdateSchemeSequential(PedestrianOSM pedestrian) {
public UpdateSchemeSequential(PedestrianOSM pedestrian, Topography topography) {
this.pedestrian = pedestrian;
this.topography = topography;
}
@Override
public void update(double timeStepInSec, double currentTimeInSec, CallMethod callMethod) {
VPoint oldPosition = pedestrian.getPosition();
pedestrian.setTimeCredit(pedestrian.getTimeCredit() + timeStepInSec);
pedestrian.setDurationNextStep(pedestrian.getStepSize() / pedestrian.getDesiredSpeed());
......@@ -20,5 +26,7 @@ public class UpdateSchemeSequential implements UpdateSchemeOSM {
pedestrian.makeStep(timeStepInSec);
pedestrian.setDurationNextStep(pedestrian.getStepSize() / pedestrian.getDesiredSpeed());
}
topography.moveElement(pedestrian, oldPosition);
}
}
......@@ -4,10 +4,12 @@ import java.awt.geom.RectangularShape;
import java.util.*;
import org.vadere.util.geometry.LinkedCellsGrid;
import org.vadere.util.geometry.shapes.VPoint;
public class DynamicElementContainer<T extends DynamicElement> {
private transient final List<DynamicElementAddListener<T>> addListener;
private transient final List<DynamicElementRemoveListener<T>> removeListener;
private transient final List<DynamicElementMoveListener<T>> moveListener;
private final Map<Integer, T> elementMap;
......@@ -32,6 +34,7 @@ public class DynamicElementContainer<T extends DynamicElement> {
this.addListener = new LinkedList<>();
this.removeListener = new LinkedList<>();
this.moveListener = new LinkedList<>();
}
public LinkedCellsGrid<T> getCellsElements() {
......@@ -56,13 +59,21 @@ public class DynamicElementContainer<T extends DynamicElement> {
public void addElement(T element) {
this.elementMap.put(element.getId(), element);
this.cellsElements.addObject(element, element.getPosition());
this.cellsElements.addObject(element);
for (DynamicElementAddListener<T> listener : addListener) {
listener.elementAdded(element);
}
}
public void moveElement(T element, VPoint oldPosition) {
this.cellsElements.moveObject(element, oldPosition);
for (DynamicElementMoveListener<T> listener : moveListener) {
listener.elementMove(element);
}
}
public void removeElement(T element) {
this.elementMap.remove(element.getId());
this.cellsElements.removeObject(element);
......
package org.vadere.state.scenario;
/**
* @Benedikt Zoennchen
*/
public interface DynamicElementMoveListener<T extends DynamicElement> {
public void elementMove(T element);
}
......@@ -220,6 +220,10 @@ public class Topography {
((DynamicElementContainer<T>) getContainer(element.getClass())).removeElement(element);
}
public <T extends DynamicElement> void moveElement(T element, final VPoint oldPosition) {
((DynamicElementContainer<T>) getContainer(element.getClass())).moveElement(element, oldPosition);
}
public List<Source> getSources() {
return sources;
}
......
package org.vadere.util.geometry;
import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
......@@ -14,75 +15,19 @@ import org.vadere.util.geometry.shapes.VPoint;
/**
* A grid augmenting the position of generic objects, for faster access. O(1)
* instead of O(n) for one fixed radius check. See
* {@link LinkedCellsGrid#getObjects(java.awt.geometry.shapes.VPoint, double)}.
* {@link LinkedCellsGrid#getObjects(VPoint, double)}.
*
*
*/
public class LinkedCellsGrid<T> implements Iterable<T> {
/**
* Key value pair holding an object with its assigned position.
*
*
*/
private class ObjectWithPosition<U> {
U object;
VPoint position;
public ObjectWithPosition(U object, VPoint pos) {
this.object = object;
this.position = pos;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result
+ ((object == null) ? 0 : object.hashCode());
result = prime * result
+ ((position == null) ? 0 : position.hashCode());
return result;
}
@SuppressWarnings("unchecked")
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
ObjectWithPosition<U> other = (ObjectWithPosition<U>) obj;
if (object == null) {
if (other.object != null) {
return false;
}
} else if (!object.equals(other.object)) {
return false;
}
if (position == null) {
if (other.position != null) {
return false;
}
} else if (!position.equals(other.position)) {
return false;
}
return true;
}
}
public class LinkedCellsGrid<T extends PointPositioned> implements Iterable<T> {
final private double left;
final private double top;
final private double width;
final private double height;
private GridCell<T>[][] grid;
private List<ObjectWithPosition<T>> totalObjects = new LinkedList<ObjectWithPosition<T>>();
private int[] gridSize = new int[2];
private double[] cellSize = new double[2];
private int size;
/**
* One cell in the grid. It contains a mapping from points to lists of
......@@ -92,8 +37,8 @@ public class LinkedCellsGrid<T> implements Iterable<T> {
* @param <E>
* type of objects stored in this cell.
*/
private class GridCell<E> {
public Map<VPoint, List<E>> objects = new HashMap<VPoint, List<E>>();
private class GridCell<E extends PointPositioned> {
public List<E> objects = new ArrayList<>();
@Override
public int hashCode() {
......@@ -148,7 +93,7 @@ public class LinkedCellsGrid<T> implements Iterable<T> {
for (int r = 0; r < grid.length; r++) {
// TODO [priority=medium] [task=test] changed this [20.08.2014] here 1 to r - pls check this
for (int c = 0; c < grid[r].length; c++) {
grid[r][c] = new GridCell<T>();
grid[r][c] = new GridCell<>();
}
}
......@@ -177,6 +122,7 @@ public class LinkedCellsGrid<T> implements Iterable<T> {
this.top = top;
this.width = width;
this.height = height;
this.size = 0;
// create grid
......@@ -221,30 +167,20 @@ public class LinkedCellsGrid<T> implements Iterable<T> {
}
/**
* Adds a given object to the grid at the given position. The position is
* Adds a given object to the grid at position of the object. The position is
* discretized automatically to fit in the cells.
*
* @param object
* object to add
* @param pos
* position in the grid
* @param object object to add
*/
public void addObject(final T object, final VPoint pos) {
int[] gridPos = gridPos(pos);
// store object in the grid cell.
// if there is nothing there yet, create the list.
if (!this.grid[gridPos[0]][gridPos[1]].objects.containsKey(pos)) {
this.grid[gridPos[0]][gridPos[1]].objects.put(pos,
new LinkedList<T>());
}
List<T> objects = this.grid[gridPos[0]][gridPos[1]].objects.get(pos);
// add the object to the list stored in this cell
objects.add(object);
public synchronized void addObject(final T object) {
int[] gridPos = gridPos(object.getPosition());
grid[gridPos[0]][gridPos[1]].objects.add(object);
size++;
}
// also store it in the total objects list for easy iteration over all
// stored objects.
totalObjects.add(new ObjectWithPosition<T>(object, pos));
public void moveObject(final T object, final VPoint oldPosition) {
removeObject(object, oldPosition);
addObject(object);
}
/**
......@@ -256,25 +192,24 @@ public class LinkedCellsGrid<T> implements Iterable<T> {
* radius of the ball
* @return set of objects, or an empty set if no objects are present.
*/
public List<T> getObjects(final VPoint pos, final double radius) {
public synchronized List<T> getObjects(final VPoint pos, final double radius) {
final List<T> result = new LinkedList<T>();
int[] gridPos = gridPos(pos);
int[] discreteRad = new int[2];
discreteRad[0] = (int) Math.ceil(radius / this.cellSize[0]);
discreteRad[1] = (int) Math.ceil(radius / this.cellSize[1]);
discreteRad[0] = (int) Math.ceil(radius / cellSize[0]);
discreteRad[1] = (int) Math.ceil(radius / cellSize[1]);
final int maxRow = Math.min(this.gridSize[0] - 1, gridPos[0] + discreteRad[0]);
final int maxCol = Math.min(this.gridSize[1] - 1, gridPos[1] + discreteRad[1]);
final int maxRow = Math.min(gridSize[0] - 1, gridPos[0] + discreteRad[0]);
final int maxCol = Math.min(gridSize[1] - 1, gridPos[1] + discreteRad[1]);
for (int row = Math.max(0, gridPos[0] - discreteRad[0]); row <= maxRow; row++) {
for (int col = Math.max(0, gridPos[1] - discreteRad[1]); col <= maxCol; col++) {
for (Entry<VPoint, List<T>> entry : this.grid[row][col].objects
.entrySet()) {
for (T object : grid[row][col].objects) {
// if the given position is closer than the radius, add all objects stored there
if (entry.getKey().distance(pos) < radius) {
result.addAll(entry.getValue());
if (object.getPosition().distance(pos) < radius) {
result.add(object);
}
}
}
......@@ -289,26 +224,17 @@ public class LinkedCellsGrid<T> implements Iterable<T> {
*
* @param object
*/
public void removeObject(T object) {
for (Iterator<ObjectWithPosition<T>> iter = totalObjects.iterator(); iter
.hasNext();) {
ObjectWithPosition<T> obj = iter.next();
if (obj.object.equals(object)) {
iter.remove();
// get the list of objects stored at the given position and
// remove the object.
VPoint pos = obj.position;
int[] gridPos = gridPos(pos);
List<T> objectsAtPos = this.grid[gridPos[0]][gridPos[1]].objects
.get(pos);
objectsAtPos.remove(object);
// if the list is empty, remove the entry at this position
if (objectsAtPos.isEmpty()) {
this.grid[gridPos[0]][gridPos[1]].objects.remove(pos);
}
}
public synchronized void removeObject(T object) {
int[] gridPos = gridPos(object.getPosition());
if(grid[gridPos[0]][gridPos[1]].objects.removeIf(element -> element.equals(object))){
size--;
}
}
public synchronized void removeObject(T object, final VPoint oldPosition) {
int[] gridPos = gridPos(oldPosition);
if(grid[gridPos[0]][gridPos[1]].objects.removeIf(element -> element.equals(object))){
size--;
}
}
......@@ -316,8 +242,20 @@ public class LinkedCellsGrid<T> implements Iterable<T> {
* Removes all objects.
*/
public void clear() {
totalObjects.clear();
this.grid = generateGrid(gridSize[0], gridSize[1]);
grid = generateGrid(gridSize[0], gridSize[1]);
size = 0;
}
public List<T> getElements() {
List<T> elements = new ArrayList<>();
for (int r = 0; r < grid.length; r++) {
// TODO [priority=medium] [task=test] changed this [20.08.2014] here 1 to r - pls check this
for (int c = 0; c < grid[r].length; c++) {
elements.addAll(grid[r][c].objects);
}
}
return elements;
}
/**
......@@ -325,31 +263,7 @@ public class LinkedCellsGrid<T> implements Iterable<T> {
*/
@Override
public Iterator<T> iterator() {
return new Iterator<T>() {
private Iterator<ObjectWithPosition<T>> objectsIter = totalObjects
.iterator();
@Override
public boolean hasNext() {
return objectsIter.hasNext();
}
@Override
public T next() {
// only return the object itself, not the position
ObjectWithPosition<T> obj = objectsIter.next();
if (obj == null) {
return null;
} else {
return obj.object;
}
}
@Override
public void remove() {
objectsIter.remove();
}
};
return getElements().iterator();
}
/**
......@@ -358,7 +272,7 @@ public class LinkedCellsGrid<T> implements Iterable<T> {
* @return the size (number of different keys &lt;T&gt;) of List
*/
public int size() {
return totalObjects.size();
return size;
}
/**
......@@ -393,8 +307,6 @@ public class LinkedCellsGrid<T> implements Iterable<T> {
result = prime * result + (int) (temp ^ (temp >>> 32));
temp = java.lang.Double.doubleToLongBits(top);
result = prime * result + (int) (temp ^ (temp >>> 32));
result = prime * result
+ ((totalObjects == null) ? 0 : totalObjects.hashCode());
temp = java.lang.Double.doubleToLongBits(width);
result = prime * result + (int) (temp ^ (temp >>> 32));
return result;
......@@ -434,13 +346,6 @@ public class LinkedCellsGrid<T> implements Iterable<T> {
.doubleToLongBits(other.top)) {
return false;
}
if (totalObjects == null) {
if (other.totalObjects != null) {
return false;
}
} else if (!totalObjects.equals(other.totalObjects)) {
return false;
}
if (java.lang.Double.doubleToLongBits(width) != java.lang.Double
.doubleToLongBits(other.width)) {
return false;
......
......@@ -24,11 +24,34 @@ public class TestLinkedCellsGrid {
private static Logger logger = LogManager
.getLogger(TestLinkedCellsGrid.class);
private class NotComparableObject {
private class NotComparableObject implements PointPositioned {
public int value;
public VPoint coord;
public NotComparableObject(int value) {
public NotComparableObject(int value, VPoint coord) {
this.value = value;
this.coord = coord;
}
@Override
public VPoint getPosition() {
return coord;
}
}
private static class CoordinatedInteger implements PointPositioned {
public final Integer number;
public final VPoint coordinate;
public CoordinatedInteger(Integer number, VPoint coordinate) {
this.number = number;
this.coordinate = coordinate;
}
@Override
public VPoint getPosition() {
return coordinate;
}
}
......@@ -47,13 +70,13 @@ public class TestLinkedCellsGrid {
int int3 = 3;
int int4 = 4;
NotComparableObject obj1 = new NotComparableObject(1);
NotComparableObject obj2 = new NotComparableObject(2);
NotComparableObject obj3 = new NotComparableObject(3);
NotComparableObject obj4 = new NotComparableObject(4);
NotComparableObject obj1 = new NotComparableObject(1, pos1);
NotComparableObject obj2 = new NotComparableObject(2, pos2);
NotComparableObject obj3 = new NotComparableObject(3, pos3);
NotComparableObject obj4 = new NotComparableObject(4, pos3);
/** linked cells grid with comparable objects */
private static LinkedCellsGrid<Integer> linkedCellsInteger;
private static LinkedCellsGrid<CoordinatedInteger> linkedCellsInteger;
/** linked cells grid with non comparable objects */
private static LinkedCellsGrid<NotComparableObject> linkedCellsObject;
......@@ -64,7 +87,7 @@ public class TestLinkedCellsGrid {
*/
@Before
public void setUp() throws Exception {
linkedCellsInteger = new LinkedCellsGrid<Integer>(left, top, width,
linkedCellsInteger = new LinkedCellsGrid<CoordinatedInteger>(left, top, width,
height, sideLength);
linkedCellsObject = new LinkedCellsGrid<NotComparableObject>(left, top,
width, height, sideLength);
......@@ -72,64 +95,64 @@ public class TestLinkedCellsGrid {
/**
* Test method for
* {@link org.vadere.util.geometry.LinkedCellsGrid#addObject(java.lang.Object, java.awt.geometry.shapes.VPoint)}
* {@link org.vadere.util.geometry.LinkedCellsGrid#addObject(PointPositioned)}
* . adds several integer objects and tries to retrieve them via
* {@link LinkedCellsGrid#getObjects(java.awt.geometry.shapes.VPoint, double)}
* {@link LinkedCellsGrid#getObjects(VPoint, double)}
* .
*/
@Test
public void testAddObject() {
linkedCellsInteger.addObject(int1, pos1);
linkedCellsInteger.addObject(int2, pos2);
linkedCellsInteger.addObject(int3, pos3);
CoordinatedInteger coordinatedInteger1 = new CoordinatedInteger(int1, pos1);
CoordinatedInteger coordinatedInteger2 = new CoordinatedInteger(int2, pos2);
CoordinatedInteger coordinatedInteger3 = new CoordinatedInteger(int3, pos3);
linkedCellsInteger.addObject(coordinatedInteger1);
linkedCellsInteger.addObject(coordinatedInteger2);
linkedCellsInteger.addObject(coordinatedInteger3);
// the values are chosen so that all points should clearly be inside the
// ball
VPoint testpos1 = new VPoint(25, 25);
double testradius1 = 40;
List<Integer> objects1 = linkedCellsInteger.getObjects(testpos1,
testradius1);
List<CoordinatedInteger> objects1 = linkedCellsInteger.getObjects(testpos1, testradius1);
assertEquals("the grid did not add the correct number of objects.", 3,
objects1.size());
assertTrue("the first object was not added correctly",
objects1.contains(int1));