geocore 0.10.1 copy "geocore: ^0.10.1" to clipboard
geocore: ^0.10.1 copied to clipboard

Geospatial data structures (points, geometry, features, meta) and parsers (GeoJSON, WKT) for Dart.

example/geocore_example.dart

// Copyright (c) 2020-2023 Navibyte (https://navibyte.com). All rights reserved.
// Use of this source code is governed by a “BSD-3-Clause”-style license that is
// specified in the LICENSE file.
//
// Docs: https://github.com/navibyte/geospatial

// NOTE : lint rules disabled for the purpose of making sample code readable
//
// ignore_for_file: avoid_print, avoid_redundant_argument_values
// ignore_for_file: cascade_invocations, unused_local_variable
// ignore_for_file: prefer_const_constructors
// ignore_for_file: prefer_const_literals_to_create_immutables

import 'package:equatable/equatable.dart';

import 'package:geocore/geocore.dart';

/*
To test run this from command line: 

dart example/geocore_example.dart
*/

void main() {
  // configure Equatable to apply toString() default impls
  EquatableConfig.stringify = true;

  // call simple demos
  _parseGeoJSON();
  _readmeIntro();

  print('\nWrite Point values as string');
  _pointValuesAsString();

  print('\nWrite Point to different formats');
  _pointToGeoJsonAndWKT();

  print('\nFeatureCollection as GeoJSON');
  _geoJsonFeatureCollection();
}

void _parseGeoJSON() {
  print('Parse GeoJSON sample data.');

  // sample GeoJSON data
  const sample = '''
    {
      "type": "FeatureCollection",
      "features": [
        {
          "type": "Feature",
          "id": "ROG",
          "geometry": {
            "type": "Point",
            "coordinates": [-0.0014, 51.4778, 45.0]  
          },
          "properties": {
            "title": "Royal Observatory",
            "place": "Greenwich",
            "city": "London",
            "isMuseum": true,
            "code": "000",
            "founded": 1675,
            "prime": "1884-10-22", 
            "measure": 5.79
          }
        }  
      ]
    }
  ''';

  // parse FeatureCollection using a GeoJSON parser with geographic coordinates
  final format = GeoJSON();
  final parser = format.parserGeographic(geographicPoints);
  final fc = parser.featureCollection(sample);

  // loop through features and print id, geometry and properties for each
  for (final f in fc.features) {
    print('Feature with id: ${f.id}');
    print('  geometry: ${f.geometry}');
    print('  properties:');
    for (final key in f.properties.keys) {
      print('    $key: ${f.properties[key]}');
    }
  }
}

