814 lines
30 KiB
Java
814 lines
30 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.
|
|
*
|
|
* Pin.java
|
|
*
|
|
* Created on 6. Juni 2003, 08:04
|
|
*/
|
|
|
|
package eu.mihosoft.freerouting.board;
|
|
|
|
|
|
import eu.mihosoft.freerouting.geometry.planar.Point;
|
|
import eu.mihosoft.freerouting.geometry.planar.IntPoint;
|
|
import eu.mihosoft.freerouting.geometry.planar.Shape;
|
|
import eu.mihosoft.freerouting.geometry.planar.ConvexShape;
|
|
import eu.mihosoft.freerouting.geometry.planar.TileShape;
|
|
import eu.mihosoft.freerouting.geometry.planar.Vector;
|
|
import eu.mihosoft.freerouting.geometry.planar.Direction;
|
|
import eu.mihosoft.freerouting.geometry.planar.Line;
|
|
import eu.mihosoft.freerouting.geometry.planar.Polyline;
|
|
import eu.mihosoft.freerouting.geometry.planar.FloatPoint;
|
|
|
|
import eu.mihosoft.freerouting.library.Package;
|
|
import eu.mihosoft.freerouting.library.Padstack;
|
|
|
|
/**
|
|
* Class describing the functionality of an electrical Item on the eu.mihosoft.freerouting.board
|
|
* with a shape on 1 or several layers.
|
|
*
|
|
* @author Alfons Wirtz
|
|
*/
|
|
public class Pin extends DrillItem implements java.io.Serializable
|
|
{
|
|
/** Creates a new instance of Pin with the input parameters.
|
|
* (p_to_layer - p_from_layer + 1) shapes must be provided.
|
|
* p_pin_no isthe number of the pin in its component (starting with 0).
|
|
*/
|
|
Pin(int p_component_no, int p_pin_no, int[] p_net_no_arr, int p_clearance_type, int p_id_no,
|
|
FixedState p_fixed_state, BasicBoard p_board)
|
|
{
|
|
super(null, p_net_no_arr, p_clearance_type, p_id_no, p_component_no, p_fixed_state, p_board);
|
|
|
|
this.pin_no = p_pin_no;
|
|
}
|
|
|
|
/**
|
|
* Calculates the relative location of this pin to its component.
|
|
*/
|
|
public Vector relative_location()
|
|
{
|
|
Component component = board.components.get(this.get_component_no());
|
|
Package lib_package = component.get_package();
|
|
Package.Pin package_pin = lib_package.get_pin(this.pin_no);
|
|
Vector rel_location = package_pin.relative_location;
|
|
double component_rotation = component.get_rotation_in_degree();
|
|
if (!component.placed_on_front() && !board.components.get_flip_style_rotate_first())
|
|
{
|
|
rel_location = package_pin.relative_location.mirror_at_y_axis();
|
|
}
|
|
if (component_rotation % 90 == 0)
|
|
{
|
|
int component_ninety_degree_factor = ((int) component_rotation )/ 90;
|
|
if (component_ninety_degree_factor != 0)
|
|
{
|
|
rel_location = rel_location.turn_90_degree(component_ninety_degree_factor);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// rotation may be not exact
|
|
FloatPoint location_approx = rel_location.to_float();
|
|
location_approx = location_approx.rotate(Math.toRadians(component_rotation), FloatPoint.ZERO);
|
|
rel_location = location_approx.round().difference_by(Point.ZERO);
|
|
}
|
|
if (!component.placed_on_front() && board.components.get_flip_style_rotate_first())
|
|
{
|
|
rel_location = rel_location.mirror_at_y_axis();
|
|
}
|
|
return rel_location;
|
|
}
|
|
|
|
|
|
public Point get_center()
|
|
{
|
|
Point pin_center = super.get_center();
|
|
if (pin_center == null)
|
|
{
|
|
|
|
// Calculate the pin center.
|
|
Component component = board.components.get(this.get_component_no());
|
|
pin_center = component.get_location().translate_by(this.relative_location());
|
|
|
|
// check that the pin center is inside the pin shape and correct it eventually
|
|
|
|
Padstack padstack = get_padstack();
|
|
int from_layer = padstack.from_layer();
|
|
int to_layer = padstack.to_layer();
|
|
Shape curr_shape = null;
|
|
for (int i = 0; i < to_layer - from_layer + 1; ++i)
|
|
{
|
|
curr_shape = this.get_shape(i);
|
|
if (curr_shape != null)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
if (curr_shape == null)
|
|
{
|
|
System.out.println("Pin: At least 1 shape != null expected");
|
|
}
|
|
else if (!curr_shape.contains_inside(pin_center))
|
|
{
|
|
pin_center = curr_shape.centre_of_gravity().round();
|
|
}
|
|
this.set_center(pin_center);
|
|
}
|
|
return pin_center;
|
|
}
|
|
|
|
public Padstack get_padstack()
|
|
{
|
|
Component component = board.components.get(get_component_no());
|
|
if (component == null)
|
|
{
|
|
System.out.println("Pin.get_padstack; component not found");
|
|
return null;
|
|
}
|
|
int padstack_no = component.get_package().get_pin(pin_no).padstack_no;
|
|
return board.library.padstacks.get(padstack_no);
|
|
}
|
|
|
|
public Item copy(int p_id_no)
|
|
{
|
|
int [] curr_net_no_arr = new int [this.net_count()];
|
|
for (int i = 0; i < curr_net_no_arr.length; ++i)
|
|
{
|
|
curr_net_no_arr[i] = get_net_no(i);
|
|
}
|
|
return new Pin(get_component_no(), this.pin_no, curr_net_no_arr, clearance_class_no(),
|
|
p_id_no, get_fixed_state(), board);
|
|
}
|
|
|
|
/**
|
|
* Return the name of this pin in the package of this component.
|
|
*/
|
|
public String name()
|
|
{
|
|
Component component = board.components.get(this.get_component_no());
|
|
if (component == null)
|
|
{
|
|
System.out.println("Pin.name: component not found");
|
|
return null;
|
|
}
|
|
return component.get_package().get_pin(pin_no).name;
|
|
}
|
|
|
|
/**
|
|
* Gets index of this pin in the eu.mihosoft.freerouting.library package of the pins component.
|
|
*/
|
|
public int get_index_in_package()
|
|
{
|
|
return pin_no;
|
|
}
|
|
|
|
public Shape get_shape(int p_index)
|
|
{
|
|
Padstack padstack = get_padstack();
|
|
if (this.precalculated_shapes == null)
|
|
{
|
|
// all shapes have to be calculated at once, because otherwise calculation
|
|
// of from_layer and to_layer may not be correct
|
|
this.precalculated_shapes = new Shape[padstack.to_layer() - padstack.from_layer() + 1];
|
|
|
|
Component component = board.components.get(this.get_component_no());
|
|
if (component == null)
|
|
{
|
|
System.out.println("Pin.get_shape: component not found");
|
|
return null;
|
|
}
|
|
Package lib_package = component.get_package();
|
|
if (lib_package == null)
|
|
{
|
|
System.out.println("Pin.get_shape: package not found");
|
|
return null;
|
|
}
|
|
Package.Pin package_pin = lib_package.get_pin(this.pin_no);
|
|
if (package_pin == null)
|
|
{
|
|
System.out.println("Pin.get_shape: pin_no out of range");
|
|
return null;
|
|
}
|
|
Vector rel_location = package_pin.relative_location;
|
|
double component_rotation = component.get_rotation_in_degree();
|
|
|
|
boolean mirror_at_y_axis = !component.placed_on_front() && !board.components.get_flip_style_rotate_first();
|
|
|
|
if (mirror_at_y_axis)
|
|
{
|
|
rel_location = package_pin.relative_location.mirror_at_y_axis();
|
|
}
|
|
|
|
Vector component_translation = component.get_location().difference_by(Point.ZERO);
|
|
|
|
for (int index = 0; index < this.precalculated_shapes.length; ++index)
|
|
{
|
|
|
|
int padstack_layer = get_padstack_layer(index);
|
|
|
|
ConvexShape curr_shape = padstack.get_shape(padstack_layer);
|
|
if (curr_shape == null)
|
|
{
|
|
continue;
|
|
}
|
|
double pin_rotation = package_pin.rotation_in_degree;
|
|
if (pin_rotation % 90 == 0)
|
|
{
|
|
int pin_ninety_degree_factor = ((int) pin_rotation)/ 90;
|
|
if (pin_ninety_degree_factor!= 0)
|
|
{
|
|
curr_shape = (ConvexShape) curr_shape.turn_90_degree(pin_ninety_degree_factor, Point.ZERO);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
curr_shape = (ConvexShape) curr_shape.rotate_approx(Math.toRadians(pin_rotation), FloatPoint.ZERO);
|
|
}
|
|
|
|
if (mirror_at_y_axis)
|
|
{
|
|
curr_shape = (ConvexShape) curr_shape.mirror_vertical(Point.ZERO);
|
|
}
|
|
|
|
// translate the shape first relative to the component
|
|
ConvexShape translated_shape = (ConvexShape) curr_shape.translate_by(rel_location);
|
|
|
|
if (component_rotation % 90 == 0)
|
|
{
|
|
int component_ninety_degree_factor = ((int) component_rotation )/ 90;
|
|
if (component_ninety_degree_factor != 0)
|
|
{
|
|
translated_shape = (ConvexShape) translated_shape.turn_90_degree(component_ninety_degree_factor, Point.ZERO);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
translated_shape = (ConvexShape) translated_shape.rotate_approx(Math.toRadians(component_rotation), FloatPoint.ZERO);
|
|
}
|
|
if (!component.placed_on_front() && board.components.get_flip_style_rotate_first())
|
|
{
|
|
translated_shape = (ConvexShape) translated_shape.mirror_vertical(Point.ZERO);
|
|
}
|
|
this.precalculated_shapes[index] = (ConvexShape) translated_shape.translate_by(component_translation);
|
|
}
|
|
|
|
}
|
|
return this.precalculated_shapes[p_index];
|
|
}
|
|
|
|
/**
|
|
* Returns the layer of the padstack shape corresponding to the shape with index p_index.
|
|
*/
|
|
int get_padstack_layer(int p_index)
|
|
{
|
|
Padstack padstack = get_padstack();
|
|
Component component = board.components.get(this.get_component_no());
|
|
int padstack_layer;
|
|
if (component.placed_on_front() || padstack.placed_absolute)
|
|
{
|
|
padstack_layer = p_index + this.first_layer();
|
|
}
|
|
else
|
|
{
|
|
padstack_layer = padstack.board_layer_count() - p_index - this.first_layer() - 1;
|
|
}
|
|
return padstack_layer;
|
|
}
|
|
|
|
/**
|
|
* Calculates the allowed trace exit directions of the shape of this padstack on layer p_layer
|
|
* together with the minimal trace line lengths into thei directions.
|
|
* Currently only implemented only for box shapes, where traces are allowed to exit
|
|
* the pad only on the small sides.
|
|
*/
|
|
public java.util.Collection<TraceExitRestriction> get_trace_exit_restrictions(int p_layer)
|
|
{
|
|
java.util.Collection<TraceExitRestriction> result = new java.util.LinkedList<TraceExitRestriction>();
|
|
int padstack_layer = this.get_padstack_layer(p_layer - this.first_layer());
|
|
double pad_xy_factor = 1.5;
|
|
// setting 1.5 to a higher factor may hinder the shove algorithm of the autorouter between
|
|
// the pins of SMD components, because the channels can get blocked by the shove_fixed stubs.
|
|
|
|
Component component = board.components.get(this.get_component_no());
|
|
if (component != null)
|
|
{
|
|
if (component.get_package().pin_count() <= 3)
|
|
{
|
|
pad_xy_factor *= 2; // allow connection to the longer side also for shorter pads.
|
|
}
|
|
}
|
|
|
|
java.util.Collection<Direction> padstack_exit_directions =
|
|
this.get_padstack().get_trace_exit_directions(padstack_layer, pad_xy_factor );
|
|
if (padstack_exit_directions.isEmpty())
|
|
{
|
|
return result;
|
|
}
|
|
|
|
if (component == null)
|
|
{
|
|
return result;
|
|
}
|
|
Shape curr_shape = this.get_shape(p_layer - this.first_layer());
|
|
if (curr_shape == null || !(curr_shape instanceof TileShape))
|
|
{
|
|
return result;
|
|
}
|
|
TileShape pad_shape = (TileShape) curr_shape;
|
|
double component_rotation = component.get_rotation_in_degree();
|
|
Point pin_center = this.get_center();
|
|
FloatPoint center_approx = pin_center.to_float();
|
|
|
|
for (Direction curr_padstack_exit_direction : padstack_exit_directions)
|
|
{
|
|
|
|
Package lib_package = component.get_package();
|
|
if (lib_package == null)
|
|
{
|
|
continue;
|
|
}
|
|
Package.Pin package_pin = lib_package.get_pin(this.pin_no);
|
|
if (package_pin == null)
|
|
{
|
|
continue;
|
|
}
|
|
double curr_rotation_in_degree = component_rotation + package_pin.rotation_in_degree;
|
|
Direction curr_exit_direction;
|
|
if (curr_rotation_in_degree % 45 == 0)
|
|
{
|
|
int fortyfive_degree_factor = ((int) curr_rotation_in_degree)/ 45;
|
|
curr_exit_direction = curr_padstack_exit_direction.turn_45_degree(fortyfive_degree_factor);
|
|
}
|
|
else
|
|
{
|
|
double curr_angle_in_radian =
|
|
Math.toRadians(curr_rotation_in_degree) + curr_padstack_exit_direction.angle_approx();
|
|
curr_exit_direction = Direction.get_instance_approx(curr_angle_in_radian);
|
|
}
|
|
// calculate the minimum line length from the pin center into curr_exit_direction
|
|
int intersecting_border_line_no = pad_shape.intersecting_border_line_no(pin_center, curr_exit_direction);
|
|
if (intersecting_border_line_no < 0)
|
|
{
|
|
System.out.println("Pin.get_trace_exit_restrictions: border line not found");
|
|
continue;
|
|
}
|
|
Line curr_exit_line = new Line(pin_center, curr_exit_direction);
|
|
FloatPoint nearest_border_point = curr_exit_line.intersection_approx(pad_shape.border_line(intersecting_border_line_no));
|
|
TraceExitRestriction curr_exit_restriction =
|
|
new TraceExitRestriction(curr_exit_direction, center_approx.distance(nearest_border_point));
|
|
result.add(curr_exit_restriction);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Returns true, if this pin has exit restrictions on some kayer.
|
|
*/
|
|
public boolean has_trace_exit_restrictions()
|
|
{
|
|
for (int i = this.first_layer(); i <= this.last_layer(); ++i)
|
|
{
|
|
java.util.Collection<TraceExitRestriction> curr_exit_restrictions = get_trace_exit_restrictions(i);
|
|
if (curr_exit_restrictions.size() > 0)
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Returns true, if vias throw the pads of this pins are allowed, false, otherwise.
|
|
* Currently drills are allowed to SMD-pins.
|
|
*/
|
|
public boolean drill_allowed()
|
|
{
|
|
return (this.first_layer() == this.last_layer());
|
|
}
|
|
|
|
public boolean is_obstacle(Item p_other)
|
|
{
|
|
if (p_other == this || p_other instanceof ObstacleArea)
|
|
{
|
|
return false;
|
|
}
|
|
if (!p_other.shares_net(this))
|
|
{
|
|
return true;
|
|
}
|
|
if (p_other instanceof Trace)
|
|
{
|
|
return false;
|
|
}
|
|
if (this.drill_allowed() && p_other instanceof Via && ((Via) p_other).attach_allowed)
|
|
{
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
public void turn_90_degree(int p_factor, IntPoint p_pole)
|
|
{
|
|
this.set_center(null);
|
|
clear_derived_data();
|
|
}
|
|
|
|
public void rotate_approx(double p_angle_in_degree, FloatPoint p_pole)
|
|
{
|
|
this.set_center(null);
|
|
this.clear_derived_data();
|
|
}
|
|
|
|
public void change_placement_side(IntPoint p_pole)
|
|
{
|
|
this.set_center(null);
|
|
this.clear_derived_data();
|
|
}
|
|
|
|
public void clear_derived_data()
|
|
{
|
|
super.clear_derived_data();
|
|
this.precalculated_shapes = null;
|
|
}
|
|
|
|
/**
|
|
* Return all Pins, that can be swapped with this pin.
|
|
*/
|
|
public java.util.Set<Pin> get_swappable_pins()
|
|
{
|
|
java.util.Set<Pin> result = new java.util.TreeSet<Pin>();
|
|
Component component = this.board.components.get(this.get_component_no());
|
|
if (component == null)
|
|
{
|
|
return result;
|
|
}
|
|
eu.mihosoft.freerouting.library.LogicalPart logical_part = component.get_logical_part();
|
|
if (logical_part == null)
|
|
{
|
|
return result;
|
|
}
|
|
eu.mihosoft.freerouting.library.LogicalPart.PartPin this_part_pin = logical_part.get_pin(this.pin_no);
|
|
if (this_part_pin == null)
|
|
{
|
|
return result;
|
|
}
|
|
if (this_part_pin.gate_pin_swap_code <= 0)
|
|
{
|
|
return result;
|
|
}
|
|
// look up all part pins with the same gate_name and the same gate_pin_swap_code
|
|
for( int i = 0; i < logical_part.pin_count(); ++i)
|
|
{
|
|
if (i == this.pin_no)
|
|
{
|
|
continue;
|
|
}
|
|
eu.mihosoft.freerouting.library.LogicalPart.PartPin curr_part_pin = logical_part.get_pin(i);
|
|
if (curr_part_pin != null && curr_part_pin.gate_pin_swap_code == this_part_pin.gate_pin_swap_code
|
|
&& curr_part_pin.gate_name.equals(this_part_pin.gate_name))
|
|
{
|
|
Pin curr_swappeble_pin = this.board.get_pin(this.get_component_no(), curr_part_pin.pin_no);
|
|
if (curr_swappeble_pin != null)
|
|
{
|
|
result.add(curr_swappeble_pin);
|
|
}
|
|
else
|
|
{
|
|
System.out.println("Pin.get_swappable_pins: swappable pin not found");
|
|
}
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
public boolean is_selected_by_filter(ItemSelectionFilter p_filter)
|
|
{
|
|
if (!this.is_selected_by_fixed_filter(p_filter))
|
|
{
|
|
return false;
|
|
}
|
|
return p_filter.is_selected(ItemSelectionFilter.SelectableChoices.PINS);
|
|
}
|
|
|
|
public java.awt.Color[] get_draw_colors(eu.mihosoft.freerouting.boardgraphics.GraphicsContext p_graphics_context)
|
|
{
|
|
java.awt.Color[] result;
|
|
if (this.net_count() > 0)
|
|
{
|
|
result = p_graphics_context.get_pin_colors();
|
|
}
|
|
else
|
|
{
|
|
// display unconnected pins as obstacles
|
|
result = p_graphics_context.get_obstacle_colors();
|
|
}
|
|
return result;
|
|
}
|
|
|
|
public double get_draw_intensity(eu.mihosoft.freerouting.boardgraphics.GraphicsContext p_graphics_context)
|
|
{
|
|
return p_graphics_context.get_pin_color_intensity();
|
|
}
|
|
|
|
/**
|
|
* Swaps the nets of this pin and p_other.
|
|
* Returns false on error.
|
|
*/
|
|
public boolean swap(Pin p_other)
|
|
{
|
|
if (this.net_count() > 1 || p_other.net_count() > 1)
|
|
{
|
|
System.out.println("Pin.swap not yet implemented for pins belonging to more than 1 net ");
|
|
return false;
|
|
}
|
|
int this_net_no;
|
|
if (this.net_count() > 0)
|
|
{
|
|
this_net_no = this.get_net_no(0);
|
|
}
|
|
else
|
|
{
|
|
this_net_no = 0;
|
|
}
|
|
int other_net_no;
|
|
if (p_other.net_count() > 0)
|
|
{
|
|
other_net_no = p_other.get_net_no(0);
|
|
}
|
|
else
|
|
{
|
|
other_net_no = 0;
|
|
}
|
|
this.assign_net_no(other_net_no);
|
|
p_other.assign_net_no(this_net_no);
|
|
Pin tmp = this.changed_to;
|
|
this.changed_to = p_other.changed_to;
|
|
p_other.changed_to = tmp;
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Returns the pin, this pin was changed to by pin swapping, or this pin, if it was not swapped.
|
|
*/
|
|
public Pin get_changed_to()
|
|
{
|
|
return changed_to;
|
|
}
|
|
|
|
public boolean write(java.io.ObjectOutputStream p_stream)
|
|
{
|
|
try
|
|
{
|
|
p_stream.writeObject(this);
|
|
}
|
|
catch (java.io.IOException e)
|
|
{
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
|
|
/** False, if this drillitem is places on the back side of the eu.mihosoft.freerouting.board */
|
|
public boolean is_placed_on_front()
|
|
{
|
|
boolean result = true;
|
|
Component component = board.components.get(this.get_component_no());
|
|
if (component != null)
|
|
{
|
|
result = component.placed_on_front();
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Returns the smallest width of the pin shape on layer p_layer.
|
|
*/
|
|
public double get_min_width(int p_layer)
|
|
{
|
|
int padstack_layer = get_padstack_layer(p_layer - this.first_layer());
|
|
Shape padstack_shape = this.get_padstack().get_shape(padstack_layer);
|
|
if (padstack_shape == null)
|
|
{
|
|
System.out.println("Pin.get_min_width: padstack_shape is null");
|
|
return 0;
|
|
}
|
|
eu.mihosoft.freerouting.geometry.planar.IntBox padstack_bounding_box = padstack_shape.bounding_box();
|
|
if (padstack_bounding_box == null)
|
|
{
|
|
System.out.println("Pin.get_min_width: padstack_bounding_box is null");
|
|
return 0;
|
|
}
|
|
return padstack_bounding_box.min_width();
|
|
}
|
|
|
|
/**
|
|
* Returns the neckdown half width for traces on p_layer.
|
|
* The neckdown width is used, when the pin width is smmaller than the trace width
|
|
* to enter or leave the pin with a trace.
|
|
*/
|
|
public int get_trace_neckdown_halfwidth(int p_layer)
|
|
{
|
|
double result = Math.max (0.5 * this.get_min_width(p_layer) - 1, 1);
|
|
return (int) result;
|
|
}
|
|
|
|
/**
|
|
* Returns the largest width of the pin shape on layer p_layer.
|
|
*/
|
|
public double get_max_width(int p_layer)
|
|
{
|
|
int padstack_layer = get_padstack_layer(p_layer - this.first_layer());
|
|
Shape padstack_shape = this.get_padstack().get_shape(padstack_layer);
|
|
if (padstack_shape == null)
|
|
{
|
|
System.out.println("Pin.get_max_width: padstack_shape is null");
|
|
return 0;
|
|
}
|
|
eu.mihosoft.freerouting.geometry.planar.IntBox padstack_bounding_box = padstack_shape.bounding_box();
|
|
if (padstack_bounding_box == null)
|
|
{
|
|
System.out.println("Pin.get_max_width: padstack_bounding_box is null");
|
|
return 0;
|
|
}
|
|
return padstack_bounding_box.max_width();
|
|
}
|
|
|
|
public void print_info(ObjectInfoPanel p_window, java.util.Locale p_locale)
|
|
{
|
|
java.util.ResourceBundle resources =
|
|
java.util.ResourceBundle.getBundle("eu.mihosoft.freerouting.board.resources.ObjectInfoPanel", p_locale);
|
|
p_window.append_bold(resources.getString("pin") + ": ");
|
|
p_window.append(resources.getString("component_2") + " ");
|
|
Component component = board.components.get(this.get_component_no());
|
|
p_window.append(component.name, resources.getString("component_info"), component);
|
|
p_window.append(", " + resources.getString("pin_2") + " ");
|
|
p_window.append(component.get_package().get_pin(this.pin_no).name);
|
|
p_window.append(", " + resources.getString("padstack") + " ");
|
|
eu.mihosoft.freerouting.library.Padstack padstack = this.get_padstack();
|
|
p_window.append(padstack.name, resources.getString("padstack_info"), padstack);
|
|
p_window.append(" " + resources.getString("at") + " ");
|
|
p_window.append(this.get_center().to_float());
|
|
this.print_connectable_item_info(p_window, p_locale);
|
|
p_window.newline();
|
|
}
|
|
|
|
/**
|
|
* Calculates the nearest exit restriction direction for changing p_trace_polyline.
|
|
* p_trace_polyline is assumed to start at the pin center.
|
|
* Returns null, if there is no matching exit restrictions.
|
|
*/
|
|
Direction calc_nearest_exit_restriction_direction(Polyline p_trace_polyline, int p_trace_half_width, int p_layer)
|
|
{
|
|
java.util.Collection<Pin.TraceExitRestriction> trace_exit_restrictions = this.get_trace_exit_restrictions(p_layer);
|
|
if (trace_exit_restrictions.isEmpty())
|
|
{
|
|
return null;
|
|
}
|
|
Shape pin_shape = this.get_shape(p_layer - this.first_layer());
|
|
Point pin_center = this.get_center();
|
|
if (!(pin_shape instanceof TileShape))
|
|
{
|
|
return null;
|
|
}
|
|
final double edge_to_turn_dist = this.board.rules.get_pin_edge_to_turn_dist();
|
|
if (edge_to_turn_dist < 0)
|
|
{
|
|
return null;
|
|
}
|
|
TileShape offset_pin_shape = (TileShape)((TileShape)pin_shape).offset(edge_to_turn_dist + p_trace_half_width);
|
|
int [][] entries = offset_pin_shape.entrance_points(p_trace_polyline);
|
|
if (entries.length == 0)
|
|
{
|
|
return null;
|
|
}
|
|
int [] latest_entry_tuple = entries[entries.length - 1];
|
|
FloatPoint trace_entry_location_approx =
|
|
p_trace_polyline.arr[latest_entry_tuple[0]].intersection_approx(offset_pin_shape.border_line(latest_entry_tuple[1]));
|
|
// calculate the nearest legal pin exit point to trace_entry_location_approx
|
|
double min_exit_corner_distance = Double.MAX_VALUE;
|
|
FloatPoint nearest_exit_corner = null;
|
|
Direction pin_exit_direction = null;
|
|
final double TOLERANCE = 1;
|
|
for (Pin.TraceExitRestriction curr_exit_restriction : trace_exit_restrictions)
|
|
{
|
|
int curr_intersecting_border_line_no = offset_pin_shape.intersecting_border_line_no(pin_center, curr_exit_restriction.direction);
|
|
Line curr_pin_exit_ray = new Line(pin_center, curr_exit_restriction.direction);
|
|
FloatPoint curr_exit_corner = curr_pin_exit_ray.intersection_approx(offset_pin_shape.border_line(curr_intersecting_border_line_no));
|
|
double curr_exit_corner_distance = curr_exit_corner.distance_square(trace_entry_location_approx);
|
|
boolean new_nearest_corner_found = false;
|
|
if (curr_exit_corner_distance + TOLERANCE < min_exit_corner_distance)
|
|
{
|
|
new_nearest_corner_found = true;
|
|
}
|
|
else if (curr_exit_corner_distance < min_exit_corner_distance + TOLERANCE)
|
|
{
|
|
// the distances are near equal, compare to the previous corners of p_trace_polyline
|
|
for (int i = 1; i < p_trace_polyline.corner_count(); ++i )
|
|
{
|
|
FloatPoint curr_trace_corner = p_trace_polyline.corner_approx(i);
|
|
double curr_trace_corner_distance = curr_trace_corner.distance_square(curr_exit_corner);
|
|
double old_trace_corner_distance = curr_trace_corner.distance_square(nearest_exit_corner);
|
|
if (curr_trace_corner_distance + TOLERANCE < old_trace_corner_distance)
|
|
{
|
|
new_nearest_corner_found = true;
|
|
break;
|
|
}
|
|
else if (curr_trace_corner_distance > old_trace_corner_distance + TOLERANCE)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if (new_nearest_corner_found)
|
|
{
|
|
min_exit_corner_distance = curr_exit_corner_distance;
|
|
pin_exit_direction = curr_exit_restriction.direction;
|
|
nearest_exit_corner = curr_exit_corner;
|
|
}
|
|
}
|
|
return pin_exit_direction;
|
|
}
|
|
|
|
/**
|
|
* Calculates the nearest trace exit point of the pin on p_layer.
|
|
* Returns null, if the pin has no trace exit restrictions.
|
|
*/
|
|
public FloatPoint nearest_trace_exit_corner(FloatPoint p_from_point, int p_trace_half_width, int p_layer)
|
|
{
|
|
java.util.Collection<Pin.TraceExitRestriction> trace_exit_restrictions = this.get_trace_exit_restrictions(p_layer);
|
|
if (trace_exit_restrictions.isEmpty())
|
|
{
|
|
return null;
|
|
}
|
|
Shape pin_shape = this.get_shape(p_layer - this.first_layer());
|
|
Point pin_center = this.get_center();
|
|
if (!(pin_shape instanceof TileShape))
|
|
{
|
|
return null;
|
|
}
|
|
final double edge_to_turn_dist = this.board.rules.get_pin_edge_to_turn_dist();
|
|
if (edge_to_turn_dist < 0)
|
|
{
|
|
return null;
|
|
}
|
|
TileShape offset_pin_shape = (TileShape)((TileShape)pin_shape).offset(edge_to_turn_dist + p_trace_half_width);
|
|
|
|
// calculate the nearest legal pin exit point to trace_entry_location_approx
|
|
double min_exit_corner_distance = Double.MAX_VALUE;
|
|
FloatPoint nearest_exit_corner = null;
|
|
for (Pin.TraceExitRestriction curr_exit_restriction : trace_exit_restrictions)
|
|
{
|
|
int curr_intersecting_border_line_no = offset_pin_shape.intersecting_border_line_no(pin_center, curr_exit_restriction.direction);
|
|
Line curr_pin_exit_ray = new Line(pin_center, curr_exit_restriction.direction);
|
|
FloatPoint curr_exit_corner = curr_pin_exit_ray.intersection_approx(offset_pin_shape.border_line(curr_intersecting_border_line_no));
|
|
double curr_exit_corner_distance = curr_exit_corner.distance_square(p_from_point);
|
|
if (curr_exit_corner_distance < min_exit_corner_distance)
|
|
{
|
|
min_exit_corner_distance = curr_exit_corner_distance;
|
|
nearest_exit_corner = curr_exit_corner;
|
|
}
|
|
}
|
|
return nearest_exit_corner;
|
|
}
|
|
|
|
/** The number of this pin in its component (starting with 0). */
|
|
public final int pin_no;
|
|
|
|
/**
|
|
* The pin, this pin was changed to by swapping or this pin, if no pin swap accured.
|
|
*/
|
|
private Pin changed_to = this;
|
|
|
|
private transient Shape[] precalculated_shapes = null;
|
|
|
|
/**
|
|
* Describes an exit restriction from a trace from a pin pad.
|
|
*/
|
|
public static class TraceExitRestriction
|
|
{
|
|
|
|
/** Creates a new instance of TraceExitRestriction */
|
|
public TraceExitRestriction(Direction p_direction, double p_min_length)
|
|
{
|
|
direction = p_direction;
|
|
min_length = p_min_length;
|
|
}
|
|
|
|
public final Direction direction;
|
|
public final double min_length;
|
|
}
|
|
}
|