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/>
|
Alter execution of the translated applet: <br/>
|
||||||
<label for="showall">Show all applet entities, even hidden ones</label>
|
<label for="showall">Show all applet entities, even hidden ones</label>
|
||||||
<input type="checkbox" id="showall"><br/>
|
<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">
|
<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>
|
<script src="options.js" type="module"></script>
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
|
@ -64,7 +64,7 @@ document.addEventListener "DOMContentLoaded", async =>
|
|||||||
use3d = true
|
use3d = true
|
||||||
break
|
break
|
||||||
codebase .= browser.runtime.getURL 'deps/GeoGebra/HTML5/5.0/'
|
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 }
|
adapParams: AdapParams := {codebase, config, joyceApplets }
|
||||||
apars := JSON.stringify(adapParams)
|
apars := JSON.stringify(adapParams)
|
||||||
addScriptTag(browser.runtime.getURL 'deps/GeoGebra/deployggb.js').then =>
|
addScriptTag(browser.runtime.getURL 'deps/GeoGebra/deployggb.js').then =>
|
||||||
|
@ -35,6 +35,20 @@ type Description
|
|||||||
// with the otherName property:
|
// with the otherName property:
|
||||||
type JoyceElements = Record<AnyName, Description>
|
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 = '')
|
function postApplets(jApplets: AppletDescription[], codebase = '')
|
||||||
for each jApp of jApplets
|
for each jApp of jApplets
|
||||||
params := {
|
params := {
|
||||||
@ -48,7 +62,7 @@ function postApplets(jApplets: AppletDescription[], codebase = '')
|
|||||||
backgroundRGB := [255, 255, 255] as RGB
|
backgroundRGB := [255, 255, 255] as RGB
|
||||||
config3d := contains3d jApp.params
|
config3d := contains3d jApp.params
|
||||||
if config3d
|
if config3d
|
||||||
worked := api.enable3D true
|
api.enable3D true
|
||||||
api.setPerspective 'T'
|
api.setPerspective 'T'
|
||||||
// Get rid of the xy-plane indicator
|
// Get rid of the xy-plane indicator
|
||||||
xml .= api.getXML()
|
xml .= api.getXML()
|
||||||
@ -56,6 +70,8 @@ function postApplets(jApplets: AppletDescription[], codebase = '')
|
|||||||
api.setXML xml
|
api.setXML xml
|
||||||
else if codebase.includes 'web3d'
|
else if codebase.includes 'web3d'
|
||||||
api.setPerspective 'G'
|
api.setPerspective 'G'
|
||||||
|
if adapParams.config?.algebra
|
||||||
|
api.setPerspective '+A'
|
||||||
for name, value in jApp.params
|
for name, value in jApp.params
|
||||||
dispatchJcommand
|
dispatchJcommand
|
||||||
api, name, value, elements, backgroundRGB, config3d
|
api, name, value, elements, backgroundRGB, config3d
|
||||||
@ -78,22 +94,6 @@ function postApplets(jApplets: AppletDescription[], codebase = '')
|
|||||||
if codebase then geoApp.setHTML5Codebase codebase
|
if codebase then geoApp.setHTML5Codebase codebase
|
||||||
geoApp.inject jApp.id
|
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:
|
// Always use the final joyceApplets if there are any:
|
||||||
if joyceApplets.length
|
if joyceApplets.length
|
||||||
adapParams.joyceApplets = joyceApplets
|
adapParams.joyceApplets = joyceApplets
|
||||||
@ -412,12 +412,24 @@ function geoname(jname: JoyceName, elements: JoyceElements): GeoName
|
|||||||
return .= 'Geo' + numCode.toString(36);
|
return .= 'Geo' + numCode.toString(36);
|
||||||
return += '1' while return.value in elements
|
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
|
// 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, is3d): Commander =>
|
point: (name, method, args, index, is3d): Commander =>
|
||||||
return := freshCommander()
|
return := freshCommander()
|
||||||
{commands, callbacks, parts, auxiliaries} := return.value
|
{commands, callbacks, parts, auxiliaries} := return.value
|
||||||
|
zeroVector := is3d ? 'Vector((0,0,0))' : 'Vector((0,0))'
|
||||||
aux := name + 'aUx'
|
aux := name + 'aUx'
|
||||||
parts[0].push name
|
parts[0].push name
|
||||||
switch method
|
switch method
|
||||||
@ -440,22 +452,25 @@ classHandler: Record<JoyceClass, ClassHandler> :=
|
|||||||
`${aux}4 = Rotate(${start}, ${aux}3/${n}, ${center}${inPlane})`
|
`${aux}4 = Rotate(${start}, ${aux}3/${n}, ${center}${inPlane})`
|
||||||
`${name} = Intersect(${destination}, Ray(${center}, ${aux}4))`
|
`${name} = Intersect(${destination}, Ray(${center}, ${aux}4))`
|
||||||
auxiliaries.push ...[2..4].map (i) => `${aux}${i}`
|
auxiliaries.push ...[2..4].map (i) => `${aux}${i}`
|
||||||
'extend'
|
'circleSlider'
|
||||||
sp := args.subpoints
|
unless args.circle then return
|
||||||
unless sp then return
|
commands.push `${name} = Point(${args.circle[0]})`
|
||||||
direction .= `UnitVector(Vector(${sp[0]},${sp[1]}))`
|
if args.scalar and args.scalar.length
|
||||||
if args.line and (
|
callbacks.push (api: AppletObject) =>
|
||||||
not args.point or args.point[0] !== sp[0])
|
api.setCoords name, ...args.scalar as XYZ
|
||||||
direction = `UnitVector(${args.line[0]})`
|
/cutoff|extend/
|
||||||
displacement := `Distance(${sp[2]}, ${sp[3]})*${direction}`
|
pt := args.subpoints
|
||||||
commands.push `${name} = Translate(${sp[1]}, ${displacement})`
|
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'
|
'first'
|
||||||
unless args.subpoints then return
|
unless args.subpoints then return
|
||||||
commands.push `${name} = ${args.subpoints[0]}`
|
commands.push `${name} = Point(${args.subpoints[0]},${zeroVector})`
|
||||||
/fixed|free/
|
/fixed|free/
|
||||||
coords := args.scalar
|
coords := args.scalar
|
||||||
unless coords then return
|
unless coords then return
|
||||||
commands.push `${name} = (${coords.join ','})`
|
commands.push `${name} = Point({${coords.join ','}})`
|
||||||
if method is 'fixed'
|
if method is 'fixed'
|
||||||
callbacks.push (api: AppletObject) => api.setFixed name, true
|
callbacks.push (api: AppletObject) => api.setFixed name, true
|
||||||
'foot'
|
'foot'
|
||||||
@ -476,7 +491,8 @@ classHandler: Record<JoyceClass, ClassHandler> :=
|
|||||||
commands.push `${name} = Intersect(${l1},${e2})`
|
commands.push `${name} = Intersect(${l1},${e2})`
|
||||||
'last'
|
'last'
|
||||||
unless args.subpoints then return
|
unless args.subpoints then return
|
||||||
commands.push `${name} = ${args.subpoints.at(-1)}`
|
commands.push
|
||||||
|
`${name} = Point(${args.subpoints.at(-1)}, ${zeroVector})`
|
||||||
'lineSegmentSlider'
|
'lineSegmentSlider'
|
||||||
segment .= args.line?[0]
|
segment .= args.line?[0]
|
||||||
unless segment
|
unless segment
|
||||||
@ -528,7 +544,7 @@ classHandler: Record<JoyceClass, ClassHandler> :=
|
|||||||
commands.push
|
commands.push
|
||||||
`${name} = Vertex(${args.polygon?[0]},${args.scalar?[0]})`
|
`${name} = Vertex(${args.polygon?[0]},${args.scalar?[0]})`
|
||||||
|
|
||||||
line: (name, method, args) =>
|
line: (name, method, args, index, is3d) =>
|
||||||
return := freshCommander()
|
return := freshCommander()
|
||||||
return.value.ends = ['', '']
|
return.value.ends = ['', '']
|
||||||
{commands, callbacks, parts, auxiliaries, ends} := return.value
|
{commands, callbacks, parts, auxiliaries, ends} := return.value
|
||||||
@ -536,10 +552,62 @@ classHandler: Record<JoyceClass, ClassHandler> :=
|
|||||||
parts[1].push name
|
parts[1].push name
|
||||||
madeSegment .= false
|
madeSegment .= false
|
||||||
switch method
|
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'
|
'connect'
|
||||||
unless args.subpoints and args.subpoints.length is 2 then return
|
unless args.subpoints and args.subpoints.length is 2 then return
|
||||||
ends[0] = args.subpoints[0]
|
ends[0] = args.subpoints[0]
|
||||||
ends[1] = args.subpoints[1]
|
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'
|
'parallel'
|
||||||
unless args.subpoints then return
|
unless args.subpoints then return
|
||||||
[newStart, oldStart, oldEnd] := args.subpoints
|
[newStart, oldStart, oldEnd] := args.subpoints
|
||||||
@ -555,24 +623,6 @@ classHandler: Record<JoyceClass, ClassHandler> :=
|
|||||||
madeSegment = true
|
madeSegment = true
|
||||||
else
|
else
|
||||||
commands.push `${aux}2 = Translate(${oldEnd}, ${aux}1)`
|
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
|
unless madeSegment
|
||||||
commands.push `${name} = Segment(${ends[0]},${ends[1]})`
|
commands.push `${name} = Segment(${ends[0]},${ends[1]})`
|
||||||
callbacks.push (api: AppletObject) => api.setLabelVisible name, true
|
callbacks.push (api: AppletObject) => api.setLabelVisible name, true
|
||||||
@ -585,9 +635,19 @@ classHandler: Record<JoyceClass, ClassHandler> :=
|
|||||||
parts[1].push name
|
parts[1].push name
|
||||||
switch method
|
switch method
|
||||||
'radius'
|
'radius'
|
||||||
unless args.subpoints then return
|
pt := args.subpoints
|
||||||
[center, point] := args.subpoints
|
unless pt then return
|
||||||
commands.push `${name} = Circle(${center}, ${point})`
|
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
|
callbacks.push (api: AppletObject) => api.setLabelVisible name, true
|
||||||
|
|
||||||
polygon: (name, method, args, index) =>
|
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 FlagType = (typeof flags)[number]
|
||||||
export type ConfigType = Partial<Record<FlagType, boolean>>
|
export type ConfigType = Partial<Record<FlagType, boolean>>
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user