Search code examples
javacomputational-geometryintersectionworldwind

WorldWind Sphere Line Intersection Bug?


I'm seeing what appears to be contradictory behavior out of WorldWind's Sphere-Line intersection logic. I create a Sphere and Line and they intersect but then the intersection returns null (scan code for comment: // *** This is where it gets whacky).

Here is what's going on visually (the line is gray it's there but hard to see): 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);

    }
}

And here are the dependencies I declared to get WorldWind into my maven project (I also did try version '2.0.0-986', but that didn't seem to help):

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

To be completely thorough, here are the code imports:

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;

Solution

  • If you look at the implementation of Sphere#intersect() it is expecting the line in coordinates centered at the sphere's origin (not the Earth's) which is almost certainly a bug. You should be able to do:

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

    Keep in mind that the intersections returned are still in Cartesian coordinates centered at the sphere's origin, so to transform them back to World Wind Cartesian you need to do:

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

    The implementation also considers the line to be infinitely long so it will return two points, not one.

    It would be pretty straight forward to implement your own version of intersect() that works in normal coordinates and takes into account the length of the line, see here.