WorldWind PointPlacemark标题

在NASA WorldWind Java中,我使用PointPlacemark来表示图像,因为无论缩放级别如何,它都保持相同的大小。 问题是我想在Point Placemark上设置标题,即使相机倾斜,它也会保持在指南针上。 它在查看一个倾斜的地球时完全按照我想要的方式工作,但是当我倾斜时,地标继续面向屏幕而不是与地球一起倾斜,这导致它行为奇怪。

这是一个GIF,说明了我所看到的: https : //giphy.com/embed/3o7WIqZUceR8xh6BOg

我希望点地标图像保持在相对于地球的标题上,即使在倾斜时 – 因此当视图倾斜时图像基本上“平坦化”,而不管缩放级别如何仍然保持相同的大小。

这是我正在使用的代码片段。 我正在设置attrs.setHeadingReference(AVKey.RELATIVE_TO_GLOBE); 在关联的PointPlacemarkAttributes上。 在此示例中,我将标题设置为135度。

import gov.nasa.worldwind.WorldWind; import gov.nasa.worldwind.avlist.AVKey; import gov.nasa.worldwind.geom.Position; import gov.nasa.worldwind.layers.RenderableLayer; import gov.nasa.worldwind.render.Offset; import gov.nasa.worldwind.render.PointPlacemark; import gov.nasa.worldwind.render.PointPlacemarkAttributes; public class Placemarks extends ApplicationTemplate { public static class AppFrame extends ApplicationTemplate.AppFrame { public AppFrame() { super(true, true, false); final RenderableLayer layer = new RenderableLayer(); PointPlacemark pp = new PointPlacemark(Position.fromDegrees(28, -102, 30000)); pp.setLabelText("Airplane"); pp.setLineEnabled(false); pp.setAltitudeMode(WorldWind.ABSOLUTE); PointPlacemarkAttributes attrs = new PointPlacemarkAttributes(); attrs.setImageAddress("images/airplane.png"); attrs.setScale(0.05); attrs.setImageOffset(Offset.CENTER); //Point to 135.0 attrs.setHeading(135.0); attrs.setHeadingReference(AVKey.RELATIVE_TO_GLOBE); pp.setAttributes(attrs); layer.addRenderable(pp); // Add the layer to the model. insertBeforeCompass(getWwd(), layer); } } public static void main(String[] args) { ApplicationTemplate.start("WorldWind Placemarks", AppFrame.class); } } 

我也玩过使用带有纹理的Polygon。 面向它的方式是我正在寻找的 – 除了我希望图标保持相同的大小,无论缩放级别如何(如PointPlacemark所做的那样)。

这是一个GIF,说明了我在使用Polygon时所看到的内容。 注意当地球倾斜时它是如何起作用的: https : //giphy.com/embed/xThta4USlDzd8Ii5ZS

这是我用于Polygon的源代码:

 import java.awt.geom.AffineTransform; import java.util.Arrays; import java.util.List; import gov.nasa.worldwind.WorldWind; import gov.nasa.worldwind.geom.Position; import gov.nasa.worldwind.layers.RenderableLayer; import gov.nasa.worldwind.render.BasicShapeAttributes; import gov.nasa.worldwind.render.Polygon; public class TexturedPolygon extends ApplicationTemplate { public static Polygon createPolygonTexturedImage(String filePath, Position pos, double heading, double scale) { double offsetDist = 1.0D * scale; Position p1 = Position.fromDegrees(pos.getLatitude().addDegrees(-offsetDist).getDegrees(), pos.getLongitude().addDegrees(-offsetDist).getDegrees(), pos.getAltitude()); Position p2 = Position.fromDegrees(pos.getLatitude().addDegrees(offsetDist).getDegrees(), pos.getLongitude().addDegrees(-offsetDist).getDegrees()); Position p3 = Position.fromDegrees(pos.getLatitude().addDegrees(offsetDist).getDegrees(), pos.getLongitude().addDegrees(offsetDist).getDegrees()); Position p4 = Position.fromDegrees(pos.getLatitude().addDegrees(-offsetDist).getDegrees(), pos.getLongitude().addDegrees(offsetDist).getDegrees()); double[] points = new double[] { p1.getLatitude().getDegrees(), p1.getLongitude().getDegrees(), p2.getLatitude().getDegrees(), p2.getLongitude().getDegrees(), p3.getLatitude().getDegrees(), p3.getLongitude().getDegrees(), p4.getLatitude().getDegrees(), p4.getLongitude().getDegrees() }; double[] transformedPoints = new double[8]; AffineTransform rotation = new AffineTransform(); rotation.rotate(Math.toRadians(heading), pos.getLatitude().getDegrees(), pos.getLongitude().getDegrees()); rotation.transform(points, 0, transformedPoints, 0, 4); double altitude = pos.getAltitude(); p1 = Position.fromDegrees(transformedPoints[0], transformedPoints[1], altitude); p2 = Position.fromDegrees(transformedPoints[2], transformedPoints[3], altitude); p3 = Position.fromDegrees(transformedPoints[4], transformedPoints[5], altitude); p4 = Position.fromDegrees(transformedPoints[6], transformedPoints[7], altitude); List positions = Arrays.asList(p1, p2, p3, p4); Polygon polygon = new Polygon(positions); polygon.setAltitudeMode(WorldWind.ABSOLUTE); BasicShapeAttributes mattr = new BasicShapeAttributes(); mattr.setDrawOutline(false); mattr.setDrawInterior(true); polygon.setAttributes(mattr); polygon.setTextureImageSource(filePath, new float[] { 0.0F, 0.0F, 1.0F, 0.0F, 1.0F, 1.0F, 0.0F, 1.0F }, 4); return polygon; } public static class AppFrame extends ApplicationTemplate.AppFrame { public AppFrame() { super(true, true, false); final RenderableLayer layer = new RenderableLayer(); Position pos = Position.fromDegrees(28, -102, 30000); String url = "images/airplane.png"; layer.addRenderable(createPolygonTexturedImage(url, pos, 135.0, 1.05)); // Add the layer to the model. insertBeforeCompass(getWwd(), layer); } } public static void main(String[] args) { ApplicationTemplate.start("WorldWind Placemarks", AppFrame.class); } } 

为了完整起见 – 这是我用作我的airplane.png的图像:

总结一下,我在寻找什么:

  • 由图标图像表示的可渲染
  • 无论缩放级别如何,图标都保持相同的大小
  • 即使摄像机视图倾斜,图标仍保持朝向地球罗盘方向

通过将解决方案与此问题相结合以及将屏幕倾斜与音高相关联的CompassLayer逻辑。

将此方法添加到PointPlacemark.java(取自CompassLayer):

 protected double computePitch(View view) { if (view == null) return 0.0; if (!(view instanceof OrbitView)) return 0.0; OrbitView orbitView = (OrbitView) view; return orbitView.getPitch().getDegrees(); } 

然后在doDrawOrderedRenderable(DrawContext dc,PickSupport pickCandidates,OrderedPlacemark opm)方法中,使用以下逻辑:

 protected void doDrawOrderedRenderable(DrawContext dc, PickSupport pickCandidates, OrderedPlacemark opm) { if (this.isDrawLine(dc, opm)) this.drawLine(dc, pickCandidates, opm); if (this.activeTexture == null) { if (this.isDrawPoint(dc)) this.drawPoint(dc, pickCandidates, opm); return; } GL2 gl = dc.getGL().getGL2(); // GL initialization checks for GL2 compatibility. OGLStackHandler osh = new OGLStackHandler(); try { if (dc.isPickingMode()) { // Set up to replace the non-transparent texture colors with the single pick color. gl.glEnable(GL.GL_TEXTURE_2D); gl.glTexEnvf(GL2.GL_TEXTURE_ENV, GL2.GL_TEXTURE_ENV_MODE, GL2.GL_COMBINE); gl.glTexEnvf(GL2.GL_TEXTURE_ENV, GL2.GL_SRC0_RGB, GL2.GL_PREVIOUS); gl.glTexEnvf(GL2.GL_TEXTURE_ENV, GL2.GL_COMBINE_RGB, GL2.GL_REPLACE); Color pickColor = dc.getUniquePickColor(); pickCandidates.addPickableObject(this.createPickedObject(dc, pickColor)); gl.glColor3ub((byte) pickColor.getRed(), (byte) pickColor.getGreen(), (byte) pickColor.getBlue()); } else { gl.glEnable(GL.GL_TEXTURE_2D); Color color = this.getActiveAttributes().getImageColor(); if (color == null) color = PointPlacemarkAttributes.DEFAULT_IMAGE_COLOR; gl.glColor4ub((byte) color.getRed(), (byte) color.getGreen(), (byte) color.getBlue(), (byte) color.getAlpha()); } // This was relocated from the check in version. // Compute the scale double xscale; Double scale = this.getActiveAttributes().getScale(); if (scale != null) xscale = scale * this.activeTexture.getWidth(dc); else xscale = this.activeTexture.getWidth(dc); double yscale; if (scale != null) yscale = scale * this.activeTexture.getHeight(dc); else yscale = this.activeTexture.getHeight(dc); double maxwh = Math.max(xscale, yscale); // The image is drawn using a parallel projection. // This came from the fix in https://stackoverflow.com/questions/49637844/worldwind-pointplacemark-pitch osh.pushProjectionIdentity(gl); gl.glOrtho(0d, dc.getView().getViewport().width, 0d, dc.getView().getViewport().height, -0.6 * maxwh, 0.6 * maxwh); // Apply the depth buffer but don't change it (for screen-space shapes). if ((!dc.isDeepPickingEnabled())) gl.glEnable(GL.GL_DEPTH_TEST); gl.glDepthMask(false); // Suppress any fully transparent image pixels. gl.glEnable(GL2.GL_ALPHA_TEST); gl.glAlphaFunc(GL2.GL_GREATER, 0.001f); // Adjust depth of image to bring it slightly forward double depth = opm.screenPoint.z - (8d * 0.00048875809d); depth = depth < 0d ? 0d : (depth > 1d ? 1d : depth); gl.glDepthFunc(GL.GL_LESS); gl.glDepthRange(depth, depth); // The image is drawn using a translated and scaled unit quad. // Translate to screen point and adjust to align hot spot. osh.pushModelviewIdentity(gl); gl.glTranslated(opm.screenPoint.x + this.dx, opm.screenPoint.y + this.dy, 0); Double heading = getActiveAttributes().getHeading(); Double pitch = this.computePitch(dc.getView()); // Adjust heading to be relative to globe or screen if (heading != null) { if (AVKey.RELATIVE_TO_GLOBE.equals(this.getActiveAttributes().getHeadingReference())) heading = dc.getView().getHeading().degrees - heading; else heading = -heading; } // Apply the heading and pitch if specified. if (heading != null || pitch != null) { gl.glTranslated(xscale / 2, yscale / 2, 0); if (pitch != null) gl.glRotated(pitch, 1, 0, 0); if (heading != null) gl.glRotated(heading, 0, 0, 1); gl.glTranslated(-xscale / 2, -yscale / 2, 0); } // Scale the unit quad gl.glScaled(xscale, yscale, 1); if (this.activeTexture.bind(dc)) dc.drawUnitQuad(activeTexture.getTexCoords()); gl.glDepthRange(0, 1); // reset depth range to the OGL default if (this.mustDrawLabel()) { if (!dc.isPickingMode() || this.isEnableLabelPicking()) this.drawLabel(dc, pickCandidates, opm); } } finally { if (dc.isPickingMode()) { gl.glTexEnvf(GL2.GL_TEXTURE_ENV, GL2.GL_TEXTURE_ENV_MODE, OGLUtil.DEFAULT_TEX_ENV_MODE); gl.glTexEnvf(GL2.GL_TEXTURE_ENV, GL2.GL_SRC0_RGB, OGLUtil.DEFAULT_SRC0_RGB); gl.glTexEnvf(GL2.GL_TEXTURE_ENV, GL2.GL_COMBINE_RGB, OGLUtil.DEFAULT_COMBINE_RGB); } gl.glDisable(GL.GL_TEXTURE_2D); osh.pop(gl); } } 

它看起来像这样:

在此处输入图像描述

您想要实现的是根据相机的眼睛位置缩放多边形,并使多边形保持在地图上。

您可以尝试更新第二个解决方案,并在渲染之前添加RenderingListener ro更新多边形的大小:

 wwd.addRenderingListener(new RenderingListener() { public void stageChanged(RenderingEvent event) { if (RenderingEvent.BEFORE_RENDERING.equals(event.getStage()) { if (wwd.getView() != null && wwd.getView().getEyePosition() != null) { // compute distance between eyePosition and object position, and set the scale. } } } });