我试图弄清楚为什么PointPlacemarkAttributes中的setPitch似乎无法正常工作。

我相信PointPlacemark.java中的这个JOGL代码是出问题的地方:

        Double heading = getActiveAttributes().getHeading();
        Double pitch = getActiveAttributes().getPitch();

        // 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);

这是我一直在使用的简单驱动程序:
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("PointPlacemark");
            pp.setLineEnabled(false);
            pp.setAltitudeMode(WorldWind.ABSOLUTE);
            PointPlacemarkAttributes attrs = new PointPlacemarkAttributes();
            attrs.setImageAddress("gov/nasa/worldwindx/examples/images/georss.png");
            attrs.setScale(1.0);
            attrs.setImageOffset(Offset.CENTER);


            attrs.setPitch(45.0);

            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);
    }
}

如果我不设置音高,看起来很好:

java - Worldwind Point地标音高-LMLPHP

但是,当我将间距设置为45度时,它看起来像这样:

java - Worldwind Point地标音高-LMLPHP

我不了解它与我设置的值之间的关系。我希望它能像CompassLayer中的指南针一样工作:

java - Worldwind Point地标音高-LMLPHP

更新

建议通过迭代遍历音调值以查看其工作原理。我做到了,但我仍然没有看到它应该如何工作。看起来它只是水平“裁剪”图像,而不执行其他任何操作。这是一些代码:
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("PointPlacemark");
            pp.setLineEnabled(false);
            pp.setAltitudeMode(WorldWind.ABSOLUTE);
            PointPlacemarkAttributes attrs = new PointPlacemarkAttributes();
            attrs.setImageAddress("gov/nasa/worldwindx/examples/images/georss.png");
            attrs.setScale(1.0);
            attrs.setImageOffset(Offset.CENTER);


            pp.setAttributes(attrs);
            layer.addRenderable(pp);

            // Add the layer to the model.
            insertBeforeCompass(getWwd(), layer);

            Thread t = new Thread(new Runnable() {

                @Override
                public void run() {
                    for(double i = 0.0; i<360; i+=.1) {
                        attrs.setPitch(i);


                        System.out.println("Pitch is now "+i);

                        try {
                            Thread.sleep(100);
                        } catch (InterruptedException e) {
                            // TODO Auto-generated catch block
                            e.printStackTrace();
                        }

                        AppFrame.this.getWwd().redrawNow();
                    }

                }
            });
            t.start();
        }
    }

    public static void main(String[] args) {
        ApplicationTemplate.start("WorldWind Placemarks", AppFrame.class);
    }
}

并在屏幕上记录了GIF:

java - Worldwind Point地标音高-LMLPHP

最佳答案

问题在于,在PointPlacemark.doDrawOrderedRenderable()中,所使用的正交投影矩阵使用了从-1到1的一系列深度值。

当音高保持为0时,z坐标也将保持为0,安全地处于该范围的中间(实际上,WorldWind中此坐标有些模糊,但不要紧)。随着俯仰,z坐标当然会变化,直到90°时所有y坐标都为0,而z会达到图像高度的一半。这就是为什么只裁剪-1,1范围内的一部分图像而其余部分被裁剪的原因。

z范围由以下代码定义:

// The image is drawn using a parallel projection.
osh.pushProjectionIdentity(gl);
gl.glOrtho(0d, dc.getView().getViewport().width, 0d, dc.getView().getViewport().height, -1d, 1d);

如果我们检查CompassLayer中的等效代码,我们可以看到它们确实影响了缩放的图标大小(尽管注释表明也许在更早的迭代中,对z维度的关注较少):
double width = this.getScaledIconWidth();
double height = this.getScaledIconHeight();

// Load a parallel projection with xy dimensions (viewportWidth, viewportHeight)
// into the GL projection matrix.
java.awt.Rectangle viewport = dc.getView().getViewport();
ogsh.pushProjectionIdentity(gl);
double maxwh = width > height ? width : height;
if (maxwh == 0)
    maxwh = 1;
gl.glOrtho(0d, viewport.width, 0d, viewport.height, -0.6 * maxwh, 0.6 * maxwh);

在这种情况下,z(±0.6 * maxwh)的参数大概使用0.6作为0.5加上一些余量。实际几何形状是一个单位四边形,它以x/y的一半的宽度/高度转换,并相应缩放和旋转。

对于PointPlacemark,我们可以以类似的方式考虑可渲染对象的大小。稍微重新排列代码,以便在设置投影并添加maxwh值之前进行比例计算:
// 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.
osh.pushProjectionIdentity(gl);
gl.glOrtho(0d, dc.getView().getViewport().width, 0d, dc.getView().getViewport().height, -0.6 * maxwh, 0.6 * maxwh);

同样,0.6允许一些余量。

只要对z范围具有硬编码值,只要它们对于我们可能要绘制的任何图像足够大,但又不会太大而导致数值精度成为问题,则可能会很好。相反,人们可以走得更远,并进行分析以得出给定旋转度和图像尺寸所需的实际深度,但是这样做并不会带来太多好处。

实际上,这已经报告了WorldWindJava的错误,并在此处提供了此修复程序的链接。

10-06 05:48