feat: Enable 3D constructions when adapting Geometry Applet #40

Merged
glen merged 3 commits from enable_3d into main 2023-10-08 17:11:02 +00:00
3 changed files with 49 additions and 20 deletions
Showing only changes of commit e67cc4dc01 - Show all commits

View File

@ -16,8 +16,10 @@
<br/>
<br/>
Alter execution of the translated applet: <br/>
<label for="showall">Show all entities, even hidden ones</label>
<input type="checkbox" id="showall">
<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>
<input type="checkbox" id="showaux">
<script src="options.js" type="module"></script>
</body>

View File

@ -122,7 +122,11 @@ function freshCommander(): Commander
type JoyceArguments =
Partial<Record<JoyceClass|'subpoints', GeoName[]> & {scalar: number[]}>
type ClassHandler = (
name: GeoName, m: string, args: JoyceArguments, index: number) => Commander
name: GeoName,
method: string,
args: JoyceArguments,
index: number,
is3d: boolean) => Commander
type RGB = [number, number, number]
type XYZ = RGB
@ -154,10 +158,12 @@ function dispatchJcommand(
/e\[\d+\]/
num := parseInt(name.slice(2))
{commands, callbacks, parts} :=
jToG value, elements, num, backgroundRGB
jToG value, elements, num, backgroundRGB, is3d
if commands.length
lastTried .= 0
if commands.filter((&)).every (cmd) =>
if adapParams.config?.commands
console.log 'Translated to:', cmd
api.evalCommand(cmd) and ++lastTried
callbacks.forEach &(api, parts)
else console.warn
@ -173,7 +179,8 @@ function jToG(
jCom: string,
elements: JoyceElements,
index: number,
backgroundRGB: RGB): Commander
backgroundRGB: RGB
is3d: boolean): Commander
[jname, klass, method, data, ...colors] := jCom.split ';'
if adapParams.config?.commands
console.log 'Defining', jname, 'as a', klass, 'constructed by',
@ -201,11 +208,11 @@ function jToG(
(args.subpoints ?= []).push depGeo
else if depKlass is 'line'
(args.subpoints ?= []).push ...ends ?? []
cmdr = classHandler[klass] name, method, args, index
cmdr = classHandler[klass] name, method, args, index, is3d
unless name is jname then cmdr.callbacks.push (api: AppletObject) =>
api.setCaption name, jname
api.setLabelStyle name, 3 // style CAPTION = 3
if cmdr.auxiliaries.length
if cmdr.auxiliaries.length and not adapParams.config?.showaux
cmdr.callbacks.push (api: AppletObject) =>
for each aux of cmdr.auxiliaries
api.setAuxiliary aux, true
@ -399,14 +406,14 @@ function geoname(jname: JoyceName, elements: JoyceElements): GeoName
// All of the detailed semantics of each available command lies in this
// function.
classHandler: Record<JoyceClass, ClassHandler> :=
point: (name, method, args): Commander =>
point: (name, method, args, index, is3d): Commander =>
return := freshCommander()
{commands, callbacks, parts, auxiliaries} := return.value
aux := name + 'aUx'
parts[0].push name
switch method
'angleDivider'
// Note doesn't yet handle plane argument
/angle(?:Bisector|Divider)/
// Note we just ignore a possible plane argument; it's irrelevant
unless args.subpoints return
[start, center, end] := args.subpoints
// see if we need to make the destination segment from start to end
@ -416,11 +423,13 @@ classHandler: Record<JoyceClass, ClassHandler> :=
auxiliaries.push destination
commands.push `${destination} = Segment(${start}, ${end})`
else destination = args.line[0]
n := args.scalar?[0]
n := method is 'angleBisector' ? 2 : args.scalar?[0]
console.log 'Dividing angle', start, center, end, 'by', n
inPlane := is3d ? `, Plane(${start}, ${center}, ${end})` : ''
commands.push
`${aux}2 = Angle(${start}, ${center}, ${end})`
`${aux}2 = Angle(${start}, ${center}, ${end}${inPlane})`
`${aux}3 = If(${aux}2 > pi, ${aux}2 - 2*pi, ${aux}2)`
`${aux}4 = Rotate(${start}, ${aux}3/${n}, ${center})`
`${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'
@ -444,15 +453,19 @@ classHandler: Record<JoyceClass, ClassHandler> :=
'foot'
pt := args.subpoints
unless pt then return
destination := args.plane
? args.plane[0]
: `Line(${pt[1]},${pt[2]})`
commands.push
`${name} = ClosestPoint(Line(${pt[1]},${pt[2]}), ${pt[0]})`
`${name} = ClosestPoint(${destination}, ${pt[0]})`
'intersection'
// Checking Joyce source, means intersection of lines, not
// intersection of line segments
unless args.subpoints then return
l1 := `Line(${args.subpoints[0]},${args.subpoints[1]})`
l2 := `Line(${args.subpoints[2]},${args.subpoints[3]})`
commands.push `${name} = Intersect(${l1},${l2})`
pt := args.subpoints
unless pt then return
l1 := `Line(${pt[0]},${pt[1]})`
e2 := args.plane ? args.plane[0] : `Line(${pt[2]},${pt[3]})`
commands.push `${name} = Intersect(${l1},${e2})`
'last'
unless args.subpoints then return
commands.push `${name} = ${args.subpoints.at(-1)}`
@ -626,8 +639,22 @@ classHandler: Record<JoyceClass, ClassHandler> :=
// copy of the entity, and so we have to hide the original one
api.setVisible name, false
plane: (name, method, args) => freshCommander()
plane: (name, method, args) =>
return := freshCommander()
{commands, callbacks, parts, auxiliaries} := return.value
parts[2].push name
switch method
'3points'
unless args.subpoints?.length is 3 then return
commands.push `${name} = Plane(${args.subpoints.join ','})`
'perpendicular'
unless args.subpoints?.length is 2 then return
[thru, perp] := args.subpoints
commands.push
`${name} = PerpendicularPlane(${thru}, Line(${thru}, ${perp}))`
sphere: (name, method, args) => freshCommander()
polyhedron: (name, method, args, index) =>
return := freshCommander()
return.value.ends = ['', '']

View File

@ -1,4 +1,4 @@
export const flags = ['color', 'commands', 'showall'] as const
export const flags = ['color', 'commands', 'showall', 'showaux'] as const
export type FlagType = (typeof flags)[number]
export type ConfigType = Partial<Record<FlagType, boolean>>