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 + -
显示快捷键?