/**
*/
package wblut.geom;
import java.util.List;
import wblut.WB_Epsilon;
import javolution.util.FastList;
import javolution.util.FastMap;
// TODO: Auto-generated Javadoc
/**
* Stripped version of Zhenyu Pan's JAVA transcription of Shane O'Sullivan's C
* implementation of Fortune's sweep algorithm. I added degenerate point
* detection.
*
* http://shaneosullivan.wordpress.com/2007/04/05/fortunes-sweep-line-voronoi-
* algorithm-implemented-in-java/
*
* @author Frederik Vanhoutte, W:Blut, extremely derivative
*
*/
public class WB_Voronoi2D {
/**
* The Class VoronoiEdge2D.
*/
private class VoronoiEdge2D {
/** The c. */
public double a = 0, b = 0, c = 0;
/** The end points. */
WB_Point2d[] endPoints;
/** The between sites. */
WB_Point2d[] betweenSites;
/** The indices. */
int[] indices;
/**
* Instantiates a new voronoi edge2 d.
*/
VoronoiEdge2D() {
endPoints = new WB_Point2d[2];
betweenSites = new WB_Point2d[2];
indices = new int[2];
}
}
/**
* The Class VoronoiHalfedge2D.
*/
private class VoronoiHalfedge2D {
/** The right halfedge. */
VoronoiHalfedge2D leftHalfedge, rightHalfedge;
/** The voronoi edge. */
VoronoiEdge2D voronoiEdge;
/** The deleted. */
boolean deleted;
/** The E lpm. */
int ELpm;
/** The vertex. */
WB_Point2d vertex;
/** The ystar. */
double ystar;
/** The next halfedge in point queue. */
VoronoiHalfedge2D nextHalfedgeInPointQueue;
/**
* Instantiates a new voronoi halfedge2 d.
*/
VoronoiHalfedge2D() {
nextHalfedgeInPointQueue = null;
}
}
/** The border max y. */
private double borderMinX, borderMaxX, borderMinY,
borderMaxY;
/** The current site. */
private int currentSite;
/** The deltay. */
private double xmin, xmax, ymin, ymax, deltax,
deltay;
/** The nsites. */
private int nsites;
/** The sites. */
private WB_Point2d[] sites;
/** The bottomsite. */
private WB_Point2d bottomsite;
/** The number of point queu markers. */
private int pointQueueSize, pointQueueMin,
numberOfPointQueuMarkers;
/** The point queue markers. */
private VoronoiHalfedge2D pointQueueMarkers[];
/** The left end. */
private static int leftEnd = 0;
/** The right end. */
private static int rightEnd = 1;
/** The number of edge list markers. */
private int numberOfEdgeListMarkers;
/** The edge list markers. */
private VoronoiHalfedge2D edgeListMarkers[];
/** The edge list right end. */
private VoronoiHalfedge2D edgeListLeftEnd, edgeListRightEnd;
/** The all edges. */
private FastList<WB_IndexedBisector2D> allEdges;
/** The indices. */
private FastMap<WB_Point2d, Integer> indices;
/**
* Instantiates a new w b_ voronoi2 d.
*/
public WB_Voronoi2D() {
}
/**
* Generate voronoi.
*
* @param minX the min x
* @param maxX the max x
* @param minY the min y
* @param maxY the max y
* @param points the points
* @return the list
*/
public List<WB_IndexedBisector2D> generateVoronoi(final double minX,
final double maxX, final double minY, final double maxY,
final WB_Point2d[] points) {
final FastList<WB_Point2d> ppoints = new FastList<WB_Point2d>();
for (final WB_Point2d point : points) {
ppoints.add(point);
}
return generateVoronoi(minX, maxX, minY, maxY, ppoints);
}
/**
* Generate voronoi.
*
* @param minX the min x
* @param maxX the max x
* @param minY the min y
* @param maxY the max y
* @param points the points
* @return the list
*/
public List<WB_IndexedBisector2D> generateVoronoi(double minX, double maxX,
double minY, double maxY, final List<WB_Point2d> points) {
double temp = 0;
if (minX > maxX) {
temp = minX;
minX = maxX;
maxX = temp;
}
if (minY > maxY) {
temp = minY;
minY = maxY;
maxY = temp;
}
borderMinX = minX;
borderMinY = minY;
borderMaxX = maxX;
borderMaxY = maxY;
currentSite = 0;
collectSites(points);
createVoronoi2D();
final List<WB_IndexedBisector2D> result = new FastList<WB_IndexedBisector2D>(
allEdges.size());
result.addAll(allEdges);
return result;
}
/**
* Collect sites.
*
* @param pointsIn the points in
*/
private void collectSites(final List<WB_Point2d> pointsIn) {
allEdges = new FastList<WB_IndexedBisector2D>();
final FastList<WB_Point2d> points = new FastList<WB_Point2d>();
final WB_KDTree2Dold<Integer> kdtree = new WB_KDTree2Dold<Integer>();
WB_KDNeighbor2D<Integer>[] neighbors;
WB_Point2d p = new WB_Point2d(pointsIn.get(0));
kdtree.put(p, 0);
points.add(p);
for (int i = 1; i < pointsIn.size(); i++) {
p = new WB_Point2d(pointsIn.get(i));
neighbors = kdtree.getNearestNeighbors(p, 1, false);
if (neighbors[0].sqDistance() > WB_Epsilon.SQEPSILON) {
kdtree.put(p, i);
points.add(p);
}
}
sortSites(points);
}
/**
* Sort sites.
*
* @param points the points
*/
private void sortSites(final FastList<WB_Point2d> points) {
sites = new WB_Point2d[nsites];
xmin = points.get(0).x;
ymin = points.get(0).y;
xmax = xmin;
ymax = ymin;
indices = new FastMap<WB_Point2d, Integer>();
for (int i = 0; i < nsites; i++) {
sites[i] = new WB_Point2d(points.get(i).x, points.get(i).y);
indices.put(sites[i], i);
final double xi = points.get(i).x;
if (xi < xmin) {
xmin = xi;
} else if (xi > xmax) {
xmax = xi;
}
final double yi = points.get(i).y;
if (yi < ymin) {
ymin = yi;
} else if (yi > ymax) {
ymax = yi;
}
}
WB_Point2d tmp;
for (int i = 0; i < nsites; i++) {
for (int j = i + 1; j < nsites; j++) {
if (sites[i].compareToY1st(sites[j]) > 0) {
tmp = sites[i];
sites[i] = sites[j];
sites[j] = tmp;
}
}
}
deltay = ymax - ymin;
deltax = xmax - xmin;
}
/**
* Creates the voronoi2 d.
*
* @return true, if successful
*/
private boolean createVoronoi2D() {
WB_Point2d newsite, bot, top, temp, p;
WB_Point2d v;
WB_Point2d newintstar = null;
int pm;
VoronoiHalfedge2D lbnd, rbnd, llbnd, rrbnd, bisector;
VoronoiEdge2D e;
currentSite = 0;
pointQueueInitialize();
edgeListInitialize();
bottomsite = getNextSite();
newsite = getNextSite();
while (true) {
if (!isPointQueueEmpty()) {
newintstar = pointQueueMin();
}
if (newsite != null
&& (isPointQueueEmpty() || newsite.y < newintstar.y || (newsite.y == newintstar.y && newsite.x < newintstar.x))) {
/* new site is smallest -this is a site event */
// get the first HalfEdge to the LEFT of the new site
lbnd = ELleftbnd((newsite));
// get the first HalfEdge to the RIGHT of the new site
rbnd = lbnd.rightHalfedge;
// if this halfedge has no edge,bot =bottom site (whatever that
// is)
bot = rightreg(lbnd);
// create a new edge that bisects
e = bisect(bot, newsite);
// create a new HalfEdge, setting its ELpm field to 0
bisector = HEcreate(e, leftEnd);
// insert this new bisector edge between the left and right
// vectors in a linked list
insertHalfedgeInEdgeList(lbnd, bisector);
// if the new bisector intersects with the left edge,
// remove the left edge's vertex, and put in the new one
if ((p = intersect(lbnd, bisector)) != null) {
removeHalfedgeFromPointqueue(lbnd);
insertHalfedgeInPointqueue(lbnd, p,
WB_Distance2D.distance(p, newsite));
}
lbnd = bisector;
// create a new HalfEdge, setting its ELpm field to 1
bisector = HEcreate(e, rightEnd);
// insert the new HE to the right of the original bisector
// earlier in the IF stmt
insertHalfedgeInEdgeList(lbnd, bisector);
// if this new bisector intersects with the new HalfEdge
if ((p = intersect(bisector, rbnd)) != null) {
// push the HE into the ordered linked list of vertices
insertHalfedgeInPointqueue(bisector, p,
WB_Distance2D.distance(p, newsite));
}
newsite = getNextSite();
} else if (!isPointQueueEmpty())
/* intersection is smallest - this is a vector event */
{
// pop the HalfEdge with the lowest vector off the ordered list
// of vectors
lbnd = popMinFromPointQueue();
// get the HalfEdge to the left of the above HE
llbnd = lbnd.leftHalfedge;
// get the HalfEdge to the right of the above HE
rbnd = lbnd.rightHalfedge;
// get the HalfEdge to the right of the HE to the right of the
// lowest HE
rrbnd = rbnd.rightHalfedge;
// get the Site to the left of the left HE which it bisects
bot = leftreg(lbnd);
// get the Site to the right of the right HE which it bisects
top = rightreg(rbnd);
v = lbnd.vertex; // get the vertex that caused this event
endpoint(lbnd.voronoiEdge, lbnd.ELpm, v);
// set the endpoint of
// the left HalfEdge to be this vector
endpoint(rbnd.voronoiEdge, rbnd.ELpm, v);
// set the endpoint of the right HalfEdge to
// be this vector
deleteHalfedgeFromEdgeList(lbnd); // mark the lowest HE for
// deletion - can't delete yet because there might be pointers
// to it in Hash Map
removeHalfedgeFromPointqueue(rbnd);
// remove all vertex events to do with the right HE
deleteHalfedgeFromEdgeList(rbnd); // mark the right HE for
// deletion - can't delete yet because there might be pointers
// to it in Hash Map
pm = leftEnd; // set the pm variable to zero
if (bot.y > top.y)
// if the site to the left of the event is higher than the
// Site
{ // to the right of it, then swap them and set the 'pm'
// variable to 1
temp = bot;
bot = top;
top = temp;
pm = rightEnd;
}
e = bisect(bot, top); // create an Edge (or line)
// that is between the two Sites. This creates the formula of
// the line, and assigns a line number to it
bisector = HEcreate(e, pm); // create a HE from the Edge 'e',
// and make it point to that edge
// with its ELedge field
insertHalfedgeInEdgeList(llbnd, bisector); // insert the new
// bisector to the
// right of the left HE
endpoint(e, rightEnd - pm, v); // set one endpoint to the new
// edge
// to be the vector point 'v'.
// If the site to the left of this bisector is higher than the
// right Site, then this endpoint
// is put in position 0; otherwise in pos 1
// if left HE and the new bisector intersect, then delete
// the left HE, and reinsert it
if ((p = intersect(llbnd, bisector)) != null) {
removeHalfedgeFromPointqueue(llbnd);
insertHalfedgeInPointqueue(llbnd, p,
WB_Distance2D.distance(p, bot));
}
// if right HE and the new bisector intersect, then
// reinsert it
if ((p = intersect(bisector, rrbnd)) != null) {
insertHalfedgeInPointqueue(bisector, p,
WB_Distance2D.distance(p, bot));
}
} else {
break;
}
}
for (lbnd = edgeListLeftEnd.rightHalfedge; lbnd != edgeListRightEnd; lbnd = lbnd.rightHalfedge) {
e = lbnd.voronoiEdge;
clipToBoundary(e);
}
return true;
}
/**
* Point queue initialize.
*
* @return true, if successful
*/
private boolean pointQueueInitialize() {
pointQueueSize = 0;
pointQueueMin = 0;
numberOfPointQueuMarkers = 4 * (int) Math.sqrt(nsites + 4);
pointQueueMarkers = new VoronoiHalfedge2D[numberOfPointQueuMarkers];
for (int i = 0; i < numberOfPointQueuMarkers; i += 1) {
pointQueueMarkers[i] = new VoronoiHalfedge2D();
}
return true;
}
/**
* Point queue marker.
*
* @param he the he
* @return the int
*/
private int pointQueueMarker(final VoronoiHalfedge2D he) {
int marker;
marker = (int) ((he.ystar - ymin) / deltay * numberOfPointQueuMarkers);
if (marker < 0) {
marker = 0;
}
if (marker >= numberOfPointQueuMarkers) {
marker = numberOfPointQueuMarkers - 1;
}
if (marker < pointQueueMin) {
pointQueueMin = marker;
}
return (marker);
}
// push the HalfEdge into the ordered linked list of vertices
/**
* Insert halfedge in pointqueue.
*
* @param he the he
* @param v the v
* @param offset the offset
*/
private void insertHalfedgeInPointqueue(final VoronoiHalfedge2D he,
final WB_Point2d v, final double offset) {
VoronoiHalfedge2D last, next;
he.vertex = v;
he.ystar = (v.y + offset);
last = pointQueueMarkers[pointQueueMarker(he)];
while ((next = last.nextHalfedgeInPointQueue) != null
&& (he.ystar > next.ystar || (he.ystar == next.ystar && v.x > next.vertex.x))) {
last = next;
}
he.nextHalfedgeInPointQueue = last.nextHalfedgeInPointQueue;
last.nextHalfedgeInPointQueue = he;
pointQueueSize += 1;
}
// remove the HalfEdge from the list of vertices
/**
* Removes the halfedge from pointqueue.
*
* @param he the he
*/
private void removeHalfedgeFromPointqueue(final VoronoiHalfedge2D he) {
VoronoiHalfedge2D last;
if (he.vertex != null) {
last = pointQueueMarkers[pointQueueMarker(he)];
while (last.nextHalfedgeInPointQueue != he) {
last = last.nextHalfedgeInPointQueue;
}
last.nextHalfedgeInPointQueue = he.nextHalfedgeInPointQueue;
pointQueueSize -= 1;
he.vertex = null;
}
}
/**
* Checks if is point queue empty.
*
* @return true, if is point queue empty
*/
private boolean isPointQueueEmpty() {
return (pointQueueSize == 0);
}
/**
* Point queue min.
*
* @return the w b_ point2d
*/
private WB_Point2d pointQueueMin() {
final WB_Point2d result = new WB_Point2d();
while (pointQueueMarkers[pointQueueMin].nextHalfedgeInPointQueue == null) {
pointQueueMin += 1;
}
result.x = pointQueueMarkers[pointQueueMin].nextHalfedgeInPointQueue.vertex.x;
result.y = pointQueueMarkers[pointQueueMin].nextHalfedgeInPointQueue.ystar;
return (result);
}
/**
* Pop min from point queue.
*
* @return the voronoi halfedge2 d
*/
private VoronoiHalfedge2D popMinFromPointQueue() {
VoronoiHalfedge2D curr;
curr = pointQueueMarkers[pointQueueMin].nextHalfedgeInPointQueue;
pointQueueMarkers[pointQueueMin].nextHalfedgeInPointQueue = curr.nextHalfedgeInPointQueue;
pointQueueSize -= 1;
return (curr);
}
/**
* Edge list initialize.
*
* @return true, if successful
*/
private boolean edgeListInitialize() {
int i;
numberOfEdgeListMarkers = 2 * (int) Math.sqrt(nsites + 4);
edgeListMarkers = new VoronoiHalfedge2D[numberOfEdgeListMarkers];
for (i = 0; i < numberOfEdgeListMarkers; i += 1) {
edgeListMarkers[i] = null;
}
edgeListLeftEnd = HEcreate(null, 0);
edgeListRightEnd = HEcreate(null, 0);
edgeListLeftEnd.leftHalfedge = null;
edgeListLeftEnd.rightHalfedge = edgeListRightEnd;
edgeListRightEnd.leftHalfedge = edgeListLeftEnd;
edgeListRightEnd.rightHalfedge = null;
edgeListMarkers[0] = edgeListLeftEnd;
edgeListMarkers[numberOfEdgeListMarkers - 1] = edgeListRightEnd;
return true;
}
/**
* Insert halfedge in edge list.
*
* @param lb the lb
* @param newHe the new he
*/
private void insertHalfedgeInEdgeList(final VoronoiHalfedge2D lb,
final VoronoiHalfedge2D newHe) {
newHe.leftHalfedge = lb;
newHe.rightHalfedge = lb.rightHalfedge;
(lb.rightHalfedge).leftHalfedge = newHe;
lb.rightHalfedge = newHe;
}
/*
* This delete routine can't reclaim node, since pointers from hash table
* may be present.
*/
/**
* Delete halfedge from edge list.
*
* @param he the he
*/
private void deleteHalfedgeFromEdgeList(final VoronoiHalfedge2D he) {
(he.leftHalfedge).rightHalfedge = he.rightHalfedge;
(he.rightHalfedge).leftHalfedge = he.leftHalfedge;
he.deleted = true;
}
/* Get entry from hash table, pruning any deleted nodes */
/**
* Edge list marker.
*
* @param b the b
* @return the voronoi halfedge2 d
*/
private VoronoiHalfedge2D edgeListMarker(final int b) {
VoronoiHalfedge2D he;
if (b < 0 || b >= numberOfEdgeListMarkers) {
return (null);
}
he = edgeListMarkers[b];
if (he == null || !he.deleted) {
return (he);
}
/* Hash table points to deleted half edge. Patch as necessary. */
edgeListMarkers[b] = null;
return (null);
}
/**
* E lleftbnd.
*
* @param p the p
* @return the voronoi halfedge2 d
*/
private VoronoiHalfedge2D ELleftbnd(final WB_Point2d p) {
int i, marker;
VoronoiHalfedge2D he;
/* Use hash table to get close to desired halfedge */
// use the hash function to find the place in the hash map that this
// HalfEdge should be
marker = (int) ((p.x - xmin) / deltax * numberOfEdgeListMarkers);
// make sure that the bucket position in within the range of the hash
// array
if (marker < 0) {
marker = 0;
}
if (marker >= numberOfEdgeListMarkers) {
marker = numberOfEdgeListMarkers - 1;
}
he = edgeListMarker(marker);
if (he == null)
// if the HE isn't found, search backwards and forwards in the hash map
// for the first non-null entry
{
for (i = 1; i < numberOfEdgeListMarkers; i += 1) {
if ((he = edgeListMarker(marker - i)) != null) {
break;
}
if ((he = edgeListMarker(marker + i)) != null) {
break;
}
}
}
/* Now search linear list of halfedges for the correct one */
if (he == edgeListLeftEnd
|| (he != edgeListRightEnd && isPointToRightOfEdge(he, p))) {
// keep going right on the list until either the end is reached, or
// you find the 1st edge which the point isn't to the right of
do {
he = he.rightHalfedge;
} while (he != edgeListRightEnd && isPointToRightOfEdge(he, p));
he = he.leftHalfedge;
} else {
// if the point is to the left of the HalfEdge, then search left for
// the HE just to the left of the point
do {
he = he.leftHalfedge;
} while (he != edgeListLeftEnd && !isPointToRightOfEdge(he, p));
}
/* Update hash table and reference counts */
if (marker > 0 && marker < numberOfEdgeListMarkers - 1) {
edgeListMarkers[marker] = he;
}
return (he);
}
/**
* Gets the next site.
*
* @return the next site
*/
private WB_Point2d getNextSite() {
WB_Point2d s;
if (currentSite < nsites) {
s = sites[currentSite];
currentSite += 1;
return (s);
} else {
return (null);
}
}
/**
* Bisect.
*
* @param s1 the s1
* @param s2 the s2
* @return the voronoi edge2 d
*/
private VoronoiEdge2D bisect(final WB_Point2d s1, final WB_Point2d s2) {
double dx, dy, adx, ady;
VoronoiEdge2D newedge;
newedge = new VoronoiEdge2D();
newedge.betweenSites[0] = s1;
newedge.betweenSites[1] = s2;
newedge.endPoints[0] = null;
newedge.endPoints[1] = null;
// get the difference in x dist between the sites
dx = s2.x - s1.x;
dy = s2.y - s1.y;
// make sure that the difference in positive
adx = dx > 0 ? dx : -dx;
ady = dy > 0 ? dy : -dy;
newedge.c = s1.x * dx + s1.y * dy + (dx * dx + dy * dy) * 0.5;// get
// the
// slope
// of
// the
// line
if (adx > ady) {
newedge.a = 1.0f;
newedge.b = dy / dx;
newedge.c /= dx;// set formula of line, with x fixed to 1
} else {
newedge.b = 1.0f;
newedge.a = dx / dy;
newedge.c /= dy;// set formula of line, with y fixed to 1
}
newedge.indices[0] = indices.get(s1);
newedge.indices[1] = indices.get(s2);
return (newedge);
}
/**
* H ecreate.
*
* @param e the e
* @param pm the pm
* @return the voronoi halfedge2 d
*/
private VoronoiHalfedge2D HEcreate(final VoronoiEdge2D e, final int pm) {
VoronoiHalfedge2D result;
result = new VoronoiHalfedge2D();
result.voronoiEdge = e;
result.ELpm = pm;
result.nextHalfedgeInPointQueue = null;
result.vertex = null;
return (result);
}
/**
* Leftreg.
*
* @param he the he
* @return the w b_ point2d
*/
private WB_Point2d leftreg(final VoronoiHalfedge2D he) {
if (he.voronoiEdge == null) {
return (bottomsite);
}
return (he.ELpm == leftEnd ? he.voronoiEdge.betweenSites[leftEnd]
: he.voronoiEdge.betweenSites[rightEnd]);
}
/**
* Clip to boundary.
*
* @param e the e
*/
private void clipToBoundary(final VoronoiEdge2D e) {
double pxmin, pxmax, pymin, pymax;
WB_Point2d s1, s2;
double x1 = 0, x2 = 0, y1 = 0, y2 = 0;
x1 = e.betweenSites[0].x;
x2 = e.betweenSites[1].x;
y1 = e.betweenSites[0].y;
y2 = e.betweenSites[1].y;
pxmin = borderMinX;
pxmax = borderMaxX;
pymin = borderMinY;
pymax = borderMaxY;
if (e.a == 1.0 && e.b >= 0.0) {
s1 = e.endPoints[1];
s2 = e.endPoints[0];
} else {
s1 = e.endPoints[0];
s2 = e.endPoints[1];
}
if (e.a == 1.0) {
y1 = pymin;
if (s1 != null && s1.y > pymin) {
y1 = s1.y;
}
if (y1 > pymax) {
y1 = pymax;
}
x1 = e.c - e.b * y1;
y2 = pymax;
if (s2 != null && s2.y < pymax) {
y2 = s2.y;
}
if (y2 < pymin) {
y2 = pymin;
}
x2 = (e.c) - (e.b) * y2;
if (((x1 > pxmax) & (x2 > pxmax)) | ((x1 < pxmin) & (x2 < pxmin))) {
return;
}
if (x1 > pxmax) {
x1 = pxmax;
y1 = (e.c - x1) / e.b;
}
if (x1 < pxmin) {
x1 = pxmin;
y1 = (e.c - x1) / e.b;
}
if (x2 > pxmax) {
x2 = pxmax;
y2 = (e.c - x2) / e.b;
}
if (x2 < pxmin) {
x2 = pxmin;
y2 = (e.c - x2) / e.b;
}
} else {
x1 = pxmin;
if (s1 != null && s1.x > pxmin) {
x1 = s1.x;
}
if (x1 > pxmax) {
x1 = pxmax;
}
y1 = e.c - e.a * x1;
x2 = pxmax;
if (s2 != null && s2.x < pxmax) {
x2 = s2.x;
}
if (x2 < pxmin) {
x2 = pxmin;
}
y2 = e.c - e.a * x2;
if (((y1 > pymax) & (y2 > pymax)) | ((y1 < pymin) & (y2 < pymin))) {
return;
}
if (y1 > pymax) {
y1 = pymax;
x1 = (e.c - y1) / e.a;
}
if (y1 < pymin) {
y1 = pymin;
x1 = (e.c - y1) / e.a;
}
if (y2 > pymax) {
y2 = pymax;
x2 = (e.c - y2) / e.a;
}
if (y2 < pymin) {
y2 = pymin;
x2 = (e.c - y2) / e.a;
}
}
final WB_IndexedBisector2D ib = new WB_IndexedBisector2D();
ib.start = new WB_Point2d(x1, y1);
ib.end = new WB_Point2d(x2, y2);
ib.i = e.indices[0];
ib.j = e.indices[1];
allEdges.add(ib);
}
/**
* Endpoint.
*
* @param e the e
* @param lr the lr
* @param s the s
*/
private void endpoint(final VoronoiEdge2D e, final int lr,
final WB_Point2d s) {
e.endPoints[lr] = s;
if (e.endPoints[rightEnd - lr] == null) {
return;
}
clipToBoundary(e);
}
/* returns 1 if p is to right of halfedge e */
/**
* Checks if is point to right of edge.
*
* @param el the el
* @param p the p
* @return true, if is point to right of edge
*/
private boolean isPointToRightOfEdge(final VoronoiHalfedge2D el,
final WB_Point2d p) {
VoronoiEdge2D e;
WB_Point2d topsite;
boolean toRightOfSite;
boolean above, fast;
double dxp, dyp, dxs, t1, t2, t3, yl;
e = el.voronoiEdge;
topsite = e.betweenSites[1];
if (p.x > topsite.x) {
toRightOfSite = true;
} else {
toRightOfSite = false;
}
if (toRightOfSite && el.ELpm == leftEnd) {
return (true);
}
if (!toRightOfSite && el.ELpm == rightEnd) {
return (false);
}
if (e.a == 1.0) {
dyp = p.y - topsite.y;
dxp = p.x - topsite.x;
fast = false;
if ((!toRightOfSite & (e.b < 0.0)) | (toRightOfSite & (e.b >= 0.0))) {
above = dyp >= e.b * dxp;
fast = above;
} else {
above = p.x + p.y * e.b > e.c;
if (e.b < 0.0) {
above = !above;
}
if (!above) {
fast = true;
}
}
if (!fast) {
dxs = topsite.x - (e.betweenSites[0]).x;
above = e.b * (dxp * dxp - dyp * dyp) < dxs * dyp
* (1.0 + 2.0 * dxp / dxs + e.b * e.b);
if (e.b < 0.0) {
above = !above;
}
}
} else /* e.b==1.0 */
{
yl = e.c - e.a * p.x;
t1 = p.y - yl;
t2 = p.x - topsite.x;
t3 = yl - topsite.y;
above = t1 * t1 > t2 * t2 + t3 * t3;
}
return (el.ELpm == leftEnd ? above : !above);
}
/**
* Rightreg.
*
* @param he the he
* @return the w b_ point2d
*/
private WB_Point2d rightreg(final VoronoiHalfedge2D he) {
if (he.voronoiEdge == null) {
// if this halfedge has no edge, return the bottom site (whatever
// that is)
return (bottomsite);
}
// if the ELpm field is zero, return the site 0 that this edge bisects,
// otherwise return site number 1
return (he.ELpm == leftEnd ? he.voronoiEdge.betweenSites[rightEnd]
: he.voronoiEdge.betweenSites[leftEnd]);
}
/**
* Intersect.
*
* @param el1 the el1
* @param el2 the el2
* @return the w b_ point2d
*/
private WB_Point2d intersect(final VoronoiHalfedge2D el1,
final VoronoiHalfedge2D el2) {
VoronoiEdge2D e1, e2, e;
VoronoiHalfedge2D el;
double d, xint, yint;
boolean right_of_site;
WB_Point2d v;
e1 = el1.voronoiEdge;
e2 = el2.voronoiEdge;
if (e1 == null || e2 == null) {
return null;
}
// if the two edges bisect the same parent, return null
if (e1.betweenSites[1] == e2.betweenSites[1]) {
return null;
}
d = e1.a * e2.b - e1.b * e2.a;
if (-1.0e-10 < d && d < 1.0e-10) {
return null;
}
xint = (e1.c * e2.b - e2.c * e1.b) / d;
yint = (e2.c * e1.a - e1.c * e2.a) / d;
if ((e1.betweenSites[1].y < e2.betweenSites[1].y)
|| (e1.betweenSites[1].y == e2.betweenSites[1].y && e1.betweenSites[1].x < e2.betweenSites[1].x)) {
el = el1;
e = e1;
} else {
el = el2;
e = e2;
}
right_of_site = xint >= e.betweenSites[1].x;
if ((right_of_site && el.ELpm == leftEnd)
|| (!right_of_site && el.ELpm == rightEnd)) {
return null;
}
// create a new site at the point of intersection - this is a new vector
// event waiting to happen
v = new WB_Point2d();
v.x = xint;
v.y = yint;
return (v);
}
}