feat: Complete operation through Book Twelve (#58)

The only actual new command is the construction of a polygon
   as a face of a previously defined polyhedron.
   Aside from that, just adds some hacky "bugfixes" to Joyce's
   underlying Geometry Applet code to convert drawings that
   Joyce left in 2D when they should be in 3D.

Reviewed-on: #58
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 05:30:36 +00:00 committed by Glen Whitney
parent 0b241e010e
commit be13a384b1

View File

@ -30,6 +30,7 @@ type Description
usesCaptions: JoyceName[] usesCaptions: JoyceName[]
klass: JoyceClass klass: JoyceClass
ends?: [GeoName, GeoName] ends?: [GeoName, GeoName]
parts?: string[][]
// We put both JoyceNames and GeoNames in here, pointing to each other // We put both JoyceNames and GeoNames in here, pointing to each other
// with the otherName property: // with the otherName property:
@ -188,7 +189,8 @@ type ClassHandler = (
args: JoyceArguments, args: JoyceArguments,
index: number, index: number,
cdata: ConstructionData, cdata: ConstructionData,
colors: string[]) => Commander colors: string[],
jname: string) => Commander
type RGB = [number, number, number] type RGB = [number, number, number]
type XYZ = RGB type XYZ = RGB
@ -274,7 +276,7 @@ function jToG(
(args.subpoints ?= []).push depGeo (args.subpoints ?= []).push depGeo
else if depKlass is 'line' else if depKlass is 'line'
(args.subpoints ?= []).push ...ends ?? [] (args.subpoints ?= []).push ...ends ?? []
cmdr = classHandler[klass] name, method, args, index, cdata, colors 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
api.setLabelStyle name, 3 // style CAPTION = 3 api.setLabelStyle name, 3 // style CAPTION = 3
@ -428,8 +430,10 @@ function jToG(
console.log 'Setting label vis of', name, 'to', show if traceC console.log 'Setting label vis of', name, 'to', show if traceC
api.setLabelVisible name, show api.setLabelVisible name, show
cdata.elements[jname] = {otherName: name, usesCaptions, klass, cmdr.ends} cdata.elements[jname] =
cdata.elements[name] = {otherName: jname, usesCaptions, klass, cmdr.ends} {otherName: name, usesCaptions, klass, cmdr.ends, cmdr.parts}
cdata.elements[name] =
{otherName: jname, usesCaptions, klass, cmdr.ends, cmdr.parts}
cmdr cmdr
function pivotListener(slider: string) function pivotListener(slider: string)
@ -574,7 +578,7 @@ function proportionSimilar(
// All of the detailed semantics of each available command lies in this // All of the detailed semantics of each available command lies in this
// function. // function.
classHandler: Record<JoyceClass, ClassHandler> := classHandler: Record<JoyceClass, ClassHandler> :=
point: (name, method, args, index, cdata, colors): Commander => point: (name, method, args, index, cdata, colors, jname): Commander =>
return := freshCommander() return := freshCommander()
{commands, callbacks, parts, auxiliaries} := return.value {commands, callbacks, parts, auxiliaries} := return.value
zeroVector := cdata.is3d ? 'Vector((0,0,0))' : 'Vector((0,0))' zeroVector := cdata.is3d ? 'Vector((0,0,0))' : 'Vector((0,0))'
@ -582,7 +586,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 // HACK: Special-case corrections for Joyce Elements Bk XI & XII
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'
@ -598,6 +602,18 @@ classHandler: Record<JoyceClass, ClassHandler> :=
args.subpoints = ['B','P1','P3'] args.subpoints = ['B','P1','P3']
args.plane = ['xOyPlane'] args.plane = ['xOyPlane']
commands.push 'B=(80,140)' commands.push 'B=(80,140)'
if cdata.title is 'XII.7'
if (name is 'E' and method is 'lineSlider'
and args.subpoints?[1] is cdata.elements['1Y'].otherName)
args.subpoints[1] = cdata.elements['1Z'].otherName
if cdata.title is 'XII.8'
if (name is 'M' and method is 'lineSlider'
and args.subpoints?[1] is cdata.elements['1Y'].otherName)
args.subpoints[1] = cdata.elements['1Z'].otherName
if cdata.title is 'XII.9'
if (jname is 'a' and method is 'lineSlider'
and args.subpoints?[1] is cdata.elements['1Y'].otherName)
args.subpoints[1] = cdata.elements['1Z'].otherName
switch method switch method
/angle(?:Bisector|Divider)/ /angle(?:Bisector|Divider)/
{center, foot} := {center, foot} :=
@ -976,6 +992,11 @@ classHandler: Record<JoyceClass, ClassHandler> :=
'point' 'point'
moreParts[0].push newObj moreParts[0].push newObj
api.setVisible newObj, false api.setVisible newObj, false
'face'
unless args.polyhedron?.length is 1 then return
unless args.scalar?.length is 1 then return
element := cdata.elements[args.polyhedron[0]]
commands.push `${name} = ${element.parts?[2][args.scalar[0]-1]}`
///triangle|similar|parallelogram|application|quadrilateral ///triangle|similar|parallelogram|application|quadrilateral
|octagon|pentagon|hexagon/// |octagon|pentagon|hexagon///
unless args.subpoints then return unless args.subpoints then return
@ -1058,7 +1079,7 @@ classHandler: Record<JoyceClass, ClassHandler> :=
auxiliaries.push aux + 1 auxiliaries.push aux + 1
makeLinesInvisible callbacks, name makeLinesInvisible callbacks, name
plane: (name, method, args) => plane: (name, method, args, index, cdata) =>
return := freshCommander() return := freshCommander()
{commands, callbacks, parts, auxiliaries} := return.value {commands, callbacks, parts, auxiliaries} := return.value
parts[2].push name parts[2].push name
@ -1166,7 +1187,7 @@ classHandler: Record<JoyceClass, ClassHandler> :=
'segment' 'segment'
moreParts[1].push newObj moreParts[1].push newObj
else else
moreParts[2].push newObj moreParts[2].splice 1,0,newObj
/pyramid|tetrahedron/ /pyramid|tetrahedron/
base .= args.polygon?[0] base .= args.polygon?[0]
ends[0] = base or aux + 1 ends[0] = base or aux + 1