summaryrefslogtreecommitdiff
path: root/src/Geometry.js
diff options
context:
space:
mode:
Diffstat (limited to 'src/Geometry.js')
-rw-r--r--src/Geometry.js209
1 files changed, 209 insertions, 0 deletions
diff --git a/src/Geometry.js b/src/Geometry.js
new file mode 100644
index 0000000..23ef480
--- /dev/null
+++ b/src/Geometry.js
@@ -0,0 +1,209 @@
+'use strict';
+
+
+export class Mat3 {
+ constructor(arr = null) {
+ if (arr == null) {
+ this.identity();
+ }
+ else {
+ this.arr = arr;
+ }
+ }
+
+ i(row, col) {
+ const r = row-1
+ const c = col-1
+ const index = (3*r)+c
+ return this.arr[index]
+ }
+
+ identity() {
+ this.arr = [
+ 1, 0, 0,
+ 0, 1, 0,
+ 0, 0, 1,
+ ];
+ return this;
+ }
+
+
+ mul(other) {
+ const out = []
+ out[0] = (this.i(1,1)*other.i(1,1)) + (this.i(1,2)*other.i(2,1)) + (this.i(1,3)*other.i(3,1));
+ out[1] = (this.i(1,1)*other.i(1,2)) + (this.i(1,2)*other.i(2,2)) + (this.i(1,3)*other.i(3,2));
+ out[2] = (this.i(1,1)*other.i(1,3)) + (this.i(1,2)*other.i(2,3)) + (this.i(1,3)*other.i(3,3));
+
+ out[3] = (this.i(2,1)*other.i(1,1)) + (this.i(2,2)*other.i(2,1)) + (this.i(2,3)*other.i(3,1));
+ out[4] = (this.i(2,1)*other.i(1,2)) + (this.i(2,2)*other.i(2,2)) + (this.i(2,3)*other.i(3,2));
+ out[5] = (this.i(2,1)*other.i(1,3)) + (this.i(2,2)*other.i(2,3)) + (this.i(2,3)*other.i(3,3));
+
+ out[6] = (this.i(3,1)*other.i(1,1)) + (this.i(3,2)*other.i(2,1)) + (this.i(3,3)*other.i(3,1));
+ out[7] = (this.i(3,1)*other.i(1,2)) + (this.i(3,2)*other.i(2,2)) + (this.i(3,3)*other.i(3,2));
+ out[8] = (this.i(3,1)*other.i(1,3)) + (this.i(3,2)*other.i(2,3)) + (this.i(3,3)*other.i(3,3));
+
+ this.arr = out
+ return this
+ }
+
+ mulv(vec) {
+ const x = (this.i(1,1)*vec.x) + (this.i(1,2)*vec.y) + (this.i(1,3)*vec.z);
+ const y = (this.i(2,1)*vec.x) + (this.i(2,2)*vec.y) + (this.i(2,3)*vec.z);
+ const z = (this.i(3,1)*vec.x) + (this.i(3,2)*vec.y) + (this.i(3,3)*vec.z);
+ return new Vec3(x, y, z);
+ }
+
+ rotation(axis, angle) {
+ const cos = Math.cos(angle);
+ const sin = Math.sin(angle);
+ const mcos = 1-cos;
+ const msin = 1-sin;
+
+ this.arr[0] = cos + (axis.x * axis.x * mcos);
+ this.arr[1] = (axis.x * axis.y * mcos) - (axis.z * sin);
+ this.arr[2] = (axis.x * axis.z * mcos) + (axis.y * sin);
+
+ this.arr[3] = (axis.y * axis.x * mcos) + (axis.z * sin);
+ this.arr[4] = cos + (axis.y * axis.y * mcos);
+ this.arr[5] = (axis.y * axis.z * mcos) - (axis.x * sin);
+
+
+ this.arr[6] = (axis.z * axis.x * mcos) - (axis.y * sin);
+ this.arr[7] = (axis.z * axis.y * mcos) + (axis.x * sin);
+ this.arr[8] = cos + (axis.z * axis.z * mcos);
+
+ return this
+ }
+}
+
+
+export class Point {
+ constructor(latitude, longitude) {
+ this.lat = latitude;
+ this.long = longitude;
+ }
+
+ normal() {
+ const x = Math.cos(this.lat) * Math.cos(this.long)
+ const y = Math.cos(this.lat) * Math.sin(this.long)
+ const z = Math.sin(this.lat)
+ return new Vec3(x, y, z)
+ }
+}
+
+
+export class Vec3 {
+ constructor(x, y, z) {
+ this.x = x;
+ this.y = y;
+ this.z = z;
+ }
+
+ normalize() {
+ const len2 = (this.x*this.x) + (this.y*this.y) + (this.z*this.z);
+ const len = Math.sqrt(len2);
+ this.x = this.x/len;
+ this.y = this.y/len;
+ this.z = this.z/len;
+ return this;
+ }
+
+ point() {
+ const latitude = Math.asin(this.z);
+ const longitute =
+ Math.sign(this.this.y) * Math.acos(
+ this.x / Math.sqrt( (this.x*this.x) + (this.y*this.y) )
+ )
+ return new Point(latitude, longitude)
+ }
+
+ dot(vec) {
+ return (this.x * vec.x) + (this.y * vec.y) + (this.z * vec.z);
+ }
+
+ cross(vec) {
+ const x = (this.y*vec.z) - (this.z*vec.y);
+ const y = (this.z*vec.x) - (this.x*vec.z);
+ const z = (this.x*vec.y) - (this.y*vec.x);
+ return new Vec3(x, y, z);
+ }
+
+ transform(matrix) {
+ return matrix.mulv(this);
+ }
+
+ render(ct, view) {
+ const viewNorm = view.mulv(this);
+ if (viewNorm.z >= -0.01) {
+ ct.beginPath()
+ ct.arc(viewNorm.x, viewNorm.y, 0.01, 0, 2*Math.PI);
+ ct.fill();
+ }
+ }
+}
+
+
+export class Shape {
+ constructor(normals) {
+ this.normals = normals;
+ let avgx = 0;
+ let avgy = 0;
+ let avgz = 0;
+ for (let normal of normals) {
+ avgx += normal.x;
+ avgy += normal.y;
+ avgz += normal.z;
+ }
+ avgx /= normals.length;
+ avgy /= normals.length;
+ avgz /= normals.length;
+ this.center = new Vec3(avgx, avgy, avgz).normalize();
+ this.extent = 0
+ for (let normal of normals) {
+ this.extent = Math.max(this.extent, normal.dot(this.center));
+ }
+ }
+
+ translate(circle, angle) {
+ const transform = new Mat3().rotation(circle, angle);
+ for (let i=0; i<this.normals.length; i++) {
+ this.normals[i] = transform.mulv(this.normals[i]);
+ }
+ this.center = transform.mulv(this.normals[i]);
+ }
+
+ getNextRenderPoint(ct, start, view) {
+ for (let i=start; i<this.normals.length; i++) {
+ const v = view.mulv(this.normals[i]);
+ if (v.z >= -0.01) {
+ if (i != start) {
+ ct.stroke();
+ ct.beginPath();
+ ct.moveTo(v.x, v.y);
+ }
+ return [ i+1, v ];
+ }
+ }
+
+ return [null, null];
+ }
+
+ render(ct, view) {
+ ct.beginPath();
+ let i = 0;
+ let v;
+ [ i, v ] = this.getNextRenderPoint(ct, i, view);
+ if (v == null) {
+ // no renderable points
+ return;
+ }
+
+
+ ct.moveTo(v.x, v.y);
+ while(v != null) {
+ ct.lineTo(v.x, v.y);
+ [ i, v ] = this.getNextRenderPoint(ct, i, view);
+ }
+ ct.stroke();
+ }
+}