├── .gitattributes ├── .gitignore ├── CHANGELOG.md ├── LICENSE ├── README.md └── dart ├── README.md ├── dart_analyze.sh ├── dart_downgrade.sh ├── dart_format.sh ├── dart_run_examples.sh ├── dart_test.sh ├── dart_upgrade.sh ├── geobase ├── .gitignore ├── CHANGELOG.md ├── DERIVATIVE.md ├── LICENSE ├── README.md ├── analysis_options.yaml ├── archived │ └── README.v1.1.0.md ├── assets │ └── diagrams │ │ ├── feature_objects.png │ │ ├── feature_objects.svg │ │ ├── meta_temporal_extent.png │ │ ├── meta_temporal_extent.svg │ │ ├── multi_and_collection_geometries.png │ │ ├── multi_and_collection_geometries.svg │ │ ├── point_linestring_polygon.png │ │ ├── point_linestring_polygon.svg │ │ ├── position_box_scalable.png │ │ └── position_box_scalable.svg ├── example │ ├── geobase_example.dart │ ├── geobase_old_example.dart │ └── geobase_with_proj4d_example.dart ├── lib │ ├── common.dart │ ├── coordinates.dart │ ├── geobase.dart │ ├── geodesy.dart │ ├── geometric.dart │ ├── meta.dart │ ├── projections.dart │ ├── projections_proj4d.dart │ ├── src │ │ ├── common │ │ │ ├── codes │ │ │ │ ├── axis_order.dart │ │ │ │ ├── canvas_origin.dart │ │ │ │ ├── cardinal_precision.dart │ │ │ │ ├── coord_ref_sys_type.dart │ │ │ │ ├── coords.dart │ │ │ │ ├── dimensionality.dart │ │ │ │ ├── dms_type.dart │ │ │ │ ├── geo_representation.dart │ │ │ │ ├── geom.dart │ │ │ │ └── hemisphere.dart │ │ │ ├── constants │ │ │ │ ├── epsilon.dart │ │ │ │ ├── geodetic.dart │ │ │ │ └── screen_ppi.dart │ │ │ ├── conversions │ │ │ │ ├── angle_unit.dart │ │ │ │ ├── angular_velocity_unit.dart │ │ │ │ ├── area_unit.dart │ │ │ │ ├── length_unit.dart │ │ │ │ ├── speed_unit.dart │ │ │ │ └── time_unit.dart │ │ │ ├── functions │ │ │ │ ├── geographic_functions.dart │ │ │ │ ├── position_functions.dart │ │ │ │ └── unit_conversion_extension.dart │ │ │ ├── presentation │ │ │ │ └── dms.dart │ │ │ └── reference │ │ │ │ ├── coord_ref_sys.dart │ │ │ │ ├── coord_ref_sys_resolver.dart │ │ │ │ ├── ellipsoid.dart │ │ │ │ ├── temporal_ref_sys.dart │ │ │ │ └── temporal_ref_sys_resolver.dart │ │ ├── coordinates │ │ │ ├── base │ │ │ │ ├── aligned.dart │ │ │ │ ├── bounded.dart │ │ │ │ ├── box.dart │ │ │ │ ├── position.dart │ │ │ │ ├── position_extensions.dart │ │ │ │ ├── position_scheme.dart │ │ │ │ ├── position_series.dart │ │ │ │ ├── positionable.dart │ │ │ │ └── value_positionable.dart │ │ │ ├── geographic │ │ │ │ ├── geobox.dart │ │ │ │ ├── geographic.dart │ │ │ │ └── geographic_bearing.dart │ │ │ ├── projected │ │ │ │ ├── projbox.dart │ │ │ │ └── projected.dart │ │ │ ├── projection │ │ │ │ ├── projection.dart │ │ │ │ └── projection_adapter.dart │ │ │ └── scalable │ │ │ │ ├── scalable.dart │ │ │ │ └── scalable2i.dart │ │ ├── geodesy │ │ │ ├── base │ │ │ │ ├── geodetic.dart │ │ │ │ └── geodetic_arc_segment.dart │ │ │ ├── ellipsoidal │ │ │ │ ├── datum.dart │ │ │ │ ├── datum_conversions.dart │ │ │ │ ├── ellipsoidal.dart │ │ │ │ ├── ellipsoidal_extension.dart │ │ │ │ ├── ellipsoidal_vincenty.dart │ │ │ │ ├── utm.dart │ │ │ │ ├── utm_conversions.dart │ │ │ │ └── utm_mgrs.dart │ │ │ └── spherical │ │ │ │ ├── spherical_great_circle.dart │ │ │ │ └── spherical_rhumb_line.dart │ │ ├── geometric │ │ │ ├── base │ │ │ │ └── distanced_position.dart │ │ │ └── cartesian │ │ │ │ └── areal │ │ │ │ ├── cartesian_areal_extension.dart │ │ │ │ └── polylabel.dart │ │ ├── meta │ │ │ ├── extent │ │ │ │ ├── geo_extent.dart │ │ │ │ ├── spatial_extent.dart │ │ │ │ └── temporal_extent.dart │ │ │ └── time │ │ │ │ ├── instant.dart │ │ │ │ ├── interval.dart │ │ │ │ └── temporal.dart │ │ ├── projections │ │ │ ├── ellipsoidal │ │ │ │ ├── base_ellipsoidal_projection.dart │ │ │ │ ├── ellipsoidal_projection_adapter.dart │ │ │ │ └── utm_projection_adapter.dart │ │ │ └── wgs84 │ │ │ │ ├── web_mercator_projection.dart │ │ │ │ └── wgs84.dart │ │ ├── projections_ext │ │ │ └── proj4d │ │ │ │ └── proj4d_adapter.dart │ │ ├── tiling │ │ │ ├── convert │ │ │ │ └── scaled_converter.dart │ │ │ └── tilematrix │ │ │ │ ├── base │ │ │ │ ├── geo_tile_matrix_set.dart │ │ │ │ └── tile_matrix_set.dart │ │ │ │ ├── mercator │ │ │ │ └── web_mercator_quad.dart │ │ │ │ └── plate_carree │ │ │ │ └── global_geodetic_quad.dart │ │ ├── utils │ │ │ ├── bounded_utils.dart │ │ │ ├── byte_reader.dart │ │ │ ├── byte_utils.dart │ │ │ ├── byte_writer.dart │ │ │ ├── coord_arrays_from_json.dart │ │ │ ├── coord_calculations_cartesian.dart │ │ │ ├── coord_positions.dart │ │ │ ├── coord_type.dart │ │ │ ├── coord_utils.dart │ │ │ ├── format_geojson_wkt.dart │ │ │ ├── format_impl.dart │ │ │ ├── format_validation.dart │ │ │ ├── geometry_calculations_cartesian.dart │ │ │ ├── math_utils.dart │ │ │ ├── num.dart │ │ │ ├── object_utils.dart │ │ │ ├── tiny_queue.dart │ │ │ ├── tolerance.dart │ │ │ └── web_mercator_converter.dart │ │ ├── vector │ │ │ ├── content │ │ │ │ ├── coordinates_content.dart │ │ │ │ ├── feature_content.dart │ │ │ │ ├── geometry_content.dart │ │ │ │ └── simple_geometry_content.dart │ │ │ ├── encoding │ │ │ │ ├── binary_format.dart │ │ │ │ ├── content_decoder.dart │ │ │ │ ├── content_encoder.dart │ │ │ │ └── text_format.dart │ │ │ └── formats │ │ │ │ ├── geojson │ │ │ │ ├── default_format.dart │ │ │ │ ├── geojson_decoder.dart │ │ │ │ ├── geojson_format.dart │ │ │ │ └── geojsonl_format.dart │ │ │ │ ├── wkb │ │ │ │ ├── wkb_decoder.dart │ │ │ │ ├── wkb_encoder.dart │ │ │ │ └── wkb_format.dart │ │ │ │ └── wkt │ │ │ │ ├── wkt_decoder.dart │ │ │ │ ├── wkt_format.dart │ │ │ │ └── wkt_like_format.dart │ │ └── vector_data │ │ │ └── model │ │ │ ├── feature │ │ │ ├── feature.dart │ │ │ ├── feature_builder.dart │ │ │ ├── feature_collection.dart │ │ │ └── feature_object.dart │ │ │ └── geometry │ │ │ ├── geometry.dart │ │ │ ├── geometry_builder.dart │ │ │ ├── geometry_collection.dart │ │ │ ├── linestring.dart │ │ │ ├── multi_linestring.dart │ │ │ ├── multi_point.dart │ │ │ ├── multi_polygon.dart │ │ │ ├── point.dart │ │ │ └── polygon.dart │ ├── tiling.dart │ ├── vector.dart │ └── vector_data.dart ├── pubspec.yaml └── test │ ├── advices │ ├── basic_impls.dart │ ├── coordinates_box_test.dart │ ├── coordinates_position_test.dart │ ├── vector_data_feature_test.dart │ └── vector_data_geometry_test.dart │ ├── behaviors │ └── geography_special_cases_test.dart │ ├── common │ └── conversion_test.dart │ ├── coordinates │ ├── box_coords_test.dart │ ├── box_test.dart │ ├── coordinates_bench.dart │ ├── dms_ported_test.dart │ ├── dms_test.dart │ ├── position_coords_test.dart │ ├── position_series_test.dart │ ├── position_test.dart │ └── scalable_test.dart │ ├── geodesy │ ├── ellipsoidal_test.dart │ ├── ellipsoidal_vincenty_test.dart │ ├── spherical_ported_test.dart │ ├── spherical_test.dart │ ├── utm_ported_test.dart │ └── utm_test.dart │ ├── geometric │ ├── cartesian_areal_point_in_polygon_test.dart │ ├── cartesian_areal_polylabel_test.dart │ └── data │ │ ├── water1.json │ │ └── water2.json │ ├── meta │ ├── crs_test.dart │ ├── extent_test.dart │ └── time_test.dart │ ├── projections │ ├── projection_ellipsoidal_test.dart │ ├── projection_sample.dart │ ├── projection_utm_test.dart │ └── projection_web_mercator_test.dart │ ├── projections_ext │ ├── projection_cross_test.dart │ └── projection_proj4_test.dart │ ├── tiling │ ├── global_geodetic_quad_test.dart │ └── web_mercator_quad_test.dart │ ├── utils │ └── byte_writer_reader_test.dart │ ├── vector │ ├── geojson_samples.dart │ ├── geojson_test.dart │ ├── wkb_samples.dart │ ├── wkb_test.dart │ ├── wkt_samples.dart │ └── writer_test.dart │ └── vector_data │ ├── feature_geojsonl_test.dart │ ├── geometry_wkb_test.dart │ ├── geometry_wkt_test.dart │ ├── multi_geometry_test.dart │ ├── vector_data_projections_test.dart │ └── vector_model_test.dart ├── geocore ├── .gitignore ├── CHANGELOG.md ├── LICENSE ├── README.md ├── analysis_options.yaml ├── example │ └── geocore_example.dart ├── lib │ ├── base.dart │ ├── coordinates.dart │ ├── data.dart │ ├── geocore.dart │ └── src │ │ ├── base │ │ ├── spatial.dart │ │ └── spatial │ │ │ ├── batched.dart │ │ │ ├── bounded.dart │ │ │ ├── bounded_series.dart │ │ │ ├── bounds.dart │ │ │ ├── coords.dart │ │ │ ├── geometry.dart │ │ │ ├── point.dart │ │ │ ├── point_series.dart │ │ │ ├── point_wrapper.dart │ │ │ └── spatial.dart │ │ ├── coordinates │ │ ├── geographic.dart │ │ ├── geographic │ │ │ ├── geobounds.dart │ │ │ ├── geopoint.dart │ │ │ ├── geopoint_immutable.dart │ │ │ └── geopoint_wrapper.dart │ │ ├── projected.dart │ │ ├── projected │ │ │ ├── point_immutable.dart │ │ │ └── projected_point.dart │ │ ├── transforms.dart │ │ └── transforms │ │ │ ├── basic.dart │ │ │ └── basic │ │ │ └── basic_transforms.dart │ │ ├── data │ │ ├── feature.dart │ │ ├── feature │ │ │ ├── feature.dart │ │ │ ├── feature_collection.dart │ │ │ └── feature_writable.dart │ │ ├── simple_geometry.dart │ │ └── simple_geometry │ │ │ ├── linestring.dart │ │ │ ├── multi.dart │ │ │ └── polygon.dart │ │ ├── parse │ │ ├── factory.dart │ │ ├── factory │ │ │ ├── factory.dart │ │ │ ├── point.dart │ │ │ └── range.dart │ │ ├── geojson.dart │ │ ├── geojson │ │ │ └── geojson.dart │ │ ├── wkt.dart │ │ └── wkt │ │ │ └── wkt_factory.dart │ │ └── utils │ │ ├── bounds.dart │ │ ├── bounds │ │ └── bounds_builder.dart │ │ ├── distance_haversine.dart │ │ ├── num.dart │ │ ├── num │ │ └── num_utils.dart │ │ ├── wkt.dart │ │ ├── wkt │ │ └── wkt_utils.dart │ │ ├── wkt_data.dart │ │ └── wkt_data │ │ └── wkt_simple_geometry.dart ├── pubspec.yaml └── test │ ├── coordinates │ ├── cartesian_test.dart │ └── geographic_test.dart │ ├── geocore_test.dart │ ├── geojson_sample.dart │ ├── projection_proj4_test.dart │ ├── projection_sample.dart │ ├── projection_web_mercator_test.dart │ ├── transform_test.dart │ └── wkt_test.dart └── geodata ├── .gitignore ├── CHANGELOG.md ├── LICENSE ├── README.md ├── analysis_options.yaml ├── archived └── README.v1.1.0.md ├── assets └── diagrams │ ├── decision_flowchart.png │ ├── decision_flowchart.svg │ ├── feature_data_interfaces.png │ └── feature_data_interfaces.svg ├── example ├── geodata_cli_example.dart ├── geodata_example.dart ├── geojson_example.dart └── ogcapi_features_crs_example.dart ├── lib ├── common.dart ├── core.dart ├── formats.dart ├── geodata.dart ├── geojson_client.dart ├── ogcapi_features_client.dart └── src │ ├── common │ ├── links │ │ ├── link.dart │ │ ├── links.dart │ │ └── links_aware.dart │ ├── meta │ │ └── meta_aware.dart │ ├── paged │ │ └── paged.dart │ └── service │ │ └── service_exception.dart │ ├── core │ ├── base │ │ ├── collection_meta.dart │ │ └── resource_meta.dart │ ├── data │ │ ├── bounded_items_query.dart │ │ ├── geospatial_query.dart │ │ ├── item_query.dart │ │ └── items_query.dart │ └── features │ │ ├── basic_feature_source.dart │ │ ├── feature_failure.dart │ │ ├── feature_item.dart │ │ ├── feature_items.dart │ │ └── feature_source.dart │ ├── formats │ ├── cql2 │ │ └── cql_query.dart │ └── openapi │ │ └── open_api_document.dart │ ├── geojson │ └── service │ │ └── client │ │ └── geojson_feature_client.dart │ ├── ogcapi_common │ ├── model │ │ ├── ogc_collection_meta.dart │ │ ├── ogc_conformance.dart │ │ ├── ogc_queryable_object.dart │ │ ├── ogc_service.dart │ │ └── ogc_service_meta.dart │ └── service │ │ └── client │ │ └── ogc_client.dart │ ├── ogcapi_features │ ├── model │ │ ├── ogc_feature_conformance.dart │ │ ├── ogc_feature_item.dart │ │ ├── ogc_feature_items.dart │ │ ├── ogc_feature_service.dart │ │ └── ogc_feature_source.dart │ └── service │ │ └── client │ │ └── ogc_feature_client.dart │ └── utils │ ├── cached_object.dart │ ├── feature_future_adapter.dart │ ├── feature_http_adapter.dart │ ├── object_utils.dart │ └── resolve_api_call.dart ├── pubspec.yaml └── test ├── data ├── london.geojson └── london.geojsonl ├── geodata_core_test.dart ├── geojson_feature_client_test.dart ├── usgs └── summary │ ├── 2.5_day.geojson │ ├── 2.5_day.geojsonl │ └── readme.txt └── utils └── object_utils_test.dart /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | 3 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The 3-Clause BSD License 2 | 3 | Copyright (c) 2020-2025 Navibyte. All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without modification, 6 | are permitted provided that the following conditions are met: 7 | 8 | 1. Redistributions of source code must retain the above copyright notice, this 9 | list of conditions and the following disclaimer. 10 | 11 | 2. Redistributions in binary form must reproduce the above copyright notice, 12 | this list of conditions and the following disclaimer in the documentation and/or 13 | other materials provided with the distribution. 14 | 15 | 3. Neither the name of the copyright holder nor the names of its contributors 16 | may be used to endorse or promote products derived from this software without 17 | specific prior written permission. 18 | 19 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 20 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 21 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 22 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 23 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 24 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 25 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 26 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 28 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | -------------------------------------------------------------------------------- /dart/README.md: -------------------------------------------------------------------------------- 1 | ## :compass: Dart code for geospatial tools 2 | 3 | **Geospatial** data structures, tools and utilities for 4 | [Dart](https://dart.dev/) and [Flutter](https://flutter.dev/) - coordinates, 5 | geometries, feature objects, metadata, spherical geodesy, projections, tiling 6 | schemes, vector data models and formats, and geospatial Web APIs. 7 | 8 | This folder contains [Dart](https://dart.dev/) code for packages published at 9 | [pub.dev](https://pub.dev/publishers/navibyte.com/packages): 10 | 11 | Code | Package | Description 12 | -------------- | --------| ----------- 13 | :globe_with_meridians: [geobase](geobase) | [![pub package](https://img.shields.io/pub/v/geobase.svg)](https://pub.dev/packages/geobase) | Geospatial data structures (coordinates, geometries, features, metadata), spherical geodesy, projections and tiling schemes. Vector data format support for [GeoJSON](https://geojson.org/), [WKT](https://en.wikipedia.org/wiki/Well-known_text_representation_of_geometry) and [WKB](https://en.wikipedia.org/wiki/Well-known_text_representation_of_geometry#Well-known_binary). 14 | :earth_americas: [geodata](geodata) | [![pub package](https://img.shields.io/pub/v/geodata.svg)](https://pub.dev/packages/geodata) | Geospatial feature service Web APIs with support for [GeoJSON](https://geojson.org/) and [OGC API Features](https://ogcapi.ogc.org/features/) clients. 15 | 16 | See code and package links above or 17 | [the repository root](https://github.com/navibyte/geospatial) for more 18 | information. -------------------------------------------------------------------------------- /dart/dart_analyze.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # analyze all packages 3 | 4 | cd geobase && echo "geobase" && dart analyze 5 | cd ../geocore && echo "geocore" && dart analyze 6 | cd ../geodata && echo "geodata" && dart analyze 7 | cd ../.. -------------------------------------------------------------------------------- /dart/dart_downgrade.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # downgrade all packages 3 | 4 | cd geobase && echo "geobase" && dart pub downgrade 5 | cd ../geocore && echo "geocore" && dart pub downgrade 6 | cd ../geodata && echo "geodata" && dart pub downgrade 7 | cd ../.. -------------------------------------------------------------------------------- /dart/dart_format.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # format all packages 3 | 4 | cd geobase && echo "geobase" && dart format lib example test 5 | cd ../geocore && echo "geocore" && dart format lib example test 6 | cd ../geodata && echo "geodata" && dart format lib example test 7 | cd .. 8 | -------------------------------------------------------------------------------- /dart/dart_run_examples.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # test all packages 3 | 4 | cd geobase && echo "geobase" && dart example/geobase_example.dart && dart example/geobase_with_proj4d_example.dart 5 | cd ../geocore && echo "geocore" && dart example/geocore_example.dart 6 | cd ../geodata && echo "geodata" && dart example/geodata_example.dart && dart example/geojson_example.dart && dart example/ogcapi_features_crs_example.dart 7 | cd ../.. 8 | -------------------------------------------------------------------------------- /dart/dart_test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # test all packages 3 | 4 | cd geobase && echo "geobase" && dart test 5 | cd ../geocore && echo "geocore" && dart test 6 | cd ../geodata && echo "geodata" && dart test 7 | cd ../.. -------------------------------------------------------------------------------- /dart/dart_upgrade.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # upgrade all packages 3 | 4 | cd geobase && echo "geobase" && dart pub upgrade 5 | cd ../geocore && echo "geocore" && dart pub upgrade 6 | cd ../geodata && echo "geodata" && dart pub upgrade 7 | cd ../.. -------------------------------------------------------------------------------- /dart/geobase/.gitignore: -------------------------------------------------------------------------------- 1 | # Files and directories created by pub. 2 | .dart_tool/ 3 | .packages 4 | 5 | # Conventional directory for build outputs. 6 | build/ 7 | 8 | # Omit committing pubspec.lock for library packages; see 9 | # https://dart.dev/guides/libraries/private-files#pubspeclock. 10 | pubspec.lock 11 | -------------------------------------------------------------------------------- /dart/geobase/LICENSE: -------------------------------------------------------------------------------- 1 | The 3-Clause BSD License 2 | 3 | Copyright (c) 2020-2025 Navibyte. All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without modification, 6 | are permitted provided that the following conditions are met: 7 | 8 | 1. Redistributions of source code must retain the above copyright notice, this 9 | list of conditions and the following disclaimer. 10 | 11 | 2. Redistributions in binary form must reproduce the above copyright notice, 12 | this list of conditions and the following disclaimer in the documentation and/or 13 | other materials provided with the distribution. 14 | 15 | 3. Neither the name of the copyright holder nor the names of its contributors 16 | may be used to endorse or promote products derived from this software without 17 | specific prior written permission. 18 | 19 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 20 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 21 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 22 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 23 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 24 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 25 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 26 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 28 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- /dart/geobase/assets/diagrams/feature_objects.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/navibyte/geospatial/c4e06ef8af7c0808e6c52f529e7d249b732476db/dart/geobase/assets/diagrams/feature_objects.png -------------------------------------------------------------------------------- /dart/geobase/assets/diagrams/meta_temporal_extent.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/navibyte/geospatial/c4e06ef8af7c0808e6c52f529e7d249b732476db/dart/geobase/assets/diagrams/meta_temporal_extent.png -------------------------------------------------------------------------------- /dart/geobase/assets/diagrams/multi_and_collection_geometries.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/navibyte/geospatial/c4e06ef8af7c0808e6c52f529e7d249b732476db/dart/geobase/assets/diagrams/multi_and_collection_geometries.png -------------------------------------------------------------------------------- /dart/geobase/assets/diagrams/point_linestring_polygon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/navibyte/geospatial/c4e06ef8af7c0808e6c52f529e7d249b732476db/dart/geobase/assets/diagrams/point_linestring_polygon.png -------------------------------------------------------------------------------- /dart/geobase/assets/diagrams/position_box_scalable.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/navibyte/geospatial/c4e06ef8af7c0808e6c52f529e7d249b732476db/dart/geobase/assets/diagrams/position_box_scalable.png -------------------------------------------------------------------------------- /dart/geobase/example/geobase_with_proj4d_example.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2023 Navibyte (https://navibyte.com). All rights reserved. 2 | // Use of this source code is governed by a “BSD-3-Clause”-style license that is 3 | // specified in the LICENSE file. 4 | // 5 | // Docs: https://github.com/navibyte/geospatial 6 | 7 | // ignore_for_file: avoid_print, cascade_invocations 8 | 9 | // import the default geobase library 10 | import 'package:geobase/geobase.dart'; 11 | 12 | // need also an additional import with dependency to `proj4dart` 13 | import 'package:geobase/projections_proj4d.dart'; 14 | 15 | /* 16 | To test run this from command line: 17 | 18 | dart example/geobase_with_proj4d_example.dart 19 | */ 20 | 21 | void main() { 22 | // projection samples 23 | _proj4projections(); 24 | } 25 | 26 | void _proj4projections() { 27 | // Coordinate projections based on the external proj4dart package. 28 | 29 | // The projection adapter between WGS84 (CRS84) and EPSG:23700 (definition) 30 | // (based on the sample at https://pub.dev/packages/proj4dart). 31 | final adapter = Proj4d.init( 32 | CoordRefSys.CRS84, 33 | CoordRefSys.normalized('EPSG:23700'), 34 | targetDef: '+proj=somerc +lat_0=47.14439372222222 +lon_0=19.04857177777778 ' 35 | '+k_0=0.99993 +x_0=650000 +y_0=200000 +ellps=GRS67 ' 36 | '+towgs84=52.17,-71.82,-14.9,0,0,0,0 +units=m +no_defs', 37 | ); 38 | 39 | // The forward projection from WGS84 (CRS84) to EPSG:23700. 40 | final forward = adapter.forward; 41 | 42 | // A source geographic position. 43 | const geographic = Geographic(lat: 46.8922, lon: 17.8880); 44 | 45 | // Apply the forward projection returning a projected position in EPSG:23700. 46 | final projected = geographic.project(forward); 47 | 48 | // Prints: "561647.27300,172651.56518" 49 | print(projected.toText(decimals: 5)); 50 | } 51 | -------------------------------------------------------------------------------- /dart/geobase/lib/coordinates.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2025 Navibyte (https://navibyte.com). All rights reserved. 2 | // Use of this source code is governed by a “BSD-3-Clause”-style license that is 3 | // specified in the LICENSE file. 4 | // 5 | // Docs: https://github.com/navibyte/geospatial 6 | 7 | /// Position, bounding box and positions series (with coordinate arrays). 8 | /// 9 | /// Contains also geographic (longitude-latitude) and projected positions and 10 | /// bounding boxes, scalable coordinates, and projection abstraction classes. 11 | /// 12 | /// This libary exports a subset of `package:geobase/geobase.dart`. 13 | /// 14 | /// Usage: import `package:geobase/coordinates.dart` 15 | library coordinates; 16 | 17 | export 'src/common/codes/axis_order.dart'; 18 | export 'src/common/codes/cardinal_precision.dart'; 19 | export 'src/common/codes/coords.dart'; 20 | export 'src/common/codes/dimensionality.dart'; 21 | export 'src/common/codes/dms_type.dart'; 22 | export 'src/common/codes/geo_representation.dart'; 23 | export 'src/common/constants/epsilon.dart'; 24 | export 'src/common/functions/geographic_functions.dart'; 25 | export 'src/common/functions/position_functions.dart'; 26 | export 'src/common/presentation/dms.dart'; 27 | export 'src/common/reference/coord_ref_sys.dart'; 28 | export 'src/coordinates/base/aligned.dart'; 29 | export 'src/coordinates/base/bounded.dart'; 30 | export 'src/coordinates/base/box.dart'; 31 | export 'src/coordinates/base/position.dart'; 32 | export 'src/coordinates/base/position_extensions.dart'; 33 | export 'src/coordinates/base/position_scheme.dart'; 34 | export 'src/coordinates/base/position_series.dart'; 35 | export 'src/coordinates/base/positionable.dart'; 36 | export 'src/coordinates/base/value_positionable.dart'; 37 | export 'src/coordinates/geographic/geobox.dart'; 38 | export 'src/coordinates/geographic/geographic.dart'; 39 | export 'src/coordinates/geographic/geographic_bearing.dart'; 40 | export 'src/coordinates/projected/projbox.dart'; 41 | export 'src/coordinates/projected/projected.dart'; 42 | export 'src/coordinates/projection/projection.dart'; 43 | export 'src/coordinates/projection/projection_adapter.dart'; 44 | export 'src/coordinates/scalable/scalable.dart'; 45 | export 'src/coordinates/scalable/scalable2i.dart'; 46 | -------------------------------------------------------------------------------- /dart/geobase/lib/geodesy.dart: -------------------------------------------------------------------------------- 1 | /// Ellipsoidal (*vincenty*) and spherical (*great circle*, *rhumb line*) 2 | /// geodesy tools, with ellipsoidal datum, UTM, MGRS and ECEF support. 3 | /// 4 | /// This libary exports a subset of `package:geobase/geobase.dart`. 5 | /// 6 | /// Usage: import `package:geobase/geodesy.dart` 7 | library geodesy; 8 | 9 | export 'src/common/codes/coord_ref_sys_type.dart'; 10 | export 'src/common/codes/coords.dart'; 11 | export 'src/common/codes/hemisphere.dart'; 12 | export 'src/common/constants/geodetic.dart'; 13 | export 'src/common/functions/geographic_functions.dart'; 14 | export 'src/common/functions/position_functions.dart'; 15 | export 'src/common/reference/ellipsoid.dart'; 16 | export 'src/geodesy/base/geodetic_arc_segment.dart'; 17 | export 'src/geodesy/ellipsoidal/datum.dart' 18 | hide 19 | convertDatumToDatum, 20 | convertDatumToDatumCoords, 21 | convertGeocentricCartesianInternal, 22 | convertGeographicInternal; 23 | export 'src/geodesy/ellipsoidal/ellipsoidal.dart' 24 | hide geocentricCartesianToGeographic, geographicToGeocentricCartesian; 25 | export 'src/geodesy/ellipsoidal/ellipsoidal_extension.dart'; 26 | export 'src/geodesy/ellipsoidal/ellipsoidal_vincenty.dart'; 27 | export 'src/geodesy/ellipsoidal/utm.dart' 28 | hide convertUtm, convertUtmCoords, geographicToUtm, utmToGeographic; 29 | export 'src/geodesy/ellipsoidal/utm_mgrs.dart'; 30 | export 'src/geodesy/spherical/spherical_great_circle.dart'; 31 | export 'src/geodesy/spherical/spherical_rhumb_line.dart'; 32 | -------------------------------------------------------------------------------- /dart/geobase/lib/geometric.dart: -------------------------------------------------------------------------------- 1 | /// Cartesian 2D calculations (centroid, polylabel, point-in-polygon, distance). 2 | /// 3 | /// This libary exports a subset of `package:geobase/geobase.dart`. 4 | /// 5 | /// Usage: import `package:geobase/geometric.dart` 6 | library geometric; 7 | 8 | export 'src/geometric/base/distanced_position.dart'; 9 | export 'src/geometric/cartesian/areal/cartesian_areal_extension.dart'; 10 | -------------------------------------------------------------------------------- /dart/geobase/lib/meta.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2025 Navibyte (https://navibyte.com). All rights reserved. 2 | // Use of this source code is governed by a “BSD-3-Clause”-style license that is 3 | // specified in the LICENSE file. 4 | // 5 | // Docs: https://github.com/navibyte/geospatial 6 | 7 | /// Temporal data structures (instant, interval) and spatial extents. 8 | /// 9 | /// This libary exports a subset of `package:geobase/geobase.dart`. 10 | /// 11 | /// Usage: import `package:geobase/meta.dart` 12 | library meta; 13 | 14 | export 'src/common/reference/coord_ref_sys.dart'; 15 | export 'src/common/reference/temporal_ref_sys.dart'; 16 | export 'src/meta/extent/geo_extent.dart'; 17 | export 'src/meta/extent/spatial_extent.dart'; 18 | export 'src/meta/extent/temporal_extent.dart'; 19 | export 'src/meta/time/instant.dart'; 20 | export 'src/meta/time/interval.dart'; 21 | export 'src/meta/time/temporal.dart'; 22 | -------------------------------------------------------------------------------- /dart/geobase/lib/projections_proj4d.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2025 Navibyte (https://navibyte.com). All rights reserved. 2 | // Use of this source code is governed by a “BSD-3-Clause”-style license that is 3 | // specified in the LICENSE file. 4 | // 5 | // Docs: https://github.com/navibyte/geospatial 6 | 7 | /// Projections provided by the external `proj4dart` package. 8 | /// 9 | /// This package implements a projection adapter that acts as a wrapper and uses 10 | /// internally the projection and coordinate reference system support of the 11 | /// `proj4dart` package to which there's a dependency. 12 | /// 13 | /// Usage: import `package:geobase/projections_proj4d.dart` 14 | /// 15 | /// You might want to import also `package:geobase/geobase.dart` providing base 16 | /// classes. 17 | library projections_proj4d; 18 | 19 | export 'src/common/reference/coord_ref_sys.dart'; 20 | export 'src/projections_ext/proj4d/proj4d_adapter.dart'; 21 | -------------------------------------------------------------------------------- /dart/geobase/lib/src/common/codes/axis_order.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2023 Navibyte (https://navibyte.com). All rights reserved. 2 | // Use of this source code is governed by a “BSD-3-Clause”-style license that is 3 | // specified in the LICENSE file. 4 | // 5 | // Docs: https://github.com/navibyte/geospatial 6 | 7 | /// The axis order of coordinate values in position and point representations. 8 | /// 9 | /// Internally this library uses [xy] order for geographic and projected 10 | /// coordinates. 11 | /// 12 | /// However external geospatial data representations both for human (ie. a 13 | /// common decimal degrees repsenting latitude before longitude) and machine 14 | /// interfaces (ie. formats like WKT, GeoJSON or data protocols like WFS and OGC 15 | /// API standards) may specify either [xy] or [yx] order for coordinates. 16 | enum AxisOrder { 17 | /// The axis order in position and point representations is expected to be 18 | /// `(longitude, latitude)` for geographic coordinates, `(easting, northing)` 19 | /// for projected map coordinates, and `(x, y)` for other cartesian 20 | /// coordinates. 21 | /// 22 | /// This is also the internal representation of coordinates in this library. 23 | xy, 24 | 25 | /// The axis order in position and point representations is expected to be 26 | /// `(latitude, longitude)` for geographic coordinates, `(northing, easting)` 27 | /// for projected map coordinates, and `(y, x)` for other cartesian 28 | /// coordinates. 29 | yx, 30 | } 31 | -------------------------------------------------------------------------------- /dart/geobase/lib/src/common/codes/canvas_origin.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2023 Navibyte (https://navibyte.com). All rights reserved. 2 | // Use of this source code is governed by a “BSD-3-Clause”-style license that is 3 | // specified in the LICENSE file. 4 | // 5 | // Docs: https://github.com/navibyte/geospatial 6 | 7 | /// The position of the origin in a canvas or a grid. 8 | enum CanvasOrigin { 9 | /// The origin is positioned at the top-left corner of a canvas or a grid. 10 | topLeft, 11 | 12 | /// The origin is positioned at the bottom-left corner of a canvas or a grid. 13 | bottomLeft, 14 | } 15 | -------------------------------------------------------------------------------- /dart/geobase/lib/src/common/codes/cardinal_precision.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2023 Navibyte (https://navibyte.com). All rights reserved. 2 | // Use of this source code is governed by a “BSD-3-Clause”-style license that is 3 | // specified in the LICENSE file. 4 | // 5 | // Docs: https://github.com/navibyte/geospatial 6 | 7 | /// The precision for cardinal directions (compass point). 8 | enum CardinalPrecision { 9 | /// Supported directions: N, E, S, W. 10 | cardinal(1), 11 | 12 | /// Supported directions: N, NE, E, SE, S, SW, W, NW. 13 | intercardinal(2), 14 | 15 | /// Supported directions: N, NNE, NE, ENE, E, ESE, SE, SSE, S, SSW, SW, WSW, 16 | /// W, WNW, NW, NNW. 17 | secondaryIntercardinal(3); 18 | 19 | /// A numeric value (1, 2 or 3) descibing the precision. 20 | final int value; 21 | 22 | const CardinalPrecision(this.value); 23 | } 24 | -------------------------------------------------------------------------------- /dart/geobase/lib/src/common/codes/dimensionality.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2023 Navibyte (https://navibyte.com). All rights reserved. 2 | // Use of this source code is governed by a “BSD-3-Clause”-style license that is 3 | // specified in the LICENSE file. 4 | // 5 | // Docs: https://github.com/navibyte/geospatial 6 | 7 | /// An enum for *dimensionality* or *topological dimension* in the context of 8 | /// geospatial applications. 9 | enum Dimensionality { 10 | /// A dimensionality representing a *punctual* geometry (or position, point, 11 | /// vertex, node, marker etc.) with the topological dimension of `0`. 12 | punctual(0), 13 | 14 | /// A dimensionality representing a *linear* geometry (or chain, line string, 15 | /// polyline, path, curve etc.) with the topological dimension of `1`. 16 | linear(1), 17 | 18 | /// A dimensionality representing an *areal* geometry (or polygon, area, 19 | /// surface, box etc.) with the topological dimension of `2`. 20 | areal(2), 21 | 22 | /// A dimensionality representing a *volymetric* geometry (or tetrahedron, 23 | /// polyhedron, volyme, cube etc.) with the topological dimension of `3`. 24 | volymetric(3); 25 | 26 | const Dimensionality(this.topologicalDimension); 27 | 28 | /// The topological dimension (`0`: punctual, `1`: linear, `2`: areal, 29 | /// `3`: volymetric). 30 | final int topologicalDimension; 31 | } 32 | -------------------------------------------------------------------------------- /dart/geobase/lib/src/common/codes/dms_type.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2023 Navibyte (https://navibyte.com). All rights reserved. 2 | // Use of this source code is governed by a “BSD-3-Clause”-style license that is 3 | // specified in the LICENSE file. 4 | // 5 | // Docs: https://github.com/navibyte/geospatial 6 | 7 | /// An enum for common representation of geographic positions by coordinates 8 | /// (using degrees, minutes and seconds as components). 9 | enum DmsType { 10 | /// Format degree values as decimal degrees, ie. '23.6200°W'. 11 | deg, 12 | 13 | /// Format degree values using the "degrees/minutes" pattern, ie. 14 | /// '23°37.20′W'. 15 | degMin, 16 | 17 | /// Format degree values using the "degrees/minutes/seconds" pattern, ie. 18 | /// '23°37′12″W'. 19 | degMinSec 20 | } 21 | -------------------------------------------------------------------------------- /dart/geobase/lib/src/common/codes/hemisphere.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2025 Navibyte (https://navibyte.com). All rights reserved. 2 | // Use of this source code is governed by a “BSD-3-Clause”-style license that is 3 | // specified in the LICENSE file. 4 | // 5 | // Docs: https://github.com/navibyte/geospatial 6 | 7 | /// An enum representing the hemispheres of the Earth. 8 | enum Hemisphere { 9 | /// The northern hemisphere with the [symbol] representing 'N'. 10 | north('N'), 11 | 12 | /// The southern hemisphere with the [symbol] representing 'S'. 13 | south('S'); 14 | 15 | /// The symbol of the hemisphere ('N' or 'S'). 16 | final String symbol; 17 | 18 | const Hemisphere(this.symbol); 19 | 20 | /// Get a hemisphere by its [symbol]. 21 | static Hemisphere fromSymbol(String symbol) { 22 | switch (symbol.toUpperCase()) { 23 | case 'N': 24 | return north; 25 | case 'S': 26 | return south; 27 | default: 28 | throw FormatException('Invalid hemisphere symbol: $symbol'); 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /dart/geobase/lib/src/common/constants/epsilon.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2023 Navibyte (https://navibyte.com). All rights reserved. 2 | // Use of this source code is governed by a “BSD-3-Clause”-style license that is 3 | // specified in the LICENSE file. 4 | // 5 | // Docs: https://github.com/navibyte/geospatial 6 | 7 | /// The default epsilon value `1.0e-9` used as a tolerance in `equals2D`, 8 | /// `equals3D` and similar methods in this package. 9 | /// 10 | /// NOTE: this value can be still adjusted to meet general geospatial use cases 11 | /// considering different coordinate types and accuracy requirements. 12 | /// 13 | /// See also [doublePrecisionEpsilon] and 14 | /// [decimal degree precision](https://en.wikipedia.org/wiki/Decimal_degrees). 15 | const double defaultEpsilon = 1.0e-9; 16 | 17 | /// The maximum relative precision of double numbers (IEEE 754). 18 | /// 19 | /// The constant value can be calculated as `pow(2, -52) as double`. 20 | /// 21 | /// See the Wikipedia article about 22 | /// [Machine epsilon](https://en.wikipedia.org/wiki/Machine_epsilon). 23 | const double doublePrecisionEpsilon = 2.220446049250313e-16; 24 | -------------------------------------------------------------------------------- /dart/geobase/lib/src/common/constants/geodetic.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2023 Navibyte (https://navibyte.com). All rights reserved. 2 | // Use of this source code is governed by a “BSD-3-Clause”-style license that is 3 | // specified in the LICENSE file. 4 | // 5 | // Docs: https://github.com/navibyte/geospatial 6 | 7 | import 'dart:math' as math; 8 | 9 | /// The minimum value for the geographic longitude. 10 | /// 11 | /// The value is `-180.0`. 12 | const minLongitude = -180.0; 13 | 14 | /// The maximum value for the geographic longitude. 15 | /// 16 | /// The value is `180.0`. 17 | const maxLongitude = 180.0; 18 | 19 | /// The minimum value for the geographic latitude. 20 | /// 21 | /// The value is `-90.0`. 22 | const minLatitude = -90.0; 23 | 24 | /// The maximum value for the geographic latitude. 25 | /// 26 | /// The value is `90.0`. 27 | const maxLatitude = 90.0; 28 | 29 | /// The minimum value for the geographic latitude inside the Web Mercator 30 | /// projection coverage. 31 | /// 32 | /// The value is `-85.05112878`. 33 | const minLatitudeWebMercator = -85.05112878; 34 | 35 | /// The maximum value for the geographic latitude inside the Web Mercator 36 | /// projection coverage. 37 | /// 38 | /// The value is `85.05112878`. 39 | const maxLatitudeWebMercator = 85.05112878; 40 | 41 | /// The minimum value for the geographic latitude inside the Universal 42 | /// Transverse Mercator (UTM) projection coverage. 43 | /// 44 | /// The value is `-80.0`. 45 | const minLatitudeUTM = -80.0; 46 | 47 | /// The maximum value for the geographic latitude inside the Universal 48 | /// Transverse Mercator (UTM) projection coverage. 49 | /// 50 | /// The value is `84.0`. 51 | const maxLatitudeUTM = 84.0; 52 | 53 | /// The earth equatorial radius in meters as specified by WGS 84. 54 | /// 55 | /// The value is `6378137.0`. 56 | const earthRadiusWgs84 = 6378137.0; 57 | 58 | /// The earth circumference in meters (from earth equatorial radius by WGS 84). 59 | const earthCircumferenceWgs84 = 2 * math.pi * earthRadiusWgs84; 60 | -------------------------------------------------------------------------------- /dart/geobase/lib/src/common/constants/screen_ppi.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2023 Navibyte (https://navibyte.com). All rights reserved. 2 | // Use of this source code is governed by a “BSD-3-Clause”-style license that is 3 | // specified in the LICENSE file. 4 | // 5 | // Docs: https://github.com/navibyte/geospatial 6 | 7 | /// OGC defines a screen pixel of 0.28 mm that approximates to 90.7 ppi. 8 | /// 9 | /// OGC specifies: `pixelResolution = 0.00028 * scaleDenominator` that gives 10 | /// `scaleDenominator = pixelResolution / 0.00028`. 11 | /// 12 | /// Another way to calculate a scale denominator: 13 | /// `scaleDenominator = pixelResolution * screenPPI / 0.0254` 14 | /// 15 | /// This constant: `screenPPIbyOGC = 0.0254 / 0.00028` 16 | /// 17 | /// Abbreviations: 18 | /// * PPI = pixels per inch 19 | /// * OGC = The Open Geospatial Consortium 20 | const screenPPIbyOGC = 0.0254 / 0.00028; 21 | -------------------------------------------------------------------------------- /dart/geobase/lib/src/common/conversions/angle_unit.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2025 Navibyte (https://navibyte.com). All rights reserved. 2 | // Use of this source code is governed by a “BSD-3-Clause”-style license that is 3 | // specified in the LICENSE file. 4 | // 5 | // Docs: https://github.com/navibyte/geospatial 6 | 7 | import 'dart:math'; 8 | 9 | /// An enumeration of angle units. 10 | /// 11 | /// The units are defined with conversion factors to radians. 12 | /// 13 | /// Examples: 14 | /// 15 | /// ```dart 16 | /// // Convert directly from and to radians. 17 | /// final radians = 3.14159; // ~pi 18 | /// final degrees = AngleUnit.degree.fromRadians(radians); // ~180.0 19 | /// final radians2 = AngleUnit.degree.toRadians(degrees); // ~3.14159 20 | /// 21 | /// // You can also convert between units without using radians. 22 | /// final gradians = 23 | /// AngleUnit.degree.toUnit(degrees, AngleUnit.gradian); // ~200.0 24 | /// ``` 25 | /// 26 | /// See also [Angle](https://en.wikipedia.org/wiki/Angle) in Wikipedia. 27 | enum AngleUnit { 28 | /// 1 milliradian is equal to 0.001 radians. 29 | milliradian(0.001, 'mrad'), 30 | 31 | /// The SI base unit for angles. 32 | /// 33 | /// 1 radian is approximately 57.296 degrees. 34 | radian(1.0, 'rad'), 35 | 36 | /// 1 arc second is equal to π / (180 * 60 * 60) radians. 37 | /// 38 | /// 1 degree contains 60 * 60 = 3600 arc seconds. 39 | arcSecond(pi / (180 * 60 * 60), 'arcsec'), 40 | 41 | /// 1 arc minute is equal to π / (180 * 60) radians. 42 | /// 43 | /// 1 degree contains 60 arc minutes. 44 | arcMinute(pi / (180 * 60), 'arcmin'), 45 | 46 | /// 1 degree is equal to π / 180 radians. 47 | /// 48 | /// 1 degree is 1/360 of a full circle. 49 | degree(pi / 180, 'deg'), 50 | 51 | /// 1 gradian is equal to π / 200 radians. 52 | /// 53 | /// 1 gradian is 1/400 of a full circle. 54 | gradian(pi / 200, 'gon'), 55 | 56 | /// 1 turn is equal to 2π radians. 57 | /// 58 | /// 1 turn is a full circle. 59 | turn(2 * pi, 'turn'); 60 | 61 | /// The conversion factor to radians. 62 | final double factorToRadians; 63 | 64 | /// The unit symbol. 65 | final String symbol; 66 | 67 | const AngleUnit(this.factorToRadians, this.symbol); 68 | 69 | /// Convert a value from this unit to radians. 70 | double toRadians(double value) { 71 | return value * factorToRadians; 72 | } 73 | 74 | /// Convert a value from radians to this unit. 75 | double fromRadians(double value) { 76 | return value / factorToRadians; 77 | } 78 | 79 | /// Convert a value from this unit to another unit. 80 | double toUnit(double value, AngleUnit targetUnit) { 81 | final valueInRadians = toRadians(value); 82 | return targetUnit.fromRadians(valueInRadians); 83 | } 84 | 85 | /// Convert a value from another unit to this unit. 86 | double fromUnit(double value, AngleUnit sourceUnit) { 87 | final valueInRadians = sourceUnit.toRadians(value); 88 | return fromRadians(valueInRadians); 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /dart/geobase/lib/src/common/conversions/angular_velocity_unit.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2025 Navibyte (https://navibyte.com). All rights reserved. 2 | // Use of this source code is governed by a “BSD-3-Clause”-style license that is 3 | // specified in the LICENSE file. 4 | // 5 | // Docs: https://github.com/navibyte/geospatial 6 | 7 | import 'dart:math'; 8 | 9 | /// An enumeration of angular velocity units. 10 | /// 11 | /// The units are defined with conversion factors to radians per second. 12 | /// 13 | /// Examples: 14 | /// 15 | /// ```dart 16 | /// // Convert directly from and to radians per second. 17 | /// final radiansPerSecond = 6.28319; 18 | /// final rpmUnit = AngularVelocityUnit.revolutionPerMinute; 19 | /// final rpm = rpmUnit.fromRadiansPerSecond(radiansPerSecond); // ~60.0 20 | /// final radiansPerSecond2 = rpmUnit.toRadiansPerSecond(rpm); // ~6.28319 21 | /// 22 | /// // You can also convert between units without using radians per second. 23 | /// final degreesPerSecond = 24 | /// rpmUnit.toUnit(rpm, AngularVelocityUnit.degreePerSecond); // ~360.0 25 | /// ``` 26 | /// 27 | /// See also [Angular velocity](https://en.wikipedia.org/wiki/Angular_velocity) 28 | /// in Wikipedia. 29 | enum AngularVelocityUnit { 30 | /// 1 degree per second (°/s) is equal to π / 180 radians per second. 31 | degreePerSecond(pi / 180, 'deg/s'), 32 | 33 | /// 1 radian per second is the base unit for angular velocity. 34 | radianPerSecond(1.0, 'rad/s'), 35 | 36 | /// 1 revolution per minute is equal to 2π / 60 radians per second. 37 | revolutionPerMinute(2 * pi / 60, 'rpm'), 38 | 39 | /// 1 revolution per second is equal to 2π radians per second. 40 | revolutionPerSecond(2 * pi, 'rps'), 41 | 42 | /// 1 milliradian per second is equal to 0.001 radians per second. 43 | milliradianPerSecond(0.001, 'mrad/s'); 44 | 45 | /// The conversion factor to radians per second. 46 | final double factorToRadiansPerSecond; 47 | 48 | /// The unit symbol. 49 | final String symbol; 50 | 51 | const AngularVelocityUnit(this.factorToRadiansPerSecond, this.symbol); 52 | 53 | /// Convert a value from this unit to radians per second. 54 | double toRadiansPerSecond(double value) { 55 | return value * factorToRadiansPerSecond; 56 | } 57 | 58 | /// Convert a value from radians per second to this unit. 59 | double fromRadiansPerSecond(double value) { 60 | return value / factorToRadiansPerSecond; 61 | } 62 | 63 | /// Convert a value from this unit to another unit. 64 | double toUnit(double value, AngularVelocityUnit targetUnit) { 65 | final valueInRadiansPerSecond = toRadiansPerSecond(value); 66 | return targetUnit.fromRadiansPerSecond(valueInRadiansPerSecond); 67 | } 68 | 69 | /// Convert a value from another unit to this unit. 70 | double fromUnit(double value, AngularVelocityUnit sourceUnit) { 71 | final valueInRadiansPerSecond = sourceUnit.toRadiansPerSecond(value); 72 | return fromRadiansPerSecond(valueInRadiansPerSecond); 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /dart/geobase/lib/src/common/conversions/area_unit.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2025 Navibyte (https://navibyte.com). All rights reserved. 2 | // Use of this source code is governed by a “BSD-3-Clause”-style license that is 3 | // specified in the LICENSE file. 4 | // 5 | // Docs: https://github.com/navibyte/geospatial 6 | 7 | /// An enumeration of area units. 8 | /// 9 | /// The units are defined with conversion factors to square meters. 10 | /// 11 | /// Examples: 12 | /// 13 | /// ```dart 14 | /// // Convert directly from and to square meters. 15 | /// final squareMeters = 10000.0; 16 | /// final sqKmUnit = AreaUnit.squareKilometer; 17 | /// final squareKilometers = sqKmUnit.fromSquareMeters(squareMeters); // 0.01 18 | /// final squareMeters2 = sqKmUnit.toSquareMeters(squareKilometers); // 10000.0 19 | /// 20 | /// // You can also convert between units without using square meters. 21 | /// final acres = sqKmUnit.toUnit(squareKilometers, AreaUnit.acre); // ~2.4711 22 | /// ``` 23 | /// 24 | /// See also [Area](https://en.wikipedia.org/wiki/Area) in Wikipedia. 25 | enum AreaUnit { 26 | /// 1 square millimeter is equal to 1e-6 square meters. 27 | squareMillimeter(1e-6, 'mm²'), 28 | 29 | /// 1 square centimeter is equal to 1e-4 square meters. 30 | squareCentimeter(1e-4, 'cm²'), 31 | 32 | /// The SI base unit for area. 33 | squareMeter(1.0, 'm²'), 34 | 35 | /// 1 square kilometer is equal to 1e+6 square meters. 36 | squareKilometer(1e6, 'km²'), 37 | 38 | /// 1 square inch is equal to 0.00064516 square meters. 39 | squareInch(0.00064516, 'in²'), 40 | 41 | /// 1 square foot is equal to 0.09290304 square meters. 42 | squareFoot(0.09290304, 'ft²'), 43 | 44 | /// 1 square yard is equal to 0.83612736 square meters. 45 | squareYard(0.83612736, 'yd²'), 46 | 47 | /// 1 square mile is equal to 2589988.11 square meters. 48 | squareMile(2589988.11, 'mi²'), 49 | 50 | /// 1 acre is equal to 4046.8564224 square meters. 51 | acre(4046.8564224, 'ac'), 52 | 53 | /// 1 hectare is equal to 10000 square meters. 54 | hectare(10000.0, 'ha'); 55 | 56 | /// The conversion factor to square meters. 57 | final double factorToSquareMeters; 58 | 59 | /// The unit symbol. 60 | final String symbol; 61 | 62 | const AreaUnit(this.factorToSquareMeters, this.symbol); 63 | 64 | /// Convert a value from this unit to square meters. 65 | double toSquareMeters(double value) { 66 | return value * factorToSquareMeters; 67 | } 68 | 69 | /// Convert a value from square meters to this unit. 70 | double fromSquareMeters(double value) { 71 | return value / factorToSquareMeters; 72 | } 73 | 74 | /// Convert a value from this unit to another unit. 75 | double toUnit(double value, AreaUnit targetUnit) { 76 | final valueInSquareMeters = toSquareMeters(value); 77 | return targetUnit.fromSquareMeters(valueInSquareMeters); 78 | } 79 | 80 | /// Convert a value from another unit to this unit. 81 | double fromUnit(double value, AreaUnit sourceUnit) { 82 | final valueInSquareMeters = sourceUnit.toSquareMeters(value); 83 | return fromSquareMeters(valueInSquareMeters); 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /dart/geobase/lib/src/common/conversions/length_unit.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2025 Navibyte (https://navibyte.com). All rights reserved. 2 | // Use of this source code is governed by a “BSD-3-Clause”-style license that is 3 | // specified in the LICENSE file. 4 | // 5 | // Docs: https://github.com/navibyte/geospatial 6 | 7 | /// An enumeration of length (distance) units. 8 | /// 9 | /// The units are defined with conversion factors to meters. 10 | /// 11 | /// Examples: 12 | /// 13 | /// ```dart 14 | /// // Convert directly from and to meters. 15 | /// final meters = 4000.0; 16 | /// final kmUnit = LengthUnit.kilometer; 17 | /// final kilometers = kmUnit.fromMeters(meters); // 4.0 18 | /// final meters2 = kmUnit.toMeters(kilometers); // 4000.0 19 | /// 20 | /// // You can also convert between units wihout using meters. 21 | /// final miles = kmUnit.toUnit(kilometers, LengthUnit.mile); // ~ 2.485484 22 | /// ```dart 23 | /// 24 | /// See also [Unit of length](https://en.wikipedia.org/wiki/Unit_of_length) and 25 | /// [Orders of magnitude (length)](https://en.wikipedia.org/wiki/Orders_of_magnitude_(length)) 26 | /// in Wikipedia. 27 | enum LengthUnit { 28 | /// 1 millimeter is equal to 0.001 meters. 29 | millimeter(0.001, 'mm'), 30 | 31 | /// 1 centimeter is equal to 0.01 meters. 32 | centimeter(0.01, 'cm'), 33 | 34 | /// The SI base unit for distance. 35 | meter(1.0, 'm'), 36 | 37 | /// 1 kilometer is equal to 1000 meters. 38 | kilometer(1000.0, 'km'), 39 | 40 | /// 1 inch is equal to 0.0254 meters. 41 | inch(0.0254, 'in'), 42 | 43 | /// 1 foot is equal to 0.3048 meters. 44 | foot(0.3048, 'ft'), 45 | 46 | /// 1 yard is equal to 0.9144 meters. 47 | yard(0.9144, 'yd'), 48 | 49 | /// 1 mile is equal to 1609.344 meters. 50 | mile(1609.344, 'mi'), 51 | 52 | /// 1 nautical mile is equal to 1852 meters. 53 | /// 54 | /// Official unit symbols for nautical miles are "NM", "nmi" or "M" depending 55 | /// on the context ([Wikipedia](https://en.wikipedia.org/wiki/Nautical_mile)). 56 | nauticalMile(1852.0, 'nmi'); 57 | 58 | /// The conversion factor to meters. 59 | final double factorToMeters; 60 | 61 | /// The unit symbol. 62 | final String symbol; 63 | 64 | const LengthUnit(this.factorToMeters, this.symbol); 65 | 66 | /// Convert a value from this unit to meters. 67 | double toMeters(double value) { 68 | return value * factorToMeters; 69 | } 70 | 71 | /// Convert a value from meters to this unit. 72 | double fromMeters(double value) { 73 | return value / factorToMeters; 74 | } 75 | 76 | /// Convert a value from this unit to another unit. 77 | double toUnit(double value, LengthUnit targetUnit) { 78 | final valueInMeters = toMeters(value); 79 | return targetUnit.fromMeters(valueInMeters); 80 | } 81 | 82 | /// Convert a value from another unit to this unit. 83 | double fromUnit(double value, LengthUnit sourceUnit) { 84 | final valueInMeters = sourceUnit.toMeters(value); 85 | return fromMeters(valueInMeters); 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /dart/geobase/lib/src/common/conversions/speed_unit.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2025 Navibyte (https://navibyte.com). All rights reserved. 2 | // Use of this source code is governed by a “BSD-3-Clause”-style license that is 3 | // specified in the LICENSE file. 4 | // 5 | // Docs: https://github.com/navibyte/geospatial 6 | 7 | /// An enumeration of speed units. 8 | /// 9 | /// The units are defined with conversion factors to meters per second. 10 | /// 11 | /// Examples: 12 | /// 13 | /// ```dart 14 | /// // Convert directly from and to meters per second. 15 | /// final metersPerSecond = 3.6; 16 | /// final kilometersPerHour = 17 | /// SpeedUnit.kilometerPerHour.fromMetersPerSecond(metersPerSecond); // 12.96 18 | /// final metersPerSecond2 = 19 | /// SpeedUnit.kilometerPerHour.toMetersPerSecond(kilometersPerHour); // 3.6 20 | /// 21 | /// // You can also convert between units without using meters per second. 22 | /// final milesPerHour = 23 | /// SpeedUnit.kilometerPerHour.toUnit(kilometersPerHour, 24 | /// SpeedUnit.milePerHour); // 8.04672 25 | /// ``` 26 | /// 27 | /// See also [Speed](https://en.wikipedia.org/wiki/Speed) in Wikipedia. 28 | enum SpeedUnit { 29 | /// 1 millimeter per second is equal to 0.001 meters per second. 30 | millimeterPerSecond(0.001, 'mm/s'), 31 | 32 | /// 1 centimeter per second is equal to 0.01 meters per second. 33 | centimeterPerSecond(0.01, 'cm/s'), 34 | 35 | /// 1 meter per second is the base unit for speed. 36 | meterPerSecond(1.0, 'm/s'), 37 | 38 | /// 1 kilometer per hour is equal to ~ 0.2777777778 meters per second. 39 | kilometerPerHour(0.2777777778, 'km/h'), 40 | 41 | /// 1 mile per hour is equal to 0.44704 meters per second. 42 | milePerHour(0.44704, 'mph'), 43 | 44 | /// 1 foot per second is equal to 0.3048 meters per second. 45 | footPerSecond(0.3048, 'ft/s'), 46 | 47 | /// 1 knot is equal to ~ 0.514444 meters per second. 48 | knot(0.5144444444, 'kn'); 49 | 50 | /// The conversion factor to meters per second. 51 | final double factorToMetersPerSecond; 52 | 53 | /// The unit symbol. 54 | final String symbol; 55 | 56 | const SpeedUnit(this.factorToMetersPerSecond, this.symbol); 57 | 58 | /// Convert a value from this unit to meters per second. 59 | double toMetersPerSecond(double value) { 60 | return value * factorToMetersPerSecond; 61 | } 62 | 63 | /// Convert a value from meters per second to this unit. 64 | double fromMetersPerSecond(double value) { 65 | return value / factorToMetersPerSecond; 66 | } 67 | 68 | /// Convert a value from this unit to another unit. 69 | double toUnit(double value, SpeedUnit targetUnit) { 70 | final valueInMetersPerSecond = toMetersPerSecond(value); 71 | return targetUnit.fromMetersPerSecond(valueInMetersPerSecond); 72 | } 73 | 74 | /// Convert a value from another unit to this unit. 75 | double fromUnit(double value, SpeedUnit sourceUnit) { 76 | final valueInMetersPerSecond = sourceUnit.toMetersPerSecond(value); 77 | return fromMetersPerSecond(valueInMetersPerSecond); 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /dart/geobase/lib/src/common/conversions/time_unit.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2025 Navibyte (https://navibyte.com). All rights reserved. 2 | // Use of this source code is governed by a “BSD-3-Clause”-style license that is 3 | // specified in the LICENSE file. 4 | // 5 | // Docs: https://github.com/navibyte/geospatial 6 | 7 | /// An enumeration of time units (representing values of time duration or 8 | /// intervals). 9 | /// 10 | /// The units are defined with conversion factors to seconds. 11 | /// 12 | /// Examples: 13 | /// 14 | /// ```dart 15 | /// // Convert directly from and to seconds. 16 | /// final seconds = 3600.0; 17 | /// final hours = TimeUnit.hour.fromSeconds(seconds); // 1.0 18 | /// final seconds2 = TimeUnit.hour.toSeconds(hours); // 3600.0 19 | /// 20 | /// // You can also convert between units without using seconds. 21 | /// final minutes = TimeUnit.hour.toUnit(hours, TimeUnit.minute); // 60.0 22 | /// ``` 23 | /// 24 | /// See also [Unit of time](https://en.wikipedia.org/wiki/Unit_of_time) in 25 | /// Wikipedia. 26 | enum TimeUnit { 27 | /// 1 nanosecond is equal to 1e-9 seconds. 28 | nanosecond(1e-9, 'ns'), 29 | 30 | /// 1 microsecond (μs) is equal to 1e-6 seconds. 31 | microsecond(1e-6, 'μs'), 32 | 33 | /// 1 millisecond is equal to 0.001 seconds. 34 | millisecond(0.001, 'ms'), 35 | 36 | /// 1 second is the base unit for time. 37 | second(1.0, 's'), 38 | 39 | /// 1 minute is equal to 60 seconds. 40 | minute(60.0, 'min'), 41 | 42 | /// 1 hour is equal to 3600 seconds. 43 | hour(3600.0, 'h'), 44 | 45 | /// 1 day is equal to 86400 seconds. 46 | day(86400.0, 'd'), 47 | 48 | /// 1 week is equal to 604800 seconds. 49 | week(604800.0, 'w'); 50 | 51 | /// The conversion factor to seconds. 52 | final double factorToSeconds; 53 | 54 | /// The unit symbol. 55 | final String symbol; 56 | 57 | const TimeUnit(this.factorToSeconds, this.symbol); 58 | 59 | /// Convert a value from this unit to seconds. 60 | double toSeconds(double value) { 61 | return value * factorToSeconds; 62 | } 63 | 64 | /// Convert a value from seconds to this unit. 65 | double fromSeconds(double value) { 66 | return value / factorToSeconds; 67 | } 68 | 69 | /// Convert a value from this unit to another unit. 70 | double toUnit(double value, TimeUnit targetUnit) { 71 | final valueInSeconds = toSeconds(value); 72 | return targetUnit.fromSeconds(valueInSeconds); 73 | } 74 | 75 | /// Convert a value from another unit to this unit. 76 | double fromUnit(double value, TimeUnit sourceUnit) { 77 | final valueInSeconds = sourceUnit.toSeconds(value); 78 | return fromSeconds(valueInSeconds); 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /dart/geobase/lib/src/common/functions/position_functions.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2025 Navibyte (https://navibyte.com). All rights reserved. 2 | // Use of this source code is governed by a “BSD-3-Clause”-style license that is 3 | // specified in the LICENSE file. 4 | // 5 | // Docs: https://github.com/navibyte/geospatial 6 | 7 | import 'dart:math'; 8 | 9 | const _toRad = pi / 180.0; 10 | 11 | /// An extension on [double] with basic degrees and radians utility methods. 12 | extension DoubleAngleExtension on double { 13 | /// Converts this double value in degrees to radians. 14 | /// 15 | /// See also `convertAngle()` that allows conversion between different angle 16 | /// units. 17 | double toRadians() => this * _toRad; 18 | 19 | /// Converts this double value in radians to degrees. 20 | /// 21 | /// See also `convertAngle()` that allows conversion between different angle 22 | /// units. 23 | double toDegrees() => this / _toRad; 24 | 25 | /// Normalizes this double value in degrees to the range `[0.0, 360.0[`. 26 | /// 27 | /// Examples: 28 | /// * `5.0` => `5.0` 29 | /// * `-5.0` => `355.0` 30 | /// * `362.0` => `2.0` 31 | /// 32 | /// As a special case if this is `double.nan` then `double.nan` is returned. 33 | double wrap360() { 34 | if (this >= 0.0 && this < 360.0) { 35 | return this; 36 | } 37 | return this % 360.0; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /dart/geobase/lib/src/common/reference/ellipsoid.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2025 Navibyte (https://navibyte.com). All rights reserved. 2 | // Use of this source code is governed by a “BSD-3-Clause”-style license that is 3 | // specified in the LICENSE file. 4 | // 5 | // Docs: https://github.com/navibyte/geospatial 6 | 7 | // ignore_for_file: constant_identifier_names, lines_longer_than_80_chars 8 | 9 | import 'package:meta/meta.dart'; 10 | 11 | /// A reference ellipsoid with ellipsoidal parameters (a, b and f). 12 | /// 13 | /// See also Wikipedia about 14 | /// [Earth ellipsoid](https://en.wikipedia.org/wiki/Earth_ellipsoid) and 15 | /// PROJ documentation about 16 | /// [ellipsoids](https://proj.org/en/stable/usage/ellipsoids.html). 17 | @immutable 18 | class Ellipsoid { 19 | /// The id (*short name*) of a reference ellisoid. 20 | final String id; 21 | 22 | /// The name (*ellipse name*) of a reference ellisoid. 23 | final String name; 24 | 25 | /// The *semi-major axis* (*equatorial radius*) of a reference ellipsoid. 26 | final double a; 27 | 28 | /// The *semi-minor axis* (*polar radius*) of a reference ellipsoid. 29 | final double b; 30 | 31 | /// The *flattening* of a reference ellipsoid. 32 | final double f; 33 | 34 | /// A reference ellipsoid with ellipsoidal parameters (a, b and f). 35 | const Ellipsoid({ 36 | required this.id, 37 | required this.name, 38 | required this.a, 39 | required this.b, 40 | required this.f, 41 | }); 42 | 43 | /// Ellisoidal parameters for the `WGS84` (World Geodetic System 1984) 44 | /// reference ellipsoid. 45 | /// 46 | /// See also Wikipedia about 47 | /// [World Geodetic System](https://en.wikipedia.org/wiki/World_Geodetic_System). 48 | static const WGS84 = Ellipsoid( 49 | id: 'WGS84', 50 | name: 'WGS 84', 51 | a: 6378137.0, 52 | b: 6356752.314245, 53 | f: 1.0 / 298.257223563, 54 | ); 55 | 56 | /// Ellisoidal parameters for the `GRS80` (Geodetic Reference System 1980) 57 | /// reference ellipsoid. 58 | /// 59 | /// See also Wikipedia about 60 | /// [Geodetic Reference System 1980](https://en.wikipedia.org/wiki/Geodetic_Reference_System_1980). 61 | static const GRS80 = Ellipsoid( 62 | id: 'GRS80', 63 | name: 'GRS 1980(IUGG, 1980)', 64 | a: 6378137.0, 65 | b: 6356752.314140, 66 | f: 1.0 / 298.257222101, // more accurate: 1.0 / 298.257222100882711243 67 | ); 68 | 69 | @override 70 | String toString() { 71 | return '$id;$name;$a;$b;$f'; 72 | } 73 | 74 | @override 75 | bool operator ==(Object other) => 76 | identical(this, other) || 77 | (other is Ellipsoid && 78 | id == other.id && 79 | name == other.name && 80 | a == other.a && 81 | b == other.b && 82 | f == other.f); 83 | 84 | @override 85 | int get hashCode => Object.hash(id, name, a, b, f); 86 | } 87 | -------------------------------------------------------------------------------- /dart/geobase/lib/src/common/reference/temporal_ref_sys.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2023 Navibyte (https://navibyte.com). All rights reserved. 2 | // Use of this source code is governed by a “BSD-3-Clause”-style license that is 3 | // specified in the LICENSE file. 4 | // 5 | // Docs: https://github.com/navibyte/geospatial 6 | 7 | import 'package:meta/meta.dart'; 8 | 9 | import 'temporal_ref_sys_resolver.dart'; 10 | 11 | /// Metadata about a temporal coordinate reference system (TRS) identified and 12 | /// specified by [id]. 13 | @immutable 14 | class TemporalRefSys { 15 | /// Metadata about a temporal coordinate reference system (TRS) identified and 16 | /// specified by [id]. 17 | /// 18 | /// No normalization of identifiers is done. 19 | /// 20 | /// See also [TemporalRefSys.normalized]. 21 | const TemporalRefSys.id(this.id); 22 | 23 | /// Metadata about a temporal coordinate reference system (TRS) identified and 24 | /// specified by the normalized identifier of [id]. 25 | /// 26 | /// Normalization: `TemporalRefSysResolver.registry.normalizeId(id)`. 27 | /// 28 | /// The default implementation returns [id] unmodified (however when necessary 29 | /// a custom logic can be registered for [TemporalRefSysResolver]). 30 | TemporalRefSys.normalized(String id) 31 | : id = TemporalRefSysResolver.registry.normalizeId(id); 32 | 33 | /// The temporal coordinate reference system (TRS) identifier. 34 | /// 35 | /// The identifier is authorative, it identifies a well known or referenced 36 | /// specification that defines properties for a temporal coordinate reference 37 | /// system. 38 | /// 39 | /// Examples: 40 | /// * `http://www.opengis.net/def/uom/ISO-8601/0/Gregorian`: dates or 41 | /// timestamps are in the Gregorian calendar and conform to 42 | /// [RFC 3339](https://www.rfc-editor.org/rfc/rfc3339.html). 43 | final String id; 44 | 45 | /// The temporal coordinate reference system resolved in this order: 46 | /// 1. [temporalRefSys] if it's non-null 47 | /// 2. otherwise `TemporalRefSys.normalized(trs)` if [trs] is non-null 48 | /// 3. otherwise `TemporalRefSys.gregorian` 49 | factory TemporalRefSys.from({ 50 | TemporalRefSys? temporalRefSys, 51 | String? trs, 52 | }) => 53 | temporalRefSys ?? 54 | (trs != null ? TemporalRefSys.normalized(trs) : gregorian); 55 | 56 | /// The temporal coordinate reference system identified by 57 | /// 'http://www.opengis.net/def/uom/ISO-8601/0/Gregorian'. 58 | /// 59 | /// References temporal coordinates, dates or timestamps, that are in the 60 | /// Gregorian calendar and conform to 61 | /// [RFC 3339](https://www.rfc-editor.org/rfc/rfc3339.html). 62 | static const TemporalRefSys gregorian = 63 | TemporalRefSys.id('http://www.opengis.net/def/uom/ISO-8601/0/Gregorian'); 64 | 65 | @override 66 | String toString() => id; 67 | 68 | @override 69 | bool operator ==(Object other) => 70 | identical(this, other) || (other is TemporalRefSys && id == other.id); 71 | 72 | @override 73 | int get hashCode => id.hashCode; 74 | } 75 | -------------------------------------------------------------------------------- /dart/geobase/lib/src/common/reference/temporal_ref_sys_resolver.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2023 Navibyte (https://navibyte.com). All rights reserved. 2 | // Use of this source code is governed by a “BSD-3-Clause”-style license that is 3 | // specified in the LICENSE file. 4 | // 5 | // Docs: https://github.com/navibyte/geospatial 6 | 7 | // NOTE: implement normalization for the template 8 | // `http://www.opengis.net/def/uom/{authority}/{version}/{code}`. 9 | 10 | /// An abstract class for resolving temporal coordinate reference system 11 | /// information. 12 | /// 13 | /// A resolver can be accessed using [registry] that is initially instantiated 14 | /// with the basic default implementation. It be customized by registering a 15 | /// custom instance using [register]). 16 | /// 17 | /// NOTE: The current version of this resolver class provides only the method 18 | /// [normalizeId]. In future other methods might be added. 19 | abstract class TemporalRefSysResolver { 20 | const TemporalRefSysResolver._(); 21 | 22 | /// Normalizes the temporal coordinate reference system identifier. 23 | /// 24 | /// The normalization logic depends on the resolver of [registry]. 25 | String normalizeId(String id); 26 | 27 | /// The current instance of [TemporalRefSysResolver], initially instantiated 28 | /// with the basic default implementation. 29 | /// 30 | /// Currently the basic default implemention returns identifiers unmodified. 31 | /// 32 | /// NOTE: In future the basic implementation is going to be extended to 33 | /// support also other identifier and more wide normalization logic. 34 | static TemporalRefSysResolver registry = const _BasicTemporalRefSysRegistry(); 35 | 36 | /// Registers a custom instance of [TemporalRefSysResolver], available at 37 | /// static [registry] after calling this. 38 | // ignore: use_setters_to_change_properties 39 | static void register(TemporalRefSysResolver resolver) => 40 | TemporalRefSysResolver.registry = resolver; 41 | } 42 | 43 | class _BasicTemporalRefSysRegistry implements TemporalRefSysResolver { 44 | const _BasicTemporalRefSysRegistry(); 45 | 46 | @override 47 | String normalizeId(String id) { 48 | return id; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /dart/geobase/lib/src/coordinates/base/aligned.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2023 Navibyte (https://navibyte.com). All rights reserved. 2 | // Use of this source code is governed by a “BSD-3-Clause”-style license that is 3 | // specified in the LICENSE file. 4 | // 5 | // Docs: https://github.com/navibyte/geospatial 6 | 7 | import 'package:meta/meta.dart'; 8 | 9 | /// An aligned point within a geospatial box or tile. 10 | /// 11 | /// Inspired by the 12 | /// [Alignment](https://api.flutter.dev/flutter/painting/Alignment-class.html) 13 | /// and `AlignmentDirectional` classes defined by the Flutter SDK. 14 | /// 15 | /// This class is named `Aligned` to avoid name collisions with `Alignment` and 16 | /// `Align` classes defined by the Flutter SDK. 17 | @immutable 18 | class Aligned { 19 | /// The horizontal distance fraction. 20 | /// 21 | /// The value `-1.0` represents the west side edge of the box. 22 | /// 23 | /// The value `0.0` represents the center horizontally. 24 | /// 25 | /// The value `1.0` represents the east side edge of the box. 26 | final double x; 27 | 28 | /// The vertical distance fraction. 29 | /// 30 | /// The value `-1.0` represents the south side edge of the box. 31 | /// 32 | /// The value `0.0` represents the center vertically. 33 | /// 34 | /// The value `1.0` represents the north side edge of the box. 35 | final double y; 36 | 37 | /// An aligned point within a geospatial box or tile. 38 | const Aligned({required this.x, required this.y}); 39 | 40 | /// The south west corner, with `x: -1.0, y: -1.0`. 41 | static const southWest = Aligned(x: -1.0, y: -1.0); 42 | 43 | /// The center point along the south side edge, with `x: 0.0, y: -1.0`. 44 | static const southCenter = Aligned(x: 0.0, y: -1.0); 45 | 46 | /// The south east corner, with `x: 1.0, y: -1.0`. 47 | static const southEast = Aligned(x: 1.0, y: -1.0); 48 | 49 | /// The center point along the west side edge, with `x: -1.0, y: 0.0`. 50 | static const centerWest = Aligned(x: -1.0, y: 0.0); 51 | 52 | /// The center point, with `x: 0.0, y: 0.0`. 53 | static const center = Aligned(x: 0.0, y: 0.0); 54 | 55 | /// The center point along the east side edge, with `x: 1.0, y: 0.0`. 56 | static const centerEast = Aligned(x: 1.0, y: 0.0); 57 | 58 | /// The north west corner, with `x: -1.0, y: 1.0`. 59 | static const northWest = Aligned(x: -1.0, y: 1.0); 60 | 61 | /// The center point along the north side edge, with `x: 0.0, y: 1.0`. 62 | static const northCenter = Aligned(x: 0.0, y: 1.0); 63 | 64 | /// The north east corner, with `x: 1.0, y: 1.0`. 65 | static const northEast = Aligned(x: 1.0, y: 1.0); 66 | 67 | @override 68 | String toString() { 69 | return '$x,$y'; 70 | } 71 | 72 | @override 73 | bool operator ==(Object other) => 74 | other is Aligned && x == other.x && y == other.y; 75 | 76 | @override 77 | int get hashCode => Object.hash(x, y); 78 | } 79 | -------------------------------------------------------------------------------- /dart/geobase/lib/src/coordinates/geographic/geographic_bearing.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2024 Navibyte (https://navibyte.com). All rights reserved. 2 | // Use of this source code is governed by a “BSD-3-Clause”-style license that is 3 | // specified in the LICENSE file. 4 | // 5 | // Docs: https://github.com/navibyte/geospatial 6 | 7 | import 'package:meta/meta.dart'; 8 | 9 | import 'geographic.dart'; 10 | 11 | // NOTE: This specifies an object with position and bearing. In future an 12 | // extended class (like GeographicOrientation) might provide also tilt and 13 | // roll angles, or map specific properties (tilt, zoom) like in google map 14 | // CameraPosition. This shall be analyzed later... 15 | 16 | /// {@template geobase.coordinates.geographic_bearing.about} 17 | /// 18 | /// A direction (bearing) in degrees clockwise from north at a specific 19 | /// geographic position (origin). 20 | /// 21 | /// {@endtemplate} 22 | @immutable 23 | class GeographicBearing { 24 | /// A geographic position as a origin point for a direction specified by 25 | /// [bearing]. 26 | final Geographic origin; 27 | 28 | /// A direction in degrees clockwise from north (0°..360°) as observed from 29 | /// [origin]. 30 | final double bearing; 31 | 32 | /// {@macro geobase.coordinates.geographic_bearing.about} 33 | const GeographicBearing({required this.origin, required this.bearing}); 34 | 35 | @override 36 | String toString() { 37 | return '$origin;$bearing'; 38 | } 39 | 40 | @override 41 | bool operator ==(Object other) => 42 | identical(this, other) || 43 | (other is GeographicBearing && 44 | origin == other.origin && 45 | bearing == other.bearing); 46 | 47 | @override 48 | int get hashCode => Object.hash(origin, bearing); 49 | } 50 | -------------------------------------------------------------------------------- /dart/geobase/lib/src/coordinates/projection/projection.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2023 Navibyte (https://navibyte.com). All rights reserved. 2 | // Use of this source code is governed by a “BSD-3-Clause”-style license that is 3 | // specified in the LICENSE file. 4 | // 5 | // Docs: https://github.com/navibyte/geospatial 6 | 7 | import '/src/common/codes/coords.dart'; 8 | import '/src/coordinates/base/position.dart'; 9 | 10 | /// A mixin defining an interface for (geospatial) projections. 11 | /// 12 | /// A class that implements this mixin may provide for example a map projection 13 | /// from geographic positions to projected positions, or an inverse projection 14 | /// (or an "unprojection") from projected positions to geographic positions. 15 | /// Both are called simply "projections" here. 16 | mixin Projection { 17 | /// Projects the [source] position to a position of [T] using [to] as a 18 | /// factory. 19 | /// 20 | /// Throws FormatException if cannot project. 21 | T project( 22 | Position source, { 23 | required CreatePosition to, 24 | }); 25 | 26 | /// Projects positions from [source] and returns a list of projected values. 27 | /// 28 | /// Use the required [type] to explicitely specify the type of coordinates. 29 | /// 30 | /// The [source] array contains coordinate values of positions as a flat 31 | /// structure. For example for `Coords.xyz` the first three coordinate values 32 | /// are x, y and z of the first position, the next three coordinate values are 33 | /// x, y and z of the second position, and so on. 34 | /// 35 | /// The length of the [target] array, when given, must be exactly same as the 36 | /// length of the [source] array, and [target] must be a mutable list. If 37 | /// [target] is null, then a new list instance is created. 38 | /// 39 | /// Throws FormatException if cannot project. 40 | List projectCoords( 41 | Iterable source, { 42 | List? target, 43 | required Coords type, 44 | }); 45 | } 46 | -------------------------------------------------------------------------------- /dart/geobase/lib/src/coordinates/projection/projection_adapter.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2023 Navibyte (https://navibyte.com). All rights reserved. 2 | // Use of this source code is governed by a “BSD-3-Clause”-style license that is 3 | // specified in the LICENSE file. 4 | // 5 | // Docs: https://github.com/navibyte/geospatial 6 | 7 | import '/src/common/reference/coord_ref_sys.dart'; 8 | 9 | import 'projection.dart'; 10 | 11 | /// A projection adapter bundles forward and inverse projections. 12 | mixin ProjectionAdapter { 13 | /// The source coordinate reference system (or projection), ie. 14 | /// `CoordRefSys.CRS84`. 15 | CoordRefSys get sourceCrs; 16 | 17 | /// The target coordinate reference system (or projection), ie. 18 | /// `CoordRefSys.EPSG_3857`. 19 | CoordRefSys get targetCrs; 20 | 21 | /// Returns a projection that projects from [sourceCrs] to 22 | /// [targetCrs]. 23 | Projection get forward; 24 | 25 | /// Returns a projection that projects from [targetCrs] to 26 | /// [sourceCrs]. 27 | Projection get inverse; 28 | } 29 | -------------------------------------------------------------------------------- /dart/geobase/lib/src/coordinates/scalable/scalable.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2023 Navibyte (https://navibyte.com). All rights reserved. 2 | // Use of this source code is governed by a “BSD-3-Clause”-style license that is 3 | // specified in the LICENSE file. 4 | // 5 | // Docs: https://github.com/navibyte/geospatial 6 | 7 | import 'package:meta/meta.dart'; 8 | 9 | /// A scalable object at the [zoom] level (a positive number). 10 | @immutable 11 | abstract class Scalable { 12 | final num _zoom; 13 | 14 | /// Create a scalable object at the [zoom] level (a positive number). 15 | const Scalable({required num zoom}) 16 | : _zoom = zoom, 17 | assert(zoom >= 0, 'Zoom must be >= 0'); 18 | 19 | /// The level of detail (or "zoom") for this scalable object. 20 | num get zoom => _zoom; 21 | 22 | /// Zooms in by one. 23 | Scalable zoomIn(); 24 | 25 | /// Zooms out by one. 26 | /// 27 | /// The minimum value for [zoom] of the returned scalable object is 0. 28 | Scalable zoomOut(); 29 | 30 | /// Zooms to the [zoom] level (a positive number). 31 | Scalable zoomTo(covariant num zoom); 32 | 33 | /// A string representation of coordinate values separated by [delimiter]. 34 | String toText({ 35 | String delimiter = ',', 36 | }); 37 | } 38 | -------------------------------------------------------------------------------- /dart/geobase/lib/src/geodesy/base/geodetic_arc_segment.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2024 Navibyte (https://navibyte.com). All rights reserved. 2 | // Use of this source code is governed by a “BSD-3-Clause”-style license that is 3 | // specified in the LICENSE file. 4 | // 5 | // Docs: https://github.com/navibyte/geospatial 6 | 7 | import '/src/coordinates/geographic/geographic.dart'; 8 | import '/src/coordinates/geographic/geographic_bearing.dart'; 9 | 10 | /// {@template geobase.geodesy.geodetic_arc_segment.about} 11 | /// 12 | /// A geodetic (geographic) arc segment between the [origin] position and the 13 | /// [destination] position along a geodesic. 14 | /// 15 | /// This data structure contains also an initial [bearing] (observed on the 16 | /// origin position), [distance] in meters between the two positions and a 17 | /// [finalBearing] (observed on the destination position). These values should 18 | /// be pre-calculated before constructing an instance either using spherical or 19 | /// ellipsoidal Earth models. 20 | /// 21 | /// For a spherical Earth model, a geodesic is a segment of a great circle. For 22 | /// an ellipsoidal Earth model, a geodesic is a bit more complex, but still it's 23 | /// defined to be the shortest path which can be drawn between its two points on 24 | /// the surface of the Earth (represented by an ellipsoid). 25 | /// 26 | /// Read more about [geodesics](https://en.wikipedia.org/wiki/Geodesic) in 27 | /// general and related to 28 | /// [ellipsoids](https://en.wikipedia.org/wiki/Geodesics_on_an_ellipsoid) on 29 | /// Wikipedia. 30 | /// 31 | /// {@endtemplate} 32 | class GeodeticArcSegment extends GeographicBearing { 33 | /// The distance in meters between the [origin] position and the [destination] 34 | /// position. 35 | final double distance; 36 | 37 | /// A direction in degrees clockwise from north (0°..360°) as observed on a 38 | /// geodetic arg segment when reaching the [destination] position. 39 | final double finalBearing; 40 | 41 | /// A geographic position as a destination point on a geodetic arc segment 42 | /// between [origin] and [destination] positions. 43 | final Geographic destination; 44 | 45 | /// {@macro geobase.geodesy.geodetic_arc_segment.about} 46 | const GeodeticArcSegment({ 47 | required super.origin, 48 | required super.bearing, 49 | required this.distance, 50 | required this.finalBearing, 51 | required this.destination, 52 | }); 53 | 54 | @override 55 | String toString() { 56 | return '$origin;$bearing;$distance;$finalBearing;$destination'; 57 | } 58 | 59 | @override 60 | bool operator ==(Object other) => 61 | identical(this, other) || 62 | (other is GeodeticArcSegment && 63 | origin == other.origin && 64 | bearing == other.bearing && 65 | distance == other.distance && 66 | finalBearing == other.finalBearing && 67 | destination == other.destination); 68 | 69 | @override 70 | int get hashCode => Object.hash( 71 | origin, 72 | bearing, 73 | distance, 74 | finalBearing, 75 | destination, 76 | ); 77 | } 78 | -------------------------------------------------------------------------------- /dart/geobase/lib/src/geometric/base/distanced_position.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2024 Navibyte (https://navibyte.com). All rights reserved. 2 | // Use of this source code is governed by a “BSD-3-Clause”-style license that is 3 | // specified in the LICENSE file. 4 | // 5 | // Docs: https://github.com/navibyte/geospatial 6 | 7 | import 'package:meta/meta.dart'; 8 | 9 | import '/src/coordinates/base/position.dart'; 10 | 11 | /// An object containing [position] that is within [distance] from something. 12 | @immutable 13 | class DistancedPosition { 14 | /// The reference [position]. 15 | final T position; 16 | 17 | /// The [distance] between the reference [position] and something. 18 | final double distance; 19 | 20 | /// An object containing [position] that is within [distance] from something. 21 | const DistancedPosition(this.position, this.distance); 22 | 23 | @override 24 | String toString() { 25 | return '$position;$distance'; 26 | } 27 | 28 | @override 29 | bool operator ==(Object other) => 30 | identical(this, other) || 31 | (other is DistancedPosition && 32 | position == other.position && 33 | distance == other.distance); 34 | 35 | @override 36 | int get hashCode => Object.hash(position, distance); 37 | } 38 | -------------------------------------------------------------------------------- /dart/geobase/lib/src/meta/extent/spatial_extent.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2024 Navibyte (https://navibyte.com). All rights reserved. 2 | // Use of this source code is governed by a “BSD-3-Clause”-style license that is 3 | // specified in the LICENSE file. 4 | // 5 | // Docs: https://github.com/navibyte/geospatial 6 | 7 | import 'package:meta/meta.dart'; 8 | 9 | import '/src/common/reference/coord_ref_sys.dart'; 10 | import '/src/coordinates/base/box.dart'; 11 | import '/src/utils/object_utils.dart'; 12 | 13 | /// An extent with 1 to N bounding boxes in defined coordinate reference system. 14 | @immutable 15 | class SpatialExtent { 16 | final T _first; 17 | final Iterable? _boxes; 18 | final CoordRefSys _crs; 19 | 20 | /// A spatial extent of one [bbox] with coordinate reference system specified 21 | /// by [crs]. 22 | const SpatialExtent.single( 23 | T bbox, { 24 | CoordRefSys crs = CoordRefSys.CRS84, 25 | }) : _first = bbox, 26 | _boxes = null, 27 | _crs = crs; 28 | 29 | /// A spatial extent of [boxes] with coordinate reference system specified 30 | /// by [crs]. 31 | SpatialExtent.multi( 32 | Iterable boxes, { 33 | CoordRefSys crs = CoordRefSys.CRS84, 34 | }) : _boxes = _validate(boxes), 35 | _first = boxes.first, 36 | _crs = crs; 37 | 38 | static Iterable _validate(Iterable boxes) { 39 | if (boxes.isEmpty) { 40 | throw const FormatException('At least one bounding box required.'); 41 | } 42 | return boxes; 43 | } 44 | 45 | /// The first bounding box for this extent. 46 | T get first => _first; 47 | 48 | /// All bounding boxes for this extent. 49 | Iterable get boxes => _boxes ?? [_first]; 50 | 51 | /// The coordinate reference system for bounding boxes of this extent. 52 | CoordRefSys get crs => _crs; 53 | 54 | /// Copy this spatial extent with optional [boxes] and/or [crs] parameters 55 | /// changed. 56 | SpatialExtent copyWith({Iterable? boxes, CoordRefSys? crs}) { 57 | if (boxes != null) { 58 | return SpatialExtent.multi(boxes, crs: crs ?? _crs); 59 | } else { 60 | if (crs != null) { 61 | return _boxes != null 62 | ? SpatialExtent.multi(_boxes!, crs: crs) 63 | : SpatialExtent.single(_first, crs: crs); 64 | } else { 65 | // ignore: avoid_returning_this 66 | return this; 67 | } 68 | } 69 | } 70 | 71 | @override 72 | String toString() { 73 | final buf = StringBuffer()..write(crs); 74 | for (final item in boxes) { 75 | buf 76 | ..write(',[') 77 | ..write(item) 78 | ..write(']'); 79 | } 80 | return buf.toString(); 81 | } 82 | 83 | @override 84 | bool operator ==(Object other) => 85 | identical(this, other) || 86 | (other is SpatialExtent && 87 | crs == other.crs && 88 | testIterableEquality(boxes, other.boxes)); 89 | 90 | @override 91 | int get hashCode => Object.hash(crs, Object.hashAll(boxes)); 92 | } 93 | -------------------------------------------------------------------------------- /dart/geobase/lib/src/meta/extent/temporal_extent.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2024 Navibyte (https://navibyte.com). All rights reserved. 2 | // Use of this source code is governed by a “BSD-3-Clause”-style license that is 3 | // specified in the LICENSE file. 4 | // 5 | // Docs: https://github.com/navibyte/geospatial 6 | 7 | import 'package:meta/meta.dart'; 8 | 9 | import '/src/common/reference/temporal_ref_sys.dart'; 10 | import '/src/meta/time/interval.dart'; 11 | import '/src/utils/object_utils.dart'; 12 | 13 | /// An extent with 1 to N intervals in defined temporal coordinate reference 14 | /// system. 15 | @immutable 16 | class TemporalExtent { 17 | final Interval _first; 18 | final Iterable? _intervals; 19 | final TemporalRefSys _trs; 20 | 21 | /// A temporal extent of one [interval] (temporal coordinate reference system 22 | /// in [trs]). 23 | const TemporalExtent.single( 24 | Interval interval, { 25 | TemporalRefSys trs = TemporalRefSys.gregorian, 26 | }) : _first = interval, 27 | _intervals = null, 28 | _trs = trs; 29 | 30 | /// A temporal extent of [intervals] (temporal coordinate reference system in 31 | /// [trs]). 32 | TemporalExtent.multi( 33 | Iterable intervals, { 34 | TemporalRefSys trs = TemporalRefSys.gregorian, 35 | }) : _intervals = _validate(intervals), 36 | _first = intervals.first, 37 | _trs = trs; 38 | 39 | static Iterable _validate(Iterable intervals) { 40 | if (intervals.isEmpty) { 41 | throw const FormatException('At least one interval required.'); 42 | } 43 | return intervals; 44 | } 45 | 46 | /// The first interval for this extent. 47 | Interval get first => _first; 48 | 49 | /// All intervals for this extent. 50 | Iterable get intervals => _intervals ?? [_first]; 51 | 52 | /// The temporal coordinate reference system for intervals of this extent. 53 | TemporalRefSys get trs => _trs; 54 | 55 | /// Copy this temporal extent with optional [interval] and/or [trs] 56 | /// parameters changed. 57 | TemporalExtent copyWith({Interval? interval, TemporalRefSys? trs}) { 58 | if (interval != null) { 59 | return TemporalExtent.single(interval, trs: trs ?? _trs); 60 | } else { 61 | if (trs != null) { 62 | return _intervals != null 63 | ? TemporalExtent.multi(_intervals!, trs: trs) 64 | : TemporalExtent.single(_first, trs: trs); 65 | } else { 66 | // ignore: avoid_returning_this 67 | return this; 68 | } 69 | } 70 | } 71 | 72 | @override 73 | String toString() { 74 | final buf = StringBuffer()..write(trs); 75 | for (final item in intervals) { 76 | buf 77 | ..write(',') 78 | ..write(item); 79 | } 80 | return buf.toString(); 81 | } 82 | 83 | @override 84 | bool operator ==(Object other) => 85 | identical(this, other) || 86 | (other is TemporalExtent && 87 | trs == other.trs && 88 | testIterableEquality(intervals, other.intervals)); 89 | 90 | @override 91 | int get hashCode => Object.hash(trs, Object.hashAll(intervals)); 92 | } 93 | -------------------------------------------------------------------------------- /dart/geobase/lib/src/meta/time/instant.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2024 Navibyte (https://navibyte.com). All rights reserved. 2 | // Use of this source code is governed by a “BSD-3-Clause”-style license that is 3 | // specified in the LICENSE file. 4 | // 5 | // Docs: https://github.com/navibyte/geospatial 6 | 7 | import 'package:meta/meta.dart'; 8 | 9 | import 'temporal.dart'; 10 | 11 | /// An instant with a timestamp. 12 | @immutable 13 | class Instant extends Temporal { 14 | final DateTime _time; 15 | 16 | /// Creates an instant with a [time] stamp. 17 | const Instant(DateTime time) : _time = time; 18 | 19 | /// Creates an instant from a string. 20 | /// 21 | /// The input [text] must be formatted according to RFC 3339. See 22 | /// `DateTime.parse` for reference of valid inputs. 23 | /// 24 | /// Throws FormatException if an instant cannot be parsed. 25 | factory Instant.parse(String text) => Instant(DateTime.parse(text)); 26 | 27 | /// Creates an instant from a string or returns null if cannot parse. 28 | /// 29 | /// The input [text] must be formatted according to RFC 3339. See 30 | /// `DateTime.parse` for reference of valid inputs. 31 | static Instant? tryParse(String text) { 32 | final t = DateTime.tryParse(text); 33 | return t != null ? Instant(t) : null; 34 | } 35 | 36 | /// The time stamp of this instant. 37 | DateTime get time => _time; 38 | 39 | /// Copy this instant with an optional [time] changed. 40 | Instant copyWith({DateTime? time}) => time != null ? Instant(time) : this; 41 | 42 | @override 43 | bool get isUtc => time.isUtc; 44 | 45 | @override 46 | Instant toUtc() => isUtc ? this : Instant(time.toUtc()); 47 | 48 | @override 49 | bool isAfterTime(DateTime time) => this.time.isAfter(time); 50 | 51 | @override 52 | bool isBeforeTime(DateTime time) => this.time.isBefore(time); 53 | 54 | @override 55 | String toString() => time.toIso8601String(); 56 | 57 | @override 58 | bool operator ==(Object other) => 59 | identical(this, other) || (other is Instant && time == other.time); 60 | 61 | @override 62 | int get hashCode => time.hashCode; 63 | } 64 | -------------------------------------------------------------------------------- /dart/geobase/lib/src/meta/time/temporal.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2023 Navibyte (https://navibyte.com). All rights reserved. 2 | // Use of this source code is governed by a “BSD-3-Clause”-style license that is 3 | // specified in the LICENSE file. 4 | // 5 | // Docs: https://github.com/navibyte/geospatial 6 | 7 | /// A base class for *temporal* objects like *instants* and *intervals*. 8 | abstract class Temporal { 9 | /// Default `const` constructor to allow extending this abstract class. 10 | const Temporal(); 11 | 12 | /// True if this *temporal* object is set to UTC time. 13 | bool get isUtc; 14 | 15 | /// Returns this *temporal* object in the UTC time zone. 16 | Temporal toUtc(); 17 | 18 | /// A string representation of this *temporal* object. 19 | /// 20 | /// If object is an *instant*, returns ISO-8601 full-precision extended format 21 | /// representation. See `DateTime.toIso8601String()` for reference. 22 | /// 23 | /// If object is an interval, returns a string defined as (where "" 24 | /// and "" refers to ISO-8601 formatted timestamps): 25 | /// * closed interval: "/" 26 | /// * open ended interval: "/.." 27 | /// * open started interval: "../" 28 | /// * open interval: "../.." 29 | @override 30 | String toString(); 31 | 32 | /// Returns true if this occurs fully after [time]. 33 | /// 34 | /// See `DateTime.isAfter` for reference. 35 | bool isAfterTime(DateTime time); 36 | 37 | /// Returns true if this occurs fully before [time]. 38 | /// 39 | /// See `DateTime.isAfter` for reference. 40 | bool isBeforeTime(DateTime time); 41 | 42 | /* 43 | todo: 44 | bool isAfter(Temporal other); 45 | bool isBefore(Temporal other); 46 | bool anyInteracts(Temporal other); 47 | ... 48 | */ 49 | } 50 | -------------------------------------------------------------------------------- /dart/geobase/lib/src/tiling/convert/scaled_converter.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2023 Navibyte (https://navibyte.com). All rights reserved. 2 | // Use of this source code is governed by a “BSD-3-Clause”-style license that is 3 | // specified in the LICENSE file. 4 | // 5 | // Docs: https://github.com/navibyte/geospatial 6 | 7 | /// A coordinate converter between geospatial positions and scaled coordinates. 8 | /// 9 | /// Geospatial positions may represent geographic or projected coordinates 10 | /// defined by a spatial coordinate reference system. 11 | /// 12 | /// Scaled coordinates are projected coordinates scaled to a defined range 13 | /// most often defined by a tiling scheme. 14 | abstract class ScaledConverter { 15 | /// Converts geospatial [x] to scaled x coordinate with range (0, [width]). 16 | /// 17 | /// The source geospatial [x] coordinate could be a projected x (metric) or a 18 | /// geographic longitude coordinate defined by a spatial coordinate reference 19 | /// system. 20 | /// 21 | /// The target scaled [x] coordinate could be a "world" pixel coordinate with 22 | /// a double value (ie. range 0. .. 256.0) or a projected x coordinate with 23 | /// a integer column value (of a tile or a pixel) defined by a tiling scheme. 24 | double toScaledX(num x, {num width = 256}); 25 | 26 | /// Converts geopatial [y] to scaled y coordinate with range (0, [height]). 27 | /// 28 | /// The source geospatial [y] coordinate could be a projected y (metric) or a 29 | /// geographic latitude coordinate defined by a spatial coordinate reference 30 | /// system. 31 | /// 32 | /// The target scaled [y] coordinate could be a "world" pixel coordinate with 33 | /// a double value (ie. range 0. .. 256.0) or a projected y coordinate with 34 | /// a integer row value (of a tile or a pixel) defined by a tiling scheme. 35 | double toScaledY(num y, {num height = 256}); 36 | 37 | /// Converts scaled [x] coordinate with range (0, [width]) to geospatial x. 38 | /// 39 | /// The source scaled [x] coordinate could be a "world" pixel coordinate with 40 | /// a double value (ie. range 0. .. 256.0) or a projected x coordinate with 41 | /// a integer column value (of a tile or a pixel) defined by a tiling scheme. 42 | /// 43 | /// The target geospatial [x] coordinate could be a projected x (metric) or a 44 | /// geographic longitude coordinate defined by a spatial coordinate reference 45 | /// system. 46 | double fromScaledX(num x, {num width = 256}); 47 | 48 | /// Converts scaled [y] coordinate with range (0, [height]) to geospatial y. 49 | /// 50 | /// The source scaled [y] coordinate could be a "world" pixel coordinate with 51 | /// a double value (ie. range 0. .. 256.0) or a projected y coordinate with 52 | /// a integer row value (of a tile or a pixel) defined by a tiling scheme. 53 | /// 54 | /// The target geospatial [y] coordinate could be a projected y (metric) or a 55 | /// geographic latitude coordinate defined by a spatial coordinate reference 56 | /// system. 57 | double fromScaledY(num y, {num height = 256}); 58 | } 59 | -------------------------------------------------------------------------------- /dart/geobase/lib/src/utils/byte_utils.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2024 Navibyte (https://navibyte.com). All rights reserved. 2 | // Use of this source code is governed by a “BSD-3-Clause”-style license that is 3 | // specified in the LICENSE file. 4 | // 5 | // Docs: https://github.com/navibyte/geospatial 6 | 7 | import 'dart:typed_data'; 8 | 9 | import 'package:meta/meta.dart'; 10 | 11 | /// Utilities on `Uint8List`. 12 | @internal 13 | extension Uint8ListUtils on Uint8List { 14 | /// Encode bytes as Hexadecimal (base 16) string. 15 | String toHex() => map((e) => e.toRadixString(16).padLeft(2, '0')).join(); 16 | 17 | /// Decode a hexadecimal (base 16) string in [data] to bytes as `Uint8List`. 18 | static Uint8List fromHex(String data) { 19 | final len = data.length; 20 | if (len.isEven) { 21 | final byteCount = len ~/ 2; 22 | final bytes = List.filled(byteCount, 0); 23 | for (var i = 0; i < byteCount; i++) { 24 | bytes[i] = int.parse(data.substring(i * 2, i * 2 + 2), radix: 16); 25 | } 26 | return Uint8List.fromList(bytes); 27 | } 28 | throw FormatException('not valid hex string $data'); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /dart/geobase/lib/src/utils/coord_type.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2023 Navibyte (https://navibyte.com). All rights reserved. 2 | // Use of this source code is governed by a “BSD-3-Clause”-style license that is 3 | // specified in the LICENSE file. 4 | // 5 | // Docs: https://github.com/navibyte/geospatial 6 | 7 | import 'package:meta/meta.dart'; 8 | 9 | import '/src/common/codes/coords.dart'; 10 | import '/src/coordinates/base/bounded.dart'; 11 | import '/src/coordinates/base/position.dart'; 12 | import '/src/coordinates/base/position_series.dart'; 13 | 14 | /// Resolves the coordinate type for [item] and/or [collection]. 15 | /// 16 | /// The returned type is such that it's valid for all items. For example if 17 | /// a collection has items with types `Coords.xy`, `Coords.xyz` and 18 | /// `Coords.xym`, then `Coords.xy` is returned. When all items are `Coords.xyz`, 19 | /// then `Coords.xyz` is returned. 20 | @internal 21 | Coords resolveCoordTypeFrom({ 22 | E? item, 23 | Iterable? collection, 24 | }) { 25 | var is3D = true; 26 | var isMeasured = true; 27 | 28 | if (item != null) { 29 | final type = item.coordType; 30 | is3D &= type.is3D; 31 | isMeasured &= type.isMeasured; 32 | } 33 | 34 | if (collection != null) { 35 | for (final elem in collection) { 36 | final type = elem.coordType; 37 | is3D &= type.is3D; 38 | isMeasured &= type.isMeasured; 39 | if (!is3D && !isMeasured) break; 40 | } 41 | } 42 | 43 | return Coords.select(is3D: is3D, isMeasured: isMeasured); 44 | } 45 | 46 | /// Coordinate type from the first position in [array]. 47 | @internal 48 | Coords positionArrayType(Iterable array) => 49 | array.isNotEmpty ? array.first.coordType : Coords.xy; 50 | 51 | /// Coordinate type from the first series of position in [array]. 52 | @internal 53 | Coords positionSeriesArrayType(Iterable array) => 54 | array.isNotEmpty ? array.first.coordType : Coords.xy; 55 | 56 | /// Coordinate type from the first series of position in [array]. 57 | @internal 58 | Coords positionSeriesArrayArrayType(Iterable> array) => 59 | array.isNotEmpty && array.first.isNotEmpty 60 | ? array.first.first.coordType 61 | : Coords.xy; 62 | -------------------------------------------------------------------------------- /dart/geobase/lib/src/utils/coord_utils.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2023 Navibyte (https://navibyte.com). All rights reserved. 2 | // Use of this source code is governed by a “BSD-3-Clause”-style license that is 3 | // specified in the LICENSE file. 4 | // 5 | // Docs: https://github.com/navibyte/geospatial 6 | 7 | import 'package:meta/meta.dart'; 8 | 9 | import '/src/common/codes/coords.dart'; 10 | 11 | /// Coordinate values of all positions represented by [coordinates] with 12 | /// [sourceType] 13 | /// 14 | /// Target array is structured according to [targetType]. 15 | @internal 16 | Iterable valuesByTypeIter( 17 | Iterable coordinates, { 18 | required Coords sourceType, 19 | required Coords targetType, 20 | }) sync* { 21 | final iter = coordinates.iterator; 22 | while (iter.moveNext()) { 23 | // get source x, y and optional z, m for a position in the source array 24 | final x = iter.current; 25 | if (!iter.moveNext()) break; 26 | final y = iter.current; 27 | final double? z; 28 | if (sourceType.is3D) { 29 | if (!iter.moveNext()) break; 30 | z = iter.current; 31 | } else { 32 | z = null; 33 | } 34 | final double? m; 35 | if (sourceType.isMeasured) { 36 | if (!iter.moveNext()) break; 37 | m = iter.current; 38 | } else { 39 | m = null; 40 | } 41 | 42 | // output target position x, y and optional z, m 43 | yield x; 44 | yield y; 45 | if (targetType.is3D) { 46 | yield z ?? 0.0; 47 | } 48 | if (targetType.isMeasured) { 49 | yield m ?? 0.0; 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /dart/geobase/lib/src/utils/format_impl.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2023 Navibyte (https://navibyte.com). All rights reserved. 2 | // Use of this source code is governed by a “BSD-3-Clause”-style license that is 3 | // specified in the LICENSE file. 4 | // 5 | // Docs: https://github.com/navibyte/geospatial 6 | 7 | import 'package:meta/meta.dart'; 8 | 9 | import '/src/common/reference/coord_ref_sys.dart'; 10 | import '/src/vector/encoding/content_encoder.dart'; 11 | import '/src/vector/encoding/text_format.dart'; 12 | 13 | /// A factory function to create [ContentEncoder] for [Content]. 14 | @internal 15 | typedef CreateTextEncoder = ContentEncoder 16 | Function({ 17 | StringSink? buffer, 18 | int? decimals, 19 | CoordRefSys? crs, 20 | }); 21 | 22 | /// A helper implementation of [TextWriterFormat] for [Content]. 23 | @internal 24 | class TextWriterFormatImpl 25 | with TextWriterFormat { 26 | /// A helper implementation of [TextWriterFormat] for [Content]. 27 | const TextWriterFormatImpl(this.factory); 28 | 29 | /// A factory function to create [ContentEncoder] for [Content]. 30 | final CreateTextEncoder factory; 31 | 32 | @override 33 | ContentEncoder encoder({ 34 | StringSink? buffer, 35 | int? decimals, 36 | CoordRefSys? crs, 37 | Map? options, 38 | }) => 39 | factory.call(buffer: buffer, decimals: decimals, crs: crs); 40 | } 41 | 42 | /// A factory function to create [ContentEncoder] for [Content] with [Conf]. 43 | @internal 44 | typedef CreateTextEncoderConf 45 | = ContentEncoder Function({ 46 | StringSink? buffer, 47 | int? decimals, 48 | CoordRefSys? crs, 49 | Conf? conf, 50 | }); 51 | 52 | /// A helper implementation of [TextWriterFormat] for [Content] with [Conf]. 53 | @internal 54 | class TextWriterFormatImplConf 55 | with TextWriterFormat { 56 | /// A helper implementation of [TextWriterFormat] for [Content] with [Conf]. 57 | const TextWriterFormatImplConf(this.factory, {this.conf}); 58 | 59 | /// A factory function to create [ContentEncoder] for [Content] with [Conf]. 60 | final CreateTextEncoderConf factory; 61 | 62 | /// Optional configuration. 63 | final Conf? conf; 64 | 65 | @override 66 | ContentEncoder encoder({ 67 | StringSink? buffer, 68 | int? decimals, 69 | CoordRefSys? crs, 70 | Map? options, 71 | }) => 72 | factory.call( 73 | buffer: buffer, 74 | decimals: decimals, 75 | crs: crs, 76 | conf: conf, 77 | ); 78 | } 79 | -------------------------------------------------------------------------------- /dart/geobase/lib/src/utils/format_validation.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2023 Navibyte (https://navibyte.com). All rights reserved. 2 | // Use of this source code is governed by a “BSD-3-Clause”-style license that is 3 | // specified in the LICENSE file. 4 | // 5 | // Docs: https://github.com/navibyte/geospatial 6 | 7 | import 'package:meta/meta.dart'; 8 | 9 | /// Invalid coordinate type or values. 10 | @internal 11 | const invalidCoordinates = FormatException('Invalid coordinates'); 12 | -------------------------------------------------------------------------------- /dart/geobase/lib/src/utils/geometry_calculations_cartesian.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2024 Navibyte (https://navibyte.com). All rights reserved. 2 | // Use of this source code is governed by a “BSD-3-Clause”-style license that is 3 | // specified in the LICENSE file. 4 | // 5 | // Docs: https://github.com/navibyte/geospatial 6 | 7 | import 'package:meta/meta.dart'; 8 | 9 | import '/src/coordinates/base/position.dart'; 10 | import '/src/coordinates/base/position_scheme.dart'; 11 | 12 | /// A helper class to calculate areal, linear or punctual centroids for 13 | /// composite geometries. 14 | @internal 15 | class CompositeCentroid { 16 | // See https://en.wikipedia.org/wiki/Centroid / "By geometric decomposition" 17 | 18 | // state for calculating a centroid for areal geometries 19 | var _areaSum = 0.0; 20 | var _arealX = 0.0; 21 | var _arealY = 0.0; 22 | 23 | // state for calculating a centroid for linear geometries 24 | var _lengthSum = 0.0; 25 | var _linearX = 0.0; 26 | var _linearY = 0.0; 27 | 28 | // state for calculating a centroid for punctual geometries 29 | var _numPoints = 0; 30 | var _punctualX = 0.0; 31 | var _punctualY = 0.0; 32 | 33 | void addCentroid2D(Position? pos, {double? area, double? length}) { 34 | if (pos != null) { 35 | addCentroidXY( 36 | x: pos.x, 37 | y: pos.y, 38 | area: area ?? 0.0, 39 | length: length ?? 0.0, 40 | ); 41 | } 42 | } 43 | 44 | void addCentroidXY({ 45 | required double x, 46 | required double y, 47 | double area = 0.0, 48 | double length = 0.0, 49 | }) { 50 | if (area != 0.0) { 51 | // positive or negative area 52 | _areaSum += area; 53 | _arealX += area * x; 54 | _arealY += area * y; 55 | } else if (length > 0.0) { 56 | // positive length 57 | _lengthSum += length; 58 | _linearX += length * x; 59 | _linearY += length * y; 60 | } else { 61 | _numPoints++; 62 | _punctualX += x; 63 | _punctualY += y; 64 | } 65 | } 66 | 67 | Position? centroid2D({PositionScheme scheme = Position.scheme}) { 68 | if (_areaSum > 0.0) { 69 | return scheme.position.call( 70 | x: _arealX / _areaSum, 71 | y: _arealY / _areaSum, 72 | ); 73 | } else if (_lengthSum > 0.0) { 74 | return scheme.position.call( 75 | x: _linearX / _lengthSum, 76 | y: _linearY / _lengthSum, 77 | ); 78 | } else if (_numPoints > 0) { 79 | return scheme.position.call( 80 | x: _punctualX / _numPoints, 81 | y: _punctualY / _numPoints, 82 | ); 83 | } 84 | 85 | return null; 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /dart/geobase/lib/src/utils/math_utils.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2025 Navibyte (https://navibyte.com). All rights reserved. 2 | // Use of this source code is governed by a “BSD-3-Clause”-style license that is 3 | // specified in the LICENSE file. 4 | // 5 | // Docs: https://github.com/navibyte/geospatial 6 | 7 | import 'dart:math'; 8 | 9 | import 'package:meta/meta.dart'; 10 | 11 | @internal 12 | double cosh(double x) { 13 | // The hyperbolic cosine function is defined as: 14 | // cosh(x) = (e^x + e^-x) / 2 15 | 16 | return (exp(x) + exp(-x)) / 2; 17 | } 18 | 19 | @internal 20 | double acosh(double x) { 21 | // The inverse hyperbolic cosine function is defined as: 22 | // acosh(x) = ln(x + sqrt(x^2 - 1)) 23 | 24 | return log(x + sqrt(x * x - 1)); 25 | } 26 | 27 | @internal 28 | double sinh(double x) { 29 | // The hyperbolic sine function is defined as: 30 | // sinh(x) = (e^x - e^-x) / 2 31 | 32 | return (exp(x) - exp(-x)) / 2; 33 | } 34 | 35 | @internal 36 | double asinh(double x) { 37 | // The inverse hyperbolic sine function is defined as: 38 | // asinh(x) = ln(x + sqrt(x^2 + 1)) 39 | 40 | return log(x + sqrt(x * x + 1)); 41 | } 42 | 43 | @internal 44 | double tanh(double x) { 45 | // The hyperbolic tangent function is defined as: 46 | // tanh(x) = (e^x - e^-x) / (e^x + e^-x) 47 | 48 | final expX = exp(x); 49 | final expNegX = exp(-x); 50 | return (expX - expNegX) / (expX + expNegX); 51 | } 52 | 53 | @internal 54 | double atanh(double x) { 55 | // The inverse hyperbolic tangent function is defined as: 56 | // atanh(x) = 0.5 * ln((1 + x) / (1 - x)) 57 | 58 | return 0.5 * log((1 + x) / (1 - x)); 59 | } 60 | -------------------------------------------------------------------------------- /dart/geobase/lib/src/utils/tolerance.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2023 Navibyte (https://navibyte.com). All rights reserved. 2 | // Use of this source code is governed by a “BSD-3-Clause”-style license that is 3 | // specified in the LICENSE file. 4 | // 5 | // Docs: https://github.com/navibyte/geospatial 6 | 7 | import 'package:meta/meta.dart'; 8 | 9 | /// Asserts that [tolerance] is positive (>= 0). 10 | @internal 11 | void assertTolerance(double tolerance) { 12 | assert( 13 | tolerance >= 0.0, 14 | 'Tolerance positive (>= 0)', 15 | ); 16 | } 17 | -------------------------------------------------------------------------------- /dart/geobase/lib/src/vector/content/geometry_content.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2023 Navibyte (https://navibyte.com). All rights reserved. 2 | // Use of this source code is governed by a “BSD-3-Clause”-style license that is 3 | // specified in the LICENSE file. 4 | // 5 | // Docs: https://github.com/navibyte/geospatial 6 | 7 | import '/src/common/codes/coords.dart'; 8 | import '/src/coordinates/base/box.dart'; 9 | 10 | import 'simple_geometry_content.dart'; 11 | 12 | /// A function to write geometry data to [output]. 13 | typedef WriteGeometries = void Function(GeometryContent output); 14 | 15 | /// An interface to write geometry data to format encoders and object builders. 16 | /// 17 | /// This mixin supports specific simple geometry types defined by 18 | /// [SimpleGeometryContent] and geometry collections. It's possible that in 19 | /// future versions other geometry types are added. 20 | /// 21 | /// Coordinate positions and position arrays are represented as coordinate value 22 | /// arrays of `Iterable`. 23 | mixin GeometryContent implements SimpleGeometryContent { 24 | /// Writes a geometry collection from the content provided by [geometries]. 25 | /// 26 | /// An optional [type] specifies the coordinate type of geometry objects in a 27 | /// collection. When not provided, the type can be resolved from objects. 28 | /// 29 | /// An optional expected [count], when given, specifies the number of geometry 30 | /// objects in a collection. Note that when given the count MUST be exact. 31 | /// 32 | /// Use an optional [name] to specify a name for a geometry (when applicable). 33 | /// 34 | /// An optional [bounds] can used set a minimum bounding box for a geometry 35 | /// written. A writer implementation may use it or ignore it. 36 | /// 37 | /// An example to write a geometry collection with two child geometries: 38 | /// ```dart 39 | /// content.geometryCollection( 40 | /// type: Coords.xy 41 | /// count: 2, 42 | /// (geom) => geom 43 | /// ..point([10.123, 20.25].xy) 44 | /// ..polygon( 45 | /// [ 46 | /// [ 47 | /// 10.1, 10.1, 48 | /// 5.0, 9.0, 49 | /// 12.0, 4.0, 50 | /// 10.1, 10.1, 51 | /// ].positions(Coords.xy), 52 | /// ], 53 | /// ), 54 | /// ); 55 | /// ``` 56 | void geometryCollection( 57 | WriteGeometries geometries, { 58 | Coords? type, 59 | int? count, 60 | String? name, 61 | Box? bounds, 62 | }); 63 | } 64 | -------------------------------------------------------------------------------- /dart/geobase/lib/src/vector/encoding/binary_format.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2024 Navibyte (https://navibyte.com). All rights reserved. 2 | // Use of this source code is governed by a “BSD-3-Clause”-style license that is 3 | // specified in the LICENSE file. 4 | // 5 | // Docs: https://github.com/navibyte/geospatial 6 | 7 | import 'dart:typed_data'; 8 | 9 | import '/src/common/reference/coord_ref_sys.dart'; 10 | 11 | import 'content_decoder.dart'; 12 | import 'content_encoder.dart'; 13 | 14 | /// A mixin to access binary format encoders and decoders for [Content] 15 | mixin BinaryFormat { 16 | /// Returns a binary format encoder for [Content]. 17 | /// 18 | /// {@template geobase.BinaryFormat.encoder} 19 | /// 20 | /// After writing content objects into an encoder, the binary representation 21 | /// can be accessed using `toBytes()` of the encoder. 22 | /// 23 | /// An optional [endian] specifies endianness for byte sequences written. Some 24 | /// encoders might ignore this, and some has a default value for it. 25 | /// 26 | /// Use [crs] to give hints (like axis order, and whether x and y must 27 | /// be swapped when writing) about coordinate reference system in binary 28 | /// output. When data itself have CRS information it overrides this value. 29 | /// 30 | /// Other format or encoder implementation specific options can be set by 31 | /// [options]. 32 | /// 33 | /// {@endtemplate} 34 | ContentEncoder encoder({ 35 | Endian? endian, 36 | CoordRefSys? crs, 37 | Map? options, 38 | }); 39 | 40 | /// Returns a binary format decoder that decodes bytes as [Content] to 41 | /// [builder]. 42 | /// 43 | /// {@template geobase.BinaryFormat.decoder} 44 | /// 45 | /// Content decoded by a decoder is sent to a content interface represented 46 | /// by an object [builder]. 47 | /// 48 | /// An optional [endian] specifies endianness for byte sequences read. Some 49 | /// decoders might ignore this, and some resolve it by reading data to be 50 | /// decoded. 51 | /// 52 | /// Use [crs] to give hints (like axis order, and whether x and y must 53 | /// be swapped when writing) about coordinate reference system in binary 54 | /// output. When data itself have CRS information it overrides this value. 55 | /// 56 | /// Other format or decoder implementation specific options can be set by 57 | /// [options]. 58 | /// 59 | /// {@endtemplate} 60 | ContentDecoder decoder( 61 | Content builder, { 62 | Endian? endian, 63 | CoordRefSys? crs, 64 | Map? options, 65 | }); 66 | } 67 | -------------------------------------------------------------------------------- /dart/geobase/lib/src/vector/encoding/content_decoder.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2023 Navibyte (https://navibyte.com). All rights reserved. 2 | // Use of this source code is governed by a “BSD-3-Clause”-style license that is 3 | // specified in the LICENSE file. 4 | // 5 | // Docs: https://github.com/navibyte/geospatial 6 | 7 | import 'dart:typed_data'; 8 | 9 | /// An interface to decode content from a text or binary format. 10 | abstract class ContentDecoder { 11 | /// Decodes text from [source] as content objects. 12 | /// 13 | /// The [source] text is expected to be a valid string representation of 14 | /// content for a text format decoder and and a base64 string representation 15 | /// of content for a binary format decoder. 16 | /// 17 | /// The target of objects decoded from text is not defined by this interface. 18 | /// A decoder could produce content objects sent to a content interface or 19 | /// build structured data objects with compatible model. Also some decoders 20 | /// might allow multiple calls to this method to build a larger target object 21 | /// structure. 22 | /// 23 | /// Throws `FormatException` if decoding fails. 24 | void decodeText(String source); 25 | 26 | /// Decodes bytes from [source] as content objects. 27 | /// 28 | /// The [source] as a sequence of bytes is expected to be a valid binary 29 | /// representation of content for a binary format decoder, and an UTF8 encoded 30 | /// binary representation of textual content for a text format decoder. 31 | /// 32 | /// The target of objects decoded from bytes is not defined by this interface. 33 | /// A decoder could produce content objects sent to a content interface or 34 | /// build structured data objects with compatible model. Also some decoders 35 | /// might allow multiple calls to this method to build a larger target object 36 | /// structure. 37 | /// 38 | /// Throws `FormatException` if decoding fails. 39 | void decodeBytes(Uint8List source); 40 | 41 | // NOTE : method to check whether (structured) data is supported 42 | 43 | /// Decodes structured data from [source] as content objects. 44 | /// 45 | /// The [source] data is expected to be a valid structured data representation 46 | /// of content like JSON Object or JSON Array. 47 | /// 48 | /// The target of objects decoded from text is not defined by this interface. 49 | /// A decoder could produce content objects sent to a content interface or 50 | /// build structured data objects with compatible model. Also some decoders 51 | /// might allow multiple calls to this method to build a larger target object 52 | /// structure. 53 | /// 54 | /// Some decoders may fail using this method even if [decodeText] or 55 | /// [decodeBytes] are usable. 56 | /// 57 | /// Throws `FormatException` if decoding fails. 58 | void decodeData(dynamic source); 59 | } 60 | -------------------------------------------------------------------------------- /dart/geobase/lib/src/vector/encoding/content_encoder.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2023 Navibyte (https://navibyte.com). All rights reserved. 2 | // Use of this source code is governed by a “BSD-3-Clause”-style license that is 3 | // specified in the LICENSE file. 4 | // 5 | // Docs: https://github.com/navibyte/geospatial 6 | 7 | import 'dart:typed_data'; 8 | 9 | /// An interface to encode [Content] into a text or binary format. 10 | abstract class ContentEncoder { 11 | /// Returns the [Content] writer. 12 | /// 13 | /// Calling this property never throws, but methods provided by the [Content] 14 | /// interface (that are used to write content) should throw `FormatException` 15 | /// if writing / encoding fails. 16 | Content get writer; 17 | 18 | /// The binary representation of content already written to this encoder. 19 | /// 20 | /// Returns a valid binary representation of content as a sequence of bytes 21 | /// for a binary format encoder, and an UTF8 encoded binary representation of 22 | /// textual content for a text format encoder. 23 | /// 24 | /// Throws `FormatException` if encoding fails. 25 | Uint8List toBytes(); 26 | 27 | /// The text representation of content already written to this encoder. 28 | /// 29 | /// Returns a valid string representation of content for a text format encoder 30 | /// and a base64 string representation of content for a binary format encoder. 31 | /// 32 | /// Throws `FormatException` if encoding fails. 33 | String toText(); 34 | 35 | /// The text representation of content already written to this encoder. 36 | /// 37 | /// Equals to calling [toText]. 38 | /// 39 | /// Returns a valid string representation of content for a text format encoder 40 | /// and a base64 string representation of content for a binary format encoder. 41 | /// 42 | /// Throws `FormatException` if encoding fails. 43 | @override 44 | String toString(); 45 | } 46 | -------------------------------------------------------------------------------- /dart/geobase/lib/src/vector/encoding/text_format.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2024 Navibyte (https://navibyte.com). All rights reserved. 2 | // Use of this source code is governed by a “BSD-3-Clause”-style license that is 3 | // specified in the LICENSE file. 4 | // 5 | // Docs: https://github.com/navibyte/geospatial 6 | 7 | import '/src/common/reference/coord_ref_sys.dart'; 8 | 9 | import 'content_decoder.dart'; 10 | import 'content_encoder.dart'; 11 | 12 | /// An interface to access text format encoders (writers) for [Content]. 13 | // ignore: one_member_abstracts 14 | abstract class TextWriterFormat { 15 | /// Returns a text format encoder for [Content]. 16 | /// 17 | /// When an optional [buffer] is given, then representations are written into 18 | /// it (without clearing any content it might already contain). 19 | /// 20 | /// After writing content objects into an encoder, the text representation can 21 | /// be accessed using `toText()` of the encoder (or via [buffer] when such 22 | /// is given). 23 | /// 24 | /// Use [decimals] to set a number of decimals (not applied if no decimals). 25 | /// 26 | /// Use [crs] to give hints (like axis order, and whether x and y must 27 | /// be swapped when writing) about coordinate reference system in text output. 28 | /// When data itself have CRS information it overrides this value. 29 | /// 30 | /// Other format or encoder implementation specific options can be set by 31 | /// [options]. 32 | ContentEncoder encoder({ 33 | StringSink? buffer, 34 | int? decimals, 35 | CoordRefSys? crs, 36 | Map? options, 37 | }); 38 | } 39 | 40 | /// An interface to access text format decoders (readers) for [Content]. 41 | // ignore: one_member_abstracts 42 | abstract class TextReaderFormat { 43 | /// Returns a text format decoder that decodes text as [Content] to [builder]. 44 | /// 45 | /// Content decoded by a decoder is sent to a content interface represented 46 | /// by an object [builder]. 47 | /// 48 | /// Use [crs] to give hints (like axis order, and whether x and y must 49 | /// be swapped when read in) about coordinate reference system in text input. 50 | /// When data itself have CRS information it overrides this value. 51 | /// 52 | /// Format or decoder implementation specific options can be set by [options]. 53 | ContentDecoder decoder( 54 | Content builder, { 55 | CoordRefSys? crs, 56 | Map? options, 57 | }); 58 | } 59 | 60 | /// A mixin to access text format encoders and decoders for [Content]. 61 | mixin TextFormat 62 | implements TextWriterFormat, TextReaderFormat {} 63 | -------------------------------------------------------------------------------- /dart/geobase/lib/src/vector/formats/geojson/default_format.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2023 Navibyte (https://navibyte.com). All rights reserved. 2 | // Use of this source code is governed by a “BSD-3-Clause”-style license that is 3 | // specified in the LICENSE file. 4 | // 5 | // Docs: https://github.com/navibyte/geospatial 6 | 7 | import '/src/utils/format_geojson_wkt.dart'; 8 | import '/src/utils/format_impl.dart'; 9 | import '/src/vector/content/coordinates_content.dart'; 10 | import '/src/vector/content/geometry_content.dart'; 11 | import '/src/vector/encoding/text_format.dart'; 12 | 13 | /// The "default" text format for [coordinate] and [geometry] objects. 14 | /// 15 | /// Rules applied by the format are aligned with GeoJSON. 16 | /// 17 | /// Examples: 18 | /// * point (x, y): `10.1,20.2` 19 | /// * point (x, y, z): `10.1,20.2,30.3` 20 | /// * point (x, y, m) with z formatted as 0: `10.1,20.2,0,40.4` 21 | /// * point (x, y, z, m): `10.1,20.2,30.3,40.4` 22 | /// * box (min-x, min-y, max-x, max-y): `10.1,10.1,20.2,20.2` 23 | /// * box (min-x, min-y, min-z, max-x, max-y, maz-z): 24 | /// * `10.1,10.1,10.1,20.2,20.2,20.2` 25 | /// * line string, multi point (with 2D points): 26 | /// * `[10.1,10.1],[20.2,20.2],[30.3,30.3]` 27 | /// * polygon, multi line string (with 2D points): 28 | /// * `[[35,10],[45,45],[15,40],[10,20],[35,10]]` 29 | /// * multi polygon (with 2D points): 30 | /// * `[[[35,10],[45,45],[15,40],[10,20],[35,10]]]` 31 | /// * coordinates for other geometries with similar principles 32 | /// 33 | /// When getting an encoder from text writer format objects this `DefaultFormat` 34 | /// class provides you can use `crs` parameter to give hints (like axis order, 35 | /// and whether x and y must be swapped when writing) about coordinate reference 36 | /// system in text output. When `crs` is available then `crs.swapXY` is used to 37 | /// determine whether swapping (x/longitude <-> y/latitude) should occur. 38 | class DefaultFormat { 39 | /// The (default) text writer format for coordinate objects. 40 | static const TextWriterFormat coordinate = 41 | TextWriterFormatImpl(DefaultTextWriter.new); 42 | 43 | /// The (default) text writer format for geometry objects. 44 | static const TextWriterFormat geometry = 45 | TextWriterFormatImpl(DefaultTextWriter.new); 46 | } 47 | -------------------------------------------------------------------------------- /dart/geobase/lib/src/vector/formats/wkt/wkt_like_format.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2023 Navibyte (https://navibyte.com). All rights reserved. 2 | // Use of this source code is governed by a “BSD-3-Clause”-style license that is 3 | // specified in the LICENSE file. 4 | // 5 | // Docs: https://github.com/navibyte/geospatial 6 | 7 | import '/src/utils/format_geojson_wkt.dart'; 8 | import '/src/utils/format_impl.dart'; 9 | import '/src/vector/content/coordinates_content.dart'; 10 | import '/src/vector/content/geometry_content.dart'; 11 | import '/src/vector/encoding/text_format.dart'; 12 | 13 | /// The WKT (like) text format for [coordinate] and [geometry] objects. 14 | /// 15 | /// Rules applied by the format are aligned with WKT (Well-known text 16 | /// representation of geometry) formatting of coordinate lists. 17 | /// 18 | /// Examples: 19 | /// * point (x, y): `10.1 20.2` 20 | /// * point (x, y, z): `10.1 20.2 30.3` 21 | /// * point (x, y, z, m): `10.1 20.2 30.3 40.4` 22 | /// * box (min-x, min-y, max-x, max-y): `10.1 10.1,20.2 20.2` 23 | /// * box (min-x, min-y, min-z, max-x, max-y, maz-z): 24 | /// * `10.1 10.1 10.1,20.2 20.2 20.2` 25 | /// * line string, multi point (with 2D points): 26 | /// * `10.1 10.1,20.2 20.2,30.3 30.3` 27 | /// * polygon, multi line string (with 2D points): 28 | /// * `(35 10,45 45,15 40,10 20,35 10)` 29 | /// * multi polygon (with 2D points): 30 | /// * `((35 10,45 45,15 40,10 20,35 10))` 31 | /// * coordinates for other geometries with similar principles 32 | /// 33 | /// Note that WKT does not specify bounding box formatting. In some applications 34 | /// bounding boxes are formatted as polygons. An example presented above however 35 | /// format bounding box as a point series of two points (min, max). See also 36 | /// `wktFormat` that formats them as polygons. 37 | /// 38 | /// When getting an encoder from text writer format objects this `WktLikeFormat` 39 | /// class provides you COULD use `crs` parameter to give hints (like axis order, 40 | /// and whether x and y must be swapped when writing) about coordinate reference 41 | /// system in text output. However for the WKT (like) text format such crs 42 | /// information is ignored, x/longitude is always printed before y/latitude 43 | /// regardless of crs axis order. 44 | class WktLikeFormat { 45 | /// The WKT (like) text writer format for coordinate objects. 46 | static const TextWriterFormat coordinate = 47 | TextWriterFormatImpl(WktLikeTextWriter.new); 48 | 49 | /// The WKT (like) text writer format for geometry objects. 50 | static const TextWriterFormat geometry = 51 | TextWriterFormatImpl(WktLikeTextWriter.new); 52 | } 53 | -------------------------------------------------------------------------------- /dart/geobase/lib/tiling.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2023 Navibyte (https://navibyte.com). All rights reserved. 2 | // Use of this source code is governed by a “BSD-3-Clause”-style license that is 3 | // specified in the LICENSE file. 4 | // 5 | // Docs: https://github.com/navibyte/geospatial 6 | 7 | /// Tiling schemes and tile matrix sets (web mercator, global geodetic). 8 | /// 9 | /// This libary exports a subset of `package:geobase/geobase.dart`. 10 | /// 11 | /// Usage: import `package:geobase/tiling.dart` 12 | library tiling; 13 | 14 | export 'src/common/codes/canvas_origin.dart'; 15 | export 'src/common/constants/geodetic.dart'; 16 | export 'src/common/constants/screen_ppi.dart'; 17 | export 'src/tiling/convert/scaled_converter.dart'; 18 | export 'src/tiling/tilematrix/base/geo_tile_matrix_set.dart'; 19 | export 'src/tiling/tilematrix/base/tile_matrix_set.dart'; 20 | export 'src/tiling/tilematrix/mercator/web_mercator_quad.dart'; 21 | export 'src/tiling/tilematrix/plate_carree/global_geodetic_quad.dart'; 22 | -------------------------------------------------------------------------------- /dart/geobase/lib/vector.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2025 Navibyte (https://navibyte.com). All rights reserved. 2 | // Use of this source code is governed by a “BSD-3-Clause”-style license that is 3 | // specified in the LICENSE file. 4 | // 5 | // Docs: https://github.com/navibyte/geospatial 6 | 7 | /// Text and binary formats for vector data (features, geometries, coordinates). 8 | /// 9 | /// Key features: 10 | /// * positions, position arrays and bounding boxes based on coordinate arrays 11 | /// * text format writers and parsers for features, geometries, coordinates, 12 | /// properties: 13 | /// * supported formats: [GeoJSON](https://geojson.org/) 14 | /// * text format writers and parsers for geometries and coordinates: 15 | /// * supported formats: [WKT](https://en.wikipedia.org/wiki/Well-known_text_representation_of_geometry) 16 | /// * binary format encoders and decoders for geometries: 17 | /// * supported formats: [WKB](https://en.wikipedia.org/wiki/Well-known_text_representation_of_geometry#Well-known_binary) 18 | /// 19 | /// This libary exports a subset of `package:geobase/geobase.dart`. 20 | /// 21 | /// Usage: import `package:geobase/vector.dart` 22 | library vector; 23 | 24 | export 'src/common/codes/coords.dart'; 25 | export 'src/common/codes/geo_representation.dart'; 26 | export 'src/common/codes/geom.dart'; 27 | export 'src/common/reference/coord_ref_sys.dart'; 28 | export 'src/vector/content/coordinates_content.dart'; 29 | export 'src/vector/content/feature_content.dart'; 30 | export 'src/vector/content/geometry_content.dart'; 31 | export 'src/vector/content/simple_geometry_content.dart'; 32 | export 'src/vector/encoding/binary_format.dart'; 33 | export 'src/vector/encoding/content_decoder.dart'; 34 | export 'src/vector/encoding/content_encoder.dart'; 35 | export 'src/vector/encoding/text_format.dart'; 36 | export 'src/vector/formats/geojson/default_format.dart'; 37 | export 'src/vector/formats/geojson/geojson_format.dart'; 38 | export 'src/vector/formats/wkb/wkb_format.dart'; 39 | export 'src/vector/formats/wkt/wkt_format.dart'; 40 | export 'src/vector/formats/wkt/wkt_like_format.dart'; 41 | -------------------------------------------------------------------------------- /dart/geobase/lib/vector_data.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2025 Navibyte (https://navibyte.com). All rights reserved. 2 | // Use of this source code is governed by a “BSD-3-Clause”-style license that is 3 | // specified in the LICENSE file. 4 | // 5 | // Docs: https://github.com/navibyte/geospatial 6 | 7 | // ignore_for_file: lines_longer_than_80_chars 8 | 9 | /// Data structures for geometries, geometry collections, features and feature 10 | /// collections. 11 | /// 12 | /// Key features: 13 | /// * simple geometries (point, line string, polygon, multi point, multi line 14 | /// string, multi polygon) and geometry collections 15 | /// * features (with id, properties and geometry) and feature collections 16 | /// 17 | /// This libary exports a subset of `package:geobase/geobase.dart`. 18 | /// 19 | /// Usage: import `package:geobase/vector_data.dart` 20 | library vector_data; 21 | 22 | export 'src/common/codes/coords.dart'; 23 | export 'src/common/codes/dimensionality.dart'; 24 | export 'src/common/codes/geom.dart'; 25 | export 'src/common/reference/coord_ref_sys.dart'; 26 | export 'src/vector_data/model/feature/feature.dart'; 27 | export 'src/vector_data/model/feature/feature_builder.dart'; 28 | export 'src/vector_data/model/feature/feature_collection.dart'; 29 | export 'src/vector_data/model/feature/feature_object.dart'; 30 | export 'src/vector_data/model/geometry/geometry.dart'; 31 | export 'src/vector_data/model/geometry/geometry_builder.dart'; 32 | export 'src/vector_data/model/geometry/geometry_collection.dart'; 33 | export 'src/vector_data/model/geometry/linestring.dart'; 34 | export 'src/vector_data/model/geometry/multi_linestring.dart'; 35 | export 'src/vector_data/model/geometry/multi_point.dart'; 36 | export 'src/vector_data/model/geometry/multi_polygon.dart'; 37 | export 'src/vector_data/model/geometry/point.dart'; 38 | export 'src/vector_data/model/geometry/polygon.dart'; 39 | -------------------------------------------------------------------------------- /dart/geobase/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: geobase 2 | description: Geospatial data, geometry, geodesy, projections, tiling schemes, and vector formats (GeoJSON, WKT, WKB). 3 | version: 1.5.0 4 | repository: https://github.com/navibyte/geospatial 5 | homepage: https://geospatial.navibyte.dev/ 6 | 7 | topics: 8 | - location 9 | - utility 10 | - geojson 11 | - wgs84 12 | - map 13 | 14 | environment: 15 | sdk: '>=2.17.0 <4.0.0' 16 | 17 | dependencies: 18 | meta: ^1.7.0 19 | proj4dart: ^2.0.0 20 | 21 | dev_dependencies: 22 | test: ^1.24.0 23 | very_good_analysis: ^6.0.0 24 | -------------------------------------------------------------------------------- /dart/geobase/test/advices/basic_impls.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2023 Navibyte (https://navibyte.com). All rights reserved. 2 | // Use of this source code is governed by a “BSD-3-Clause”-style license that is 3 | // specified in the LICENSE file. 4 | // 5 | // Docs: https://github.com/navibyte/geospatial 6 | 7 | // ignore_for_file: prefer_const_declarations 8 | 9 | import 'dart:typed_data'; 10 | 11 | import 'package:geobase/coordinates.dart'; 12 | 13 | import 'package:geobase/src/utils/format_validation.dart'; 14 | 15 | // A dummy projection that just adds 1.0 to x and y coordinates (for testing). 16 | class AddOneOnXYProjection with Projection { 17 | @override 18 | T project( 19 | Position source, { 20 | required CreatePosition to, 21 | }) => 22 | to.call( 23 | x: source.x + 1.0, 24 | y: source.y + 1.0, 25 | z: source.optZ, 26 | m: source.optM, 27 | ); 28 | 29 | @override 30 | List projectCoords( 31 | Iterable source, { 32 | List? target, 33 | required Coords type, 34 | }) { 35 | final dim = type.coordinateDimension; 36 | final result = target ?? Float64List(source.length); 37 | 38 | var offset = 0; 39 | final iter = source.iterator; 40 | while (iter.moveNext()) { 41 | result[offset] = iter.current + 1.0; 42 | result[offset + 1] = 43 | iter.moveNext() ? iter.current + 1.0 : throw invalidCoordinates; 44 | // optional z and m coords unchanged 45 | if (dim >= 3) { 46 | result[offset + 2] = 47 | iter.moveNext() ? iter.current : throw invalidCoordinates; 48 | } 49 | if (dim >= 4) { 50 | result[offset + 3] = 51 | iter.moveNext() ? iter.current : throw invalidCoordinates; 52 | } 53 | offset += dim; 54 | } 55 | 56 | return result; 57 | } 58 | } 59 | 60 | T addOneOnXYTransform( 61 | Position source, { 62 | required CreatePosition to, 63 | }) => 64 | to.call( 65 | x: source.x + 1.0, 66 | y: source.y + 1, 67 | z: source.optZ, 68 | m: source.optM, 69 | ); 70 | -------------------------------------------------------------------------------- /dart/geobase/test/coordinates/scalable_test.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2023 Navibyte (https://navibyte.com). All rights reserved. 2 | // Use of this source code is governed by a “BSD-3-Clause”-style license that is 3 | // specified in the LICENSE file. 4 | // 5 | // Docs: https://github.com/navibyte/geospatial 6 | 7 | // ignore_for_file: prefer_const_declarations 8 | 9 | import 'package:geobase/coordinates.dart'; 10 | 11 | import 'package:test/test.dart'; 12 | 13 | void main() { 14 | group('Basic tiling scheme tests', () { 15 | const ref0 = Scalable2i(zoom: 0, x: 1, y: 0); 16 | const ref9 = Scalable2i(zoom: 9, x: 23, y: 10); 17 | const ref9neg = Scalable2i(zoom: 9, x: -23, y: -10); 18 | test('Test Scalable2i coordinates', () { 19 | expect(Scalable2i.build(const [9, 23, 10]), ref9); 20 | expect(Scalable2i.parse('9;23;10', delimiter: ';'), ref9); 21 | expect(Scalable2i.factory(zoom: 9).call(x: 23, y: 10), ref9); 22 | }); 23 | 24 | test('Test Scalable2i coordinates (output)', () { 25 | expect(Scalable2i.build(const [9, 23, 10]).toText(), '9,23,10'); 26 | expect(Scalable2i.parse('9;23;10', delimiter: ';').values, [9, 23, 10]); 27 | 28 | final s2i = Scalable2i.factory(zoom: 9).call(x: 23, y: 10); 29 | expect(s2i[0], 9); 30 | expect(s2i[1], 23); 31 | expect(s2i[2], 10); 32 | }); 33 | 34 | test('Test Scalable2i zoomIn and zoomOut', () { 35 | expect(ref0.zoomIn(), const Scalable2i(zoom: 1, x: 2, y: 0)); 36 | expect(ref0.zoomOut(), const Scalable2i(zoom: 0, x: 1, y: 0)); 37 | expect(ref9.zoomIn(), const Scalable2i(zoom: 10, x: 46, y: 20)); 38 | expect(ref9.zoomOut(), const Scalable2i(zoom: 8, x: 11, y: 5)); 39 | expect(ref9neg.zoomIn(), const Scalable2i(zoom: 10, x: -46, y: -20)); 40 | expect(ref9neg.zoomOut(), const Scalable2i(zoom: 8, x: -12, y: -5)); 41 | }); 42 | 43 | test('Test Scalable2i zoomTo', () { 44 | expect(ref0.zoomTo(2), const Scalable2i(zoom: 2, x: 4, y: 0)); 45 | expect(ref0.zoomTo(0), const Scalable2i(zoom: 0, x: 1, y: 0)); 46 | expect(ref9.zoomTo(13), const Scalable2i(zoom: 13, x: 368, y: 160)); 47 | expect(ref9.zoomTo(6), const Scalable2i(zoom: 6, x: 2, y: 1)); 48 | expect(ref9neg.zoomTo(13), const Scalable2i(zoom: 13, x: -368, y: -160)); 49 | expect(ref9neg.zoomTo(6), const Scalable2i(zoom: 6, x: -3, y: -2)); 50 | }); 51 | }); 52 | } 53 | -------------------------------------------------------------------------------- /dart/geobase/test/meta/crs_test.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2023 Navibyte (https://navibyte.com). All rights reserved. 2 | // Use of this source code is governed by a “BSD-3-Clause”-style license that is 3 | // specified in the LICENSE file. 4 | // 5 | // Docs: https://github.com/navibyte/geospatial 6 | 7 | // ignore_for_file: prefer_const_constructors, avoid_print 8 | 9 | import 'package:geobase/common.dart'; 10 | 11 | import 'package:test/test.dart'; 12 | 13 | void main() { 14 | group('coordRefSys', () { 15 | final epsg4326 = 16 | CoordRefSys.normalized('http://www.opengis.net/def/crs/EPSG/0/4326'); 17 | 18 | test('instantiation', () { 19 | expect(epsg4326, CoordRefSys.from(coordRefSys: CoordRefSys.EPSG_4326)); 20 | expect(epsg4326, CoordRefSys.from(crs: 'EPSG:4326')); 21 | expect(epsg4326, isNot(CoordRefSys.id('EPSG:4326'))); 22 | expect( 23 | epsg4326, 24 | CoordRefSys.id('http://www.opengis.net/def/crs/EPSG/0/4326'), 25 | ); 26 | expect( 27 | epsg4326, 28 | CoordRefSys.from(coordRefSys: CoordRefSys.EPSG_4326, crs: 'what ever'), 29 | ); 30 | expect(CoordRefSys.CRS84, CoordRefSys.from()); 31 | }); 32 | 33 | test('id normalization', () { 34 | expect(epsg4326, CoordRefSys.normalized('EPSG:4326')); 35 | expect(epsg4326.id, 'http://www.opengis.net/def/crs/EPSG/0/4326'); 36 | }); 37 | test('id normalization (not normalized)', () { 38 | expect(epsg4326, isNot(CoordRefSys.normalized('4326'))); 39 | }); 40 | test('axis order', () { 41 | expect(CoordRefSys.CRS84.axisOrder, AxisOrder.xy); 42 | expect(CoordRefSys.CRS84h.axisOrder, AxisOrder.xy); 43 | expect(CoordRefSys.EPSG_4326.axisOrder, AxisOrder.yx); 44 | expect(CoordRefSys.EPSG_3857.axisOrder, AxisOrder.xy); 45 | expect(CoordRefSys.EPSG_3395.axisOrder, AxisOrder.xy); 46 | expect(CoordRefSys.id('EPSG:27700').axisOrder, isNull); 47 | }); 48 | 49 | test('epsg', () { 50 | expect(CoordRefSys.CRS84.epsg, isNull); 51 | expect(CoordRefSys.CRS84h.epsg, isNull); 52 | expect(CoordRefSys.EPSG_4326.epsg, 'EPSG:4326'); 53 | expect(CoordRefSys.EPSG_3857.epsg, 'EPSG:3857'); 54 | expect(CoordRefSys.EPSG_3395.epsg, 'EPSG:3395'); 55 | expect(CoordRefSys.id('EPSG:27700').epsg, 'EPSG:27700'); 56 | expect(CoordRefSys.normalized('EPSG:27700').epsg, 'EPSG:27700'); 57 | expect(CoordRefSys.id('EPSG:NOTVALID').epsg, isNull); 58 | expect(CoordRefSys.normalized('EPSG:NOTVALID').epsg, isNull); 59 | }); 60 | }); 61 | } 62 | -------------------------------------------------------------------------------- /dart/geobase/test/meta/extent_test.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2023 Navibyte (https://navibyte.com). All rights reserved. 2 | // Use of this source code is governed by a “BSD-3-Clause”-style license that is 3 | // specified in the LICENSE file. 4 | // 5 | // Docs: https://github.com/navibyte/geospatial 6 | 7 | // ignore_for_file: prefer_const_constructors, avoid_print 8 | 9 | import 'package:geobase/coordinates.dart'; 10 | import 'package:geobase/meta.dart'; 11 | 12 | import 'package:test/test.dart'; 13 | 14 | void main() { 15 | final bbox1 = GeoBox(west: -19.2, south: -4.5, east: 12.2, north: 24.5); 16 | final bbox2 = GeoBox(west: -19.2, south: 31.0, east: 12.2, north: 32.0); 17 | final spatialSingle = SpatialExtent.single(bbox1); 18 | final spatialMulti1 = SpatialExtent.multi([bbox1]); 19 | final spatialMulti2 = SpatialExtent.multi([bbox1, bbox2]); 20 | final spatialMulti3 = SpatialExtent.multi([bbox2, bbox1]); 21 | 22 | group('Spatial extents', () { 23 | test('Equals and key properties', () { 24 | expect(spatialSingle, spatialMulti1); 25 | expect(spatialSingle, isNot(spatialMulti2)); 26 | expect(spatialMulti3, isNot(spatialMulti2)); 27 | expect(spatialSingle.crs, spatialMulti1.crs); 28 | expect(spatialSingle.first, spatialMulti1.first); 29 | expect(spatialSingle.first, spatialMulti2.first); 30 | expect(spatialSingle.first, isNot(spatialMulti3.first)); 31 | expect( 32 | spatialSingle.boxes, 33 | [GeoBox(west: -19.2, south: -4.5, east: 12.2, north: 24.5)], 34 | ); 35 | }); 36 | }); 37 | 38 | final interval1 = Interval.closed( 39 | DateTime.parse('2020-10-03 20:30:10Z'), 40 | DateTime.parse('2020-10-05 01:15:50Z'), 41 | ); 42 | final interval2 = 43 | Interval.parse('2020-10-03T20:30:10.000Z/2020-10-05T01:15:50.000Z'); 44 | final temporalSingle = TemporalExtent.single(interval2); 45 | 46 | group('Temporal extents', () { 47 | test('Equals and key properties', () { 48 | expect(temporalSingle.first, interval1); 49 | expect(temporalSingle.intervals, [interval1]); 50 | }); 51 | }); 52 | 53 | final extent1 = GeoExtent(spatial: spatialSingle, temporal: temporalSingle); 54 | 55 | group('Geo extents', () { 56 | test('Equals and key properties', () { 57 | expect( 58 | extent1.spatial.first, 59 | GeoBox(west: -19.2, south: -4.5, east: 12.2, north: 24.5), 60 | ); 61 | expect( 62 | extent1.spatial.crs.toString(), 63 | 'http://www.opengis.net/def/crs/OGC/1.3/CRS84', 64 | ); 65 | expect(extent1.temporal!.first, interval1); 66 | expect( 67 | extent1.temporal!.trs.toString(), 68 | 'http://www.opengis.net/def/uom/ISO-8601/0/Gregorian', 69 | ); 70 | expect( 71 | extent1.toString(), 72 | '[http://www.opengis.net/def/crs/OGC/1.3/CRS84,[-19.2,-4.5,12.2,24.5]],' 73 | '[http://www.opengis.net/def/uom/ISO-8601/0/Gregorian,' 74 | '2020-10-03T20:30:10.000Z/2020-10-05T01:15:50.000Z]', 75 | ); 76 | }); 77 | }); 78 | } 79 | -------------------------------------------------------------------------------- /dart/geobase/test/vector_data/geometry_wkt_test.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2025 Navibyte (https://navibyte.com). All rights reserved. 2 | // Use of this source code is governed by a “BSD-3-Clause”-style license that is 3 | // specified in the LICENSE file. 4 | // 5 | // Docs: https://github.com/navibyte/geospatial 6 | 7 | // ignore_for_file: lines_longer_than_80_chars, avoid_redundant_argument_values 8 | 9 | import 'package:geobase/vector.dart'; 10 | import 'package:geobase/vector_data.dart'; 11 | 12 | import 'package:test/test.dart'; 13 | 14 | import '../vector/wkt_samples.dart'; 15 | 16 | void main() { 17 | group('WKT special cases', () { 18 | test('EWKT - samples', () { 19 | for (final test in wktGeometries2) { 20 | final input = test[0] as List; 21 | final geom = test[1] as Geometry; 22 | final srid = test[2] as int?; 23 | final dim = test[3] as Coords; 24 | 25 | for (final wkt in input) { 26 | const spaces = [' (', '( ', ' ( ', '( ']; 27 | 28 | for (final sp in spaces) { 29 | const formats = [ 30 | WKT.geometry, 31 | GeoJSON.geometry, 32 | DefaultFormat.geometry, 33 | ]; 34 | for (final format in formats) { 35 | final source = wkt.replaceAll('(', sp); 36 | expect( 37 | GeometryBuilder.parse( 38 | source, 39 | format: WKT.geometry, 40 | ).toText(format: format), 41 | geom.toText(format: format), 42 | ); 43 | if (srid != null && source.contains('SRID')) { 44 | expect(WKT.decodeSRID(source), srid); 45 | } 46 | expect(WKT.decodeCoordType(source), dim); 47 | } 48 | } 49 | } 50 | } 51 | }); 52 | }); 53 | } 54 | -------------------------------------------------------------------------------- /dart/geobase/test/vector_data/multi_geometry_test.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2024 Navibyte (https://navibyte.com). All rights reserved. 2 | // Use of this source code is governed by a “BSD-3-Clause”-style license that is 3 | // specified in the LICENSE file. 4 | // 5 | // Docs: https://github.com/navibyte/geospatial 6 | 7 | // ignore_for_file: cascade_invocations, lines_longer_than_80_chars 8 | 9 | import 'package:geobase/vector.dart'; 10 | import 'package:geobase/vector_data.dart'; 11 | 12 | import 'package:test/test.dart'; 13 | 14 | // see also '../vector/geojson_test.dart' 15 | 16 | void main() { 17 | group('MultiPoint', () { 18 | test('Create from coords', () { 19 | const points54 = '[1.1,2.1,3.1,4.1,5.1],[1.2,2.2,3.2,4.2]'; 20 | const points45 = '[1.1,2.1,3.1,4.1],[1.2,2.2,3.2,4.2,5.2]'; 21 | const points44 = '[1.1,2.1,3.1,4.1],[1.2,2.2,3.2,4.2]'; 22 | const points33 = '[1.1,2.1,3.1],[1.2,2.2,3.2]'; 23 | const points23 = '[1.1,2.1],[1.2,2.2,3.2]'; 24 | const points32 = '[1.1,2.1,3.1],[1.2,2.2]'; 25 | const points32_0 = '[1.1,2.1,3.1],[1.2,2.2,0]'; 26 | const points22 = '[1.1,2.1],[1.2,2.2]'; 27 | const points12 = '[1.1],[1.2,2.2]'; 28 | const points21 = '[1.1,2.1],[1.2]'; 29 | const points20 = '[1.1,2.1],[]'; 30 | const points02 = '[],[1.2,2.2]'; 31 | 32 | const tests = [ 33 | [points54, points44], 34 | [points45, points44], 35 | [points44, points44], 36 | [points33, points33], 37 | [points23, points22], 38 | [points32, points32_0], 39 | [points22, points22], 40 | ]; 41 | for (final test in tests) { 42 | expect( 43 | MultiPoint.parseCoords(_toFlat(test[0])) 44 | .toText(format: DefaultFormat.geometry), 45 | test[1], 46 | ); 47 | } 48 | expect( 49 | () => MultiPoint.parseCoords(_toFlat(points12)), 50 | throwsFormatException, 51 | ); 52 | expect( 53 | () => MultiPoint.parseCoords(_toFlat(points21)), 54 | throwsFormatException, 55 | ); 56 | expect( 57 | () => MultiPoint.parseCoords(_toFlat(points20)), 58 | throwsFormatException, 59 | ); 60 | expect( 61 | () => MultiPoint.parseCoords(_toFlat(points02)), 62 | throwsFormatException, 63 | ); 64 | }); 65 | }); 66 | } 67 | 68 | Iterable _toFlat(String test) => 69 | test.substring(1, test.length - 1).split('],['); 70 | -------------------------------------------------------------------------------- /dart/geocore/.gitignore: -------------------------------------------------------------------------------- 1 | # Files and directories created by pub 2 | .dart_tool/ 3 | .packages 4 | # Remove the following pattern if you wish to check in your lock file 5 | pubspec.lock 6 | 7 | # Conventional directory for build outputs 8 | build/ 9 | 10 | # Directory created by dartdoc 11 | doc/api/ 12 | -------------------------------------------------------------------------------- /dart/geocore/LICENSE: -------------------------------------------------------------------------------- 1 | The 3-Clause BSD License 2 | 3 | Copyright (c) 2020-2024 Navibyte. All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without modification, 6 | are permitted provided that the following conditions are met: 7 | 8 | 1. Redistributions of source code must retain the above copyright notice, this 9 | list of conditions and the following disclaimer. 10 | 11 | 2. Redistributions in binary form must reproduce the above copyright notice, 12 | this list of conditions and the following disclaimer in the documentation and/or 13 | other materials provided with the distribution. 14 | 15 | 3. Neither the name of the copyright holder nor the names of its contributors 16 | may be used to endorse or promote products derived from this software without 17 | specific prior written permission. 18 | 19 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 20 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 21 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 22 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 23 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 24 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 25 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 26 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 28 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- /dart/geocore/lib/base.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2023 Navibyte (https://navibyte.com). All rights reserved. 2 | // Use of this source code is governed by a “BSD-3-Clause”-style license that is 3 | // specified in the LICENSE file. 4 | // 5 | // Docs: https://github.com/navibyte/geospatial 6 | 7 | /// Base classes for geospatial geometries objects. 8 | /// 9 | /// *Spatial* classes include coordinates, points, bounds, point series, and 10 | /// transform and projection abstractions. 11 | /// 12 | /// Exports also `Coords`, `Position`, `TransformPosition`, `CreatePosition`, 13 | /// `Box` and `Projection` from `package:geobase/coordinates.dart`. 14 | /// 15 | /// Usage: import `package:geocore/base.dart` 16 | library base; 17 | 18 | export 'package:geobase/coordinates.dart' 19 | show Box, Coords, CreatePosition, Position, Projection, TransformPosition; 20 | 21 | export 'src/base/spatial.dart'; 22 | -------------------------------------------------------------------------------- /dart/geocore/lib/coordinates.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2023 Navibyte (https://navibyte.com). All rights reserved. 2 | // Use of this source code is governed by a “BSD-3-Clause”-style license that is 3 | // specified in the LICENSE file. 4 | // 5 | // Docs: https://github.com/navibyte/geospatial 6 | 7 | /// Projected and geographic coordinates, and basic transforms. 8 | /// 9 | /// This library exports also all classes of `package:geocore/base.dart`. 10 | /// 11 | /// Usage: import `package:geocore/coordinates.dart` 12 | library coordinates; 13 | 14 | export 'base.dart'; 15 | 16 | export 'src/coordinates/geographic.dart'; 17 | export 'src/coordinates/projected.dart'; 18 | export 'src/coordinates/transforms.dart'; 19 | -------------------------------------------------------------------------------- /dart/geocore/lib/data.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2023 Navibyte (https://navibyte.com). All rights reserved. 2 | // Use of this source code is governed by a “BSD-3-Clause”-style license that is 3 | // specified in the LICENSE file. 4 | // 5 | // Docs: https://github.com/navibyte/geospatial 6 | 7 | /// Geospatial features and geometries (linestring, polygon, multi geometries). 8 | /// 9 | /// This library exports also all classes of `package:geocore/base.dart` and 10 | /// `package:geocore/coordinates.dart`. 11 | /// 12 | /// Exports also `Coords`, `Position`, `TransformPosition`, `CreatePosition`, 13 | /// `Box` and `Projection` from `package:geobase/coordinates.dart`. 14 | /// 15 | /// Exports also `Geom`, `CoordinateContent`, `SimpleGeometryContent`, 16 | /// `GeometryContent`, `GeometryBinaryFormat`, `FeatureContent`, 17 | /// `PropertyContent`, `ContentDecoder`, `ContentEncoder`, `BinaryFormat`, 18 | /// `TextWriterFormat`, `DefaultFormat`, `WktLikeFormat`, `GeoJSON`, `WKT` and 19 | /// `WKB` from `package:geobase/vector.dart`. 20 | /// 21 | /// Usage: import `package:geocore/data.dart` 22 | library data; 23 | 24 | export 'package:geobase/vector.dart' 25 | show 26 | BinaryFormat, 27 | ContentDecoder, 28 | ContentEncoder, 29 | CoordinateContent, 30 | DefaultFormat, 31 | FeatureContent, 32 | GeoJSON, 33 | Geom, 34 | GeometryContent, 35 | PropertyContent, 36 | SimpleGeometryContent, 37 | TextWriterFormat, 38 | WKB, 39 | WKT, 40 | WktLikeFormat; 41 | 42 | export 'base.dart'; 43 | export 'coordinates.dart'; 44 | 45 | export 'src/data/feature.dart'; 46 | export 'src/data/simple_geometry.dart'; 47 | -------------------------------------------------------------------------------- /dart/geocore/lib/geocore.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2023 Navibyte (https://navibyte.com). All rights reserved. 2 | // Use of this source code is governed by a “BSD-3-Clause”-style license that is 3 | // specified in the LICENSE file. 4 | // 5 | // Docs: https://github.com/navibyte/geospatial 6 | 7 | /// Geospatial data (geometry, features, meta) and parsers (WKT, GeoJSON). 8 | /// 9 | /// Exports `Coords`, `Position`, `TransformPosition`, `CreatePosition`, `Box` 10 | /// and `Projection` from `package:geobase/coordinates.dart`. 11 | /// 12 | /// Exports also `Geom`, `CoordinateContent`, `SimpleGeometryContent`, 13 | /// `GeometryContent`, `GeometryBinaryFormat`, `FeatureContent`, 14 | /// `PropertyContent`, `ContentDecoder`, `ContentEncoder`, `BinaryFormat`, 15 | /// `TextWriterFormat`, `DefaultFormat`, `WktLikeFormat`, `GeoJSON`, `WKT` and 16 | /// `WKB` from `package:geobase/vector.dart`. 17 | /// 18 | /// Usage: import `package:geocore/geocore.dart` 19 | library geocore; 20 | 21 | // Export mini-libraries forming the whole "geocore" library. 22 | export 'base.dart'; 23 | export 'coordinates.dart'; 24 | export 'data.dart'; 25 | 26 | export 'src/parse/factory.dart'; 27 | export 'src/parse/geojson.dart'; 28 | export 'src/parse/wkt.dart'; 29 | -------------------------------------------------------------------------------- /dart/geocore/lib/src/base/spatial.dart: -------------------------------------------------------------------------------- 1 | export 'spatial/spatial.dart'; 2 | -------------------------------------------------------------------------------- /dart/geocore/lib/src/base/spatial/bounded.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2023 Navibyte (https://navibyte.com). All rights reserved. 2 | // Use of this source code is governed by a “BSD-3-Clause”-style license that is 3 | // specified in the LICENSE file. 4 | // 5 | // Docs: https://github.com/navibyte/geospatial 6 | 7 | part of 'spatial.dart'; 8 | 9 | /// An internal base interface for classes that know their [bounds]. 10 | /// 11 | /// This is extended by [Bounded] and an internal interface [_BatchedSeries]. 12 | abstract class _BoundedBase { 13 | /// Default `const` constructor to allow extending this abstract class. 14 | const _BoundedBase(); 15 | 16 | /// The [bounds] for this object (could be calculated if not explicitely set). 17 | /// 18 | /// Please note that in some cases bounds could be pre-calculated but it's 19 | /// possible that accessing this property may cause extensive calculations. 20 | /// 21 | /// For some bounded objects (like an empty collections) bounds cannot be 22 | /// resolved at all. In such case, the null value is returned. 23 | Bounds? get bounds; 24 | 25 | /// The explicit [bounds] for this object when available. 26 | /// 27 | /// Accessing this should never trigger extensive calculations. That is, if 28 | /// bounds is not known, then returns the null value. 29 | Bounds? get boundsExplicit; 30 | } 31 | 32 | /// A base interface for classes that know their [bounds]. 33 | abstract class Bounded extends _BoundedBase { 34 | /// Default `const` constructor to allow extending this abstract class. 35 | const Bounded(); 36 | 37 | /// Returns a new object with all points transformed using [transform]. 38 | /// 39 | /// The transformed bounded object must be of the same type with this object. 40 | Bounded transform(TransformPosition transform); 41 | 42 | /// Returns a new object with all points projected using [projection]. 43 | /// 44 | /// Target points of [R] are created using [to] as a point factory. 45 | Bounded project( 46 | Projection projection, { 47 | required CreatePosition to, 48 | }); 49 | } 50 | -------------------------------------------------------------------------------- /dart/geocore/lib/src/base/spatial/point_wrapper.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2023 Navibyte (https://navibyte.com). All rights reserved. 2 | // Use of this source code is governed by a “BSD-3-Clause”-style license that is 3 | // specified in the LICENSE file. 4 | // 5 | // Docs: https://github.com/navibyte/geospatial 6 | 7 | part of 'spatial.dart'; 8 | 9 | /// A point with getters to access the wrapped [point]. 10 | /// 11 | /// This class is surely immutable, but the aggregated [point] object may 12 | /// or may not to be immutable. 13 | @immutable 14 | class PointWrapper, C extends num> extends Point { 15 | /// Create a point wrapping another [point]. 16 | const PointWrapper(this.point); 17 | 18 | /// The wrapped [point]. 19 | final T point; 20 | 21 | @override 22 | Bounds? get bounds => point.bounds; 23 | 24 | @override 25 | Bounds? get boundsExplicit => point.boundsExplicit; 26 | 27 | @override 28 | int get coordinateDimension => point.coordinateDimension; 29 | 30 | @override 31 | int get spatialDimension => point.spatialDimension; 32 | 33 | @override 34 | bool get isGeographic => point.isGeographic; 35 | 36 | @override 37 | bool get is3D => point.is3D; 38 | 39 | @override 40 | bool get isMeasured => point.isMeasured; 41 | 42 | @override 43 | Coords get type => point.type; 44 | 45 | @override 46 | C operator [](int i) => point[i]; 47 | 48 | @override 49 | C get x => point.x; 50 | 51 | @override 52 | C get y => point.y; 53 | 54 | @override 55 | C get z => point.z; 56 | 57 | @override 58 | C get m => point.m; 59 | 60 | @override 61 | C? get optZ => point.optZ; 62 | 63 | @override 64 | C? get optM => point.optM; 65 | 66 | @override 67 | T copyWith({num? x, num? y, num? z, num? m}) => 68 | point.copyWith(x: x, y: y, z: z, m: m) as T; 69 | 70 | @override 71 | T newWith({num x = 0.0, num y = 0.0, num? z, num? m}) => 72 | point.newWith(x: x, y: y, z: z, m: m) as T; 73 | 74 | @override 75 | T newFrom(Iterable coords, {int? offset, int? length}) => 76 | point.newFrom(coords, offset: offset, length: length) as T; 77 | 78 | @override 79 | T transform(TransformPosition transform) => point.transform(transform) as T; 80 | 81 | @override 82 | R project( 83 | Projection projection, { 84 | required CreatePosition to, 85 | }) => 86 | point.project(projection, to: to); 87 | 88 | @override 89 | String toString() => point.toString(); 90 | 91 | @override 92 | bool operator ==(Object other) => point == other; 93 | 94 | @override 95 | int get hashCode => point.hashCode; 96 | 97 | @override 98 | bool equals2D(Position other, {num? toleranceHoriz}) => 99 | point.equals2D(other, toleranceHoriz: toleranceHoriz); 100 | 101 | @override 102 | bool equals3D( 103 | Position other, { 104 | num? toleranceHoriz, 105 | num? toleranceVert, 106 | }) => 107 | point.equals3D( 108 | other, 109 | toleranceHoriz: toleranceHoriz, 110 | toleranceVert: toleranceVert, 111 | ); 112 | } 113 | -------------------------------------------------------------------------------- /dart/geocore/lib/src/base/spatial/spatial.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2023 Navibyte (https://navibyte.com). All rights reserved. 2 | // Use of this source code is governed by a “BSD-3-Clause”-style license that is 3 | // specified in the LICENSE file. 4 | // 5 | // Docs: https://github.com/navibyte/geospatial 6 | 7 | import 'dart:collection'; 8 | 9 | import 'package:geobase/coordinates.dart'; 10 | import 'package:geobase/vector.dart'; 11 | import 'package:meta/meta.dart'; 12 | 13 | import '/src/utils/bounds.dart'; 14 | import '/src/utils/num.dart'; 15 | import '/src/utils/wkt.dart'; 16 | 17 | part 'batched.dart'; 18 | part 'bounded.dart'; 19 | part 'bounded_series.dart'; 20 | part 'bounds.dart'; 21 | part 'coords.dart'; 22 | part 'geometry.dart'; 23 | part 'point_series.dart'; 24 | part 'point_wrapper.dart'; 25 | part 'point.dart'; 26 | -------------------------------------------------------------------------------- /dart/geocore/lib/src/coordinates/geographic.dart: -------------------------------------------------------------------------------- 1 | export 'geographic/geobounds.dart'; 2 | export 'geographic/geopoint.dart'; 3 | export 'geographic/geopoint_immutable.dart'; 4 | export 'geographic/geopoint_wrapper.dart'; 5 | -------------------------------------------------------------------------------- /dart/geocore/lib/src/coordinates/geographic/geopoint.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2023 Navibyte (https://navibyte.com). All rights reserved. 2 | // Use of this source code is governed by a “BSD-3-Clause”-style license that is 3 | // specified in the LICENSE file. 4 | // 5 | // Docs: https://github.com/navibyte/geospatial 6 | 7 | import 'package:geobase/coordinates.dart'; 8 | 9 | import '/src/base/spatial.dart'; 10 | 11 | /// A geographic position with longitude, latitude and optional elevation. 12 | /// 13 | /// Longitude is available at [lon], latitude at [lat] and elevation at [elev]. 14 | /// 15 | /// Longitude (range `[-180.0, 180.0[`) and latitude (range `[-90.0, 90.0]`) are 16 | /// represented as deegrees. The unit for [elev] is meters. 17 | /// 18 | /// Extends [Point] class. Properties have equality (in context of this 19 | /// library): [lon] == [x], [lat] == [y], [elev] == [z] 20 | abstract class GeoPoint extends Point implements Geographic { 21 | /// Default `const` constructor to allow extending this abstract class. 22 | const GeoPoint(); 23 | 24 | @override 25 | double get elev => 0.0; 26 | 27 | @override 28 | double? get optElev => null; 29 | 30 | /// Distance (in meters) to another geographic point. 31 | double distanceTo(GeoPoint other); 32 | 33 | /// Copies this point with the compatible type and sets given coordinates. 34 | /// 35 | /// Optional [x], [y], [z] and [m] values, when given, override values of 36 | /// this point object. If the type of this point does not have a certain 37 | /// value, then it's ignored. 38 | /// 39 | /// Properties have equality (in context of this library): [lon] == [x], 40 | /// [lat] == [y], [elev] == [z] 41 | @override 42 | GeoPoint copyWith({num? x, num? y, num? z, num? m}); 43 | 44 | @override 45 | GeoPoint newWith({num x = 0.0, num y = 0.0, num? z, num? m}); 46 | 47 | @override 48 | GeoPoint newFrom(Iterable coords, {int? offset, int? length}); 49 | 50 | /// Returns a new point transformed from this point using [transform]. 51 | /// 52 | /// The transformed point object must be of the type with same coordinate 53 | /// value members as this object has. 54 | @override 55 | GeoPoint transform(TransformPosition transform); 56 | 57 | @override 58 | bool get isGeographic => true; 59 | 60 | @override 61 | bool operator ==(Object other) => 62 | other is GeoPoint && Position.testEquals(this, other); 63 | 64 | @override 65 | int get hashCode => Position.hash(this); 66 | } 67 | -------------------------------------------------------------------------------- /dart/geocore/lib/src/coordinates/geographic/geopoint_wrapper.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2023 Navibyte (https://navibyte.com). All rights reserved. 2 | // Use of this source code is governed by a “BSD-3-Clause”-style license that is 3 | // specified in the LICENSE file. 4 | // 5 | // Docs: https://github.com/navibyte/geospatial 6 | 7 | import '/src/base/spatial.dart'; 8 | 9 | import 'geopoint.dart'; 10 | 11 | /// A geographic position with wrapping a [GeoPoint] instance. 12 | /// 13 | /// This class is surely immutable, but the aggregated [point] object may 14 | /// or may not to be immutable. 15 | class GeoPointWrapper extends PointWrapper 16 | implements GeoPoint { 17 | /// Creates a geographic position by wrapping [point]. 18 | const GeoPointWrapper(super.point); 19 | 20 | @override 21 | double get lon => point.lon; 22 | 23 | @override 24 | double get lat => point.lat; 25 | 26 | @override 27 | double get elev => point.elev; 28 | 29 | @override 30 | double? get optElev => point.optElev; 31 | 32 | @override 33 | double distanceTo(GeoPoint other) => point.distanceTo(other); 34 | } 35 | -------------------------------------------------------------------------------- /dart/geocore/lib/src/coordinates/projected.dart: -------------------------------------------------------------------------------- 1 | export 'projected/point_immutable.dart'; 2 | export 'projected/projected_point.dart'; 3 | -------------------------------------------------------------------------------- /dart/geocore/lib/src/coordinates/projected/projected_point.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2023 Navibyte (https://navibyte.com). All rights reserved. 2 | // Use of this source code is governed by a “BSD-3-Clause”-style license that is 3 | // specified in the LICENSE file. 4 | // 5 | // Docs: https://github.com/navibyte/geospatial 6 | 7 | import 'package:geobase/coordinates.dart'; 8 | 9 | import '/src/base/spatial.dart'; 10 | 11 | /// A read-only projected (or cartesian) point with [x], [y], [z] and [m]. 12 | /// 13 | /// Coordinate values of type [C] are either `num` (allowing `double` or `int`), 14 | /// `double` or `int`. 15 | abstract class ProjectedPoint extends Point { 16 | /// Default `const` constructor to allow extending this abstract class. 17 | const ProjectedPoint(); 18 | 19 | @override 20 | ProjectedPoint copyWith({num? x, num? y, num? z, num? m}); 21 | 22 | @override 23 | ProjectedPoint newWith({num x = 0.0, num y = 0.0, num? z, num? m}); 24 | 25 | @override 26 | ProjectedPoint newFrom(Iterable coords, {int? offset, int? length}); 27 | 28 | @override 29 | ProjectedPoint transform(TransformPosition transform); 30 | 31 | @override 32 | bool get isGeographic => false; 33 | 34 | @override 35 | bool operator ==(Object other) => 36 | other is Point && 37 | isGeographic == other.isGeographic && 38 | Position.testEquals(this, other); 39 | 40 | @override 41 | int get hashCode => Position.hash(this); 42 | } 43 | -------------------------------------------------------------------------------- /dart/geocore/lib/src/coordinates/transforms.dart: -------------------------------------------------------------------------------- 1 | export 'transforms/basic.dart'; 2 | -------------------------------------------------------------------------------- /dart/geocore/lib/src/coordinates/transforms/basic.dart: -------------------------------------------------------------------------------- 1 | export 'basic/basic_transforms.dart'; 2 | -------------------------------------------------------------------------------- /dart/geocore/lib/src/data/feature.dart: -------------------------------------------------------------------------------- 1 | export 'feature/feature.dart'; 2 | export 'feature/feature_collection.dart'; 3 | export 'feature/feature_writable.dart'; 4 | -------------------------------------------------------------------------------- /dart/geocore/lib/src/data/feature/feature_writable.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2023 Navibyte (https://navibyte.com). All rights reserved. 2 | // Use of this source code is governed by a “BSD-3-Clause”-style license that is 3 | // specified in the LICENSE file. 4 | // 5 | // Docs: https://github.com/navibyte/geospatial 6 | 7 | import 'package:geobase/vector.dart'; 8 | 9 | /// An interface defining the capability to write feature objects. 10 | abstract class FeatureWritable { 11 | /// Default `const` constructor to allow extending this abstract class. 12 | const FeatureWritable(); 13 | 14 | /// Writes this feature object to [writer]. 15 | void writeTo(FeatureContent writer); 16 | 17 | /// A string representation of this object, with an optional [format] applied. 18 | /// 19 | /// When [format] is not given, then [GeoJSON] is used. 20 | /// 21 | /// Use [decimals] to set a number of decimals (not applied if no decimals). 22 | String toStringAs({ 23 | TextWriterFormat format = GeoJSON.feature, 24 | int? decimals, 25 | }) { 26 | final encoder = format.encoder(decimals: decimals); 27 | writeTo(encoder.writer); 28 | return encoder.toText(); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /dart/geocore/lib/src/data/simple_geometry.dart: -------------------------------------------------------------------------------- 1 | export 'simple_geometry/linestring.dart'; 2 | export 'simple_geometry/multi.dart'; 3 | export 'simple_geometry/polygon.dart'; 4 | -------------------------------------------------------------------------------- /dart/geocore/lib/src/parse/factory.dart: -------------------------------------------------------------------------------- 1 | export 'factory/factory.dart'; 2 | export 'factory/point.dart'; 3 | export 'factory/range.dart'; 4 | -------------------------------------------------------------------------------- /dart/geocore/lib/src/parse/factory/range.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2023 Navibyte (https://navibyte.com). All rights reserved. 2 | // Use of this source code is governed by a “BSD-3-Clause”-style license that is 3 | // specified in the LICENSE file. 4 | // 5 | // Docs: https://github.com/navibyte/geospatial 6 | 7 | import 'package:equatable/equatable.dart'; 8 | 9 | import 'package:meta/meta.dart'; 10 | 11 | // NOTE: range with spatial operations? 12 | 13 | /// A range defining a set of items on a collection. 14 | @immutable 15 | class Range with EquatableMixin { 16 | /// A new range definition with [start] (>= 0) and optional positive [limit]. 17 | const Range({required this.start, this.limit}) 18 | : assert(start >= 0, 'Start index must be >= 0.'), 19 | assert(limit == null || limit >= 0, 'Limit must be null or >= 0.'); 20 | 21 | /// The index to specify the first item (by index) of the range. 22 | final int start; 23 | 24 | /// An optional [limit] setting maximum number of items for the range. 25 | /// 26 | /// If null, then the range contains all items starting from [start]. 27 | final int? limit; 28 | 29 | @override 30 | List get props => [start, limit]; 31 | } 32 | -------------------------------------------------------------------------------- /dart/geocore/lib/src/parse/geojson.dart: -------------------------------------------------------------------------------- 1 | export 'geojson/geojson.dart'; 2 | -------------------------------------------------------------------------------- /dart/geocore/lib/src/parse/wkt.dart: -------------------------------------------------------------------------------- 1 | export 'wkt/wkt_factory.dart'; 2 | -------------------------------------------------------------------------------- /dart/geocore/lib/src/utils/bounds.dart: -------------------------------------------------------------------------------- 1 | export 'bounds/bounds_builder.dart'; 2 | -------------------------------------------------------------------------------- /dart/geocore/lib/src/utils/distance_haversine.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2022 Navibyte (https://navibyte.com). All rights reserved. 2 | // Use of this source code is governed by a “BSD-3-Clause”-style license that is 3 | // specified in the LICENSE file. 4 | // 5 | // Docs: https://github.com/navibyte/geospatial 6 | 7 | // NOTE: Copied from geobase (/src/geodesy/spherical/distance_haversine.dart). 8 | // Now as a "temporary" copy also in geocore utils. 9 | 10 | import 'dart:math'; 11 | 12 | import '/src/coordinates/geographic.dart'; 13 | 14 | /// Returns a distance in meters between [position1] and [position2]. 15 | /// 16 | /// Given [earthRadius] is used for calculation with the approximate mean radius 17 | /// as a default. 18 | double distanceHaversine( 19 | GeoPoint position1, 20 | GeoPoint position2, { 21 | double earthRadius = 6371000.0, 22 | }) { 23 | // https://en.wikipedia.org/wiki/Haversine_formula 24 | 25 | // coordinates 26 | final lon1 = position1.lon; 27 | final lat1 = position1.lat; 28 | final lon2 = position2.lon; 29 | final lat2 = position2.lat; 30 | 31 | const toRad = pi / 180.0; 32 | 33 | final lat1Rad = lat1 * toRad; 34 | final lat2Rad = lat2 * toRad; 35 | final dlat = (lat2 - lat1) * toRad; 36 | final dlon = (lon2 - lon1) * toRad; 37 | final a = sin(dlat / 2) * sin(dlat / 2) + 38 | cos(lat1Rad) * cos(lat2Rad) * sin(dlon / 2) * sin(dlon / 2); 39 | final c = 2 * atan2(sqrt(a), sqrt(1 - a)); 40 | 41 | return earthRadius * c; 42 | } 43 | -------------------------------------------------------------------------------- /dart/geocore/lib/src/utils/num.dart: -------------------------------------------------------------------------------- 1 | export 'num/num_utils.dart'; 2 | -------------------------------------------------------------------------------- /dart/geocore/lib/src/utils/num/num_utils.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2023 Navibyte (https://navibyte.com). All rights reserved. 2 | // Use of this source code is governed by a “BSD-3-Clause”-style license that is 3 | // specified in the LICENSE file. 4 | // 5 | // Docs: https://github.com/navibyte/geospatial 6 | 7 | import 'package:meta/meta.dart'; 8 | 9 | final _splitByWhitespace = RegExp(r'\s+'); 10 | 11 | /// Uses `String.toStringAsFixed()` when [n] contains decimals. 12 | /// 13 | /// For example returns '15' if a double value is 15.00, and '15.50' if a double 14 | /// value is 15.50. 15 | /// 16 | /// See: https://stackoverflow.com/questions/39958472/dart-numberformat 17 | @internal 18 | String toStringAsFixedWhenDecimals(num n, int fractionDigits) => 19 | n.toStringAsFixed(n.truncateToDouble() == n ? 0 : fractionDigits); 20 | 21 | /// Returns a lazy iterable parsing values from [text] separated by [delimiter]. 22 | /// 23 | /// If [delimiter] is not provided, values are separated by whitespace. 24 | /// 25 | /// Throws `FormatException` if cannot parse. Lazy iteration may also throw. 26 | /// 27 | /// If [text] contains less than [minCount] value items, then `FormatException`` 28 | /// is also thrown. 29 | @internal 30 | Iterable parseNumValuesFromText( 31 | String text, { 32 | Pattern? delimiter, 33 | int minCount = 2, 34 | }) { 35 | // check argumemts 36 | if (delimiter == '') throw const FormatException('Invalid delimiter'); 37 | // split by delimiter and checks that there are enough items 38 | final parts = text.trim().split(delimiter ?? _splitByWhitespace); 39 | if (parts.length < minCount) { 40 | throw const FormatException('Too few value items'); 41 | } 42 | // returns lazy iterable for num values, iteration steps may throw 43 | // FormatException (by double.parse). 44 | return parts.map((value) => double.parse(value.trim())); 45 | } 46 | 47 | /// Returns a lazy iterable parsing values from [text] separated by [delimiter]. 48 | /// 49 | /// If [delimiter] is not provided, values are separated by whitespace. 50 | /// 51 | /// Throws `FormatException` if cannot parse. Lazy iteration may also throw. 52 | /// 53 | /// If [text] contains less than [minCount] value items, then `FormatException`` 54 | /// is also thrown. 55 | @internal 56 | Iterable parseIntValuesFromText( 57 | String text, { 58 | Pattern? delimiter, 59 | int minCount = 2, 60 | }) { 61 | // check argumemts 62 | if (delimiter == '') throw const FormatException('Invalid delimiter'); 63 | // split by delimiter and checks that there are enough items 64 | final parts = text.trim().split(delimiter ?? _splitByWhitespace); 65 | if (parts.length < minCount) { 66 | throw const FormatException('Too few value items'); 67 | } 68 | // returns lazy iterable for int values, iteration steps may throw 69 | // FormatException (by double.parse). 70 | return parts.map((value) { 71 | value = value.trim(); 72 | return int.tryParse(value) ?? double.parse(value).round(); 73 | }); 74 | } 75 | -------------------------------------------------------------------------------- /dart/geocore/lib/src/utils/wkt.dart: -------------------------------------------------------------------------------- 1 | export 'wkt/wkt_utils.dart'; 2 | -------------------------------------------------------------------------------- /dart/geocore/lib/src/utils/wkt/wkt_utils.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2023 Navibyte (https://navibyte.com). All rights reserved. 2 | // Use of this source code is governed by a “BSD-3-Clause”-style license that is 3 | // specified in the LICENSE file. 4 | // 5 | // Docs: https://github.com/navibyte/geospatial 6 | 7 | import 'package:meta/meta.dart'; 8 | 9 | import '/src/base/spatial.dart'; 10 | 11 | final _splitByWhitespace = RegExp(r'\s+'); 12 | 13 | /// Create an exception telling [coords] text is invalid. 14 | FormatException _invalidCoords(String coords) => 15 | FormatException('Invalid coords: $coords'); 16 | 17 | /// Parses a num iterable from [coords] with values separated by white space. 18 | @internal 19 | Iterable parseWktCoords(String coords) { 20 | final parts = _omitParenthesis(coords.trim()).split(_splitByWhitespace); 21 | // NOTE: need to know expected coord dim 22 | if (parts.length < 2) { 23 | throw _invalidCoords(coords); 24 | } 25 | return parts.map(double.parse); 26 | } 27 | /* 28 | todo : consider behaviour? 29 | 30 | Iterable parseWktCoords(String coords) => _omitParenthesis(coords.trim()) 31 | .split(_splitByWhitespace) 32 | .map((value) => int.tryParse(value) ?? double.parse(value)); 33 | */ 34 | 35 | /// Parses an int iterable from [coords] with values separated by white space. 36 | /// 37 | /// Throws FormatException if parsing fails. 38 | @internal 39 | Iterable parseWktCoordsInt(String coords) { 40 | final parts = _omitParenthesis(coords.trim()).split(_splitByWhitespace); 41 | if (parts.length < 2) { 42 | throw _invalidCoords(coords); 43 | } 44 | return parts 45 | .map((value) => int.tryParse(value) ?? double.parse(value).round()); 46 | } 47 | 48 | /// Parses a point of [T] with num coords from [point] using the [pointFactory]. 49 | /// 50 | /// Throws FormatException if parsing fails. 51 | @internal 52 | T parseWktPoint(String point, PointFactory pointFactory) => 53 | pointFactory.newFrom(parseWktCoords(point)); 54 | 55 | /// Parses a point of [T] with int coords from [point] using the [pointFactory]. 56 | /// 57 | /// Throws FormatException if parsing fails. 58 | @internal 59 | T parseWktPointInt( 60 | String point, 61 | PointFactory pointFactory, 62 | ) => 63 | pointFactory.newFrom(parseWktCoordsInt(point)); 64 | 65 | /// Parses a series of points of [T] from [pointSeries]. 66 | /// 67 | /// Points are separated by `,` chars. Each point is parsed using the 68 | /// [pointFactory]. 69 | /// 70 | /// Throws FormatException if parsing fails. 71 | @internal 72 | PointSeries parseWktPointSeries( 73 | String pointSeries, 74 | PointFactory pointFactory, 75 | ) => 76 | PointSeries.from( 77 | pointSeries 78 | .split(',') 79 | .map((point) => pointFactory.newFrom(parseWktCoords(point))), 80 | ); 81 | 82 | String _omitParenthesis(String str) => str.startsWith('(') && str.endsWith(')') 83 | ? str.substring(1, str.length - 1) 84 | : str; 85 | -------------------------------------------------------------------------------- /dart/geocore/lib/src/utils/wkt_data.dart: -------------------------------------------------------------------------------- 1 | export 'wkt_data/wkt_simple_geometry.dart'; 2 | -------------------------------------------------------------------------------- /dart/geocore/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: geocore 2 | description: Geospatial data structures (points, geometry, features, meta) and parsers (GeoJSON, WKT) for Dart. 3 | version: 0.10.2 4 | repository: https://github.com/navibyte/geospatial 5 | homepage: https://github.com/navibyte/geospatial/tree/main/dart/geocore 6 | 7 | environment: 8 | sdk: '>=2.17.0 <4.0.0' 9 | 10 | dependencies: 11 | equatable: ^2.0.0 12 | meta: ^1.7.0 13 | 14 | geobase: ^0.3.0 15 | #geobase: 16 | # path: ../geobase 17 | 18 | dev_dependencies: 19 | test: ^1.24.0 20 | very_good_analysis: ^6.0.0 -------------------------------------------------------------------------------- /dart/geocore/test/coordinates/cartesian_test.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2022 Navibyte (https://navibyte.com). All rights reserved. 2 | // Use of this source code is governed by a “BSD-3-Clause”-style license that is 3 | // specified in the LICENSE file. 4 | // 5 | // Docs: https://github.com/navibyte/geospatial 6 | 7 | // ignore_for_file: lines_longer_than_80_chars, prefer_const_declarations 8 | 9 | import 'package:geocore/coordinates.dart'; 10 | 11 | import 'package:test/test.dart'; 12 | 13 | void main() { 14 | group('CartesianPoint classes', () { 15 | test('Equals and hashCode', () { 16 | final one = 1.0; 17 | final two = 2.0; 18 | const p1 = Point3m(x: 1.0, y: 2.0, z: 3.0, m: 4.0); 19 | final p2 = Point3m(x: one, y: 2.0, z: 3.0, m: 4.0); 20 | final p3 = Point3m(x: two, y: 2.0, z: 3.0, m: 4.0); 21 | expect(p1, p2); 22 | expect(p1, isNot(p3)); 23 | expect(p1.hashCode, p2.hashCode); 24 | expect(p1.hashCode, isNot(p3.hashCode)); 25 | 26 | final p5 = const Point3(x: 1.0, y: 2.0, z: 3.0); 27 | final p6 = const GeoPoint3(lon: 1.0, lat: 2.0, elev: 3.0); 28 | expect(p1, isNot(p5)); 29 | expect(p1, isNot(p6)); 30 | expect(p5, isNot(p6)); 31 | }); 32 | }); 33 | } 34 | -------------------------------------------------------------------------------- /dart/geocore/test/coordinates/geographic_test.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2022 Navibyte (https://navibyte.com). All rights reserved. 2 | // Use of this source code is governed by a “BSD-3-Clause”-style license that is 3 | // specified in the LICENSE file. 4 | // 5 | // Docs: https://github.com/navibyte/geospatial 6 | 7 | // ignore_for_file: lines_longer_than_80_chars, prefer_const_declarations 8 | 9 | import 'package:geocore/coordinates.dart'; 10 | 11 | import 'package:test/test.dart'; 12 | 13 | void main() { 14 | group('GeoPoint classes', () { 15 | test('Equals and hashCode', () { 16 | final one = 1.0; 17 | final two = 2.0; 18 | const p1 = GeoPoint3m(lon: 1.0, lat: 2.0, elev: 3.0, m: 4.0); 19 | final p2 = GeoPoint3m(lon: one, lat: 2.0, elev: 3.0, m: 4.0); 20 | final p3 = GeoPoint3m(lon: two, lat: 2.0, elev: 3.0, m: 4.0); 21 | expect(p1, p2); 22 | expect(p1, isNot(p3)); 23 | expect(p1.hashCode, p2.hashCode); 24 | expect(p1.hashCode, isNot(p3.hashCode)); 25 | }); 26 | 27 | test('Clamping longitude and latitude in constructor', () { 28 | expect(const GeoPoint3m(lon: 34.0, lat: 18.2).lon, 34.0); 29 | expect(const GeoPoint3m(lon: -326.0, lat: 18.2).lon, 34.0); 30 | expect(const GeoPoint3m(lon: 394.0, lat: 18.2).lon, 34.0); 31 | expect(const GeoPoint3m(lon: -180.0, lat: 18.2).lon, -180.0); 32 | expect(const GeoPoint3m(lon: -181.0, lat: 18.2).lon, 179.0); 33 | expect(const GeoPoint3m(lon: -541.0, lat: 18.2).lon, 179.0); 34 | expect(const GeoPoint3m(lon: 180.0, lat: 18.2).lon, -180.0); 35 | expect(const GeoPoint3m(lon: 181.0, lat: 18.2).lon, -179.0); 36 | expect(const GeoPoint3m(lon: 541.0, lat: 18.2).lon, -179.0); 37 | expect(const GeoPoint3m(lon: 34.2, lat: -90.0).lat, -90.0); 38 | expect(const GeoPoint3m(lon: 34.2, lat: -91.0).lat, -90.0); 39 | expect(const GeoPoint3m(lon: 34.2, lat: 90.0).lat, 90.0); 40 | expect(const GeoPoint3m(lon: 34.2, lat: 91.0).lat, 90.0); 41 | }); 42 | }); 43 | } 44 | -------------------------------------------------------------------------------- /dart/geodata/.gitignore: -------------------------------------------------------------------------------- 1 | # Files and directories created by pub 2 | .dart_tool/ 3 | .packages 4 | # Remove the following pattern if you wish to check in your lock file 5 | pubspec.lock 6 | 7 | # Conventional directory for build outputs 8 | build/ 9 | 10 | # Directory created by dartdoc 11 | doc/api/ 12 | -------------------------------------------------------------------------------- /dart/geodata/LICENSE: -------------------------------------------------------------------------------- 1 | The 3-Clause BSD License 2 | 3 | Copyright (c) 2020-2025 Navibyte. All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without modification, 6 | are permitted provided that the following conditions are met: 7 | 8 | 1. Redistributions of source code must retain the above copyright notice, this 9 | list of conditions and the following disclaimer. 10 | 11 | 2. Redistributions in binary form must reproduce the above copyright notice, 12 | this list of conditions and the following disclaimer in the documentation and/or 13 | other materials provided with the distribution. 14 | 15 | 3. Neither the name of the copyright holder nor the names of its contributors 16 | may be used to endorse or promote products derived from this software without 17 | specific prior written permission. 18 | 19 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 20 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 21 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 22 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 23 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 24 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 25 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 26 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 28 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- /dart/geodata/assets/diagrams/decision_flowchart.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/navibyte/geospatial/c4e06ef8af7c0808e6c52f529e7d249b732476db/dart/geodata/assets/diagrams/decision_flowchart.png -------------------------------------------------------------------------------- /dart/geodata/assets/diagrams/feature_data_interfaces.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/navibyte/geospatial/c4e06ef8af7c0808e6c52f529e7d249b732476db/dart/geodata/assets/diagrams/feature_data_interfaces.png -------------------------------------------------------------------------------- /dart/geodata/example/geojson_example.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2024 Navibyte (https://navibyte.com). All rights reserved. 2 | // Use of this source code is governed by a “BSD-3-Clause”-style license that is 3 | // specified in the LICENSE file. 4 | // 5 | // Docs: https://github.com/navibyte/geospatial 6 | 7 | // ignore_for_file: avoid_print 8 | 9 | /* 10 | To test run this from command line: dart example/geojson_example.dart 11 | */ 12 | 13 | // importing `dart:io` not supported on the Flutter web platform 14 | import 'dart:io' show File; 15 | 16 | import 'package:geodata/geojson_client.dart'; 17 | 18 | import 'package:http/http.dart' as http; 19 | import 'package:http/retry.dart'; 20 | 21 | Future main(List args) async { 22 | // read GeoJSON for earthquakes from web using HTTP(S) 23 | print('GeoJSON features from HTTP'); 24 | await _readFeatures( 25 | GeoJSONFeatures.http( 26 | // API address 27 | location: Uri.parse( 28 | 'https://earthquake.usgs.gov/earthquakes/feed/v1.0/summary/' 29 | '2.5_day.geojson', 30 | ), 31 | ), 32 | ); 33 | 34 | // same thing but using the standard HTTP retry client on API calls 35 | final httpClient = RetryClient(http.Client(), retries: 4); 36 | try { 37 | await _readFeatures( 38 | GeoJSONFeatures.http( 39 | // set HTTP client (if not set the default `http.Client()` is used) 40 | client: httpClient, 41 | 42 | // API address 43 | location: Uri.parse( 44 | 'https://earthquake.usgs.gov/earthquakes/feed/v1.0/summary/' 45 | '2.5_day.geojson', 46 | ), 47 | ), 48 | ); 49 | } finally { 50 | httpClient.close(); 51 | } 52 | 53 | // same thing but reading a local file 54 | print(''); 55 | print('GeoJSON features from file'); 56 | await _readFeatures( 57 | GeoJSONFeatures.any( 58 | () async => File('test/usgs/summary/2.5_day.geojson').readAsString(), 59 | ), 60 | ); 61 | } 62 | 63 | Future _readFeatures(BasicFeatureSource source) async { 64 | // read features with error handling 65 | try { 66 | // get items or features from a source, maximum 5 features returned 67 | final items = await source.itemsAll(limit: 5); 68 | 69 | // do something with actual data (features), in this sample just print them 70 | for (final f in items.collection.features) { 71 | print('Feature with id: ${f.id}'); 72 | print(' geometry: ${f.geometry}'); 73 | print(' properties:'); 74 | for (final key in f.properties.keys) { 75 | print(' $key: ${f.properties[key]}'); 76 | } 77 | } 78 | } on ServiceException catch (e) { 79 | print('Reading GeoJSON resource failed: ${e.failure.name}'); 80 | print('Cause: ${e.cause}'); 81 | } catch (e) { 82 | print('Reading GeoJSON resource failed: $e'); 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /dart/geodata/lib/common.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2023 Navibyte (https://navibyte.com). All rights reserved. 2 | // Use of this source code is governed by a “BSD-3-Clause”-style license that is 3 | // specified in the LICENSE file. 4 | // 5 | // Docs: https://github.com/navibyte/geospatial 6 | 7 | /// Common data structures and helpers (for links, metadata, paged responses). 8 | /// 9 | /// Usage: import `package:geodata/common.dart` 10 | library common; 11 | 12 | export 'src/common/links/link.dart'; 13 | export 'src/common/links/links.dart'; 14 | export 'src/common/links/links_aware.dart'; 15 | export 'src/common/meta/meta_aware.dart'; 16 | export 'src/common/paged/paged.dart'; 17 | export 'src/common/service/service_exception.dart'; 18 | -------------------------------------------------------------------------------- /dart/geodata/lib/core.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2023 Navibyte (https://navibyte.com). All rights reserved. 2 | // Use of this source code is governed by a “BSD-3-Clause”-style license that is 3 | // specified in the LICENSE file. 4 | // 5 | // Docs: https://github.com/navibyte/geospatial 6 | 7 | /// Metadata and data source abstractions of geospatial Web APIs (ie. features). 8 | /// 9 | /// Usage: import `package:geodata/core.dart` 10 | library core; 11 | 12 | export 'src/core/base/collection_meta.dart'; 13 | export 'src/core/base/resource_meta.dart'; 14 | export 'src/core/data/bounded_items_query.dart'; 15 | export 'src/core/data/geospatial_query.dart'; 16 | export 'src/core/data/item_query.dart'; 17 | export 'src/core/data/items_query.dart'; 18 | export 'src/core/features/basic_feature_source.dart'; 19 | export 'src/core/features/feature_failure.dart'; 20 | export 'src/core/features/feature_item.dart'; 21 | export 'src/core/features/feature_items.dart'; 22 | export 'src/core/features/feature_source.dart'; 23 | -------------------------------------------------------------------------------- /dart/geodata/lib/formats.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2023 Navibyte (https://navibyte.com). All rights reserved. 2 | // Use of this source code is governed by a “BSD-3-Clause”-style license that is 3 | // specified in the LICENSE file. 4 | // 5 | // Docs: https://github.com/navibyte/geospatial 6 | 7 | /// OpenAPI document and Common Query Language (CQL2) formats (partial support). 8 | /// 9 | /// Usage: import `package:geodata/formats.dart` 10 | library formats; 11 | 12 | export 'src/formats/cql2/cql_query.dart'; 13 | export 'src/formats/openapi/open_api_document.dart'; 14 | -------------------------------------------------------------------------------- /dart/geodata/lib/geodata.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2023 Navibyte (https://navibyte.com). All rights reserved. 2 | // Use of this source code is governed by a “BSD-3-Clause”-style license that is 3 | // specified in the LICENSE file. 4 | // 5 | // Docs: https://github.com/navibyte/geospatial 6 | 7 | /// A geospatial client to read GeoJSON and OGC API Features data sources. 8 | /// 9 | /// Usage: import `package:geodata/geodata.dart` 10 | library geodata; 11 | 12 | // Export mini-libraries forming the whole "geodata" library. 13 | export 'common.dart'; 14 | export 'core.dart'; 15 | export 'formats.dart'; 16 | export 'geojson_client.dart'; 17 | export 'ogcapi_features_client.dart'; 18 | -------------------------------------------------------------------------------- /dart/geodata/lib/geojson_client.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2023 Navibyte (https://navibyte.com). All rights reserved. 2 | // Use of this source code is governed by a “BSD-3-Clause”-style license that is 3 | // specified in the LICENSE file. 4 | // 5 | // Docs: https://github.com/navibyte/geospatial 6 | 7 | /// A client-side data source to read GeoJSON data from web and file resources. 8 | /// 9 | /// This library exports also all classes of `package:geodata/common.dart` and 10 | /// `package:geodata/core.dart`. 11 | /// 12 | /// Usage: import `package:geodata/geojson_client.dart` 13 | library geojson_client; 14 | 15 | export 'common.dart'; 16 | export 'core.dart'; 17 | 18 | export 'src/geojson/service/client/geojson_feature_client.dart'; 19 | -------------------------------------------------------------------------------- /dart/geodata/lib/ogcapi_features_client.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2023 Navibyte (https://navibyte.com). All rights reserved. 2 | // Use of this source code is governed by a “BSD-3-Clause”-style license that is 3 | // specified in the LICENSE file. 4 | // 5 | // Docs: https://github.com/navibyte/geospatial 6 | 7 | /// A client-side data source to read features from OGC API Features services. 8 | /// 9 | /// This library exports also all classes of `package:geodata/common.dart`, 10 | /// `package:geodata/core.dart` and `package:geodata/formats.dart`. 11 | /// 12 | /// Usage: import `package:geodata/ogcapi_features_client.dart` 13 | library ogcapi_features_client; 14 | 15 | export 'common.dart'; 16 | export 'core.dart'; 17 | export 'formats.dart'; 18 | 19 | export 'src/ogcapi_common/model/ogc_collection_meta.dart'; 20 | export 'src/ogcapi_common/model/ogc_conformance.dart'; 21 | export 'src/ogcapi_common/model/ogc_queryable_object.dart'; 22 | export 'src/ogcapi_common/model/ogc_service.dart'; 23 | export 'src/ogcapi_common/model/ogc_service_meta.dart'; 24 | export 'src/ogcapi_features/model/ogc_feature_conformance.dart'; 25 | export 'src/ogcapi_features/model/ogc_feature_item.dart'; 26 | export 'src/ogcapi_features/model/ogc_feature_items.dart'; 27 | export 'src/ogcapi_features/model/ogc_feature_service.dart'; 28 | export 'src/ogcapi_features/model/ogc_feature_source.dart'; 29 | export 'src/ogcapi_features/service/client/ogc_feature_client.dart'; 30 | -------------------------------------------------------------------------------- /dart/geodata/lib/src/common/links/links_aware.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2023 Navibyte (https://navibyte.com). All rights reserved. 2 | // Use of this source code is governed by a “BSD-3-Clause”-style license that is 3 | // specified in the LICENSE file. 4 | // 5 | // Docs: https://github.com/navibyte/geospatial 6 | 7 | import 'links.dart'; 8 | 9 | /// A mixin aware of links. 10 | mixin LinksAware { 11 | /// Links related to this object. 12 | Links get links => const Links.empty(); 13 | } 14 | -------------------------------------------------------------------------------- /dart/geodata/lib/src/common/meta/meta_aware.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2023 Navibyte (https://navibyte.com). All rights reserved. 2 | // Use of this source code is governed by a “BSD-3-Clause”-style license that is 3 | // specified in the LICENSE file. 4 | // 5 | // Docs: https://github.com/navibyte/geospatial 6 | 7 | /// A mixin aware of metadata for something. 8 | mixin MetaAware { 9 | /// Metadata as a data object (ie. data from a JSON Object). 10 | Map get meta => const {}; 11 | } 12 | -------------------------------------------------------------------------------- /dart/geodata/lib/src/common/paged/paged.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2023 Navibyte (https://navibyte.com). All rights reserved. 2 | // Use of this source code is governed by a “BSD-3-Clause”-style license that is 3 | // specified in the LICENSE file. 4 | // 5 | // Docs: https://github.com/navibyte/geospatial 6 | 7 | /// A mixin to handle sets of some items as paged responses. 8 | mixin Paged { 9 | /// The current set of items. 10 | T get current; 11 | 12 | /// True if there exists a [next] set of items on a resource. 13 | bool get hasNext; 14 | 15 | /// Get a next set of items from a resource asynchronously. 16 | /// 17 | /// Returns null if a next set of items isn't available. 18 | Future?> next(); 19 | 20 | /// True if there exists a [previous] set of items on a resource. 21 | bool get hasPrevious => false; 22 | 23 | /// Get a previous set of items from a resource asynchronously. 24 | /// 25 | /// Returns null if a previous set of items isn't available. 26 | // ignore: avoid_redundant_argument_values 27 | Future?> previous() => Future.value(null); 28 | } 29 | -------------------------------------------------------------------------------- /dart/geodata/lib/src/common/service/service_exception.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2024 Navibyte (https://navibyte.com). All rights reserved. 2 | // Use of this source code is governed by a “BSD-3-Clause”-style license that is 3 | // specified in the LICENSE file. 4 | // 5 | // Docs: https://github.com/navibyte/geospatial 6 | 7 | import 'package:meta/meta.dart'; 8 | 9 | /// An exception that may occur when accessing app business logic or a service. 10 | /// 11 | /// The required [failure] property provides an app specific failure of the type 12 | /// [T]. 13 | /// 14 | /// An optional source for the exception is provided by [cause] and [trace]. 15 | @immutable 16 | class ServiceException implements Exception { 17 | /// Create an exception with [failure], and optional [cause] and [trace]. 18 | const ServiceException(this.failure, {this.cause, this.trace}); 19 | 20 | /// The app specific failure as an object of [T]. 21 | final T failure; 22 | 23 | /// An optional source that caused the exception. 24 | /// 25 | /// This could be for example another exception, an error instance or a String 26 | /// object. 27 | final Object? cause; 28 | 29 | /// An optional stack trace that is accociated with an optional [cause]. 30 | final StackTrace? trace; 31 | 32 | @override 33 | String toString() => '$failure${cause != null ? " ($cause)" : ""}'; 34 | 35 | @override 36 | bool operator ==(Object other) => 37 | identical(this, other) || 38 | (other is ServiceException && 39 | failure == other.failure && 40 | cause == other.cause && 41 | trace == other.trace); 42 | 43 | @override 44 | int get hashCode => Object.hash(failure, cause, trace); 45 | } 46 | -------------------------------------------------------------------------------- /dart/geodata/lib/src/core/base/collection_meta.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2024 Navibyte (https://navibyte.com). All rights reserved. 2 | // Use of this source code is governed by a “BSD-3-Clause”-style license that is 3 | // specified in the LICENSE file. 4 | // 5 | // Docs: https://github.com/navibyte/geospatial 6 | 7 | import 'package:geobase/meta.dart'; 8 | 9 | import 'resource_meta.dart'; 10 | 11 | /// Metadata for a collection resource. 12 | /// 13 | /// The [id] of the collection can be used as a path segment in URLs. 14 | class CollectionMeta extends ResourceMeta { 15 | /// Create a metadata instance for a collection resource. 16 | const CollectionMeta({ 17 | required this.id, 18 | required super.title, 19 | super.description, 20 | super.attribution, 21 | required super.links, 22 | this.extent, 23 | }); 24 | 25 | /// The required [id] of the collection. 26 | /// 27 | /// In some APIs this [id] could be used as a path segment on URL references. 28 | final String id; 29 | 30 | /// An optional geospatial [extent] for this collection. 31 | final GeoExtent? extent; 32 | 33 | @override 34 | String toString() { 35 | return '$id;$title;$description;$attribution;$links;$extent'; 36 | } 37 | 38 | @override 39 | bool operator ==(Object other) => 40 | identical(this, other) || 41 | (other is CollectionMeta && 42 | id == other.id && 43 | title == other.title && 44 | description == other.description && 45 | attribution == other.attribution && 46 | links == other.links && 47 | extent == other.extent); 48 | 49 | @override 50 | int get hashCode => 51 | Object.hash(id, title, description, attribution, links, extent); 52 | } 53 | -------------------------------------------------------------------------------- /dart/geodata/lib/src/core/base/resource_meta.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2024 Navibyte (https://navibyte.com). All rights reserved. 2 | // Use of this source code is governed by a “BSD-3-Clause”-style license that is 3 | // specified in the LICENSE file. 4 | // 5 | // Docs: https://github.com/navibyte/geospatial 6 | 7 | import 'package:meta/meta.dart'; 8 | 9 | import '/src/common/links/links.dart'; 10 | import '/src/common/links/links_aware.dart'; 11 | 12 | /// Basic metadata about some resource. 13 | @immutable 14 | class ResourceMeta with LinksAware { 15 | /// A new resource metadata instance with [title], [description], 16 | /// [attribution] and [links]. 17 | const ResourceMeta({ 18 | required this.title, 19 | this.description, 20 | this.attribution, 21 | required this.links, 22 | }); 23 | 24 | /// The required title for a resource. 25 | final String title; 26 | 27 | /// An optional description for a resource. 28 | final String? description; 29 | 30 | /// An optional attribution about a resource, intended for presentation to an 31 | /// user. 32 | final String? attribution; 33 | 34 | @override 35 | final Links links; 36 | 37 | @override 38 | String toString() { 39 | return '$title;$description;$attribution;$links'; 40 | } 41 | 42 | @override 43 | bool operator ==(Object other) => 44 | identical(this, other) || 45 | (other is ResourceMeta && 46 | title == other.title && 47 | description == other.description && 48 | attribution == other.attribution && 49 | links == other.links); 50 | 51 | @override 52 | int get hashCode => Object.hash(title, description, attribution, links); 53 | } 54 | -------------------------------------------------------------------------------- /dart/geodata/lib/src/core/data/bounded_items_query.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2025 Navibyte (https://navibyte.com). All rights reserved. 2 | // Use of this source code is governed by a “BSD-3-Clause”-style license that is 3 | // specified in the LICENSE file. 4 | // 5 | // Docs: https://github.com/navibyte/geospatial 6 | 7 | import 'package:geobase/coordinates.dart'; 8 | import 'package:geobase/meta.dart'; 9 | 10 | import '/src/utils/object_utils.dart'; 11 | 12 | import 'items_query.dart'; 13 | 14 | /// A query with bounds for requesting items from a geospatial data source. 15 | class BoundedItemsQuery extends ItemsQuery { 16 | /// A query with bounds for requesting items from a geospatial data source. 17 | const BoundedItemsQuery({ 18 | super.crs, 19 | this.bboxCrs, 20 | this.bbox, 21 | this.timeFrame, 22 | super.limit, 23 | super.parameters, 24 | }); 25 | 26 | /// A new query with query parameters copied from an optional [query]. 27 | /// 28 | /// Supports reading [query] parameters from [ItemsQuery] and 29 | /// [BoundedItemsQuery]. 30 | /// 31 | /// If [query] is null, then returns an instance with all parameters set null. 32 | factory BoundedItemsQuery.fromOpt(ItemsQuery? query) => 33 | query is BoundedItemsQuery 34 | ? BoundedItemsQuery( 35 | crs: query.crs, 36 | bboxCrs: query.bboxCrs, 37 | bbox: query.bbox, 38 | timeFrame: query.timeFrame, 39 | limit: query.limit, 40 | parameters: query.parameters, 41 | ) 42 | : BoundedItemsQuery( 43 | crs: query?.crs, 44 | limit: query?.limit, 45 | parameters: query?.parameters, 46 | ); 47 | 48 | /// An optional coordinate reference system used by [bbox]. 49 | final CoordRefSys? bboxCrs; 50 | 51 | /// An optional [bbox] as a geospatial bounding filter (like `bbox`). 52 | final Box? bbox; 53 | 54 | /// An optional time frame as a temporal object (ie. instant or interval). 55 | final Temporal? timeFrame; 56 | 57 | @override 58 | String toString() { 59 | return '$crs;$bboxCrs;$bbox;$timeFrame;$limit;$mapToString(parameters)'; 60 | } 61 | 62 | @override 63 | bool operator ==(Object other) => 64 | identical(this, other) || 65 | (other is BoundedItemsQuery && 66 | crs == other.crs && 67 | bboxCrs == other.bboxCrs && 68 | bbox == other.bbox && 69 | timeFrame == other.timeFrame && 70 | limit == other.limit && 71 | testMapEquality(parameters, other.parameters)); 72 | 73 | @override 74 | int get hashCode => Object.hash( 75 | crs, 76 | bboxCrs, 77 | bbox, 78 | timeFrame, 79 | limit, 80 | mapHashCode(parameters), 81 | ); 82 | } 83 | -------------------------------------------------------------------------------- /dart/geodata/lib/src/core/data/geospatial_query.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2024 Navibyte (https://navibyte.com). All rights reserved. 2 | // Use of this source code is governed by a “BSD-3-Clause”-style license that is 3 | // specified in the LICENSE file. 4 | // 5 | // Docs: https://github.com/navibyte/geospatial 6 | 7 | import 'package:geobase/common.dart'; 8 | import 'package:meta/meta.dart'; 9 | 10 | import '/src/utils/object_utils.dart'; 11 | 12 | /// A base query for requesting data from a geospatial data source. 13 | @immutable 14 | class GeospatialQuery { 15 | /// A base query for requesting data from a geospatial data source. 16 | const GeospatialQuery({ 17 | this.crs, 18 | this.parameters, 19 | }); 20 | 21 | /// An optional id defining a coordinate reference system for result data. 22 | final CoordRefSys? crs; 23 | 24 | /// Optional query parameters for queries as a map of named parameters. 25 | /// 26 | /// Note that such parameters that are defined in other members of this class 27 | /// or it's sub type, override any parameter on [parameters], if available. 28 | /// Use this only for parameters that are not defined by other members. 29 | /// 30 | /// See also the [queryablesAsParameters] getter that maps all values to 31 | /// `String`. 32 | final Map? parameters; 33 | 34 | /// Optional query parameters for queries with values mapped to `String`. 35 | /// 36 | /// This getter maps values from [parameters] using the mapper function: 37 | /// `(key, value) => MapEntry(key, value.toString())` 38 | Map? get queryablesAsParameters => 39 | parameters?.map((key, value) => MapEntry(key, value.toString())); 40 | 41 | @override 42 | String toString() { 43 | return '$crs;$mapToString(parameters)'; 44 | } 45 | 46 | @override 47 | bool operator ==(Object other) => 48 | identical(this, other) || 49 | (other is GeospatialQuery && 50 | crs == other.crs && 51 | testMapEquality(parameters, other.parameters)); 52 | 53 | @override 54 | int get hashCode => Object.hash(crs, mapHashCode(parameters)); 55 | } 56 | -------------------------------------------------------------------------------- /dart/geodata/lib/src/core/data/item_query.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2024 Navibyte (https://navibyte.com). All rights reserved. 2 | // Use of this source code is governed by a “BSD-3-Clause”-style license that is 3 | // specified in the LICENSE file. 4 | // 5 | // Docs: https://github.com/navibyte/geospatial 6 | 7 | import '/src/utils/object_utils.dart'; 8 | 9 | import 'geospatial_query.dart'; 10 | 11 | /// A query for requesting an item from a geospatial data source. 12 | class ItemQuery extends GeospatialQuery { 13 | /// A query for requesting an item from a geospatial data source by [id]. 14 | const ItemQuery({ 15 | required this.id, 16 | super.crs, 17 | super.parameters, 18 | }); 19 | 20 | /// An identifier specifying an item on a geodata source. 21 | /// 22 | /// An identifier should be an integer number (int or BigInt) or a string. 23 | final Object id; 24 | 25 | @override 26 | String toString() { 27 | return '$id;$crs;$mapToString(parameters)'; 28 | } 29 | 30 | @override 31 | bool operator ==(Object other) => 32 | identical(this, other) || 33 | (other is ItemQuery && 34 | id == other.id && 35 | crs == other.crs && 36 | testMapEquality(parameters, other.parameters)); 37 | 38 | @override 39 | int get hashCode => Object.hash(id, crs, mapHashCode(parameters)); 40 | } 41 | -------------------------------------------------------------------------------- /dart/geodata/lib/src/core/data/items_query.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2024 Navibyte (https://navibyte.com). All rights reserved. 2 | // Use of this source code is governed by a “BSD-3-Clause”-style license that is 3 | // specified in the LICENSE file. 4 | // 5 | // Docs: https://github.com/navibyte/geospatial 6 | 7 | import '/src/utils/object_utils.dart'; 8 | 9 | import 'geospatial_query.dart'; 10 | 11 | /// A query for requesting items from a geospatial data source. 12 | class ItemsQuery extends GeospatialQuery { 13 | /// A query for requesting items from a geospatial data source. 14 | const ItemsQuery({ 15 | super.crs, 16 | this.limit, 17 | super.parameters, 18 | }); 19 | 20 | /// An optional [limit] setting maximum number of items returned. 21 | /// 22 | /// If given, must be a positive integer. 23 | final int? limit; 24 | 25 | @override 26 | String toString() { 27 | return '$crs;$limit;$mapToString(parameters)'; 28 | } 29 | 30 | @override 31 | bool operator ==(Object other) => 32 | identical(this, other) || 33 | (other is ItemsQuery && 34 | crs == other.crs && 35 | limit == other.limit && 36 | testMapEquality(parameters, other.parameters)); 37 | 38 | @override 39 | int get hashCode => Object.hash(crs, limit, mapHashCode(parameters)); 40 | } 41 | -------------------------------------------------------------------------------- /dart/geodata/lib/src/core/features/basic_feature_source.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2023 Navibyte (https://navibyte.com). All rights reserved. 2 | // Use of this source code is governed by a “BSD-3-Clause”-style license that is 3 | // specified in the LICENSE file. 4 | // 5 | // Docs: https://github.com/navibyte/geospatial 6 | 7 | import '/src/common/paged/paged.dart'; 8 | 9 | import 'feature_item.dart'; 10 | import 'feature_items.dart'; 11 | import 'feature_source.dart'; 12 | 13 | /// A basic feature source providing geospatial features. 14 | /// 15 | /// This feature source has operations to get feature items by id or to get all 16 | /// items. The [FeatureSource] extends this with queryable access to items. 17 | abstract class BasicFeatureSource { 19 | /// Fetches a single feature by [id] from this source. 20 | /// 21 | /// An identifier should be an integer number (int or BigInt) or a string. 22 | /// 23 | /// Throws `ServiceException` in a case of a failure. 24 | Future itemById(Object id); 25 | 26 | /// Fetches all features items from this source. 27 | /// 28 | /// An optional [limit] sets maximum number of items returned. If given, it 29 | /// must be a positive integer. 30 | /// 31 | /// This call accesses only one set of feature items (number of returned items 32 | /// can be limited). 33 | /// 34 | /// Throws `ServiceException` in a case of a failure. 35 | Future itemsAll({int? limit}); 36 | 37 | /// Fetches all features as paged sets from this source. 38 | /// 39 | /// An optional [limit] sets maximum number of items returned. If given, it 40 | /// must be a positive integer. 41 | /// 42 | /// This call returns a first set of feature items (number of returned items 43 | /// can be limited), with a link to an optional next set of feature items. 44 | /// 45 | /// Throws `ServiceException` in a case of a failure. 46 | Future> itemsAllPaged({int? limit}); 47 | } 48 | -------------------------------------------------------------------------------- /dart/geodata/lib/src/core/features/feature_item.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2024 Navibyte (https://navibyte.com). All rights reserved. 2 | // Use of this source code is governed by a “BSD-3-Clause”-style license that is 3 | // specified in the LICENSE file. 4 | // 5 | // Docs: https://github.com/navibyte/geospatial 6 | 7 | import 'package:geobase/vector_data.dart'; 8 | import 'package:meta/meta.dart'; 9 | 10 | import '/src/common/meta/meta_aware.dart'; 11 | import '/src/utils/object_utils.dart'; 12 | 13 | /// A result from a feature source containing [feature] and [meta] data. 14 | @immutable 15 | class FeatureItem with MetaAware { 16 | /// Create a feature item instance with [feature] and optional [meta]. 17 | const FeatureItem(this.feature, {Map? meta}) 18 | : meta = meta ?? const {}; 19 | 20 | /// The wrapped feature. 21 | final Feature feature; 22 | 23 | @override 24 | final Map meta; 25 | 26 | @override 27 | String toString() { 28 | return '$feature;$mapToString(meta)'; 29 | } 30 | 31 | @override 32 | bool operator ==(Object other) => 33 | identical(this, other) || 34 | (other is FeatureItem && 35 | feature == other.feature && 36 | testMapEquality(meta, other.meta)); 37 | 38 | @override 39 | int get hashCode => Object.hash(feature, mapHashCode(meta)); 40 | } 41 | -------------------------------------------------------------------------------- /dart/geodata/lib/src/core/features/feature_items.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2024 Navibyte (https://navibyte.com). All rights reserved. 2 | // Use of this source code is governed by a “BSD-3-Clause”-style license that is 3 | // specified in the LICENSE file. 4 | // 5 | // Docs: https://github.com/navibyte/geospatial 6 | 7 | import 'package:geobase/vector_data.dart'; 8 | import 'package:meta/meta.dart'; 9 | 10 | import '/src/common/meta/meta_aware.dart'; 11 | import '/src/utils/object_utils.dart'; 12 | 13 | /// A result from a feature source containing [collection] and [meta] data. 14 | @immutable 15 | class FeatureItems with MetaAware { 16 | /// Create a feature items instance with [collection] and optional [meta]. 17 | const FeatureItems(this.collection, {Map? meta}) 18 | : meta = meta ?? const {}; 19 | 20 | /// The wrapped feature collection. 21 | final FeatureCollection collection; 22 | 23 | @override 24 | final Map meta; 25 | 26 | @override 27 | String toString() { 28 | return '$collection;$mapToString(meta)'; 29 | } 30 | 31 | @override 32 | bool operator ==(Object other) => 33 | identical(this, other) || 34 | (other is FeatureItems && 35 | collection == other.collection && 36 | testMapEquality(meta, other.meta)); 37 | 38 | @override 39 | int get hashCode => Object.hash(collection, mapHashCode(meta)); 40 | } 41 | -------------------------------------------------------------------------------- /dart/geodata/lib/src/core/features/feature_source.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2023 Navibyte (https://navibyte.com). All rights reserved. 2 | // Use of this source code is governed by a “BSD-3-Clause”-style license that is 3 | // specified in the LICENSE file. 4 | // 5 | // Docs: https://github.com/navibyte/geospatial 6 | 7 | import '/src/common/paged/paged.dart'; 8 | import '/src/core/data/bounded_items_query.dart'; 9 | import '/src/core/data/item_query.dart'; 10 | 11 | import 'basic_feature_source.dart'; 12 | import 'feature_item.dart'; 13 | import 'feature_items.dart'; 14 | 15 | /// A feature source providing geospatial features. 16 | abstract class FeatureSource 18 | extends BasicFeatureSource { 19 | /// Fetches a single feature by id (set in [query]) from this source. 20 | /// 21 | /// Throws `ServiceException` in a case of a failure. 22 | Future item(ItemQuery query); 23 | 24 | /// Fetches features matching [query] from this source. 25 | /// 26 | /// This call accesses only one set of feature items (number of returned items 27 | /// can be limited). 28 | /// 29 | /// Throws `ServiceException` in a case of a failure. 30 | Future items(BoundedItemsQuery query); 31 | 32 | /// Fetches features as paged sets matching [query] from this source. 33 | /// 34 | /// This call returns a first set of feature items (number of returned items 35 | /// can be limited), with a link to an optional next set of feature items. 36 | /// 37 | /// Throws `ServiceException` in a case of a failure. 38 | Future> itemsPaged(BoundedItemsQuery query); 39 | } 40 | -------------------------------------------------------------------------------- /dart/geodata/lib/src/formats/openapi/open_api_document.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2024 Navibyte (https://navibyte.com). All rights reserved. 2 | // Use of this source code is governed by a “BSD-3-Clause”-style license that is 3 | // specified in the LICENSE file. 4 | // 5 | // Docs: https://github.com/navibyte/geospatial 6 | 7 | import 'package:meta/meta.dart'; 8 | 9 | import '/src/utils/object_utils.dart'; 10 | 11 | /// An OpenAPI document for some service with raw content parsed in [content]. 12 | /// 13 | /// Note: this class wraps decoded JSON Object from a JSON document containing 14 | /// OpenAPI definition. To utilize such data JSON Object tree in [content] must 15 | /// be traversed as needed. 16 | /// 17 | /// In future this class might containg also helper methods to access certain 18 | /// objects and fields according to the OpenAPI schema. Currently there is only 19 | /// the [openapi] member, other elements must be accessed from raw data. 20 | /// 21 | /// See also: 22 | /// * https://www.openapis.org/ 23 | /// * https://spec.openapis.org/oas/latest.html 24 | /// * https://swagger.io/specification/ 25 | /// 26 | /// Example: 27 | /// ```dart 28 | /// void _printOpenAPI(OpenAPIDocument document) { 29 | /// print('OpenAPI ${document.openapi}'); 30 | /// final servers = document.content['servers'] as Iterable; 31 | /// for (final s in servers) { 32 | /// final server = s as Map; 33 | /// final url = server['url'] as String; 34 | /// final desc = server['description'] as String?; 35 | /// print(' $url : $desc'); 36 | /// } 37 | /// } 38 | /// ``` 39 | @immutable 40 | class OpenAPIDocument { 41 | /// The OpenAPI document as a data object (ie. data from a JSON Object). 42 | final Map content; 43 | 44 | /// The version number of the OpenAPI Specification that this OpenAPI document 45 | /// uses. 46 | final String openapi; 47 | 48 | const OpenAPIDocument._({ 49 | this.content = const {}, 50 | required this.openapi, 51 | }); 52 | 53 | /// Parses Open API document for a service from Open API data in [content]. 54 | factory OpenAPIDocument.fromJson(Map content) => 55 | OpenAPIDocument._( 56 | content: content, 57 | openapi: content['openapi'] as String, // required 58 | ); 59 | 60 | @override 61 | String toString() => '$openapi;$mapToString(content)'; 62 | 63 | @override 64 | bool operator ==(Object other) => 65 | identical(this, other) || 66 | (other is OpenAPIDocument && 67 | openapi == other.openapi && 68 | testMapEquality(content, other.content)); 69 | 70 | @override 71 | int get hashCode => Object.hash(openapi, mapHashCode(content)); 72 | } 73 | -------------------------------------------------------------------------------- /dart/geodata/lib/src/ogcapi_common/model/ogc_service.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2023 Navibyte (https://navibyte.com). All rights reserved. 2 | // Use of this source code is governed by a “BSD-3-Clause”-style license that is 3 | // specified in the LICENSE file. 4 | // 5 | // Docs: https://github.com/navibyte/geospatial 6 | 7 | import 'ogc_conformance.dart'; 8 | import 'ogc_service_meta.dart'; 9 | 10 | /// A service compliant with the OGC API Common standard. 11 | abstract class OGCService { 12 | /// Get meta data (or "landing page" information) about this service. 13 | Future meta(); 14 | 15 | /// Conformance classes this service is conforming to. 16 | Future conformance(); 17 | } 18 | -------------------------------------------------------------------------------- /dart/geodata/lib/src/ogcapi_common/model/ogc_service_meta.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2024 Navibyte (https://navibyte.com). All rights reserved. 2 | // Use of this source code is governed by a “BSD-3-Clause”-style license that is 3 | // specified in the LICENSE file. 4 | // 5 | // Docs: https://github.com/navibyte/geospatial 6 | 7 | import 'package:meta/meta.dart'; 8 | 9 | import '/src/core/base/resource_meta.dart'; 10 | import '/src/formats/openapi/open_api_document.dart'; 11 | 12 | /// Basic metadata about OGC API service. 13 | @immutable 14 | abstract class OGCServiceMeta extends ResourceMeta { 15 | /// A new OGC API service metadata instance with [title], [description], 16 | /// [attribution] and [links]. 17 | const OGCServiceMeta({ 18 | required super.title, 19 | super.description, 20 | super.attribution, 21 | required super.links, 22 | }); 23 | 24 | /// Get an OpenAPI documentation (API definition) for this service. 25 | /// 26 | /// The API definition is retrieved: 27 | /// 1. Get a link for the relation "service-desc". 28 | /// 2. Ensure it's type is "application/vnd.oai.openapi+json". 29 | /// 3. Read JSON content from a HTTP service. 30 | /// 4. Decode content received as JSON Object using the standard JSON decoder. 31 | /// 5. Wrap such decoded object in an [OpenAPIDocument] instance. 32 | /// 33 | /// If a service does not provide an OpenAPI definition in JSON or retrieving 34 | /// it fails, then a `ServiceException` is thrown. 35 | /// 36 | /// Most often for an OGC API Features service an API definition is an 37 | /// OpenAPI 3.0 document, but this is not required by the standard. 38 | Future openAPI(); 39 | 40 | @override 41 | // ignore: hash_and_equals 42 | bool operator ==(Object other) => other is OGCServiceMeta && super == other; 43 | } 44 | -------------------------------------------------------------------------------- /dart/geodata/lib/src/ogcapi_features/model/ogc_feature_item.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2024 Navibyte (https://navibyte.com). All rights reserved. 2 | // Use of this source code is governed by a “BSD-3-Clause”-style license that is 3 | // specified in the LICENSE file. 4 | // 5 | // Docs: https://github.com/navibyte/geospatial 6 | 7 | import 'package:geobase/common.dart'; 8 | 9 | import '/src/common/links/links.dart'; 10 | import '/src/common/links/links_aware.dart'; 11 | import '/src/core/features/feature_item.dart'; 12 | 13 | /// A result from a feature source containing [feature] and [meta] data. 14 | /// 15 | /// This class extends [FeatureItem] defining some getters ([links]) that are 16 | /// OGC API Features specific. 17 | class OGCFeatureItem extends FeatureItem with LinksAware { 18 | /// Create a feature item instance with [feature] and optional [meta]. 19 | const OGCFeatureItem( 20 | super.feature, { 21 | super.meta, 22 | this.contentCrs, 23 | }); 24 | 25 | /// An optional coordinate reference system from "Content-Crs" response 26 | /// header. 27 | final CoordRefSys? contentCrs; 28 | 29 | // Note : Following getters access external data outside actual parsing code, 30 | // so there's some extra care to ensure nulls or empty data is returned if 31 | // accessing data throws. 32 | 33 | @override 34 | Links get links { 35 | final data = meta['links']; 36 | if (data is Iterable) { 37 | try { 38 | return Links.fromJson(data); 39 | } on FormatException { 40 | // nop, could not parse, but then let empty links to be returned 41 | } 42 | } 43 | return const Links.empty(); 44 | } 45 | 46 | @override 47 | String toString() { 48 | return '${super.toString()};$contentCrs'; 49 | } 50 | 51 | @override 52 | bool operator ==(Object other) => 53 | other is OGCFeatureItem && 54 | super == other && 55 | contentCrs == other.contentCrs; 56 | 57 | @override 58 | int get hashCode => Object.hash(super.hashCode, contentCrs); 59 | } 60 | -------------------------------------------------------------------------------- /dart/geodata/lib/src/ogcapi_features/model/ogc_feature_items.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2024 Navibyte (https://navibyte.com). All rights reserved. 2 | // Use of this source code is governed by a “BSD-3-Clause”-style license that is 3 | // specified in the LICENSE file. 4 | // 5 | // Docs: https://github.com/navibyte/geospatial 6 | 7 | import 'package:geobase/common.dart'; 8 | 9 | import '/src/common/links/links.dart'; 10 | import '/src/common/links/links_aware.dart'; 11 | import '/src/core/features/feature_items.dart'; 12 | 13 | /// A result from a feature source containing [collection] and [meta] data. 14 | /// 15 | /// This class extends [FeatureItems] defining some getters ([timeStamp], 16 | /// [numberMatched], [numberReturned], [links]) that are OGC API Features 17 | /// specific. 18 | class OGCFeatureItems extends FeatureItems with LinksAware { 19 | /// Create a feature items instance with [collection] and optional [meta]. 20 | const OGCFeatureItems( 21 | super.collection, { 22 | super.meta, 23 | this.contentCrs, 24 | }); 25 | 26 | /// An optional coordinate reference system from "Content-Crs" response 27 | /// header. 28 | final CoordRefSys? contentCrs; 29 | 30 | // Note : Following getters access external data outside actual parsing code, 31 | // so there's some extra care to ensure nulls or empty data is returned if 32 | // accessing data throws. 33 | 34 | /// The time stamp 35 | DateTime? get timeStamp => _tryParseDateTime(meta['timeStamp']); 36 | 37 | /// An optional count of items matched. 38 | int? get numberMatched => _tryParseInt(meta['numberMatched']); 39 | 40 | /// An optional count of items returned. 41 | int? get numberReturned => _tryParseInt(meta['numberReturned']); 42 | 43 | @override 44 | Links get links { 45 | final data = meta['links']; 46 | if (data is Iterable) { 47 | try { 48 | return Links.fromJson(data); 49 | } on FormatException { 50 | // nop, could not parse, but then let empty links to be returned 51 | } 52 | } 53 | return const Links.empty(); 54 | } 55 | 56 | @override 57 | String toString() { 58 | return '${super.toString()};$contentCrs'; 59 | } 60 | 61 | @override 62 | bool operator ==(Object other) => 63 | other is OGCFeatureItems && 64 | super == other && 65 | contentCrs == other.contentCrs; 66 | 67 | @override 68 | int get hashCode => Object.hash(super.hashCode, contentCrs); 69 | } 70 | 71 | DateTime? _tryParseDateTime(Object? data) { 72 | if (data != null) { 73 | return data is DateTime ? data : DateTime.tryParse(data.toString()); 74 | } 75 | return null; 76 | } 77 | 78 | int? _tryParseInt(Object? data) { 79 | if (data != null) { 80 | return data is num ? data.toInt() : int.tryParse(data.toString()); 81 | } 82 | return null; 83 | } 84 | -------------------------------------------------------------------------------- /dart/geodata/lib/src/ogcapi_features/model/ogc_feature_service.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2023 Navibyte (https://navibyte.com). All rights reserved. 2 | // Use of this source code is governed by a “BSD-3-Clause”-style license that is 3 | // specified in the LICENSE file. 4 | // 5 | // Docs: https://github.com/navibyte/geospatial 6 | 7 | import '/src/ogcapi_common/model/ogc_collection_meta.dart'; 8 | import '/src/ogcapi_common/model/ogc_service.dart'; 9 | 10 | import 'ogc_feature_conformance.dart'; 11 | import 'ogc_feature_source.dart'; 12 | 13 | /// A feature service compliant with the OGC API Features standard. 14 | abstract class OGCFeatureService extends OGCService { 15 | @override 16 | Future conformance(); 17 | 18 | /// Get metadata about feature collections provided by this service. 19 | Future> collections(); 20 | 21 | /// Get a feature source for a feature collection identified by [id]. 22 | Future collection(String id); 23 | } 24 | -------------------------------------------------------------------------------- /dart/geodata/lib/src/utils/cached_object.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2023 Navibyte (https://navibyte.com). All rights reserved. 2 | // Use of this source code is governed by a “BSD-3-Clause”-style license that is 3 | // specified in the LICENSE file. 4 | // 5 | // Docs: https://github.com/navibyte/geospatial 6 | 7 | import 'package:meta/meta.dart'; 8 | 9 | /// A simple utility class to cache a single object for short periods. 10 | @internal 11 | class CachedObject { 12 | final Duration _maxAge; 13 | 14 | T? _object; 15 | DateTime? _cachedTime; 16 | 17 | /// Create a cached object with [_maxAge] and empty state. 18 | CachedObject(this._maxAge); 19 | 20 | /// Get cached object of [T] synchronously, or when it's too old access a new 21 | /// one and return it. 22 | T get(T Function() accessor) { 23 | final obj = _getCached(); 24 | if (obj != null) return obj; 25 | 26 | // got nothing from cache, need to access 27 | final newObj = accessor.call(); 28 | _object = newObj; 29 | _cachedTime = DateTime.now(); 30 | return newObj; 31 | } 32 | 33 | /// Get cached object of [T] asynchronously, or when it's too old access a new 34 | /// one and return it. 35 | Future getAsync(Future Function() accessor) async { 36 | final obj = _getCached(); 37 | if (obj != null) return obj; 38 | 39 | // got nothing from cache, need to access 40 | final newObj = await accessor.call(); 41 | _object = newObj; 42 | _cachedTime = DateTime.now(); 43 | return newObj; 44 | } 45 | 46 | T? _getCached() { 47 | final obj = _object; 48 | final time = _cachedTime; 49 | if (obj != null && time != null) { 50 | if (DateTime.now().difference(time) > _maxAge) { 51 | // too old 52 | _object = null; 53 | _cachedTime = null; 54 | } else { 55 | //print('Cache hit ${obj.runtimeType}'); 56 | 57 | // still valid 58 | return obj; 59 | } 60 | } 61 | 62 | // got nothing from cache 63 | return null; 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /dart/geodata/lib/src/utils/feature_future_adapter.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2024 Navibyte (https://navibyte.com). All rights reserved. 2 | // Use of this source code is governed by a “BSD-3-Clause”-style license that is 3 | // specified in the LICENSE file. 4 | // 5 | // Docs: https://github.com/navibyte/geospatial 6 | 7 | import 'dart:convert'; 8 | 9 | import 'package:meta/meta.dart'; 10 | 11 | import '/src/common/service/service_exception.dart'; 12 | import '/src/core/features/feature_failure.dart'; 13 | 14 | /// Maps a JSON Object read from [source] to an entity using [toEntity]. 15 | /// 16 | /// The source function returns a future that fetches data from a file, a web 17 | /// resource or other sources. Content must be GeoJSON compliant data. 18 | @internal 19 | Future readEntityFromJsonObject( 20 | Future Function() source, { 21 | required T Function(Map data) toEntity, 22 | }) async { 23 | try { 24 | // read content as text 25 | final text = await source(); 26 | 27 | // decode JSON and expect a JSON Object as `Map` 28 | final data = json.decode(text) as Map; 29 | 30 | // map JSON Object to an entity 31 | return toEntity(data); 32 | } on ServiceException { 33 | rethrow; 34 | } catch (e, st) { 35 | // other exceptions (including errors) 36 | throw ServiceException(FeatureFailure.clientError, cause: e, trace: st); 37 | } 38 | } 39 | 40 | /// Maps text data read from [source] to an entity using [toEntity]. 41 | /// 42 | /// The source function returns a future that fetches data from a file, a web 43 | /// resource or other sources. Content must be GeoJSON compliant data. 44 | @internal 45 | Future readEntityFromText( 46 | Future Function() source, { 47 | required T Function(String text) toEntity, 48 | }) async { 49 | try { 50 | // read content as text 51 | final text = await source(); 52 | 53 | // map text to an entity 54 | return toEntity(text); 55 | } on ServiceException { 56 | rethrow; 57 | } catch (e, st) { 58 | // other exceptions (including errors) 59 | throw ServiceException(FeatureFailure.clientError, cause: e, trace: st); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /dart/geodata/lib/src/utils/resolve_api_call.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2023 Navibyte (https://navibyte.com). All rights reserved. 2 | // Use of this source code is governed by a “BSD-3-Clause”-style license that is 3 | // specified in the LICENSE file. 4 | // 5 | // Docs: https://github.com/navibyte/geospatial 6 | 7 | import 'package:meta/meta.dart'; 8 | 9 | /// Creates an API call path that has [subResource] as a sub path for [endpoint] 10 | /// regardless wether [endpoint] has a postfix `/` character. 11 | /// 12 | /// The [subResource] should not start with `/', or such a resource shall be 13 | /// resolved directly under the host of [endpoint]. 14 | @internal 15 | Uri resolveSubResource(Uri endpoint, String subResource) { 16 | final basePath = endpoint.path; 17 | if (basePath.endsWith('/')) { 18 | return endpoint.resolve(subResource); 19 | } else { 20 | return endpoint.replace(path: '$basePath/').resolve(subResource); 21 | } 22 | } 23 | 24 | /// Creates an API call path that has [subResource] as a sub path for [endpoint] 25 | /// regardless wether [endpoint] has a postfix `/` character. 26 | /// 27 | /// The [subResource] should not start with `/', or such a resource shall be 28 | /// resolved directly under the host of [endpoint]. 29 | @internal 30 | Uri resolveSubResourceUri(Uri endpoint, Uri subResource) { 31 | final basePath = endpoint.path; 32 | if (basePath.endsWith('/')) { 33 | return endpoint.resolveUri(subResource); 34 | } else { 35 | return endpoint.replace(path: '$basePath/').resolveUri(subResource); 36 | } 37 | } 38 | 39 | /// Creates an API call path from [link]. 40 | /// 41 | /// If [link] has an authority part, then it is returned. 42 | /// 43 | /// Otherwise `endpoint.resolveUri(link)` is returned. 44 | @internal 45 | Uri resolveLinkReferenceUri(Uri endpoint, Uri link) { 46 | if (link.hasAuthority) { 47 | return link; 48 | } else { 49 | return endpoint.resolveUri(link); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /dart/geodata/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: geodata 2 | description: A geospatial client to read GeoJSON and OGC API Features data sources. 3 | version: 1.4.0-dev.0 4 | repository: https://github.com/navibyte/geospatial 5 | homepage: https://geospatial.navibyte.dev/ 6 | publish_to: none 7 | 8 | topics: 9 | - geojson 10 | - api 11 | - client 12 | - rest 13 | - openapi 14 | 15 | environment: 16 | sdk: '>=2.17.0 <4.0.0' 17 | 18 | dependencies: 19 | http: '>=0.13.0 <2.0.0' 20 | meta: ^1.7.0 21 | 22 | #geobase: ^1.1.0 23 | geobase: 24 | path: ../geobase 25 | 26 | dev_dependencies: 27 | test: ^1.24.0 28 | very_good_analysis: ^6.0.0 29 | -------------------------------------------------------------------------------- /dart/geodata/test/data/london.geojson: -------------------------------------------------------------------------------- 1 | { 2 | "type": "FeatureCollection", 3 | "features": [ 4 | { 5 | "type": "Feature", 6 | "id": "ROG", 7 | "geometry": { 8 | "type": "Point", 9 | "coordinates": [-0.0014, 51.4778, 45.0] 10 | }, 11 | "properties": { 12 | "title": "Royal Observatory", 13 | "place": "Greenwich" 14 | } 15 | }, 16 | { 17 | "type": "Feature", 18 | "id": "TB", 19 | "geometry": { 20 | "type": "Point", 21 | "coordinates": [-0.075406, 51.5055] 22 | }, 23 | "properties": { 24 | "title": "Tower Bridge", 25 | "built": 1886 26 | } 27 | } 28 | ] 29 | } -------------------------------------------------------------------------------- /dart/geodata/test/data/london.geojsonl: -------------------------------------------------------------------------------- 1 | {"type":"Feature","id":"ROG","geometry":{"type":"Point","coordinates":[-0.0014,51.4778,45]},"properties":{"title":"Royal Observatory","place":"Greenwich"}} 2 | {"type":"Feature","id":"TB","geometry":{"type":"Point","coordinates":[-0.075406,51.5055]},"properties":{"title":"Tower Bridge","built":1886}} -------------------------------------------------------------------------------- /dart/geodata/test/usgs/summary/readme.txt: -------------------------------------------------------------------------------- 1 | The "2.5_day.geojson" data file accessed 2021-02-27 from: 2 | https://earthquake.usgs.gov/earthquakes/feed/v1.0/summary/2.5_day.geojson 3 | 4 | More information about these data feeds: 5 | https://earthquake.usgs.gov/earthquakes/feed/ 6 | 7 | The data file is stored here for testing purposes. --------------------------------------------------------------------------------