gpt4 book ai didi

java - 世风视线

转载 作者:IT老高 更新时间:2023-10-28 20:54:55 26 4
gpt4 key购买 nike

我找到了如何在 WorldWind 中渲染视线的示例:http://patmurris.blogspot.com/2008/04/ray-casting-and-line-of-sight-for-wwj.html (它有点旧,但它似乎仍然有效)。这是class在示例中使用(下面的代码稍作修改以与 WorldWind 2.0 一起使用)。看起来代码也使用了 RayCastingSupport(JavadocCode)来发挥它的魔力。

我想弄清楚的是,这个代码/示例是否使用地球的曲率/或到地平线的距离作为其逻辑的一部分。只是看代码,我不确定我完全理解它在做什么。

例如,如果我想弄清楚一个人在地球上方 200 米处可以“看到”什么地形,会考虑到地平线的距离吗?

如何修改代码以考虑到地球地平线/曲率的距离(如果还没有)?

package gov.nasa.worldwindx.examples;

import gov.nasa.worldwind.util.RayCastingSupport;
import gov.nasa.worldwind.view.orbit.OrbitView;
import gov.nasa.worldwind.geom.Angle;
import gov.nasa.worldwind.geom.Position;
import gov.nasa.worldwind.geom.Sector;
import gov.nasa.worldwind.geom.Vec4;
import gov.nasa.worldwind.globes.Globe;
import gov.nasa.worldwind.layers.CrosshairLayer;
import gov.nasa.worldwind.layers.RenderableLayer;
import gov.nasa.worldwind.render.*;

import javax.swing.*;
import javax.swing.border.CompoundBorder;
import javax.swing.border.TitledBorder;

import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;


public class LineOfSight extends ApplicationTemplate
{
public static class AppFrame extends ApplicationTemplate.AppFrame
{
private double samplingLength = 30; // Ray casting sample length
private int centerOffset = 100; // meters above ground for center
private int pointOffset = 10; // meters above ground for sampled points
private Vec4 light = new Vec4(1, 1, -1).normalize3(); // Light direction (from South-East)
private double ambiant = .4; // Minimum lighting (0 - 1)

private RenderableLayer renderableLayer;
private SurfaceImage surfaceImage;
private ScreenAnnotation screenAnnotation;
private JComboBox radiusCombo;
private JComboBox samplesCombo;
private JCheckBox shadingCheck;
private JButton computeButton;

public AppFrame()
{
super(true, true, false);

// Add USGS Topo Maps
// insertBeforePlacenames(getWwd(), new USGSTopographicMaps());

// Add our renderable layer for result display
this.renderableLayer = new RenderableLayer();
this.renderableLayer.setName("Line of sight");
this.renderableLayer.setPickEnabled(false);
insertBeforePlacenames(getWwd(), this.renderableLayer);

// Add crosshair layer
insertBeforePlacenames(getWwd(), new CrosshairLayer());

// Update layer panel
this.getLayerPanel().update(getWwd());

// Add control panel
this.getLayerPanel().add(makeControlPanel(), BorderLayout.SOUTH);
}

private JPanel makeControlPanel()
{
JPanel controlPanel = new JPanel(new GridLayout(0, 1, 0, 0));
controlPanel.setBorder(
new CompoundBorder(BorderFactory.createEmptyBorder(9, 9, 9, 9),
new TitledBorder("Line Of Sight")));

// Radius combo
JPanel radiusPanel = new JPanel(new GridLayout(0, 2, 0, 0));
radiusPanel.setBorder(BorderFactory.createEmptyBorder(6, 6, 6, 6));
radiusPanel.add(new JLabel("Max radius:"));
radiusCombo = new JComboBox(new String[] {"5km", "10km",
"20km", "30km", "50km", "100km", "200km"});
radiusCombo.setSelectedItem("10km");
radiusPanel.add(radiusCombo);

// Samples combo
JPanel samplesPanel = new JPanel(new GridLayout(0, 2, 0, 0));
samplesPanel.setBorder(BorderFactory.createEmptyBorder(6, 6, 6, 6));
samplesPanel.add(new JLabel("Samples:"));
samplesCombo = new JComboBox(new String[] {"128", "256", "512"});
samplesCombo.setSelectedItem("128");
samplesPanel.add(samplesCombo);

// Shading checkbox
JPanel shadingPanel = new JPanel(new GridLayout(0, 2, 0, 0));
shadingPanel.setBorder(BorderFactory.createEmptyBorder(6, 6, 6, 6));
shadingPanel.add(new JLabel("Light:"));
shadingCheck = new JCheckBox("Add shading");
shadingCheck.setSelected(false);
shadingPanel.add(shadingCheck);

// Compute button
JPanel buttonPanel = new JPanel(new GridLayout(0, 1, 0, 0));
buttonPanel.setBorder(BorderFactory.createEmptyBorder(6, 6, 6, 6));
computeButton = new JButton("Compute");
computeButton.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent actionEvent)
{
update();
}
});
buttonPanel.add(computeButton);

