[EN] Geodesic Parallel Hatching

Parallel lines hatched in polygon

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:

  1. Normalize Everything
  2. Work in Meters Using Spherical Math
  3. Compute Hatch Span via Perpendicular Projection
  4. 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:

  1. Create a long geodesic segment across the polygon extent.
  2. Compute intersections with the polygon.
  3. Sort intersections along the line.
  4. Pair them sequentially.
  5. 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