feat: Get all of Rostamian's old pages working #44

Merged
glen merged 4 commits from rostamian_old into main 2023-10-18 01:07:58 +00:00
4 changed files with 119 additions and 54 deletions
Showing only changes of commit bb1713a674 - Show all commits

View File

@ -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>

View File

@ -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 =>

View File

@ -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) =>

View File

@ -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>>