📄 surfaceshapegeometry.java
字号:
this.p1Lon = p1.getLongitude().degrees; this.p1Lat = p1.getLatitude().degrees; } deltaX = p1Lon - p0Lon; deltaY = p1Lat - p0Lat; } public double getLonAtLat(double lat) { if (Math.abs(deltaY) < 1.e-10) { return Double.MAX_VALUE; } double t = (lat - p0Lat) / deltaY; return (p0Lon + t * deltaX); } public double getLatAtLon(double lon) { if (Math.abs(deltaX) < 1.e-10) { return Double.MAX_VALUE; } double t = (lon - p0Lon) / deltaX; return (p0Lat + t * deltaY); } } // // Returns a list of SectorGeometry objects whose extent overlaps that of this object. // protected Iterable<SectorGeometry> getIntersectingGeometryTiles(SectorGeometryList sg) { ArrayList<SectorGeometry> intersectingGeom = null; for (SectorGeometry geom : sg) { if (!this.getSector().intersects(geom.getSector())) continue; if (intersectingGeom == null) intersectingGeom = new ArrayList<SectorGeometry>(); intersectingGeom.add(geom); } return intersectingGeom; } public Position getReferencePosition() { // Here we pick a vertex arbitrarily. Whereas it might seem reasonable to pick the centroid of the // collection of points, computing that value is tricky in cases where the shape spans the dateline. return new Position(positions.get(0), 0); } public Vec4 getReferencePoint() { Position ref = getReferencePosition(); double elev = this.globe.getElevation(ref.getLatitude(), ref.getLongitude()); return this.globe.computePointFromPosition(ref.getLatitude(), ref.getLongitude(), elev); } public void move(Position delta) { if (delta == null) { String msg = Logging.getMessage("nullValue.PositionIsNull"); Logging.logger().severe(msg); throw new IllegalArgumentException(msg); } this.moveTo(this.getReferencePosition().add(delta)); } /** * Move the shape over the sphereoid surface without maintaining its original azimuth -- its orientation relative to * North. * * @param position the new position to move the shapes reference position to. */ public void shiftTo(Position position) { if (this.globe == null) return; if (position == null) { String msg = Logging.getMessage("nullValue.PositionIsNull"); Logging.logger().severe(msg); throw new IllegalArgumentException(msg); } Vec4 p1 = globe.computePointFromPosition(this.getReferencePosition().getLatitude(), this.getReferencePosition().getLongitude(), 0); Vec4 p2 = globe.computePointFromPosition(position.getLatitude(), position.getLongitude(), 0); Vec4 delta = p2.subtract3(p1); for (int i = 0; i < this.positions.size(); i++) { LatLon ll = this.positions.get(i); Vec4 p = globe.computePointFromPosition(ll.getLatitude(), ll.getLongitude(), 0); p = p.add3(delta); Position pos = globe.computePositionFromPoint(p); this.positions.set(i, new LatLon(pos.getLatitude(), pos.getLongitude())); } this.polyline.setPositions(this.positions, 0.); for (Triangle t : triangles) { for (int i = 0; i < 3; i++) { LatLon ll = t.vertices[i]; Vec4 p = globe.computePointFromPosition(ll.getLatitude(), ll.getLongitude(), 0); p = p.add3(delta); Position pos = globe.computePositionFromPoint(p); t.vertices[i] = new LatLon(pos.getLatitude(), pos.getLongitude()); } t.setOrClearDatelineFlag(); } resetBounds(); this.forceSurfaceIntersect = true; } /** * Move the shape over the sphereoid surface while maintaining its original azimuth -- its orientation relative to * North. * * @param position the new position to move the shapes reference position to. */ public void moveTo(Position position) { if (LatLon.positionsCrossDateLine(this.positions)) { // TODO: Replace this hack by figuring out how to *accurately* move date-line crossing shapes using the // distance/azimuth method used below for shapes that do not cross the dateline. shiftTo(position); return; } LatLon oldRef = this.getReferencePosition(); for (int i = 0; i < this.positions.size(); i++) { LatLon p = this.positions.get(i); double distance = LatLon.greatCircleDistance(oldRef, p).radians; double azimuth = LatLon.greatCircleAzimuth(oldRef, p).radians; LatLon pp = LatLon.greatCircleEndPosition(position, azimuth, distance); this.positions.set(i, pp); } this.polyline.setPositions(positions, 0.); for (Triangle t : this.triangles) { for (int i = 0; i < 3; i++) { LatLon p = t.vertices[i]; double distance = LatLon.greatCircleDistance(oldRef, p).radians; double azimuth = LatLon.greatCircleAzimuth(oldRef, p).radians; LatLon pp = LatLon.greatCircleEndPosition(position, azimuth, distance); t.vertices[i] = pp; } t.setOrClearDatelineFlag(); } resetBounds(); this.forceSurfaceIntersect = true; } public static SurfaceShapeGeometry createEllipse(Globe globe, LatLon center, double majorAxisLength, double minorAxisLength, Angle orientation, int intervals, Color interiorColor, Color borderColor) { if (orientation == null) orientation = Angle.ZERO; if (majorAxisLength <= 0) { String message = Logging.getMessage("Geom.MajorAxisInvalid"); Logging.logger().severe(message); throw new IllegalArgumentException(message); } if (minorAxisLength <= 0) { String message = Logging.getMessage("Geom.MajorAxisInvalid"); Logging.logger().severe(message); throw new IllegalArgumentException(message); } int numPositions = 1 + Math.max(intervals, 4); final ArrayList<LatLon> positions = new ArrayList<LatLon>(); double radius = globe.getRadiusAt(center.getLatitude(), center.getLongitude()); double da = 2 * Math.PI / (numPositions - 1); for (int i = 0; i < numPositions; i++) { // azimuth runs positive clockwise from north and through 360 degrees. double angle = (i != numPositions - 1) ? i * da : 0; double azimuth = Math.PI / 2 - (angle + orientation.radians); double xLength = majorAxisLength * Math.cos(angle); double yLength = minorAxisLength * Math.sin(angle); double distance = Math.sqrt(xLength * xLength + yLength * yLength); LatLon p = LatLon.greatCircleEndPosition(center, azimuth, distance / radius); positions.add(p); } return new SurfacePolygonGeometry(positions, interiorColor, borderColor); } private Sector getSector() { if (this.sector == null) this.sector = Sector.boundingSector(this.positions); return this.sector; } private Extent getExtent(DrawContext dc) { if (this.extent == null) this.extent = this.globe.computeBoundingCylinder(dc.getVerticalExaggeration(), this.getSector()); return extent; } private void resetBounds() { this.sector = null; this.extent = null; } // // Uses OpenGL's GLU facilities to perform a top-level triangulation of our SurfaceShape. // private void tessellate() { this.triangles = new Vector<Triangle>(); GLU glu = new GLU(); GLUtessellator tobj = glu.gluNewTess(); TessCallback tessCallback = new TessCallback(glu); glu.gluTessCallback(tobj, GLU.GLU_TESS_VERTEX, tessCallback); glu.gluTessCallback(tobj, GLU.GLU_TESS_COMBINE, tessCallback); glu.gluTessCallback(tobj, GLU.GLU_EDGE_FLAG, tessCallback); glu.gluTessCallback(tobj, GLU.GLU_TESS_BEGIN, tessCallback); glu.gluTessCallback(tobj, GLU.GLU_TESS_END, tessCallback); glu.gluTessCallback(tobj, GLU.GLU_TESS_ERROR, tessCallback); // GLU wants double arrays for the vertices... int len = this.positions.size(); double[][] pnts = new double[len][3]; glu.gluTessBeginPolygon(tobj, null); glu.gluTessBeginContour(tobj); for (int i = 0; i < len; i++) { LatLon p = this.positions.get(i); pnts[i][X] = p.getLongitude().degrees; if (pnts[i][X] > 0.) pnts[i][X] -= Angle.POS360.degrees; // deal with dateline issues; will get correct at triangle re-assembly... pnts[i][Y] = p.getLatitude().degrees; // NOTE: found out the hard way that these polygons had better be planar! // The tessellation fails or misbehaves otherwise. pnts[i][Z] = 0.; glu.gluTessVertex(tobj, pnts[i], 0, pnts[i]); } glu.gluTessEndContour(tobj); glu.gluTessEndPolygon(tobj); glu.gluDeleteTess(tobj); // free this resource. } // // Tessellation callback implementation. // private class TessCallback extends GLUtessellatorCallbackAdapter { public TessCallback(GLU glu) { this.glu = glu; } public void begin(int type) { this.state = 0; this.type = type; this.flipOrder = false; this.currTriangle = new Triangle(); } public void end() { // NO-OP } public void vertex(Object data) { if (!(data instanceof double[])) { return; } double[] d = (double[]) data; Angle lon = Angle.normalizedLongitude(Angle.fromDegrees(d[0])); Angle lat = Angle.normalizedLatitude(Angle.fromDegrees(d[1])); this.currTriangle.vertices[this.state++] = new LatLon(lat, lon); if (this.state == 3) { this.currTriangle.setOrClearDatelineFlag(); SurfaceShapeGeometry.this.triangles.add(this.currTriangle); // Depending upon type of triangles we're being handed, we may already have 2 vertices for the // next triangle; gather those accordingly. switch (this.type) { case GL.GL_TRIANGLE_FAN: Triangle t = new Triangle(); t.vertices[0] = this.currTriangle.vertices[0]; // these indices reflect the definition of t.vertices[1] = this.currTriangle.vertices[2]; // TRIANGLE_FAN this.currTriangle = t; this.state = 2; break; case GL.GL_TRIANGLE_STRIP: t = new Triangle(); short first; short second; if (this.flipOrder) { first = 0; // Again, these indices reflect how TRIANGLE_STRIPs work. second = 2; } else { first = 2; second = 1; } this.flipOrder = !this.flipOrder; t.vertices[0] = this.currTriangle.vertices[first]; t.vertices[1] = this.currTriangle.vertices[second]; this.currTriangle = t; this.state = 2; break; case GL.GL_TRIANGLES: this.currTriangle = new Triangle(); this.state = 0; break; default: String msg = Logging.getMessage("SurfaceShape.UnknownTriangleForm", this.type); Logging.logger().severe(msg); } } } public void combine(double[] coords, Object[] data, float[] weight, Object[] outData) { double[] newCoord = new double[3]; newCoord[X] = coords[X]; newCoord[Y] = coords[Y]; newCoord[Z] = coords[Z]; outData[0] = newCoord; } public void edgeFlag(boolean isEdge) { } public void error(int errnum) { String glErrorMsg = glu.gluErrorString(errnum); String msg = Logging.getMessage("SurfaceShape.TessellationError", glErrorMsg); Logging.logger().severe(msg); throw new RuntimeException(); } private GLU glu; private int type; private Triangle currTriangle; private short state; // state is the number of vertices we've collected to make a triangle... private boolean flipOrder; // reflect the rules for gathering vertices from a triangle_strip } private static class Triangle { LatLon[] vertices; boolean spansDateline; public Triangle() { vertices = new LatLon[3]; spansDateline = false; } public void setOrClearDatelineFlag() { spansDateline = false; if (vertices[0] != null || vertices[1] != null || vertices[2] != null) { if (LatLon.positionsCrossLongitudeBoundary(vertices[0], vertices[1]) || LatLon.positionsCrossLongitudeBoundary(vertices[1], vertices[2]) || LatLon.positionsCrossLongitudeBoundary(vertices[0], vertices[2])) { spansDateline = true; } } } }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -