delaunay.js 1.0.7 → 1.0.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "delaunay.js",
3
- "version": "1.0.7",
3
+ "version": "1.0.8",
4
4
  "description": "Delaunay triangulation using the Bowyer-Watson algorithm, in JavaScript ",
5
5
  "keywords": [
6
6
  "triangulation",
@@ -26,9 +26,11 @@
26
26
  "src/"
27
27
  ],
28
28
  "scripts": {
29
- "test": "node test/test.js"
29
+ "test": "node test/test.js 10",
30
+ "prof": "node --prof test/test.js 20000",
31
+ "cpu-prof": "node --cpu-prof --cpu-prof-dir=./cpu-prof test/test.js 20000"
30
32
  },
31
33
  "dependencies": {
32
- "vectory-lib": "^0.0.7"
34
+ "vectory-lib": "^0.0.9"
33
35
  }
34
36
  }
@@ -1,45 +1,42 @@
1
1
  import Triangle from './triangle.js';
2
2
 
3
3
  export default function bowyerWatson (superTriangle, pointList) {
4
- // pointList is a set of coordinates defining the
4
+ // pointList is a set of coordinates defining the
5
5
  // points to be triangulated
6
6
  let triangulation = [];
7
7
 
8
- // add super-triangle to triangulation
9
- // must be large enough to completely contain all
8
+ // add super-triangle to triangulation
9
+ // must be large enough to completely contain all
10
10
  // the points in pointList
11
11
  triangulation.push(superTriangle);
12
12
 
13
13
  // add all the points one at a time to the triangulation
14
14
  pointList.forEach(point => {
15
15
  let badTriangles = [];
16
-
17
- // first find all the triangles that are no
16
+
17
+ // first find all the triangles that are no
18
18
  // longer valid due to the insertion
19
- triangulation.forEach(triangle => {
19
+ triangulation.forEach(triangle => {
20
20
  if(triangle.pointIsInsideCircumcircle(point)) {
21
- badTriangles.push(triangle);
21
+ badTriangles.push(triangle);
22
22
  }
23
23
  });
24
24
  let polygon = [];
25
-
25
+
26
26
  // find the boundary of the polygonal hole
27
27
  badTriangles.forEach(triangle => {
28
28
  triangle.edges().forEach(edge => {
29
- let edgeIsShared = false;
30
- badTriangles.forEach(otherTriangle => {
31
- if(triangle !== otherTriangle && otherTriangle.hasEdge(edge)) {
32
- edgeIsShared = true;
33
- }
29
+ let edgeIsShared = badTriangles.some(otherTriangle => {
30
+ return triangle !== otherTriangle && otherTriangle.hasEdge(edge);
34
31
  });
35
32
  if(!edgeIsShared) {
36
- //edge is not shared by any other
33
+ // edge is not shared by any other
37
34
  // triangles in badTriangles
38
35
  polygon.push(edge);
39
36
  }
40
37
  });
41
38
  });
42
-
39
+
43
40
  // remove them from the data structure
44
41
  badTriangles.forEach(triangle => {
45
42
  let index = triangulation.indexOf(triangle);
@@ -47,27 +44,27 @@ export default function bowyerWatson (superTriangle, pointList) {
47
44
  triangulation.splice(index, 1);
48
45
  }
49
46
  });
50
-
47
+
51
48
  // re-triangulate the polygonal hole
52
49
  polygon.forEach(edge => {
53
- //form a triangle from edge to point
50
+ // form a triangle from edge to point
54
51
  let newTri = new Triangle(edge[0], edge[1], point);
55
52
  triangulation.push(newTri);
56
53
  });
57
54
  });
58
-
55
+
59
56
  // done inserting points, now clean up
60
57
  let i = triangulation.length;
61
58
  while(i--) {
62
59
  let triangle = triangulation[i];
63
60
  if(triangle.sharesAVertexWith(superTriangle)) {
64
- //remove triangle from triangulation
61
+ // remove triangle from triangulation
65
62
  let index = triangulation.indexOf(triangle);
66
63
  if (index > -1) {
67
64
  triangulation.splice(index, 1);
68
65
  }
69
- }
66
+ }
70
67
  }
71
-
68
+
72
69
  return triangulation;
73
70
  }
package/src/triangle.js CHANGED
@@ -6,15 +6,11 @@ export default class Triangle {
6
6
  this.b = b;
7
7
  this.c = c;
8
8
  }
9
-
9
+
10
10
  vertexes() {
11
11
  return [this.a, this.b, this.c];
12
12
  }
13
13
 
14
- vertexesAsString() {
15
- return this.vertexes().map(vertex => `${vertex.x}, ${vertex.y}`).join(", ");
16
- }
17
-
18
14
  edges() {
19
15
  return [
20
16
  [this.a, this.b],
@@ -22,7 +18,7 @@ export default class Triangle {
22
18
  [this.c, this.a]
23
19
  ];
24
20
  }
25
-
21
+
26
22
  sharesAVertexWith(triangle) {
27
23
  // TODO: optimize me please!
28
24
  for(let i = 0; i < 3; i++) {
@@ -40,51 +36,74 @@ export default class Triangle {
40
36
  hasEdge(edge) {
41
37
  for(let i = 0; i < 3; i++) {
42
38
  let e = this.edges()[i];
43
- if(e[0].equals(edge[0]) && e[1].equals(edge[1]) ||
39
+ if(e[0].equals(edge[0]) && e[1].equals(edge[1]) ||
44
40
  e[1].equals(edge[0]) && e[0].equals(edge[1])) {
45
41
  return true;
46
42
  }
47
43
  }
48
44
  return false;
49
45
  }
50
-
46
+
51
47
  get circumcenter() {
52
48
  if(!this._circumcenter) {
53
- let d = 2 * (this.a.x * (this.b.y - this.c.y) +
54
- this.b.x * (this.c.y - this.a.y) +
49
+ let d = 2 * (this.a.x * (this.b.y - this.c.y) +
50
+ this.b.x * (this.c.y - this.a.y) +
55
51
  this.c.x * (this.a.y - this.b.y));
56
52
 
57
53
  let x = 1 / d * ((this.a.x * this.a.x + this.a.y * this.a.y) * (this.b.y - this.c.y) +
58
- (this.b.x * this.b.x + this.b.y * this.b.y) * (this.c.y - this.a.y) +
54
+ (this.b.x * this.b.x + this.b.y * this.b.y) * (this.c.y - this.a.y) +
59
55
  (this.c.x * this.c.x + this.c.y * this.c.y) * (this.a.y - this.b.y));
60
56
 
61
- let y = 1 / d * ((this.a.x * this.a.x + this.a.y * this.a.y) * (this.c.x - this.b.x) +
62
- (this.b.x * this.b.x + this.b.y * this.b.y) * (this.a.x - this.c.x) +
57
+ let y = 1 / d * ((this.a.x * this.a.x + this.a.y * this.a.y) * (this.c.x - this.b.x) +
58
+ (this.b.x * this.b.x + this.b.y * this.b.y) * (this.a.x - this.c.x) +
63
59
  (this.c.x * this.c.x + this.c.y * this.c.y) * (this.b.x - this.a.x));
64
60
  this._circumcenter = new Vector(x, y);
65
61
  }
66
-
62
+
67
63
  return this._circumcenter;
68
-
64
+
69
65
  }
70
-
66
+
71
67
  get centroid() {
72
68
  if(!this._centroid) {
73
69
  this._centroid = this.a.add(this.b).add(this.c).div(3);
74
70
  }
75
71
  return this._centroid;
76
72
  }
77
-
78
- get circumradius() {
79
- if(!this._circumradius) {
80
- this._circumradius = this.circumcenter.sub(this.a).getLength();
73
+
74
+ get circumradiusSq() {
75
+ if(!this._circumradiusSq) {
76
+ this._circumradiusSq = this.circumcenter.sub(this.a).getLengthSq();
81
77
  }
82
- return this._circumradius;
78
+ return this._circumradiusSq;
83
79
  }
84
80
 
85
81
  pointIsInsideCircumcircle(point) {
86
- let dist = point.sub(this.circumcenter).getLength();
87
-
88
- return dist < this.circumradius;
82
+ let dist = point.sub(this.circumcenter).getLengthSq();
83
+
84
+ return dist < this.circumradiusSq;
85
+ }
86
+
87
+ // Methods below are not needed for Delaunay triangulation, but useful for drawing.
88
+ vertexesAsString() {
89
+ return this.vertexes().map(vertex => `${vertex.x}, ${vertex.y}`).join(", ");
90
+ }
91
+
92
+ edgeLengths() {
93
+ return this.edges().map(v => v[0].sub(v[1]).getLength());
94
+ }
95
+
96
+ heights() {
97
+ let [a, b, c] = this.edgeLengths();
98
+ function height(a, b, c) {
99
+ const s = (a + b + c) / 2;
100
+ const h = 2 * Math.sqrt(s * (s - a) * (s - b) * (s - c)) / b;
101
+ return h;
102
+ }
103
+ return [height(a, b, c), height(b, c, a), height(c, a, b)];
104
+ }
105
+
106
+ shortestHeight() {
107
+ return Math.min(...this.heights());
89
108
  }
90
109
  }