On profite que toute construction disparaît si elle est construite à partir d'au moins un point "undefined"
(intersection d'objets ne se coupant pas).
Mais aussi elle peut dépendre du résultat d'un calcul.
On profite du fait que pour x < 0, @sqrt ne renvoie pas une erreur mais simplement "undefined",
@sgn_@sqrt renvoie donc 1 si > 0, 0 si = 0 et "undefined" si < 0
Enfin le résultat du calcul peut être simplement 0 ou 1 selon la condition testée,
par les fonctions @sgn_, @rond ou @trnc.
Lorsque la construction est la même à partir d'éléments construits différemment selon la condition,
on a alors intérêt à tester cette condition par résultat d'un calcul,
ou a effectuer la construction initiale elle même
par un calcul, pour éviter d'avoir à dupliquer
la suite de la construction.
{ test si A et O dans deux demi-plans différents } {A?} Point (x,y)[cyan,layer(1)]; {OA?} Segment (O,A?) [hidden]; {I} Intersect (OA,d)[hidden]; {A} Dilation (A?,I,1)[label('A'),red,layer(2)]; { test si A et O dans le même demi-plan } {A?} Point (x,y)[cyan,layer(1)]; {O!} Reflection (O,d)[hidden]; {OA?} Segment (O!,A?)[hidden]; {I} Intersect (OA?,d)[hidden]; {A} Dilation (A?,I,1)[label('A'),red,layer(2)]; |
Dans la démo, on définit un triangle ABC tel que AB < AC et ABC dans le sens trigonométrique,
c'est à dire que A soit dans le quart de plan cyan, en répétant deux fois le test.
C'est à dire si le point I1 = CA?∩med(BC) existe (AB < AC) et si le point I2 = RA?∩bc existe,
R étant défini par rotation de B de centre M de +π/2.
Le point A change de couleur et le triangle est tracé seulement si A est dans cette région.
Le changement de couleur se fait par le layer(), le point A? étant recouvert
par le point A s'il existe.
On peut avec la même technique imposer un point à l'intérieur d'un polygone convexe.
Un polygone non convexe pose plus de problèmes.
{A?} Point (x,y)[cyan,layer(1)]; { A extérieur à C } {OA?} Segment (O,A?) [hidden]; {I1} Intersect1 (OA,C)[hidden]; {A1} Dilation (A?,I1,1)[label('A1'),red,layer(2)]; { A intérieur à C } {O!} Dilation (O, A?,-1)[hidden]; {OA2?} Ray (O!,A?)[hidden]; {I2} Intersect2 (OA2?,C)[hidden]; {A2} Dilation (A?,I2,1)[label('A2'),red,layer(2)]; |
Pour résoudre ces problèmes, on peut opérer par calcul :
|
{A?} Point (140,80)[cyan,layer(1)]; { mesures } {d} Distance (O,A?,0,0,' ')[hidden]; {r} Radius (C,0,0,' ')[hidden]; { A extérieur if (d-r>0) } {if1} Calculate (0,0,' ','AB-@sgn_1-@sqrt')(d,r)[hidden]; {A1} Dilation/MarkedRatio (A?,A?,if1)[label('A extérieur'),red,layer(2)]; { A intérieur if (r-d>0) } {if2} Calculate (0,0,' ','BA-@sgn_1-@sqrt')(d,r)[hidden]; {A2} Dilation/MarkedRatio (A?,A?,if2)[label('A intérieur'),red,layer(2)]; { A sur le cercle if (r-d=0) } {if3} Calculate (0,0,' ','BA-@sgn_@abs_!@sqrt')(d,r)[hidden]; {A3} Dilation/MarkedRatio (A?,A?,if3)[label('A dessus'),red,layer(2)]; |
La même technique permet de tester des conditions diverses, ici le calcul préalable était juste d-r, des expressions plus complexes peuvent être testées, et les mesures peuvent être ce que l'on veut, par exemple la distance à une droite (donnant comme résultat "A est sur la droite"), etc...
{ mesures } {A!} Reflection (A,d)[hidden]; {a} Distance (A,A!,0,0,' ')[hidden]; {B!} Reflection (B,d)[hidden]; {b} Distance (B,B!,0,0,' ')[hidden]; { r=0 si A plus proche, =1 si B plus proche ou egal } {r} Calculate (200,15,'r = ','AB-@sgn_1+@sgn_')(a,b)[color(0,180,0)]; {M} Dilation/MarkedRatio (B,A,r)[label(' plus proche'),red,layer(2)]; { ... suite construction à partir de M } |
Malheureusement il n'est pas possible de transformer une condition {0 ou undefined} en condition {0 ou 1}
Ceci permettrait d'appliquer cette technique de choix à partir d'une condition géométrique (un Intersect).
Il est donc nécessaire de simuler le Intersect par calcul pour effectuer un choix "A ou B" basé
sur le résultat d'une intersection.
Soient donc deux droites définies par d = DE et d' = UV.
La mesure de Slope de d et d' échoue si l'une d'elle est verticale (Slope renvoie undefined).
La mesure est donc effectué par le sinus de l'angle des droites.
On obtient ainsi une condition 1 si elles se coupent et 0 si elles sont parallèles ou confondues.
On prend alors le point V' = V si cette condition vaut 1 et E si elle vaut 0
La droite d" = UV' est alors une droite identique à d' si d coupe d', et une droite UE coupant d' en E sinon.
Le point final est donc l'intersection A" de d et d" (A" = A ou V) dans tous les cas.
On termine au besoin en reportant le choix M = A" ou B selon le test
Ici l'applet trace la droite XA, concourante ou parallèle avec d et d'.
B = VectorTranslation (U,D,E).
{V1} VectorTranslation (E,D,U)[hidden]; {a} Angle (V,U,V1,0,0,'')[hidden]; {big} Parameter (10000000,0,0,'')[hidden]; {ifinter} Calculate (0,0,'','A1@atan*45/@sin_B*@rond@sgn_@abs_')(a,big)[hidden]; {V!} Dilation/MarkedRatio (V,E,ifinter)[hidden]; {d!!} Line (U,V!)[hidden]; {A} Intersect (d,d!!)[hidden]; {M} Dilation/MarkedRatio (A,B,ifinter); |
Il est possible de tester ce cas en testant l'angle DEV, en plus de l'angle VUV1 :
Les droites étant confondues si les deux angles sont nuls modulo π,
parallèles si VUV1 = 0 mod π et DEV ≠ 0 mod π
(avec la condition que les points E et V sont différents)
Les intersections de segments se font en testant si les intersections des droites donnent un point dans le segment.
(en testant la valeur d'un Ratio/Points)
Les intersections de cercles se font en testant la distance au centre,
les intersections d'un segment avec un cercle se font de même en testant si
l'intersection de droite, si elle existe,
est dans le segment.
Surfaces
Images Lignes Boutons et textes Points |
Il est donc hélas impossible de cacher un bouton sous un polygone
(couleur fond par exemple) ce qui permettrait de faire un "hidden calculé"
Pour les textes, lignes et images, on peut les accrocher sur des points conditionnels
(avec PeggedText, ImageOnPoint, ou des points conditionnels dans leur construction)
permettant de faire cela autrement, sans avoir besoin du layer( ).
On peut par contre cacher un polygone par un autre, une droite par un segment, etc...
En jouant sur l'existence de ces éléments, cela permet de jouer par calcul sur la couleur d'un élément :
Un point draggable peut ainsi changer de couleur ou de label selon une condition.
On a vu cela lors de la démo précédente. S'il existe, le point M cache le point draggable A ou B situé dessous,
et les deux labels, celui de A/B : 'A'/'B',
et celui de M : ' plus proche', se superposent donnant l'illusion
que le point A/B lui-même change de couleur et de label.
{A} Point (40,80)[blue,label('A'),layer(1)]; ... {M} Dilation/MarkedRatio (B,A,r)[red,label(' plus proche'),layer(2)]; |
Pour faire passer une ligne sous un polygone ou une image, il faut construire les points d'intersection
et découper la ligne en plusieurs tronçons.
Plutôt que de tracer effectivement la ligne en plusieurs morceaux,
on peut cacher des parties de la ligne entière par des segments de layer supérieur, de la couleur du polygone :
{AB} Segment (A,B)[layer(3)]; { ... } {ABC} Polygon (A,B,C)[cyan]; {uv} Line (U,V)[red,layer(1)]; {A!} Intersect (uv,BC)[hidden]; {B!} Intersect (uv,AC)[hidden]; {C!} Intersect (uv,AB)[hidden]; {AB!} Segment (A!,B!)[layer(2),cyan,thick]; {BC!} Segment (B!,C!)[layer(2),cyan,thick]; {AC!} Segment (A!,C!)[layer(2),cyan,thick]; |
{sbh} ShowButton (0,0,'')(ah,bh,ch,Ha,Hb,Hc,AH,BH,CH,H)[hidden]; {hbh} HideButton (0,0,'')(ah,bh,ch,Ha,Hb,Hc,AH,BH,CH,H)[hidden]; {sbm1} ShowButton (0,0,'')(Ma,Mb,Mc)[hidden]; {hbm1} HideButton (0,0,'')(Ma,Mb,Mc)[hidden]; {sbm2} ShowButton (0,0,'')(AM,BM,CM,G)[hidden]; {hbm2} HideButton (0,0,'')(AM,BM,CM,G)[hidden]; {sbo} ShowButton (0,0,'')(ma,mb,mc,O,Ko)[hidden]; {hbo} HideButton (0,0,'')(ma,mb,mc,O,Ko)[hidden]; {med} SimultaneousButton (2,2,'médianes')(hbo,hbh,sbm1,sbm2); {alt} SimultaneousButton (72,2,'hauteurs')(hbo,hbm1,hbm2,sbh); {circ} SimultaneousButton (140,2,'médiatrices')(hbh,hbm2,sbm1,sbo); |
On notera que les points Ma,Mb,Mc appartiennent à la fois aux médianes et aux médiatrices.
Il est fortement déconseillé de mettre un même élément à la fois en show et en hide.
Ils sont dans un couple Show/HideButton à part.
Tous les éléments sont hidden au départ sauf ceux des médianes.
Ici les boutons pilotent le choix d'une même construction (le conjugué isogonal) à partir de G ou de H.
{ construit G et H } { comme d'hab ... } { boutons de commande } {zero} FixedPoint (0,0)[hidden]; {un} FixedPoint (1,0)[hidden]; {ctrl} Point (0,0)[hidden]; {setH} MoveButton (2,2, 10,'H')(zero,ctrl); {setG} MoveButton (22,2, 10,'G')(un,ctrl); {r} Ratio/Points (zero,un,ctrl,0,0,'')[hidden]; { Point = G ou H selon boutons } {P} Dilation/MarkedRatio (G,H,r)[hidden]; { conjugué isogonal } {rab} Rotation/MarkedAngle (ab,A,P,A,C)[hidden]; {rbc} Rotation/MarkedAngle (bc,B,P,B,A)[hidden]; {Q} Intersect (rab,rbc); |
Contrairement à la démo précédente, où on effectuait les différentes constructions,
en cachant ensuite l'une ou l'autre, ici, la construction est effectuée une seule fois, à partir
du même point P pouvant prendre plusieurs définitions.
La même technique peut être étendue à plus de deux boutons de sélection, par déplacement de
plusieurs points de contrôle cachés, ou du même pouvant prendre plus de deux valeurs.