Esri / Esri/geometry-api-java

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

Open
#328 3 comments 0 reactions 1 assignee Claimed by @DavidHollman View on GitHub
bug fixed_to_verify
Dominant language
Java
Stars
710
Forks
269
Avg merge
7d 23h
Merged PRs (30d)
1

Description

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:

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

```text
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.

```csharp
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:

```text
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:

```csharp
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:

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

This reports `true` for the failing closed-path case.

### Reversing `p2` still fails

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

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

## Observed stack location

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

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.