Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
98d04bb
Update combine_ways.js
Beakerboy Apr 28, 2025
9348186
Update combine_ways.js
Beakerboy Apr 28, 2025
6944255
Update combine_ways.js
Beakerboy Apr 28, 2025
97b766c
Update combine_ways.js
Beakerboy Apr 28, 2025
c76745d
Rename combine_ways.js to combine_ways.test.js
Beakerboy Apr 28, 2025
121fe39
Update combine_ways.test.js
Beakerboy Apr 28, 2025
ba31144
Update combine_ways.test.js
Beakerboy Apr 28, 2025
34d09c2
Update combine_ways.test.js
Beakerboy Apr 28, 2025
752623a
Update combine_ways.test.js
Beakerboy Apr 28, 2025
20ec54f
Update combine_ways.test.js
Beakerboy Apr 28, 2025
4081b02
Update BuildingShapeUtils.js
Beakerboy Apr 28, 2025
214fd33
Update combine_ways.test.js
Beakerboy Apr 28, 2025
0783bc6
Update combine_ways.test.js
Beakerboy Apr 28, 2025
0afd87c
Update combine_ways.test.js
Beakerboy Apr 28, 2025
7434c50
Update combine_ways.test.js
Beakerboy Apr 28, 2025
4df2289
Update combine_ways.test.js
Beakerboy Apr 28, 2025
16156d6
Update combine_ways.test.js
Beakerboy Apr 28, 2025
662da99
Update combine_ways.test.js
Beakerboy Apr 28, 2025
073f8ab
Update combine_ways.test.js
Beakerboy Apr 28, 2025
7928ef9
Update combine_ways.test.js
Beakerboy Apr 28, 2025
f8ba849
Update combine_ways.test.js
Beakerboy Apr 28, 2025
0944f44
Update BuildingShapeUtils.js
Beakerboy Apr 28, 2025
1bac46f
Update utils.test.js
Beakerboy Apr 28, 2025
2e77b97
Update BuildingShapeUtils.js
Beakerboy Apr 28, 2025
6f18570
Update BuildingShapeUtils.js
Beakerboy Apr 28, 2025
2c40c37
Update BuildingShapeUtils.js
Beakerboy Apr 28, 2025
a4ff57e
Update BuildingShapeUtils.js
Beakerboy Apr 28, 2025
707017b
Update BuildingShapeUtils.js
Beakerboy Apr 28, 2025
966fa33
Update BuildingShapeUtils.js
Beakerboy Apr 29, 2025
cbcbda9
Update BuildingShapeUtils.js
Beakerboy Apr 29, 2025
835da74
Update BuildingShapeUtils.js
Beakerboy Apr 29, 2025
3beb723
Update BuildingShapeUtils.js
Beakerboy Apr 29, 2025
2be96fa
Update BuildingShapeUtils.js
Beakerboy Apr 29, 2025
bf4a067
Update BuildingShapeUtils.js
Beakerboy Apr 29, 2025
32c2626
Update combine_ways.test.js
Beakerboy Apr 29, 2025
4dbc4cb
Update utils.test.js
Beakerboy Apr 29, 2025
6c1a502
Update utils.test.js
Beakerboy Apr 29, 2025
661a862
Update utils.test.js
Beakerboy Apr 29, 2025
d7a4f4f
Update utils.test.js
Beakerboy Apr 29, 2025
da9a3c1
Update utils.test.js
Beakerboy Apr 29, 2025
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
29 changes: 26 additions & 3 deletions src/extras/BuildingShapeUtils.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ class BuildingShapeUtils extends ShapeUtils {
}

/**
* Check if a way is a cloased shape.
* Check if a way is a closed shape.
*
* @param {DOM.Element} way - OSM XML way element.
*
Expand All @@ -49,6 +49,29 @@ class BuildingShapeUtils extends ShapeUtils {
return elements[0].getAttribute('ref') === elements[elements.length - 1].getAttribute('ref');
}

/**
* Check if a way is self-intersecting.
*
* @param {DOM.Element} way - OSM XML way element.
*
* @return {boolean}
*/
static isSelfIntersecting(way) {
const nodes = Array.from(way.getElementsByTagName('nd'));
if (BuildingShapeUtils.isClosed(way)){
nodes.pop();
}
const refs = new Set();
for (const node of nodes) {
const ref = node.getAttribute('ref');
if (refs.has(ref)){
return true;
}
refs.add(ref);
}
return false;
}

/**
* Walk through an array and seperate any closed ways.
* Attempt to find matching open ways to enclose them.
Expand Down Expand Up @@ -92,8 +115,8 @@ class BuildingShapeUtils extends ShapeUtils {
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]);
const tempway = BuildingShapeUtils.reverseWay(ways[i+1]);
const result = BuildingShapeUtils.joinWays(tempway, ways[i]);
openWays.push(result);
i++;
changed = true;
Expand Down
92 changes: 0 additions & 92 deletions test/combine_ways.js

This file was deleted.

101 changes: 101 additions & 0 deletions test/combine_ways.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
/**
* @jest-environment jsdom
*/

import {toBeDeepCloseTo} from 'jest-matcher-deep-close-to';
expect.extend({toBeDeepCloseTo});

import { TextEncoder } from 'node:util';
global.TextEncoder = TextEncoder;

import { Shape } from 'three';

