Giter VIP home page Giter VIP logo

geospatial's People

Contributors

navispatial avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

geospatial's Issues

Refactor coordinate value members of immutable Point classes

Immutable Point classes has constructors, members and getters like this, for example Point2:

  /// A point at given [x] and [y].
  const Point2({required num x, required num y})
      : _x = x,
        _y = y;

 final num _x, _y;

 @override
  num get x => _x;

  @override
  num get y => _y;

Streamline code a bit be refactoring these like this:

  /// A point at given [x] and [y].
  const Point2({required this.x, required this.y});

  @override
  final num x;

  @override
  final num y;

UriResolver moved and new Anchor interface

UriResolver defined (already previously too)

/// A function to resolve an absolute URI from an URI [reference].
///
/// Throws [ClientException] if the given [reference] is not allowed
/// according to security policies of a resolver, or if it's not resolvable.
typedef UriResolver = Uri Function(Uri reference);

UriResolver was moved to => lib/src/api/address folder

A new interface defined also on some code folder:

/// An anchor for a resource.
abstract class Anchor {
  const Anchor();

  /// The URI [reference] to a resource this anchor is referring.
  Uri get reference;
}

Then Content definition was changed to implement Anchor too:

abstract class Content extends Head implements Anchor, Body 

All definitions mentioned available via package:datatools/base_api.dart

Refactor Feature class inheritance and types of id and properties members

The geocore package (and also geodata) has dependency to the attributes package via following imports:

import 'package:attributes/entity.dart';
import 'package:attributes/values.dart';

It's used only for following things:

  • Feature extends Entity from the attributes package
  • id member of Entity is of the type Identifider
  • properties member of Entity is of the type DataObject

References are located in following source code:

  • lib/src/feature/feature.dart
  • lib/src/parse/geojson/geojson.dart

Consider removing the dependency to the attributes package and use some more generic types instead.

Properties could be handled as Map<String, Object?> and id stored as String (even if both number and text representations could occur for feature ids in GeoJSON for example).

This change would allow more generic usage of the geocore library and Feature classes it defines without introducing a dependency to a single package (that is now used only very partially).

Any side effects from this change?

How to check also the geodata package.

Ensure FormatException, not errors, is thrown when parsing invalid input data from external data sources

Background

Bob Nyström (2013):

  • Error and its subclasses are for programmatic errors. If one of those occurs, your code is bad and you should fix your code.
  • Non-Error exception classes are for runtime errors. Sometimes you can prevent them from being thrown, but often you cannot.
  • Except in a few special circumstances, idiomatic Dart should throw Errors, but never catch them. They exists specifically to not be caught so that they take down the app and alert the programmer to the location of the bug.

When parsing data from some external data source, like WKT or GeoJSON data, in the scope of this library, such external data might have invalid data that parser code must handle. When encountering invalid data, and if a parser cannot handle such invalid data, it might be better to throw an exception (like FormatException in Dart) rather than throwing an error. Invalid data from an external data source or file are not programmatic errors.

Some code in geocore still might throw errors when reading (and cannot handle) invalid data. So must check and correct such occurences if found.

Easier constructor to make point and other geometry instances.

New constructors for Point concrete classes like, here a sample for Point2, other classes in similar ways:

  /// A point parsed from [text] with coordinates in order: x, y.
  ///
  /// If [parser] is null, then WKT [text] like "10.0 20.0" is expected.
  ///
  /// Throws FormatException if cannot parse.
  factory Point2.parse(String text, {ParseCoords? parser});

  /// A point parsed from [text] with coordinates in order: x, y.
  ///
  /// If [parser] is null, then WKT [text] like "10.0 20.0" is expected.
  ///
  /// Returns null if cannot parse.
  static Point2? tryParse(String text, {ParseCoords? parser});

