2016-02-14 41 views
6

Vedo quello che sembra essere il comportamento contraddittorio di WorldWind Sphere -Linea logica intersezione. Creo una sfera e una linea e si intersecano, ma poi l'intersezione restituisce null (codice di scansione per il commento: // *** Qui è dove arriva whacky).WorldWind Sphere Line Intersection Bug?

Ecco che cosa sta succedendo visivamente (la linea è grigia che è lì, ma difficile da vedere): 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); 

    } 
} 

E qui sono le dipendenze ho dichiarato di ottenere WorldWind nel mio progetto Maven (ho anche fatto provare versione '2.0.0-986', ma che non sembra aiutare):

<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> 

per essere completamente accurata, ecco le importazioni di codice:

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

Il POC tecnico principale di worldwind è stato contattato e ha dichiarato che questo errore verrà inserito nella coda per essere riparato. Grazie per il tuo aiuto Chris e Kyle :) –

risposta

2

Se si guarda all'implementazione di Sphere#intersect(), si aspetta la linea in coordinate centrate all'origine della sfera (non quella della Terra) che è quasi certamente un bug. Si dovrebbe essere in grado di fare:

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); 

Tenete a mente che le intersezioni restituiti sono ancora in coordinate cartesiane centrato all'origine della sfera, in modo da trasformare di nuovo al World Wind cartesiana che devi fare:

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

L'implementazione considera inoltre che la linea sia infinitamente lunga, quindi restituirà due punti, non uno.

Sarebbe piuttosto semplice implementare la propria versione di intersect() che funziona in coordinate normali e tiene conto della lunghezza della linea, vedere here.

+0

@Chris_K se sei disponibile/interessato ad aiutare a scrivere alcune efficienti routine di geometria computazionale WGS-84 per favore mandami un messaggio, dovrei essere facile da trovare su FB, Twitter, LinkedIn, eccetera. –

2

Se si guarda alla Worldwind source code, in particolare i interseca() e si intersecano() metodi della classe Sphere e passo attraverso di loro con il codice come input, si vede il seguente:

Il metodo:

public boolean intersects(Line line) 

restituisce true perché la distanza dal centro della sfera alla linea è inferiore al raggio della sfera, come previsto.

Per il metodo:

public final Intersection[] intersect(Line line) 

risulta che la discriminante quadratica è minore di zero (cioè ci sono vere radici dell'equazione quadratica - due radici complesse distinti).

Il riferimento API WorldWind è here.

I metodi specifici coinvolti sono:

/** 
* 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; 
} 

e:

/** 
* 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)}; 
    } 
} 

che utilizza:

/** 
* 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 questo caso il codice non riesce il:

if (discriminant < 0) 
test

.

Sembra che sia stato un po 'lento nel rispondere a questa domanda, e nel frattempo è stato sottolineato da Chris K che ciò è dovuto al metodo intersect() che prevede che le coordinate della linea siano centrate sul origine della sfera e non della Terra.

Come ha detto Chris K, questo sembra essere un bug e probabilmente dovrebbe essere registrato con i manutentori di questo codice sorgente.