feat: complete commands needed for Book Eleven

This commit is contained in:
Glen Whitney 2024-02-09 22:59:55 -08:00
parent e10da118a7
commit c903a42f89

View File

@ -67,6 +67,7 @@ type ConstructionData
height: number height: number
elements: JoyceElements elements: JoyceElements
pivot: string pivot: string
title?: string
// Global data setup for pivoting (ugh, but necessary because the api // Global data setup for pivoting (ugh, but necessary because the api
// is not passed to the callback, so we have to look up the slider in // is not passed to the callback, so we have to look up the slider in
@ -186,7 +187,8 @@ type ClassHandler = (
method: string, method: string,
args: JoyceArguments, args: JoyceArguments,
index: number, index: number,
cdata: ConstructionData) => Commander cdata: ConstructionData,
colors: string[]) => Commander
type RGB = [number, number, number] type RGB = [number, number, number]
type XYZ = RGB type XYZ = RGB
@ -208,6 +210,7 @@ function dispatchJcommand(
'title' 'title'
if adapParams.config?.commands if adapParams.config?.commands
console.log 'Setting title to', value console.log 'Setting title to', value
cdata.title = value
api.evalCommand `TitlePoint = Corner(1,1) api.evalCommand `TitlePoint = Corner(1,1)
Text("${value}", TitlePoint + (2,5))` Text("${value}", TitlePoint + (2,5))`
'pivot' 'pivot'
@ -257,7 +260,7 @@ function jToG(
args: JoyceArguments := {} args: JoyceArguments := {}
usesCaptions := [] usesCaptions := []
for each jdep of data.split ',' for each jdep of data.split ','
scalar := parseFloat jdep scalar := Number jdep
if scalar is scalar // not NaN if scalar is scalar // not NaN
(args.scalar ?= []).push scalar (args.scalar ?= []).push scalar
continue continue
@ -271,7 +274,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 cmdr = classHandler[klass] name, method, args, index, cdata, colors
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
@ -517,7 +520,7 @@ function pointDefaultColorName(
function geoname( function geoname(
jname: JoyceName, elements: JoyceElements, klass: JoyceClass): GeoName jname: JoyceName, elements: JoyceElements, klass: JoyceClass): GeoName
unless jname.substring(0,3) is 'Geo' // those might clash unless jname is 'floor' or jname.substring(0,3) is 'Geo' // those might clash
// Names with word characters starting with a capital are always good: // Names with word characters starting with a capital are always good:
if /^[A-Z]['\w]*$/.test jname then return jname if /^[A-Z]['\w]*$/.test jname then return jname
// If it's not a point, can start with any letter: // If it's not a point, can start with any letter:
@ -571,7 +574,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): Commander => point: (name, method, args, index, cdata, colors): 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))'
@ -579,6 +582,22 @@ 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
if cdata.title is 'XI.4'
if name is 'Z' and method is 'fixed' and args.scalar?.length is 3
method = 'perpendicular'
args.subpoints = ['E','P2','A']
args.plane = ['baseplane']
colors[0] = '0'
colors[1] = '0'
if name is 'F' and method is 'lineSlider' and args.subpoints?[0] is 'E'
args.scalar = [160,40,60]
if cdata.title is 'XI.5'
if name is 'A' and method is 'free'
method = 'perpendicular'
args.subpoints = ['B','P1','P3']
args.plane = ['xOyPlane']
commands.push 'B=(80,140)'
switch method switch method
/angle(?:Bisector|Divider)/ /angle(?:Bisector|Divider)/
{center, foot} := {center, foot} :=
@ -608,6 +627,12 @@ classHandler: Record<JoyceClass, ClassHandler> :=
if args.scalar and args.scalar.length if args.scalar and args.scalar.length
callbacks.push (api: AppletObject) => callbacks.push (api: AppletObject) =>
api.setCoords name, ...vertFlipped(args.scalar or [], cdata) api.setCoords name, ...vertFlipped(args.scalar or [], cdata)
'circumcenter'
unless args.subpoints?.length is 3 then return
commands.push
`${aux} = Circle(${args.subpoints.join ','})`
`${name} = Center(${aux})`
auxiliaries.push aux
/cutoff|extend/ /cutoff|extend/
pt := args.subpoints pt := args.subpoints
unless pt and pt.length is 4 then return unless pt and pt.length is 4 then return
@ -616,9 +641,9 @@ classHandler: Record<JoyceClass, ClassHandler> :=
commands.push `${name} = Translate(${source}, ${displacement})` commands.push `${name} = Translate(${source}, ${displacement})`
'first' 'first'
unless args.subpoints then return unless args.subpoints then return
// HACK: Special-case correction for Joyce Elements Bk II, prop 14
index .= 0 index .= 0
if name === 'H' and args.line and args.line[0] === 'HH2' // HACK: Special-case correction for Joyce Elements Bk II, prop 14
if cdata.title is 'II.14' and name is 'H' and args.line?[0] is 'HH2'
index = 1 index = 1
commands.push `${name} = ${args.subpoints[index]}` commands.push `${name} = ${args.subpoints[index]}`
/fixed|free/ /fixed|free/
@ -642,9 +667,9 @@ classHandler: Record<JoyceClass, ClassHandler> :=
// Checking Joyce source, means intersection of lines, not // Checking Joyce source, means intersection of lines, not
// intersection of line segments // intersection of line segments
pt := args.subpoints pt := args.subpoints
unless pt then return unless pt and pt.length > 1 then return
l1 := `Line(${pt[0]},${pt[1]})` l1 := `Line(${pt[0]},${pt[1]})`
e2 := args.plane ? args.plane[0] : `Line(${pt[2]},${pt[3]})` e2 := pt.length < 3 ? args.plane?[0] : `Line(${pt[2]},${pt[3]})`
commands.push `${name} = Intersect(${l1},${e2})` commands.push `${name} = Intersect(${l1},${e2})`
'last' 'last'
unless args.subpoints then return unless args.subpoints then return
@ -696,8 +721,9 @@ classHandler: Record<JoyceClass, ClassHandler> :=
`${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 // Uses lots of auxiliaries
radius := `Distance(${pt[1]}, ${pt[2]})`
commands.push commands.push
`${aux}1 = Circle(${center}, Distance(${pt[1]}, ${pt[2]})${inPlane})` `${aux}1 = Circle(${center}, ${radius}${inPlane})`
`${aux}2 = PointIn(${aux}1)` `${aux}2 = PointIn(${aux}1)`
`${aux}3 = PerpendicularLine(${center}${inPlane})` `${aux}3 = PerpendicularLine(${center}${inPlane})`
`${aux}4 = Plane(${aux}2, ${aux}3)` `${aux}4 = Plane(${aux}2, ${aux}3)`
@ -847,7 +873,17 @@ classHandler: Record<JoyceClass, ClassHandler> :=
commands.push commands.push
`${aux} = Rotate(${pt[1]}, pi/2, ${pt[0]}${inPlane})` `${aux} = Rotate(${pt[1]}, pi/2, ${pt[0]}${inPlane})`
when 3 when 3
return // TODO: line perpendicular to plane radius := `Distance(${pt[1]}, ${pt[2]})`
commands.push
`${aux}1 = PerpendicularLine(${pt[1]}${inPlane})`
`${aux}2 = Intersect(${aux}1${inPlane})`
`${aux}3 = Circle(${aux}2, ${radius}${inPlane})`
`${aux}4 = PointIn(${aux}3)`
`${aux}5 = Plane(${aux}4, ${aux}1)`
`${aux}6 = Rotate(${aux}4, pi/2, ${aux}2, ${aux}5)`
ends[0] = aux + 2
ends[1] = aux + 6
auxiliaries.push aux+n for n of [1..6]
when 4 when 4
ends[0] = pt[0] ends[0] = pt[0]
ends[1] = aux + 2 ends[1] = aux + 2
@ -998,7 +1034,7 @@ classHandler: Record<JoyceClass, ClassHandler> :=
aux := name + 'aUx' aux := name + 'aUx'
parts[2].push name parts[2].push name
defaultPlane := cdata.is3d ? ', xOyPlane' : '' defaultPlane := cdata.is3d ? ', xOyPlane' : ''
inPlane := args.plane ? `, ${args.plane[0]}` : defaultPlane inPlane .= args.plane ? `, ${args.plane[0]}` : defaultPlane
switch method switch method
/arc|sector/ /arc|sector/
unless args.subpoints?.length is 3 return unless args.subpoints?.length is 3 return
@ -1012,6 +1048,7 @@ classHandler: Record<JoyceClass, ClassHandler> :=
center = temp center = temp
parms = start + ', ' + center + ', ' + end parms = start + ', ' + center + ', ' + end
prefix = 'Circumcircular' prefix = 'Circumcircular'
inPlane = '' // not needed in 3-point case
ends[0] = start ends[0] = start
ends[1] = end ends[1] = end
commands.push commands.push
@ -1029,6 +1066,10 @@ classHandler: Record<JoyceClass, ClassHandler> :=
'3points' '3points'
unless args.subpoints?.length is 3 then return unless args.subpoints?.length is 3 then return
commands.push `${name} = Plane(${args.subpoints.join ','})` commands.push `${name} = Plane(${args.subpoints.join ','})`
'parallel'
unless args.subpoints?.length is 1 then return
unless args.plane?.length is 1 then return
commands.push `${name} = Plane(${args.subpoints[0]}, ${args.plane[0]})`
'perpendicular' 'perpendicular'
unless args.subpoints?.length is 2 then return unless args.subpoints?.length is 2 then return
[thru, perp] := args.subpoints [thru, perp] := args.subpoints
@ -1099,6 +1140,33 @@ classHandler: Record<JoyceClass, ClassHandler> :=
api.renameObject obj, newObj api.renameObject obj, newObj
moreParts[1].push newObj moreParts[1].push newObj
ix += 1 ix += 1
'prism'
unless args.polygon?.length is 1 then return
base := args.polygon[0]
ends[0] = base
pt := args.subpoints
unless pt and pt.length is 2 then return
commands.push
`${aux}1 = Vertex(${base},1) + ${pt[1]} - ${pt[0]}`
auxiliaries.push aux+1
ends[1] = aux+1
parts[0].push aux+1
parts[2].push ends[0]
callbacks.push (api: AppletObject, moreParts: DimParts) =>
made := api.evalCommandGetLabels
`${name} = Prism(${base}, ${aux}1)`
if not made return
for each obj of made.split ','
if obj is name continue
newObj := 'GeoAux' + index + obj
api.renameObject obj, newObj
switch api.getObjectType newObj
'point'
moreParts[0].push newObj
'segment'
moreParts[1].push newObj
else
moreParts[2].push 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