/* * 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. * * CopyItemState.java * * Created on 11. November 2003, 08:23 */ package interactive; import geometry.planar.FloatPoint; import geometry.planar.Point; import geometry.planar.Vector; import geometry.planar.ConvexShape; import java.util.Collection; import java.util.Iterator; import java.util.LinkedList; import java.util.Map; import java.util.TreeMap; import library.Padstack; import library.Package; import board.Item; import board.DrillItem; import board.ObstacleArea; import board.Via; import board.Component; import board.RoutingBoard; /** * Interactive copying of items. * * @author Alfons Wirtz */ public class CopyItemState extends InteractiveState { /** * Returns a new instance of CopyItemState or null, if p_item_list is empty. */ public static CopyItemState get_instance(FloatPoint p_location, Collection<Item> p_item_list, InteractiveState p_parent_state, BoardHandling p_board_handling, Logfile p_logfile) { if (p_item_list.size() == 0) { return null; } p_board_handling.remove_ratsnest(); // copying an item may change the connectivity. return new CopyItemState(p_location, p_item_list, p_parent_state, p_board_handling, p_logfile); } /** Creates a new instance of CopyItemState */ private CopyItemState(FloatPoint p_location, Collection<Item> p_item_list, InteractiveState p_parent_state, BoardHandling p_board_handling, Logfile p_logfile) { super(p_parent_state, p_board_handling, p_logfile); item_list = new LinkedList<Item>(); start_position = p_location.round(); current_layer = p_board_handling.settings.layer; layer_changed = false; current_position = start_position; previous_position = current_position; Iterator<Item> it = p_item_list.iterator(); while (it.hasNext()) { Item curr_item = it.next(); if (curr_item instanceof DrillItem || curr_item instanceof ObstacleArea) { Item new_item = curr_item.copy(0); item_list.add(new_item); } } if (logfile != null) { logfile.start_scope(LogfileScope.COPYING_ITEMS, p_location); } } public InteractiveState mouse_moved() { super.mouse_moved(); change_position(hdlg.get_current_mouse_position()); return this; } /** * Changes the position for inserting the copied items to p_new_location. */ private void change_position(FloatPoint p_new_position) { current_position = p_new_position.round(); if (!current_position.equals(previous_position)) { Vector translate_vector = current_position.difference_by(previous_position); Iterator<board.Item> it = item_list.iterator(); while (it.hasNext()) { board.Item curr_item = it.next(); curr_item.translate_by(translate_vector); } previous_position = current_position; hdlg.repaint(); } } /** * Changes the first layer of the items in the copy list to p_new_layer. */ public boolean change_layer_action(int p_new_layer) { if (logfile != null) { logfile.start_scope(LogfileScope.CHANGE_LAYER, p_new_layer); } current_layer = p_new_layer; layer_changed = true; hdlg.set_layer(p_new_layer); return true; } /** * Inserts the items in the copy list into the board. * Items, which would produce a clearance violation, are not inserted. */ public void insert() { if (item_list == null) { return; } Map<Padstack, Padstack> padstack_pairs = new TreeMap<Padstack, Padstack>(); // Contains old and new padstacks after layer change. RoutingBoard board = hdlg.get_routing_board(); if (layer_changed) { // create new via padstacks Iterator<Item> it = item_list.iterator(); while (it.hasNext()) { Item curr_ob = it.next(); if (curr_ob instanceof Via) { Via curr_via = (Via) curr_ob; Padstack new_padstack = change_padstack_layers( curr_via.get_padstack(), current_layer, board, padstack_pairs); curr_via.set_padstack(new_padstack); } } } // Copy the components of the old items and assign the new items to the copied components. /** Contailns the old and new id no of a copied component. */ Map<Integer, Integer> cmp_no_pairs = new TreeMap<Integer, Integer>(); /** Contains the new created components after copying. */ Collection<Component> copied_components = new LinkedList<Component>(); Vector translate_vector = current_position.difference_by(start_position); Iterator<Item> it = item_list.iterator(); while (it.hasNext()) { Item curr_item = it.next(); int curr_cmp_no = curr_item.get_component_no(); if (curr_cmp_no > 0) { //This item belongs to a component int new_cmp_no; Integer curr_key = new Integer(curr_cmp_no); if (cmp_no_pairs.containsKey(curr_key)) { // the new component for this pin is already created Integer curr_value = cmp_no_pairs.get(curr_key); new_cmp_no = curr_value.intValue(); } else { Component old_component = board.components.get(curr_cmp_no); if (old_component == null) { System.out.println("CopyItemState: component not found"); continue; } Point new_location = old_component.get_location().translate_by(translate_vector); Package new_package; if (layer_changed) { // create a new package with changed layers of the padstacks. Package.Pin [] new_pin_arr = new Package.Pin[ old_component.get_package().pin_count()]; for (int i = 0; i < new_pin_arr.length; ++i) { Package.Pin old_pin = old_component.get_package().get_pin(i); Padstack old_padstack = board.library.padstacks.get(old_pin.padstack_no); if (old_padstack == null) { System.out.println("CopyItemState.insert: package padstack not found"); return; } Padstack new_padstack = change_padstack_layers( old_padstack, current_layer, board, padstack_pairs); new_pin_arr[i] = new Package.Pin(old_pin.name, new_padstack.no, old_pin.relative_location, old_pin.rotation_in_degree); } new_package = board.library.packages.add(new_pin_arr); } else { new_package = old_component.get_package(); } Component new_component = board.components.add(new_location, old_component.get_rotation_in_degree(), old_component.placed_on_front(), new_package); copied_components.add(new_component); new_cmp_no = new_component.no; cmp_no_pairs.put(new Integer(curr_cmp_no), new Integer(new_cmp_no)); } curr_item.assign_component_no(new_cmp_no); } } boolean all_items_inserted = true; it = item_list.iterator(); boolean first_time = true; while (it.hasNext()) { Item curr_item = it.next(); if (curr_item.board != null && curr_item.clearance_violation_count() == 0) { if (first_time) { // make the current situation restorable by undo board.generate_snapshot(); first_time = false; } board.insert_item(curr_item.copy(0)); } else { all_items_inserted = false; } } if (all_items_inserted) { hdlg.screen_messages.set_status_message(resources.getString("all_items_inserted")); } else { hdlg.screen_messages.set_status_message(resources.getString("some_items_not_inserted_because_of_obstacles")); } if (logfile != null) { logfile.add_corner(this.current_position.to_float()); } start_position = current_position; layer_changed = false; hdlg.repaint(); } public InteractiveState left_button_clicked(FloatPoint p_location) { insert(); return this; } public InteractiveState process_logfile_point(FloatPoint p_location) { change_position(p_location); insert(); return this; } public void draw(java.awt.Graphics p_graphics) { if (item_list == null) { return; } Iterator<Item> it = item_list.iterator(); while (it.hasNext()) { Item curr_item = it.next(); curr_item.draw(p_graphics, hdlg.graphics_context, hdlg.graphics_context.get_hilight_color(), hdlg.graphics_context.get_hilight_color_intensity()); } } public javax.swing.JPopupMenu get_popup_menu() { return hdlg.get_panel().popup_menu_copy; } /** * Creates a new padstack from p_old_pastack with a layer range starting at p_new_layer. */ private static Padstack change_padstack_layers(Padstack p_old_padstack, int p_new_layer, RoutingBoard p_board, Map<Padstack, Padstack> p_padstack_pairs) { Padstack new_padstack; int old_layer = p_old_padstack.from_layer(); if (old_layer == p_new_layer) { new_padstack = p_old_padstack; } else if (p_padstack_pairs.containsKey(p_old_padstack)) { // New padstack already created, assign it to the via. new_padstack = p_padstack_pairs.get(p_old_padstack); } else { // Create a new padstack. ConvexShape[] new_shapes = new ConvexShape[p_board.get_layer_count()]; int layer_diff = old_layer - p_new_layer; for (int i = 0; i < new_shapes.length; ++i) { int new_layer_no = i + layer_diff; if (new_layer_no >= 0 && new_layer_no < new_shapes.length) { new_shapes[i] = p_old_padstack.get_shape(i + layer_diff); } } new_padstack = p_board.library.padstacks.add(new_shapes); p_padstack_pairs.put(p_old_padstack, new_padstack); } return new_padstack; } private Collection<Item> item_list; private Point start_position; private Point current_position; private int current_layer; private boolean layer_changed; private Point previous_position; }