terrainprofilelayer.java
来自「world wind java sdk 源码」· Java 代码 · 共 1,710 行 · 第 1/5 页
JAVA
1,710 行
this.color.getGreen(), (int) (this.color.getBlue() * .8), (int) (255 * .8)));
}
else
this.pickedShape.setPositions(posList);
}
}
}
return pickPosition;
}
/**
* Compute the sample number along the path closest to the given <code>LatLon</code>.
*
* @param pos the object <code>LatLon</code>
* @return the sample number or -1 if not found.
*/
private int computeObjectSample(LatLon pos)
{
if (this.pathPositions.size() < 2)
return -1;
double radius = this.wwd.getModel().getGlobe().getRadius();
double maxDistanceFromPath = 1000; // meters
double distanceFromStart = 0;
int segmentIndex = 0;
LatLon pos1 = this.pathPositions.get(segmentIndex);
for (int i = 1; i < this.pathPositions.size(); i++)
{
LatLon pos2 = this.pathPositions.get(i);
double segmentLength = LatLon.greatCircleDistance(pos1, pos2).radians * radius;
// Check wether the position is close to the segment line
Vec4 v0 = new Vec4(pos.getLatitude().radians, pos.getLongitude().radians, 0, 0);
Vec4 v1 = new Vec4(pos1.getLatitude().radians, pos1.getLongitude().radians, 0, 0);
Vec4 v2 = new Vec4(pos2.getLatitude().radians, pos2.getLongitude().radians, 0, 0);
Line line = new Line(v1, v2.subtract3(v1));
if (line.distanceTo(v0) * radius <= maxDistanceFromPath)
{
// Check whether the position is inside the segment
double length1 = LatLon.greatCircleDistance(pos1, pos).radians * radius;
double length2 = LatLon.greatCircleDistance(pos2, pos).radians * radius;
if (length1 <= segmentLength && length2 <= segmentLength)
{
// Compute portion of segment length
distanceFromStart += length1 / (length1 + length2) * segmentLength;
break;
}
else
distanceFromStart += segmentLength;
}
else
distanceFromStart += segmentLength;
// Next segment
pos1 = pos2;
}
double pathLength = this.computePathLength();
return distanceFromStart < pathLength ? (int)(distanceFromStart / pathLength * this.samples) : -1;
}
// ** Position listener impl. ************************************************************
public void moved(PositionEvent event)
{
if (this.wwd != null && this.isEnabled())
{
// Update profile if FOLLOW_CURSOR
if (this.follow.equals(FOLLOW_CURSOR))
this.setUpdate(true);
}
else
this.positions = null;
}
// ** Select listener impl. ************************************************************
public void selected(SelectEvent event)
{
if (event.hasObjects() && event.getEventAction().equals(SelectEvent.LEFT_CLICK))
{
Object o = event.getTopObject();
if (o == this.buttonMinimize)
{
if (this.isMaximized)
this.setIsMaximized(false);
else
this.setIsMinimized(true);
}
else if (o == this.buttonMaximize)
{
this.setIsMaximized(true);
}
else if (o == this && this.isMinimized)
{
this.setIsMinimized(false);
this.setUpdate(true);
}
}
}
// ** Property change listener ***********************************************************
public void propertyChange(PropertyChangeEvent propertyChangeEvent)
{
if (this.wwd != null && this.isEnabled())
{
// Update profile if FOLLOW_VIEW or FOLLOW_EYE or terrain elevations changed
if (this.follow.equals(FOLLOW_VIEW)
|| this.follow.equals(FOLLOW_EYE)
|| propertyChangeEvent.getPropertyName().equals(AVKey.ELEVATION_MODEL))
this.setUpdate(true);
}
else
this.positions = null;
}
// Sets the wwd local reference and add us to the position listeners
// the view and elevation model property change listener
public void setEventSource(WorldWindow wwd)
{
if (this.wwd != null)
{
this.wwd.removePositionListener(this);
this.wwd.getView().removePropertyChangeListener(this);
// this.wwd.getModel().getGlobe().getElevationModel().removePropertyChangeListener(this);
this.wwd.removeSelectListener(this);
}
this.wwd = wwd;
if (this.wwd != null)
{
this.wwd.addPositionListener(this);
this.wwd.getView().addPropertyChangeListener(this);
// this.wwd.getModel().getGlobe().getElevationModel().addPropertyChangeListener(this);
this.wwd.addSelectListener(this);
}
}
// ** Profile data collection ************************************************************
/**
* Compute the terrain profile. <p> If {@link #FOLLOW_VIEW ], {@link #FOLLOW_EYE] or {@link #FOLLOW_CURSOR] collects
* terrain profile data along a great circle line centered at the current position (view, eye or cursor) and
* perpendicular to the view heading. If {@link #FOLLOW_NONE] the profile is computed in between start and end
* latlon </p>
*
* @param dc the current <code>DrawContext</code>
*/
private void computeProfile(DrawContext dc)
{
if (this.wwd == null)
return;
try
{
// Find center position
OrbitView view = (OrbitView) this.wwd.getView(); // TODO: check for OrbitView instance first
Position groundPos = view.computePositionFromScreenPoint(
view.getViewport().getWidth() / 2, view.getViewport().getHeight() / 2);
if (view.getCenterPosition() != null)
groundPos = new Position(view.getCenterPosition(), 0);
if (this.follow.equals(FOLLOW_CURSOR))
groundPos = computeCursorPosition(dc);
if (this.follow.equals(FOLLOW_EYE))
groundPos = view.getEyePosition();
if (this.follow.equals(FOLLOW_OBJECT))
groundPos = this.objectPosition;
// Compute profile if we can
if ((this.follow.equals(FOLLOW_VIEW) && groundPos != null) ||
(this.follow.equals(FOLLOW_EYE) && groundPos != null) ||
(this.follow.equals(FOLLOW_CURSOR) && groundPos != null) ||
(this.follow.equals(FOLLOW_NONE) && this.startLatLon != null && this.endLatLon != null) ||
(this.follow.equals(FOLLOW_OBJECT) && this.objectPosition != null && this.objectHeading != null) ||
(this.follow.equals(FOLLOW_PATH) && this.pathPositions != null && this.pathPositions.size() >= 2))
{
this.positions = new Position[samples];
this.minElevation = Double.MAX_VALUE;
this.maxElevation = -1e6; // Note: Double.MIN_VALUE would fail below min-max tests for some reason
// Compute profile positions
if (this.follow.equals(FOLLOW_PATH))
computePathPositions();
else
computeMirroredPositions(groundPos);
// Update shape on ground
if (this.selectionShape == null)
{
this.selectionShape = new Polyline(Arrays.asList(this.positions));
this.selectionShape.setLineWidth(2);
this.selectionShape.setFollowTerrain(true);
this.selectionShape.setColor(new Color(this.color.getRed(),
this.color.getGreen(), (int) (this.color.getBlue() * .5), (int) (255 * .8)));
}
else
this.selectionShape.setPositions(Arrays.asList(this.positions));
}
else
{
// Off globe or something missing
this.positions = null;
}
}
catch (Exception e)
{
this.positions = null;
}
// Clear update flag
this.update = false;
}
private void computeMirroredPositions(LatLon centerLatLon)
{
OrbitView view = (OrbitView) this.wwd.getView();
this.length = Math.min(view.getZoom() * .8 * this.profileLengthFactor,
this.wwd.getModel().getGlobe().getRadius() * Math.PI);
if (length <= 0)
this.length = Math.min(view.getEyePosition().getElevation() * .8 * this.profileLengthFactor,
this.wwd.getModel().getGlobe().getRadius() * Math.PI);
if (this.follow.equals(FOLLOW_NONE))
this.length = LatLon.greatCircleDistance(this.startLatLon, this.endLatLon).radians
* this.wwd.getModel().getGlobe().getRadius();
if (this.follow.equals(FOLLOW_OBJECT))
this.length = Math.min(this.objectPosition.getElevation() * .8 * this.profileLengthFactor,
this.wwd.getModel().getGlobe().getRadius() * Math.PI);
double lengthRadian = this.length / this.wwd.getModel().getGlobe().getRadius();
// Iterate on both sides of the center point
int i;
double step = lengthRadian / (samples - 1);
for (i = 0; i < this.samples; i++)
{
LatLon latLon = null;
if (!this.follow.equals(FOLLOW_NONE))
{
// Compute segments perpendicular to view or object heading
double azimuth = view.getHeading().subtract(Angle.POS90).radians;
if (this.follow.equals(FOLLOW_OBJECT))
azimuth = this.objectHeading.subtract(Angle.POS90).radians;
if (i > (float) (this.samples - 1) / 2f)
{
//azimuth = view.getHeading().subtract(Angle.NEG90).radians;
azimuth += Math.PI;
}
double distance = Math.abs(((double) i - ((double) (this.samples - 1) / 2d)) * step);
latLon = LatLon.greatCircleEndPosition(centerLatLon, azimuth, distance);
}
else if (this.follow.equals(FOLLOW_NONE) && this.startLatLon != null
&& this.endLatLon != null)
{
// Compute segments between start and end positions latlon
latLon = LatLon.interpolate((double) i / (this.samples - 1), this.startLatLon, this.endLatLon);
}
this.setPosition(i, latLon);
}
}
private void computePathPositions()
{
this.length = computePathLength();
double lengthRadians = this.length / this.wwd.getModel().getGlobe().getRadius();
double step = lengthRadians / (this.samples - 1);
int segmentIndex = 0;
LatLon latLon = this.pathPositions.get(segmentIndex);
// Set first sample at path start
this.setPosition(0, latLon);
// Compute in between samples
double distance, azimuth;
for (int i = 1; i < this.samples - 1; i++)
{
double stepToGo = step;
while (stepToGo > 0)
{
if (this.pathType == Polyline.RHUMB_LINE)
distance = LatLon.rhumbDistance(latLon, this.pathPositions.get(segmentIndex + 1)).radians;
else
distance = LatLon.greatCircleDistance(latLon, this.pathPositions.get(segmentIndex + 1)).radians;
if (distance >= stepToGo)
{
if (this.pathType == Polyline.RHUMB_LINE)
{
azimuth = LatLon.rhumbAzimuth(this.pathPositions.get(segmentIndex),
this.pathPositions.get(segmentIndex + 1)).radians;
latLon = LatLon.rhumbEndPosition(latLon, azimuth, stepToGo);
}
else
{
azimuth = LatLon.greatCircleAzimuth(this.pathPositions.get(segmentIndex),
this.pathPositions.get(segmentIndex + 1)).radians;
latLon = LatLon.greatCircleEndPosition(latLon, azimuth, stepToGo);
}
this.setPosition(i, latLon);
stepToGo = 0;
}
else
{
segmentIndex++;
latLon = this.pathPositions.get(segmentIndex);
stepToGo -= distance;
}
}
}
// Set last sample at path end
this.setPosition(this.samples -1, this.pathPositions.get(this.pathPositions.size() - 1));
}
private double computePathLength()
{
double pathLengthRadians = 0;
LatLon pos1 = null;
for (LatLon pos2 : this.pathPositions)
{
if (pos1 != null)
pathLengthRadians += LatLon.greatCircleDistance(pos1, pos2).radians;
pos1 = pos2;
}
return pathLengthRadians * this.wwd.getModel().getGlobe().getRadius();
}
private void setPosition(int index, LatLon latLon)
{
Double elevation =
this.wwd.getModel().getGlobe().getElevation(latLon.getLatitude(), latLon.getLongitude());
this.minElevation = elevation < this.minElevation ? elevation : this.minElevation;
this.maxElevation = elevation > this.maxElevation ? elevation : this.maxElevation;
// Add position to the list
positions[index] = new Position(latLon, elevation);
}
private Position computeCursorPosition(DrawContext dc)
{
Position pos = this.wwd.getCurrentPosition();
if (pos == null && dc.getPickPoint() != null)
pos = dc.getView().computePositionFromScreenPoint(dc.getPickPoint().x, dc.getPickPoint().y);
return pos;
}
@Override
public String toString()
{
return Logging.getMessage("layers.Earth.TerrainProfileLayer.Name");
}
}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?