@@ -149,11 +149,57 @@ function geojsonToOsmGeometry(
149149 return [ relation ] ;
150150 }
151151
152- // TODO: support other geometries
152+ // this logic is based on what RapiD uses:
153+ // https://github.com/facebookincubator/Rapid/blob/8a58b2/modules/services/esri_data.js#L103-L134
153154 case 'Polygon' :
154155 case 'MultiPolygon' : {
155- return undefined ;
156+ const nodes : OsmNode [ ] = [ ] ;
157+ const ways : { way : OsmWay ; role : string } [ ] = [ ] ;
158+
159+ const groups =
160+ geom . type === 'Polygon' ? [ geom . coordinates ] : geom . coordinates ;
161+
162+ for ( const rings of groups ) {
163+ for ( const [ index , ring ] of rings . entries ( ) ) {
164+ const ringNodes = ring . map ( coordToNode ) ;
165+ if ( ringNodes . length < 3 ) return [ ] ;
166+
167+ const first = ringNodes [ 0 ] ;
168+ const last = ringNodes . at ( - 1 ) ;
169+ if ( first !== last ) ringNodes . push ( first ) ; // sanity check, ensure rings are closed
170+
171+ const way : OsmWay = {
172+ ...TEMPLATE_OSM_FEATURE ,
173+ type : 'way' ,
174+ id : nextId . way -- ,
175+ nodes : ringNodes . map ( ( n ) => n . id ) ,
176+ } ;
177+ nodes . push ( ...ringNodes ) ;
178+ ways . push ( { way, role : index === 0 ? 'outer' : 'inner' } ) ;
179+ }
180+
181+ if ( groups . length === 1 && rings . length === 1 ) {
182+ // special case: only 1 ring, so we don't need a multipolygon,
183+ // we can just create a simple way and abort early.
184+ const way : OsmWay = { ...baseFeature , ...ways [ 0 ] . way } ;
185+ return [ way , ...nodes ] ;
186+ }
187+ }
188+
189+ const relation : OsmRelation = {
190+ ...baseFeature ,
191+ tags : { type : 'multipolygon' , ...baseFeature . tags } ,
192+ type : 'relation' ,
193+ id : nextId . relation -- ,
194+ members : ways . map ( ( { way, role } ) => ( {
195+ type : 'way' ,
196+ ref : way . id ,
197+ role,
198+ } ) ) ,
199+ } ;
200+ return [ relation , ...ways . map ( ( w ) => w . way ) , ...nodes ] ;
156201 }
202+
157203 default : {
158204 return undefined ;
159205 }
0 commit comments