com.vividsolutions.jts.algorithm.CGAlgorithms Java Examples
The following examples show how to use
com.vividsolutions.jts.algorithm.CGAlgorithms.
You can vote up the ones you like or vote down the ones you don't like,
and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: CoordinateUtil.java From geowe-core with GNU General Public License v3.0 | 6 votes |
public Coordinate[] ensureOrientation( final int desiredOrientation, final Coordinate... coord) { if (coord.length == 0) { return coord; } final int orientation = CGAlgorithms.isCCW(coord) ? CGAlgorithms.COUNTERCLOCKWISE : CGAlgorithms.CLOCKWISE; if (orientation != desiredOrientation) { final Coordinate[] reverse = (Coordinate[]) coord.clone(); reverse(reverse); return reverse; } return coord; }
Example #2
Source File: DistanceLineLineStressTest.java From jts with GNU Lesser General Public License v2.1 | 6 votes |
public void testRandomDisjointCollinearSegments() throws Exception { int n = 1000000; int failCount = 0; for (int i = 0; i < n; i++) { //System.out.println(i); Coordinate[] seg = randomDisjointCollinearSegments(); if (0 == CGAlgorithms.distanceLineLine(seg[0], seg[1], seg[2], seg[3])) { /* System.out.println("FAILED! - " + WKTWriter.toLineString(seg[0], seg[1]) + " - " + WKTWriter.toLineString(seg[2], seg[3])); */ failCount++; } } System.out.println("# failed = " + failCount + " out of " + n); }
Example #3
Source File: MinimumClearance.java From jts with GNU Lesser General Public License v2.1 | 6 votes |
private double segmentDistance(FacetSequence fs1, FacetSequence fs2) { for (int i1 = 0; i1 < fs1.size(); i1++) { for (int i2 = 1; i2 < fs2.size(); i2++) { Coordinate p = fs1.getCoordinate(i1); Coordinate seg0 = fs2.getCoordinate(i2-1); Coordinate seg1 = fs2.getCoordinate(i2); if (! (p.equals2D(seg0) || p.equals2D(seg1))) { double d = CGAlgorithms.distancePointLine(p, seg0, seg1); if (d < minDist) { minDist = d; updatePts(p, seg0, seg1); if (d == 0.0) return d; } } } } return minDist; }
Example #4
Source File: FacetSequence.java From jts with GNU Lesser General Public License v2.1 | 6 votes |
private double computeLineLineDistance(FacetSequence facetSeq) { // both linear - compute minimum segment-segment distance double minDistance = Double.MAX_VALUE; for (int i = start; i < end - 1; i++) { for (int j = facetSeq.start; j < facetSeq.end - 1; j++) { pts.getCoordinate(i, p0); pts.getCoordinate(i + 1, p1); facetSeq.pts.getCoordinate(j, q0); facetSeq.pts.getCoordinate(j + 1, q1); double dist = CGAlgorithms.distanceLineLine(p0, p1, q0, q1); if (dist == 0.0) return 0.0; if (dist < minDistance) { minDistance = dist; } } } return minDistance; }
Example #5
Source File: OffsetSegmentGenerator.java From jts with GNU Lesser General Public License v2.1 | 6 votes |
/** * Adds points for a circular fillet arc * between two specified angles. * The start and end point for the fillet are not added - * the caller must add them if required. * * @param direction is -1 for a CW angle, 1 for a CCW angle * @param radius the radius of the fillet */ private void addFillet(Coordinate p, double startAngle, double endAngle, int direction, double radius) { int directionFactor = direction == CGAlgorithms.CLOCKWISE ? -1 : 1; double totalAngle = Math.abs(startAngle - endAngle); int nSegs = (int) (totalAngle / filletAngleQuantum + 0.5); if (nSegs < 1) return; // no segments because angle is less than increment - nothing to do! double initAngle, currAngleInc; // choose angle increment so that each segment has equal length initAngle = 0.0; currAngleInc = totalAngle / nSegs; double currAngle = initAngle; Coordinate pt = new Coordinate(); while (currAngle < totalAngle) { double angle = startAngle + directionFactor * currAngle; pt.x = p.x + radius * Math.cos(angle); pt.y = p.y + radius * Math.sin(angle); segList.addPt(pt); currAngle += currAngleInc; } }
Example #6
Source File: OffsetSegmentGenerator.java From jts with GNU Lesser General Public License v2.1 | 6 votes |
/** * Add points for a circular fillet around a reflex corner. * Adds the start and end points * * @param p base point of curve * @param p0 start point of fillet curve * @param p1 endpoint of fillet curve * @param direction the orientation of the fillet * @param radius the radius of the fillet */ private void addFillet(Coordinate p, Coordinate p0, Coordinate p1, int direction, double radius) { double dx0 = p0.x - p.x; double dy0 = p0.y - p.y; double startAngle = Math.atan2(dy0, dx0); double dx1 = p1.x - p.x; double dy1 = p1.y - p.y; double endAngle = Math.atan2(dy1, dx1); if (direction == CGAlgorithms.CLOCKWISE) { if (startAngle <= endAngle) startAngle += 2.0 * Math.PI; } else { // direction == COUNTERCLOCKWISE if (startAngle >= endAngle) startAngle -= 2.0 * Math.PI; } segList.addPt(p0); addFillet(p, startAngle, endAngle, direction, radius); segList.addPt(p1); }
Example #7
Source File: BufferInputLineSimplifier.java From jts with GNU Lesser General Public License v2.1 | 6 votes |
/** * Simplify the input coordinate list. * If the distance tolerance is positive, * concavities on the LEFT side of the line are simplified. * If the supplied distance tolerance is negative, * concavities on the RIGHT side of the line are simplified. * * @param distanceTol simplification distance tolerance to use * @return the simplified coordinate list */ public Coordinate[] simplify(double distanceTol) { this.distanceTol = Math.abs(distanceTol); if (distanceTol < 0) angleOrientation = CGAlgorithms.CLOCKWISE; // rely on fact that boolean array is filled with false value isDeleted = new byte[inputLine.length]; boolean isChanged = false; do { isChanged = deleteShallowConcavities(); } while (isChanged); return collapseLine(); }
Example #8
Source File: RoadSkill.java From gama with GNU General Public License v3.0 | 6 votes |
public static int getSegmentIndex(final IAgent road, final IAgent driver) { final GamaPoint[] coords = GeometryUtils.getPointsOf(road); if (coords.length == 2) { return 0; } final GamaPoint loc = driver.getLocation().toGamaPoint(); for (int i = 0; i < coords.length - 1; i++) { if (coords[i].equals(loc)) { return i; } } double distanceS = Double.MAX_VALUE; int indexSegment = 0; final int nbSp = coords.length; for (int i = 0; i < nbSp - 1; i++) { final double distS = CGAlgorithms.distancePointLine(loc, coords[i], coords[i + 1]); if (distS < distanceS) { distanceS = distS; indexSegment = i; } } return indexSegment; }
Example #9
Source File: GeometryLocationsWriter.java From jts with GNU Lesser General Public License v2.1 | 6 votes |
private String componentType(GeometryLocation loc) { String compType = ""; if (loc.getComponent() instanceof LinearRing) { boolean isCCW = CGAlgorithms.isCCW(loc.getComponent().getCoordinates()); compType = "Ring" + (isCCW ? "-CCW" : "-CW ") + " "; } else if (loc.getComponent() instanceof LineString) { compType = "Line "; } else if (loc.getComponent() instanceof Point) { compType = "Point "; } return compType; }
Example #10
Source File: CGAlgorithmFunctions.java From jts with GNU Lesser General Public License v2.1 | 5 votes |
public static int orientationIndex(Geometry segment, Geometry ptGeom) { if (segment.getNumPoints() != 2 || ptGeom.getNumPoints() != 1) { throw new IllegalArgumentException("A must have two points and B must have one"); } Coordinate[] segPt = segment.getCoordinates(); Coordinate p = ptGeom.getCoordinate(); int index = CGAlgorithms.orientationIndex(segPt[0], segPt[1], p); return index; }
Example #11
Source File: LinearRingImpl.java From mrgeo with Apache License 2.0 | 5 votes |
@Override public boolean isCCW() { Coordinate[] coordinates = new Coordinate[getNumPoints()]; for (int i = 0; i < getNumPoints(); i++) { Point pt = getPoint(i); coordinates[i] = new Coordinate(pt.getX(), pt.getY()); } return CGAlgorithms.isCCW(coordinates); }
Example #12
Source File: CoordinateUtil.java From geowe-core with GNU General Public License v3.0 | 5 votes |
public void addCoordinateArrays(final Geometry geometry, final boolean orientPolygons, final List<Coordinate[]> coordArrayList) { if (geometry.getDimension() <= 0) { return; } else if (geometry instanceof LineString) { final LineString l = (LineString) geometry; coordArrayList.add(l.getCoordinates()); } else if (geometry instanceof Polygon) { final Polygon poly = (Polygon) geometry; Coordinate[] shell = poly.getExteriorRing().getCoordinates(); if (orientPolygons) { shell = ensureOrientation(CGAlgorithms.CLOCKWISE, shell); } coordArrayList.add(shell); for (int numRing = 0; numRing < poly.getNumInteriorRing(); numRing++) { Coordinate[] hole = poly.getInteriorRingN(numRing).getCoordinates(); if (orientPolygons) { hole = ensureOrientation( CGAlgorithms.COUNTERCLOCKWISE, hole); } coordArrayList.add(hole); } } else if (geometry instanceof GeometryCollection) { final GeometryCollection gc = (GeometryCollection) geometry; for (int numGeom = 0; numGeom < gc.getNumGeometries(); numGeom++) { addCoordinateArrays(gc.getGeometryN(numGeom), orientPolygons, coordArrayList); } } }
Example #13
Source File: RobustLineIntersectorTest.java From jts with GNU Lesser General Public License v2.1 | 5 votes |
public void testA() { Coordinate p1 = new Coordinate(-123456789, -40); Coordinate p2 = new Coordinate(381039468754763d, 123456789); Coordinate q = new Coordinate(0, 0); LineString l = new GeometryFactory().createLineString(new Coordinate[] {p1, p2}); Point p = new GeometryFactory().createPoint(q); assertEquals(false, l.intersects(p)); assertEquals(false, CGAlgorithms.isOnLine(q, new Coordinate[] {p1, p2})); assertEquals(-1, CGAlgorithms.computeOrientation(p1, p2, q)); }
Example #14
Source File: RobustLineIntersectorTest.java From jts with GNU Lesser General Public License v2.1 | 5 votes |
public void testIsCCW2() { assertEquals(0, CGAlgorithms.computeOrientation( new Coordinate(10, 10), new Coordinate(20, 20), new Coordinate(0, 0))); assertEquals(0, NonRobustCGAlgorithms.computeOrientation( new Coordinate(10, 10), new Coordinate(20, 20), new Coordinate(0, 0))); }
Example #15
Source File: EdgeRing.java From jts with GNU Lesser General Public License v2.1 | 5 votes |
/** * This method will cause the ring to be computed. * It will also check any holes, if they have been assigned. */ public boolean containsPoint(Coordinate p) { LinearRing shell = getLinearRing(); Envelope env = shell.getEnvelopeInternal(); if (! env.contains(p)) return false; if (! CGAlgorithms.isPointInRing(p, shell.getCoordinates()) ) return false; for (Iterator i = holes.iterator(); i.hasNext(); ) { EdgeRing hole = (EdgeRing) i.next(); if (hole.containsPoint(p) ) return false; } return true; }
Example #16
Source File: EdgeRing.java From jts with GNU Lesser General Public License v2.1 | 5 votes |
/** * Compute a LinearRing from the point list previously collected. * Test if the ring is a hole (i.e. if it is CCW) and set the hole flag * accordingly. */ public void computeRing() { if (ring != null) return; // don't compute more than once Coordinate[] coord = new Coordinate[pts.size()]; for (int i = 0; i < pts.size(); i++) { coord[i] = (Coordinate) pts.get(i); } ring = geometryFactory.createLinearRing(coord); isHole = CGAlgorithms.isCCW(ring.getCoordinates()); //Debug.println( (isHole ? "hole - " : "shell - ") + WKTWriter.toLineString(new CoordinateArraySequence(ring.getCoordinates()))); }
Example #17
Source File: SimpleMinimumClearance.java From jts with GNU Lesser General Public License v2.1 | 5 votes |
private void checkSegmentDistance(Coordinate seg0, Coordinate seg1) { if (queryPt.equals2D(seg0) || queryPt.equals2D(seg1)) return; double segDist = CGAlgorithms.distancePointLine(queryPt, seg1, seg0); if (segDist > 0) updateClearance(segDist, queryPt, seg1, seg0); }
Example #18
Source File: FacetSequence.java From jts with GNU Lesser General Public License v2.1 | 5 votes |
private double computePointLineDistance(Coordinate pt, FacetSequence facetSeq) { double minDistance = Double.MAX_VALUE; for (int i = facetSeq.start; i < facetSeq.end - 1; i++) { facetSeq.pts.getCoordinate(i, q0); facetSeq.pts.getCoordinate(i + 1, q1); double dist = CGAlgorithms.distancePointLine(pt, q0, q1); if (dist == 0.0) return 0.0; if (dist < minDistance) { minDistance = dist; } } return minDistance; }
Example #19
Source File: OffsetSegmentGenerator.java From jts with GNU Lesser General Public License v2.1 | 5 votes |
private void addCollinear(boolean addStartPoint) { /** * This test could probably be done more efficiently, * but the situation of exact collinearity should be fairly rare. */ li.computeIntersection(s0, s1, s1, s2); int numInt = li.getIntersectionNum(); /** * if numInt is < 2, the lines are parallel and in the same direction. In * this case the point can be ignored, since the offset lines will also be * parallel. */ if (numInt >= 2) { /** * segments are collinear but reversing. * Add an "end-cap" fillet * all the way around to other direction This case should ONLY happen * for LineStrings, so the orientation is always CW. (Polygons can never * have two consecutive segments which are parallel but reversed, * because that would be a self intersection. * */ if (bufParams.getJoinStyle() == BufferParameters.JOIN_BEVEL || bufParams.getJoinStyle() == BufferParameters.JOIN_MITRE) { if (addStartPoint) segList.addPt(offset0.p1); segList.addPt(offset1.p0); } else { addFillet(s1, offset0.p1, offset1.p0, CGAlgorithms.CLOCKWISE, distance); } } }
Example #20
Source File: OffsetSegmentGenerator.java From jts with GNU Lesser General Public License v2.1 | 5 votes |
public void addNextSegment(Coordinate p, boolean addStartPoint) { // s0-s1-s2 are the coordinates of the previous segment and the current one s0 = s1; s1 = s2; s2 = p; seg0.setCoordinates(s0, s1); computeOffsetSegment(seg0, side, distance, offset0); seg1.setCoordinates(s1, s2); computeOffsetSegment(seg1, side, distance, offset1); // do nothing if points are equal if (s1.equals(s2)) return; int orientation = CGAlgorithms.computeOrientation(s0, s1, s2); boolean outsideTurn = (orientation == CGAlgorithms.CLOCKWISE && side == Position.LEFT) || (orientation == CGAlgorithms.COUNTERCLOCKWISE && side == Position.RIGHT); if (orientation == 0) { // lines are collinear addCollinear(addStartPoint); } else if (outsideTurn) { addOutsideTurn(orientation, addStartPoint); } else { // inside turn addInsideTurn(orientation, addStartPoint); } }
Example #21
Source File: GeometryFunctions.java From jts with GNU Lesser General Public License v2.1 | 5 votes |
public static boolean isCCW(Geometry g) { Coordinate[] pts = null; if (g instanceof Polygon) { pts = ((Polygon) g).getExteriorRing().getCoordinates(); } else if (g instanceof LineString && ((LineString) g).isClosed()) { pts = g.getCoordinates(); } if (pts == null) return false; return CGAlgorithms.isCCW(pts); }
Example #22
Source File: BufferInputLineSimplifier.java From jts with GNU Lesser General Public License v2.1 | 5 votes |
private boolean isShallowConcavity(Coordinate p0, Coordinate p1, Coordinate p2, double distanceTol) { int orientation = CGAlgorithms.computeOrientation(p0, p1, p2); boolean isAngleToSimplify = (orientation == angleOrientation); if (! isAngleToSimplify) return false; double dist = CGAlgorithms.distancePointLine(p1, p0, p2); return dist < distanceTol; }
Example #23
Source File: SmallHoleRemover.java From jts with GNU Lesser General Public License v2.1 | 4 votes |
public boolean value(Geometry geom) { double holeArea = Math.abs(CGAlgorithms.signedArea(geom.getCoordinates())); return holeArea <= area; }
Example #24
Source File: GeometryValidator.java From geowe-core with GNU General Public License v3.0 | 4 votes |
private void validate(final Geometry geom, final List<ValidationResult> validationErrors) { if (geom.isEmpty()) { return; } if (geom instanceof GeometryCollection) { final GeometryCollection gc = (GeometryCollection) geom; for (int numGeom = 0; numGeom < gc.getNumGeometries(); numGeom++) { validate(gc.getGeometryN(numGeom), validationErrors); } } final ValidationResult result = new ValidationResult(); result.setWkt(geom.toText()); final List<String> messages = new ArrayList<String>(); if (!geom.isValid()) { messages.add("Error en topología básica"); } if (!geom.isSimple()) { messages.add("No es una geometría simple"); } if (repeatedPointTester.hasRepeatedPoint(geom)) { messages.add("Se encuentran vértices repetidos"); } if (geom instanceof Polygon) { final Polygon polygon = (Polygon) geom; if (CGAlgorithms.isCCW(polygon.getExteriorRing().getCoordinates())) { messages.add("Error en orientación del polígono"); } else { for (int numRing = 0; numRing < polygon.getNumInteriorRing(); numRing++) { if (!CGAlgorithms.isCCW(polygon.getInteriorRingN(numRing).getCoordinates())) { messages.add("Error en orientación del polígono en anillos interiores"); break; } } } if (!validateMinPolygonArea(geom)) { messages.add("Error en validación mínima de area de un polígono"); } } if (!validateMinSegmentLength(geom)) { messages.add("Error en validación mínima de longitud de segmento. Coordenadas"); result.setErrorsPoints(errorCoordinates); } if(!messages.isEmpty()) { result.setMessages(messages); validationErrors.add(result); } }
Example #25
Source File: BufferInputLineSimplifier.java From jts with GNU Lesser General Public License v2.1 | 4 votes |
private boolean isShallow(Coordinate p0, Coordinate p1, Coordinate p2, double distanceTol) { double dist = CGAlgorithms.distancePointLine(p1, p0, p2); return dist < distanceTol; }
Example #26
Source File: OffsetSegmentGenerator.java From jts with GNU Lesser General Public License v2.1 | 4 votes |
/** * Add an end cap around point p1, terminating a line segment coming from p0 */ public void addLineEndCap(Coordinate p0, Coordinate p1) { LineSegment seg = new LineSegment(p0, p1); LineSegment offsetL = new LineSegment(); computeOffsetSegment(seg, Position.LEFT, distance, offsetL); LineSegment offsetR = new LineSegment(); computeOffsetSegment(seg, Position.RIGHT, distance, offsetR); double dx = p1.x - p0.x; double dy = p1.y - p0.y; double angle = Math.atan2(dy, dx); switch (bufParams.getEndCapStyle()) { case BufferParameters.CAP_ROUND: // add offset seg points with a fillet between them segList.addPt(offsetL.p1); addFillet(p1, angle + Math.PI / 2, angle - Math.PI / 2, CGAlgorithms.CLOCKWISE, distance); segList.addPt(offsetR.p1); break; case BufferParameters.CAP_FLAT: // only offset segment points are added segList.addPt(offsetL.p1); segList.addPt(offsetR.p1); break; case BufferParameters.CAP_SQUARE: // add a square defined by extensions of the offset segment endpoints Coordinate squareCapSideOffset = new Coordinate(); squareCapSideOffset.x = Math.abs(distance) * Math.cos(angle); squareCapSideOffset.y = Math.abs(distance) * Math.sin(angle); Coordinate squareCapLOffset = new Coordinate( offsetL.p1.x + squareCapSideOffset.x, offsetL.p1.y + squareCapSideOffset.y); Coordinate squareCapROffset = new Coordinate( offsetR.p1.x + squareCapSideOffset.x, offsetR.p1.y + squareCapSideOffset.y); segList.addPt(squareCapLOffset); segList.addPt(squareCapROffset); break; } }
Example #27
Source File: QuadEdgeTriangle.java From jts with GNU Lesser General Public License v2.1 | 4 votes |
public boolean contains(Coordinate pt) { Coordinate[] ring = getCoordinates(); return CGAlgorithms.isPointInRing(pt, ring); }
Example #28
Source File: PolygonHandler.java From jts with GNU Lesser General Public License v2.1 | 4 votes |
private ArrayList assignHolesToShells(ArrayList shells, ArrayList holes) { // now we have a list of all shells and all holes ArrayList holesForShells = new ArrayList(shells.size()); for (int i = 0; i < shells.size(); i++) { holesForShells.add(new ArrayList()); } // find homes for (int i = 0; i < holes.size(); i++) { LinearRing testHole = (LinearRing) holes.get(i); LinearRing minShell = null; Envelope minEnv = null; Envelope testHoleEnv = testHole.getEnvelopeInternal(); Coordinate testHolePt = testHole.getCoordinateN(0); LinearRing tryShell; int nShells = shells.size(); for (int j = 0; j < nShells; j++) { tryShell = (LinearRing) shells.get(j); Envelope tryShellEnv = tryShell.getEnvelopeInternal(); if (! tryShellEnv.contains(testHoleEnv)) continue; boolean isContained = false; Coordinate[] coordList = tryShell.getCoordinates(); if (nShells <= 1 || CGAlgorithms.isPointInRing(testHolePt, coordList) || pointInList(testHolePt, coordList)) isContained = true; // check if new containing ring is smaller than the current minimum ring if (minShell != null) minEnv = minShell.getEnvelopeInternal(); if (isContained) { if (minShell == null || minEnv.contains(tryShellEnv)) { minShell = tryShell; } } } if (minShell == null) { System.err.println("Found polygon with a hole not inside a shell"); } else { // ((ArrayList)holesForShells.get(shells.indexOf(minShell))).add(testRing); ((ArrayList) holesForShells.get(findIndex(shells, minShell))) .add(testHole); } } return holesForShells; }
Example #29
Source File: OraReader.java From jts with GNU Lesser General Public License v2.1 | 4 votes |
/** * Read {@link Polygon) from encoded geometry. * * @param oraGeom SDO_GEOMETRY attributes being read * @param elemIndex the element being read * @param coords the coordinates of the entire geometry * @return Polygon as encoded by elemInfo, or null when faced with and * encoding that can not be captured by JTS * @throws IllegalArgumentException When faced with an invalid SDO encoding */ private Polygon readPolygon(OraGeom oraGeom, int elemIndex) { int etype = oraGeom.eType(elemIndex); int interpretation = oraGeom.interpretation(elemIndex); checkOrdinates(oraGeom, elemIndex, "Polygon"); checkETYPE(etype,OraGeom.ETYPE.POLYGON, OraGeom.ETYPE.POLYGON_EXTERIOR, "Polygon"); checkInterpretation(interpretation, OraGeom.INTERP.POLYGON, OraGeom.INTERP.RECTANGLE, "Polygon"); int nElem = oraGeom.numElements(); // ETYPE is either POLYGON or POLYGON_EXTERIOR LinearRing exteriorRing = readLinearRing(oraGeom, elemIndex); /** * Holes are read as long as ETYPE = POLYGON_INTERIOR * or ETYPE = POLYGON && orient = CW (Hole) */ List holeRings = new ArrayList(); for (int i = elemIndex + 1; i < nElem; i++) { etype = oraGeom.eType(i); if (etype == OraGeom.ETYPE.POLYGON_INTERIOR) { holeRings.add(readLinearRing(oraGeom, i)); } else if (etype == OraGeom.ETYPE.POLYGON) { // test orientation of Ring to see if it is // an interior (hole) ring LinearRing ring = readLinearRing(oraGeom, i); // TODO: use the coordSeq directly (requires new CGAlgorithms method) boolean isHole = ! CGAlgorithms.isCCW(ring.getCoordinates()); // if not a hole, exit if (! isHole) break; // it is an Interior Hole holeRings.add(ring); } else { // not a LinearRing - get out of here break; } } Polygon poly = geometryFactory.createPolygon(exteriorRing, GeometryFactory.toLinearRingArray(holeRings)); return poly; }
Example #30
Source File: HalfEdge.java From jts with GNU Lesser General Public License v2.1 | 4 votes |
/** * Implements the total order relation: * <p> * The angle of edge a is greater than the angle of edge b, * where the angle of an edge is the angle made by * the first segment of the edge with the positive x-axis * <p> * When applied to a list of edges originating at the same point, * this produces a CCW ordering of the edges around the point. * <p> * Using the obvious algorithm of computing the angle is not robust, * since the angle calculation is susceptible to roundoff error. * A robust algorithm is: * <ul> * <li>First, compare the quadrants the edge vectors lie in. * If the quadrants are different, * it is trivial to determine which edge has a greater angle. * * <li>if the vectors lie in the same quadrant, the * {@link CGAlgorithms#computeOrientation(Coordinate, Coordinate, Coordinate)} function * can be used to determine the relative orientation of the vectors. * </ul> */ public int compareAngularDirection(HalfEdge e) { double dx = deltaX(); double dy = deltaY(); double dx2 = e.deltaX(); double dy2 = e.deltaY(); // same vector if (dx == dx2 && dy == dy2) return 0; double quadrant = Quadrant.quadrant(dx, dy); double quadrant2 = Quadrant.quadrant(dx2, dy2); // if the vectors are in different quadrants, determining the ordering is trivial if (quadrant > quadrant2) return 1; if (quadrant < quadrant2) return -1; // vectors are in the same quadrant // Check relative orientation of direction vectors // this is > e if it is CCW of e return CGAlgorithms.computeOrientation(e.orig, e.dest(), dest()); }