@@ -10,6 +10,7 @@ class BuildingShapeUtils extends ShapeUtils {
1010 *
1111 * @param {DOM.Element } way - OSM XML way element.
1212 * @param {[number, number] } nodelist - list of all nodes
13+ * @param augmentedNodelist - list of nodes outside bbox
1314 *
1415 * @return {THREE.Shape } shape - the shape
1516 */
@@ -82,62 +83,82 @@ class BuildingShapeUtils extends ShapeUtils {
8283 */
8384 static combineWays ( ways ) {
8485 const closedWays = [ ] ;
85- let openWays = [ ] ;
86- let changed = true ;
87- let watchDogCounter = 0
88- while ( changed ) {
89- if ( watchDogCounter ++ > 2_000_000 ) {
90- throw 'Infinite loop in combineWays' ;
86+ const wayBegins = { } ;
87+ const wayEnds = { } ;
88+
89+ ways . forEach ( w => {
90+ const firstNodeID = w . querySelector ( 'nd' ) . getAttribute ( 'ref' ) ;
91+ if ( wayBegins [ firstNodeID ] ) {
92+ wayBegins [ firstNodeID ] . push ( w ) ;
93+ } else {
94+ wayBegins [ firstNodeID ] = [ w ] ;
95+ }
96+
97+ const lastNodeID = w . querySelector ( 'nd:last-of-type' ) . getAttribute ( 'ref' ) ;
98+ if ( wayEnds [ lastNodeID ] ) {
99+ wayEnds [ lastNodeID ] . push ( w ) ;
100+ } else {
101+ wayEnds [ lastNodeID ] = [ w ] ;
91102 }
92- changed = false ;
93- for ( let i = 0 ; i < ways . length - 1 ; i ++ ) {
94- if ( BuildingShapeUtils . isClosed ( ways [ i ] ) ) {
95- closedWays . push ( ways [ i ] ) ;
96- } else {
97- // These are HTMLCollections of nodes, not ways.
98- const way1 = ways [ i ] . getElementsByTagName ( 'nd' ) ;
99- const way2 = ways [ i + 1 ] . getElementsByTagName ( 'nd' ) ;
103+ } ) ;
100104
101- // If the first node of way2 is the same as the last in way one, they can be combined
102- // Or if the first node of way1 is the same as the last in way2
103- // Need to extend this to tip-to-tip connections as well.
104- // Need to add a "reverse way" function somewhere.
105- if ( way2 [ 0 ] . getAttribute ( 'ref' ) === way1 [ way1 . length - 1 ] . getAttribute ( 'ref' ) ) {
106- const result = BuildingShapeUtils . joinWays ( ways [ i ] , ways [ i + 1 ] ) ;
107- openWays . push ( result ) ;
108- i ++ ;
109- changed = true ;
110- } else if ( way1 [ 0 ] . getAttribute ( 'ref' ) === way2 [ way2 . length - 1 ] . getAttribute ( 'ref' ) ) {
111- const result = BuildingShapeUtils . joinWays ( ways [ i + 1 ] , ways [ i ] ) ;
112- openWays . push ( result ) ;
113- i ++ ;
114- changed = true ;
115- } else if ( way1 [ way1 . length - 1 ] . getAttribute ( 'ref' ) === way2 [ way2 . length - 1 ] . getAttribute ( 'ref' ) ) {
116- const tempway = BuildingShapeUtils . reverseWay ( ways [ i + 1 ] ) ;
117- const result = BuildingShapeUtils . joinWays ( ways [ i ] , tempway ) ;
118- openWays . push ( result ) ;
119- i ++ ;
120- changed = true ;
121- } else if ( way1 [ 0 ] . getAttribute ( 'ref' ) === way2 [ 0 ] . getAttribute ( 'ref' ) ) {
122- const tempway = BuildingShapeUtils . reverseWay ( ways [ i + 1 ] ) ;
123- const result = BuildingShapeUtils . joinWays ( tempway , ways [ i ] ) ;
124- openWays . push ( result ) ;
125- i ++ ;
126- changed = true ;
127- } else {
128- openWays . push ( ways [ i ] ) ;
129- }
105+ const usedWays = new Set ( ) ;
106+
107+ function tryMakeRing ( currentRingWays ) {
108+ if ( currentRingWays [ 0 ] . querySelector ( 'nd' ) . getAttribute ( 'ref' ) ===
109+ currentRingWays [ currentRingWays . length - 1 ] . querySelector ( 'nd:last-of-type' ) . getAttribute ( 'ref' ) ) {
110+ return currentRingWays ;
111+ }
112+
113+ const lastWay = currentRingWays [ currentRingWays . length - 1 ] ;
114+ const lastNodeID = lastWay . querySelector ( 'nd:last-of-type' ) . getAttribute ( 'ref' ) ;
115+ for ( let way of wayBegins [ lastNodeID ] ?? [ ] ) {
116+ const wayID = way . getAttribute ( 'id' ) ;
117+ if ( usedWays . has ( wayID ) ) {
118+ continue ;
119+ }
120+ usedWays . add ( wayID ) ;
121+ currentRingWays . push ( way ) ;
122+ if ( tryMakeRing ( currentRingWays ) . length ) {
123+ return currentRingWays ;
130124 }
125+ currentRingWays . pop ( ) ;
126+ usedWays . delete ( wayID ) ;
131127 }
132- const lastWay = ways [ ways . length - 1 ] ;
133- if ( BuildingShapeUtils . isClosed ( lastWay ) ) {
134- closedWays . push ( lastWay ) ;
135- } else {
136- openWays . push ( lastWay ) ;
128+
129+ for ( let way of wayEnds [ lastNodeID ] ?? [ ] ) {
130+ const wayID = way . getAttribute ( 'id' ) ;
131+ if ( usedWays . has ( wayID ) ) {
132+ continue ;
133+ }
134+ usedWays . add ( wayID ) ;
135+ currentRingWays . push ( BuildingShapeUtils . reverseWay ( way ) ) ;
136+ if ( tryMakeRing ( currentRingWays ) . length ) {
137+ return currentRingWays ;
138+ }
139+ currentRingWays . pop ( ) ;
140+ usedWays . delete ( wayID ) ;
137141 }
138- ways = openWays ;
139- openWays = [ ] ;
142+
143+ return [ ] ;
140144 }
145+
146+ ways . forEach ( w => {
147+ const wayID = w . getAttribute ( 'ref' ) ;
148+ if ( usedWays . has ( wayID ) ) {
149+ return ;
150+ }
151+ usedWays . add ( wayID ) ;
152+ const result = tryMakeRing ( [ w ] ) ;
153+ if ( result . length ) {
154+ let ring = result [ 0 ] ;
155+ result . slice ( 1 ) . forEach ( w => {
156+ ring = this . joinWays ( ring , w ) ;
157+ } ) ;
158+ closedWays . push ( ring ) ;
159+ }
160+ } ) ;
161+
141162 return closedWays ;
142163 }
143164
0 commit comments