Skip to content

Commit

Permalink
Extract toClipSpace function, various cleanup and prep for future work.
Browse files Browse the repository at this point in the history
  • Loading branch information
brcolow committed Jul 7, 2024
1 parent 3a3fbdc commit f7f8c60
Show file tree
Hide file tree
Showing 2 changed files with 66 additions and 51 deletions.
76 changes: 47 additions & 29 deletions main.js
Original file line number Diff line number Diff line change
Expand Up @@ -259,14 +259,22 @@ let tableScaleMatrix = Mat4.create()
let tableTranslateMatrix = Mat4.create()
let initialTableRotation = Mat4.create()

function mapToSphere(mouseX, mouseY, canvas) {
const radius = 3
function toClipSpace(canvas, x, y) {
const res = Math.max(canvas.getBoundingClientRect().width, canvas.getBoundingClientRect().height) - 1
const x = (2 * (mouseX - canvas.getBoundingClientRect().x) - canvas.getBoundingClientRect().width - 1) / res
const y = (2 * (mouseY - canvas.getBoundingClientRect().y) - canvas.getBoundingClientRect().height - 1) / res
return [
(2 * (x - canvas.getBoundingClientRect().x) - canvas.getBoundingClientRect().width - 1) / res,
(2 * (y - canvas.getBoundingClientRect().y) - canvas.getBoundingClientRect().height - 1) / res
]
}

function mapToSphere(mouseX, mouseY, canvas) {
const xy = toClipSpace(canvas, mouseX, mouseY)
const x = xy[0]
const y = xy[1]
const lengthSquared = x * x + y * y

console.log(lengthSquared)
const radius = 3

// Map to sphere when x^2 + y^2 <= r^2 / 2 - otherwise map to the hyperbolic function f(x,y) = (r^2 / 2) / sqrt(x^2 + y^2).
if (2 * lengthSquared <= radius * radius) {
return new Vector3(x, y, Math.sqrt((radius * radius) - lengthSquared))
Expand Down Expand Up @@ -362,7 +370,9 @@ function initialize3DTableGraphic(moodyReport) {
return
}
cumulativeZoomFactor *= zoomFactor

// TODO: Keep zoom centered at mouse cursor.
// See: https://stackoverflow.com/questions/57892652/webgl-2d-camera-zoom-to-mouse-point
tableScaleMatrix.scale([zoomFactor, zoomFactor, zoomFactor])
}

Expand Down Expand Up @@ -469,7 +479,7 @@ function initialize3DTableGraphic(moodyReport) {
requestAnimationFrame(render)
}

let then = 0
let then = 0
const frameTimes = []
let frameCursor = 0
let numFrames = 0
Expand Down Expand Up @@ -676,20 +686,26 @@ const fsSource = `#version 300 es
`

function getBuffers(gl, moodyReport, zMultiplier) {
const positionBuffer = getPositionBuffer(gl, moodyReport, zMultiplier)
const lineColorBuffer = getColorBuffer(gl, moodyReport, positionBuffer.triangleVertices)
const buffers = getNonColorBuffers(gl, moodyReport, zMultiplier)
const lineColorBuffer = getColorBuffer(gl, moodyReport, buffers.triangleVertices)

const areEqual = (x, y, z, w, v) => x === y && y === z && z === w && w === v
console.assert(areEqual(buffers.positions.length / 3, buffers.normals.length / 3, buffers.textureCoordinates.length / 2, buffers.types.length, lineColorBuffer.colors.length / 4),
`All buffers must be of the same size (per vertex) but were not. Position buffer: ${buffers.positions.length / 3},
Normal buffer: ${buffers.normals.length / 3}, Texture buffer: ${buffers.textureCoordinates.length / 2}, Type buffer: ${buffers.types.length},
Color buffer: ${lineColorBuffer.colors.length / 4}`)

return {
positionBuffer: positionBuffer.positionBuffer,
normalBuffer: positionBuffer.normalBuffer,
triangleVertices: positionBuffer.triangleVertices,
textureBuffer: positionBuffer.textureBuffer,
typeBuffer: positionBuffer.typeBuffer,
lineColors: lineColorBuffer,
positionBuffer: buffers.positionBuffer,
normalBuffer: buffers.normalBuffer,
triangleVertices: buffers.triangleVertices,
textureBuffer: buffers.textureBuffer,
typeBuffer: buffers.typeBuffer,
lineColors: lineColorBuffer.colorBuffer,
}
}

function getPositionBuffer(gl, moodyReport, zMultiplier) {
function getNonColorBuffers(gl, moodyReport, zMultiplier) {
const vertices = moodyReport.vertices(zMultiplier).map(vertex => new Vertex(vertex[0], vertex[1], vertex[2])).flat(1)

const triangulation = bowyerWatson(vertices)
Expand All @@ -711,7 +727,6 @@ function getPositionBuffer(gl, moodyReport, zMultiplier) {
0, 0, 0, 0, 0, axisSize)
)

console.log("Position buffer size: " + positions.length / 3)
const positionBuffer = gl.createBuffer()
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer)
gl.bufferData(gl.ARRAY_BUFFER, positions, gl.STATIC_DRAW)
Expand All @@ -729,7 +744,6 @@ function getPositionBuffer(gl, moodyReport, zMultiplier) {
triangle.surfaceNormal().x / length, triangle.surfaceNormal().y / length, triangle.surfaceNormal().z / length]
}).flat(1)
const normals = new Float32Array(lineNormals.concat(triangleNormals).concat(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0))
console.log("Normals buffer size: " + normals.length / 3)
const normalBuffer = gl.createBuffer()
gl.bindBuffer(gl.ARRAY_BUFFER, normalBuffer)
gl.bufferData(gl.ARRAY_BUFFER, normals, gl.STATIC_DRAW)
Expand All @@ -746,27 +760,32 @@ function getPositionBuffer(gl, moodyReport, zMultiplier) {
// Map [minX, maxX] => [0, 1] and [minY, maxY] => [0, 1]
// (val - A) * (b - a) / (B - A) + a
const triangleTextureCoords = triangulation.map((triangle) => [
((triangle.v0.x - boundingBoxCache[zMultiplier].maxX) * (numRepeatsX + 1)) / (boundingBoxCache[zMultiplier].maxX - boundingBoxCache[zMultiplier].minX), ((triangle.v0.y - boundingBoxCache[zMultiplier].maxY) * (numRepeatsY + 1)) / (boundingBoxCache[zMultiplier].maxY - boundingBoxCache[zMultiplier].minY),
((triangle.v1.x - boundingBoxCache[zMultiplier].maxX) * (numRepeatsX + 1)) / (boundingBoxCache[zMultiplier].maxX - boundingBoxCache[zMultiplier].maxX), ((triangle.v1.y - boundingBoxCache[zMultiplier].maxY) * (numRepeatsY + 1)) / (boundingBoxCache[zMultiplier].maxY - boundingBoxCache[zMultiplier].minY),
((triangle.v2.x - boundingBoxCache[zMultiplier].maxX) * (numRepeatsX + 1)) / (boundingBoxCache[zMultiplier].maxX - boundingBoxCache[zMultiplier].minX), ((triangle.v2.y - boundingBoxCache[zMultiplier].maxY) * (numRepeatsY + 1)) / (boundingBoxCache[zMultiplier].maxY - boundingBoxCache[zMultiplier].minY),]
((triangle.v0.x - boundingBoxCache[zMultiplier].maxX) * (numRepeatsX + 1)) / (boundingBoxCache[zMultiplier].maxX - boundingBoxCache[zMultiplier].minX),
((triangle.v0.y - boundingBoxCache[zMultiplier].maxY) * (numRepeatsY + 1)) / (boundingBoxCache[zMultiplier].maxY - boundingBoxCache[zMultiplier].minY),
((triangle.v1.x - boundingBoxCache[zMultiplier].maxX) * (numRepeatsX + 1)) / (boundingBoxCache[zMultiplier].maxX - boundingBoxCache[zMultiplier].maxX),
((triangle.v1.y - boundingBoxCache[zMultiplier].maxY) * (numRepeatsY + 1)) / (boundingBoxCache[zMultiplier].maxY - boundingBoxCache[zMultiplier].minY),
((triangle.v2.x - boundingBoxCache[zMultiplier].maxX) * (numRepeatsX + 1)) / (boundingBoxCache[zMultiplier].maxX - boundingBoxCache[zMultiplier].minX),
((triangle.v2.y - boundingBoxCache[zMultiplier].maxY) * (numRepeatsY + 1)) / (boundingBoxCache[zMultiplier].maxY - boundingBoxCache[zMultiplier].minY),
]
).flat(1)

