/* * 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 rules; /** * * NxN Matrix describing the spacing restrictions * between N clearance classes on a fixed set of layers. * * * @author Alfons Wirtz */ public class ClearanceMatrix implements java.io.Serializable { /** * Creates a new instance with the 2 clearance classes "none"and "default" * ans initializes it with p_default_value. */ public static ClearanceMatrix get_default_instance(board.LayerStructure p_layer_structure, int p_default_value) { String [] name_arr = new String [2]; name_arr[0] = "null"; name_arr[1] = "default"; ClearanceMatrix result = new ClearanceMatrix(2, p_layer_structure, name_arr); result.set_default_value(p_default_value); return result; } /** * Creates a new instance for p_class_count clearance classes on * p_layer_count layers. * p_names is an array of dimension p_class_count; */ public ClearanceMatrix(int p_class_count, board.LayerStructure p_layer_structure, String [] p_name_arr) { class_count = Math.max(p_class_count, 1); layer_structure = p_layer_structure; row = new Row [class_count]; for (int i = 0; i < class_count; ++i) { row[i] = new Row(p_name_arr[i]); } this.max_value_on_layer = new int[layer_structure.arr.length]; } /** * Returns the number of the clearance class with the input name, * or -1, if no such clearance class exists. */ public int get_no(String p_name) { for (int i = 0; i < class_count; ++i) { if (row[i].name.compareToIgnoreCase(p_name) == 0) { return i; } } return -1; } /** * Gets the name of the clearance class with the input number. */ public String get_name(int p_cl_class) { if (p_cl_class < 0 || p_cl_class >= row.length) { System.out.println("CleatranceMatrix.get_name: p_cl_class out of range"); return null; } return row[p_cl_class].name; } /** * Sets the value of all clearance classes with number >= 1 * to p_value on all layers. */ public void set_default_value(int p_value) { for (int i = 0; i < layer_structure.arr.length; ++i) { set_default_value(i, p_value); } } /** * Sets the value of all clearance classes with number >= 1 * to p_value on p_layer. */ public void set_default_value(int p_layer, int p_value) { for (int i = 1; i < class_count; ++i) { for (int j = 1; j < class_count; ++j) { set_value(i, j, p_layer, p_value); } } } /** * Sets the value of an entry in the clearance matrix to p_value * on all layers. */ public void set_value(int p_i, int p_j, int p_value) { for (int layer = 0; layer < layer_structure.arr.length; ++layer) { set_value(p_i, p_j, layer, p_value); } } /** * Sets the value of an entry in the clearance matrix to p_value * on all inner layers. */ public void set_inner_value(int p_i, int p_j, int p_value) { for (int layer = 1; layer < layer_structure.arr.length - 1; ++layer) { set_value(p_i, p_j, layer, p_value); } } /** * Sets the value of an entry in the clearance matrix to p_value. */ public void set_value(int p_i, int p_j, int p_layer, int p_value) { Row curr_row = row[p_j]; MatrixEntry curr_entry = curr_row.column[p_i]; // assure, that the clearance value is even int value = Math.max(p_value, 0); value += value % 2; curr_entry.layer[p_layer] = value; curr_row.max_value[p_layer] = Math.max(curr_row.max_value[p_layer], p_value); this.max_value_on_layer[p_layer] = Math.max(this.max_value_on_layer[p_layer], p_value); } /** * Cets the required spacing of clearance classes with index p_i and p_j * on p_layer. This value will be always an even integer. */ public int value(int p_i, int p_j, int p_layer) { if (p_i < 0 || p_i >= class_count || p_j < 0 || p_j >= class_count || p_layer < 0 || p_layer >= layer_structure.arr.length) { return 0; } return row[p_j].column[p_i].layer[p_layer]; } /** * Returns the maximal required spacing of clearance class with * index p_i to all other clearance classes on layer p_layer. */ public int max_value(int p_i, int p_layer) { int i = Math.max(p_i, 0); i = Math.min(i, class_count - 1); int layer = Math.max(p_layer, 0); layer = Math.min(layer, layer_structure.arr.length - 1); return row[i].max_value[layer]; } public int max_value(int p_layer) { int layer = Math.max(p_layer, 0); layer = Math.min(layer, layer_structure.arr.length - 1); return this.max_value_on_layer[layer]; } /** * Returns true, if the values of the clearance matrix * in the p_i-th column and the p_j-th row are not equal on all layers. */ public boolean is_layer_dependent(int p_i, int p_j) { int compare_value = row[p_j].column[p_i].layer[0]; for (int l = 1; l < layer_structure.arr.length; ++l) { if (row[p_j].column[p_i].layer[l] != compare_value) { return true; } } return false; } /** * Returns true, if the values of the clearance matrix * in the p_i-th column and the p_j-th row are not equal on all inner layers. */ public boolean is_inner_layer_dependent(int p_i, int p_j) { if (layer_structure.arr.length <= 2) { return false; // no inner layers } int compare_value = row[p_j].column[p_i].layer[1]; for (int l = 2; l < layer_structure.arr.length - 1; ++l) { if (row[p_j].column[p_i].layer[l] != compare_value) { return true; } } return false; } /** * Returns the row with index p_no */ public Row get_row(int p_no) { if (p_no < 0 || p_no >= this.row.length) { System.out.println("ClearanceMatrix.get_row: p_no out of range"); return null; } return this.row[p_no]; } public int get_class_count() { return this.class_count; } /** * Return the layer count of this clearance matrix;# */ public int get_layer_count() { return layer_structure.arr.length; } /** * Return the clearance compensation value of p_clearance_class_no on layer p_layer. */ public int clearance_compensation_value(int p_clearance_class_no, int p_layer) { return (this.value(p_clearance_class_no, p_clearance_class_no, p_layer) + 1)/ 2; } /** * Appends a new clearance class to the clearence matrix and * initializes it with the values of the default class. * Returns false, oif a clearance class with name p_class_name is already existing. */ public boolean append_class(String p_class_name) { if (this.get_no(p_class_name) >= 0) { return false; } int old_class_count = this.class_count; ++this.class_count; Row [] new_row = new Row [this.class_count]; // append a matrix entry to each old row for (int i = 0; i < old_class_count; ++i) { Row curr_old_row = this.row[i]; new_row[i] = new Row(curr_old_row.name); Row curr_new_row = new_row[i]; curr_new_row.max_value = curr_old_row.max_value; for (int j = 0; j < old_class_count; ++j) { curr_new_row.column[j] = curr_old_row.column[j]; } curr_new_row.column[old_class_count] = new MatrixEntry(); } // append the new row new_row [old_class_count] = new Row(p_class_name); this.row = new_row; // Set the new matrix elements to default values. for (int i = 0; i < old_class_count; ++i) { for (int j = 0; j < this.layer_structure.arr.length; ++j) { int default_value = this.value(1, i, j); this.set_value(old_class_count, i, j, default_value); this.set_value(i, old_class_count, j, default_value); } } for (int j = 0; j < this.layer_structure.arr.length; ++j) { int default_value = this.value(1, 1, j); this.set_value(old_class_count, old_class_count, j, default_value); } return true; } /** * Removes the class with index p_index from the clearance matrix. */ void remove_class(int p_index) { int old_class_count = this.class_count; --this.class_count; Row [] new_row = new Row [this.class_count]; // remove the matrix entry with inded p_index in to each old row int new_row_index = 0; for (int i = 0; i < old_class_count; ++i) { if (i == p_index) { continue; } Row curr_old_row = this.row[i]; new_row[new_row_index] = new Row(curr_old_row.name); Row curr_new_row = new_row[new_row_index]; int new_column_index = 0; for (int j = 0; j < old_class_count; ++j) { if (j == p_index) { continue; } curr_new_row.column[new_column_index] = curr_old_row.column[j]; ++new_column_index; } ++new_row_index; } this.row = new_row; } /** * Returns true, if all clearance values of the class with index p_1 are equal to * the clearance values of index p_2. */ public boolean is_equal(int p_1, int p_2) { if (p_1 == p_2) { return true; } if (p_1 < 0 || p_2 < 0 || p_1 >= this.class_count || p_2 >= this.class_count) { return false; } Row row_1 = this.row[p_1]; Row row_2 = this.row[p_2]; for (int i = 1; i < class_count; ++i) { if (!row_1.column[i].equals(row_2.column[i])) { return false; } } return true; } /** * count of clearance classes */ private int class_count; private final board.LayerStructure layer_structure; private Row [] row; // vector of class_count rows of the clearance matrix private int [] max_value_on_layer; // maximum clearance value for each layer /** * contains a row of entries of the clearance matrix */ private class Row implements board.ObjectInfoPanel.Printable, java.io.Serializable { private Row(String p_name) { name = p_name; column = new MatrixEntry [class_count]; for (int i = 0; i < class_count; ++i) { column[i] = new MatrixEntry(); } max_value = new int[layer_structure.arr.length]; } public void print_info(board.ObjectInfoPanel p_window, java.util.Locale p_locale) { java.util.ResourceBundle resources = java.util.ResourceBundle.getBundle("board.resources.ObjectInfoPanel", p_locale); p_window.append_bold(resources.getString("spacing_from_clearance_class") + " "); p_window.append_bold(this.name); for (int i = 1; i < this.column.length; ++i) { p_window.newline(); p_window.indent(); p_window.append(" " + resources.getString("to_class") + " "); p_window.append(row[i].name); MatrixEntry curr_column = this.column[i]; if (curr_column.is_layer_dependent()) { p_window.append(" " + resources.getString("on_layer") + " "); for (int j = 0; j < layer_structure.arr.length; ++j) { p_window.newline(); p_window.indent(); p_window.indent(); p_window.append(layer_structure.arr[j].name); p_window.append(" = "); p_window.append(curr_column.layer[j]); } } else { p_window.append(" = "); p_window.append(curr_column.layer[0]); } } } final String name; int [] max_value; final MatrixEntry [] column; } /** * a single entry of the clearance matrix */ private class MatrixEntry implements java.io.Serializable { private MatrixEntry() { layer = new int [layer_structure.arr.length]; for (int i = 0; i < layer_structure.arr.length; ++i) { layer[i] = 0; } } /** * Returns thrue of all clearances values of this and p_other are equal. */ boolean equals(MatrixEntry p_other) { for (int i = 0; i < layer_structure.arr.length; ++i) { if (this.layer[i] != p_other.layer[i]) { return false; } } return true; } /** * Return true, if not all layer values are equal. */ boolean is_layer_dependent() { int compare_value = layer[0]; for (int i = 1; i < layer_structure.arr.length; ++i) { if (layer[i] != compare_value) { return true; } } return false; } int [] layer; } }