@Override public Geom buffer(double amt, Linearizer linearizer, Tolerance tolerance) throws IllegalArgumentException, NullPointerException { if (amt == 0) { return this; } else if (amt < 0) { return null; } VectList result = new VectList(); VectBuilder vect = new VectBuilder(); projectOutward(0, -amt, tolerance, vect); double ix = vect.getX(); double iy = vect.getY(); result.add(ix, iy); projectOutward(0, amt, tolerance, vect); linearizer.linearizeSegment(ax, ay, ix, iy, vect.getX(), vect.getY(), result); projectOutward(1, amt, tolerance, vect); double jx = vect.getX(); double jy = vect.getY(); result.add(jx, jy); projectOutward(1, -amt, tolerance, vect); linearizer.linearizeSegment(bx, by, jx, jy, vect.getX(), vect.getY(), result); result.add(ix, iy); return new Area(new Ring(result, null)); }
static void intersectionLineCircleInternal( double ax, double ay, double bx, double by, double cx, double cy, double radius, Tolerance tolerance, VectBuilder working, VectList intersections) { projectOnToLineInternal( ax, ay, bx, by, cx, cy, tolerance, working); // get the closest point on the line to the circle center double dx = working.getX(); double dy = working.getY(); double distToLineSq = Vect.distSq(cx, cy, dx, dy); double radiusSq = radius * radius; switch (tolerance.check(distToLineSq - radiusSq)) { case 1: // dist to line is greater than radius - line does not intersect circle return; case 0: // dist to line matches radius - line touches circle intersections.add(dx, dy); return; default: // dist to line is less than radius - line crosses circle double mx = bx - ax; double my = by - ay; double segmentLen = Math.sqrt(mx * mx + my * my); double projectDist; if (tolerance.check(distToLineSq) == 0) { // line crosses circle center projectDist = radius; dx = cx; dy = cy; } else { projectDist = Math.sqrt(radiusSq - distToLineSq); } double mul = projectDist / segmentLen; mx *= mul; my *= mul; intersections.add(dx - mx, dy - my); intersections.add(dx + mx, dy + my); } }
static boolean project( double ax, double ay, double bx, double by, double u, Tolerance tolerance, VectBuilder target) { double x = (u * (bx - ax)) + ax; double y = (u * (by - ay)) + ay; if (tolerance.match(x, y, ax, ay)) { target.set(ax, ay); return true; } else if (tolerance.match(x, y, bx, by)) { target.set(bx, by); return true; } else { target.set(x, y); return ((u > 0) && (u < 1)); } }
/** * Project the value given along the line segment, where 0 represents A and 1 represents B. * Tolerance is used to snap points to A or B if close enough. If u < 0 return A and if u > 1 * return B and the point is beyond the tolerance, return null * * @param u * @param tolerance tolerance for snapping to end points * @param target target vector * @throws IllegalArgumentException if u was infinite or NaN * @throws NullPointerException if tolerance or target was null */ public void projectClosest(double u, Tolerance tolerance, VectBuilder target) throws NullPointerException, IllegalArgumentException { double x = (u * (bx - ax)) + ax; double y = (u * (by - ay)) + ay; if ((u < 0) || tolerance.match(x, y, ax, ay)) { getA(target); } else if ((u > 1) || tolerance.match(x, y, bx, by)) { getB(target); } else { target.set(x, y); } }
static boolean projectOutward( double ax, double ay, double bx, double by, double u, double distFromLine, Tolerance tolerance, VectBuilder target) { boolean ret = project(ax, ay, bx, by, u, tolerance, target); double dx = bx - ax; double dy = by - ay; double len = Math.sqrt(dx * dx + dy * dy); double mul = Math.abs(distFromLine) / len; dx *= mul; dy *= mul; if (distFromLine < 0) { target.add(-dy, dx); } else { target.add(dy, -dx); } return ret; }
/** * Determine if the triangle formed by the points a, vect, b is counterclockwise * * @param vect vector * @param accuracy * @return 1 if counter clockwise, -1 if clockwise, 0 if point is on line segment ab */ public int counterClockwise(VectBuilder vect, Tolerance accuracy) throws NullPointerException { return counterClockwise(ax, ay, bx, by, vect.getX(), vect.getY(), accuracy); }
static boolean intersectionSegInternal( double ax, double ay, double bx, double by, double jax, double jay, double jbx, double jby, Tolerance tolerance, VectBuilder target) throws NullPointerException { if (Vect.compare(ax, ay, bx, by) > 0) { double tmp = ax; ax = bx; bx = tmp; tmp = ay; ay = by; by = tmp; } if (Vect.compare(jax, jay, jbx, jby) > 0) { double tmp = jax; jax = jbx; jbx = tmp; tmp = jay; jay = jby; jby = tmp; } if (compare(ax, ay, bx, by, jax, jay, jbx, jby) > 0) { double tmp = ax; ax = jax; jax = tmp; tmp = ay; ay = jay; jay = tmp; tmp = bx; bx = jbx; jbx = tmp; tmp = by; by = jby; jby = tmp; } double denom = getDenom(ax, ay, bx, by, jax, jay, jbx, jby); if (denom == 0.0) { // Lines are parallel. return false; } double ui = ((jbx - jax) * (ay - jay) - (jby - jay) * (ax - jax)) / denom; // projected distance along i and j double uj = ((bx - ax) * (ay - jay) - (by - ay) * (ax - jax)) / denom; double x, y; if (ax == bx) { x = ax; } else if (jax == jbx) { x = jax; } else { x = (ui * (bx - ax)) + ax; } if (ay == by) { y = ay; } else if (jay == jby) { y = jay; } else { y = (ui * (by - ay)) + ay; } boolean ia = tolerance.match(x, y, ax, ay); boolean ib = tolerance.match(x, y, bx, by); boolean i = ia || ib || ((ui >= 0) && (ui <= 1)); boolean ja = tolerance.match(x, y, jax, jay); boolean jb = tolerance.match(x, y, jbx, jby); boolean j = ja || jb || ((uj >= 0) && (uj <= 1)); if (i && j) { if (ia) { target.set(ax, ay); } else if (ib) { target.set(bx, by); } else if (ja) { target.set(jax, jay); } else if (jb) { target.set(jbx, jby); } else { target.set(x, y); } return true; } return false; }
/** * Get the mid point * * @param target target in which to place mid point * @return target */ public VectBuilder getMid(VectBuilder target) { return target.set((ax + bx) / 2, (ay + by) / 2); }
/** * Get B * * @param target target in which to place B * @return target */ public VectBuilder getB(VectBuilder target) { target.set(bx, by); return target; }
/** * Get A * * @param target target in which to place A * @return target */ public VectBuilder getA(VectBuilder target) { target.set(ax, ay); return target; }
@Override public int relate(VectBuilder vect, Tolerance tolerance) throws NullPointerException { return (distSegVectSq(ax, ay, bx, by, vect.getX(), vect.getY()) <= tolerance.toleranceSq) ? (Relation.TOUCH | Relation.A_OUTSIDE_B) : Relation.DISJOINT; }