Worldwind PointPlacemark Pitch

mai*_*rgs 6 java geometry jogl worldwind

我试图弄清楚为什么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);
Run Code Online (Sandbox Code Playgroud)

这是一个我用过的简单驱动程序:

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);
    }
}
Run Code Online (Sandbox Code Playgroud)

如果我没有设置音高,它看起来很好:

在此输入图像描述

但当我设置45度的音高时,它看起来像这样:

在此输入图像描述

我不明白它与我设定的价值有何关联.我希望它能像指南针在CompassLayer中那样工作:

在此输入图像描述

更新

评论建议迭代音高值以查看其工作原理.我这样做了,我仍然没有看到它应该如何工作.看起来它只是水平地"裁剪"图像,而不是做任何其他事情.这是一些代码:

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);
    }
}
Run Code Online (Sandbox Code Playgroud)

并且屏幕录制了GIF:

在此输入图像描述

Pet*_*erT 3

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

\n\n

当音高保持为 0 时,z 坐标也保持为 0,安全地位于该范围的中间(实际上,WorldWind 中对该坐标有一些轻微的捏造,但不要介意)。当它倾斜时,z 坐标当然会改变,直到 90\xc2\xb0 所有 y 坐标都为 0,而 z 将达到图像高度的一半。这就是为什么只有位于 -1,1 范围内的图像切片可见,而其余部分被剪裁的原因。

\n\n

该 z 范围由以下代码定义:

\n\n
// The image is drawn using a parallel projection.\nosh.pushProjectionIdentity(gl);\ngl.glOrtho(0d, dc.getView().getViewport().width, 0d, dc.getView().getViewport().height, -1d, 1d);\n
Run Code Online (Sandbox Code Playgroud)\n\n

如果我们检查 中的等效代码CompassLayer,我们可以看到这里它们确实考虑缩放的图标大小(尽管注释表明也许在某些早期迭代中,对 z 维度的关注较少):

\n\n
double width = this.getScaledIconWidth();\ndouble height = this.getScaledIconHeight();\n\n// Load a parallel projection with xy dimensions (viewportWidth, viewportHeight)\n// into the GL projection matrix.\njava.awt.Rectangle viewport = dc.getView().getViewport();\nogsh.pushProjectionIdentity(gl);\ndouble maxwh = width > height ? width : height;\nif (maxwh == 0)\n    maxwh = 1;\ngl.glOrtho(0d, viewport.width, 0d, viewport.height, -0.6 * maxwh, 0.6 * maxwh);\n
Run Code Online (Sandbox Code Playgroud)\n\n

z在本例中, ( )的参数\xc2\xb10.6 * maxwh使用 0.6 大概相当于 0.5 加上一些余量。实际的几何图形是一个单位四边形,它按 x/y 方向的半宽度/高度进行平移,并相应地缩放和旋转。

\n\n

对于PointPlacemark,我们可以以类似的方式计算可渲染的大小。稍微重新排列代码,以便在设置投影之前进行比例计算,并添加maxwh

\n\n
// Compute the scale\ndouble xscale;\nDouble scale = this.getActiveAttributes().getScale();\nif (scale != null)\n    xscale = scale * this.activeTexture.getWidth(dc);\nelse\n    xscale = this.activeTexture.getWidth(dc);\n\ndouble yscale;\nif (scale != null)\n    yscale = scale * this.activeTexture.getHeight(dc);\nelse\n    yscale = this.activeTexture.getHeight(dc);\ndouble maxwh = Math.max(xscale, yscale);\n\n// The image is drawn using a parallel projection.\nosh.pushProjectionIdentity(gl);\ngl.glOrtho(0d, dc.getView().getViewport().width, 0d, dc.getView().getViewport().height, -0.6 * maxwh, 0.6 * maxwh);\n
Run Code Online (Sandbox Code Playgroud)\n\n

同样,0.6 允许有一些余量。

\n\n

为 z 范围提供硬编码值可能是完全可以的,只要它们对于我们可能想要绘制的任何图像来说足够大,但又不会大到导致数值精度成为问题。相反,我们可以更进一步,考虑三角函数来计算出给定旋转和图像尺寸所需的实际深度,但这样做不会获得太多好处。

\n\n

这确实是已报告的 WorldWindJava 的错误,以及此处的修复链接。

\n