'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) } copy() { return new Vec3(this.x, this.y, this.z); } add(vec) { this.x = this.x + vec.x; this.y = this.y + vec.y; this.z = this.z + vec.z; return this } sub(vec) { this.x = this.x - vec.x; this.y = this.y - vec.y; this.z = this.z - vec.z; return this; } scale(a) { this.x = this.x * a; this.y = this.y * a; this.z = this.z * a; return this; } 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 function RandomNormal() { const theta = 2*Math.PI*Math.random(); const z = 2*Math.random() - 1; const s = Math.sqrt(1-(z*z)); return new Vec3(s*Math.cos(theta), s*Math.sin(theta), z).normalize(); } export class Shape { constructor(normals) { this.normals = normals; } translate(circle, angle) { const transform = new Mat3().rotation(circle, angle); for (let i=0; i= -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); let count = 0; while(v != null) { count += 1; ct.lineTo(v.x, v.y); [ i, v ] = this.getNextRenderPoint(ct, i, view); } if (count == this.normals.length) { ct.closePath(); } ct.stroke(); } } export function ConvexHull(points) { const hull = []; console.log("compute center"); // compute the average of the group of points let center = new Vec3(0, 0, 0); for (let point of points) { center.add(point); } center.scale(1/points.length).normalize; console.log("find furthest"); // find the furthest point from the center let furthest = null; let mindot = 1; for (let point of points) { const d = center.dot(point); if (d < mindot) { mindot = d; furthest = point; } } const t0 = furthest.copy().sub(center).cross(furthest).normalize(); function getNextHullPoint(p, tangent) { let next = null; let max = -1; for (let point of points) { const v = point.copy().sub(p).normalize(); const d = v.dot(tangent); if (d > max) { max = d; next = point; } } return next; } function tangent(p, prev) { return p.copy().sub(prev).normalize(); } hull.push[furthest]; let p = getNextHullPoint(furthest, t0); let tan = tangent(p, furthest); // begin loop console.log("loop"); let count = 0; while (p != null) { count += 1; hull.push(p); p = getNextHullPoint(p, tan); tan = tangent(p, hull[hull.length-1]); if (p == furthest || count > 50) { console.log(count); p = null; } } return new Shape(hull); }