feat: handle the 'pivot' parameter of the Geometry Applet
Dealing with general click and drag on the applet and differentiating between a background drag and dragging an element seemed like too big a task, so this PR simply provides a slider to rotate the diagram when the pivot is defined. Implementing this required storing much more construction data, and also dealing head-on with GeoGebra's shall we say "strange" choice where the value of an expression depends on what name it is assigned to... The resolution of this last bit was to use different GeoGebra names for Geometry Applet points that start with something other than an uppercase Roman letter.
This commit is contained in:
parent
bb1713a674
commit
85ad82d9e2
@ -101,7 +101,7 @@ export interface AppletObject {
|
||||
getXcoord(objName: string): number;
|
||||
getYcoord(objName: string): number;
|
||||
getZcoord(objName: string): number;
|
||||
setCoords(objName: string, x: number, y: number, z: number): void;
|
||||
setCoords(objName: string, x: number, y: number, z?: number): void;
|
||||
getValue(objName: string): number;
|
||||
getVersion(): string;
|
||||
getScreenshotBase64(callback: (data: string) => void, scale?: number): void;
|
||||
|
@ -49,6 +49,28 @@ adapParams: AdapParams :=
|
||||
? {loader: 'https://www.geogebra.org/apps/deployggb.js', joyceApplets: []}
|
||||
: JSON.parse(adapptScript.dataset.params ?? '') as AdapParams
|
||||
|
||||
type ConstructionData
|
||||
id: string
|
||||
bg: RGB
|
||||
is3d: boolean
|
||||
width: number
|
||||
height: number
|
||||
elements: JoyceElements
|
||||
pivot: string
|
||||
|
||||
// Global data setup for pivoting (ugh, but necessary because the api
|
||||
// is not passed to the callback, so we have to look up the slider in
|
||||
// a global list):
|
||||
|
||||
type PivotData
|
||||
api: AppletObject
|
||||
pivot: string
|
||||
lastAngle: number
|
||||
rotatable: string[]
|
||||
fixed: Record<string, boolean>
|
||||
|
||||
pivotData: Record<string, PivotData> := {}
|
||||
|
||||
function postApplets(jApplets: AppletDescription[], codebase = '')
|
||||
for each jApp of jApplets
|
||||
params := {
|
||||
@ -58,10 +80,8 @@ function postApplets(jApplets: AppletDescription[], codebase = '')
|
||||
jApp.width,
|
||||
jApp.height,
|
||||
appletOnLoad: (api: AppletObject) =>
|
||||
elements: JoyceElements := {}
|
||||
backgroundRGB := [255, 255, 255] as RGB
|
||||
config3d := contains3d jApp.params
|
||||
if config3d
|
||||
is3d := contains3d jApp.params
|
||||
if is3d
|
||||
api.enable3D true
|
||||
api.setPerspective 'T'
|
||||
// Get rid of the xy-plane indicator
|
||||
@ -72,10 +92,24 @@ function postApplets(jApplets: AppletDescription[], codebase = '')
|
||||
api.setPerspective 'G'
|
||||
if adapParams.config?.algebra
|
||||
api.setPerspective '+A'
|
||||
elements := {}
|
||||
pivot .= ''
|
||||
if 'pivot' in jApp.params
|
||||
if is3d
|
||||
console.warn('Geometry Applet "pivot" only supported for '
|
||||
+ '2D constrcutions. Ignoring.')
|
||||
else
|
||||
pivot = geoname(jApp.id, elements, 'point') + 'Pivot'
|
||||
pivotData[pivot] = {
|
||||
api, jApp.params.pivot,
|
||||
lastAngle: 0, rotatable: [], fixed: {}}
|
||||
cdata: ConstructionData := {
|
||||
bg: ([255, 255, 255] as RGB),
|
||||
is3d, jApp.id, jApp.width, jApp.height, elements, pivot}
|
||||
for name, value in jApp.params
|
||||
dispatchJcommand
|
||||
api, name, value, elements, backgroundRGB, config3d
|
||||
if config3d
|
||||
api, name, value, cdata
|
||||
if is3d
|
||||
depth .= jApp.width
|
||||
if jApp.height > depth then depth = jApp.height
|
||||
api.setCoordSystem
|
||||
@ -135,7 +169,7 @@ type ClassHandler = (
|
||||
method: string,
|
||||
args: JoyceArguments,
|
||||
index: number,
|
||||
is3d: boolean) => Commander
|
||||
cdata: ConstructionData) => Commander
|
||||
type RGB = [number, number, number]
|
||||
type XYZ = RGB
|
||||
|
||||
@ -146,28 +180,26 @@ function dispatchJcommand(
|
||||
api: AppletObject,
|
||||
name: string,
|
||||
value: string,
|
||||
elements: JoyceElements
|
||||
backgroundRGB: RGB,
|
||||
is3d: boolean): void
|
||||
cdata: ConstructionData): void
|
||||
switch name
|
||||
'background'
|
||||
newback := joyce2rgb value, backgroundRGB
|
||||
cdata.bg = joyce2rgb value, cdata.bg
|
||||
if adapParams.config?.commands
|
||||
console.log 'Setting background to', value, 'interpreted as',
|
||||
newback
|
||||
for i of [0..2]
|
||||
backgroundRGB[i] = newback[i]
|
||||
api.setGraphicsOptions 1, bgColor: colorsea(backgroundRGB).hex()
|
||||
cdata.bg
|
||||
api.setGraphicsOptions 1, bgColor: colorsea(cdata.bg).hex()
|
||||
'title'
|
||||
if adapParams.config?.commands
|
||||
console.log 'Setting title to', value
|
||||
corner := is3d ? 'Corner(-1,1)' : 'Corner(1,1)'
|
||||
corner := cdata.is3d ? 'Corner(-1,1)' : 'Corner(1,1)'
|
||||
api.evalCommand `TitlePoint = ${corner}
|
||||
Text("${value}", TitlePoint + (2,5))`
|
||||
'pivot'
|
||||
return // already handled in postApplets
|
||||
/e\[\d+\]/
|
||||
num := parseInt(name.slice(2))
|
||||
{commands, callbacks, parts} :=
|
||||
jToG value, elements, num, backgroundRGB, is3d
|
||||
jToG value, num, cdata
|
||||
if commands.length
|
||||
lastTried .= 0
|
||||
if commands.filter((&)).every (cmd) =>
|
||||
@ -180,16 +212,14 @@ function dispatchJcommand(
|
||||
(part of translation of '${value}')
|
||||
failed.`
|
||||
else console.warn `Could not parse command '${value}'`
|
||||
else console.warn `Unkown param ${name} = ${value}`
|
||||
else console.warn `Unknown param ${name} = ${value}`
|
||||
|
||||
// Parses a Joyce element-creating command, extending the elements
|
||||
// by side effect:
|
||||
function jToG(
|
||||
jCom: string,
|
||||
elements: JoyceElements,
|
||||
index: number,
|
||||
backgroundRGB: RGB
|
||||
is3d: boolean): Commander
|
||||
cdata: ConstructionData): Commander
|
||||
[jname, klass, method, data, ...colors] := jCom.split ';'
|
||||
if adapParams.config?.commands
|
||||
console.log 'Defining', jname, 'as a', klass, 'constructed by',
|
||||
@ -199,7 +229,9 @@ function jToG(
|
||||
console.warn `Unknown entity class ${klass}`
|
||||
return cmdr
|
||||
assertJoyceClass klass // shouldn't need to do that :-/
|
||||
name := if /^\p{L}\w*$/u.test jname then jname else geoname jname, elements
|
||||
isPivot := !!cdata.pivot and jname is pivotData[cdata.pivot].pivot
|
||||
name := geoname jname, cdata.elements, klass
|
||||
if isPivot then pivotData[cdata.pivot].pivot = name
|
||||
args: JoyceArguments := {}
|
||||
usesCaptions := []
|
||||
for each jdep of data.split ','
|
||||
@ -207,17 +239,17 @@ function jToG(
|
||||
if scalar is scalar // not NaN
|
||||
(args.scalar ?= []).push scalar
|
||||
continue
|
||||
unless jdep in elements
|
||||
unless jdep in cdata.elements
|
||||
console.warn `Reference to unknown geometric entity ${jdep} in $jCom}`
|
||||
return cmdr
|
||||
usesCaptions.push jdep
|
||||
{klass: depKlass, otherName: depGeo, ends} := elements[jdep]
|
||||
{klass: depKlass, otherName: depGeo, ends} := cdata.elements[jdep]
|
||||
(args[depKlass] ?= []).push depGeo
|
||||
if depKlass is 'point'
|
||||
(args.subpoints ?= []).push depGeo
|
||||
else if depKlass is 'line'
|
||||
(args.subpoints ?= []).push ...ends ?? []
|
||||
cmdr = classHandler[klass] name, method, args, index, is3d
|
||||
cmdr = classHandler[klass] name, method, args, index, cdata
|
||||
unless name is jname then cmdr.callbacks.push (api: AppletObject) =>
|
||||
api.setCaption name, jname
|
||||
api.setLabelStyle name, 3 // style CAPTION = 3
|
||||
@ -226,6 +258,25 @@ function jToG(
|
||||
for each aux of cmdr.auxiliaries
|
||||
api.setAuxiliary aux, true
|
||||
api.setVisible aux,false
|
||||
|
||||
// set up the pivot if there is one
|
||||
if isPivot
|
||||
unless klass is 'point'
|
||||
console.warn(`Can only pivot around a point, not the ${klass}`
|
||||
+ `named ${jname}. Ignoring.`)
|
||||
cdata.pivot = ''
|
||||
cmdr.commands.push(`${cdata.pivot} = `
|
||||
+ `Slider(0°,360°,1°,1,${cdata.width/3},true,true,false,false)`)
|
||||
cmdr.callbacks.push (api: AppletObject) =>
|
||||
api.setCaption cdata.pivot, 'Rotate Display'
|
||||
api.setLabelStyle cdata.pivot, 3
|
||||
api.setCoords(cdata.pivot, 2*cdata.width/3, cdata.height-10)
|
||||
// Not sure how to let TypeScript deal with putting a new function
|
||||
// on the global window object, so punting at least for now:
|
||||
// @ts-ignore
|
||||
window.pivotListener = pivotListener
|
||||
api.registerObjectUpdateListener(cdata.pivot, 'pivotListener')
|
||||
|
||||
// Create callback to assign colors
|
||||
if colors.length is 4 and colors.every (color) => invisible color
|
||||
cmdr.callbacks.push (api: AppletObject) => api.setVisible name, false
|
||||
@ -243,11 +294,11 @@ function jToG(
|
||||
console.log 'Fading out interior of', face if trace
|
||||
// hide the interior by making it transparent
|
||||
api.setFilling face, 0
|
||||
else if face not in elements
|
||||
else if face not in cdata.elements
|
||||
console.log 'Hiding face', face if trace
|
||||
api.setVisible face, false
|
||||
else
|
||||
faceRGB := joyce2rgb(colors[3] or 'brighter', backgroundRGB)
|
||||
faceRGB := joyce2rgb(colors[3] or 'brighter', cdata.bg)
|
||||
deep := ['circle', 'polygon', 'sector']
|
||||
filling := deep.includes(klass) ? 0.7 : 0.2
|
||||
for each face of parts[2]
|
||||
@ -259,28 +310,30 @@ function jToG(
|
||||
// Lines default to black:
|
||||
if invisible colors[2]
|
||||
for each line of parts[1]
|
||||
if line is name or line not in elements
|
||||
if line is name or line not in cdata.elements
|
||||
console.log 'Hiding line', line if trace
|
||||
api.setVisible line, false
|
||||
else
|
||||
lineRGB := joyce2rgb(colors[2] or 'black', backgroundRGB)
|
||||
lineRGB := joyce2rgb(colors[2] or 'black', cdata.bg)
|
||||
for each line of parts[1]
|
||||
console.log 'Coloring line', line, 'to', colors[2] if trace
|
||||
api.setVisible line, true
|
||||
api.setColor line, ...lineRGB
|
||||
|
||||
// Now color the points:
|
||||
console.log 'Considering point colors for', name if trace
|
||||
if trace
|
||||
console.log
|
||||
'Considering point colors for', name, 'of dimension', dimension
|
||||
if invisible colors[1]
|
||||
// Hide all the dim-0 elements that are not distinct independent
|
||||
// items:
|
||||
for each point of parts[0]
|
||||
if point is name or point not in elements
|
||||
if point is name or point not in cdata.elements
|
||||
console.log 'Hiding point', point if trace
|
||||
api.setVisible point, false
|
||||
else if dimension is 0 or colors[1] // Need to color the points
|
||||
ptRGB := colors[1] ? joyce2rgb colors[1], backgroundRGB
|
||||
: pointDefaultRGB name, method
|
||||
ptRGB := colors[1] ? joyce2rgb colors[1], cdata.bg
|
||||
: pointDefaultRGB name, method, isPivot
|
||||
for each point of parts[0]
|
||||
console.log 'Coloring point', point, 'to', colors[1] if trace
|
||||
api.setVisible point, true
|
||||
@ -290,12 +343,12 @@ function jToG(
|
||||
if invisible colors[0]
|
||||
console.log 'Hiding label', name if trace
|
||||
api.setLabelVisible name, false
|
||||
else if colors[dimension] and colors[dimension] is not colors[0]
|
||||
else if colors[dimension+1] and colors[dimension+1] is not colors[0]
|
||||
// Have to make a text to provide the caption, since GeoGebra
|
||||
// doesn't allow caption different color from entity.
|
||||
textName := 'GeoText' + index
|
||||
locationExpr := switch klass
|
||||
when 'point' then `1.02${name})`
|
||||
when 'point' then `1.02${name}`
|
||||
when 'line'
|
||||
(`Midpoint(${name}) + `
|
||||
+ `Rotate(Direction(${name})*Length(${name})*0.02, pi/2)`)
|
||||
@ -315,8 +368,12 @@ function jToG(
|
||||
unless parts[0].includes ex1 then ex1 = `Centroid(${ex1})`
|
||||
unless parts[0].includes ex2 then ex2 = `Centroid(${ex2})`
|
||||
`(4*${ex1}+${ex2})/5`
|
||||
api.evalCommand `${textName} = Text("${jname}", ${locationExpr})`
|
||||
api.setColor textName, ...joyce2rgb colors[0], backgroundRGB
|
||||
textCmd := `${textName} = Text("${jname}", ${locationExpr})`
|
||||
textCol := joyce2rgb colors[0], cdata.bg
|
||||
if trace
|
||||
console.log `Making text '${textCmd}' colored`, textCol
|
||||
api.evalCommand textCmd
|
||||
api.setColor textName, ...textCol
|
||||
// and hide the underlying GeoGebra label
|
||||
api.setLabelVisible name, false
|
||||
else if colors[0]
|
||||
@ -331,19 +388,35 @@ function jToG(
|
||||
console.log 'Setting label vis of', name, 'to', show if trace
|
||||
api.setLabelVisible name, show
|
||||
|
||||
// window[hideListener] = (arg) =>
|
||||
// api.setVisible name, false
|
||||
// api.registerObjectUpdateListener name, hideListener
|
||||
if cmdr.ends // line or sector
|
||||
elements[jname] =
|
||||
{otherName: name, usesCaptions, klass, cmdr.ends}
|
||||
elements[name] =
|
||||
{otherName: jname, usesCaptions, klass, cmdr.ends}
|
||||
else // any other geometry
|
||||
elements[jname] = {otherName: name, usesCaptions, klass}
|
||||
elements[name] = {otherName: jname, usesCaptions, klass}
|
||||
cdata.elements[jname] = {otherName: name, usesCaptions, klass, cmdr.ends}
|
||||
cdata.elements[name] = {otherName: jname, usesCaptions, klass, cmdr.ends}
|
||||
cmdr
|
||||
|
||||
function pivotListener(slider: string)
|
||||
pd := pivotData[slider]
|
||||
newval := pd.api.getValue slider
|
||||
if newval is pd.lastAngle then return
|
||||
rotation := newval - pd.lastAngle
|
||||
pd.lastAngle = newval
|
||||
pX := pd.api.getXcoord pd.pivot
|
||||
pY := pd.api.getYcoord pd.pivot
|
||||
relX: Record<string, number> := {}
|
||||
relY: Record<string, number> := {}
|
||||
for each anchor of pd.rotatable
|
||||
relX[anchor] = pd.api.getXcoord(anchor) - pX
|
||||
relY[anchor] = pd.api.getYcoord(anchor) - pY
|
||||
console.log 'Unfixing', anchor, relX[anchor], relY[anchor]
|
||||
pd.api.setFixed anchor, false
|
||||
ct := Math.cos rotation
|
||||
st := Math.sin rotation
|
||||
for each anchor of pd.rotatable
|
||||
rX := relX[anchor]*ct - relY[anchor]*st
|
||||
rY := relY[anchor]*ct + relX[anchor]*st
|
||||
pd.api.setCoords(anchor, rX + pX, rY + pY)
|
||||
if pd.fixed[anchor]
|
||||
console.log 'Re-fixing', anchor, rX, rY
|
||||
pd.api.setFixed anchor, true
|
||||
|
||||
function invisible(cname: string): boolean
|
||||
if adapParams.config?.showall then return false
|
||||
cname is '0' or cname is 'none'
|
||||
@ -397,8 +470,8 @@ function joyce2rgb(cname: string, backgroundRGB?: RGB): RGB
|
||||
console.warn 'Could not parse color:', cname
|
||||
[128, 128, 128]
|
||||
|
||||
function pointDefaultRGB(name: string, method: string): RGB
|
||||
// Need to short-circuit with green for pivot point, once that is implemented
|
||||
function pointDefaultRGB(name: string, method: string, isPivot: boolean): RGB
|
||||
if isPivot then return joyce2rgb 'green'
|
||||
switch method
|
||||
'free'
|
||||
joyce2rgb 'red'
|
||||
@ -406,7 +479,14 @@ function pointDefaultRGB(name: string, method: string): RGB
|
||||
joyce2rgb 'orange'
|
||||
else joyce2rgb 'black'
|
||||
|
||||
function geoname(jname: JoyceName, elements: JoyceElements): GeoName
|
||||
function geoname(
|
||||
jname: JoyceName, elements: JoyceElements, klass: JoyceClass): GeoName
|
||||
unless jname.substring(0,3) is 'Geo' // those might clash
|
||||
// Names with word characters starting with a capital are always good:
|
||||
if /^[A-Z]['\w]*$/.test jname then return jname
|
||||
// If it's not a point, can start with any letter:
|
||||
if klass !== 'point' and /^\p{L}['\w]*$/u.test jname then return jname
|
||||
// GeoGebra won't deal with this name, so hash it:
|
||||
numCode .= 0n
|
||||
numCode = numCode*128n + BigInt ch.codePointAt(0) ?? 1 for each ch of jname
|
||||
return .= 'Geo' + numCode.toString(36);
|
||||
@ -426,11 +506,12 @@ function cutoffExtend(
|
||||
// All of the detailed semantics of each available command lies in this
|
||||
// function.
|
||||
classHandler: Record<JoyceClass, ClassHandler> :=
|
||||
point: (name, method, args, index, is3d): Commander =>
|
||||
point: (name, method, args, index, cdata): Commander =>
|
||||
return := freshCommander()
|
||||
{commands, callbacks, parts, auxiliaries} := return.value
|
||||
zeroVector := is3d ? 'Vector((0,0,0))' : 'Vector((0,0))'
|
||||
zeroVector := cdata.is3d ? 'Vector((0,0,0))' : 'Vector((0,0))'
|
||||
aux := name + 'aUx'
|
||||
pivotable := cdata.pivot and name !== pivotData[cdata.pivot].pivot
|
||||
parts[0].push name
|
||||
switch method
|
||||
/angle(?:Bisector|Divider)/
|
||||
@ -445,7 +526,7 @@ classHandler: Record<JoyceClass, ClassHandler> :=
|
||||
commands.push `${destination} = Segment(${start}, ${end})`
|
||||
else destination = args.line[0]
|
||||
n := method is 'angleBisector' ? 2 : args.scalar?[0]
|
||||
inPlane := is3d ? `, Plane(${start}, ${center}, ${end})` : ''
|
||||
inPlane := cdata.is3d ? `, Plane(${start}, ${center}, ${end})` : ''
|
||||
commands.push
|
||||
`${aux}2 = Angle(${start}, ${center}, ${end}${inPlane})`
|
||||
`${aux}3 = If(${aux}2 > pi, ${aux}2 - 2*pi, ${aux}2)`
|
||||
@ -454,7 +535,12 @@ classHandler: Record<JoyceClass, ClassHandler> :=
|
||||
auxiliaries.push ...[2..4].map (i) => `${aux}${i}`
|
||||
'circleSlider'
|
||||
unless args.circle then return
|
||||
commands.push `${name} = Point(${args.circle[0]})`
|
||||
circ := args.circle[0]
|
||||
commands.push `${name} = Point(${circ})`
|
||||
if (pivotable
|
||||
and cdata.elements[circ].ends?[0] // center
|
||||
is pivotData[cdata.pivot].pivot)
|
||||
pivotData[cdata.pivot].rotatable.push name
|
||||
if args.scalar and args.scalar.length
|
||||
callbacks.push (api: AppletObject) =>
|
||||
api.setCoords name, ...args.scalar as XYZ
|
||||
@ -466,12 +552,15 @@ classHandler: Record<JoyceClass, ClassHandler> :=
|
||||
commands.push `${name} = Translate(${source}, ${displacement})`
|
||||
'first'
|
||||
unless args.subpoints then return
|
||||
commands.push `${name} = Point(${args.subpoints[0]},${zeroVector})`
|
||||
commands.push `${name} = ${args.subpoints[0]}`
|
||||
/fixed|free/
|
||||
coords := args.scalar
|
||||
unless coords then return
|
||||
commands.push `${name} = Point({${coords.join ','}})`
|
||||
scoord := coords.join ','
|
||||
if pivotable then pivotData[cdata.pivot].rotatable.push name
|
||||
commands.push `${name} = (${scoord})`
|
||||
if method is 'fixed'
|
||||
if pivotable then pivotData[cdata.pivot].fixed[name] = true
|
||||
callbacks.push (api: AppletObject) => api.setFixed name, true
|
||||
'foot'
|
||||
pt := args.subpoints
|
||||
@ -492,7 +581,7 @@ classHandler: Record<JoyceClass, ClassHandler> :=
|
||||
'last'
|
||||
unless args.subpoints then return
|
||||
commands.push
|
||||
`${name} = Point(${args.subpoints.at(-1)}, ${zeroVector})`
|
||||
`${name} = ${args.subpoints.at(-1)}`
|
||||
'lineSegmentSlider'
|
||||
segment .= args.line?[0]
|
||||
unless segment
|
||||
@ -524,7 +613,7 @@ classHandler: Record<JoyceClass, ClassHandler> :=
|
||||
unless pt.length is 5 then return
|
||||
sourcePlane .= ''
|
||||
destPlane .= ''
|
||||
if is3d
|
||||
if cdata.is3d
|
||||
unless args.plane then return
|
||||
destPlane = `, ${args.plane[0]}`
|
||||
if args.plane.length > 1
|
||||
@ -544,7 +633,7 @@ classHandler: Record<JoyceClass, ClassHandler> :=
|
||||
commands.push
|
||||
`${name} = Vertex(${args.polygon?[0]},${args.scalar?[0]})`
|
||||
|
||||
line: (name, method, args, index, is3d) =>
|
||||
line: (name, method, args, index, cdata) =>
|
||||
return := freshCommander()
|
||||
return.value.ends = ['', '']
|
||||
{commands, callbacks, parts, auxiliaries, ends} := return.value
|
||||
@ -561,7 +650,7 @@ classHandler: Record<JoyceClass, ClassHandler> :=
|
||||
unless cr return
|
||||
commands.push ...[1..2].map (n) =>
|
||||
`${aux}${n} = Intersect(${cr[0]}, ${cr[1]}, ${n})`
|
||||
inPlane := is3d ? `Plane(${cr[0]})` : ''
|
||||
inPlane := cdata.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})`)
|
||||
@ -630,7 +719,8 @@ classHandler: Record<JoyceClass, ClassHandler> :=
|
||||
|
||||
circle: (name, method, args) =>
|
||||
return := freshCommander()
|
||||
{commands, callbacks, parts, auxiliaries} := return.value
|
||||
return.value.ends = ['', '']
|
||||
{commands, callbacks, parts, auxiliaries, ends} := return.value
|
||||
parts[2].push name
|
||||
parts[1].push name
|
||||
switch method
|
||||
@ -641,10 +731,12 @@ classHandler: Record<JoyceClass, ClassHandler> :=
|
||||
switch pt.length
|
||||
when 2
|
||||
[center, point] := pt
|
||||
ends[0] = center
|
||||
commands.push
|
||||
`${name} = Circle(${center}, ${point}${inPlane})`
|
||||
when 3
|
||||
center := pt[0]
|
||||
ends[0] = center
|
||||
radius := `Distance(${pt[1]}, ${pt[2]})`
|
||||
commands.push
|
||||
`${name} = Circle(${center}, ${radius}${inPlane})`
|
||||
|
Loading…
Reference in New Issue
Block a user