Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 37 additions & 1 deletion src/extras/BuildingShapeUtils.js
Original file line number Diff line number Diff line change
Expand Up @@ -67,8 +67,14 @@ class BuildingShapeUtils extends ShapeUtils {
if (BuildingShapeUtils.isClosed(ways[i])) {
closedWays.push(ways[i]);
} else {
// These are HTMLCollections of nodes, not ways.
const way1 = ways[i].getElementsByTagName('nd');
const way2 = ways[i + 1].getElementsByTagName('nd');

// If the first node of way2 is the same as the last in way one, they can be combined
// Or if the first node of way1 is the same as the last in way2
// Need to extend this to tip-to-tip connections as well.
// Need to add a "reverse way" function somewhere.
if (way2[0].getAttribute('ref') === way1[way1.length - 1].getAttribute('ref')) {
const result = BuildingShapeUtils.joinWays(ways[i], ways[i + 1]);
openWays.push(result);
Expand All @@ -79,8 +85,20 @@ class BuildingShapeUtils extends ShapeUtils {
openWays.push(result);
i++;
changed = true;
} else if (way1[way1.length - 1].getAttribute('ref') === way2[way2.length - 1].getAttribute('ref')) {
const tempway = BuildingShapeUtils.reverseWay(ways[i + 1]);
const result = BuildingShapeUtils.joinWays(ways[i], tempway);
openWays.push(result);
i++;
changed = true;
} else if (way1[0].getAttribute('ref') === way2[0].getAttribute('ref')) {
const tempway = BuildingShapeUtils.reverseWay(ways[i]);
const result = BuildingShapeUtils.joinWays(tempway, ways[i + 1]);
openWays.push(result);
i++;
changed = true;
} else {
openWays.push(way1);
openWays.push(ways[i]);
}
}
}
Expand Down Expand Up @@ -113,6 +131,24 @@ class BuildingShapeUtils extends ShapeUtils {
return way1;
}

/**
* Reverse the order of nodes in a way.
*
* @param {DOM.Element} way - a way
*
* @return {DOM.Element} way
*/
static reverseWay(way) {
const elements = way.getElementsByTagName('nd');
const newWay = way.cloneNode(true);
newWay.innerHTML = '';
for (let i = 0; i < elements.length; i++) {
let elem = elements[elements.length - 1 - i].cloneNode();
newWay.appendChild(elem);
}
return newWay;
}

/**
* Find the center of a closed way
*
Expand Down
69 changes: 69 additions & 0 deletions test/split_way_multipolygon_reverse.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
/**
* @jest-environment jsdom
*/

import { Shape, Mesh } from 'three';
import { TextEncoder } from 'node:util';
global.TextEncoder = TextEncoder;

import { Building } from '../src/building.js';
import { MultiBuildingPart } from '../src/multibuildingpart.js';
// ways 1 and 3 are tip-to-tip.
const data = `
<osm>
<node id="12" lat="4" lon="4"/>
<node id="11" lat="4" lon="4.001"/>
<node id="6" lat="4.001" lon="4.001"/>
<node id="7" lat="4.001" lon="4"/>
<node id="8" lat="4.00025" lon="4.00025"/>
<node id="9" lat="4.00025" lon="4.00075"/>
<node id="10" lat="4.00075" lon="4.0005"/>
<relation id="5">
<member ref="1" role="outer"/>
<member ref="3" role="outer"/>
<member ref="2" role="inner"/>
<tag k="type" v="multipolygon"/>
<tag k="building" v="yes"/>
<tag k="roof:shape" v="skillion"/>
<tag k="roof:direction" v="0"/>
<tag k="roof:angle" v="45"/>
</relation>
<way id="1">
<nd ref="12"/>
<nd ref="11"/>
<nd ref="6"/>
</way>
<way id="2">
<nd ref="8"/>
<nd ref="9"/>
<nd ref="10"/>
<nd ref="8"/>
</way>
<way id="3">
<nd ref="12"/>
<nd ref="7"/>
<nd ref="6"/>
</way>
</osm>`;

beforeEach(() => {
errors = [];
});

test('Test Simple Multipolygon', () => {
let xmlData = new window.DOMParser().parseFromString(data, 'text/xml');
const nodelist = Building.buildNodeList(xmlData);
const shape = new MultiBuildingPart('5', xmlData, nodelist);
expect(shape.id).toBe('5');
expect(shape.shape).toBeInstanceOf(Shape);
// expect(shape.roof).toBeInstanceOf(Mesh);
expect(errors.length).toBe(0);
});

window.printError = printError;

var errors = [];

function printError(txt) {
errors.push[txt];
}
37 changes: 36 additions & 1 deletion test/utils.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,15 @@ test('Test Closed Way', () => {
expect(BuildingShapeUtils.isClosed(xmlData)).toBe(true);
});

test('Reverse way', () => {
var way1 = '<way id="1"><nd ref="1"/><nd ref="2"/><nd ref="3"/></way>';
var way2 = '<way id="1"><nd ref="3"/><nd ref="2"/><nd ref="1"/></way>';
let parser = new window.DOMParser();
let xml1 = parser.parseFromString(way1, 'text/xml').getElementsByTagName('way')[0];
let result = BuildingShapeUtils.reverseWay(xml1);
expect(result.outerHTML).toBe(way2);
});

test('Test Open Way', () => {
var way = '<way id="1"><nd ref="2"/><nd ref="3"/><nd ref="4"/><nd ref="5"/><nd ref="6"/></way>';
let parser = new window.DOMParser();
Expand All @@ -38,7 +47,7 @@ test('Test joining 2 ways', () => {
expect(result.outerHTML).toBe(way3);
});

test('Test combining 2 ways', () => {
test('Test combining 2 ways 1->2', () => {
var way1 = '<way id="1"><nd ref="1"/><nd ref="2"/><nd ref="3"/></way>';
var way2 = '<way id="2"><nd ref="3"/><nd ref="4"/><nd ref="1"/></way>';
var way3 = '<way id="1"><nd ref="1"/><nd ref="2"/><nd ref="3"/><nd ref="4"/><nd ref="1"/></way>';
Expand All @@ -51,6 +60,32 @@ test('Test combining 2 ways', () => {
expect(result[0].outerHTML).toBe(way3);
});

test('Test combining 2 ways 2->1', () => {
var way2 = '<way id="1"><nd ref="1"/><nd ref="2"/><nd ref="3"/></way>';
var way1 = '<way id="2"><nd ref="3"/><nd ref="4"/><nd ref="1"/></way>';
var way3 = '<way id="2"><nd ref="3"/><nd ref="4"/><nd ref="1"/><nd ref="2"/><nd ref="3"/></way>';
let parser = new window.DOMParser();
let xml1 = parser.parseFromString(way1, 'text/xml').getElementsByTagName('way')[0];
let xml2 = parser.parseFromString(way2, 'text/xml').getElementsByTagName('way')[0];
let result = BuildingShapeUtils.combineWays([xml1, xml2]);
expect(result.length).toBe(1);
let expected = parser.parseFromString(way3, 'text/xml');
expect(result[0].outerHTML).toBe(way3);
});

test('Test combining 2 unaligned ways', () => {
var way1 = '<way id="1"><nd ref="1"/><nd ref="2"/><nd ref="3"/></way>';
var way2 = '<way id="2"><nd ref="1"/><nd ref="4"/><nd ref="3"/></way>';
var way3 = '<way id="1"><nd ref="1"/><nd ref="2"/><nd ref="3"/><nd ref="4"/><nd ref="1"/></way>';
let parser = new window.DOMParser();
let xml1 = parser.parseFromString(way1, 'text/xml').getElementsByTagName('way')[0];
let xml2 = parser.parseFromString(way2, 'text/xml').getElementsByTagName('way')[0];
let result = BuildingShapeUtils.combineWays([xml1, xml2]);
expect(result.length).toBe(1);
let expected = parser.parseFromString(way3, 'text/xml');
expect(result[0].outerHTML).toBe(way3);
});

const rightTriangle = new Shape();
rightTriangle.moveTo(1, 1);
rightTriangle.lineTo(1, -1);
Expand Down