Worldwind PointPlacemark Pitch

Posted

技术标签:

【中文标题】Worldwind PointPlacemark Pitch【英文标题】: 【发布时间】:2018-09-13 05:43:32 【问题描述】:

我试图弄清楚为什么 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);
    

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

但是当我设置 45 度的俯仰角时,它看起来像这样:

我不明白它与我设置的值有何关联。我希望它能够像 Compass 在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);
    

还有一个屏幕录制的 GIF:

【问题讨论】:

似乎 pitch 是围绕 X 轴在“平行”方向上的旋转(Y 轴作为“子午线”)。 heading 围绕 Z 轴旋转,垂直于切平面。设置不同的、小步增加的俯仰和航向值,看看它们是如何工作的。 好主意——我在上面的问题中添加了一些代码来做到这一点。标题按我的预期工作,我可以看到它围绕 Z 轴旋转。不过,音高似乎并没有绕 Y 轴旋转。对我来说,它看起来就像是在裁剪图像。 顺便说一句,我注意到您指向代码的 repo 是一个旧的已弃用的;查看未解决的问题以了解我的意思。 github.com/NASAWorldWind/WorldWindJava 似乎是活跃的,确实有一个关于这个问题的错误报告,甚至可能是由@systemoutprintln... 啊。好的 - 我修复了链接。是的,就是我 :-)。 【参考方案1】:

问题在于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 错误,以及此处的修复链接。

【讨论】:

哇,太棒了。我想我已经玩过这个文件中的所有内容,除了那些试图弄清楚这一点的人。对于 -100 到 100 的范围,您能帮我理解这与我正在使用的可渲染对象的实际大小有何关系吗?谢谢!! 或者他们代表什么 数字与模型视图矩阵中的哪些坐标将投影到视图中有关。所以xy 分别从0 到宽度/高度,而z 被定义为从-1 到1。没有从俯仰旋转,坐标都具有z = 0。当它在 x 中旋转时,z 超出了 -1,1 的范围,因此只有部分可见。调试您提到的可疑代码的最后一行,我看到 xscaleyscale 是 38.4(这可能与加载的不同图标不同) - 这将是 z 可以达到的值。 事实上,如果您查看CompassLayer 中的等效代码,您会发现它们使用±0.6 * maxwh,其中maxwhgetScaledIconWidth\Height() 中的较大者。我相信0.60.5 + breathing room。实际上,也许在那种情况下,图像本身并没有延伸到边缘,因为即使 0.4 似乎也可以......无论如何,我会编辑我的答案以包含更合适的解决方案。 耶,假网点!干杯@systemoutprintln,祝你工作顺利。

以上是关于Worldwind PointPlacemark Pitch的主要内容,如果未能解决你的问题,请参考以下文章

[转]有关WorldWind1.4的worldwind.cs窗口设计器打开错误的解决方法

WorldWind源码剖析系列:WorldWind实时确定更新初始化和渲染地形和纹理数据

WorldWind:地面高度

WorldWind源码剖析系列:WorldWind如何确定与视点相关的地形数据的LOD层级与范围

Worldwind 缺少依赖项

Worldwind - 形状总是显示在图像之上?