Also more complex geometries new ways to construct, for example LineString:

  /// Create [LineString] from [values] with a chain of points.
  ///
  /// An optional [bounds] can be provided or it's lazy calculated if null.
  factory LineString.make(
          Iterable<Iterable<num>> values, PointFactory<T> pointFactory,
          {LineStringType type = LineStringType.any, Bounds? bounds});

  /// Create [LineString] parsed from [text] with a chain of points.
  ///
  /// If [parser] is null, then WKT [text] like "25.1 53.1, 25.2 53.2" is
  /// expected.
  ///
  /// Throws FormatException if cannot parse.
  factory LineString.parse(String text, PointFactory<T> pointFactory,
          {LineStringType type = LineStringType.any,
          ParseCoordsList? parser});

Other geometries in similar ways.

Add support for empty geometries other than Point and abstract Geometry

Now we have support for creating "empty geometries":
Point.empty()
Geometry.empty()

But no direct way to create "empty geometries" for other geometry types like LineString, Polygon, etc.

What are empty geometries anyway?
Geospatial formats like WKT support this kind of stuff:

POINT EMPTY
MULTIPOLYGON EMPTY

Add full support to all geometry types and WKT parser at least.

Factory and other fixes on Bounds, GeometryCollection, Instant etc.

Smaller fixes for the geocore BETA version 0.6.2:

  • Bounds with new make and parse factory methods
  • CoordinateFactory: checking throws FormatException if check fails
  • GeometryCollection: constructors that create BoundedSeries
  • Instant: parse and tryParse factory methods

BoundsBuilder as utility class

Currently specified as private helper class on package:geocore/base.dart:

/// A helper class to calculate [bounds] for a set of points and other bounds.
///
/// Use [addPoint] and [addBounds] methods to add geometries to be used on
/// calculation. A value for calculations can be obtained from [bounds].
class _BoundsBuilder {
...

As this is utility class, move from "base" to under "lib/src/utils/bounds" as public class, but not exported.

Rename point factories of Point classes

Classes implementing Point has static const factories named geometry:

  /// A [PointFactory] creating [Point2] instances.
  static const PointFactory<Point2> geometry =
      CastingPointFactory<Point2>(Point2.origin());

Usage like this:

LineString.parse('100.0 200.0, 400.0 500.0', Point2.geometry);
LineString.parse('100.0 200.0 300.0 23.4, 400.0 500.0 600.0 54.8', Point3m.geometry);

Consider renaming geometry to coordinates, that would make usage more descriptive, maybe?

Usage would be like this:

LineString.parse('100.0 200.0, 400.0 500.0', Point2.coordinates);
LineString.parse('100.0 200.0 300.0 23.4, 400.0 500.0 600.0 54.8', Point3m.coordinates);

Factories named geometry would be kept for some time, but deprecated.

Enhance methods of Point returning coordinate values as String

Goal: Enhance methods of Point returning coordinate values as String
Need from entity classes with point geometries - making json element serialization easier.

Point and Bounds classes, new optional parameter fractionDigits, see method definitions updated:

  /// Writes coordinate values to [buffer] delimited by [delimiter].
  ///
  /// Use [fractionDigits] to set a number of decimals to nums with decimals.
  void writeValues(
    StringSink buffer, {
    String delimiter = ',',
    int? fractionDigits,
  });

  /// Returns coordinate values as a string delimimited by [delimiter].
  ///
  /// Use [fractionDigits] to set a number of decimals to nums with decimals.
  String valuesAsString({
    String delimiter = ',',
    int? fractionDigits,
  });

Point class, new method:

