2016-02-14 12 views
6

Ich sehe, was scheint widersprüchliches Verhalten aus WorldWind Sphere -Line Schnittpunktlogik. Ich erstelle eine Kugel und eine Linie und sie schneiden sich, aber dann gibt die Schnittmenge null zurück (Scan-Code für Kommentar: // *** Dies ist, wo es verrückt wird).WorldWind Sphere Line Intersection Bug?

ist hier, was visuell vor sich geht (die Linie ist grau, es ist da, aber schwer zu sehen): Sphere-Line Intersecting

public class WWTest extends ApplicationTemplate { 

    public static class VisualizationFrame extends ApplicationTemplate.AppFrame { 

     public VisualizationFrame() { 
      super(new Dimension(1200, 1024)); 
      final Globe globe = getWwd().getModel().getGlobe(); 

      //Create a sphere at 0,0 on the surface of the Earth wtih a 60 NMi radius 
      final Vec4 sphereCenter = globe.computePointFromLocation(LatLon.ZERO); 
      final Sphere sphere = new Sphere(sphereCenter, 111120); 
      // Draw the sphere 
      final RenderableLayer sphereLayer = new RenderableLayer(); 
      sphereLayer.addRenderable(sphere); 

      final RenderableLayer pathLayer = new RenderableLayer(); 
      // Create a line at 10k feet (3048 meters) that starts outside the sphere at (2,-2) and proceeds into the sphere at (0.5, 0.5) 
      final Position lineStart = Position.fromDegrees(2, -2, 3048); 
      final Position lineEnds = Position.fromDegrees(0.5, 0.5, 3048); 
      final Path asPath = new Path(lineStart, lineEnds); 
      pathLayer.addRenderable(asPath); 

      // Now that we've visualized the line, let's do some intersection math 
      final Vec4 lineStartsAsVec = globe.computePointFromPosition(lineStart); 
      final Vec4 lineEndsAsVec = globe.computePointFromPosition(lineEnds); 
      final Line asLine = Line.fromSegment(lineStartsAsVec, lineEndsAsVec); 

      // *** This is where it gets whacky - true, but no intersection? 
      final boolean doesIntersect = sphere.intersects(asLine); 
      final Intersection[] intersection = sphere.intersect(asLine); 
      //outputs: Intersection found: null 
      System.out.println(doesIntersect ? "Intersection found: " + Arrays.toString(intersection) : "No intersection, Why Not!?!?"); 

      insertBeforeCompass(getWwd(), sphereLayer); 
      insertBeforeCompass(getWwd(), pathLayer); 
      getWwd().getView().setEyePosition(Position.fromDegrees(0, 0, 500_000)); 
      getLayerPanel().update(getWwd()); 
     } 
    } 

    public static void main(String[] args) { 
     ApplicationTemplate.start("World Wind Sphere-Line Intersection", VisualizationFrame.class); 

    } 
} 

Und hier sind die Abhängigkeiten ich erklärte World in mein Maven Projekt zu bekommen (ich habe auch versuchen Version '2.0.0-986', aber das schien nicht zu helfen):

<dependency> 
    <groupId>gov.nasa</groupId> 
    <artifactId>worldwind</artifactId> 
    <version>2.0.0</version> 
</dependency> 
<dependency> 
    <groupId>gov.nasa</groupId> 
    <artifactId>worldwindx</artifactId> 
    <version>2.0.0</version> 
</dependency> 
<dependency> 
    <groupId>org.jogamp.gluegen</groupId> 
    <artifactId>gluegen-rt-main</artifactId> 
    <version>2.2.4</version> 
</dependency> 
<dependency> 
    <groupId>org.jogamp.jogl</groupId> 
    <artifactId>jogl-all-main</artifactId> 
    <version>2.2.4</version> 
</dependency> 

um ganz gründlich zu sein, hier sind die Code-Importe:

import gov.nasa.worldwind.geom.Intersection; 
import gov.nasa.worldwind.geom.LatLon; 
import gov.nasa.worldwind.geom.Line; 
import gov.nasa.worldwind.geom.Position; 
import gov.nasa.worldwind.geom.Sphere; 
import gov.nasa.worldwind.geom.Vec4; 
import gov.nasa.worldwind.globes.Globe; 
import gov.nasa.worldwind.layers.RenderableLayer; 
import gov.nasa.worldwind.render.Path; 
import gov.nasa.worldwindx.examples.ApplicationTemplate; 
import static gov.nasa.worldwindx.examples.ApplicationTemplate.insertBeforeCompass; 
import java.awt.Dimension; 
import java.util.Arrays; 
+0

Die primäre technische POC von Worldwind wurde kontaktiert und sagte, dass dieser Bug in ihre Warteschlange gesetzt werden soll, um behoben zu werden. Danke für Ihre Hilfe Chris und Kyle :) –

Antwort

2

Wenn man sich die Implementierung von Sphere#intersect() anschaut, erwartet man die Linie in Koordinaten, die am Ursprung der Kugel zentriert sind (nicht an der der Erde), was mit ziemlicher Sicherheit ein Fehler ist. Sie sollten der Lage zu tun:

final Vec4 pa = lineStartsAsVec.subtract3(sphereCenter); 
final Vec4 pb = lineEndsAsVec.subtract3(sphereCenter); 
final Line asLine2 = Line.fromSegment(pa, pb); 
final Intersection[] intersection = sphere.intersect(asLine2); 

