feat: implement more commands needed for Alberts trisection
These include circleSlider, line cutoff, and bichord. Also makes the order of points in the chord command more true to Joyce. Represents more progress on #36. Next up is dealing with the pivot parameter.
This commit is contained in:
parent
5433719440
commit
bb1713a674
@ -18,8 +18,12 @@
|
||||
Alter execution of the translated applet: <br/>
|
||||
<label for="showall">Show all applet entities, even hidden ones</label>
|
||||
<input type="checkbox" id="showall"><br/>
|
||||
<label for="showaux">Show geogebra auxiliaries (not in applet)</label>
|
||||
<label for="showaux">Show GeoGebra auxiliaries (not in applet)</label>
|
||||
<input type="checkbox" id="showaux">
|
||||
<br/>
|
||||
<br/>
|
||||
<label for="algebra">Show the GeoGebra algebra pane</label>
|
||||
<input type="checkbox" id="algebra">
|
||||
<script src="options.js" type="module"></script>
|
||||
</body>
|
||||
|
||||
|
@ -64,7 +64,7 @@ document.addEventListener "DOMContentLoaded", async =>
|
||||
use3d = true
|
||||
break
|
||||
codebase .= browser.runtime.getURL 'deps/GeoGebra/HTML5/5.0/'
|
||||
codebase += use3d ? 'web3d' : 'webSimple'
|
||||
codebase += (use3d or config.algebra) ? 'web3d' : 'webSimple'
|
||||
adapParams: AdapParams := {codebase, config, joyceApplets }
|
||||
apars := JSON.stringify(adapParams)
|
||||
addScriptTag(browser.runtime.getURL 'deps/GeoGebra/deployggb.js').then =>
|
||||
|
@ -35,6 +35,20 @@ type Description
|
||||
// with the otherName property:
|
||||
type JoyceElements = Record<AnyName, Description>
|
||||
|
||||
adapptScript := findAdappt() as HTMLScriptElement
|
||||
|
||||
function findAdappt()
|
||||
scripts := document.querySelectorAll 'script'
|
||||
for scrip of scripts
|
||||
src := scrip.getAttribute 'src'
|
||||
if src and src.includes 'adapptlet'
|
||||
return scrip
|
||||
|
||||
adapParams: AdapParams :=
|
||||
typeof GGBApplet is 'undefined'
|
||||
? {loader: 'https://www.geogebra.org/apps/deployggb.js', joyceApplets: []}
|
||||
: JSON.parse(adapptScript.dataset.params ?? '') as AdapParams
|
||||
|
||||
function postApplets(jApplets: AppletDescription[], codebase = '')
|
||||
for each jApp of jApplets
|
||||
params := {
|
||||
@ -48,7 +62,7 @@ function postApplets(jApplets: AppletDescription[], codebase = '')
|
||||
backgroundRGB := [255, 255, 255] as RGB
|
||||
config3d := contains3d jApp.params
|
||||
if config3d
|
||||
worked := api.enable3D true
|
||||
api.enable3D true
|
||||
api.setPerspective 'T'
|
||||
// Get rid of the xy-plane indicator
|
||||
xml .= api.getXML()
|
||||
@ -56,6 +70,8 @@ function postApplets(jApplets: AppletDescription[], codebase = '')
|
||||
api.setXML xml
|
||||
else if codebase.includes 'web3d'
|
||||
api.setPerspective 'G'
|
||||
if adapParams.config?.algebra
|
||||
api.setPerspective '+A'
|
||||
for name, value in jApp.params
|
||||
dispatchJcommand
|
||||
api, name, value, elements, backgroundRGB, config3d
|
||||
@ -78,22 +94,6 @@ function postApplets(jApplets: AppletDescription[], codebase = '')
|
||||
if codebase then geoApp.setHTML5Codebase codebase
|
||||
geoApp.inject jApp.id
|
||||
|
||||
adapptScript := findAdappt() as HTMLScriptElement
|
||||
|
||||
function findAdappt()
|
||||
scripts := document.querySelectorAll 'script'
|
||||
for scrip of scripts
|
||||
src := scrip.getAttribute 'src'
|
||||
if src and src.includes 'adapptlet'
|
||||
return scrip
|
||||
|
||||
console.log 'In script', document.currentScript, adapptScript
|
||||
|
||||
adapParams: AdapParams :=
|
||||
typeof GGBApplet is 'undefined'
|
||||
? {loader: 'https://www.geogebra.org/apps/deployggb.js', joyceApplets: []}
|
||||
: JSON.parse(adapptScript.dataset.params ?? '') as AdapParams
|
||||
|
||||
// Always use the final joyceApplets if there are any:
|
||||
if joyceApplets.length
|
||||
adapParams.joyceApplets = joyceApplets
|
||||
@ -412,12 +412,24 @@ function geoname(jname: JoyceName, elements: JoyceElements): GeoName
|
||||
return .= 'Geo' + numCode.toString(36);
|
||||
return += '1' while return.value in elements
|
||||
|
||||
// Helper for similar point/line functions:
|
||||
function cutoffExtend(
|
||||
method: string, pt: string[], point?: string[], line?: string[]
|
||||
): [string, string]
|
||||
direction .= `UnitVector(Vector(${pt[0]},${pt[1]}))`
|
||||
if line and (not point or point[0] !== pt[0])
|
||||
direction = `UnitVector(${line[0]})`
|
||||
displacement := `Distance(${pt[2]}, ${pt[3]})*${direction}`
|
||||
source := method is 'cutoff' ? pt[0] : pt[1]
|
||||
[source, displacement]
|
||||
|
||||
// All of the detailed semantics of each available command lies in this
|
||||
// function.
|
||||
classHandler: Record<JoyceClass, ClassHandler> :=
|
||||
point: (name, method, args, index, is3d): Commander =>
|
||||
return := freshCommander()
|
||||
{commands, callbacks, parts, auxiliaries} := return.value
|
||||
zeroVector := is3d ? 'Vector((0,0,0))' : 'Vector((0,0))'
|
||||
aux := name + 'aUx'
|
||||
parts[0].push name
|
||||
switch method
|
||||
@ -440,22 +452,25 @@ classHandler: Record<JoyceClass, ClassHandler> :=
|
||||
`${aux}4 = Rotate(${start}, ${aux}3/${n}, ${center}${inPlane})`
|
||||
`${name} = Intersect(${destination}, Ray(${center}, ${aux}4))`
|
||||
auxiliaries.push ...[2..4].map (i) => `${aux}${i}`
|
||||
'extend'
|
||||
sp := args.subpoints
|
||||
unless sp then return
|
||||
direction .= `UnitVector(Vector(${sp[0]},${sp[1]}))`
|
||||
if args.line and (
|
||||
not args.point or args.point[0] !== sp[0])
|
||||
direction = `UnitVector(${args.line[0]})`
|
||||
displacement := `Distance(${sp[2]}, ${sp[3]})*${direction}`
|
||||
commands.push `${name} = Translate(${sp[1]}, ${displacement})`
|
||||
'circleSlider'
|
||||
unless args.circle then return
|
||||
commands.push `${name} = Point(${args.circle[0]})`
|
||||
if args.scalar and args.scalar.length
|
||||
callbacks.push (api: AppletObject) =>
|
||||
api.setCoords name, ...args.scalar as XYZ
|
||||
/cutoff|extend/
|
||||
pt := args.subpoints
|
||||
unless pt and pt.length is 4 then return
|
||||
[source, displacement] :=
|
||||
cutoffExtend method, pt, args.point, args.line
|
||||
commands.push `${name} = Translate(${source}, ${displacement})`
|
||||
'first'
|
||||
unless args.subpoints then return
|
||||
commands.push `${name} = ${args.subpoints[0]}`
|
||||
commands.push `${name} = Point(${args.subpoints[0]},${zeroVector})`
|
||||
/fixed|free/
|
||||
coords := args.scalar
|
||||
unless coords then return
|
||||
commands.push `${name} = (${coords.join ','})`
|
||||
commands.push `${name} = Point({${coords.join ','}})`
|
||||
if method is 'fixed'
|
||||
callbacks.push (api: AppletObject) => api.setFixed name, true
|
||||
'foot'
|
||||
@ -476,7 +491,8 @@ classHandler: Record<JoyceClass, ClassHandler> :=
|
||||
commands.push `${name} = Intersect(${l1},${e2})`
|
||||
'last'
|
||||
unless args.subpoints then return
|
||||
commands.push `${name} = ${args.subpoints.at(-1)}`
|
||||
commands.push
|
||||
`${name} = Point(${args.subpoints.at(-1)}, ${zeroVector})`
|
||||
'lineSegmentSlider'
|
||||
segment .= args.line?[0]
|
||||
unless segment
|
||||
@ -528,7 +544,7 @@ classHandler: Record<JoyceClass, ClassHandler> :=
|
||||
commands.push
|
||||
`${name} = Vertex(${args.polygon?[0]},${args.scalar?[0]})`
|
||||
|
||||
line: (name, method, args) =>
|
||||
line: (name, method, args, index, is3d) =>
|
||||
return := freshCommander()
|
||||
return.value.ends = ['', '']
|
||||
{commands, callbacks, parts, auxiliaries, ends} := return.value
|
||||
@ -536,10 +552,62 @@ classHandler: Record<JoyceClass, ClassHandler> :=
|
||||
parts[1].push name
|
||||
madeSegment .= false
|
||||
switch method
|
||||
'bichord'
|
||||
// To match Joyce, we need to get the ordering here correct.
|
||||
// we want the order so that start -> end sweeping past the
|
||||
// center of the other circle is counterclockwise in the first
|
||||
// circle
|
||||
cr := args.circle
|
||||
unless cr return
|
||||
commands.push ...[1..2].map (n) =>
|
||||
`${aux}${n} = Intersect(${cr[0]}, ${cr[1]}, ${n})`
|
||||
inPlane := is3d ? `Plane(${cr[0]})` : ''
|
||||
ctr := cr.map (c) => `Center(${c})`
|
||||
condition := (`Angle(${aux}1,${ctr[0]},${ctr[1]}${inPlane})`
|
||||
+ `< Angle(${aux}2,${ctr[0]},${ctr[1]}${inPlane})`)
|
||||
commands.push
|
||||
`${aux}3 = If(${condition}, ${aux}2, ${aux}1)`
|
||||
`${aux}4 = If(${condition}, ${aux}1, ${aux}2)`
|
||||
ends[0] = aux + 3
|
||||
ends[1] = aux + 4
|
||||
auxiliaries.push ...[1..4].map (n) => aux + n
|
||||
'chord'
|
||||
// To match Joyce, we need to get the ordering here correct.
|
||||
// The complicated condition about distances is modeled after
|
||||
// Joyce's code, but it boils down to: take the endpoint of the
|
||||
// chord closest to the first subpoint, unless that first
|
||||
// subpoint is essentially at the midpoint of the chord, in
|
||||
// which case start with the endpoint nearest the second subpoint.
|
||||
unless args.subpoints and args.circle then return
|
||||
// We intersect with the whole line, not just the segment:
|
||||
line := `Line(${args.subpoints.join ','})`
|
||||
pA := args.subpoints[0]
|
||||
pB := args.subpoints[1]
|
||||
commands.push ...[1..2].map (n) =>
|
||||
`${aux}${n} = Intersect(${args.circle}, ${line}, ${n})`
|
||||
s := `Distance(${aux}1,${aux}2)`
|
||||
d := `Distance(${aux}1,${pA}) - Distance(${aux}2,${pA})`
|
||||
condition := (`If(${s}/10^9 < abs(${d}), ${d} > 0,`
|
||||
+ `Distance(${aux}2,${pB}) < Distance(${aux}1,${pB}))`)
|
||||
commands.push
|
||||
`${aux}3 = If(${condition}, ${aux}2, ${aux}1)`
|
||||
`${aux}4 = If(${condition}, ${aux}1, ${aux}2)`
|
||||
ends[0] = aux + 3
|
||||
ends[1] = aux + 4
|
||||
auxiliaries.push ...[1..4].map (n) => aux + n
|
||||
'connect'
|
||||
unless args.subpoints and args.subpoints.length is 2 then return
|
||||
ends[0] = args.subpoints[0]
|
||||
ends[1] = args.subpoints[1]
|
||||
/cutoff|extend/
|
||||
pt := args.subpoints
|
||||
unless pt and pt.length is 4 then return
|
||||
[source, displacement] :=
|
||||
cutoffExtend method, pt, args.point, args.line
|
||||
ends[0] = source
|
||||
commands.push `${aux} = Translate(${source}, ${displacement})`
|
||||
auxiliaries.push aux
|
||||
ends[1] = aux
|
||||
'parallel'
|
||||
unless args.subpoints then return
|
||||
[newStart, oldStart, oldEnd] := args.subpoints
|
||||
@ -555,24 +623,6 @@ classHandler: Record<JoyceClass, ClassHandler> :=
|
||||
madeSegment = true
|
||||
else
|
||||
commands.push `${aux}2 = Translate(${oldEnd}, ${aux}1)`
|
||||
'chord'
|
||||
// To match Joyce, we need to get the ordering here correct.
|
||||
// ends[0] should be the one closer to args.subpoints[0]
|
||||
unless args.subpoints and args.circle then return
|
||||
line := `Line(${args.subpoints.join ','})`
|
||||
pt := args.subpoints[0]
|
||||
commands.push ...[1..2].map (n) =>
|
||||
`${aux}${n} = Intersect(${args.circle}, ${line}, ${n})`
|
||||
condition := `Distance(${aux}2,${pt}) < Distance(${aux}1,${pt})`
|
||||
// NOTE: Joyce's code has special case for when pt is almost
|
||||
// at midpoint of chord; in that case, it starts at endpoint
|
||||
// closer to the second subpoint... postponing that nicety
|
||||
commands.push
|
||||
`${aux}3 = If(${condition}, ${aux}2, ${aux}1)`
|
||||
`${aux}4 = If(${condition}, ${aux}1, ${aux}2)`
|
||||
ends[0] = aux + 3
|
||||
ends[1] = aux + 4
|
||||
auxiliaries.push ...[1..4].map (n) => aux + n
|
||||
unless madeSegment
|
||||
commands.push `${name} = Segment(${ends[0]},${ends[1]})`
|
||||
callbacks.push (api: AppletObject) => api.setLabelVisible name, true
|
||||
@ -585,9 +635,19 @@ classHandler: Record<JoyceClass, ClassHandler> :=
|
||||
parts[1].push name
|
||||
switch method
|
||||
'radius'
|
||||
unless args.subpoints then return
|
||||
[center, point] := args.subpoints
|
||||
commands.push `${name} = Circle(${center}, ${point})`
|
||||
pt := args.subpoints
|
||||
unless pt then return
|
||||
inPlane := args.plane ? `, ${args.plane[0]}` : ''
|
||||
switch pt.length
|
||||
when 2
|
||||
[center, point] := pt
|
||||
commands.push
|
||||
`${name} = Circle(${center}, ${point}${inPlane})`
|
||||
when 3
|
||||
center := pt[0]
|
||||
radius := `Distance(${pt[1]}, ${pt[2]})`
|
||||
commands.push
|
||||
`${name} = Circle(${center}, ${radius}${inPlane})`
|
||||
callbacks.push (api: AppletObject) => api.setLabelVisible name, true
|
||||
|
||||
polygon: (name, method, args, index) =>
|
||||
|
@ -1,4 +1,5 @@
|
||||
export const flags = ['color', 'commands', 'showall', 'showaux'] as const
|
||||
export const flags = [
|
||||
'color', 'commands', 'showall', 'showaux', 'algebra'] as const
|
||||
export type FlagType = (typeof flags)[number]
|
||||
export type ConfigType = Partial<Record<FlagType, boolean>>
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user