我试图弄清楚为什么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度时,它看起来像这样:
我不了解它与我设置的值之间的关系。我希望它能像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:
最佳答案
问题在于,在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的错误,并在此处提供了此修复程序的链接。