255 lines
8.2 KiB
Java
255 lines
8.2 KiB
Java
/*
|
|
* 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 <http://www.gnu.org/licenses/>
|
|
* for more details.
|
|
*
|
|
* ExpansionDoor.java
|
|
*
|
|
* Created on 6. Januar 2004, 07:23
|
|
*/
|
|
package eu.mihosoft.freerouting.autoroute;
|
|
|
|
import eu.mihosoft.freerouting.geometry.planar.TileShape;
|
|
import eu.mihosoft.freerouting.geometry.planar.FloatPoint;
|
|
import eu.mihosoft.freerouting.geometry.planar.FloatLine;
|
|
import eu.mihosoft.freerouting.geometry.planar.Point;
|
|
|
|
/**
|
|
* An ExpansionDoor is a common edge between two ExpansionRooms
|
|
*
|
|
*
|
|
* @author Alfons Wirtz
|
|
*/
|
|
public class ExpansionDoor implements ExpandableObject
|
|
{
|
|
|
|
/** Creates a new instance of ExpansionDoor */
|
|
public ExpansionDoor(ExpansionRoom p_first_room, ExpansionRoom p_second_room, int p_dimension)
|
|
{
|
|
first_room = p_first_room;
|
|
second_room = p_second_room;
|
|
dimension = p_dimension;
|
|
}
|
|
|
|
/** Creates a new instance of ExpansionDoor */
|
|
public ExpansionDoor(ExpansionRoom p_first_room, ExpansionRoom p_second_room)
|
|
{
|
|
first_room = p_first_room;
|
|
second_room = p_second_room;
|
|
dimension = first_room.get_shape().intersection(second_room.get_shape()).dimension();
|
|
}
|
|
|
|
/**
|
|
* Calculates the intersection of the shapes of the 2 rooms belonging to this door.
|
|
*/
|
|
@Override
|
|
public TileShape get_shape()
|
|
{
|
|
TileShape first_shape = first_room.get_shape();
|
|
TileShape second_shape = second_room.get_shape();
|
|
return first_shape.intersection(second_shape);
|
|
}
|
|
|
|
/**
|
|
* The dimension of a door may be 1 or 2.
|
|
* 2-dimensional doors can only exist between ObstacleExpansionRooms
|
|
*/
|
|
@Override
|
|
public int get_dimension()
|
|
{
|
|
return this.dimension;
|
|
}
|
|
|
|
/**
|
|
* Returns the other room of this door, or null, if p_roon
|
|
* is neither equal to this.first_room nor to this.second_room.
|
|
*/
|
|
public ExpansionRoom other_room(ExpansionRoom p_room)
|
|
{
|
|
ExpansionRoom result;
|
|
if (p_room == first_room)
|
|
{
|
|
result = second_room;
|
|
}
|
|
else if (p_room == second_room)
|
|
{
|
|
result = first_room;
|
|
}
|
|
else
|
|
{
|
|
result = null;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Returns the other room of this door, or null, if p_roon
|
|
* is neither equal to this.first_room nor to this.second_room,
|
|
* or if the other room is not a CompleteExpansionRoom.
|
|
*/
|
|
public CompleteExpansionRoom other_room(CompleteExpansionRoom p_room)
|
|
{
|
|
ExpansionRoom result;
|
|
if (p_room == first_room)
|
|
{
|
|
result = second_room;
|
|
}
|
|
else if (p_room == second_room)
|
|
{
|
|
result = first_room;
|
|
}
|
|
else
|
|
{
|
|
result = null;
|
|
}
|
|
if (!(result instanceof CompleteExpansionRoom))
|
|
{
|
|
result = null;
|
|
}
|
|
return (CompleteExpansionRoom) result;
|
|
}
|
|
|
|
public int maze_search_element_count()
|
|
{
|
|
return this.section_arr.length;
|
|
}
|
|
|
|
public MazeSearchElement get_maze_search_element(int p_no)
|
|
{
|
|
return this.section_arr[p_no];
|
|
}
|
|
|
|
/**
|
|
* Calculates the Line segments of the sections of this door.
|
|
*/
|
|
public FloatLine[] get_section_segments(double p_offset)
|
|
{
|
|
double offset = p_offset + AutorouteEngine.TRACE_WIDTH_TOLERANCE;
|
|
TileShape door_shape = this.get_shape();
|
|
{
|
|
if (door_shape.is_empty())
|
|
{
|
|
return new FloatLine[0];
|
|
}
|
|
}
|
|
FloatLine door_line_segment;
|
|
FloatLine shrinked_line_segment;
|
|
if (this.dimension == 1)
|
|
{
|
|
door_line_segment = door_shape.diagonal_corner_segment();
|
|
shrinked_line_segment = door_line_segment.shrink_segment(offset);
|
|
}
|
|
else if (this.dimension == 2 && this.first_room instanceof CompleteFreeSpaceExpansionRoom && this.second_room instanceof CompleteFreeSpaceExpansionRoom)
|
|
{
|
|
// Overlapping doors at a corner possible in case of 90- or 45-degree routing.
|
|
// In case of freeangle routing the corners are cut off.
|
|
door_line_segment = calc_door_line_segment(door_shape);
|
|
if (door_line_segment == null)
|
|
{
|
|
// CompleteFreeSpaceExpansionRoom inside other room
|
|
return new FloatLine[0];
|
|
}
|
|
if (door_line_segment.b.distance_square(door_line_segment.a) < 4 * offset * offset)
|
|
{
|
|
// door is small, 2 dimensional small doors are not yet expanded.
|
|
return new FloatLine[0];
|
|
}
|
|
shrinked_line_segment = door_line_segment.shrink_segment(offset);
|
|
}
|
|
else
|
|
{
|
|
FloatPoint gravity_point = door_shape.centre_of_gravity();
|
|
door_line_segment = new FloatLine(gravity_point, gravity_point);
|
|
shrinked_line_segment = door_line_segment;
|
|
}
|
|
final double c_max_door_section_width = 10 * offset;
|
|
int section_count = (int) (door_line_segment.b.distance(door_line_segment.a) / c_max_door_section_width) + 1;
|
|
this.allocate_sections(section_count);
|
|
FloatLine[] result = shrinked_line_segment.divide_segment_into_sections(section_count);
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Calculates a diagonal line of the 2-dimensional p_door_shape which represents the restraint line
|
|
* between the shapes of this.first_room and this.second_room.
|
|
*/
|
|
private FloatLine calc_door_line_segment(TileShape p_door_shape)
|
|
{
|
|
TileShape first_room_shape = this.first_room.get_shape();
|
|
TileShape second_room_shape = this.second_room.get_shape();
|
|
Point first_corner = null;
|
|
Point second_corner = null;
|
|
int corner_count = p_door_shape.border_line_count();
|
|
for (int i = 0; i < corner_count; ++i)
|
|
{
|
|
Point curr_corner = p_door_shape.corner(i);
|
|
if (!first_room_shape.contains_inside(curr_corner) && !second_room_shape.contains_inside(curr_corner))
|
|
{
|
|
// curr_corner is on the border of both room shapes.
|
|
if (first_corner == null)
|
|
{
|
|
first_corner = curr_corner;
|
|
}
|
|
else if (second_corner == null && !first_corner.equals(curr_corner))
|
|
{
|
|
second_corner = curr_corner;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if (first_corner == null || second_corner == null)
|
|
{
|
|
return null;
|
|
}
|
|
return new FloatLine(first_corner.to_float(), second_corner.to_float());
|
|
}
|
|
|
|
/**
|
|
* Resets this ExpandableObject for autorouting the next connection.
|
|
*/
|
|
public void reset()
|
|
{
|
|
if (section_arr != null)
|
|
{
|
|
for (MazeSearchElement curr_section : section_arr)
|
|
{
|
|
curr_section.reset();
|
|
}
|
|
}
|
|
}
|
|
|
|
/** allocates and initialises p_section_count sections */
|
|
void allocate_sections(int p_section_count)
|
|
{
|
|
if (section_arr != null && section_arr.length == p_section_count)
|
|
{
|
|
return; // already allocated
|
|
}
|
|
section_arr = new MazeSearchElement[p_section_count];
|
|
for (int i = 0; i < section_arr.length; ++i)
|
|
{
|
|
section_arr[i] = new MazeSearchElement();
|
|
}
|
|
}
|
|
/** each section of the following arrray can be expanded seperately by the maze search algorithm */
|
|
MazeSearchElement[] section_arr = null;
|
|
/** The first room of this door. */
|
|
public final ExpansionRoom first_room;
|
|
/** The second room of this door. */
|
|
public final ExpansionRoom second_room;
|
|
/**
|
|
* The dimension of a door may be 1 or 2.
|
|
*/
|
|
public final int dimension;
|
|
}
|