// Help text
JPanel helpPanel = new JPanel(new GridLayout(0, 1, 0, 0));
buttonPanel.setBorder(BorderFactory.createEmptyBorder(6, 6, 6, 6));
helpPanel.add(new JLabel("Place view center on an elevated"));
helpPanel.add(new JLabel("location and click \"Compute\""));

// Panel assembly
controlPanel.add(radiusPanel);
controlPanel.add(samplesPanel);
controlPanel.add(shadingPanel);
controlPanel.add(buttonPanel);
controlPanel.add(helpPanel);

return controlPanel;
}

// Update line of sight computation
private void update()
{
new Thread(new Runnable() {
public void run()
{
computeLineOfSight();
}
}, "LOS thread").start();
}

private void computeLineOfSight()
{
computeButton.setEnabled(false);
computeButton.setText("Computing...");

try
{
Globe globe = getWwd().getModel().getGlobe();
OrbitView view = (OrbitView)getWwd().getView();
Position centerPosition = view.getCenterPosition();

// Compute sector
String radiusString = ((String)radiusCombo.getSelectedItem());
double radius = 1000 * Double.parseDouble(radiusString.substring(0, radiusString.length() - 2));
double deltaLatRadians = radius / globe.getEquatorialRadius();
double deltaLonRadians = deltaLatRadians / Math.cos(centerPosition.getLatitude().radians);
Sector sector = new Sector(centerPosition.getLatitude().subtractRadians(deltaLatRadians),
centerPosition.getLatitude().addRadians(deltaLatRadians),
centerPosition.getLongitude().subtractRadians(deltaLonRadians),
centerPosition.getLongitude().addRadians(deltaLonRadians));

// Compute center point
double centerElevation = globe.getElevation(centerPosition.getLatitude(),
centerPosition.getLongitude());
Vec4 center = globe.computePointFromPosition(
new Position(centerPosition, centerElevation + centerOffset));

// Compute image
float hueScaleFactor = .7f;
int samples = Integer.parseInt((String)samplesCombo.getSelectedItem());
BufferedImage image = new BufferedImage(samples, samples, BufferedImage.TYPE_4BYTE_ABGR);
double latStepRadians = sector.getDeltaLatRadians() / image.getHeight();
double lonStepRadians = sector.getDeltaLonRadians() / image.getWidth();
for (int x = 0; x < image.getWidth(); x++)
{
Angle lon = sector.getMinLongitude().addRadians(lonStepRadians * x + lonStepRadians / 2);
for (int y = 0; y < image.getHeight(); y++)
{
Angle lat = sector.getMaxLatitude().subtractRadians(latStepRadians * y + latStepRadians / 2);
double el = globe.getElevation(lat, lon);
// Test line of sight from point to center
Vec4 point = globe.computePointFromPosition(lat, lon, el + pointOffset);
double distance = point.distanceTo3(center);
if (distance <= radius)
{
if (RayCastingSupport.intersectSegmentWithTerrain(
globe, point, center, samplingLength, samplingLength) == null)
{
// Center visible from point: set pixel color and shade
float hue = (float)Math.min(distance / radius, 1) * hueScaleFactor;
float shade = shadingCheck.isSelected() ?
(float)computeShading(globe, lat, lon, light, ambiant) : 0f;
image.setRGB(x, y, Color.HSBtoRGB(hue, 1f, 1f - shade));
}
else if (shadingCheck.isSelected())
{
// Center not visible: apply shading nonetheless if selected
float shade = (float)computeShading(globe, lat, lon, light, ambiant);
image.setRGB(x, y, new Color(0f, 0f, 0f, shade).getRGB());
}
}
}
}
// Blur image
PatternFactory.blur(PatternFactory.blur(PatternFactory.blur(PatternFactory.blur(image))));

// Update surface image
if (this.surfaceImage != null)
this.renderableLayer.removeRenderable(this.surfaceImage);
this.surfaceImage = new SurfaceImage(image, sector);
this.surfaceImage.setOpacity(.5);
this.renderableLayer.addRenderable(this.surfaceImage);

// Compute distance scale image
BufferedImage scaleImage = new BufferedImage(64, 256, BufferedImage.TYPE_4BYTE_ABGR);
Graphics g2 = scaleImage.getGraphics();
int divisions = 10;
int labelStep = scaleImage.getHeight() / divisions;
for (int y = 0; y < scaleImage.getHeight(); y++)
{
int x1 = scaleImage.getWidth() / 5;
if (y % labelStep == 0 && y != 0)
{
double d = radius / divisions * y / labelStep / 1000;
String label = Double.toString(d) + "km";
g2.setColor(Color.BLACK);
g2.drawString(label, x1 + 6, y + 6);
g2.setColor(Color.WHITE);
g2.drawLine(x1, y, x1 + 4 , y);
g2.drawString(label, x1 + 5, y + 5);
}
float hue = (float)y / (scaleImage.getHeight() - 1) * hueScaleFactor;
g2.setColor(Color.getHSBColor(hue, 1f, 1f));
g2.drawLine(0, y, x1, y);
}

// Update distance scale screen annotation
if (this.screenAnnotation != null)
this.renderableLayer.removeRenderable(this.screenAnnotation);
this.screenAnnotation = new ScreenAnnotation("", new Point(20, 20));
this.screenAnnotation.getAttributes().setImageSource(scaleImage);
this.screenAnnotation.getAttributes().setSize(
new Dimension(scaleImage.getWidth(), scaleImage.getHeight()));
this.screenAnnotation.getAttributes().setAdjustWidthToText(Annotation.SIZE_FIXED);
this.screenAnnotation.getAttributes().setDrawOffset(new Point(scaleImage.getWidth() / 2, 0));
this.screenAnnotation.getAttributes().setBorderWidth(0);
this.screenAnnotation.getAttributes().setCornerRadius(0);
this.screenAnnotation.getAttributes().setBackgroundColor(new Color(0f, 0f, 0f, 0f));
this.renderableLayer.addRenderable(this.screenAnnotation);

// Redraw
this.getWwd().redraw();
}
finally
{
computeButton.setEnabled(true);
computeButton.setText("Compute");
}
}

