/* * 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 autoroute; import java.util.Collection; import java.util.SortedSet; import datastructures.TimeLimit; import geometry.planar.FloatPoint; import board.RoutingBoard; import interactive.InteractiveActionThread; /** * Handles the sequencing of the fanout inside the batch autorouter. * * @author Alfons Wirtz */ public class BatchFanout { public static void fanout_board(InteractiveActionThread p_thread) { BatchFanout fanout_instance = new BatchFanout(p_thread); final int MAX_PASS_COUNT = 20; for (int i = 0; i < MAX_PASS_COUNT; ++i) { int routed_count = fanout_instance.fanout_pass(i); if (routed_count == 0) { break; } } } private BatchFanout(InteractiveActionThread p_thread) { this.thread = p_thread; this.routing_board = p_thread.hdlg.get_routing_board(); Collection<board.Pin> board_smd_pin_list = routing_board.get_smd_pins(); this.sorted_components = new java.util.TreeSet<Component>(); for (int i = 1; i <= routing_board.components.count(); ++i) { board.Component curr_board_component = routing_board.components.get(i); Component curr_component = new Component(curr_board_component, board_smd_pin_list); if (curr_component.smd_pin_count > 0) { sorted_components.add(curr_component); } } } /** * Routes a fanout pass and returns the number of new fanouted SMD-pins * in this pass. */ private int fanout_pass(int p_pass_no) { int components_to_go = this.sorted_components.size(); int routed_count = 0; int not_routed_count = 0; int insert_error_count = 0; int ripup_costs = this.thread.hdlg.get_settings().autoroute_settings.get_start_ripup_costs() * (p_pass_no + 1); for (Component curr_component : this.sorted_components) { this.thread.hdlg.screen_messages.set_batch_fanout_info(p_pass_no + 1, components_to_go); for (Component.Pin curr_pin : curr_component.smd_pins) { double max_milliseconds = 10000 * (p_pass_no + 1); TimeLimit time_limit = new TimeLimit((int) max_milliseconds); this.routing_board.start_marking_changed_area(); AutorouteEngine.AutorouteResult curr_result = this.routing_board.fanout(curr_pin.board_pin, this.thread.hdlg.get_settings(), ripup_costs, this.thread, time_limit); if (curr_result == AutorouteEngine.AutorouteResult.ROUTED) { ++routed_count; } else if (curr_result == AutorouteEngine.AutorouteResult.NOT_ROUTED) { ++not_routed_count; } else if (curr_result == AutorouteEngine.AutorouteResult.INSERT_ERROR) { ++insert_error_count; } if (curr_result != AutorouteEngine.AutorouteResult.NOT_ROUTED) { this.thread.hdlg.repaint(); } if (this.thread.is_stop_requested()) { return routed_count; } } --components_to_go; } if (this.routing_board.get_test_level() != board.TestLevel.RELEASE_VERSION) { System.out.println("fanout pass: " + (p_pass_no + 1) + ", routed: " + routed_count + ", not routed: " + not_routed_count + ", errors: " + insert_error_count); } return routed_count; } private final InteractiveActionThread thread; private final RoutingBoard routing_board; private static class Component implements Comparable<Component> { Component(board.Component p_board_component, Collection<board.Pin> p_board_smd_pin_list) { this.board_component = p_board_component; // calcoulate the center of gravity of all SMD pins of this component. Collection<board.Pin> curr_pin_list = new java.util.LinkedList<board.Pin>(); int cmp_no = p_board_component.no; for (board.Pin curr_board_pin : p_board_smd_pin_list) { if (curr_board_pin.get_component_no() == cmp_no) { curr_pin_list.add(curr_board_pin); } } double x = 0; double y = 0; for (board.Pin curr_pin : curr_pin_list) { FloatPoint curr_point = curr_pin.get_center().to_float(); x += curr_point.x; y += curr_point.y; } this.smd_pin_count = curr_pin_list.size(); x /= this.smd_pin_count; y /= this.smd_pin_count; this.gravity_center_of_smd_pins = new FloatPoint(x, y); // calculate the sorted SMD pins of this component this.smd_pins = new java.util.TreeSet<Pin>(); for (board.Pin curr_board_pin : curr_pin_list) { this.smd_pins.add(new Pin(curr_board_pin)); } } /** * Sort the components, so that components with maor pins come first */ public int compareTo(Component p_other) { int compare_value = this.smd_pin_count - p_other.smd_pin_count; int result; if (compare_value > 0) { result = -1; } else if (compare_value < 0) { result = 1; } else { result = this.board_component.no - p_other.board_component.no; } return result; } final board.Component board_component; final int smd_pin_count; final SortedSet<Pin> smd_pins; /** The center of gravity of all SMD pins of this component. */ final FloatPoint gravity_center_of_smd_pins; class Pin implements Comparable<Pin> { Pin(board.Pin p_board_pin) { this.board_pin = p_board_pin; FloatPoint pin_location = p_board_pin.get_center().to_float(); this.distance_to_component_center = pin_location.distance(gravity_center_of_smd_pins); } public int compareTo(Pin p_other) { int result; double delta_dist = this.distance_to_component_center - p_other.distance_to_component_center; if (delta_dist > 0) { result = 1; } else if (delta_dist < 0) { result = -1; } else { result = this.board_pin.pin_no - p_other.board_pin.pin_no; } return result; } final board.Pin board_pin; final double distance_to_component_center; } } private final SortedSet<Component> sorted_components; }