[EN] Geodesic Parallel Hatching

Parallel hatching sounds simple: draw evenly spaced parallel lines and clip them to a polygon. In practice, it becomes a geometry, projection, and performance problem, especially when you need:
- Meter-accurate spacing
- Arbitrary bearings
- Concave polygon support
- Frontend responsiveness
This implementation solves those constraints using Turf.js and spherical math, while remaining UI-safe for interactive maps.
Design Goals
The solution prioritizes:
- Geodesic correctness (meters, not degrees)
- Bearing-aware generation
- Accurate clipping for concave polygons
- Performance guardrails for large shapes
- Leaflet / GeoJSON input flexibility
It deliberately avoids naive degree-based shifting, which breaks at higher latitudes and rotated bearings.
Core Strategy
The approach consists of four stages:
- Normalize Everything
- Work in Meters Using Spherical Math
- Compute Hatch Span via Perpendicular Projection
- Generate → Intersect → Slice
Normalize Everything
Polygon inputs can arrive in many forms:
- [lon, lat][]
- L.LatLng[]
- Nested rings
- Lat/Lng objects
The algorithm first normalizes everything into a closed [lon, lat] outer ring. This prevents geometry errors later and ensures Turf receives a valid polygon.
This is a necessary precondition for reliable spatial operations.
Work in Meters Using Spherical Math
Instead of shifting longitude/latitude directly, lines are generated using a spherical destination formula:
destinationM(origin, distanceMeters, bearingDeg)
This ensures:
- Accurate spacing in meters
- Global correctness
- Stable rotation behavior
Relying on planar assumptions could silently distort the result. This one does not.
Compute Hatch Span via Perpendicular Projection
Rather than sweeping the entire bounding box, the algorithm:
- Computes polygon bounding box
- Finds its center
- Projects bbox corners onto the perpendicular axis
- Determines minimum and maximum perpendicular distance
This gives the exact span required to fully cover the polygon at the requested bearing. That avoids generating unnecessary lines.
Generate → Intersect → Slice
For each hatch line:
- Create a long geodesic segment across the polygon extent.
- Compute intersections with the polygon.
- Sort intersections along the line.
- Pair them sequentially.
- Slice segments between entry/exit pairs.
Pairing intersections ([0-1], [2-3], ...) correctly handles concave shapes.
No assumptions about convexity are made.
Tradeoffs
Why not project to Web Mercator or UTM?
A planar projection would be faster.
However:
- It introduces projection distortion
- Requires reprojection logic
- Adds complexity
This implementation favors correctness + simplicity over maximum theoretical performance.
For frontend-scale applications, that’s the right trade.
Scaling and Refactor
For high res polygon (1000+ vertices), extreme small step values (< 5m), then projected planar geometry engine combined with server-side batch processing at massive scale.
Source
https://gist.github.com/purnamasari/89faf6ba248fb5e838a31d121c0465b1