@@ -59,62 +59,82 @@ class BuildingShapeUtils extends ShapeUtils {
5959 */
6060 static combineWays ( ways ) {
6161 const closedWays = [ ] ;
62- let openWays = [ ] ;
63- let changed = true ;
64- let watchDogCounter = 0
65- while ( changed ) {
66- if ( watchDogCounter ++ > 2_000_000 ) {
67- throw 'Infinite loop in combineWays' ;
62+ const wayBegins = { } ;
63+ const wayEnds = { } ;
64+
65+ ways . forEach ( w => {
66+ const firstNodeID = w . querySelector ( 'nd' ) . getAttribute ( 'ref' ) ;
67+ if ( wayBegins [ firstNodeID ] ) {
68+ wayBegins [ firstNodeID ] . push ( w ) ;
69+ } else {
70+ wayBegins [ firstNodeID ] = [ w ] ;
71+ }
72+
73+ const lastNodeID = w . querySelector ( 'nd:last-of-type' ) . getAttribute ( 'ref' ) ;
74+ if ( wayEnds [ lastNodeID ] ) {
75+ wayEnds [ lastNodeID ] . push ( w ) ;
76+ } else {
77+ wayEnds [ lastNodeID ] = [ w ] ;
6878 }
69- changed = false ;
70- for ( let i = 0 ; i < ways . length - 1 ; i ++ ) {
71- if ( BuildingShapeUtils . isClosed ( ways [ i ] ) ) {
72- closedWays . push ( ways [ i ] ) ;
73- } else {
74- // These are HTMLCollections of nodes, not ways.
75- const way1 = ways [ i ] . getElementsByTagName ( 'nd' ) ;
76- const way2 = ways [ i + 1 ] . getElementsByTagName ( 'nd' ) ;
79+ } ) ;
7780
78- // If the first node of way2 is the same as the last in way one, they can be combined
79- // Or if the first node of way1 is the same as the last in way2
80- // Need to extend this to tip-to-tip connections as well.
81- // Need to add a "reverse way" function somewhere.
82- if ( way2 [ 0 ] . getAttribute ( 'ref' ) === way1 [ way1 . length - 1 ] . getAttribute ( 'ref' ) ) {
83- const result = BuildingShapeUtils . joinWays ( ways [ i ] , ways [ i + 1 ] ) ;
84- openWays . push ( result ) ;
85- i ++ ;
86- changed = true ;
87- } else if ( way1 [ 0 ] . getAttribute ( 'ref' ) === way2 [ way2 . length - 1 ] . getAttribute ( 'ref' ) ) {
88- const result = BuildingShapeUtils . joinWays ( ways [ i + 1 ] , ways [ i ] ) ;
89- openWays . push ( result ) ;
90- i ++ ;
91- changed = true ;
92- } else if ( way1 [ way1 . length - 1 ] . getAttribute ( 'ref' ) === way2 [ way2 . length - 1 ] . getAttribute ( 'ref' ) ) {
93- const tempway = BuildingShapeUtils . reverseWay ( ways [ i + 1 ] ) ;
94- const result = BuildingShapeUtils . joinWays ( ways [ i ] , tempway ) ;
95- openWays . push ( result ) ;
96- i ++ ;
97- changed = true ;
98- } else if ( way1 [ 0 ] . getAttribute ( 'ref' ) === way2 [ 0 ] . getAttribute ( 'ref' ) ) {
99- const tempway = BuildingShapeUtils . reverseWay ( ways [ i ] ) ;
100- const result = BuildingShapeUtils . joinWays ( tempway , ways [ i + 1 ] ) ;
101- openWays . push ( result ) ;
102- i ++ ;
103- changed = true ;
104- } else {
105- openWays . push ( ways [ i ] ) ;
106- }
81+ const usedWays = new Set ( ) ;
82+
83+ function tryMakeRing ( currentRingWays ) {
84+ if ( currentRingWays [ 0 ] . querySelector ( 'nd' ) . getAttribute ( 'ref' ) ===
85+ currentRingWays [ currentRingWays . length - 1 ] . querySelector ( 'nd:last-of-type' ) . getAttribute ( 'ref' ) ) {
86+ return currentRingWays ;
87+ }
88+
89+ const lastWay = currentRingWays [ currentRingWays . length - 1 ] ;
90+ const lastNodeID = lastWay . querySelector ( 'nd:last-of-type' ) . getAttribute ( 'ref' ) ;
91+ for ( let way of wayBegins [ lastNodeID ] ?? [ ] ) {
92+ const wayID = way . getAttribute ( 'id' ) ;
93+ if ( usedWays . has ( wayID ) ) {
94+ continue ;
95+ }
96+ usedWays . add ( wayID ) ;
97+ currentRingWays . push ( way ) ;
98+ if ( tryMakeRing ( currentRingWays ) . length ) {
99+ return currentRingWays ;
107100 }
101+ currentRingWays . pop ( ) ;
102+ usedWays . delete ( wayID ) ;
108103 }
109- const lastWay = ways [ ways . length - 1 ] ;
110- if ( BuildingShapeUtils . isClosed ( lastWay ) ) {
111- closedWays . push ( lastWay ) ;
112- } else {
113- openWays . push ( lastWay ) ;
104+
105+ for ( let way of wayEnds [ lastNodeID ] ?? [ ] ) {
106+ const wayID = way . getAttribute ( 'id' ) ;
107+ if ( usedWays . has ( wayID ) ) {
108+ continue ;
109+ }
110+ usedWays . add ( wayID ) ;
111+ currentRingWays . push ( BuildingShapeUtils . reverseWay ( way ) ) ;
112+ if ( tryMakeRing ( currentRingWays ) . length ) {
113+ return currentRingWays ;
114+ }
115+ currentRingWays . pop ( ) ;
116+ usedWays . delete ( wayID ) ;
114117 }
115- ways = openWays ;
116- openWays = [ ] ;
118+
119+ return [ ] ;
117120 }
121+
122+ ways . forEach ( w => {
123+ const wayID = w . getAttribute ( 'ref' ) ;
124+ if ( usedWays . has ( wayID ) ) {
125+ return ;
126+ }
127+ usedWays . add ( wayID ) ;
128+ const result = tryMakeRing ( [ w ] ) ;
129+ if ( result . length ) {
130+ let ring = result [ 0 ] ;
131+ result . slice ( 1 ) . forEach ( w => {
132+ ring = this . joinWays ( ring , w ) ;
133+ } ) ;
134+ closedWays . push ( ring ) ;
135+ }
136+ } ) ;
137+
118138 return closedWays ;
119139 }
120140
0 commit comments