void _readmeIntro() {
  // Some samples for README
  //    (https://github.com/navibyte/geospatial/tree/main/dart/geocore).
  // Note that following samples are just created, not used, even printed.

  // -----------

  // Spatial bounds

  Bounds.of(min: Point2(x: 10.1, y: 10.1), max: Point2(x: 20.2, y: 20.2));
  Bounds.of(min: Point3i(x: 10, y: 10, z: 3), max: Point3i(x: 20, y: 20, z: 5));
  GeoBounds.bboxLonLat(-20.3, 50.2, 20.5, 60.9);

  // A feature (a geospatial entity) contains an id, a geometry and properties:

  Feature(
    id: 'ROG',
    geometry: GeoPoint3(lon: -0.0014, lat: 51.4778, elev: 45.0),
    properties: {
      'place': 'Greenwich',
      'city': 'London',
    },
  );

  // Parsing GeoJSON data.

  final geoJsonParser = GeoJSON().parserGeographic(GeoPoint3.coordinates);
  geoJsonParser.feature(
    '''
    {
      "type": "Feature",
      "id": "ROG",
      "geometry": {
        "type": "Point",
        "coordinates": [-0.0014, 51.4778, 45.0]  
      },
      "properties": {
        "place": "Greenwich",
        "city": "London"
      }
    }  
  ''',
  );

  // Parsing WKT data.

  // Parse using specific point factories for coordinates with and without M
  final wktParser = WKT().parser(Point2.coordinates, Point2m.coordinates);
  wktParser.parse('POINT (100.0 200.0)'); // => Point2;
  wktParser.parse('POINT M (100.0 200.0 5.0)'); // => Point2m;

  // Projected (or cartesian) coordinates (Point2, Point2m, Point3 or Point3m)
  WKT().parserProjected().parse('LINESTRING (200.1 500.9, 210.2 510.4)');

  // Geographic coordinates (GeoPoint2, GeoPoint2m, GeoPoint3 or GeoPoint3m)
  WKT().parserGeographic().parse(
        'POLYGON ((40 15, 50 50, 15 45, 10 15, 40 15),'
        ' (25 25, 25 40, 35 30, 25 25))',
      );

  // -----------

  // Projected point with X, Y and Z coordinates in two ways.
  Point3(x: 708221.0, y: 5707225.0, z: 45.0);
  Point3.xyz(708221.0, 5707225.0, 45.0);

  // The same point created from `Iterable<num>`.
  Point3.from([708221.0, 5707225.0, 45.0]);

  // The same point parsed from WKT compatible text.
  // Actually WKT representation would be : "POINT (708221.0 5707225.0 45.0)",
  // but this parser takes only coordinate data between paranthesis.
  Point3.parse('708221.0 5707225.0 45.0');

  // The `parse` method throws when text is invalid, but `tryParse` returns null
  // in such case. This can be utilized for fallbacks.
  Point3.tryParse('nop') ?? Point3.parse('708221.0 5707225.0 45.0');

  // The same point parsed using the WKT parser for projected geometries.
  // Here `wktProjected` is a global constant for a WKT factory implementation.
  WKT().parserProjected().parse('POINT Z (708221.0 5707225.0 45.0)');

  // -----------

  // A sample point with x, y, z and m coordinates.
  final source = Point3m.xyzm(708221.0, 5707225.0, 45.0, 123.0);

  // Return new points of the same type by changing only some coordinate values.
  source.copyWith(m: 150.0);
  source.copyWith(x: 708221.7, z: 46.2);

  // Returns a point of the same type, but no previous values are preserved
  // (result here is Point3m.xyzm(1.0, 2.0, 3.0, 0.0)) with default 0.0 for m).
  source.newWith(x: 1.0, y: 2.0, z: 3.0);

  // This returns also Point3m.xyzm(1.0, 2.0, 3.0, 0.0)).
  source.newFrom([1.0, 2.0, 3.0, 0.0]);

  // -----------

  // Geographic point with longitude, latitude, elevation and measure.
  GeoPoint3m(lon: -0.0014, lat: 51.4778, elev: 45.0, m: 123.0);
  GeoPoint3m.lonLatElevM(-0.0014, 51.4778, 45.0, 123.0);

  // Someone might want to represent latitude before longitude, it's fine too.
  GeoPoint3m.latLonElevM(51.4778, -0.0014, 45.0, 123.0);

  // When creating from value array, the order is: lon, lat, elev, m.
  GeoPoint3m.from([-0.0014, 51.4778, 45.0, 123.0]);

  // Also here it's possible to parse from WKT compatible text.
  GeoPoint3m.parse('-0.0014 51.4778 45.0 123.0');

  // The WKT parser for geographic coordinates parses full representations.
  WKT().parserGeographic().parse('POINT ZM (-0.0014 51.4778 45.0 123.0)');

  // -----------

  // A point series of `Point2` composed of list of points that are of `Point2`
  // or it's sub classes.
  PointSeries<Point2>.from([
    Point2(x: 10.0, y: 10.0),
    Point2(x: 20.0, y: 20.0),
    Point2m(x: 30.0, y: 30.0, m: 5.0),
    Point3(x: 40.0, y: 40.0, z: 40.0),
    Point3m(x: 50.0, y: 50.0, z: 50.0, m: 5.0),
  ]);

  // Making a point series of `Point3` from a list of a list of nums.
  PointSeries.make(
    // three points each with x, y and z coordinates
    [
      [10.0, 11.0, 12.0],
      [20.0, 21.0, 22.0],
      [30.0, 31.0, 32.0],
    ],
    // This is `PointFactory` that converts `Iterable<num>` to a point instance,
    // in this example using a factory creating `Point3` instances.
    Point3.coordinates,
  );

  // Parsing a point series of `GeoPoint` from WKT compatible text with
  // `GeoPoint3` as a concrete point class.
  PointSeries<GeoPoint>.parse(
    '10.0 11.0 12.0, 20.0 21.0 22.0, 30.0 31.0 32.0',
    GeoPoint3.coordinates,
  );

  // -----------

  // This makes a a line string of `Point3m` from a list of points.
  LineString.make(
    [
      [10.0, 11.0, 12.0, 5.1],
      [20.0, 21.0, 22.0, 5.2],
      [30.0, 31.0, 32.0, 5.3],
    ],
    Point3m.coordinates,
  );

  // Using the WKT factory produces the same result as the previous sample.
  WKT().parserProjected().parse<Point3m>(
        'LINESTRING ZM(10.0 11.0 12.0 5.1, 20.0 21.0'
        ' 22.0 5.2, 30.0 31.0 32.0 5.3)',
      );

  // Also this sample, parsing from WKT compatible text, gives the same result.
  LineString.parse(
    '10.0 11.0 12.0 5.1, 20.0 21.0 22.0 5.2, 30.0 31.0 32.0 5.3',
    Point3m.coordinates,
  );

  // -----------

  // Making a polygon of `GeoPoint2` from a list of a list of a list of nums:
  Polygon.make(
    [
      // this is an exterior boundary or an outer ring
      [
        [35, 10],
        [45, 45],
        [15, 40],
        [10, 20],
        [35, 10]
      ],
      // this is an interior boundary or an inner ring representing a hole
      [
        [20, 30],
        [35, 35],
        [30, 20],
        [20, 30]
      ],
    ],
    GeoPoint2.coordinates,
  );

  // The same polygon geometry as above, but parsed from a WKT compatible text.
  Polygon.parse(
    '(35 10, 45 45, 15 40, 10 20, 35 10) (20 30, 35 35, 30 20, 20 30)',
    GeoPoint2.coordinates,
  );

  // -----------

  // A multi point of `GeoPoint2` with four lon-lat points.
  MultiPoint.parse('10 40, 40 30, 20 20, 30 10', GeoPoint2.coordinates);

  // A multi line string of `Point2` with two line strings.
  MultiLineString.parse(
    '(10 10, 20 20, 10 40), (40 40, 30 30, 40 20, 30 10)',
    Point2.coordinates,
  );

  // A multi polygon of `GeoPoint2` with two polygon (both with exterior
  // boundary without holes).
  MultiPolygon.parse(
    '((30 20, 45 40, 10 40, 30 20)), ((15 5, 40 10, 10 20, 5 10, 15 5))',
    GeoPoint2.coordinates,
  );

  // -----------

  // A geometry collection can contain any other geometry types. Items for such
  // a collection can be constructed using different ways.
  GeometryCollection([
    // A point with integer values using a constructor with named parameters.
    Point2(x: 40, y: 10),
    // A line string made from a list of points (each a list of nums).
    LineString.make(
      [
        [10, 10],
        [20, 20],
        [10, 40]
      ],
      Point2.coordinates,
    ),
    // A polygon parsed from WKT compatible text.
    Polygon.parse('(40 40, 20 45, 45 30, 40 40)', Point2.coordinates)
  ]);

  // A geometry collection can also be parsed from WKT text.
  WKT().parserProjected().parse<Point2>(
    '''
      GEOMETRYCOLLECTION (
        POINT (40 10),
        LINESTRING (10 10, 20 20, 10 40),
        POLYGON ((40 40, 20 45, 45 30, 40 40)))
      ''',
  );

  // -----------

  // Bounds (2D) or bounding box from minimum and maximum 2D projected points.
  Bounds.of(min: Point2(x: 10.0, y: 10.0), max: Point2(x: 20.0, y: 20.0));

  // Bounds (3D) made from a list of list of nums.
  Bounds.make(
    [
      [10.0, 10.0, 10.0],
      [20.0, 20.0, 20.0]
    ],
    Point3.coordinates,
  );

  // Bounds (3D with measure) parsed from WKT compatible text.
  Bounds.parse('10.0 10.0 10.0 5.0, 20.0 20.0 20.0 5.0', Point3m.coordinates);

  // -----------

  // Geographical bounds (-20.0 .. 20.0 in longitude, 50.0 .. 60.0 in latitude).
  GeoBounds.bboxLonLat(-20.0, 50.0, 20.0, 60.0);

  // The same bounds created of 2D geographic point instances.
  GeoBounds.of(
    min: GeoPoint2(lon: -20.0, lat: 50.0),
    max: GeoPoint2(lon: 20.0, lat: 60.0),
  );

  // -----------

  // Geospatial feature with an identification, a point geometry and properties.
  Feature(
    id: 'ROG',
    geometry: GeoPoint3(lon: -0.0014, lat: 51.4778, elev: 45.0),
    properties: {
      'title': 'Royal Observatory',
      'place': 'Greenwich',
      'city': 'London',
      'isMuseum': true,
      'code': '000',
      'founded': 1675,
      'prime': DateTime.utc(1884, 10, 22),
      'measure': 5.79,
    },
  );

  // -----------

  // get WKT format
  final format = WKT();

  // Parse projected points from WKT (result is different concrete classes).
  final parser1 = format.parserProjected();
  parser1.parse('POINT (100.0 200.0)'); // => Point2
  parser1.parse('POINT M (100.0 200.0 5.0)'); // => Point2m
  parser1.parse('POINT (100.0 200.0 300.0)'); // => Point3
  parser1.parse('POINT Z (100.0 200.0 300.0)'); // => Point3
  parser1.parse('POINT ZM (100.0 200.0 300.0 5.0)'); // => Point3m

  // Parse geographical line string, from (10.0 50.0) to (11.0 51.0).
  final parser2 = format.parser(GeoPoint2.coordinates);
  parser2.parse('LINESTRING (10.0 50.0, 11.0 51.0)');

  // Parse geographical polygon with a hole.
  final parser3 = format.parserGeographic();
  parser3.parse(
    'POLYGON ((40 15, 50 50, 15 45, 10 15, 40 15),'
    ' (25 25, 25 40, 35 30, 25 25))',
  );
}

