/* * 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. * * BoardRules.java * * Created on 1. Juni 2004, 07:16 */ package rules; import geometry.planar.ConvexShape; /** * Contains the rules and constraints required for items * to be inserted into a routing board * * @author Alfons Wirtz */ public class BoardRules implements java.io.Serializable { /** * Creates a new instance of this class. */ public BoardRules(board.LayerStructure p_layer_structure, ClearanceMatrix p_clearance_matrix) { layer_structure = p_layer_structure; clearance_matrix = p_clearance_matrix; nets = new Nets(); this.trace_angle_restriction = board.AngleRestriction.FORTYFIVE_DEGREE; this.min_trace_half_width = 100000; this.max_trace_half_width = 100; } /** * Returns the trace halfwidth used for routing with the input net on the input layer. */ public int get_trace_half_width( int p_net_no, int p_layer) { Net curr_net = nets.get(p_net_no); return curr_net.get_class().get_trace_half_width(p_layer); } /** * Returns true, if the trace widths used for routing for the input net are equal on all layers. * If p_net_no < 0, the default trace widths for all nets are checked. */ public boolean trace_widths_are_layer_dependent(int p_net_no) { int compare_width = get_trace_half_width(p_net_no, 0); for (int i = 1; i < this.layer_structure.arr.length; ++i) { if (get_trace_half_width(p_net_no, i) != compare_width) { return true; } } return false; } /** Returns he smallest of all default trace half widths*/ public int get_min_trace_half_width() { return min_trace_half_width; } /** Returns he biggest of all default trace half widths*/ public int get_max_trace_half_width() { return max_trace_half_width; } /** * Changes the default trace halfwidth used for routing on the input layer. */ public void set_default_trace_half_width(int p_layer, int p_value) { this.get_default_net_class().set_trace_half_width(p_layer, p_value); min_trace_half_width = Math.min(min_trace_half_width, p_value); max_trace_half_width = Math.max(max_trace_half_width, p_value); } public int get_default_trace_half_width (int p_layer) { return this.get_default_net_class().get_trace_half_width(p_layer); } /** * Changes the default trace halfwidth used for routing on all layers * to the input value. */ public void set_default_trace_half_widths(int p_value) { if (p_value <= 0) { System.out.println("BoardRules.set_trace_half_widths: p_value out of range"); return; } this.get_default_net_class().set_trace_half_width(p_value); min_trace_half_width = Math.min(min_trace_half_width, p_value); max_trace_half_width = Math.max(max_trace_half_width, p_value); } /** * Returns the net rule used for all nets, for whichh no special rrule was set. */ public NetClass get_default_net_class() { if (this.net_classes.count() <= 0) { // net rules not yet initialized this.create_default_net_class(); } return this.net_classes.get(0); } /** Gets the default item clearance class */ public static int default_clearance_class() { return 1; } /** For items with no clearances */ public static int clearance_class_none() { return 0; } /** * Returns an empty new net rule with an internally created name. */ public NetClass get_new_net_class(java.util.Locale p_locale) { NetClass result = this.net_classes.append(this.layer_structure, this.clearance_matrix, p_locale); result.set_trace_clearance_class(this.get_default_net_class().get_trace_clearance_class()); result.set_via_rule(this.get_default_via_rule()); result.set_trace_half_width(this.get_default_net_class().get_trace_half_width(0)); return result; } /** * Returns an empty new net rule with an internally created name. */ public NetClass get_new_net_class(String p_name) { NetClass result = this.net_classes.append(p_name, this.layer_structure, this.clearance_matrix); result.set_trace_clearance_class(this.get_default_net_class().get_trace_clearance_class()); result.set_via_rule(this.get_default_via_rule()); result.set_trace_half_width(this.get_default_net_class().get_trace_half_width(0)); return result; } /** * Create a default via rule for p_net_class with name p_name. * If more than one via infos with the same layer range are found, * only the via info with the smmallest pad size is inserted. */ public void create_default_via_rule(NetClass p_net_class, String p_name) { if (this.via_infos.count() == 0) { return; } // Add the rule containing all vias. ViaRule default_rule = new ViaRule(p_name); int default_via_cl_class = p_net_class.default_item_clearance_classes.get(DefaultItemClearanceClasses.ItemClass.VIA); for (int i = 0; i < this.via_infos.count(); ++i) { ViaInfo curr_via_info = this.via_infos.get(i); if (curr_via_info.get_clearance_class() == default_via_cl_class) { library.Padstack curr_padstack = curr_via_info.get_padstack(); int curr_from_layer = curr_padstack.from_layer(); int curr_to_layer = curr_padstack.to_layer(); ViaInfo existing_via = default_rule.get_layer_range(curr_from_layer, curr_to_layer); if (existing_via != null) { ConvexShape new_shape = curr_padstack.get_shape(curr_from_layer); ConvexShape existing_shape = existing_via.get_padstack().get_shape(curr_from_layer); if (new_shape.max_width() < existing_shape.max_width()) { // The via with the smallest pad shape is preferred default_rule.remove_via(existing_via); default_rule.append_via(curr_via_info); } } else { default_rule.append_via(curr_via_info); } } } this.via_rules.add(default_rule); p_net_class.set_via_rule(default_rule); } public void create_default_net_class() { // add the default net rule NetClass default_net_class = this.net_classes.append("default", this.layer_structure, this.clearance_matrix); int default_trace_half_width = 1500; default_net_class.set_trace_half_width(default_trace_half_width); default_net_class.set_trace_clearance_class(1); } /** * Appends a new net class initialized with default data and a default name. */ public NetClass append_net_class(java.util.Locale p_locale) { NetClass new_class = this.net_classes.append(this.layer_structure, this.clearance_matrix, p_locale); NetClass default_class = this.net_classes.get(0); new_class.set_via_rule(default_class.get_via_rule()); new_class.set_trace_half_width(default_class.get_trace_half_width(0)); new_class.set_trace_clearance_class(default_class.get_trace_clearance_class()); return new_class; } /** * Appends a new net class initialized with default data and returns that class. * If a class with p_name exists, this class is returned withoout appending a new class. */ public NetClass append_net_class(String p_name) { NetClass found_class = this.net_classes.get(p_name); if (found_class != null) { return found_class; } NetClass new_class = this.net_classes.append(p_name, this.layer_structure, this.clearance_matrix); NetClass default_class = this.net_classes.get(0); new_class.default_item_clearance_classes = new DefaultItemClearanceClasses(default_class.default_item_clearance_classes); new_class.set_via_rule(default_class.get_via_rule()); new_class.set_trace_half_width(default_class.get_trace_half_width(0)); new_class.set_trace_clearance_class(default_class.get_trace_clearance_class()); return new_class; } /** * Returns the default via rule for routing or null, if no via rule exists. */ public ViaRule get_default_via_rule() { if (this.via_rules.isEmpty()) { return null; } return this.via_rules.get(0); } /** * Returns the via rule wit name p_name, or null, if no such rule exists. */ public ViaRule get_via_rule(String p_name) { for (ViaRule curr_rule : via_rules) { if(curr_rule.name.equals(p_name)) { return curr_rule; } } return null; } /** * Changes the clearance class index of all objects on the board with index p_from_no * to p_to_no. */ public void change_clearance_class_no(int p_from_no, int p_to_no, java.util.Collection<board.Item> p_board_items) { for(board.Item curr_item : p_board_items) { if (curr_item.clearance_class_no() == p_from_no) { curr_item.set_clearance_class_no(p_to_no); } } for (int i = 0; i < this.net_classes.count(); ++i) { rules.NetClass curr_net_class = this.net_classes.get(i); if (curr_net_class.get_trace_clearance_class() == p_from_no) { curr_net_class.set_trace_clearance_class(p_to_no); } for (DefaultItemClearanceClasses.ItemClass curr_item_class : DefaultItemClearanceClasses.ItemClass.values()) { if (curr_net_class.default_item_clearance_classes.get(curr_item_class) == p_from_no) { curr_net_class.default_item_clearance_classes.set(curr_item_class, p_to_no); } } } for (int i = 0; i < this.via_infos.count(); ++i) { rules.ViaInfo curr_via = this.via_infos.get(i); if (curr_via.get_clearance_class() == p_from_no) { curr_via.set_clearance_class(p_to_no); } } } /** * Removes the clearance class with number p_index. * Returns false, if that was not possible, because there were still items assigned to this class. */ public boolean remove_clearance_class(int p_index, java.util.Collection<board.Item> p_board_items) { for(board.Item curr_item : p_board_items) { if (curr_item.clearance_class_no() == p_index) { return false; } } for (int i = 0; i < this.net_classes.count(); ++i) { rules.NetClass curr_net_class = this.net_classes.get(i); if (curr_net_class.get_trace_clearance_class() == p_index) { return false; } for (DefaultItemClearanceClasses.ItemClass curr_item_class : DefaultItemClearanceClasses.ItemClass.values()) { if (curr_net_class.default_item_clearance_classes.get(curr_item_class) == p_index) { return false; } } } for (int i = 0; i < this.via_infos.count(); ++i) { rules.ViaInfo curr_via = this.via_infos.get(i); if (curr_via.get_clearance_class() == p_index) { return false; } } for(board.Item curr_item : p_board_items) { if (curr_item.clearance_class_no() > p_index) { curr_item.set_clearance_class_no(curr_item.clearance_class_no() - 1); } } for (int i = 0; i < this.net_classes.count(); ++i) { rules.NetClass curr_net_class = this.net_classes.get(i); if (curr_net_class.get_trace_clearance_class() > p_index) { curr_net_class.set_trace_clearance_class(curr_net_class.get_trace_clearance_class() - 1); } for (DefaultItemClearanceClasses.ItemClass curr_item_class : DefaultItemClearanceClasses.ItemClass.values()) { int curr_class_no = curr_net_class.default_item_clearance_classes.get(curr_item_class); if (curr_class_no > p_index) { curr_net_class.default_item_clearance_classes.set(curr_item_class, curr_class_no - 1); } } } for (int i = 0; i < this.via_infos.count(); ++i) { rules.ViaInfo curr_via = this.via_infos.get(i); if (curr_via.get_clearance_class() > p_index) { curr_via.set_clearance_class(curr_via.get_clearance_class() - 1); } } this.clearance_matrix.remove_class(p_index); return true; } /** * Returns the minimum distance between the pin border and the next corner * of a connected trace por a pin with connection restrictions. * If the result is <= 0, there are no exit restrictions. */ public double get_pin_edge_to_turn_dist() { return this.pin_edge_to_turn_dist; } /** * Sets he minimum distance between the pin border and the next corner * of a connected trace por a pin with connection restrictions. * if p_value is <= 0, there are no exit restrictions. */ public void set_pin_edge_to_turn_dist(double p_value) { this.pin_edge_to_turn_dist = p_value; } /** * Tells the router, if conduction areas should be ignored.. */ public void set_ignore_conduction(boolean p_value) { this.ignore_conduction = p_value; } /** * If true, the router ignores conduction areas. */ public boolean get_ignore_conduction() { return this.ignore_conduction; } /** The angle restriction for tracese: 90 degree, 45 degree or none. */ public board.AngleRestriction get_trace_angle_restriction() { return this.trace_angle_restriction; } /** Sets the angle restriction for tracese: 90 degree, 45 degree or none. */ public void set_trace_angle_restriction(board.AngleRestriction p_angle_restriction) { this.trace_angle_restriction = p_angle_restriction; } /** * If true, shapes of type Simplex are always used in the autorouter algorithm. * If false, shapes of type IntBox are used in 90 degree autorouting * and shapes of type IntOctagon are used in 45 degree autorouting. */ public void set_slow_autoroute_algorithm(boolean p_value) { slow_autoroute_algorithm = p_value; } /** * If true, shapes of type Simplex are always used in the autorouter algorithm. * If false, shapes of type IntBox are used in 90 degree autorouting * and shapes of type IntOctagon are used in 45 degree autorouting. */ public boolean get_slow_autoroute_algorithm() { return slow_autoroute_algorithm; } /** * Returns the Maximum of the diameter of the default via on its first and last layer. */ public double get_default_via_diameter() { ViaRule default_via_rule = this.get_default_via_rule(); if (default_via_rule == null) { return 0; } if (default_via_rule.via_count() <= 0) { return 0; } library.Padstack via_padstack = default_via_rule.get_via(0).get_padstack(); ConvexShape curr_shape = via_padstack.get_shape(via_padstack.from_layer()); double result = curr_shape.max_width(); curr_shape = via_padstack.get_shape(via_padstack.to_layer()); result = Math.max(result, curr_shape.max_width()); return result; } /** Writes an instance of this class to a file */ private void writeObject(java.io.ObjectOutputStream p_stream) throws java.io.IOException { p_stream.defaultWriteObject(); p_stream.writeInt(trace_angle_restriction.get_no()); } /** Reads an instance of this class from a file */ private void readObject(java.io.ObjectInputStream p_stream) throws java.io.IOException, java.lang.ClassNotFoundException { p_stream.defaultReadObject(); int snap_angle_no = p_stream.readInt(); this.trace_angle_restriction = board.AngleRestriction.arr[snap_angle_no]; } /** * The matrix describing the spacing restrictions between * item clearance classes. */ public final ClearanceMatrix clearance_matrix; /** * Describes the electrical nets on the board. */ public final Nets nets; /** The angle restriction for traces: 90 degree, 45 degree or none. */ private transient board.AngleRestriction trace_angle_restriction; /** * If true, the router ignores conduction areas. */ private boolean ignore_conduction = true; private final board.LayerStructure layer_structure; public final ViaInfos via_infos = new ViaInfos(); public final java.util.Vector<ViaRule> via_rules = new java.util.Vector<ViaRule>(); public final NetClasses net_classes = new NetClasses(); /** The smallest of all default trace half widths */ private int min_trace_half_width; /** The biggest of all default trace half widths */ private int max_trace_half_width; /** * The minimum distance of the pad border to the first turn of a connected trace * to a pin with restricted exit directions. * If the value is <= 0, there are no exit restrictions. */ private double pin_edge_to_turn_dist; private boolean slow_autoroute_algorithm = false; }