feat: Improve 3D operation
Working toward successfully rendering Book Eleven. Specific changes in this commit include: * Improvement to coordinate system/initial view for 3D constructions * More attention to ambient plane for some 2D commands * Add sphereSlider construction method for point * Add intersection construction method for circle (intersection of two spheres) * Fix display/non-display of perimeter of sectors * Add sphere construction by radius * Add polyhedron construction methods parallelepiped and pyramid
This commit is contained in:
parent
9e69613425
commit
a4f3a96d6e
@ -13,7 +13,8 @@ obs := new MutationObserver (mutationList) =>
|
||||
newNode := (newGenericNode as HTMLElement)
|
||||
newParent := (change.target as HTMLElement)
|
||||
unless newNode.tagName is 'APPLET' then continue
|
||||
unless newNode.getAttribute('code') is 'Geometry' then continue
|
||||
code := newNode.getAttribute('code')
|
||||
unless code is 'Geometry' or code is 'Geometry.class' then continue
|
||||
id .= newParent.getAttribute 'id'
|
||||
unless id
|
||||
id = 'joyceApplet' + joyceApplets.length
|
||||
|
@ -56,7 +56,7 @@ function vertFlipped(coords: number[], cdata: ConstructionData): XYZ
|
||||
coords = coords.slice()
|
||||
if cdata.is3d
|
||||
if coords[Z] then coords[Z] = -coords[Z]
|
||||
else coords[Y] = cdata.height - coords[Y]
|
||||
coords[Y] = cdata.height - coords[Y]
|
||||
return coords as XYZ
|
||||
|
||||
type ConstructionData
|
||||
@ -128,11 +128,12 @@ function postApplets(jApplets: AppletDescription[], codebase = '')
|
||||
if is3d
|
||||
depth .= jApp.width
|
||||
if jApp.height > depth then depth = jApp.height
|
||||
depth /= 8
|
||||
api.setCoordSystem
|
||||
-10, 10 + jApp.width,
|
||||
-10, 10 + jApp.height,
|
||||
-depth - 10, depth + 10,
|
||||
false
|
||||
-10 + jApp.width/6, 10 + 4*jApp.width/6,
|
||||
-10 + jApp.height/6, 10 + 4*jApp.height/6,
|
||||
-2*depth - 10, depth + 10,
|
||||
true
|
||||
api.setAxesVisible 3, false, false, false
|
||||
api.setGridVisible 3, false
|
||||
else
|
||||
@ -207,8 +208,7 @@ function dispatchJcommand(
|
||||
'title'
|
||||
if adapParams.config?.commands
|
||||
console.log 'Setting title to', value
|
||||
corner := cdata.is3d ? 'Corner(-1,1)' : 'Corner(1,1)'
|
||||
api.evalCommand `TitlePoint = ${corner}
|
||||
api.evalCommand `TitlePoint = Corner(1,1)
|
||||
Text("${value}", TitlePoint + (2,5))`
|
||||
'pivot'
|
||||
return // already handled in postApplets
|
||||
@ -485,7 +485,7 @@ function joyce2rgb(cname: string, backgroundRGB?: RGB): RGB
|
||||
/yellow/i
|
||||
[255,255,0]
|
||||
/random/i
|
||||
colorsea.random().lighten(40).rgb()
|
||||
colorsea.random().lighten(30).rgb()
|
||||
/background/i
|
||||
bg
|
||||
/brighter/i
|
||||
@ -572,6 +572,7 @@ classHandler: Record<JoyceClass, ClassHandler> :=
|
||||
return := freshCommander()
|
||||
{commands, callbacks, parts, auxiliaries} := return.value
|
||||
zeroVector := cdata.is3d ? 'Vector((0,0,0))' : 'Vector((0,0))'
|
||||
defaultPlane := cdata.is3d ? ', xOyPlane' : ''
|
||||
aux := name + 'aUx'
|
||||
pivotable := cdata.pivot and name !== pivotData[cdata.pivot].pivot
|
||||
parts[0].push name
|
||||
@ -684,13 +685,22 @@ classHandler: Record<JoyceClass, ClassHandler> :=
|
||||
'perpendicular'
|
||||
// Note only the two-point option implemented so far
|
||||
unless args.subpoints return
|
||||
inPlane := args.plane ? `,${args.plane[0]}` : defaultPlane
|
||||
[center, direction] := args.subpoints
|
||||
commands.push `${name} = Rotate(${direction}, pi/2, ${center})`
|
||||
commands.push
|
||||
`${name} = Rotate(${direction}, pi/2, ${center}${inPlane})`
|
||||
/proportion|similar/
|
||||
[source, displacement] :=
|
||||
proportionSimilar method, args, cdata, aux, commands, auxiliaries
|
||||
unless source then return
|
||||
commands.push `${name} = Translate(${source}, ${displacement})`
|
||||
'sphereSlider'
|
||||
sph := args.sphere?[0]
|
||||
unless sph then return
|
||||
commands.push `${name} = PointIn(${sph})`
|
||||
if args.scalar and args.scalar.length
|
||||
callbacks.push (api: AppletObject) =>
|
||||
api.setCoords name, ...vertFlipped(args.scalar or [], cdata)
|
||||
'vertex'
|
||||
commands.push
|
||||
`${name} = Vertex(${args.polygon?[0]},${args.scalar?[0]})`
|
||||
@ -836,22 +846,27 @@ classHandler: Record<JoyceClass, ClassHandler> :=
|
||||
callbacks.push (api: AppletObject) => api.setLabelVisible name, true
|
||||
parts[0].push ...ends
|
||||
|
||||
circle: (name, method, args) =>
|
||||
circle: (name, method, args, index, cdata) =>
|
||||
return := freshCommander()
|
||||
return.value.ends = ['', '']
|
||||
{commands, callbacks, parts, auxiliaries, ends} := return.value
|
||||
aux := name + 'aUx'
|
||||
parts[1].push name
|
||||
circle .= ''
|
||||
defaultPlane := cdata.is3d ? ', xOyPlane' : ''
|
||||
switch method
|
||||
'circumcircle'
|
||||
pt := args.subpoints
|
||||
unless pt and pt.length is 3 then return
|
||||
circle = `Circle(${pt.join ','})`
|
||||
'intersection'
|
||||
sph := args.sphere
|
||||
unless sph and sph.length is 2 then return
|
||||
circle = `IntersectConic(${sph[0]}, ${sph[1]})`
|
||||
'radius'
|
||||
pt := args.subpoints
|
||||
unless pt then return
|
||||
inPlane := args.plane ? `, ${args.plane[0]}` : ''
|
||||
inPlane := args.plane ? `, ${args.plane[0]}` : defaultPlane
|
||||
switch pt.length
|
||||
when 2
|
||||
[center, point] := pt
|
||||
@ -949,12 +964,14 @@ classHandler: Record<JoyceClass, ClassHandler> :=
|
||||
api.renameObject obj, newObj
|
||||
moreParts[1].push newObj
|
||||
|
||||
sector: (name, method, args, index) =>
|
||||
sector: (name, method, args, index, cdata) =>
|
||||
return := freshCommander()
|
||||
return.value.ends = ['', '']
|
||||
{commands, callbacks, parts, auxiliaries, ends} := return.value
|
||||
aux := name + 'aUx'
|
||||
parts[2].push name
|
||||
defaultPlane := cdata.is3d ? ', xOyPlane' : ''
|
||||
inPlane := args.plane ? `, ${args.plane[0]}` : defaultPlane
|
||||
switch method
|
||||
/arc|sector/
|
||||
unless args.subpoints?.length is 3 return
|
||||
@ -971,9 +988,10 @@ classHandler: Record<JoyceClass, ClassHandler> :=
|
||||
ends[0] = start
|
||||
ends[1] = end
|
||||
commands.push
|
||||
`${name} = ${prefix}Sector(${parms})`
|
||||
`${aux}1 = ${prefix}Arc(${parms})`
|
||||
`${name} = ${prefix}Sector(${parms}${inPlane})`
|
||||
`${aux}1 = ${prefix}Arc(${parms}${inPlane})`
|
||||
parts[1].push aux + 1
|
||||
auxiliaries.push aux + 1
|
||||
makeLinesInvisible callbacks, name
|
||||
|
||||
plane: (name, method, args) =>
|
||||
@ -990,22 +1008,86 @@ classHandler: Record<JoyceClass, ClassHandler> :=
|
||||
commands.push
|
||||
`${name} = PerpendicularPlane(${thru}, Line(${thru}, ${perp}))`
|
||||
|
||||
sphere: (name, method, args) => freshCommander()
|
||||
|
||||
polyhedron: (name, method, args, index) =>
|
||||
sphere: (name, method, args) =>
|
||||
return := freshCommander()
|
||||
return.value.ends = ['', '']
|
||||
{commands, callbacks, parts, auxiliaries, ends} := return.value
|
||||
aux := name + 'aUx'
|
||||
switch method
|
||||
'tetrahedron'
|
||||
parts[2].push name
|
||||
pt := args.subpoints
|
||||
if method is 'radius' and pt
|
||||
switch pt.length
|
||||
when 2
|
||||
[center, point] := pt
|
||||
ends[0] = center
|
||||
commands.push `${name} = Sphere(${center}, ${point})`
|
||||
when 3
|
||||
center := pt[0]
|
||||
ends[0] = center
|
||||
radius := `Distance(${pt[1]}, ${pt[2]})`
|
||||
commands.push `${name} = Sphere(${center}, ${radius})`
|
||||
|
||||
polyhedron: (name, method, args, index, cdata) =>
|
||||
return := freshCommander()
|
||||
return.value.ends = ['', '']
|
||||
{commands, callbacks, parts, auxiliaries, ends} := return.value
|
||||
aux := geoname name + 'aUx', cdata.elements, 'point'
|
||||
switch method
|
||||
'parallelepiped'
|
||||
pt .= args.subpoints
|
||||
unless pt and pt.length is 4 then return
|
||||
// create all of the vertices we will need:
|
||||
commands.push
|
||||
`${aux}4 = ${pt[2]} + ${pt[1]} - ${pt[0]}`
|
||||
`${aux}5 = ${pt[3]} + ${pt[1]} - ${pt[0]}`
|
||||
`${aux}6 = ${pt[3]} + ${pt[2]} - ${pt[0]}`
|
||||
`${aux}7 = ${pt[3]} + ${pt[2]} + ${pt[1]} - 2*${pt[0]}`
|
||||
for i of [4..7]
|
||||
auxiliaries.push aux+i
|
||||
pt = [...pt, ...auxiliaries]
|
||||
parts[0].push ...pt
|
||||
generalRecipe :=
|
||||
A: [0,1,4,2]
|
||||
B: [0,1,5,3]
|
||||
C: [0,2,6,3]
|
||||
D: [3,5,7,6]
|
||||
E: [2,4,7,6]
|
||||
F: [1,4,7,5]
|
||||
letters := ['A'..'F'] as const
|
||||
recipe: Record<string, string[]> := {}
|
||||
for ltr of letters
|
||||
auxlet := aux + ltr
|
||||
auxiliaries.push auxlet
|
||||
parts[2].push auxlet
|
||||
recipe[auxlet] = (pt[i] for each i of generalRecipe[ltr])
|
||||
ends[0] = aux + 'A'
|
||||
ends[1] = aux + 'D'
|
||||
callbacks.push (api: AppletObject, moreParts: DimParts) =>
|
||||
ix .= 0
|
||||
for piece in recipe
|
||||
madeIt := api.evalCommandGetLabels
|
||||
`${piece} = Polygon(${recipe[piece].join ','})`
|
||||
if not madeIt return
|
||||
for each obj of madeIt.split ','
|
||||
if obj is piece continue
|
||||
newObj := 'GeoAux' + index + obj + ix
|
||||
api.renameObject obj, newObj
|
||||
moreParts[1].push newObj
|
||||
ix += 1
|
||||
/pyramid|tetrahedron/
|
||||
base .= args.polygon?[0]
|
||||
ends[0] = base or aux + 1
|
||||
pt := args.subpoints
|
||||
unless pt and pt.length > 0 then return
|
||||
// A tetrahedron is just a pyramid where we have to build the
|
||||
// base from three points ourselves. But it has to be done in the
|
||||
// callback, since we have to capture the edges.
|
||||
if method is 'tetrahedron' and pt.length !== 4 then return
|
||||
commands.push '' // hack, make sure there is a command
|
||||
parts[0].push ...pt
|
||||
ends[0] = aux + 1
|
||||
ends[1] = pt[3]
|
||||
parts[2].push ends[0]
|
||||
ends[1] = pt.at(-1) or ''
|
||||
callbacks.push (api: AppletObject, moreParts: DimParts) =>
|
||||
if not base
|
||||
madeBase := api.evalCommandGetLabels
|
||||
`${ends[0]} = Polygon(${pt[0]},${pt[1]},${pt[2]})`
|
||||
if not madeBase return
|
||||
@ -1014,8 +1096,9 @@ classHandler: Record<JoyceClass, ClassHandler> :=
|
||||
newObj := 'GeoAux' + index + obj
|
||||
api.renameObject obj, newObj
|
||||
moreParts[1].push newObj
|
||||
base = ends[0]
|
||||
made := api.evalCommandGetLabels
|
||||
`${name} = Pyramid(${aux}1, ${pt[3]})`
|
||||
`${name} = Pyramid(${base}, ${ends[1]})`
|
||||
if not made return
|
||||
for each obj of made.split ','
|
||||
if obj is name continue
|
||||
|
Loading…
Reference in New Issue
Block a user