302 lines
12 KiB
Java
302 lines
12 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.
|
|
*
|
|
* ForcedViaAlgo.java
|
|
*
|
|
* Created on 25. April 2004, 09:55
|
|
*/
|
|
|
|
package eu.mihosoft.freerouting.board;
|
|
|
|
import eu.mihosoft.freerouting.geometry.planar.ConvexShape;
|
|
import eu.mihosoft.freerouting.geometry.planar.IntPoint;
|
|
import eu.mihosoft.freerouting.geometry.planar.Point;
|
|
import eu.mihosoft.freerouting.geometry.planar.FloatPoint;
|
|
import eu.mihosoft.freerouting.geometry.planar.Shape;
|
|
import eu.mihosoft.freerouting.geometry.planar.TileShape;
|
|
import eu.mihosoft.freerouting.geometry.planar.Simplex;
|
|
import eu.mihosoft.freerouting.geometry.planar.IntBox;
|
|
import eu.mihosoft.freerouting.geometry.planar.Circle;
|
|
import eu.mihosoft.freerouting.geometry.planar.Vector;
|
|
import eu.mihosoft.freerouting.geometry.planar.Limits;
|
|
import eu.mihosoft.freerouting.rules.ViaInfo;
|
|
import eu.mihosoft.freerouting.library.Padstack;
|
|
|
|
|
|
/**
|
|
* Class with static functions for checking and inserting forced vias.
|
|
*
|
|
* @author alfons
|
|
*/
|
|
public class ForcedViaAlgo
|
|
{
|
|
/**
|
|
* Checks, if a Via is possible at the input layer after evtl. shoving aside obstacle traces.
|
|
* p_room_shape is used for calculating the from_side.
|
|
*/
|
|
public static ForcedPadAlgo.CheckDrillResult check_layer(double p_via_radius, int p_cl_class, boolean p_attach_smd_allowed,
|
|
TileShape p_room_shape, Point p_location, int p_layer,
|
|
int[] p_net_no_arr, int p_max_recursion_depth,
|
|
int p_max_via_recursion_depth, RoutingBoard p_board)
|
|
{
|
|
if (p_via_radius <= 0)
|
|
{
|
|
return ForcedPadAlgo.CheckDrillResult.DRILLABLE;
|
|
}
|
|
ForcedPadAlgo forced_pad_algo = new ForcedPadAlgo(p_board);
|
|
if (!(p_location instanceof IntPoint))
|
|
{
|
|
return ForcedPadAlgo.CheckDrillResult.NOT_DRILLABLE;
|
|
}
|
|
ConvexShape via_shape = new Circle((IntPoint) p_location, (int) Math.ceil(p_via_radius));
|
|
|
|
double check_radius =
|
|
p_via_radius + 0.5 * p_board.clearance_value(p_cl_class, p_cl_class, p_layer)
|
|
+ p_board.get_min_trace_half_width();
|
|
|
|
TileShape tile_shape;
|
|
boolean is_90_degree;
|
|
if (p_board.rules.get_trace_angle_restriction() == AngleRestriction.NINETY_DEGREE)
|
|
{
|
|
tile_shape = via_shape.bounding_box();
|
|
is_90_degree = true;
|
|
}
|
|
else
|
|
{
|
|
tile_shape = via_shape.bounding_octagon();
|
|
is_90_degree = false;
|
|
}
|
|
|
|
CalcFromSide from_side = calculate_from_side(p_location.to_float(), tile_shape, p_room_shape.to_Simplex(), check_radius, is_90_degree);
|
|
if (from_side == null)
|
|
{
|
|
return ForcedPadAlgo.CheckDrillResult.NOT_DRILLABLE;
|
|
}
|
|
|
|
ForcedPadAlgo.CheckDrillResult result = forced_pad_algo.check_forced_pad(tile_shape, from_side, p_layer, p_net_no_arr,
|
|
p_cl_class, p_attach_smd_allowed, null, p_max_recursion_depth, p_max_via_recursion_depth, false, null);
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Checks, if a Via is possible with the input parameter after evtl. shoving aside obstacle traces.
|
|
*/
|
|
public static boolean check(ViaInfo p_via_info, Point p_location, int[] p_net_no_arr, int p_max_recursion_depth,
|
|
int p_max_via_recursion_depth, RoutingBoard p_board)
|
|
{
|
|
Vector translate_vector = p_location.difference_by(Point.ZERO);
|
|
int calc_from_side_offset = p_board.get_min_trace_half_width();
|
|
ForcedPadAlgo forced_pad_algo = new ForcedPadAlgo(p_board);
|
|
Padstack via_padstack = p_via_info.get_padstack();
|
|
for (int i = via_padstack.from_layer(); i <= via_padstack.to_layer(); ++i)
|
|
{
|
|
Shape curr_pad_shape = via_padstack.get_shape(i);
|
|
if (curr_pad_shape == null)
|
|
{
|
|
continue;
|
|
}
|
|
curr_pad_shape = (Shape) curr_pad_shape.translate_by(translate_vector);
|
|
TileShape tile_shape;
|
|
if (p_board.rules.get_trace_angle_restriction() == AngleRestriction.NINETY_DEGREE)
|
|
{
|
|
tile_shape = curr_pad_shape.bounding_box();
|
|
}
|
|
else
|
|
{
|
|
tile_shape = curr_pad_shape.bounding_octagon();
|
|
}
|
|
CalcFromSide from_side
|
|
= forced_pad_algo.calc_from_side(tile_shape, p_location, i, calc_from_side_offset,p_via_info.get_clearance_class());
|
|
if (forced_pad_algo.check_forced_pad(tile_shape, from_side, i, p_net_no_arr, p_via_info.get_clearance_class(),
|
|
p_via_info.attach_smd_allowed(), null, p_max_recursion_depth, p_max_via_recursion_depth, false, null)
|
|
== ForcedPadAlgo.CheckDrillResult.NOT_DRILLABLE)
|
|
{
|
|
p_board.set_shove_failing_layer(i);
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Shoves aside traces, so that a via with the input parameters can be
|
|
* inserted without clearance violations. If the shove failed, the database may be damaged, so that an undo
|
|
* becomes necessesary.
|
|
* p_trace_clearance_class_no and p_trace_pen_halfwidth_arr is provided to make space for starting a trace
|
|
* in case the trace width is bigger than the via shape.
|
|
* Returns false, if the forced via failed.
|
|
*/
|
|
public static boolean insert( ViaInfo p_via_info, Point p_location, int[] p_net_no_arr,
|
|
int p_trace_clearance_class_no, int [] p_trace_pen_halfwidth_arr, int p_max_recursion_depth,
|
|
int p_max_via_recursion_depth, RoutingBoard p_board)
|
|
{
|
|
Vector translate_vector = p_location.difference_by(Point.ZERO);
|
|
int calc_from_side_offset = p_board.get_min_trace_half_width();
|
|
ForcedPadAlgo forced_pad_algo = new ForcedPadAlgo(p_board);
|
|
Padstack via_padstack = p_via_info.get_padstack();
|
|
for (int i = via_padstack.from_layer(); i <= via_padstack.to_layer(); ++i)
|
|
{
|
|
Shape curr_pad_shape = via_padstack.get_shape(i);
|
|
if (curr_pad_shape == null)
|
|
{
|
|
continue;
|
|
}
|
|
curr_pad_shape = (Shape) curr_pad_shape.translate_by(translate_vector);
|
|
TileShape tile_shape;
|
|
Circle start_trace_circle;
|
|
if (p_trace_pen_halfwidth_arr[i] > 0 && p_location instanceof IntPoint)
|
|
{
|
|
start_trace_circle = new Circle((IntPoint) p_location, p_trace_pen_halfwidth_arr[i]);
|
|
}
|
|
else
|
|
{
|
|
start_trace_circle = null;
|
|
}
|
|
TileShape start_trace_shape = null;
|
|
if (p_board.rules.get_trace_angle_restriction() == AngleRestriction.NINETY_DEGREE)
|
|
{
|
|
tile_shape = curr_pad_shape.bounding_box();
|
|
if (start_trace_circle != null)
|
|
{
|
|
start_trace_shape = start_trace_circle.bounding_box();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
tile_shape = curr_pad_shape.bounding_octagon();
|
|
if (start_trace_circle != null)
|
|
{
|
|
start_trace_shape = start_trace_circle.bounding_octagon();
|
|
}
|
|
}
|
|
CalcFromSide from_side
|
|
= forced_pad_algo.calc_from_side(tile_shape, p_location, i, calc_from_side_offset,p_via_info.get_clearance_class());
|
|
if (!forced_pad_algo.forced_pad(tile_shape, from_side, i, p_net_no_arr, p_via_info.get_clearance_class(),
|
|
p_via_info.attach_smd_allowed(), null, p_max_recursion_depth, p_max_via_recursion_depth))
|
|
{
|
|
p_board.set_shove_failing_layer(i);
|
|
return false;
|
|
}
|
|
if (start_trace_shape != null)
|
|
{
|
|
// necessesary in case strart_trace_shape is bigger than tile_shape
|
|
if (!forced_pad_algo.forced_pad(start_trace_shape, from_side, i, p_net_no_arr, p_trace_clearance_class_no,
|
|
true, null, p_max_recursion_depth, p_max_via_recursion_depth))
|
|
{
|
|
p_board.set_shove_failing_layer(i);
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
p_board.insert_via(via_padstack, p_location, p_net_no_arr, p_via_info.get_clearance_class(),
|
|
FixedState.UNFIXED, p_via_info.attach_smd_allowed());
|
|
return true;
|
|
}
|
|
|
|
static private CalcFromSide calculate_from_side(FloatPoint p_via_location, TileShape p_via_shape, Simplex p_room_shape, double p_dist, boolean is_90_degree)
|
|
{
|
|
IntBox via_box = p_via_shape.bounding_box();
|
|
for (int i = 0; i < 4; ++i)
|
|
{
|
|
FloatPoint check_point;
|
|
double border_x;
|
|
double border_y;
|
|
if (i == 0)
|
|
{
|
|
check_point = new FloatPoint(p_via_location.x, p_via_location.y - p_dist);
|
|
border_x = p_via_location.x;
|
|
border_y = via_box.ll.y;
|
|
}
|
|
else if (i == 1)
|
|
{
|
|
check_point = new FloatPoint(p_via_location.x + p_dist, p_via_location.y);
|
|
border_x = via_box.ur.x;
|
|
border_y = p_via_location.y;
|
|
}
|
|
else if (i == 2)
|
|
{
|
|
check_point = new FloatPoint(p_via_location.x, p_via_location.y + p_dist);
|
|
border_x = p_via_location.x;
|
|
border_y = via_box.ur.y;
|
|
}
|
|
else // i == 3
|
|
{
|
|
check_point = new FloatPoint(p_via_location.x - p_dist, p_via_location.y);
|
|
border_x = via_box.ll.x;
|
|
border_y = p_via_location.y;
|
|
}
|
|
if (p_room_shape.contains(check_point))
|
|
{
|
|
int from_side_no;
|
|
if (is_90_degree)
|
|
{
|
|
from_side_no = i;
|
|
}
|
|
else
|
|
{
|
|
from_side_no = 2 * i;
|
|
}
|
|
FloatPoint curr_border_point = new FloatPoint(border_x, border_y);
|
|
return new CalcFromSide(from_side_no, curr_border_point);
|
|
}
|
|
}
|
|
if (is_90_degree)
|
|
{
|
|
return null;
|
|
}
|
|
// try the diagonal drections
|
|
double dist = p_dist / Limits.sqrt2;
|
|
double border_dist = via_box.max_width() / (2 * Limits.sqrt2);
|
|
for (int i = 0; i < 4; ++i)
|
|
{
|
|
FloatPoint check_point;
|
|
double border_x;
|
|
double border_y;
|
|
if (i == 0)
|
|
{
|
|
check_point = new FloatPoint(p_via_location.x + dist, p_via_location.y - dist);
|
|
border_x = p_via_location.x + border_dist;
|
|
border_y = p_via_location.y - border_dist;
|
|
}
|
|
else if (i == 1)
|
|
{
|
|
check_point = new FloatPoint(p_via_location.x + dist, p_via_location.y + dist);
|
|
border_x = p_via_location.x + border_dist;
|
|
border_y = p_via_location.y + border_dist;
|
|
}
|
|
else if (i == 2)
|
|
{
|
|
check_point = new FloatPoint(p_via_location.x - dist, p_via_location.y + dist);
|
|
border_x = p_via_location.x - border_dist;
|
|
border_y = p_via_location.y + border_dist;
|
|
}
|
|
else // i == 3
|
|
{
|
|
check_point = new FloatPoint(p_via_location.x - dist, p_via_location.y - dist);
|
|
border_x = p_via_location.x - border_dist;
|
|
border_y = p_via_location.y - border_dist;
|
|
}
|
|
if (p_room_shape.contains(check_point))
|
|
{
|
|
|
|
int from_side_no = 2 * i + 1;
|
|
FloatPoint curr_border_point = new FloatPoint(border_x, border_y);
|
|
return new CalcFromSide(from_side_no, curr_border_point);
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
}
|