const textureCoordinates = new Float32Array(lineTextureCoords.concat(triangleTextureCoords).concat(0.0, 1.0, 0.0, 1.0, 0.0, 1.0, 0.0, 1.0, 0.0, 1.0, 0.0, 1.0))
console.log("Texture buffer size: " + textureCoordinates.length / 2)
const textureBuffer = gl.createBuffer()
gl.bindBuffer(gl.ARRAY_BUFFER, textureBuffer)
gl.bufferData(gl.ARRAY_BUFFER, textureCoordinates, gl.STATIC_DRAW)

const types = new Float32Array(
moodyReport.vertices(zMultiplier).map(v => [0.0]).flat(1) // "Union jack" colored lines have type "0.0"
.concat(triangulation.map(_ => [1.0, 1.0, 1.0]).flat(1)) // Table vertices have type "1.0"
.concat(0.0, 0.0, 0.0, 0.0, 0.0, 0.0)) // Axes vertices have type "0.0"
console.log("Type buffer size: " + types.length)
.concat(0.0, 0.0, 0.0, 0.0, 0.0, 0.0)) // Axis vertices have type "0.0"

const typeBuffer = gl.createBuffer()
gl.bindBuffer(gl.ARRAY_BUFFER, typeBuffer)
gl.bufferData(gl.ARRAY_BUFFER, types, gl.STATIC_DRAW)

return { positionBuffer: positionBuffer, normalBuffer: normalBuffer, textureBuffer: textureBuffer, typeBuffer: typeBuffer, triangleVertices: triangulatedVertices }
return { positionBuffer: positionBuffer, positions: positions, normalBuffer: normalBuffer, normals: normals,
textureBuffer: textureBuffer, textureCoordinates: textureCoordinates, typeBuffer: typeBuffer, types: types,
triangleVertices: triangulatedVertices }
}

function getColorBuffer(gl, moodyReport, triangleVertices) {
Expand All @@ -784,16 +803,15 @@ function getColorBuffer(gl, moodyReport, triangleVertices) {
.concat(new Array(moodyReport.horizontalCenterTable.numStations).fill([0.0, 0.749019607843137, 0.8470588235294118, 1.0]).flat(1))
.concat(new Array(moodyReport.verticalCenterTable.numStations).fill([0.607843137254902, 0.1568627450980392, 0.6862745098039216, 1.0]).flat(1))
.concat(colorMappedZValues.flat(1)) // Add color mapped colors for the triangles z-value.
.concat(1, 1, 1, 1, 1, 0, 0, 1,
1, 1, 1, 1, 0, 1, 0, 1,
1, 1, 1, 1, 0, 0, 1, 1) // Add colors for axes lines.
.concat(1, 1, 1, 1, 1, 0, 0, 1,
1, 1, 1, 1, 0, 1, 0, 1,
1, 1, 1, 1, 0, 0, 1, 1) // Add colors for axes lines.

console.log("Color buffer size: " + colors.length / 4)
const colorBuffer = gl.createBuffer()
gl.bindBuffer(gl.ARRAY_BUFFER, colorBuffer)
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(colors), gl.STATIC_DRAW)

return colorBuffer
return { colorBuffer: colorBuffer, colors: colors }
}

function setPositionAttribute(gl, buffers, programInfo) {
Expand Down
41 changes: 19 additions & 22 deletions moody.js
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,9 @@ class Table {
surfacePlateWidthInches
surfacePlateDiagonalInches
suggestedDiagonalInset
plateDiagonalAngle
xInset
yInset

constructor(lineSegment, arcSecondData, reflectorFootSpacingInches, surfacePlateHeightInches, surfacePlateWidthInches, suggestedDiagonalInset) {
this.lineSegment = lineSegment
Expand All @@ -69,6 +72,9 @@ class Table {
this.surfacePlateHeightInches = surfacePlateHeightInches
this.surfacePlateWidthInches = surfacePlateWidthInches
this.suggestedDiagonalInset = suggestedDiagonalInset
this.plateDiagonalAngle = Math.atan(this.surfacePlateWidthInches / this.surfacePlateHeightInches)
this.xInset = this.suggestedDiagonalInset * Math.sin(this.plateDiagonalAngle)
this.yInset = this.suggestedDiagonalInset * Math.cos(this.plateDiagonalAngle)
}

printDebug() {
Expand Down Expand Up @@ -177,25 +183,22 @@ class DiagonalTable extends Table {
// We could make it so we also calculate the suggestedHorizontal and suggestedVertical insets. Right now we are assuming the reflectorFootSpacing evenly divides into the plate width/height - but what if it is non-standard?
// (0,0) origin is bottom left corner of surface plate.
vertices(zMultiplier = 1) {
const plateDiagonalAngle = Math.atan(this.surfacePlateWidthInches / this.surfacePlateHeightInches)
const xInset = this.suggestedDiagonalInset * Math.sin(plateDiagonalAngle)
const yInset = this.suggestedDiagonalInset * Math.cos(plateDiagonalAngle)
if (this.lineSegment.start == Direction.Northwest) {
// Top-Starting Diagonal
// y = -(table_width/table_height) * x + table_height
// sin(theta) = y / reflector_foot_spacing
// tan(theta) = y / x
return this.displacementsFromBaseLineLinear.map((z, i) => {
const x = xInset + (i * Math.sin(plateDiagonalAngle) * this.reflectorFootSpacingInches)
const y = this.surfacePlateHeightInches - yInset - (i * Math.cos(plateDiagonalAngle) * this.reflectorFootSpacingInches)
const x = this.xInset + (i * Math.sin(this.plateDiagonalAngle) * this.reflectorFootSpacingInches)
const y = this.surfacePlateHeightInches - this.yInset - (i * Math.cos(this.plateDiagonalAngle) * this.reflectorFootSpacingInches)
return [x, y, z * zMultiplier]
})
} else {
// Bottom starting diagonal
// y = (table_width/table_height) * x
return this.displacementsFromBaseLineLinear.map((z, i) => {
const x = this.surfacePlateWidthInches - xInset - (i * Math.sin(plateDiagonalAngle) * this.reflectorFootSpacingInches)
const y = this.surfacePlateHeightInches - yInset - (i * Math.cos(plateDiagonalAngle) * this.reflectorFootSpacingInches)
const x = this.surfacePlateWidthInches - this.xInset - (i * Math.sin(this.plateDiagonalAngle) * this.reflectorFootSpacingInches)
const y = this.surfacePlateHeightInches - this.yInset - (i * Math.cos(this.plateDiagonalAngle) * this.reflectorFootSpacingInches)
return [x, y, z * zMultiplier]
})
}
Expand Down Expand Up @@ -226,21 +229,18 @@ class PerimeterTable extends Table {

// (0,0) origin is bottom left corner of surface plate.
vertices(zMultiplier = 1) {
const plateDiagonalAngle = Math.atan(this.surfacePlateWidthInches / this.surfacePlateHeightInches)
const xInset = this.suggestedDiagonalInset * Math.sin(plateDiagonalAngle)
const yInset = this.suggestedDiagonalInset * Math.cos(plateDiagonalAngle)
if (this.lineSegment.start == Direction.Northeast && this.lineSegment.end == Direction.Northwest) {
// North Perimeter
return this.displacementsFromBaseLineLinear.map((z, i) => [this.surfacePlateWidthInches - xInset - (i * this.reflectorFootSpacingInches), this.surfacePlateHeightInches - yInset, z * zMultiplier])
return this.displacementsFromBaseLineLinear.map((z, i) => [this.surfacePlateWidthInches - this.xInset - (i * this.reflectorFootSpacingInches), this.surfacePlateHeightInches - this.yInset, z * zMultiplier])
} else if (this.lineSegment.start == Direction.Northeast && this.lineSegment.end == Direction.Southeast) {
// East Perimeter
return this.displacementsFromBaseLineLinear.map((z, i) => [this.surfacePlateWidthInches - xInset, this.surfacePlateHeightInches - yInset - (i * this.reflectorFootSpacingInches), z * zMultiplier])
return this.displacementsFromBaseLineLinear.map((z, i) => [this.surfacePlateWidthInches - this.xInset, this.surfacePlateHeightInches - this.yInset - (i * this.reflectorFootSpacingInches), z * zMultiplier])
} else if (this.lineSegment.start == Direction.Southeast && this.lineSegment.end == Direction.Southwest) {
// South Perimeter
return this.displacementsFromBaseLineLinear.map((z, i) => [this.surfacePlateWidthInches - xInset - (i * this.reflectorFootSpacingInches), yInset, z * zMultiplier])
return this.displacementsFromBaseLineLinear.map((z, i) => [this.surfacePlateWidthInches - this.xInset - (i * this.reflectorFootSpacingInches), this.yInset, z * zMultiplier])
} else if (this.lineSegment.start == Direction.Northwest && this.lineSegment.end == Direction.Southwest) {
// West Perimeter
return this.displacementsFromBaseLineLinear.map((z, i) => [xInset, this.surfacePlateHeightInches - yInset - (i * this.reflectorFootSpacingInches), z * zMultiplier])
return this.displacementsFromBaseLineLinear.map((z, i) => [this.xInset, this.surfacePlateHeightInches - this.yInset - (i * this.reflectorFootSpacingInches), z * zMultiplier])
}
}
}
Expand Down Expand Up @@ -308,15 +308,12 @@ class CenterTable extends Table {

// (0,0) origin is bottom left corner of surface plate.
vertices(zMultiplier = 1) {
const plateDiagonalAngle = Math.atan(this.surfacePlateWidthInches / this.surfacePlateHeightInches)
const xInset = this.suggestedDiagonalInset * Math.sin(plateDiagonalAngle)
const yInset = this.suggestedDiagonalInset * Math.cos(plateDiagonalAngle)
if (this.lineSegment.start == Direction.East) {
// Horizontal Center Line
return this.displacementsFromBaseLineLinear.map((z, i) => { return [this.surfacePlateWidthInches - xInset - (i * this.reflectorFootSpacingInches), this.surfacePlateHeightInches / 2, z * zMultiplier] })
return this.displacementsFromBaseLineLinear.map((z, i) => { return [this.surfacePlateWidthInches - this.xInset - (i * this.reflectorFootSpacingInches), this.surfacePlateHeightInches / 2, z * zMultiplier] })
} else if (this.lineSegment.start == Direction.North) {
// Vertical Center Line
return this.displacementsFromBaseLineLinear.map((z, i) => [this.surfacePlateWidthInches / 2, this.surfacePlateHeightInches - yInset - (i * this.reflectorFootSpacingInches), z * zMultiplier])
return this.displacementsFromBaseLineLinear.map((z, i) => [this.surfacePlateWidthInches / 2, this.surfacePlateHeightInches - this.yInset - (i * this.reflectorFootSpacingInches), z * zMultiplier])
}
}

Expand Down Expand Up @@ -420,8 +417,8 @@ class MoodyReport {
this.southPerimeterTable.midStationValue(this.southPerimeterTable.displacementsFromDatumPlane),
verticalCenterReadings, surfacePlate.reflectorFootSpacingInches, surfacePlate.surfacePlateHeightInches, surfacePlate.surfacePlateWidthInches, surfacePlate.suggestedDiagonalInset)

// Moody uses North Perimeter Line as the example, for the other one's it requires a bit of thinking as to which
// diagonal line values need to be copied to the other perimeter lines for consistency.
// Moody uses the North Perimeter Line as an example; for the other one's, it requires a bit of thinking as to which
// diagonal line values need to be copied to the other perimeter lines for consistency (with the example).

// Copy value in Column #6 of NE end of NE-SW diagonal in to Columns #5 and #6 for perimeter lines.
this.northPerimeterTable.cumulativeCorrectionFactors.unshift(this.topStartingDiagonalTable.displacementsFromDatumPlane[0])
Expand All @@ -442,7 +439,7 @@ class MoodyReport {
this.westPerimeterTable.displacementsFromDatumPlane.unshift(this.topStartingDiagonalTable.displacementsFromDatumPlane[0])
this.westPerimeterTable.displacementsFromDatumPlane.unshift(this.bottomStartingDiagonalTable.displacementsFromDatumPlane.at(-1))

// Moody uses the Horizontal Center Line as the example, for the other one (Vertical Center Line), it requires a bit of
// Moody uses the Horizontal Center Line as an example; for the other one (Vertical Center Line), it requires a bit of
// thinking as to which perimeter line values need to be copied to the other center line for consistency.

// Enter the value for the midpoint of the east perimeter line opposite the first station in Columns #5 and #6.
Expand Down

0 comments on commit f7f8c60

Please sign in to comment.