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

Open
#328 3 comments 0 reactions 1 assignee View on GitHub

@DavidHollman is already working on this.

Since Sep 8, 2026.

Assessment

This issue has not been assessed yet.

Description

bug fixed_to_verify

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
Dominant language
Java
Stars
710
Forks
268
Avg merge
7d 23h
Merged PRs (30d)
1

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from Esri/geometry-api-java

All issues in Esri/geometry-api-java

Similar issues

More Java issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.