From 1cf31443848853149c16254b6ba23807527df04a Mon Sep 17 00:00:00 2001 From: xiaogu Date: Tue, 26 Jul 2022 15:59:09 +0800 Subject: [PATCH 1/2] update geojson IsValid judgment method --- example/data/geojson.json | 19 ++++- example/data/multiPolygon0.geojson | 84 ++++++++++++++++++++ example/data/multiPolygon1.geojson | 40 ++++++++++ example/data/multiPolygon2.geojson | 41 ++++++++++ example/data/multiPolygon3.geojson | 40 ++++++++++ geoencoding/encoding_test.go | 93 ++++++++++++++++++++++- geoencoding/geojson/feature_collection.go | 21 ++++- 7 files changed, 331 insertions(+), 7 deletions(-) create mode 100644 example/data/multiPolygon0.geojson create mode 100644 example/data/multiPolygon1.geojson create mode 100644 example/data/multiPolygon2.geojson create mode 100644 example/data/multiPolygon3.geojson diff --git a/example/data/geojson.json b/example/data/geojson.json index 2499b70..124962c 100644 --- a/example/data/geojson.json +++ b/example/data/geojson.json @@ -1 +1,18 @@ -{"type":"FeatureCollection","features":[{"type":"Feature","geometry":{"type":"Point","coordinates":[102,0.5]},"properties":{"prop0":"value0"}}]} \ No newline at end of file +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "geometry": { + "type": "Point", + "coordinates": [ + 102, + 0.5 + ] + }, + "properties": { + "prop0": "value0" + } + } + ] +} \ No newline at end of file diff --git a/example/data/multiPolygon0.geojson b/example/data/multiPolygon0.geojson new file mode 100644 index 0000000..cc5778a --- /dev/null +++ b/example/data/multiPolygon0.geojson @@ -0,0 +1,84 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "geometry": { + "type": "MultiPolygon", + "coordinates": [ + [ + [ + [ + -47.900390625, + -14.944784875088372 + ], + [ + -51.591796875, + -19.91138351415555 + ], + [ + -41.11083984375, + -21.309846141087192 + ], + [ + -43.39599609375, + -15.390135715305204 + ], + [ + -47.900390625, + -14.944784875088372 + ] + ], + [ + [ + -46.6259765625, + -17.14079039331664 + ], + [ + -47.548828125, + -16.804541076383455 + ], + [ + -46.23046874999999, + -16.699340234594537 + ], + [ + -45.3515625, + -19.31114335506464 + ], + [ + -46.6259765625, + -17.14079039331664 + ] + ], + [ + [ + -44.40673828125, + -18.375379094031825 + ], + [ + -44.4287109375, + -20.097206227083888 + ], + [ + -42.9345703125, + -18.979025953255267 + ], + [ + -43.52783203125, + -17.602139123350838 + ], + [ + -44.40673828125, + -18.375379094031825 + ] + ] + ] + ] + }, + "properties": { + "prop0": "value0" + } + } + ] +} \ No newline at end of file diff --git a/example/data/multiPolygon1.geojson b/example/data/multiPolygon1.geojson new file mode 100644 index 0000000..1e226c0 --- /dev/null +++ b/example/data/multiPolygon1.geojson @@ -0,0 +1,40 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "geometry": { + "type": "MultiPolygon", + "coordinates": [ + [ + [ + [ + -47.900390625, + -14.944784875088372 + ], + [ + -51.591796875, + -19.91138351415555 + ], + [ + -41.11083984375, + -21.309846141087192 + ], + [ + -43.39599609375, + -15.390135715305204 + ], + [ + -47.900390625, + -14.944784875088372 + ] + ] + ] + ] + }, + "properties": { + "prop0": "value0" + } + } + ] +} \ No newline at end of file diff --git a/example/data/multiPolygon2.geojson b/example/data/multiPolygon2.geojson new file mode 100644 index 0000000..5a05e62 --- /dev/null +++ b/example/data/multiPolygon2.geojson @@ -0,0 +1,41 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "_id": "pwBn4x", + "type": "Feature", + "geometry": { + "type": "MultiPolygon", + "coordinates": [ + [ + [ + [ + -48.368811019, + -23.906519878 + ], + [ + -51.58525, + -19.90553 + ], + [ + -41.1044, + -21.30375 + ], + [ + -43.38951, + -15.38404 + ], + [ + -48.368811019, + -23.906519878 + ] + ] + ] + ] + }, + "properties": { + "prop0": "value0" + } + } + ] +} \ No newline at end of file diff --git a/example/data/multiPolygon3.geojson b/example/data/multiPolygon3.geojson new file mode 100644 index 0000000..d763b91 --- /dev/null +++ b/example/data/multiPolygon3.geojson @@ -0,0 +1,40 @@ +{"type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "geometry": { + "type": "MultiPolygon", + "coordinates": [ + [ + + [ + 113.25094290192146, + 22.420572852340314 + ], + [ + 113.19425990189126, + 22.467313981848253 + ], + [ + 113.19322990256966, + 22.469693937260413 + ], + [ + 113.19803690263932, + 22.471279907877356 + ], + [ + 113.20524690238221, + 22.46715598456933 + ], + [ + 113.25094290192146, + 22.420572852340314 + ] + + ] + ] + } + } + ] + } \ No newline at end of file diff --git a/geoencoding/encoding_test.go b/geoencoding/encoding_test.go index 44717d5..735df74 100644 --- a/geoencoding/encoding_test.go +++ b/geoencoding/encoding_test.go @@ -223,7 +223,7 @@ func TestReadGeoJSON(t *testing.T) { "type": "MultiPolygon", "coordinates": [ [ - + [ 113.25094290192146, 22.420572852340314 @@ -248,7 +248,7 @@ func TestReadGeoJSON(t *testing.T) { 113.25094290192146, 22.420572852340314 ] - + ] ] } @@ -258,6 +258,91 @@ func TestReadGeoJSON(t *testing.T) { want: nil, wantErr: true, }, + {name: "geojson string", args: args{ + []byte(`{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "geometry": { + "type": "MultiPolygon", + "coordinates": [ + [ + [ + [ + -47.900390625, + -14.944784875088372 + ], + [ + -51.591796875, + -19.91138351415555 + ], + [ + -41.11083984375, + -21.309846141087192 + ], + [ + -43.39599609375, + -15.390135715305204 + ] + ] + ] + ] + }, + "properties": { + "prop0": "value0" + } + } + ] + }`), GeoJSON}, + want: nil, + wantErr: false, + }, + {name: "geojson string", args: args{ + []byte(`{ + "type": "FeatureCollection", + "features": [ + { + "_id": "pwBn4x", + "type": "Feature", + "geometry": { + "type": "MultiPolygon", + "coordinates": [ + [ + [ + [ + -48.368811019, + -23.906519878 + ], + [ + -51.58525, + -19.90553 + ], + [ + -41.1044, + -21.30375 + ], + [ + -43.38951, + -15.38404 + ], + [ + -48.368811019, + -23.906519878 + ] + ] + ] + ] + }, + "properties": { + "prop0": "value0" + } + } + ] + }`), GeoJSON}, + want: nil, + wantErr: false, + }, {name: "geojson string", args: args{ []byte(`{"type": "FeatureCollection", "features": [ @@ -267,7 +352,7 @@ func TestReadGeoJSON(t *testing.T) { "type": "Polygon", "coordinates": [ [ - + [ 113.25094290192146, 22.420572852340314 @@ -288,7 +373,7 @@ func TestReadGeoJSON(t *testing.T) { 113.20524690238221, 22.46715598456933 ] - + ] ] } diff --git a/geoencoding/geojson/feature_collection.go b/geoencoding/geojson/feature_collection.go index 31af567..c321e98 100644 --- a/geoencoding/geojson/feature_collection.go +++ b/geoencoding/geojson/feature_collection.go @@ -79,16 +79,33 @@ func UnmarshalFeatureCollection(data []byte) (*FeatureCollection, error) { if !space.Ring(ring).IsClosed() { poly[i] = append(ring, ring[0]) } - + } + } else if mult, ok := v.Geometry.Geometry().(space.MultiPolygon); ok { + for _, poly := range mult { + for i, ring := range poly { + if !space.Ring(ring).IsClosed() { + poly[i] = append(ring, ring[0]) + } + } } } + if !v.Geometry.Geometry().IsValid() { if v.Geometry.Geometry().GeoJSONType() == space.TypePolygon { v.Geometry.Coordinates = space.TransGeometry( operation.CorrectPolygonMatrixSelfIntersect( v.Geometry.Geometry().(space.Polygon).ToMatrix())) + } else if v.Geometry.Geometry().GeoJSONType() == space.TypeMultiPolygon { + mult := v.Geometry.Geometry().(space.MultiPolygon) + for _, poly := range mult { + if len(poly[0][0]) == 0 { + return nil, ErrInvalidGeometry + } + v.Geometry.Coordinates = space.TransGeometry( + operation.CorrectPolygonMatrixSelfIntersect(poly.ToMatrix())) + } } - return nil, ErrInvalidGeometry + // return nil, ErrInvalidGeometry } } From 10c000460959fdc37d551e6f6c9e695f785d1592 Mon Sep 17 00:00:00 2001 From: xiaogu Date: Wed, 27 Jul 2022 13:47:05 +0800 Subject: [PATCH 2/2] add check geometry struct func 'IsCorrect' --- example/data/multiPolygon0.geojson | 84 ----------------------- example/data/multiPolygon1.geojson | 40 ----------- example/data/multiPolygon2.geojson | 41 ----------- example/data/multiPolygon3.geojson | 40 ----------- geoencoding/geojson/feature_collection.go | 26 +++---- space/bound.go | 5 ++ space/collection.go | 10 +++ space/geometry.go | 3 + space/line_string.go | 13 ++++ space/multi_line_string.go | 10 +++ space/multi_point.go | 10 +++ space/multi_polygon.go | 10 +++ space/point.go | 5 ++ space/polygon.go | 13 ++++ space/ring.go | 7 +- 15 files changed, 98 insertions(+), 219 deletions(-) delete mode 100644 example/data/multiPolygon0.geojson delete mode 100644 example/data/multiPolygon1.geojson delete mode 100644 example/data/multiPolygon2.geojson delete mode 100644 example/data/multiPolygon3.geojson diff --git a/example/data/multiPolygon0.geojson b/example/data/multiPolygon0.geojson deleted file mode 100644 index cc5778a..0000000 --- a/example/data/multiPolygon0.geojson +++ /dev/null @@ -1,84 +0,0 @@ -{ - "type": "FeatureCollection", - "features": [ - { - "type": "Feature", - "geometry": { - "type": "MultiPolygon", - "coordinates": [ - [ - [ - [ - -47.900390625, - -14.944784875088372 - ], - [ - -51.591796875, - -19.91138351415555 - ], - [ - -41.11083984375, - -21.309846141087192 - ], - [ - -43.39599609375, - -15.390135715305204 - ], - [ - -47.900390625, - -14.944784875088372 - ] - ], - [ - [ - -46.6259765625, - -17.14079039331664 - ], - [ - -47.548828125, - -16.804541076383455 - ], - [ - -46.23046874999999, - -16.699340234594537 - ], - [ - -45.3515625, - -19.31114335506464 - ], - [ - -46.6259765625, - -17.14079039331664 - ] - ], - [ - [ - -44.40673828125, - -18.375379094031825 - ], - [ - -44.4287109375, - -20.097206227083888 - ], - [ - -42.9345703125, - -18.979025953255267 - ], - [ - -43.52783203125, - -17.602139123350838 - ], - [ - -44.40673828125, - -18.375379094031825 - ] - ] - ] - ] - }, - "properties": { - "prop0": "value0" - } - } - ] -} \ No newline at end of file diff --git a/example/data/multiPolygon1.geojson b/example/data/multiPolygon1.geojson deleted file mode 100644 index 1e226c0..0000000 --- a/example/data/multiPolygon1.geojson +++ /dev/null @@ -1,40 +0,0 @@ -{ - "type": "FeatureCollection", - "features": [ - { - "type": "Feature", - "geometry": { - "type": "MultiPolygon", - "coordinates": [ - [ - [ - [ - -47.900390625, - -14.944784875088372 - ], - [ - -51.591796875, - -19.91138351415555 - ], - [ - -41.11083984375, - -21.309846141087192 - ], - [ - -43.39599609375, - -15.390135715305204 - ], - [ - -47.900390625, - -14.944784875088372 - ] - ] - ] - ] - }, - "properties": { - "prop0": "value0" - } - } - ] -} \ No newline at end of file diff --git a/example/data/multiPolygon2.geojson b/example/data/multiPolygon2.geojson deleted file mode 100644 index 5a05e62..0000000 --- a/example/data/multiPolygon2.geojson +++ /dev/null @@ -1,41 +0,0 @@ -{ - "type": "FeatureCollection", - "features": [ - { - "_id": "pwBn4x", - "type": "Feature", - "geometry": { - "type": "MultiPolygon", - "coordinates": [ - [ - [ - [ - -48.368811019, - -23.906519878 - ], - [ - -51.58525, - -19.90553 - ], - [ - -41.1044, - -21.30375 - ], - [ - -43.38951, - -15.38404 - ], - [ - -48.368811019, - -23.906519878 - ] - ] - ] - ] - }, - "properties": { - "prop0": "value0" - } - } - ] -} \ No newline at end of file diff --git a/example/data/multiPolygon3.geojson b/example/data/multiPolygon3.geojson deleted file mode 100644 index d763b91..0000000 --- a/example/data/multiPolygon3.geojson +++ /dev/null @@ -1,40 +0,0 @@ -{"type": "FeatureCollection", - "features": [ - { - "type": "Feature", - "geometry": { - "type": "MultiPolygon", - "coordinates": [ - [ - - [ - 113.25094290192146, - 22.420572852340314 - ], - [ - 113.19425990189126, - 22.467313981848253 - ], - [ - 113.19322990256966, - 22.469693937260413 - ], - [ - 113.19803690263932, - 22.471279907877356 - ], - [ - 113.20524690238221, - 22.46715598456933 - ], - [ - 113.25094290192146, - 22.420572852340314 - ] - - ] - ] - } - } - ] - } \ No newline at end of file diff --git a/geoencoding/geojson/feature_collection.go b/geoencoding/geojson/feature_collection.go index c321e98..73c84bf 100644 --- a/geoencoding/geojson/feature_collection.go +++ b/geoencoding/geojson/feature_collection.go @@ -90,22 +90,22 @@ func UnmarshalFeatureCollection(data []byte) (*FeatureCollection, error) { } } - if !v.Geometry.Geometry().IsValid() { - if v.Geometry.Geometry().GeoJSONType() == space.TypePolygon { - v.Geometry.Coordinates = space.TransGeometry( - operation.CorrectPolygonMatrixSelfIntersect( - v.Geometry.Geometry().(space.Polygon).ToMatrix())) - } else if v.Geometry.Geometry().GeoJSONType() == space.TypeMultiPolygon { - mult := v.Geometry.Geometry().(space.MultiPolygon) - for _, poly := range mult { - if len(poly[0][0]) == 0 { - return nil, ErrInvalidGeometry - } + if v.Geometry.Geometry().IsCorrect() { + if !v.Geometry.Geometry().IsValid() { + if v.Geometry.Geometry().GeoJSONType() == space.TypePolygon { v.Geometry.Coordinates = space.TransGeometry( - operation.CorrectPolygonMatrixSelfIntersect(poly.ToMatrix())) + operation.CorrectPolygonMatrixSelfIntersect( + v.Geometry.Geometry().(space.Polygon).ToMatrix())) + } else if v.Geometry.Geometry().GeoJSONType() == space.TypeMultiPolygon { + mult := v.Geometry.Geometry().(space.MultiPolygon) + for _, poly := range mult { + v.Geometry.Coordinates = space.TransGeometry( + operation.CorrectPolygonMatrixSelfIntersect(poly.ToMatrix())) + } } } - // return nil, ErrInvalidGeometry + } else { + return nil, ErrInvalidGeometry } } diff --git a/space/bound.go b/space/bound.go index bc06034..3bd253a 100644 --- a/space/bound.go +++ b/space/bound.go @@ -303,6 +303,11 @@ func (b Bound) IsValid() bool { return b.Min.IsValid() && b.Max.IsValid() } +// IsCorrect returns true if the geometry struct is Correct. +func (b Bound) IsCorrect() bool { + return b.Min.IsCorrect() && b.Max.IsCorrect() +} + // CoordinateSystem return Coordinate System. func (b Bound) CoordinateSystem() int { return defaultCoordinateSystem() diff --git a/space/collection.go b/space/collection.go index b18b316..379808d 100644 --- a/space/collection.go +++ b/space/collection.go @@ -290,6 +290,16 @@ func (c Collection) IsValid() bool { return true } +// IsCorrect returns true if the geometry struct is Correct. +func (c Collection) IsCorrect() bool { + for _, v := range c { + if !v.IsCorrect() { + return false + } + } + return true +} + // CoordinateSystem return Coordinate System. func (c Collection) CoordinateSystem() int { return defaultCoordinateSystem() diff --git a/space/geometry.go b/space/geometry.go index 2e05a02..4db6d4a 100644 --- a/space/geometry.go +++ b/space/geometry.go @@ -103,6 +103,9 @@ type Geometry interface { // IsValid returns true if the geometry is valid. IsValid() bool + // IsCorrect returns true if the geometry struct is Correct. + IsCorrect() bool + // Length Returns the length of this geometry Length() float64 diff --git a/space/line_string.go b/space/line_string.go index 06feea3..98bc0e0 100644 --- a/space/line_string.go +++ b/space/line_string.go @@ -254,6 +254,19 @@ func (ls LineString) IsValid() bool { return true } +// IsCorrect returns true if the geometry struct is Correct. +func (ls LineString) IsCorrect() bool { + if ls.IsEmpty() { + return false + } + for _, v := range ls { + if !Point(v).IsCorrect() { + return false + } + } + return true +} + // CoordinateSystem return Coordinate System. func (ls LineString) CoordinateSystem() int { return defaultCoordinateSystem() diff --git a/space/multi_line_string.go b/space/multi_line_string.go index 95700d6..0f9fb4f 100644 --- a/space/multi_line_string.go +++ b/space/multi_line_string.go @@ -262,6 +262,16 @@ func (mls MultiLineString) IsValid() bool { return true } +// IsCorrect returns true if the geometry struct is Correct. +func (mls MultiLineString) IsCorrect() bool { + for _, v := range mls { + if !v.IsCorrect() { + return false + } + } + return true +} + // CoordinateSystem return Coordinate System. func (mls MultiLineString) CoordinateSystem() int { return defaultCoordinateSystem() diff --git a/space/multi_point.go b/space/multi_point.go index bb73e26..04a0878 100644 --- a/space/multi_point.go +++ b/space/multi_point.go @@ -225,6 +225,16 @@ func (mp MultiPoint) IsValid() bool { return true } +// IsCorrect returns true if the geometry struct is Correct. +func (mp MultiPoint) IsCorrect() bool { + for _, v := range mp { + if !v.IsCorrect() { + return false + } + } + return true +} + // CoordinateSystem return Coordinate System. func (mp MultiPoint) CoordinateSystem() int { return defaultCoordinateSystem() diff --git a/space/multi_polygon.go b/space/multi_polygon.go index 2fcde9b..02e5ddf 100644 --- a/space/multi_polygon.go +++ b/space/multi_polygon.go @@ -244,6 +244,16 @@ func (mp MultiPolygon) IsValid() bool { return true } +// IsCorrect returns true if the geometry struct is Correct. +func (mp MultiPolygon) IsCorrect() bool { + for _, v := range mp { + if !v.IsCorrect() { + return false + } + } + return true +} + // CoordinateSystem return Coordinate System. func (mp MultiPolygon) CoordinateSystem() int { return defaultCoordinateSystem() diff --git a/space/point.go b/space/point.go index e9dd5c7..0d72fae 100644 --- a/space/point.go +++ b/space/point.go @@ -222,6 +222,11 @@ func (p Point) IsRing() bool { // IsValid returns true if the geometry is valid. func (p Point) IsValid() bool { + return p.IsCorrect() +} + +// IsCorrect returns true if the geometry struct is Correct. +func (p Point) IsCorrect() bool { return len(p) >= 2 } diff --git a/space/polygon.go b/space/polygon.go index 045b76e..0cd647a 100644 --- a/space/polygon.go +++ b/space/polygon.go @@ -301,6 +301,19 @@ func (p Polygon) IsValid() bool { return true } +// IsCorrect returns true if the geometry struct is Correct. +func (p Polygon) IsCorrect() bool { + if p.IsEmpty() { + return false + } + for _, v := range p { + if !Ring(v).IsCorrect() { + return false + } + } + return true +} + // CoordinateSystem return Coordinate System. func (p Polygon) CoordinateSystem() int { return defaultCoordinateSystem() diff --git a/space/ring.go b/space/ring.go index 7775f26..c12ebca 100644 --- a/space/ring.go +++ b/space/ring.go @@ -177,11 +177,16 @@ func (r Ring) IsRing() bool { return LineString(r).IsRing() } -// IsValid returns true if the geometry is valid. +// IsValid returns true if the geometry is valid. func (r Ring) IsValid() bool { return LineString(r).IsValid() && (!r.IsEmpty()) && r.IsRing() } +// IsCorrect returns true if the geometry struct is Correct. +func (r Ring) IsCorrect() bool { + return LineString(r).IsCorrect() && (!r.IsEmpty()) +} + // CoordinateSystem return Coordinate System. func (r Ring) CoordinateSystem() int { return defaultCoordinateSystem()