protected void onHorizontalTranslateRel( Angle forwardChange, Angle sideChange, ViewInputAttributes.ActionAttributes actionAttribs) { View view = this.getView(); if (view == null) // include this test to ensure any derived implementation performs it { return; } if (forwardChange.equals(Angle.ZERO) && sideChange.equals(Angle.ZERO)) { return; } if (view instanceof BasicFlyView) { Vec4 forward = view.getForwardVector(); Vec4 up = view.getUpVector(); Vec4 side = forward.transformBy3(Matrix.fromAxisAngle(Angle.fromDegrees(90), up)); forward = forward.multiply3(forwardChange.getDegrees()); side = side.multiply3(sideChange.getDegrees()); Vec4 eyePoint = view.getEyePoint(); eyePoint = eyePoint.add3(forward.add3(side)); Position newPosition = view.getGlobe().computePositionFromPoint(eyePoint); this.setEyePosition(this.uiAnimControl, view, newPosition, actionAttribs); view.firePropertyChange(AVKey.VIEW, null, view); } }
protected void assembleVertexControlPoints(DrawContext dc) { Terrain terrain = dc.getTerrain(); ExtrudedPolygon polygon = this.getPolygon(); Position refPos = polygon.getReferencePosition(); Vec4 refPoint = terrain.getSurfacePoint(refPos.getLatitude(), refPos.getLongitude(), 0); int altitudeMode = polygon.getAltitudeMode(); double height = polygon.getHeight(); Vec4 vaa = null; double vaaLength = 0; // used to compute independent length of each cap vertex double vaLength = 0; int i = 0; for (LatLon location : polygon.getOuterBoundary()) { Vec4 vert; // Compute the top/cap point. if (altitudeMode == WorldWind.CONSTANT || !(location instanceof Position)) { if (vaa == null) { // Compute the vector lengths of the top and bottom points at the reference position. vaa = refPoint.multiply3(height / refPoint.getLength3()); vaaLength = vaa.getLength3(); vaLength = refPoint.getLength3(); } // Compute the bottom point, which is on the terrain. vert = terrain.getSurfacePoint(location.getLatitude(), location.getLongitude(), 0); double delta = vaLength - vert.dot3(refPoint) / vaLength; vert = vert.add3(vaa.multiply3(1d + delta / vaaLength)); } else if (altitudeMode == WorldWind.RELATIVE_TO_GROUND) { vert = terrain.getSurfacePoint( location.getLatitude(), location.getLongitude(), ((Position) location).getAltitude()); } else // WorldWind.ABSOLUTE { vert = terrain .getGlobe() .computePointFromPosition( location.getLatitude(), location.getLongitude(), ((Position) location).getAltitude() * terrain.getVerticalExaggeration()); } Position vertexPosition = this.wwd.getModel().getGlobe().computePositionFromPoint(vert); this.controlPoints.add( new ControlPointMarker( MOVE_VERTEX_ACTION, vertexPosition, vert, this.vertexControlAttributes, i)); i++; } }
/** * Construct a unit-length cube centered at a specified point. * * @param point the center of the cube. * @throws IllegalArgumentException if the point is null. */ public Box(Vec4 point) { if (point == null) { String msg = Logging.getMessage("nullValue.PointIsNull"); Logging.error(msg); throw new IllegalArgumentException(msg); } this.ru = new Vec4(1, 0, 0, 1); this.su = new Vec4(0, 1, 0, 1); this.tu = new Vec4(0, 0, 1, 1); this.r = this.ru; this.s = this.su; this.t = this.tu; this.rLength = 1; this.sLength = 1; this.tLength = 1; // Plane normals point outwards from the box. this.planes = new Plane[6]; double d = 0.5 * point.getLength3(); this.planes[0] = new Plane(-this.ru.x, -this.ru.y, -this.ru.z, -(d + 0.5)); this.planes[1] = new Plane(+this.ru.x, +this.ru.y, +this.ru.z, -(d + 0.5)); this.planes[2] = new Plane(-this.su.x, -this.su.y, -this.su.z, -(d + 0.5)); this.planes[3] = new Plane(+this.su.x, +this.su.y, +this.su.z, -(d + 0.5)); this.planes[4] = new Plane(-this.tu.x, -this.tu.y, -this.tu.z, -(d + 0.5)); this.planes[5] = new Plane(+this.tu.x, +this.tu.y, +this.tu.z, -(d + 0.5)); this.center = ru.add3(su).add3(tu).multiply3(0.5); Vec4 rHalf = r.multiply3(0.5); this.topCenter = this.center.add3(rHalf); this.bottomCenter = this.center.subtract3(rHalf); }
/** * Construct a box from three specified unit axes and the locations of the box faces relative to * those axes. The box faces are specified by two scalar locations along each axis, each location * indicating a face. The non-unit length of an axis is the distance between its respective two * locations. The longest side is specified first, followed by the second longest side and then * the shortest side. * * <p>The axes are normally principal axes computed from a collection of points in order to form * an oriented bounding volume. See {@link WWMath#computePrincipalAxes(Iterable)}. * * <p>Note: No check is made to ensure the order of the face locations. * * @param axes the unit-length axes. * @param rMin the location along the first axis corresponding to the left-most box side relative * to the axis. * @param rMax the location along the first axis corresponding to the right-most box side relative * to the axis. * @param sMin the location along the second axis corresponding to the left-most box side relative * to the axis. * @param sMax the location along the second axis corresponding to the right-most box side * relative to the axis. * @param tMin the location along the third axis corresponding to the left-most box side relative * to the axis. * @param tMax the location along the third axis corresponding to the right-most box side relative * to the axis. * @throws IllegalArgumentException if the axes array or one of its entries is null. */ public Box( Vec4 axes[], double rMin, double rMax, double sMin, double sMax, double tMin, double tMax) { if (axes == null || axes[0] == null || axes[1] == null || axes[2] == null) { String msg = Logging.getMessage("nullValue.AxesIsNull"); Logging.error(msg); throw new IllegalArgumentException(msg); } this.ru = axes[0]; this.su = axes[1]; this.tu = axes[2]; this.r = this.ru.multiply3(rMax - rMin); this.s = this.su.multiply3(sMax - sMin); this.t = this.tu.multiply3(tMax - tMin); this.rLength = this.r.getLength3(); this.sLength = this.s.getLength3(); this.tLength = this.t.getLength3(); // Plane normals point outward from the box. this.planes = new Plane[6]; this.planes[0] = new Plane(-this.ru.x, -this.ru.y, -this.ru.z, +rMin); this.planes[1] = new Plane(+this.ru.x, +this.ru.y, +this.ru.z, -rMax); this.planes[2] = new Plane(-this.su.x, -this.su.y, -this.su.z, +sMin); this.planes[3] = new Plane(+this.su.x, +this.su.y, +this.su.z, -sMax); this.planes[4] = new Plane(-this.tu.x, -this.tu.y, -this.tu.z, +tMin); this.planes[5] = new Plane(+this.tu.x, +this.tu.y, +this.tu.z, -tMax); double a = 0.5 * (rMin + rMax); double b = 0.5 * (sMin + sMax); double c = 0.5 * (tMin + tMax); this.center = ru.multiply3(a).add3(su.multiply3(b)).add3(tu.multiply3(c)); Vec4 rHalf = r.multiply3(0.5); this.topCenter = this.center.add3(rHalf); this.bottomCenter = this.center.subtract3(rHalf); }
public void lookAt(Position lookAtPos, long timeToMove) { BasicFlyView view = (BasicFlyView) this.getView(); Vec4 lookDirection; double distanceToSurface; Vec4 currentLookAtPt = view.getCenterPoint(); Position newPosition; if (currentLookAtPt == null) { view.getGlobe().computePointFromPosition(lookAtPos); double elevAtLookAtPos = view.getGlobe().getElevation(lookAtPos.getLatitude(), lookAtPos.getLongitude()); newPosition = new Position(lookAtPos, elevAtLookAtPos + 10000); } else { Vec4 currentEyePt = view.getEyePoint(); distanceToSurface = currentEyePt.distanceTo3(currentLookAtPt); lookDirection = currentLookAtPt.subtract3(currentEyePt).normalize3(); Vec4 newLookAtPt = view.getGlobe().computePointFromPosition(lookAtPos); Vec4 flyToPoint = newLookAtPt.add3(lookDirection.multiply3(-distanceToSurface)); newPosition = view.getGlobe().computePositionFromPoint(flyToPoint); } ViewUtil.ViewState viewCoords = view.getViewState(newPosition, lookAtPos); FlyToFlyViewAnimator panAnimator = FlyToFlyViewAnimator.createFlyToFlyViewAnimator( view, view.getEyePosition(), newPosition, view.getHeading(), viewCoords.getHeading(), view.getPitch(), viewCoords.getPitch(), view.getEyePosition().getElevation(), viewCoords.getPosition().getElevation(), timeToMove, WorldWind.ABSOLUTE); this.gotoAnimControl.put(VIEW_ANIM_PAN, panAnimator); this.getView().firePropertyChange(AVKey.VIEW, null, this.getView()); view.firePropertyChange(AVKey.VIEW, null, view); }
/** * Determine the positions that make up the arrowhead. * * @param dc Current draw context. * @param startPosition Position of the arrow's base. * @param endPosition Position of the arrow head tip. * @return Positions that define the arrowhead. */ protected List<Position> computeArrowheadPositions( DrawContext dc, Position startPosition, Position endPosition) { Globe globe = dc.getGlobe(); // Arrowhead looks like this: // _ // A\ | 1/2 width // ________B\ _| // Pt. 1 / // C/ // | | // Length Vec4 p1 = globe.computePointFromPosition(startPosition); Vec4 pB = globe.computePointFromPosition(endPosition); // Find vector in the direction of the arrow Vec4 vB1 = p1.subtract3(pB); double arrowLengthFraction = this.getArrowLength(); // Find the point at the base of the arrowhead Vec4 arrowBase = pB.add3(vB1.multiply3(arrowLengthFraction)); Vec4 normal = globe.computeSurfaceNormalAtPoint(arrowBase); // Compute the length of the arrowhead double arrowLength = vB1.getLength3() * arrowLengthFraction; double arrowHalfWidth = arrowLength * this.getArrowAngle().tanHalfAngle(); // Compute a vector perpendicular to the segment and the normal vector Vec4 perpendicular = vB1.cross3(normal); perpendicular = perpendicular.normalize3().multiply3(arrowHalfWidth); // Find points A and C Vec4 pA = arrowBase.add3(perpendicular); Vec4 pC = arrowBase.subtract3(perpendicular); return TacticalGraphicUtil.asPositionList(globe, pA, pB, pC); }
/** * Compute points on either side of a line segment. This method requires a point on the line, and * either a next point, previous point, or both. * * @param point Center point about which to compute side points. * @param prev Previous point on the line. May be null if {@code next} is non-null. * @param next Next point on the line. May be null if {@code prev} is non-null. * @param leftPositions Left position will be added to this list. * @param rightPositions Right position will be added to this list. * @param halfWidth Distance from the center line to the left or right lines. * @param globe Current globe. */ protected void generateParallelPoints( Vec4 point, Vec4 prev, Vec4 next, List<Position> leftPositions, List<Position> rightPositions, double halfWidth, Globe globe) { if ((point == null) || (prev == null && next == null)) { String message = Logging.getMessage("nullValue.PointIsNull"); Logging.logger().severe(message); throw new IllegalArgumentException(message); } if (leftPositions == null || rightPositions == null) { String message = Logging.getMessage("nullValue.PositionListIsNull"); Logging.logger().severe(message); throw new IllegalArgumentException(message); } if (globe == null) { String message = Logging.getMessage("nullValue.GlobeIsNull"); Logging.logger().severe(message); throw new IllegalArgumentException(message); } Vec4 offset; Vec4 normal = globe.computeSurfaceNormalAtPoint(point); // Compute vector in the direction backward along the line. Vec4 backward = (prev != null) ? prev.subtract3(point) : point.subtract3(next); // Compute a vector perpendicular to segment BC, and the globe normal vector. Vec4 perpendicular = backward.cross3(normal); double length; // If both next and previous points are supplied then calculate the angle that bisects the angle // current, next, prev. if (next != null && prev != null && !Vec4.areColinear(prev, point, next)) { // Compute vector in the forward direction. Vec4 forward = next.subtract3(point); // Calculate the vector that bisects angle ABC. offset = forward.normalize3().add3(backward.normalize3()); offset = offset.normalize3(); // Compute the scalar triple product of the vector BC, the normal vector, and the offset // vector to // determine if the offset points to the left or the right of the control line. double tripleProduct = perpendicular.dot3(offset); if (tripleProduct < 0) { offset = offset.multiply3(-1); } // Determine the length of the offset vector that will keep the left and right lines parallel // to the control // line. Angle theta = backward.angleBetween3(offset); if (!Angle.ZERO.equals(theta)) length = halfWidth / theta.sin(); else length = halfWidth; } else { offset = perpendicular.normalize3(); length = halfWidth; } offset = offset.multiply3(length); // Determine the left and right points by applying the offset. Vec4 ptRight = point.add3(offset); Vec4 ptLeft = point.subtract3(offset); // Convert cartesian points to geographic. Position posLeft = globe.computePositionFromPoint(ptLeft); Position posRight = globe.computePositionFromPoint(ptRight); leftPositions.add(posLeft); rightPositions.add(posRight); }
protected void onMoveTo( Position focalPosition, ViewInputAttributes.DeviceAttributes deviceAttributes, ViewInputAttributes.ActionAttributes actionAttribs) { BasicFlyView view = (BasicFlyView) this.getView(); if (view == null) // include this test to ensure any derived implementation performs it { return; } // We're treating a speed parameter as smoothing here. A greater speed results in greater // smoothing and // slower response. Therefore the min speed used at lower altitudes ought to be *greater* than // the max // speed used at higher altitudes. double smoothing = this.getScaleValueElevation(deviceAttributes, actionAttribs); if (!actionAttribs.isEnableSmoothing()) smoothing = 0.0; Vec4 currentLookAtPt = view.getCenterPoint(); if (currentLookAtPt == null) { currentLookAtPt = view.getGlobe().computePointFromPosition(focalPosition); } Vec4 currentEyePt = view.getEyePoint(); double distanceToSurface = currentEyePt.distanceTo3(currentLookAtPt); Vec4 lookDirection = currentEyePt.subtract3(currentLookAtPt).normalize3(); Vec4 newLookAtPt = view.getGlobe().computePointFromPosition(focalPosition); Vec4 flyToPoint = newLookAtPt.add3(lookDirection.multiply3(distanceToSurface)); Position newPosition = view.getGlobe().computePositionFromPoint(flyToPoint); ViewUtil.ViewState viewCoords = view.getViewState(newPosition, focalPosition); this.stopAnimators(); this.gotoAnimControl.put( VIEW_ANIM_HEADING, new RotateToAngleAnimator( view.getHeading(), viewCoords.getHeading(), smoothing, ViewPropertyAccessor.createHeadingAccessor(view))); this.gotoAnimControl.put( VIEW_ANIM_PITCH, new RotateToAngleAnimator( view.getPitch(), viewCoords.getPitch(), smoothing, ViewPropertyAccessor.createPitchAccessor(view))); double elevation = ((FlyViewLimits) view.getViewPropertyLimits()) .limitEyeElevation(newPosition, view.getGlobe()); if (elevation != newPosition.getElevation()) { newPosition = new Position(newPosition, elevation); } this.gotoAnimControl.put( VIEW_ANIM_POSITION, new MoveToPositionAnimator( view.getEyePosition(), newPosition, smoothing, ViewPropertyAccessor.createEyePositionAccessor(view))); view.firePropertyChange(AVKey.VIEW, null, view); }