import { BuildingShapeUtils } from '../src/extras/BuildingShapeUtils.js';
// import { JSDOM } from 'jsdom';

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

test('Test combining 2 ways 1->2', () => {
var way1 = '<way id="1"><nd ref="1"/><nd ref="2"/></way>';
var way2 = '<way id="2"><nd ref="2"/><nd ref="3"/></way>';
var way3 = '<way id="3"><nd ref="3"/><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 xml3 = parser.parseFromString(way3, 'text/xml').getElementsByTagName('way')[0];
let result = BuildingShapeUtils.combineWays([xml1, xml2, xml3]);
// Expect one closed way with 3 unique nodes.
expect(result.length).toBe(1);
expect(BuildingShapeUtils.isClosed(result[0])).toBe(true);
expect(result[0].getElementsByTagName('nd').length).toBe(4);
expect(BuildingShapeUtils.isSelfIntersecting(result[0])).toBe(false);
});

test('Test combining 3 ways 2->1->3', () => {
var way1 = '<way id="1"><nd ref="1"/><nd ref="2"/></way>';
var way2 = '<way id="2"><nd ref="3"/><nd ref="1"/></way>';
var way3 = '<way id="3"><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 xml3 = parser.parseFromString(way3, 'text/xml').getElementsByTagName('way')[0];
let result = BuildingShapeUtils.combineWays([xml1, xml2, xml3]);
expect(result.length).toBe(1);
expect(BuildingShapeUtils.isClosed(result[0])).toBe(true);
expect(BuildingShapeUtils.isSelfIntersecting(result[0])).toBe(false);
expect(result[0].getElementsByTagName('nd').length).toBe(4);
});

test('Test combining 2 unaligned ways', () => {
var way1 = '<way id="1"><nd ref="1"/><nd ref="2"/></way>';
var way2 = '<way id="2"><nd ref="3"/><nd ref="2"/></way>';
var way3 = '<way id="3"><nd ref="3"/><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 xml3 = parser.parseFromString(way3, 'text/xml').getElementsByTagName('way')[0];
let result = BuildingShapeUtils.combineWays([xml1, xml2, xml3]);
expect(result.length).toBe(1);
expect(BuildingShapeUtils.isClosed(result[0])).toBe(true);
expect(BuildingShapeUtils.isSelfIntersecting(result[0])).toBe(false);
expect(result[0].getElementsByTagName('nd').length).toBe(4);
});

test('Test combining 3 ways 1->2->3', () => {
var way1 = '<way id="1"><nd ref="1"/><nd ref="2"/></way>';
var way2 = '<way id="2"><nd ref="1"/><nd ref="3"/></way>';
var way3 = '<way id="3"><nd ref="2"/><nd ref="3"/></way>';
var way4 = '<way id="2"><nd ref="3"/><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 xml3 = parser.parseFromString(way3, 'text/xml').getElementsByTagName('way')[0];
let result = BuildingShapeUtils.combineWays([xml1, xml2, xml3]);
expect(result.length).toBe(1);
expect(BuildingShapeUtils.isClosed(result[0])).toBe(true);
expect(BuildingShapeUtils.isSelfIntersecting(result[0])).toBe(false);
expect(result[0].getElementsByTagName('nd').length).toBe(4);
});

test('Test combining 4 ways', () => {
var way1 = '<way id="1"><nd ref="1"/><nd ref="2"/></way>';
var way2 = '<way id="2"><nd ref="3"/><nd ref="4"/></way>';
var way3 = '<way id="3"><nd ref="4"/><nd ref="1"/></way>';
var way4 = '<way id="4"><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 xml3 = parser.parseFromString(way3, 'text/xml').getElementsByTagName('way')[0];
let xml4 = parser.parseFromString(way4, 'text/xml').getElementsByTagName('way')[0];
let result = BuildingShapeUtils.combineWays([xml1, xml2, xml3, xml4]);
expect(result.length).toBe(1);
expect(BuildingShapeUtils.isClosed(result[0]));
expect(BuildingShapeUtils.isSelfIntersecting(result[0])).toBe(false);
expect(result[0].getElementsByTagName('nd').length).toBe(5);
});
13 changes: 13 additions & 0 deletions test/utils.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -75,3 +75,16 @@ test('Longest side angle', () => {
expect(rightTriangle.extractPoints().shape.length).toBe(3);
expect(BuildingShapeUtils.longestSideAngle(rightTriangle)).toBe(-Math.PI / 4);
});

describe('isSelfIntersecting', () => {
test.each([
['<way id="1"><nd ref="1"/><nd ref="2"/></way>', false, 'open non-intersecting'],
['<way id="1"><nd ref="1"/><nd ref="2"/><nd ref="3"/><nd ref="1"/></way>', false, 'closed non-intersecting'],
['<way id="1"><nd ref="1"/><nd ref="2"/><nd ref="3"/><nd ref="2"/></way>', true, 'open intersecting'],
['<way id="1"><nd ref="1"/><nd ref="2"/><nd ref="3"/><nd ref="4"/><nd ref="3"/><nd ref="1"/></way>', true, 'closed intersecting'],
])('${description}', (way, expected, description) => {
let parser = new window.DOMParser();
let xml = parser.parseFromString(way, 'text/xml').getElementsByTagName('way')[0];
expect(BuildingShapeUtils.isSelfIntersecting(xml)).toBe(expected);
});
});