diff --git a/src/adapptlet.civet b/src/adapptlet.civet index 31a02b9..edec023 100644 --- a/src/adapptlet.civet +++ b/src/adapptlet.civet @@ -67,6 +67,7 @@ type ConstructionData height: number elements: JoyceElements pivot: string + title?: 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 @@ -186,7 +187,8 @@ type ClassHandler = ( method: string, args: JoyceArguments, index: number, - cdata: ConstructionData) => Commander + cdata: ConstructionData, + colors: string[]) => Commander type RGB = [number, number, number] type XYZ = RGB @@ -208,6 +210,7 @@ function dispatchJcommand( 'title' if adapParams.config?.commands console.log 'Setting title to', value + cdata.title = value api.evalCommand `TitlePoint = Corner(1,1) Text("${value}", TitlePoint + (2,5))` 'pivot' @@ -257,7 +260,7 @@ function jToG( args: JoyceArguments := {} usesCaptions := [] for each jdep of data.split ',' - scalar := parseFloat jdep + scalar := Number jdep if scalar is scalar // not NaN (args.scalar ?= []).push scalar continue @@ -271,7 +274,7 @@ function jToG( (args.subpoints ?= []).push depGeo else if depKlass is 'line' (args.subpoints ?= []).push ...ends ?? [] - cmdr = classHandler[klass] name, method, args, index, cdata + cmdr = classHandler[klass] name, method, args, index, cdata, colors unless name is jname then cmdr.callbacks.push (api: AppletObject) => api.setCaption name, jname api.setLabelStyle name, 3 // style CAPTION = 3 @@ -517,7 +520,7 @@ function pointDefaultColorName( function geoname( jname: JoyceName, elements: JoyceElements, klass: JoyceClass): GeoName - unless jname.substring(0,3) is 'Geo' // those might clash + unless jname is 'floor' or 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: @@ -571,7 +574,7 @@ function proportionSimilar( // All of the detailed semantics of each available command lies in this // function. classHandler: Record := - point: (name, method, args, index, cdata): Commander => + point: (name, method, args, index, cdata, colors): Commander => return := freshCommander() {commands, callbacks, parts, auxiliaries} := return.value zeroVector := cdata.is3d ? 'Vector((0,0,0))' : 'Vector((0,0))' @@ -579,6 +582,22 @@ classHandler: Record := aux := name + 'aUx' pivotable := cdata.pivot and name !== pivotData[cdata.pivot].pivot parts[0].push name + // HACK: Special-case corrections for Joyce Elements Bk XI + if cdata.title is 'XI.4' + if name is 'Z' and method is 'fixed' and args.scalar?.length is 3 + method = 'perpendicular' + args.subpoints = ['E','P2','A'] + args.plane = ['baseplane'] + colors[0] = '0' + colors[1] = '0' + if name is 'F' and method is 'lineSlider' and args.subpoints?[0] is 'E' + args.scalar = [160,40,60] + if cdata.title is 'XI.5' + if name is 'A' and method is 'free' + method = 'perpendicular' + args.subpoints = ['B','P1','P3'] + args.plane = ['xOyPlane'] + commands.push 'B=(80,140)' switch method /angle(?:Bisector|Divider)/ {center, foot} := @@ -608,6 +627,12 @@ classHandler: Record := if args.scalar and args.scalar.length callbacks.push (api: AppletObject) => api.setCoords name, ...vertFlipped(args.scalar or [], cdata) + 'circumcenter' + unless args.subpoints?.length is 3 then return + commands.push + `${aux} = Circle(${args.subpoints.join ','})` + `${name} = Center(${aux})` + auxiliaries.push aux /cutoff|extend/ pt := args.subpoints unless pt and pt.length is 4 then return @@ -616,9 +641,9 @@ classHandler: Record := commands.push `${name} = Translate(${source}, ${displacement})` 'first' unless args.subpoints then return - // HACK: Special-case correction for Joyce Elements Bk II, prop 14 index .= 0 - if name === 'H' and args.line and args.line[0] === 'HH2' + // HACK: Special-case correction for Joyce Elements Bk II, prop 14 + if cdata.title is 'II.14' and name is 'H' and args.line?[0] is 'HH2' index = 1 commands.push `${name} = ${args.subpoints[index]}` /fixed|free/ @@ -642,9 +667,9 @@ classHandler: Record := // Checking Joyce source, means intersection of lines, not // intersection of line segments pt := args.subpoints - unless pt then return + unless pt and pt.length > 1 then return l1 := `Line(${pt[0]},${pt[1]})` - e2 := args.plane ? args.plane[0] : `Line(${pt[2]},${pt[3]})` + e2 := pt.length < 3 ? args.plane?[0] : `Line(${pt[2]},${pt[3]})` commands.push `${name} = Intersect(${l1},${e2})` 'last' unless args.subpoints then return @@ -696,8 +721,9 @@ classHandler: Record := `${name} = Rotate(${pt[1]}, pi/2, ${center}${inPlane})` when 3 // perpendicular **to** the plane // Uses lots of auxiliaries + radius := `Distance(${pt[1]}, ${pt[2]})` commands.push - `${aux}1 = Circle(${center}, Distance(${pt[1]}, ${pt[2]})${inPlane})` + `${aux}1 = Circle(${center}, ${radius}${inPlane})` `${aux}2 = PointIn(${aux}1)` `${aux}3 = PerpendicularLine(${center}${inPlane})` `${aux}4 = Plane(${aux}2, ${aux}3)` @@ -847,7 +873,17 @@ classHandler: Record := commands.push `${aux} = Rotate(${pt[1]}, pi/2, ${pt[0]}${inPlane})` when 3 - return // TODO: line perpendicular to plane + radius := `Distance(${pt[1]}, ${pt[2]})` + commands.push + `${aux}1 = PerpendicularLine(${pt[1]}${inPlane})` + `${aux}2 = Intersect(${aux}1${inPlane})` + `${aux}3 = Circle(${aux}2, ${radius}${inPlane})` + `${aux}4 = PointIn(${aux}3)` + `${aux}5 = Plane(${aux}4, ${aux}1)` + `${aux}6 = Rotate(${aux}4, pi/2, ${aux}2, ${aux}5)` + ends[0] = aux + 2 + ends[1] = aux + 6 + auxiliaries.push aux+n for n of [1..6] when 4 ends[0] = pt[0] ends[1] = aux + 2 @@ -998,7 +1034,7 @@ classHandler: Record := aux := name + 'aUx' parts[2].push name defaultPlane := cdata.is3d ? ', xOyPlane' : '' - inPlane := args.plane ? `, ${args.plane[0]}` : defaultPlane + inPlane .= args.plane ? `, ${args.plane[0]}` : defaultPlane switch method /arc|sector/ unless args.subpoints?.length is 3 return @@ -1012,6 +1048,7 @@ classHandler: Record := center = temp parms = start + ', ' + center + ', ' + end prefix = 'Circumcircular' + inPlane = '' // not needed in 3-point case ends[0] = start ends[1] = end commands.push @@ -1029,6 +1066,10 @@ classHandler: Record := '3points' unless args.subpoints?.length is 3 then return commands.push `${name} = Plane(${args.subpoints.join ','})` + 'parallel' + unless args.subpoints?.length is 1 then return + unless args.plane?.length is 1 then return + commands.push `${name} = Plane(${args.subpoints[0]}, ${args.plane[0]})` 'perpendicular' unless args.subpoints?.length is 2 then return [thru, perp] := args.subpoints @@ -1099,6 +1140,33 @@ classHandler: Record := api.renameObject obj, newObj moreParts[1].push newObj ix += 1 + 'prism' + unless args.polygon?.length is 1 then return + base := args.polygon[0] + ends[0] = base + pt := args.subpoints + unless pt and pt.length is 2 then return + commands.push + `${aux}1 = Vertex(${base},1) + ${pt[1]} - ${pt[0]}` + auxiliaries.push aux+1 + ends[1] = aux+1 + parts[0].push aux+1 + parts[2].push ends[0] + callbacks.push (api: AppletObject, moreParts: DimParts) => + made := api.evalCommandGetLabels + `${name} = Prism(${base}, ${aux}1)` + if not made return + for each obj of made.split ',' + if obj is name continue + newObj := 'GeoAux' + index + obj + api.renameObject obj, newObj + switch api.getObjectType newObj + 'point' + moreParts[0].push newObj + 'segment' + moreParts[1].push newObj + else + moreParts[2].push newObj /pyramid|tetrahedron/ base .= args.polygon?[0] ends[0] = base or aux + 1