polyfill method

  1. @override
List<BigInt> polyfill({
  1. required List<GeoCoord> coordinates,
  2. required int resolution,
  3. List<List<GeoCoord>> holes = const [],
})
override

Takes a given coordinates and resolution and returns hexagons that are contained by them.

resolution must be in the range 0, 15.

This implementation traces the GeoJSON geofence(s) in cartesian space with hexagons, tests them and their neighbors to be contained by the geofence(s), and then any newly found hexagons are used to test again until no new hexagons are found.

final hexagons = h3.polyfill(
  coordinates: const [
    GeoCoord(lat: 37.813318999983238, lon: -122.4089866999972145),
    GeoCoord(lat: 37.7866302000007224, lon: -122.3805436999997056),
    GeoCoord(lat: 37.7198061999978478, lon: -122.3544736999993603),
    GeoCoord(lat: 37.7076131999975672, lon: -122.5123436999983966),
    GeoCoord(lat: 37.7835871999971715, lon: -122.5247187000021967),
    GeoCoord(lat: 37.8151571999998453, lon: -122.4798767000009008),
  ],
  resolution: 9,
)

Implementation

@override
List<BigInt> polyfill({
  required List<GeoCoord> coordinates,
  required int resolution,
  List<List<GeoCoord>> holes = const [],
}) {
  assert(resolution >= 0 && resolution < 16,
      'Resolution must be in [0, 15] range');
  return using((arena) {
    // polygon outer boundary
    final nativeCoordinatesPointer = arena<c.GeoCoord>(coordinates.length);
    for (var i = 0; i < coordinates.length; i++) {
      final pointer = Pointer<c.GeoCoord>.fromAddress(
        nativeCoordinatesPointer.address + sizeOf<c.GeoCoord>() * i,
      );
      coordinates[i]
          .toRadians(_geoCoordConverter)
          .assignToNative(pointer.ref);
    }

    final polygon = arena<c.GeoPolygon>();
    final outergeofence = arena<c.Geofence>();

    // outer boundary
    polygon.ref.geofence = outergeofence.ref;
    polygon.ref.geofence.verts = nativeCoordinatesPointer;
    polygon.ref.geofence.numVerts = coordinates.length;

    // polygon holes
    if (holes.isNotEmpty) {
      final holesgeofencePointer = arena<c.Geofence>(holes.length);
      for (var h = 0; h < holes.length; h++) {
        final holeCoords = holes[h];

        final singleHoleGFencePointer = Pointer<c.Geofence>.fromAddress(
          holesgeofencePointer.address + sizeOf<c.Geofence>() * h,
        );

        final holeNativeCoordinatesPointer =
            arena<c.GeoCoord>(holeCoords.length);

        // assign the hole coord to holeptr
        for (var i = 0; i < holeCoords.length; i++) {
          final coordPointer = Pointer<c.GeoCoord>.fromAddress(
              holeNativeCoordinatesPointer.address +
                  sizeOf<c.GeoCoord>() * i);
          holeCoords[i]
              .toRadians(_geoCoordConverter)
              .assignToNative(coordPointer.ref);
        }

        singleHoleGFencePointer.ref.numVerts = holeCoords.length;
        singleHoleGFencePointer.ref.verts = holeNativeCoordinatesPointer;
      }

      polygon.ref.numHoles = holes.length;
      polygon.ref.holes = holesgeofencePointer;
    } else {
      polygon.ref.numHoles = 0;
      polygon.ref.holes = Pointer.fromAddress(0);
    }

    final nbIndex = _h3c.maxPolyfillSize(polygon, resolution);

    final out = arena<Uint64>(nbIndex);
    _h3c.polyfill(polygon, resolution, out);
    final list = out.asTypedList(nbIndex).toList();
    return list.where((e) => e != 0).map((e) => e.toBigInt()).toList();
  });
}