@@ -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 */
@@ -59,62 +60,82 @@ class BuildingShapeUtils extends ShapeUtils {
5960 */
6061 static combineWays ( ways ) {
6162 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' ;
63+ const wayBegins = { } ;
64+ const wayEnds = { } ;
65+
66+ ways . forEach ( w => {
67+ const firstNodeID = w . querySelector ( 'nd' ) . getAttribute ( 'ref' ) ;
68+ if ( wayBegins [ firstNodeID ] ) {
69+ wayBegins [ firstNodeID ] . push ( w ) ;
70+ } else {
71+ wayBegins [ firstNodeID ] = [ w ] ;
72+ }
73+
74+ const lastNodeID = w . querySelector ( 'nd:last-of-type' ) . getAttribute ( 'ref' ) ;
75+ if ( wayEnds [ lastNodeID ] ) {
76+ wayEnds [ lastNodeID ] . push ( w ) ;
77+ } else {
78+ wayEnds [ lastNodeID ] = [ w ] ;
6879 }
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' ) ;
80+ } ) ;
7781
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- }
82+ const usedWays = new Set ( ) ;
83+
84+ function tryMakeRing ( currentRingWays ) {
85+ if ( currentRingWays [ 0 ] . querySelector ( 'nd' ) . getAttribute ( 'ref' ) ===
86+ currentRingWays [ currentRingWays . length - 1 ] . querySelector ( 'nd:last-of-type' ) . getAttribute ( 'ref' ) ) {
87+ return currentRingWays ;
88+ }
89+
90+ const lastWay = currentRingWays [ currentRingWays . length - 1 ] ;
91+ const lastNodeID = lastWay . querySelector ( 'nd:last-of-type' ) . getAttribute ( 'ref' ) ;
92+ for ( let way of wayBegins [ lastNodeID ] ?? [ ] ) {
93+ const wayID = way . getAttribute ( 'id' ) ;
94+ if ( usedWays . has ( wayID ) ) {
95+ continue ;
96+ }
97+ usedWays . add ( wayID ) ;
98+ currentRingWays . push ( way ) ;
99+ if ( tryMakeRing ( currentRingWays ) . length ) {
100+ return currentRingWays ;
107101 }
102+ currentRingWays . pop ( ) ;
103+ usedWays . delete ( wayID ) ;
108104 }
109- const lastWay = ways [ ways . length - 1 ] ;
110- if ( BuildingShapeUtils . isClosed ( lastWay ) ) {
111- closedWays . push ( lastWay ) ;
112- } else {
113- openWays . push ( lastWay ) ;
105+
106+ for ( let way of wayEnds [ lastNodeID ] ?? [ ] ) {
107+ const wayID = way . getAttribute ( 'id' ) ;
108+ if ( usedWays . has ( wayID ) ) {
109+ continue ;
110+ }
111+ usedWays . add ( wayID ) ;
112+ currentRingWays . push ( BuildingShapeUtils . reverseWay ( way ) ) ;
113+ if ( tryMakeRing ( currentRingWays ) . length ) {
114+ return currentRingWays ;
115+ }
116+ currentRingWays . pop ( ) ;
117+ usedWays . delete ( wayID ) ;
114118 }
115- ways = openWays ;
116- openWays = [ ] ;
119+
120+ return [ ] ;
117121 }
122+
123+ ways . forEach ( w => {
124+ const wayID = w . getAttribute ( 'ref' ) ;
125+ if ( usedWays . has ( wayID ) ) {
126+ return ;
127+ }
128+ usedWays . add ( wayID ) ;
129+ const result = tryMakeRing ( [ w ] ) ;
130+ if ( result . length ) {
131+ let ring = result [ 0 ] ;
132+ result . slice ( 1 ) . forEach ( w => {
133+ ring = this . joinWays ( ring , w ) ;
134+ } ) ;
135+ closedWays . push ( ring ) ;
136+ }
137+ } ) ;
138+
118139 return closedWays ;
119140 }
120141
0 commit comments