  /// Returns WKT coords (ie. "35 10" for a point with x=35 and y=10).
  /// 
  /// Use [fractionDigits] to set a number of decimals to nums with decimals.
  String toWktCoords({int? fractionDigits}) =>
      valuesAsString(delimiter: ' ', fractionDigits: fractionDigits);

Also internal utility function:

/// Uses `String.toStringAsFixed()` when [n] contains decimals.
/// 
/// For example returns '15' if a double value is 15.00, and '15.50' if a double
/// value is 15.50.
/// 
/// See: https://stackoverflow.com/questions/39958472/dart-numberformat
String toStringAsFixedWhenDecimals(num n, int fractionDigits) =>
    n.toStringAsFixed(n.truncateToDouble() == n ? 0 : fractionDigits);

Client-side support for calling reading GeoJSON web or file resource

Geocore package has support for GeoJSON parser.

Geodata package provides client side access to different resources. Currently only partial support for OGC API Features (see #9).

Implement also support for accessing a web or file resource hosting GeoJSON file to geodata package.

Need also "client" implementation for a file resource to datatools package + other enchancements maybe too.

Resource metadata domain model in "geodata" package

Adapt to #16 and #17 enhancements.

New planned class hierarchy

  • ResourceMeta class with with descriptor and links properties
    • ProviderMeta class for metadata about API provider, with conformance and collections properties too
    • CollectionMeta class for metadata about a geospatial collection under a provider, with id and extent prorperty too

Basic error management and logging features

Currently just throws an exception when calling async fetching functions to read data from an external data source.

Consider is this fine, or some other mechanism. Or specific exception clasess.

GeoJSON parser to allow extended Feature data

GeoJSON parser supports constructing Feature objects containing id, properties and geometry as described on GeoJSON spec at RFC 7946.

However GeoJSON spec allows foreign members like on snippets extracted from the spec below:

Here "title" is foreign member:

{
       "type": "Feature",
       "id": "f1",
       "geometry": {...},
       "properties": {...},
       "title": "Example Feature"
   }

And here "centerline" is foreign member and NOT a GeoJSON geometry

   {
       "type": "Feature",
       "id": "f2",
       "geometry": {...},
       "properties": {...},
       "centerline": {
           "type": "LineString",
           "coordinates": [
               [-170, 10],
               [170, 11]
           ]
       }
   }

GeoJSON parser should be refactored to allow parser clients to read also foreign member data.

Restructuring web api client for geospatial data

DRAFT for some future version (0.8 or 0.9 maybe).

Planned structure for restructuring web api client for geospatial data, something like this

  • base/
    • features/
      • FeatureStore.dart
  • geojson/
    • GeoJsonFeatureService.dart (with default impl using "http(s)" binding)
    • GeoJsonFeatureStore.dart
  • ogcapi/
    • common/
      • data/
        • ItemsMeta.dart
        • ResourceMeta.dart
    • features/
      • data/
        • FeaturesMeta.dart
      • service/
        • OGCFeatureService.dart (with default impl using "http(s)" binding)
      • store/
        • OGCFeatureStore.dart

Services do not have common abstractions, as different services differ so much starting from standard specific stuff.

However FeatureStore above is meant to be common abstraction, letting accessing features (or other geospatial data) from different service types with shared interface. Services just provide async methods to access remote and local resources. Stores uses services, and may combine different services, and may cache data, and has mechanism to notify listeners.

ValueAccessor and PropertyMap changes

Changes on ValueAccessor:

  • moved to package:attributes/values.dart
  • not implementing Counted any more
    • Some value accessors might not have size of values contained.
  • renamed accessor bool existsNull(K key);, was previously hasNull
    • Returns true if a value with key exists and that value is null.
  • new accessor bool existsNonNull(K key);
    • Returns true if a value with key exists and that value is non-null.
  • new accessor num getNum(K key, {num? min, num? max});
    • Returns a value of num type at key.
    • Still getInt and getDouble properties available too.
    • Use getNum when accessor might have either int or double property value.
  • new accessor num? tryNum(K key, {num? min, num? max});
    • similar as previous
    • but this returns null if if an underlying value is unavailable or cannot be converted to num.
  • changed accessor DateTime getTimeUTC(K key, {DateTime Function(Object?)? parse});
    • new parameter parse to define app specific conversion.
  • changed accessor DateTime? tryTimeUTC(K key, {DateTime Function(Object?)? parse});
    • new parameter parse to define app specific conversion.

Changes on ValueAccessorMixin

  • moved to package:attributes/values.dart
  • provides now default implementations only to accessor with "try" prefix
  • those now check for Exception not only FormatException

Example of ValueAccessorMixin method:

  @override
  String? tryString(K key) {
    try {
      return getString(key);
    } on Exception {
      return null;
    }
  }

New base interface for property collections (maps and lists)

abstract class Properties<K> extends ValueAccessor<K> implements Counted {
  PropertyMap getMap(K key);
  PropertyMap? tryMap(K key);
  PropertyList getList(K key);
  PropertyList? tryList(K key);
}

Changes on PropertyMap:

  • not anymore implementing ValueAccessor<String> directly
  • but via extending Properties<String>
  • removed factory PropertyMap.from(Map<String, dynamic> source)
  • new factory PropertyMap.decodeJson(String data)

Also new PropertyList that extends Properties<int>

Add copyWith method to Point classes

New member to be defined on Point abstract class and implemented in sub classes:

  /// Copies this point with the compatible type and sets given coordinates.
  ///
  /// Optional [x], [y], [z] and [m] values, when given, override values of
  /// this point object. If the type of this point does not have a certain 
  /// value, then it's ignored.
  Point copyWith({num? x, num? y, num? z, num? m});

Same definition on GeoPoint that extends Point:

  /// Copies this point with the compatible type and sets given coordinates.
  ///
  /// Optional [x], [y], [z] and [m] values, when given, override values of
  /// this point object. If the type of this point does not have a certain
  /// value, then it's ignored.
  ///
  /// Properties have equality (in context of this library): [lon] == [x],
  /// [lat] == [y], [elev] == [z]
  @override
  GeoPoint copyWith({num? x, num? y, num? z, num? m});

Check if point series is closed by tolerance

PointSeries has property to check whether is closed:

  /// True if the first and last point equals in 2D.
  bool get isClosed;

Add also a method to check within a tolerance:

  /// True if the first and last point equals in 2D within [toleranceHoriz].
  bool isClosedBy(num toleranceHoriz);

Adapt factory changes to GeoJSON parser

Related:
#2
#3
#4

Refactor package:geocore/parse_factory.dart and package:geocore/geojson_factory.dart mini-libraries adapting changes introduced on those issues. May required quite substantial refactoring on classes of these mini-libraries.

Add EWKT support

Plan updated 2024-04-16

Implementation for v.1.1.0

  • Support decoding also EWKT data (ignoring an optional srid).
  • Utilities to decode a coordinate type and SRID from WKT text.
  • A sample for decoding EWKT text data.

Point factory constructor consistency

Factory constructors on classes implementing Point are of form:
factory Point2.from(Iterable<double> coords)

See #2 and #3 for other issues about coordinate values and methods creating new instances.

Change factory constructors also similary to new signature:
factory Point2.from(Iterable<num> coords, {int? offset});

Define consistent mini library exports with base classes included

Some mini libraries should also export some of base classes.

For example if needing GeoJSON parser but also base geometries, you have to import:

import 'package:geocore/base.dart';
import 'package:geocore/parse_geojson.dart';

Maybe it would be handy if import for parse_geojson.dart would export also base geometries (and factory abstractions).

Libraries (currently in version 0.62 situation) for geocore

The package contains following mini-libraries:

Library Description
base Geometry classes including points, bounds, line strings, polygons and more.
crs Classes to represent coordinate reference system (CRS) identifiers.
feature Feature and FeatureCollection to handle dynamic geospatial data objects.
geo Geographic points and bounds classes to represent longitude-latitude data
meta_extent Metadata structures to handle extents with spatial and temporal parts.
parse_factory Base interfaces and implementations for geospatial data factories.
parse_geojson Geospatial data factory to parse GeoJSON from text strings.
parse_wkt Geospatial data factory to parse WKT from text strings.

For example to access a mini library you should use an import like:

import 'package:geocore/base.dart';

To use all libraries of the package:

import 'package:geocore/geocore.dart';

Elev and m coordinate values as default in some GeoPoint classes

GeoPoint2m, GeoPoint3and GeoPoint3m geographical points has either elev or m coordinate values, or both. Default constructor requires also these, for example:

  const GeoPoint3m({
    required double lon,
    required double lat,
    required double elev,
    required this.m,
  }) : super(lon: lon, lat: lat, elev: elev);

To be consistent with Point2m, Point3and Point3m change definition so that elev and m has default 0.0 value on default constructors.

const GeoPoint3m({
    required double lon,
    required double lat,
    double elev = 0.0,
    this.m = 0.0,
  }

Populate results by default when intersecting with bounds on point and bounded series

PointSeries and BoundedSeries have methods, whose definition:

  /// Returns a new lazy series where items intersects with [bounds].
  ///
  /// Even if an item on this series has a complex geometry, only bounds
  /// of that geometry is tested (intersection) with the given [bounds].
  ///
  /// Those items that has empty bounds are not matched.
  S intersectByBounds(Bounds bounds);

  /// Returns a new lazy series where items intersects with [bounds] in 2D.
  ///
  /// Even if an item on this series has a complex geometry, only bounds
  /// of that geometry is tested (intersection) with the given [bounds].
  ///
  /// Those items that has empty bounds are not matched.
  S intersectByBounds2D(Bounds bounds);

Change their definition (and also implementations):

  /// Returns a new series where items intersects with [bounds].
  ///
  /// The intersected series is populated by default. If [lazy] is set true then
  /// returns a new lazy series with items intersected lazily.
  ///
  /// Even if an item on this series has a complex geometry, only bounds
  /// of that geometry is tested (intersection) with the given [bounds].
  ///
  /// Those items that has empty bounds are not matched.
  S intersectByBounds(Bounds bounds, {bool lazy = false});

  /// Returns a new series where items intersects with [bounds] in 2D.
  ///
  /// The intersected series is populated by default. If [lazy] is set true then
  /// returns a new lazy series with items intersected lazily.
  ///
  /// Even if an item on this series has a complex geometry, only bounds
  /// of that geometry is tested (intersection) with the given [bounds].
  ///
  /// Those items that has empty bounds are not matched.
  S intersectByBounds2D(Bounds bounds, {bool lazy = false});

Add fromText and toText serialization to Point classes

For example Point2:

  /// A point parsed from [text] with coordinates given in order: x, y.
  ///
  /// Coordinate values in [text] are separated by [delimiter]. For example
  /// `Point2.fromText('10.0;20.0', delimiter: ';')` returns the same point as
  /// `Point2.xy(10.0, 20.0)`.
  ///
  /// If [delimiter] is not provided, values are separated by whitespace.
  ///
  /// Throws FormatException if cannot parse.
  factory Point2.fromText(
    String text, {
    Pattern? delimiter,
  });

Also similar methods to other Point classes.

Otherway, new method added to Point abstract base class:

  /// Returns coordinate values as text separated by [delimiter].
  ///
  /// If [delimiter] is not provided, values are separated by whitespace. For 
  /// example "10.1 20.2" is returned for a point with x=10.1 and y=20.2.
  ///
  /// Use [fractionDigits] to set a number of decimals to nums with decimals.
  String toText({
    String delimiter = ' ',
    int? fractionDigits,
  });

Deprecating this on Point abstract class:

  /// Returns WKT coords (ie. "35 10" for a point with x=35 and y=10).
  ///
  /// Use [fractionDigits] to set a number of decimals to nums with decimals.
  @Deprecated('Use toText instead')
  String toWktCoords({int? fractionDigits});

Some helper methods needed on package internal utilities.

Test point equality in 2D or 3D by tolerance in Point class

Currently we have for Point class:

  /// True if this point equals with [other] point in 2D.
  bool equals2D(Point other) =>
      isNotEmpty && other.isNotEmpty && x == other.x && y == other.y;

  /// True if this point equals with [other] point in 3D.
  bool equals3D(Point other) => equals2D(other) && z == other.z;

Add optional tolerance argument to have:

  /// True if this point equals with [other] point in 2D by testing x and y.
  ///
  /// If [toleranceHoriz] is given, then differences on x and y coordinate
  /// values between this and [other] must be <= tolerance. Otherwise value
  /// must be exactly same.
  ///
  /// Tolerance values must be null or positive (>= 0).
  bool equals2D(Point other, {num? toleranceHoriz}) {
    assert(
      toleranceHoriz == null || toleranceHoriz >= 0.0,
      'Tolerance must be null or positive (>= 0)',
    );
    if (isEmpty || other.isEmpty) {
      return false;
    }
    return toleranceHoriz != null
        ? (x - other.x).abs() <= toleranceHoriz &&
            (y - other.y).abs() <= toleranceHoriz
        : x == other.x && y == other.y;
  }

  /// True if this point equals with [other] point in 3D by testing x, y and z.
  ///
  /// If [toleranceHoriz] is given, then differences on x and y coordinate
  /// values between this and [other] must be <= tolerance. Otherwise value
  /// must be exactly same.
  ///
  /// The tolerance for z coordinate values is given by an optional
  /// [toleranceVert] value.
  ///
  /// Tolerance values must be null or positive (>= 0).
  bool equals3D(Point other, {num? toleranceHoriz, num? toleranceVert}) {
    assert(
      toleranceVert == null || toleranceVert >= 0.0,
      'Tolerance must be null or positive (>= 0)',
    );
    if (!equals2D(other, toleranceHoriz: toleranceHoriz)) {
      return false;
    }
    return toleranceVert != null
        ? (z - other.z).abs() <= toleranceVert
        : z == other.z;
  }

New package "datatools/base_api.dart"

New package or sub library definition:

/// Generic API abstractions (addresses, content, control data, exceptions).
///
/// Usage: import `package:datatools/base_api.dart`
library base_api;

export 'src/api/address.dart';
export 'src/api/content.dart';
export 'src/api/control.dart';
export 'src/api/exceptions.dart';

The previously available package package:datatools/fetch_api.dart is now defined as

/// Fetch API abstraction (addresses, content, control data, exceptions, fetch).
///
/// Usage: import `package:datatools/fetch_api.dart`
library fetch_api;

export 'base_api.dart';
export 'src/api/fetch.dart';

Point and geometry factory interfaces and implementations

Point has following method to create new points of the same sub class point type with given values:
Point newPoint({double x = 0.0, double y = 0.0, double z = 0.0, double m = 0.0});

This has issues

  • how to give plain int as param, need to change params to num, see #2
  • x and y are required for all points, but z and m should be optional,
  • consistent naming

Change to:
Point newWith({num x = 0.0, num y = 0.0, num? z, num? m});

Also another version of point factory letting reading from coord array:
Point newFrom(Iterable<num> coords, {int? offset, int? length});

The latter could be generalized:

abstract class CoordinateFactory<T extends Geometry> {
  T newFrom(Iterable<num> coords, {int? offset, int? length})
}

Add support for other geometry classes known by WKT

https://en.wikipedia.org/wiki/Well-known_text_representation_of_geometry

Now (at least some level of) support for:

  • Point, MultiPoint
  • LineString, MultiLineString
  • Polygon, MultiPolygon
  • GeometryCollection

However NO support for these, and not yet even planned any, is there need?

  • Triangle
  • PolyhedralSurface
  • TIN (Triangulated irregular network)

Well-known binary (WKB) seems to have even more, but maybe most of these are totally out of focus for the geocore library...

  • CircularString
  • CompoundCurve
  • CurvePolygon
  • MultiCurve
  • MultiSurface
  • Curve
  • Surface
  • Circle
  • GeodesicString
  • EllipticalCurve
  • NurbsCurve
  • Clothoid
  • SpiralCurve
  • CompoundSurface
  • BrepSolid
  • AffinePlacement

Equality and hashcodes on Point and other Geometry classes

Most immutable classes uses EquatableMixin from equatable package that helps to implement equality without needing to explicitly override == and hashCode

However for example points has common interface Point and multiple implementing classes like (Point2, Point3 etc.). Need some consideration how == and hashCode should work on these classes. Same issue with other classes extending Geometry.

Coordinate transformations on core classes (and reading datasource)

Currently no support at all.

Need some specification what's really needed or not.

There are good libraries for coordinate transformations, at least following, maybe others too.

proj4dart by maRci002:
A Dart library to transform point coordinates from one coordinate system to another, including datum transformations

Initial WKT support

Support creating geometry classes from POINT, LINESTRING, POLYGON, MULTIPOINT, MULTILINESTRING and MULTIPOLYGON types.

Define more specific return type on newWith and newFrom methods of Point sub classes

The abstract Point class following factory methods to create new point instances of the same sub type methods are called on.

  Point newWith({num x = 0.0, num y = 0.0, num? z, num? m});
  Point newFrom(Iterable<num> coords, {int? offset, int? length});

Sub classes like Point2 implement these methods like:

  @override
  Point newWith({num x = 0.0, num y = 0.0, num? z, num? m}) =>
      Point2(x: x, y: y);

  @override
  Point newFrom(Iterable<num> coords, {int? offset, int? length}) {
    CoordinateFactory.checkCoords(2, coords, offset: offset, length: length);
    return Point2.from(coords, offset: offset);
  }

This should work fine.

However if you are using a specific Point sub type, like Point2, then it might be useful to define more specific return type.

That is, for Point2 the implementation would change to following:

  @override
  Point2 newWith({num x = 0.0, num y = 0.0, num? z, num? m}) =>
      Point2(x: x, y: y);

  @override
  Point2 newFrom(Iterable<num> coords, {int? offset, int? length}) {
    CoordinateFactory.checkCoords(2, coords, offset: offset, length: length);
    return Point2.from(coords, offset: offset);
  }

Apply consistent imports (relative / absolute)

Sample from current code at src/geo/geobounds.dart:

import 'package:equatable/equatable.dart';

import '../base.dart';

import 'geopoint.dart';

This has three kind of imports:

  1. absolute import from separate library package resolved via pub.dev
  2. relative import from another folder under /src of the same package
  3. relative import from the same folder of the same package

Relative imports are short and useful, but relative imports from other folders could some time mean imports like ../../subpackage/otherclass.dart where multiple .. can make it difficult to see directly what folder offers a particular class.

Convention to be applied:

  1. as them are now, full absolute import starting with package:
  2. absolute import from the root of the current library package, so starting with /src
  3. relative import referring only another filename on the same folder

The sample shall change:

import 'package:equatable/equatable.dart';

import '/src/base.dart';

import 'geopoint.dart';

Coordinate value getter properties as num on points

Point-interface has x, y, z and m getter properties returning double.
Most implementing classes use also double as storage.

However there Point2i and Point3i use int as storage. As x, y, z and m getter properties are used, int must be returned as double.

Feature change: getters return num which can be either int or double.

Metadata element for describing items

For example The Atom Syndication format by RFC 4287 has descriptive fields, explained by Introduction to Atom

  • feed element
    • title: Contains a human readable title for the feed. Often the same as the title of the associated website.
    • subTitle: Contains a human-readable description or subtitle for the feed.
  • entry element
    • title: Contains a human readable title for the entry.
    • summary: Conveys a short summary, abstract, or excerpt of the entry.

Atom has many other fields too for category, author, ids, links etc, but they are not generic descriptive elements.

Suggested generic metadata item for describing some item on this package:

  • Descriptor class
    • title (required): A human-readable title or header for an item
    • subTitle (optional): A human-readable subtitle, sub header or description for an item
    • summary (optional): A short summary or abstract for an item

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.