feat: Conway notation page working
This commit is contained in:
parent
af2d9e02c7
commit
cbe44238a1
@ -7,6 +7,11 @@
|
|||||||
|
|
||||||
<body>
|
<body>
|
||||||
<h3>Debugging</h3>
|
<h3>Debugging</h3>
|
||||||
|
<h4>Embedded VRML/X3D display</h4>
|
||||||
|
Write to the JavaScript console: <br/>
|
||||||
|
<label for="vrml97">Generated VRML97 specifications</label>
|
||||||
|
<input type="checkbox" id="vrml97">
|
||||||
|
<br />
|
||||||
<h4>Java Geometry Applets</h4>
|
<h4>Java Geometry Applets</h4>
|
||||||
Trace the following to the JavaScript console: <br/>
|
Trace the following to the JavaScript console: <br/>
|
||||||
<label for="commands">Commands executed</label>
|
<label for="commands">Commands executed</label>
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
|
// This file is a bit misnamed, as it has options for giveAwrl, too.
|
||||||
|
|
||||||
export const flags = [
|
export const flags = [
|
||||||
'color', 'commands', 'showall', 'showaux', 'algebra'] as const
|
'color', 'commands', 'showall', 'showaux', 'algebra', 'vrml97'] as const
|
||||||
export type FlagType = (typeof flags)[number]
|
export type FlagType = (typeof flags)[number]
|
||||||
export type ConfigType = Partial<Record<FlagType, boolean>>
|
export type ConfigType = Partial<Record<FlagType, boolean>>
|
||||||
|
|
||||||
|
266
src/conway.civet
266
src/conway.civet
@ -92,6 +92,9 @@ function orb(r: number, n: number,
|
|||||||
for i of [0...n]
|
for i of [0...n]
|
||||||
[r*Math.cos(rho + i*theta), r*Math.sin(rho + i*theta), height] as XYZ
|
[r*Math.cos(rho + i*theta), r*Math.sin(rho + i*theta), height] as XYZ
|
||||||
|
|
||||||
|
operator add(a: XYZ, b: XYZ)
|
||||||
|
accumulate copy(a), b
|
||||||
|
|
||||||
seeds :=
|
seeds :=
|
||||||
P: (n: number) => // Prism
|
P: (n: number) => // Prism
|
||||||
unless n then n = 3
|
unless n then n = 3
|
||||||
@ -130,7 +133,7 @@ seeds :=
|
|||||||
depth := Math.sqrt (1-c)/(1+c)
|
depth := Math.sqrt (1-c)/(1+c)
|
||||||
height := 2*Math.sqrt 1/(1 - c*c)
|
height := 2*Math.sqrt 1/(1 - c*c)
|
||||||
xyz := orb baseRadius, n, depth
|
xyz := orb baseRadius, n, depth
|
||||||
edgeMid2 := add xyz[0], xyz[1]
|
edgeMid2 := xyz[0] add xyz[1]
|
||||||
xyz.push [0, 0, depth-height]
|
xyz.push [0, 0, depth-height]
|
||||||
face := ([i, (i+1)%n, n] for i of [0...n])
|
face := ([i, (i+1)%n, n] for i of [0...n])
|
||||||
face.unshift [n-1..0]
|
face.unshift [n-1..0]
|
||||||
@ -158,7 +161,7 @@ function kisjoin(P: Polyhedron, notation: string,
|
|||||||
// first collect a directory from face indices to new vertex numbers
|
// first collect a directory from face indices to new vertex numbers
|
||||||
nextVertex .= P.xyz.length
|
nextVertex .= P.xyz.length
|
||||||
newVixes :=
|
newVixes :=
|
||||||
for f of P.face
|
for each f of P.face
|
||||||
!digits or f.length is in allowed ? nextVertex++ : 0
|
!digits or f.length is in allowed ? nextVertex++ : 0
|
||||||
if nextVertex is P.xyz.length then return P // nothing to do
|
if nextVertex is P.xyz.length then return P // nothing to do
|
||||||
xyz := P.xyz ++ faceCenters(P).filter (f,ix) => newVixes[ix]
|
xyz := P.xyz ++ faceCenters(P).filter (f,ix) => newVixes[ix]
|
||||||
@ -179,11 +182,13 @@ function kisjoin(P: Polyhedron, notation: string,
|
|||||||
if pw < w // avoid adding same face twice
|
if pw < w // avoid adding same face twice
|
||||||
face.push [v, pw, newVixes[neighbor], w]
|
face.push [v, pw, newVixes[neighbor], w]
|
||||||
else face.push [v, pw, w]
|
else face.push [v, pw, w]
|
||||||
adjustXYZ({face, xyz}, notation, 3)
|
adjustXYZ {face, xyz}, notation, 3
|
||||||
|
|
||||||
|
// how enums ought to work?
|
||||||
|
FromCenter := Symbol()
|
||||||
|
AlongEdge := Symbol()
|
||||||
|
type Gyway = typeof FromCenter | typeof AlongEdge
|
||||||
|
|
||||||
enum Gyway
|
|
||||||
FromCenter
|
|
||||||
AlongEdge
|
|
||||||
function gyropel(P: Polyhedron, notation: string,
|
function gyropel(P: Polyhedron, notation: string,
|
||||||
digits: string, ...ways: Gyway[]): Polyhedron
|
digits: string, ...ways: Gyway[]): Polyhedron
|
||||||
// gyro and propellor are closely related operations. Both of them add new
|
// gyro and propellor are closely related operations. Both of them add new
|
||||||
@ -194,7 +199,59 @@ function gyropel(P: Polyhedron, notation: string,
|
|||||||
// they are just connected in sequence. For completeness, we also allow
|
// they are just connected in sequence. For completeness, we also allow
|
||||||
// both at the same time, which is equivalent to propellor followed by kis
|
// both at the same time, which is equivalent to propellor followed by kis
|
||||||
// just on the new rotated faces.
|
// just on the new rotated faces.
|
||||||
// TO BE IMPLEMENTED
|
fromCenter := FromCenter is in ways
|
||||||
|
alongEdge := AlongEdge is in ways
|
||||||
|
unless fromCenter or alongEdge then return P // nothing to do
|
||||||
|
allowed := parseSides digits
|
||||||
|
// first collect a directory from directed edges to new vertex numbers
|
||||||
|
xyz := P.xyz.slice()
|
||||||
|
startV := xyz.length
|
||||||
|
edgeV: number[][] := []
|
||||||
|
for each f of P.face
|
||||||
|
if digits and f.length is not in allowed then continue
|
||||||
|
for each v, ix of f
|
||||||
|
pv := f æ (ix-1)
|
||||||
|
(edgeV[pv] ??= [])[v] = xyz.length
|
||||||
|
xyz.push lerp xyz[pv], xyz[v], 1/3
|
||||||
|
if xyz.length is startV then return P // nothing to do
|
||||||
|
|
||||||
|
// Now revisit each face, accumulating the new faces.
|
||||||
|
face: Face[] := []
|
||||||
|
centers: XYZ[] := fromCenter ? faceCenters P : []
|
||||||
|
for each f, fx of P.face
|
||||||
|
if digits and f.length is not in allowed
|
||||||
|
// Just collect all of the vertices around
|
||||||
|
newFace: Face := []
|
||||||
|
for each v, ix of f
|
||||||
|
pv := f æ (ix-1)
|
||||||
|
reverseV := edgeV[v]?[pv] ?? -1
|
||||||
|
if reverseV >= 0 then newFace.push reverseV
|
||||||
|
newFace.push v
|
||||||
|
face.push newFace
|
||||||
|
continue
|
||||||
|
centerV := xyz.length
|
||||||
|
if fromCenter then xyz.push centers[fx]
|
||||||
|
aroundOutside: Face .= []
|
||||||
|
for each v, ix of f
|
||||||
|
pv := f æ (ix-1)
|
||||||
|
ppv := f æ (ix-2)
|
||||||
|
firstNew := edgeV[ppv][pv]
|
||||||
|
newSection := [firstNew]
|
||||||
|
reverseV := edgeV[pv][ppv] ?? -1
|
||||||
|
if reverseV >= 0 then newSection.push reverseV
|
||||||
|
newSection.push pv
|
||||||
|
secondNew := edgeV[pv][v]
|
||||||
|
if alongEdge
|
||||||
|
newSection.push secondNew
|
||||||
|
face.push newSection
|
||||||
|
if fromCenter then face.push ð centerV, firstNew, secondNew
|
||||||
|
else aroundOutside.push firstNew
|
||||||
|
else if fromCenter
|
||||||
|
newSection.push secondNew, centerV
|
||||||
|
face.push newSection
|
||||||
|
else aroundOutside ++= newSection
|
||||||
|
if aroundOutside.length then face.push aroundOutside
|
||||||
|
adjustXYZ {face, xyz}, notation, 3
|
||||||
|
|
||||||
function parseSides(digits: string): number[]
|
function parseSides(digits: string): number[]
|
||||||
unless digits return []
|
unless digits return []
|
||||||
@ -218,17 +275,41 @@ transforms :=
|
|||||||
kisjoin P, notation, digits, false
|
kisjoin P, notation, digits, false
|
||||||
j: (P: Polyhedron, notation: string, digits: string) => // join
|
j: (P: Polyhedron, notation: string, digits: string) => // join
|
||||||
kisjoin P, notation, digits, true
|
kisjoin P, notation, digits, true
|
||||||
|
g: (P: Polyhedron, notation: string, digits: string) => // gyro
|
||||||
|
gyropel P, notation, digits, FromCenter
|
||||||
|
p: (P: Polyhedron, notation: string, digits: string) => // propellor
|
||||||
|
gyropel P, notation, digits, AlongEdge
|
||||||
|
f: (P: Polyhedron, notation: string, digits: string) => // fan [new? name?]
|
||||||
|
gyropel P, notation, digits, AlongEdge, FromCenter
|
||||||
|
r: (P: Polyhedron) => // reverse (mirror)
|
||||||
|
face: (f.toReversed() for each f of P.face)
|
||||||
|
xyz: (scale copy(v), -1 for each v of P.xyz)
|
||||||
|
d: (P: Polyhedron, notation: string, digits: string) => // dual
|
||||||
|
if digits
|
||||||
|
console.error `Ignoring ${digits} arg of d in ${notation}`
|
||||||
|
// Create a "fake" of P and adjust it (so we don't disturb the
|
||||||
|
// cached P), which will create the dual
|
||||||
|
parentNotation := notation[1+digits.length..]
|
||||||
|
adjustXYZ {face: P.face.slice(), P.xyz}, parentNotation, 1
|
||||||
|
polyCache.`d${parentNotation}`
|
||||||
|
c: (P: Polyhedron, notation: string, digits: string) => // canonicalize
|
||||||
|
face: P.face.slice()
|
||||||
|
xyz: canonicalXYZ P, notation, Number(digits) or 10
|
||||||
|
x: approxCanonicalize // iterative direct adjustment algorithm
|
||||||
type TransformOp = keyof typeof transforms
|
type TransformOp = keyof typeof transforms
|
||||||
|
|
||||||
function dispatch(op: string, digits: string,
|
function dispatch(op: string, digits: string,
|
||||||
P: Polyhedron, notation: string): Polyhedron
|
P: Polyhedron, mynotation: string): Polyhedron
|
||||||
|
// Note mynotation starts with op!
|
||||||
return .= P
|
return .= P
|
||||||
if op in seeds
|
if op in seeds
|
||||||
return = seeds[op as SeedOp] Number(digits) or 0
|
return = seeds[op as SeedOp] Number(digits) or 0
|
||||||
else if op in transforms
|
else if op in transforms
|
||||||
return = transforms[op as TransformOp] P, notation, digits
|
return = transforms[op as TransformOp] P, mynotation, digits
|
||||||
polyCache[notation] = return.value
|
else
|
||||||
|
console.error `Unknown operation ${op}${digits} in ${mynotation}.`
|
||||||
|
return = polyCache.T
|
||||||
|
polyCache[mynotation] = return.value
|
||||||
|
|
||||||
function topoDual(P: Polyhedron): Polyhedron
|
function topoDual(P: Polyhedron): Polyhedron
|
||||||
// Note this maintains correspondence between V and F indices, but
|
// Note this maintains correspondence between V and F indices, but
|
||||||
@ -273,7 +354,7 @@ function approxDualVertex(f: Face, v: XYZ[]): XYZ
|
|||||||
// to the line joining the origin to its nearest approach to the origin.
|
// to the line joining the origin to its nearest approach to the origin.
|
||||||
// This function returns the point closest to being on all of those planes
|
// This function returns the point closest to being on all of those planes
|
||||||
// (in the least-squares sense).
|
// (in the least-squares sense).
|
||||||
// This method seems to work well when the neighborhood of f is convex,
|
// This method seems to work OK when the neighborhood of f is convex,
|
||||||
// and very poorly otherwise. So it probably would not provide any better
|
// and very poorly otherwise. So it probably would not provide any better
|
||||||
// canonicalization than other methods of approximating the dual.
|
// canonicalization than other methods of approximating the dual.
|
||||||
normals := (tangentPoint(v[f æ (i-1)], v[f[i]]) for i of [0...f.length])
|
normals := (tangentPoint(v[f æ (i-1)], v[f[i]]) for i of [0...f.length])
|
||||||
@ -294,9 +375,12 @@ function det(a: XYZ, b: XYZ, c:XYZ)
|
|||||||
a[0]*b[1]*c[2] + a[1]*b[2]*c[0] + a[2]*b[0]*c[1]
|
a[0]*b[1]*c[2] + a[1]*b[2]*c[0] + a[2]*b[0]*c[1]
|
||||||
- a[2]*b[1]*c[0] - a[1]*b[0]*c[2] - a[0]*b[2]*c[1]
|
- a[2]*b[1]*c[0] - a[1]*b[0]*c[2] - a[0]*b[2]*c[1]
|
||||||
|
|
||||||
|
operator sub(a: XYZ, b: XYZ)
|
||||||
|
diminish copy(a), b
|
||||||
|
|
||||||
function tangentPoint(v: XYZ, w: XYZ) // closest point on vw to origin
|
function tangentPoint(v: XYZ, w: XYZ) // closest point on vw to origin
|
||||||
d := sub w,v
|
d := w sub v
|
||||||
sub v, scale d, d dot v / mag2 d
|
v sub scale d, d dot v / mag2 d
|
||||||
|
|
||||||
function faceCenters(P: Polyhedron): XYZ[]
|
function faceCenters(P: Polyhedron): XYZ[]
|
||||||
for each face of P.face
|
for each face of P.face
|
||||||
@ -307,7 +391,7 @@ function adjustXYZ(P: Polyhedron, notation: string, iterations = 1): Polyhedron
|
|||||||
dualNotation := 'd' + notation
|
dualNotation := 'd' + notation
|
||||||
D .= topoDual P
|
D .= topoDual P
|
||||||
if dualNotation in polyCache
|
if dualNotation in polyCache
|
||||||
console.error 'Error: Creating', notation, 'after its dual'
|
console.error 'Creating', notation, '_after_ its dual'
|
||||||
D = polyCache[dualNotation]
|
D = polyCache[dualNotation]
|
||||||
for iter of [1..iterations]
|
for iter of [1..iterations]
|
||||||
D.xyz = reciprocalC P
|
D.xyz = reciprocalC P
|
||||||
@ -320,6 +404,143 @@ function reciprocalC(P: Polyhedron): XYZ[]
|
|||||||
for each v of return.value
|
for each v of return.value
|
||||||
scale v, 1/mag2 v
|
scale v, 1/mag2 v
|
||||||
|
|
||||||
|
function canonicalXYZ(P: Polyhedron, notation: string, iterations: number): XYZ[]
|
||||||
|
dualNotation := 'd' + notation
|
||||||
|
D .= topoDual P
|
||||||
|
if dualNotation in polyCache
|
||||||
|
console.error 'Creating', notation, '_after_ its dual'
|
||||||
|
D = polyCache[dualNotation]
|
||||||
|
tempP := Object.assign({}, P) // algorithm is read-only on original data
|
||||||
|
if iterations < 1 then iterations = 1
|
||||||
|
for iter of [1..iterations]
|
||||||
|
D.xyz = reciprocalN tempP
|
||||||
|
tempP.xyz = reciprocalN D
|
||||||
|
polyCache[dualNotation] = D
|
||||||
|
tempP.xyz
|
||||||
|
|
||||||
|
operator cross(v: XYZ, w: XYZ): XYZ
|
||||||
|
[ v[1]*w[2] - v[2]*w[1], v[2]*w[0] - v[0]*w[2], v[0]*w[1] - v[1]*w[0] ]
|
||||||
|
|
||||||
|
function reciprocalN(P: Polyhedron): XYZ[]
|
||||||
|
for each f of P.face
|
||||||
|
centroid := ð 0, 0, 0
|
||||||
|
normal := ð 0, 0, 0
|
||||||
|
meanEdgeRadius .= 0
|
||||||
|
for each vlabel, ix of f
|
||||||
|
v := P.xyz[vlabel]
|
||||||
|
accumulate centroid, v
|
||||||
|
pv := P.xyz[f æ (ix-1)]
|
||||||
|
ppv := P.xyz[f æ (ix-2)]
|
||||||
|
// original doc says unit normal but below isn't. Didn't help to try, tho
|
||||||
|
nextNormal := (pv sub ppv) cross (v sub pv)
|
||||||
|
// or instead, just chop down big ones: (didn't work either)
|
||||||
|
// magNext := mag nextNormal
|
||||||
|
// if magNext > 1 then scale nextNormal, 1/magNext
|
||||||
|
accumulate normal, nextNormal
|
||||||
|
meanEdgeRadius += mag tangentPoint pv, v
|
||||||
|
scale centroid, 1/f.length
|
||||||
|
scale normal, 1/mag normal
|
||||||
|
meanEdgeRadius /= f.length
|
||||||
|
scale normal, centroid dot normal
|
||||||
|
scale normal, 1/mag2 normal // invert in unit sphere
|
||||||
|
scale normal, (1 + meanEdgeRadius)/2
|
||||||
|
|
||||||
|
operator dist(a: XYZ, b: XYZ) mag a sub b
|
||||||
|
|
||||||
|
// adapted from Polyhedronisme https://levskaya.github.io/polyhedronisme/
|
||||||
|
function approxCanonicalize(P: Polyhedron, notation: string,
|
||||||
|
digits: String): Polyhedron
|
||||||
|
THRESHOLD := 1e-6
|
||||||
|
// A difficulty is that the planarizing sometimes has the effect of
|
||||||
|
// "folding over" neighboring faces, in which case all is lost.
|
||||||
|
// Keeping the weight of the edge smoothing high compared to planarizing
|
||||||
|
// seems to help with that.
|
||||||
|
EDGE_SMOOTH_FACTOR := 0.5
|
||||||
|
PLANARIZE_FACTOR := 0.1
|
||||||
|
edge := edges P
|
||||||
|
xyz := P.xyz.map copy
|
||||||
|
V := xyz.length
|
||||||
|
normalizeEdges xyz, edge
|
||||||
|
for iter of [1..Number(digits) or 10]
|
||||||
|
start := xyz.map copy
|
||||||
|
smoothEdgeDists xyz, edge, EDGE_SMOOTH_FACTOR
|
||||||
|
normalizeEdges xyz, edge
|
||||||
|
planarize xyz, P.face, PLANARIZE_FACTOR
|
||||||
|
normalizeEdges xyz, edge
|
||||||
|
if Math.max(...(xyz[i] dist start[i] for i of [0...V])) < THRESHOLD
|
||||||
|
break
|
||||||
|
{face: P.face.slice(), xyz}
|
||||||
|
|
||||||
|
type Edge = [number, number]
|
||||||
|
function edges(P:Polyhedron): Edge[]
|
||||||
|
return: Edge[] := []
|
||||||
|
for each f of P.face
|
||||||
|
for each v, ix of f
|
||||||
|
pv := f æ (ix-1)
|
||||||
|
if pv < v then return.value.push ð pv, v
|
||||||
|
|
||||||
|
function normalizeEdges(xyz: XYZ[], edge: Edge[]): void
|
||||||
|
// Adjusts xyz so that edge tangentpoints have centroid at origin and
|
||||||
|
// mean radius 1
|
||||||
|
edgeP .= edge.map ([a,b]) => tangentPoint xyz[a], xyz[b]
|
||||||
|
edgeCentroid := centroid edgeP
|
||||||
|
xyz.forEach (pt) => diminish pt, edgeCentroid
|
||||||
|
edgeScale := 1/(mean edge.map ([a,b]) => mag tangentPoint xyz[a], xyz[b])
|
||||||
|
xyz.forEach (pt) => scale pt, edgeScale
|
||||||
|
|
||||||
|
function centroid(xyz: XYZ[]): XYZ
|
||||||
|
scale xyz.reduce(accumulate, ð 0,0,0), 1/xyz.length
|
||||||
|
|
||||||
|
function smoothEdgeDists(xyz: XYZ[], edge: Edge[], fudge: number): void
|
||||||
|
// Attempts in the most straightforward way possible to reduce the
|
||||||
|
// variance of the radii of the edgepoints
|
||||||
|
V := xyz.length
|
||||||
|
adj := (ð 0,0,0 for i of [1..V])
|
||||||
|
edgeDistsStart := edge.map ([a,b]) => mag tangentPoint xyz[a], xyz[b]
|
||||||
|
for each [a,b] of edge
|
||||||
|
t := tangentPoint xyz[a], xyz[b]
|
||||||
|
scale t, (1 - mag t)/2
|
||||||
|
accumulate adj[a], t
|
||||||
|
accumulate adj[b], t
|
||||||
|
for i of [0...V]
|
||||||
|
accumulate xyz[i], scale adj[i], fudge
|
||||||
|
edgeDistsEnd := edge.map ([a,b]) => mag tangentPoint xyz[a], xyz[b]
|
||||||
|
|
||||||
|
function summary(data: number[])
|
||||||
|
[Math.min(...data), Math.max(...data), mean(data),
|
||||||
|
mean(data.map((x) => Math.abs(1-x)))]
|
||||||
|
|
||||||
|
function planarize(xyz: XYZ[], face: Face[], fudge: number): void
|
||||||
|
V := xyz.length
|
||||||
|
adj := (ð 0,0,0 for i of [1..V])
|
||||||
|
for each f of face
|
||||||
|
if f.length is 3 then continue // triangles always planar
|
||||||
|
fxyz := (xyz[v] for each v of f)
|
||||||
|
c := centroid fxyz
|
||||||
|
n := meanNormal fxyz
|
||||||
|
if c dot n < 0 then scale n, -1
|
||||||
|
for each v of f
|
||||||
|
accumulate adj[v], scale copy(n), n dot (c sub xyz[v])
|
||||||
|
for i of [0...V]
|
||||||
|
accumulate xyz[i], scale adj[i], fudge
|
||||||
|
|
||||||
|
function meanNormal(xyz: XYZ[]): XYZ
|
||||||
|
mNormal := ð 0,0,0
|
||||||
|
[v1, v2] .= xyz.slice(-2);
|
||||||
|
for each v3 of xyz
|
||||||
|
nextNormal := (v2 sub v1) cross (v3 sub v2)
|
||||||
|
magNext := mag nextNormal
|
||||||
|
// reduce influence of long edges? (didn't seem to help in brief testing)
|
||||||
|
// if magNext > 1 then scale nextNormal, 1/Math.sqrt magNext
|
||||||
|
accumulate mNormal, nextNormal
|
||||||
|
[v1, v2] = [v2, v3] // shift over one
|
||||||
|
scale mNormal, 1/mag mNormal
|
||||||
|
|
||||||
|
function mean(a: number[])
|
||||||
|
m .= 0
|
||||||
|
m += e for each e of a
|
||||||
|
m / a.length
|
||||||
|
|
||||||
// arithmetic on 3-vectors
|
// arithmetic on 3-vectors
|
||||||
function accumulate(basket: XYZ, egg: XYZ)
|
function accumulate(basket: XYZ, egg: XYZ)
|
||||||
basket[0] += egg[0]
|
basket[0] += egg[0]
|
||||||
@ -336,24 +557,27 @@ function diminish(basket: XYZ, egg: XYZ)
|
|||||||
function copy(a: XYZ)
|
function copy(a: XYZ)
|
||||||
ð a[0], a[1], a[2]
|
ð a[0], a[1], a[2]
|
||||||
|
|
||||||
function add(a: XYZ, b: XYZ)
|
|
||||||
accumulate copy(a), b
|
|
||||||
|
|
||||||
function sub(a: XYZ, b: XYZ)
|
|
||||||
diminish copy(a), b
|
|
||||||
|
|
||||||
function mag2(a: XYZ)
|
function mag2(a: XYZ)
|
||||||
a[0]*a[0] + a[1]*a[1] + a[2]*a[2]
|
a[0]*a[0] + a[1]*a[1] + a[2]*a[2]
|
||||||
|
|
||||||
function mag(a: XYZ)
|
function mag(a: XYZ)
|
||||||
Math.sqrt mag2 a
|
Math.sqrt mag2 a
|
||||||
|
|
||||||
|
function normalize(v: XYZ)
|
||||||
|
scale v, 1/mag v
|
||||||
|
|
||||||
|
function unit
|
||||||
|
|
||||||
function scale(subject: XYZ, by: number)
|
function scale(subject: XYZ, by: number)
|
||||||
subject[0] *= by
|
subject[0] *= by
|
||||||
subject[1] *= by
|
subject[1] *= by
|
||||||
subject[2] *= by
|
subject[2] *= by
|
||||||
subject
|
subject
|
||||||
|
|
||||||
|
function lerp(start: XYZ, end: XYZ, howFar: number)
|
||||||
|
basket := scale copy(start), 1-howFar
|
||||||
|
accumulate basket, scale copy(end), howFar
|
||||||
|
|
||||||
// Feedback
|
// Feedback
|
||||||
|
|
||||||
function inform(x: string)
|
function inform(x: string)
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import ./deps/jquery.js
|
import ./deps/jquery.js
|
||||||
{convert} from ./deps/vrml1to97/index.js
|
{convert} from ./deps/vrml1to97/index.js
|
||||||
|
{ConfigType} from ./adapptypes.ts
|
||||||
|
|
||||||
knownExtensions := /[.](?:wrl|x3d|gltf|glb|obj|stl|ply)$/
|
knownExtensions := /[.](?:wrl|x3d|gltf|glb|obj|stl|ply)$/
|
||||||
certainlyHandled :=
|
certainlyHandled :=
|
||||||
@ -42,6 +43,7 @@ function makeBrowser(url: string, width: string, height: string)
|
|||||||
text .= await response.text()
|
text .= await response.text()
|
||||||
if /#\s*VRML\s*V?1[.]/i.test text
|
if /#\s*VRML\s*V?1[.]/i.test text
|
||||||
text = convert text
|
text = convert text
|
||||||
|
maybeDebug text
|
||||||
browser3D.baseURL = url
|
browser3D.baseURL = url
|
||||||
scene := await browser3D.createX3DFromString text
|
scene := await browser3D.createX3DFromString text
|
||||||
browser3D.replaceWorld scene
|
browser3D.replaceWorld scene
|
||||||
@ -90,8 +92,9 @@ links.after ->
|
|||||||
canvas.style.marginRight = imgSty.getPropertyValue 'margin-right'
|
canvas.style.marginRight = imgSty.getPropertyValue 'margin-right'
|
||||||
if float is 'right'
|
if float is 'right'
|
||||||
canvas.style.left = $(eye).width() + 'px'
|
canvas.style.left = $(eye).width() + 'px'
|
||||||
else
|
else if float is 'left'
|
||||||
canvas.style.right = $(eye).width() + 'px'
|
canvas.style.right = $(eye).width() + 'px'
|
||||||
|
else canvas.style.left = floatLike.offsetLeft
|
||||||
$(eye).append canvas
|
$(eye).append canvas
|
||||||
if state is 'off'
|
if state is 'off'
|
||||||
eye.setAttribute 'data', 'on'
|
eye.setAttribute 'data', 'on'
|
||||||
@ -102,6 +105,10 @@ links.after ->
|
|||||||
$(eye).css 'text-decoration', 'none'
|
$(eye).css 'text-decoration', 'none'
|
||||||
$(eye.lastElementChild as Element).hide()
|
$(eye.lastElementChild as Element).hide()
|
||||||
|
|
||||||
|
function maybeDebug(vrml: string)
|
||||||
|
config := await browser.storage.local.get(['vrml97']) as ConfigType
|
||||||
|
if config.vrml97 then console.log 'Generated VRML97', vrml
|
||||||
|
|
||||||
let conwayBrowser: any
|
let conwayBrowser: any
|
||||||
madeConway .= false
|
madeConway .= false
|
||||||
|
|
||||||
@ -117,6 +124,7 @@ if inputs.length is 1
|
|||||||
notation := $('input[name="notation"]').val()
|
notation := $('input[name="notation"]').val()
|
||||||
unless notation then return
|
unless notation then return
|
||||||
vrml := conway.generateVRML notation.toString()
|
vrml := conway.generateVRML notation.toString()
|
||||||
|
maybeDebug vrml
|
||||||
unless madeConway
|
unless madeConway
|
||||||
{canvas, browser3D} := await makeBrowser '', '250px', '250px'
|
{canvas, browser3D} := await makeBrowser '', '250px', '250px'
|
||||||
conwayBrowser = browser3D
|
conwayBrowser = browser3D
|
||||||
|
Loading…
Reference in New Issue
Block a user