From 25df24af2b1b076c40c04ab5e4204807bb41a574 Mon Sep 17 00:00:00 2001 From: Jonas Siedentop Date: Fri, 1 Mar 2024 18:01:06 +0100 Subject: [PATCH] Update readme (#179) * moved progress and update readme * add progress link * add logo * add badges * update url --- .github/turf-logo.png | Bin 0 -> 21982 bytes Progress.md | 180 +++++++++++++++++++++++++++++++++++++ README.md | 200 ++++-------------------------------------- 3 files changed, 195 insertions(+), 185 deletions(-) create mode 100644 .github/turf-logo.png create mode 100644 Progress.md diff --git a/.github/turf-logo.png b/.github/turf-logo.png new file mode 100644 index 0000000000000000000000000000000000000000..f874967f024d9097ae6aefd478d870b9cc4046ab GIT binary patch literal 21982 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%0AFOB*)?T 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 +
+ TurfDart Logo + -[![pub package](https://img.shields.io/pub/v/turf.svg)](https://pub.dev/packages/turf) +

A TurfJs-like geospatial analysis library written in pure Dart. +

+
-THIS PROJECT IS WORK IN PROCESS +[![pub package](https://img.shields.io/pub/v/turf.svg)](https://pub.dev/packages/turf) +![dart unit tests](https://github.com/dartclub/turf_dart/actions/workflows/dart-unit-tests.yml/badge.svg) +![dart publish](https://github.com/dartclub/turf_dart/actions/workflows/dart-pub-publish.yml/badge.svg) +![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg) -A [turf.js](https://github.com/Turfjs/turf)-like geospatial analysis library working with GeoJSON, written in pure Dart. +TurfDart is a Dart library for [spatial analysis](https://en.wikipedia.org/wiki/Spatial_analysis). It includes traditional spatial operations, helper functions for creating GeoJSON data, and data classification and statistics tools. You can use TurfDart in your Flutter applications on the web, mobile and desktop or in pure Dart applications running on the server. -This includes a fully [RFC 7946](https://tools.ietf.org/html/rfc7946)-compliant object-representation and serialization for GeoJSON. +As the foundation, we are using [Geotypes](https://github.com/dartclub/geotypes), a lightweight dart library that provides a strong GeoJSON object model and fully [RFC 7946](https://tools.ietf.org/html/rfc7946) compliant serializers. -Most of the implementation is a direct translation from [turf.js](https://github.com/Turfjs/turf). +Most of the functionality is a translation from [turf.js](https://github.com/Turfjs/turf), the progress can be found [here](Progress.md). ## Get started @@ -59,7 +67,7 @@ void main() { ![polymorphism](https://user-images.githubusercontent.com/10634693/159876354-f9da2f37-02b3-4546-b32a-c0f82c372272.png) -## Notable Design Decisions +### Notable Design Decisions - Nested `GeometryCollections` (as described in [RFC 7946 section 3.1.8](https://datatracker.ietf.org/doc/html/rfc7946#section-3.1.8)) @@ -73,181 +81,3 @@ Tests are run with `dart test` and benchmarks can be run with Any new benchmarks must be named `*_benchmark.dart` and reside in the `./benchmark` folder. - -## Components - -### Measurement - -- [x] [along](https://github.com/dartclub/turf_dart/blob/main/lib/src/along.dart) -- [x] [area](https://github.com/dartclub/turf_dart/blob/main/lib/src/area.dart) -- [x] [bbox](https://github.com/dartclub/turf_dart/blob/main/lib/src/bbox.dart) -- [x] [bboxPolygon](https://github.com/dartclub/turf_dart/blob/main/lib/src/bbox_polygon.dart) -- [x] [bearing](https://github.com/dartclub/turf_dart/blob/main/lib/src/bearing.dart) -- [x] [center](https://github.com/Dennis-Mwea/turf_dart/blob/main/lib/src/center.dart) -- [ ] centerOfMass -- [x] [centroid](https://github.com/dartclub/turf_dart/blob/main/lib/src/centroid.dart) -- [x] [destination](https://github.com/dartclub/turf_dart/blob/main/lib/src/destination.dart) -- [x] [distance](https://github.com/dartclub/turf_dart/blob/main/lib/src/distance.dart) -- [ ] envelope -- [x] [length](https://github.com/dartclub/turf_dart/blob/main/lib/src/length.dart) -- [x] [midpoint](https://github.com/dartclub/turf_dart/blob/main/lib/src/midpoint.dart) -- [ ] pointOnFeature -- [ ] polygonTangents -- [ ] pointToLineDistance -- [x] [rhumbBearing](https://github.com/dartclub/turf_dart/blob/main/lib/src/rhumb_bearing.dart) -- [x] [rhumbDestination](https://github.com/dartclub/turf_dart/blob/main/lib/src/rhumb_destination.dart) -- [x] [rhumbDistance](https://github.com/dartclub/turf_dart/blob/main/lib/src/rhumb_distance.dart) -- [ ] square -- [ ] greatCircle - -### Coordinate Mutation - -- [x] [cleanCoords](https://github.com/dartclub/turf_dart/blob/main/lib/src/clean_coords.dart) -- [ ] flip -- [ ] rewind -- [ ] round -- [x] [truncate](https://github.com/dartclub/turf_dart/blob/main/lib/src/truncate.dart) - -### Transformation - -- [ ] bboxClip -- [ ] bezierSpline -- [ ] buffer -- [ ] circle -- [x] clone - implemented as a member function of each [GeoJSONObject] -- [ ] concave -- [ ] convex -- [ ] difference -- [ ] dissolve -- [ ] intersect -- [ ] lineOffset -- [x] [polygonSmooth](https://github.com/dartclub/turf_dart/blob/main/lib/src/polygon_smooth.dart) -- [ ] simplify -- [ ] tesselate -- [x] [transformRotate](https://github.com/dartclub/turf_dart/blob/main/lib/src/transform_rotate.dart) -- [ ] transformTranslate -- [ ] transformScale -- [ ] union -- [ ] voronoi -- [x] [polyLineDecode](https://github.com/dartclub/turf_dart/blob/main/lib/src/polyline.dart) - -### Feature Conversion - -- [ ] combine -- [x] [explode](https://github.com/dartclub/turf_dart/blob/main/lib/src/explode.dart) -- [ ] flatten -- [x] [lineToPolygon](https://github.com/dartclub/turf_dart/blob/main/lib/src/line_to_polygon.dart) -- [ ] polygonize -- [x] [polygonToLine](https://github.com/dartclub/turf_dart/blob/main/lib/src/polygon_to_line.dart) - -### MISC - -- [ ] ellipse -- [ ] kinks -- [ ] lineArc -- [ ] lineChunk -- [ ] [lineIntersect](https://github.com/dartclub/turf_dart/blob/main/lib/src/line_intersect.dart) -- [x] [lineOverlap](https://github.com/dartclub/turf_dart/blob/main/lib/src/line_overlap.dart) -- [x] [lineSegment](https://github.com/dartclub/turf_dart/blob/main/lib/src/line_segment.dart) -- [x] [lineSlice](https://github.com/dartclub/turf_dart/blob/main/lib/src/line_slice.dart) -- [ ] lineSliceAlong -- [ ] lineSplit -- [ ] mask -- [x] [nearestPointOnLine](https://github.com/dartclub/turf_dart/blob/main/lib/src/nearest_point_on_line.dart) -- [ ] sector -- [ ] shortestPath -- [ ] unkinkPolygon - -### Random - -- [ ] randomPosition -- [ ] randomPoint -- [ ] randomLineString -- [ ] randomPolygon - -### Data - -- [ ] sample - -### Interpolation - -- [ ] interpolate -- [ ] isobands -- [ ] isolines -- [ ] planepoint -- [ ] tin - -### Joins - -- [ ] pointsWithinPolygon -- [ ] tag - -### Grids - -- [ ] hexGrid -- [ ] pointGrid -- [ ] squareGrid -- [ ] triangleGrid - -### Classification - -- [x] [nearestPoint](https://github.com/dartclub/turf_dart/blob/main/lib/src/nearest_point.dart) - -### Aggregation - -- [ ] collect -- [ ] clustersDbscan -- [ ] clustersKmeans - -### META - -- [x] [coordAll](https://github.com/dartclub/turf_dart/blob/main/lib/src/meta/coord.dart) -- [x] [coordEach](https://github.com/dartclub/turf_dart/blob/main/lib/src/meta/coord.dart) -- [x] [coordReduce](https://github.com/dartclub/turf_dart/blob/main/lib/src/meta/coord.dart) -- [x] [featureEach](https://github.com/dartclub/turf_dart/blob/main/lib/src/meta/feature.dart) -- [x] [featureReduce](https://github.com/dartclub/turf_dart/blob/main/lib/src/meta/feature.dart) -- [x] [flattenEach](https://github.com/dartclub/turf_dart/blob/main/lib/src/meta/flatten.dart) -- [x] [flattenReduce](https://github.com/dartclub/turf_dart/blob/main/lib/src/meta/flatten.dart) -- [x] [geomEach](https://github.com/dartclub/turf_dart/blob/main/lib/src/meta/geom.dart) -- [x] [geomReduce](https://github.com/dartclub/turf_dart/blob/main/lib/src/meta/geom.dart) -- [x] [propEach](https://github.com/dartclub/turf_dart/blob/main/lib/src/meta/prop.dart) -- [x] [propReduce](https://github.com/dartclub/turf_dart/blob/main/lib/src/meta/prop.dart) -- [x] [segmentEach](https://github.com/dartclub/turf_dart/blob/main/lib/src/line_segment.dart) -- [x] [segmentReduce](https://github.com/dartclub/turf_dart/blob/main/lib/src/line_segment.dart) -- [x] [getCluster](https://github.com/dartclub/turf_dart/blob/main/lib/src/meta/cluster.dart) -- [x] [clusterEach](https://github.com/dartclub/turf_dart/blob/main/lib/src/meta/cluster.dart) -- [x] [clusterReduce](https://github.com/dartclub/turf_dart/blob/main/lib/src/meta/cluster.dart) - -### Invariants - -- [x] [getCoord](https://github.com/dartclub/turf_dart/blob/main/lib/src/meta/coord.dart) -- [x] [getCoords](https://github.com/dartclub/turf_dart/blob/main/lib/src/invariant.dart) -- [x] [getGeom](https://github.com/dartclub/turf_dart/blob/main/lib/src/invariant.dart) - -### Booleans - -- [x] [booleanClockwise](https://github.com/dartclub/turf_dart/blob/main/lib/src/booleans/boolean_clockwise.dart) -- [x] [booleanConcave](https://github.com/dartclub/turf_dart/blob/main/lib/src/booleans/boolean_concave.dart) -- [x] [booleanContains](https://github.com/dartclub/turf_dart/blob/main/lib/src/booleans/boolean_contains.dart) -- [x] [booleanCrosses](https://github.com/dartclub/turf_dart/blob/main/lib/src/booleans/boolean_crosses.dart) -- [x] [booleanDisjoint](https://github.com/dartclub/turf_dart/blob/main/lib/src/booleans/boolean_disjoint.dart) -- [x] [booleanEqual](https://github.com/dartclub/turf_dart/blob/main/lib/src/booleans/boolean_equal.dart) -- [x] [booleanIntersects](https://github.com/dartclub/turf_dart/blob/main/lib/src/booleans/boolean_intersects.dart) -- [x] [booleanOverlap](https://github.com/dartclub/turf_dart/blob/main/lib/src/booleans/boolean_overlap.dart) -- [x] [booleanParallel](https://github.com/dartclub/turf_dart/blob/main/lib/src/booleans/boolean_parallel.dart) -- [x] [booleanPointInPolygon](https://github.com/dartclub/turf_dart/blob/main/lib/src/booleans/boolean_point_in_polygon.dart) -- [x] [booleanPointOnLine](https://github.com/dartclub/turf_dart/blob/main/lib/src/booleans/boolean_point_on_line.dart) -- [x] [booleanWithin](https://github.com/dartclub/turf_dart/blob/main/lib/src/booleans/boolean_within.dart) - -### Unit Conversion - -- [x] [bearingToAzimuth](https://github.com/dartclub/turf_dart/blob/main/lib/src/helpers.dart) -- [x] [convertArea](https://github.com/dartclub/turf_dart/blob/main/lib/src/helpers.dart) -- [x] [convertLength](https://github.com/dartclub/turf_dart/blob/main/lib/src/helpers.dart) -- [x] [degreesToRadians](https://github.com/dartclub/turf_dart/blob/main/lib/src/helpers.dart) -- [x] [lengthToRadians](https://github.com/dartclub/turf_dart/blob/main/lib/src/helpers.dart) -- [x] [lengthToDegrees](https://github.com/dartclub/turf_dart/blob/main/lib/src/helpers.dart) -- [x] [radiansToLength](https://github.com/dartclub/turf_dart/blob/main/lib/src/helpers.dart) -- [x] [radiansToDegrees](https://github.com/dartclub/turf_dart/blob/main/lib/src/helpers.dart) -- [ ] toMercator -- [ ] toWgs84