/*
* 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 board;
import geometry.planar.FloatPoint;
import geometry.planar.IntBox;
import geometry.planar.IntOctagon;
/**
*
* Used internally for marking changed areas on the board
* after shoving and optimizing items.
*
* @author Alfons Wirtz
*/
class ChangedArea
{
public ChangedArea(int p_layer_count)
{
layer_count = p_layer_count;
arr = new MutableOctagon [layer_count];
// initialise all octagons to empty
for (int i = 0; i < layer_count; ++i)
{
arr[i] = new MutableOctagon();
arr[i].set_empty();
}
}
/**
* enlarges the octagon on p_layer, so that it contains p_point
*/
public void join (FloatPoint p_point, int p_layer)
{
MutableOctagon curr = arr[p_layer];
curr.lx = Math.min(p_point.x, curr.lx);
curr.ly = Math.min(p_point.y, curr.ly);
curr.rx = Math.max(curr.rx, p_point.x);
curr.uy = Math.max(curr.uy, p_point.y);
double tmp = p_point.x - p_point.y;
curr.ulx = Math.min(curr.ulx, tmp);
curr.lrx = Math.max(curr.lrx, tmp);
tmp = p_point.x + p_point.y;
curr.llx = Math.min(curr.llx, tmp);
curr.urx = Math.max(curr.urx, tmp);
}
/**
* enlarges the octagon on p_layer, so that it contains p_shape
*/
public void join (geometry.planar.TileShape p_shape, int p_layer)
{
if (p_shape == null)
{
return;
}
int corner_count = p_shape.border_line_count();
for (int i = 0; i < corner_count; ++i)
{
join(p_shape.corner_approx(i), p_layer);
}
}
/**
* get the marking octagon on layer p_layer
*/
public IntOctagon get_area (int p_layer)
{
return arr[p_layer].to_int();
}
public IntBox surrounding_box()
{
int llx = Integer.MAX_VALUE;
int lly = Integer.MAX_VALUE;
int urx = Integer.MIN_VALUE;
int ury = Integer.MIN_VALUE;
for (int i = 0; i < layer_count; ++i)
{
MutableOctagon curr = arr[i];
llx = Math.min (llx, (int)Math.floor(curr.lx));
lly = Math.min (lly, (int)Math.floor(curr.ly));
urx = Math.max (urx, (int)Math.ceil(curr.rx));
ury = Math.max (ury, (int)Math.ceil(curr.uy));
}
if (llx > urx || lly > ury)
{
return IntBox.EMPTY;
}
return new IntBox(llx, lly, urx, ury);
}
/**
* inizialises the marking octagon on p_layer to empty
*/
void set_empty(int p_layer)
{
arr[p_layer].set_empty();
}
final int layer_count;
MutableOctagon [] arr;
/**
* mutable octagon with double coordinates (see geometry.planar.IntOctagon)
*/
private static class MutableOctagon
{
double lx;
double ly;
double rx;
double uy;
double ulx;
double lrx;
double llx;
double urx;
void set_empty()
{
lx = Integer.MAX_VALUE;
ly = Integer.MAX_VALUE;
rx = Integer.MIN_VALUE;
uy = Integer.MIN_VALUE;
ulx = Integer.MAX_VALUE;
lrx = Integer.MIN_VALUE;
llx = Integer.MAX_VALUE;
urx = Integer.MIN_VALUE;
}
/**
* calculates the smallest IntOctagon containing this octagon.
*/
IntOctagon to_int()
{
if (rx < lx || uy < ly || lrx < ulx || urx < llx)
{
return IntOctagon.EMPTY;
}
return new IntOctagon ((int)Math.floor(lx), (int)Math.floor(ly),
(int)Math.ceil(rx), (int)Math.ceil(uy),
(int)Math.floor(ulx), (int)Math.ceil(lrx),
(int)Math.floor(llx), (int)Math.ceil(urx));
}
}
}