216 lines
7.6 KiB
Java
216 lines
7.6 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.
|
|
*
|
|
* Connection.java
|
|
*
|
|
* Created on 4. Juni 2006, 07:24
|
|
*
|
|
*/
|
|
|
|
package eu.mihosoft.freerouting.autoroute;
|
|
|
|
import java.util.Collection;
|
|
import java.util.Set;
|
|
import java.util.TreeSet;
|
|
|
|
import eu.mihosoft.freerouting.geometry.planar.Point;
|
|
|
|
import eu.mihosoft.freerouting.board.Item;
|
|
import eu.mihosoft.freerouting.board.Trace;
|
|
|
|
/**
|
|
* Describes a routing connection ending at the next fork or terminal item.
|
|
*
|
|
* @author Alfons Wirtz
|
|
*/
|
|
public class Connection
|
|
{
|
|
|
|
/**
|
|
* Gets the connection this item belongs to. A connection ends at the next fork or terminal item.
|
|
* Returns null, if p_item is not a route item, or if it is a via belonging to more than 1 connection.
|
|
*/
|
|
public static Connection get(Item p_item)
|
|
{
|
|
if (!p_item.is_route())
|
|
{
|
|
return null;
|
|
}
|
|
Connection precalculated_connection = p_item.get_autoroute_info().get_precalculated_connection();
|
|
if (precalculated_connection != null)
|
|
{
|
|
return precalculated_connection;
|
|
}
|
|
Set<Item> contacts = p_item.get_normal_contacts();
|
|
Set<Item> connection_items = new TreeSet<Item>();
|
|
connection_items.add(p_item);
|
|
|
|
Point start_point = null;
|
|
int start_layer = 0;
|
|
Point end_point = null;
|
|
int end_layer = 0;
|
|
|
|
for (Item curr_item : contacts)
|
|
{
|
|
Point prev_contact_point = p_item.normal_contact_point(curr_item);
|
|
if (prev_contact_point == null)
|
|
{
|
|
// no unique contact point
|
|
continue;
|
|
}
|
|
int prev_contact_layer = p_item.first_common_layer(curr_item);
|
|
boolean fork_found = false;
|
|
if (p_item instanceof Trace)
|
|
{
|
|
// Check, that there is only 1 contact at this location.
|
|
// Only for pins and vias items of more than 1 connection
|
|
// are collected
|
|
Trace start_trace = (Trace) p_item;
|
|
Collection<Item> check_contacts = start_trace.get_normal_contacts(prev_contact_point, false);
|
|
if (check_contacts.size() != 1)
|
|
{
|
|
fork_found = true;
|
|
}
|
|
}
|
|
// Search from curr_item along the contacts
|
|
// until the next fork or nonroute item.
|
|
for (;;)
|
|
{
|
|
if(!curr_item.is_route() || fork_found)
|
|
{
|
|
// connection ends
|
|
if (start_point == null)
|
|
{
|
|
start_point = prev_contact_point;
|
|
start_layer = prev_contact_layer;
|
|
}
|
|
else if (!prev_contact_point.equals(start_point))
|
|
{
|
|
end_point = prev_contact_point;
|
|
end_layer = prev_contact_layer;
|
|
}
|
|
break;
|
|
}
|
|
connection_items.add(curr_item);
|
|
Collection<Item> curr_item_contacts = curr_item.get_normal_contacts();
|
|
// filter the contacts at the previous contact point,
|
|
// because we were already there.
|
|
// If then there is not exactly 1 new contact left, there is
|
|
// a stub or a fork.
|
|
Point next_contact_point = null;
|
|
int next_contact_layer = -1;
|
|
Item next_contact = null;
|
|
for (Item tmp_contact : curr_item_contacts)
|
|
{
|
|
int tmp_contact_layer = curr_item.first_common_layer(tmp_contact);
|
|
if (tmp_contact_layer >= 0)
|
|
{
|
|
Point tmp_contact_point = curr_item.normal_contact_point(tmp_contact);
|
|
if (tmp_contact_point == null)
|
|
{
|
|
// no unique contact point
|
|
fork_found = true;
|
|
break;
|
|
}
|
|
if (prev_contact_layer != tmp_contact_layer ||
|
|
!prev_contact_point.equals(tmp_contact_point))
|
|
{
|
|
next_contact_point = tmp_contact_point;
|
|
next_contact_layer = tmp_contact_layer;
|
|
if (next_contact != null)
|
|
{
|
|
// second new contact found
|
|
fork_found = true;
|
|
break;
|
|
}
|
|
next_contact = tmp_contact;
|
|
}
|
|
}
|
|
}
|
|
if (next_contact == null)
|
|
{
|
|
break;
|
|
}
|
|
curr_item = next_contact;
|
|
prev_contact_point = next_contact_point;
|
|
prev_contact_layer = next_contact_layer;
|
|
}
|
|
}
|
|
Connection result = new Connection(start_point, start_layer, end_point, end_layer, connection_items);
|
|
for (Item curr_item : connection_items)
|
|
{
|
|
curr_item.get_autoroute_info().set_precalculated_connection(result);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Creates a new instance of Connection
|
|
*/
|
|
private Connection(Point p_start_point, int p_start_layer, Point p_end_point, int p_end_layer, Set<Item> p_item_list)
|
|
{
|
|
start_point = p_start_point;
|
|
start_layer = p_start_layer;
|
|
end_point = p_end_point;
|
|
end_layer = p_end_layer;
|
|
item_list = p_item_list;
|
|
}
|
|
|
|
/**
|
|
* Returns the cumulative length of the traces in this connection.
|
|
*/
|
|
public double trace_length()
|
|
{
|
|
double result = 0;
|
|
for (Item curr_item : item_list)
|
|
{
|
|
if (curr_item instanceof Trace)
|
|
{
|
|
result += ((Trace) curr_item).get_length();
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
|
|
/**
|
|
* Returns an estimation of the actual length of the connection divided by the minimal possible length.
|
|
*/
|
|
public double get_detour()
|
|
{
|
|
if (start_point == null || end_point == null)
|
|
{
|
|
return Integer.MAX_VALUE;
|
|
}
|
|
double min_trace_length = start_point.to_float().distance(end_point.to_float());
|
|
double detour = (this.trace_length() + DETOUR_ADD) / (min_trace_length + DETOUR_ADD) +
|
|
DETOUR_ITEM_COST * (item_list.size() - 1);
|
|
return detour;
|
|
}
|
|
|
|
|
|
/**
|
|
* If the connection ens in empty space, start_point or end_point may be null.
|
|
*/
|
|
public final Point start_point;
|
|
public final int start_layer;
|
|
public final Point end_point;
|
|
public final int end_layer;
|
|
public final Set<Item> item_list;
|
|
|
|
private static final double DETOUR_ADD = 100;
|
|
private static final double DETOUR_ITEM_COST = 0.1;
|
|
}
|