Skip to content

Commit fe21892

Browse files
committed
rewrite combineWays()
1 parent e61795f commit fe21892

File tree

1 file changed

+73
-49
lines changed

1 file changed

+73
-49
lines changed

src/extras/BuildingShapeUtils.js

Lines changed: 73 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)