/* * 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. * * HoleConstructionState.java * * Created on 7. November 2003, 18:40 */ package interactive; import geometry.planar.Area; import geometry.planar.Circle; import geometry.planar.FloatPoint; import geometry.planar.IntPoint; import geometry.planar.PolygonShape; import geometry.planar.PolylineArea; import geometry.planar.PolylineShape; import geometry.planar.Shape; import java.util.Iterator; import board.ObstacleArea; import board.ItemSelectionFilter; /** * Interactive cutting a hole into an obstacle shape * * @author Alfons Wirtz */ public class HoleConstructionState extends CornerItemConstructionState { /** * Returns a new instance of this class or null, * if that was not possible with the input parameters. * If p_logfile != null, the construction of this hole is stored in a logfile. */ public static HoleConstructionState get_instance(FloatPoint p_location, InteractiveState p_parent_state, BoardHandling p_board_handling, Logfile p_logfile) { HoleConstructionState new_instance = new HoleConstructionState(p_parent_state, p_board_handling, p_logfile); if (!new_instance.start_ok(p_location)) { new_instance = null; } return new_instance; } /** Creates a new instance of HoleConstructionState */ private HoleConstructionState(InteractiveState p_parent_state, BoardHandling p_board_handling, Logfile p_logfile) { super(p_parent_state, p_board_handling, p_logfile); } /** * Looks for an obstacle area to modify * Returns false, if it cannot find one. */ private boolean start_ok(FloatPoint p_location) { IntPoint pick_location = p_location.round(); ItemSelectionFilter.SelectableChoices[] selectable_choices = { ItemSelectionFilter.SelectableChoices.KEEPOUT, ItemSelectionFilter.SelectableChoices.VIA_KEEPOUT, ItemSelectionFilter.SelectableChoices.CONDUCTION }; ItemSelectionFilter selection_filter = new ItemSelectionFilter(selectable_choices); java.util.Collection<board.Item> found_items = hdlg.get_routing_board().pick_items(pick_location, hdlg.settings.layer, selection_filter); if (found_items.size() != 1) { hdlg.screen_messages.set_status_message(resources.getString("no_item_found_for_adding_hole")); return false; } board.Item found_item = found_items.iterator().next(); if (!(found_item instanceof ObstacleArea)) { hdlg.screen_messages.set_status_message(resources.getString("no_obstacle_area_found_for_adding_hole")); return false; } this.item_to_modify = (ObstacleArea)found_item; if (item_to_modify.get_area() instanceof Circle) { hdlg.screen_messages.set_status_message(resources.getString("adding_hole_to_circle_not_yet_implemented")); return false; } if (this.logfile != null) { logfile.start_scope(LogfileScope.ADDING_HOLE); } this.add_corner(p_location); return true; } /** * Adds a corner to the polygon of the the hole under construction. */ public InteractiveState left_button_clicked(FloatPoint p_next_corner) { if (item_to_modify == null) { return this.return_state; } if(item_to_modify.get_area().contains(p_next_corner)) { super.add_corner(p_next_corner); hdlg.repaint(); } return this; } /** * adds the just constructed hole to the item under modification, * if that is possible without clearance violations */ public InteractiveState complete() { if (item_to_modify == null) { return this.return_state; } add_corner_for_snap_angle(); int corner_count = corner_list.size(); boolean construction_succeeded = (corner_count > 2); PolylineShape [] new_holes = null; PolylineShape new_border = null; if (construction_succeeded) { Area obs_area = item_to_modify.get_area(); Shape[] old_holes = obs_area.get_holes(); new_border = (PolylineShape)obs_area.get_border(); if (new_border == null) { construction_succeeded = false; } else { new_holes = new PolylineShape[old_holes.length + 1]; for (int i = 0; i < old_holes.length; ++i) { new_holes[i] = (PolylineShape)old_holes[i]; if (new_holes[i] == null) { construction_succeeded = false; break; } } } } if (construction_succeeded) { IntPoint [] new_hole_corners = new IntPoint[corner_count]; Iterator<IntPoint> it = corner_list.iterator(); for (int i = 0; i < corner_count ; ++i) { new_hole_corners[i] = it.next(); } new_holes[new_holes.length - 1] = new PolygonShape(new_hole_corners); PolylineArea new_obs_area = new PolylineArea(new_border, new_holes); if (new_obs_area.split_to_convex() == null) { // shape is invalid, maybe it has selfintersections construction_succeeded = false; } else { this.observers_activated = !hdlg.get_routing_board().observers_active(); if (this.observers_activated) { hdlg.get_routing_board().start_notify_observers(); } hdlg.get_routing_board().generate_snapshot(); hdlg.get_routing_board().remove_item( item_to_modify); hdlg.get_routing_board().insert_obstacle(new_obs_area, item_to_modify.get_layer(), item_to_modify.clearance_class_no(), board.FixedState.UNFIXED); if (this.observers_activated) { hdlg.get_routing_board().end_notify_observers(); this.observers_activated = false; } } } if (construction_succeeded) { hdlg.screen_messages.set_status_message(resources.getString("adding_hole_completed")); } else { hdlg.screen_messages.set_status_message(resources.getString("adding_hole_failed")); } if (logfile != null) { logfile.start_scope(LogfileScope.COMPLETE_SCOPE); } return this.return_state; } public void display_default_message() { hdlg.screen_messages.set_status_message(resources.getString("adding_hole_to_obstacle_area")); } private ObstacleArea item_to_modify = null; }