feat: Reimplementation of prism generator #65

Merged
glen merged 3 commits from prism into main 2024-02-19 21:52:56 +00:00
Showing only changes of commit f089f02f0e - Show all commits

View File

@ -74,6 +74,15 @@ DEF Far Viewpoint {
// Useful constants // Useful constants
tau := 2*Math.PI tau := 2*Math.PI
// Array "postscript" operator
operator ps<T>(main: T[], extra: T): T[]
main.push extra
main
// Array "preface" operator
operator pf<T>(extra: T, main: T[]): T[]
main.unshift extra
main
function shIx(name: string): number function shIx(name: string): number
shapeName.findIndex((sn) => name is in sn) shapeName.findIndex((sn) => name is in sn)
@ -81,40 +90,149 @@ type ShapeMethod = (n: number, theta: number, d?: number) => string
shapeMethod: ShapeMethod[] := [] shapeMethod: ShapeMethod[] := []
shapeMethods: Record<string, ShapeMethod> := shapeMethods: Record<string, ShapeMethod> :=
prism: (n, theta) => prism: (n, theta) =>
name := 'Prism'
h := Math.sin theta/2 h := Math.sin theta/2
vrml: string[] := []
coords := orb(1, n, h, theta) ++ orb(1, n, -h, theta) ++ [[0,0,h], [0,0,-h]] coords := orb(1, n, h, theta) ++ orb(1, n, -h, theta) ps [0,0,h] ps [0,0,-h]
top := ([i, (i+1)%n, 2*n] for i of [0...n]) top := ([i, (i+1)%n, 2*n] for i of [0...n])
bottom := ([(i+1)%n + n, i+n, 2*n+1] for i of [0...n]) bottom := ([(i+1)%n + n, i+n, 2*n+1] for i of [0...n])
firstFaces vrml, 'Prism', '0.8 0.7 0.5', coords, top ++ bottom vrml := firstFaces name, '0.8 0.7 0.5', coords, top ++ bottom
sides := ([i, (i+1)%n, (i+1)%n + n, i+n] for i of [0...n]) sides := ([i, (i+1)%n, (i+1)%n + n, i+n] for i of [0...n])
laterFaces vrml, 'Prism', '0.3 0.5 0.9', sides laterFaces vrml, name, '0.3 0.5 0.9', sides
laterLines vrml, 'Prism', sides laterLines vrml, name, sides
emitObject vrml emitObject vrml
dipyr: (n, theta) => dipyr: (n, theta) =>
name := 'Dipyramid' name := 'Dipyramid'
c := 1/Math.cos theta/2 c := 1/Math.cos theta/2
d := 1/Math.sin theta/2 d := 1/Math.sin theta/2
vrml: string[] := []
coords := [[0,0,d]] ++ orb(c, n, 0, theta, 0.5) ++ [[0,0,-d]] coords := [0,0,d] pf orb(c, n, 0, theta, 0.5) ps [0,0,-d]
cap := ([0, i, i%n + 1] for i of [1..n]) cap := ([0, i, i%n + 1] for i of [1..n])
cup := ([i%n + 1, i, n+1] for i of [1..n]) cup := ([i%n + 1, i, n+1] for i of [1..n])
firstFaces vrml, name, '0.9 0.3 0.3', coords, cap++cup vrml := firstFaces name, '0.9 0.3 0.3', coords, cap++cup
edges := [[1..n]] ++ ([0, i, n+1] for i of [1..n]) edges := [1..n] pf ([0, i, n+1] for i of [1..n])
laterLines vrml, name, edges laterLines vrml, name, edges
emitObject vrml emitObject vrml
compound: (n, theta) => compound: (n, theta) =>
shapeMethod[shIx 'prism'](n, theta) + shapeMethod[shIx 'dipyr'](n, theta) shapeMethod[shIx 'prism'](n, theta) + shapeMethod[shIx 'dipyr'](n, theta)
antip: (n, theta) =>
name := 'Antiprism'
{h, r} := antiprismDims theta
coords := (orb(r, n, h, theta) ++ orb(r, n, -h, theta, 0.5)
ps [0,0,h] ps [0,0,-h])
top := ([i, 2*n, (i+1)%n] for i of [0...n])
bottom := ([(i+1)%n + n, 2*n + 1, i+n] for i of [0...n])
vrml := firstFaces name, '0.8 0.7 0.5', coords, top ++ bottom
topsides := ([(i+1)%n, i+n, i] for i of [0...n])
botsides := ([i, i+n, (n+i-1)%n + n] for i of [0...n])
laterFaces vrml, name, '0.9 0.3 0.4', topsides ++ botsides
laterLines vrml, name, [[0...n] ps 0, [n...2*n] ps n, ...topsides]
emitObject vrml
trap: (n, theta) =>
name := 'Trapezohedron'
{h, r} := antiprismDims theta
[t, z] := dualPoint r*Math.cos(theta/2), h, r, -h
botzig := orb(t, n, -z, theta) ps [0, 0, -1/h]
topzig := orb(t, n, z, theta, 0.5) ps [0, 0, 1/h]
coords := alternate botzig, topzig
faces :=
for i of [0...2*n]
if i%2
[2*n + 1, (i+2)%(2*n), (i+1)%(2*n), i]
else [2*n, i, i+1, (i+2)%(2*n)]
vrml := firstFaces name, '0.3 0.5 0.9', coords, faces
edges :=
for i of [0...2*n]
i%2 ? [2*n + 1, i, (i + 1)%(2*n)] : [2*n, i, i+1]
laterLines vrml, name, edges
emitObject vrml
'antiprism + trap': (n, theta) =>
shapeMethod[shIx 'antip'](n, theta) + shapeMethod[shIx 'trap'](n, theta)
crossed: (n, theta) => // should really unify with antiprism, code is so close
name := 'CrossedAntiprism'
{h, r} := crossedDims theta
coords := (orb(r, n, h, theta) ++ orb(-r, n, -h, theta, 0.5)
ps [0,0,h] ps [0,0,-h])
top := ([i, (i+1)%n, 2*n] for i of [0...n])
bottom := ([(i+1)%n + n, i+n, 2*n + 1] for i of [0...n])
vrml := firstFaces name, '0.8 0.7 0.5', coords, top ++ bottom
topsides := ([(i+1)%n, i+n, i] for i of [0...n])
botsides := ([i, i+n, (n+i-1)%n + n] for i of [0...n])
laterFaces vrml, name, '0.9 0.3 0.4', topsides ++ botsides
laterLines vrml, name, [[0...n] ps 0, [n...2*n] ps n, ...topsides]
emitObject vrml
concave: (n, theta, d) =>
name := 'ConcaveTrapezohedron'
{h, r} := crossedDims theta
[t, z] := dualPoint r*Math.cos(theta/2), h, -r, -h
d ??= Math.floor (n-1)/2 // won't be needed, for TypeScript's sake
eta := tau * (n-d)/n
botzig := orb(-t, n, -z, eta) ps [0, 0, -1/h]
topzig := orb(-t, n, z, eta, 0.5) ps [0, 0, 1/h]
coords := alternate botzig, topzig
halfFaces :=
for i of [0...2*n]
i%2 ? [(i+1)%(2*n), i, 2*n + 1] : [2*n, i, i+1]
otherFaces :=
for i of [0...2*n]
i%2 ? [2*n + 1, (i+2)%(2*n), (i+1)%(2*n)] : [2*n, i+1, (i+2)%(2*n)]
vrml := firstFaces name, '0.3 0.5 0.9', coords, halfFaces ++ otherFaces
laterLines vrml, name, halfFaces
emitObject vrml
'prism + concave': (n, theta, d) =>
shapeMethod[shIx 'cross'](n, theta) + shapeMethod[shIx 'conc'](n, theta, d)
polygon: (n, theta) =>
name := 'Polygon'
coords := orb(1, n, 0, theta) ps [0, 0, 0]
faces := ([i, (i+1)%n, n] for i of [0...n])
vrml := firstFaces name, '0.5 0.8 0.5', coords, faces
laterLines vrml, name, [[0...n] ps 0]
emitObject vrml
for key, method in shapeMethods for key, method in shapeMethods
shapeMethod[shIx key] = method shapeMethod[shIx key] = method
function antiprismDims(theta: number)
h .= Math.sqrt 1 - 4/(4 + 2*Math.cos(theta/2) - 2*Math.cos(theta))
r .= Math.sqrt 1 - h*h
f := Math.sqrt h*h + (r*Math.cos theta/2)**2
h /= f
r /= f
{h, r}
function crossedDims(theta: number)
r .= 2/Math.sqrt 4 - 2*Math.cos(theta/2) - 2*Math.cos(theta)
h .= Math.sqrt 1 - r*r
f .= Math.sqrt h*h + (r*Math.cos theta/2)**2
r /= f
h /= f
{h, r}
function dualPoint(x1: number, y1: number, x2: number, y2: number)
len := Math.sqrt (x2-x1)*(x2-x1) + (y2-y1)*(y2-y1)
vx := (y2 - y1)/len
vy := (x1 - x2)/len
d := vx*x1 + vy*y1
[vx/d, vy/d]
function vrmlBody(which: number, n: number, d: number) function vrmlBody(which: number, n: number, d: number)
theta := tau * d/n theta := tau * d/n
shapeMethod[which](n, theta, d) shapeMethod[which](n, theta, d)
@ -124,20 +242,26 @@ function orb(r: number, n: number, height: number, theta: number, t=0)
for i of [0...n] for i of [0...n]
[r*Math.cos(rho+i*theta), r*Math.sin(rho+i*theta), height] [r*Math.cos(rho+i*theta), r*Math.sin(rho+i*theta), height]
function firstFaces(container: string[], name: string, color: string, function alternate<T>(a: T[], b: T[])
coords: number[][], faces: number[][]): void return: T[] := []
startShape container, color return.value.push n, b[i] for each n, i of a
container.push 'geometry IndexedFaceSet {',
`coord DEF ${name}Coords Coordinate { point [`
container.push coord.join(' ') + ',' for each coord of coords
container.push '] }', 'creaseAngle 0 solid FALSE coordIndex ['
container.push face.join(', ') + ', -1,' for each face of faces
container.push '] } }'
function startShape(container: string[], color: string): void function firstFaces(name: string, color: string,
coords: number[][], faces: number[][])
return: string[] := []
startShape return.value, color
return.value.push 'geometry IndexedFaceSet {',
`coord DEF ${name}Coords Coordinate { point [`
return.value.push coord.join(' ') + ',' for each coord of coords
return.value.push '] }',
'creaseAngle 0 solid FALSE coordIndex ['
return.value.push face.join(', ') + ', -1,' for each face of faces
return.value.push '] } }'
function startShape(container: string[], color: string, colType = 'diffuse'): void
container.push 'Shape { appearance Appearance {', container.push 'Shape { appearance Appearance {',
' material Material {', ' material Material {',
` diffuseColor ${color} } }` ` ${colType}Color ${color} } }`
function laterFaces(container: string[], name: string, color: string, function laterFaces(container: string[], name: string, color: string,
faces: number[][]): void faces: number[][]): void
@ -149,7 +273,7 @@ function laterFaces(container: string[], name: string, color: string,
container.push '] } }' container.push '] } }'
function laterLines(container: string[], name: string, edges: number[][]): void function laterLines(container: string[], name: string, edges: number[][]): void
startShape container, '0 0 0' startShape container, '0 0 0', 'emissive' // per VRML97 standard
container.push 'geometry IndexedLineSet {', container.push 'geometry IndexedLineSet {',
`coord USE ${name}Coords`, `coord USE ${name}Coords`,
'coordIndex [' 'coordIndex ['