protected boolean areShapesIntersecting(Airspace a1, Airspace a2) { if ((a1 instanceof SphereAirspace) && (a2 instanceof SphereAirspace)) { SphereAirspace s1 = (SphereAirspace) a1; SphereAirspace s2 = (SphereAirspace) a2; LatLon location1 = s1.getLocation(); LatLon location2 = s2.getLocation(); double altitude1 = s1.getAltitudes()[0]; double altitude2 = s2.getAltitudes()[0]; boolean terrainConforming1 = s1.isTerrainConforming()[0]; boolean terrainConforming2 = s2.isTerrainConforming()[0]; // We have to compute the 3D coordinates of the sphere's center ourselves here. Vec4 p1 = terrainConforming1 ? this.getSurfacePoint(location1, altitude1) : this.getPoint(location1, altitude1); Vec4 p2 = terrainConforming2 ? this.getSurfacePoint(location2, altitude2) : this.getPoint(location2, altitude2); double r1 = s1.getRadius(); double r2 = s2.getRadius(); double d = p1.distanceTo3(p2); return d <= (r1 + r2); } return false; }
/** * Performs one line of sight calculation between the reference position and a specified grid * position. * * @param gridPosition the grid position. * @throws InterruptedException if the operation is interrupted. */ protected void performIntersection(Position gridPosition) throws InterruptedException { // Intersect the line between this grid point and the selected position. Intersection[] intersections = this.terrain.intersect(this.referencePosition, gridPosition); if (intersections == null || intersections.length == 0) { // No intersection, so the line goes from the center to the grid point. this.sightLines.add(new Position[] {this.referencePosition, gridPosition}); return; } // Only the first intersection is shown. Vec4 iPoint = intersections[0].getIntersectionPoint(); Vec4 gPoint = terrain.getSurfacePoint( gridPosition.getLatitude(), gridPosition.getLongitude(), gridPosition.getAltitude()); // Check to see whether the intersection is beyond the grid point. if (iPoint.distanceTo3(this.referencePoint) >= gPoint.distanceTo3(this.referencePoint)) { // Intersection is beyond the grid point; the line goes from the center to the grid point. this.addSightLine(this.referencePosition, gridPosition); return; } // Compute the position corresponding to the intersection. Position iPosition = this.terrain.getGlobe().computePositionFromPoint(iPoint); // The sight line goes from the user-selected position to the intersection position. this.addSightLine(this.referencePosition, new Position(iPosition, 0)); // Keep track of the intersection positions. this.addIntersectionPosition(iPosition); this.updateProgress(); }
public static void main(String[] args) { BarycentricPlanarShape bc = new BarycentricQuadrilateral(i0, i1, i2, i3); for (Vec4 point : testPoints) { double[] w = bc.getBarycentricCoords(point); Vec4 p = bc.getPoint(w); double[] uv = bc.getBilinearCoords(w[1], w[2]); System.out.printf( "%s, %s: ( %f, %f, %f) : ( %f, %f), %s\n", point, p, w[0], w[1], w[2], uv[0], uv[1], p.equals(point) ? "true" : "false"); } // // BarycentricPlanarShape bc = new BarycentricQuadrilateral(new Vec4(4, 3, 0), new // Vec4(7, 1, 0), // new Vec4(10, 5, 0), new Vec4(7, 7, 0)); // // ArrayList<Vec4> points = makePoints(0, 0, 14, 10); // for (Vec4 point : points) // { // double[] w = bc.getBarycentricCoords(point); // Vec4 p = bc.getPoint(w); // double[] uv = bc.getBilinearCoords(w[1], w[2]); // // System.out.printf("%s, %s: ( %f, %f, %f) : ( %f, %f), %s\n", // point, p, w[0], w[1], w[2], uv[0], uv[1], p.equals(point) ? "true" : "false"); // } }
protected void assembleHeightControlPoints() { if (this.controlPoints.size() < 2) return; // Add one control point for the height between the first and second vertices. // TODO: ensure that this control point is visible Position firstVertex = this.controlPoints.get(0).getPosition(); Position secondVertex = this.controlPoints.get(1).getPosition(); Globe globe = this.wwd.getModel().getGlobe(); // Get cartesian points for the vertices Vec4 firstPoint = globe.computePointFromPosition(firstVertex); Vec4 secondPoint = globe.computePointFromPosition(secondVertex); // Find the midpoint of the line segment that connects the vertices Vec4 halfwayPoint = firstPoint.add3(secondPoint).divide3(2.0); Position halfwayPosition = globe.computePositionFromPoint(halfwayPoint); this.controlPoints.add( new ControlPointMarker( CHANGE_HEIGHT_ACTION, halfwayPosition, halfwayPoint, this.heightControlAttributes, this.controlPoints.size())); }
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++; } }
protected void addToolTip(DrawContext dc, WWIcon icon, Vec4 iconPoint) { if (icon.getToolTipFont() == null && icon.getToolTipText() == null) return; Vec4 screenPoint = dc.getView().project(iconPoint); if (screenPoint == null) return; if (icon.getToolTipOffset() != null) screenPoint = screenPoint.add3(icon.getToolTipOffset()); OrderedText tip = new OrderedText( icon.getToolTipText(), icon.getToolTipFont(), screenPoint, icon.getToolTipTextColor(), 0d); dc.addOrderedRenderable(tip); }
// Draw the scale label private void drawLabel(DrawContext dc, String text, Vec4 screenPoint) { TextRenderer textRenderer = OGLTextRenderer.getOrCreateTextRenderer(dc.getTextRendererCache(), this.defaultFont); Rectangle2D nameBound = textRenderer.getBounds(text); int x = (int) (screenPoint.x() - nameBound.getWidth() / 2d); int y = (int) screenPoint.y(); textRenderer.begin3DRendering(); textRenderer.setColor(this.getBackgroundColor(this.color)); textRenderer.draw(text, x + 1, y - 1); textRenderer.setColor(this.color); textRenderer.draw(text, x, y); textRenderer.end3DRendering(); }
/** * Add a vertex to the polygon's outer boundary. * * @param mousePoint the point at which the mouse was clicked. The new vertex will be placed as * near as possible to this point, at the elevation of the polygon. */ protected void addVertex(Point mousePoint) { // Try to find the edge that is closest to a ray passing through the screen point. We're trying // to determine // the user's intent as to which edge a new two control points should be added to. Line ray = this.wwd.getView().computeRayFromScreenPoint(mousePoint.getX(), mousePoint.getY()); Vec4 pickPoint = this.intersectPolygonAltitudeAt(ray); double nearestDistance = Double.MAX_VALUE; int newVertexIndex = 0; // Loop through the control points and determine which edge is closest to the pick point for (int i = 0; i < this.controlPoints.size(); i++) { ControlPointMarker thisMarker = (ControlPointMarker) this.controlPoints.get(i); ControlPointMarker nextMarker = (ControlPointMarker) this.controlPoints.get((i + 1) % this.controlPoints.size()); Vec4 pointOnEdge = AirspaceEditorUtil.nearestPointOnSegment(thisMarker.point, nextMarker.point, pickPoint); if (!AirspaceEditorUtil.isPointBehindLineOrigin(ray, pointOnEdge)) { double d = pointOnEdge.distanceTo3(pickPoint); if (d < nearestDistance) { newVertexIndex = i + 1; nearestDistance = d; } } } Position newPosition = this.wwd.getModel().getGlobe().computePositionFromPoint(pickPoint); // Copy the outer boundary list ArrayList<Position> positionList = new ArrayList<Position>(this.controlPoints.size()); for (LatLon position : this.getPolygon().getOuterBoundary()) { positionList.add((Position) position); } // Add the new vertex positionList.add(newVertexIndex, newPosition); this.getPolygon().setOuterBoundary(positionList); }
/** * Computes the lat/lon of the pickPoint over the world map * * @param dc the current <code>DrawContext</code> * @param locationSW the screen location of the bottom left corner of the map * @param mapSize the world map screen dimension in pixels * @return the picked Position */ protected Position computePickPosition(DrawContext dc, Vec4 locationSW, Dimension mapSize) { Position pickPosition = null; Point pickPoint = dc.getPickPoint(); if (pickPoint != null) { Rectangle viewport = dc.getView().getViewport(); // Check if pickpoint is inside the map if (pickPoint.getX() >= locationSW.getX() && pickPoint.getX() < locationSW.getX() + mapSize.width && viewport.height - pickPoint.getY() >= locationSW.getY() && viewport.height - pickPoint.getY() < locationSW.getY() + mapSize.height) { double lon = (pickPoint.getX() - locationSW.getX()) / mapSize.width * 360 - 180; double lat = (viewport.height - pickPoint.getY() - locationSW.getY()) / mapSize.height * 180 - 90; double pickAltitude = 1000e3; pickPosition = new Position(Angle.fromDegrees(lat), Angle.fromDegrees(lon), pickAltitude); } } return pickPosition; }
/** * 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); }
protected void drawIcon(DrawContext dc) { if (this.getIconFilePath() == null) return; GL gl = dc.getGL(); OGLStackHandler ogsh = new OGLStackHandler(); try { // Initialize texture if necessary Texture iconTexture = dc.getTextureCache().getTexture(this.getIconFilePath()); if (iconTexture == null) { this.initializeTexture(dc); iconTexture = dc.getTextureCache().getTexture(this.getIconFilePath()); if (iconTexture == null) { String msg = Logging.getMessage("generic.ImageReadFailed"); Logging.logger().finer(msg); return; } } gl.glDisable(GL.GL_DEPTH_TEST); double width = this.getScaledIconWidth(); double height = this.getScaledIconHeight(); // Load a parallel projection with xy dimensions (viewportWidth, viewportHeight) // into the GL projection matrix. java.awt.Rectangle viewport = dc.getView().getViewport(); ogsh.pushProjectionIdentity(gl); double maxwh = width > height ? width : height; gl.glOrtho(0d, viewport.width, 0d, viewport.height, -0.6 * maxwh, 0.6 * maxwh); // Translate and scale ogsh.pushModelviewIdentity(gl); double scale = this.computeScale(viewport); Vec4 locationSW = this.computeLocation(viewport, scale); gl.glTranslated(locationSW.x(), locationSW.y(), locationSW.z()); // Scale to 0..1 space gl.glScaled(scale, scale, 1); gl.glScaled(width, height, 1d); if (!dc.isPickingMode()) { gl.glEnable(GL.GL_BLEND); gl.glBlendFunc(GL.GL_SRC_ALPHA, GL.GL_ONE_MINUS_SRC_ALPHA); // Draw background color behind the map gl.glColor4ub( (byte) this.backColor.getRed(), (byte) this.backColor.getGreen(), (byte) this.backColor.getBlue(), (byte) (this.backColor.getAlpha() * this.getOpacity())); dc.drawUnitQuad(); // Draw world map icon gl.glColor4d(1d, 1d, 1d, this.getOpacity()); gl.glEnable(GL.GL_TEXTURE_2D); iconTexture.bind(); TextureCoords texCoords = iconTexture.getImageTexCoords(); dc.drawUnitQuad(texCoords); gl.glBindTexture(GL.GL_TEXTURE_2D, 0); gl.glDisable(GL.GL_TEXTURE_2D); // Draw crosshair for current location gl.glLoadIdentity(); gl.glTranslated(locationSW.x(), locationSW.y(), locationSW.z()); // Scale to width x height space gl.glScaled(scale, scale, 1); // Set color float[] colorRGB = this.color.getRGBColorComponents(null); gl.glColor4d(colorRGB[0], colorRGB[1], colorRGB[2], this.getOpacity()); // Draw crosshair Position groundPos = this.computeGroundPosition(dc, dc.getView()); if (groundPos != null) { int x = (int) (width * (groundPos.getLongitude().degrees + 180) / 360); int y = (int) (height * (groundPos.getLatitude().degrees + 90) / 180); int w = 10; // cross branch length // Draw gl.glBegin(GL.GL_LINE_STRIP); gl.glVertex3d(x - w, y, 0); gl.glVertex3d(x + w + 1, y, 0); gl.glEnd(); gl.glBegin(GL.GL_LINE_STRIP); gl.glVertex3d(x, y - w, 0); gl.glVertex3d(x, y + w + 1, 0); gl.glEnd(); } // Draw view footprint in map icon space if (this.showFootprint) { this.footPrintPositions = this.computeViewFootPrint(dc, 32); if (this.footPrintPositions != null) { gl.glBegin(GL.GL_LINE_STRIP); LatLon p1 = this.footPrintPositions.get(0); for (LatLon p2 : this.footPrintPositions) { int x = (int) (width * (p2.getLongitude().degrees + 180) / 360); int y = (int) (height * (p2.getLatitude().degrees + 90) / 180); // Draw if (LatLon.locationsCrossDateline(p1, p2)) { int y1 = (int) (height * (p1.getLatitude().degrees + 90) / 180); gl.glVertex3d(x < width / 2 ? width : 0, (y1 + y) / 2, 0); gl.glEnd(); gl.glBegin(GL.GL_LINE_STRIP); gl.glVertex3d(x < width / 2 ? 0 : width, (y1 + y) / 2, 0); } gl.glVertex3d(x, y, 0); p1 = p2; } gl.glEnd(); } } // Draw 1px border around and inside the map gl.glBegin(GL.GL_LINE_STRIP); gl.glVertex3d(0, 0, 0); gl.glVertex3d(width, 0, 0); gl.glVertex3d(width, height - 1, 0); gl.glVertex3d(0, height - 1, 0); gl.glVertex3d(0, 0, 0); gl.glEnd(); } else { // Picking this.pickSupport.clearPickList(); this.pickSupport.beginPicking(dc); // Where in the world are we picking ? Position pickPosition = computePickPosition( dc, locationSW, new Dimension((int) (width * scale), (int) (height * scale))); Color color = dc.getUniquePickColor(); int colorCode = color.getRGB(); this.pickSupport.addPickableObject(colorCode, this, pickPosition, false); gl.glColor3ub((byte) color.getRed(), (byte) color.getGreen(), (byte) color.getBlue()); dc.drawUnitQuad(); this.pickSupport.endPicking(dc); this.pickSupport.resolvePick(dc, dc.getPickPoint(), this); } } finally { dc.restoreDefaultDepthTesting(); dc.restoreDefaultCurrentColor(); if (dc.isPickingMode()) dc.restoreDefaultBlending(); ogsh.pop(gl); } }
public static double[] invertBilinear(Vec4 U, Vec4 X, Vec4 Y, Vec4 Z, Vec4 W) { Vec4 s1 = W.subtract3(X); Vec4 s2 = Z.subtract3(Y); Vec4 UminX = U.subtract3(X); Vec4 UminY = U.subtract3(Y); Vec4 normal = Z.subtract3(X).cross3(W.subtract3(Y)); double A = s1.cross3(s2).dot3(normal); double B = s2.cross3(UminX).dot3(normal) - s1.cross3(UminY).dot3(normal); double C = UminX.cross3(UminY).dot3(normal); double descriminant = B * B - 4d * A * C; if (descriminant < 0) return null; descriminant = Math.sqrt(descriminant); double beta = B > 0 ? (-B - descriminant) / (2d * A) : 2d * C / (-B + descriminant); Vec4 Sbeta1 = Vec4.mix3(beta, X, W); Vec4 Sbeta2 = Vec4.mix3(beta, Y, Z); double alpha = U.subtract3(Sbeta1).dot3(Sbeta2.subtract3(Sbeta1)) / Sbeta2.subtract3(Sbeta1).dotSelf3(); return new double[] {alpha, beta}; }
// Rendering public void draw(DrawContext dc) { GL gl = dc.getGL(); boolean attribsPushed = false; boolean modelviewPushed = false; boolean projectionPushed = false; try { gl.glPushAttrib( GL.GL_DEPTH_BUFFER_BIT | GL.GL_COLOR_BUFFER_BIT | GL.GL_ENABLE_BIT | GL.GL_TEXTURE_BIT | GL.GL_TRANSFORM_BIT | GL.GL_VIEWPORT_BIT | GL.GL_CURRENT_BIT); attribsPushed = true; gl.glDisable(GL.GL_TEXTURE_2D); // no textures gl.glEnable(GL.GL_BLEND); gl.glBlendFunc(GL.GL_SRC_ALPHA, GL.GL_ONE_MINUS_SRC_ALPHA); gl.glDisable(GL.GL_DEPTH_TEST); double width = this.size.width; double height = this.size.height; // Load a parallel projection with xy dimensions (viewportWidth, viewportHeight) // into the GL projection matrix. java.awt.Rectangle viewport = dc.getView().getViewport(); gl.glMatrixMode(javax.media.opengl.GL.GL_PROJECTION); gl.glPushMatrix(); projectionPushed = true; gl.glLoadIdentity(); double maxwh = width > height ? width : height; gl.glOrtho(0d, viewport.width, 0d, viewport.height, -0.6 * maxwh, 0.6 * maxwh); gl.glMatrixMode(GL.GL_MODELVIEW); gl.glPushMatrix(); modelviewPushed = true; gl.glLoadIdentity(); // Scale to a width x height space // located at the proper position on screen double scale = this.computeScale(viewport); Vec4 locationSW = this.computeLocation(viewport, scale); gl.glTranslated(locationSW.x(), locationSW.y(), locationSW.z()); gl.glScaled(scale, scale, 1); // Compute scale size in real world Position referencePosition = dc.getViewportCenterPosition(); if (referencePosition != null) { Vec4 groundTarget = dc.getGlobe().computePointFromPosition(referencePosition); Double distance = dc.getView().getEyePoint().distanceTo3(groundTarget); this.pixelSize = dc.getView().computePixelSizeAtDistance(distance); Double scaleSize = this.pixelSize * width * scale; // meter String unitLabel = "m"; if (this.unit.equals(UNIT_METRIC)) { if (scaleSize > 10000) { scaleSize /= 1000; unitLabel = "Km"; } } else if (this.unit.equals(UNIT_IMPERIAL)) { scaleSize *= 3.280839895; // feet unitLabel = "ft"; if (scaleSize > 5280) { scaleSize /= 5280; unitLabel = "mile(s)"; } } // Rounded division size int pot = (int) Math.floor(Math.log10(scaleSize)); if (!Double.isNaN(pot)) { int digit = Integer.parseInt(String.format("%.0f", scaleSize).substring(0, 1)); double divSize = digit * Math.pow(10, pot); if (digit >= 5) divSize = 5 * Math.pow(10, pot); else if (digit >= 2) divSize = 2 * Math.pow(10, pot); double divWidth = width * divSize / scaleSize; // Draw scale if (!dc.isPickingMode()) { // Set color using current layer opacity Color backColor = this.getBackgroundColor(this.color); float[] colorRGB = backColor.getRGBColorComponents(null); gl.glColor4d( colorRGB[0], colorRGB[1], colorRGB[2], (double) backColor.getAlpha() / 255d * this.getOpacity()); gl.glTranslated((width - divWidth) / 2, 0d, 0d); this.drawScale(dc, divWidth, height); colorRGB = this.color.getRGBColorComponents(null); gl.glColor4d(colorRGB[0], colorRGB[1], colorRGB[2], this.getOpacity()); gl.glTranslated(-1d / scale, 1d / scale, 0d); this.drawScale(dc, divWidth, height); // Draw label String label = String.format("%.0f ", divSize) + unitLabel; gl.glLoadIdentity(); gl.glDisable(GL.GL_CULL_FACE); drawLabel( dc, label, locationSW.add3( new Vec4(divWidth * scale / 2 + (width - divWidth) / 2, height * scale, 0))); } else { // Picking this.pickSupport.clearPickList(); this.pickSupport.beginPicking(dc); // Draw unique color across the map Color color = dc.getUniquePickColor(); int colorCode = color.getRGB(); // Add our object(s) to the pickable list this.pickSupport.addPickableObject(colorCode, this, referencePosition, false); gl.glColor3ub((byte) color.getRed(), (byte) color.getGreen(), (byte) color.getBlue()); gl.glTranslated((width - divWidth) / 2, 0d, 0d); this.drawRectangle(dc, divWidth, height); // Done picking this.pickSupport.endPicking(dc); this.pickSupport.resolvePick(dc, dc.getPickPoint(), this); } } } } finally { if (projectionPushed) { gl.glMatrixMode(GL.GL_PROJECTION); gl.glPopMatrix(); } if (modelviewPushed) { gl.glMatrixMode(GL.GL_MODELVIEW); gl.glPopMatrix(); } if (attribsPushed) gl.glPopAttrib(); } }