void _pointValuesAsString() {
  // create a point (XYZ)
  final point = Point3(x: 10.123, y: 20.25, z: -30.95);

  // print value list as string
  print('Values: ${point.valuesAsString()}');
  print('Values (delimiter = ";"): ${point.valuesAsString(delimiter: ';')}');
}

void _pointToGeoJsonAndWKT() {
  // create a point (XYZ)
  final point = Point3(x: 10.123, y: 20.25, z: -30.95);

  // print with default format
  print('Default format: $point');
  print('Default format (decimals = 0): ${point.toStringAs(decimals: 0)}');

  // print with WKT format
  print('WKT format: ${point.toStringAs(format: WKT.geometry)}');

  // print with GeoJSON format
  print('GeoJSON format: ${point.toStringAs(format: GeoJSON.geometry)}');
  print(
    'GeoJSON (decimals = 1) format: ${point.toStringAs(
      format: GeoJSON.geometry,
      decimals: 1,
    )}',
  );
}

void _geoJsonFeatureCollection() {
  // feature text encoder for GeoJSON
  final encoder = GeoJSON.feature.encoder();

  // create a feature collection with two features
  final collection = FeatureCollection(
    bounds: GeoBounds.of(
      min: GeoPoint2(lon: -1.1, lat: -3.49),
      max: GeoPoint2(lon: 10.12, lat: 20.25),
    ),
    features: [
      Feature(
        id: 'fid-1',
        geometry: GeoPoint2(lon: 10.123, lat: 20.25),
        properties: {
          'foo': 100,
          'bar': 'this is property value',
        },
      ),
      Feature(
        geometry: LineString.make(
          [
            [-1.1, -1.1],
            [2.1, -2.5],
            [3.5, -3.49]
          ],
          GeoPoint2.coordinates,
          type: LineStringType.any,
          bounds: GeoBounds.make(
            [
              [-1.1, -3.49],
              [3.5, -1.1]
            ],
            GeoPoint2.coordinates,
          ),
        ),
        properties: {},
      ),
    ],
  );

  // write the feture collection to the content writer of the encoder
  // (encoder.writer is FeatureContent)
  collection.writeTo(encoder.writer);

  // print GeoJSON text
  print(encoder.toText());

  // the previous line prints (however without line breaks):
  //    {"type":"FeatureCollection",
  //     "bbox":[-1.1,-3.49,10.123,20.25],
  //     "features":[
  //        {"type":"Feature",
  //         "id":"fid-1",
  //         "geometry":{"type":"Point","coordinates":[10.123,20.25]},
  //         "properties":{"foo":100,"bar":"this is property value"}},
  //        {"type":"Feature",
  //         "geometry":{"type":"LineString",
  //                     "bbox":[-1.1,-3.49,3.5,-1.1],
  //                     "coordinates":[[-1.1,-1.1],[2.1,-2.5],[3.5,-3.49]]},
  //         "properties":{}}]}
}
16
likes
140
points
586
downloads

Publisher

verified publishernavibyte.com

Weekly Downloads

Geospatial data structures (points, geometry, features, meta) and parsers (GeoJSON, WKT) for Dart.

Homepage
Repository (GitHub)

Documentation

API reference

License

BSD-3-Clause (license)

Dependencies

equatable, geobase, meta

More

Packages that depend on geocore