Obsolete (plus d'applets Java)

Constructions conditionnelles

Très souvent, la construction effectuée n'est pas valable si une certaine condition a lieu. Par exemple si deux points sont confondus, 3 points alignés etc...
La construction peut alors simplement disparaître, ce qui est un moindre mal, ou pire donner un résultat aberrant ou trop imprécis.
Il faut alors effectuer des constructions différentes selon une certaine condition.

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.

Contraintes sur l'énoncé

Un premier contrôle sur les points variables de l'énoncé peut être obtenu par des Point on object.
Mais toutes les contraintes ne peuvent pas s'exprimer ainsi.

Point dans un demi-plan

On veut imposer un point variable A de l'énoncé dans un demi-plan défini par (d) et un point O donné
Le test est ici très simple : le segment OA coupe (d) ou non selon que A est dans le même demi-plan que O ou non.
Pour inverser la condition, il suffit d'effectuer une symétrie sur (d) (Reflexion).

Désolé, votre navigateur n'est pas compatible Java.

{ 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)];
Le point A n'existe que si le point de controle draggable A? est dans le demi-plan voulu
La suite de la construction est alors à partir du point A conditionnel, et pas à partir de A? draggable.

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.

Point intérieur/extérieur à un cercle

Désolé, votre navigateur n'est pas compatible Java. Si le test de A extérieur ne pose aucune difficulté (Intersection du segment OA avec le cercle), le test 'A intérieur' nécessite une astuce : on utilise la demi droite opposée à O.

{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)];
Dans l'applet le test se manifeste par le changement de nom du point.
Si A est exactement sur le cercle, les deux résultats se superposent, A est considéré à la fois comme intérieur et exterieur.
Enfin le centre même n'est pas "à l'intérieur" car la droite OA est indéfinie.

Pour résoudre ces problèmes, on peut opérer par calcul :

if (x=0) : @sgn_@abs_!@sqrt renvoie 0 si x = 0 et undefined si x ≠ 0
if (x≠0) : @sgn_@abs_1-@sqrt renvoie 0 si x ≠ 0 et undefined si x = 0
if (x>0) : @sgn_1-@sqrt renvoie 0 si x > 0 et undefined si x ≤ 0
if (x≥0) : @sgn_@sqrt2/@trnc renvoie 0 si x ≥ 0 et undefined si x < 0
if (x<0) et if (x≤0) s'obtiennent de même (par exemple en changeant x en -x)
On peut enfin obtenir 1 au lieu de 0 dans les expressions précédentes par expr 1+
D'autres formules du même genre sont possibles... mais tout dépend comment réagit la fonction utilisée si on lui transmet undefined !
Les calculs propagent le undefined sauf @rond et @sgn_ si ce undefined est généré dans le même Calculate.
Si le undefined vient de l'extérieur @rond et @sgn_ propagent aussi le undefined ! Comportement bizarre de JavaSketchpad... et dommage.
@trnc est OK ici, permettant de convertir le "0 ou 1" en "0" pour le test x≥0

Désolé, votre navigateur n'est pas compatible Java.

{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...

A ou B

On peut avoir besoin de faire une construction à partir d'un objet A ou de B selon une condition.
Par exemple construire à partir du point "le plus proche", du cercle "le plus petit" etc...
On utilise la même technique de calcul, mais ici il faut retourner 0 ou 1 et non pas 0 ou undefined.

Désolé, votre navigateur n'est pas compatible Java.

{ 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 }
Ici s'ils sont à égale distance, c'est B qui est choisi.
La mesure effectuée est en fait ici le double de la distance du point à la droite, juste pour simplifier (pas besoin ainsi du pied de la perpendiculaire)
La suite de la construction est ici la projection sur d
On notera aussi que le label du point est "complèté" par superposition d'un label '    plus proche'.

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.

Tests d'intersection

On veut donc obtenir un point M = intersection A de d,d' si elle existe, B sinon.
Une construction géométrique a été vue, il en existe d'autres mais aucune "automatique" qui fonctionne dans tous les cas. La solution est ici encore par calcul.
Utiliser de quelque façon que ce soit le point A est voué à l'échec.
L'astuce est de remplacer d' par une droite d" qui est d' si d coupe d' et une droite garantie coupant d sinon.

Désolé, votre navigateur n'est pas compatible Java. 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);
La multiplication de sin(α) par big = 10000000 et l'arrondi est nécessaire car le sin de 180° est un "0 non nul" !
Cette construction échoue seulement si les droites sont confondues, mais le problème n'a alors aucun sens !

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.

Layer(n)

Cette option permet aussi de "cacher sous le tapis" des éléments, simplifiant ainsi les constructions.
Mais... c'est par catégorie d'objets. On a la hiérarchie, en partant du fond d'écran :

Surfaces
Images
Lignes
Boutons et textes
Points
Dans chaque catégorie, le layer joue indépendamment.
Ainsi un Polygon[layer(10)] sera dessous une Image[layer(1)] !

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)];
r ne pouvant prendre que les valeurs 0 ou 1 ici, M est donc en A ou B.
Si r prenait la valeur 'undefined', M n'existerait même pas et les points A et B afficheraient tous deux leur couleur d'origine.
Le fait que A/B soit caché par M n'empêche pas A/B d'être toujours draggable !

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 :

Désolé, votre navigateur n'est pas compatible Java.

{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];

Pour éviter un aliasing du segment superposé, on met celui-ci 'thick' (sinon marche uniquement pour des segments exactement horizontaux/verticaux).
Les côtés du triangle sont de layer encore plus grand (sinon cachés par le masque)
Lorsque la droite est exactement un côté de ABC, le masque déborde ... de 1 pixel, quasiment invisible.
Sans aller jusque là, on peut observer un aliasing inévitable de 1 pixel à l'extérieur de ABC.

Boutons

Au delà de la définition même des différents types de boutons offerts par JavaSketchpad, citons les applications spécifiques suivantes :

Affichage sélectif

Les différents éléments d'un dessin sont affichés/cachés en fonction de HideButton et ShowButton
Pour obtenir une sélection plus maitrisée, on les groupe dans un SimultaneousButton

Désolé, votre navigateur n'est pas compatible Java.

{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.

Flip-flop

Il n'est hélas pas possible d'avoir un bouton qui se cache lui même (car pas de "références en avant" dans JavaSketchpad). Il faudra donc toujours deux boutons effectifs apparents.
Au dela de l'affichage sélectif, un flip-flop peut agir sur la construction elle-même par l'astuce suivante :
On définit deux positions A et B, un MoveButton fait passer un point de contrôle M entre A et B
Le rapport AM/AB = 0 ou 1 fournit un élément de contrôle pour les constructions conditionnelles
Un simple MoveButton sur le résultat de la construction ne fonctionne pas, car si ensuite on faisait varier les éléments de base, le point libre soumis au MoveButton ne suivrait pas.

Ici les boutons pilotent le choix d'une même construction (le conjugué isogonal) à partir de G ou de H.

Désolé, votre navigateur n'est pas compatible Java.

{ 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.

 

Accueil Arithmétiques Géométrique Divers Thèmes Scripts Jeux Exercices Sujet précédent Sujet suivant   Parent