feat: Improve construction element handling #32
BIN
public/Geometry.zip
Normal file
BIN
public/Geometry.zip
Normal file
Binary file not shown.
@ -8,6 +8,7 @@
|
||||
<h2>Joyce Geometry Applet</h2>
|
||||
<ul>
|
||||
<li> <a href="inscribed-equilateral.html">Before</a> </li>
|
||||
<li> <a href="inscribed-revived.html">Revived</a> </li>
|
||||
<li> <a href="inscribed-modified.html">After</a> </li>
|
||||
</ul>
|
||||
<h2>WRL Files</h2>
|
||||
|
135
public/inscribed-revived.html
Normal file
135
public/inscribed-revived.html
Normal file
@ -0,0 +1,135 @@
|
||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
|
||||
<html>
|
||||
<head>
|
||||
<!-- fix buggy IE8, especially for mathjax -->
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=EmulateIE7">
|
||||
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||
<title>An equilateral triangle inscribed in a rectangle</title>
|
||||
<link rel="stylesheet" type="text/css" media="screen" href="style.css">
|
||||
|
||||
<script type="text/javascript"
|
||||
src="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML,http://userpages.umbc.edu/~rostamia/mathjax-config.js">
|
||||
MathJax.Hub.Queue( function() {document.body.style.visibility="visible"} );
|
||||
</script>
|
||||
|
||||
</head>
|
||||
<body style="visibility:hidden">
|
||||
|
||||
<h1>An equilateral triangle inscribed in a rectangle</h1>
|
||||
|
||||
<table class="centered">
|
||||
<tr><td align="center">
|
||||
<applet code="Geometry" archive="Geometry.zip" width="410" height="370">
|
||||
<param name="background" value="ffffff">
|
||||
<param name="title" value="An equilateral triangle inscribed in a rectangle">
|
||||
|
||||
<!-- the moving mechanism -->
|
||||
<param name="e[1]" value="O;point;fixed;290,320">
|
||||
<param name="e[2]" value="U1;point;fixed;510,320">
|
||||
<param name="e[3]" value="V1;point;perpendicular;O,U1">
|
||||
<param name="e[4]" value="U;point;angleDivider;U1,O,V1,3">
|
||||
<param name="e[5]" value="V;point;angleDivider;V1,O,U1,3">
|
||||
<param name="e[6]" value="circ1;circle;radius;O,U">
|
||||
<param name="e[7]" value="li1;line;parallel;U,O,U1">
|
||||
<param name="e[8]" value="li2;line;parallel;V,O,V1">
|
||||
<param name="e[9]" value="W;point;intersection;li1,li2">
|
||||
<param name="e[10]" value="VW;line;connect;V,W;0;0;lightGray">
|
||||
<param name="e[11]" value="@;point;lineSegmentSlider;V,W,0,220;red;red">
|
||||
<param name="e[12]" value="li3;line;parallel;@,O,U1">
|
||||
<param name="e[13]" value="li4;line;chord;circ1,li3">
|
||||
<param name="e[14]" value="X1;point;first;li4">
|
||||
|
||||
<!-- the triangle -->
|
||||
<param name="e[15]" value="A;point;fixed;50,320">
|
||||
<param name="e[16]" value="V2;point;perpendicular;A,U1">
|
||||
<param name="e[17]" value="li5;line;parallel;A,O,X1">
|
||||
<param name="e[18]" value="X2;point;last;li5">
|
||||
<param name="e[19]" value="X;point;extend;A,X2,A,X2">
|
||||
|
||||
<param name="e[20]" value="tri1;polygon;equilateralTriangle;X,A">
|
||||
<param name="e[21]" value="Y;point;vertex;tri1,3">
|
||||
<param name="e[22]" value="B;point;midpoint;X,Y">
|
||||
<param name="e[23]" value="ABC;polygon;equilateralTriangle;A,B">
|
||||
<param name="e[24]" value="C;point;vertex;ABC,3">
|
||||
|
||||
<!-- the rectangle -->
|
||||
<param name="e[25]" value="D;point;foot;B,A,U1">
|
||||
<param name="e[26]" value="F;point;foot;C,A,V2">
|
||||
<param name="e[27]" value="FE;line;parallel;F,A,D">
|
||||
<param name="e[28]" value="E;point;last;FE">
|
||||
<param name="e[29]" value="rect;polygon;quadrilateral;A,D,E,F;0;0;black;0">
|
||||
<param name="e[30]" value="ADB;polygon;triangle;A,D,B;0;0;0;pink">
|
||||
<param name="e[31]" value="ACF;polygon;triangle;A,C,F;0;0;0;pink">
|
||||
<param name="e[32]" value="BCE;polygon;triangle;B,C,E;0;0;0;cyan">
|
||||
|
||||
</applet>
|
||||
</td></tr>
|
||||
<tr><td>
|
||||
<b>
|
||||
Slide the “@” up and down to change the geometry.<br>
|
||||
Press “r” to reset the diagram to its initial state.<br>
|
||||
Proposition: The blue area equals the sum of the two pink areas.
|
||||
</b>
|
||||
</td></tr></table>
|
||||
|
||||
<h2>Problem statement</h2>
|
||||
|
||||
<p>
|
||||
The diagram above shows an equilateral triangle inscribed in a rectangle
|
||||
in such a way that the two have a vertex in common. This subdivides the
|
||||
rectangle into four disjoint triangles.
|
||||
The original equilateral triangle is shown in white
|
||||
in the diagram; the other three are shown in color.
|
||||
|
||||
<p>
|
||||
<b>Proposition</b>
|
||||
<em>
|
||||
The area of the blue triangle equals the sum
|
||||
of the areas of the two pink triangles.
|
||||
</em>
|
||||
|
||||
<p>
|
||||
The trigonometric proof is quite straightforward. I don't
|
||||
know of a classical proof <i>a la</i> <span class="name">Euclid</span>.
|
||||
(Well, actually I haven't tried much.)
|
||||
If you can think of a neat non-trigonometric proof, let me know. I will
|
||||
put it here with due credit.
|
||||
|
||||
<p>
|
||||
This problem appeared as a conjecture
|
||||
<a href="http://mathforum.org/kb/thread.jspa?forumID=129&messageID=1083967">in an article</a>
|
||||
in the <code>geometry.puzzles</code> newsgroup on March 15, 1997.
|
||||
|
||||
<p>
|
||||
<b>Note added January 8, 2017:</b>
|
||||
Here is a
|
||||
<a href="inscribed-equilateral-solution.html">clever solution</a>
|
||||
that <b>Peter Renz</b> sent me a in December 2016. Thanks, Peter!
|
||||
|
||||
<hr width="60%">
|
||||
<p>
|
||||
<em>This applet was created by
|
||||
<a href="http://userpages.umbc.edu/~rostamia">Rouben Rostamian</a>
|
||||
using
|
||||
<a href="http://aleph0.clarku.edu/~djoyce/home.html">David Joyce</a>'s
|
||||
<a href="http://aleph0.clarkU.edu/~djoyce/java/Geometry/Geometry.html">Geometry
|
||||
Applet</a>
|
||||
on July 2, 2010.
|
||||
</em>
|
||||
<p>
|
||||
|
||||
<table width="100%">
|
||||
<tr>
|
||||
<td valign="top">Go to <a href="index.html">Geometry Problems and Puzzles</a></td>
|
||||
<td align="right" style="width:200px;">
|
||||
<a href="http://validator.w3.org/check?uri=referer">
|
||||
<img src="/~rostamia/images/valid-html401.png" class="noborder" width="88" height="31" alt="Valid HTML"></a>
|
||||
<a href="http://jigsaw.w3.org/css-validator/check/referer">
|
||||
<img src="/~rostamia/images/valid-css.png" class="noborder" width="88" height="31" alt="Valid CSS"></a>
|
||||
</td></tr>
|
||||
</table>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
@ -16,6 +16,30 @@ $('applet[code="Geometry"]').before (i, html) ->
|
||||
height: parseInt(this.getAttribute('height') ?? '200') }
|
||||
`<div id="${id}"></div>`
|
||||
|
||||
type Split<S extends string>
|
||||
S extends `${infer W} ${infer R}` ? (W | Split<R>) : S
|
||||
|
||||
classes := 'point line circle polygon sector plane sphere polyhedron'
|
||||
type JoyceClass = Split<typeof classes>
|
||||
function assertJoyceClass(s: string): asserts s is JoyceClass
|
||||
unless classes.includes s then throw new Error `Oops ${s} slipped through`
|
||||
|
||||
type JoyceName = string // we use this to indicate where the names
|
||||
// from the Joyce commands (which are used as captions in the GeoGebra
|
||||
// applet) go.
|
||||
type GeoName = string // and this to indicate where GeoGebra identifiers go
|
||||
type AnyName = GeoName | JoyceName // and this for slots that can be either
|
||||
|
||||
type Description
|
||||
otherName: AnyName
|
||||
usesCaptions: JoyceName[]
|
||||
klass: JoyceClass
|
||||
ends?: [GeoName, GeoName]
|
||||
|
||||
// We put both JoyceNames and GeoNames in here, pointing to each other
|
||||
// with the otherName property:
|
||||
type JoyceElements = Record<AnyName, Description>
|
||||
|
||||
jQuery.getScript 'https://www.geogebra.org/apps/deployggb.js', =>
|
||||
for each jApp of joyceApplets
|
||||
params := {
|
||||
@ -23,100 +47,325 @@ jQuery.getScript 'https://www.geogebra.org/apps/deployggb.js', =>
|
||||
jApp.width,
|
||||
jApp.height,
|
||||
appletOnLoad: (api: AppletObject) =>
|
||||
elements: JoyceElements := {}
|
||||
for child of jApp.children
|
||||
dispatchJcommand api, child
|
||||
dispatchJcommand api, child, elements
|
||||
api.setCoordSystem(-10, 10 + jApp.width, -10, 10 + jApp.height)
|
||||
} as const
|
||||
geoApp := new GGBApplet params
|
||||
geoApp.inject jApp.id
|
||||
|
||||
type GeogebraCallback = (api: AppletObject) => void
|
||||
type DimParts = [string[], string[], string[]] // Gives GeoNames
|
||||
// or expressions for 0-, 1-, and 2-dimensional parts for coloring
|
||||
|
||||
// need to pass the parts into the callbacks because sometimes the parts
|
||||
// are not generated until callback time
|
||||
type GeogebraCallback = (api: AppletObject, parts: DimParts) => void
|
||||
type Commander
|
||||
command: string
|
||||
commands: string[]
|
||||
callbacks: GeogebraCallback[]
|
||||
parts: DimParts
|
||||
auxiliaries: GeoName[] // extra entities needed in GeoGebra
|
||||
ends?: [GeoName, GeoName]
|
||||
|
||||
function freshCommander(): Commander
|
||||
commands: []
|
||||
callbacks: []
|
||||
parts: [[], [], []]
|
||||
auxiliaries: []
|
||||
|
||||
type JoyceArguments =
|
||||
Partial<Record<JoyceClass|'subpoints', GeoName[]> & {scalar: number[]}>
|
||||
|
||||
type ClassHandler = (
|
||||
name: string, m: string, data: string, colors: string[]) => Commander
|
||||
name: GeoName, m: string, args: JoyceArguments, index: number) => Commander
|
||||
|
||||
function dispatchJcommand(api: AppletObject, param: Element): void
|
||||
// Executes the command corresponding to param against the GeoGebra applet
|
||||
// api, consulting and extending by side effect the elements that are
|
||||
// present in that applet
|
||||
function dispatchJcommand(
|
||||
api: AppletObject, param: Element, elements: JoyceElements): void
|
||||
val := param.getAttribute 'value'
|
||||
unless val return
|
||||
switch param.getAttribute 'name'
|
||||
attr := param.getAttribute 'name'
|
||||
switch attr
|
||||
'background'
|
||||
api.setGraphicsOptions 1, bgColor: `#${val}`
|
||||
'title'
|
||||
api.evalCommand `TitlePoint = Corner(1,1)
|
||||
Text("${val}", TitlePoint + (2,5))`
|
||||
/e\[\d+\]/
|
||||
{command, callbacks} := jToG val
|
||||
if command
|
||||
if api.evalCommand command
|
||||
for each cb of callbacks
|
||||
cb(api)
|
||||
else
|
||||
console.log `Geogebra command '${command}' translated from`,
|
||||
val, 'failed.'
|
||||
else
|
||||
console.log `Could not parse command '${val}'`
|
||||
else
|
||||
console.log `Unkown param ${param}`
|
||||
num := parseInt(attr.slice(2))
|
||||
{commands, callbacks, parts} := jToG val, elements, num
|
||||
if commands.length
|
||||
lastTried .= 0
|
||||
if commands.filter((&)).every (cmd) =>
|
||||
api.evalCommand(cmd) and ++lastTried
|
||||
callbacks.forEach &(api, parts)
|
||||
else console.log
|
||||
`Geogebra command '${commands[lastTried]}'
|
||||
(part of translation of '${val}')
|
||||
failed.`
|
||||
else console.log `Could not parse command '${val}'`
|
||||
else console.log `Unkown param ${param}`
|
||||
|
||||
function jToG(jCom: string): Commander
|
||||
[name, klass, method, data, ...colors] := jCom.split(';')
|
||||
if klass in classHandler
|
||||
return classHandler[klass] name, method, data, colors
|
||||
console.log `Unknown entity class ${klass}`
|
||||
command: '', callbacks: []
|
||||
// function myListener(...args: unknown[]) {
|
||||
// console.log 'In my listener with', args
|
||||
// }
|
||||
|
||||
classHandler: Record<string, ClassHandler> :=
|
||||
point: (name, method, data, colors) =>
|
||||
command .= ''
|
||||
callbacks: GeogebraCallback[] .= []
|
||||
args := data.split(',')
|
||||
// window.myListener = myListener
|
||||
|
||||
// Parses a Joyce element-creating command, extending the elements
|
||||
// by side effect:
|
||||
function jToG(jCom: string, elements: JoyceElements, index: number): Commander
|
||||
[jname, klass, method, data, ...colors] := jCom.split(';')
|
||||
cmdr .= freshCommander()
|
||||
unless klass in classHandler
|
||||
console.log `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
|
||||
args: JoyceArguments := {}
|
||||
usesCaptions := []
|
||||
for each jdep of data.split ','
|
||||
scalar := parseFloat jdep
|
||||
if scalar is scalar // not NaN
|
||||
(args.scalar ?= []).push scalar
|
||||
continue
|
||||
unless jdep in elements
|
||||
console.log `Reference to unknown geometric entity ${jdep} in $jCom}`
|
||||
return cmdr
|
||||
usesCaptions.push jdep
|
||||
{klass: depKlass, otherName: depGeo, ends} := 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
|
||||
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
|
||||
cmdr.callbacks.push (api: AppletObject) =>
|
||||
for each aux of cmdr.auxiliaries
|
||||
api.setAuxiliary(aux, true)
|
||||
api.setVisible(aux,false)
|
||||
// Create callback to assign colors
|
||||
if colors.length is 4 and colors.every (color) =>
|
||||
false and color is '0' or color is 'none'
|
||||
cmdr.callbacks.push (api: AppletObject) =>
|
||||
api.setVisible(name, false)
|
||||
// window[hideListener] = (arg) =>
|
||||
// console.log('Hello', arg, 'disappearing', name)
|
||||
// api.setVisible(name, false)
|
||||
api.registerObjectUpdateListener(name, hideListener)
|
||||
if cmdr.ends or klass is 'line'
|
||||
elements[jname] =
|
||||
{otherName: name, usesCaptions, klass: 'line', cmdr.ends}
|
||||
elements[name] =
|
||||
{otherName: jname, usesCaptions, klass: 'line', cmdr.ends}
|
||||
else // any other geometry
|
||||
elements[jname] = {otherName: name, usesCaptions, klass}
|
||||
elements[name] = {otherName: jname, usesCaptions, klass}
|
||||
cmdr
|
||||
|
||||
function geoname(jname: JoyceName, elements: JoyceElements): GeoName
|
||||
numCode .= 0n
|
||||
numCode = numCode*128n + BigInt ch.codePointAt(0) ?? 1 for each ch of jname
|
||||
return .= 'Geo' + numCode.toString(36);
|
||||
return += '1' while return.value in elements
|
||||
|
||||
// All of the detailed semantics of each available command lies in this
|
||||
// function.
|
||||
classHandler: Record<JoyceClass, ClassHandler> :=
|
||||
point: (name, method, args): Commander =>
|
||||
return := freshCommander()
|
||||
{commands, callbacks, parts, auxiliaries} := return.value
|
||||
aux := name + 'aUx'
|
||||
parts[0].push name
|
||||
switch method
|
||||
/free|fixed/
|
||||
command += `${name} = (${data})`
|
||||
commands.push `${name} = (${args.scalar?.join ','})`
|
||||
if method is 'fixed'
|
||||
callbacks.push (api: AppletObject) => api.setFixed(name, true)
|
||||
'perpendicular'
|
||||
[center, direction] := args
|
||||
command += `${name} = Rotate(${direction}, 3*pi/2, ${center})`
|
||||
// Note only the two-point option implemented so far
|
||||
unless args.subpoints return
|
||||
[center, direction] := args.subpoints
|
||||
// Note clockwise 90° rotation (3π/2) confirmed in Joyce source
|
||||
commands.push `${name} = Rotate(${direction}, 3*pi/2, ${center})`
|
||||
'angleDivider'
|
||||
n .= -1
|
||||
// use the fact that NaN doesn't equal itself:
|
||||
nLoc := args.findIndex((arg) => (n = parseInt arg) is n)
|
||||
if n >= 0
|
||||
args.splice(nLoc)
|
||||
[center, start, end] := args
|
||||
command += `${name}aUx1 = Segment(${start}, ${end})
|
||||
${name}aUx2 = Angle(${start}, ${center}, ${end})
|
||||
${name}aUx2a = If(${name}aUx2 > pi, ${name}aUx2 - 2*pi, ${name}aUx2)
|
||||
${name}aUx3 = Rotate(${start}, ${name}aUx2a/${n}, ${center})
|
||||
${name}aUx4 = Ray(${center}, ${name}aUx3)
|
||||
${name} = Intersect(${name}aUx1, ${name}aUx4)`
|
||||
// Note doesn't yet handle plane argument
|
||||
unless args.subpoints return
|
||||
[start, center, end] := args.subpoints
|
||||
// see if we need to make the destination segment from start to end
|
||||
destination .= ''
|
||||
unless args.line?.length is 1 and args.point?[0] is center
|
||||
destination = aux + '1'
|
||||
auxiliaries.push destination
|
||||
commands.push `${destination} = Segment(${start}, ${end})`
|
||||
else destination = args.line[0]
|
||||
n := args.scalar?[0]
|
||||
commands.push
|
||||
`${aux}2 = Angle(${start}, ${center}, ${end})`
|
||||
`${aux}3 = If(${aux}2 > pi, ${aux}2 - 2*pi, ${aux}2)`
|
||||
`${aux}4 = Rotate(${start}, ${aux}3/${n}, ${center})`
|
||||
`${name} = Intersect(${destination}, Ray(${center}, ${aux}4))`
|
||||
auxiliaries.push ...[2..4].map (i) => `${aux}${i}`
|
||||
'intersection'
|
||||
command += `${name} = Intersect(${data})`
|
||||
return {command, callbacks}
|
||||
// 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})`
|
||||
'lineSegmentSlider'
|
||||
segment .= args.line?[0]
|
||||
unless segment
|
||||
unless args.point then return
|
||||
commands.push `${aux} = Segment(${args.point.join ','})`
|
||||
auxiliaries.push aux
|
||||
segment = aux
|
||||
commands.push `${name} = Point(${segment})`
|
||||
if args.scalar and args.scalar.length
|
||||
callbacks.push (api: AppletObject) =>
|
||||
api.setCoords name,
|
||||
...args.scalar as [number, number, number]
|
||||
'first'
|
||||
unless args.subpoints then return
|
||||
commands.push `${name} = ${args.subpoints[0]}`
|
||||
'last'
|
||||
unless args.subpoints then return
|
||||
commands.push `${name} = ${args.subpoints.at(-1)}`
|
||||
'extend'
|
||||
unless args.subpoints then return
|
||||
sp := args.subpoints
|
||||
direction .= `UnitVector(Vector(${sp[0]},${sp[1]}))`
|
||||
if args.line and (
|
||||
not args.point or args.point[0] !== args.subpoints[0])
|
||||
direction = `UnitVector(${args.line[0]})`
|
||||
displacement := `Distance(${sp[2]}, ${sp[3]})*${direction}`
|
||||
commands.push `${name} = Translate(${sp[1]}, ${displacement})`
|
||||
'vertex'
|
||||
commands.push
|
||||
`${name} = Vertex(${args.polygon?[0]},${args.scalar?[0]})`
|
||||
'midpoint'
|
||||
if args.line
|
||||
commands.push `${name} = Midpoint(${args.line[0]})`
|
||||
else
|
||||
commands.push
|
||||
`${name} = Midpoint(${args.point?[0]},${args.point?[1]})`
|
||||
'foot'
|
||||
pt := args.subpoints
|
||||
unless pt then return
|
||||
commands.push
|
||||
`${name} = ClosestPoint(Line(${pt[1]},${pt[2]}), ${pt[0]})`
|
||||
|
||||
line: (name, method, data, colors) =>
|
||||
command .= ''
|
||||
callbacks: GeogebraCallback[] .= []
|
||||
args := data.split(',')
|
||||
line: (name, method, args) =>
|
||||
return := freshCommander()
|
||||
return.value.ends = ['', '']
|
||||
{commands, callbacks, parts, auxiliaries, ends} := return.value
|
||||
aux := name + 'aUx'
|
||||
parts[1].push name
|
||||
madeSegment .= false
|
||||
switch method
|
||||
'connect'
|
||||
command += `${name} = Segment(${data})`
|
||||
unless args.subpoints and args.subpoints.length is 2 then return
|
||||
ends[0] = args.subpoints[0]
|
||||
ends[1] = args.subpoints[1]
|
||||
'parallel'
|
||||
[newStart, oldStart, oldEnd] := args
|
||||
command += `${name}aUx1 = Vector(${oldStart}, ${newStart})
|
||||
${name}aUx2 = Translate(${oldEnd}, ${name}aUx1)
|
||||
${name} = Segment(${newStart}, ${name}aUx2)`
|
||||
return {command, callbacks}
|
||||
unless args.subpoints then return
|
||||
[newStart, oldStart, oldEnd] := args.subpoints
|
||||
commands.push `${aux}1 = Vector(${oldStart}, ${newStart})`
|
||||
auxiliaries.push aux + 1, aux + 2
|
||||
ends[0] = newStart
|
||||
ends[1] = aux + 2
|
||||
if args.line?.length is 1 and args.point?[0] is args.subpoints[0]
|
||||
// In this case we are translating an existing segment
|
||||
commands.push
|
||||
`${name} = Translate(${args.line[0]}, ${aux}1)`
|
||||
`${aux}2 = Vertex(${name}, 2)`
|
||||
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)
|
||||
parts[0].push ...ends
|
||||
|
||||
circle: (name, method, data, colors) =>
|
||||
command .= ''
|
||||
callbacks: GeogebraCallback[] .= []
|
||||
circle: (name, method, args) =>
|
||||
return := freshCommander()
|
||||
{commands, callbacks, parts, auxiliaries} := return.value
|
||||
parts[2].push name
|
||||
parts[1].push name
|
||||
switch method
|
||||
'radius'
|
||||
[center, point] := data.split(',')
|
||||
command += `${name} = Circle(${center}, ${point})`
|
||||
return {command, callbacks}
|
||||
unless args.subpoints then return
|
||||
[center, point] := args.subpoints
|
||||
commands.push `${name} = Circle(${center}, ${point})`
|
||||
callbacks.push (api: AppletObject) => api.setLabelVisible(name, true)
|
||||
|
||||
polygon: (name, method, args, index) =>
|
||||
return := freshCommander()
|
||||
{commands, callbacks, parts, auxiliaries} := return.value
|
||||
parts[2].push name
|
||||
// what to push for edges?
|
||||
switch method
|
||||
'equilateralTriangle'
|
||||
pt := args.subpoints
|
||||
unless pt then return
|
||||
commands.push '' // hack, make sure there is a command
|
||||
parts[0].push pt[0], pt[1]
|
||||
callbacks.push (api: AppletObject, moreParts: DimParts) =>
|
||||
made:= api.evalCommandGetLabels
|
||||
`${name} = Polygon(${pt[1]},${pt[0]}, 3)`
|
||||
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
|
||||
'segment'
|
||||
parts[1].push newObj
|
||||
'point'
|
||||
parts[0].push newObj
|
||||
api.setVisible(newObj, false)
|
||||
/triangle|quadrilateral/
|
||||
pt := args.subpoints
|
||||
unless pt then return
|
||||
commands.push ''
|
||||
parts[0].push ...pt
|
||||
callbacks.push (api: AppletObject, moreParts: DimParts) =>
|
||||
made := api.evalCommandGetLabels
|
||||
`${name} = Polygon(${pt.join ','})`
|
||||
if not made return
|
||||
for each obj of made.split ','
|
||||
if obj is name continue
|
||||
newObj := 'GeoAux' + index + obj
|
||||
api.renameObject obj, newObj
|
||||
parts[1].push newObj
|
||||
|
||||
sector: (name, method, args) => freshCommander()
|
||||
plane: (name, method, args) => freshCommander()
|
||||
sphere: (name, method, args) => freshCommander()
|
||||
polyhedron: (name, method, args) => freshCommander()
|
||||
|
@ -47,7 +47,7 @@ function makeBrowser(url: string)
|
||||
canvas
|
||||
|
||||
// Put eye icons after all of the eligible links
|
||||
links := $('a').filter -> !!@.getAttribute('href')?.match knownExtensions
|
||||
links := $('a').filter -> knownExtensions.test @.getAttribute('href') ?? ''
|
||||
links.after ->
|
||||
newSpan := $('<span>👁</span>')
|
||||
newSpan.hover
|
||||
|
Loading…
Reference in New Issue
Block a user