freerouting/src/main/java/eu/mihosoft/freerouting/board/MoveComponent.java

235 lines
8.4 KiB
Java

/*
* 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.
*
* MoveItemGroup.java
*
* Created on 25. Oktober 2003, 09:03
*/
package eu.mihosoft.freerouting.board;
import eu.mihosoft.freerouting.datastructures.TimeLimit;
import eu.mihosoft.freerouting.geometry.planar.FloatPoint;
import eu.mihosoft.freerouting.geometry.planar.IntPoint;
import eu.mihosoft.freerouting.geometry.planar.Point;
import eu.mihosoft.freerouting.geometry.planar.Vector;
import java.util.Collection;
import java.util.Iterator;
import java.util.LinkedList;
import eu.mihosoft.freerouting.datastructures.Signum;
/**
* Class for moving a group of items on the eu.mihosoft.freerouting.board
* @author Alfons Wirtz
*/
public class MoveComponent
{
/** Creates a new instance of MoveItemGroup */
public MoveComponent(Item p_item, Vector p_translate_vector, int p_max_recursion_depth, int p_max_via_recursion_depth)
{
translate_vector = p_translate_vector;
max_recursion_depth = p_max_recursion_depth;
max_via_recursion_depth = p_max_via_recursion_depth;
if (p_item.board instanceof RoutingBoard)
{
board = (RoutingBoard) p_item.board;
}
else
{
board = null;
all_items_movable = false;
}
Collection<Item> item_group_list;
int component_no = p_item.get_component_no();
if (component_no > 0)
{
item_group_list = board.get_component_items(component_no);
this.component = board.components.get(component_no);
}
else
{
item_group_list = new LinkedList<Item>();
item_group_list.add(p_item);
}
Collection<FloatPoint> item_centers = new LinkedList<FloatPoint>();
for (Item curr_item : item_group_list)
{
boolean curr_item_movable = !curr_item.is_user_fixed() && ((curr_item instanceof DrillItem) || (curr_item instanceof ObstacleArea) || (curr_item instanceof ComponentOutline));
if (!curr_item_movable)
{
// MoveItemGroup currently only implemented for DrillItems
all_items_movable = false;
return;
}
if (curr_item instanceof DrillItem)
{
item_centers.add(((DrillItem) curr_item).get_center().to_float());
}
}
// calculate the gravity point of all item centers
double gravity_x = 0;
double gravity_y = 0;
for (FloatPoint curr_center : item_centers)
{
gravity_x += curr_center.x;
gravity_y += curr_center.y;
}
gravity_x /= item_centers.size();
gravity_y /= item_centers.size();
Point gravity_point = new IntPoint((int) Math.round(gravity_x), (int) Math.round(gravity_y));
item_group_arr = new SortedItem[item_group_list.size()];
Iterator<Item> it = item_group_list.iterator();
for (int i = 0; i < item_group_arr.length; ++i)
{
Item curr_item = it.next();
Point item_center;
if (curr_item instanceof DrillItem)
{
item_center = ((DrillItem) curr_item).get_center();
}
else
{
item_center = curr_item.bounding_box().centre_of_gravity().round();
}
Vector compare_vector = gravity_point.difference_by(item_center);
double curr_projection = compare_vector.scalar_product(translate_vector);
item_group_arr[i] = new SortedItem(curr_item, curr_projection);
}
// sort the items, in the direction of p_translate_vector, so that
// the items in front come first.
java.util.Arrays.sort(item_group_arr);
}
/**
* Checks, if all items in the group can be moved by shoving obstacle trace aside
* without creating clearance violations.
*/
public boolean check()
{
if (!all_items_movable)
{
return false;
}
TimeLimit time_limit = new TimeLimit(CHECK_TIME_LIMIT);
Collection<Item> ignore_items = new LinkedList<Item>();
for (int i = 0; i < item_group_arr.length; ++i)
{
boolean move_ok;
if (item_group_arr[i].item instanceof DrillItem)
{
DrillItem curr_drill_item = (DrillItem) item_group_arr[i].item;
if (this.translate_vector.length_approx() >= curr_drill_item.min_width())
{
// a clearance violation with a connecting trace may occur
move_ok = false;
}
else
{
move_ok = MoveDrillItemAlgo.check(curr_drill_item, this.translate_vector,
this.max_recursion_depth, this.max_via_recursion_depth,
ignore_items, board, time_limit);
}
}
else
{
move_ok = board.check_move_item(item_group_arr[i].item, this.translate_vector, ignore_items);
}
if (!move_ok)
{
return false;
}
}
return true;
}
/**
* Moves all items in the group by this.translate_vector and shoves aside
* obstacle traces. Returns false, if that was not possible without
* creating clearance violations. In this case an undo may be necessary.
*/
public boolean insert(int p_tidy_width, int p_pull_tight_accuracy)
{
if (!all_items_movable)
{
return false;
}
if (this.component != null)
{
// component must be moved first, so that the new pin shapes are calculeted correctly
board.components.move(this.component.no, translate_vector);
// let the observers syncronize the moving
board.communication.observers.notify_moved(this.component);
}
for (int i = 0; i < item_group_arr.length; ++i)
{
if (item_group_arr[i].item instanceof DrillItem)
{
DrillItem curr_drill_item = (DrillItem) item_group_arr[i].item;
boolean move_ok = board.move_drill_item(curr_drill_item,
this.translate_vector, this.max_recursion_depth, this.max_via_recursion_depth,
p_tidy_width, p_pull_tight_accuracy, PULL_TIGHT_TIME_LIMIT);
if (!move_ok)
{
if (this.component != null)
{
this.component.translate_by(translate_vector.negate());
// Otherwise the component outline is not restored correctly by the undo algorithm.
}
return false;
}
}
else
{
item_group_arr[i].item.move_by(this.translate_vector);
}
}
return true;
}
private final Vector translate_vector;
private final int max_recursion_depth;
private final int max_via_recursion_depth;
private final RoutingBoard board;
private boolean all_items_movable = true;
private SortedItem[] item_group_arr;
private Component component = null;
private static int PULL_TIGHT_TIME_LIMIT = 1000;
private static int CHECK_TIME_LIMIT = 3000;
/**
* used to sort the group items in the direction of translate_vector,
* so that the front items can be moved first.
*/
private static class SortedItem implements Comparable<SortedItem>
{
SortedItem(Item p_item, double p_projection)
{
item = p_item;
projection = p_projection;
}
public int compareTo(SortedItem p_other)
{
return Signum.as_int(this.projection - p_other.projection);
}
final Item item;
final double projection;
}
}