📄 surfaceshapegeometry.java
字号:
/*Copyright (C) 2001, 2008 United States Governmentas represented by the Administrator of theNational Aeronautics and Space Administration.All Rights Reserved.*/package gov.nasa.worldwind.render;import com.sun.opengl.util.*;import gov.nasa.worldwind.*;import gov.nasa.worldwind.geom.*;import gov.nasa.worldwind.globes.*;import gov.nasa.worldwind.terrain.*;import gov.nasa.worldwind.util.*;import javax.media.opengl.*;import javax.media.opengl.glu.*;import java.awt.*;import java.nio.*;import java.util.*;/** * @author $Author$ * @version $Id: SurfaceShapeGeometry.java 8280 2008-12-24 23:08:45Z tgaskins $ */public abstract class SurfaceShapeGeometry implements Renderable, Disposable, Movable { protected Globe globe; protected ArrayList<LatLon> positions = new ArrayList<LatLon>(); private Sector sector; private Vector<Triangle> triangles; private Vector<Polygon> polygons = new Vector<Polygon>(); private Polyline polyline; private Extent extent; private long lastFrameTime = 0; private boolean forceSurfaceIntersect = true; private Color interiorColor; private float[] interiorColorGL = new float[4]; private boolean drawBorder = true; private boolean drawInterior = true; private boolean antiAlias = true; private DoubleBuffer buff; private int[] firsts; private int[] counts; private static long THROTTLE_RATE = 1000L; private static final double EPSILON = 1.e-10; private static final Color DEFAULT_COLOR = new Color(1f, 1f, 0f, 0.4f); private static final Color DEFAULT_BORDER_COLOR = new Color(1f, 1f, 0f, 0.7f); // symbolic indices into double[] arrays holding coordinates... private static final int X = 0; private static final int Y = 1; private static final int Z = 2; public SurfaceShapeGeometry(Iterable<? extends LatLon> positions, Color color, Color borderColor) { if (positions == null) { String message = Logging.getMessage("nullValue.PositionsListIsNull"); Logging.logger().severe(message); throw new IllegalArgumentException(message); } setInteriorColor((color != null) ? color : DEFAULT_COLOR); this.polyline = new Polyline(); this.polyline.setColor(borderColor != null ? borderColor : DEFAULT_BORDER_COLOR); this.polyline.setFollowTerrain(true); this.polyline.setPathType(Polyline.LINEAR); // Copy positions list. this.replacePositions(positions); } private void replacePositions(Iterable<? extends LatLon> newPositions) { this.positions.clear(); for (LatLon position : newPositions) { this.positions.add(position); } this.polyline.setPositions(this.positions, 0.); resetBounds(); } public void dispose() { } public ArrayList<Sector> getSectors() { ArrayList<Sector> sectors = new ArrayList<Sector>(); sectors.add(this.sector); return sectors; } public Iterable<LatLon> getPositions() { return this.positions; } public void setPositions(Iterable<? extends LatLon> positions) { this.replacePositions(positions); } public Paint getInteriorColor() { return interiorColor; } public void setInteriorColor(Color color) { this.interiorColor = color; this.interiorColorGL[0] = this.interiorColor.getRed() / 255f; this.interiorColorGL[1] = this.interiorColor.getGreen() / 255f; this.interiorColorGL[2] = this.interiorColor.getBlue() / 255f; this.interiorColorGL[3] = this.interiorColor.getAlpha() / 255f; } public Color getBorderColor() { return this.polyline.getColor(); } public void setBorderColor(Color borderColor) { this.polyline.setColor(borderColor); } public void setBorderWidth(double width) { this.polyline.setLineWidth(width); } public double getBorderWidth() { return this.polyline.getLineWidth(); } public boolean isDrawBorder() { return drawBorder; } public void setDrawBorder(boolean drawBorder) { this.drawBorder = drawBorder; } public boolean isDrawInterior() { return drawInterior; } public void setDrawInterior(boolean drawInterior) { this.drawInterior = drawInterior; } public boolean isAntiAlias() { return antiAlias; } public void setAntiAlias(boolean antiAlias) { this.antiAlias = antiAlias; } /* * *********************** * public double getNumEdgeIntervalsPerDegree() { * return numEdgeIntervalsPerDegree; * } * <p/> * public void setNumEdgeIntervalsPerDegree(double numEdgeIntervals) { * this.numEdgeIntervalsPerDegree = numEdgeIntervals; * this.clearTextureData(); * } * ********************* */ public double getPerimeter() { return this.polyline.getLength(); } public double getArea() throws IllegalStateException { if (this.polygons == null || this.polygons.size() == 0 || this.globe == null) { // TODO: I8N this... throw new IllegalStateException("NPE in getArea"); } double area = 0.; double[] PQ = new double[3]; double[] PR = new double[3]; for (Polygon p : this.polygons) { // We have 3,4,5,6 sided, convex polygons. Treat them like a triangle-fan, and compute the area // of the individual triangles using the cross-product method. for (int i = 2; i < p.numVerts; i++) { // The convention here is that we have a triangle with vertices P, Q, and R. // Compute the cross-product of the vectors PQ and PR... // NOTE: we are purposefully avoiding the use of Vec4 here to avoid having to allocate // so many instances. // Also note that we've previously stored the polygon coordinates with the ReferencePoint subtracted, // so we are not dealing with as huge of numbers in these calculations. PQ[0] = (p.xy[i - 1][X]) - (p.xy[0][X]); PQ[1] = (p.xy[i - 1][Y]) - (p.xy[0][Y]); PQ[2] = (p.xy[i - 1][Z]) - (p.xy[0][Z]); PR[0] = (p.xy[i][X]) - (p.xy[0][X]); PR[1] = (p.xy[i][Y]) - (p.xy[0][Y]); PR[2] = (p.xy[i][Z]) - (p.xy[0][Z]); // Compute cross product: PQ X PR. Note that the crossY component should be negated for the actual // cross product. But we're just after the magnitude of the vector, and are going to "square-away" // the sign, so it doesn't matter. double crossX = PQ[Y] * PR[Z] - PR[Y] * PQ[Z]; double crossY = PQ[X] * PR[Z] - PR[X] * PQ[Z]; double crossZ = PQ[X] * PR[Y] - PR[X] * PQ[Y]; area += 0.5 * Math.sqrt(crossX * crossX + crossY * crossY + crossZ * crossZ); } } return area; } public void render(DrawContext dc) { // Capture this right away, as several subsequent computations require it.... this.globe = dc.getGlobe(); Frustum f = dc.getView().getFrustumInModelCoordinates(); if (!getExtent(dc).intersects(f)) return; // Do we need to perform top-level tessellation? THis is generally performed once, the first time around... if (this.triangles == null) { this.tessellate(); } if ((System.currentTimeMillis() - this.lastFrameTime) > THROTTLE_RATE || this.forceSurfaceIntersect) { Iterable<SectorGeometry> geom = getIntersectingGeometryTiles(dc.getSurfaceGeometry()); intersectSurfaceGeometry(geom); packagePolygonsForDrawing(); this.lastFrameTime = System.currentTimeMillis(); this.forceSurfaceIntersect = false; } renderPolygons(dc); } // // Package up the polygon data into a vertex array. // private void packagePolygonsForDrawing() { if (polygons.size() == 0) return; int buffSize = 0; for (Polygon p : this.polygons) { buffSize += p.numVerts; } this.buff = BufferUtil.newDoubleBuffer(buffSize*3); this.firsts = new int[polygons.size()]; this.counts = new int[polygons.size()]; buffSize = 0; int i = 0; for (Polygon p : this.polygons) { this.firsts[i] = buffSize; this.counts[i] = p.numVerts; for (int j=0; j<p.numVerts; j++) { this.buff.put(p.xy[j]); } buffSize += p.numVerts; i++; } } private void renderPolygons(DrawContext dc) { Vec4 refPoint = getReferencePoint(); GL gl = dc.getGL(); gl.glPushAttrib(GL.GL_COLOR_BUFFER_BIT | GL.GL_POLYGON_BIT | GL.GL_CURRENT_BIT); dc.getView().pushReferenceCenter(dc, refPoint); this.pushOffset(dc); try { if (!dc.isPickingMode()) { gl.glEnable(GL.GL_BLEND); gl.glBlendFunc(GL.GL_SRC_ALPHA, GL.GL_ONE_MINUS_SRC_ALPHA); gl.glColor4fv(this.interiorColorGL, 0); } if (this.drawInterior || dc.isPickingMode()) { gl.glPolygonMode(GL.GL_FRONT_AND_BACK, GL.GL_FILL); gl.glEnableClientState(GL.GL_VERTEX_ARRAY); buff.rewind(); gl.glVertexPointer(3, GL.GL_DOUBLE, 0, buff); gl.glMultiDrawArrays(GL.GL_TRIANGLE_FAN, this.firsts, 0, this.counts, 0, this.firsts.length); gl.glDisableClientState(GL.GL_VERTEX_ARRAY); } /** pre vertex-array style drawing. Leave for now; not convinced VA's have helped enough here * to warrant their memory overhead. if (this.drawInterior) { gl.glPolygonMode(GL.GL_FRONT_AND_BACK, GL.GL_FILL); for (Polygon p : polygons) { gl.glBegin(GL.GL_TRIANGLE_FAN); for (int i = 0; i < p.numVerts; i++) { gl.glVertex3d(p.xy[i][X]-refPoint.x, p.xy[i][Y]-refPoint.y, p.xy[i][Z]-refPoint.z); } gl.glEnd(); } } ***********/ /****************** // Draw the border... if (!dc.isPickingMode()) { gl.glColor4fv(this.borderColorGL, 0); } gl.glBegin(GL.GL_LINE_LOOP); for (LatLon p : positions) { elev = dc.getGlobe().getElevation(p.getLatitude(), p.getLongitude()); Position pos = new Position(p, elev); Vec4 pnt = this.globe.computePointFromPosition(pos); pnt = pnt.subtract3(refCenterPoint); gl.glVertex3d(pnt.x, pnt.y, pnt.z); } gl.glEnd(); ********************/ // delegate to render the border... if (!dc.isPickingMode() && this.drawBorder) this.polyline.render(dc); } finally { this.popOffset(dc); dc.getView().popReferenceCenter(dc); gl.glPopAttrib(); } } private void pushOffset(DrawContext dc) { // Modify the projection transform to shift the depth values slightly toward the camera in order to // ensure the lines are selected during depth buffering. GL gl = dc.getGL(); float[] pm = new float[16]; gl.glGetFloatv(GL.GL_PROJECTION_MATRIX, pm, 0); pm[10] *= 0.99; // TODO: See Lengyel 2 ed. Section 9.1.2 to compute optimal/minimal offset gl.glPushAttrib(GL.GL_TRANSFORM_BIT); gl.glMatrixMode(GL.GL_PROJECTION); gl.glPushMatrix(); gl.glLoadMatrixf(pm, 0); } private void popOffset(DrawContext dc) { GL gl = dc.getGL(); gl.glMatrixMode(GL.GL_PROJECTION); gl.glPopMatrix(); gl.glPopAttrib(); } // // Intersects the collection of triangles that make up this object with a set of SectorGeometry // objects. // private void intersectSurfaceGeometry(Iterable<SectorGeometry> geom) { // clear existing polygon list... this.polygons.clear(); if (geom == null) return; for (SectorGeometry g : geom) { RectangularTessellator.RectGeometry terrain = RectangularTessellator.getTerrainGeometry(g); for (Triangle t : this.triangles) { if (t.spansDateline)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -