freerouting/src/main/java/eu/mihosoft/freerouting/board/DrillItem.java

517 lines
16 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.
*
* DrillItem.java
*
* Created on 27. Juni 2003, 11:38
*/
package eu.mihosoft.freerouting.board;
import eu.mihosoft.freerouting.geometry.planar.IntBox;
import eu.mihosoft.freerouting.geometry.planar.FloatPoint;
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.TileShape;
import eu.mihosoft.freerouting.geometry.planar.Vector;
import java.util.Collection;
import java.util.Iterator;
import java.util.Set;
import java.util.TreeSet;
import eu.mihosoft.freerouting.library.Padstack;
/**
* Common superclass for Pins and Vias
*
* @author Alfons Wirtz
*/
public abstract class DrillItem extends Item implements Connectable, java.io.Serializable
{
public DrillItem( Point p_center, int[] p_net_no_arr, int p_clearance_type, int p_id_no,
int p_group_no, FixedState p_fixed_state, BasicBoard p_board)
{
super(p_net_no_arr, p_clearance_type, p_id_no, p_group_no, p_fixed_state, p_board);
this.center = p_center;
}
/**
* Works only for symmettric DrillItems
*/
public void translate_by(Vector p_vector)
{
if (center != null)
{
center = center.translate_by(p_vector);
}
this.clear_derived_data();
}
public void turn_90_degree(int p_factor, IntPoint p_pole)
{
if (center != null)
{
center = center.turn_90_degree(p_factor, p_pole);
}
this.clear_derived_data();
}
public void rotate_approx(double p_angle_in_degree, FloatPoint p_pole)
{
if (center != null)
{
FloatPoint new_center = center.to_float().rotate(Math.toRadians(p_angle_in_degree), p_pole);
this.center = new_center.round();
}
this.clear_derived_data();
}
public void change_placement_side(IntPoint p_pole)
{
if (center != null)
{
center = center.mirror_vertical(p_pole);
}
this.clear_derived_data();
}
public void move_by(Vector p_vector)
{
Point old_center = this.get_center();
// remember the contact situation of this drillitem to traces on each layer
Set<TraceInfo> contact_trace_info = new TreeSet<TraceInfo>();
Collection<Item> contacts = this.get_normal_contacts();
Iterator<Item> it = contacts.iterator();
while (it.hasNext())
{
Item curr_contact = it.next();
if (curr_contact instanceof Trace)
{
Trace curr_trace = (Trace) curr_contact;
TraceInfo curr_trace_info =
new TraceInfo(curr_trace.get_layer(), curr_trace.get_half_width(), curr_trace.clearance_class_no());
contact_trace_info.add(curr_trace_info);
}
}
super.move_by(p_vector);
// Insert a Trace from the old center to the new center, on all layers, where
// this DrillItem was connected to a Trace.
Collection<Point> connect_point_list = new java.util.LinkedList<Point>();
connect_point_list.add(old_center);
Point new_center = this.get_center();
IntPoint add_corner = null;
if (old_center instanceof IntPoint && new_center instanceof IntPoint)
{
// Make shure, that the traces will remain 90- or 45-degree.
if (board.rules.get_trace_angle_restriction() == AngleRestriction.NINETY_DEGREE)
{
add_corner = ((IntPoint)old_center).ninety_degree_corner((IntPoint)new_center, true);
}
else if (board.rules.get_trace_angle_restriction() == AngleRestriction.FORTYFIVE_DEGREE)
{
add_corner = ((IntPoint)old_center).fortyfive_degree_corner((IntPoint)new_center, true);
}
}
if (add_corner != null)
{
connect_point_list.add(add_corner);
}
connect_point_list.add(new_center);
Point[] connect_points = new Point[connect_point_list.size()];
Iterator<Point> it3 = connect_point_list.iterator();
for (int i = 0 ; i < connect_points.length; ++i)
{
connect_points[i] = it3.next();
}
Iterator<TraceInfo> it2 = contact_trace_info.iterator();
while (it2.hasNext())
{
TraceInfo curr_trace_info = it2.next();
board.insert_trace(connect_points, curr_trace_info.layer, curr_trace_info.half_width,
this.net_no_arr, curr_trace_info.clearance_type, FixedState.UNFIXED);
}
}
public int shape_layer(int p_index)
{
int index = Math.max( p_index, 0);
int from_layer = first_layer();
int to_layer = last_layer();
index = Math.min(index, to_layer - from_layer);
return from_layer + index;
}
public boolean is_on_layer(int p_layer)
{
return p_layer >= first_layer() && p_layer <= last_layer();
}
public int first_layer()
{
if (this.precalculated_first_layer < 0)
{
Padstack padstack = get_padstack();
if (this.is_placed_on_front() || padstack.placed_absolute)
{
this.precalculated_first_layer = padstack.from_layer();
}
else
{
this.precalculated_first_layer = padstack.board_layer_count() - padstack.to_layer() - 1;
}
}
return this.precalculated_first_layer;
}
public int last_layer()
{
if (this.precalculated_last_layer < 0)
{
Padstack padstack = get_padstack();
if (this.is_placed_on_front()|| padstack.placed_absolute)
{
this.precalculated_last_layer = padstack.to_layer();
}
else
{
this.precalculated_last_layer = padstack.board_layer_count() - padstack.from_layer() - 1;
}
}
return this.precalculated_last_layer;
}
public abstract Shape get_shape(int p_index);
public IntBox bounding_box()
{
IntBox result = IntBox.EMPTY;
for (int i = 0; i < tile_shape_count(); ++i)
{
Shape curr_shape = this.get_shape(i);
if (curr_shape != null)
{
result = result.union(curr_shape.bounding_box());
}
}
return result;
}
public int tile_shape_count()
{
Padstack padstack = get_padstack();
int from_layer = padstack.from_layer();
int to_layer = padstack.to_layer();
return to_layer - from_layer + 1;
}
protected TileShape[] calculate_tree_shapes(ShapeSearchTree p_search_tree)
{
return p_search_tree.calculate_tree_shapes(this);
}
/**
* Returns the smallest distance from the center to the border of
* the shape on any layer.
*/
public double smallest_radius()
{
double result = Double.MAX_VALUE;
FloatPoint c = get_center().to_float();
for (int i = 0; i < tile_shape_count(); ++i)
{
Shape curr_shape = get_shape(i);
if (curr_shape != null)
{
result = Math.min(result, curr_shape.border_distance(c));
}
}
return result;
}
/** Returns the center point of this DrillItem. */
public Point get_center()
{
return center;
}
protected void set_center(Point p_center)
{
center = p_center;
}
/**
* Returns the padstack of this drillitem.
*/
public abstract Padstack get_padstack();
public TileShape get_tree_shape_on_layer(ShapeSearchTree p_tree, int p_layer)
{
int from_layer = first_layer();
int to_layer = last_layer();
if (p_layer < from_layer || p_layer > to_layer)
{
System.out.println("DrillItem.get_tree_shape_on_layer: p_layer out of range");
return null;
}
return get_tree_shape(p_tree, p_layer - from_layer);
}
public TileShape get_tile_shape_on_layer(int p_layer)
{
int from_layer = first_layer();
int to_layer = last_layer();
if (p_layer < from_layer || p_layer > to_layer)
{
System.out.println("DrillItem.get_tile_shape_on_layer: p_layer out of range");
return null;
}
return get_tile_shape(p_layer - from_layer);
}
public Shape get_shape_on_layer(int p_layer)
{
int from_layer = first_layer();
int to_layer = last_layer();
if (p_layer < from_layer || p_layer > to_layer)
{
System.out.println("DrillItem.get_shape_on_layer: p_layer out of range");
return null;
}
return get_shape(p_layer - from_layer);
}
public Set<Item> get_normal_contacts()
{
Point drill_center = this.get_center();
TileShape search_shape = TileShape.get_instance(drill_center);
Set<SearchTreeObject> overlaps = board.overlapping_objects(search_shape, -1);
Iterator<SearchTreeObject> it = overlaps.iterator();
Set<Item> result = new TreeSet<Item>();
while(it.hasNext())
{
SearchTreeObject curr_ob = it.next();
if (!(curr_ob instanceof Item))
{
continue;
}
Item curr_item = (Item) curr_ob;
if (curr_item != this && curr_item.shares_net(this) && curr_item.shares_layer(this))
{
if (curr_item instanceof Trace)
{
Trace curr_trace = (Trace) curr_item;
if(drill_center.equals(curr_trace.first_corner())
|| drill_center.equals(curr_trace.last_corner()))
{
result.add(curr_item);
}
}
else if (curr_item instanceof DrillItem)
{
DrillItem curr_drill_item = (DrillItem) curr_item;
if (drill_center.equals(curr_drill_item.get_center()))
{
result.add(curr_item);
}
}
else if (curr_item instanceof ConductionArea)
{
ConductionArea curr_area = (ConductionArea) curr_item;
if (curr_area.get_area().contains(drill_center))
{
result.add(curr_item);
}
}
}
}
return result;
}
public Point normal_contact_point(Item p_other)
{
return p_other.normal_contact_point(this);
}
Point normal_contact_point(DrillItem p_other)
{
if (this.shares_layer(p_other) && this.get_center().equals(p_other.get_center()))
{
return this.get_center();
}
return null;
}
Point normal_contact_point(Trace p_trace)
{
if (!this.shares_layer(p_trace))
{
return null;
}
Point drill_center = this.get_center();
if (drill_center.equals(p_trace.first_corner()) || drill_center.equals(p_trace.last_corner()))
{
return drill_center;
}
return null;
}
public Point[] get_ratsnest_corners()
{
Point[] result = new Point[1];
result[0] = this.get_center();
return result;
}
public TileShape get_trace_connection_shape(ShapeSearchTree p_search_tree, int p_index)
{
return TileShape.get_instance(this.get_center());
}
/** False, if this drillitem is places on the back side of the eu.mihosoft.freerouting.board */
public boolean is_placed_on_front()
{
return true;
}
/**
* Return the mininal width of the shapes of this DrillItem on all signal layers.
*/
public double min_width()
{
if (this.precalculated_min_width < 0)
{
double min_width = Integer.MAX_VALUE;
int begin_layer = this.first_layer();
int end_layer = this.last_layer();
for (int curr_layer = begin_layer; curr_layer <= end_layer; ++curr_layer )
{
if(this.board != null && !this.board.layer_structure.arr[curr_layer].is_signal)
{
continue;
}
Shape curr_shape = this.get_shape_on_layer(curr_layer);
if (curr_shape != null)
{
IntBox curr_bounding_box = curr_shape.bounding_box();
min_width = Math.min(min_width, curr_bounding_box.width());
min_width = Math.min(min_width, curr_bounding_box.height());
}
}
this.precalculated_min_width = min_width;
}
return this.precalculated_min_width;
}
public void clear_derived_data()
{
super.clear_derived_data();
this.precalculated_first_layer = -1;
this.precalculated_last_layer = -1;
}
public int get_draw_priority()
{
return eu.mihosoft.freerouting.boardgraphics.Drawable.MIDDLE_DRAW_PRIORITY;
}
public void draw(java.awt.Graphics p_g, eu.mihosoft.freerouting.boardgraphics.GraphicsContext p_graphics_context,
java.awt.Color[] p_color_arr, double p_intensity)
{
if (p_graphics_context == null|| p_intensity <= 0)
{
return;
}
int from_layer = first_layer();
int to_layer = last_layer();
// Decrease the drawing intensity for items with many layers.
double visibility_factor = 0;
for (int i = from_layer; i <= to_layer; ++i)
{
visibility_factor += p_graphics_context.get_layer_visibility(i);
}
if (visibility_factor < 0.001)
{
return;
}
double intensity = p_intensity / Math.max(visibility_factor, 1);
for (int i = 0; i <= to_layer - from_layer; ++i)
{
Shape curr_shape = this.get_shape(i);
if (curr_shape == null)
{
continue;
}
java.awt.Color color = p_color_arr[from_layer + i];
double layer_intensity = intensity * p_graphics_context.get_layer_visibility(from_layer + i);
p_graphics_context.fill_area(curr_shape, p_g, color, layer_intensity);
}
}
/** The center point of the drillitem */
private Point center;
/**
* Contains the precalculated mininal width of the shapes of this DrillItem on all layers.
* If < 0, the value is not yet calculated
*/
private double precalculated_min_width = -1;
/**
* Contains the precalculated first layer, where this DrillItem contains a pad shape.
* If < 0, the value is not yet calculated
*/
private int precalculated_first_layer = -1;
/**
* Contains the precalculated last layer, where this DrillItem contains a pad shape.
* If < 0, the value is not yet calculated
*/
private int precalculated_last_layer = -1;
/**
* Auxiliary class used in the method move_by
*/
private static class TraceInfo implements Comparable<TraceInfo>
{
TraceInfo(int p_layer, int p_half_width, int p_clearance_type)
{
layer = p_layer;
half_width = p_half_width;
clearance_type = p_clearance_type;
}
/**
* Implements the comparable interface.
*/
public int compareTo(TraceInfo p_other)
{
return p_other.layer - this.layer;
}
int layer;
int half_width;
int clearance_type;
}
}