feat: Reimplementation of prism generator #65
166
src/prism.civet
166
src/prism.civet
@ -74,6 +74,15 @@ DEF Far Viewpoint {
|
||||
// Useful constants
|
||||
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
|
||||
shapeName.findIndex((sn) => name is in sn)
|
||||
|
||||
@ -81,40 +90,149 @@ type ShapeMethod = (n: number, theta: number, d?: number) => string
|
||||
shapeMethod: ShapeMethod[] := []
|
||||
shapeMethods: Record<string, ShapeMethod> :=
|
||||
prism: (n, theta) =>
|
||||
name := 'Prism'
|
||||
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])
|
||||
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])
|
||||
laterFaces vrml, 'Prism', '0.3 0.5 0.9', sides
|
||||
laterLines vrml, 'Prism', sides
|
||||
laterFaces vrml, name, '0.3 0.5 0.9', sides
|
||||
laterLines vrml, name, sides
|
||||
emitObject vrml
|
||||
|
||||
dipyr: (n, theta) =>
|
||||
name := 'Dipyramid'
|
||||
c := 1/Math.cos 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])
|
||||
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
|
||||
emitObject vrml
|
||||
|
||||
compound: (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
|
||||
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)
|
||||
theta := tau * d/n
|
||||
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]
|
||||
[r*Math.cos(rho+i*theta), r*Math.sin(rho+i*theta), height]
|
||||
|
||||
function firstFaces(container: string[], name: string, color: string,
|
||||
coords: number[][], faces: number[][]): void
|
||||
startShape container, color
|
||||
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 alternate<T>(a: T[], b: T[])
|
||||
return: T[] := []
|
||||
return.value.push n, b[i] for each n, i of a
|
||||
|
||||
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 {',
|
||||
' material Material {',
|
||||
` diffuseColor ${color} } }`
|
||||
` ${colType}Color ${color} } }`
|
||||
|
||||
function laterFaces(container: string[], name: string, color: string,
|
||||
faces: number[][]): void
|
||||
@ -149,7 +273,7 @@ function laterFaces(container: string[], name: string, color: string,
|
||||
container.push '] } }'
|
||||
|
||||
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 {',
|
||||
`coord USE ${name}Coords`,
|
||||
'coordIndex ['
|
||||
|
Loading…
Reference in New Issue
Block a user