/** * Compute the bounding screen extent of a rotated rectangle. * * @param rect Rectangle to rotate. * @param x X coordinate of the rotation point. * @param y Y coordinate of the rotation point. * @param rotation Rotation angle. * @return The smallest rectangle that completely contains {@code rect} when rotated by the * specified angle. */ protected Rectangle computeRotatedScreenExtent(Rectangle rect, int x, int y, Angle rotation) { Rectangle r = new Rectangle(rect); // Translate the rectangle to the rotation point. r.translate(-x, -y); // Compute corner points Vec4[] corners = { new Vec4(r.getMaxX(), r.getMaxY()), new Vec4(r.getMaxX(), r.getMinY()), new Vec4(r.getMinX(), r.getMaxY()), new Vec4(r.getMinX(), r.getMinY()) }; // Rotate the rectangle Matrix rotationMatrix = Matrix.fromRotationZ(rotation); for (int i = 0; i < corners.length; i++) { corners[i] = corners[i].transformBy3(rotationMatrix); } // Find the bounding rectangle of rotated points. int minX = Integer.MAX_VALUE; int minY = Integer.MAX_VALUE; int maxX = -Integer.MAX_VALUE; int maxY = -Integer.MAX_VALUE; for (Vec4 v : corners) { if (v.x > maxX) maxX = (int) v.x; if (v.x < minX) minX = (int) v.x; if (v.y > maxY) maxY = (int) v.y; if (v.y < minY) minY = (int) v.y; } // Set bounds and translate the rectangle back to where it started. r.setBounds(minX, minY, maxX - minX, maxY - minY); r.translate(x, y); return r; }
/** * Indicates the transform matrix applied to this document. * * @return Transform matrix. */ protected Matrix getMatrix() { // If the matrix has already been computed then just return the cached value. if (this.matrix != null) return this.matrix; Matrix m = Matrix.IDENTITY; if (this.heading != null) m = m.multiply(Matrix.fromRotationZ(Angle.POS360.subtract(this.heading))); if (this.pitch != null) m = m.multiply(Matrix.fromRotationX(this.pitch)); if (this.roll != null) m = m.multiply(Matrix.fromRotationY(this.roll)); // Apply scaling factor to convert file units to meters. double scale = this.getScale(); m = m.multiply(Matrix.fromScale(scale)); if (this.modelScale != null) m = m.multiply(Matrix.fromScale(this.modelScale)); this.matrix = m; return m; }
/** * Compute the label's screen position from its geographic position. * * @param dc Current draw context. */ protected void computeGeometry(DrawContext dc) { // Project the label position onto the viewport Position pos = this.getPosition(); if (pos == null) return; this.placePoint = dc.computeTerrainPoint(pos.getLatitude(), pos.getLongitude(), 0); this.screenPlacePoint = dc.getView().project(this.placePoint); this.eyeDistance = this.placePoint.distanceTo3(dc.getView().getEyePoint()); boolean orientationReversed = false; if (this.orientationPosition != null) { // Project the orientation point onto the screen Vec4 orientationPlacePoint = dc.computeTerrainPoint( this.orientationPosition.getLatitude(), this.orientationPosition.getLongitude(), 0); Vec4 orientationScreenPoint = dc.getView().project(orientationPlacePoint); this.rotation = this.computeRotation(this.screenPlacePoint, orientationScreenPoint); // The orientation is reversed if the orientation point falls to the right of the screen // point. Text is // never drawn upside down, so when the orientation is reversed the text flips vertically to // keep the text // right side up. orientationReversed = (orientationScreenPoint.x <= this.screenPlacePoint.x); } this.computeBoundsIfNeeded(dc); Offset offset = this.getOffset(); Point2D offsetPoint = offset.computeOffset(this.bounds.getWidth(), this.bounds.getHeight(), null, null); // If a rotation is applied to the text, then rotate the offset as well. An offset in the x // direction // will move the text along the orientation line, and a offset in the y direction will move the // text // perpendicular to the orientation line. if (this.rotation != null) { double dy = offsetPoint.getY(); // If the orientation is reversed we need to adjust the vertical offset to compensate for the // flipped // text. For example, if the offset normally aligns the top of the text with the place point // then without // this adjustment the bottom of the text would align with the place point when the // orientation is // reversed. if (orientationReversed) { dy = -(dy + this.bounds.getHeight()); } Vec4 pOffset = new Vec4(offsetPoint.getX(), dy); Matrix rot = Matrix.fromRotationZ(this.rotation.multiply(-1)); pOffset = pOffset.transformBy3(rot); offsetPoint = new Point((int) pOffset.getX(), (int) pOffset.getY()); } int x = (int) (this.screenPlacePoint.x + offsetPoint.getX()); int y = (int) (this.screenPlacePoint.y - offsetPoint.getY()); this.screenPoint = new Point(x, y); this.screenExtent = this.computeTextExtent(x, y, this.rotation); }