Skip to content

GeometryEngine.Difference throws GeometryException: internal error for closed polyline touching endpoint #328

Description

@DavidHollman

I've been using the project https://github.com/EchoParkLabs/geometry-api-cs which seems to be derived from here. Hopefully this report is still useful even though its not the same codebase.

Summary

com.epl.geometry.GeometryEngine.Difference() throws

  • com.epl.geometry.GeometryException: internal error

when subtracting a two-point polyline from a multi-path polyline whose first path is closed and shares its start/end vertex with the subtractor.

The two geometries only touch at one endpoint. GeometryEngine.Intersect reports an empty result for this case. Removing the duplicate closing vertex from the first path makes Difference succeed.

Minimal failing geometry

p1

p1 contains two paths. The first path is closed because its final point repeats its initial point:

MULTILINESTRING (
  (
    117422 -64366,
    119336 -64652,
    119218 -65440,
    114999 -64810,
    115034 -64578,
    115117 -64022,
    117422 -64366
  ),
  (
    111611 -62617,
    111365 -64268,
    110476 -64135,
    110722 -62484,
    110975 -62522,
    111611 -62617
  )
)

p2

MULTILINESTRING (
  (
    117422 -64366,
    117911 -61089
  )
)

The first point of p2 equals both the first and final point of the first path in p1.

Minimal C# reproduction

This code targets .NET Framework 4.8 and references geometry-api-cs. The code below uses only the failing first path; adding the second path from p1 above also fails.

using System;
using com.epl.geometry;

internal static class Program
{
    private static void Main()
    {
        var p1 = CreatePolyline(new[]
        {
            (117422, -64366),
            (119336, -64652),
            (119218, -65440),
            (114999, -64810),
            (115034, -64578),
            (115117, -64022),
            (117422, -64366)
        });

        var p2 = CreatePolyline(new[]
        {
            (117422, -64366),
            (117911, -61089)
        });

        try
        {
            var result = GeometryEngine.Difference(p1, p2, null);
            Console.WriteLine("Difference succeeded: " + !result.IsEmpty());
        }
        catch (Exception exception)
        {
            Console.WriteLine(exception.GetType().FullName);
            Console.WriteLine(exception.Message);
        }
    }

    private static Polyline CreatePolyline((int X, int Y)[] points)
    {
        var polyline = new Polyline();
        polyline.StartPath(new Point(points[0].X, points[0].Y));

        for (var i = 1; i < points.Length; i++)
        {
            polyline.LineTo(new Point(points[i].X, points[i].Y));
        }

        return polyline;
    }
}

Expected output:

com.epl.geometry.GeometryException
internal error

Control cases

Open first path succeeds

Changing p1 so its first path does not repeat its initial point causes Difference to succeed:

var p1 = CreatePolyline(new[]
{
    (117422, -64366),
    (119336, -64652),
    (119218, -65440),
    (114999, -64810),
    (115034, -64578),
    (115117, -64022)
});

Intersection reports no overlap

The geometries only meet at the shared endpoint:

var intersection = GeometryEngine.Intersect(p1, p2, null);
Console.WriteLine(intersection.IsEmpty());

This reports true for the failing closed-path case.

Reversing p2 still fails

var p2Reversed = CreatePolyline(new[]
{
    (117911, -61089),
    (117422, -64366)
});

Difference(p1, p2Reversed, null) also throws GeometryException: internal error.

Observed stack location

com.epl.geometry.TopologicalOperations.RestorePolylineParts_
com.epl.geometry.TopologicalOperations.TopoOperationPolylinePolylineOrPolygon_
com.epl.geometry.TopologicalOperations.Difference
com.epl.geometry.TopologicalOperations.Difference
com.epl.geometry.OperatorDifferenceLocal.Difference
com.epl.geometry.OperatorDifferenceCursor.Next
com.epl.geometry.OperatorDifferenceLocal.Execute
com.epl.geometry.GeometryEngine.Difference

Environment / Misc details

  • Operating system: Windows
  • Runtime: .NET Framework 4.8
  • Spatial reference: null

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions