feat: Get all of Rostamian's old pages working #44
4 changed files with 119 additions and 54 deletions
|
@ -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…
Add table
Reference in a new issue