@@ -81,59 +81,83 @@ class BuildingShapeUtils extends ShapeUtils {
8181 * @return {[DOM.Element] } array of closed ways.
8282 */
8383 static combineWays ( ways ) {
84- var closedWays = [ ] ;
85- var openWays = [ ] ;
86- var changed = true ;
87- while ( changed ) {
88- changed = false ;
89- for ( let i = 0 ; i < ways . length - 1 ; i ++ ) {
90- if ( BuildingShapeUtils . isClosed ( ways [ i ] ) ) {
91- closedWays . push ( ways [ i ] ) ;
92- } else {
93- // These are HTMLCollections of nodes, not ways.
94- const way1 = ways [ i ] . getElementsByTagName ( 'nd' ) ;
95- const way2 = ways [ i + 1 ] . getElementsByTagName ( 'nd' ) ;
96-
97- // If the first node of way2 is the same as the last in way one, they can be combined
98- // Or if the first node of way1 is the same as the last in way2
99- // Need to extend this to tip-to-tip connections as well.
100- // Need to add a "reverse way" function somewhere.
101- if ( way2 [ 0 ] . getAttribute ( 'ref' ) === way1 [ way1 . length - 1 ] . getAttribute ( 'ref' ) ) {
102- const result = BuildingShapeUtils . joinWays ( ways [ i ] , ways [ i + 1 ] ) ;
103- openWays . push ( result ) ;
104- i ++ ;
105- changed = true ;
106- } else if ( way1 [ 0 ] . getAttribute ( 'ref' ) === way2 [ way2 . length - 1 ] . getAttribute ( 'ref' ) ) {
107- const result = BuildingShapeUtils . joinWays ( ways [ i + 1 ] , ways [ i ] ) ;
108- openWays . push ( result ) ;
109- i ++ ;
110- changed = true ;
111- } else if ( way1 [ way1 . length - 1 ] . getAttribute ( 'ref' ) === way2 [ way2 . length - 1 ] . getAttribute ( 'ref' ) ) {
112- const tempway = BuildingShapeUtils . reverseWay ( ways [ i + 1 ] ) ;
113- const result = BuildingShapeUtils . joinWays ( ways [ i ] , tempway ) ;
114- openWays . push ( result ) ;
115- i ++ ;
116- changed = true ;
117- } else if ( way1 [ 0 ] . getAttribute ( 'ref' ) === way2 [ 0 ] . getAttribute ( 'ref' ) ) {
118- const tempway = BuildingShapeUtils . reverseWay ( ways [ i + 1 ] ) ;
119- const result = BuildingShapeUtils . joinWays ( tempway , ways [ i ] ) ;
120- openWays . push ( result ) ;
121- i ++ ;
122- changed = true ;
123- } else {
124- openWays . push ( ways [ i ] ) ;
125- }
126- }
84+ const closedWays = [ ] ;
85+ const wayBegins = { } ;
86+ const wayEnds = { } ;
87+
88+ ways . forEach ( w => {
89+ const firstNodeID = w . querySelector ( 'nd' ) . getAttribute ( 'ref' ) ;
90+ if ( wayBegins [ firstNodeID ] ) {
91+ wayBegins [ firstNodeID ] . push ( w ) ;
92+ } else {
93+ wayBegins [ firstNodeID ] = [ w ] ;
12794 }
128- const lastWay = ways [ ways . length - 1 ] ;
129- if ( BuildingShapeUtils . isClosed ( lastWay ) ) {
130- closedWays . push ( lastWay ) ;
95+
96+ const lastNodeID = w . querySelector ( 'nd:last-of-type' ) . getAttribute ( 'ref' ) ;
97+ if ( wayEnds [ lastNodeID ] ) {
98+ wayEnds [ lastNodeID ] . push ( w ) ;
13199 } else {
132- openWays . push ( lastWay ) ;
100+ wayEnds [ lastNodeID ] = [ w ] ;
101+ }
102+ } ) ;
103+
104+ const usedWays = new Set ( ) ;
105+
106+ function tryMakeRing ( currentRingWays ) {
107+ if ( currentRingWays [ 0 ] . querySelector ( 'nd' ) . getAttribute ( 'ref' ) ===
108+ currentRingWays [ currentRingWays . length - 1 ] . querySelector ( 'nd:last-of-type' ) . getAttribute ( 'ref' ) ) {
109+ return currentRingWays ;
110+ }
111+
112+ const lastWay = currentRingWays [ currentRingWays . length - 1 ] ;
113+ const lastNodeID = lastWay . querySelector ( 'nd:last-of-type' ) . getAttribute ( 'ref' ) ;
114+ for ( let way of wayBegins [ lastNodeID ] ?? [ ] ) {
115+ const wayID = way . getAttribute ( 'id' ) ;
116+ if ( usedWays . has ( wayID ) ) {
117+ continue ;
118+ }
119+ usedWays . add ( wayID ) ;
120+ currentRingWays . push ( way ) ;
121+ if ( tryMakeRing ( currentRingWays ) . length ) {
122+ return currentRingWays ;
123+ }
124+ currentRingWays . pop ( ) ;
125+ usedWays . delete ( wayID ) ;
126+ }
127+
128+ for ( let way of wayEnds [ lastNodeID ] ?? [ ] ) {
129+ const wayID = way . getAttribute ( 'id' ) ;
130+ if ( usedWays . has ( wayID ) ) {
131+ continue ;
132+ }
133+ usedWays . add ( wayID ) ;
134+ currentRingWays . push ( BuildingShapeUtils . reverseWay ( way ) ) ;
135+ if ( tryMakeRing ( currentRingWays ) . length ) {
136+ return currentRingWays ;
137+ }
138+ currentRingWays . pop ( ) ;
139+ usedWays . delete ( wayID ) ;
133140 }
134- ways = openWays ;
135- openWays = [ ] ;
141+
142+ return [ ] ;
136143 }
144+
145+ ways . forEach ( w => {
146+ const wayID = w . getAttribute ( 'id' ) ;
147+ if ( usedWays . has ( wayID ) ) {
148+ return ;
149+ }
150+ usedWays . add ( wayID ) ;
151+ const result = tryMakeRing ( [ w ] ) ;
152+ if ( result . length ) {
153+ let ring = result [ 0 ] ;
154+ result . slice ( 1 ) . forEach ( w => {
155+ ring = this . joinWays ( ring , w ) ;
156+ } ) ;
157+ closedWays . push ( ring ) ;
158+ }
159+ } ) ;
160+
137161 return closedWays ;
138162 }
139163
0 commit comments