/** Constructor for case (2). * Generate an endpoint, given a single cutoff plane plus upper and lower edge points. *@param point is the center point. *@param cutoffPlane is the plane from the adjoining path segment marking the boundary between this endpoint and that segment. */ public SegmentEndpoint(final GeoPoint point, final SidedPlane cutoffPlane) { this.point = point; this.cutoffPlanes = new Membership[]{new SidedPlane(cutoffPlane)}; this.notablePoints = new GeoPoint[]{point}; }
/** Constructor for case (2). * Generate an endpoint, given a single cutoff plane plus upper and lower edge points. *@param point is the center point. *@param cutoffPlane is the plane from the adjoining path segment marking the boundary between this endpoint and that segment. *@param topEdgePoint is a point on the cutoffPlane that should be also on the circle plane. *@param bottomEdgePoint is another point on the cutoffPlane that should be also on the circle plane. */ public SegmentEndpoint(final GeoPoint point, final SidedPlane cutoffPlane, final GeoPoint topEdgePoint, final GeoPoint bottomEdgePoint) { this.point = point; this.cutoffPlanes = new Membership[]{new SidedPlane(cutoffPlane)}; this.notablePoints = new GeoPoint[]{topEdgePoint, bottomEdgePoint}; // To construct the plane, we now just need D, which is simply the negative of the evaluation of the circle normal vector at one of the points. this.circlePlane = SidedPlane.constructNormalizedPerpendicularSidedPlane(point, cutoffPlane, topEdgePoint, bottomEdgePoint); }
public ApproximationSlice(final GeoPoint center, final GeoPoint endPoint1, final double point1Bearing, final GeoPoint endPoint2, final double point2Bearing, final GeoPoint middlePoint, final double middlePointBearing, final boolean mustSplit) { this.endPoint1 = endPoint1; this.point1Bearing = point1Bearing; this.endPoint2 = endPoint2; this.point2Bearing = point2Bearing; this.middlePoint = middlePoint; this.middlePointBearing = middlePointBearing; this.mustSplit = mustSplit; // Construct the plane going through the three given points this.plane = SidedPlane.constructNormalizedThreePointSidedPlane(center, endPoint1, endPoint2, middlePoint); if (this.plane == null) { throw new IllegalArgumentException("Either circle is too small or accuracy is too high; could not construct a plane with endPoint1="+endPoint1+" bearing "+point1Bearing+", endPoint2="+endPoint2+" bearing "+point2Bearing+", middle="+middlePoint+" bearing "+middlePointBearing); } if (this.plane.isWithin(-center.x, -center.y, -center.z)) { //Plane is bogus, we cannot build the circle throw new IllegalArgumentException("Could not construct a valid plane for this planet model with endPoint1="+endPoint1+" bearing "+point1Bearing+", endPoint2="+endPoint2+" bearing "+point2Bearing+", middle="+middlePoint+" bearing "+middlePointBearing); } }
final boolean cand1IsOtherWithin = candidate1!=null?candidate1.isWithin(notCand1Point):false; final boolean cand2IsOtherWithin = candidate2!=null?candidate2.isWithin(notCand2Point):false; final boolean cand3IsOtherWithin = candidate3!=null?candidate3.isWithin(notCand3Point):false; final boolean cand4IsOtherWithin = candidate4!=null?candidate4.isWithin(notCand4Point):false; this.cutoffPlanes = new Membership[]{new SidedPlane(prevCutoffPlane), new SidedPlane(nextCutoffPlane)}; } else if (cand1IsOtherWithin) { this.cutoffPlanes = new Membership[]{new SidedPlane(nextCutoffPlane)}; } else if (cand2IsOtherWithin) { this.cutoffPlanes = new Membership[]{new SidedPlane(nextCutoffPlane)}; } else if (cand3IsOtherWithin) { this.circlePlane = candidate3; this.notablePoints = new GeoPoint[]{notCand4Point, notCand1Point, notCand2Point}; this.cutoffPlanes = new Membership[]{new SidedPlane(prevCutoffPlane)}; } else if (cand4IsOtherWithin) { this.circlePlane = candidate4; this.notablePoints = new GeoPoint[]{notCand1Point, notCand2Point, notCand3Point}; this.cutoffPlanes = new Membership[]{new SidedPlane(prevCutoffPlane)}; } else {
final SidedPlane sp = new SidedPlane(check, start, end); edges[i] = sp; notableEdgePoints[i] = new GeoPoint[]{start, end}; final SidedPlane edge = edges[edgeIndex]; int bound1Index = legalIndex(edgeIndex+1); while (edges[bound1Index].isNumericallyIdentical(edge)) { if (bound1Index == edgeIndex) { throw new IllegalArgumentException("Constructed planes are all coplanar: "+points); while (edges[bound2Index].isNumericallyIdentical(edge)) { if (bound2Index == edgeIndex) { throw new IllegalArgumentException("Constructed planes are all coplanar: "+points); if (!edges[bound1Index].isWithin(interiorPoint) || !edges[bound2Index].isWithin(interiorPoint)) { throw new IllegalArgumentException("Convex polygon has a side that is more than 180 degrees");
final SidedPlane testPointBound1 = new SidedPlane(intersectionPoint, testPointPlane, testPoint); final SidedPlane testPointBound2 = new SidedPlane(testPoint, testPointPlane, intersectionPoint); if (testPointBound1.isFunctionallyIdentical(testPointBound2)) { throw new IllegalArgumentException("Dual iterator unreliable when bounds planes are functionally identical"); this.testPointOtherCutoffPlane = testPointBound2; final SidedPlane checkPointBound1 = new SidedPlane(intersectionPoint, travelPlane, thePointX, thePointY, thePointZ); final SidedPlane checkPointBound2 = new SidedPlane(thePointX, thePointY, thePointZ, travelPlane, intersectionPoint); if (checkPointBound1.isFunctionallyIdentical(checkPointBound2)) { throw new IllegalArgumentException("Dual iterator unreliable when bounds planes are functionally identical"); assert testPointCutoffPlane.isWithin(intersectionPoint) : "intersection must be within testPointCutoffPlane"; assert testPointOtherCutoffPlane.isWithin(intersectionPoint) : "intersection must be within testPointOtherCutoffPlane"; assert checkPointCutoffPlane.isWithin(intersectionPoint) : "intersection must be within checkPointCutoffPlane"; assert checkPointOtherCutoffPlane.isWithin(intersectionPoint) : "intersection must be within checkPointOtherCutoffPlane";
/** * Check whether a point is strictly within a plane. * @param v is the point. * @return true if within. */ public boolean strictlyWithin(final Vector v) { double evalResult = evaluate(v.x, v.y, v.z); double sigNum = Math.signum(evalResult); return sigNum == 0.0 || sigNum == this.sigNum; }
upperConnectingPlane = new SidedPlane(start, normalizedConnectingPlane, -planeBoundingOffset); lowerConnectingPlane = new SidedPlane(start, normalizedConnectingPlane, planeBoundingOffset); startCutoffPlane = new SidedPlane(end, normalizedConnectingPlane, start); endCutoffPlane = new SidedPlane(start, normalizedConnectingPlane, end); final Membership[] upperSide = new Membership[]{upperConnectingPlane}; final Membership[] lowerSide = new Membership[]{lowerConnectingPlane}; final Membership[] endSide = new Membership[]{endCutoffPlane}; GeoPoint[] points; points = upperConnectingPlane.findIntersections(planetModel, startCutoffPlane, lowerSide, endSide); if (points.length == 0) { throw new IllegalArgumentException("Some segment boundary points are off the ellipsoid; path too wide"); points = upperConnectingPlane.findIntersections(planetModel, endCutoffPlane, lowerSide, startSide); if (points.length == 0) { throw new IllegalArgumentException("Some segment boundary points are off the ellipsoid; path too wide"); points = lowerConnectingPlane.findIntersections(planetModel, startCutoffPlane, upperSide, endSide); if (points.length == 0) { throw new IllegalArgumentException("Some segment boundary points are off the ellipsoid; path too wide"); points = lowerConnectingPlane.findIntersections(planetModel, endCutoffPlane, upperSide, startSide); if (points.length == 0) { throw new IllegalArgumentException("Some segment boundary points are off the ellipsoid; path too wide");
minXPlane = new SidedPlane(maxX,0.0,0.0,xUnitVector,-minX); maxXPlane = new SidedPlane(minX,0.0,0.0,xUnitVector,-maxX); minYPlane = new SidedPlane(0.0,maxY,0.0,yUnitVector,-minY); maxYPlane = new SidedPlane(0.0,minY,0.0,yUnitVector,-maxY); minZPlane = new SidedPlane(0.0,0.0,maxZ,zUnitVector,-minZ); maxZPlane = new SidedPlane(0.0,0.0,minZ,zUnitVector,-maxZ); final GeoPoint[] minXminY = minXPlane.findIntersections(planetModel,minYPlane,maxXPlane,maxYPlane,minZPlane,maxZPlane); final GeoPoint[] minXmaxY = minXPlane.findIntersections(planetModel,maxYPlane,maxXPlane,minYPlane,minZPlane,maxZPlane); final GeoPoint[] minXminZ = minXPlane.findIntersections(planetModel,minZPlane,maxXPlane,maxZPlane,minYPlane,maxYPlane); final GeoPoint[] minXmaxZ = minXPlane.findIntersections(planetModel,maxZPlane,maxXPlane,minZPlane,minYPlane,maxYPlane); final GeoPoint[] maxXminY = maxXPlane.findIntersections(planetModel,minYPlane,minXPlane,maxYPlane,minZPlane,maxZPlane); final GeoPoint[] maxXmaxY = maxXPlane.findIntersections(planetModel,maxYPlane,minXPlane,minYPlane,minZPlane,maxZPlane); final GeoPoint[] maxXminZ = maxXPlane.findIntersections(planetModel,minZPlane,minXPlane,maxZPlane,minYPlane,maxYPlane); final GeoPoint[] maxXmaxZ = maxXPlane.findIntersections(planetModel,maxZPlane,minXPlane,minZPlane,minYPlane,maxYPlane); final GeoPoint[] minYminZ = minYPlane.findIntersections(planetModel,minZPlane,maxYPlane,maxZPlane,minXPlane,maxXPlane); final GeoPoint[] minYmaxZ = minYPlane.findIntersections(planetModel,maxZPlane,maxYPlane,minZPlane,minXPlane,maxXPlane); final GeoPoint[] maxYminZ = maxYPlane.findIntersections(planetModel,minZPlane,minYPlane,maxZPlane,minXPlane,maxXPlane); final GeoPoint[] maxYmaxZ = maxYPlane.findIntersections(planetModel,maxZPlane,minYPlane,minZPlane,minXPlane,maxXPlane); final GeoPoint intPoint = minXPlane.getSampleIntersectionPoint(planetModel, xVerticalPlane); if (intPoint != null) { minXEdges = new GeoPoint[]{intPoint}; final GeoPoint intPoint = maxXPlane.getSampleIntersectionPoint(planetModel, xVerticalPlane); if (intPoint != null) { maxXEdges = new GeoPoint[]{intPoint};
/** Determine if this endpoint intersects a specified plane. *@param planetModel is the planet model. *@param p is the plane. *@param notablePoints are the points associated with the plane. *@param bounds are any bounds which the intersection must lie within. *@return true if there is a matching intersection. */ public boolean intersects(final PlanetModel planetModel, final Plane p, final GeoPoint[] notablePoints, final Membership[] bounds) { return upperConnectingPlane.intersects(planetModel, p, notablePoints, upperConnectingPlanePoints, bounds, lowerConnectingPlane, startCutoffPlane, endCutoffPlane) || lowerConnectingPlane.intersects(planetModel, p, notablePoints, lowerConnectingPlanePoints, bounds, upperConnectingPlane, startCutoffPlane, endCutoffPlane); }
public SectorLinearCrossingEdgeIterator(final GeoPoint testPoint, final Plane plane, final Plane abovePlane, final Plane belowPlane, final double thePointX, final double thePointY, final double thePointZ) { assert plane.evaluateIsZero(thePointX, thePointY, thePointZ) : "Check point is not on travel plane"; assert plane.evaluateIsZero(testPoint) : "Test point is not on travel plane"; this.testPoint = testPoint; this.plane = plane; this.abovePlane = abovePlane; this.belowPlane = belowPlane; // We have to be sure we don't accidently create two bounds that would exclude all points. // Not sure this can happen but... final SidedPlane bound1Plane = new SidedPlane(thePointX, thePointY, thePointZ, plane, testPoint); final SidedPlane bound2Plane = new SidedPlane(testPoint, plane, thePointX, thePointY, thePointZ); if (bound1Plane.isNumericallyIdentical(bound2Plane)) { throw new IllegalArgumentException("Sector iterator unreliable when bounds planes are numerically identical"); } this.bound1 = bound1Plane; this.bound2 = bound2Plane; this.thePointX = thePointX; this.thePointY = thePointY; this.thePointZ = thePointZ; //System.out.println(" Constructing sector linear crossing edge iterator"); //debugIntersectAllEdges(plane, bound1, bound2); }
this.circlePlane = SidedPlane.constructNormalizedPerpendicularSidedPlane(center, normalPlane, upperPoint, lowerPoint); if (circlePlane == null) throw new IllegalArgumentException("Couldn't construct circle plane, probably too small? Cutoff angle = "+cutoffAngle+"; upperPoint = "+upperPoint+"; lowerPoint = "+lowerPoint); final GeoPoint recomputedIntersectionPoint = circlePlane.getSampleIntersectionPoint(planetModel, normalPlane); if (recomputedIntersectionPoint == null) throw new IllegalArgumentException("Couldn't construct intersection point, probably circle too small? Plane = "+circlePlane);
this.edgePoints = new GeoPoint[]{onlyEndpoint.circlePlane.getSampleIntersectionPoint(planetModel, normalPlane)}; return; final SidedPlane candidate1 = SidedPlane.constructNormalizedThreePointSidedPlane(currentSegment.start, prevSegment.URHC, currentSegment.ULHC, currentSegment.LLHC); final SidedPlane candidate2 = SidedPlane.constructNormalizedThreePointSidedPlane(currentSegment.start, currentSegment.ULHC, currentSegment.LLHC, prevSegment.LRHC); final SidedPlane candidate3 = SidedPlane.constructNormalizedThreePointSidedPlane(currentSegment.start, currentSegment.LLHC, prevSegment.LRHC, prevSegment.URHC); final SidedPlane candidate4 = SidedPlane.constructNormalizedThreePointSidedPlane(currentSegment.start, prevSegment.LRHC, prevSegment.URHC, currentSegment.ULHC);
if (lastEdge.plane.isFunctionallyIdentical(newLastEdge.plane)) { throw new TileException("Two adjacent edge planes are effectively parallel despite filtering; give up on tiling"); break; returnBoundary = new SidedPlane(firstEdge.endPoint, firstEdge.startPoint, newLastEdge.endPoint); } else { returnBoundary = null; if (firstEdge.plane.isFunctionallyIdentical(newFirstEdge.plane)) { throw new TileException("Two adjacent edge planes are effectively parallel despite filtering; give up on tiling"); break; returnBoundary = new SidedPlane(lastEdge.startPoint, lastEdge.endPoint, newFirstEdge.startPoint); } else { returnBoundary = null; if (firstEdge.plane.isFunctionallyIdentical(lastEdge.plane)) { throw new TileException("Two adjacent edge planes are effectively parallel despite filtering; give up on tiling"); } else { final SidedPlane returnSidedPlane = new SidedPlane(firstEdge.endPoint, false, firstEdge.startPoint, lastEdge.endPoint); final Edge returnEdge = new Edge(firstEdge.startPoint, lastEdge.endPoint, returnSidedPlane, true); if (returnEdge.plane.isFunctionallyIdentical(lastEdge.plane) || returnEdge.plane.isFunctionallyIdentical(firstEdge.plane)) { throw new TileException("Two adjacent edge planes are effectively parallel despite filtering; give up on tiling");
@Override public int hashCode() { int result = super.hashCode(); result = 31 * result + (isWholeWorld?1:0); if (!isWholeWorld) { result = 31 * result + minXPlane.hashCode(); result = 31 * result + maxXPlane.hashCode(); result = 31 * result + minYPlane.hashCode(); result = 31 * result + maxYPlane.hashCode(); result = 31 * result + minZPlane.hashCode(); result = 31 * result + maxZPlane.hashCode(); } return result; }
@Override public boolean equals(Object o) { if (!(o instanceof StandardXYZSolid)) return false; StandardXYZSolid other = (StandardXYZSolid) o; if (!super.equals(other) || other.isWholeWorld != isWholeWorld) { return false; } if (!isWholeWorld) { return other.minXPlane.equals(minXPlane) && other.maxXPlane.equals(maxXPlane) && other.minYPlane.equals(minYPlane) && other.maxYPlane.equals(maxYPlane) && other.minZPlane.equals(minZPlane) && other.maxZPlane.equals(maxZPlane); } return true; }
/** Constructor for case (1). * Generate a simple circle cutoff plane. *@param point is the center point. *@param upperPoint is a point that must be on the circle plane. *@param lowerPoint is another point that must be on the circle plane. */ public SegmentEndpoint(final GeoPoint point, final Plane normalPlane, final GeoPoint upperPoint, final GeoPoint lowerPoint) { this.point = point; // Construct a sided plane that goes through the two points and whose normal is in the normalPlane. this.circlePlane = SidedPlane.constructNormalizedPerpendicularSidedPlane(point, normalPlane, upperPoint, lowerPoint); this.cutoffPlanes = NO_MEMBERSHIP; this.notablePoints = circlePoints; }
this.topPlane = new SidedPlane(centerPoint, planetModel, sinTopLat); this.leftPlane = new SidedPlane(centerPoint, cosLeftLon, sinLeftLon); this.rightPlane = new SidedPlane(centerPoint, cosRightLon, sinRightLon); assert(topPlane.isWithin(centerPoint)); assert(leftPlane.isWithin(centerPoint)); assert(rightPlane.isWithin(centerPoint)); this.backingPlane = new SidedPlane(this.centerPoint, cosMiddleLon, sinMiddleLon, 0.0, 0.0);
edges[i] = new SidedPlane(check, false, start, end); invertedEdges[i] = new SidedPlane(edges[i]); notableEdgePoints[i] = new GeoPoint[]{start, end}; final SidedPlane invertedEdge = invertedEdges[edgeIndex]; int bound1Index = legalIndex(edgeIndex+1); while (invertedEdges[bound1Index].isNumericallyIdentical(invertedEdge)) { if (bound1Index == edgeIndex) { throw new IllegalArgumentException("Constructed planes are all coplanar: "+points); while (invertedEdges[bound2Index].isNumericallyIdentical(invertedEdge)) { if (bound2Index == edgeIndex) { throw new IllegalArgumentException("Constructed planes are all coplanar: "+points); if (!invertedEdges[bound1Index].isWithin(interiorPoint) || !invertedEdges[bound2Index].isWithin(interiorPoint)) { throw new IllegalArgumentException("Concave polygon has a side that is more than 180 degrees");
/** * Check whether a point is strictly within a plane. * @param x is the point x value. * @param y is the point y value. * @param z is the point z value. * @return true if within. */ public boolean strictlyWithin(double x, double y, double z) { double evalResult = evaluate(x, y, z); double sigNum = Math.signum(evalResult); return sigNum == 0.0 || sigNum == this.sigNum; }