📄 obstacleworld.java
字号:
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; }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -