freerouting/src/main/java/eu/mihosoft/freerouting/autoroute/DestinationDistance.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;
}