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

View File

@ -266,8 +266,13 @@ function jToG(
if scalar is scalar // not NaN if scalar is scalar // not NaN
(args.scalar ?= []).push scalar (args.scalar ?= []).push scalar
continue continue
if jdep is 'screen'
// special case for Joyce; assume xOyPlane
(args.plane ?= []).push 'xOyPlane'
else
unless jdep in cdata.elements unless jdep in cdata.elements
console.warn `Reference to unknown geometric entity ${jdep} in $jCom}` console.warn
`Reference to unknown geometric entity ${jdep} in ${jCom}`
return cmdr return cmdr
usesCaptions.push jdep usesCaptions.push jdep
{klass: depKlass, otherName: depGeo, ends} := cdata.elements[jdep] {klass: depKlass, otherName: depGeo, ends} := cdata.elements[jdep]
@ -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