diff --git a/etc/options.html b/etc/options.html index e618cf5..b512c0e 100644 --- a/etc/options.html +++ b/etc/options.html @@ -18,8 +18,12 @@ Alter execution of the translated applet:

- + +
+
+ + diff --git a/src/adapptext.civet b/src/adapptext.civet index 8b0be59..5138235 100644 --- a/src/adapptext.civet +++ b/src/adapptext.civet @@ -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 => diff --git a/src/adapptlet.civet b/src/adapptlet.civet index e049d75..a08a6a2 100644 --- a/src/adapptlet.civet +++ b/src/adapptlet.civet @@ -35,6 +35,20 @@ type Description // with the otherName property: type JoyceElements = Record +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 := 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 := `${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 := 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 := 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 := 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 := 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 := 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) => diff --git a/src/adapptypes.civet b/src/adapptypes.civet index 5abf456..72d28ea 100644 --- a/src/adapptypes.civet +++ b/src/adapptypes.civet @@ -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>