-
Notifications
You must be signed in to change notification settings - Fork 944
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Support Null geometries #866
Changes from 2 commits
e6b4004
25ca919
11fb27a
dc07802
060df66
2b4fb44
d972c1f
42f837c
9f1ba47
72f2191
d653e8f
70ff401
8fbee2f
e1714d9
b2a99a5
c1edd39
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -208,3 +208,17 @@ test('invariant#getGeomType', t => { | |
t.throws(() => invariant.getGeomType(collection, 'featureCollection not valid')); | ||
t.end(); | ||
}); | ||
|
||
// https://github.com/Turfjs/turf/issues/853 | ||
test('null geometries', t => { | ||
const nullFeature = { | ||
type: 'Feature', | ||
properties: {}, | ||
geometry: null | ||
} | ||
t.equal(invariant.getGeom(null), null); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @DenisCarriere why supporting |
||
t.equal(invariant.getGeomType(null), null); | ||
t.equal(invariant.getGeom(nullFeature), null); | ||
t.equal(invariant.getGeomType(nullFeature), null); | ||
t.end(); | ||
}); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
import {point, lineString, polygon, geometryCollection, featureCollection} from '@turf/helpers' | ||
import * as invariant from './' | ||
|
||
const pt = point([0, 0]) | ||
const line = lineString([[0, 0], [1, 1]]) | ||
const poly = polygon([[[0, 0], [1, 1], [2, 2], [0, 0]]]) | ||
const gc = geometryCollection([pt.geometry, line.geometry, poly.geometry]) | ||
const fc = featureCollection([pt, line, poly]) | ||
|
||
/** | ||
* getGeomType | ||
*/ | ||
// invariant.getGeomType(fc) // Argument of type 'FeatureCollection<any>' is not assignable to parameter of type | ||
invariant.getGeomType(gc) | ||
invariant.getGeomType(pt) | ||
invariant.getGeomType(poly) | ||
invariant.getGeomType(line) | ||
invariant.getGeomType(pt.geometry) | ||
|
||
/** | ||
* getGeom | ||
*/ | ||
// invariant.getGeom(fc) // Argument of type 'FeatureCollection<any>' is not assignable to parameter of type | ||
invariant.getGeom(gc) | ||
invariant.getGeom(pt) | ||
invariant.getGeom(line) | ||
invariant.getGeom(poly) | ||
invariant.getGeom(pt.geometry) |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -48,64 +48,73 @@ function coordEach(geojson, callback, excludeWrapCoord) { | |
wrapShrink = 0, | ||
currentIndex = 0, | ||
isGeometryCollection, | ||
isFeatureCollection = geojson.type === 'FeatureCollection', | ||
isFeature = geojson.type === 'Feature', | ||
type = (geojson) ? geojson.type : null, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @DenisCarriere isn't geojson required here? I mean, shouldn't this actually throw an error if There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Well since a Maybe its' best to add the if (geojson === null) return; That way the rest of the code can remain unchanged. |
||
isFeatureCollection = type === 'FeatureCollection', | ||
isFeature = type === 'Feature', | ||
stop = isFeatureCollection ? geojson.features.length : 1; | ||
|
||
// This logic may look a little weird. The reason why it is that way | ||
// is because it's trying to be fast. GeoJSON supports multiple kinds | ||
// of objects at its root: FeatureCollection, Features, Geometries. | ||
// This function has the responsibility of handling all of them, and that | ||
// means that some of the `for` loops you see below actually just don't apply | ||
// to certain inputs. For instance, if you give this just a | ||
// Point geometry, then both loops are short-circuited and all we do | ||
// is gradually rename the input until it's called 'geometry'. | ||
// | ||
// This also aims to allocate as few resources as possible: just a | ||
// few numbers and booleans, rather than any temporary arrays as would | ||
// be required with the normalization approach. | ||
// This logic may look a little weird. The reason why it is that way | ||
// is because it's trying to be fast. GeoJSON supports multiple kinds | ||
// of objects at its root: FeatureCollection, Features, Geometries. | ||
// This function has the responsibility of handling all of them, and that | ||
// means that some of the `for` loops you see below actually just don't apply | ||
// to certain inputs. For instance, if you give this just a | ||
// Point geometry, then both loops are short-circuited and all we do | ||
// is gradually rename the input until it's called 'geometry'. | ||
// | ||
// This also aims to allocate as few resources as possible: just a | ||
// few numbers and booleans, rather than any temporary arrays as would | ||
// be required with the normalization approach. | ||
for (i = 0; i < stop; i++) { | ||
|
||
geometryMaybeCollection = (isFeatureCollection ? geojson.features[i].geometry : | ||
(isFeature ? geojson.geometry : geojson)); | ||
isGeometryCollection = geometryMaybeCollection.type === 'GeometryCollection'; | ||
isGeometryCollection = (geometryMaybeCollection) ? geometryMaybeCollection.type === 'GeometryCollection' : false; | ||
stopG = isGeometryCollection ? geometryMaybeCollection.geometries.length : 1; | ||
|
||
for (g = 0; g < stopG; g++) { | ||
geometry = isGeometryCollection ? | ||
geometryMaybeCollection.geometries[g] : geometryMaybeCollection; | ||
coords = geometry.coordinates; | ||
coords = (geometry === null) ? null : geometry.coordinates; | ||
var geomType = (geometry === null) ? null : geometry.type; | ||
|
||
wrapShrink = (excludeWrapCoord && | ||
(geometry.type === 'Polygon' || geometry.type === 'MultiPolygon')) ? | ||
1 : 0; | ||
wrapShrink = (excludeWrapCoord && (geomType === 'Polygon' || geomType === 'MultiPolygon')) ? 1 : 0; | ||
|
||
if (geometry.type === 'Point') { | ||
switch (geomType) { | ||
case null: | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @DenisCarriere same here, from the specs:
I guess the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This section is more internal and doesn't need to reflect the exact spec. Only way to iterate over a FeatureCollection (containing valid var geomType = (geometry === null) ? null : geometry.type;
switch (geomType) {
case null:
return; Simply breaks the loop and moves on to the next valid geometry. |
||
return; | ||
case 'Point': | ||
callback(coords, currentIndex); | ||
currentIndex++; | ||
} else if (geometry.type === 'LineString' || geometry.type === 'MultiPoint') { | ||
break; | ||
case 'LineString': | ||
case 'MultiPoint': | ||
for (j = 0; j < coords.length; j++) { | ||
callback(coords[j], currentIndex); | ||
currentIndex++; | ||
} | ||
} else if (geometry.type === 'Polygon' || geometry.type === 'MultiLineString') { | ||
break; | ||
case 'Polygon': | ||
case 'MultiLineString': | ||
for (j = 0; j < coords.length; j++) | ||
for (k = 0; k < coords[j].length - wrapShrink; k++) { | ||
callback(coords[j][k], currentIndex); | ||
currentIndex++; | ||
} | ||
} else if (geometry.type === 'MultiPolygon') { | ||
break; | ||
case 'MultiPolygon': | ||
for (j = 0; j < coords.length; j++) | ||
for (k = 0; k < coords[j].length; k++) | ||
for (l = 0; l < coords[j][k].length - wrapShrink; l++) { | ||
callback(coords[j][k][l], currentIndex); | ||
currentIndex++; | ||
} | ||
} else if (geometry.type === 'GeometryCollection') { | ||
break; | ||
case 'GeometryCollection': | ||
for (j = 0; j < geometry.geometries.length; j++) | ||
coordEach(geometry.geometries[j], callback, excludeWrapCoord); | ||
} else { | ||
throw new Error('Unknown Geometry Type'); | ||
break; | ||
default: throw new Error('Unknown Geometry Type'); | ||
} | ||
} | ||
} | ||
|
@@ -544,28 +553,33 @@ function geomEach(geojson, callback) { | |
(isFeature ? geojson.geometry : geojson)); | ||
geometryProperties = (isFeatureCollection ? geojson.features[i].properties : | ||
(isFeature ? geojson.properties : {})); | ||
isGeometryCollection = geometryMaybeCollection.type === 'GeometryCollection'; | ||
isGeometryCollection = (geometryMaybeCollection) ? geometryMaybeCollection.type === 'GeometryCollection' : false; | ||
stopG = isGeometryCollection ? geometryMaybeCollection.geometries.length : 1; | ||
|
||
for (g = 0; g < stopG; g++) { | ||
geometry = isGeometryCollection ? | ||
geometryMaybeCollection.geometries[g] : geometryMaybeCollection; | ||
|
||
if (geometry.type === 'Point' || | ||
geometry.type === 'LineString' || | ||
geometry.type === 'MultiPoint' || | ||
geometry.type === 'Polygon' || | ||
geometry.type === 'MultiLineString' || | ||
geometry.type === 'MultiPolygon') { | ||
var type = (geometry === null) ? null : geometry.type; | ||
switch (type) { | ||
case null: | ||
case 'Point': | ||
case 'LineString': | ||
case 'MultiPoint': | ||
case 'Polygon': | ||
case 'MultiLineString': | ||
case 'MultiPolygon': { | ||
callback(geometry, currentIndex, geometryProperties); | ||
currentIndex++; | ||
} else if (geometry.type === 'GeometryCollection') { | ||
break; | ||
} | ||
case 'GeometryCollection': { | ||
for (j = 0; j < geometry.geometries.length; j++) { | ||
callback(geometry.geometries[j], currentIndex, geometryProperties); | ||
currentIndex++; | ||
} | ||
} else { | ||
throw new Error('Unknown Geometry Type'); | ||
break; | ||
} | ||
default: throw new Error('Unknown Geometry Type'); | ||
} | ||
} | ||
} | ||
|
@@ -693,9 +707,11 @@ function geomReduce(geojson, callback, initialValue) { | |
*/ | ||
function flattenEach(geojson, callback) { | ||
geomEach(geojson, function (geometry, index, properties) { | ||
var type = (geometry === null) ? null : geometry.type; | ||
|
||
// Callback for single geometry | ||
switch (geometry.type) { | ||
switch (type) { | ||
case null: | ||
case 'Point': | ||
case 'LineString': | ||
case 'Polygon': | ||
|
@@ -706,7 +722,7 @@ function flattenEach(geojson, callback) { | |
var geomType; | ||
|
||
// Callback for multi-geometry | ||
switch (geometry.type) { | ||
switch (type) { | ||
case 'MultiPoint': | ||
geomType = 'Point'; | ||
break; | ||
|
@@ -813,7 +829,7 @@ function flattenReduce(geojson, callback, initialValue) { | |
* @returns {Feature} GeoJSON Feature | ||
*/ | ||
function feature(geometry, properties) { | ||
if (!geometry) throw new Error('No geometry passed'); | ||
if (geometry === undefined) throw new Error('No geometry passed'); | ||
|
||
return { | ||
type: 'Feature', | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@DenisCarriere just being very fussy here, but from specs geometryCollections can have an empty
geometries
array.But
(!geometries)
would exclude that, right?Same goes actually for FeatureCollection, which I'm noticing has the same check.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can add those in the tests, but
!geometries
would not exclude empty geometries inside, it would only excludegeometries: null
orundefined
.lets add them to the tests and see what happens from there :) lol
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(!geometries)
would not throw an error if you provide an empty Array.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added tests for this case: c1edd39
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ah! 👍 sorry, PHP confusion! 😄
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lol! Everything language has their quirks