/* * 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. * * PullTight90.java * * Created on 19. Juli 2003, 18:54 */ package board; import datastructures.Stoppable; import geometry.planar.FloatPoint; import geometry.planar.Point; import geometry.planar.Line; import geometry.planar.Polyline; import geometry.planar.TileShape; /** * * @author Alfons Wirtz */ class PullTightAlgo90 extends PullTightAlgo { /** Creates a new instance of PullTight90 */ public PullTightAlgo90(RoutingBoard p_board, int[] p_only_net_no_arr, Stoppable p_stoppable_thread, int p_time_limit, Point p_keep_point, int p_keep_point_layer) { super(p_board, p_only_net_no_arr, p_stoppable_thread, p_time_limit, p_keep_point, p_keep_point_layer); } Polyline pull_tight(Polyline p_polyline) { Polyline new_result = avoid_acid_traps(p_polyline); Polyline prev_result = null; while (new_result != prev_result) { if (this.is_stop_requested()) { break; } prev_result = new_result; Polyline tmp1 = try_skip_second_corner(prev_result); Polyline tmp2 = try_skip_corners(tmp1); new_result = reposition_lines(tmp2); } return new_result; } /** * Tries to skip the second corner of p_polyline. * Return p_polyline, if nothing was changed. */ private Polyline try_skip_second_corner(Polyline p_polyline) { if (p_polyline.arr.length < 5) { return p_polyline; } Line[] check_lines = new Line[4]; check_lines[0] = p_polyline.arr[1]; check_lines[1] = p_polyline.arr[0]; check_lines[2] = p_polyline.arr[3]; check_lines[3] = p_polyline.arr[4]; Polyline check_polyline = new Polyline(check_lines); if (check_polyline.arr.length != 4 || curr_clip_shape != null && !curr_clip_shape.contains(check_polyline.corner_approx(1))) { return p_polyline; } for (int i = 0; i < 2; ++i) { TileShape shape_to_check = check_polyline.offset_shape(curr_half_width, i); if (!board.check_trace_shape(shape_to_check, curr_layer, curr_net_no_arr, curr_cl_type, this.contact_pins)) { return p_polyline; } } // now the second corner can be skipped. Line [] new_lines = new Line [p_polyline.arr.length - 1]; new_lines[0] = p_polyline.arr[1]; new_lines[1] = p_polyline.arr[0]; for (int i = 2; i < new_lines.length; ++i) { new_lines[i] = p_polyline.arr[i + 1]; } return new Polyline(new_lines); } /** * Tries to reduce the amount of corners of p_polyline. * Return p_polyline, if nothing was changed. */ private Polyline try_skip_corners(Polyline p_polyline) { Line [] new_lines = new Line [p_polyline.arr.length]; new_lines[0] = p_polyline.arr[0]; new_lines[1] = p_polyline.arr[1]; int new_line_index = 1; boolean polyline_changed = false; Line[] check_lines = new Line[4]; boolean second_last_corner_skipped = false; for (int i = 5; i <= p_polyline.arr.length; ++i) { boolean skip_lines = false; boolean in_clip_shape = curr_clip_shape == null || curr_clip_shape.contains(p_polyline.corner_approx(i - 3)); if (in_clip_shape) { check_lines[0] = new_lines[new_line_index - 1]; check_lines[1] = new_lines[new_line_index]; check_lines[2] = p_polyline.arr[i - 1]; if (i < p_polyline.arr.length) { check_lines[3] = p_polyline.arr[i]; } else { // use as concluding line the second last line check_lines[3] = p_polyline.arr[i - 2]; } Polyline check_polyline = new Polyline(check_lines); skip_lines = check_polyline.arr.length == 4 && (curr_clip_shape == null || curr_clip_shape.contains(check_polyline.corner_approx(1))); if (skip_lines) { TileShape shape_to_check = check_polyline.offset_shape(curr_half_width, 0); skip_lines = board.check_trace_shape(shape_to_check, curr_layer, curr_net_no_arr, curr_cl_type, this.contact_pins); } if (skip_lines) { TileShape shape_to_check = check_polyline.offset_shape(curr_half_width, 1); skip_lines = board.check_trace_shape(shape_to_check, curr_layer, curr_net_no_arr, curr_cl_type, this.contact_pins); } } if (skip_lines) { if (i == p_polyline.arr.length) { second_last_corner_skipped = true; } if (board.changed_area != null) { FloatPoint new_corner = check_lines[1].intersection_approx(check_lines[2]); board.changed_area.join(new_corner, curr_layer); FloatPoint skipped_corner = p_polyline.arr[i - 2].intersection_approx(p_polyline.arr[i - 3]); board.changed_area.join(skipped_corner, curr_layer); } polyline_changed = true; ++i; } else { ++new_line_index; new_lines [new_line_index ] = p_polyline.arr[i - 3]; } } if (!polyline_changed) { return p_polyline; } if (second_last_corner_skipped) { // The second last corner of p_polyline was skipped ++new_line_index; new_lines [new_line_index] = p_polyline.arr[ p_polyline.arr.length -1]; ++new_line_index; new_lines [new_line_index] = p_polyline.arr[ p_polyline.arr.length -2]; } else { for (int i = 3; i > 0; --i) { ++new_line_index; new_lines [new_line_index ] = p_polyline.arr[ p_polyline.arr.length - i]; } } Line [] cleaned_new_lines = new Line [new_line_index + 1]; System.arraycopy(new_lines, 0, cleaned_new_lines, 0, cleaned_new_lines.length); Polyline result = new Polyline(cleaned_new_lines); return result; } Polyline smoothen_start_corner_at_trace(PolylineTrace p_trace) { return null; } Polyline smoothen_end_corner_at_trace(PolylineTrace p_trace) { return null; } }