-
Notifications
You must be signed in to change notification settings - Fork 5
Description
This is not a trivial task to implement as a common solution.
Geospatial data formats
GeoJSON
GeoJSON (RFC 7946)
- data expected to be WGS84 longitude / latitude
- However, where all involved parties have a prior arrangement, alternative coordinate reference systems can be used without risk of data being misinterpreted
- anyway no mechanisms to announce CRS identifiers
JSON-FG
See #53
- when a geometry objects has "place" element, then an optional "coordRefSys" field can specify an alternative coordinate system (other than WGS84 longitude / latitude)
- there are multiple ways to specify such an CRS identifier (or not just id but also properties of such a reference system), alternatives listed below, copied from the JSON-FG editorial draft
A reference system can be specified in a JSON-FG document using a "coordRefSys" member...:
- URI: "http://www.opengis.net/def/crs/EPSG/0/3857"
- Safe CURIE: "[EPSG:3857]"
- A reference system value by reference (URI) and with an epoch:
{ "type": "Reference", "href": "http://www.opengis.net/def/crs/EPSG/0/4979", "epoch": 2017.23 }
- A ad hoc compound reference system value (using URIs):
[ { "type": "Reference", "href": "http://www.opengis.net/def/crs/EPSG/0/4258", "epoch": 2016.47 }, "http://www.opengis.net/def/crs/EPSG/0/7837" ]
WKT
Well-known text representation of geometry (WKT)
- no mechanisms to announce CRS identifiers
WKB
Well-known binary representation of geometry (WKB)
- no mechanisms to announce CRS identifiers
EWKT
CRS identifier as an integer (assuming an EPSG code here) just like wikipedia page describes:
SRID=4326;POINT(-44.3 60.1)
See PostGIS: ST_GeomFromEWKT for more examples.
EWKB
See
- PostGIS: ST_asEWKB
- GEOS: Extended WKB
SRID integer can be encoded after wkbType
in binary encoding.
Geobase 1.0.x implementation
CoordRefSys class
- can be instantiated using identifiers like "http://www.opengis.net/def/crs/OGC/1.3/CRS84", "http://www.opengis.net/def/crs/EPSG/0/4326", "EPSG:4326"
- provides support for most common coordinate reference system ids but currently the support is not very wide
Related class to provide logic, can be customized by extending and registering: CoordRefSysResolver.
Feature and Geometry classes
Feature and geometry objects are specified by the vector_data sub package:
- FeatureObject
- FeatureCollection
- Feature
- Geometry
- SimpleGeometry
- Point
- LineString
- Polygon
- MultiPoint
- MultiLineString
- MultiPolygon
- GeometryCollection
- SimpleGeometry
These classes do not have members for CRS information. It's assumed that a CRS applied is known by an application context, or stored outside feature and geometry objects. This should work as long as all feature and geometry objects share a same CRS.
Some encoding / decoding methods has a parameter allowing passing such CRS information to a encoder / decoder.
For example Point:
/// Parses a point geometry from text conforming to format.
Point.parse(String text, {TextReaderFormat<SimpleGeometryContent> format = GeoJSON.geometry, CoordRefSys? crs, Map<String, dynamic>? options});
/// The string representation of this geometry object, with format applied.
String toText({TextWriterFormat<SimpleGeometryContent> format = GeoJSON.geometry, int? decimals, CoordRefSys? crs, Map<String, dynamic>? options});
Text format
Such a crs
parameter is passed to a text format object that has following definition:
/// Returns a text format decoder that decodes text as Content to builder.
ContentDecoder decoder(Content builder, {CoordRefSys? crs, Map<String, dynamic>? options});
/// Returns a text format encoder for Content.
ContentEncoder<Content> encoder({StringSink? buffer, int? decimals, CoordRefSys? crs, Map<String, dynamic>? options});
An optional CoordRefSys? crs
is then passed to actual decoder or encoder implementation, that can use crs information for example to handle axis order logic for all geospatial features and geometries applied.
Content interfaces
Decoders, encoders and object builder also use "content interfaces" to send decoded or encoded elements, for example SimpleGeometryContent:
/// Writes a point geometry with position.
void point(Position position, {String? name});
/// Writes a line string geometry with a chain of positions.
void lineString(PositionSeries chain, {String? name, Box? bounds});
/// ....
Currently methods on these content interfaces do not have a parameter for a geometry or feature instance specific CRS information (only decoder / encoder specific common value is available for some formats).
Issues with current implementation
No issues when decoding/encoding GeoJSON, WKT or WKB data.
However supporting EWKT, EWKB and JSON-FG properly might require a way to pass geometry or feature object specific CRS identifier between decoders, encoders and object builders.
And supporting instantiating an object tree parsed from a JSON-FG document might require an optional CRS member for each feature and geometry objects. So that when null
either a default CRS (like WGS 84) or a CRS from a parent object would be assumed.
Geobase 1.1.x proposal
See #165 both decoding and encoding of EWKB can be implemented without major changes.
Geobase 2.0.x proposal
CoordRefSys class
Should be ensured that integer ids (from EWKB or EWKT) and different type of URI, CURIE, lists of URIs / CURIEs, URIs or CURIEs with epoch data (that are going to be used by JSON-FG) etc. can be parsed and used.
Add some basic logic to CoordRefSysResolver
to cover most common reference systems.
Feature and Geometry classes
Add the CoordRefSys? crs
member to feature and geometry objects with backward compatibility in mind. Such information would be totally optional, so by default null
value would be stored.
New constructors / static factories might be needed that allow storing an instance of CoordRefSys
to crs
member.
Content interfaces
Changes to signatures of all methods building a geometry or a feature would be needed. For example:
/// Writes a point geometry with position.
void point(Position position, {String? name, CoordRefSys? crs});
/// Writes a line string geometry with a chain of positions.
void lineString(PositionSeries chain, {String? name, Box? bounds, CoordRefSys? crs});
/// ....
Decoding
Decoders / parsers could use changed methods to pass a geometry or feature specific CRS information to consumers.
As a consumer for example object builders (like GeometryBuilder
and FeatureBuilder
) would then use any non-null crs
data when instantiating geometries or features.
Encoding
Similarly when encoding / writing a geometry or feature object to external data format.
Currently Point
has methods to write as text format:
@override
void writeTo(SimpleGeometryContent writer, {String? name}) =>
isEmptyByGeometry
? writer.emptyGeometry(Geom.point, name: name)
: writer.point(position, name: name);
@override
String toText({
TextWriterFormat<SimpleGeometryContent> format = GeoJSON.geometry,
int? decimals,
CoordRefSys? crs,
Map<String, dynamic>? options,
}) {
final encoder =
format.encoder(decimals: decimals, crs: crs, options: options);
writeTo(encoder.writer);
return encoder.toText();
}
This should be changed to something like this:
@override
void writeTo(SimpleGeometryContent writer, {String? name}) =>
isEmptyByGeometry
? writer.emptyGeometry(Geom.point, name: name)
: writer.point(position, name: name, crs: this.crs);
@override
String toText({
TextWriterFormat<SimpleGeometryContent> format = GeoJSON.geometry,
int? decimals,
CoordRefSys? crs,
Map<String, dynamic>? options,
}) {
final encoder =
format.encoder(decimals: decimals, crs: this.crs ?? crs, options: options);
writeTo(encoder.writer);
return encoder.toText();
}
Target version
Changes described above can be implemented with backward compatibility - at least for package user, however if someone has extended classes mentioned above, then there might be some risks.
As package API changes are needed to multiple sub packages it would be most safe to target geobase 2.0.0
version with changes described.
Also #29, #53, #165 should be associated to these changes too.