fix: hacks and bugfixes to get Book 13 working (#59)

Reviewed-on: #59
Co-authored-by: Glen Whitney <glen@studioinfinity.org>
Co-committed-by: Glen Whitney <glen@studioinfinity.org>
This commit is contained in:
Glen Whitney 2024-02-11 23:34:43 +00:00 committed by Glen Whitney
parent be13a384b1
commit d2c872020c
1 changed files with 68 additions and 33 deletions

View File

@ -266,16 +266,21 @@ function jToG(
if scalar is scalar // not NaN
(args.scalar ?= []).push scalar
continue
unless jdep in cdata.elements
console.warn `Reference to unknown geometric entity ${jdep} in $jCom}`
return cmdr
usesCaptions.push jdep
{klass: depKlass, otherName: depGeo, ends} := cdata.elements[jdep]
(args[depKlass] ?= []).push depGeo
if depKlass is 'point'
(args.subpoints ?= []).push depGeo
else if depKlass is 'line'
(args.subpoints ?= []).push ...ends ?? []
if jdep is 'screen'
// special case for Joyce; assume xOyPlane
(args.plane ?= []).push 'xOyPlane'
else
unless jdep in cdata.elements
console.warn
`Reference to unknown geometric entity ${jdep} in ${jCom}`
return cmdr
usesCaptions.push jdep
{klass: depKlass, otherName: depGeo, ends} := cdata.elements[jdep]
(args[depKlass] ?= []).push depGeo
if depKlass is 'point'
(args.subpoints ?= []).push depGeo
else if depKlass is 'line'
(args.subpoints ?= []).push ...ends ?? []
cmdr = classHandler[klass] name, method, args, index, cdata, colors, jname
unless name is jname then cmdr.callbacks.push (api: AppletObject) =>
api.setCaption name, jname
@ -586,7 +591,7 @@ classHandler: Record<JoyceClass, ClassHandler> :=
aux := name + 'aUx'
pivotable := cdata.pivot and name !== pivotData[cdata.pivot].pivot
parts[0].push name
// HACK: Special-case corrections for Joyce Elements Bk XI & XII
// HACK: Special-case corrections for Joyce Elements Bk XI -- XIII
if cdata.title is 'XI.4'
if name is 'Z' and method is 'fixed' and args.scalar?.length is 3
method = 'perpendicular'
@ -614,6 +619,23 @@ classHandler: Record<JoyceClass, ClassHandler> :=
if (jname is 'a' and method is 'lineSlider'
and args.subpoints?[1] is cdata.elements['1Y'].otherName)
args.subpoints[1] = cdata.elements['1Z'].otherName
if cdata.title is 'XIII.17'
// Joyce's point perpendicular to a plane is ambiguous between
// two possible positions, and Geogebra's choice does not
// always agree with what Joyce's code did. So we just have to flip
// one of his choices in the dodecahedron
if name is 'U' and method is 'extend' and args.subpoints?[0] is "U'"
method = 'midpoint'
args.point = ["U'", "U'"] // hacky way to make U = U'
if cdata.title is 'Dodecahedron and cube'
// similar issues to XIII.17
if (name is 'VAB' or name is 'VBC') and method is 'perpendicular'
args.scalar = [1]
if cdata.title is 'XIII.18'
// Joyce just mistook where N is
if name is 'N' and method is 'intersection'
method = 'golden'
args.subpoints = ['B', 'F']
switch method
/angle(?:Bisector|Divider)/
{center, foot} :=
@ -679,6 +701,12 @@ classHandler: Record<JoyceClass, ClassHandler> :=
: `Line(${pt[1]},${pt[2]})`
commands.push
`${name} = ClosestPoint(${destination}, ${pt[0]})`
'golden'
// Added in this implementation to ease fix of XIII.18
pt := args.subpoints
unless pt and pt.length is 2 then return
commands.push
`${name} = ${pt[0]} + ((sqrt(5)-1)/2)*(${pt[1]}-${pt[0]})`
'intersection'
// Checking Joyce source, means intersection of lines, not
// intersection of line segments
@ -736,15 +764,13 @@ classHandler: Record<JoyceClass, ClassHandler> :=
commands.push
`${name} = Rotate(${pt[1]}, pi/2, ${center}${inPlane})`
when 3 // perpendicular **to** the plane
// Uses lots of auxiliaries
radius := `Distance(${pt[1]}, ${pt[2]})`
which := args.scalar ? args.scalar[0] : 2 //HACK: 2 vs 1??
commands.push
`${aux}1 = Circle(${center}, ${radius}${inPlane})`
`${aux}2 = PointIn(${aux}1)`
`${aux}3 = PerpendicularLine(${center}${inPlane})`
`${aux}4 = Plane(${aux}2, ${aux}3)`
`${name} = Rotate(${aux}2, pi/2, ${center}, ${aux}4)`
auxiliaries.push aux+n for n of [1..4]
`${aux}1 = Sphere(${center}, ${radius})`
`${aux}2 = PerpendicularLine(${center}${inPlane})`
`${name} = Intersect(${aux}2,${aux}1,${which})`
auxiliaries.push aux+1, aux+2
when 4
commands.push
`${aux}1 = Ray(${center}, Rotate(${pt[1]}, pi/2, ${center}${inPlane}))`
@ -932,7 +958,6 @@ classHandler: Record<JoyceClass, ClassHandler> :=
aux := name + 'aUx'
parts[1].push name
circle .= ''
defaultPlane := cdata.is3d ? ', xOyPlane' : ''
switch method
'circumcircle'
pt := args.subpoints
@ -944,18 +969,17 @@ classHandler: Record<JoyceClass, ClassHandler> :=
circle = `IntersectConic(${sph[0]}, ${sph[1]})`
'radius'
pt := args.subpoints
unless pt then return
inPlane := args.plane ? `, ${args.plane[0]}` : defaultPlane
switch pt.length
when 2
[center, point] := pt
ends[0] = center
circle = `Circle(${center}, ${point}${inPlane})`
when 3
center := pt[0]
ends[0] = center
radius := `Distance(${pt[1]}, ${pt[2]})`
circle = `Circle(${center}, ${radius}${inPlane})`
unless pt and pt.length > 1 and pt.length < 4 then return
ends[0] = pt[0]
if pt.length is 2 and not cdata.is3d
circle = `Circle(${pt[0]}, ${pt[1]})`
else // 3d or three points
radIx := pt.length - 2
inPlane := (cdata.is3d
? args.plane ? `, ${args.plane[0]}` : ', xOyPlane'
: '')
radius := `Distance(${pt[radIx]}, ${pt[radIx+1]})`
circle = `Circle(${pt[0]}, ${radius}${inPlane})`
commands.push
`${aux} = ${circle}` // for the filling
`${name} = ${circle}` // for the perimeter
@ -978,9 +1002,14 @@ classHandler: Record<JoyceClass, ClassHandler> :=
N = args.scalar[0]
commands.push '' // hack, make sure there is a command
parts[0].push pt[0], pt[1]
inPlane := cdata.is3d
? args.plane ? `, ${args.plane[0]}` : ', xOyPlane'
: ''
callbacks.push (api: AppletObject, moreParts: DimParts) =>
made:= api.evalCommandGetLabels
`${name} = Polygon(${pt[0]},${pt[1]}, ${N})`
command := `${name} = Polygon(${pt[0]},${pt[1]}, ${N}${inPlane})`
made:= api.evalCommandGetLabels command
if adapParams.config?.commands
console.log 'Finishing with', command, 'producing', made
if not made return
for each obj of made.split ','
if obj is name continue
@ -1212,6 +1241,12 @@ classHandler: Record<JoyceClass, ClassHandler> :=
api.renameObject obj, newObj
moreParts[1].push newObj
base = ends[0]
else // need to grab the parts of the base, which become
// parts of the polyhedron
baseParts := cdata.elements[base].parts
if baseParts
parts[0].push ...baseParts[0]
parts[1].push ...baseParts[1]
made := api.evalCommandGetLabels
`${name} = Pyramid(${base}, ${ends[1]})`
if not made return