Skip to content

Bring back some old AreaTree concepts when preparing BL and FoW - #5355

Merged
cwisniew merged 4 commits into
RPTools:developfrom
kwvanderlinde:bugfix/5159-bring-back-AreaTree-for-polygonizing-Area
Apr 8, 2025
Merged

Bring back some old AreaTree concepts when preparing BL and FoW#5355
cwisniew merged 4 commits into
RPTools:developfrom
kwvanderlinde:bugfix/5159-bring-back-AreaTree-for-polygonizing-Area

Conversation

@kwvanderlinde

@kwvanderlinde kwvanderlinde commented Apr 7, 2025

Copy link
Copy Markdown
Collaborator

Identify the Bug or Feature request

Fixes #5159

Description of the Change

First, some history:

  • In 1.12, we started restricting pathfinding to exposed FoW areas, converting these areas to JTS Geometry in the same way as MBL was already.
  • In 1.13, the MBL and FoW areas were converted to Geometry using GeometryUtil.toJts(), which was based on JTS Polygonizer for simplicity.
  • In 1.14 and prior, we used an AreaTree representation of *BL for vision and lighting that was based on a hierarchy of oceans (clear space) and islands (filled space). Converting from Area to AreaTree was done through custom logic that detected the orientation of each ring in the Area.
  • In 1.15, we still used the AreaTree for *BL, but built it using JTS's Polygonizer as it was faster and simpler. This is the same polygonizer used for pathfinding since 1.13.
  • In 1.16, we no longer built an entire AreaTree, but let each island live on its own as a JTS Polygon. Buillding these polygons was still based on the Polygonizer as in 1.15.

Since 1.15 especially, we've had various reports of existing VBL and FoW breaking pathfinding and vision. Despite trying to tune the Polygonizer to fix these reports, cases have continued to be reported..

In an attempt to fix these issues, I've added several new test cases that are based on real-world issues encountered in recent MT versions. I tried a wide range of techniques to produce acceptable results for all of these cases, but I could not get any Polygonizer-based solution to work - different cases needed different incompatible fixes to be applid. And JTS's Polygonizer itself is not interested in (or is not capable of) preserving the specific structures that we rely on (nested polygons).

In the end, I just removed the Polygonizer from GeometryUtil.toJts() and GeometryUtil.toJtsPolygons() and went back to the custom logic we used to use when building AreaTree. We don't build an entire tree as that would be quite wasteful, and we're not reintroducing any of the related types that have long been removed. We are only incorporating just enough of the concept to produce Polygon objects from an Area:

  1. Every clockwise ring is considered an island boundary.
  2. Every counterclockwise ring is considered an ocean boundary.
  3. Each ocean is attached to the smallest parent island containing the ocean (there is no global ocean in this concept).
  4. Islands are not attached to any parent (we could do this, but it would be wasteful as mentioned above).

Once all oceans are associated with their parent islands, we convert each island into a Polygon. At this point, the resulting geometry is structurally valid, but there can still be small defects with the boundary of any given polygon or its holes. To address this, we pipe the polygon through a GeometryPrecisionReducer that will remove any ultra-precise defects from a polygon, possibly dividing an invalid polygon into more than one valid polygon.

There is finally a change to MovementBlockingTopology to filter out empty geometry as this can cause issues witth PreparedGeometry.

Possible Drawbacks

Hopefully none as this seems to work for more cases than ever. But it's possible there is some other existing combination of VBL, MBL and FoW that will still cause issues.

Documentation Notes

N/A

Release Notes

  • Modified how we handle vision and fog-of-war geometry to avoid problematic cases.

This change is Reviewable

These new test cases focus on extremely precise geometry that includes self intersections with small and large loops,
interior rings being near or touching exterior rings, and also a test that bounding boxes aren't used as the only
determinant for whether one ring is contained in another.
- `s/areaProvider2/areaProvider/`
- Avoid `Arguments.of(Named.of("name", first), ...)`, use flatter `Arguments.argumentSet("name", ...)`.
This is inspired by and based on our original `AreaTree` / `AreaMeta` construction from 1.14 and earlier. For each
clockwise ring, we construct a `GeometryUtil.Island` to represent the solid portion of the geometry. For each
counterclockwise ring, we treat it as an ocean. After retrieving all islands and oceans, we stitch each ocean to each
island as an interior polygonal ring. Once all oceans are connected to islands, we convert each island to a JTS
`Polygon`.

Differences from the original `AreaTree` construction are:
1. No need to build an entire tree. We only connect oceans to parent islands, but we do not care about connecting
   islands to parent oceans. Each island with their child oceans becomes a polygon.
2. The resulting polygons are run through a `GeometryPrecisionReducer` so callers will not need to worry about
   ultra-precise points. This reducer internally ensures the results remain valid, e.g., by eliminating mistaken
   self-intersections that would cause confusion about interior and exterior points.
`PreparedGeometry` does not handle empty geometries at all, despite no documentation suggesting this should be anything
special. We now make sure to filter out empty geometries and won't bother preparing them.
@kwvanderlinde kwvanderlinde self-assigned this Apr 7, 2025
@github-actions github-actions Bot added the bug label Apr 7, 2025
@kwvanderlinde kwvanderlinde moved this from Todo to Awaiting-Review in MapTool 1.18 Apr 7, 2025
@github-project-automation github-project-automation Bot moved this from Awaiting-Review to To-Be-Merged in MapTool 1.18 Apr 8, 2025
@cwisniew
cwisniew added this pull request to the merge queue Apr 8, 2025
Merged via the queue into RPTools:develop with commit bbbac1a Apr 8, 2025
@github-project-automation github-project-automation Bot moved this from To-Be-Merged to Merged in MapTool 1.18 Apr 8, 2025
@kwvanderlinde
kwvanderlinde deleted the bugfix/5159-bring-back-AreaTree-for-polygonizing-Area branch April 8, 2025 03:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

Status: Merged

Development

Successfully merging this pull request may close these issues.

[Bug]: Movement distance not shown in player mode (either server client or "show as player")

2 participants