Beachten Sie, dass die zurückgegebenen Kreuzungen sind noch in rechtwinkligen Koordinaten in der Sphäre des Ursprung zentriert, so sie zu World Wind cartesianischen Sie tun müssen, um verwandeln zurück:

final Vec4 intersectionPos = intersection[0].getIntersectionPoint().add3(sphereCenter); 

Die Implementierung betrachtet auch die Linie als unendlich lang, so dass sie zwei Punkte zurückgibt, nicht einen.

Es wäre ziemlich einfach, Ihre eigene Version von intersect() zu implementieren, die in normalen Koordinaten arbeitet und die Länge der Linie berücksichtigt, siehe here.

+0

@Chris_K Wenn Sie verfügbar sind/daran interessiert zu schreiben einige anspruchsvolle effiziente WGS-84 Computational Geometry Routinen bitte schieße mir eine Nachricht, ich sollte leicht zu finden auf FB, Twitter, LinkedIn, etc. –

2

Wenn man sich die Worldwind source code aussehen, speziell auf die intersects() und schneiden() Methoden der Sphere-Klasse und Schritt durch sie mit Ihrem Code als Eingabe, sehen Sie Folgendes:

Die Methode:

public boolean intersects(Line line) 

gibt True zurück, da der Abstand vom Kugelmittelpunkt zur Linie wie erwartet kleiner als der Radius der Kugel ist.

Für das Verfahren:

public final Intersection[] intersect(Line line) 

es stellt mich heraus, daß die Diskriminante des quadratischen kleine als Null ist (das heißt, es die quadratische Gleichung keine echten Wurzeln sind - zwei verschiedene komplexe Wurzeln).

Die WorldWind-API-Referenz lautet here.

Die spezifischen Methoden beteiligt sind:

/** 
* Tests for intersection with a <code>Line</code>. 
* 
* @param line the <code>Line</code> with which to test for intersection 
* 
* @return true if <code>line</code> intersects or makes a tangent with the surface of this <code>Sphere</code> 
* 
* @throws IllegalArgumentException if <code>line</code> is null 
*/ 
public boolean intersects(Line line) 
{ 
    if (line == null) 
    { 
     String msg = Logging.getMessage("nullValue.LineIsNull"); 
     Logging.logger().severe(msg); 
     throw new IllegalArgumentException(msg); 
    } 
    return line.distanceTo(this.center) <= this.radius; 
} 

und:

/** 
* Obtains the intersections of this sphere with a line. The returned array may be either null or of zero length if 
* no intersections are discovered. It does not contain null elements and will have a size of 2 at most. Tangential 
* intersections are marked as such. <code>line</code> is considered to have infinite length in both directions. 
* 
* @param line the <code>Line</code> with which to intersect this <code>Sphere</code> 
* 
* @return an array containing all the intersections of this <code>Sphere</code> and <code>line</code> 
* 
* @throws IllegalArgumentException if <code>line</code> is null 
*/ 
public final Intersection[] intersect(Line line) 
{ 
    if (line == null) 
    { 
     String message = Logging.getMessage("nullValue.LineIsNull"); 
     Logging.logger().severe(message); 
     throw new IllegalArgumentException(message); 
    } 

    double a = line.getDirection().getLengthSquared3(); 
    double b = 2 * line.selfDot(); 
    double c = line.getOrigin().getLengthSquared3() - this.radius * this.radius; 

    double discriminant = Sphere.discriminant(a, b, c); 
    if (discriminant < 0) 
     return null; 

    double discriminantRoot = Math.sqrt(discriminant); 
    if (discriminant == 0) 
    { 
     Vec4 p = line.getPointAt((-b - discriminantRoot)/(2 * a)); 
     return new Intersection[] {new Intersection(p, true)}; 
    } 
    else // (discriminant > 0) 
    { 
     Vec4 near = line.getPointAt((-b - discriminantRoot)/(2 * a)); 
     Vec4 far = line.getPointAt((-b + discriminantRoot)/(2 * a)); 
     return new Intersection[] {new Intersection(near, false), new Intersection(far, false)}; 
    } 
} 

, die verwendet:

/** 
* Calculates a discriminant. A discriminant is useful to determine the number of roots to a quadratic equation. If 
* the discriminant is less than zero, there are no roots. If it equals zero, there is one root. If it is greater 
* than zero, there are two roots. 
* 
* @param a the coefficient of the second order pronumeral 
* @param b the coefficient of the first order pronumeral 
* @param c the constant parameter in the quadratic equation 
* 
* @return the discriminant "b squared minus 4ac" 
*/ 
private static double discriminant(double a, double b, double c) 
{ 
    return b * b - 4 * a * c; 
} 

in diesem Fall der Code nicht das:

if (discriminant < 0) 

testen.

Es sieht so aus, als wäre ich bei der Beantwortung dieser Frage etwas langsam gewesen, und in der Zwischenzeit wurde von Chris K darauf hingewiesen, dass dies auf die intersect() - Methode zurückzuführen ist, bei der die Linienkoordinaten zentriert werden Ursprung der Sphäre und nicht der Erde.

Wie Chris K sagte, dies scheint ein Fehler zu sein und sollte wahrscheinlich mit den Betreuern dieses Quellcodes protokolliert werden.