497 lines
17 KiB
Java
497 lines
17 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.
|
|
*
|
|
* DestinationDistance.java
|
|
*
|
|
* Created on 26. Januar 2004, 10:08
|
|
*/
|
|
|
|
package eu.mihosoft.freerouting.autoroute;
|
|
|
|
import eu.mihosoft.freerouting.geometry.planar.FloatPoint;
|
|
import eu.mihosoft.freerouting.geometry.planar.IntBox;
|
|
import eu.mihosoft.freerouting.autoroute.AutorouteControl.ExpansionCostFactor;
|
|
|
|
|
|
|
|
/**
|
|
* Calculation of a good lower bound for the distance between a new MazeExpansionElement
|
|
* and the destination set of the expansion.
|
|
*
|
|
* @author Alfons Wirtz
|
|
*/
|
|
public class DestinationDistance
|
|
{
|
|
|
|
/**
|
|
* Creates a new instance of DestinationDistance.
|
|
* p_trace_costs and p_layer_active are arrays of dimension layer_count.
|
|
*/
|
|
public DestinationDistance( ExpansionCostFactor [] p_trace_costs,
|
|
boolean [] p_layer_active, double p_min_normal_via_cost, double p_min_cheap_via_cost)
|
|
{
|
|
trace_costs = p_trace_costs;
|
|
layer_active = p_layer_active;
|
|
layer_count = p_layer_active.length;
|
|
min_normal_via_cost = p_min_normal_via_cost;
|
|
min_cheap_via_cost = p_min_cheap_via_cost;
|
|
int curr_active_layer_count = 0;
|
|
for (int ind = 0; ind < layer_count; ++ind)
|
|
{
|
|
if (layer_active[ind])
|
|
{
|
|
++curr_active_layer_count;
|
|
}
|
|
}
|
|
this.active_layer_count = curr_active_layer_count;
|
|
|
|
if (layer_active[0])
|
|
{
|
|
if (trace_costs[0].horizontal < trace_costs[0].vertical)
|
|
{
|
|
min_component_side_trace_cost = trace_costs[0].horizontal;
|
|
max_component_side_trace_cost = trace_costs[0].vertical;
|
|
}
|
|
else
|
|
{
|
|
min_component_side_trace_cost = trace_costs[0].vertical;
|
|
max_component_side_trace_cost = trace_costs[0].horizontal;
|
|
}
|
|
}
|
|
|
|
if (layer_active[layer_count - 1])
|
|
{
|
|
ExpansionCostFactor curr_trace_cost = trace_costs[layer_count - 1];
|
|
|
|
if (curr_trace_cost.horizontal < curr_trace_cost.vertical)
|
|
{
|
|
min_solder_side_trace_cost = curr_trace_cost.horizontal;
|
|
max_solder_side_trace_cost = curr_trace_cost.vertical;
|
|
}
|
|
else
|
|
{
|
|
min_solder_side_trace_cost = curr_trace_cost.vertical;
|
|
max_solder_side_trace_cost = curr_trace_cost.horizontal;
|
|
}
|
|
}
|
|
|
|
// Note: for inner layers we assume, that cost in preferred direction is 1
|
|
max_inner_side_trace_cost =
|
|
Math.min(max_component_side_trace_cost, max_solder_side_trace_cost);
|
|
for (int ind2 = 1; ind2 < layer_count - 1; ++ind2)
|
|
{
|
|
if (!layer_active[ind2])
|
|
{
|
|
continue;
|
|
}
|
|
double curr_max_cost = Math.max(trace_costs[ind2].horizontal, trace_costs[ind2].vertical);
|
|
|
|
max_inner_side_trace_cost = Math.min(max_inner_side_trace_cost, curr_max_cost);
|
|
}
|
|
min_component_inner_trace_cost = Math.min(min_component_side_trace_cost, max_inner_side_trace_cost);
|
|
min_solder_inner_trace_cost = Math.min(min_solder_side_trace_cost, max_inner_side_trace_cost);
|
|
min_component_solder_inner_trace_cost = Math.min(min_component_inner_trace_cost, min_solder_inner_trace_cost);
|
|
}
|
|
|
|
public void join(IntBox p_box, int p_layer)
|
|
{
|
|
if (p_layer == 0)
|
|
{
|
|
component_side_box = component_side_box.union(p_box);
|
|
component_side_box_is_empty = false;
|
|
}
|
|
else if (p_layer == layer_count - 1)
|
|
{
|
|
solder_side_box =solder_side_box.union(p_box);
|
|
solder_side_box_is_empty = false;
|
|
}
|
|
else
|
|
{
|
|
inner_side_box = inner_side_box.union(p_box);
|
|
inner_side_box_is_empty = false;
|
|
}
|
|
box_is_empty = false;
|
|
}
|
|
|
|
public double calculate(FloatPoint p_point, int p_layer)
|
|
{
|
|
return calculate( p_point.bounding_box(), p_layer);
|
|
}
|
|
|
|
public double calculate(IntBox p_box, int p_layer)
|
|
{
|
|
if (box_is_empty)
|
|
{
|
|
return Integer.MAX_VALUE;
|
|
}
|
|
|
|
double component_side_delta_x;
|
|
double component_side_delta_y;
|
|
|
|
if (p_box.ll.x > component_side_box.ur.x)
|
|
{
|
|
component_side_delta_x = p_box.ll.x - component_side_box.ur.x;
|
|
}
|
|
else if (p_box.ur.x < component_side_box.ll.x)
|
|
{
|
|
component_side_delta_x = component_side_box.ll.x - p_box.ur.x;
|
|
}
|
|
else
|
|
{
|
|
component_side_delta_x = 0;
|
|
}
|
|
|
|
if (p_box.ll.y > component_side_box.ur.y)
|
|
{
|
|
component_side_delta_y = p_box.ll.y - component_side_box.ur.y;
|
|
}
|
|
else if (p_box.ur.y < component_side_box.ll.y)
|
|
{
|
|
component_side_delta_y = component_side_box.ll.y - p_box.ur.y;
|
|
}
|
|
else
|
|
{
|
|
component_side_delta_y = 0;
|
|
}
|
|
|
|
double solder_side_delta_x;
|
|
double solder_side_delta_y;
|
|
|
|
if (p_box.ll.x > solder_side_box.ur.x)
|
|
{
|
|
solder_side_delta_x = p_box.ll.x - solder_side_box.ur.x;
|
|
}
|
|
else if (p_box.ur.x < solder_side_box.ll.x)
|
|
{
|
|
solder_side_delta_x = solder_side_box.ll.x - p_box.ur.x;
|
|
}
|
|
else
|
|
{
|
|
solder_side_delta_x = 0;
|
|
}
|
|
|
|
if (p_box.ll.y > solder_side_box.ur.y)
|
|
{
|
|
solder_side_delta_y = p_box.ll.y - solder_side_box.ur.y;
|
|
}
|
|
else if (p_box.ur.y < solder_side_box.ll.y)
|
|
{
|
|
solder_side_delta_y = solder_side_box.ll.y - p_box.ur.y;
|
|
}
|
|
else
|
|
{
|
|
solder_side_delta_y = 0;
|
|
}
|
|
|
|
double inner_side_delta_x;
|
|
double inner_side_delta_y;
|
|
|
|
if (p_box.ll.x > inner_side_box.ur.x)
|
|
{
|
|
inner_side_delta_x = p_box.ll.x - inner_side_box.ur.x;
|
|
}
|
|
else if (p_box.ur.x < inner_side_box.ll.x)
|
|
{
|
|
inner_side_delta_x = inner_side_box.ll.x - p_box.ur.x;
|
|
}
|
|
else
|
|
{
|
|
inner_side_delta_x = 0;
|
|
}
|
|
|
|
if (p_box.ll.y > inner_side_box.ur.y)
|
|
{
|
|
inner_side_delta_y = p_box.ll.y - inner_side_box.ur.y;
|
|
}
|
|
else if (p_box.ur.y < inner_side_box.ll.y)
|
|
{
|
|
inner_side_delta_y = inner_side_box.ll.y - p_box.ur.y;
|
|
}
|
|
else
|
|
{
|
|
inner_side_delta_y = 0;
|
|
}
|
|
|
|
double component_side_max_delta;
|
|
double component_side_min_delta;
|
|
|
|
if (component_side_delta_x > component_side_delta_y)
|
|
{
|
|
component_side_max_delta = component_side_delta_x;
|
|
component_side_min_delta = component_side_delta_y;
|
|
}
|
|
else
|
|
{
|
|
component_side_max_delta = component_side_delta_y;
|
|
component_side_min_delta = component_side_delta_x;
|
|
}
|
|
|
|
double solder_side_max_delta;
|
|
double solder_side_min_delta;
|
|
|
|
if (solder_side_delta_x > solder_side_delta_y)
|
|
{
|
|
solder_side_max_delta = solder_side_delta_x;
|
|
solder_side_min_delta = solder_side_delta_y;
|
|
}
|
|
else
|
|
{
|
|
solder_side_max_delta = solder_side_delta_y;
|
|
solder_side_min_delta = solder_side_delta_x;
|
|
}
|
|
|
|
double inner_side_max_delta;
|
|
double inner_side_min_delta;
|
|
|
|
if (inner_side_delta_x > inner_side_delta_y)
|
|
{
|
|
inner_side_max_delta = inner_side_delta_x;
|
|
inner_side_min_delta = inner_side_delta_y;
|
|
}
|
|
else
|
|
{
|
|
inner_side_max_delta = inner_side_delta_y;
|
|
inner_side_min_delta = inner_side_delta_x;
|
|
}
|
|
|
|
double result = Integer.MAX_VALUE;
|
|
|
|
if (p_layer == 0)
|
|
// calculate shortest distance to component side box
|
|
{
|
|
// calculate one layer distance
|
|
|
|
if (!component_side_box_is_empty)
|
|
{
|
|
result =
|
|
p_box.weighted_distance(component_side_box,
|
|
trace_costs[0].horizontal, trace_costs[0].vertical);
|
|
}
|
|
|
|
if (active_layer_count <= 1)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
// calculate two layer distance on component and solder side
|
|
|
|
double tmp_distance;
|
|
if (min_solder_side_trace_cost < min_component_side_trace_cost)
|
|
tmp_distance =
|
|
min_solder_side_trace_cost * solder_side_max_delta
|
|
+ min_component_side_trace_cost * solder_side_min_delta
|
|
+ min_normal_via_cost;
|
|
else
|
|
tmp_distance =
|
|
min_component_side_trace_cost * solder_side_max_delta
|
|
+ min_solder_side_trace_cost * solder_side_min_delta
|
|
+ min_normal_via_cost;
|
|
|
|
result = Math.min(result, tmp_distance);
|
|
|
|
// calculate two layer distance on component and solde side
|
|
// with two vias
|
|
|
|
tmp_distance = component_side_max_delta
|
|
+ component_side_min_delta * min_component_inner_trace_cost
|
|
+ 2 * min_normal_via_cost;
|
|
|
|
result = Math.min(result, tmp_distance);
|
|
|
|
if (active_layer_count <= 2)
|
|
return result;
|
|
|
|
// calculate two layer distance on component side and an inner side
|
|
|
|
tmp_distance = inner_side_max_delta +
|
|
inner_side_min_delta * min_component_inner_trace_cost +
|
|
min_normal_via_cost;
|
|
|
|
result = Math.min(result, tmp_distance);
|
|
|
|
// calculate three layer distance
|
|
|
|
tmp_distance = solder_side_max_delta +
|
|
+min_component_solder_inner_trace_cost * solder_side_min_delta
|
|
+ 2 * min_normal_via_cost;
|
|
result = Math.min(result, tmp_distance);
|
|
|
|
tmp_distance = component_side_max_delta +
|
|
component_side_min_delta + 2 * min_normal_via_cost;
|
|
result = Math.min(result, tmp_distance);
|
|
|
|
if (active_layer_count <= 3)
|
|
return result;
|
|
|
|
tmp_distance = inner_side_max_delta + inner_side_min_delta
|
|
+ 2 * min_normal_via_cost;
|
|
|
|
result = Math.min(result, tmp_distance);
|
|
|
|
// calculate four layer distance
|
|
|
|
tmp_distance = solder_side_max_delta + solder_side_min_delta
|
|
+ 3 * min_normal_via_cost;
|
|
|
|
result = Math.min(result, tmp_distance);
|
|
|
|
return result;
|
|
}
|
|
if (p_layer == layer_count - 1)
|
|
// calculate shortest distance to solder side box
|
|
{
|
|
// calculate one layer distance
|
|
|
|
if (!solder_side_box_is_empty)
|
|
{
|
|
result =
|
|
p_box.weighted_distance(solder_side_box,
|
|
trace_costs[p_layer].horizontal, trace_costs[p_layer].vertical);
|
|
}
|
|
|
|
// calculate two layer distance
|
|
double tmp_distance;
|
|
if (min_component_side_trace_cost < min_solder_side_trace_cost)
|
|
{
|
|
tmp_distance =
|
|
min_component_side_trace_cost * component_side_max_delta
|
|
+ min_solder_side_trace_cost * component_side_min_delta
|
|
+ min_normal_via_cost;
|
|
}
|
|
else
|
|
{
|
|
tmp_distance =
|
|
min_solder_side_trace_cost * component_side_max_delta
|
|
+ min_component_side_trace_cost * component_side_min_delta
|
|
+ min_normal_via_cost;
|
|
}
|
|
result = Math.min(result, tmp_distance);
|
|
tmp_distance = solder_side_max_delta
|
|
+ solder_side_min_delta * min_solder_inner_trace_cost
|
|
+ 2 * min_normal_via_cost;
|
|
result = Math.min(result, tmp_distance);
|
|
if (active_layer_count <= 2)
|
|
{
|
|
return result;
|
|
}
|
|
tmp_distance = inner_side_min_delta * min_solder_inner_trace_cost
|
|
+ inner_side_max_delta + min_normal_via_cost;
|
|
result = Math.min(result, tmp_distance);
|
|
|
|
// calculate three layer distance
|
|
|
|
tmp_distance = component_side_max_delta +
|
|
min_component_solder_inner_trace_cost * component_side_min_delta
|
|
+ 2 * min_normal_via_cost;
|
|
result = Math.min(result, tmp_distance);
|
|
tmp_distance = solder_side_max_delta + solder_side_min_delta
|
|
+ 2 * min_normal_via_cost;
|
|
result = Math.min(result, tmp_distance);
|
|
if (active_layer_count <= 3)
|
|
return result;
|
|
tmp_distance = inner_side_max_delta + inner_side_min_delta
|
|
+ 2 * min_normal_via_cost;
|
|
result = Math.min(result, tmp_distance);
|
|
|
|
// calculate four layer distance
|
|
|
|
tmp_distance = component_side_max_delta + component_side_min_delta
|
|
+ 3 * min_normal_via_cost;
|
|
result = Math.min(result, tmp_distance);
|
|
return result;
|
|
}
|
|
|
|
// calculate distance to inner layer box
|
|
|
|
// calculate one layer distance
|
|
|
|
if (!inner_side_box_is_empty)
|
|
{
|
|
result =
|
|
p_box.weighted_distance(inner_side_box,
|
|
trace_costs[p_layer].horizontal, trace_costs[p_layer].vertical);
|
|
}
|
|
|
|
// calculate two layer distance
|
|
|
|
double tmp_distance = inner_side_max_delta + inner_side_min_delta + min_normal_via_cost;
|
|
|
|
result = Math.min(result, tmp_distance);
|
|
tmp_distance = component_side_max_delta
|
|
+ component_side_min_delta * min_component_inner_trace_cost
|
|
+ min_normal_via_cost;
|
|
result = Math.min(result, tmp_distance);
|
|
tmp_distance = solder_side_max_delta
|
|
+ solder_side_min_delta * min_solder_inner_trace_cost
|
|
+ min_normal_via_cost;
|
|
result = Math.min(result, tmp_distance);
|
|
|
|
// calculate three layer distance
|
|
|
|
tmp_distance = component_side_max_delta + component_side_min_delta
|
|
+ 2 * min_normal_via_cost;
|
|
result = Math.min(result, tmp_distance);
|
|
tmp_distance = solder_side_max_delta + solder_side_min_delta
|
|
+ 2 * min_normal_via_cost;
|
|
result = Math.min(result, tmp_distance);
|
|
|
|
return result;
|
|
}
|
|
|
|
public double calculate_cheap_distance(IntBox p_box, int p_layer)
|
|
{
|
|
double min_normal_via_cost_save = min_normal_via_cost;
|
|
|
|
min_normal_via_cost = min_cheap_via_cost;
|
|
double result = calculate(p_box, p_layer);
|
|
|
|
min_normal_via_cost = min_normal_via_cost_save;
|
|
return result;
|
|
}
|
|
|
|
|
|
|
|
|
|
private final ExpansionCostFactor [] trace_costs;
|
|
private final boolean [] layer_active;
|
|
private final int layer_count;
|
|
private final int active_layer_count;
|
|
|
|
private double min_normal_via_cost;
|
|
private double min_cheap_via_cost;
|
|
double min_component_side_trace_cost;
|
|
double max_component_side_trace_cost;
|
|
double min_solder_side_trace_cost;
|
|
double max_solder_side_trace_cost;
|
|
double max_inner_side_trace_cost;
|
|
// minimum of the maximal trace costs on each inner layer
|
|
double min_component_inner_trace_cost;
|
|
// minimum of min_component_side_trace_cost and
|
|
// max_inner_side_trace_cost
|
|
double min_solder_inner_trace_cost;
|
|
// minimum of min_solder_side_trace_cost and max_inner_side_trace_cost
|
|
double min_component_solder_inner_trace_cost;
|
|
// minimum of min_component_inner_trace_cost and
|
|
// min_solder_inner_trace_cost
|
|
private IntBox component_side_box = IntBox.EMPTY;
|
|
private IntBox solder_side_box = IntBox.EMPTY;
|
|
private IntBox inner_side_box = IntBox.EMPTY;
|
|
|
|
private boolean box_is_empty = true;
|
|
private boolean component_side_box_is_empty = true;
|
|
private boolean solder_side_box_is_empty = true;
|
|
private boolean inner_side_box_is_empty = true;
|
|
}
|