// **********************************************************************
//
// <copyright>
//
// BBN Technologies
// 10 Moulton Street
// Cambridge, MA 02138
// (617) 873-8000
//
// Copyright (C) BBNT Solutions LLC. All rights reserved.
//
// </copyright>
// **********************************************************************
//
// $Source: /cvs/distapps/openmap/src/openmap/com/bbn/openmap/proj/Clip.java,v $
// $RCSfile: Clip.java,v $
// $Revision: 1.3 $
// $Date: 2004/10/14 18:06:21 $
// $Author: dietrick $
//
// **********************************************************************
package com.bbn.openmap.proj;
/**
* Clipping functions.
*/
public class Clip {
// cannot construct
private Clip() {}
/**
* Calculate the float[] x,y buffer length for nverts.
* <p>
*
* @param nverts number of verts
* @return int length required
*
*/
public static final int liang_get_buflen(int nverts) {
//*2 for x,y pairs, *2 for potential extra points, +2 for
// closure,
//and +1 for return length
return (nverts << 2) + 3;
}
/**
* Liang Barsy polygon clipping algorithm.
* <p>
* Viewport: xleft < xright, ybottom < ytop
* <p>
* Set up with: <code>
* float[] ret_val = new float[n*2*2];
* ret_val = liang_clip(,...,ret_val);
* </code>
* <p>
* Points: xpoints, ypoints, npts HACK: closure on these points?
*
* @param xleft left side of viewport
* @param xright right side of viewport
* @param ytop top of viewport
* @param ybottom bottom of viewport
* @param x float[] x coords
* @param y float[] y coords
* @param n numcoords
* @param ret_val float[] clipped polygon
* @see #liang_get_buflen
*
*/
public static final float[] liang_clip(int xleft, int xright, int ytop,
int ybottom, float[] x, float[] y, int n,
float[] ret_val) {
int i, num = 0;
double dx, dy, xin, xout, yin, yout, tinx, tiny, tin1, tin2, toutx, touty, tout1;
/*
* If you put in an n-sided polygon, you will never get more
* than a 2n-sided polygon out (actually you get less, but we
* are being conservative)
*/
for (i = 0; i < n; i++) {
dx = x[i + 1] - x[i]; // (assuming closure of polygon)
dy = y[i + 1] - y[i];
/* line points right */
if ((dx > 0) || ((dx == 0) && (x[i] > xright))) {
xin = xleft;
xout = xright;
}
/* line points left */
else {
xin = xright;
xout = xleft;
}
/* line points up */
if ((dy > 0) || ((dy == 0) && (y[i] > ytop))) {
yin = ybottom;
yout = ytop;
}
/* line points down */
else {
yin = ytop;
yout = ybottom;
}
tinx = (dx != 0) ? (xin - x[i]) / dx : Double.NEGATIVE_INFINITY;
tiny = (dy != 0) ? (yin - y[i]) / dy : Double.NEGATIVE_INFINITY;
if (tinx < tiny) { /* first entry at x then y */
tin1 = tinx;
tin2 = tiny;
} else { /* first entry at y then x */
tin1 = tiny;
tin2 = tinx;
}
if (tin1 <= 1) { /* case 2, 3, 4, 6 */
if (tin1 > 0) { /* case 5 - turning vertex */
ret_val[num++] = (int) ProjMath.qint((double) (xin));
ret_val[num++] = (int) ProjMath.qint((double) (yin));
}
if (tin2 <= 1) { /* case 3, 4, 6 */
if (dx != 0)
toutx = (xout - x[i]) / dx;
else
/* vertical */
toutx = ((xleft <= x[i]) && (x[i] <= xright)) ? Double.POSITIVE_INFINITY
: Double.NEGATIVE_INFINITY;
if (dy != 0)
touty = (yout - y[i]) / dy;
else
/* horizontal */
touty = ((ybottom <= y[i]) && (y[i] <= ytop)) ? Double.POSITIVE_INFINITY
: Double.NEGATIVE_INFINITY;
tout1 = (toutx < touty) ? toutx : touty;
if ((tin2 > 0) || (tout1 > 0)) { /* case 4, 6 */
if (tin2 <= tout1) { /*
* case 4 - visible
* segment
*/
if (tin2 > 0) /* v[i] outside window */
if (tinx > tiny) { /*
* vertical
* boundary
*/
ret_val[num++] = (int) ProjMath.qint(xin);
ret_val[num++] = (int) ProjMath.qint(y[i]
+ (tinx * dy));
} else { /* horiz boundary */
ret_val[num++] = (int) ProjMath.qint(x[i]
+ (tiny * dx));
ret_val[num++] = (int) ProjMath.qint(yin);
}
if (tout1 < 1) { /* v[i+1] outside window */
if (toutx < touty) { /*
* vertical
* boundary
*/
ret_val[num++] = (int) ProjMath.qint(xout);
ret_val[num++] = (int) ProjMath.qint(y[i]
+ (toutx * dy));
} else { /* horiz boundary */
ret_val[num++] = (int) ProjMath.qint(x[i]
+ (touty * dx));
ret_val[num++] = (int) ProjMath.qint(yout);
}
} else {
ret_val[num++] = (int) (x[i + 1]);
ret_val[num++] = (int) (y[i + 1]);
}
} else { /* case 6 - turning vertex */
if (tinx > tiny) { /* second entry at x */
ret_val[num++] = (int) ProjMath.qint(xin);
ret_val[num++] = (int) ProjMath.qint(yout);
} else { /* second entry at y */
ret_val[num++] = (int) ProjMath.qint(xout);
ret_val[num++] = (int) ProjMath.qint(yin);
}
}
}
}
}
}
if (num != 0) {
// Close the polygon
ret_val[num++] = ret_val[0];/* lat */
ret_val[num++] = ret_val[1];/* lon */
// note the total length
ret_val[ret_val.length - 1] = num;
} else
ret_val[ret_val.length - 1] = num;
return ret_val;
}
// enum Values
static final class Values {
final static char LEFT = 0x1;
final static char RIGHT = 0x2;
final static char BOTTOM = 0x4;
final static char TOP = 0x8;
}
private static final int _quick_code(int x, int y, int xleft, int xright,
int ytop, int ybottom) {
int val = 0x0;
if (x < xleft)
val = Values.LEFT;
else if (x > xright)
val = Values.RIGHT;
if (y < ytop)
val |= Values.TOP;
else if (y > ybottom)
val |= Values.BOTTOM;
return val;
}
/**
* Check if a line is completely inside or completely outside
* viewport.
* <p>
*
* @param x1 pt1.x
* @param y1 pt1.y
* @param x2 pt2.x
* @param y2 pt2.y
* @param xleft left
* @param xright right
* @param ytop ytop < ybottom
* @param ybottom ybottom < ytop
* @return int -1=outside, 1=inside, 0=undetermined
*
*/
public final static int quickCheckLineClip(int x1, int y1, int x2, int y2,
int xleft, int xright, int ytop,
int ybottom)
// xleft < xright, ytop < ybottom
{
/*
* return values: 1 = line is fully in window 0 = line is NOT
* fully in window. THIS DOES NOT IMPLY THAT LINE IS PARTIALLY
* INSIDE WINDOW. -1 = line is NOT in window at all
*/
int pt1 = _quick_code(x1, y1, xleft, xright, ytop, ybottom);
int pt2 = _quick_code(x2, y2, xleft, xright, ytop, ybottom);
if ((pt1 & pt2) != 0)
return -1; // completely outside
else if ((pt1 | pt2) == 0)
return 1; // completely inside
else
return 0; // partially inside?
}
/*
* public static void main(String[] args) { int xleft = 0; int
* xright = 1024; int ytop = 0; int ybottom = 1024; float[] ret_val =
* null; float[] xs = null, ys = null;
*
* int n = 4; xs = new float[n+1]; ys = new float[n+1]; xs[0] = -100;
* ys[0] = 400; xs[1] = 700; ys[1] = -100; xs[2] = 1100; ys[2] =
* 400; xs[3] = 700; ys[3] = 1100; xs[4] = -100; ys[4] = 400;
* ret_val = new float[liang_get_buflen(n)];
*
* ret_val = liang_clip( xleft, xright, ybottom, ytop, xs, ys, n,
* ret_val); n = ret_val[ret_val.length-1]-2;// unclosed length
*
* Debug.output("num pairs = " + n); Debug.output("total buffer
* len = " + ret_val.length); for (int i = 0; i < n; i+=2) {
* Debug.output( "(" + ret_val[i] + "," + ret_val[i+1] + ")"); } }
*/
}