/**
* ORIPA - Origami Pattern Editor
* Copyright (C) 2005-2009 Jun Mitani http://mitani.cs.tsukuba.ac.jp/
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 for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package oripa.geom;
import javax.vecmath.Vector2d;
public class RectangleClipper {
final static int LEFT = 1;
final static int RIGHT = 2;
final static int TOP = 4;
final static int BOTTOM = 8;
private double m_minX;
private double m_minY;
private double m_maxX;
private double m_maxY;
public RectangleClipper(double x0, double y0, double x1, double y1) {
m_minX = x0;
m_minY = y0;
m_maxX = x1;
m_maxY = y1;
}
private int calcCode(double x, double y) {
int code = 0;
if (x < m_minX) {
code += LEFT;
}
if (x > m_maxX) {
code += RIGHT;
}
if (y < m_minY) {
code += TOP;
}
if (y > m_maxY) {
code += BOTTOM;
}
return code;
}
/*
* finding the coordinates after clipping
*/
private int calcClippedPoint(int code, OriLine l, Vector2d p) {
double cx, cy;
// Outside from the left edge of the window
if ((code & LEFT) != 0) {
cy = (l.p1.y - l.p0.y) * (m_minX - l.p0.x) / (l.p1.x - l.p0.x) + l.p0.y;
if ((cy >= m_minY) && (cy <= m_maxY)) {
p.x = m_minX;
p.y = cy;
return 1;
}
}
//Outside the right edge of the window
if ((code & RIGHT) != 0) {
cy = (l.p1.y - l.p0.y) * (m_maxX - l.p0.x) / (l.p1.x - l.p0.x) + l.p0.y;
if ((cy >= m_minY) && (cy <= m_maxY)) {
p.x = m_maxX;
p.y = cy;
return 1;
}
}
// Outside from the top of the window
if ((code & TOP) != 0) {
cx = (l.p1.x - l.p0.x) * (m_minY - l.p0.y) / (l.p1.y - l.p0.y) + l.p0.x;
if ((cx >= m_minX) && (cx <= m_maxX)) {
p.x = cx;
p.y = m_minY;
return 1;
}
}
// Outside from the bottom of the window
if ((code & BOTTOM) != 0) {
cx = (l.p1.x - l.p0.x) * (m_maxY - l.p0.y) / (l.p1.y - l.p0.y) + l.p0.x;
if ((cx >= m_minX) && (cx <= m_maxX)) {
p.x = cx;
p.y = m_maxY;
return 1;
}
}
return -1; // If it is not clipping, line segment is completely invisible
}
// Returns false if not included in the area
public boolean clip(OriLine l) {
if (Math.abs(l.p0.x - m_minX) < oripa.Constants.EPS && Math.abs(l.p1.x - m_minX) < oripa.Constants.EPS) {
return false;
}
if (Math.abs(l.p0.x - m_maxX) < oripa.Constants.EPS && Math.abs(l.p1.x - m_maxX) < oripa.Constants.EPS) {
return false;
}
if (Math.abs(l.p0.y - m_minY) < oripa.Constants.EPS && Math.abs(l.p1.y - m_minY) < oripa.Constants.EPS) {
return false;
}
if (Math.abs(l.p0.y - m_maxY) < oripa.Constants.EPS && Math.abs(l.p1.y - m_maxY) < oripa.Constants.EPS) {
return false;
}
int s_code = calcCode(l.p0.x, l.p0.y);
int e_code = calcCode(l.p1.x, l.p1.y);
if ((s_code == 0) && (e_code == 0)) {
return true;
}
if ((s_code & e_code) != 0) {
return false;
}
if (s_code != 0) {
if (calcClippedPoint(s_code, l, l.p0) < 0) {
return false;
}
}
if (e_code != 0) {
if (calcClippedPoint(e_code, l, l.p1) < 0) {
return false;
}
}
return true;
}
public boolean clipTest(OriLine l) {
int s_code = calcCode(l.p0.x, l.p0.y);
int e_code = calcCode(l.p1.x, l.p1.y);
if ((s_code == 0) && (e_code == 0)) {
return true;
}
if ((s_code & e_code) != 0) {
return false;
}
OriLine lcopy = new OriLine(l);
if (s_code != 0) {
if (calcClippedPoint(s_code, lcopy, lcopy.p0) < 0) {
return false;
}
}
if (e_code != 0) {
if (calcClippedPoint(e_code, lcopy, lcopy.p1) < 0) {
return false;
}
}
return true;
}
}