/*
* CohenSutherland.java
* --------------------
* (c) 2007 by Intevation GmbH
*
* @author Sascha L. Teichmann (teichmann@intevation.de)
* @author Ludwig Reiter (ludwig@intevation.de)
*
* This program is free software under the LGPL (>=v2.1)
* Read the file LICENSE.txt coming with the sources for details.
*/
package technology.tabula;
import java.awt.geom.Rectangle2D;
import java.awt.geom.Line2D;
/**
* Implements the well known Cohen Sutherland line
* clipping algorithm (line against clip rectangle).
*/
public final class CohenSutherlandClipping
{
private double xMin;
private double yMin;
private double xMax;
private double yMax;
/**
* Creates a Cohen Sutherland clipper with clip rect (0, 0, 0, 0).
*/
public CohenSutherlandClipping() {
}
/**
* Creates a Cohen Sutherland clipper with the given clip rectangle.
* @param clip the clip rectangle to use
*/
public CohenSutherlandClipping(Rectangle2D clip) {
setClip(clip);
}
/**
* Sets the clip rectangle.
* @param clip the clip rectangle
*/
public void setClip(Rectangle2D clip) {
xMin = clip.getX();
xMax = xMin + clip.getWidth();
yMin = clip.getY();
yMax = yMin + clip.getHeight();
}
private static final int INSIDE = 0;
private static final int LEFT = 1;
private static final int RIGHT = 2;
private static final int BOTTOM = 4;
private static final int TOP = 8;
private final int regionCode(double x, double y) {
int code = x < xMin
? LEFT
: x > xMax
? RIGHT
: INSIDE;
if (y < yMin) code |= BOTTOM;
else if (y > yMax) code |= TOP;
return code;
}
/**
* Clips a given line against the clip rectangle.
* The modification (if needed) is done in place.
* @param line the line to clip
* @return true if line is clipped, false if line is
* totally outside the clip rect.
*/
public boolean clip(Line2D.Float line) {
double p1x = line.getX1();
double p1y = line.getY1();
double p2x = line.getX2();
double p2y = line.getY2();
double qx = 0d;
double qy = 0d;
boolean vertical = p1x == p2x;
double slope = vertical
? 0d
: (p2y-p1y)/(p2x-p1x);
int c1 = regionCode(p1x, p1y);
int c2 = regionCode(p2x, p2y);
while (c1 != INSIDE || c2 != INSIDE) {
if ((c1 & c2) != INSIDE)
return false;
int c = c1 == INSIDE ? c2 : c1;
if ((c & LEFT) != INSIDE) {
qx = xMin;
qy = (Utils.feq(qx, p1x) ? 0 : qx-p1x)*slope + p1y;
}
else if ((c & RIGHT) != INSIDE) {
qx = xMax;
qy = (Utils.feq(qx, p1x) ? 0 : qx-p1x)*slope + p1y;
}
else if ((c & BOTTOM) != INSIDE) {
qy = yMin;
qx = vertical
? p1x
: (Utils.feq(qy, p1y) ? 0 : qy-p1y)/slope + p1x;
}
else if ((c & TOP) != INSIDE) {
qy = yMax;
qx = vertical
? p1x
: (Utils.feq(qy, p1y) ? 0 : qy-p1y)/slope + p1x;
}
if (c == c1) {
p1x = qx;
p1y = qy;
c1 = regionCode(p1x, p1y);
}
else {
p2x = qx;
p2y = qy;
c2 = regionCode(p2x, p2y);
}
}
line.setLine(p1x, p1y, p2x, p2y);
return true;
}
}
// end of file