Worldwind PointPlacemark Pitch [英] Worldwind PointPlacemark Pitch

查看:248
本文介绍了Worldwind PointPlacemark Pitch的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图找出为什么



但是当我设定45度的音高它看起来像这样:





我不了解它与我所设定的价值之间的关系。我希望它能像Compass在



更新



建议您通过音高值进行迭代,以了解其工作原理。我这样做了,但我仍然没有看到它应该如何工作。它看起来只是水平地裁剪图像,而没有做其他任何事情。以下是一些代码:

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

//将图层添加到模型中。
insertBeforeCompass(getWwd(),layer);

线程t =新线程(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自动生成的catch块
e.printStackTrace );
}

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

}
});
t.start();



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


和一个屏幕录制GIF:



解决方案

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

当音高保持在0时,z坐标也保持为0,安全地在这个范围的中间(实际上,WorldWind中这个坐标有一些轻微的欺骗,但是没关系)。当它间距变化时,z坐标变化,直到90°时,所有的y坐标都是0,而z将达到图像高度的一半。这就是为什么只有在-1,1范围内的图像切片可见而其余部分被切割。



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

  //使用平行投影绘制图像。 
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();

//将xy尺寸(viewportWidth,viewportHeight)
//的平行投影加载到GL投影矩阵中。
java.awt.Rectangle viewport = dc.getView()。getViewport();
ogsh.pushProjectionIdentity(gl);
double maxwh = width>身高?宽度:高度;
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 值:

  //计算比例
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);

//使用平行投影绘制图像。
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的bug报告,以及修复的链接。


I'm trying to figure out why the setPitch in the PointPlacemarkAttributes does not seem to work correctly.

I believe this JOGL code in PointPlacemark.java is where things are going wrong:

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

Here is a simple driver I've been using to play with it:

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

If I set no pitch, it looks fine:

But when I set a pitch of 45 degrees it looks like this:

Which I'm not understanding how it correlates to the value I set. I'd expect it to work like the Compass does in the CompassLayer:

Update

Comment suggested to iterate through pitch values to see how it works. I did that and I'm still not seeing how it is supposed to work. It looks like it is just "cropping" the image horizontally, and not doing anything else. Here is some code:

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

And a screen recorded GIF:

解决方案

The problem is that in PointPlacemark.doDrawOrderedRenderable(), the orthographic projection matrix used uses a range of depth values from -1 to 1.

When the pitch remains at 0, the z coordinates also remain at 0, safely in the middle of this range (actually, there is some slight fudging of this coordinate in WorldWind, but never mind that). As it pitches, of course the z coordinates change, until at 90° all of the y coordinates are 0 while z will go to half of the height of the image. This is why only a slice of the image that falls within the range -1,1 is visible while the rest is clipped.

That z range is defined by the following code:

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

If we examine the equivalent code in CompassLayer, we can see that here they do factor in the scaled icon size (although the comment suggests that perhaps at some earlier iteration, less care had been taken over the z dimension):

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

In this case, the arguments for z (±0.6 * maxwh) use 0.6 presumably as 0.5 plus some margin. The actual geometry is a unit quad, which is translated by half width/height in x/y, scaled and rotated accordingly.

For PointPlacemark, we can account for the size of the renderable in a similar way. Rearranging the code slightly so that scale computation happens before setting the projection, and adding a maxwh value:

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

Again, 0.6 allows some margin.

It would probably be perfectly fine to have hardcoded values for the z range, as long as they were large enough for any image we might want to draw but not so large that numerical precision became an issue. Conversely, one could go even further and factor in trig to work out the actual depth needed for a given rotation and image size, but there would not be much to gain by doing so.

This was indeed a bug with WorldWindJava that has been reported, along with a link here for the fix.

这篇关于Worldwind PointPlacemark Pitch的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