Worldwind's Point PlaceMark renderable has the feature to drop a line from the Placemark down to the terrain by calling setLineEnabled as in this screenshot:
What I'm trying to do is add a line like this that also works with the Tactical Symbol renderable. My first thought was to just borrow the logic to do this from the PointPlacemark renderable and add it to the AbstractTacticalSymbol renderable. I've tried that and I have been unsuccessful so far.
Here is what I've done so far:
Added this to OrderedSymbol class:
public Vec4 terrainPoint;
Updated computeSymbolPoints to calculate terrainPoint
protected void computeSymbolPoints(DrawContext dc, OrderedSymbol osym) { osym.placePoint = null; osym.screenPoint = null; osym.terrainPoint = null; osym.eyeDistance = 0; Position pos = this.getPosition(); if (pos == null) return; if (this.altitudeMode == WorldWind.CLAMP_TO_GROUND || dc.is2DGlobe()) { osym.placePoint = dc.computeTerrainPoint(pos.getLatitude(), pos.getLongitude(), 0); } else if (this.altitudeMode == WorldWind.RELATIVE_TO_GROUND) { osym.placePoint = dc.computeTerrainPoint(pos.getLatitude(), pos.getLongitude(), pos.getAltitude()); } else // Default to ABSOLUTE { double height = pos.getElevation() * dc.getVerticalExaggeration(); osym.placePoint = dc.getGlobe().computePointFromPosition(pos.getLatitude(), pos.getLongitude(), height); } if (osym.placePoint == null) return; // Compute the symbol's screen location the distance between the eye point and the place point. osym.screenPoint = dc.getView().project(osym.placePoint); osym.eyeDistance = osym.placePoint.distanceTo3(dc.getView().getEyePoint()); // Compute a terrain point if needed. if (this.isLineEnabled() && this.altitudeMode != WorldWind.CLAMP_TO_GROUND && !dc.is2DGlobe()) osym.terrainPoint = dc.computeTerrainPoint(pos.getLatitude(), pos.getLongitude(), 0); }
Added this logic (taken from PointPlacemark.java and updated for compliance to AbstractTacticalSymbol.java). Note that I have lineEnabled set to true, so it should draw the line by default.
boolean lineEnabled = true; double lineWidth = 1; protected int linePickWidth = 10; Color lineColor = Color.white; /** * Indicates whether a line from the placemark point to the corresponding position on the terrain is drawn. * * @return true if the line is drawn, otherwise false. */ public boolean isLineEnabled() { return lineEnabled; } /** * Specifies whether a line from the placemark point to the corresponding position on the terrain is drawn. * * @param lineEnabled true if the line is drawn, otherwise false. */ public void setLineEnabled(boolean lineEnabled) { this.lineEnabled = lineEnabled; } /** * Determines whether the placemark's optional line should be drawn and whether it intersects the view frustum. * * @param dc the current draw context. * * @return true if the line should be drawn and it intersects the view frustum, otherwise false. */ protected boolean isDrawLine(DrawContext dc, OrderedSymbol opm) { if (!this.isLineEnabled() || dc.is2DGlobe() || this.getAltitudeMode() == WorldWind.CLAMP_TO_GROUND || opm.terrainPoint == null) return false; if (dc.isPickingMode()) return dc.getPickFrustums().intersectsAny(opm.placePoint, opm.terrainPoint); else return dc.getView().getFrustumInModelCoordinates().intersectsSegment(opm.placePoint, opm.terrainPoint); } /** * Draws the placemark's line. * * @param dc the current draw context. * @param pickCandidates the pick support object to use when adding this as a pick candidate. */ protected void drawLine(DrawContext dc, PickSupport pickCandidates, OrderedSymbol opm) { GL2 gl = dc.getGL().getGL2(); // GL initialization checks for GL2 compatibility. if ((!dc.isDeepPickingEnabled())) gl.glEnable(GL.GL_DEPTH_TEST); gl.glDepthFunc(GL.GL_LEQUAL); gl.glDepthMask(true); try { dc.getView().pushReferenceCenter(dc, opm.placePoint); // draw relative to the place point this.setLineWidth(dc); this.setLineColor(dc, pickCandidates); gl.glBegin(GL2.GL_LINE_STRIP); gl.glVertex3d(Vec4.ZERO.x, Vec4.ZERO.y, Vec4.ZERO.z); gl.glVertex3d(opm.terrainPoint.x - opm.placePoint.x, opm.terrainPoint.y - opm.placePoint.y, opm.terrainPoint.z - opm.placePoint.z); gl.glEnd(); } finally { dc.getView().popReferenceCenter(dc); } } /** * Sets the width of the placemark's line during rendering. * * @param dc the current draw context. */ protected void setLineWidth(DrawContext dc) { Double lineWidth = this.lineWidth; if (lineWidth != null) { GL gl = dc.getGL(); if (dc.isPickingMode()) { gl.glLineWidth(lineWidth.floatValue() + linePickWidth); } else gl.glLineWidth(lineWidth.floatValue()); if (!dc.isPickingMode()) { gl.glHint(GL.GL_LINE_SMOOTH_HINT, GL.GL_FASTEST); gl.glEnable(GL.GL_LINE_SMOOTH); } } } /** * Sets the color of the placemark's line during rendering. * * @param dc the current draw context. * @param pickCandidates the pick support object to use when adding this as a pick candidate. */ protected void setLineColor(DrawContext dc, PickSupport pickCandidates) { GL2 gl = dc.getGL().getGL2(); // GL initialization checks for GL2 compatibility. if (!dc.isPickingMode()) { Color color = this.lineColor; gl.glColor4ub((byte) color.getRed(), (byte) color.getGreen(), (byte) color.getBlue(), (byte) color.getAlpha()); } else { Color pickColor = dc.getUniquePickColor(); Object delegateOwner = this.getDelegateOwner(); pickCandidates.addPickableObject(pickColor.getRGB(), delegateOwner != null ? delegateOwner : this, this.getPosition()); gl.glColor3ub((byte) pickColor.getRed(), (byte) pickColor.getGreen(), (byte) pickColor.getBlue()); } }
Added this call to the beginning of the drawOrderedRenderable method:
boolean drawLine = this.isDrawLine(dc, osym); if (drawLine) this.drawLine(dc, pickCandidates, osym);
I believe this closely mirrors what PointPlacemark is doing to get the line to terrain appear, but this is what I get when I run the TacticalSymbols example with my changes:
Here is the whole AbsractTacticalSymbol file with my (attempted) changes: http://pastebin.com/aAC7zn0p (its too large for SO)