b5c94910ac
like /tools/mspsim. This is a very simple modification that affects a very large number of files in Contiki: Cooja, /platform/cooja, Collect-view, Coffe-manager, and Cooja simulation files (.csc). I've gone through Contiki to update all references I could find. Nevertheless, this commit will likely break external dependencies, like saved Cooja simulation files.
652 lines
23 KiB
Java
652 lines
23 KiB
Java
/*
|
|
* Copyright (c) 2006, Swedish Institute of Computer Science.
|
|
* All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions
|
|
* are met:
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the distribution.
|
|
* 3. Neither the name of the Institute nor the names of its contributors
|
|
* may be used to endorse or promote products derived from this software
|
|
* without specific prior written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
|
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
|
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
* SUCH DAMAGE.
|
|
*
|
|
*/
|
|
|
|
package org.contikios.mrm;
|
|
|
|
import java.awt.Point;
|
|
import java.awt.geom.*;
|
|
import java.util.Collection;
|
|
import java.util.Enumeration;
|
|
import java.util.Vector;
|
|
import org.apache.log4j.Logger;
|
|
import org.jdom.Element;
|
|
|
|
/**
|
|
* This class represents an area with obstacles.
|
|
* Obstacles may only be of rectangular shape.
|
|
*
|
|
* @author Fredrik Osterlind
|
|
*/
|
|
class ObstacleWorld {
|
|
private static Logger logger = Logger.getLogger(ObstacleWorld.class);
|
|
|
|
// All registered obstacles
|
|
private Vector<Rectangle2D> allObstacles = null;
|
|
|
|
// All registered obstacles, with spatial information
|
|
private int spatialResolution = 10;
|
|
private Vector<Rectangle2D>[][] allObstaclesSpatial = new Vector[spatialResolution][spatialResolution];
|
|
private boolean obstaclesOrganized = false;
|
|
|
|
// Outer bounds of all obstacles
|
|
private Rectangle2D outerBounds = null;
|
|
|
|
|
|
/**
|
|
* Creates a new obstacle world without any obstacles.
|
|
*/
|
|
public ObstacleWorld() {
|
|
// No obstacles present so far
|
|
allObstacles = new Vector<Rectangle2D>();
|
|
|
|
for (int x=0; x < spatialResolution; x++)
|
|
for (int y=0; y < spatialResolution; y++)
|
|
allObstaclesSpatial[x][y] = new Vector<Rectangle2D>();
|
|
|
|
outerBounds = new Rectangle2D.Double(0,0,0,0);
|
|
}
|
|
|
|
/**
|
|
* @return The total number of registered obstacles
|
|
*/
|
|
public int getNrObstacles() {
|
|
return allObstacles.size();
|
|
}
|
|
|
|
/**
|
|
* This method can be used to find extreme coordinates of all obstacles.
|
|
*
|
|
* @return Outer bounds of all registered obstacles
|
|
*/
|
|
public Rectangle2D getOuterBounds() {
|
|
return outerBounds;
|
|
}
|
|
|
|
/**
|
|
* Returns obstacle registered at given position.
|
|
* The coordinates of an obstacles should never
|
|
* be changed directly on an object returned by this method.
|
|
*
|
|
* @param i Obstacle position
|
|
* @return Obstacle at given position
|
|
*/
|
|
public Rectangle2D getObstacle(int i) {
|
|
return allObstacles.get(i);
|
|
}
|
|
|
|
/**
|
|
* @return All registered obstacles
|
|
*/
|
|
public Vector<Rectangle2D> getAllObstacles() {
|
|
return allObstacles;
|
|
}
|
|
|
|
/**
|
|
* Returns at least all registered obstacles that contains given point.
|
|
* Note that obstacles close to but not containing the point may also
|
|
* be returned.
|
|
*
|
|
* @param center Center point
|
|
* @return All obstacles containing or near center
|
|
*/
|
|
public Vector<Rectangle2D> getAllObstaclesNear(Point2D center) {
|
|
double boxWidth = outerBounds.getWidth() / (double) spatialResolution;
|
|
double boxHeight = outerBounds.getHeight() / (double) spatialResolution;
|
|
double areaStartX = outerBounds.getMinX();
|
|
double areaStartY = outerBounds.getMinY();
|
|
|
|
double centerX = (center.getX() - areaStartX)/boxWidth;
|
|
double centerY = (center.getY() - areaStartY)/boxHeight;
|
|
|
|
Vector<Rectangle2D> allNearObstacles = new Vector<Rectangle2D>();
|
|
|
|
Point pointToAdd = new Point((int) centerX, (int) centerY);
|
|
if (pointToAdd.x >= 0 &&
|
|
pointToAdd.x < allObstaclesSpatial.length &&
|
|
pointToAdd.y >= 0 &&
|
|
pointToAdd.y < allObstaclesSpatial[0].length)
|
|
allNearObstacles.addAll(allObstaclesSpatial[pointToAdd.x][pointToAdd.y]);
|
|
|
|
// Add borders if needed
|
|
boolean addedXBorder = false;
|
|
boolean addedYBorder = false;
|
|
if (Math.floor(centerX) == centerX) {
|
|
pointToAdd = new Point((int) centerX-1, (int) centerY);
|
|
if (pointToAdd.x >= 0 &&
|
|
pointToAdd.x < allObstaclesSpatial.length &&
|
|
pointToAdd.y >= 0 &&
|
|
pointToAdd.y < allObstaclesSpatial[0].length) {
|
|
allNearObstacles.addAll(allObstaclesSpatial[pointToAdd.x][pointToAdd.y]);
|
|
addedXBorder = true;
|
|
}
|
|
}
|
|
|
|
if (Math.floor(centerY) == centerY) {
|
|
pointToAdd = new Point((int) centerX, (int) centerY-1);
|
|
if (pointToAdd.x >= 0 &&
|
|
pointToAdd.x < allObstaclesSpatial.length &&
|
|
pointToAdd.y >= 0 &&
|
|
pointToAdd.y < allObstaclesSpatial[0].length) {
|
|
allNearObstacles.addAll(allObstaclesSpatial[pointToAdd.x][pointToAdd.y]);
|
|
addedYBorder = true;
|
|
}
|
|
}
|
|
|
|
if (addedXBorder && addedYBorder) {
|
|
pointToAdd = new Point((int) centerX-1, (int) centerY-1);
|
|
allNearObstacles.addAll(allObstaclesSpatial[pointToAdd.x][pointToAdd.y]);
|
|
}
|
|
|
|
return allNearObstacles;
|
|
}
|
|
|
|
/**
|
|
* Returns at least all registered obstacles inside the given angle
|
|
* interval when at the given center point. Note that obstacles partly or
|
|
* completely outside the interval may also be returned.
|
|
* All obstacles are preferably returned in order of distance from given
|
|
* center point, although this is not guaranteed.
|
|
*
|
|
* @param center Center point
|
|
* @param angleInterval Angle interval
|
|
* @return All obstacles in given angle interval
|
|
*/
|
|
public Vector<Rectangle2D> getAllObstaclesInAngleInterval(Point2D center, AngleInterval angleInterval) {
|
|
Vector<Rectangle2D> obstaclesToReturn = new Vector<Rectangle2D>();
|
|
if (!obstaclesOrganized) {
|
|
reorganizeSpatialObstacles();
|
|
}
|
|
|
|
double boxWidth = outerBounds.getWidth() / (double) spatialResolution;
|
|
double boxHeight = outerBounds.getHeight() / (double) spatialResolution;
|
|
double areaStartX = outerBounds.getMinX();
|
|
double areaStartY = outerBounds.getMinY();
|
|
|
|
// Calculate which boxes to check (and in which order)
|
|
Point centerInArray = new Point(
|
|
(int) ((center.getX() - areaStartX)/boxWidth),
|
|
(int) ((center.getY() - areaStartY)/boxHeight)
|
|
);
|
|
Vector<Point> pointsToCheck = new Vector<Point>();
|
|
|
|
int currentDistance = 0;
|
|
while (currentDistance < 2*spatialResolution) {
|
|
|
|
if (currentDistance > 0) {
|
|
int currentX = centerInArray.x - currentDistance;
|
|
int currentY = centerInArray.y - currentDistance;
|
|
|
|
// Step right
|
|
while (currentX < centerInArray.x + currentDistance) {
|
|
if (currentX >= 0 &&
|
|
currentX < allObstaclesSpatial.length &&
|
|
currentY >= 0 &&
|
|
currentY < allObstaclesSpatial[0].length)
|
|
pointsToCheck.add(new Point(currentX, currentY));
|
|
currentX++;
|
|
}
|
|
|
|
// Step right
|
|
while (currentY < centerInArray.y + currentDistance) {
|
|
if (currentX >= 0 &&
|
|
currentX < allObstaclesSpatial.length &&
|
|
currentY >= 0 &&
|
|
currentY < allObstaclesSpatial[0].length)
|
|
pointsToCheck.add(new Point(currentX, currentY));
|
|
currentY++;
|
|
}
|
|
|
|
// Step left
|
|
while (currentX > centerInArray.x - currentDistance) {
|
|
if (currentX >= 0 &&
|
|
currentX < allObstaclesSpatial.length &&
|
|
currentY >= 0 &&
|
|
currentY < allObstaclesSpatial[0].length)
|
|
pointsToCheck.add(new Point(currentX, currentY));
|
|
currentX--;
|
|
}
|
|
|
|
// Step up
|
|
while (currentY > centerInArray.y - currentDistance) {
|
|
if (currentX >= 0 &&
|
|
currentX < allObstaclesSpatial.length &&
|
|
currentY >= 0 &&
|
|
currentY < allObstaclesSpatial[0].length)
|
|
pointsToCheck.add(new Point(currentX, currentY));
|
|
currentY--;
|
|
}
|
|
|
|
} else {
|
|
if (centerInArray.x >= 0 &&
|
|
centerInArray.x < allObstaclesSpatial.length &&
|
|
centerInArray.y >= 0 &&
|
|
centerInArray.y < allObstaclesSpatial[0].length) {
|
|
pointsToCheck.add(new Point(centerInArray.x, centerInArray.y));
|
|
}
|
|
}
|
|
currentDistance++;
|
|
}
|
|
|
|
for (int pointNr=0; pointNr < pointsToCheck.size(); pointNr++) {
|
|
// Check which obstacles should be in this box
|
|
boolean hit = false;
|
|
int x = pointsToCheck.get(pointNr).x;
|
|
int y = pointsToCheck.get(pointNr).y;
|
|
|
|
// Test if we are inside test box
|
|
if (!hit) {
|
|
if (new Rectangle2D.Double(
|
|
areaStartX + x*boxWidth,
|
|
areaStartY + y*boxHeight,
|
|
boxWidth,
|
|
boxHeight).contains(center)) {
|
|
hit = true;
|
|
for (int i=0; i < allObstaclesSpatial[x][y].size(); i++) {
|
|
if (!obstaclesToReturn.contains(allObstaclesSpatial[x][y].get(i)))
|
|
obstaclesToReturn.add(allObstaclesSpatial[x][y].get(i));
|
|
}
|
|
}
|
|
}
|
|
|
|
// Test first diagonal
|
|
if (!hit) {
|
|
AngleInterval testInterval = AngleInterval.getAngleIntervalOfLine(
|
|
center,
|
|
new Line2D.Double(
|
|
areaStartX + x*boxWidth,
|
|
areaStartY + y*boxHeight,
|
|
areaStartX + (x+1)*boxWidth,
|
|
areaStartY + (y+1)*boxHeight)
|
|
);
|
|
if (testInterval.intersects(angleInterval)) {
|
|
hit = true;
|
|
for (int i=0; i < allObstaclesSpatial[x][y].size(); i++) {
|
|
if (!obstaclesToReturn.contains(allObstaclesSpatial[x][y].get(i)))
|
|
obstaclesToReturn.add(allObstaclesSpatial[x][y].get(i));
|
|
}
|
|
}
|
|
}
|
|
|
|
// Test second diagonal
|
|
if (!hit) {
|
|
AngleInterval testInterval = AngleInterval.getAngleIntervalOfLine(
|
|
center,
|
|
new Line2D.Double(
|
|
areaStartX + x*boxWidth,
|
|
areaStartY + (y+1)*boxHeight,
|
|
areaStartX + (x+1)*boxWidth,
|
|
areaStartY + y*boxHeight)
|
|
);
|
|
if (testInterval.intersects(angleInterval)) {
|
|
hit = true;
|
|
for (int i=0; i < allObstaclesSpatial[x][y].size(); i++) {
|
|
if (!obstaclesToReturn.contains(allObstaclesSpatial[x][y].get(i)))
|
|
obstaclesToReturn.add(allObstaclesSpatial[x][y].get(i));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return obstaclesToReturn;
|
|
}
|
|
|
|
/**
|
|
* Removes all registered obstacles.
|
|
*/
|
|
public void removeAll() {
|
|
allObstacles.removeAllElements();
|
|
for (int x=0; x < spatialResolution; x++)
|
|
for (int y=0; y < spatialResolution; y++)
|
|
allObstaclesSpatial[x][y].removeAllElements();
|
|
|
|
outerBounds = new Rectangle2D.Double(0,0,0,0);
|
|
}
|
|
|
|
/**
|
|
* Returns true of given point is on a corner of
|
|
* any of the structures build from the obstacles.
|
|
* Internally this method checks how many of four point
|
|
* close to and located around given point (diagonally) are
|
|
* inside any obstacle.
|
|
* This method returns true if exactly one point is inside an obstacle.
|
|
*
|
|
* @param point Point to check
|
|
* @return True of point is on a corner, false otherwise
|
|
*/
|
|
public boolean pointIsNearCorner(Point2D point) {
|
|
double boxWidth = outerBounds.getWidth() / (double) spatialResolution;
|
|
double boxHeight = outerBounds.getHeight() / (double) spatialResolution;
|
|
double areaStartX = outerBounds.getMinX();
|
|
double areaStartY = outerBounds.getMinY();
|
|
|
|
// Which obstacles should be checked
|
|
Point centerInArray = new Point(
|
|
(int) ((point.getX() - areaStartX)/boxWidth),
|
|
(int) ((point.getY() - areaStartY)/boxHeight)
|
|
);
|
|
Vector<Rectangle2D> allObstaclesToCheck = null;
|
|
if (centerInArray.x < 0)
|
|
centerInArray.x = 0;
|
|
if (centerInArray.x >= spatialResolution)
|
|
centerInArray.x = spatialResolution-1;
|
|
if (centerInArray.y < 0)
|
|
centerInArray.y = 0;
|
|
if (centerInArray.y >= spatialResolution)
|
|
centerInArray.y = spatialResolution-1;
|
|
|
|
allObstaclesToCheck = allObstaclesSpatial[centerInArray.x][centerInArray.y];
|
|
|
|
if (allObstaclesToCheck.size() == 0) {
|
|
return false;
|
|
}
|
|
|
|
// Create the four point to check
|
|
double deltaDistance = 0.01; // 1 cm TODO Change this?
|
|
Point2D point1 = new Point2D.Double(point.getX() - deltaDistance, point.getY() - deltaDistance);
|
|
Point2D point2 = new Point2D.Double(point.getX() - deltaDistance, point.getY() + deltaDistance);
|
|
Point2D point3 = new Point2D.Double(point.getX() + deltaDistance, point.getY() - deltaDistance);
|
|
Point2D point4 = new Point2D.Double(point.getX() + deltaDistance, point.getY() + deltaDistance);
|
|
|
|
int containedPoints = 0;
|
|
Enumeration<Rectangle2D> allObstaclesToCheckEnum = allObstaclesToCheck.elements();
|
|
while (allObstaclesToCheckEnum.hasMoreElements()) {
|
|
Rectangle2D obstacleToCheck = allObstaclesToCheckEnum.nextElement();
|
|
if (obstacleToCheck.contains(point1))
|
|
containedPoints++;
|
|
if (obstacleToCheck.contains(point2))
|
|
containedPoints++;
|
|
if (obstacleToCheck.contains(point3))
|
|
containedPoints++;
|
|
if (obstacleToCheck.contains(point4))
|
|
containedPoints++;
|
|
|
|
// Abort if already to many contained points
|
|
if (containedPoints > 1) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return (containedPoints == 1);
|
|
}
|
|
|
|
/**
|
|
* Checks if specified obstacle can be merged with any existing obstacle
|
|
* in order to reduce the total number of obstacles. And in that case a merge
|
|
* is performed and this method returns the new obstacle object.
|
|
* The checking is performed by looping through all existing obstacles and
|
|
* for each one comparing the union area of it and the given obstacle to the
|
|
* area sum of the two. And since obstacles are not allowed to overlap, if the
|
|
* union area is equal to the area sum, they can be merged.
|
|
* If a merge is performed, another may be made possible so this method
|
|
* should be looped until returning null.
|
|
*
|
|
* This method does not notify observers of changes made!
|
|
*
|
|
* @return New object of a merge was performed, null otherwise
|
|
*/
|
|
private Rectangle2D mergeObstacle(Rectangle2D mergeObstacle) {
|
|
double mergeObstacleArea = mergeObstacle.getWidth() * mergeObstacle.getHeight();
|
|
double mergeObstacleTolerance = mergeObstacleArea * 0.01; // 1%
|
|
|
|
// Loop through all existing obstacles (but ignore itself)
|
|
for (int i=0; i < getNrObstacles(); i++) {
|
|
Rectangle2D existingObstacle = getObstacle(i);
|
|
if (!existingObstacle.equals(mergeObstacle)) {
|
|
double existingObstacleArea = existingObstacle.getWidth() * existingObstacle.getHeight();
|
|
Rectangle2D unionObstacle = existingObstacle.createUnion(mergeObstacle);
|
|
double unionArea = unionObstacle.getWidth() * unionObstacle.getHeight();
|
|
|
|
// Fault-tolerance
|
|
double faultTolerance = Math.min(mergeObstacleTolerance, existingObstacleArea*0.01);
|
|
|
|
// Compare areas
|
|
if (unionArea - faultTolerance <= existingObstacleArea + mergeObstacleArea) {
|
|
// Remove both old obstacles, add union
|
|
removeObstacle(mergeObstacle);
|
|
removeObstacle(existingObstacle);
|
|
addObstacle(unionObstacle, false);
|
|
|
|
obstaclesOrganized = false;
|
|
return unionObstacle;
|
|
}
|
|
}
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
* Register new obstacle with given attributes.
|
|
* This method will try to merge this obstacle with other already existing obstacles.
|
|
*
|
|
* @param startX Start X coordinate
|
|
* @param startY Start Y coordinate
|
|
* @param width Width
|
|
* @param height Height
|
|
*/
|
|
public void addObstacle(double startX, double startY, double width, double height) {
|
|
addObstacle(startX, startY, width, height, true);
|
|
}
|
|
|
|
/**
|
|
* Register new obstacle with given attributes.
|
|
* This method will, depending on given argument, try to merge
|
|
* this obstacle with other already existing obstacles.
|
|
*
|
|
* @param startX Start X coordinate
|
|
* @param startY Start Y coordinate
|
|
* @param width Width
|
|
* @param height Height
|
|
* @param merge Should this obstacle, if possible, be merged with existing obstacles
|
|
*/
|
|
public void addObstacle(double startX, double startY, double width, double height, boolean merge) {
|
|
Rectangle2D newRect = new Rectangle2D.Double(startX, startY, width, height);
|
|
addObstacle(newRect, merge);
|
|
}
|
|
|
|
/**
|
|
* Registers a given obstacle.
|
|
* This method will try to merge this obstacle with other already existing obstacles.
|
|
*
|
|
* @param obstacle New obstacle
|
|
*/
|
|
public void addObstacle(Rectangle2D obstacle) {
|
|
addObstacle(obstacle, true);
|
|
}
|
|
|
|
/**
|
|
* Registers a given obstacle.
|
|
* This method will, depending on the given argument, try to
|
|
* merge this obstacle with other already existing obstacles.
|
|
*
|
|
* @param obstacle New obstacle
|
|
*/
|
|
public void addObstacle(Rectangle2D obstacle, boolean merge) {
|
|
// TODO Should we keep the rounding?
|
|
obstacle.setRect(
|
|
Math.round(obstacle.getMinX()*1000.0) / 1000.0,
|
|
Math.round(obstacle.getMinY()*1000.0) / 1000.0,
|
|
Math.round(obstacle.getWidth()*1000.0) / 1000.0,
|
|
Math.round(obstacle.getHeight()*1000.0) / 1000.0
|
|
);
|
|
|
|
allObstacles.add(obstacle);
|
|
outerBounds = outerBounds.createUnion(obstacle);
|
|
|
|
if (merge) {
|
|
// Check if obstacle can be merged with another obstacle
|
|
Rectangle2D mergedObstacle = mergeObstacle(obstacle);
|
|
|
|
// Keep merging...
|
|
while (mergedObstacle != null)
|
|
mergedObstacle = mergeObstacle(mergedObstacle);
|
|
}
|
|
|
|
obstaclesOrganized = false;
|
|
}
|
|
|
|
/**
|
|
* Remove the given obstacle, if it exists.
|
|
*
|
|
* @param obstacle Obstacle to remove
|
|
*/
|
|
public void removeObstacle(Rectangle2D obstacle) {
|
|
allObstacles.remove(obstacle);
|
|
|
|
recreateOuterBounds();
|
|
obstaclesOrganized = false;
|
|
}
|
|
|
|
/**
|
|
* This method recreates the outer bounds of
|
|
* this obstacle area by checking all registered
|
|
* obstacles.
|
|
* This method should never have to be called directly
|
|
* by a user.
|
|
*/
|
|
public void recreateOuterBounds() {
|
|
outerBounds = new Rectangle2D.Double(0,0,0,0);
|
|
for (int i=0; i < allObstacles.size(); i++) {
|
|
outerBounds = outerBounds.createUnion(allObstacles.get(i));
|
|
}
|
|
obstaclesOrganized = false;
|
|
}
|
|
|
|
/**
|
|
* Reorganizes all registered obstacles in order to speed up
|
|
* searches for obstacles in spatial areas.
|
|
* This method is run automatically
|
|
*/
|
|
public void reorganizeSpatialObstacles() {
|
|
// Remove all spatial obstacles
|
|
for (int x=0; x < spatialResolution; x++)
|
|
for (int y=0; y < spatialResolution; y++)
|
|
allObstaclesSpatial[x][y].removeAllElements();
|
|
|
|
double boxWidth = outerBounds.getWidth() / (double) spatialResolution;
|
|
double boxHeight = outerBounds.getHeight() / (double) spatialResolution;
|
|
double currentBoxMinX = outerBounds.getMinX();
|
|
double currentBoxMinY = outerBounds.getMinY();
|
|
|
|
// For each box, add obstacles that belong there
|
|
for (int x=0; x < spatialResolution; x++)
|
|
for (int y=0; y < spatialResolution; y++) {
|
|
// Check which obstacles should be in this box
|
|
Rectangle2D boxToCheck = new Rectangle2D.Double(currentBoxMinX + x*boxWidth, currentBoxMinY + y*boxHeight, boxWidth, boxHeight);
|
|
for (int i=0; i < allObstacles.size(); i++) {
|
|
if (allObstacles.get(i).intersects(boxToCheck)) {
|
|
allObstaclesSpatial[x][y].add(allObstacles.get(i));
|
|
}
|
|
}
|
|
}
|
|
|
|
obstaclesOrganized = true;
|
|
|
|
//printObstacleGridToConsole();
|
|
}
|
|
|
|
/**
|
|
* Prints a description of all obstacles to the console
|
|
*/
|
|
public void printObstacleGridToConsole() {
|
|
logger.info("<<<<<<< printObstacleGridToConsole >>>>>>>");
|
|
logger.info(". Number of obstacles:\t" + getNrObstacles());
|
|
logger.info(". Outer boundary min:\t" + getOuterBounds().getMinX() + ", " + getOuterBounds().getMinY());
|
|
logger.info(". Outer boundary max:\t" + getOuterBounds().getMaxX() + ", " + getOuterBounds().getMaxY());
|
|
|
|
Vector<Rectangle2D> uniqueSpatialObstacles = new Vector<Rectangle2D>();
|
|
for (int x=0; x < spatialResolution; x++)
|
|
for (int y=0; y < spatialResolution; y++)
|
|
for (int i=0; i < allObstaclesSpatial[x][y].size(); i++)
|
|
if (!uniqueSpatialObstacles.contains(allObstaclesSpatial[x][y].get(i)))
|
|
uniqueSpatialObstacles.add(allObstaclesSpatial[x][y].get(i));
|
|
logger.info(". Unique spatial obstacles:\t" + uniqueSpatialObstacles.size());
|
|
|
|
int allSpatialObstacles = 0;
|
|
for (int x=0; x < spatialResolution; x++)
|
|
for (int y=0; y < spatialResolution; y++)
|
|
for (int i=0; i < allObstaclesSpatial[x][y].size(); i++)
|
|
allSpatialObstacles++;
|
|
logger.debug(". All spatial obstacles:\t" + allSpatialObstacles);
|
|
|
|
logger.info(". Spatial map counts:");
|
|
for (int y=0; y < spatialResolution; y++) {
|
|
for (int x=0; x < spatialResolution; x++) {
|
|
System.out.print(allObstaclesSpatial[x][y].size() + " ");
|
|
}
|
|
System.out.println("");
|
|
}
|
|
|
|
}
|
|
|
|
/**
|
|
* Returns XML elements representing the current obstacles.
|
|
*
|
|
* @see #setConfigXML(Collection)
|
|
* @return XML elements representing the obstacles
|
|
*/
|
|
public Collection<Element> getConfigXML() {
|
|
Vector<Element> config = new Vector<Element>();
|
|
Element element;
|
|
|
|
for (Rectangle2D rect: allObstacles) {
|
|
element = new Element("obst");
|
|
element.setText(rect.getMinX() + ";" + rect.getMinY() + ";" + rect.getWidth() + ";" + rect.getHeight());
|
|
config.add(element);
|
|
}
|
|
return config;
|
|
}
|
|
|
|
/**
|
|
* Sets the current obstacles depending on the given XML elements.
|
|
*
|
|
* @see #getConfigXML()
|
|
* @param configXML
|
|
* Config XML elements
|
|
* @return True if config was set successfully, false otherwise
|
|
*/
|
|
public boolean setConfigXML(Collection<Element> configXML) {
|
|
for (Element element : configXML) {
|
|
if (element.getName().equals("obst")) {
|
|
String rectValues[] = element.getText().split(";");
|
|
Rectangle2D newObst = new Rectangle2D.Double(
|
|
Double.parseDouble(rectValues[0]),
|
|
Double.parseDouble(rectValues[1]),
|
|
Double.parseDouble(rectValues[2]),
|
|
Double.parseDouble(rectValues[3]));
|
|
this.addObstacle(newObst, false);
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
}
|
|
|