@Override protected List<Vec4> computeMinimalGeometry(Globe globe, double verticalExaggeration) { double[] angles = this.computeAngles(); // Angles are equal, fall back to building a closed cylinder. if (angles == null) return super.computeMinimalGeometry(globe, verticalExaggeration); double[] radii = this.getRadii(); Matrix transform = this.computeTransform(globe, verticalExaggeration); GeometryBuilder gb = this.getGeometryBuilder(); int count = gb.getPartialDiskVertexCount(MINIMAL_GEOMETRY_SLICES, MINIMAL_GEOMETRY_LOOPS); int numCoords = 3 * count; float[] verts = new float[numCoords]; gb.makePartialDiskVertices( (float) radii[0], (float) radii[1], // Inner radius, outer radius. MINIMAL_GEOMETRY_SLICES, MINIMAL_GEOMETRY_LOOPS, // Slices, loops, (float) angles[0], (float) angles[2], // Start angle, sweep angle. verts); List<LatLon> locations = new ArrayList<LatLon>(); for (int i = 0; i < numCoords; i += 3) { Vec4 v = new Vec4(verts[i], verts[i + 1], verts[i + 2]); v = v.transformBy4(transform); locations.add(globe.computePositionFromPoint(v)); } ArrayList<Vec4> points = new ArrayList<Vec4>(); this.makeExtremePoints(globe, verticalExaggeration, locations, points); return points; }
private void makeRadialWall( DrawContext dc, double[] radii, double angle, double[] altitudes, boolean[] terrainConformant, int pillars, int stacks, int orientation, Vec4 referenceCenter, Geometry dest) { GeometryBuilder gb = this.getGeometryBuilder(); gb.setOrientation(orientation); float height = (float) (altitudes[1] - altitudes[0]); int count = gb.getRadialWallVertexCount(pillars, stacks); int numCoords = 3 * count; float[] verts = new float[numCoords]; float[] norms = new float[numCoords]; gb.makeRadialWallVertices( (float) radii[0], (float) radii[1], height, (float) angle, pillars, stacks, verts); this.makeRadialWallTerrainConformant( dc, pillars, stacks, verts, altitudes, terrainConformant, referenceCenter); gb.makeRadialWallNormals( (float) radii[0], (float) radii[1], height, (float) angle, pillars, stacks, norms); dest.setVertexData(count, verts); dest.setNormalData(count, norms); }
private void makeSectionOutlineIndices( int subdivisions, int vertexPos, int indexPos, int[] indices, boolean beginEdgeFlag, boolean endEdgeFlag) { GeometryBuilder gb = this.getGeometryBuilder(); int count = gb.getSubdivisionPointsVertexCount(subdivisions); int index = indexPos; int pos, nextPos; if (beginEdgeFlag) { pos = vertexPos; indices[index++] = pos; indices[index++] = pos + 1; } for (int i = 0; i < count - 1; i++) { pos = vertexPos + 2 * i; nextPos = vertexPos + 2 * (i + 1); indices[index++] = pos; indices[index++] = nextPos; indices[index++] = pos + 1; indices[index++] = nextPos + 1; } if (endEdgeFlag) { pos = vertexPos + 2 * (count - 1); indices[index++] = pos; indices[index] = pos + 1; } }
private void makePartialCylinder( DrawContext dc, double radius, double[] altitudes, boolean[] terrainConformant, int slices, int stacks, int orientation, double start, double sweep, Vec4 referenceCenter, Geometry dest) { GeometryBuilder gb = this.getGeometryBuilder(); gb.setOrientation(orientation); float height = (float) (altitudes[1] - altitudes[0]); int count = gb.getPartialCylinderVertexCount(slices, stacks); int numCoords = 3 * count; float[] verts = new float[numCoords]; float[] norms = new float[numCoords]; gb.makePartialCylinderVertices( (float) radius, height, slices, stacks, (float) start, (float) sweep, verts); gb.makePartialCylinderNormals( (float) radius, height, slices, stacks, (float) start, (float) sweep, norms); this.makePartialCylinderTerrainConformant( dc, slices, stacks, verts, altitudes, terrainConformant, referenceCenter); dest.setVertexData(count, verts); dest.setNormalData(count, norms); }
protected void makeTessellatedLocations( Globe globe, int subdivisions, List<LatLon> locations, List<LatLon> tessellatedLocations) { ArrayList<Vec4> points = new ArrayList<Vec4>(); for (LatLon ll : locations) { points.add(globe.computePointFromLocation(ll)); } //noinspection StringEquality if (WWMath.computeWindingOrderOfLocations(locations) != AVKey.COUNTER_CLOCKWISE) Collections.reverse(locations); Vec4 centerPoint = Vec4.computeAveragePoint(points); Vec4 surfaceNormal = globe.computeSurfaceNormalAtPoint(centerPoint); int numPoints = points.size(); float[] coords = new float[3 * numPoints]; for (int i = 0; i < numPoints; i++) { points.get(i).toFloatArray(coords, 3 * i, 3); } GeometryBuilder gb = new GeometryBuilder(); GeometryBuilder.IndexedTriangleArray tessellatedPoints = gb.tessellatePolygon(0, numPoints, coords, surfaceNormal); for (int i = 0; i < subdivisions; i++) { gb.subdivideIndexedTriangleArray(tessellatedPoints); } for (int i = 0; i < tessellatedPoints.getVertexCount(); i++) { Vec4 v = Vec4.fromFloatArray(tessellatedPoints.getVertices(), 3 * i, 3); tessellatedLocations.add(globe.computePositionFromPoint(v)); } }
private int getSectionOutlineIndexCount( int subdivisions, boolean beginEdgeFlag, boolean endEdgeFlag) { GeometryBuilder gb = this.getGeometryBuilder(); int count = 4 * (gb.getSubdivisionPointsVertexCount(subdivisions) - 1); if (beginEdgeFlag) count += 2; if (endEdgeFlag) count += 2; return count; }
private void makeEdge( DrawContext dc, int count, float[] locations, Boolean[] edgeFlags, double[] altitudes, boolean[] terrainConformant, int subdivisions, int orientation, Matrix locationTransform, Vec4 referenceCenter, int fillIndexPos, int[] fillIndices, int outlineIndexPos, int[] outlineIndices, int vertexPos, float[] vertices, float[] normals) { GeometryBuilder gb = this.getGeometryBuilder(); gb.setOrientation(orientation); int sectionFillIndexCount = this.getSectionFillIndexCount(subdivisions); int sectionVertexCount = this.getSectionVertexCount(subdivisions); for (int i = 0; i < count - 1; i++) { boolean beginEdgeFlag = edgeFlags[i]; boolean endEdgeFlag = edgeFlags[i + 1]; this.makeSectionFillIndices(subdivisions, vertexPos, fillIndexPos, fillIndices); this.makeSectionOutlineIndices( subdivisions, vertexPos, outlineIndexPos, outlineIndices, beginEdgeFlag, endEdgeFlag); this.makeSectionVertices( dc, i, locations, altitudes, terrainConformant, subdivisions, locationTransform, referenceCenter, vertexPos, vertices); gb.makeIndexedTriangleArrayNormals( fillIndexPos, sectionFillIndexCount, fillIndices, vertexPos, sectionVertexCount, vertices, normals); fillIndexPos += sectionFillIndexCount; outlineIndexPos += this.getSectionOutlineIndexCount(subdivisions, beginEdgeFlag, endEdgeFlag); vertexPos += sectionVertexCount; } }
private void makeRadialWallIndices(int pillars, int stacks, int orientation, Geometry dest) { GeometryBuilder gb = this.getGeometryBuilder(); gb.setOrientation(orientation); int mode = gb.getRadialWallDrawMode(); int count = gb.getRadialWallIndexCount(pillars, stacks); int[] indices = new int[count]; gb.makeRadialWallIndices(pillars, stacks, indices); dest.setElementData(mode, count, indices); }
private void makePartialDiskIndices(int slices, int loops, int orientation, Geometry dest) { GeometryBuilder gb = this.getGeometryBuilder(); gb.setOrientation(orientation); int mode = gb.getPartialDiskDrawMode(); int count = gb.getPartialDiskIndexCount(slices, loops); int[] indices = new int[count]; gb.makePartialDiskIndices(slices, loops, indices); dest.setElementData(mode, count, indices); }
private void makeCap( DrawContext dc, GeometryBuilder.IndexedTriangleArray ita, double altitude, boolean terrainConformant, int orientation, Matrix locationTransform, Vec4 referenceCenter, int indexPos, int[] indices, int vertexPos, float[] vertices, float[] normals) { GeometryBuilder gb = this.getGeometryBuilder(); Globe globe = dc.getGlobe(); int indexCount = ita.getIndexCount(); int vertexCount = ita.getVertexCount(); int[] locationIndices = ita.getIndices(); float[] locationVerts = ita.getVertices(); this.copyIndexArray( indexCount, (orientation == GeometryBuilder.INSIDE), locationIndices, vertexPos, indexPos, indices); for (int i = 0; i < vertexCount; i++) { int index = 3 * i; Vec4 vec = new Vec4(locationVerts[index], locationVerts[index + 1], locationVerts[index + 2]); vec = vec.transformBy4(locationTransform); Position pos = globe.computePositionFromPoint(vec); vec = this.computePointFromPosition( dc, pos.getLatitude(), pos.getLongitude(), altitude, terrainConformant); index = 3 * (vertexPos + i); vertices[index] = (float) (vec.x - referenceCenter.x); vertices[index + 1] = (float) (vec.y - referenceCenter.y); vertices[index + 2] = (float) (vec.z - referenceCenter.z); } gb.makeIndexedTriangleArrayNormals( indexPos, indexCount, indices, vertexPos, vertexCount, vertices, normals); }
private void makeSectionVertices( DrawContext dc, int locationPos, float[] locations, double[] altitude, boolean[] terrainConformant, int subdivisions, Matrix locationTransform, Vec4 referenceCenter, int vertexPos, float[] vertices) { GeometryBuilder gb = this.getGeometryBuilder(); int numPoints = gb.getSubdivisionPointsVertexCount(subdivisions); Globe globe = dc.getGlobe(); int index1 = 3 * locationPos; int index2 = 3 * (locationPos + 1); float[] locationVerts = new float[3 * numPoints]; gb.makeSubdivisionPoints( locations[index1], locations[index1 + 1], locations[index1 + 2], locations[index2], locations[index2 + 1], locations[index2 + 2], subdivisions, locationVerts); for (int i = 0; i < numPoints; i++) { int index = 3 * i; Vec4 vec = new Vec4(locationVerts[index], locationVerts[index + 1], locationVerts[index + 2]); vec = vec.transformBy4(locationTransform); Position pos = globe.computePositionFromPoint(vec); for (int j = 0; j < 2; j++) { vec = this.computePointFromPosition( dc, pos.getLatitude(), pos.getLongitude(), altitude[j], terrainConformant[j]); index = 2 * i + j; index = 3 * (vertexPos + index); vertices[index] = (float) (vec.x - referenceCenter.x); vertices[index + 1] = (float) (vec.y - referenceCenter.y); vertices[index + 2] = (float) (vec.z - referenceCenter.z); } } }
private void makeSectionFillIndices( int subdivisions, int vertexPos, int indexPos, int[] indices) { GeometryBuilder gb = this.getGeometryBuilder(); int count = gb.getSubdivisionPointsVertexCount(subdivisions); int index = indexPos; int pos, nextPos; for (int i = 0; i < count - 1; i++) { pos = vertexPos + 2 * i; nextPos = vertexPos + 2 * (i + 1); indices[index++] = pos + 1; indices[index++] = pos; indices[index++] = nextPos + 1; indices[index++] = nextPos + 1; indices[index++] = pos; indices[index++] = nextPos; } }
private void makePartialDisk( DrawContext dc, double[] radii, double altitude, boolean terrainConformant, int slices, int loops, int orientation, double start, double sweep, Vec4 referenceCenter, Geometry dest) { GeometryBuilder gb = this.getGeometryBuilder(); gb.setOrientation(orientation); int count = gb.getPartialDiskIndexCount(slices, loops); int numCoords = 3 * count; float[] verts = new float[numCoords]; float[] norms = new float[numCoords]; gb.makePartialDiskVertices( (float) radii[0], (float) radii[1], slices, loops, (float) start, (float) sweep, verts); this.makePartialDiskTerrainConformant( dc, numCoords, verts, altitude, terrainConformant, referenceCenter); gb.makePartialDiskVertexNormals( (float) radii[0], (float) radii[1], slices, loops, (float) start, (float) sweep, verts, norms); dest.setVertexData(count, verts); dest.setNormalData(count, norms); }
private int getSectionVertexCount(int subdivisions) { GeometryBuilder gb = this.getGeometryBuilder(); return 2 * gb.getSubdivisionPointsVertexCount(subdivisions); }
private int getSectionFillIndexCount(int subdivisions) { GeometryBuilder gb = this.getGeometryBuilder(); return 6 * (gb.getSubdivisionPointsVertexCount(subdivisions) - 1); }
private void makePolygon( DrawContext dc, List<LatLon> locations, List<Boolean> edgeFlags, double[] altitudes, boolean[] terrainConformant, boolean enableCaps, int subdivisions, Vec4 referenceCenter, PolygonGeometry dest) { if (locations.size() == 0) return; GeometryBuilder gb = this.getGeometryBuilder(); Vec4[] polyPoints = new Vec4[locations.size() + 1]; Boolean[] polyEdgeFlags = new Boolean[locations.size() + 1]; Matrix[] polyTransform = new Matrix[1]; int polyCount = this.computeCartesianPolygon( dc.getGlobe(), locations, edgeFlags, polyPoints, polyEdgeFlags, polyTransform); // Compute the winding order of the planar cartesian points. If the order is not // counter-clockwise, then // reverse the locations and points ordering. int winding = gb.computePolygonWindingOrder2(0, polyCount, polyPoints); if (winding != GeometryBuilder.COUNTER_CLOCKWISE) { gb.reversePoints(0, polyCount, polyPoints); gb.reversePoints(0, polyCount, polyEdgeFlags); } float[] polyVertices = new float[3 * polyCount]; this.makePolygonVertices(polyCount, polyPoints, polyVertices); int fillDrawMode = GL.GL_TRIANGLES; int outlineDrawMode = GL.GL_LINES; int fillIndexCount = 0; int outlineIndexCount = 0; int vertexCount = 0; GeometryBuilder.IndexedTriangleArray ita = null; fillIndexCount += this.getEdgeFillIndexCount(polyCount, subdivisions); outlineIndexCount += this.getEdgeOutlineIndexCount(polyCount, subdivisions, polyEdgeFlags); vertexCount += this.getEdgeVertexCount(polyCount, subdivisions); if (enableCaps) { ita = gb.tessellatePolygon2(0, polyCount, polyVertices); for (int i = 0; i < subdivisions; i++) { gb.subdivideIndexedTriangleArray(ita); } fillIndexCount += ita.getIndexCount(); vertexCount += ita.getVertexCount(); // Bottom cap isn't drawn if airspace is collapsed. if (!this.isAirspaceCollapsed()) { fillIndexCount += ita.getIndexCount(); vertexCount += ita.getVertexCount(); } } int[] fillIndices = new int[fillIndexCount]; int[] outlineIndices = new int[outlineIndexCount]; float[] vertices = new float[3 * vertexCount]; float[] normals = new float[3 * vertexCount]; int fillIndexPos = 0; int outlineIndexPos = 0; int vertexPos = 0; this.makeEdge( dc, polyCount, polyVertices, polyEdgeFlags, altitudes, terrainConformant, subdivisions, GeometryBuilder.OUTSIDE, polyTransform[0], referenceCenter, fillIndexPos, fillIndices, outlineIndexPos, outlineIndices, vertexPos, vertices, normals); fillIndexPos += this.getEdgeFillIndexCount(polyCount, subdivisions); outlineIndexPos += this.getEdgeOutlineIndexCount(polyCount, subdivisions, polyEdgeFlags); vertexPos += this.getEdgeVertexCount(polyCount, subdivisions); if (enableCaps) { this.makeCap( dc, ita, altitudes[1], terrainConformant[1], GeometryBuilder.OUTSIDE, polyTransform[0], referenceCenter, fillIndexPos, fillIndices, vertexPos, vertices, normals); fillIndexPos += ita.getIndexCount(); vertexPos += ita.getVertexCount(); // Bottom cap isn't drawn if airspace is collapsed. if (!this.isAirspaceCollapsed()) { this.makeCap( dc, ita, altitudes[0], terrainConformant[0], GeometryBuilder.INSIDE, polyTransform[0], referenceCenter, fillIndexPos, fillIndices, vertexPos, vertices, normals); fillIndexPos += ita.getIndexCount(); vertexPos += ita.getVertexCount(); } } dest.getFillIndexGeometry().setElementData(fillDrawMode, fillIndexCount, fillIndices); dest.getOutlineIndexGeometry() .setElementData(outlineDrawMode, outlineIndexCount, outlineIndices); dest.getVertexGeometry().setVertexData(vertexCount, vertices); dest.getVertexGeometry().setNormalData(vertexCount, normals); }