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 的范围,您能帮我理解这与我正在使用的可渲染对象的实际大小有何关系吗?谢谢!! 或者他们代表什么 数字与模型视图矩阵中的哪些坐标将投影到视图中有关。所以x
和y
分别从0 到宽度/高度,而z
被定义为从-1 到1。没有从俯仰旋转,坐标都具有z = 0。当它在 x 中旋转时,z 超出了 -1,1 的范围,因此只有部分可见。调试您提到的可疑代码的最后一行,我看到 xscale
和 yscale
是 38.4(这可能与加载的不同图标不同) - 这将是 z 可以达到的值。
事实上,如果您查看CompassLayer
中的等效代码,您会发现它们使用±0.6 * maxwh
,其中maxwh
是getScaledIconWidth\Height()
中的较大者。我相信0.6
是0.5 + breathing room
。实际上,也许在那种情况下,图像本身并没有延伸到边缘,因为即使 0.4 似乎也可以......无论如何,我会编辑我的答案以包含更合适的解决方案。
耶,假网点!干杯@systemoutprintln,祝你工作顺利。以上是关于Worldwind PointPlacemark Pitch的主要内容,如果未能解决你的问题,请参考以下文章
[转]有关WorldWind1.4的worldwind.cs窗口设计器打开错误的解决方法
WorldWind源码剖析系列:WorldWind实时确定更新初始化和渲染地形和纹理数据