diff options
author | sanine <sanine.not@pm.me> | 2023-03-31 17:17:27 -0500 |
---|---|---|
committer | sanine <sanine.not@pm.me> | 2023-03-31 17:17:27 -0500 |
commit | 673e9c13aea6cd1b11f5ca3e1f6edd474bbb1a19 (patch) | |
tree | 5764ff2cfd6b8dea3b615a1bb2f1dc1c078b07e7 /src/Geometry.js | |
parent | 8aa6645f2311de78f74b35f804cc45c7fcf38f57 (diff) |
implement nice map grid
Diffstat (limited to 'src/Geometry.js')
-rw-r--r-- | src/Geometry.js | 209 |
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(); + } +} |