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

Merged
glen merged 1 commits from BookThirteen into main 2024-02-11 23:34:44 +00:00

View File

@ -266,16 +266,21 @@ function jToG(
if scalar is scalar // not NaN if scalar is scalar // not NaN
(args.scalar ?= []).push scalar (args.scalar ?= []).push scalar
continue continue
unless jdep in cdata.elements if jdep is 'screen'
console.warn `Reference to unknown geometric entity ${jdep} in $jCom}` // special case for Joyce; assume xOyPlane
return cmdr (args.plane ?= []).push 'xOyPlane'
usesCaptions.push jdep else
{klass: depKlass, otherName: depGeo, ends} := cdata.elements[jdep] unless jdep in cdata.elements
(args[depKlass] ?= []).push depGeo console.warn
if depKlass is 'point' `Reference to unknown geometric entity ${jdep} in ${jCom}`
(args.subpoints ?= []).push depGeo return cmdr
else if depKlass is 'line' usesCaptions.push jdep
(args.subpoints ?= []).push ...ends ?? [] {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 cmdr = classHandler[klass] name, method, args, index, cdata, colors, jname
unless name is jname then cmdr.callbacks.push (api: AppletObject) => unless name is jname then cmdr.callbacks.push (api: AppletObject) =>
api.setCaption name, jname api.setCaption name, jname
@ -586,7 +591,7 @@ classHandler: Record<JoyceClass, ClassHandler> :=
aux := name + 'aUx' aux := name + 'aUx'
pivotable := cdata.pivot and name !== pivotData[cdata.pivot].pivot pivotable := cdata.pivot and name !== pivotData[cdata.pivot].pivot
parts[0].push name 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 cdata.title is 'XI.4'
if name is 'Z' and method is 'fixed' and args.scalar?.length is 3 if name is 'Z' and method is 'fixed' and args.scalar?.length is 3
method = 'perpendicular' method = 'perpendicular'
@ -614,6 +619,23 @@ classHandler: Record<JoyceClass, ClassHandler> :=
if (jname is 'a' and method is 'lineSlider' if (jname is 'a' and method is 'lineSlider'
and args.subpoints?[1] is cdata.elements['1Y'].otherName) and args.subpoints?[1] is cdata.elements['1Y'].otherName)
args.subpoints[1] = cdata.elements['1Z'].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 switch method
/angle(?:Bisector|Divider)/ /angle(?:Bisector|Divider)/
{center, foot} := {center, foot} :=
@ -679,6 +701,12 @@ classHandler: Record<JoyceClass, ClassHandler> :=
: `Line(${pt[1]},${pt[2]})` : `Line(${pt[1]},${pt[2]})`
commands.push commands.push
`${name} = ClosestPoint(${destination}, ${pt[0]})` `${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' 'intersection'
// Checking Joyce source, means intersection of lines, not // Checking Joyce source, means intersection of lines, not
// intersection of line segments // intersection of line segments
@ -736,15 +764,13 @@ classHandler: Record<JoyceClass, ClassHandler> :=
commands.push commands.push
`${name} = Rotate(${pt[1]}, pi/2, ${center}${inPlane})` `${name} = Rotate(${pt[1]}, pi/2, ${center}${inPlane})`
when 3 // perpendicular **to** the plane when 3 // perpendicular **to** the plane
// Uses lots of auxiliaries
radius := `Distance(${pt[1]}, ${pt[2]})` radius := `Distance(${pt[1]}, ${pt[2]})`
which := args.scalar ? args.scalar[0] : 2 //HACK: 2 vs 1??
commands.push commands.push
`${aux}1 = Circle(${center}, ${radius}${inPlane})` `${aux}1 = Sphere(${center}, ${radius})`
`${aux}2 = PointIn(${aux}1)` `${aux}2 = PerpendicularLine(${center}${inPlane})`
`${aux}3 = PerpendicularLine(${center}${inPlane})` `${name} = Intersect(${aux}2,${aux}1,${which})`
`${aux}4 = Plane(${aux}2, ${aux}3)` auxiliaries.push aux+1, aux+2
`${name} = Rotate(${aux}2, pi/2, ${center}, ${aux}4)`
auxiliaries.push aux+n for n of [1..4]
when 4 when 4
commands.push commands.push
`${aux}1 = Ray(${center}, Rotate(${pt[1]}, pi/2, ${center}${inPlane}))` `${aux}1 = Ray(${center}, Rotate(${pt[1]}, pi/2, ${center}${inPlane}))`
@ -932,7 +958,6 @@ classHandler: Record<JoyceClass, ClassHandler> :=
aux := name + 'aUx' aux := name + 'aUx'
parts[1].push name parts[1].push name
circle .= '' circle .= ''
defaultPlane := cdata.is3d ? ', xOyPlane' : ''
switch method switch method
'circumcircle' 'circumcircle'
pt := args.subpoints pt := args.subpoints
@ -944,18 +969,17 @@ classHandler: Record<JoyceClass, ClassHandler> :=
circle = `IntersectConic(${sph[0]}, ${sph[1]})` circle = `IntersectConic(${sph[0]}, ${sph[1]})`
'radius' 'radius'
pt := args.subpoints pt := args.subpoints
unless pt then return unless pt and pt.length > 1 and pt.length < 4 then return
inPlane := args.plane ? `, ${args.plane[0]}` : defaultPlane ends[0] = pt[0]
switch pt.length if pt.length is 2 and not cdata.is3d
when 2 circle = `Circle(${pt[0]}, ${pt[1]})`
[center, point] := pt else // 3d or three points
ends[0] = center radIx := pt.length - 2
circle = `Circle(${center}, ${point}${inPlane})` inPlane := (cdata.is3d
when 3 ? args.plane ? `, ${args.plane[0]}` : ', xOyPlane'
center := pt[0] : '')
ends[0] = center radius := `Distance(${pt[radIx]}, ${pt[radIx+1]})`
radius := `Distance(${pt[1]}, ${pt[2]})` circle = `Circle(${pt[0]}, ${radius}${inPlane})`
circle = `Circle(${center}, ${radius}${inPlane})`
commands.push commands.push
`${aux} = ${circle}` // for the filling `${aux} = ${circle}` // for the filling
`${name} = ${circle}` // for the perimeter `${name} = ${circle}` // for the perimeter
@ -978,9 +1002,14 @@ classHandler: Record<JoyceClass, ClassHandler> :=
N = args.scalar[0] N = args.scalar[0]
commands.push '' // hack, make sure there is a command commands.push '' // hack, make sure there is a command
parts[0].push pt[0], pt[1] parts[0].push pt[0], pt[1]
inPlane := cdata.is3d
? args.plane ? `, ${args.plane[0]}` : ', xOyPlane'
: ''
callbacks.push (api: AppletObject, moreParts: DimParts) => callbacks.push (api: AppletObject, moreParts: DimParts) =>
made:= api.evalCommandGetLabels command := `${name} = Polygon(${pt[0]},${pt[1]}, ${N}${inPlane})`
`${name} = Polygon(${pt[0]},${pt[1]}, ${N})` made:= api.evalCommandGetLabels command
if adapParams.config?.commands
console.log 'Finishing with', command, 'producing', made
if not made return if not made return
for each obj of made.split ',' for each obj of made.split ','
if obj is name continue if obj is name continue
@ -1212,6 +1241,12 @@ classHandler: Record<JoyceClass, ClassHandler> :=
api.renameObject obj, newObj api.renameObject obj, newObj
moreParts[1].push newObj moreParts[1].push newObj
base = ends[0] 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 made := api.evalCommandGetLabels
`${name} = Pyramid(${base}, ${ends[1]})` `${name} = Pyramid(${base}, ${ends[1]})`
if not made return if not made return