1481 lines
47 KiB
Java
1481 lines
47 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.
|
|
*/
|
|
package eu.mihosoft.freerouting.board;
|
|
|
|
import java.util.Collection;
|
|
import java.util.LinkedList;
|
|
|
|
import eu.mihosoft.freerouting.geometry.planar.Point;
|
|
import eu.mihosoft.freerouting.geometry.planar.IntPoint;
|
|
import eu.mihosoft.freerouting.geometry.planar.FloatPoint;
|
|
import eu.mihosoft.freerouting.geometry.planar.TileShape;
|
|
import eu.mihosoft.freerouting.geometry.planar.Vector;
|
|
import eu.mihosoft.freerouting.geometry.planar.IntBox;
|
|
|
|
import java.awt.Color;
|
|
import java.awt.Graphics;
|
|
import java.io.Serializable;
|
|
import java.util.Iterator;
|
|
import java.util.Set;
|
|
import java.util.TreeSet;
|
|
|
|
import eu.mihosoft.freerouting.rules.Nets;
|
|
import eu.mihosoft.freerouting.boardgraphics.Drawable;
|
|
import eu.mihosoft.freerouting.boardgraphics.GraphicsContext;
|
|
|
|
import eu.mihosoft.freerouting.datastructures.UndoableObjects;
|
|
import eu.mihosoft.freerouting.datastructures.ShapeTree;
|
|
import eu.mihosoft.freerouting.datastructures.ShapeTree.TreeEntry;
|
|
|
|
/**
|
|
* Basic class of the items on a eu.mihosoft.freerouting.board.
|
|
*
|
|
* @author Alfons Wirtz
|
|
*/
|
|
public abstract class Item implements Drawable, SearchTreeObject, ObjectInfoPanel.Printable, UndoableObjects.Storable, Serializable
|
|
{
|
|
|
|
/**
|
|
* Implements the comparable interface.
|
|
*/
|
|
public int compareTo(Object p_other)
|
|
{
|
|
int result;
|
|
if (p_other instanceof Item)
|
|
{
|
|
result = ((Item) p_other).id_no - id_no;
|
|
}
|
|
else
|
|
{
|
|
result = 1;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* returns the unique idcentification number of this item
|
|
*/
|
|
public int get_id_no()
|
|
{
|
|
return id_no;
|
|
}
|
|
|
|
/**
|
|
* Returns true if the net number array of this item contains p_net_no.
|
|
*/
|
|
public boolean contains_net(int p_net_no)
|
|
{
|
|
if (p_net_no <= 0)
|
|
{
|
|
return false;
|
|
}
|
|
for (int i = 0; i < net_no_arr.length; ++i)
|
|
{
|
|
if (net_no_arr[i] == p_net_no)
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
public boolean is_obstacle(int p_net_no)
|
|
{
|
|
return !contains_net(p_net_no);
|
|
}
|
|
|
|
public boolean is_trace_obstacle(int p_net_no)
|
|
{
|
|
return !contains_net(p_net_no);
|
|
}
|
|
|
|
/**
|
|
* Returns, if this item in not allowed to overlap with p_other.
|
|
*/
|
|
public abstract boolean is_obstacle(Item p_other);
|
|
|
|
/**
|
|
* Returns true if the net number arrays of this and p_other have a common
|
|
* number.
|
|
*/
|
|
public boolean shares_net(Item p_other)
|
|
{
|
|
return this.shares_net_no(p_other.net_no_arr);
|
|
}
|
|
|
|
/**
|
|
* Returns true if the net number array of this and p_net_no_arr have a common
|
|
* number.
|
|
*/
|
|
public boolean shares_net_no(int[] p_net_no_arr)
|
|
{
|
|
for (int i = 0; i < net_no_arr.length; ++i)
|
|
{
|
|
for (int j = 0; j < p_net_no_arr.length; ++j)
|
|
{
|
|
if (net_no_arr[i] == p_net_no_arr[j])
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Returns the number of shapes of this item after decomposition into convex polygonal shapes
|
|
*/
|
|
public abstract int tile_shape_count();
|
|
|
|
/**
|
|
* Returns the p_index-throws shape of this item after decomposition into convex polygonal shapes
|
|
*/
|
|
public TileShape get_tile_shape(int p_index)
|
|
{
|
|
if (this.board == null)
|
|
{
|
|
System.out.println("Item.get_tile_shape: eu.mihosoft.freerouting.board is null");
|
|
return null;
|
|
}
|
|
return get_tree_shape(this.board.search_tree_manager.get_default_tree(), p_index);
|
|
}
|
|
|
|
public int tree_shape_count(ShapeTree p_tree)
|
|
{
|
|
if (this.board == null)
|
|
{
|
|
return 0;
|
|
}
|
|
TileShape[] precalculated_tree_shapes = this.get_precalculated_tree_shapes(p_tree);
|
|
return precalculated_tree_shapes.length;
|
|
}
|
|
|
|
public TileShape get_tree_shape(ShapeTree p_tree, int p_index)
|
|
{
|
|
if (this.board == null)
|
|
{
|
|
return null;
|
|
}
|
|
TileShape[] precalculated_tree_shapes = this.get_precalculated_tree_shapes(p_tree);
|
|
return precalculated_tree_shapes[p_index];
|
|
}
|
|
|
|
private TileShape[] get_precalculated_tree_shapes(ShapeTree p_tree)
|
|
{
|
|
if (this.search_trees_info == null)
|
|
{
|
|
this.search_trees_info = new ItemSearchTreesInfo();
|
|
}
|
|
TileShape[] precalculated_tree_shapes = this.search_trees_info.get_precalculated_tree_shapes(p_tree);
|
|
if (precalculated_tree_shapes == null)
|
|
{
|
|
precalculated_tree_shapes = this.calculate_tree_shapes((ShapeSearchTree) p_tree);
|
|
this.search_trees_info.set_precalculated_tree_shapes(precalculated_tree_shapes, p_tree);
|
|
}
|
|
return precalculated_tree_shapes;
|
|
}
|
|
|
|
/**
|
|
* Caculates the tree shapes for this item for p_search_tree.
|
|
*/
|
|
protected abstract TileShape[] calculate_tree_shapes(ShapeSearchTree p_search_tree);
|
|
|
|
/**
|
|
* Returns false, if this item is deleted oor not inserted into
|
|
* the eu.mihosoft.freerouting.board.
|
|
*/
|
|
public boolean is_on_the_board()
|
|
{
|
|
return this.on_the_board;
|
|
}
|
|
|
|
void set_on_the_board(boolean p_value)
|
|
{
|
|
this.on_the_board = p_value;
|
|
}
|
|
|
|
/**
|
|
* Creates a copy of this item with id number p_id_no.
|
|
* If p_id_no <= 0, the id_no of the new item is generated internally
|
|
*/
|
|
public abstract Item copy(int p_id_no);
|
|
|
|
public Object clone()
|
|
{
|
|
return copy(this.get_id_no());
|
|
}
|
|
|
|
/**
|
|
* returns true, if the layer range of this item contains p_layer
|
|
*/
|
|
public abstract boolean is_on_layer(int p_layer);
|
|
|
|
/**
|
|
* Returns the number of the first layer containing geometry of this item.
|
|
*/
|
|
public abstract int first_layer();
|
|
|
|
/**
|
|
* Returns the number of the last layer containing geometry of this item.
|
|
*/
|
|
public abstract int last_layer();
|
|
|
|
/**
|
|
* write this item to an output stream
|
|
*/
|
|
public abstract boolean write(java.io.ObjectOutputStream p_stream);
|
|
|
|
/**
|
|
* Translates the shapes of this item by p_vector.
|
|
* Does not move the item in the eu.mihosoft.freerouting.board.
|
|
*/
|
|
public abstract void translate_by(Vector p_vector);
|
|
|
|
/**
|
|
* Turns this Item by p_factor times 90 degree around p_pole.
|
|
* Does not update the item in the eu.mihosoft.freerouting.board.
|
|
*/
|
|
public abstract void turn_90_degree(int p_factor, IntPoint p_pole);
|
|
|
|
/**
|
|
* Rotates this Item by p_angle_in_degree around p_pole.
|
|
* Does not update the item in the eu.mihosoft.freerouting.board.
|
|
*/
|
|
public abstract void rotate_approx(double p_angle_in_degree, FloatPoint p_pole);
|
|
|
|
/**
|
|
* Changes the placement side of this Item and mirrors it at the vertical line through p_pole.
|
|
* Does not update the item in the eu.mihosoft.freerouting.board.
|
|
*/
|
|
public abstract void change_placement_side(IntPoint p_pole);
|
|
|
|
/**
|
|
* Returns a box containing the geometry of this item.
|
|
*/
|
|
public abstract IntBox bounding_box();
|
|
|
|
/**
|
|
* Translates this item by p_vector in the eu.mihosoft.freerouting.board.
|
|
*/
|
|
public void move_by(Vector p_vector)
|
|
{
|
|
board.item_list.save_for_undo(this);
|
|
board.search_tree_manager.remove(this);
|
|
this.translate_by(p_vector);
|
|
board.search_tree_manager.insert(this);
|
|
// let the observers syncronize the changes
|
|
board.communication.observers.notify_changed(this);
|
|
}
|
|
|
|
/**
|
|
* Returns true, if some shapes of this item and p_other are
|
|
* on the same layer.
|
|
*/
|
|
public boolean shares_layer(Item p_other)
|
|
{
|
|
int max_first_layer = Math.max(this.first_layer(), p_other.first_layer());
|
|
int min_last_layer = Math.min(this.last_layer(), p_other.last_layer());
|
|
return max_first_layer <= min_last_layer;
|
|
}
|
|
|
|
/**
|
|
* Returns the first layer, where both this item and p_other have a shape.
|
|
* Returns -1, if such a layer does not exisr.
|
|
*/
|
|
public int first_common_layer(Item p_other)
|
|
{
|
|
int max_first_layer = Math.max(this.first_layer(), p_other.first_layer());
|
|
int min_last_layer = Math.min(this.last_layer(), p_other.last_layer());
|
|
if (max_first_layer > min_last_layer)
|
|
{
|
|
return -1;
|
|
}
|
|
return max_first_layer;
|
|
}
|
|
|
|
/**
|
|
* Returns the last layer, where both this item and p_other have a shape.
|
|
* Returns -1, if such a layer does not exisr.
|
|
*/
|
|
public int last_common_layer(Item p_other)
|
|
{
|
|
int max_first_layer = Math.max(this.first_layer(), p_other.first_layer());
|
|
int min_last_layer = Math.min(this.last_layer(), p_other.last_layer());
|
|
if (max_first_layer > min_last_layer)
|
|
{
|
|
return -1;
|
|
}
|
|
return min_last_layer;
|
|
}
|
|
|
|
/**
|
|
* Return the name of the component of this item or null, if this item does not belong to a component.
|
|
*/
|
|
public String component_name()
|
|
{
|
|
if (component_no <= 0)
|
|
{
|
|
return null;
|
|
}
|
|
return board.components.get(component_no).name;
|
|
}
|
|
|
|
/**
|
|
* Returns the count of clearance violations of this item with
|
|
* other items.
|
|
*/
|
|
public int clearance_violation_count()
|
|
{
|
|
Collection<ClearanceViolation> violations = this.clearance_violations();
|
|
return violations.size();
|
|
}
|
|
|
|
/**
|
|
* Returns a list of all clearance violations of this item with other items.
|
|
* The objects in the list are of type ClearanceViolations.
|
|
* The first_item in such an object is always this item.
|
|
*/
|
|
public Collection<ClearanceViolation> clearance_violations()
|
|
{
|
|
Collection<ClearanceViolation> result = new LinkedList<ClearanceViolation>();
|
|
if (this.board == null)
|
|
{
|
|
return result;
|
|
}
|
|
ShapeSearchTree default_tree = board.search_tree_manager.get_default_tree();
|
|
for (int i = 0; i < tile_shape_count(); ++i)
|
|
{
|
|
TileShape curr_tile_shape = get_tile_shape(i);
|
|
Collection<TreeEntry> curr_overlapping_items =
|
|
default_tree.overlapping_tree_entries_with_clearance(curr_tile_shape, shape_layer(i), new int[0], clearance_class);
|
|
Iterator<TreeEntry> it = curr_overlapping_items.iterator();
|
|
while (it.hasNext())
|
|
{
|
|
TreeEntry curr_entry = it.next();
|
|
if (!(curr_entry.object instanceof Item) || curr_entry.object == this)
|
|
{
|
|
continue;
|
|
}
|
|
Item curr_item = (Item) curr_entry.object;
|
|
boolean is_obstacle = curr_item.is_obstacle(this);
|
|
if (is_obstacle && this instanceof Trace && curr_item instanceof Trace)
|
|
{
|
|
// Look, if both traces are connected to the same tie pin.
|
|
// In this case they are allowed to overlap without sharing a net.
|
|
Trace this_trace = (Trace) this;
|
|
Point contact_point = this_trace.first_corner();
|
|
boolean contact_found = false;
|
|
Collection<Item> curr_contacts = this_trace.get_normal_contacts(contact_point, true);
|
|
{
|
|
if (curr_contacts.contains(curr_item))
|
|
{
|
|
contact_found = true;
|
|
}
|
|
}
|
|
if (!contact_found)
|
|
{
|
|
contact_point = this_trace.last_corner();
|
|
curr_contacts = this_trace.get_normal_contacts(contact_point, true);
|
|
{
|
|
if (curr_contacts.contains(curr_item))
|
|
{
|
|
contact_found = true;
|
|
}
|
|
}
|
|
}
|
|
if (contact_found)
|
|
{
|
|
for (Item curr_contact : curr_contacts)
|
|
{
|
|
if (curr_contact instanceof Pin)
|
|
{
|
|
if (curr_contact.shares_net(this) && curr_contact.shares_net(curr_item))
|
|
{
|
|
is_obstacle = false;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (is_obstacle)
|
|
{
|
|
TileShape shape_1 = curr_tile_shape;
|
|
TileShape shape_2 = curr_item.get_tree_shape(default_tree, curr_entry.shape_index_in_object);
|
|
if (shape_1 == null || shape_2 == null)
|
|
{
|
|
System.out.println("Item.clearance_violations: unexpected null shape");
|
|
continue;
|
|
}
|
|
if (!this.board.search_tree_manager.is_clearance_compensation_used())
|
|
{
|
|
double cl_offset = 0.5 *
|
|
board.rules.clearance_matrix.value(curr_item.clearance_class, this.clearance_class, shape_layer(i));
|
|
shape_1 = (TileShape) shape_1.enlarge(cl_offset);
|
|
shape_2 = (TileShape) shape_2.enlarge(cl_offset);
|
|
}
|
|
|
|
TileShape intersection = shape_1.intersection(shape_2);
|
|
if (intersection.dimension() == 2)
|
|
{
|
|
ClearanceViolation curr_violation =
|
|
new ClearanceViolation(this, curr_item, intersection, shape_layer(i));
|
|
result.add(curr_violation);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Returns all connectable Items with a direct contacts to this item.
|
|
* The result will be empty, if this item is not connectable.
|
|
*/
|
|
public Set<Item> get_all_contacts()
|
|
{
|
|
Set<Item> result = new TreeSet<Item>();
|
|
if (!(this instanceof Connectable))
|
|
{
|
|
return result;
|
|
}
|
|
for (int i = 0; i < this.tile_shape_count(); ++i)
|
|
{
|
|
Collection<SearchTreeObject> overlapping_items = board.overlapping_objects(get_tile_shape(i), shape_layer(i));
|
|
Iterator<SearchTreeObject> it = overlapping_items.iterator();
|
|
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 instanceof Connectable && curr_item.shares_net(this))
|
|
{
|
|
result.add(curr_item);
|
|
}
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Returns all connectable Items with a direct contacts to this item on the input layer.
|
|
* The result will be empty, if this item is not connectable.
|
|
*/
|
|
public Set<Item> get_all_contacts(int p_layer)
|
|
{
|
|
Set<Item> result = new TreeSet<Item>();
|
|
if (!(this instanceof Connectable))
|
|
{
|
|
return result;
|
|
}
|
|
for (int i = 0; i < this.tile_shape_count(); ++i)
|
|
{
|
|
if (this.shape_layer(i) != p_layer)
|
|
{
|
|
continue;
|
|
}
|
|
Collection<SearchTreeObject> overlapping_items = board.overlapping_objects(get_tile_shape(i), p_layer);
|
|
Iterator<SearchTreeObject> it = overlapping_items.iterator();
|
|
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 instanceof Connectable && curr_item.shares_net(this))
|
|
{
|
|
result.add(curr_item);
|
|
}
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Checks, if this item is electrically connected to another connectable
|
|
* item. Returns false for items, which are not connectable.
|
|
*/
|
|
public boolean is_connected()
|
|
{
|
|
Collection<Item> contacts = this.get_all_contacts();
|
|
return (contacts.size() > 0);
|
|
}
|
|
|
|
/**
|
|
* Checks, if this item is electrically connected to another connectable
|
|
* item on the input layer. Returns false for items, which are not connectable.
|
|
*/
|
|
public boolean is_connected_on_layer(int p_layer)
|
|
{
|
|
Collection<Item> contacts_on_layer = this.get_all_contacts(p_layer);
|
|
return (contacts_on_layer.size() > 0);
|
|
}
|
|
|
|
/**
|
|
* default implementation to be overwritten in the Connectable subclasses
|
|
*/
|
|
public Set<Item> get_normal_contacts()
|
|
{
|
|
return new TreeSet<Item>();
|
|
}
|
|
|
|
/**
|
|
* Returns the contact point, if this item and p_other are Connectable
|
|
* and have a unique normal contact.
|
|
* Returns null otherwise
|
|
*/
|
|
public Point normal_contact_point(Item p_other)
|
|
{
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
* auxiliary function
|
|
*/
|
|
Point normal_contact_point(Trace p_other)
|
|
{
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
* auxiliary function
|
|
*/
|
|
Point normal_contact_point(DrillItem p_other)
|
|
{
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
* Returns the set of all Connectable items of the net with number p_net_no which can be reached recursively
|
|
* via normal contacts from this item.
|
|
* If p_net_no <= 0, the net number is ignored.
|
|
*/
|
|
public Set<Item> get_connected_set(int p_net_no)
|
|
{
|
|
return get_connected_set(p_net_no, false);
|
|
}
|
|
|
|
/**
|
|
* Returns the set of all Connectable items of the net with number p_net_no which can be reached recursively
|
|
* via normal contacts from this item.
|
|
* If p_net_no <= 0, the net number is ignored.
|
|
* If p_stop_at_plane, the recursive algorithm stops, when a conduction area is reached,
|
|
* which does not belong to a component.
|
|
*/
|
|
public Set<Item> get_connected_set(int p_net_no, boolean p_stop_at_plane)
|
|
{
|
|
Set<Item> result = new TreeSet<Item>();
|
|
if (p_net_no > 0 && !this.contains_net(p_net_no))
|
|
{
|
|
return result;
|
|
}
|
|
result.add(this);
|
|
get_connected_set_recu(result, p_net_no, p_stop_at_plane);
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* recursive part of get_connected_set
|
|
*/
|
|
private void get_connected_set_recu(Set<Item> p_result, int p_net_no, boolean p_stop_at_plane)
|
|
{
|
|
Collection<Item> contact_list = get_normal_contacts();
|
|
if (contact_list == null)
|
|
{
|
|
return;
|
|
}
|
|
for (Item curr_contact : contact_list)
|
|
{
|
|
if (p_stop_at_plane && curr_contact instanceof ConductionArea && curr_contact.get_component_no() <= 0)
|
|
{
|
|
continue;
|
|
}
|
|
if (p_net_no > 0 && !curr_contact.contains_net(p_net_no))
|
|
{
|
|
continue;
|
|
}
|
|
if (p_result.add(curr_contact))
|
|
{
|
|
curr_contact.get_connected_set_recu(p_result, p_net_no, p_stop_at_plane);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Returns true, if this item contains some overlap to be cleaned.
|
|
*/
|
|
public boolean is_overlap()
|
|
{
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Recursive part of Trace.is_cycle.
|
|
* If p_ignore_areas is true, cycles where conduction areas are involved are ignored.
|
|
*/
|
|
boolean is_cycle_recu(Set<Item> p_visited_items, Item p_search_item, Item p_come_from_item,
|
|
boolean p_ignore_areas)
|
|
{
|
|
if (p_ignore_areas && this instanceof ConductionArea)
|
|
{
|
|
return false;
|
|
}
|
|
Collection<Item> contact_list = get_normal_contacts();
|
|
if (contact_list == null)
|
|
{
|
|
return false;
|
|
}
|
|
Iterator<Item> it = contact_list.iterator();
|
|
while (it.hasNext())
|
|
{
|
|
Item curr_contact = it.next();
|
|
if (curr_contact == p_come_from_item)
|
|
{
|
|
continue;
|
|
}
|
|
if (curr_contact == p_search_item)
|
|
{
|
|
return true;
|
|
}
|
|
if (p_visited_items.add(curr_contact))
|
|
{
|
|
if (curr_contact.is_cycle_recu(p_visited_items, p_search_item, this, p_ignore_areas))
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Returns the set of all Connectable items belonging to the net with number p_net_no,
|
|
* which are not in the connected set of this item.
|
|
* If p_net_no <= 0, the net numbers contained in this items are used instead of p_net_no.
|
|
*/
|
|
public Set<Item> get_unconnected_set(int p_net_no)
|
|
{
|
|
Set<Item> result = new TreeSet<Item>();
|
|
if (p_net_no > 0 && !this.contains_net(p_net_no))
|
|
{
|
|
return result;
|
|
}
|
|
if (p_net_no > 0)
|
|
{
|
|
result.addAll(board.get_connectable_items(p_net_no));
|
|
}
|
|
else
|
|
{
|
|
for (int curr_net_no : this.net_no_arr)
|
|
{
|
|
result.addAll(board.get_connectable_items(curr_net_no));
|
|
}
|
|
}
|
|
result.removeAll(this.get_connected_set(p_net_no));
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Returns all traces and vias from this item until the next fork or terminal item.
|
|
*/
|
|
public Set<Item> get_connection_items()
|
|
{
|
|
return get_connection_items(StopConnectionOption.NONE);
|
|
}
|
|
|
|
/**
|
|
* Returns all traces and vias from this item until the next fork or terminal item.
|
|
* If p_stop_option == StopConnectionOption.FANOUT_VIA, the algorithm will stop at the next fanout via,
|
|
* If p_stop_option == StopConnectionOption.VIA, the algorithm will stop at any via.
|
|
*/
|
|
public Set<Item> get_connection_items(StopConnectionOption p_stop_option)
|
|
{
|
|
Set<Item> contacts = this.get_normal_contacts();
|
|
Set<Item> result = new TreeSet<Item>();
|
|
if (this.is_route())
|
|
{
|
|
result.add(this);
|
|
}
|
|
Iterator<Item> it = contacts.iterator();
|
|
while (it.hasNext())
|
|
{
|
|
Item curr_item = it.next();
|
|
Point prev_contact_point = this.normal_contact_point(curr_item);
|
|
if (prev_contact_point == null)
|
|
{
|
|
// no unique contact point
|
|
continue;
|
|
}
|
|
int prev_contact_layer = this.first_common_layer(curr_item);
|
|
if (this instanceof Trace)
|
|
{
|
|
// Check, that there is only 1 contact at this location.
|
|
// Only for pins and vias items of more than 1 connection
|
|
// are collected
|
|
Trace start_trace = (Trace) this;
|
|
Collection<Item> check_contacts = start_trace.get_normal_contacts(prev_contact_point, false);
|
|
if (check_contacts.size() != 1)
|
|
{
|
|
continue;
|
|
}
|
|
}
|
|
// Search from curr_item along the contacts
|
|
// until the next fork or nonroute item.
|
|
for (;;)
|
|
{
|
|
if (!curr_item.is_route())
|
|
{
|
|
// connection ends
|
|
break;
|
|
}
|
|
if (curr_item instanceof Via)
|
|
{
|
|
if (p_stop_option == StopConnectionOption.VIA)
|
|
{
|
|
break;
|
|
}
|
|
if (p_stop_option == StopConnectionOption.FANOUT_VIA)
|
|
{
|
|
if (curr_item.is_fanout_via(result))
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
result.add(curr_item);
|
|
Collection<Item> curr_ob_contacts = curr_item.get_normal_contacts();
|
|
// filter the contacts at the previous contact point,
|
|
// because we were already there.
|
|
// If then there is not exactly 1 new contact left, there is
|
|
// a stub or a fork.
|
|
Point next_contact_point = null;
|
|
int next_contact_layer = -1;
|
|
Item next_contact = null;
|
|
boolean fork_found = false;
|
|
Iterator<Item> curr_it = curr_ob_contacts.iterator();
|
|
while (curr_it.hasNext())
|
|
{
|
|
Item tmp_contact = curr_it.next();
|
|
int tmp_contact_layer = curr_item.first_common_layer(tmp_contact);
|
|
if (tmp_contact_layer >= 0)
|
|
{
|
|
Point tmp_contact_point = curr_item.normal_contact_point(tmp_contact);
|
|
if (tmp_contact_point == null)
|
|
{
|
|
// no unique contact point
|
|
fork_found = true;
|
|
break;
|
|
}
|
|
if (prev_contact_layer != tmp_contact_layer ||
|
|
!prev_contact_point.equals(tmp_contact_point))
|
|
{
|
|
if (next_contact != null)
|
|
{
|
|
// second new contact found
|
|
fork_found = true;
|
|
break;
|
|
}
|
|
next_contact = tmp_contact;
|
|
next_contact_point = tmp_contact_point;
|
|
next_contact_layer = tmp_contact_layer;
|
|
}
|
|
}
|
|
}
|
|
if (next_contact == null || fork_found)
|
|
{
|
|
break;
|
|
}
|
|
curr_item = next_contact;
|
|
prev_contact_point = next_contact_point;
|
|
prev_contact_layer = next_contact_layer;
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Function o be overwritten by classes Trace ans Via
|
|
*/
|
|
public boolean is_tail()
|
|
{
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Returns all corners of this item, which are used for displaying the ratsnest.
|
|
* To be overwritten in derived classes implementing the Connectable interface.
|
|
*/
|
|
public Point[] get_ratsnest_corners()
|
|
{
|
|
return new Point[0];
|
|
}
|
|
|
|
public void draw(Graphics p_g, GraphicsContext p_graphics_context, Color p_color, double p_intensity)
|
|
{
|
|
Color[] color_arr = new Color[board.get_layer_count()];
|
|
for (int i = 0; i < color_arr.length; ++i)
|
|
{
|
|
color_arr[i] = p_color;
|
|
}
|
|
draw(p_g, p_graphics_context, color_arr, p_intensity);
|
|
}
|
|
|
|
/**
|
|
* Draws this item whith its draw colors from p_graphics_context.
|
|
* p_layer_visibility[i] is expected between 0 and 1 for each layer i.
|
|
*/
|
|
public void draw(Graphics p_g, GraphicsContext p_graphics_context)
|
|
{
|
|
Color[] layer_colors = get_draw_colors(p_graphics_context);
|
|
draw(p_g, p_graphics_context, layer_colors, get_draw_intensity(p_graphics_context));
|
|
}
|
|
|
|
/**
|
|
* Test function checking the item for inconsitencies.
|
|
*/
|
|
public boolean validate()
|
|
{
|
|
boolean result = true;
|
|
if (!board.search_tree_manager.validate_entries(this))
|
|
{
|
|
result = false;
|
|
}
|
|
for (int i = 0; i < this.tile_shape_count(); ++i)
|
|
{
|
|
TileShape curr_shape = this.get_tile_shape(i);
|
|
if (curr_shape.is_empty())
|
|
{
|
|
System.out.println("Item.validate: shape is empty");
|
|
result = false;
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Returns for this item the layer of the shape with index p_index.
|
|
* If p_id_no <= 0, it w2ill be generated internally.
|
|
*/
|
|
public abstract int shape_layer(int p_index);
|
|
|
|
Item(int[] p_net_no_arr, int p_clearance_type, int p_id_no,
|
|
int p_component_no, FixedState p_fixed_state, BasicBoard p_board)
|
|
{
|
|
if (p_net_no_arr == null)
|
|
{
|
|
net_no_arr = new int[0];
|
|
}
|
|
else
|
|
{
|
|
net_no_arr = new int[p_net_no_arr.length];
|
|
System.arraycopy(p_net_no_arr, 0, net_no_arr, 0, p_net_no_arr.length);
|
|
}
|
|
clearance_class = p_clearance_type;
|
|
component_no = p_component_no;
|
|
fixed_state = p_fixed_state;
|
|
board = p_board;
|
|
if (p_id_no <= 0)
|
|
{
|
|
id_no = board.communication.id_no_generator.new_no();
|
|
}
|
|
else
|
|
{
|
|
id_no = p_id_no;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Returns true, if it is not allowed to change this item except evtl. shoving the item
|
|
*/
|
|
public boolean is_user_fixed()
|
|
{
|
|
return (fixed_state.ordinal() >= FixedState.USER_FIXED.ordinal());
|
|
}
|
|
|
|
/**
|
|
* Returns true, if it is not allowed to delete this item.
|
|
*/
|
|
boolean is_delete_fixed()
|
|
{
|
|
// Items belonging to a component are delete_fixed.
|
|
if (this.component_no > 0 || is_user_fixed())
|
|
{
|
|
return true;
|
|
}
|
|
// Also power planes are delete_fixed.
|
|
if (this instanceof ConductionArea)
|
|
{
|
|
if (!this.board.layer_structure.arr[((ConductionArea) this).get_layer()].is_signal)
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Returns true, if it is not allowed to change the location of this item by the push algorithm.
|
|
*/
|
|
public boolean is_shove_fixed()
|
|
{
|
|
return (this.fixed_state.ordinal() >= FixedState.SHOVE_FIXED.ordinal());
|
|
}
|
|
|
|
/**
|
|
* Returns the fixed state of this Item.
|
|
*/
|
|
public FixedState get_fixed_state()
|
|
{
|
|
return this.fixed_state;
|
|
}
|
|
|
|
/**
|
|
* Returns false, if this item is an obstacle for vias with the input net number.
|
|
*/
|
|
public boolean is_drillable(int p_net_no)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Fixes the item.
|
|
*/
|
|
public void set_fixed_state(FixedState p_fixed_state)
|
|
{
|
|
fixed_state = p_fixed_state;
|
|
}
|
|
|
|
/**
|
|
* Unfixes the item, if it is not fixed by the system.
|
|
*/
|
|
public void unfix()
|
|
{
|
|
if (fixed_state != FixedState.SYSTEM_FIXED)
|
|
{
|
|
fixed_state = FixedState.UNFIXED;
|
|
}
|
|
|
|
}
|
|
|
|
/**
|
|
* returns true, if this item is an unfixed trace or via
|
|
*/
|
|
public boolean is_route()
|
|
{
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Returns, if this item can be routed to.
|
|
*/
|
|
public boolean is_connectable()
|
|
{
|
|
return ((this instanceof Connectable) && this.net_count() > 0);
|
|
}
|
|
|
|
/**
|
|
* Returns the count of nets this item belongs to.
|
|
*/
|
|
public int net_count()
|
|
{
|
|
return net_no_arr.length;
|
|
}
|
|
|
|
/**
|
|
* gets the p_no-th net number of this item for 0 <= p_no < this.net_count().
|
|
*/
|
|
public int get_net_no(int p_no)
|
|
{
|
|
return net_no_arr[p_no];
|
|
}
|
|
|
|
/**
|
|
* Return the component number of this item or 0, if it does not belong to a component.
|
|
*/
|
|
public int get_component_no()
|
|
{
|
|
return component_no;
|
|
}
|
|
|
|
/**
|
|
* Removes p_net_no from the net number array.
|
|
* Returns false, if p_net_no was not contained in this array.
|
|
*/
|
|
public boolean remove_from_net(int p_net_no)
|
|
{
|
|
int found_index = -1;
|
|
for (int i = 0; i < this.net_no_arr.length; ++i)
|
|
{
|
|
if (this.net_no_arr[i] == p_net_no)
|
|
{
|
|
found_index = i;
|
|
}
|
|
}
|
|
if (found_index < 0)
|
|
{
|
|
return false;
|
|
}
|
|
int[] new_net_no_arr = new int[this.net_no_arr.length - 1];
|
|
for (int i = 0; i < found_index; ++i)
|
|
{
|
|
new_net_no_arr[i] = this.net_no_arr[i];
|
|
}
|
|
for (int i = found_index; i < new_net_no_arr.length; ++i)
|
|
{
|
|
new_net_no_arr[i] = this.net_no_arr[i + 1];
|
|
}
|
|
this.net_no_arr = new_net_no_arr;
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Returns the index in the clearance matrix describing the required spacing
|
|
* of this item to other items
|
|
*/
|
|
public int clearance_class_no()
|
|
{
|
|
return clearance_class;
|
|
}
|
|
|
|
/**
|
|
* Sets the index in the clearance matrix describing the required spacing
|
|
* of this item to other items.
|
|
*/
|
|
public void set_clearance_class_no(int p_index)
|
|
{
|
|
if (p_index < 0 || p_index >= this.board.rules.clearance_matrix.get_class_count())
|
|
{
|
|
System.out.println("Item.set_clearance_class_no: p_index out of range");
|
|
return;
|
|
}
|
|
clearance_class = p_index;
|
|
}
|
|
|
|
/**
|
|
* Changes the clearance class of this item and updates the search tree.
|
|
*/
|
|
public void change_clearance_class(int p_index)
|
|
{
|
|
if (p_index < 0 || p_index >= this.board.rules.clearance_matrix.get_class_count())
|
|
{
|
|
System.out.println("Item.set_clearance_class_no: p_index out of range");
|
|
return;
|
|
}
|
|
clearance_class = p_index;
|
|
this.clear_derived_data();
|
|
if (this.board != null && this.board.search_tree_manager.is_clearance_compensation_used())
|
|
{
|
|
// reinsert the item into the search tree, because the compensated shape has changed.
|
|
this.board.search_tree_manager.remove(this);
|
|
this.board.search_tree_manager.insert(this);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Assigns this item to the component with the input component number.
|
|
*/
|
|
public void assign_component_no(int p_no)
|
|
{
|
|
component_no = p_no;
|
|
}
|
|
|
|
/**
|
|
* Makes this item connectable and assigns it to the input net.
|
|
* If p_net_no < 0, the net items net number will be removed and the item will no longer be connectable.
|
|
*/
|
|
public void assign_net_no(int p_net_no)
|
|
{
|
|
if (!Nets.is_normal_net_no(p_net_no))
|
|
{
|
|
return;
|
|
}
|
|
if (p_net_no > board.rules.nets.max_net_no())
|
|
{
|
|
System.out.println("Item.assign_net_no: p_net_no to big");
|
|
return;
|
|
}
|
|
board.item_list.save_for_undo(this);
|
|
if (p_net_no <= 0)
|
|
{
|
|
net_no_arr = new int[0];
|
|
}
|
|
else
|
|
{
|
|
if (net_no_arr.length == 0)
|
|
{
|
|
net_no_arr = new int[1];
|
|
}
|
|
else if (net_no_arr.length > 1)
|
|
{
|
|
System.out.println("Item.assign_net_no: unexpected net_count > 1");
|
|
}
|
|
net_no_arr[0] = p_net_no;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Returns true, if p_item is contained in the input filter.
|
|
*/
|
|
public abstract boolean is_selected_by_filter(ItemSelectionFilter p_filter);
|
|
|
|
/**
|
|
* Internally used for implementing the function is_selectrd_by_filter
|
|
*/
|
|
protected boolean is_selected_by_fixed_filter(ItemSelectionFilter p_filter)
|
|
{
|
|
boolean result;
|
|
if (this.is_user_fixed())
|
|
{
|
|
result = p_filter.is_selected(ItemSelectionFilter.SelectableChoices.FIXED);
|
|
}
|
|
else
|
|
{
|
|
result = p_filter.is_selected(ItemSelectionFilter.SelectableChoices.UNFIXED);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Sets the item tree entries for the tree with identification number p_tree_no.
|
|
*/
|
|
public void set_search_tree_entries(ShapeTree.Leaf[] p_tree_entries, ShapeTree p_tree)
|
|
{
|
|
if (this.board == null)
|
|
{
|
|
return;
|
|
}
|
|
if (this.search_trees_info == null)
|
|
{
|
|
this.search_trees_info = new ItemSearchTreesInfo();
|
|
}
|
|
this.search_trees_info.set_tree_entries(p_tree_entries, p_tree);
|
|
}
|
|
|
|
/**
|
|
* Returns the tree entries for the tree with identification number p_tree_no,
|
|
* or null, if for this tree no entries of this item are inserted.
|
|
*/
|
|
public ShapeTree.Leaf[] get_search_tree_entries(ShapeSearchTree p_tree)
|
|
{
|
|
if (this.search_trees_info == null)
|
|
{
|
|
return null;
|
|
}
|
|
return this.search_trees_info.get_tree_entries(p_tree);
|
|
}
|
|
|
|
/**
|
|
* Sets the precalculated tree shapes tree entries for the tree with identification number p_tree_no.
|
|
*/
|
|
protected void set_precalculated_tree_shapes(TileShape[] p_shapes, ShapeSearchTree p_tree)
|
|
{
|
|
if (this.board == null)
|
|
{
|
|
return;
|
|
}
|
|
if (this.search_trees_info == null)
|
|
{
|
|
System.out.println("Item.set_precalculated_tree_shapes search_trees_info not allocated");
|
|
return;
|
|
}
|
|
this.search_trees_info.set_precalculated_tree_shapes(p_shapes, p_tree);
|
|
}
|
|
|
|
/**
|
|
* Sets the searh tree entries of this item to null.
|
|
*/
|
|
public void clear_search_tree_entries()
|
|
{
|
|
this.search_trees_info = null;
|
|
}
|
|
|
|
/**
|
|
* Gets the information for the eu.mihosoft.freerouting.autoroute algorithm.
|
|
* Creates it, if it does not yet exist.
|
|
*/
|
|
public eu.mihosoft.freerouting.autoroute.ItemAutorouteInfo get_autoroute_info()
|
|
{
|
|
if (autoroute_info == null)
|
|
{
|
|
autoroute_info = new eu.mihosoft.freerouting.autoroute.ItemAutorouteInfo(this);
|
|
}
|
|
return autoroute_info;
|
|
}
|
|
|
|
/**
|
|
* Gets the information for the eu.mihosoft.freerouting.autoroute algorithm.
|
|
*/
|
|
public eu.mihosoft.freerouting.autoroute.ItemAutorouteInfo get_autoroute_info_pur()
|
|
{
|
|
return autoroute_info;
|
|
}
|
|
|
|
/**
|
|
* Clears the data allocated for the eu.mihosoft.freerouting.autoroute algorithm.
|
|
*/
|
|
public void clear_autoroute_info()
|
|
{
|
|
autoroute_info = null;
|
|
}
|
|
|
|
/**
|
|
* Clear all cached or derived data. so that they have to be recalculated,
|
|
* when they are used next time.
|
|
*/
|
|
public void clear_derived_data()
|
|
{
|
|
if (this.search_trees_info != null)
|
|
{
|
|
this.search_trees_info.clear_precalculated_tree_shapes();
|
|
}
|
|
autoroute_info = null;
|
|
}
|
|
|
|
/**
|
|
* Internal funktion used in the implementation of print_info
|
|
*/
|
|
protected void print_net_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);
|
|
for (int i = 0; i < this.net_count(); ++i)
|
|
{
|
|
p_window.append(", " + resources.getString("net") + " ");
|
|
eu.mihosoft.freerouting.rules.Net curr_net = board.rules.nets.get(this.get_net_no(i));
|
|
p_window.append(curr_net.name, resources.getString("net_info"), curr_net);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Internal funktion used in the implementation of print_info
|
|
*/
|
|
protected void print_clearance_info(ObjectInfoPanel p_window, java.util.Locale p_locale)
|
|
{
|
|
if (this.clearance_class > 0)
|
|
{
|
|
java.util.ResourceBundle resources =
|
|
java.util.ResourceBundle.getBundle("eu.mihosoft.freerouting.board.resources.ObjectInfoPanel", p_locale);
|
|
p_window.append(", " + resources.getString("clearance_class") + " ");
|
|
String name = board.rules.clearance_matrix.get_name(this.clearance_class);
|
|
p_window.append(name, resources.getString("clearance_info"), board.rules.clearance_matrix.get_row(this.clearance_class));
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Internal funktion used in the implementation of print_info
|
|
*/
|
|
protected void print_fixed_info(ObjectInfoPanel p_window, java.util.Locale p_locale)
|
|
{
|
|
if (this.fixed_state != FixedState.UNFIXED)
|
|
{
|
|
java.util.ResourceBundle resources =
|
|
java.util.ResourceBundle.getBundle("eu.mihosoft.freerouting.board.resources.FixedState", p_locale);
|
|
p_window.append(", ");
|
|
p_window.append(resources.getString(this.fixed_state.toString()));
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Internal funktion used in the implementation of print_info
|
|
*/
|
|
protected void print_contact_info(ObjectInfoPanel p_window, java.util.Locale p_locale)
|
|
{
|
|
Collection<Item> contacts = this.get_normal_contacts();
|
|
if (!contacts.isEmpty())
|
|
{
|
|
java.util.ResourceBundle resources =
|
|
java.util.ResourceBundle.getBundle("eu.mihosoft.freerouting.board.resources.ObjectInfoPanel", p_locale);
|
|
p_window.append(", " + resources.getString("contacts") + " ");
|
|
Integer contact_count = contacts.size();
|
|
p_window.append_items(contact_count.toString(), resources.getString("contact_info"), contacts);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Internal funktion used in the implementation of print_info
|
|
*/
|
|
protected void print_clearance_violation_info(ObjectInfoPanel p_window, java.util.Locale p_locale)
|
|
{
|
|
Collection<ClearanceViolation> clearance_violations = this.clearance_violations();
|
|
if (!clearance_violations.isEmpty())
|
|
{
|
|
java.util.ResourceBundle resources =
|
|
java.util.ResourceBundle.getBundle("eu.mihosoft.freerouting.board.resources.ObjectInfoPanel", p_locale);
|
|
p_window.append(", ");
|
|
Integer violation_count = clearance_violations.size();
|
|
Collection<ObjectInfoPanel.Printable> violations = new java.util.LinkedList<ObjectInfoPanel.Printable>();
|
|
violations.addAll(clearance_violations);
|
|
p_window.append_objects(violation_count.toString(), resources.getString("violation_info"), violations);
|
|
if (violation_count == 1)
|
|
{
|
|
p_window.append(" " + resources.getString("clearance_violation"));
|
|
}
|
|
else
|
|
{
|
|
p_window.append(" " + resources.getString("clearance_violations"));
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Internal funktion used in the implementation of print_info
|
|
*/
|
|
protected void print_connectable_item_info(ObjectInfoPanel p_window, java.util.Locale p_locale)
|
|
{
|
|
this.print_clearance_info(p_window, p_locale);
|
|
this.print_fixed_info(p_window, p_locale);
|
|
this.print_net_info(p_window, p_locale);
|
|
this.print_contact_info(p_window, p_locale);
|
|
this.print_clearance_violation_info(p_window, p_locale);
|
|
}
|
|
|
|
/**
|
|
* Internal funktion used in the implementation of print_info
|
|
*/
|
|
protected void print_item_info(ObjectInfoPanel p_window, java.util.Locale p_locale)
|
|
{
|
|
this.print_clearance_info(p_window, p_locale);
|
|
this.print_fixed_info(p_window, p_locale);
|
|
this.print_clearance_violation_info(p_window, p_locale);
|
|
}
|
|
|
|
/**
|
|
* Checks, if all nets of this items are normal.
|
|
*/
|
|
public boolean nets_normal()
|
|
{
|
|
for (int i = 0; i < this.net_no_arr.length; ++i)
|
|
{
|
|
if (!Nets.is_normal_net_no(this.net_no_arr[i]))
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Checks, if this item and p_other contain exactly the same net numbers.
|
|
*/
|
|
public boolean nets_equal(Item p_other)
|
|
{
|
|
return nets_equal(p_other.net_no_arr);
|
|
}
|
|
|
|
/**
|
|
* Checks, if this item contains exacly the nets in p_net_no_arr
|
|
*/
|
|
public boolean nets_equal(int[] p_net_no_arr)
|
|
{
|
|
if (this.net_no_arr.length != p_net_no_arr.length)
|
|
{
|
|
return false;
|
|
}
|
|
for (int curr_net_no : p_net_no_arr)
|
|
{
|
|
if (!this.contains_net(curr_net_no))
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Returns true, if the via is directly ob by a trace connected to a nearby SMD-pin.
|
|
* If p_ignore_items != null, contact traces in P-ignore_items are ignored.
|
|
*/
|
|
boolean is_fanout_via(Set<Item> p_ignore_items)
|
|
{
|
|
Collection<Item> contact_list = this.get_normal_contacts();
|
|
for (Item curr_contact : contact_list)
|
|
{
|
|
if (curr_contact instanceof Pin && curr_contact.first_layer() == curr_contact.last_layer() && curr_contact.get_normal_contacts().size() <= 1)
|
|
{
|
|
return true;
|
|
}
|
|
if (curr_contact instanceof Trace)
|
|
{
|
|
if (p_ignore_items != null && p_ignore_items.contains(curr_contact))
|
|
{
|
|
continue;
|
|
}
|
|
Trace curr_trace = (Trace) curr_contact;
|
|
if (curr_trace.get_length() >= PROTECT_FANOUT_LENGTH * curr_trace.get_half_width())
|
|
{
|
|
continue;
|
|
}
|
|
Collection<Item> trace_contact_list = curr_trace.get_normal_contacts();
|
|
for (Item tmp_contact : trace_contact_list)
|
|
{
|
|
if (tmp_contact instanceof Pin && curr_contact.first_layer() == curr_contact.last_layer() && tmp_contact.get_normal_contacts().size() <= 1)
|
|
{
|
|
return true;
|
|
}
|
|
if (tmp_contact instanceof PolylineTrace && tmp_contact.get_fixed_state() == FixedState.SHOVE_FIXED)
|
|
{
|
|
// look for shove fixed exit traces of SMD-pins
|
|
PolylineTrace contact_trace = (PolylineTrace) tmp_contact;
|
|
if (contact_trace.corner_count() == 2)
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
/**
|
|
* the index in the clearance matrix describing the required spacing
|
|
* to other items
|
|
*/
|
|
private int clearance_class;
|
|
/** The eu.mihosoft.freerouting.board this Itewm is on */
|
|
transient public BasicBoard board;
|
|
/** The nets, to which this item belongs */
|
|
int[] net_no_arr;
|
|
/** points to the entries of this item in the ShapeSearchTrees */
|
|
transient private ItemSearchTreesInfo search_trees_info = null;
|
|
private FixedState fixed_state;
|
|
/** not 0, if this item belongs to a component */
|
|
private int component_no = 0;
|
|
private final int id_no;
|
|
/**
|
|
* Folse, if the item is deleted or not inserted into the eu.mihosoft.freerouting.board
|
|
*/
|
|
private boolean on_the_board = false;
|
|
/** Temporary data used in the eu.mihosoft.freerouting.autoroute algorithm. */
|
|
transient private eu.mihosoft.freerouting.autoroute.ItemAutorouteInfo autoroute_info = null;
|
|
private static double PROTECT_FANOUT_LENGTH = 400;
|
|
|
|
/**
|
|
* Used as parameter of get_connection to control, that the connection
|
|
* stops at the next fanout via or at any via.
|
|
*/
|
|
public enum StopConnectionOption
|
|
{
|
|
|
|
NONE, FANOUT_VIA, VIA
|
|
}
|
|
}
|