();
diff --git a/autoroute/InsertFoundConnectionAlgo.java b/src/main/java/autoroute/InsertFoundConnectionAlgo.java
similarity index 98%
rename from autoroute/InsertFoundConnectionAlgo.java
rename to src/main/java/autoroute/InsertFoundConnectionAlgo.java
index e36ca3c..99d180d 100644
--- a/autoroute/InsertFoundConnectionAlgo.java
+++ b/src/main/java/autoroute/InsertFoundConnectionAlgo.java
@@ -42,6 +42,7 @@
* Inserts the traces and vias of the connection found by the autoroute algorithm.
*
* @author Alfons Wirtz
+ * @version $Id: $Id
*/
public class InsertFoundConnectionAlgo
{
@@ -49,6 +50,11 @@ public class InsertFoundConnectionAlgo
/**
* Creates a new instance of InsertFoundConnectionAlgo .
* Returns null, if the insertion did not succeed.
+ *
+ * @param p_connection a {@link autoroute.LocateFoundConnectionAlgo} object.
+ * @param p_board a {@link board.RoutingBoard} object.
+ * @param p_ctrl a {@link autoroute.AutorouteControl} object.
+ * @return a {@link autoroute.InsertFoundConnectionAlgo} object.
*/
public static InsertFoundConnectionAlgo get_instance(LocateFoundConnectionAlgo p_connection,
RoutingBoard p_board, AutorouteControl p_ctrl)
diff --git a/autoroute/ItemAutorouteInfo.java b/src/main/java/autoroute/ItemAutorouteInfo.java
similarity index 84%
rename from autoroute/ItemAutorouteInfo.java
rename to src/main/java/autoroute/ItemAutorouteInfo.java
index 3219944..5258a00 100644
--- a/autoroute/ItemAutorouteInfo.java
+++ b/src/main/java/autoroute/ItemAutorouteInfo.java
@@ -29,10 +29,15 @@
* Temporary data stored in board Items used in the autoroute algorithm
*
* @author Alfons Wirtz
+ * @version $Id: $Id
*/
-
public class ItemAutorouteInfo
{
+ /**
+ * Constructor for ItemAutorouteInfo.
+ *
+ * @param p_item a {@link board.Item} object.
+ */
public ItemAutorouteInfo(Item p_item)
{
this.item = p_item;
@@ -40,6 +45,8 @@ public ItemAutorouteInfo(Item p_item)
/**
* Looks, if the corresponding item belongs to the start or destination set of the autoroute algorithm.
* Only used, if the item belongs to the net, which will be currently routed.
+ *
+ * @return a boolean.
*/
public boolean is_start_info()
{
@@ -49,6 +56,8 @@ public boolean is_start_info()
/**
* Sets, if the corresponding item belongs to the start or destination set of the autoroute algorithm.
* Only used, if the item belongs to the net, which will be currently routed.
+ *
+ * @param p_value a boolean.
*/
public void set_start_info(boolean p_value)
{
@@ -58,6 +67,8 @@ public void set_start_info(boolean p_value)
/**
* Returns the precalculated connection of this item
* or null, if it is not yet precalculated.
+ *
+ * @return a {@link autoroute.Connection} object.
*/
public Connection get_precalculated_connection()
{
@@ -66,6 +77,8 @@ public Connection get_precalculated_connection()
/**
* Sets the precalculated connnection of this item.
+ *
+ * @param p_connection a {@link autoroute.Connection} object.
*/
public void set_precalculated_connection(Connection p_connection)
{
@@ -75,6 +88,10 @@ public void set_precalculated_connection(Connection p_connection)
/**
* Gets the ExpansionRoom of of index p_index.
* Creates it, if it is not yet existing.
+ *
+ * @param p_index a int.
+ * @param p_autoroute_tree a {@link board.ShapeSearchTree} object.
+ * @return a {@link autoroute.ObstacleExpansionRoom} object.
*/
public ObstacleExpansionRoom get_expansion_room(int p_index, ShapeSearchTree p_autoroute_tree)
{
@@ -113,6 +130,11 @@ public void reset_doors()
/**
* Draws the shapes of the expansion rooms of this info for testing purposes.
+ *
+ * @param p_graphics a {@link java.awt.Graphics} object.
+ * @param p_graphics_context a {@link boardgraphics.GraphicsContext} object.
+ * @param p_graphics_context a {@link boardgraphics.GraphicsContext} object.
+ * @param p_intensity a double.
*/
public void draw(java.awt.Graphics p_graphics, boardgraphics.GraphicsContext p_graphics_context, double p_intensity)
{
diff --git a/autoroute/LocateFoundConnectionAlgo.java b/src/main/java/autoroute/LocateFoundConnectionAlgo.java
similarity index 93%
rename from autoroute/LocateFoundConnectionAlgo.java
rename to src/main/java/autoroute/LocateFoundConnectionAlgo.java
index 2c79777..2eec6a0 100644
--- a/autoroute/LocateFoundConnectionAlgo.java
+++ b/src/main/java/autoroute/LocateFoundConnectionAlgo.java
@@ -36,8 +36,10 @@
import board.TestLevel;
/**
+ * Abstract LocateFoundConnectionAlgo class.
*
* @author Alfons Wirtz
+ * @version $Id: $Id
*/
public abstract class LocateFoundConnectionAlgo
{
@@ -45,6 +47,14 @@ public abstract class LocateFoundConnectionAlgo
/**
* Returns a new Instance of LocateFoundConnectionAlgo or null,
* if p_destination_door is null.
+ *
+ * @param p_maze_search_result a {@link autoroute.MazeSearchAlgo.Result} object.
+ * @param p_ctrl a {@link autoroute.AutorouteControl} object.
+ * @param p_search_tree a {@link board.ShapeSearchTree} object.
+ * @param p_angle_restriction a {@link board.AngleRestriction} object.
+ * @param p_ripped_item_list a {@link java.util.SortedSet} object.
+ * @param p_test_level a {@link board.TestLevel} object.
+ * @return a {@link autoroute.LocateFoundConnectionAlgo} object.
*/
public static LocateFoundConnectionAlgo get_instance(MazeSearchAlgo.Result p_maze_search_result, AutorouteControl p_ctrl,
ShapeSearchTree p_search_tree, AngleRestriction p_angle_restriction, SortedSet- p_ripped_item_list, TestLevel p_test_level)
@@ -67,7 +77,16 @@ public static LocateFoundConnectionAlgo get_instance(MazeSearchAlgo.Result p_maz
return result;
}
- /** Creates a new instance of LocateFoundConnectionAlgo */
+ /**
+ * Creates a new instance of LocateFoundConnectionAlgo
+ *
+ * @param p_maze_search_result a {@link autoroute.MazeSearchAlgo.Result} object.
+ * @param p_ctrl a {@link autoroute.AutorouteControl} object.
+ * @param p_search_tree a {@link board.ShapeSearchTree} object.
+ * @param p_angle_restriction a {@link board.AngleRestriction} object.
+ * @param p_ripped_item_list a {@link java.util.SortedSet} object.
+ * @param p_test_level a {@link board.TestLevel} object.
+ */
protected LocateFoundConnectionAlgo(MazeSearchAlgo.Result p_maze_search_result, AutorouteControl p_ctrl,
ShapeSearchTree p_search_tree, AngleRestriction p_angle_restriction, SortedSet
- p_ripped_item_list, TestLevel p_test_level)
{
@@ -265,10 +284,18 @@ private ResultItem calculate_next_trace(boolean p_layer_changed, boolean p_at_fa
/**
* Returns the next list of corners for the construction of the trace
* in calculate_next_trace. If the result is emppty, the trace is already completed.
+ *
+ * @return a java$util$Collection object.
*/
protected abstract Collection calculate_next_trace_corners();
- /** Test display of the baktrack rooms. */
+ /**
+ * Test display of the baktrack rooms.
+ *
+ * @param p_graphics a {@link java.awt.Graphics} object.
+ * @param p_graphics_context a {@link boardgraphics.GraphicsContext} object.
+ * @param p_graphics_context a {@link boardgraphics.GraphicsContext} object.
+ */
public void draw(java.awt.Graphics p_graphics, boardgraphics.GraphicsContext p_graphics_context)
{
for (int i = 0; i < backtrack_array.length; ++i)
diff --git a/autoroute/LocateFoundConnectionAlgo45Degree.java b/src/main/java/autoroute/LocateFoundConnectionAlgo45Degree.java
similarity index 95%
rename from autoroute/LocateFoundConnectionAlgo45Degree.java
rename to src/main/java/autoroute/LocateFoundConnectionAlgo45Degree.java
index 051ea30..c63dd76 100644
--- a/autoroute/LocateFoundConnectionAlgo45Degree.java
+++ b/src/main/java/autoroute/LocateFoundConnectionAlgo45Degree.java
@@ -39,14 +39,23 @@
import board.TestLevel;
/**
+ *
LocateFoundConnectionAlgo45Degree class.
*
* @author Alfons Wirtz
+ * @version $Id: $Id
*/
public class LocateFoundConnectionAlgo45Degree extends LocateFoundConnectionAlgo
{
/**
* Creates a new instance of LocateFoundConnectionAlgo45Degree
+ *
+ * @param p_maze_search_result a {@link autoroute.MazeSearchAlgo.Result} object.
+ * @param p_ctrl a {@link autoroute.AutorouteControl} object.
+ * @param p_search_tree a {@link board.ShapeSearchTree} object.
+ * @param p_angle_restriction a {@link board.AngleRestriction} object.
+ * @param p_ripped_item_list a {@link java.util.SortedSet} object.
+ * @param p_test_level a {@link board.TestLevel} object.
*/
public LocateFoundConnectionAlgo45Degree(MazeSearchAlgo.Result p_maze_search_result,
AutorouteControl p_ctrl, ShapeSearchTree p_search_tree, AngleRestriction p_angle_restriction,
@@ -55,6 +64,11 @@ public LocateFoundConnectionAlgo45Degree(MazeSearchAlgo.Result p_maze_search_res
super(p_maze_search_result, p_ctrl, p_search_tree, p_angle_restriction, p_ripped_item_list, p_test_level);
}
+ /**
+ * calculate_next_trace_corners.
+ *
+ * @return a {@link java.util.Collection} object.
+ */
protected Collection calculate_next_trace_corners()
{
Collection result = new LinkedList();
diff --git a/autoroute/LocateFoundConnectionAlgoAnyAngle.java b/src/main/java/autoroute/LocateFoundConnectionAlgoAnyAngle.java
similarity index 97%
rename from autoroute/LocateFoundConnectionAlgoAnyAngle.java
rename to src/main/java/autoroute/LocateFoundConnectionAlgoAnyAngle.java
index e907d2a..d6df3dc 100644
--- a/autoroute/LocateFoundConnectionAlgoAnyAngle.java
+++ b/src/main/java/autoroute/LocateFoundConnectionAlgoAnyAngle.java
@@ -44,7 +44,16 @@
class LocateFoundConnectionAlgoAnyAngle extends LocateFoundConnectionAlgo
{
- /** Creates a new instance of LocateFoundConnectionAlgo */
+ /**
+ * Creates a new instance of LocateFoundConnectionAlgo
+ *
+ * @param p_maze_search_result a {@link autoroute.MazeSearchAlgo.Result} object.
+ * @param p_ctrl a {@link autoroute.AutorouteControl} object.
+ * @param p_search_tree a {@link board.ShapeSearchTree} object.
+ * @param p_angle_restriction a {@link board.AngleRestriction} object.
+ * @param p_ripped_item_list a {@link java.util.SortedSet} object.
+ * @param p_test_level a {@link board.TestLevel} object.
+ */
protected LocateFoundConnectionAlgoAnyAngle(MazeSearchAlgo.Result p_maze_search_result, AutorouteControl p_ctrl,
ShapeSearchTree p_search_tree, AngleRestriction p_angle_restriction,
SortedSet- p_ripped_item_list, TestLevel p_test_level)
@@ -55,6 +64,8 @@ protected LocateFoundConnectionAlgoAnyAngle(MazeSearchAlgo.Result p_maze_search_
/**
* Calculates a list with the next point of the trace under construction.
* If the trace is completed, the result list will be empty.
+ *
+ * @return a {@link java.util.Collection} object.
*/
protected Collection calculate_next_trace_corners()
{
diff --git a/autoroute/MazeListElement.java b/src/main/java/autoroute/MazeListElement.java
similarity index 80%
rename from autoroute/MazeListElement.java
rename to src/main/java/autoroute/MazeListElement.java
index 46527c6..e92e66c 100644
--- a/autoroute/MazeListElement.java
+++ b/src/main/java/autoroute/MazeListElement.java
@@ -27,11 +27,26 @@
* while the maze expanding algorithm is in progress.
*
* @author Alfons Wirtz
+ * @version $Id: $Id
*/
public class MazeListElement implements Comparable
{
- /** Creates a new instance of ExpansionInfo */
+ /**
+ * Creates a new instance of ExpansionInfo
+ *
+ * @param p_door a {@link autoroute.ExpandableObject} object.
+ * @param p_section_no_of_door a int.
+ * @param p_backtrack_door a {@link autoroute.ExpandableObject} object.
+ * @param p_section_no_of_backtrack_door a int.
+ * @param p_expansion_value a double.
+ * @param p_sorting_value a double.
+ * @param p_next_room a {@link autoroute.CompleteExpansionRoom} object.
+ * @param p_shape_entry a {@link geometry.planar.FloatLine} object.
+ * @param p_room_ripped a boolean.
+ * @param p_adjustment a {@link autoroute.MazeSearchElement.Adjustment} object.
+ * @param p_already_checked a boolean.
+ */
public MazeListElement(ExpandableObject p_door, int p_section_no_of_door,
ExpandableObject p_backtrack_door, int p_section_no_of_backtrack_door,
double p_expansion_value, double p_sorting_value,
@@ -51,6 +66,12 @@ public MazeListElement(ExpandableObject p_door, int p_section_no_of_door,
already_checked = p_already_checked;
}
+ /**
+ *
compareTo.
+ *
+ * @param p_other a {@link autoroute.MazeListElement} object.
+ * @return a int.
+ */
public int compareTo(MazeListElement p_other)
{
double compare_value = (this.sorting_value - p_other.sorting_value);
diff --git a/autoroute/MazeSearchAlgo.java b/src/main/java/autoroute/MazeSearchAlgo.java
similarity index 99%
rename from autoroute/MazeSearchAlgo.java
rename to src/main/java/autoroute/MazeSearchAlgo.java
index 56c1452..02511ff 100644
--- a/autoroute/MazeSearchAlgo.java
+++ b/src/main/java/autoroute/MazeSearchAlgo.java
@@ -49,6 +49,7 @@
* Class for autorouting an incomplete connection via a maze search algorithm.
*
* @author Alfons Wirtz
+ * @version $Id: $Id
*/
public class MazeSearchAlgo
{
@@ -57,6 +58,12 @@ public class MazeSearchAlgo
* Initializes a new instance of MazeSearchAlgo for secrching a connection
* between p_start_items and p_destination_items.
* Returns null, if the initialisation failed.
+ *
+ * @param p_start_items a {@link java.util.Set} object.
+ * @param p_destination_items a {@link java.util.Set} object.
+ * @param p_autoroute_database a {@link autoroute.AutorouteEngine} object.
+ * @param p_ctrl a {@link autoroute.AutorouteControl} object.
+ * @return a {@link autoroute.MazeSearchAlgo} object.
*/
public static MazeSearchAlgo get_instance(Set- p_start_items,
Set
- p_destination_items, AutorouteEngine p_autoroute_database, AutorouteControl p_ctrl)
@@ -92,6 +99,8 @@ public static MazeSearchAlgo get_instance(Set
- p_start_items,
* destination items. If the algorithm succeeds, the ExpansionDoor and its section number of
* the found destination is returned, from where the whole found connection
* can be backtracked. Otherwise the return value will be null.
+ *
+ * @return a {@link autoroute.MazeSearchAlgo.Result} object.
*/
public Result find_connection()
{
@@ -108,6 +117,8 @@ public Result find_connection()
/**
* Expands the next element in the maze expansion list.
* Returns false, if the expansion list is exhausted or the destination is reached.
+ *
+ * @return a boolean.
*/
public boolean occupy_next_element()
{
diff --git a/autoroute/MazeSearchElement.java b/src/main/java/autoroute/MazeSearchElement.java
similarity index 98%
rename from autoroute/MazeSearchElement.java
rename to src/main/java/autoroute/MazeSearchElement.java
index e7cccf6..aa11257 100644
--- a/autoroute/MazeSearchElement.java
+++ b/src/main/java/autoroute/MazeSearchElement.java
@@ -24,6 +24,7 @@
* Describes the structure of a section of an ExpandebleObject.
*
* @author Alfons Wirtz
+ * @version $Id: $Id
*/
public class MazeSearchElement
{
diff --git a/autoroute/MazeShoveTraceAlgo.java b/src/main/java/autoroute/MazeShoveTraceAlgo.java
similarity index 97%
rename from autoroute/MazeShoveTraceAlgo.java
rename to src/main/java/autoroute/MazeShoveTraceAlgo.java
index 93f7868..b5fa8ca 100644
--- a/autoroute/MazeShoveTraceAlgo.java
+++ b/src/main/java/autoroute/MazeShoveTraceAlgo.java
@@ -1,408 +1,417 @@
-/*
- * Copyright (C) 2014 Alfons Wirtz
- * website www.freerouting.net
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License at
- * for more details.
- *
- * MazeShoveTraceAlgo.java
- *
- * Created on 10. Mai 2006, 06:41
- *
- */
-
-package autoroute;
-
-import java.util.Collection;
-
-import geometry.planar.TileShape;
-import geometry.planar.Line;
-import geometry.planar.Polyline;
-import geometry.planar.Point;
-import geometry.planar.FloatPoint;
-import geometry.planar.FloatLine;
-import geometry.planar.Side;
-import geometry.planar.Direction;
-import geometry.planar.LineSegment;
-
-import board.Item;
-import board.RoutingBoard;
-import board.ShoveTraceAlgo;
-
-/**
- * Auxiliary functions used in MazeSearchAlgo.
- *
- * @author Alfons Wirtz
- */
-public class MazeShoveTraceAlgo
-{
-
- /**
- * Returns false, if the algorithm did not succeed and trying to shove from another door section
- * may be more successful.
- */
- public static boolean check_shove_trace_line(MazeListElement p_list_element,
- ObstacleExpansionRoom p_obstacle_room, RoutingBoard p_board, AutorouteControl p_ctrl,
- boolean p_shove_to_the_left, Collection p_to_door_list)
- {
- if (!(p_list_element.door instanceof ExpansionDoor))
- {
- return true;
- }
- ExpansionDoor from_door = (ExpansionDoor) p_list_element.door;
- if (!(p_obstacle_room.get_item() instanceof board.PolylineTrace))
- {
- return true;
- }
- board.PolylineTrace obstacle_trace = (board.PolylineTrace)p_obstacle_room.get_item();
- int trace_layer = p_obstacle_room.get_layer();
- // only traces with the same halfwidth and the same clearance class can be shoved.
- if (obstacle_trace.get_half_width() != p_ctrl.trace_half_width[trace_layer]
- || obstacle_trace.clearance_class_no() != p_ctrl.trace_clearance_class_no)
- {
- return true;
- }
- double compensated_trace_half_width = p_ctrl.compensated_trace_half_width[trace_layer];
- TileShape from_door_shape = from_door.get_shape();
- if (from_door_shape.max_width() < 2 * compensated_trace_half_width)
- {
- return true;
- }
- int trace_corner_no = p_obstacle_room.get_index_in_item();
-
- Polyline trace_polyline = obstacle_trace.polyline();
-
- if (trace_corner_no >= trace_polyline.arr.length - 1)
- {
- System.out.println("MazeShoveTraceAlgo.check_shove_trace_line: trace_corner_no to big");
- return false;
- }
- Collection room_doors = p_obstacle_room.get_doors();
- // The side of the trace line seen from the doors to expand.
- // Used to determine, if a door is on the right side to put it into the p_door_list.
- LineSegment shove_line_segment;
- if (from_door.dimension == 2)
- {
- // shove from a link door into the direction of the other link door.
- CompleteExpansionRoom other_room = from_door.other_room(p_obstacle_room);
- if (!(other_room instanceof ObstacleExpansionRoom))
- {
- return false;
- }
- if (!end_points_matching(obstacle_trace, ((ObstacleExpansionRoom)other_room).get_item()))
- {
- return false;
- }
- FloatPoint door_center = from_door_shape.centre_of_gravity();
- FloatPoint corner_1 = trace_polyline.corner_approx(trace_corner_no);
- FloatPoint corner_2 = trace_polyline.corner_approx(trace_corner_no + 1);
- if (corner_1.distance_square(corner_2) < 1)
- {
- // shove_line_segment may be reduced to a point
- return false;
- }
- boolean shove_into_direction_of_trace_start =
- door_center.distance_square(corner_2) < door_center.distance_square(corner_1);
- shove_line_segment = new LineSegment(trace_polyline, trace_corner_no + 1);
- if (shove_into_direction_of_trace_start)
- {
-
- // shove from the endpoint to the start point of the line segment
- shove_line_segment = shove_line_segment.opposite();
- }
- }
- else
- {
- CompleteExpansionRoom from_room = from_door.other_room(p_obstacle_room);
- FloatPoint from_point = from_room.get_shape().centre_of_gravity();
- Line shove_trace_line = trace_polyline.arr[trace_corner_no + 1];
- FloatLine door_line_segment = from_door_shape.diagonal_corner_segment();
- Side side_of_trace_line = shove_trace_line.side_of(door_line_segment.a, 0);
-
- FloatLine polar_line_segment = from_door_shape.polar_line_segment(from_point);
-
- boolean door_line_swapped =
- polar_line_segment.b.distance_square(door_line_segment.a) <
- polar_line_segment.a.distance_square(door_line_segment.a);
-
- boolean section_ok;
- // shove only from the right most section to the right or from the left most section to the left.
-
- double shape_entry_check_distance = compensated_trace_half_width + 5;
- double check_dist_square = shape_entry_check_distance * shape_entry_check_distance;
-
- if (p_shove_to_the_left && !door_line_swapped || !p_shove_to_the_left && door_line_swapped)
- {
- section_ok =
- p_list_element.section_no_of_door == p_list_element.door.maze_search_element_count() - 1
- && (p_list_element.shape_entry.a.distance_square(door_line_segment.b) <= check_dist_square
- || p_list_element.shape_entry.b.distance_square(door_line_segment.b) <= check_dist_square);
- }
- else
- {
- section_ok =
- p_list_element.section_no_of_door == 0
- && (p_list_element.shape_entry.a.distance_square(door_line_segment.a) <= check_dist_square
- || p_list_element.shape_entry.b.distance_square(door_line_segment.a) <= check_dist_square);
- }
- if (!section_ok)
- {
- return false;
- }
-
-
- // create the line segment for shoving
-
- FloatLine shrinked_line_segment = polar_line_segment.shrink_segment(compensated_trace_half_width);
- Direction perpendicular_direction = shove_trace_line.direction().turn_45_degree(2);
- if (side_of_trace_line == Side.ON_THE_LEFT)
- {
- if (p_shove_to_the_left)
- {
- Line start_closing_line = new Line(shrinked_line_segment.b.round(), perpendicular_direction);
- shove_line_segment =
- new LineSegment(start_closing_line, trace_polyline.arr[trace_corner_no + 1],
- trace_polyline.arr[trace_corner_no + 2]);
- }
- else
- {
- Line start_closing_line = new Line(shrinked_line_segment.a.round(), perpendicular_direction);
- shove_line_segment =
- new LineSegment(start_closing_line, trace_polyline.arr[trace_corner_no + 1].opposite(),
- trace_polyline.arr[trace_corner_no].opposite());
- }
- }
- else
- {
- if (p_shove_to_the_left)
- {
- Line start_closing_line = new Line(shrinked_line_segment.b.round(), perpendicular_direction);
- shove_line_segment =
- new LineSegment(start_closing_line, trace_polyline.arr[trace_corner_no + 1].opposite(),
- trace_polyline.arr[trace_corner_no].opposite());
- }
- else
- {
- Line start_closing_line = new Line(shrinked_line_segment.a.round(), perpendicular_direction);
- shove_line_segment =
- new LineSegment(start_closing_line, trace_polyline.arr[trace_corner_no + 1],
- trace_polyline.arr[trace_corner_no + 2]);
- }
- }
- }
- int trace_half_width = p_ctrl.trace_half_width[trace_layer];
- int [] net_no_arr = new int[1];
- net_no_arr[0] = p_ctrl.net_no;
-
- double shove_width =
- p_board.check_trace_segment(shove_line_segment, trace_layer, net_no_arr, trace_half_width,
- p_ctrl.trace_clearance_class_no, true);
- boolean segment_shortened = false;
- if (shove_width < Integer.MAX_VALUE)
- {
- // shorten shove_line_segment
- shove_width = shove_width - 1;
- if (shove_width <= 0)
- {
- return true;
- }
- shove_line_segment = shove_line_segment.change_length_approx(shove_width);
- segment_shortened = true;
- }
-
- FloatPoint from_corner = shove_line_segment.start_point_approx();
- FloatPoint to_corner = shove_line_segment.end_point_approx();
- boolean segment_ist_point = from_corner.distance_square(to_corner) < 0.1;
-
- if (!segment_ist_point)
- {
- shove_width = ShoveTraceAlgo.check(p_board, shove_line_segment, p_shove_to_the_left, trace_layer, net_no_arr, trace_half_width,
- p_ctrl.trace_clearance_class_no, p_ctrl.max_shove_trace_recursion_depth, p_ctrl.max_shove_via_recursion_depth);
-
- if (shove_width <= 0)
- {
- return true;
- }
- }
-
- // Put the doors on this side of the room into p_to_door_list with
- if (segment_shortened)
- {
- shove_width = Math.min(shove_width, from_corner.distance(to_corner));
- }
-
- Line shove_line = shove_line_segment.get_line();
-
- // From_door_compare_distance is used to check, that a door is between from_door and the end point
- // of the shove line.
- double from_door_compare_distance;
- if (from_door.dimension == 2 || segment_ist_point)
- {
- from_door_compare_distance = Double.MAX_VALUE;
- }
- else
- {
- from_door_compare_distance = to_corner.distance_square(from_door_shape.corner_approx(0));
- }
-
- for (ExpansionDoor curr_door : room_doors)
- {
- if (curr_door == from_door)
- {
- continue;
- }
- if (curr_door.first_room instanceof ObstacleExpansionRoom &&
- curr_door.second_room instanceof ObstacleExpansionRoom)
- {
- Item first_room_item = ((ObstacleExpansionRoom)curr_door.first_room).get_item();
- Item second_room_item = ((ObstacleExpansionRoom)curr_door.second_room).get_item();
- if (first_room_item != second_room_item)
- {
- // there may be topological problems at a trace fork
- continue;
- }
- }
- TileShape curr_door_shape = curr_door.get_shape();
- if (curr_door.dimension == 2 && shove_width >= Integer.MAX_VALUE)
- {
- boolean add_link_door = curr_door_shape.contains(to_corner);
-
-
- if (add_link_door)
- {
- FloatLine[] line_sections = curr_door.get_section_segments(compensated_trace_half_width);
- p_to_door_list.add(new DoorSection(curr_door, 0, line_sections[0]));
- }
- continue;
- }
- else if (!segment_ist_point)
- {
- // now curr_door is 1-dimensional
-
- // check, that curr_door is on the same border_line as p_from_door.
- FloatLine curr_door_segment = curr_door_shape.diagonal_corner_segment();
- if (curr_door_segment == null)
- {
- if (p_board.get_test_level() == board.TestLevel.ALL_DEBUGGING_OUTPUT)
- {
- System.out.println("MazeShoveTraceAlgo.check_shove_trace_line: door shape is empty");
- }
- continue;
- }
- Side start_corner_side_of_trace_line = shove_line.side_of(curr_door_segment.a, 0);
- Side end_corner_side_of_trace_line = shove_line.side_of(curr_door_segment.b, 0);
- if (p_shove_to_the_left)
- {
- if (start_corner_side_of_trace_line != Side.ON_THE_LEFT || end_corner_side_of_trace_line != Side.ON_THE_LEFT)
- {
- continue;
- }
- }
- else
- {
- if (start_corner_side_of_trace_line != Side.ON_THE_RIGHT || end_corner_side_of_trace_line != Side.ON_THE_RIGHT)
- {
- continue;
- }
- }
- FloatLine curr_door_line = curr_door_shape.polar_line_segment(from_corner);
- FloatPoint curr_door_nearest_corner;
- if (curr_door_line.a.distance_square(from_corner) <= curr_door_line.b.distance_square(from_corner))
- {
- curr_door_nearest_corner = curr_door_line.a;
- }
- else
- {
- curr_door_nearest_corner = curr_door_line.b;
- }
- if (to_corner.distance_square(curr_door_nearest_corner) >= from_door_compare_distance)
- {
- // curr_door is not located into the direction of to_corner.
- continue;
- }
- FloatPoint curr_door_projection = curr_door_nearest_corner.projection_approx(shove_line);
-
- if (curr_door_projection.distance(from_corner) + compensated_trace_half_width <= shove_width)
- {
- FloatLine[] line_sections = curr_door.get_section_segments(compensated_trace_half_width);
- for (int i = 0; i < line_sections.length; ++i)
- {
- FloatLine curr_line_section = line_sections[i];
- FloatPoint curr_section_nearest_corner;
- if (curr_line_section.a.distance_square(from_corner) <= curr_line_section.b.distance_square(from_corner))
- {
- curr_section_nearest_corner = curr_line_section.a;
- }
- else
- {
- curr_section_nearest_corner = curr_line_section.b;
- }
- FloatPoint curr_section_projection = curr_section_nearest_corner.projection_approx(shove_line);
- if (curr_section_projection.distance(from_corner) <= shove_width)
- {
- p_to_door_list.add(new DoorSection(curr_door, i, curr_line_section));
- }
- }
- }
- }
- }
- return true;
- }
-
- /**
- * Check if the endpoints of p_trace and p_from_item are maching, so that the
- * shove can continue through a link door.
- */
- private static boolean end_points_matching(board.PolylineTrace p_trace, Item p_from_item)
- {
- if (p_from_item == p_trace)
- {
- return true;
- }
- if (!p_trace.shares_net(p_from_item))
- {
- return false;
- }
- boolean points_matching;
- if (p_from_item instanceof board.DrillItem)
- {
- Point from_center = ((board.DrillItem) p_from_item).get_center();
- points_matching = from_center.equals(p_trace.first_corner()) || from_center.equals(p_trace.last_corner());
- }
- else if (p_from_item instanceof board.PolylineTrace)
- {
- board.PolylineTrace from_trace = (board.PolylineTrace) p_from_item;
- points_matching = p_trace.first_corner().equals(from_trace.first_corner()) ||
- p_trace.first_corner().equals(from_trace.last_corner()) ||
- p_trace.last_corner().equals(from_trace.first_corner()) ||
- p_trace.last_corner().equals(from_trace.last_corner());
- }
- else
- {
- points_matching = false;
- }
- return points_matching;
- }
-
- public static class DoorSection
- {
- DoorSection(ExpansionDoor p_door, int p_section_no, FloatLine p_section_line)
- {
- door = p_door;
- section_no = p_section_no;
- section_line = p_section_line;
-
- }
- final ExpansionDoor door;
- final int section_no;
- final FloatLine section_line;
- }
-}
+/*
+ * Copyright (C) 2014 Alfons Wirtz
+ * website www.freerouting.net
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License at
+ * for more details.
+ *
+ * MazeShoveTraceAlgo.java
+ *
+ * Created on 10. Mai 2006, 06:41
+ *
+ */
+
+package autoroute;
+
+import java.util.Collection;
+
+import geometry.planar.TileShape;
+import geometry.planar.Line;
+import geometry.planar.Polyline;
+import geometry.planar.Point;
+import geometry.planar.FloatPoint;
+import geometry.planar.FloatLine;
+import geometry.planar.Side;
+import geometry.planar.Direction;
+import geometry.planar.LineSegment;
+
+import board.Item;
+import board.RoutingBoard;
+import board.ShoveTraceAlgo;
+
+/**
+ * Auxiliary functions used in MazeSearchAlgo.
+ *
+ * @author Alfons Wirtz
+ * @version $Id: $Id
+ */
+public class MazeShoveTraceAlgo
+{
+
+ /**
+ * Returns false, if the algorithm did not succeed and trying to shove from another door section
+ * may be more successful.
+ *
+ * @param p_list_element a {@link autoroute.MazeListElement} object.
+ * @param p_obstacle_room a {@link autoroute.ObstacleExpansionRoom} object.
+ * @param p_board a {@link board.RoutingBoard} object.
+ * @param p_ctrl a {@link autoroute.AutorouteControl} object.
+ * @param p_shove_to_the_left a boolean.
+ * @param p_to_door_list a {@link java.util.Collection} object.
+ * @return a boolean.
+ */
+ public static boolean check_shove_trace_line(MazeListElement p_list_element,
+ ObstacleExpansionRoom p_obstacle_room, RoutingBoard p_board, AutorouteControl p_ctrl,
+ boolean p_shove_to_the_left, Collection p_to_door_list)
+ {
+ if (!(p_list_element.door instanceof ExpansionDoor))
+ {
+ return true;
+ }
+ ExpansionDoor from_door = (ExpansionDoor) p_list_element.door;
+ if (!(p_obstacle_room.get_item() instanceof board.PolylineTrace))
+ {
+ return true;
+ }
+ board.PolylineTrace obstacle_trace = (board.PolylineTrace)p_obstacle_room.get_item();
+ int trace_layer = p_obstacle_room.get_layer();
+ // only traces with the same halfwidth and the same clearance class can be shoved.
+ if (obstacle_trace.get_half_width() != p_ctrl.trace_half_width[trace_layer]
+ || obstacle_trace.clearance_class_no() != p_ctrl.trace_clearance_class_no)
+ {
+ return true;
+ }
+ double compensated_trace_half_width = p_ctrl.compensated_trace_half_width[trace_layer];
+ TileShape from_door_shape = from_door.get_shape();
+ if (from_door_shape.max_width() < 2 * compensated_trace_half_width)
+ {
+ return true;
+ }
+ int trace_corner_no = p_obstacle_room.get_index_in_item();
+
+ Polyline trace_polyline = obstacle_trace.polyline();
+
+ if (trace_corner_no >= trace_polyline.arr.length - 1)
+ {
+ System.out.println("MazeShoveTraceAlgo.check_shove_trace_line: trace_corner_no to big");
+ return false;
+ }
+ Collection room_doors = p_obstacle_room.get_doors();
+ // The side of the trace line seen from the doors to expand.
+ // Used to determine, if a door is on the right side to put it into the p_door_list.
+ LineSegment shove_line_segment;
+ if (from_door.dimension == 2)
+ {
+ // shove from a link door into the direction of the other link door.
+ CompleteExpansionRoom other_room = from_door.other_room(p_obstacle_room);
+ if (!(other_room instanceof ObstacleExpansionRoom))
+ {
+ return false;
+ }
+ if (!end_points_matching(obstacle_trace, ((ObstacleExpansionRoom)other_room).get_item()))
+ {
+ return false;
+ }
+ FloatPoint door_center = from_door_shape.centre_of_gravity();
+ FloatPoint corner_1 = trace_polyline.corner_approx(trace_corner_no);
+ FloatPoint corner_2 = trace_polyline.corner_approx(trace_corner_no + 1);
+ if (corner_1.distance_square(corner_2) < 1)
+ {
+ // shove_line_segment may be reduced to a point
+ return false;
+ }
+ boolean shove_into_direction_of_trace_start =
+ door_center.distance_square(corner_2) < door_center.distance_square(corner_1);
+ shove_line_segment = new LineSegment(trace_polyline, trace_corner_no + 1);
+ if (shove_into_direction_of_trace_start)
+ {
+
+ // shove from the endpoint to the start point of the line segment
+ shove_line_segment = shove_line_segment.opposite();
+ }
+ }
+ else
+ {
+ CompleteExpansionRoom from_room = from_door.other_room(p_obstacle_room);
+ FloatPoint from_point = from_room.get_shape().centre_of_gravity();
+ Line shove_trace_line = trace_polyline.arr[trace_corner_no + 1];
+ FloatLine door_line_segment = from_door_shape.diagonal_corner_segment();
+ Side side_of_trace_line = shove_trace_line.side_of(door_line_segment.a, 0);
+
+ FloatLine polar_line_segment = from_door_shape.polar_line_segment(from_point);
+
+ boolean door_line_swapped =
+ polar_line_segment.b.distance_square(door_line_segment.a) <
+ polar_line_segment.a.distance_square(door_line_segment.a);
+
+ boolean section_ok;
+ // shove only from the right most section to the right or from the left most section to the left.
+
+ double shape_entry_check_distance = compensated_trace_half_width + 5;
+ double check_dist_square = shape_entry_check_distance * shape_entry_check_distance;
+
+ if (p_shove_to_the_left && !door_line_swapped || !p_shove_to_the_left && door_line_swapped)
+ {
+ section_ok =
+ p_list_element.section_no_of_door == p_list_element.door.maze_search_element_count() - 1
+ && (p_list_element.shape_entry.a.distance_square(door_line_segment.b) <= check_dist_square
+ || p_list_element.shape_entry.b.distance_square(door_line_segment.b) <= check_dist_square);
+ }
+ else
+ {
+ section_ok =
+ p_list_element.section_no_of_door == 0
+ && (p_list_element.shape_entry.a.distance_square(door_line_segment.a) <= check_dist_square
+ || p_list_element.shape_entry.b.distance_square(door_line_segment.a) <= check_dist_square);
+ }
+ if (!section_ok)
+ {
+ return false;
+ }
+
+
+ // create the line segment for shoving
+
+ FloatLine shrinked_line_segment = polar_line_segment.shrink_segment(compensated_trace_half_width);
+ Direction perpendicular_direction = shove_trace_line.direction().turn_45_degree(2);
+ if (side_of_trace_line == Side.ON_THE_LEFT)
+ {
+ if (p_shove_to_the_left)
+ {
+ Line start_closing_line = new Line(shrinked_line_segment.b.round(), perpendicular_direction);
+ shove_line_segment =
+ new LineSegment(start_closing_line, trace_polyline.arr[trace_corner_no + 1],
+ trace_polyline.arr[trace_corner_no + 2]);
+ }
+ else
+ {
+ Line start_closing_line = new Line(shrinked_line_segment.a.round(), perpendicular_direction);
+ shove_line_segment =
+ new LineSegment(start_closing_line, trace_polyline.arr[trace_corner_no + 1].opposite(),
+ trace_polyline.arr[trace_corner_no].opposite());
+ }
+ }
+ else
+ {
+ if (p_shove_to_the_left)
+ {
+ Line start_closing_line = new Line(shrinked_line_segment.b.round(), perpendicular_direction);
+ shove_line_segment =
+ new LineSegment(start_closing_line, trace_polyline.arr[trace_corner_no + 1].opposite(),
+ trace_polyline.arr[trace_corner_no].opposite());
+ }
+ else
+ {
+ Line start_closing_line = new Line(shrinked_line_segment.a.round(), perpendicular_direction);
+ shove_line_segment =
+ new LineSegment(start_closing_line, trace_polyline.arr[trace_corner_no + 1],
+ trace_polyline.arr[trace_corner_no + 2]);
+ }
+ }
+ }
+ int trace_half_width = p_ctrl.trace_half_width[trace_layer];
+ int [] net_no_arr = new int[1];
+ net_no_arr[0] = p_ctrl.net_no;
+
+ double shove_width =
+ p_board.check_trace_segment(shove_line_segment, trace_layer, net_no_arr, trace_half_width,
+ p_ctrl.trace_clearance_class_no, true);
+ boolean segment_shortened = false;
+ if (shove_width < Integer.MAX_VALUE)
+ {
+ // shorten shove_line_segment
+ shove_width = shove_width - 1;
+ if (shove_width <= 0)
+ {
+ return true;
+ }
+ shove_line_segment = shove_line_segment.change_length_approx(shove_width);
+ segment_shortened = true;
+ }
+
+ FloatPoint from_corner = shove_line_segment.start_point_approx();
+ FloatPoint to_corner = shove_line_segment.end_point_approx();
+ boolean segment_ist_point = from_corner.distance_square(to_corner) < 0.1;
+
+ if (!segment_ist_point)
+ {
+ shove_width = ShoveTraceAlgo.check(p_board, shove_line_segment, p_shove_to_the_left, trace_layer, net_no_arr, trace_half_width,
+ p_ctrl.trace_clearance_class_no, p_ctrl.max_shove_trace_recursion_depth, p_ctrl.max_shove_via_recursion_depth);
+
+ if (shove_width <= 0)
+ {
+ return true;
+ }
+ }
+
+ // Put the doors on this side of the room into p_to_door_list with
+ if (segment_shortened)
+ {
+ shove_width = Math.min(shove_width, from_corner.distance(to_corner));
+ }
+
+ Line shove_line = shove_line_segment.get_line();
+
+ // From_door_compare_distance is used to check, that a door is between from_door and the end point
+ // of the shove line.
+ double from_door_compare_distance;
+ if (from_door.dimension == 2 || segment_ist_point)
+ {
+ from_door_compare_distance = Double.MAX_VALUE;
+ }
+ else
+ {
+ from_door_compare_distance = to_corner.distance_square(from_door_shape.corner_approx(0));
+ }
+
+ for (ExpansionDoor curr_door : room_doors)
+ {
+ if (curr_door == from_door)
+ {
+ continue;
+ }
+ if (curr_door.first_room instanceof ObstacleExpansionRoom &&
+ curr_door.second_room instanceof ObstacleExpansionRoom)
+ {
+ Item first_room_item = ((ObstacleExpansionRoom)curr_door.first_room).get_item();
+ Item second_room_item = ((ObstacleExpansionRoom)curr_door.second_room).get_item();
+ if (first_room_item != second_room_item)
+ {
+ // there may be topological problems at a trace fork
+ continue;
+ }
+ }
+ TileShape curr_door_shape = curr_door.get_shape();
+ if (curr_door.dimension == 2 && shove_width >= Integer.MAX_VALUE)
+ {
+ boolean add_link_door = curr_door_shape.contains(to_corner);
+
+
+ if (add_link_door)
+ {
+ FloatLine[] line_sections = curr_door.get_section_segments(compensated_trace_half_width);
+ p_to_door_list.add(new DoorSection(curr_door, 0, line_sections[0]));
+ }
+ continue;
+ }
+ else if (!segment_ist_point)
+ {
+ // now curr_door is 1-dimensional
+
+ // check, that curr_door is on the same border_line as p_from_door.
+ FloatLine curr_door_segment = curr_door_shape.diagonal_corner_segment();
+ if (curr_door_segment == null)
+ {
+ if (p_board.get_test_level() == board.TestLevel.ALL_DEBUGGING_OUTPUT)
+ {
+ System.out.println("MazeShoveTraceAlgo.check_shove_trace_line: door shape is empty");
+ }
+ continue;
+ }
+ Side start_corner_side_of_trace_line = shove_line.side_of(curr_door_segment.a, 0);
+ Side end_corner_side_of_trace_line = shove_line.side_of(curr_door_segment.b, 0);
+ if (p_shove_to_the_left)
+ {
+ if (start_corner_side_of_trace_line != Side.ON_THE_LEFT || end_corner_side_of_trace_line != Side.ON_THE_LEFT)
+ {
+ continue;
+ }
+ }
+ else
+ {
+ if (start_corner_side_of_trace_line != Side.ON_THE_RIGHT || end_corner_side_of_trace_line != Side.ON_THE_RIGHT)
+ {
+ continue;
+ }
+ }
+ FloatLine curr_door_line = curr_door_shape.polar_line_segment(from_corner);
+ FloatPoint curr_door_nearest_corner;
+ if (curr_door_line.a.distance_square(from_corner) <= curr_door_line.b.distance_square(from_corner))
+ {
+ curr_door_nearest_corner = curr_door_line.a;
+ }
+ else
+ {
+ curr_door_nearest_corner = curr_door_line.b;
+ }
+ if (to_corner.distance_square(curr_door_nearest_corner) >= from_door_compare_distance)
+ {
+ // curr_door is not located into the direction of to_corner.
+ continue;
+ }
+ FloatPoint curr_door_projection = curr_door_nearest_corner.projection_approx(shove_line);
+
+ if (curr_door_projection.distance(from_corner) + compensated_trace_half_width <= shove_width)
+ {
+ FloatLine[] line_sections = curr_door.get_section_segments(compensated_trace_half_width);
+ for (int i = 0; i < line_sections.length; ++i)
+ {
+ FloatLine curr_line_section = line_sections[i];
+ FloatPoint curr_section_nearest_corner;
+ if (curr_line_section.a.distance_square(from_corner) <= curr_line_section.b.distance_square(from_corner))
+ {
+ curr_section_nearest_corner = curr_line_section.a;
+ }
+ else
+ {
+ curr_section_nearest_corner = curr_line_section.b;
+ }
+ FloatPoint curr_section_projection = curr_section_nearest_corner.projection_approx(shove_line);
+ if (curr_section_projection.distance(from_corner) <= shove_width)
+ {
+ p_to_door_list.add(new DoorSection(curr_door, i, curr_line_section));
+ }
+ }
+ }
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Check if the endpoints of p_trace and p_from_item are maching, so that the
+ * shove can continue through a link door.
+ */
+ private static boolean end_points_matching(board.PolylineTrace p_trace, Item p_from_item)
+ {
+ if (p_from_item == p_trace)
+ {
+ return true;
+ }
+ if (!p_trace.shares_net(p_from_item))
+ {
+ return false;
+ }
+ boolean points_matching;
+ if (p_from_item instanceof board.DrillItem)
+ {
+ Point from_center = ((board.DrillItem) p_from_item).get_center();
+ points_matching = from_center.equals(p_trace.first_corner()) || from_center.equals(p_trace.last_corner());
+ }
+ else if (p_from_item instanceof board.PolylineTrace)
+ {
+ board.PolylineTrace from_trace = (board.PolylineTrace) p_from_item;
+ points_matching = p_trace.first_corner().equals(from_trace.first_corner()) ||
+ p_trace.first_corner().equals(from_trace.last_corner()) ||
+ p_trace.last_corner().equals(from_trace.first_corner()) ||
+ p_trace.last_corner().equals(from_trace.last_corner());
+ }
+ else
+ {
+ points_matching = false;
+ }
+ return points_matching;
+ }
+
+ public static class DoorSection
+ {
+ DoorSection(ExpansionDoor p_door, int p_section_no, FloatLine p_section_line)
+ {
+ door = p_door;
+ section_no = p_section_no;
+ section_line = p_section_line;
+
+ }
+ final ExpansionDoor door;
+ final int section_no;
+ final FloatLine section_line;
+ }
+}
diff --git a/autoroute/ObstacleExpansionRoom.java b/src/main/java/autoroute/ObstacleExpansionRoom.java
similarity index 86%
rename from autoroute/ObstacleExpansionRoom.java
rename to src/main/java/autoroute/ObstacleExpansionRoom.java
index f63bc89..a6b1240 100644
--- a/autoroute/ObstacleExpansionRoom.java
+++ b/src/main/java/autoroute/ObstacleExpansionRoom.java
@@ -1,207 +1,253 @@
-/*
- * Copyright (C) 2014 Alfons Wirtz
- * website www.freerouting.net
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License at
- * for more details.
- *
- * ObstacleExpansionRoom.java
- *
- * Created on 17. April 2006, 06:45
- *
- */
-
-package autoroute;
-
-import java.util.List;
-import java.util.Collection;
-
-import board.ShapeSearchTree;
-import board.SearchTreeObject;
-import board.PolylineTrace;
-
-import geometry.planar.TileShape;
-
-import board.Item;
-
-/**
- * Expansion Room used for pushing and ripping obstacles in the autoroute algorithm.
- *
- * @author Alfons Wirtz
- */
-public class ObstacleExpansionRoom implements CompleteExpansionRoom
-{
-
- /** Creates a new instance of ObstacleExpansionRoom */
- ObstacleExpansionRoom(Item p_item, int p_index_in_item, ShapeSearchTree p_shape_tree)
- {
- this.item = p_item;
- this.index_in_item = p_index_in_item;
- this.shape = p_item.get_tree_shape(p_shape_tree, p_index_in_item);
- this.doors = new java.util.LinkedList();
- }
-
- public int get_index_in_item()
- {
- return this.index_in_item;
- }
-
- public int get_layer()
- {
- return this.item.shape_layer(this.index_in_item);
- }
-
- public TileShape get_shape()
- {
- return this.shape;
- }
-
- /**
- * Checks, if this room has already a 1-dimensional door to p_other
- */
- public boolean door_exists(ExpansionRoom p_other)
- {
- if (doors != null)
- {
- for (ExpansionDoor curr_door : this.doors)
- {
- if (curr_door.first_room == p_other || curr_door.second_room == p_other)
- {
- return true;
- }
- }
- }
- return false;
- }
-
- /**
- * Adds a door to the door list of this room.
- */
- public void add_door(ExpansionDoor p_door)
- {
- this.doors.add(p_door);
- }
-
- /**
- * Creates a 2-dim door with the other obstacle room, if that is useful for the autoroute algorithm.
- * It is assumed that this room and p_other have a 2-dimensional overlap.
- * Returns false, if no door was created.
- */
- public boolean create_overlap_door(ObstacleExpansionRoom p_other)
- {
- if (this.door_exists(p_other))
- {
- return false;
- }
- if (!(this.item.is_route() && p_other.item.is_route()))
- {
- return false;
- }
- if (!this.item.shares_net(p_other.item))
- {
- return false;
- }
- if (this.item == p_other.item)
- {
- if (!(this.item instanceof PolylineTrace))
- {
- return false;
- }
- // create only doors between consecutive trace segments
- if (this.index_in_item != p_other.index_in_item + 1 && this.index_in_item != p_other.index_in_item - 1)
- {
- return false;
- }
- }
- ExpansionDoor new_door = new ExpansionDoor(this, p_other, 2);
- this.add_door(new_door);
- p_other.add_door(new_door);
- return true;
- }
-
- /**
- * Returns the list of doors of this room to neighbour expansion rooms
- */
- public List get_doors()
- {
- return this.doors;
- }
-
- /**
- * Removes all doors from this room.
- */
- public void clear_doors()
- {
- this.doors = new java.util.LinkedList();
- }
-
- public void reset_doors()
- {
- for (ExpandableObject curr_door : this.doors)
- {
- curr_door.reset();
- }
- }
-
- public Collection get_target_doors()
- {
- return new java.util.LinkedList();
- }
-
- public Item get_item()
- {
- return this.item;
- }
-
- public SearchTreeObject get_object()
- {
- return this.item;
- }
-
- public boolean remove_door(ExpandableObject p_door)
- {
- return this.doors.remove(p_door);
- }
-
- /**
- * Returns, if all doors to the neighbour rooms are calculated.
- */
- boolean all_doors_calculated()
- {
- return this.doors_calculated;
- }
-
- void set_doors_calculated(boolean p_value)
- {
- this.doors_calculated = p_value;
- }
-
-
- /**
- * Draws the shape of this room.
- */
- public void draw(java.awt.Graphics p_graphics, boardgraphics.GraphicsContext p_graphics_context, double p_intensity)
- {
- java.awt.Color draw_color = java.awt.Color.WHITE;
- double layer_visibility = p_graphics_context.get_layer_visibility(this.get_layer());
- p_graphics_context.fill_area(this.get_shape(), p_graphics, draw_color, p_intensity * layer_visibility);
- p_graphics_context.draw_boundary(this.get_shape(), 0, draw_color, p_graphics, layer_visibility);
- }
-
- private final Item item;
- private final int index_in_item;
- private final TileShape shape;
-
- /** The list of doors to neighbour expansion rooms */
- private List doors;
-
- private boolean doors_calculated = false;
-}
+/*
+ * Copyright (C) 2014 Alfons Wirtz
+ * website www.freerouting.net
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License at
+ * for more details.
+ *
+ * ObstacleExpansionRoom.java
+ *
+ * Created on 17. April 2006, 06:45
+ *
+ */
+
+package autoroute;
+
+import java.util.List;
+import java.util.Collection;
+
+import board.ShapeSearchTree;
+import board.SearchTreeObject;
+import board.PolylineTrace;
+
+import geometry.planar.TileShape;
+
+import board.Item;
+
+/**
+ * Expansion Room used for pushing and ripping obstacles in the autoroute algorithm.
+ *
+ * @author Alfons Wirtz
+ * @version $Id: $Id
+ */
+public class ObstacleExpansionRoom implements CompleteExpansionRoom
+{
+
+ /** Creates a new instance of ObstacleExpansionRoom */
+ ObstacleExpansionRoom(Item p_item, int p_index_in_item, ShapeSearchTree p_shape_tree)
+ {
+ this.item = p_item;
+ this.index_in_item = p_index_in_item;
+ this.shape = p_item.get_tree_shape(p_shape_tree, p_index_in_item);
+ this.doors = new java.util.LinkedList();
+ }
+
+ /**
+ *
get_index_in_item.
+ *
+ * @return a int.
+ */
+ public int get_index_in_item()
+ {
+ return this.index_in_item;
+ }
+
+ /**
+ * get_layer.
+ *
+ * @return a int.
+ */
+ public int get_layer()
+ {
+ return this.item.shape_layer(this.index_in_item);
+ }
+
+ /**
+ * get_shape.
+ *
+ * @return a {@link geometry.planar.TileShape} object.
+ */
+ public TileShape get_shape()
+ {
+ return this.shape;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * Checks, if this room has already a 1-dimensional door to p_other
+ */
+ public boolean door_exists(ExpansionRoom p_other)
+ {
+ if (doors != null)
+ {
+ for (ExpansionDoor curr_door : this.doors)
+ {
+ if (curr_door.first_room == p_other || curr_door.second_room == p_other)
+ {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * Adds a door to the door list of this room.
+ */
+ public void add_door(ExpansionDoor p_door)
+ {
+ this.doors.add(p_door);
+ }
+
+ /**
+ * Creates a 2-dim door with the other obstacle room, if that is useful for the autoroute algorithm.
+ * It is assumed that this room and p_other have a 2-dimensional overlap.
+ * Returns false, if no door was created.
+ *
+ * @param p_other a {@link autoroute.ObstacleExpansionRoom} object.
+ * @return a boolean.
+ */
+ public boolean create_overlap_door(ObstacleExpansionRoom p_other)
+ {
+ if (this.door_exists(p_other))
+ {
+ return false;
+ }
+ if (!(this.item.is_route() && p_other.item.is_route()))
+ {
+ return false;
+ }
+ if (!this.item.shares_net(p_other.item))
+ {
+ return false;
+ }
+ if (this.item == p_other.item)
+ {
+ if (!(this.item instanceof PolylineTrace))
+ {
+ return false;
+ }
+ // create only doors between consecutive trace segments
+ if (this.index_in_item != p_other.index_in_item + 1 && this.index_in_item != p_other.index_in_item - 1)
+ {
+ return false;
+ }
+ }
+ ExpansionDoor new_door = new ExpansionDoor(this, p_other, 2);
+ this.add_door(new_door);
+ p_other.add_door(new_door);
+ return true;
+ }
+
+ /**
+ * Returns the list of doors of this room to neighbour expansion rooms
+ *
+ * @return a {@link java.util.List} object.
+ */
+ public List get_doors()
+ {
+ return this.doors;
+ }
+
+ /**
+ * Removes all doors from this room.
+ */
+ public void clear_doors()
+ {
+ this.doors = new java.util.LinkedList();
+ }
+
+ /**
+ * reset_doors.
+ */
+ public void reset_doors()
+ {
+ for (ExpandableObject curr_door : this.doors)
+ {
+ curr_door.reset();
+ }
+ }
+
+ /**
+ * get_target_doors.
+ *
+ * @return a {@link java.util.Collection} object.
+ */
+ public Collection get_target_doors()
+ {
+ return new java.util.LinkedList();
+ }
+
+ /**
+ * get_item.
+ *
+ * @return a {@link board.Item} object.
+ */
+ public Item get_item()
+ {
+ return this.item;
+ }
+
+ /**
+ * get_object.
+ *
+ * @return a {@link board.SearchTreeObject} object.
+ */
+ public SearchTreeObject get_object()
+ {
+ return this.item;
+ }
+
+ /** {@inheritDoc} */
+ public boolean remove_door(ExpandableObject p_door)
+ {
+ return this.doors.remove(p_door);
+ }
+
+ /**
+ * Returns, if all doors to the neighbour rooms are calculated.
+ */
+ boolean all_doors_calculated()
+ {
+ return this.doors_calculated;
+ }
+
+ void set_doors_calculated(boolean p_value)
+ {
+ this.doors_calculated = p_value;
+ }
+
+
+ /**
+ * {@inheritDoc}
+ *
+ * Draws the shape of this room.
+ */
+ public void draw(java.awt.Graphics p_graphics, boardgraphics.GraphicsContext p_graphics_context, double p_intensity)
+ {
+ java.awt.Color draw_color = java.awt.Color.WHITE;
+ double layer_visibility = p_graphics_context.get_layer_visibility(this.get_layer());
+ p_graphics_context.fill_area(this.get_shape(), p_graphics, draw_color, p_intensity * layer_visibility);
+ p_graphics_context.draw_boundary(this.get_shape(), 0, draw_color, p_graphics, layer_visibility);
+ }
+
+ private final Item item;
+ private final int index_in_item;
+ private final TileShape shape;
+
+ /** The list of doors to neighbour expansion rooms */
+ private List doors;
+
+ private boolean doors_calculated = false;
+}
diff --git a/autoroute/Sorted45DegreeRoomNeighbours.java b/src/main/java/autoroute/Sorted45DegreeRoomNeighbours.java
similarity index 97%
rename from autoroute/Sorted45DegreeRoomNeighbours.java
rename to src/main/java/autoroute/Sorted45DegreeRoomNeighbours.java
index 3cde936..355d25c 100644
--- a/autoroute/Sorted45DegreeRoomNeighbours.java
+++ b/src/main/java/autoroute/Sorted45DegreeRoomNeighbours.java
@@ -1,1131 +1,1140 @@
-/*
- * Copyright (C) 2014 Alfons Wirtz
- * website www.freerouting.net
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License at
- * for more details.
- *
- * Sorted45DegreeRoomNeighbours.java
- *
- * Created on 6. Juli 2007, 07:28
- *
- */
-
-package autoroute;
-
-import java.util.Collection;
-import java.util.Iterator;
-import java.util.LinkedList;
-import java.util.SortedSet;
-import java.util.TreeSet;
-
-import datastructures.ShapeTree;
-
-import geometry.planar.Limits;
-import geometry.planar.IntOctagon;
-import geometry.planar.IntPoint;
-import geometry.planar.TileShape;
-import geometry.planar.FloatPoint;
-
-import board.ShapeSearchTree;
-import board.SearchTreeObject;
-import board.Item;
-
-/**
- *
- * @author Alfons Wirtz
- */
-public class Sorted45DegreeRoomNeighbours
-{
-
- public static CompleteExpansionRoom calculate(ExpansionRoom p_room, AutorouteEngine p_autoroute_engine)
- {
- int net_no = p_autoroute_engine.get_net_no();
- Sorted45DegreeRoomNeighbours room_neighbours = Sorted45DegreeRoomNeighbours.calculate_neighbours(p_room, net_no,
- p_autoroute_engine.autoroute_search_tree, p_autoroute_engine.generate_room_id_no());
- if (room_neighbours == null)
- {
- return null;
- }
-
- // Check, that each side of the romm shape has at least one touching neighbour.
- // Otherwise improve the room shape by enlarging.
- boolean edge_removed = room_neighbours.try_remove_edge_line(net_no, p_autoroute_engine.autoroute_search_tree);
- CompleteExpansionRoom result = room_neighbours.completed_room;
- if (edge_removed)
- {
- p_autoroute_engine.remove_all_doors(result);
- return calculate(p_room, p_autoroute_engine);
- }
-
- // Now calculate the new incomplete rooms together with the doors
- // between this room and the sorted neighbours.
-
- if (room_neighbours.sorted_neighbours.isEmpty())
- {
- if (result instanceof ObstacleExpansionRoom)
- {
- room_neighbours.calculate_edge_incomplete_rooms_of_obstacle_expansion_room(0, 7, p_autoroute_engine);
- }
- }
- else
- {
- room_neighbours.calculate_new_incomplete_rooms(p_autoroute_engine);
- }
- return result;
- }
-
- /**
- * Calculates all touching neighbours of p_room and sorts them in
- * counterclock sense around the boundary of the room shape.
- */
- private static Sorted45DegreeRoomNeighbours calculate_neighbours(ExpansionRoom p_room, int p_net_no,
- ShapeSearchTree p_autoroute_search_tree, int p_room_id_no)
- {
- TileShape room_shape = p_room.get_shape();
- CompleteExpansionRoom completed_room;
- if (p_room instanceof IncompleteFreeSpaceExpansionRoom)
- {
- completed_room = new CompleteFreeSpaceExpansionRoom(room_shape, p_room.get_layer(), p_room_id_no);
- }
- else if (p_room instanceof ObstacleExpansionRoom)
- {
- completed_room = (ObstacleExpansionRoom)p_room;
- }
- else
- {
- System.out.println("Sorted45DegreeRoomNeighbours.calculate_neighbours: unexpected expansion room type");
- return null;
- }
- IntOctagon room_oct = room_shape.bounding_octagon();
- Sorted45DegreeRoomNeighbours result = new Sorted45DegreeRoomNeighbours(p_room, completed_room);
- Collection overlapping_objects = new LinkedList();
- p_autoroute_search_tree.overlapping_tree_entries(room_shape, p_room.get_layer(), overlapping_objects);
- // Calculate the touching neigbour objects and sort them in counterclock sence
- // around the border of the room shape.
- for (ShapeTree.TreeEntry curr_entry : overlapping_objects)
- {
- SearchTreeObject curr_object = (SearchTreeObject) curr_entry.object;
- if (curr_object == p_room)
- {
- continue;
- }
- if ((completed_room instanceof CompleteFreeSpaceExpansionRoom) && !curr_object.is_trace_obstacle(p_net_no))
- {
- ((CompleteFreeSpaceExpansionRoom) completed_room).calculate_target_doors(curr_entry,
- p_net_no, p_autoroute_search_tree);
- continue;
- }
- TileShape curr_shape =
- curr_object.get_tree_shape(p_autoroute_search_tree, curr_entry.shape_index_in_object);
- IntOctagon curr_oct = curr_shape.bounding_octagon();
- IntOctagon intersection = room_oct.intersection(curr_oct);
- int dimension = intersection.dimension();
- if (dimension > 1 && completed_room instanceof ObstacleExpansionRoom)
- {
- if (curr_object instanceof Item)
- {
- // only Obstacle expansion roos may have a 2-dim overlap
- Item curr_item = (Item) curr_object;
- if (curr_item.is_route())
- {
- ItemAutorouteInfo item_info = curr_item.get_autoroute_info();
- ObstacleExpansionRoom curr_overlap_room =
- item_info.get_expansion_room(curr_entry.shape_index_in_object, p_autoroute_search_tree);
- ((ObstacleExpansionRoom) completed_room).create_overlap_door(curr_overlap_room);
- }
- }
- continue;
- }
- if (dimension < 0)
- {
- // may happen at a corner from 2 diagonal lines with non integer coordinates (--.5, ---.5).
- continue;
- }
- result.add_sorted_neighbour(curr_oct, intersection);
- if (dimension > 0)
- {
- // make shure, that there is a door to the neighbour room.
- ExpansionRoom neighbour_room = null;
- if (curr_object instanceof ExpansionRoom)
- {
- neighbour_room = (ExpansionRoom) curr_object;
- }
- else if (curr_object instanceof Item)
- {
- Item curr_item = (Item) curr_object;
- if (curr_item.is_route())
- {
- // expand the item for ripup and pushing purposes
- ItemAutorouteInfo item_info = curr_item.get_autoroute_info();
- neighbour_room =
- item_info.get_expansion_room(curr_entry.shape_index_in_object, p_autoroute_search_tree);
- }
- }
- if (neighbour_room != null)
- {
- if (SortedRoomNeighbours.insert_door_ok(completed_room, neighbour_room, intersection))
- {
- ExpansionDoor new_door = new ExpansionDoor(completed_room, neighbour_room);
- neighbour_room.add_door(new_door);
- completed_room.add_door(new_door);
- }
- }
- }
- }
- return result;
- }
-
-
- /** Creates a new instance of Sorted45DegreeRoomNeighbours */
- private Sorted45DegreeRoomNeighbours(ExpansionRoom p_from_room, CompleteExpansionRoom p_completed_room)
- {
- from_room = p_from_room;
- completed_room = p_completed_room;
- room_shape = p_completed_room.get_shape().bounding_octagon();
- sorted_neighbours = new TreeSet();
-
- edge_interiour_touches_obstacle = new boolean[8];
- for (int i = 0; i < 8; ++i)
- {
- edge_interiour_touches_obstacle[i] = false;
- }
- }
-
- private void add_sorted_neighbour(IntOctagon p_neighbour_shape, IntOctagon p_intersection)
- {
- SortedRoomNeighbour new_neighbour = new SortedRoomNeighbour(p_neighbour_shape, p_intersection);
- if (new_neighbour.last_touching_side >= 0)
- {
- sorted_neighbours.add(new_neighbour);
- }
- }
-
- /**
- * Calculates an incomplete room for each edge side from p_from_side_no to p_to_side_no.
- */
- private void calculate_edge_incomplete_rooms_of_obstacle_expansion_room(int p_from_side_no, int p_to_side_no, AutorouteEngine p_autoroute_engine)
- {
- if (!(this.from_room instanceof ObstacleExpansionRoom))
- {
- System.out.println("Sorted45DegreeRoomNeighbours.calculate_side_incomplete_rooms_of_obstacle_expansion_room: ObstacleExpansionRoom expected for this.from_room");
- return;
- }
- IntOctagon board_bounding_oct = p_autoroute_engine.board.get_bounding_box().bounding_octagon();
- IntPoint curr_corner = this.room_shape.corner(p_from_side_no);
- int curr_side_no = p_from_side_no;
- for (;;)
- {
- int next_side_no = (curr_side_no + 1) % 8;
- IntPoint next_corner = this.room_shape.corner(next_side_no);
- if (!curr_corner.equals(next_corner))
- {
- int lx = board_bounding_oct.lx;
- int ly = board_bounding_oct.ly;
- int rx = board_bounding_oct.rx;
- int uy = board_bounding_oct.uy;
- int ulx = board_bounding_oct.ulx;
- int lrx = board_bounding_oct.lrx;
- int llx = board_bounding_oct.llx;
- int urx = board_bounding_oct.urx;
- if (curr_side_no == 0)
- {
- uy = this.room_shape.ly;
- }
- else if (curr_side_no == 1)
- {
- ulx = this.room_shape.lrx;
- }
- else if (curr_side_no == 2)
- {
- lx = this.room_shape.rx;
- }
- else if (curr_side_no == 3)
- {
- llx = this.room_shape.urx;
- }
- else if (curr_side_no == 4)
- {
- ly = this.room_shape.uy;
- }
- else if (curr_side_no == 5)
- {
- lrx = this.room_shape.ulx;
- }
- else if (curr_side_no == 6)
- {
- rx = this.room_shape.lx;
- }
- else if (curr_side_no == 7)
- {
- urx = this.room_shape.llx;
- }
- else
- {
- System.out.println("SortedOrthoganelRoomNeighbours.calculate_edge_incomplete_rooms_of_obstacle_expansion_room: curr_side_no illegal");
- return;
- }
- insert_incomplete_room(p_autoroute_engine, lx, ly, rx, uy, ulx, lrx, llx, urx);
- }
- if (curr_side_no == p_to_side_no)
- {
- break;
- }
- curr_side_no = next_side_no;
- }
- }
-
- private static IntOctagon remove_not_touching_border_lines( IntOctagon p_room_oct,
- boolean[] p_edge_interiour_touches_obstacle)
- {
- int lx;
- if (p_edge_interiour_touches_obstacle[6])
- {
- lx = p_room_oct.lx;
- }
- else
- {
- lx = -Limits.CRIT_INT;
- }
-
- int ly;
- if (p_edge_interiour_touches_obstacle[0])
- {
- ly = p_room_oct.ly;
- }
- else
- {
- ly = -Limits.CRIT_INT;
- }
-
- int rx;
- if (p_edge_interiour_touches_obstacle[2])
- {
- rx = p_room_oct.rx;
- }
- else
- {
- rx = Limits.CRIT_INT;
- }
-
-
- int uy;
- if (p_edge_interiour_touches_obstacle[4])
- {
- uy = p_room_oct.uy;
- }
- else
- {
- uy = Limits.CRIT_INT;
- }
-
- int ulx;
- if (p_edge_interiour_touches_obstacle[5])
- {
- ulx = p_room_oct.ulx;
- }
- else
- {
- ulx = -Limits.CRIT_INT;
- }
-
- int lrx;
- if (p_edge_interiour_touches_obstacle[1])
- {
- lrx = p_room_oct.lrx;
- }
- else
- {
- lrx = Limits.CRIT_INT;
- }
-
- int llx;
- if (p_edge_interiour_touches_obstacle[7])
- {
- llx = p_room_oct.llx;
- }
- else
- {
- llx = -Limits.CRIT_INT;
- }
-
- int urx;
- if (p_edge_interiour_touches_obstacle[3])
- {
- urx = p_room_oct.urx;
- }
- else
- {
- urx = Limits.CRIT_INT;
- }
-
- IntOctagon result = new IntOctagon( lx, ly, rx, uy, ulx, lrx, llx, urx);
- return result.normalize();
- }
- /**
- * Check, that each side of the romm shape has at least one touching neighbour.
- * Otherwise the room shape will be improved the by enlarging.
- * Returns true, if the room shape was changed.
- */
- private boolean try_remove_edge_line(int p_net_no, ShapeSearchTree p_autoroute_search_tree)
- {
- if (!(this.from_room instanceof IncompleteFreeSpaceExpansionRoom))
- {
- return false;
- }
- IncompleteFreeSpaceExpansionRoom curr_incomplete_room = (IncompleteFreeSpaceExpansionRoom) this.from_room;
- if (!(curr_incomplete_room.get_shape() instanceof IntOctagon))
- {
- System.out.println("Sorted45DegreeRoomNeighbours.try_remove_edge_line: IntOctagon expected for room_shape type");
- return false;
- }
- IntOctagon room_oct = (IntOctagon) curr_incomplete_room.get_shape();
- double room_area = room_oct.area();
-
- boolean try_remove_edge_lines = false;
- for (int i = 0; i < 8; ++i)
- {
- if (!this.edge_interiour_touches_obstacle[i])
- {
- FloatPoint prev_corner = this.room_shape.corner_approx(i);
- FloatPoint next_corner = this.room_shape.corner_approx(this.room_shape.next_no(i));
- if(prev_corner.distance_square(next_corner) > 1)
- {
- try_remove_edge_lines = true;
- break;
- }
- }
- }
-
- if (try_remove_edge_lines)
- {
- // Touching neighbour missing at the edge side with index remove_edge_no
- // Remove the edge line and restart the algorithm.
-
- IntOctagon enlarged_oct = remove_not_touching_border_lines( room_oct, this.edge_interiour_touches_obstacle);
-
- Collection door_list = this.completed_room.get_doors();
- TileShape ignore_shape = null;
- SearchTreeObject ignore_object = null;
- double max_door_area = 0;
- for (ExpansionDoor curr_door: door_list)
- {
- // insert the overlapping doors with CompleteFreeSpaceExpansionRooms
- // for the information in complete_shape about the objects to ignore.
- if (curr_door.dimension == 2)
- {
- CompleteExpansionRoom other_room = curr_door.other_room(this.completed_room);
- {
- if (other_room instanceof CompleteFreeSpaceExpansionRoom)
- {
- TileShape curr_door_shape = curr_door.get_shape();
- double curr_door_area = curr_door_shape.area();
- if (curr_door_area > max_door_area)
- {
- max_door_area = curr_door_area;
- ignore_shape = curr_door_shape;
- ignore_object = (CompleteFreeSpaceExpansionRoom) other_room;
- }
- }
- }
- }
- }
- IncompleteFreeSpaceExpansionRoom enlarged_room =
- new IncompleteFreeSpaceExpansionRoom(enlarged_oct, curr_incomplete_room.get_layer(),
- curr_incomplete_room.get_contained_shape());
- Collection new_rooms =
- p_autoroute_search_tree.complete_shape(enlarged_room, p_net_no, ignore_object, ignore_shape);
- if (new_rooms.size() == 1)
- {
- // Check, that the area increases to prevent endless loop.
- IncompleteFreeSpaceExpansionRoom new_room = new_rooms.iterator().next();
- if (new_room.get_shape().area() > room_area)
- {
- curr_incomplete_room.set_shape(new_room.get_shape());
- curr_incomplete_room.set_contained_shape(new_room.get_contained_shape());
- return true;
- }
- }
- }
- return false;
- }
-
- /**
- * Inserts a new incomplete room with an octagon shape.
- */
- private void insert_incomplete_room(AutorouteEngine p_autoroute_engine, int p_lx, int p_ly, int p_rx, int p_uy,
- int p_ulx, int p_lrx, int p_llx, int p_urx)
- {
- IntOctagon new_incomplete_room_shape = new IntOctagon(p_lx, p_ly, p_rx, p_uy, p_ulx, p_lrx, p_llx, p_urx);
- new_incomplete_room_shape = new_incomplete_room_shape.normalize();
- if (new_incomplete_room_shape.dimension() == 2)
- {
- IntOctagon new_contained_shape = this.room_shape.intersection(new_incomplete_room_shape);
- if (!new_contained_shape.is_empty())
- {
- int door_dimension = new_contained_shape.dimension();
- if (door_dimension > 0)
- {
- FreeSpaceExpansionRoom new_room =
- p_autoroute_engine.add_incomplete_expansion_room(new_incomplete_room_shape, this.from_room.get_layer(), new_contained_shape);
- ExpansionDoor new_door = new ExpansionDoor(this.completed_room, new_room, door_dimension);
- this.completed_room.add_door(new_door);
- new_room.add_door(new_door);
- }
- }
- }
- }
-
- private void calculate_new_incomplete_rooms_for_obstacle_expansion_room(SortedRoomNeighbour p_prev_neighbour,
- SortedRoomNeighbour p_next_neighbour, AutorouteEngine p_autoroute_engine)
- {
- int from_side_no = p_prev_neighbour.last_touching_side;
- int to_side_no = p_next_neighbour.first_touching_side;
- if (from_side_no == to_side_no && p_prev_neighbour != p_next_neighbour)
- {
- // no return in case of only 1 neighbour.
- return;
- }
- IntOctagon board_bounding_oct = p_autoroute_engine.board.bounding_box.bounding_octagon();
-
- // insert the new incomplete room from p_prev_neighbour to the next corner of the room shape.
-
- int lx = board_bounding_oct.lx;
- int ly = board_bounding_oct.ly;
- int rx = board_bounding_oct.rx;
- int uy = board_bounding_oct.uy;
- int ulx = board_bounding_oct.ulx;
- int lrx = board_bounding_oct.lrx;
- int llx = board_bounding_oct.llx;
- int urx = board_bounding_oct.urx;
- if (from_side_no == 0)
- {
- uy = this.room_shape.ly;
- ulx = p_prev_neighbour.intersection.lrx;
- }
- else if (from_side_no == 1)
- {
- ulx = this.room_shape.lrx;
- lx = p_prev_neighbour.intersection.rx;
- }
- else if (from_side_no == 2)
- {
- lx = this.room_shape.rx;
- llx = p_prev_neighbour.intersection.urx;
- }
- else if (from_side_no == 3)
- {
- llx = this.room_shape.urx;
- ly = p_prev_neighbour.intersection.uy;
- }
- else if (from_side_no == 4)
- {
- ly = this.room_shape.uy;
- lrx = p_prev_neighbour.intersection.ulx;
- }
- else if (from_side_no == 5)
- {
- lrx = this.room_shape.ulx;
- rx = p_prev_neighbour.intersection.lx;
- }
- else if (from_side_no == 6)
- {
- rx = this.room_shape.lx;
- urx = p_prev_neighbour.intersection.llx;
- }
- else if (from_side_no == 7)
- {
- urx = this.room_shape.llx;
- uy = p_prev_neighbour.intersection.ly;
- }
- insert_incomplete_room(p_autoroute_engine, lx, ly, rx, uy, ulx, lrx, llx, urx);
-
- // insert the new incomplete room from p_prev_neighbour to the next corner of the room shape.
-
- lx = board_bounding_oct.lx;
- ly = board_bounding_oct.ly;
- rx = board_bounding_oct.rx;
- uy = board_bounding_oct.uy;
- ulx = board_bounding_oct.ulx;
- lrx = board_bounding_oct.lrx;
- llx = board_bounding_oct.llx;
- urx = board_bounding_oct.urx;
-
- if (to_side_no == 0)
- {
- uy = this.room_shape.ly;
- urx = p_next_neighbour.intersection.llx;
- }
- else if (to_side_no == 1)
- {
- ulx = this.room_shape.lrx;
- uy = p_next_neighbour.intersection.ly;
- }
- else if (to_side_no == 2)
- {
- lx = this.room_shape.rx;
- ulx = p_next_neighbour.intersection.lrx;
- }
- else if (to_side_no == 3)
- {
- llx = this.room_shape.urx;
- lx = p_next_neighbour.intersection.rx;
- }
- else if (to_side_no == 4)
- {
- ly = this.room_shape.uy;
- llx = p_next_neighbour.intersection.urx;
- }
- else if (to_side_no == 5)
- {
- lrx = this.room_shape.ulx;
- ly = p_next_neighbour.intersection.uy;
- }
- else if (to_side_no == 6)
- {
- rx = this.room_shape.lx;
- lrx = p_next_neighbour.intersection.ulx;
- }
- else if (to_side_no == 7)
- {
- urx = this.room_shape.llx;
- rx = p_next_neighbour.intersection.lx;
- }
- insert_incomplete_room(p_autoroute_engine, lx, ly, rx, uy, ulx, lrx, llx, urx);
-
- // Insert the new incomplete rooms on the intermediate free sides of the obstacle expansion room.
- int curr_from_side_no = (from_side_no + 1) % 8;
- if (curr_from_side_no == to_side_no)
- {
- return;
- }
- int curr_to_side_no = (to_side_no + 7) % 8;
- this.calculate_edge_incomplete_rooms_of_obstacle_expansion_room(curr_from_side_no,
- curr_to_side_no, p_autoroute_engine);
- }
-
- private void calculate_new_incomplete_rooms(AutorouteEngine p_autoroute_engine)
- {
- IntOctagon board_bounding_oct = p_autoroute_engine.board.bounding_box.bounding_octagon();
- SortedRoomNeighbour prev_neighbour = this.sorted_neighbours.last();
- if (this.from_room instanceof ObstacleExpansionRoom && this.sorted_neighbours.size() == 1)
- {
- // ObstacleExpansionRoom has only only 1 neighbour
- calculate_new_incomplete_rooms_for_obstacle_expansion_room(prev_neighbour, prev_neighbour, p_autoroute_engine);
- return;
- }
- Iterator it = this.sorted_neighbours.iterator();
-
- while (it.hasNext())
- {
- SortedRoomNeighbour next_neighbour = it.next();
-
- boolean insert_incomplete_room;
-
- if (this.completed_room instanceof ObstacleExpansionRoom && this.sorted_neighbours.size() == 2)
- {
- // check, if this site is touching or open.
- TileShape intersection = next_neighbour.intersection.intersection(prev_neighbour.intersection);
- if (intersection.is_empty())
- {
- insert_incomplete_room = true;
- }
- else if (intersection.dimension() >= 1)
- {
- insert_incomplete_room = false;
- }
- else // dimension = 1
- {
- if (prev_neighbour.last_touching_side == next_neighbour.first_touching_side)
- {
- // touch along the side of the room shape
- insert_incomplete_room = false;
- }
- else if(prev_neighbour.last_touching_side == (next_neighbour.first_touching_side + 1) % 8)
- {
- // touch at a corner of the room shape
- insert_incomplete_room = false;
- }
- else
- {
- insert_incomplete_room = true;
- }
- }
- }
- else
- {
- // the 2 neigbours do not touch
- insert_incomplete_room = !next_neighbour.intersection.intersects(prev_neighbour.intersection);
- }
-
-
- if (insert_incomplete_room)
- {
- // create a door to a new incomplete expansion room between
- // the last corner of the previous neighbour and the first corner of the
- // current neighbour
-
- if (this.from_room instanceof ObstacleExpansionRoom &&
- next_neighbour.first_touching_side != prev_neighbour.last_touching_side)
- {
- calculate_new_incomplete_rooms_for_obstacle_expansion_room(prev_neighbour, next_neighbour, p_autoroute_engine);
- }
- else
- {
- int lx = board_bounding_oct.lx;
- int ly = board_bounding_oct.ly;
- int rx = board_bounding_oct.rx;
- int uy = board_bounding_oct.uy;
- int ulx = board_bounding_oct.ulx;
- int lrx = board_bounding_oct.lrx;
- int llx = board_bounding_oct.llx;
- int urx = board_bounding_oct.urx;
-
- if (next_neighbour.first_touching_side == 0)
- {
- if (prev_neighbour.intersection.llx < next_neighbour.intersection.llx)
- {
- urx = next_neighbour.intersection.llx;
- uy = prev_neighbour.intersection.ly;
- if (prev_neighbour.last_touching_side == 0)
- {
- ulx = prev_neighbour.intersection.lrx;
- }
- }
- else if (prev_neighbour.intersection.llx > next_neighbour.intersection.llx)
- {
- rx = next_neighbour.intersection.lx;
- urx = prev_neighbour.intersection.llx;
- }
- else // prev_neighbour.intersection.llx == next_neighbour.intersection.llx
- {
- urx = next_neighbour.intersection.llx;
- }
- }
- else if (next_neighbour.first_touching_side == 1)
- {
- if (prev_neighbour.intersection.ly < next_neighbour.intersection.ly)
- {
- uy = next_neighbour.intersection.ly;
- ulx = prev_neighbour.intersection.lrx;
- if (prev_neighbour.last_touching_side == 1)
- {
- lx = prev_neighbour.intersection.rx;
- }
- }
- else if (prev_neighbour.intersection.ly > next_neighbour.intersection.ly)
- {
- uy = prev_neighbour.intersection.ly;
- urx = next_neighbour.intersection.llx;
- }
- else // prev_neighbour.intersection.ly == next_neighbour.intersection.ly
- {
- uy = next_neighbour.intersection.ly;
- }
- }
- else if (next_neighbour.first_touching_side == 2)
- {
- if (prev_neighbour.intersection.lrx > next_neighbour.intersection.lrx)
- {
- ulx = next_neighbour.intersection.lrx;
- lx = prev_neighbour.intersection.rx;
- if (prev_neighbour.last_touching_side == 2)
- {
- llx = prev_neighbour.intersection.urx;
- }
- }
- else if (prev_neighbour.intersection.lrx < next_neighbour.intersection.lrx)
- {
- uy = next_neighbour.intersection.ly;
- ulx = prev_neighbour.intersection.lrx;
- }
- else // prev_neighbour.intersection.lrx == next_neighbour.intersection.lrx
- {
- ulx = next_neighbour.intersection.lrx;
- }
- }
- else if (next_neighbour.first_touching_side == 3)
- {
- if (prev_neighbour.intersection.rx > next_neighbour.intersection.rx)
- {
- lx = next_neighbour.intersection.rx;
- llx = prev_neighbour.intersection.urx;
- if (prev_neighbour.last_touching_side == 3)
- {
- ly = prev_neighbour.intersection.uy;
- }
- }
- else if (prev_neighbour.intersection.rx < next_neighbour.intersection.rx)
- {
- lx = prev_neighbour.intersection.rx;
- ulx = next_neighbour.intersection.lrx;
- }
- else // prev_neighbour.intersection.ry == next_neighbour.intersection.ry
- {
- lx = next_neighbour.intersection.rx;
- }
- }
- else if (next_neighbour.first_touching_side == 4)
- {
- if (prev_neighbour.intersection.urx > next_neighbour.intersection.urx)
- {
- llx = next_neighbour.intersection.urx;
- ly = prev_neighbour.intersection.uy;
- if (prev_neighbour.last_touching_side == 4)
- {
- lrx = prev_neighbour.intersection.ulx;
- }
- }
- else if (prev_neighbour.intersection.urx < next_neighbour.intersection.urx)
- {
- lx = next_neighbour.intersection.rx;
- llx = prev_neighbour.intersection.urx;
- }
- else // prev_neighbour.intersection.urx == next_neighbour.intersection.urx
- {
- llx = next_neighbour.intersection.urx;
- }
- }
- else if (next_neighbour.first_touching_side == 5)
- {
- if (prev_neighbour.intersection.uy > next_neighbour.intersection.uy)
- {
- ly = next_neighbour.intersection.uy;
- lrx = prev_neighbour.intersection.ulx;
- if (prev_neighbour.last_touching_side == 5)
- {
- rx = prev_neighbour.intersection.lx;
- }
- }
- else if (prev_neighbour.intersection.uy < next_neighbour.intersection.uy)
- {
- ly = prev_neighbour.intersection.uy;
- llx = next_neighbour.intersection.urx;
- }
- else // prev_neighbour.intersection.uy == next_neighbour.intersection.uy
- {
- ly = next_neighbour.intersection.uy;
- }
- }
- else if (next_neighbour.first_touching_side == 6)
- {
- if (prev_neighbour.intersection.ulx < next_neighbour.intersection.ulx)
- {
- lrx = next_neighbour.intersection.ulx;
- rx = prev_neighbour.intersection.lx;
- if (prev_neighbour.last_touching_side == 6)
- {
- urx = prev_neighbour.intersection.llx;
- }
- }
- else if (prev_neighbour.intersection.ulx > next_neighbour.intersection.ulx)
- {
- ly = next_neighbour.intersection.uy;
- lrx = prev_neighbour.intersection.ulx;
- }
- else // prev_neighbour.intersection.ulx == next_neighbour.intersection.ulx
- {
- lrx = next_neighbour.intersection.ulx;
- }
- }
- else if (next_neighbour.first_touching_side == 7)
- {
- if (prev_neighbour.intersection.lx < next_neighbour.intersection.lx)
- {
- rx = next_neighbour.intersection.lx;
- urx = prev_neighbour.intersection.llx;
- if (prev_neighbour.last_touching_side == 7)
- {
- uy = prev_neighbour.intersection.ly;
- }
- }
- else if (prev_neighbour.intersection.lx > next_neighbour.intersection.lx)
- {
- rx = prev_neighbour.intersection.lx;
- lrx = next_neighbour.intersection.ulx;
- }
- else // prev_neighbour.intersection.lx == next_neighbour.intersection.lx
- {
- rx = next_neighbour.intersection.lx;
- }
- }
- else
- {
- System.out.println("Sorted45DegreeRoomNeighbour.calculate_new_incomplete: illegal touching side");
- }
- insert_incomplete_room(p_autoroute_engine, lx, ly, rx, uy, ulx, lrx, llx, urx);
- }
- }
- prev_neighbour = next_neighbour;
- }
- }
-
- public final CompleteExpansionRoom completed_room;
- public final SortedSet sorted_neighbours;
- private final ExpansionRoom from_room;
- private final IntOctagon room_shape;
-
- private final boolean[] edge_interiour_touches_obstacle;
-
- /**
- * Helper class to sort the doors of an expansion room counterclockwise
- * arount the border of the room shape.
- */
-
- private class SortedRoomNeighbour implements Comparable
- {
-
- /**
- * Creates a new instance of SortedRoomNeighbour and calculates the first and last
- * touching sides with the room shape.
- * this.last_touching_side will be -1, if sorting did not work because
- * the room_shape is contained in the neighbour shape.
- */
- public SortedRoomNeighbour(IntOctagon p_neighbour_shape, IntOctagon p_intersection)
- {
- shape = p_neighbour_shape;
- intersection = p_intersection;
-
- if (intersection.ly == room_shape.ly && intersection.llx > room_shape.llx)
- {
- this.first_touching_side = 0;
- }
- else if (intersection.lrx == room_shape.lrx && intersection.ly > room_shape.ly)
- {
- this.first_touching_side = 1;
- }
- else if (intersection.rx == room_shape.rx && intersection.lrx < room_shape.lrx)
- {
- this.first_touching_side = 2;
- }
- else if (intersection.urx == room_shape.urx && intersection.rx < room_shape.rx)
- {
- this.first_touching_side = 3;
- }
- else if (intersection.uy == room_shape.uy && intersection.urx < room_shape.urx)
- {
- this.first_touching_side = 4;
- }
- else if (intersection.ulx == room_shape.ulx && intersection.uy < room_shape.uy)
- {
- this.first_touching_side = 5;
- }
- else if (intersection.lx == room_shape.lx && intersection.ulx > room_shape.ulx)
- {
- this.first_touching_side = 6;
- }
- else if (intersection.llx == room_shape.llx && intersection.lx > room_shape.lx)
- {
- this.first_touching_side = 7;
- }
- else
- {
- // the room_shape may be contained in the neighbour_shape
- this.first_touching_side = -1;
- this.last_touching_side = -1;
- return;
- }
-
- if (intersection.llx == room_shape.llx && intersection.ly > room_shape.ly)
- {
- this.last_touching_side = 7;
- }
- else if (intersection.lx == room_shape.lx && intersection.llx > room_shape.llx)
- {
- this.last_touching_side = 6;
- }
- else if (intersection.ulx == room_shape.ulx && intersection.lx > room_shape.lx)
- {
- this.last_touching_side = 5;
- }
- else if (intersection.uy == room_shape.uy && intersection.ulx > room_shape.ulx)
- {
- this.last_touching_side = 4;
- }
- else if (intersection.urx == room_shape.urx && intersection.uy < room_shape.uy)
- {
- this.last_touching_side = 3;
- }
- else if (intersection.rx == room_shape.rx && intersection.urx < room_shape.urx)
- {
- this.last_touching_side = 2;
- }
- else if (intersection.lrx == room_shape.lrx && intersection.rx < room_shape.rx)
- {
- this.last_touching_side = 1;
- }
- else if (intersection.ly == room_shape.ly && intersection.lrx < room_shape.lrx)
- {
- this.last_touching_side = 0;
- }
- else
- {
- // the room_shape may be contained in the neighbour_shape
- this.last_touching_side = -1;
- return;
- }
-
- int next_side_no = this.first_touching_side;
- for (;;)
- {
- int curr_side_no = next_side_no;
- next_side_no = (next_side_no + 1) % 8;
- if (!edge_interiour_touches_obstacle[curr_side_no])
- {
- boolean touch_only_at_corner = false;
- if (curr_side_no == this.first_touching_side)
- {
- if (intersection.corner(curr_side_no).equals(room_shape.corner(next_side_no)))
- {
- touch_only_at_corner = true;
- }
- }
- if (curr_side_no == this.last_touching_side)
- {
- if (intersection.corner(next_side_no).equals(room_shape.corner(curr_side_no)))
- {
- touch_only_at_corner = true;
- }
- }
- if (!touch_only_at_corner)
- {
- edge_interiour_touches_obstacle[curr_side_no] = true;
- }
- }
- if (curr_side_no == this.last_touching_side)
- {
- break;
- }
-
- }
- }
-
- /**
- * Compare function for or sorting the neighbours in counterclock sense
- * around the border of the room shape in ascending order.
- */
- public int compareTo(SortedRoomNeighbour p_other)
- {
- if (this.first_touching_side > p_other.first_touching_side)
- {
- return 1;
- }
- if (this.first_touching_side < p_other.first_touching_side)
- {
- return -1;
- }
-
- // now the first touch of this and p_other is at the same side
- IntOctagon is1 = this.intersection;
- IntOctagon is2 = p_other.intersection;
- int cmp_value;
-
- if (first_touching_side == 0)
- {
- cmp_value = is1.corner(0).x - is2.corner(0).x;
- }
- else if (first_touching_side == 1)
- {
- cmp_value = is1.corner(1).x - is2.corner(1).x;
- }
- else if (first_touching_side == 2)
- {
- cmp_value = is1.corner(2).y - is2.corner(2).y;
- }
- else if (first_touching_side == 3)
- {
- cmp_value = is1.corner(3).y - is2.corner(3).y;
- }
- else if (first_touching_side == 4)
- {
- cmp_value = is2.corner(4).x - is1.corner(4).x;
- }
- else if (first_touching_side == 5)
- {
- cmp_value = is2.corner(5).x - is1.corner(5).x;
- }
- else if (first_touching_side == 6)
- {
- cmp_value = is2.corner(6).y - is1.corner(6).y;
- }
- else if (first_touching_side == 7)
- {
- cmp_value = is2.corner(7).y - is1.corner(7).y;
- }
- else
- {
- System.out.println("SortedRoomNeighbour.compareTo: first_touching_side out of range ");
- return 0;
- }
-
- if (cmp_value == 0)
- {
- // The first touching points of this neighbour and p_other with the room shape are equal.
- // Compare the last touching points.
- int this_touching_side_diff = (this.last_touching_side - this.first_touching_side + 8) % 8;
- int other_touching_side_diff = (p_other.last_touching_side - p_other.first_touching_side + 8) % 8;
- if (this_touching_side_diff > other_touching_side_diff)
- {
- return 1;
- }
- if (this_touching_side_diff < other_touching_side_diff)
- {
- return -1;
- }
- // now the last touch of this and p_other is at the same side
- if (last_touching_side == 0)
- {
- cmp_value = is1.corner(1).x - is2.corner(1).x;
- }
- else if (last_touching_side == 1)
- {
- cmp_value = is1.corner(2).x - is2.corner(2).x;
- }
- else if (last_touching_side == 2)
- {
- cmp_value = is1.corner(3).y - is2.corner(3).y;
- }
- else if (last_touching_side == 3)
- {
- cmp_value = is1.corner(4).y - is2.corner(4).y;
- }
- else if (last_touching_side == 4)
- {
- cmp_value = is2.corner(5).x - is1.corner(5).x;
- }
- else if (last_touching_side == 5)
- {
- cmp_value = is2.corner(6).x - is1.corner(6).x;
- }
- else if (last_touching_side == 6)
- {
- cmp_value = is2.corner(7).y - is1.corner(7).y;
- }
- else if (last_touching_side == 7)
- {
- cmp_value = is2.corner(0).y - is1.corner(0).y;
- }
- }
- return cmp_value;
- }
- /** The shape of the neighbour room */
- public final IntOctagon shape;
-
- /** The intersection of tnis ExpansionRoom shape with the neighbour_shape */
- public final IntOctagon intersection;
-
- /** The first side of the room shape, where the neighbour_shape touches */
- public final int first_touching_side;
-
- /** The last side of the room shape, where the neighbour_shape touches */
- public final int last_touching_side;
- }
-}
+/*
+ * Copyright (C) 2014 Alfons Wirtz
+ * website www.freerouting.net
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License at
+ * for more details.
+ *
+ * Sorted45DegreeRoomNeighbours.java
+ *
+ * Created on 6. Juli 2007, 07:28
+ *
+ */
+
+package autoroute;
+
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.SortedSet;
+import java.util.TreeSet;
+
+import datastructures.ShapeTree;
+
+import geometry.planar.Limits;
+import geometry.planar.IntOctagon;
+import geometry.planar.IntPoint;
+import geometry.planar.TileShape;
+import geometry.planar.FloatPoint;
+
+import board.ShapeSearchTree;
+import board.SearchTreeObject;
+import board.Item;
+
+/**
+ * Sorted45DegreeRoomNeighbours class.
+ *
+ * @author Alfons Wirtz
+ * @version $Id: $Id
+ */
+public class Sorted45DegreeRoomNeighbours
+{
+
+ /**
+ * calculate.
+ *
+ * @param p_room a {@link autoroute.ExpansionRoom} object.
+ * @param p_autoroute_engine a {@link autoroute.AutorouteEngine} object.
+ * @return a {@link autoroute.CompleteExpansionRoom} object.
+ */
+ public static CompleteExpansionRoom calculate(ExpansionRoom p_room, AutorouteEngine p_autoroute_engine)
+ {
+ int net_no = p_autoroute_engine.get_net_no();
+ Sorted45DegreeRoomNeighbours room_neighbours = Sorted45DegreeRoomNeighbours.calculate_neighbours(p_room, net_no,
+ p_autoroute_engine.autoroute_search_tree, p_autoroute_engine.generate_room_id_no());
+ if (room_neighbours == null)
+ {
+ return null;
+ }
+
+ // Check, that each side of the romm shape has at least one touching neighbour.
+ // Otherwise improve the room shape by enlarging.
+ boolean edge_removed = room_neighbours.try_remove_edge_line(net_no, p_autoroute_engine.autoroute_search_tree);
+ CompleteExpansionRoom result = room_neighbours.completed_room;
+ if (edge_removed)
+ {
+ p_autoroute_engine.remove_all_doors(result);
+ return calculate(p_room, p_autoroute_engine);
+ }
+
+ // Now calculate the new incomplete rooms together with the doors
+ // between this room and the sorted neighbours.
+
+ if (room_neighbours.sorted_neighbours.isEmpty())
+ {
+ if (result instanceof ObstacleExpansionRoom)
+ {
+ room_neighbours.calculate_edge_incomplete_rooms_of_obstacle_expansion_room(0, 7, p_autoroute_engine);
+ }
+ }
+ else
+ {
+ room_neighbours.calculate_new_incomplete_rooms(p_autoroute_engine);
+ }
+ return result;
+ }
+
+ /**
+ * Calculates all touching neighbours of p_room and sorts them in
+ * counterclock sense around the boundary of the room shape.
+ */
+ private static Sorted45DegreeRoomNeighbours calculate_neighbours(ExpansionRoom p_room, int p_net_no,
+ ShapeSearchTree p_autoroute_search_tree, int p_room_id_no)
+ {
+ TileShape room_shape = p_room.get_shape();
+ CompleteExpansionRoom completed_room;
+ if (p_room instanceof IncompleteFreeSpaceExpansionRoom)
+ {
+ completed_room = new CompleteFreeSpaceExpansionRoom(room_shape, p_room.get_layer(), p_room_id_no);
+ }
+ else if (p_room instanceof ObstacleExpansionRoom)
+ {
+ completed_room = (ObstacleExpansionRoom)p_room;
+ }
+ else
+ {
+ System.out.println("Sorted45DegreeRoomNeighbours.calculate_neighbours: unexpected expansion room type");
+ return null;
+ }
+ IntOctagon room_oct = room_shape.bounding_octagon();
+ Sorted45DegreeRoomNeighbours result = new Sorted45DegreeRoomNeighbours(p_room, completed_room);
+ Collection overlapping_objects = new LinkedList();
+ p_autoroute_search_tree.overlapping_tree_entries(room_shape, p_room.get_layer(), overlapping_objects);
+ // Calculate the touching neigbour objects and sort them in counterclock sence
+ // around the border of the room shape.
+ for (ShapeTree.TreeEntry curr_entry : overlapping_objects)
+ {
+ SearchTreeObject curr_object = (SearchTreeObject) curr_entry.object;
+ if (curr_object == p_room)
+ {
+ continue;
+ }
+ if ((completed_room instanceof CompleteFreeSpaceExpansionRoom) && !curr_object.is_trace_obstacle(p_net_no))
+ {
+ ((CompleteFreeSpaceExpansionRoom) completed_room).calculate_target_doors(curr_entry,
+ p_net_no, p_autoroute_search_tree);
+ continue;
+ }
+ TileShape curr_shape =
+ curr_object.get_tree_shape(p_autoroute_search_tree, curr_entry.shape_index_in_object);
+ IntOctagon curr_oct = curr_shape.bounding_octagon();
+ IntOctagon intersection = room_oct.intersection(curr_oct);
+ int dimension = intersection.dimension();
+ if (dimension > 1 && completed_room instanceof ObstacleExpansionRoom)
+ {
+ if (curr_object instanceof Item)
+ {
+ // only Obstacle expansion roos may have a 2-dim overlap
+ Item curr_item = (Item) curr_object;
+ if (curr_item.is_route())
+ {
+ ItemAutorouteInfo item_info = curr_item.get_autoroute_info();
+ ObstacleExpansionRoom curr_overlap_room =
+ item_info.get_expansion_room(curr_entry.shape_index_in_object, p_autoroute_search_tree);
+ ((ObstacleExpansionRoom) completed_room).create_overlap_door(curr_overlap_room);
+ }
+ }
+ continue;
+ }
+ if (dimension < 0)
+ {
+ // may happen at a corner from 2 diagonal lines with non integer coordinates (--.5, ---.5).
+ continue;
+ }
+ result.add_sorted_neighbour(curr_oct, intersection);
+ if (dimension > 0)
+ {
+ // make shure, that there is a door to the neighbour room.
+ ExpansionRoom neighbour_room = null;
+ if (curr_object instanceof ExpansionRoom)
+ {
+ neighbour_room = (ExpansionRoom) curr_object;
+ }
+ else if (curr_object instanceof Item)
+ {
+ Item curr_item = (Item) curr_object;
+ if (curr_item.is_route())
+ {
+ // expand the item for ripup and pushing purposes
+ ItemAutorouteInfo item_info = curr_item.get_autoroute_info();
+ neighbour_room =
+ item_info.get_expansion_room(curr_entry.shape_index_in_object, p_autoroute_search_tree);
+ }
+ }
+ if (neighbour_room != null)
+ {
+ if (SortedRoomNeighbours.insert_door_ok(completed_room, neighbour_room, intersection))
+ {
+ ExpansionDoor new_door = new ExpansionDoor(completed_room, neighbour_room);
+ neighbour_room.add_door(new_door);
+ completed_room.add_door(new_door);
+ }
+ }
+ }
+ }
+ return result;
+ }
+
+
+ /** Creates a new instance of Sorted45DegreeRoomNeighbours */
+ private Sorted45DegreeRoomNeighbours(ExpansionRoom p_from_room, CompleteExpansionRoom p_completed_room)
+ {
+ from_room = p_from_room;
+ completed_room = p_completed_room;
+ room_shape = p_completed_room.get_shape().bounding_octagon();
+ sorted_neighbours = new TreeSet();
+
+ edge_interiour_touches_obstacle = new boolean[8];
+ for (int i = 0; i < 8; ++i)
+ {
+ edge_interiour_touches_obstacle[i] = false;
+ }
+ }
+
+ private void add_sorted_neighbour(IntOctagon p_neighbour_shape, IntOctagon p_intersection)
+ {
+ SortedRoomNeighbour new_neighbour = new SortedRoomNeighbour(p_neighbour_shape, p_intersection);
+ if (new_neighbour.last_touching_side >= 0)
+ {
+ sorted_neighbours.add(new_neighbour);
+ }
+ }
+
+ /**
+ * Calculates an incomplete room for each edge side from p_from_side_no to p_to_side_no.
+ */
+ private void calculate_edge_incomplete_rooms_of_obstacle_expansion_room(int p_from_side_no, int p_to_side_no, AutorouteEngine p_autoroute_engine)
+ {
+ if (!(this.from_room instanceof ObstacleExpansionRoom))
+ {
+ System.out.println("Sorted45DegreeRoomNeighbours.calculate_side_incomplete_rooms_of_obstacle_expansion_room: ObstacleExpansionRoom expected for this.from_room");
+ return;
+ }
+ IntOctagon board_bounding_oct = p_autoroute_engine.board.get_bounding_box().bounding_octagon();
+ IntPoint curr_corner = this.room_shape.corner(p_from_side_no);
+ int curr_side_no = p_from_side_no;
+ for (;;)
+ {
+ int next_side_no = (curr_side_no + 1) % 8;
+ IntPoint next_corner = this.room_shape.corner(next_side_no);
+ if (!curr_corner.equals(next_corner))
+ {
+ int lx = board_bounding_oct.lx;
+ int ly = board_bounding_oct.ly;
+ int rx = board_bounding_oct.rx;
+ int uy = board_bounding_oct.uy;
+ int ulx = board_bounding_oct.ulx;
+ int lrx = board_bounding_oct.lrx;
+ int llx = board_bounding_oct.llx;
+ int urx = board_bounding_oct.urx;
+ if (curr_side_no == 0)
+ {
+ uy = this.room_shape.ly;
+ }
+ else if (curr_side_no == 1)
+ {
+ ulx = this.room_shape.lrx;
+ }
+ else if (curr_side_no == 2)
+ {
+ lx = this.room_shape.rx;
+ }
+ else if (curr_side_no == 3)
+ {
+ llx = this.room_shape.urx;
+ }
+ else if (curr_side_no == 4)
+ {
+ ly = this.room_shape.uy;
+ }
+ else if (curr_side_no == 5)
+ {
+ lrx = this.room_shape.ulx;
+ }
+ else if (curr_side_no == 6)
+ {
+ rx = this.room_shape.lx;
+ }
+ else if (curr_side_no == 7)
+ {
+ urx = this.room_shape.llx;
+ }
+ else
+ {
+ System.out.println("SortedOrthoganelRoomNeighbours.calculate_edge_incomplete_rooms_of_obstacle_expansion_room: curr_side_no illegal");
+ return;
+ }
+ insert_incomplete_room(p_autoroute_engine, lx, ly, rx, uy, ulx, lrx, llx, urx);
+ }
+ if (curr_side_no == p_to_side_no)
+ {
+ break;
+ }
+ curr_side_no = next_side_no;
+ }
+ }
+
+ private static IntOctagon remove_not_touching_border_lines( IntOctagon p_room_oct,
+ boolean[] p_edge_interiour_touches_obstacle)
+ {
+ int lx;
+ if (p_edge_interiour_touches_obstacle[6])
+ {
+ lx = p_room_oct.lx;
+ }
+ else
+ {
+ lx = -Limits.CRIT_INT;
+ }
+
+ int ly;
+ if (p_edge_interiour_touches_obstacle[0])
+ {
+ ly = p_room_oct.ly;
+ }
+ else
+ {
+ ly = -Limits.CRIT_INT;
+ }
+
+ int rx;
+ if (p_edge_interiour_touches_obstacle[2])
+ {
+ rx = p_room_oct.rx;
+ }
+ else
+ {
+ rx = Limits.CRIT_INT;
+ }
+
+
+ int uy;
+ if (p_edge_interiour_touches_obstacle[4])
+ {
+ uy = p_room_oct.uy;
+ }
+ else
+ {
+ uy = Limits.CRIT_INT;
+ }
+
+ int ulx;
+ if (p_edge_interiour_touches_obstacle[5])
+ {
+ ulx = p_room_oct.ulx;
+ }
+ else
+ {
+ ulx = -Limits.CRIT_INT;
+ }
+
+ int lrx;
+ if (p_edge_interiour_touches_obstacle[1])
+ {
+ lrx = p_room_oct.lrx;
+ }
+ else
+ {
+ lrx = Limits.CRIT_INT;
+ }
+
+ int llx;
+ if (p_edge_interiour_touches_obstacle[7])
+ {
+ llx = p_room_oct.llx;
+ }
+ else
+ {
+ llx = -Limits.CRIT_INT;
+ }
+
+ int urx;
+ if (p_edge_interiour_touches_obstacle[3])
+ {
+ urx = p_room_oct.urx;
+ }
+ else
+ {
+ urx = Limits.CRIT_INT;
+ }
+
+ IntOctagon result = new IntOctagon( lx, ly, rx, uy, ulx, lrx, llx, urx);
+ return result.normalize();
+ }
+ /**
+ * Check, that each side of the romm shape has at least one touching neighbour.
+ * Otherwise the room shape will be improved the by enlarging.
+ * Returns true, if the room shape was changed.
+ */
+ private boolean try_remove_edge_line(int p_net_no, ShapeSearchTree p_autoroute_search_tree)
+ {
+ if (!(this.from_room instanceof IncompleteFreeSpaceExpansionRoom))
+ {
+ return false;
+ }
+ IncompleteFreeSpaceExpansionRoom curr_incomplete_room = (IncompleteFreeSpaceExpansionRoom) this.from_room;
+ if (!(curr_incomplete_room.get_shape() instanceof IntOctagon))
+ {
+ System.out.println("Sorted45DegreeRoomNeighbours.try_remove_edge_line: IntOctagon expected for room_shape type");
+ return false;
+ }
+ IntOctagon room_oct = (IntOctagon) curr_incomplete_room.get_shape();
+ double room_area = room_oct.area();
+
+ boolean try_remove_edge_lines = false;
+ for (int i = 0; i < 8; ++i)
+ {
+ if (!this.edge_interiour_touches_obstacle[i])
+ {
+ FloatPoint prev_corner = this.room_shape.corner_approx(i);
+ FloatPoint next_corner = this.room_shape.corner_approx(this.room_shape.next_no(i));
+ if(prev_corner.distance_square(next_corner) > 1)
+ {
+ try_remove_edge_lines = true;
+ break;
+ }
+ }
+ }
+
+ if (try_remove_edge_lines)
+ {
+ // Touching neighbour missing at the edge side with index remove_edge_no
+ // Remove the edge line and restart the algorithm.
+
+ IntOctagon enlarged_oct = remove_not_touching_border_lines( room_oct, this.edge_interiour_touches_obstacle);
+
+ Collection door_list = this.completed_room.get_doors();
+ TileShape ignore_shape = null;
+ SearchTreeObject ignore_object = null;
+ double max_door_area = 0;
+ for (ExpansionDoor curr_door: door_list)
+ {
+ // insert the overlapping doors with CompleteFreeSpaceExpansionRooms
+ // for the information in complete_shape about the objects to ignore.
+ if (curr_door.dimension == 2)
+ {
+ CompleteExpansionRoom other_room = curr_door.other_room(this.completed_room);
+ {
+ if (other_room instanceof CompleteFreeSpaceExpansionRoom)
+ {
+ TileShape curr_door_shape = curr_door.get_shape();
+ double curr_door_area = curr_door_shape.area();
+ if (curr_door_area > max_door_area)
+ {
+ max_door_area = curr_door_area;
+ ignore_shape = curr_door_shape;
+ ignore_object = (CompleteFreeSpaceExpansionRoom) other_room;
+ }
+ }
+ }
+ }
+ }
+ IncompleteFreeSpaceExpansionRoom enlarged_room =
+ new IncompleteFreeSpaceExpansionRoom(enlarged_oct, curr_incomplete_room.get_layer(),
+ curr_incomplete_room.get_contained_shape());
+ Collection new_rooms =
+ p_autoroute_search_tree.complete_shape(enlarged_room, p_net_no, ignore_object, ignore_shape);
+ if (new_rooms.size() == 1)
+ {
+ // Check, that the area increases to prevent endless loop.
+ IncompleteFreeSpaceExpansionRoom new_room = new_rooms.iterator().next();
+ if (new_room.get_shape().area() > room_area)
+ {
+ curr_incomplete_room.set_shape(new_room.get_shape());
+ curr_incomplete_room.set_contained_shape(new_room.get_contained_shape());
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Inserts a new incomplete room with an octagon shape.
+ */
+ private void insert_incomplete_room(AutorouteEngine p_autoroute_engine, int p_lx, int p_ly, int p_rx, int p_uy,
+ int p_ulx, int p_lrx, int p_llx, int p_urx)
+ {
+ IntOctagon new_incomplete_room_shape = new IntOctagon(p_lx, p_ly, p_rx, p_uy, p_ulx, p_lrx, p_llx, p_urx);
+ new_incomplete_room_shape = new_incomplete_room_shape.normalize();
+ if (new_incomplete_room_shape.dimension() == 2)
+ {
+ IntOctagon new_contained_shape = this.room_shape.intersection(new_incomplete_room_shape);
+ if (!new_contained_shape.is_empty())
+ {
+ int door_dimension = new_contained_shape.dimension();
+ if (door_dimension > 0)
+ {
+ FreeSpaceExpansionRoom new_room =
+ p_autoroute_engine.add_incomplete_expansion_room(new_incomplete_room_shape, this.from_room.get_layer(), new_contained_shape);
+ ExpansionDoor new_door = new ExpansionDoor(this.completed_room, new_room, door_dimension);
+ this.completed_room.add_door(new_door);
+ new_room.add_door(new_door);
+ }
+ }
+ }
+ }
+
+ private void calculate_new_incomplete_rooms_for_obstacle_expansion_room(SortedRoomNeighbour p_prev_neighbour,
+ SortedRoomNeighbour p_next_neighbour, AutorouteEngine p_autoroute_engine)
+ {
+ int from_side_no = p_prev_neighbour.last_touching_side;
+ int to_side_no = p_next_neighbour.first_touching_side;
+ if (from_side_no == to_side_no && p_prev_neighbour != p_next_neighbour)
+ {
+ // no return in case of only 1 neighbour.
+ return;
+ }
+ IntOctagon board_bounding_oct = p_autoroute_engine.board.bounding_box.bounding_octagon();
+
+ // insert the new incomplete room from p_prev_neighbour to the next corner of the room shape.
+
+ int lx = board_bounding_oct.lx;
+ int ly = board_bounding_oct.ly;
+ int rx = board_bounding_oct.rx;
+ int uy = board_bounding_oct.uy;
+ int ulx = board_bounding_oct.ulx;
+ int lrx = board_bounding_oct.lrx;
+ int llx = board_bounding_oct.llx;
+ int urx = board_bounding_oct.urx;
+ if (from_side_no == 0)
+ {
+ uy = this.room_shape.ly;
+ ulx = p_prev_neighbour.intersection.lrx;
+ }
+ else if (from_side_no == 1)
+ {
+ ulx = this.room_shape.lrx;
+ lx = p_prev_neighbour.intersection.rx;
+ }
+ else if (from_side_no == 2)
+ {
+ lx = this.room_shape.rx;
+ llx = p_prev_neighbour.intersection.urx;
+ }
+ else if (from_side_no == 3)
+ {
+ llx = this.room_shape.urx;
+ ly = p_prev_neighbour.intersection.uy;
+ }
+ else if (from_side_no == 4)
+ {
+ ly = this.room_shape.uy;
+ lrx = p_prev_neighbour.intersection.ulx;
+ }
+ else if (from_side_no == 5)
+ {
+ lrx = this.room_shape.ulx;
+ rx = p_prev_neighbour.intersection.lx;
+ }
+ else if (from_side_no == 6)
+ {
+ rx = this.room_shape.lx;
+ urx = p_prev_neighbour.intersection.llx;
+ }
+ else if (from_side_no == 7)
+ {
+ urx = this.room_shape.llx;
+ uy = p_prev_neighbour.intersection.ly;
+ }
+ insert_incomplete_room(p_autoroute_engine, lx, ly, rx, uy, ulx, lrx, llx, urx);
+
+ // insert the new incomplete room from p_prev_neighbour to the next corner of the room shape.
+
+ lx = board_bounding_oct.lx;
+ ly = board_bounding_oct.ly;
+ rx = board_bounding_oct.rx;
+ uy = board_bounding_oct.uy;
+ ulx = board_bounding_oct.ulx;
+ lrx = board_bounding_oct.lrx;
+ llx = board_bounding_oct.llx;
+ urx = board_bounding_oct.urx;
+
+ if (to_side_no == 0)
+ {
+ uy = this.room_shape.ly;
+ urx = p_next_neighbour.intersection.llx;
+ }
+ else if (to_side_no == 1)
+ {
+ ulx = this.room_shape.lrx;
+ uy = p_next_neighbour.intersection.ly;
+ }
+ else if (to_side_no == 2)
+ {
+ lx = this.room_shape.rx;
+ ulx = p_next_neighbour.intersection.lrx;
+ }
+ else if (to_side_no == 3)
+ {
+ llx = this.room_shape.urx;
+ lx = p_next_neighbour.intersection.rx;
+ }
+ else if (to_side_no == 4)
+ {
+ ly = this.room_shape.uy;
+ llx = p_next_neighbour.intersection.urx;
+ }
+ else if (to_side_no == 5)
+ {
+ lrx = this.room_shape.ulx;
+ ly = p_next_neighbour.intersection.uy;
+ }
+ else if (to_side_no == 6)
+ {
+ rx = this.room_shape.lx;
+ lrx = p_next_neighbour.intersection.ulx;
+ }
+ else if (to_side_no == 7)
+ {
+ urx = this.room_shape.llx;
+ rx = p_next_neighbour.intersection.lx;
+ }
+ insert_incomplete_room(p_autoroute_engine, lx, ly, rx, uy, ulx, lrx, llx, urx);
+
+ // Insert the new incomplete rooms on the intermediate free sides of the obstacle expansion room.
+ int curr_from_side_no = (from_side_no + 1) % 8;
+ if (curr_from_side_no == to_side_no)
+ {
+ return;
+ }
+ int curr_to_side_no = (to_side_no + 7) % 8;
+ this.calculate_edge_incomplete_rooms_of_obstacle_expansion_room(curr_from_side_no,
+ curr_to_side_no, p_autoroute_engine);
+ }
+
+ private void calculate_new_incomplete_rooms(AutorouteEngine p_autoroute_engine)
+ {
+ IntOctagon board_bounding_oct = p_autoroute_engine.board.bounding_box.bounding_octagon();
+ SortedRoomNeighbour prev_neighbour = this.sorted_neighbours.last();
+ if (this.from_room instanceof ObstacleExpansionRoom && this.sorted_neighbours.size() == 1)
+ {
+ // ObstacleExpansionRoom has only only 1 neighbour
+ calculate_new_incomplete_rooms_for_obstacle_expansion_room(prev_neighbour, prev_neighbour, p_autoroute_engine);
+ return;
+ }
+ Iterator it = this.sorted_neighbours.iterator();
+
+ while (it.hasNext())
+ {
+ SortedRoomNeighbour next_neighbour = it.next();
+
+ boolean insert_incomplete_room;
+
+ if (this.completed_room instanceof ObstacleExpansionRoom && this.sorted_neighbours.size() == 2)
+ {
+ // check, if this site is touching or open.
+ TileShape intersection = next_neighbour.intersection.intersection(prev_neighbour.intersection);
+ if (intersection.is_empty())
+ {
+ insert_incomplete_room = true;
+ }
+ else if (intersection.dimension() >= 1)
+ {
+ insert_incomplete_room = false;
+ }
+ else // dimension = 1
+ {
+ if (prev_neighbour.last_touching_side == next_neighbour.first_touching_side)
+ {
+ // touch along the side of the room shape
+ insert_incomplete_room = false;
+ }
+ else if(prev_neighbour.last_touching_side == (next_neighbour.first_touching_side + 1) % 8)
+ {
+ // touch at a corner of the room shape
+ insert_incomplete_room = false;
+ }
+ else
+ {
+ insert_incomplete_room = true;
+ }
+ }
+ }
+ else
+ {
+ // the 2 neigbours do not touch
+ insert_incomplete_room = !next_neighbour.intersection.intersects(prev_neighbour.intersection);
+ }
+
+
+ if (insert_incomplete_room)
+ {
+ // create a door to a new incomplete expansion room between
+ // the last corner of the previous neighbour and the first corner of the
+ // current neighbour
+
+ if (this.from_room instanceof ObstacleExpansionRoom &&
+ next_neighbour.first_touching_side != prev_neighbour.last_touching_side)
+ {
+ calculate_new_incomplete_rooms_for_obstacle_expansion_room(prev_neighbour, next_neighbour, p_autoroute_engine);
+ }
+ else
+ {
+ int lx = board_bounding_oct.lx;
+ int ly = board_bounding_oct.ly;
+ int rx = board_bounding_oct.rx;
+ int uy = board_bounding_oct.uy;
+ int ulx = board_bounding_oct.ulx;
+ int lrx = board_bounding_oct.lrx;
+ int llx = board_bounding_oct.llx;
+ int urx = board_bounding_oct.urx;
+
+ if (next_neighbour.first_touching_side == 0)
+ {
+ if (prev_neighbour.intersection.llx < next_neighbour.intersection.llx)
+ {
+ urx = next_neighbour.intersection.llx;
+ uy = prev_neighbour.intersection.ly;
+ if (prev_neighbour.last_touching_side == 0)
+ {
+ ulx = prev_neighbour.intersection.lrx;
+ }
+ }
+ else if (prev_neighbour.intersection.llx > next_neighbour.intersection.llx)
+ {
+ rx = next_neighbour.intersection.lx;
+ urx = prev_neighbour.intersection.llx;
+ }
+ else // prev_neighbour.intersection.llx == next_neighbour.intersection.llx
+ {
+ urx = next_neighbour.intersection.llx;
+ }
+ }
+ else if (next_neighbour.first_touching_side == 1)
+ {
+ if (prev_neighbour.intersection.ly < next_neighbour.intersection.ly)
+ {
+ uy = next_neighbour.intersection.ly;
+ ulx = prev_neighbour.intersection.lrx;
+ if (prev_neighbour.last_touching_side == 1)
+ {
+ lx = prev_neighbour.intersection.rx;
+ }
+ }
+ else if (prev_neighbour.intersection.ly > next_neighbour.intersection.ly)
+ {
+ uy = prev_neighbour.intersection.ly;
+ urx = next_neighbour.intersection.llx;
+ }
+ else // prev_neighbour.intersection.ly == next_neighbour.intersection.ly
+ {
+ uy = next_neighbour.intersection.ly;
+ }
+ }
+ else if (next_neighbour.first_touching_side == 2)
+ {
+ if (prev_neighbour.intersection.lrx > next_neighbour.intersection.lrx)
+ {
+ ulx = next_neighbour.intersection.lrx;
+ lx = prev_neighbour.intersection.rx;
+ if (prev_neighbour.last_touching_side == 2)
+ {
+ llx = prev_neighbour.intersection.urx;
+ }
+ }
+ else if (prev_neighbour.intersection.lrx < next_neighbour.intersection.lrx)
+ {
+ uy = next_neighbour.intersection.ly;
+ ulx = prev_neighbour.intersection.lrx;
+ }
+ else // prev_neighbour.intersection.lrx == next_neighbour.intersection.lrx
+ {
+ ulx = next_neighbour.intersection.lrx;
+ }
+ }
+ else if (next_neighbour.first_touching_side == 3)
+ {
+ if (prev_neighbour.intersection.rx > next_neighbour.intersection.rx)
+ {
+ lx = next_neighbour.intersection.rx;
+ llx = prev_neighbour.intersection.urx;
+ if (prev_neighbour.last_touching_side == 3)
+ {
+ ly = prev_neighbour.intersection.uy;
+ }
+ }
+ else if (prev_neighbour.intersection.rx < next_neighbour.intersection.rx)
+ {
+ lx = prev_neighbour.intersection.rx;
+ ulx = next_neighbour.intersection.lrx;
+ }
+ else // prev_neighbour.intersection.ry == next_neighbour.intersection.ry
+ {
+ lx = next_neighbour.intersection.rx;
+ }
+ }
+ else if (next_neighbour.first_touching_side == 4)
+ {
+ if (prev_neighbour.intersection.urx > next_neighbour.intersection.urx)
+ {
+ llx = next_neighbour.intersection.urx;
+ ly = prev_neighbour.intersection.uy;
+ if (prev_neighbour.last_touching_side == 4)
+ {
+ lrx = prev_neighbour.intersection.ulx;
+ }
+ }
+ else if (prev_neighbour.intersection.urx < next_neighbour.intersection.urx)
+ {
+ lx = next_neighbour.intersection.rx;
+ llx = prev_neighbour.intersection.urx;
+ }
+ else // prev_neighbour.intersection.urx == next_neighbour.intersection.urx
+ {
+ llx = next_neighbour.intersection.urx;
+ }
+ }
+ else if (next_neighbour.first_touching_side == 5)
+ {
+ if (prev_neighbour.intersection.uy > next_neighbour.intersection.uy)
+ {
+ ly = next_neighbour.intersection.uy;
+ lrx = prev_neighbour.intersection.ulx;
+ if (prev_neighbour.last_touching_side == 5)
+ {
+ rx = prev_neighbour.intersection.lx;
+ }
+ }
+ else if (prev_neighbour.intersection.uy < next_neighbour.intersection.uy)
+ {
+ ly = prev_neighbour.intersection.uy;
+ llx = next_neighbour.intersection.urx;
+ }
+ else // prev_neighbour.intersection.uy == next_neighbour.intersection.uy
+ {
+ ly = next_neighbour.intersection.uy;
+ }
+ }
+ else if (next_neighbour.first_touching_side == 6)
+ {
+ if (prev_neighbour.intersection.ulx < next_neighbour.intersection.ulx)
+ {
+ lrx = next_neighbour.intersection.ulx;
+ rx = prev_neighbour.intersection.lx;
+ if (prev_neighbour.last_touching_side == 6)
+ {
+ urx = prev_neighbour.intersection.llx;
+ }
+ }
+ else if (prev_neighbour.intersection.ulx > next_neighbour.intersection.ulx)
+ {
+ ly = next_neighbour.intersection.uy;
+ lrx = prev_neighbour.intersection.ulx;
+ }
+ else // prev_neighbour.intersection.ulx == next_neighbour.intersection.ulx
+ {
+ lrx = next_neighbour.intersection.ulx;
+ }
+ }
+ else if (next_neighbour.first_touching_side == 7)
+ {
+ if (prev_neighbour.intersection.lx < next_neighbour.intersection.lx)
+ {
+ rx = next_neighbour.intersection.lx;
+ urx = prev_neighbour.intersection.llx;
+ if (prev_neighbour.last_touching_side == 7)
+ {
+ uy = prev_neighbour.intersection.ly;
+ }
+ }
+ else if (prev_neighbour.intersection.lx > next_neighbour.intersection.lx)
+ {
+ rx = prev_neighbour.intersection.lx;
+ lrx = next_neighbour.intersection.ulx;
+ }
+ else // prev_neighbour.intersection.lx == next_neighbour.intersection.lx
+ {
+ rx = next_neighbour.intersection.lx;
+ }
+ }
+ else
+ {
+ System.out.println("Sorted45DegreeRoomNeighbour.calculate_new_incomplete: illegal touching side");
+ }
+ insert_incomplete_room(p_autoroute_engine, lx, ly, rx, uy, ulx, lrx, llx, urx);
+ }
+ }
+ prev_neighbour = next_neighbour;
+ }
+ }
+
+ public final CompleteExpansionRoom completed_room;
+ public final SortedSet sorted_neighbours;
+ private final ExpansionRoom from_room;
+ private final IntOctagon room_shape;
+
+ private final boolean[] edge_interiour_touches_obstacle;
+
+ /**
+ * Helper class to sort the doors of an expansion room counterclockwise
+ * arount the border of the room shape.
+ */
+
+ private class SortedRoomNeighbour implements Comparable
+ {
+
+ /**
+ * Creates a new instance of SortedRoomNeighbour and calculates the first and last
+ * touching sides with the room shape.
+ * this.last_touching_side will be -1, if sorting did not work because
+ * the room_shape is contained in the neighbour shape.
+ */
+ public SortedRoomNeighbour(IntOctagon p_neighbour_shape, IntOctagon p_intersection)
+ {
+ shape = p_neighbour_shape;
+ intersection = p_intersection;
+
+ if (intersection.ly == room_shape.ly && intersection.llx > room_shape.llx)
+ {
+ this.first_touching_side = 0;
+ }
+ else if (intersection.lrx == room_shape.lrx && intersection.ly > room_shape.ly)
+ {
+ this.first_touching_side = 1;
+ }
+ else if (intersection.rx == room_shape.rx && intersection.lrx < room_shape.lrx)
+ {
+ this.first_touching_side = 2;
+ }
+ else if (intersection.urx == room_shape.urx && intersection.rx < room_shape.rx)
+ {
+ this.first_touching_side = 3;
+ }
+ else if (intersection.uy == room_shape.uy && intersection.urx < room_shape.urx)
+ {
+ this.first_touching_side = 4;
+ }
+ else if (intersection.ulx == room_shape.ulx && intersection.uy < room_shape.uy)
+ {
+ this.first_touching_side = 5;
+ }
+ else if (intersection.lx == room_shape.lx && intersection.ulx > room_shape.ulx)
+ {
+ this.first_touching_side = 6;
+ }
+ else if (intersection.llx == room_shape.llx && intersection.lx > room_shape.lx)
+ {
+ this.first_touching_side = 7;
+ }
+ else
+ {
+ // the room_shape may be contained in the neighbour_shape
+ this.first_touching_side = -1;
+ this.last_touching_side = -1;
+ return;
+ }
+
+ if (intersection.llx == room_shape.llx && intersection.ly > room_shape.ly)
+ {
+ this.last_touching_side = 7;
+ }
+ else if (intersection.lx == room_shape.lx && intersection.llx > room_shape.llx)
+ {
+ this.last_touching_side = 6;
+ }
+ else if (intersection.ulx == room_shape.ulx && intersection.lx > room_shape.lx)
+ {
+ this.last_touching_side = 5;
+ }
+ else if (intersection.uy == room_shape.uy && intersection.ulx > room_shape.ulx)
+ {
+ this.last_touching_side = 4;
+ }
+ else if (intersection.urx == room_shape.urx && intersection.uy < room_shape.uy)
+ {
+ this.last_touching_side = 3;
+ }
+ else if (intersection.rx == room_shape.rx && intersection.urx < room_shape.urx)
+ {
+ this.last_touching_side = 2;
+ }
+ else if (intersection.lrx == room_shape.lrx && intersection.rx < room_shape.rx)
+ {
+ this.last_touching_side = 1;
+ }
+ else if (intersection.ly == room_shape.ly && intersection.lrx < room_shape.lrx)
+ {
+ this.last_touching_side = 0;
+ }
+ else
+ {
+ // the room_shape may be contained in the neighbour_shape
+ this.last_touching_side = -1;
+ return;
+ }
+
+ int next_side_no = this.first_touching_side;
+ for (;;)
+ {
+ int curr_side_no = next_side_no;
+ next_side_no = (next_side_no + 1) % 8;
+ if (!edge_interiour_touches_obstacle[curr_side_no])
+ {
+ boolean touch_only_at_corner = false;
+ if (curr_side_no == this.first_touching_side)
+ {
+ if (intersection.corner(curr_side_no).equals(room_shape.corner(next_side_no)))
+ {
+ touch_only_at_corner = true;
+ }
+ }
+ if (curr_side_no == this.last_touching_side)
+ {
+ if (intersection.corner(next_side_no).equals(room_shape.corner(curr_side_no)))
+ {
+ touch_only_at_corner = true;
+ }
+ }
+ if (!touch_only_at_corner)
+ {
+ edge_interiour_touches_obstacle[curr_side_no] = true;
+ }
+ }
+ if (curr_side_no == this.last_touching_side)
+ {
+ break;
+ }
+
+ }
+ }
+
+ /**
+ * Compare function for or sorting the neighbours in counterclock sense
+ * around the border of the room shape in ascending order.
+ */
+ public int compareTo(SortedRoomNeighbour p_other)
+ {
+ if (this.first_touching_side > p_other.first_touching_side)
+ {
+ return 1;
+ }
+ if (this.first_touching_side < p_other.first_touching_side)
+ {
+ return -1;
+ }
+
+ // now the first touch of this and p_other is at the same side
+ IntOctagon is1 = this.intersection;
+ IntOctagon is2 = p_other.intersection;
+ int cmp_value;
+
+ if (first_touching_side == 0)
+ {
+ cmp_value = is1.corner(0).x - is2.corner(0).x;
+ }
+ else if (first_touching_side == 1)
+ {
+ cmp_value = is1.corner(1).x - is2.corner(1).x;
+ }
+ else if (first_touching_side == 2)
+ {
+ cmp_value = is1.corner(2).y - is2.corner(2).y;
+ }
+ else if (first_touching_side == 3)
+ {
+ cmp_value = is1.corner(3).y - is2.corner(3).y;
+ }
+ else if (first_touching_side == 4)
+ {
+ cmp_value = is2.corner(4).x - is1.corner(4).x;
+ }
+ else if (first_touching_side == 5)
+ {
+ cmp_value = is2.corner(5).x - is1.corner(5).x;
+ }
+ else if (first_touching_side == 6)
+ {
+ cmp_value = is2.corner(6).y - is1.corner(6).y;
+ }
+ else if (first_touching_side == 7)
+ {
+ cmp_value = is2.corner(7).y - is1.corner(7).y;
+ }
+ else
+ {
+ System.out.println("SortedRoomNeighbour.compareTo: first_touching_side out of range ");
+ return 0;
+ }
+
+ if (cmp_value == 0)
+ {
+ // The first touching points of this neighbour and p_other with the room shape are equal.
+ // Compare the last touching points.
+ int this_touching_side_diff = (this.last_touching_side - this.first_touching_side + 8) % 8;
+ int other_touching_side_diff = (p_other.last_touching_side - p_other.first_touching_side + 8) % 8;
+ if (this_touching_side_diff > other_touching_side_diff)
+ {
+ return 1;
+ }
+ if (this_touching_side_diff < other_touching_side_diff)
+ {
+ return -1;
+ }
+ // now the last touch of this and p_other is at the same side
+ if (last_touching_side == 0)
+ {
+ cmp_value = is1.corner(1).x - is2.corner(1).x;
+ }
+ else if (last_touching_side == 1)
+ {
+ cmp_value = is1.corner(2).x - is2.corner(2).x;
+ }
+ else if (last_touching_side == 2)
+ {
+ cmp_value = is1.corner(3).y - is2.corner(3).y;
+ }
+ else if (last_touching_side == 3)
+ {
+ cmp_value = is1.corner(4).y - is2.corner(4).y;
+ }
+ else if (last_touching_side == 4)
+ {
+ cmp_value = is2.corner(5).x - is1.corner(5).x;
+ }
+ else if (last_touching_side == 5)
+ {
+ cmp_value = is2.corner(6).x - is1.corner(6).x;
+ }
+ else if (last_touching_side == 6)
+ {
+ cmp_value = is2.corner(7).y - is1.corner(7).y;
+ }
+ else if (last_touching_side == 7)
+ {
+ cmp_value = is2.corner(0).y - is1.corner(0).y;
+ }
+ }
+ return cmp_value;
+ }
+ /** The shape of the neighbour room */
+ public final IntOctagon shape;
+
+ /** The intersection of tnis ExpansionRoom shape with the neighbour_shape */
+ public final IntOctagon intersection;
+
+ /** The first side of the room shape, where the neighbour_shape touches */
+ public final int first_touching_side;
+
+ /** The last side of the room shape, where the neighbour_shape touches */
+ public final int last_touching_side;
+ }
+}
diff --git a/autoroute/SortedOrthogonalRoomNeighbours.java b/src/main/java/autoroute/SortedOrthogonalRoomNeighbours.java
similarity index 97%
rename from autoroute/SortedOrthogonalRoomNeighbours.java
rename to src/main/java/autoroute/SortedOrthogonalRoomNeighbours.java
index 80a83a5..be60df4 100644
--- a/autoroute/SortedOrthogonalRoomNeighbours.java
+++ b/src/main/java/autoroute/SortedOrthogonalRoomNeighbours.java
@@ -1,729 +1,738 @@
-/*
- * Copyright (C) 2014 Alfons Wirtz
- * website www.freerouting.net
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License at
- * for more details.
- *
- * OrthogonalAutorouteEngine.java
- *
- * Created on 24. Mai 2007, 07:51
- *
- */
-
-package autoroute;
-
-import java.util.Collection;
-import java.util.Iterator;
-import java.util.LinkedList;
-import java.util.SortedSet;
-import java.util.TreeSet;
-
-import datastructures.ShapeTree;
-
-import geometry.planar.IntBox;
-import geometry.planar.TileShape;
-import geometry.planar.Limits;
-
-import board.SearchTreeObject;
-import board.ShapeSearchTree;
-import board.Item;
-
-/**
- *
- * @author Alfons Wirtz
- */
-public class SortedOrthogonalRoomNeighbours
-{
-
- public static CompleteExpansionRoom calculate(ExpansionRoom p_room, AutorouteEngine p_autoroute_engine)
- {
- int net_no = p_autoroute_engine.get_net_no();
- SortedOrthogonalRoomNeighbours room_neighbours = SortedOrthogonalRoomNeighbours.calculate_neighbours(p_room, net_no,
- p_autoroute_engine.autoroute_search_tree, p_autoroute_engine.generate_room_id_no());
- if (room_neighbours == null)
- {
- return null;
- }
-
- // Check, that each side of the romm shape has at least one touching neighbour.
- // Otherwise improve the room shape by enlarging.
- boolean edge_removed = room_neighbours.try_remove_edge(net_no, p_autoroute_engine.autoroute_search_tree);
- CompleteExpansionRoom result = room_neighbours.completed_room;
- if (edge_removed)
- {
- p_autoroute_engine.remove_all_doors(result);
- return calculate(p_room, p_autoroute_engine);
- }
-
- // Now calculate the new incomplete rooms together with the doors
- // between this room and the sorted neighbours.
-
- if (room_neighbours.sorted_neighbours.isEmpty())
- {
- if (result instanceof ObstacleExpansionRoom)
- {
- calculate_incomplete_rooms_with_empty_neighbours((ObstacleExpansionRoom) p_room, p_autoroute_engine);
- }
- }
- else
- {
- room_neighbours.calculate_new_incomplete_rooms(p_autoroute_engine);
- }
- return result;
- }
-
- private static void calculate_incomplete_rooms_with_empty_neighbours(ObstacleExpansionRoom p_room, AutorouteEngine p_autoroute_engine)
- {
- TileShape room_shape = p_room.get_shape();
- if (!(room_shape instanceof IntBox))
- {
- System.out.println("SortedOrthoganelRoomNeighbours.calculate_incomplete_rooms_with_empty_neighbours: IntBox expected for room_shape");
- return;
- }
- IntBox room_box = (IntBox) room_shape;
- IntBox bounding_box = p_autoroute_engine.board.get_bounding_box();
- for (int i = 0; i < 4; ++i)
- {
- IntBox new_room_box;
- if (i == 0)
- {
- new_room_box = new IntBox(bounding_box.ll.x, bounding_box.ll.y, bounding_box.ur.x, room_box.ll.y);
- }
- else if (i == 1)
- {
- new_room_box = new IntBox(room_box.ur.x, bounding_box.ll.y, bounding_box.ur.x, bounding_box.ur.y);
- }
- else if (i == 2)
- {
- new_room_box = new IntBox(bounding_box.ll.x, room_box.ur.y, bounding_box.ur.x, bounding_box.ur.y);
- }
- else if (i == 3)
- {
- new_room_box = new IntBox(bounding_box.ll.x, bounding_box.ll.y, room_box.ll.x, bounding_box.ur.y);
- }
- else
- {
- System.out.println("SortedOrthoganelRoomNeighbours.calculate_incomplete_rooms_with_empty_neighbours: illegal index i");
- return;
- }
- IntBox new_contained_box = room_box.intersection(new_room_box);
- FreeSpaceExpansionRoom new_room = p_autoroute_engine.add_incomplete_expansion_room(new_room_box, p_room.get_layer(), new_contained_box);
- ExpansionDoor new_door = new ExpansionDoor(p_room, new_room, 1);
- p_room.add_door(new_door);
- new_room.add_door(new_door);
- }
- }
-
- /**
- * Calculates all touching neighbours of p_room and sorts them in
- * counterclock sense around the boundary of the room shape.
- */
- private static SortedOrthogonalRoomNeighbours calculate_neighbours(ExpansionRoom p_room, int p_net_no,
- ShapeSearchTree p_autoroute_search_tree, int p_room_id_no)
- {
- TileShape room_shape = p_room.get_shape();
- if (!(room_shape instanceof IntBox))
- {
- System.out.println("SortedOrthogonalRoomNeighbours.calculate: IntBox expected for room_shape");
- return null;
- }
- IntBox room_box = (IntBox) room_shape;
- CompleteExpansionRoom completed_room;
- if (p_room instanceof IncompleteFreeSpaceExpansionRoom)
- {
- completed_room = new CompleteFreeSpaceExpansionRoom(room_shape, p_room.get_layer(), p_room_id_no);
- }
- else if (p_room instanceof ObstacleExpansionRoom)
- {
- completed_room = (ObstacleExpansionRoom)p_room;
- }
- else
- {
- System.out.println("SortedOrthogonalRoomNeighbours.calculate: unexpected expansion room type");
- return null;
- }
- SortedOrthogonalRoomNeighbours result = new SortedOrthogonalRoomNeighbours(p_room, completed_room);
- Collection overlapping_objects = new LinkedList();
- p_autoroute_search_tree.overlapping_tree_entries(room_shape, p_room.get_layer(), overlapping_objects);
- // Calculate the touching neigbour objects and sort them in counterclock sence
- // around the border of the room shape.
- for (ShapeTree.TreeEntry curr_entry : overlapping_objects)
- {
- SearchTreeObject curr_object = (SearchTreeObject) curr_entry.object;
- if (curr_object == p_room)
- {
- continue;
- }
- if ((completed_room instanceof CompleteFreeSpaceExpansionRoom) && !curr_object.is_trace_obstacle(p_net_no))
- {
- ((CompleteFreeSpaceExpansionRoom) completed_room).calculate_target_doors(curr_entry,
- p_net_no, p_autoroute_search_tree);
- continue;
- }
- TileShape curr_shape =
- curr_object.get_tree_shape(p_autoroute_search_tree, curr_entry.shape_index_in_object);
- if (!(curr_shape instanceof IntBox))
- {
- System.out.println("OrthogonalAutorouteEngine:calculate_sorted_neighbours: IntBox expected for curr_shape");
- return null;
- }
- IntBox curr_box = (IntBox) curr_shape;
- IntBox intersection = room_box.intersection(curr_box);
- int dimension = intersection.dimension();
- if (dimension > 1 && completed_room instanceof ObstacleExpansionRoom)
- {
- if (curr_object instanceof Item)
- {
- // only Obstacle expansion roos may have a 2-dim overlap
- Item curr_item = (Item) curr_object;
- if (curr_item.is_route())
- {
- ItemAutorouteInfo item_info = curr_item.get_autoroute_info();
- ObstacleExpansionRoom curr_overlap_room =
- item_info.get_expansion_room(curr_entry.shape_index_in_object, p_autoroute_search_tree);
- ((ObstacleExpansionRoom) completed_room).create_overlap_door(curr_overlap_room);
- }
-
- }
- continue;
- }
- if (dimension < 0)
- {
-
- System.out.println("AutorouteEngine.calculate_doors: dimension >= 0 expected");
- continue;
- }
- result.add_sorted_neighbour(curr_box, intersection);
- if (dimension > 0)
- {
- // make shure, that there is a door to the neighbour room.
- ExpansionRoom neighbour_room = null;
- if (curr_object instanceof ExpansionRoom)
- {
- neighbour_room = (ExpansionRoom) curr_object;
- }
- else if (curr_object instanceof Item)
- {
- Item curr_item = (Item) curr_object;
- if (curr_item.is_route())
- {
- // expand the item for ripup and pushing purposes
- ItemAutorouteInfo item_info = curr_item.get_autoroute_info();
- neighbour_room =
- item_info.get_expansion_room(curr_entry.shape_index_in_object, p_autoroute_search_tree);
- }
- }
- if (neighbour_room != null)
- {
- if (SortedRoomNeighbours.insert_door_ok(completed_room, neighbour_room, intersection))
- {
- ExpansionDoor new_door = new ExpansionDoor(completed_room, neighbour_room);
- neighbour_room.add_door(new_door);
- completed_room.add_door(new_door);
- }
- }
- }
- }
- return result;
- }
-
- private void calculate_new_incomplete_rooms(AutorouteEngine p_autoroute_engine)
- {
- IntBox board_bounds = p_autoroute_engine.board.bounding_box;
- SortedRoomNeighbour prev_neighbour = this.sorted_neighbours.last();
- Iterator it = this.sorted_neighbours.iterator();
-
- while (it.hasNext())
- {
- SortedRoomNeighbour next_neighbour = it.next();
-
- if (!next_neighbour.intersection.intersects(prev_neighbour.intersection))
- {
- // create a door to a new incomplete expansion room between
- // the last corner of the previous neighbour and the first corner of the
- // current neighbour.
- if (next_neighbour.first_touching_side == 0)
- {
- if (prev_neighbour.last_touching_side == 0)
- {
- if (prev_neighbour.intersection.ur.x < next_neighbour.intersection.ll.x)
- {
- insert_incomplete_room(p_autoroute_engine, prev_neighbour.intersection.ur.x, board_bounds.ll.y,
- next_neighbour.intersection.ll.x, this.room_shape.ll.y);
- }
- }
- else
- {
- if (prev_neighbour.intersection.ll.y > this.room_shape.ll.y
- || next_neighbour.intersection.ll.x > this.room_shape.ll.x)
- {
- if (is_obstacle_expansion_room)
- {
- // no 2-dim doors between obstacle_expansion_rooms and free space rooms allowed.
- if (prev_neighbour.last_touching_side == 3)
- {
- insert_incomplete_room(p_autoroute_engine, board_bounds.ll.x, room_shape.ll.y,
- room_shape.ll.x, prev_neighbour.intersection.ll.y);
- }
- insert_incomplete_room(p_autoroute_engine, room_shape.ll.x, board_bounds.ll.y,
- next_neighbour.intersection.ll.x, room_shape.ll.y);
- }
- else
- {
- insert_incomplete_room(p_autoroute_engine, board_bounds.ll.x, board_bounds.ll.y,
- next_neighbour.intersection.ll.x, prev_neighbour.intersection.ll.y);
- }
- }
- }
- }
- else if (next_neighbour.first_touching_side == 1)
- {
- if (prev_neighbour.last_touching_side == 1)
- {
- if (prev_neighbour.intersection.ur.y < next_neighbour.intersection.ll.y)
- {
- insert_incomplete_room(p_autoroute_engine, this.room_shape.ur.x, prev_neighbour.intersection.ur.y,
- board_bounds.ur.x, next_neighbour.intersection.ll.y );
- }
- }
- else
- {
- if (prev_neighbour.intersection.ur.x < this.room_shape.ur.x
- || next_neighbour.intersection.ll.y > this.room_shape.ll.y)
- {
- if (is_obstacle_expansion_room)
- {
- // no 2-dim doors between obstacle_expansion_rooms and free space rooms allowed.
- if (prev_neighbour.last_touching_side == 0)
- {
- insert_incomplete_room(p_autoroute_engine, prev_neighbour.intersection.ur.x, board_bounds.ll.y,
- room_shape.ur.x, room_shape.ll.y);
- }
- insert_incomplete_room(p_autoroute_engine, room_shape.ur.x, room_shape.ll.y,
- room_shape.ur.x, next_neighbour.intersection.ll.y );
- }
- else
- {
- insert_incomplete_room(p_autoroute_engine, prev_neighbour.intersection.ur.x, board_bounds.ll.y,
- board_bounds.ur.x, next_neighbour.intersection.ll.y);
- }
- }
- }
- }
- else if (next_neighbour.first_touching_side == 2)
- {
- if (prev_neighbour.last_touching_side == 2)
- {
- if (prev_neighbour.intersection.ll.x > next_neighbour.intersection.ur.x)
- {
- insert_incomplete_room(p_autoroute_engine, next_neighbour.intersection.ur.x, this.room_shape.ur.y,
- prev_neighbour.intersection.ll.x, board_bounds.ur.y);
- }
- }
- else
- {
- if (prev_neighbour.intersection.ur.y < this.room_shape.ur.y
- || next_neighbour.intersection.ur.x < this.room_shape.ur.x)
- {
- if (is_obstacle_expansion_room)
- {
- // no 2-dim doors between obstacle_expansion_rooms and free space rooms allowed.
- if (prev_neighbour.last_touching_side == 1)
- {
- insert_incomplete_room(p_autoroute_engine, room_shape.ur.x, prev_neighbour.intersection.ur.y,
- board_bounds.ur.x, room_shape.ur.y);
- }
- insert_incomplete_room(p_autoroute_engine, next_neighbour.intersection.ur.x, room_shape.ur.y,
- room_shape.ur.x, board_bounds.ur.y );
- }
- else
- {
- insert_incomplete_room(p_autoroute_engine, next_neighbour.intersection.ur.x, prev_neighbour.intersection.ur.y,
- board_bounds.ur.x, board_bounds.ur.y);
- }
- }
- }
- }
- else if (next_neighbour.first_touching_side == 3)
- {
- if (prev_neighbour.last_touching_side == 3)
- {
- if (prev_neighbour.intersection.ll.y > next_neighbour.intersection.ur.y)
- {
- insert_incomplete_room(p_autoroute_engine, board_bounds.ll.x, next_neighbour.intersection.ur.y,
- this.room_shape.ll.x, prev_neighbour.intersection.ll.y);
- }
- }
- else
- {
- if (next_neighbour.intersection.ur.y < this.room_shape.ur.y
- || prev_neighbour.intersection.ll.x > this.room_shape.ll.x)
- {
- if (is_obstacle_expansion_room)
- {
- // no 2-dim doors between obstacle_expansion_rooms and free space rooms allowed.
- if (prev_neighbour.last_touching_side == 2)
- {
- insert_incomplete_room(p_autoroute_engine, room_shape.ll.x, room_shape.ur.y,
- prev_neighbour.intersection.ll.x, board_bounds.ur.y);
- }
- insert_incomplete_room(p_autoroute_engine, board_bounds.ll.x, next_neighbour.intersection.ur.y,
- room_shape.ll.x, room_shape.ur.y);
- }
- else
- {
- insert_incomplete_room(p_autoroute_engine, board_bounds.ll.x, next_neighbour.intersection.ur.y,
- prev_neighbour.intersection.ll.x, board_bounds.ur.y);
- }
- }
- }
- }
- else
- {
- System.out.println("SortedOrthogonalRoomNeighbour.calculate_new_incomplete: illegal touching side");
- }
- }
- prev_neighbour = next_neighbour;
- }
- }
-
- private void insert_incomplete_room(AutorouteEngine p_autoroute_engine, int p_ll_x, int p_ll_y, int p_ur_x, int p_ur_y)
- {
- IntBox new_incomplete_room_shape = new IntBox(p_ll_x, p_ll_y, p_ur_x, p_ur_y);
- if (new_incomplete_room_shape.dimension() == 2)
- {
- IntBox new_contained_shape = this.room_shape.intersection(new_incomplete_room_shape);
- if (!new_contained_shape.is_empty())
- {
- int door_dimension = new_incomplete_room_shape.intersection(this.room_shape).dimension();
- if (door_dimension > 0)
- {
- FreeSpaceExpansionRoom new_room =
- p_autoroute_engine.add_incomplete_expansion_room(new_incomplete_room_shape, this.from_room.get_layer(), new_contained_shape);
- ExpansionDoor new_door = new ExpansionDoor(this.completed_room, new_room, door_dimension);
- this.completed_room.add_door(new_door);
- new_room.add_door(new_door);
- }
- }
- }
- }
-
- /** Creates a new instance of SortedOrthogonalRoomNeighbours */
- private SortedOrthogonalRoomNeighbours(ExpansionRoom p_from_room, CompleteExpansionRoom p_completed_room)
- {
- from_room = p_from_room;
- completed_room = p_completed_room;
- is_obstacle_expansion_room = p_from_room instanceof ObstacleExpansionRoom;
- room_shape = (IntBox) p_completed_room.get_shape();
- sorted_neighbours = new TreeSet();
- edge_interiour_touches_obstacle = new boolean[4];
- for (int i = 0; i < 4; ++i)
- {
- edge_interiour_touches_obstacle[i] = false;
- }
- }
-
- /**
- * Check, that each side of the romm shape has at least one touching neighbour.
- * Otherwise the room shape will be improved the by enlarging.
- * Returns true, if the room shape was changed.
- */
- private boolean try_remove_edge(int p_net_no, ShapeSearchTree p_autoroute_search_tree)
- {
- if (!(this.from_room instanceof IncompleteFreeSpaceExpansionRoom))
- {
- return false;
- }
- IncompleteFreeSpaceExpansionRoom curr_incomplete_room = (IncompleteFreeSpaceExpansionRoom) this.from_room;
- if (!(curr_incomplete_room.get_shape() instanceof IntBox))
- {
- System.out.println("SortedOrthogonalRoomNeighbours.try_remove_edge: IntBox expected for room_shape type");
- return false;
- }
- IntBox room_box = (IntBox) curr_incomplete_room.get_shape();
- double room_area = room_box.area();
-
- int remove_edge_no = -1;
- for (int i = 0; i < 4; ++i)
- {
- if (!this.edge_interiour_touches_obstacle[i])
- {
- remove_edge_no = i;
- break;
- }
- }
-
- if (remove_edge_no >= 0)
- {
- // Touching neighbour missing at the edge side with index remove_edge_no
- // Remove the edge line and restart the algorithm.
- IntBox enlarged_box = remove_border_line( room_box, remove_edge_no);
- Collection door_list = this.completed_room.get_doors();
- TileShape ignore_shape = null;
- SearchTreeObject ignore_object = null;
- double max_door_area = 0;
- for (ExpansionDoor curr_door: door_list)
- {
- // insert the overlapping doors with CompleteFreeSpaceExpansionRooms
- // for the information in complete_shape about the objects to ignore.
- if (curr_door.dimension == 2)
- {
- CompleteExpansionRoom other_room = curr_door.other_room(this.completed_room);
- {
- if (other_room instanceof CompleteFreeSpaceExpansionRoom)
- {
- TileShape curr_door_shape = curr_door.get_shape();
- double curr_door_area = curr_door_shape.area();
- if (curr_door_area > max_door_area)
- {
- max_door_area = curr_door_area;
- ignore_shape = curr_door_shape;
- ignore_object = (CompleteFreeSpaceExpansionRoom) other_room;
- }
- }
- }
- }
- }
- IncompleteFreeSpaceExpansionRoom enlarged_room =
- new IncompleteFreeSpaceExpansionRoom(enlarged_box, curr_incomplete_room.get_layer(),
- curr_incomplete_room.get_contained_shape());
- Collection new_rooms =
- p_autoroute_search_tree.complete_shape(enlarged_room, p_net_no, ignore_object, ignore_shape);
- if (new_rooms.size() == 1)
- {
- // Check, that the area increases to prevent endless loop.
- IncompleteFreeSpaceExpansionRoom new_room = new_rooms.iterator().next();
- if (new_room.get_shape().area() > room_area)
- {
- curr_incomplete_room.set_shape(new_room.get_shape());
- curr_incomplete_room.set_contained_shape(new_room.get_contained_shape());
- return true;
- }
- }
- }
- return false;
- }
-
- private static IntBox remove_border_line( IntBox p_room_box, int p_remove_edge_no)
- {
- IntBox result;
- if (p_remove_edge_no == 0)
- {
- result = new IntBox(p_room_box.ll.x, -Limits.CRIT_INT, p_room_box.ur.x, p_room_box.ur.y);
- }
- else if (p_remove_edge_no == 1)
- {
- result = new IntBox(p_room_box.ll.x, p_room_box.ll.y, Limits.CRIT_INT, p_room_box.ur.y);
- }
- else if (p_remove_edge_no == 2)
- {
- result = new IntBox(p_room_box.ll.x, p_room_box.ll.y, p_room_box.ur.x, Limits.CRIT_INT);
- }
- else if (p_remove_edge_no == 3)
- {
- result = new IntBox(-Limits.CRIT_INT, p_room_box.ll.y, p_room_box.ur.x, p_room_box.ur.y);
- }
- else
- {
- System.out.println("SortedOrthogonalRoomNeighbours.remove_border_line: illegal p_remove_edge_no");
- result = null;
- }
- return result;
- }
-
- private void add_sorted_neighbour(IntBox p_neighbour_shape, IntBox p_intersection)
- {
- SortedRoomNeighbour new_neighbour = new SortedRoomNeighbour(p_neighbour_shape, p_intersection);
- sorted_neighbours.add(new_neighbour);
- }
-
- public final CompleteExpansionRoom completed_room;
- public final SortedSet sorted_neighbours;
- private final ExpansionRoom from_room;
- private final boolean is_obstacle_expansion_room;
- private final IntBox room_shape;
-
- private final boolean[] edge_interiour_touches_obstacle;
-
- /**
- * Helper class to sort the doors of an expansion room counterclockwise
- * arount the border of the room shape.
- */
-
- private class SortedRoomNeighbour implements Comparable
- {
- public SortedRoomNeighbour(IntBox p_neighbour_shape, IntBox p_intersection)
- {
- shape = p_neighbour_shape;
- intersection = p_intersection;
-
- if( p_intersection.ll.y == room_shape.ll.y
- && p_intersection.ur.x > room_shape.ll.x && p_intersection.ll.x < room_shape.ur.x)
- {
- edge_interiour_touches_obstacle[0] = true;
- }
- if( p_intersection.ur.x == room_shape.ur.x
- && p_intersection.ur.y > room_shape.ll.y && p_intersection.ll.y < room_shape.ur.y)
- {
- edge_interiour_touches_obstacle[1] = true;
- }
- if( p_intersection.ur.y == room_shape.ur.y
- && p_intersection.ur.x > room_shape.ll.x && p_intersection.ll.x < room_shape.ur.x)
- {
- edge_interiour_touches_obstacle[2] = true;
- }
- if( p_intersection.ll.x == room_shape.ll.x
- && p_intersection.ur.y > room_shape.ll.y && p_intersection.ll.y < room_shape.ur.y)
- {
- edge_interiour_touches_obstacle[3] = true;
- }
-
- if (p_intersection.ll.y == room_shape.ll.y && p_intersection.ll.x > room_shape.ll.x)
- {
- this.first_touching_side = 0;
- }
- else if (p_intersection.ur.x == room_shape.ur.x && p_intersection.ll.y > room_shape.ll.y)
- {
- this.first_touching_side = 1;
- }
- else if (p_intersection.ur.y == room_shape.ur.y )
- {
- this.first_touching_side = 2;
- }
- else if (p_intersection.ll.x == room_shape.ll.x)
- {
- this.first_touching_side = 3;
- }
- else
- {
- System.out.println("SortedRoomNeighbour: case not expected");
- this.first_touching_side = -1;
- }
-
- if (p_intersection.ll.x == room_shape.ll.x && p_intersection.ll.y > room_shape.ll.y)
- {
- this.last_touching_side = 3;
- }
- else if (p_intersection.ur.y == room_shape.ur.y && p_intersection.ll.x > room_shape.ll.x)
- {
- this.last_touching_side = 2;
- }
- else if (p_intersection.ur.x == room_shape.ur.x)
- {
- this.last_touching_side = 1;
- }
- else if (p_intersection.ll.y == room_shape.ll.y)
- {
- this.last_touching_side = 0;
- }
- else
- {
- System.out.println("SortedRoomNeighbour: case not expected");
- this.last_touching_side = -1;
- }
- }
-
- /**
- * Compare function for or sorting the neighbours in counterclock sense
- * around the border of the room shape in ascending order.
- */
- public int compareTo(SortedRoomNeighbour p_other)
- {
- if (this.first_touching_side > p_other.first_touching_side)
- {
- return 1;
- }
- if (this.first_touching_side < p_other.first_touching_side)
- {
- return -1;
- }
-
- // now the first touch of this and p_other is at the same side
- IntBox is1 = this.intersection;
- IntBox is2 = p_other.intersection;
- int cmp_value;
-
- if (first_touching_side == 0)
- {
- cmp_value = is1.ll.x - is2.ll.x;
- }
- else if (first_touching_side == 1)
- {
- cmp_value = is1.ll.y - is2.ll.y;
- }
- else if (first_touching_side == 2)
- {
- cmp_value = is2.ur.x - is1.ur.x;
- }
- else if (first_touching_side == 3)
- {
- cmp_value = is2.ur.y - is1.ur.y;
- }
- else
- {
- System.out.println("SortedRoomNeighbour.compareTo: first_touching_side out of range ");
- return 0;
- }
- if (cmp_value == 0)
- {
- // The first touching points of this neighbour and p_other with the room shape are equal.
- // Compare the last touching points.
- int this_touching_side_diff = (this.last_touching_side - this.first_touching_side + 4) % 4;
- int other_touching_side_diff = (p_other.last_touching_side - p_other.first_touching_side + 4) % 4;
- if (this_touching_side_diff > other_touching_side_diff)
- {
- return 1;
- }
- if (this_touching_side_diff < other_touching_side_diff)
- {
- return -1;
- }
-
- // now the last touch of this and p_other is at the same side
- if (last_touching_side == 0)
- {
- cmp_value = is1.ur.x - is2.ur.x;
- }
- else if (last_touching_side == 1)
- {
- cmp_value = is1.ur.y - is2.ur.y;
- }
- else if (last_touching_side == 2)
- {
- cmp_value = is2.ll.x - is1.ll.x;
- }
- else if (last_touching_side == 3)
- {
- cmp_value = is2.ll.y - is1.ll.y;
- }
- else
- {
- System.out.println("SortedRoomNeighbour.compareTo: first_touching_side out of range ");
- return 0;
- }
- }
- return cmp_value;
- }
-
- /** The shape of the neighbour room */
- public final IntBox shape;
-
- /** The intersection of tnis ExpansionRoom shape with the neighbour_shape */
- public final IntBox intersection;
-
- /** The first side of the room shape, where the neighbour_shape touches */
- public final int first_touching_side;
-
- /** The last side of the room shape, where the neighbour_shape touches */
- public final int last_touching_side;
- }
-}
+/*
+ * Copyright (C) 2014 Alfons Wirtz
+ * website www.freerouting.net
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License at
+ * for more details.
+ *
+ * OrthogonalAutorouteEngine.java
+ *
+ * Created on 24. Mai 2007, 07:51
+ *
+ */
+
+package autoroute;
+
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.SortedSet;
+import java.util.TreeSet;
+
+import datastructures.ShapeTree;
+
+import geometry.planar.IntBox;
+import geometry.planar.TileShape;
+import geometry.planar.Limits;
+
+import board.SearchTreeObject;
+import board.ShapeSearchTree;
+import board.Item;
+
+/**
+ * SortedOrthogonalRoomNeighbours class.
+ *
+ * @author Alfons Wirtz
+ * @version $Id: $Id
+ */
+public class SortedOrthogonalRoomNeighbours
+{
+
+ /**
+ * calculate.
+ *
+ * @param p_room a {@link autoroute.ExpansionRoom} object.
+ * @param p_autoroute_engine a {@link autoroute.AutorouteEngine} object.
+ * @return a {@link autoroute.CompleteExpansionRoom} object.
+ */
+ public static CompleteExpansionRoom calculate(ExpansionRoom p_room, AutorouteEngine p_autoroute_engine)
+ {
+ int net_no = p_autoroute_engine.get_net_no();
+ SortedOrthogonalRoomNeighbours room_neighbours = SortedOrthogonalRoomNeighbours.calculate_neighbours(p_room, net_no,
+ p_autoroute_engine.autoroute_search_tree, p_autoroute_engine.generate_room_id_no());
+ if (room_neighbours == null)
+ {
+ return null;
+ }
+
+ // Check, that each side of the romm shape has at least one touching neighbour.
+ // Otherwise improve the room shape by enlarging.
+ boolean edge_removed = room_neighbours.try_remove_edge(net_no, p_autoroute_engine.autoroute_search_tree);
+ CompleteExpansionRoom result = room_neighbours.completed_room;
+ if (edge_removed)
+ {
+ p_autoroute_engine.remove_all_doors(result);
+ return calculate(p_room, p_autoroute_engine);
+ }
+
+ // Now calculate the new incomplete rooms together with the doors
+ // between this room and the sorted neighbours.
+
+ if (room_neighbours.sorted_neighbours.isEmpty())
+ {
+ if (result instanceof ObstacleExpansionRoom)
+ {
+ calculate_incomplete_rooms_with_empty_neighbours((ObstacleExpansionRoom) p_room, p_autoroute_engine);
+ }
+ }
+ else
+ {
+ room_neighbours.calculate_new_incomplete_rooms(p_autoroute_engine);
+ }
+ return result;
+ }
+
+ private static void calculate_incomplete_rooms_with_empty_neighbours(ObstacleExpansionRoom p_room, AutorouteEngine p_autoroute_engine)
+ {
+ TileShape room_shape = p_room.get_shape();
+ if (!(room_shape instanceof IntBox))
+ {
+ System.out.println("SortedOrthoganelRoomNeighbours.calculate_incomplete_rooms_with_empty_neighbours: IntBox expected for room_shape");
+ return;
+ }
+ IntBox room_box = (IntBox) room_shape;
+ IntBox bounding_box = p_autoroute_engine.board.get_bounding_box();
+ for (int i = 0; i < 4; ++i)
+ {
+ IntBox new_room_box;
+ if (i == 0)
+ {
+ new_room_box = new IntBox(bounding_box.ll.x, bounding_box.ll.y, bounding_box.ur.x, room_box.ll.y);
+ }
+ else if (i == 1)
+ {
+ new_room_box = new IntBox(room_box.ur.x, bounding_box.ll.y, bounding_box.ur.x, bounding_box.ur.y);
+ }
+ else if (i == 2)
+ {
+ new_room_box = new IntBox(bounding_box.ll.x, room_box.ur.y, bounding_box.ur.x, bounding_box.ur.y);
+ }
+ else if (i == 3)
+ {
+ new_room_box = new IntBox(bounding_box.ll.x, bounding_box.ll.y, room_box.ll.x, bounding_box.ur.y);
+ }
+ else
+ {
+ System.out.println("SortedOrthoganelRoomNeighbours.calculate_incomplete_rooms_with_empty_neighbours: illegal index i");
+ return;
+ }
+ IntBox new_contained_box = room_box.intersection(new_room_box);
+ FreeSpaceExpansionRoom new_room = p_autoroute_engine.add_incomplete_expansion_room(new_room_box, p_room.get_layer(), new_contained_box);
+ ExpansionDoor new_door = new ExpansionDoor(p_room, new_room, 1);
+ p_room.add_door(new_door);
+ new_room.add_door(new_door);
+ }
+ }
+
+ /**
+ * Calculates all touching neighbours of p_room and sorts them in
+ * counterclock sense around the boundary of the room shape.
+ */
+ private static SortedOrthogonalRoomNeighbours calculate_neighbours(ExpansionRoom p_room, int p_net_no,
+ ShapeSearchTree p_autoroute_search_tree, int p_room_id_no)
+ {
+ TileShape room_shape = p_room.get_shape();
+ if (!(room_shape instanceof IntBox))
+ {
+ System.out.println("SortedOrthogonalRoomNeighbours.calculate: IntBox expected for room_shape");
+ return null;
+ }
+ IntBox room_box = (IntBox) room_shape;
+ CompleteExpansionRoom completed_room;
+ if (p_room instanceof IncompleteFreeSpaceExpansionRoom)
+ {
+ completed_room = new CompleteFreeSpaceExpansionRoom(room_shape, p_room.get_layer(), p_room_id_no);
+ }
+ else if (p_room instanceof ObstacleExpansionRoom)
+ {
+ completed_room = (ObstacleExpansionRoom)p_room;
+ }
+ else
+ {
+ System.out.println("SortedOrthogonalRoomNeighbours.calculate: unexpected expansion room type");
+ return null;
+ }
+ SortedOrthogonalRoomNeighbours result = new SortedOrthogonalRoomNeighbours(p_room, completed_room);
+ Collection overlapping_objects = new LinkedList();
+ p_autoroute_search_tree.overlapping_tree_entries(room_shape, p_room.get_layer(), overlapping_objects);
+ // Calculate the touching neigbour objects and sort them in counterclock sence
+ // around the border of the room shape.
+ for (ShapeTree.TreeEntry curr_entry : overlapping_objects)
+ {
+ SearchTreeObject curr_object = (SearchTreeObject) curr_entry.object;
+ if (curr_object == p_room)
+ {
+ continue;
+ }
+ if ((completed_room instanceof CompleteFreeSpaceExpansionRoom) && !curr_object.is_trace_obstacle(p_net_no))
+ {
+ ((CompleteFreeSpaceExpansionRoom) completed_room).calculate_target_doors(curr_entry,
+ p_net_no, p_autoroute_search_tree);
+ continue;
+ }
+ TileShape curr_shape =
+ curr_object.get_tree_shape(p_autoroute_search_tree, curr_entry.shape_index_in_object);
+ if (!(curr_shape instanceof IntBox))
+ {
+ System.out.println("OrthogonalAutorouteEngine:calculate_sorted_neighbours: IntBox expected for curr_shape");
+ return null;
+ }
+ IntBox curr_box = (IntBox) curr_shape;
+ IntBox intersection = room_box.intersection(curr_box);
+ int dimension = intersection.dimension();
+ if (dimension > 1 && completed_room instanceof ObstacleExpansionRoom)
+ {
+ if (curr_object instanceof Item)
+ {
+ // only Obstacle expansion roos may have a 2-dim overlap
+ Item curr_item = (Item) curr_object;
+ if (curr_item.is_route())
+ {
+ ItemAutorouteInfo item_info = curr_item.get_autoroute_info();
+ ObstacleExpansionRoom curr_overlap_room =
+ item_info.get_expansion_room(curr_entry.shape_index_in_object, p_autoroute_search_tree);
+ ((ObstacleExpansionRoom) completed_room).create_overlap_door(curr_overlap_room);
+ }
+
+ }
+ continue;
+ }
+ if (dimension < 0)
+ {
+
+ System.out.println("AutorouteEngine.calculate_doors: dimension >= 0 expected");
+ continue;
+ }
+ result.add_sorted_neighbour(curr_box, intersection);
+ if (dimension > 0)
+ {
+ // make shure, that there is a door to the neighbour room.
+ ExpansionRoom neighbour_room = null;
+ if (curr_object instanceof ExpansionRoom)
+ {
+ neighbour_room = (ExpansionRoom) curr_object;
+ }
+ else if (curr_object instanceof Item)
+ {
+ Item curr_item = (Item) curr_object;
+ if (curr_item.is_route())
+ {
+ // expand the item for ripup and pushing purposes
+ ItemAutorouteInfo item_info = curr_item.get_autoroute_info();
+ neighbour_room =
+ item_info.get_expansion_room(curr_entry.shape_index_in_object, p_autoroute_search_tree);
+ }
+ }
+ if (neighbour_room != null)
+ {
+ if (SortedRoomNeighbours.insert_door_ok(completed_room, neighbour_room, intersection))
+ {
+ ExpansionDoor new_door = new ExpansionDoor(completed_room, neighbour_room);
+ neighbour_room.add_door(new_door);
+ completed_room.add_door(new_door);
+ }
+ }
+ }
+ }
+ return result;
+ }
+
+ private void calculate_new_incomplete_rooms(AutorouteEngine p_autoroute_engine)
+ {
+ IntBox board_bounds = p_autoroute_engine.board.bounding_box;
+ SortedRoomNeighbour prev_neighbour = this.sorted_neighbours.last();
+ Iterator it = this.sorted_neighbours.iterator();
+
+ while (it.hasNext())
+ {
+ SortedRoomNeighbour next_neighbour = it.next();
+
+ if (!next_neighbour.intersection.intersects(prev_neighbour.intersection))
+ {
+ // create a door to a new incomplete expansion room between
+ // the last corner of the previous neighbour and the first corner of the
+ // current neighbour.
+ if (next_neighbour.first_touching_side == 0)
+ {
+ if (prev_neighbour.last_touching_side == 0)
+ {
+ if (prev_neighbour.intersection.ur.x < next_neighbour.intersection.ll.x)
+ {
+ insert_incomplete_room(p_autoroute_engine, prev_neighbour.intersection.ur.x, board_bounds.ll.y,
+ next_neighbour.intersection.ll.x, this.room_shape.ll.y);
+ }
+ }
+ else
+ {
+ if (prev_neighbour.intersection.ll.y > this.room_shape.ll.y
+ || next_neighbour.intersection.ll.x > this.room_shape.ll.x)
+ {
+ if (is_obstacle_expansion_room)
+ {
+ // no 2-dim doors between obstacle_expansion_rooms and free space rooms allowed.
+ if (prev_neighbour.last_touching_side == 3)
+ {
+ insert_incomplete_room(p_autoroute_engine, board_bounds.ll.x, room_shape.ll.y,
+ room_shape.ll.x, prev_neighbour.intersection.ll.y);
+ }
+ insert_incomplete_room(p_autoroute_engine, room_shape.ll.x, board_bounds.ll.y,
+ next_neighbour.intersection.ll.x, room_shape.ll.y);
+ }
+ else
+ {
+ insert_incomplete_room(p_autoroute_engine, board_bounds.ll.x, board_bounds.ll.y,
+ next_neighbour.intersection.ll.x, prev_neighbour.intersection.ll.y);
+ }
+ }
+ }
+ }
+ else if (next_neighbour.first_touching_side == 1)
+ {
+ if (prev_neighbour.last_touching_side == 1)
+ {
+ if (prev_neighbour.intersection.ur.y < next_neighbour.intersection.ll.y)
+ {
+ insert_incomplete_room(p_autoroute_engine, this.room_shape.ur.x, prev_neighbour.intersection.ur.y,
+ board_bounds.ur.x, next_neighbour.intersection.ll.y );
+ }
+ }
+ else
+ {
+ if (prev_neighbour.intersection.ur.x < this.room_shape.ur.x
+ || next_neighbour.intersection.ll.y > this.room_shape.ll.y)
+ {
+ if (is_obstacle_expansion_room)
+ {
+ // no 2-dim doors between obstacle_expansion_rooms and free space rooms allowed.
+ if (prev_neighbour.last_touching_side == 0)
+ {
+ insert_incomplete_room(p_autoroute_engine, prev_neighbour.intersection.ur.x, board_bounds.ll.y,
+ room_shape.ur.x, room_shape.ll.y);
+ }
+ insert_incomplete_room(p_autoroute_engine, room_shape.ur.x, room_shape.ll.y,
+ room_shape.ur.x, next_neighbour.intersection.ll.y );
+ }
+ else
+ {
+ insert_incomplete_room(p_autoroute_engine, prev_neighbour.intersection.ur.x, board_bounds.ll.y,
+ board_bounds.ur.x, next_neighbour.intersection.ll.y);
+ }
+ }
+ }
+ }
+ else if (next_neighbour.first_touching_side == 2)
+ {
+ if (prev_neighbour.last_touching_side == 2)
+ {
+ if (prev_neighbour.intersection.ll.x > next_neighbour.intersection.ur.x)
+ {
+ insert_incomplete_room(p_autoroute_engine, next_neighbour.intersection.ur.x, this.room_shape.ur.y,
+ prev_neighbour.intersection.ll.x, board_bounds.ur.y);
+ }
+ }
+ else
+ {
+ if (prev_neighbour.intersection.ur.y < this.room_shape.ur.y
+ || next_neighbour.intersection.ur.x < this.room_shape.ur.x)
+ {
+ if (is_obstacle_expansion_room)
+ {
+ // no 2-dim doors between obstacle_expansion_rooms and free space rooms allowed.
+ if (prev_neighbour.last_touching_side == 1)
+ {
+ insert_incomplete_room(p_autoroute_engine, room_shape.ur.x, prev_neighbour.intersection.ur.y,
+ board_bounds.ur.x, room_shape.ur.y);
+ }
+ insert_incomplete_room(p_autoroute_engine, next_neighbour.intersection.ur.x, room_shape.ur.y,
+ room_shape.ur.x, board_bounds.ur.y );
+ }
+ else
+ {
+ insert_incomplete_room(p_autoroute_engine, next_neighbour.intersection.ur.x, prev_neighbour.intersection.ur.y,
+ board_bounds.ur.x, board_bounds.ur.y);
+ }
+ }
+ }
+ }
+ else if (next_neighbour.first_touching_side == 3)
+ {
+ if (prev_neighbour.last_touching_side == 3)
+ {
+ if (prev_neighbour.intersection.ll.y > next_neighbour.intersection.ur.y)
+ {
+ insert_incomplete_room(p_autoroute_engine, board_bounds.ll.x, next_neighbour.intersection.ur.y,
+ this.room_shape.ll.x, prev_neighbour.intersection.ll.y);
+ }
+ }
+ else
+ {
+ if (next_neighbour.intersection.ur.y < this.room_shape.ur.y
+ || prev_neighbour.intersection.ll.x > this.room_shape.ll.x)
+ {
+ if (is_obstacle_expansion_room)
+ {
+ // no 2-dim doors between obstacle_expansion_rooms and free space rooms allowed.
+ if (prev_neighbour.last_touching_side == 2)
+ {
+ insert_incomplete_room(p_autoroute_engine, room_shape.ll.x, room_shape.ur.y,
+ prev_neighbour.intersection.ll.x, board_bounds.ur.y);
+ }
+ insert_incomplete_room(p_autoroute_engine, board_bounds.ll.x, next_neighbour.intersection.ur.y,
+ room_shape.ll.x, room_shape.ur.y);
+ }
+ else
+ {
+ insert_incomplete_room(p_autoroute_engine, board_bounds.ll.x, next_neighbour.intersection.ur.y,
+ prev_neighbour.intersection.ll.x, board_bounds.ur.y);
+ }
+ }
+ }
+ }
+ else
+ {
+ System.out.println("SortedOrthogonalRoomNeighbour.calculate_new_incomplete: illegal touching side");
+ }
+ }
+ prev_neighbour = next_neighbour;
+ }
+ }
+
+ private void insert_incomplete_room(AutorouteEngine p_autoroute_engine, int p_ll_x, int p_ll_y, int p_ur_x, int p_ur_y)
+ {
+ IntBox new_incomplete_room_shape = new IntBox(p_ll_x, p_ll_y, p_ur_x, p_ur_y);
+ if (new_incomplete_room_shape.dimension() == 2)
+ {
+ IntBox new_contained_shape = this.room_shape.intersection(new_incomplete_room_shape);
+ if (!new_contained_shape.is_empty())
+ {
+ int door_dimension = new_incomplete_room_shape.intersection(this.room_shape).dimension();
+ if (door_dimension > 0)
+ {
+ FreeSpaceExpansionRoom new_room =
+ p_autoroute_engine.add_incomplete_expansion_room(new_incomplete_room_shape, this.from_room.get_layer(), new_contained_shape);
+ ExpansionDoor new_door = new ExpansionDoor(this.completed_room, new_room, door_dimension);
+ this.completed_room.add_door(new_door);
+ new_room.add_door(new_door);
+ }
+ }
+ }
+ }
+
+ /** Creates a new instance of SortedOrthogonalRoomNeighbours */
+ private SortedOrthogonalRoomNeighbours(ExpansionRoom p_from_room, CompleteExpansionRoom p_completed_room)
+ {
+ from_room = p_from_room;
+ completed_room = p_completed_room;
+ is_obstacle_expansion_room = p_from_room instanceof ObstacleExpansionRoom;
+ room_shape = (IntBox) p_completed_room.get_shape();
+ sorted_neighbours = new TreeSet();
+ edge_interiour_touches_obstacle = new boolean[4];
+ for (int i = 0; i < 4; ++i)
+ {
+ edge_interiour_touches_obstacle[i] = false;
+ }
+ }
+
+ /**
+ * Check, that each side of the romm shape has at least one touching neighbour.
+ * Otherwise the room shape will be improved the by enlarging.
+ * Returns true, if the room shape was changed.
+ */
+ private boolean try_remove_edge(int p_net_no, ShapeSearchTree p_autoroute_search_tree)
+ {
+ if (!(this.from_room instanceof IncompleteFreeSpaceExpansionRoom))
+ {
+ return false;
+ }
+ IncompleteFreeSpaceExpansionRoom curr_incomplete_room = (IncompleteFreeSpaceExpansionRoom) this.from_room;
+ if (!(curr_incomplete_room.get_shape() instanceof IntBox))
+ {
+ System.out.println("SortedOrthogonalRoomNeighbours.try_remove_edge: IntBox expected for room_shape type");
+ return false;
+ }
+ IntBox room_box = (IntBox) curr_incomplete_room.get_shape();
+ double room_area = room_box.area();
+
+ int remove_edge_no = -1;
+ for (int i = 0; i < 4; ++i)
+ {
+ if (!this.edge_interiour_touches_obstacle[i])
+ {
+ remove_edge_no = i;
+ break;
+ }
+ }
+
+ if (remove_edge_no >= 0)
+ {
+ // Touching neighbour missing at the edge side with index remove_edge_no
+ // Remove the edge line and restart the algorithm.
+ IntBox enlarged_box = remove_border_line( room_box, remove_edge_no);
+ Collection door_list = this.completed_room.get_doors();
+ TileShape ignore_shape = null;
+ SearchTreeObject ignore_object = null;
+ double max_door_area = 0;
+ for (ExpansionDoor curr_door: door_list)
+ {
+ // insert the overlapping doors with CompleteFreeSpaceExpansionRooms
+ // for the information in complete_shape about the objects to ignore.
+ if (curr_door.dimension == 2)
+ {
+ CompleteExpansionRoom other_room = curr_door.other_room(this.completed_room);
+ {
+ if (other_room instanceof CompleteFreeSpaceExpansionRoom)
+ {
+ TileShape curr_door_shape = curr_door.get_shape();
+ double curr_door_area = curr_door_shape.area();
+ if (curr_door_area > max_door_area)
+ {
+ max_door_area = curr_door_area;
+ ignore_shape = curr_door_shape;
+ ignore_object = (CompleteFreeSpaceExpansionRoom) other_room;
+ }
+ }
+ }
+ }
+ }
+ IncompleteFreeSpaceExpansionRoom enlarged_room =
+ new IncompleteFreeSpaceExpansionRoom(enlarged_box, curr_incomplete_room.get_layer(),
+ curr_incomplete_room.get_contained_shape());
+ Collection new_rooms =
+ p_autoroute_search_tree.complete_shape(enlarged_room, p_net_no, ignore_object, ignore_shape);
+ if (new_rooms.size() == 1)
+ {
+ // Check, that the area increases to prevent endless loop.
+ IncompleteFreeSpaceExpansionRoom new_room = new_rooms.iterator().next();
+ if (new_room.get_shape().area() > room_area)
+ {
+ curr_incomplete_room.set_shape(new_room.get_shape());
+ curr_incomplete_room.set_contained_shape(new_room.get_contained_shape());
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ private static IntBox remove_border_line( IntBox p_room_box, int p_remove_edge_no)
+ {
+ IntBox result;
+ if (p_remove_edge_no == 0)
+ {
+ result = new IntBox(p_room_box.ll.x, -Limits.CRIT_INT, p_room_box.ur.x, p_room_box.ur.y);
+ }
+ else if (p_remove_edge_no == 1)
+ {
+ result = new IntBox(p_room_box.ll.x, p_room_box.ll.y, Limits.CRIT_INT, p_room_box.ur.y);
+ }
+ else if (p_remove_edge_no == 2)
+ {
+ result = new IntBox(p_room_box.ll.x, p_room_box.ll.y, p_room_box.ur.x, Limits.CRIT_INT);
+ }
+ else if (p_remove_edge_no == 3)
+ {
+ result = new IntBox(-Limits.CRIT_INT, p_room_box.ll.y, p_room_box.ur.x, p_room_box.ur.y);
+ }
+ else
+ {
+ System.out.println("SortedOrthogonalRoomNeighbours.remove_border_line: illegal p_remove_edge_no");
+ result = null;
+ }
+ return result;
+ }
+
+ private void add_sorted_neighbour(IntBox p_neighbour_shape, IntBox p_intersection)
+ {
+ SortedRoomNeighbour new_neighbour = new SortedRoomNeighbour(p_neighbour_shape, p_intersection);
+ sorted_neighbours.add(new_neighbour);
+ }
+
+ public final CompleteExpansionRoom completed_room;
+ public final SortedSet sorted_neighbours;
+ private final ExpansionRoom from_room;
+ private final boolean is_obstacle_expansion_room;
+ private final IntBox room_shape;
+
+ private final boolean[] edge_interiour_touches_obstacle;
+
+ /**
+ * Helper class to sort the doors of an expansion room counterclockwise
+ * arount the border of the room shape.
+ */
+
+ private class SortedRoomNeighbour implements Comparable
+ {
+ public SortedRoomNeighbour(IntBox p_neighbour_shape, IntBox p_intersection)
+ {
+ shape = p_neighbour_shape;
+ intersection = p_intersection;
+
+ if( p_intersection.ll.y == room_shape.ll.y
+ && p_intersection.ur.x > room_shape.ll.x && p_intersection.ll.x < room_shape.ur.x)
+ {
+ edge_interiour_touches_obstacle[0] = true;
+ }
+ if( p_intersection.ur.x == room_shape.ur.x
+ && p_intersection.ur.y > room_shape.ll.y && p_intersection.ll.y < room_shape.ur.y)
+ {
+ edge_interiour_touches_obstacle[1] = true;
+ }
+ if( p_intersection.ur.y == room_shape.ur.y
+ && p_intersection.ur.x > room_shape.ll.x && p_intersection.ll.x < room_shape.ur.x)
+ {
+ edge_interiour_touches_obstacle[2] = true;
+ }
+ if( p_intersection.ll.x == room_shape.ll.x
+ && p_intersection.ur.y > room_shape.ll.y && p_intersection.ll.y < room_shape.ur.y)
+ {
+ edge_interiour_touches_obstacle[3] = true;
+ }
+
+ if (p_intersection.ll.y == room_shape.ll.y && p_intersection.ll.x > room_shape.ll.x)
+ {
+ this.first_touching_side = 0;
+ }
+ else if (p_intersection.ur.x == room_shape.ur.x && p_intersection.ll.y > room_shape.ll.y)
+ {
+ this.first_touching_side = 1;
+ }
+ else if (p_intersection.ur.y == room_shape.ur.y )
+ {
+ this.first_touching_side = 2;
+ }
+ else if (p_intersection.ll.x == room_shape.ll.x)
+ {
+ this.first_touching_side = 3;
+ }
+ else
+ {
+ System.out.println("SortedRoomNeighbour: case not expected");
+ this.first_touching_side = -1;
+ }
+
+ if (p_intersection.ll.x == room_shape.ll.x && p_intersection.ll.y > room_shape.ll.y)
+ {
+ this.last_touching_side = 3;
+ }
+ else if (p_intersection.ur.y == room_shape.ur.y && p_intersection.ll.x > room_shape.ll.x)
+ {
+ this.last_touching_side = 2;
+ }
+ else if (p_intersection.ur.x == room_shape.ur.x)
+ {
+ this.last_touching_side = 1;
+ }
+ else if (p_intersection.ll.y == room_shape.ll.y)
+ {
+ this.last_touching_side = 0;
+ }
+ else
+ {
+ System.out.println("SortedRoomNeighbour: case not expected");
+ this.last_touching_side = -1;
+ }
+ }
+
+ /**
+ * Compare function for or sorting the neighbours in counterclock sense
+ * around the border of the room shape in ascending order.
+ */
+ public int compareTo(SortedRoomNeighbour p_other)
+ {
+ if (this.first_touching_side > p_other.first_touching_side)
+ {
+ return 1;
+ }
+ if (this.first_touching_side < p_other.first_touching_side)
+ {
+ return -1;
+ }
+
+ // now the first touch of this and p_other is at the same side
+ IntBox is1 = this.intersection;
+ IntBox is2 = p_other.intersection;
+ int cmp_value;
+
+ if (first_touching_side == 0)
+ {
+ cmp_value = is1.ll.x - is2.ll.x;
+ }
+ else if (first_touching_side == 1)
+ {
+ cmp_value = is1.ll.y - is2.ll.y;
+ }
+ else if (first_touching_side == 2)
+ {
+ cmp_value = is2.ur.x - is1.ur.x;
+ }
+ else if (first_touching_side == 3)
+ {
+ cmp_value = is2.ur.y - is1.ur.y;
+ }
+ else
+ {
+ System.out.println("SortedRoomNeighbour.compareTo: first_touching_side out of range ");
+ return 0;
+ }
+ if (cmp_value == 0)
+ {
+ // The first touching points of this neighbour and p_other with the room shape are equal.
+ // Compare the last touching points.
+ int this_touching_side_diff = (this.last_touching_side - this.first_touching_side + 4) % 4;
+ int other_touching_side_diff = (p_other.last_touching_side - p_other.first_touching_side + 4) % 4;
+ if (this_touching_side_diff > other_touching_side_diff)
+ {
+ return 1;
+ }
+ if (this_touching_side_diff < other_touching_side_diff)
+ {
+ return -1;
+ }
+
+ // now the last touch of this and p_other is at the same side
+ if (last_touching_side == 0)
+ {
+ cmp_value = is1.ur.x - is2.ur.x;
+ }
+ else if (last_touching_side == 1)
+ {
+ cmp_value = is1.ur.y - is2.ur.y;
+ }
+ else if (last_touching_side == 2)
+ {
+ cmp_value = is2.ll.x - is1.ll.x;
+ }
+ else if (last_touching_side == 3)
+ {
+ cmp_value = is2.ll.y - is1.ll.y;
+ }
+ else
+ {
+ System.out.println("SortedRoomNeighbour.compareTo: first_touching_side out of range ");
+ return 0;
+ }
+ }
+ return cmp_value;
+ }
+
+ /** The shape of the neighbour room */
+ public final IntBox shape;
+
+ /** The intersection of tnis ExpansionRoom shape with the neighbour_shape */
+ public final IntBox intersection;
+
+ /** The first side of the room shape, where the neighbour_shape touches */
+ public final int first_touching_side;
+
+ /** The last side of the room shape, where the neighbour_shape touches */
+ public final int last_touching_side;
+ }
+}
diff --git a/autoroute/SortedRoomNeighbours.java b/src/main/java/autoroute/SortedRoomNeighbours.java
similarity index 97%
rename from autoroute/SortedRoomNeighbours.java
rename to src/main/java/autoroute/SortedRoomNeighbours.java
index 15f29c2..6fef152 100644
--- a/autoroute/SortedRoomNeighbours.java
+++ b/src/main/java/autoroute/SortedRoomNeighbours.java
@@ -1,848 +1,855 @@
-/*
- * Copyright (C) 2014 Alfons Wirtz
- * website www.freerouting.net
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License at
- * for more details.
- *
- * SortedRoomNeighbours.java
- *
- * Created on 28. Mai 2007, 07:27
- *
- */
-
-package autoroute;
-
-import java.util.Collection;
-import java.util.LinkedList;
-import java.util.TreeSet;
-import java.util.SortedSet;
-import java.util.Iterator;
-
-import datastructures.Signum;
-import datastructures.ShapeTree;
-
-import geometry.planar.Side;
-import geometry.planar.Direction;
-import geometry.planar.Point;
-import geometry.planar.IntPoint;
-import geometry.planar.FloatPoint;
-import geometry.planar.Line;
-import geometry.planar.TileShape;
-import geometry.planar.Simplex;
-
-import board.ShapeSearchTree;
-import board.SearchTreeObject;
-import board.Connectable;
-import board.Item;
-import board.PolylineTrace;
-import board.TestLevel;
-
-/**
- * To calculate the neigbour rooms of an expansion room.
- * The neighbour rooms will be sorted in counterclock sense around the border of the shape of p_room.
- * Overlapping neighbours containing an item may be stored in an unordered list.
- *
- * @author Alfons Wirtz
- */
-public class SortedRoomNeighbours
-{
- /**
- * To calculate the neigbour rooms of an expansion room.
- * The neighbour rooms will be sorted in counterclock sense around the border of the shape of p_room.
- * Overlapping neighbours containing an item may be stored in an unordered list.
- */
- public static CompleteExpansionRoom calculate(ExpansionRoom p_room, AutorouteEngine p_autoroute_engine)
- {
- int net_no = p_autoroute_engine.get_net_no();
- TestLevel test_level = p_autoroute_engine.board.get_test_level();
- SortedRoomNeighbours room_neighbours = calculate_neighbours(p_room, net_no, p_autoroute_engine.autoroute_search_tree,
- p_autoroute_engine.generate_room_id_no(), test_level);
-
- // Check, that each side of the romm shape has at least one touching neighbour.
- // Otherwise improve the room shape by enlarging.
-
- boolean edge_removed = room_neighbours.try_remove_edge(net_no,
- p_autoroute_engine.autoroute_search_tree, test_level);
- CompleteExpansionRoom result = room_neighbours.completed_room;
- if (edge_removed)
- {
- p_autoroute_engine.remove_all_doors(result);
- return calculate(p_room, p_autoroute_engine);
- }
-
- // Now calculate the new incomplete rooms together with the doors
- // between this room and the sorted neighbours.
- if (room_neighbours.sorted_neighbours.isEmpty())
- {
- if (result instanceof ObstacleExpansionRoom)
- {
- calculate_incomplete_rooms_with_empty_neighbours((ObstacleExpansionRoom) p_room, p_autoroute_engine);
- }
- }
- else
- {
- room_neighbours.calculate_new_incomplete_rooms(p_autoroute_engine);
- if (test_level.ordinal() >= TestLevel.ALL_DEBUGGING_OUTPUT.ordinal() && result.get_shape().dimension() < 2)
- {
- System.out.println("AutorouteEngine.calculate_new_incomplete_rooms_with_mmore_than_1_neighbour: unexpected dimension for smoothened_shape");
- }
- }
-
- if (result instanceof CompleteFreeSpaceExpansionRoom)
- {
- calculate_target_doors((CompleteFreeSpaceExpansionRoom) result,
- room_neighbours.own_net_objects, p_autoroute_engine);
- }
- return result;
- }
-
- private static void calculate_incomplete_rooms_with_empty_neighbours(ObstacleExpansionRoom p_room, AutorouteEngine p_autoroute_engine)
- {
- TileShape room_shape = p_room.get_shape();
- for (int i = 0; i < room_shape.border_line_count(); ++i)
- {
- Line curr_line = room_shape.border_line(i);
- if (SortedRoomNeighbours.insert_door_ok(p_room, curr_line))
- {
- Line[] shape_line = new Line[1];
- shape_line[0] = curr_line.opposite();
- TileShape new_room_shape = new Simplex(shape_line);
- TileShape new_contained_shape = room_shape.intersection(new_room_shape);
- FreeSpaceExpansionRoom new_room = p_autoroute_engine.add_incomplete_expansion_room(new_room_shape, p_room.get_layer(), new_contained_shape);
- ExpansionDoor new_door = new ExpansionDoor(p_room, new_room, 1);
- p_room.add_door(new_door);
- new_room.add_door(new_door);
- }
- }
- }
-
-
- private static void calculate_target_doors(CompleteFreeSpaceExpansionRoom p_room,
- Collection p_own_net_objects, AutorouteEngine p_autoroute_engine)
- {
- if (!p_own_net_objects.isEmpty())
- {
- p_room.set_net_dependent();
- }
- for (ShapeTree.TreeEntry curr_entry : p_own_net_objects)
- {
- if (curr_entry.object instanceof Connectable)
- {
- Connectable curr_object = (Connectable) curr_entry.object;
- if (curr_object.contains_net(p_autoroute_engine.get_net_no()))
- {
- TileShape curr_connection_shape =
- curr_object.get_trace_connection_shape(p_autoroute_engine.autoroute_search_tree, curr_entry.shape_index_in_object);
- if (curr_connection_shape != null && p_room.get_shape().intersects(curr_connection_shape))
- {
- Item curr_item = (Item) curr_object;
- TargetItemExpansionDoor new_target_door =
- new TargetItemExpansionDoor(curr_item, curr_entry.shape_index_in_object, p_room,
- p_autoroute_engine.autoroute_search_tree);
- p_room.add_target_door(new_target_door);
- }
- }
- }
- }
- }
-
- private static SortedRoomNeighbours calculate_neighbours(ExpansionRoom p_room, int p_net_no,
- ShapeSearchTree p_autoroute_search_tree, int p_room_id_no, TestLevel p_test_level)
- {
- TileShape room_shape = p_room.get_shape();
- CompleteExpansionRoom completed_room;
- if (p_room instanceof IncompleteFreeSpaceExpansionRoom)
- {
- completed_room = new CompleteFreeSpaceExpansionRoom(room_shape, p_room.get_layer(), p_room_id_no);
- }
- else if (p_room instanceof ObstacleExpansionRoom)
- {
- completed_room = (ObstacleExpansionRoom)p_room;
- }
- else
- {
- System.out.println("SortedRoomNeighbours.calculate: unexpected expansion room type");
- return null;
- }
- SortedRoomNeighbours result = new SortedRoomNeighbours(p_room, completed_room);
- Collection overlapping_objects = new LinkedList();
- p_autoroute_search_tree.overlapping_tree_entries(room_shape, p_room.get_layer(), overlapping_objects);
- // Calculate the touching neigbour objects and sort them in counterclock sence
- // around the border of the room shape.
- for (ShapeTree.TreeEntry curr_entry : overlapping_objects)
- {
- SearchTreeObject curr_object = (SearchTreeObject) curr_entry.object;
- if (curr_object == p_room)
- {
- continue;
- }
- if ((p_room instanceof IncompleteFreeSpaceExpansionRoom) && !curr_object.is_trace_obstacle(p_net_no))
- {
- // delay processing the target doors until the room shape will not change any more
- result.own_net_objects.add(curr_entry);
- continue;
- }
- TileShape curr_shape =
- curr_object.get_tree_shape(p_autoroute_search_tree, curr_entry.shape_index_in_object);
- TileShape intersection = room_shape.intersection(curr_shape);
- int dimension = intersection.dimension();
- if (dimension > 1)
- {
- if (completed_room instanceof ObstacleExpansionRoom && curr_object instanceof Item)
- {
- // only Obstacle expansion roos may have a 2-dim overlap
- Item curr_item = (Item) curr_object;
- if (curr_item.is_route())
- {
- ItemAutorouteInfo item_info = curr_item.get_autoroute_info();
- ObstacleExpansionRoom curr_overlap_room =
- item_info.get_expansion_room(curr_entry.shape_index_in_object, p_autoroute_search_tree);
- ((ObstacleExpansionRoom) completed_room).create_overlap_door(curr_overlap_room);
- }
- }
- else if (p_test_level.ordinal() >= TestLevel.ALL_DEBUGGING_OUTPUT.ordinal())
- {
- System.out.println("SortedRoomNeighbours.calculate: unexpected area overlap of free space expansion room");
- }
- continue;
- }
- if (dimension < 0)
- {
- if (p_test_level.ordinal() >= TestLevel.CRITICAL_DEBUGGING_OUTPUT.ordinal())
- {
- System.out.println("SortedRoomNeighbours.calculate: dimension >= 0 expected");
- }
- continue;
- }
- if (dimension == 1)
- {
- int[] touching_sides = room_shape.touching_sides(curr_shape);
- if (touching_sides.length != 2)
- {
- if (p_test_level.ordinal() >= TestLevel.CRITICAL_DEBUGGING_OUTPUT.ordinal())
- {
- System.out.println("SortedRoomNeighbours.calculate: touching_sides length 2 expected");
- }
- continue;
- }
- result.add_sorted_neighbour(curr_shape, intersection, touching_sides[0],
- touching_sides[1], false, false);
- // make shure, that there is a door to the neighbour room.
- ExpansionRoom neighbour_room = null;
- if (curr_object instanceof ExpansionRoom)
- {
- neighbour_room = (ExpansionRoom) curr_object;
- }
- else if (curr_object instanceof Item)
- {
- Item curr_item = (Item) curr_object;
- if (curr_item.is_route())
- {
- // expand the item for ripup and pushing purposes
- ItemAutorouteInfo item_info = curr_item.get_autoroute_info();
- neighbour_room =
- item_info.get_expansion_room(curr_entry.shape_index_in_object, p_autoroute_search_tree);
- }
- }
- if (neighbour_room != null)
- {
- if (SortedRoomNeighbours.insert_door_ok(completed_room, neighbour_room, intersection))
- {
- ExpansionDoor new_door = new ExpansionDoor(completed_room, neighbour_room, 1);
- neighbour_room.add_door(new_door);
- completed_room.add_door(new_door);
- }
- }
- }
- else // dimensin = 0
- {
- Point touching_point = intersection.corner(0);
- int room_corner_no = room_shape.equals_corner(touching_point);
- boolean room_touch_is_corner;
- int touching_side_no_of_room;
- if (room_corner_no >= 0)
- {
- room_touch_is_corner = true;
- touching_side_no_of_room = room_corner_no;
- }
- else
- {
- room_touch_is_corner = false;
- touching_side_no_of_room = room_shape.contains_on_border_line_no(touching_point);
- if (touching_side_no_of_room < 0 && p_test_level.ordinal() >= TestLevel.CRITICAL_DEBUGGING_OUTPUT.ordinal())
- {
- System.out.println("SortedRoomNeighbours.calculate: touching_side_no_of_room >= 0 expected");
- }
- }
- int neighbour_room_corner_no = curr_shape.equals_corner(touching_point);
- boolean neighbour_room_touch_is_corner;
- int touching_side_no_of_neighbour_room;
- if (neighbour_room_corner_no >= 0)
- {
- neighbour_room_touch_is_corner = true;
- // The previous border line is preferred to make the shape of the incomplete room as big as possible
- touching_side_no_of_neighbour_room = curr_shape.prev_no(neighbour_room_corner_no);
- }
- else
- {
- neighbour_room_touch_is_corner = false;
- touching_side_no_of_neighbour_room = curr_shape.contains_on_border_line_no(touching_point);
- if (touching_side_no_of_neighbour_room < 0 && p_test_level.ordinal() >= TestLevel.CRITICAL_DEBUGGING_OUTPUT.ordinal())
- {
- System.out.println("AutorouteEngine.SortedRoomNeighbours.calculate: touching_side_no_of_neighbour_room >= 0 expected");
- }
- }
- result.add_sorted_neighbour(curr_shape, intersection,
- touching_side_no_of_room , touching_side_no_of_neighbour_room,
- room_touch_is_corner , neighbour_room_touch_is_corner);
- }
- }
- return result;
- }
-
-
-
- /** Creates a new instance of SortedRoomNeighbours */
- private SortedRoomNeighbours(ExpansionRoom p_from_room, CompleteExpansionRoom p_completed_room)
- {
- from_room = p_from_room;
- completed_room = p_completed_room;
- room_shape = p_completed_room.get_shape();
- sorted_neighbours = new TreeSet();
- own_net_objects = new LinkedList();
- }
-
- private void add_sorted_neighbour(TileShape p_neighbour_shape, TileShape p_intersection,
- int p_touching_side_no_of_room, int p_touching_side_no_of_neighbour_room,
- boolean p_room_touch_is_corner, boolean p_neighbour_room_touch_is_corner)
- {
- SortedRoomNeighbour new_neighbour = new SortedRoomNeighbour(p_neighbour_shape, p_intersection,
- p_touching_side_no_of_room, p_touching_side_no_of_neighbour_room,
- p_room_touch_is_corner, p_neighbour_room_touch_is_corner);
- sorted_neighbours.add(new_neighbour);
- }
-
- /**
- * Check, that each side of the romm shape has at least one touching neighbour.
- * Otherwise the room shape will be improved the by enlarging.
- * Returns true, if the room shape was changed.
- */
- private boolean try_remove_edge(int p_net_no, ShapeSearchTree p_autoroute_search_tree, TestLevel p_test_level)
- {
- if (!(this.from_room instanceof IncompleteFreeSpaceExpansionRoom))
- {
- return false;
- }
- IncompleteFreeSpaceExpansionRoom curr_incomplete_room = (IncompleteFreeSpaceExpansionRoom) this.from_room;
- Iterator it = sorted_neighbours.iterator();
- int remove_edge_no = -1;
- Simplex room_simplex = curr_incomplete_room.get_shape().to_Simplex();
- double room_shape_area = room_simplex.area();
-
- int prev_edge_no = -1;
- int curr_edge_no = 0;
- while (it.hasNext())
- {
- SortedRoomNeighbour next_neighbour = it.next();
- if (next_neighbour.touching_side_no_of_room == prev_edge_no)
- {
- continue;
- }
- if (next_neighbour.touching_side_no_of_room == curr_edge_no)
- {
- prev_edge_no = curr_edge_no;
- ++curr_edge_no;
- }
- else
- {
- // On the edge side with index curr_edge_no is no touching
- // neighbour.
- remove_edge_no = curr_edge_no;
- break;
- }
- }
-
- if (remove_edge_no < 0 && curr_edge_no < room_simplex.border_line_count())
- {
- // missing touching neighbour at the last edge side.
- remove_edge_no = curr_edge_no;
- }
-
-
-
- if (remove_edge_no >= 0)
- {
- // Touching neighbour missing at the edge side with index remove_edge_no
- // Remove the edge line and restart the algorithm.
- Simplex enlarged_shape = room_simplex.remove_border_line(remove_edge_no);
- IncompleteFreeSpaceExpansionRoom enlarged_room =
- new IncompleteFreeSpaceExpansionRoom(enlarged_shape, curr_incomplete_room.get_layer(),
- curr_incomplete_room.get_contained_shape());
- Collection new_rooms =
- p_autoroute_search_tree.complete_shape(enlarged_room, p_net_no, null, null);
- if (new_rooms.size() != 1)
- {
- if (p_test_level.ordinal() >= TestLevel.ALL_DEBUGGING_OUTPUT.ordinal())
- {
- System.out.println("AutorouteEngine.calculate_doors: 1 completed shape expected");
- }
- return false;
- }
- boolean remove_edge = false;
- if (new_rooms.size() == 1)
- {
- // Check, that the area increases to prevent endless loop.
- IncompleteFreeSpaceExpansionRoom new_shape = new_rooms.iterator().next();
- if (new_shape.get_shape().area() > room_shape_area)
- {
- remove_edge = true;
- }
- }
- if (remove_edge)
- {
- Iterator it2 = new_rooms.iterator();
- IncompleteFreeSpaceExpansionRoom new_room = it2.next();
- curr_incomplete_room.set_shape(new_room.get_shape());
- curr_incomplete_room.set_contained_shape(new_room.get_contained_shape());
- return true;
- }
- }
- return false;
- }
-
- /**
- * Called from calculate_doors().
- * The shape of the room p_result may change inside this function.
- */
- public void calculate_new_incomplete_rooms(AutorouteEngine p_autoroute_engine)
- {
- SortedRoomNeighbour prev_neighbour = this.sorted_neighbours.last();
- Iterator it = this.sorted_neighbours.iterator();
- Simplex room_simplex = this.from_room.get_shape().to_Simplex();
- while (it.hasNext())
- {
- SortedRoomNeighbour next_neighbour = it.next();
- int first_touching_side_no = prev_neighbour.touching_side_no_of_room;
- int last_touching_side_no = next_neighbour.touching_side_no_of_room;
-
- int curr_next_no = room_simplex.next_no(first_touching_side_no);
- boolean intersection_with_prev_neighbour_ends_at_corner =
- (first_touching_side_no != last_touching_side_no || prev_neighbour == this.sorted_neighbours.last())
- && prev_neighbour.last_corner().equals(room_simplex.corner(curr_next_no));
- boolean intersection_with_next_neighbour_starts_at_corner =
- (first_touching_side_no != last_touching_side_no || prev_neighbour == this.sorted_neighbours.last())
- && next_neighbour.first_corner().equals(room_simplex.corner(last_touching_side_no));
-
- if (intersection_with_prev_neighbour_ends_at_corner)
- {
- first_touching_side_no = curr_next_no;
- }
-
- if(intersection_with_next_neighbour_starts_at_corner)
- {
- last_touching_side_no = room_simplex.prev_no(last_touching_side_no);
- }
- boolean neighbours_touch = false;
-
- if (this.sorted_neighbours.size() > 1)
- {
- neighbours_touch = prev_neighbour.last_corner().equals(next_neighbour.first_corner());
- }
-
- if (!neighbours_touch)
- {
- // create a door to a new incomplete expansion room between
- // the last corner of the previous neighbour and the first corner of the
- // current neighbour.
- int last_bounding_line_no = prev_neighbour.touching_side_no_of_neighbour_room;
- if (!(intersection_with_prev_neighbour_ends_at_corner
- || prev_neighbour.room_touch_is_corner))
- {
- last_bounding_line_no = prev_neighbour.neighbour_shape.prev_no(last_bounding_line_no);
- }
-
-
- int first_bounding_line_no = next_neighbour.touching_side_no_of_neighbour_room;
- if (!(intersection_with_next_neighbour_starts_at_corner
- || next_neighbour.neighbour_room_touch_is_corner))
- {
- first_bounding_line_no = next_neighbour.neighbour_shape.next_no(first_bounding_line_no);
- }
- Line start_edge_line = next_neighbour.neighbour_shape.border_line(first_bounding_line_no).opposite();
- // start_edge_line is only used for the first new incomplete room.
- Line middle_edge_line = null;
- int curr_touching_side_no = last_touching_side_no;
- boolean first_time = true;
- // The loop goes backwards fromm the edge line of next_neigbour to the edge line of prev_neigbour.
- for (;;)
- {
- boolean corner_cut_off = false;
- if (this.from_room instanceof IncompleteFreeSpaceExpansionRoom)
- {
- IncompleteFreeSpaceExpansionRoom incomplete_room = (IncompleteFreeSpaceExpansionRoom) this.from_room;
- if (curr_touching_side_no == last_touching_side_no
- && first_touching_side_no != last_touching_side_no)
- {
- // Create a new line approximately from the last corner of the previous
- // neighbour to the first corner of the next neighbour to cut off
- // the outstanding corners of the room shape in the empty space.
- // That is only tried in the first pass of the loop.
- IntPoint cut_line_start = prev_neighbour.last_corner().to_float().round();
- IntPoint cut_line_end = next_neighbour.first_corner().to_float().round();
- Line cut_line = new Line(cut_line_start, cut_line_end);
- TileShape cut_half_plane = TileShape.get_instance(cut_line);
- ((CompleteFreeSpaceExpansionRoom)this.completed_room).set_shape(this.completed_room.get_shape().intersection(cut_half_plane));
- corner_cut_off = true;
- if (incomplete_room.get_contained_shape().side_of(cut_line) != Side.ON_THE_LEFT)
- {
- // Otherwise p_room.contained_shape would no longer be contained
- // in the shape after cutting of the corner.
- corner_cut_off = false;
- }
- if (corner_cut_off)
- {
- middle_edge_line = cut_line.opposite();
- }
- }
- }
- int next_touching_side_no = room_simplex.prev_no(curr_touching_side_no);
-
- if (!corner_cut_off)
- {
- middle_edge_line = room_simplex.border_line(curr_touching_side_no).opposite();
- }
-
- Direction middle_line_dir = middle_edge_line.direction();
-
- boolean last_time =
- curr_touching_side_no == first_touching_side_no
- && !(prev_neighbour == this.sorted_neighbours.last() && first_time)
- // The expression above handles the case, when all neigbours are on 1 edge line.
- || corner_cut_off;
-
- Line end_edge_line;
- // end_edge_line is only used for the last new incomplete room.
- if (last_time)
- {
- end_edge_line = prev_neighbour.neighbour_shape.border_line(last_bounding_line_no).opposite();
- if (end_edge_line.direction().side_of(middle_line_dir) != Side.ON_THE_LEFT)
- {
- // Concave corner between the middle and the last line.
- // May be there is a 1 point touch.
- end_edge_line = null;
- }
- }
- else
- {
- end_edge_line = null;
- }
-
- if (start_edge_line != null && middle_line_dir.side_of(start_edge_line.direction()) != Side.ON_THE_LEFT)
- {
- // concave corner between the first and the middle line
- // May be there is a 1 point touch.
- start_edge_line = null;
- }
- int new_edge_line_count = 1;
- if (start_edge_line != null)
- {
- ++new_edge_line_count;
- }
- if (end_edge_line != null)
- {
- ++new_edge_line_count;
- }
- Line [] new_edge_lines = new Line[new_edge_line_count];
- int curr_index = 0;
- if (start_edge_line != null)
- {
- new_edge_lines[curr_index] = start_edge_line;
- ++curr_index;
- }
- new_edge_lines[curr_index] = middle_edge_line;
- if (end_edge_line != null)
- {
- ++curr_index;
- new_edge_lines[curr_index] = end_edge_line;
- }
- Simplex new_room_shape = Simplex.get_instance(new_edge_lines);
- if (!new_room_shape.is_empty())
- {
-
- TileShape new_contained_shape = this.completed_room.get_shape().intersection(new_room_shape);
- if (!new_contained_shape.is_empty())
- {
- FreeSpaceExpansionRoom new_room =
- p_autoroute_engine.add_incomplete_expansion_room(new_room_shape, this.from_room.get_layer(), new_contained_shape);
- ExpansionDoor new_door = new ExpansionDoor(this.completed_room, new_room, 1);
- this.completed_room.add_door(new_door);
- new_room.add_door(new_door);
- }
- }
- if (last_time)
- {
- break;
- }
- curr_touching_side_no = next_touching_side_no;
- start_edge_line = null;
- first_time = false;
- }
- }
- prev_neighbour = next_neighbour;
- }
- }
-
- /**
- * p_door_shape is expected to bave dimension 1.
- */
- static boolean insert_door_ok(ExpansionRoom p_room_1, ExpansionRoom p_room_2, TileShape p_door_shape)
- {
- if (p_room_1.door_exists(p_room_2))
- {
- return false;
- }
- if (p_room_1 instanceof ObstacleExpansionRoom && p_room_2 instanceof ObstacleExpansionRoom)
- {
- Item first_item = ((ObstacleExpansionRoom) p_room_1).get_item();
- Item second_item = ((ObstacleExpansionRoom) p_room_2).get_item();
- // insert only overlap_doors between items of the same net for performance reasons.
- return (first_item.shares_net(second_item));
- }
- if (!(p_room_1 instanceof ObstacleExpansionRoom) && !(p_room_2 instanceof ObstacleExpansionRoom))
- {
- return true;
- }
- // Insert 1 dimensional doors of trace rooms only, if they are parallel to the trace line.
- // Otherwise there may be check ripup problems with entering at the wrong side at a fork.
- Line door_line = null;
- Point prev_corner = p_door_shape.corner(0);
- int corner_count = p_door_shape.border_line_count();
- for (int i = 1; i < corner_count; ++i)
- {
- Point curr_corner = p_door_shape.corner(i);
- if (!curr_corner.equals(prev_corner))
- {
- door_line = p_door_shape.border_line(i - 1);
- break;
- }
- prev_corner = curr_corner;
- }
- if (p_room_1 instanceof ObstacleExpansionRoom)
- {
- if (!insert_door_ok((ObstacleExpansionRoom) p_room_1, door_line))
- {
- return false;
- }
- }
- if (p_room_2 instanceof ObstacleExpansionRoom)
- {
- if (!insert_door_ok((ObstacleExpansionRoom) p_room_2, door_line))
- {
- return false;
- }
- }
- return true;
- }
- /**
- * Insert 1 dimensional doors for the first and the last room of a trace rooms only,
- * if they are parallel to the trace line.
- * Otherwise there may be check ripup problems with entering at the wrong side at a fork.
- */
- private static boolean insert_door_ok(ObstacleExpansionRoom p_room, Line p_door_line)
- {
- if (p_door_line == null)
- {
- System.out.println("SortedRoomNeighbours.insert_door_ok: p_door_line is null");
- return false;
- }
- Item curr_item = p_room.get_item();
- if (curr_item instanceof PolylineTrace)
- {
- int room_index = p_room.get_index_in_item();
- PolylineTrace curr_trace = (PolylineTrace) curr_item;
- if (room_index == 0 || room_index == curr_trace.tile_shape_count() - 1)
- {
- Line curr_trace_line = curr_trace.polyline().arr[room_index + 1];
- if (!curr_trace_line.is_parallel(p_door_line))
- {
- return false;
- }
- }
- }
- return true;
- }
-
- private final ExpansionRoom from_room;
- private final CompleteExpansionRoom completed_room;
- private final TileShape room_shape;
- private final SortedSet sorted_neighbours;
- private final Collection own_net_objects;
-
- /**
- * Helper class to sort the doors of an expansion room counterclockwise
- * arount the border of the room shape.
- *
- * @author Alfons Wirtz
- */
-
- private class SortedRoomNeighbour implements Comparable
- {
- public SortedRoomNeighbour(TileShape p_neighbour_shape, TileShape p_intersection,
- int p_touching_side_no_of_room, int p_touching_side_no_of_neighbour_room,
- boolean p_room_touch_is_corner, boolean p_neighbour_room_touch_is_corner)
- {
- neighbour_shape = p_neighbour_shape;
- intersection = p_intersection;
- touching_side_no_of_room = p_touching_side_no_of_room;
- touching_side_no_of_neighbour_room = p_touching_side_no_of_neighbour_room;
- room_touch_is_corner = p_room_touch_is_corner;
- neighbour_room_touch_is_corner = p_neighbour_room_touch_is_corner;
- }
-
- /**
- * Compare function for or sorting the neighbours in counterclock sense
- * around the border of the room shape in ascending order.
- */
- public int compareTo(SortedRoomNeighbour p_other)
- {
- int compare_value = this.touching_side_no_of_room - p_other.touching_side_no_of_room;
- if (compare_value != 0)
- {
- return compare_value;
- }
- FloatPoint compare_corner = room_shape.corner_approx(touching_side_no_of_room);
- double this_distance = this.first_corner().to_float().distance(compare_corner);
- double other_distance = p_other.first_corner().to_float().distance(compare_corner);
- double delta_distance = this_distance - other_distance;
- if (Math.abs(delta_distance) <= c_dist_tolerance)
- {
- // check corners for equality
- if (this.first_corner().equals(p_other.first_corner()))
- {
- // in this case compare the last corners
- double this_distance2 = this.last_corner().to_float().distance(compare_corner);
- double other_distance2 = p_other.last_corner().to_float().distance(compare_corner);
- delta_distance = this_distance2 - other_distance2;
- if (Math.abs(delta_distance) <= c_dist_tolerance)
- {
- if (this.neighbour_room_touch_is_corner && p_other.neighbour_room_touch_is_corner)
- // Otherwise there may be a short 1 dim. touch at a link between 2 trace lines.
- // In this case equality is ok, because the 2 intersection pieces with
- // the expansion room are identical, so that only 1 obstacle is needed.
- {
- int compare_line_no = touching_side_no_of_room;
- if (room_touch_is_corner)
- {
- compare_line_no = room_shape.prev_no(compare_line_no);
- }
- Direction compare_dir = room_shape.border_line(compare_line_no).direction().opposite();
- Line this_compare_line = this.neighbour_shape.border_line(this.touching_side_no_of_neighbour_room);
- Line other_compare_line = p_other.neighbour_shape.border_line(p_other.touching_side_no_of_neighbour_room);
- delta_distance = compare_dir.compare_from(this_compare_line.direction(), other_compare_line.direction());
- }
- }
- }
- }
- int result = Signum.as_int(delta_distance);
- return result;
- }
-
- /**
- * Returns the first corner of the intersection shape with the neighbour.
- */
- public Point first_corner()
- {
- if (precalculated_first_corner == null)
- {
- if (room_touch_is_corner)
- {
- precalculated_first_corner = room_shape.corner(touching_side_no_of_room);
- }
- else if (neighbour_room_touch_is_corner)
- {
- precalculated_first_corner = neighbour_shape.corner(touching_side_no_of_neighbour_room);
- }
- else
- {
- Point curr_first_corner = neighbour_shape.corner(neighbour_shape.next_no(touching_side_no_of_neighbour_room));
- Line prev_line = room_shape.border_line(room_shape.prev_no(touching_side_no_of_room));
- if (prev_line.side_of(curr_first_corner) == Side.ON_THE_RIGHT)
- {
- precalculated_first_corner = curr_first_corner;
- }
- else // curr_first_corner is outside the door shape
- {
- precalculated_first_corner = room_shape.corner(touching_side_no_of_room);
- }
- }
- }
- return precalculated_first_corner;
- }
-
- /**
- * Returns the last corner of the intersection shape with the neighbour.
- */
- public Point last_corner()
- {
- if (precalculated_last_corner == null)
- {
- if (room_touch_is_corner)
- {
- precalculated_last_corner = room_shape.corner(touching_side_no_of_room);
- }
- else if (neighbour_room_touch_is_corner)
- {
- precalculated_last_corner = neighbour_shape.corner(touching_side_no_of_neighbour_room);
- }
- else
- {
- Point curr_last_corner = neighbour_shape.corner(touching_side_no_of_neighbour_room);
- Line next_line = room_shape.border_line(room_shape.next_no(touching_side_no_of_room));
- if (next_line.side_of(curr_last_corner) == Side.ON_THE_RIGHT)
- {
- precalculated_last_corner = curr_last_corner;
- }
- else // curr_last_corner is outside the door shape
- {
- precalculated_last_corner = room_shape.corner(room_shape.next_no(touching_side_no_of_room));
- }
- }
- }
- return precalculated_last_corner;
- }
-
- /** The shape of the neighbour room */
- public final TileShape neighbour_shape;
-
- /** The intersection of tnis ExpansionRoom shape with the neighbour_shape */
- public final TileShape intersection;
-
- /** The side number of this room, where it touches the neighbour */
- public final int touching_side_no_of_room ;
-
- /** The side number of the neighbour room, where it touches this room */
- public final int touching_side_no_of_neighbour_room ;
-
- /** True, if the intersection of this room and the neighbour is
- * equal to a corner of this room */
- public final boolean room_touch_is_corner;
-
- /** True, if the intersection of this room and the neighbour is
- * equal to a corner of the neighbour room */
- public final boolean neighbour_room_touch_is_corner;
-
- private Point precalculated_first_corner = null;
- private Point precalculated_last_corner = null;
-
- static private final double c_dist_tolerance = 1;
- }
-}
+/*
+ * Copyright (C) 2014 Alfons Wirtz
+ * website www.freerouting.net
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License at
+ * for more details.
+ *
+ * SortedRoomNeighbours.java
+ *
+ * Created on 28. Mai 2007, 07:27
+ *
+ */
+
+package autoroute;
+
+import java.util.Collection;
+import java.util.LinkedList;
+import java.util.TreeSet;
+import java.util.SortedSet;
+import java.util.Iterator;
+
+import datastructures.Signum;
+import datastructures.ShapeTree;
+
+import geometry.planar.Side;
+import geometry.planar.Direction;
+import geometry.planar.Point;
+import geometry.planar.IntPoint;
+import geometry.planar.FloatPoint;
+import geometry.planar.Line;
+import geometry.planar.TileShape;
+import geometry.planar.Simplex;
+
+import board.ShapeSearchTree;
+import board.SearchTreeObject;
+import board.Connectable;
+import board.Item;
+import board.PolylineTrace;
+import board.TestLevel;
+
+/**
+ * To calculate the neigbour rooms of an expansion room.
+ * The neighbour rooms will be sorted in counterclock sense around the border of the shape of p_room.
+ * Overlapping neighbours containing an item may be stored in an unordered list.
+ *
+ * @author Alfons Wirtz
+ * @version $Id: $Id
+ */
+public class SortedRoomNeighbours
+{
+ /**
+ * To calculate the neigbour rooms of an expansion room.
+ * The neighbour rooms will be sorted in counterclock sense around the border of the shape of p_room.
+ * Overlapping neighbours containing an item may be stored in an unordered list.
+ *
+ * @param p_room a {@link autoroute.ExpansionRoom} object.
+ * @param p_autoroute_engine a {@link autoroute.AutorouteEngine} object.
+ * @return a {@link autoroute.CompleteExpansionRoom} object.
+ */
+ public static CompleteExpansionRoom calculate(ExpansionRoom p_room, AutorouteEngine p_autoroute_engine)
+ {
+ int net_no = p_autoroute_engine.get_net_no();
+ TestLevel test_level = p_autoroute_engine.board.get_test_level();
+ SortedRoomNeighbours room_neighbours = calculate_neighbours(p_room, net_no, p_autoroute_engine.autoroute_search_tree,
+ p_autoroute_engine.generate_room_id_no(), test_level);
+
+ // Check, that each side of the romm shape has at least one touching neighbour.
+ // Otherwise improve the room shape by enlarging.
+
+ boolean edge_removed = room_neighbours.try_remove_edge(net_no,
+ p_autoroute_engine.autoroute_search_tree, test_level);
+ CompleteExpansionRoom result = room_neighbours.completed_room;
+ if (edge_removed)
+ {
+ p_autoroute_engine.remove_all_doors(result);
+ return calculate(p_room, p_autoroute_engine);
+ }
+
+ // Now calculate the new incomplete rooms together with the doors
+ // between this room and the sorted neighbours.
+ if (room_neighbours.sorted_neighbours.isEmpty())
+ {
+ if (result instanceof ObstacleExpansionRoom)
+ {
+ calculate_incomplete_rooms_with_empty_neighbours((ObstacleExpansionRoom) p_room, p_autoroute_engine);
+ }
+ }
+ else
+ {
+ room_neighbours.calculate_new_incomplete_rooms(p_autoroute_engine);
+ if (test_level.ordinal() >= TestLevel.ALL_DEBUGGING_OUTPUT.ordinal() && result.get_shape().dimension() < 2)
+ {
+ System.out.println("AutorouteEngine.calculate_new_incomplete_rooms_with_mmore_than_1_neighbour: unexpected dimension for smoothened_shape");
+ }
+ }
+
+ if (result instanceof CompleteFreeSpaceExpansionRoom)
+ {
+ calculate_target_doors((CompleteFreeSpaceExpansionRoom) result,
+ room_neighbours.own_net_objects, p_autoroute_engine);
+ }
+ return result;
+ }
+
+ private static void calculate_incomplete_rooms_with_empty_neighbours(ObstacleExpansionRoom p_room, AutorouteEngine p_autoroute_engine)
+ {
+ TileShape room_shape = p_room.get_shape();
+ for (int i = 0; i < room_shape.border_line_count(); ++i)
+ {
+ Line curr_line = room_shape.border_line(i);
+ if (SortedRoomNeighbours.insert_door_ok(p_room, curr_line))
+ {
+ Line[] shape_line = new Line[1];
+ shape_line[0] = curr_line.opposite();
+ TileShape new_room_shape = new Simplex(shape_line);
+ TileShape new_contained_shape = room_shape.intersection(new_room_shape);
+ FreeSpaceExpansionRoom new_room = p_autoroute_engine.add_incomplete_expansion_room(new_room_shape, p_room.get_layer(), new_contained_shape);
+ ExpansionDoor new_door = new ExpansionDoor(p_room, new_room, 1);
+ p_room.add_door(new_door);
+ new_room.add_door(new_door);
+ }
+ }
+ }
+
+
+ private static void calculate_target_doors(CompleteFreeSpaceExpansionRoom p_room,
+ Collection p_own_net_objects, AutorouteEngine p_autoroute_engine)
+ {
+ if (!p_own_net_objects.isEmpty())
+ {
+ p_room.set_net_dependent();
+ }
+ for (ShapeTree.TreeEntry curr_entry : p_own_net_objects)
+ {
+ if (curr_entry.object instanceof Connectable)
+ {
+ Connectable curr_object = (Connectable) curr_entry.object;
+ if (curr_object.contains_net(p_autoroute_engine.get_net_no()))
+ {
+ TileShape curr_connection_shape =
+ curr_object.get_trace_connection_shape(p_autoroute_engine.autoroute_search_tree, curr_entry.shape_index_in_object);
+ if (curr_connection_shape != null && p_room.get_shape().intersects(curr_connection_shape))
+ {
+ Item curr_item = (Item) curr_object;
+ TargetItemExpansionDoor new_target_door =
+ new TargetItemExpansionDoor(curr_item, curr_entry.shape_index_in_object, p_room,
+ p_autoroute_engine.autoroute_search_tree);
+ p_room.add_target_door(new_target_door);
+ }
+ }
+ }
+ }
+ }
+
+ private static SortedRoomNeighbours calculate_neighbours(ExpansionRoom p_room, int p_net_no,
+ ShapeSearchTree p_autoroute_search_tree, int p_room_id_no, TestLevel p_test_level)
+ {
+ TileShape room_shape = p_room.get_shape();
+ CompleteExpansionRoom completed_room;
+ if (p_room instanceof IncompleteFreeSpaceExpansionRoom)
+ {
+ completed_room = new CompleteFreeSpaceExpansionRoom(room_shape, p_room.get_layer(), p_room_id_no);
+ }
+ else if (p_room instanceof ObstacleExpansionRoom)
+ {
+ completed_room = (ObstacleExpansionRoom)p_room;
+ }
+ else
+ {
+ System.out.println("SortedRoomNeighbours.calculate: unexpected expansion room type");
+ return null;
+ }
+ SortedRoomNeighbours result = new SortedRoomNeighbours(p_room, completed_room);
+ Collection overlapping_objects = new LinkedList();
+ p_autoroute_search_tree.overlapping_tree_entries(room_shape, p_room.get_layer(), overlapping_objects);
+ // Calculate the touching neigbour objects and sort them in counterclock sence
+ // around the border of the room shape.
+ for (ShapeTree.TreeEntry curr_entry : overlapping_objects)
+ {
+ SearchTreeObject curr_object = (SearchTreeObject) curr_entry.object;
+ if (curr_object == p_room)
+ {
+ continue;
+ }
+ if ((p_room instanceof IncompleteFreeSpaceExpansionRoom) && !curr_object.is_trace_obstacle(p_net_no))
+ {
+ // delay processing the target doors until the room shape will not change any more
+ result.own_net_objects.add(curr_entry);
+ continue;
+ }
+ TileShape curr_shape =
+ curr_object.get_tree_shape(p_autoroute_search_tree, curr_entry.shape_index_in_object);
+ TileShape intersection = room_shape.intersection(curr_shape);
+ int dimension = intersection.dimension();
+ if (dimension > 1)
+ {
+ if (completed_room instanceof ObstacleExpansionRoom && curr_object instanceof Item)
+ {
+ // only Obstacle expansion roos may have a 2-dim overlap
+ Item curr_item = (Item) curr_object;
+ if (curr_item.is_route())
+ {
+ ItemAutorouteInfo item_info = curr_item.get_autoroute_info();
+ ObstacleExpansionRoom curr_overlap_room =
+ item_info.get_expansion_room(curr_entry.shape_index_in_object, p_autoroute_search_tree);
+ ((ObstacleExpansionRoom) completed_room).create_overlap_door(curr_overlap_room);
+ }
+ }
+ else if (p_test_level.ordinal() >= TestLevel.ALL_DEBUGGING_OUTPUT.ordinal())
+ {
+ System.out.println("SortedRoomNeighbours.calculate: unexpected area overlap of free space expansion room");
+ }
+ continue;
+ }
+ if (dimension < 0)
+ {
+ if (p_test_level.ordinal() >= TestLevel.CRITICAL_DEBUGGING_OUTPUT.ordinal())
+ {
+ System.out.println("SortedRoomNeighbours.calculate: dimension >= 0 expected");
+ }
+ continue;
+ }
+ if (dimension == 1)
+ {
+ int[] touching_sides = room_shape.touching_sides(curr_shape);
+ if (touching_sides.length != 2)
+ {
+ if (p_test_level.ordinal() >= TestLevel.CRITICAL_DEBUGGING_OUTPUT.ordinal())
+ {
+ System.out.println("SortedRoomNeighbours.calculate: touching_sides length 2 expected");
+ }
+ continue;
+ }
+ result.add_sorted_neighbour(curr_shape, intersection, touching_sides[0],
+ touching_sides[1], false, false);
+ // make shure, that there is a door to the neighbour room.
+ ExpansionRoom neighbour_room = null;
+ if (curr_object instanceof ExpansionRoom)
+ {
+ neighbour_room = (ExpansionRoom) curr_object;
+ }
+ else if (curr_object instanceof Item)
+ {
+ Item curr_item = (Item) curr_object;
+ if (curr_item.is_route())
+ {
+ // expand the item for ripup and pushing purposes
+ ItemAutorouteInfo item_info = curr_item.get_autoroute_info();
+ neighbour_room =
+ item_info.get_expansion_room(curr_entry.shape_index_in_object, p_autoroute_search_tree);
+ }
+ }
+ if (neighbour_room != null)
+ {
+ if (SortedRoomNeighbours.insert_door_ok(completed_room, neighbour_room, intersection))
+ {
+ ExpansionDoor new_door = new ExpansionDoor(completed_room, neighbour_room, 1);
+ neighbour_room.add_door(new_door);
+ completed_room.add_door(new_door);
+ }
+ }
+ }
+ else // dimensin = 0
+ {
+ Point touching_point = intersection.corner(0);
+ int room_corner_no = room_shape.equals_corner(touching_point);
+ boolean room_touch_is_corner;
+ int touching_side_no_of_room;
+ if (room_corner_no >= 0)
+ {
+ room_touch_is_corner = true;
+ touching_side_no_of_room = room_corner_no;
+ }
+ else
+ {
+ room_touch_is_corner = false;
+ touching_side_no_of_room = room_shape.contains_on_border_line_no(touching_point);
+ if (touching_side_no_of_room < 0 && p_test_level.ordinal() >= TestLevel.CRITICAL_DEBUGGING_OUTPUT.ordinal())
+ {
+ System.out.println("SortedRoomNeighbours.calculate: touching_side_no_of_room >= 0 expected");
+ }
+ }
+ int neighbour_room_corner_no = curr_shape.equals_corner(touching_point);
+ boolean neighbour_room_touch_is_corner;
+ int touching_side_no_of_neighbour_room;
+ if (neighbour_room_corner_no >= 0)
+ {
+ neighbour_room_touch_is_corner = true;
+ // The previous border line is preferred to make the shape of the incomplete room as big as possible
+ touching_side_no_of_neighbour_room = curr_shape.prev_no(neighbour_room_corner_no);
+ }
+ else
+ {
+ neighbour_room_touch_is_corner = false;
+ touching_side_no_of_neighbour_room = curr_shape.contains_on_border_line_no(touching_point);
+ if (touching_side_no_of_neighbour_room < 0 && p_test_level.ordinal() >= TestLevel.CRITICAL_DEBUGGING_OUTPUT.ordinal())
+ {
+ System.out.println("AutorouteEngine.SortedRoomNeighbours.calculate: touching_side_no_of_neighbour_room >= 0 expected");
+ }
+ }
+ result.add_sorted_neighbour(curr_shape, intersection,
+ touching_side_no_of_room , touching_side_no_of_neighbour_room,
+ room_touch_is_corner , neighbour_room_touch_is_corner);
+ }
+ }
+ return result;
+ }
+
+
+
+ /** Creates a new instance of SortedRoomNeighbours */
+ private SortedRoomNeighbours(ExpansionRoom p_from_room, CompleteExpansionRoom p_completed_room)
+ {
+ from_room = p_from_room;
+ completed_room = p_completed_room;
+ room_shape = p_completed_room.get_shape();
+ sorted_neighbours = new TreeSet();
+ own_net_objects = new LinkedList();
+ }
+
+ private void add_sorted_neighbour(TileShape p_neighbour_shape, TileShape p_intersection,
+ int p_touching_side_no_of_room, int p_touching_side_no_of_neighbour_room,
+ boolean p_room_touch_is_corner, boolean p_neighbour_room_touch_is_corner)
+ {
+ SortedRoomNeighbour new_neighbour = new SortedRoomNeighbour(p_neighbour_shape, p_intersection,
+ p_touching_side_no_of_room, p_touching_side_no_of_neighbour_room,
+ p_room_touch_is_corner, p_neighbour_room_touch_is_corner);
+ sorted_neighbours.add(new_neighbour);
+ }
+
+ /**
+ * Check, that each side of the romm shape has at least one touching neighbour.
+ * Otherwise the room shape will be improved the by enlarging.
+ * Returns true, if the room shape was changed.
+ */
+ private boolean try_remove_edge(int p_net_no, ShapeSearchTree p_autoroute_search_tree, TestLevel p_test_level)
+ {
+ if (!(this.from_room instanceof IncompleteFreeSpaceExpansionRoom))
+ {
+ return false;
+ }
+ IncompleteFreeSpaceExpansionRoom curr_incomplete_room = (IncompleteFreeSpaceExpansionRoom) this.from_room;
+ Iterator it = sorted_neighbours.iterator();
+ int remove_edge_no = -1;
+ Simplex room_simplex = curr_incomplete_room.get_shape().to_Simplex();
+ double room_shape_area = room_simplex.area();
+
+ int prev_edge_no = -1;
+ int curr_edge_no = 0;
+ while (it.hasNext())
+ {
+ SortedRoomNeighbour next_neighbour = it.next();
+ if (next_neighbour.touching_side_no_of_room == prev_edge_no)
+ {
+ continue;
+ }
+ if (next_neighbour.touching_side_no_of_room == curr_edge_no)
+ {
+ prev_edge_no = curr_edge_no;
+ ++curr_edge_no;
+ }
+ else
+ {
+ // On the edge side with index curr_edge_no is no touching
+ // neighbour.
+ remove_edge_no = curr_edge_no;
+ break;
+ }
+ }
+
+ if (remove_edge_no < 0 && curr_edge_no < room_simplex.border_line_count())
+ {
+ // missing touching neighbour at the last edge side.
+ remove_edge_no = curr_edge_no;
+ }
+
+
+
+ if (remove_edge_no >= 0)
+ {
+ // Touching neighbour missing at the edge side with index remove_edge_no
+ // Remove the edge line and restart the algorithm.
+ Simplex enlarged_shape = room_simplex.remove_border_line(remove_edge_no);
+ IncompleteFreeSpaceExpansionRoom enlarged_room =
+ new IncompleteFreeSpaceExpansionRoom(enlarged_shape, curr_incomplete_room.get_layer(),
+ curr_incomplete_room.get_contained_shape());
+ Collection new_rooms =
+ p_autoroute_search_tree.complete_shape(enlarged_room, p_net_no, null, null);
+ if (new_rooms.size() != 1)
+ {
+ if (p_test_level.ordinal() >= TestLevel.ALL_DEBUGGING_OUTPUT.ordinal())
+ {
+ System.out.println("AutorouteEngine.calculate_doors: 1 completed shape expected");
+ }
+ return false;
+ }
+ boolean remove_edge = false;
+ if (new_rooms.size() == 1)
+ {
+ // Check, that the area increases to prevent endless loop.
+ IncompleteFreeSpaceExpansionRoom new_shape = new_rooms.iterator().next();
+ if (new_shape.get_shape().area() > room_shape_area)
+ {
+ remove_edge = true;
+ }
+ }
+ if (remove_edge)
+ {
+ Iterator it2 = new_rooms.iterator();
+ IncompleteFreeSpaceExpansionRoom new_room = it2.next();
+ curr_incomplete_room.set_shape(new_room.get_shape());
+ curr_incomplete_room.set_contained_shape(new_room.get_contained_shape());
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Called from calculate_doors().
+ * The shape of the room p_result may change inside this function.
+ *
+ * @param p_autoroute_engine a {@link autoroute.AutorouteEngine} object.
+ */
+ public void calculate_new_incomplete_rooms(AutorouteEngine p_autoroute_engine)
+ {
+ SortedRoomNeighbour prev_neighbour = this.sorted_neighbours.last();
+ Iterator it = this.sorted_neighbours.iterator();
+ Simplex room_simplex = this.from_room.get_shape().to_Simplex();
+ while (it.hasNext())
+ {
+ SortedRoomNeighbour next_neighbour = it.next();
+ int first_touching_side_no = prev_neighbour.touching_side_no_of_room;
+ int last_touching_side_no = next_neighbour.touching_side_no_of_room;
+
+ int curr_next_no = room_simplex.next_no(first_touching_side_no);
+ boolean intersection_with_prev_neighbour_ends_at_corner =
+ (first_touching_side_no != last_touching_side_no || prev_neighbour == this.sorted_neighbours.last())
+ && prev_neighbour.last_corner().equals(room_simplex.corner(curr_next_no));
+ boolean intersection_with_next_neighbour_starts_at_corner =
+ (first_touching_side_no != last_touching_side_no || prev_neighbour == this.sorted_neighbours.last())
+ && next_neighbour.first_corner().equals(room_simplex.corner(last_touching_side_no));
+
+ if (intersection_with_prev_neighbour_ends_at_corner)
+ {
+ first_touching_side_no = curr_next_no;
+ }
+
+ if(intersection_with_next_neighbour_starts_at_corner)
+ {
+ last_touching_side_no = room_simplex.prev_no(last_touching_side_no);
+ }
+ boolean neighbours_touch = false;
+
+ if (this.sorted_neighbours.size() > 1)
+ {
+ neighbours_touch = prev_neighbour.last_corner().equals(next_neighbour.first_corner());
+ }
+
+ if (!neighbours_touch)
+ {
+ // create a door to a new incomplete expansion room between
+ // the last corner of the previous neighbour and the first corner of the
+ // current neighbour.
+ int last_bounding_line_no = prev_neighbour.touching_side_no_of_neighbour_room;
+ if (!(intersection_with_prev_neighbour_ends_at_corner
+ || prev_neighbour.room_touch_is_corner))
+ {
+ last_bounding_line_no = prev_neighbour.neighbour_shape.prev_no(last_bounding_line_no);
+ }
+
+
+ int first_bounding_line_no = next_neighbour.touching_side_no_of_neighbour_room;
+ if (!(intersection_with_next_neighbour_starts_at_corner
+ || next_neighbour.neighbour_room_touch_is_corner))
+ {
+ first_bounding_line_no = next_neighbour.neighbour_shape.next_no(first_bounding_line_no);
+ }
+ Line start_edge_line = next_neighbour.neighbour_shape.border_line(first_bounding_line_no).opposite();
+ // start_edge_line is only used for the first new incomplete room.
+ Line middle_edge_line = null;
+ int curr_touching_side_no = last_touching_side_no;
+ boolean first_time = true;
+ // The loop goes backwards fromm the edge line of next_neigbour to the edge line of prev_neigbour.
+ for (;;)
+ {
+ boolean corner_cut_off = false;
+ if (this.from_room instanceof IncompleteFreeSpaceExpansionRoom)
+ {
+ IncompleteFreeSpaceExpansionRoom incomplete_room = (IncompleteFreeSpaceExpansionRoom) this.from_room;
+ if (curr_touching_side_no == last_touching_side_no
+ && first_touching_side_no != last_touching_side_no)
+ {
+ // Create a new line approximately from the last corner of the previous
+ // neighbour to the first corner of the next neighbour to cut off
+ // the outstanding corners of the room shape in the empty space.
+ // That is only tried in the first pass of the loop.
+ IntPoint cut_line_start = prev_neighbour.last_corner().to_float().round();
+ IntPoint cut_line_end = next_neighbour.first_corner().to_float().round();
+ Line cut_line = new Line(cut_line_start, cut_line_end);
+ TileShape cut_half_plane = TileShape.get_instance(cut_line);
+ ((CompleteFreeSpaceExpansionRoom)this.completed_room).set_shape(this.completed_room.get_shape().intersection(cut_half_plane));
+ corner_cut_off = true;
+ if (incomplete_room.get_contained_shape().side_of(cut_line) != Side.ON_THE_LEFT)
+ {
+ // Otherwise p_room.contained_shape would no longer be contained
+ // in the shape after cutting of the corner.
+ corner_cut_off = false;
+ }
+ if (corner_cut_off)
+ {
+ middle_edge_line = cut_line.opposite();
+ }
+ }
+ }
+ int next_touching_side_no = room_simplex.prev_no(curr_touching_side_no);
+
+ if (!corner_cut_off)
+ {
+ middle_edge_line = room_simplex.border_line(curr_touching_side_no).opposite();
+ }
+
+ Direction middle_line_dir = middle_edge_line.direction();
+
+ boolean last_time =
+ curr_touching_side_no == first_touching_side_no
+ && !(prev_neighbour == this.sorted_neighbours.last() && first_time)
+ // The expression above handles the case, when all neigbours are on 1 edge line.
+ || corner_cut_off;
+
+ Line end_edge_line;
+ // end_edge_line is only used for the last new incomplete room.
+ if (last_time)
+ {
+ end_edge_line = prev_neighbour.neighbour_shape.border_line(last_bounding_line_no).opposite();
+ if (end_edge_line.direction().side_of(middle_line_dir) != Side.ON_THE_LEFT)
+ {
+ // Concave corner between the middle and the last line.
+ // May be there is a 1 point touch.
+ end_edge_line = null;
+ }
+ }
+ else
+ {
+ end_edge_line = null;
+ }
+
+ if (start_edge_line != null && middle_line_dir.side_of(start_edge_line.direction()) != Side.ON_THE_LEFT)
+ {
+ // concave corner between the first and the middle line
+ // May be there is a 1 point touch.
+ start_edge_line = null;
+ }
+ int new_edge_line_count = 1;
+ if (start_edge_line != null)
+ {
+ ++new_edge_line_count;
+ }
+ if (end_edge_line != null)
+ {
+ ++new_edge_line_count;
+ }
+ Line [] new_edge_lines = new Line[new_edge_line_count];
+ int curr_index = 0;
+ if (start_edge_line != null)
+ {
+ new_edge_lines[curr_index] = start_edge_line;
+ ++curr_index;
+ }
+ new_edge_lines[curr_index] = middle_edge_line;
+ if (end_edge_line != null)
+ {
+ ++curr_index;
+ new_edge_lines[curr_index] = end_edge_line;
+ }
+ Simplex new_room_shape = Simplex.get_instance(new_edge_lines);
+ if (!new_room_shape.is_empty())
+ {
+
+ TileShape new_contained_shape = this.completed_room.get_shape().intersection(new_room_shape);
+ if (!new_contained_shape.is_empty())
+ {
+ FreeSpaceExpansionRoom new_room =
+ p_autoroute_engine.add_incomplete_expansion_room(new_room_shape, this.from_room.get_layer(), new_contained_shape);
+ ExpansionDoor new_door = new ExpansionDoor(this.completed_room, new_room, 1);
+ this.completed_room.add_door(new_door);
+ new_room.add_door(new_door);
+ }
+ }
+ if (last_time)
+ {
+ break;
+ }
+ curr_touching_side_no = next_touching_side_no;
+ start_edge_line = null;
+ first_time = false;
+ }
+ }
+ prev_neighbour = next_neighbour;
+ }
+ }
+
+ /**
+ * p_door_shape is expected to bave dimension 1.
+ */
+ static boolean insert_door_ok(ExpansionRoom p_room_1, ExpansionRoom p_room_2, TileShape p_door_shape)
+ {
+ if (p_room_1.door_exists(p_room_2))
+ {
+ return false;
+ }
+ if (p_room_1 instanceof ObstacleExpansionRoom && p_room_2 instanceof ObstacleExpansionRoom)
+ {
+ Item first_item = ((ObstacleExpansionRoom) p_room_1).get_item();
+ Item second_item = ((ObstacleExpansionRoom) p_room_2).get_item();
+ // insert only overlap_doors between items of the same net for performance reasons.
+ return (first_item.shares_net(second_item));
+ }
+ if (!(p_room_1 instanceof ObstacleExpansionRoom) && !(p_room_2 instanceof ObstacleExpansionRoom))
+ {
+ return true;
+ }
+ // Insert 1 dimensional doors of trace rooms only, if they are parallel to the trace line.
+ // Otherwise there may be check ripup problems with entering at the wrong side at a fork.
+ Line door_line = null;
+ Point prev_corner = p_door_shape.corner(0);
+ int corner_count = p_door_shape.border_line_count();
+ for (int i = 1; i < corner_count; ++i)
+ {
+ Point curr_corner = p_door_shape.corner(i);
+ if (!curr_corner.equals(prev_corner))
+ {
+ door_line = p_door_shape.border_line(i - 1);
+ break;
+ }
+ prev_corner = curr_corner;
+ }
+ if (p_room_1 instanceof ObstacleExpansionRoom)
+ {
+ if (!insert_door_ok((ObstacleExpansionRoom) p_room_1, door_line))
+ {
+ return false;
+ }
+ }
+ if (p_room_2 instanceof ObstacleExpansionRoom)
+ {
+ if (!insert_door_ok((ObstacleExpansionRoom) p_room_2, door_line))
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+ /**
+ * Insert 1 dimensional doors for the first and the last room of a trace rooms only,
+ * if they are parallel to the trace line.
+ * Otherwise there may be check ripup problems with entering at the wrong side at a fork.
+ */
+ private static boolean insert_door_ok(ObstacleExpansionRoom p_room, Line p_door_line)
+ {
+ if (p_door_line == null)
+ {
+ System.out.println("SortedRoomNeighbours.insert_door_ok: p_door_line is null");
+ return false;
+ }
+ Item curr_item = p_room.get_item();
+ if (curr_item instanceof PolylineTrace)
+ {
+ int room_index = p_room.get_index_in_item();
+ PolylineTrace curr_trace = (PolylineTrace) curr_item;
+ if (room_index == 0 || room_index == curr_trace.tile_shape_count() - 1)
+ {
+ Line curr_trace_line = curr_trace.polyline().arr[room_index + 1];
+ if (!curr_trace_line.is_parallel(p_door_line))
+ {
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+
+ private final ExpansionRoom from_room;
+ private final CompleteExpansionRoom completed_room;
+ private final TileShape room_shape;
+ private final SortedSet sorted_neighbours;
+ private final Collection own_net_objects;
+
+ /**
+ * Helper class to sort the doors of an expansion room counterclockwise
+ * arount the border of the room shape.
+ *
+ * @author Alfons Wirtz
+ */
+
+ private class SortedRoomNeighbour implements Comparable
+ {
+ public SortedRoomNeighbour(TileShape p_neighbour_shape, TileShape p_intersection,
+ int p_touching_side_no_of_room, int p_touching_side_no_of_neighbour_room,
+ boolean p_room_touch_is_corner, boolean p_neighbour_room_touch_is_corner)
+ {
+ neighbour_shape = p_neighbour_shape;
+ intersection = p_intersection;
+ touching_side_no_of_room = p_touching_side_no_of_room;
+ touching_side_no_of_neighbour_room = p_touching_side_no_of_neighbour_room;
+ room_touch_is_corner = p_room_touch_is_corner;
+ neighbour_room_touch_is_corner = p_neighbour_room_touch_is_corner;
+ }
+
+ /**
+ * Compare function for or sorting the neighbours in counterclock sense
+ * around the border of the room shape in ascending order.
+ */
+ public int compareTo(SortedRoomNeighbour p_other)
+ {
+ int compare_value = this.touching_side_no_of_room - p_other.touching_side_no_of_room;
+ if (compare_value != 0)
+ {
+ return compare_value;
+ }
+ FloatPoint compare_corner = room_shape.corner_approx(touching_side_no_of_room);
+ double this_distance = this.first_corner().to_float().distance(compare_corner);
+ double other_distance = p_other.first_corner().to_float().distance(compare_corner);
+ double delta_distance = this_distance - other_distance;
+ if (Math.abs(delta_distance) <= c_dist_tolerance)
+ {
+ // check corners for equality
+ if (this.first_corner().equals(p_other.first_corner()))
+ {
+ // in this case compare the last corners
+ double this_distance2 = this.last_corner().to_float().distance(compare_corner);
+ double other_distance2 = p_other.last_corner().to_float().distance(compare_corner);
+ delta_distance = this_distance2 - other_distance2;
+ if (Math.abs(delta_distance) <= c_dist_tolerance)
+ {
+ if (this.neighbour_room_touch_is_corner && p_other.neighbour_room_touch_is_corner)
+ // Otherwise there may be a short 1 dim. touch at a link between 2 trace lines.
+ // In this case equality is ok, because the 2 intersection pieces with
+ // the expansion room are identical, so that only 1 obstacle is needed.
+ {
+ int compare_line_no = touching_side_no_of_room;
+ if (room_touch_is_corner)
+ {
+ compare_line_no = room_shape.prev_no(compare_line_no);
+ }
+ Direction compare_dir = room_shape.border_line(compare_line_no).direction().opposite();
+ Line this_compare_line = this.neighbour_shape.border_line(this.touching_side_no_of_neighbour_room);
+ Line other_compare_line = p_other.neighbour_shape.border_line(p_other.touching_side_no_of_neighbour_room);
+ delta_distance = compare_dir.compare_from(this_compare_line.direction(), other_compare_line.direction());
+ }
+ }
+ }
+ }
+ int result = Signum.as_int(delta_distance);
+ return result;
+ }
+
+ /**
+ * Returns the first corner of the intersection shape with the neighbour.
+ */
+ public Point first_corner()
+ {
+ if (precalculated_first_corner == null)
+ {
+ if (room_touch_is_corner)
+ {
+ precalculated_first_corner = room_shape.corner(touching_side_no_of_room);
+ }
+ else if (neighbour_room_touch_is_corner)
+ {
+ precalculated_first_corner = neighbour_shape.corner(touching_side_no_of_neighbour_room);
+ }
+ else
+ {
+ Point curr_first_corner = neighbour_shape.corner(neighbour_shape.next_no(touching_side_no_of_neighbour_room));
+ Line prev_line = room_shape.border_line(room_shape.prev_no(touching_side_no_of_room));
+ if (prev_line.side_of(curr_first_corner) == Side.ON_THE_RIGHT)
+ {
+ precalculated_first_corner = curr_first_corner;
+ }
+ else // curr_first_corner is outside the door shape
+ {
+ precalculated_first_corner = room_shape.corner(touching_side_no_of_room);
+ }
+ }
+ }
+ return precalculated_first_corner;
+ }
+
+ /**
+ * Returns the last corner of the intersection shape with the neighbour.
+ */
+ public Point last_corner()
+ {
+ if (precalculated_last_corner == null)
+ {
+ if (room_touch_is_corner)
+ {
+ precalculated_last_corner = room_shape.corner(touching_side_no_of_room);
+ }
+ else if (neighbour_room_touch_is_corner)
+ {
+ precalculated_last_corner = neighbour_shape.corner(touching_side_no_of_neighbour_room);
+ }
+ else
+ {
+ Point curr_last_corner = neighbour_shape.corner(touching_side_no_of_neighbour_room);
+ Line next_line = room_shape.border_line(room_shape.next_no(touching_side_no_of_room));
+ if (next_line.side_of(curr_last_corner) == Side.ON_THE_RIGHT)
+ {
+ precalculated_last_corner = curr_last_corner;
+ }
+ else // curr_last_corner is outside the door shape
+ {
+ precalculated_last_corner = room_shape.corner(room_shape.next_no(touching_side_no_of_room));
+ }
+ }
+ }
+ return precalculated_last_corner;
+ }
+
+ /** The shape of the neighbour room */
+ public final TileShape neighbour_shape;
+
+ /** The intersection of tnis ExpansionRoom shape with the neighbour_shape */
+ public final TileShape intersection;
+
+ /** The side number of this room, where it touches the neighbour */
+ public final int touching_side_no_of_room ;
+
+ /** The side number of the neighbour room, where it touches this room */
+ public final int touching_side_no_of_neighbour_room ;
+
+ /** True, if the intersection of this room and the neighbour is
+ * equal to a corner of this room */
+ public final boolean room_touch_is_corner;
+
+ /** True, if the intersection of this room and the neighbour is
+ * equal to a corner of the neighbour room */
+ public final boolean neighbour_room_touch_is_corner;
+
+ private Point precalculated_first_corner = null;
+ private Point precalculated_last_corner = null;
+
+ static private final double c_dist_tolerance = 1;
+ }
+}
diff --git a/autoroute/TargetItemExpansionDoor.java b/src/main/java/autoroute/TargetItemExpansionDoor.java
similarity index 76%
rename from autoroute/TargetItemExpansionDoor.java
rename to src/main/java/autoroute/TargetItemExpansionDoor.java
index 536e833..eefe9b5 100644
--- a/autoroute/TargetItemExpansionDoor.java
+++ b/src/main/java/autoroute/TargetItemExpansionDoor.java
@@ -28,11 +28,19 @@
* An expansion door leading to a start or destination item of the autoroute algorithm.
*
* @author Alfons Wirtz
+ * @version $Id: $Id
*/
public class TargetItemExpansionDoor implements ExpandableObject
{
- /** Creates a new instance of ItemExpansionInfo */
+ /**
+ * Creates a new instance of ItemExpansionInfo
+ *
+ * @param p_item a {@link board.Item} object.
+ * @param p_tree_entry_no a int.
+ * @param p_room a {@link autoroute.CompleteExpansionRoom} object.
+ * @param p_search_tree a {@link board.ShapeSearchTree} object.
+ */
public TargetItemExpansionDoor(Item p_item, int p_tree_entry_no, CompleteExpansionRoom p_room, ShapeSearchTree p_search_tree)
{
item = p_item;
@@ -50,37 +58,62 @@ public TargetItemExpansionDoor(Item p_item, int p_tree_entry_no, CompleteExpansi
maze_search_info = new MazeSearchElement();
}
+ /**
+ * get_shape.
+ *
+ * @return a {@link geometry.planar.TileShape} object.
+ */
public TileShape get_shape()
{
return this.shape;
}
+ /**
+ * get_dimension.
+ *
+ * @return a int.
+ */
public int get_dimension()
{
return 2;
}
+ /**
+ * is_destination_door.
+ *
+ * @return a boolean.
+ */
public boolean is_destination_door()
{
ItemAutorouteInfo item_info = this.item.get_autoroute_info();
return !item_info.is_start_info();
}
+ /** {@inheritDoc} */
public CompleteExpansionRoom other_room(CompleteExpansionRoom p_room)
{
return null;
}
+ /** {@inheritDoc} */
public MazeSearchElement get_maze_search_element(int p_no)
{
return maze_search_info;
}
+ /**
+ * maze_search_element_count.
+ *
+ * @return a int.
+ */
public int maze_search_element_count()
{
return 1;
}
+ /**
+ * reset.
+ */
public void reset()
{
maze_search_info.reset();
diff --git a/autoroute/package.html b/src/main/java/autoroute/package.html
similarity index 100%
rename from autoroute/package.html
rename to src/main/java/autoroute/package.html
diff --git a/board/AngleRestriction.java b/src/main/java/board/AngleRestriction.java
similarity index 85%
rename from board/AngleRestriction.java
rename to src/main/java/board/AngleRestriction.java
index afd770f..b798a40 100644
--- a/board/AngleRestriction.java
+++ b/src/main/java/board/AngleRestriction.java
@@ -24,13 +24,18 @@
* Enum for angle restrictions none, fortyfive degree and ninety degree.
*
* @author Alfons Wirtz
+ * @version $Id: $Id
*/
public class AngleRestriction
{
+ /** Constant NONE */
public static final AngleRestriction NONE = new AngleRestriction("none", 0);
+ /** Constant FORTYFIVE_DEGREE */
public static final AngleRestriction FORTYFIVE_DEGREE = new AngleRestriction("45 degree", 1);
+ /** Constant NINETY_DEGREE */
public static final AngleRestriction NINETY_DEGREE = new AngleRestriction("90 degree", 2);
+ /** Constant arr */
public static final AngleRestriction[] arr =
{
NONE, FORTYFIVE_DEGREE, NINETY_DEGREE
@@ -38,6 +43,8 @@ public class AngleRestriction
/**
* Returns the string of this instance
+ *
+ * @return a {@link java.lang.String} object.
*/
public String to_string()
{
@@ -46,6 +53,8 @@ public String to_string()
/**
* Returns the number of this instance
+ *
+ * @return a int.
*/
public int get_no()
{
@@ -60,4 +69,4 @@ private AngleRestriction(String p_name, int p_no)
private final String name;
private final int no;
-}
\ No newline at end of file
+}
diff --git a/board/BasicBoard.java b/src/main/java/board/BasicBoard.java
similarity index 83%
rename from board/BasicBoard.java
rename to src/main/java/board/BasicBoard.java
index b0e084e..5880ab6 100644
--- a/board/BasicBoard.java
+++ b/src/main/java/board/BasicBoard.java
@@ -1,1568 +1,1837 @@
-/*
- * Copyright (C) 2014 Alfons Wirtz
- * website www.freerouting.net
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License at
- * for more details.
- */
-package board;
-
-import geometry.planar.Area;
-import geometry.planar.ConvexShape;
-import geometry.planar.IntBox;
-import geometry.planar.IntOctagon;
-import geometry.planar.Point;
-import geometry.planar.Vector;
-import geometry.planar.Polyline;
-import geometry.planar.PolylineShape;
-import geometry.planar.TileShape;
-
-import java.awt.Graphics;
-
-import java.util.Collection;
-import java.util.Iterator;
-import java.util.LinkedList;
-import java.util.Set;
-import java.util.SortedSet;
-import java.util.TreeSet;
-
-import datastructures.ShapeTree.TreeEntry;
-
-import library.BoardLibrary;
-import library.Padstack;
-import rules.BoardRules;
-import boardgraphics.GraphicsContext;
-import boardgraphics.Drawable;
-import datastructures.UndoableObjects;
-
-/**
- *
- * Provides basic functionality of a board with geometric items.
- * Contains functions such as inserting, deleting, modifying
- * and picking items and elementary checking functions.
- * A board may have 1 or several layers.
- *
- * @author Alfons Wirtz
- */
-public class BasicBoard implements java.io.Serializable
-{
-
- /**
- * Creates a new instance of a routing Board with surrrounding box
- * p_bounding_box
- * Rules contains the restrictions to obey when inserting items.
- * Among other things it may contain a clearance matrix.
- * p_observers is used for syncronisation, if the board is generated
- * by a host database. Otherwise it is null.
- * If p_test_level != RELEASE_VERSION,, some features may be used, which are still in experimental state.
- * Also warnings for debugging may be printed depending on the size of p_test_level.
- */
- public BasicBoard(IntBox p_bounding_box, LayerStructure p_layer_structure, PolylineShape[] p_outline_shapes,
- int p_outline_cl_class_no, BoardRules p_rules, Communication p_communication, TestLevel p_test_level)
- {
- layer_structure = p_layer_structure;
- rules = p_rules;
- library = new BoardLibrary();
- item_list = new UndoableObjects();
- components = new Components();
- communication = p_communication;
- bounding_box = p_bounding_box;
- this.test_level = p_test_level;
- search_tree_manager = new SearchTreeManager(this);
- p_rules.nets.set_board(this);
- insert_outline(p_outline_shapes, p_outline_cl_class_no);
- }
-
- /**
- * Inserts a trace into the board, whose geometry is described by
- * a Polyline. p_clearance_class is the index in the clearance_matix,
- * which describes the required clearance restrictions to other items.
- * Because no internal cleaning of items is done, the new inserted
- * item can be returned.
- */
- public PolylineTrace insert_trace_without_cleaning(Polyline p_polyline, int p_layer,
- int p_half_width, int[] p_net_no_arr, int p_clearance_class, FixedState p_fixed_state)
- {
- if (p_polyline.corner_count() < 2)
- {
- return null;
- }
- PolylineTrace new_trace = new PolylineTrace(p_polyline, p_layer, p_half_width, p_net_no_arr,
- p_clearance_class, 0, 0, p_fixed_state, this);
- if (new_trace.first_corner().equals(new_trace.last_corner()))
- {
- if (p_fixed_state.ordinal() < FixedState.USER_FIXED.ordinal())
- {
- return null;
- }
- }
- insert_item(new_trace);
- if (new_trace.nets_normal())
- {
- max_trace_half_width = Math.max(max_trace_half_width, p_half_width);
- min_trace_half_width = Math.min(min_trace_half_width, p_half_width);
- }
- return new_trace;
- }
-
- /**
- * Inserts a trace into the board, whose geometry is described by
- * a Polyline. p_clearance_class is the index in the clearance_matix,
- * which describes the required clearance restrictions to other items.
- */
- public void insert_trace(Polyline p_polyline, int p_layer,
- int p_half_width, int[] p_net_no_arr, int p_clearance_class, FixedState p_fixed_state)
- {
- PolylineTrace new_trace =
- insert_trace_without_cleaning(p_polyline, p_layer, p_half_width,
- p_net_no_arr, p_clearance_class, p_fixed_state);
- if (new_trace == null)
- {
- return;
- }
- IntOctagon clip_shape = null;
- if (this instanceof RoutingBoard)
- {
- ChangedArea changed_area = ((RoutingBoard) this).changed_area;
- if (changed_area != null)
- {
- clip_shape = changed_area.get_area(p_layer);
- }
- }
- new_trace.normalize(clip_shape);
- }
-
- /**
- * Inserts a trace into the board, whose geometry is described by
- * an array of points, and cleans up the net.
- */
- public void insert_trace(Point[] p_points, int p_layer,
- int p_half_width, int[] p_net_no_arr, int p_clearance_class, FixedState p_fixed_state)
- {
- for (int i = 0; i < p_points.length; ++i)
- {
- if (!this.bounding_box.contains(p_points[i]))
- {
- System.out.println("LayeredBoard.insert_trace: input point out of range");
- }
- }
- Polyline poly = new Polyline(p_points);
- insert_trace(poly, p_layer, p_half_width, p_net_no_arr, p_clearance_class, p_fixed_state);
- }
-
- /**
- * Inserts a via into the board. p_attach_allowed indicates, if the via may overlap with smd pins
- * of the same net.
- */
- public Via insert_via(Padstack p_padstack, Point p_center, int[] p_net_no_arr, int p_clearance_class,
- FixedState p_fixed_state, boolean p_attach_allowed)
- {
- Via new_via = new Via(p_padstack, p_center, p_net_no_arr, p_clearance_class, 0, 0, p_fixed_state,
- p_attach_allowed, this);
- insert_item(new_via);
- int from_layer = p_padstack.from_layer();
- int to_layer = p_padstack.to_layer();
- for (int i = from_layer; i < to_layer; ++i)
- {
- for (int curr_net_no : p_net_no_arr)
- {
- split_traces(p_center, i, curr_net_no);
- }
- }
- return new_via;
- }
-
- /**
- * Inserts a pin into the board.
- * p_pin_no is the number of this pin in the library package of its component (starting with 0).
- */
- public Pin insert_pin(int p_component_no, int p_pin_no, int[] p_net_no_arr, int p_clearance_class, FixedState p_fixed_state)
- {
- Pin new_pin = new Pin(p_component_no, p_pin_no, p_net_no_arr, p_clearance_class, 0, p_fixed_state, this);
- insert_item(new_pin);
- return new_pin;
- }
-
- /**
- * Inserts an obstacle into the board , whose geometry is described
- * by a polygonyal shape, which may have holes.
- * If p_component_no != 0, the obstacle belongs to a component.
- */
- public ObstacleArea insert_obstacle(Area p_area, int p_layer, int p_clearance_class, FixedState p_fixed_state)
- {
- if (p_area == null)
- {
- System.out.println("BasicBoard.insert_obstacle: p_area is null");
- return null;
- }
- ObstacleArea obs = new ObstacleArea(p_area, p_layer, Vector.ZERO, 0, false, p_clearance_class, 0, 0, null, p_fixed_state, this);
- insert_item(obs);
- return obs;
- }
-
- /**
- * Inserts an obstacle belonging to a component into the board
- * p_name is to identify the corresponding ObstacstacleArea in the component package.
- */
- public ObstacleArea insert_obstacle(Area p_area, int p_layer, Vector p_translation, double p_rotation_in_degree,
- boolean p_side_changed, int p_clearance_class, int p_component_no, String p_name, FixedState p_fixed_state)
- {
- if (p_area == null)
- {
- System.out.println("BasicBoard.insert_obstacle: p_area is null");
- return null;
- }
- ObstacleArea obs = new ObstacleArea(p_area, p_layer, p_translation, p_rotation_in_degree, p_side_changed,
- p_clearance_class, 0, p_component_no, p_name, p_fixed_state, this);
- insert_item(obs);
- return obs;
- }
-
- /**
- * Inserts an via obstacle area into the board , whose geometry is described
- * by a polygonyal shape, which may have holes.
- */
- public ViaObstacleArea insert_via_obstacle(Area p_area, int p_layer, int p_clearance_class,
- FixedState p_fixed_state)
- {
- if (p_area == null)
- {
- System.out.println("BasicBoard.insert_via_obstacle: p_area is null");
- return null;
- }
- ViaObstacleArea obs = new ViaObstacleArea(p_area, p_layer, Vector.ZERO, 0, false,
- p_clearance_class, 0, 0, null, p_fixed_state, this);
- insert_item(obs);
- return obs;
- }
-
- /**
- * Inserts an via obstacle belonging to a component into the board
- * p_name is to identify the corresponding ObstacstacleArea in the component package.
- */
- public ViaObstacleArea insert_via_obstacle(Area p_area, int p_layer, Vector p_translation, double p_rotation_in_degree,
- boolean p_side_changed, int p_clearance_class, int p_component_no, String p_name,
- FixedState p_fixed_state)
- {
- if (p_area == null)
- {
- System.out.println("BasicBoard.insert_via_obstacle: p_area is null");
- return null;
- }
- ViaObstacleArea obs = new ViaObstacleArea(p_area, p_layer, p_translation, p_rotation_in_degree, p_side_changed,
- p_clearance_class, 0, p_component_no, p_name, p_fixed_state, this);
- insert_item(obs);
- return obs;
- }
-
- /**
- * Inserts a component obstacle area into the board , whose geometry is described
- * by a polygonyal shape, which may have holes.
- */
- public ComponentObstacleArea insert_component_obstacle(Area p_area, int p_layer,
- int p_clearance_class, FixedState p_fixed_state)
- {
- if (p_area == null)
- {
- System.out.println("BasicBoard.insert_component_obstacle: p_area is null");
- return null;
- }
- ComponentObstacleArea obs = new ComponentObstacleArea(p_area, p_layer, Vector.ZERO, 0, false,
- p_clearance_class, 0, 0, null, p_fixed_state, this);
- insert_item(obs);
- return obs;
- }
-
- /**
- * Inserts a component obstacle belonging to a component into the board.
- * p_name is to identify the corresponding ObstacstacleArea in the component package.
- */
- public ComponentObstacleArea insert_component_obstacle(Area p_area, int p_layer, Vector p_translation, double p_rotation_in_degree,
- boolean p_side_changed, int p_clearance_class, int p_component_no, String p_name, FixedState p_fixed_state)
- {
- if (p_area == null)
- {
- System.out.println("BasicBoard.insert_component_obstacle: p_area is null");
- return null;
- }
- ComponentObstacleArea obs = new ComponentObstacleArea(p_area, p_layer, p_translation, p_rotation_in_degree, p_side_changed,
- p_clearance_class, 0, p_component_no, p_name, p_fixed_state, this);
- insert_item(obs);
- return obs;
- }
-
- /**
- * Inserts a component ouline into the board.
- */
- public ComponentOutline insert_component_outline(Area p_area, boolean p_is_front, Vector p_translation, double p_rotation_in_degree,
- int p_component_no, FixedState p_fixed_state)
- {
- if (p_area == null)
- {
- System.out.println("BasicBoard.insert_component_outline: p_area is null");
- return null;
- }
- if (!p_area.is_bounded())
- {
- System.out.println("BasicBoard.insert_component_outline: p_area is not bounded");
- return null;
- }
- ComponentOutline outline = new ComponentOutline(p_area, p_is_front, p_translation, p_rotation_in_degree,
- p_component_no, p_fixed_state, this);
- insert_item(outline);
- return outline;
- }
-
- /**
- * Inserts a condution area into the board , whose geometry is described
- * by a polygonyal shape, which may have holes.
- * If p_is_obstacle is false, it is possible to route through the conduction area
- * with traces and vias of foreign nets.
- */
- public ConductionArea insert_conduction_area(Area p_area, int p_layer,
- int[] p_net_no_arr, int p_clearance_class, boolean p_is_obstacle, FixedState p_fixed_state)
- {
- if (p_area == null)
- {
- System.out.println("BasicBoard.insert_conduction_area: p_area is null");
- return null;
- }
- ConductionArea c = new ConductionArea(p_area, p_layer, Vector.ZERO, 0, false, p_net_no_arr, p_clearance_class,
- 0, 0, null, p_is_obstacle, p_fixed_state, this);
- insert_item(c);
- return c;
- }
-
- /**
- * Inserts an Outline into the board.
- */
- public BoardOutline insert_outline(PolylineShape[] p_outline_shapes, int p_clearance_class_no)
- {
- BoardOutline result = new BoardOutline(p_outline_shapes, p_clearance_class_no, 0, this);
- insert_item(result);
- return result;
- }
-
- /**
- * Returns the outline of the board.
- */
- public BoardOutline get_outline()
- {
- Iterator it = item_list.start_read_object();
- for (;;)
- {
- UndoableObjects.Storable curr_item = item_list.read_object(it);
- if (curr_item == null)
- {
- break;
- }
- if (curr_item instanceof BoardOutline)
- {
- return (BoardOutline) curr_item;
- }
- }
- return null;
- }
-
- /**
- * Removes an item from the board
- */
- public void remove_item(Item p_item)
- {
- if (p_item == null)
- {
- return;
- }
- additional_update_after_change(p_item); // must be called before p_item is deleted.
- search_tree_manager.remove(p_item);
- item_list.delete(p_item);
-
- // let the observers syncronize the deletion
- communication.observers.notify_deleted(p_item);
- }
-
- /**
- * looks, if an item with id_no p_id_no is on the board.
- * Returns the found item or null, if no such item is found.
- */
- public Item get_item(int p_id_no)
- {
- Iterator it = item_list.start_read_object();
- for (;;)
- {
- Item curr_item = (Item) item_list.read_object(it);
- if (curr_item == null)
- {
- break;
- }
- if (curr_item.get_id_no() == p_id_no)
- {
- return curr_item;
- }
- }
- return null;
- }
-
- /**
- * Returns the list of all items on the board
- */
- public Collection- get_items()
- {
- Collection
- result = new LinkedList
- ();
- Iterator it = item_list.start_read_object();
- for (;;)
- {
- Item curr_item = (Item) item_list.read_object(it);
- if (curr_item == null)
- {
- break;
- }
- result.add(curr_item);
- }
- return result;
- }
-
- /**
- * Returns all connectable items on the board containing p_net_no
- */
- public Collection
- get_connectable_items(int p_net_no)
- {
- Collection
- result = new LinkedList
- ();
- Iterator it = item_list.start_read_object();
- for (;;)
- {
- Item curr_item = (Item) item_list.read_object(it);
- if (curr_item == null)
- {
- break;
- }
- if (curr_item instanceof Connectable && curr_item.contains_net(p_net_no))
- {
- result.add(curr_item);
- }
- }
- return result;
- }
-
- /**
- * Returns the count of connectable items of the net with number p_net_no
- */
- public int connectable_item_count(int p_net_no)
- {
- int result = 0;
- Iterator it = item_list.start_read_object();
- for (;;)
- {
- Item curr_item = (Item) item_list.read_object(it);
- if (curr_item == null)
- {
- break;
- }
- if (curr_item instanceof Connectable && curr_item.contains_net(p_net_no))
- {
- ++result;
- }
- }
- return result;
- }
-
- /**
- * Returns all items with the input component number
- */
- public Collection
- get_component_items(int p_component_no)
- {
- Collection
- result = new LinkedList
- ();
- Iterator it = item_list.start_read_object();
- for (;;)
- {
- Item curr_item = (Item) item_list.read_object(it);
- if (curr_item == null)
- {
- break;
- }
- if (curr_item.get_component_no() == p_component_no)
- {
- result.add(curr_item);
- }
- }
- return result;
- }
-
- /**
- * Returns all pins with the input component number
- */
- public Collection get_component_pins(int p_component_no)
- {
- Collection result = new LinkedList();
- Iterator it = item_list.start_read_object();
- for (;;)
- {
- Item curr_item = (Item) item_list.read_object(it);
- if (curr_item == null)
- {
- break;
- }
- if (curr_item.get_component_no() == p_component_no && curr_item instanceof Pin)
- {
- result.add((Pin) curr_item);
- }
- }
- return result;
- }
-
- /**
- * Returns the pin with the input component number and pin number, or null, if no such pinn exists.
- */
- public Pin get_pin(int p_component_no, int p_pin_no)
- {
- Iterator it = item_list.start_read_object();
- for (;;)
- {
- Item curr_item = (Item) item_list.read_object(it);
- if (curr_item == null)
- {
- break;
- }
- if (curr_item.get_component_no() == p_component_no && curr_item instanceof Pin)
- {
- Pin curr_pin = (Pin) curr_item;
- if (curr_pin.pin_no == p_pin_no)
- {
- return curr_pin;
- }
- }
- }
- return null;
- }
-
- /**
- * Removes the items in p_item_list.
- * Returns false, if some items could not be removed, bcause they are fixed.
- */
- public boolean remove_items(Collection
- p_item_list, boolean p_with_delete_fixed)
- {
- boolean result = true;
- Iterator
- it = p_item_list.iterator();
- while (it.hasNext())
- {
- Item curr_item = it.next();
- if (!p_with_delete_fixed && curr_item.is_delete_fixed() || curr_item.is_user_fixed())
- {
- result = false;
- }
- else
- {
- remove_item(curr_item);
- }
- }
- return result;
- }
-
- /**
- * Returns the list of all conduction areas on the board
- */
- public Collection get_conduction_areas()
- {
- Collection result = new LinkedList();
- Iterator it = item_list.start_read_object();
- for (;;)
- {
- UndoableObjects.Storable curr_item = item_list.read_object(it);
- if (curr_item == null)
- {
- break;
- }
- if (curr_item instanceof ConductionArea)
- {
- result.add((ConductionArea) curr_item);
- }
- }
- return result;
- }
-
- /**
- * Returns the list of all pins on the board
- */
- public Collection get_pins()
- {
- Collection result = new LinkedList();
- Iterator it = item_list.start_read_object();
- for (;;)
- {
- UndoableObjects.Storable curr_item = item_list.read_object(it);
- if (curr_item == null)
- {
- break;
- }
- if (curr_item instanceof Pin)
- {
- result.add((Pin) curr_item);
- }
- }
- return result;
- }
-
- /**
- * Returns the list of all pins on the board with only 1 layer
- */
- public Collection get_smd_pins()
- {
- Collection result = new LinkedList();
- Iterator it = item_list.start_read_object();
- for (;;)
- {
- UndoableObjects.Storable curr_item = item_list.read_object(it);
- if (curr_item == null)
- {
- break;
- }
- if (curr_item instanceof Pin)
- {
- Pin curr_pin = (Pin) curr_item;
- if (curr_pin.first_layer() == curr_pin.last_layer())
- {
- result.add(curr_pin);
- }
- }
- }
- return result;
- }
-
- /**
- * Returns the list of all vias on the board
- */
- public Collection get_vias()
- {
- Collection result = new LinkedList();
- Iterator it = item_list.start_read_object();
- for (;;)
- {
- UndoableObjects.Storable curr_item = item_list.read_object(it);
- if (curr_item == null)
- {
- break;
- }
- if (curr_item instanceof Via)
- {
- result.add((Via) curr_item);
- }
- }
- return result;
- }
-
- /**
- * Returns the list of all traces on the board
- */
- public Collection get_traces()
- {
- Collection result = new LinkedList();
- Iterator it = item_list.start_read_object();
- for (;;)
- {
- UndoableObjects.Storable curr_item = item_list.read_object(it);
- if (curr_item == null)
- {
- break;
- }
- if (curr_item instanceof Trace)
- {
- result.add((Trace) curr_item);
- }
- }
- return result;
- }
-
- /**
- * Returns the cumulative length of all traces on the board
- */
- public double cumulative_trace_length()
- {
- double result = 0;
- Iterator it = item_list.start_read_object();
- for (;;)
- {
- UndoableObjects.Storable curr_item = item_list.read_object(it);
- if (curr_item == null)
- {
- break;
- }
- if (curr_item instanceof Trace)
- {
- result += ((Trace) curr_item).get_length();
- }
- }
- return result;
- }
-
- /**
- * Combines the connected traces of this net, which have only 1 contact
- * at the connection point.
- * if p_net_no < 0 traces of all nets are combined.
- */
- public boolean combine_traces(int p_net_no)
- {
- boolean result = false;
- boolean something_changed = true;
- while (something_changed)
- {
- something_changed = false;
- Iterator it = item_list.start_read_object();
- for (;;)
- {
- Item curr_item = (Item) item_list.read_object(it);
- if (curr_item == null)
- {
- break;
- }
- if ((p_net_no < 0 || curr_item.contains_net(p_net_no)) && curr_item instanceof Trace && curr_item.is_on_the_board())
- {
- if (((Trace) curr_item).combine())
- {
- something_changed = true;
- result = true;
- break;
- }
- }
- }
- }
- return result;
- }
-
- /**
- * Normalizes the traces of this net
- */
- public boolean normalize_traces(int p_net_no)
- {
- boolean result = false;
- boolean something_changed = true;
- Item curr_item = null;
- while (something_changed)
- {
- something_changed = false;
- Iterator it = item_list.start_read_object();
- for (;;)
- {
- try
- {
- curr_item = (Item) item_list.read_object(it);
- }
- catch (java.util.ConcurrentModificationException e)
- {
- something_changed = true;
- break;
- }
- if (curr_item == null)
- {
- break;
- }
- if (curr_item.contains_net(p_net_no) && curr_item instanceof PolylineTrace && curr_item.is_on_the_board())
- {
- PolylineTrace curr_trace = (PolylineTrace) curr_item;
- if (curr_trace.normalize(null))
- {
- something_changed = true;
- result = true;
- }
- else if (!curr_trace.is_user_fixed() && this.remove_if_cycle(curr_trace))
- {
- something_changed = true;
- result = true;
- }
- }
- }
- }
- return result;
- }
-
- /**
- * Looks for traces of the input net on the input layer, so that p_location is on the trace polygon,
- * and splits these traces. Returns false, if no trace was split.
- */
- public boolean split_traces(Point p_location, int p_layer, int p_net_no)
- {
- ItemSelectionFilter filter = new ItemSelectionFilter(ItemSelectionFilter.SelectableChoices.TRACES);
- Collection
- picked_items = this.pick_items(p_location, p_layer, filter);
- IntOctagon location_shape = TileShape.get_instance(p_location).bounding_octagon();
- boolean trace_split = false;
- for (Item curr_item : picked_items)
- {
- Trace curr_trace = (Trace) curr_item;
- if (curr_trace.contains_net(p_net_no))
- {
- Collection split_pieces = curr_trace.split(location_shape);
- if (split_pieces.size() != 1)
- {
- trace_split = true;
- }
- }
- }
- return trace_split;
- }
-
- /**
- * Returs a Collection of Collections of items forming a connected set.
- */
- public Collection