/**
* Compute shadow intensity at a globe position.
* @param globe the <code>Globe</code>.
* @param lat the location latitude.
* @param lon the location longitude.
* @param light the light direction vector. Expected to be normalized.
* @param ambiant the minimum ambiant light level (0..1).
* @return the shadow intensity for the location. No shadow = 0, totaly obscured = 1.
*/
private static double computeShading(Globe globe, Angle lat, Angle lon, Vec4 light, double ambiant)
{
double thirtyMetersRadians = 30 / globe.getEquatorialRadius();
Vec4 p0 = globe.computePointFromPosition(lat, lon, 0);
Vec4 px = globe.computePointFromPosition(lat, Angle.fromRadians(lon.radians - thirtyMetersRadians), 0);
Vec4 py = globe.computePointFromPosition(Angle.fromRadians(lat.radians + thirtyMetersRadians), lon, 0);

double el0 = globe.getElevation(lat, lon);
double elx = globe.getElevation(lat, Angle.fromRadians(lon.radians - thirtyMetersRadians));
double ely = globe.getElevation(Angle.fromRadians(lat.radians + thirtyMetersRadians), lon);

Vec4 vx = new Vec4(p0.distanceTo3(px), 0, elx - el0).normalize3();
Vec4 vy = new Vec4(0, p0.distanceTo3(py), ely - el0).normalize3();
Vec4 normal = vx.cross3(vy).normalize3();

return 1d - Math.max(-light.dot3(normal), ambiant);
}
}

public static void main(String[] args)
{
ApplicationTemplate.start("World Wind Line Of Sight Calculation", AppFrame.class);
}
}

最佳答案

你是对的。此代码未考虑地球曲线。据我所见,光线的中心是为光的中心完成的,但光的锥体是在图像上绘制的(我不确定,但看起来这个例子是在灰度图像上绘制的)。这个演示的任何方式都是关于检测撞击地面以停止光线追踪。据我了解,算法在以形式设置的距离后停止(5km,10km ... 200km 等)我不明白射线的方向。仅当您检查来自太空的光线时,检查 200 公里半径才有意义....如果你想考虑地平线,你应该首先检查光源的间距。它与正音高值(高于地平线)相关。在这种情况下,您应该决定在灯光中心离地面非常高时何时停止。多高取决于您将光线指向相对平坦的山坡,或者光源是窄光束还是宽光束。

关于java - 世风视线,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28651578/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com