freerouting/src/main/java/eu/mihosoft/freerouting/autoroute/LocateFoundConnectionAlgo45...

340 lines
13 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.
*
* LocateFoundConnectionAlgo45Degree.java
*
* Created on 1. Februar 2006, 07:43
*
*/
package eu.mihosoft.freerouting.autoroute;
import java.util.Collection;
import java.util.LinkedList;
import java.util.SortedSet;
import eu.mihosoft.freerouting.datastructures.Signum;
import eu.mihosoft.freerouting.geometry.planar.FloatPoint;
import eu.mihosoft.freerouting.geometry.planar.FloatLine;
import eu.mihosoft.freerouting.geometry.planar.TileShape;
import eu.mihosoft.freerouting.geometry.planar.IntBox;
import eu.mihosoft.freerouting.geometry.planar.Simplex;
import eu.mihosoft.freerouting.board.ShapeSearchTree;
import eu.mihosoft.freerouting.board.AngleRestriction;
import eu.mihosoft.freerouting.board.Item;
import eu.mihosoft.freerouting.board.TestLevel;
/**
*
* @author Alfons Wirtz
*/
public class LocateFoundConnectionAlgo45Degree extends LocateFoundConnectionAlgo
{
/**
* Creates a new instance of LocateFoundConnectionAlgo45Degree
*/
public LocateFoundConnectionAlgo45Degree(MazeSearchAlgo.Result p_maze_search_result,
AutorouteControl p_ctrl, ShapeSearchTree p_search_tree, AngleRestriction p_angle_restriction,
SortedSet<Item> p_ripped_item_list, TestLevel p_test_level)
{
super(p_maze_search_result, p_ctrl, p_search_tree, p_angle_restriction, p_ripped_item_list, p_test_level);
}
protected Collection<FloatPoint> calculate_next_trace_corners()
{
Collection<FloatPoint> result = new LinkedList<FloatPoint>();
if (this.current_to_door_index > this.current_target_door_index)
{
return result;
}
BacktrackElement curr_from_info = this.backtrack_array[this.current_to_door_index - 1];
if (curr_from_info.next_room == null)
{
System.out.println("LocateFoundConnectionAlgo45Degree.calculate_next_trace_corners: next_room is null");
return result;
}
TileShape room_shape = curr_from_info.next_room.get_shape();
int trace_halfwidth = this.ctrl.compensated_trace_half_width[this.current_trace_layer];
int trace_halfwidth_add = trace_halfwidth + AutorouteEngine.TRACE_WIDTH_TOLERANCE; // add some tolerance for free space expansion rooms.
int shrink_offset;
if (curr_from_info.next_room instanceof ObstacleExpansionRoom)
{
shrink_offset = trace_halfwidth;
}
else
{
shrink_offset = trace_halfwidth_add;
}
TileShape shrinked_room_shape = (TileShape) room_shape.offset(-shrink_offset);
if (!shrinked_room_shape.is_empty())
{
// enter the shrinked room shape by a 45 degree angle first
FloatPoint nearest_room_point = shrinked_room_shape.nearest_point_approx(this.current_from_point);
boolean horizontal_first =
calc_horizontal_first_from_door(curr_from_info.door, this.current_from_point, nearest_room_point);
nearest_room_point = round_to_integer(nearest_room_point);
result.add(calculate_additional_corner(this.current_from_point, nearest_room_point,
horizontal_first, this.angle_restriction));
result.add(nearest_room_point);
this.current_from_point = nearest_room_point;
}
else
{
shrinked_room_shape = room_shape;
}
if (this.current_to_door_index == this.current_target_door_index)
{
FloatPoint nearest_point = this.current_target_shape.nearest_point_approx(this.current_from_point);
nearest_point = round_to_integer(nearest_point);
FloatPoint add_corner = calculate_additional_corner(this.current_from_point, nearest_point, true, this.angle_restriction);
if (!shrinked_room_shape.contains(add_corner))
{
add_corner = calculate_additional_corner(this.current_from_point, nearest_point, false, this.angle_restriction);
}
result.add(add_corner);
result.add(nearest_point);
++this.current_to_door_index;
return result;
}
BacktrackElement curr_to_info = this.backtrack_array[this.current_to_door_index];
if (!(curr_to_info.door instanceof ExpansionDoor))
{
System.out.println("LocateFoundConnectionAlgo45Degree.calculate_next_trace_corners: ExpansionDoor expected");
return result;
}
ExpansionDoor curr_to_door = (ExpansionDoor) curr_to_info.door;
FloatPoint nearest_to_door_point;
if (curr_to_door.dimension == 2)
{
// May not happen in free angle routing mode because then corners are cut off.
TileShape to_door_shape = curr_to_door.get_shape();
TileShape shrinked_to_door_shape = (TileShape) to_door_shape.shrink(shrink_offset);
nearest_to_door_point = shrinked_to_door_shape.nearest_point_approx(this.current_from_point);
nearest_to_door_point = round_to_integer(nearest_to_door_point);
}
else
{
FloatLine[] line_sections = curr_to_door.get_section_segments(trace_halfwidth);
if (curr_to_info.section_no_of_door >= line_sections.length)
{
System.out.println("LocateFoundConnectionAlgo45Degree.calculate_next_trace_corners: line_sections inconsistent");
return result;
}
FloatLine curr_line_section = line_sections[curr_to_info.section_no_of_door];
nearest_to_door_point = curr_line_section.nearest_segment_point(this.current_from_point);
boolean nearest_to_door_point_ok = true;
if (curr_to_info.next_room != null)
{
Simplex next_room_shape = curr_to_info.next_room.get_shape().to_Simplex();
// with IntBox or IntOctagon the next calculation will not work, because they have
// border lines of lenght 0.
FloatPoint[] nearest_points = next_room_shape.nearest_border_points_approx(nearest_to_door_point, 2);
if (nearest_points.length >= 2)
{
nearest_to_door_point_ok = nearest_points[1].distance(nearest_to_door_point) >= trace_halfwidth_add;
}
}
if (!nearest_to_door_point_ok)
{
// may be the room has an acute (45 degree) angle at a corner of the door
nearest_to_door_point = curr_line_section.a.middle_point(curr_line_section.b);
}
}
nearest_to_door_point = round_to_integer(nearest_to_door_point);
boolean horizontal_first =
calc_horizontal_first_to_door(curr_to_info.door, this.current_from_point, nearest_to_door_point);
result.add(calculate_additional_corner(this.current_from_point, nearest_to_door_point,
horizontal_first, this.angle_restriction));
result.add(nearest_to_door_point);
++this.current_to_door_index;
return result;
}
private static FloatPoint round_to_integer(FloatPoint p_point)
{
return p_point.round().to_float();
}
/**
* Calculates, if the next 45-degree angle should be horizontal first when coming fromm
* p_from_point on p_from_door.
*/
private static boolean calc_horizontal_first_from_door(ExpandableObject p_from_door,
FloatPoint p_from_point, FloatPoint p_to_point)
{
TileShape door_shape = p_from_door.get_shape();
IntBox from_door_box = door_shape.bounding_box();
if (p_from_door.get_dimension() != 1)
{
return from_door_box.height() >= from_door_box.width();
}
FloatLine door_line_segment = door_shape.diagonal_corner_segment();
FloatPoint left_corner;
FloatPoint right_corner;
if (door_line_segment.a.x < door_line_segment.b.x || door_line_segment.a.x == door_line_segment.b.x
&& door_line_segment.a.y <= door_line_segment.b.y)
{
left_corner = door_line_segment.a;
right_corner = door_line_segment.b;
}
else
{
left_corner = door_line_segment.b;
right_corner = door_line_segment.a;
}
double door_dx = right_corner.x - left_corner.x;
double door_dy = right_corner.y - left_corner.y;
double abs_door_dy = Math.abs(door_dy);
double door_max_width = Math.max(door_dx, abs_door_dy);
boolean result;
double door_half_max_width = 0.5 * door_max_width;
if (from_door_box.width() <= door_half_max_width)
{
// door is about vertical
result = true;
}
else if (from_door_box.height() <= door_half_max_width)
{
// door is about horizontal
result = false;
}
else
{
double dx = p_to_point.x - p_from_point.x;
double dy = p_to_point.y - p_from_point.y;
if (left_corner.y < right_corner.y)
{
// door is about right diagonal
if (Signum.of(dx) == Signum.of(dy))
{
result = Math.abs(dx) > Math.abs(dy);
}
else
{
result = Math.abs(dx) < Math.abs(dy);
}
}
else
{
// door is about left diagonal
if (Signum.of(dx) == Signum.of(dy))
{
result = Math.abs(dx) < Math.abs(dy);
}
else
{
result = Math.abs(dx) > Math.abs(dy);
}
}
}
return result;
}
/**
* Calculates, if the 45-degree angle to the next door shape should be horizontal first when coming fromm
* p_from_point.
*/
private boolean calc_horizontal_first_to_door(ExpandableObject p_to_door,
FloatPoint p_from_point, FloatPoint p_to_point)
{
TileShape door_shape = p_to_door.get_shape();
IntBox from_door_box = door_shape.bounding_box();
if (p_to_door.get_dimension() != 1)
{
return from_door_box.height() <= from_door_box.width();
}
FloatLine door_line_segment = door_shape.diagonal_corner_segment();
FloatPoint left_corner;
FloatPoint right_corner;
if (door_line_segment.a.x < door_line_segment.b.x || door_line_segment.a.x == door_line_segment.b.x
&& door_line_segment.a.y <= door_line_segment.b.y)
{
left_corner = door_line_segment.a;
right_corner = door_line_segment.b;
}
else
{
left_corner = door_line_segment.b;
right_corner = door_line_segment.a;
}
double door_dx = right_corner.x - left_corner.x;
double door_dy = right_corner.y - left_corner.y;
double abs_door_dy = Math.abs(door_dy);
double door_max_width = Math.max(door_dx, abs_door_dy);
boolean result;
double door_half_max_width = 0.5 * door_max_width;
if (from_door_box.width() <= door_half_max_width)
{
// door is about vertical
result = false;
}
else if (from_door_box.height() <= door_half_max_width)
{
// door is about horizontal
result = true;
}
else
{
double dx = p_to_point.x - p_from_point.x;
double dy = p_to_point.y - p_from_point.y;
if (left_corner.y < right_corner.y)
{
// door is about right diagonal
if (Signum.of(dx) == Signum.of(dy))
{
result = Math.abs(dx) < Math.abs(dy);
}
else
{
result = Math.abs(dx) > Math.abs(dy);
}
}
else
{
// door is about left diagonal
if (Signum.of(dx) == Signum.of(dy))
{
result = Math.abs(dx) > Math.abs(dy);
}
else
{
result = Math.abs(dx) < Math.abs(dy);
}
}
}
return result;
}
}