viewcontrolsselectlistener.java

来自「world wind java sdk 源码」· Java 代码 · 共 524 行 · 第 1/2 页

JAVA
524
字号
        }
    }

    protected void updateView(ScreenAnnotation control, String controlType)
    {
        if (this.wwd == null)
            return;
        if (!(this.wwd.getView() instanceof OrbitView))
            return;

        OrbitView view = (OrbitView)this.wwd.getView();
        view.stopStateIterators();
        view.stopMovement();

        if(controlType.equals(AVKey.VIEW_PAN))
        {
            resetOrbitView(view);
            // Go some distance in the control mouse direction
            Angle heading = computePanHeading(view, control);
            Angle distance = computePanAmount(this.wwd.getModel().getGlobe(), view, control, panStep);
            LatLon newViewCenter = LatLon.greatCircleEndPosition(view.getCenterPosition(),
                    heading, distance);
            // Turn around if passing by a pole - TODO: better handling of the pole crossing situation
            if (Math.abs(newViewCenter.getLongitude().degrees - view.getCenterPosition().getLongitude().degrees) > 20)
                view.setHeading(Angle.POS180.subtract(view.getHeading()));
            // Set new center pos
            view.setCenterPosition(new Position(newViewCenter, view.getCenterPosition().getElevation()));
        }
        else if(controlType.equals(AVKey.VIEW_LOOK))
        {
            setupFirstPersonView(view);
            Angle heading = computeLookHeading(view, control, headingStep);
            Angle pitch = computeLookPitch(view, control, pitchStep);
            // Check whether the view will still point at terrain
            Vec4 surfacePoint = computeSurfacePoint(view, heading, pitch);
            if (surfacePoint != null)
            {
                // Change view state
                final Position eyePos = view.getEyePosition();// Save current eye position
                view.setHeading(heading);
                view.setPitch(pitch);
                view.setZoom(0);
                view.setCenterPosition(eyePos); // Set center at the eye position
            }
        }
        else if (controlType.equals(AVKey.VIEW_ZOOM_IN))
        {
            resetOrbitView(view);
            view.setZoom(computeNewZoom(view, -zoomStep));
        }
        else if(controlType.equals(AVKey.VIEW_ZOOM_OUT))
        {
            resetOrbitView(view);
            view.setZoom(computeNewZoom(view, zoomStep));
        }
        else if(controlType.equals(AVKey.VIEW_HEADING_LEFT))
        {
            resetOrbitView(view);
            view.setHeading(view.getHeading().addDegrees(headingStep));
        }
        else if(controlType.equals(AVKey.VIEW_HEADING_RIGHT))
        {
            resetOrbitView(view);
            view.setHeading(view.getHeading().addDegrees(-headingStep));
        }
        else if(controlType.equals(AVKey.VIEW_PITCH_UP))
        {
            resetOrbitView(view);
            if (view.getPitch().degrees >= pitchStep)
                view.setPitch(view.getPitch().addDegrees(-pitchStep));
        }
        else if(controlType.equals(AVKey.VIEW_PITCH_DOWN))
        {
            resetOrbitView(view);
            if (view.getPitch().degrees <= 90 - pitchStep)
                view.setPitch(view.getPitch().addDegrees(pitchStep));
        }
        else if(controlType.equals(AVKey.VIEW_FOV_NARROW))
        {
            if (view.getFieldOfView().degrees / fovStep >= 4)
                view.setFieldOfView(view.getFieldOfView().divide(fovStep));
        }
        else if(controlType.equals(AVKey.VIEW_FOV_WIDE))
        {
            if (view.getFieldOfView().degrees * fovStep < 120)
                view.setFieldOfView(view.getFieldOfView().multiply(fovStep));
        }
        this.wwd.redraw();
    }

    protected double computeNewZoom(OrbitView view, double amount)
    {
        double coeff = 0.05;
        double change = coeff * amount;
        double logZoom = view.getZoom() != 0 ? Math.log(view.getZoom()) : 0;
        // Zoom changes are treated as logarithmic values. This accomplishes two things:
        // 1) Zooming is slow near the globe, and fast at great distances.
        // 2) Zooming in then immediately zooming out returns the viewer to the same zoom value.
        return Math.exp(logZoom + change);
    }

    protected Angle computePanHeading(OrbitView view, ScreenAnnotation control)
    {
        // Compute last pick point 'heading' relative to pan control center
        double size = control.getAttributes().getSize().width * control.getAttributes().getScale();
        Vec4 center = new Vec4(control.getScreenPoint().x, control.getScreenPoint().y + size / 2, 0);
        double px = lastPickPoint.x - center.x;
        double py = view.getViewport().getHeight() - lastPickPoint.y - center.y;
        Angle heading = view.getHeading().add(Angle.fromRadians(Math.atan2(px, py)));
        heading = heading.degrees >= 0 ? heading : heading.addDegrees(360);
        return heading;
    }

    protected Angle computePanAmount(Globe globe, OrbitView view, ScreenAnnotation control, double panStep)
    {
        // Compute last pick point distance relative to pan control center
        double size = control.getAttributes().getSize().width * control.getAttributes().getScale();
        Vec4 center = new Vec4(control.getScreenPoint().x, control.getScreenPoint().y + size / 2, 0);
        double px = lastPickPoint.x - center.x;
        double py = view.getViewport().getHeight() - lastPickPoint.y - center.y;
        double pickDistance = Math.sqrt(px * px + py * py);
        double pickDistanceFactor = Math.min(pickDistance / 10, 5);

        // Compute globe angular distance depending on eye altitude
        Position eyePos = view.getEyePosition();
        double radius = globe.getRadiusAt(eyePos);
        double minValue = 0.5 * (180.0 / (Math.PI * radius)); // Minimum change ~0.5 meters
        double maxValue = 1.0; // Maximum change ~1 degree

        // Compute an interpolated value between minValue and maxValue, using (eye altitude)/(globe radius) as
        // the interpolant. Interpolation is performed on an exponential curve, to keep the value from
        // increasing too quickly as eye altitude increases.
        double a = eyePos.getElevation() / radius;
        a = (a < 0 ? 0 : (a > 1 ? 1 : a));
        double expBase = 2.0; // Exponential curve parameter.
        double value = minValue + (maxValue - minValue) * ((Math.pow(expBase, a) - 1.0) / (expBase - 1.0));

        return Angle.fromDegrees(value * pickDistanceFactor * panStep);
    }

    protected Angle computeLookHeading(OrbitView view, ScreenAnnotation control, double headingStep)
    {
        // Compute last pick point 'heading' relative to look control center on x
        double size = control.getAttributes().getSize().width * control.getAttributes().getScale();
        Vec4 center = new Vec4(control.getScreenPoint().x, control.getScreenPoint().y + size / 2, 0);
        double px = lastPickPoint.x - center.x;
        double pickDistanceFactor = Math.min(Math.abs(px) / 3000, 5) * Math.signum(px);
        // New heading
        Angle heading = view.getHeading().add(Angle.fromRadians(headingStep * pickDistanceFactor));
        heading = heading.degrees >= 0 ? heading : heading.addDegrees(360);
        return heading;
    }

    protected Angle computeLookPitch(OrbitView view, ScreenAnnotation control, double pitchStep)
    {
        // Compute last pick point 'pitch' relative to look control center on y
        double size = control.getAttributes().getSize().width * control.getAttributes().getScale();
        Vec4 center = new Vec4(control.getScreenPoint().x, control.getScreenPoint().y + size / 2, 0);
        double py = view.getViewport().getHeight() - lastPickPoint.y - center.y;
        double pickDistanceFactor = Math.min(Math.abs(py) / 3000, 5) * Math.signum(py);
        // New pitch
        Angle pitch = view.getPitch().add(Angle.fromRadians(pitchStep * pickDistanceFactor));
        pitch = pitch.degrees >= 0 ? (pitch.degrees <= 90 ? pitch : Angle.fromDegrees(90)) : Angle.ZERO;
        return pitch;
    }

    /**
     * Reset the view to an orbit view state if in first person mode (zoom = 0)
     *
     * @param view the orbit view to reset
     */
    protected void resetOrbitView(OrbitView view)
    {
        if (view.getZoom() > 0)   // already in orbit view mode
            return;

        // Find out where on the terrain the eye is looking at in the viewport center
        // TODO: if no terrain is found in the viewport center, iterate toward viewport bottom until it is found
        Vec4 centerPoint = computeSurfacePoint(view, view.getHeading(), view.getPitch());
        // Reset the orbit view center point heading, pitch and zoom
        if (centerPoint != null)
        {
            Vec4 eyePoint = view.getEyePoint();
            // Center pos on terrain surface
            Position centerPosition = wwd.getModel().getGlobe().computePositionFromPoint(centerPoint);
            // Compute pitch and heading relative to center position
            Vec4 normal = wwd.getModel().getGlobe().computeSurfaceNormalAtLocation(centerPosition.getLatitude(),
                    centerPosition.getLongitude());
            Vec4 north = wwd.getModel().getGlobe().computeNorthPointingTangentAtLocation(centerPosition.getLatitude(),
                    centerPosition.getLongitude());
            // Pitch
            view.setPitch(Angle.POS180.subtract(view.getForwardVector().angleBetween3(normal)));
            // Heading
            Vec4 perpendicular = view.getForwardVector().perpendicularTo3(normal);
            Angle heading = perpendicular.angleBetween3(north);
            double direction = Math.signum(-normal.cross3(north).dot3(perpendicular));
            view.setHeading(heading.multiply(direction));
            // Zoom
            view.setZoom(eyePoint.distanceTo3(centerPoint));
            // Center pos
            view.setCenterPosition(centerPosition);
        }
    }

    /**
     * Setup the view to a first person mode (zoom = 0)
     *
     * @param view the orbit view to set into a first person view.
     */
    protected void setupFirstPersonView(OrbitView view)
    {
        if (view.getZoom() == 0)  // already in first person mode
            return;

        Vec4 eyePoint = view.getEyePoint();
        // Center pos at eye pos
        Position centerPosition = wwd.getModel().getGlobe().computePositionFromPoint(eyePoint);
        // Compute pitch and heading relative to center position
        Vec4 normal = wwd.getModel().getGlobe().computeSurfaceNormalAtLocation(centerPosition.getLatitude(),
                centerPosition.getLongitude());
        Vec4 north = wwd.getModel().getGlobe().computeNorthPointingTangentAtLocation(centerPosition.getLatitude(),
                centerPosition.getLongitude());
        // Pitch
        view.setPitch(Angle.POS180.subtract(view.getForwardVector().angleBetween3(normal)));
        // Heading
        Vec4 perpendicular = view.getForwardVector().perpendicularTo3(normal);
        Angle heading = perpendicular.angleBetween3(north);
        double direction = Math.signum(-normal.cross3(north).dot3(perpendicular));
        view.setHeading(heading.multiply(direction));
        // Zoom
        view.setZoom(0);
        // Center pos
        view.setCenterPosition(centerPosition);
    }

    /**
     * Find out where on the terrain surface the eye would be looking at
     * with the given heading and pitch angles.
     *
     * @param view the orbit view
     * @param heading heading direction clockwise from north.
     * @param pitch view pitch angle from the surface normal at the center point.
     * @return the terrain surface point the view would be looking at in the viewport center.
     */
    protected Vec4 computeSurfacePoint(OrbitView view, Angle heading, Angle pitch)
    {
        Globe globe = wwd.getModel().getGlobe();
        // Compute transform to be applied to north pointing Y so that it would point in the view direction
        // Move coordinate system to view center point
        Matrix transform = globe.computeTransformToPosition(view.getCenterPosition());
        // Rotate so that the north pointing axes Y will point in the look at direction
        transform = transform.multiply(Matrix.fromRotationZ(heading.multiply(-1)));
        transform = transform.multiply(Matrix.fromRotationX(Angle.NEG90.add(pitch)));
        // Compute forward vector
        Vec4 forward = Vec4.UNIT_Y.transformBy4(transform);
        // Return intersection with terrain
        Intersection[] intersections = wwd.getSceneController().getTerrain().intersect(new Line(view.getEyePoint(), forward));
        return (intersections != null && intersections.length != 0) ? intersections[0].getIntersectionPoint() : null;
    }

}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?