世界风点地标球场
Worldwind PointPlacemark Pitch
我想弄清楚为什么 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:
中的 Compass 那样工作
更新
评论建议迭代音高值以查看其工作原理。我这样做了,但我仍然没有看到它应该如何工作。看起来它只是水平 "cropping" 图像,没有做任何其他事情。这是一些代码:
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 中平移一半 width/height,并相应地缩放和旋转。
对于 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 错误,以及 link 此处的修复程序。
我想弄清楚为什么 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:
中的 Compass 那样工作更新
评论建议迭代音高值以查看其工作原理。我这样做了,但我仍然没有看到它应该如何工作。看起来它只是水平 "cropping" 图像,没有做任何其他事情。这是一些代码:
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 中平移一半 width/height,并相应地缩放和旋转。
对于 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 错误,以及 link 此处的修复程序。