' ******************************************************************************
' *                                  Zoom                                      *
' ******************************************************************************
' *                                  V1.0                                      *
' ******************************************************************************
' *                          © François PAULHIAC , 1993                        *
' ******************************************************************************
' * Sources compilées avec Hisoft Basic.                                       *
' * Ce programme peut-être librement distribué tant que personne n'en          *
' * tire de profit. Voir la doc pour les détails.                              *
' ******************************************************************************

' Réglez les tabulations de votre éditeur à 3 caractères.

' Options du compilateur
REM $EVENT OFF
REM $OPTION K40,Y+,A-,E-,G+,X-,L-,V+,B-,N-,O-,U+,W+

DEFINT a-z


' =========================================================================
' =                            Constantes                                 =
' =========================================================================


' Couleurs utilisées
CONST CouleurCar=1,CouleurFond=3,CouleurLignes=3


'  Constantes utilisées par l'interpréteur de fonctions 
CONST Max_niveaux = 30 : ' taille de la pile
CONST Max_tblfc = 80, Max_tblnb = 40 : ' dimension des tableaux


' Ces constantes sont utilisées par la routine servant à transformer une 
' expression mathématique écrite sous forme usuelle en deux tableaux.
' Le premier tableau est un tableau d'entier : chacun des lexèmes (nombre,
' opérateur, fonction, variable, parenthèse ouvrante ou fermante) trouvé
' dans l'expression de départ correspondra à un élément de ce tableau.
' La table de constantes ci-dessous donne un numéro à chaque type de lexème
' trouvé dans la chaîne de départ.

CONST Op_plus=1, Op_moins=2, Op_mul=3, Op_div=4, Op_puiss=5
CONST Fc_sin=26, Fc_cos=27, Fc_tan=28
CONST Fc_log=35, Fc_log10=29, Fc_exp=30, Fc_sqr=31
CONST Fc_fix=32, Fc_cot=33, Fc_abs=34
CONST Fc_arcsin=19, Fc_arccos=20, Fc_arctan=21
CONST Fc_sinh=23, Fc_cosh=24, Fc_tanh=25
CONST Fc_arcsinh=16, Fc_arccosh=17, Fc_arctanh=18
CONST Fc_arccot=22
CONST Par_ouverte=8, Par_fermee=9
CONST Var_x=36,Var_y=38,Var_r=40,Var_u=42,Var_t=44


' Constantes indiquant quelle est la nature du lexème trouvé dans le tableau.
CONST Min_operateur=1, Max_operateur=5
CONST Min_fonction=16, Max_fonction=35
CONST Min_variable=36, Max_variable=45
CONST Fin_de_chaine=7, Nombre=6


' Nombre de fonctions reconnues par l'interpréteur, et nombre maximum de 
' caractères que peut comporter un nom de fonction.
CONST Tot_fonctions=19, Max_caracteres=7


'  Nombre maximum de points dans le polygône résultant du fenêtrage
'  d'un quadrilatère par rapport à une fenêtre rectangle. 
CONST Max_Polygons=49


' =============================================================================
' =                             Variables globales                            =
' =============================================================================


'  Nombres usuels 
COMMON SHARED pi!,pisur2!
pi!=3.14159265 : pisur2!=pi!/2.0


'  Niveaux de priorité des opérations pour l'interpréteur 
DIM SHARED priorite(Max_operateur)
priorite(Op_plus)=1
priorite(Op_moins)=1
priorite(Op_mul)=2
priorite(Op_div)=2
priorite(Op_puiss)=3


'  Fonctions reconnues 
DIM SHARED fonctions$(Tot_fonctions)
FOR m=0 TO Tot_fonctions
	READ fonctions$(m)
NEXT m
' Fonctions reconnues par l'interpréteur. A chacune de ces fonctions 
' correspond une constante : voir ci-dessus. Les constantes doivent être dans
' le même ordre que les chaînes de caractères associées. 
DATA "arcsinh","arccosh","arctanh"
DATA "arcsin","arccos","arctan","arccot"
DATA "sinh","cosh","tanh"
DATA "sin","cos","tan","log","exp","sqr","fix","cot","abs"
DATA "ln"


'  Largeur de l'écran 
CONST ScreenLarge=639


'  Utilisé pour le tracé des courbes polaires et paramêtrées 
CONST Fraction_Initiale=32 : ' pas_initial=(tmax-tmin)/Fraction_Initiale


'  Variables globales: hauteur de l'écran 
COMMON SHARED screenhigh : ' sauf boîte de dialogue


'  Minimums et maximums pour le tracé de la courbe 
COMMON SHARED xmin!,xmax!,ymin!,ymax!,zmin!,zmax!,tmin!,tmax!


'  Minimums et maximums projetés pour les surfaces 
COMMON SHARED xmins!,ymins!,xmaxs!,ymaxs!


'  Angles de rotations et leur sinus et cosinus 
COMMON SHARED ax!,az!,sx!,cx!,sz!,cz!


'  Redresser la déformation de l'image due à la résolution de l'écran 
COMMON SHARED aspect!


'  Pour mettre en relief une surface 
COMMON SHARED multhauteur! : ' z=z*multhauteur


'  Affichage des messages d'erreur 
COMMON SHARED erreur,paramerr,xmess,ymess,lgmess,effacemessage


'  Pour éviter les Overflows (pas toujours efficace!) 
COMMON SHARED minv!,maxproduit!,maxadd!,majinv!
COMMON SHARED maxexponentielle!,maxtangente!,mtan!
minv!=1/9e9 : maxproduit!=3.033e9 : maxadd!=4.5e18 : mtan!=5e-3
maxexponentielle!=43.667 : maxtangente!=pisur2!-1e-4


'  Utilisé pour le tracé des courbes 
COMMON SHARED accpas!,epsilon!,aspect!
COMMON SHARED distance
accpas!=1.2 : epsilon!=1.0/500.0 : aspect!=0.62
distance=5


' ========================================================================
' =           Liste des fonctions utilisées et leurs paramêtres          =
' ========================================================================


'  Préparation de l'affichage 

DECLARE SUB inibox
DECLARE SUB efface
DECLARE SUB iniaffichage
DECLARE SUB enablemenus
DECLARE SUB disablemenus

'  Manipulation des chaînes 

DECLARE SUB tronquestring(chaine$,VAL position)
DECLARE SUB insertinstring(chaine$,VAL car$,VAL position)
DECLARE SUB killcar(chaine$,c$)

'  Saisie des paramêtres 

DECLARE SUB affcrsr(VAL x,VAL y,VAL cr$,VAL af)
DECLARE SUB refreshaff(VAL chaine$,VAL x,VAL y,posonscreen,posinstring, _
	firstcaraff,VAL maxonscreen,VAL affaspace)
DECLARE SUB saisieat(chaine$,VAL x,VAL y,VAL maxonscreen,sortcode,men)
DECLARE SUB tableauoptions(menuselect,icsortie,option$(1),valeur$(1), _
	taillechamp(1),posx(1),posy(1),VAL premiergadget,VAL nboptions,currentopt)
DECLARE SUB boxtableauoptions(VAL x,VAL y,VAL w,VAL h,menuselect,icsortie, _
	option$(1),valeur$(1),taillechamp(1),posx(1),posy(1),VAL premiergadget, _
	VAL nboptions,VAL currentopt)

'  Interpréteur de fonctions 

DECLARE FUNCTION decoupecaractere(f$,n,nombre!)
DECLARE SUB traduitfonction(VAL fc$,tableau_fc(1),tableau_nb!(1))
DECLARE SUB verifiefonction(tblfc(1))
DECLARE FUNCTION appliqueop!(VAL nombre1!,VAL nombre2!,VAL operateur)
DECLARE FUNCTION appliquefc!(VAL nombre!,VAL fc)
DECLARE FUNCTION inter!(tblfc(1),tblnb!(1),xv!,yv!,uv!,tv!)
DECLARE FUNCTION interconst!(c$)

'  Procédures de calcul 

DECLARE FUNCTION modulo!(VAL nombre!,VAL intervalle!)
DECLARE FUNCTION min!(VAL a!,VAL b!)
DECLARE FUNCTION max!(VAL a!,VAL b!)
DECLARE FUNCTION continue(tblff(1),tblfn!(1),VAL x1!,VAL y1!,VAL x2!,VAL y2!)
DECLARE SUB trnpoint(VAL xi!,VAL yi!,VAL zi!,xf!,yf!,zf!)

'  Procédures de tracé 

DECLARE FUNCTION ptscreen(VAL x,VAL y)
DECLARE FUNCTION intersection(VAL xa1,VAL ya1,VAL xb1,VAL yb1,VAL xa2, _
	VAL ya2,VAL xb2,VAL yb2,x,y)
DECLARE SUB fenetresegment(VAL x1,VAL y1,VAL x2,VAL y2,VAL xs1,VAL ys1, _
	VAL xs2,VAL ys2,tblsortie(2),j)
DECLARE SUB fenetragepoly(tblpoly(2),tblsortie(2),nbpoints,VAL xs1, _
	VAL ys1,VAL xs2,VAL ys2)
DECLARE SUB fenquadripoly(tblpoly(2),nbelements,VAL x1,VAL y1,VAL x2,VAL y2)
DECLARE SUB fillpolygon(VAL x1,VAL y1,VAL x2,VAL y2,VAL x3,VAL y3,VAL x4, _
	VAL y4,VAL c)
DECLARE SUB represente(VAL x!,VAL y!,xr,yr)
DECLARE SUB tdreppoint(VAL xi!,VAL yi!,VAL zi!,xs,ys)

'  Tracé des courbes et des surfaces 

DECLARE SUB traceaxes(VAL xaxe!,VAL yaxe!,VAL xmin!,VAL xmax!,VAL ymin!, _
	VAL ymax!)
DECLARE SUB tracecourbe(x$,VAL tracelignes)
DECLARE SUB tracecourbeparametree(x$,y$,VAL type,VAL tracelignes)
DECLARE SUB echangeparametres(x1!,y1!,x2!,y2!)
DECLARE SUB tracesurface(z$,VAL divx,VAL divy)
DECLARE SUB inirotation
DECLARE SUB iniextremums

'  Messages d'erreur 

DECLARE SUB boxmessage(x,y,message$(1),VAL mode)
DECLARE FUNCTION erreur$

'  Tableau des paramêtres 

DECLARE SUB parametres(epsilon!,distance,aspect!)

'  Aide 

DECLARE SUB aide


' ===========================================================================
' =                         Préparation de l'affichage                      =
' ===========================================================================


' Prépare un rectangle noir en bas de l'écran pour l'affichage des
' paramêtres.

SUB inibox
	LINE (0,screenhigh+1)-(640,256),2,bf
END SUB


' Efface la partie de l'écran où est affichée la courbe.

SUB efface
	LINE(0,0)-(ScreenLarge,screenhigh),0,bf
END SUB


' Ouvre la fenêtre, prépare les deux parties de l'affichage et
' initialise les menus.

SUB iniaffichage
	SCREEN 1,640,256,2,2
	WINDOW 1,"Zoom",(0,0)-(640,256),32+64+128+256,1
	PALETTE 0,0,0,0
	PALETTE 1,1,1,1
	PALETTE 2,1,0,0
	PALETTE 3,0,0,1
	MENU 1,0,1,"Mode"
	MENU 1,1,2,"  Courbes simples (F1)"
	MENU 1,2,1,"  Courbes paramétrées (F2)"
	MENU 1,3,1,"  Courbes polaires (F3)"
	MENU 1,4,1,"  Surfaces (F4)"
	MENU 1,5,1,"Quitter"
	MENU 2,0,1,"Options"
	MENU 2,1,1,"Paramêtres (F5)"
	MENU 2,2,2,"  Tracer lignes (F6)"
	MENU 2,3,1,"Aide (Help)"
END SUB


' Active les menus.

SUB enablemenus
	MENU 1,0,1
	MENU 2,0,1
END SUB


' Désactive les menus

SUB disablemenus
	MENU 1,0,0
	MENU 2,0,0
END SUB


' =========================================================================
' =                          Traitement des chaînes                       =
' =========================================================================


' Supprime le position-ième caractère de chaine$.

SUB TronqueString (chaine$,VAL Position)
	chaine$=LEFT$(chaine$,position-1)+MID$(chaine$,position+1, _
	LEN(chaine$)-position)
END SUB


' Insère car$ en position-ième place de chaine$.

SUB InsertInString (chaine$,VAL car$,VAL position)
	chaine$=LEFT$(chaine$,position-1)+car$+RIGHT$(chaine$, _
	LEN(chaine$)-position+1)
END SUB


' Supprime toutes les occurrences du caractère c$ dans la chaîne chaine$.

SUB killcar(chaine$,c$)
LOCAL i
	i=1
	DO WHILE i<=LEN(chaine$)
		IF MID$(chaine$,i,1)=c$ THEN
			chaine$=LEFT$(chaine$,i-1)+RIGHT$(chaine$,LEN(chaine$)-i)
		ELSE
			INCR i
		END IF
	LOOP
END SUB


' =========================================================================
' =                    Procédures de saisie des paramêtres                =
' =========================================================================


' Affiche un curseur rectangulaire aux coordonnées (x%,y%) si af=1,
' ou l'efface si af=0.
' cr$ est le caractère situé sous le curseur 
' CouleurFond, CouleurCar: couleur des caractères et du curseur.

SUB AffCrsr (VAL x,VAL y,VAL cr$,VAL af)
	LOCATE y%,x%
	IF af% THEN COLOR CouleurFond,CouleurCar
	IF cr$="" THEN PRINT CHR$(32); ELSE PRINT cr$;
	IF af% THEN COLOR CouleurCar,CouleurFond
END SUB


' Si PosInString est compris entre FirstCarAff et FirstCarAff+MaxOnScreen,
' affiche les caractères de la chaîne compris entre FirstCarAff et
' FirstCarAff+MaxOnScreen.
' Si PosInString=FirstCarAff+MaxOnScreen+1, incrémente de 1 FirstCarAff
' et affiche la chaîne.
' Si PosInString=FirstCarAff-1, decrémente de 1 FirstCarAff et affiche.
' Ceci à condition que PosInString reste compris entre 1 et LEN(chaine$).
' Sinon, fixe PosInString à 1 si PosInString<1,
' où à LEN(chaine$) si PosInString>LEN(chaine$).

SUB RefreshAff (VAL chaine$,VAL x,VAL y,PosOnScreen,PosInString,FirstCarAff, _
	VAL MaxOnScreen,VAL AffASpace)
	IF PosOnScreen>MaxOnScreen THEN
		PosOnScreen=MaxOnScreen
		IF PosInString<=LEN(chaine$)+1 THEN
			INCR FirstCarAff
		ELSE
			PosInString=LEN(chaine$)+1
		END IF
	ELSEIF PosOnScreen<0 THEN
		PosOnScreen=0
		IF FirstCarAff>1 THEN
			DECR FirstCarAff
		ELSE
			PosInString=1
		END IF
	ELSEIF PosInString>LEN(chaine$)+1 THEN
		DECR PosOnScreen
		PosInString=LEN(chaine$)+1
	END IF
	LOCATE y,x
	IF AffASpace THEN chaine$=chaine$+CHR$(32)
	PRINT MID$(chaine$,FirstCarAff,MaxOnScreen+1);
	IF AffASpace THEN chaine$=LEFT$(chaine$,LEN(chaine$)-1)
END SUB


' Trace un rectangle de la couleur 2 aux coordonnées (x,y) de longueur 
' MaxOnScreen * 8 pixels et de hauteur 8 pixels. Ensuite, positionne
' un curseur texte aux coordonnées (x,y) pour permettre à l'utilisateur
' de rentrer une chaine de caractères.
' MaxOnScreen est la longueur du champ.
' Pour sortir de la saisie:
' - Touche curseur haut: sortcode renvoie 1,
' - Touche curseur bas: sortcode renvoie 2,
' - Touche Return: sortcode renvoie 0,
' - Choix d'un menu: sortcode renvoie 4 et Men le numéro du menu,
' - Click de la souris en dehors du champ: sortcode renvoie 4,
' - Touche de fonction: sortcode renvoie le code ASCII de la touche.

SUB SaisieAT(Chaine$,VAL x%,VAL y%,VAL MaxOnScreen%,SortCode%,Men%)
LOCAL buffer$,act$,newscreenpos,newstringpos,posonscreen,posinstring
LOCAL firstcaraff,xm,ym,dummy$(0)
	buffer$=chaine$
	PosOnScreen=0:PosInString=1:FirstCarAff=1
	SortCode=0
	LOCATE y,x
	PRINT LEFT$(chaine$,MaxOnScreen);
	DECR MaxOnScreen
	act$=CHR$(0)
	DO
		AffCrsr x+PosOnScreen,y,MID$(chaine$,PosInString,1),-1
		DO
			SLEEP
			act$=INKEY$
			IF effacemessage AND act$<>"" THEN
				boxmessage xmess,ymess,dummy$(),0
				effacemessage=0
			END IF
			men=MENU(0)
			IF men<>0 THEN
				sortcode=3
			ELSE
				men=MOUSE(0)
				IF men<>0 THEN
					xm=MOUSE(1):ym=MOUSE(2)+8
					NewScreenPos=(xm-x*8+4)\8
					IF (ym-8*(y-1)<=8) AND (ym-8*(y-1))>=0 AND (NewScreenPos>=0)  _
						AND (NewScreenPos<=MaxOnScreen) THEN
						NewStringPos=FirstCarAff+NewScreenPos
						IF NewStringPos<=LEN(chaine$)+1 THEN
							Affcrsr x+PosOnScreen,y,MID$(chaine$,PosInString,1),0
							PosOnScreen=NewScreenPos
							PosInString=NewStringPos
								Affcrsr x+PosOnScreen,y,MID$(chaine$,PosInString,1),-1
						END IF
					ELSE
						sortcode=4
					END IF
				END IF
			END IF
		LOOP UNTIL (act$<>"") OR (sortcode<>0)
		AffCrsr x+PosOnScreen,y,MID$(chaine$,PosInString,1),0
		IF act$<>CHR$(0) THEN
			SELECT CASE act$
				CASE CHR$(27),CHR$(129) TO CHR$(139)
					sortcode=ASC(act$)
				CASE CHR$(8)
					IF PosInString>1 THEN
						DECR PosOnScreen
						DECR PosInString
						TronqueString chaine$,PosInString
						RefreshAff chaine$,x,y,PosOnScreen,PosInString, _
							FirstCarAff,MaxOnScreen,-1
					END IF
				CASE CHR$(127)
					IF PosInString<=LEN(chaine$)THEN
						TronqueString chaine$,PosInString
						RefreshAff chaine$,x,y,PosOnScreen,PosInString, _
							FirstCarAff,MaxOnScreen,-1
					END IF
				CASE CHR$(31)
					DECR PosOnScreen
					DECR PosInString
					RefreshAff chaine$,x,y,PosOnScreen,PosInString, _
						FirstCarAff,MaxOnScreen,0
				CASE CHR$(30)
					INCR PosOnScreen
					INCR PosInString
					RefreshAff chaine$,x,y,PosOnScreen,PosInString, _
						FirstCarAff,MaxOnScreen,0
				CASE CHR$(28)
					sortcode=1
				CASE CHR$(29)
					sortcode=2
				CASE CHR$(13)
					'Rien!
				CASE CHR$(215)
					buffer$=chaine$
					chaine$=""
					LOCATE y,x : PRINT SPACE$(MaxOnScreen+1);
					PosOnScreen=0:PosInString=1:FirstCarAff=1
				CASE CHR$(229)
					SWAP chaine$,buffer$
					PosOnScreen=0:PosInString=1:FirstCarAff=1
					LOCATE y,x : PRINT SPACE$(maxonscreen+1);
					RefreshAff chaine$,x,y,PosOnScreen,PosInString,FirstCarAff, _
						MaxOnScreen,0
				CASE ELSE
					InsertInString chaine$,act$,PosInString
					INCR PosInString
					INCR PosOnScreen
				   RefreshAff chaine$,x,y,PosOnScreen,PosInString,FirstCarAff, _
						MaxOnScreen,0
			END SELECT
		END IF
	LOOP UNTIL (act$=CHR$(13)) OR (sortcode<>0)
	RefreshAff chaine$,x,y,0,1,1,MaxOnScreen,0
END SUB


' Crée un "masque de saisie" à l'écran pour permettre à l'utilisateur de 
' rentrer des paramêtres. 
' option$() contient les titres des rubriques à remplir. Ces titres seront 
' affiché à gauche des champs permettant de rentrer des données.
' valeur$(): le contenu initial de ces rubriques
' taillechamp(): la longueur des champs destinés à la saisie associées.
' posx(),posy(): position (en coordonnées "mode texte") à l'écran des rubriques
' Ces tableaux doivent contenir les positions des titres des rubriques. Les
' champs de saisie eux-mêmes sont affichés juste à droite.
' nboptions: nombre de masques de saisie.
' currentopt: option à activer au lancement de cette routine.

' La sortie de cette procédure se fait par:
' - Click sur un gadget de sortie: IcSortie renvoie son numéro
' - (le premier gadget porte le numéro 0),
' - Choix d'un menu: MenuSelect renvoie son numéro, et IcSortie=-1,
' - Touche de fonction: IcSortie renvoie son code ASCII.

' Les gadgets de sortie sont des sortes de gadgets booléens contenant 
' uniquement du texte. Pour fabriquer ces gadgets, placer leur texte
' dans le tableau "option$()", juste aprés le titre de la dernière rubrique
' du masque de saisie.

SUB TableauOptions(MenuSelect,IcSortie,option$(1),valeur$(1),taillechamp(1), _
	posx(1),posy(1),VAL premiergadget,VAL nboptions,currentopt)
	LOCAL m,codesortie,columnxm,lineym,ancopt,oldopt
	IF premiergadget>0 THEN
		FOR m=0 TO premiergadget-1
			IF posx(m)>0 THEN
				LOCATE posy(m),posx(m)
				COLOR 1,2
				PRINT option$(m);
				COLOR 2,3
				PRINT SPACE$(taillechamp(m));
				LOCATE posy(m),posx(m)+LEN(option$(m))
				COLOR 1,3
				PRINT LEFT$(valeur$(m),taillechamp(m));
			END IF
		NEXT m
	END IF
	FOR m=premiergadget TO NbOptions
		COLOR 1,3
		LOCATE posy(m),posx(m)
		PRINT option$(m);
	NEXT m
	MenuSelect=0
	DO WHILE MOUSE(0)<>0
		SLEEP
	LOOP
	DO
		IF premiergadget=0 THEN
			DO WHILE MOUSE(0)=0
				SLEEP
			LOOP
			CodeSortie=4 : CurrentOpt=-1
		ELSE
			DO
				SaisieAt valeur$(CurrentOpt),posx(CurrentOpt)+ _
					LEN(option$(CurrentOpt)),posy(CurrentOpt), _
					taillechamp(CurrentOpt),CodeSortie,MenuSelect
				OldOpt=CurrentOpt
				SELECT CASE CodeSortie
					CASE 0,2
						ancopt=currentopt
						DO WHILE currentopt<premiergadget-1
							INCR currentopt
						LOOP UNTIL posx(currentopt)>0
						IF currentopt=premiergadget-1 AND posx(currentopt)=0 _
							THEN currentopt=ancopt
					CASE 1
						ancopt=currentopt
						DO WHILE currentopt>0
							DECR currentopt
						LOOP UNTIL posx(currentopt)>0
						IF currentopt=0 AND posx(0)=0 THEN currentopt=ancopt
				END SELECT
			LOOP UNTIL CodeSortie=3 OR CodeSortie=4 OR codesortie=27 OR _
				codesortie>128
		END IF
		SELECT CASE CodeSortie
			CASE 4
				ColumnXm=MOUSE(1)\8+1:LineYm=MOUSE(2)\8+2
				IF premiergadget>0 THEN
					FOR m=0 TO premiergadget-1
						IF posx(m)<>0 THEN
							IF (LineYm=posy(m)) AND (posx(m)+LEN(option$(m))<=ColumnXm) AND (ColumnXm<=posx(m)+LEN(option$(m))+taillechamp(m)) THEN
								CurrentOpt=m
							END IF
						END IF
					NEXT m
				END IF
				FOR m=premiergadget TO NbOptions
					IF (LineYm=posy(m)) AND (posx(m)<=ColumnXm) AND _
						(ColumnXm<=posx(m)+LEN(option$(m))) THEN
						CurrentOpt=m
						LOCATE posy(m),posx(m)
						COLOR 3,1
						PRINT option$(m);
						DO WHILE MOUSE(0)<>0
						LOOP
						LOCATE posy(m),posx(m)
						COLOR 1,3
						PRINT option$(m);
					END IF
				NEXT m
		END SELECT
	LOOP UNTIL (CodeSortie=3) OR (codesortie>128) OR (codesortie=27) OR _
	(CurrentOpt>=premiergadget)
	IF CurrentOpt>=premiergadget THEN
		IcSortie=CurrentOpt-premiergadget
		CurrentOpt=OldOpt
	ELSEIF codesortie=3 THEN
		IcSortie=-1
	ELSEIF codesortie>128 OR codesortie=27 THEN
		IcSortie=codesortie
	END IF
END SUB


' Idem que ci-dessus, mais crée en plus un rectangle de la couleur 2
' autour du tableau. x,y,w,h sont les coordonnées, la longueur et
' la hauteur de ce rectangle (graphiques).

SUB boxtableauoptions(VAL x,VAL y,VAL w,VAL h,menuselect,icsortie,option$(1), _
	valeur$(1),taillechamp(1),posx(1),posy(1),VAL premiergadget,VAL nboptions, _
	VAL currentopt)
	LOCAL xt,yt
	STATIC sauveimage()
	xt=x\8:yt=y\8
	DIM sauveimage(2*(h+1)*(w\16+1)+3)
	GET (x,y)-(x+w,y+h),sauveimage
	LINE (x,y)-(x+w,y+h),2,bf
	tableauoptions menuselect,icsortie,option$(),valeur$(),taillechamp(),posx(),posy(),premiergadget,nboptions,currentopt
	PUT (x,y),sauveimage,PSET
	ERASE sauveimage	
END SUB


' ========================================================================
' =                         Procédures de calcul                         =
' ========================================================================


' Renvoie nombre modulo intervalle

FUNCTION modulo!(VAL nombre!,VAL intervalle!)
LOCAL k
	IF nombre!>=0 THEN
		k=FIX(nombre!/intervalle!)
	ELSE
		k=FIX(nombre!/intervalle!)-1
	END IF
	modulo!=nombre!-k*intervalle!
END FUNCTION		


' Renvoie le minimum de 2 nombres

FUNCTION min!(VAL a!,VAL b!)
	IF a!<b! THEN min!=a! ELSE min!=b!
END FUNCTION


' Renvoie le maximum de 2 nombres

FUNCTION max!(VAL a!,VAL b!)
	IF a!>b! THEN max!=a! ELSE max!=b!
END FUNCTION


' Vrai si, avec x1<xm<x2, f(x1)<f(xm)<f(x2)
' ou si, avec x1>xm>x2, f(x1)>f(xm)>f(x2).

FUNCTION continue(tblff(1),tblfn!(),VAL x1!,VAL y1!,VAL x2!,VAL y2!)
STATIC ym!
	ym!=inter!(tblff(),tblfn!(),(x2!+x1!)/2,0!,0!,0!)
	IF y2!>y1! THEN
		IF ym!>y1! AND ym!<y2! THEN continue=-1 ELSE continue=0
	ELSE
		IF ym!<y1! AND ym!>y2! THEN continue=-1 ELSE continue=0
	END IF
END FUNCTION


' Tourne un point d'un angle az autour de l'axe des z, puis
' d'un angle ax autour de l'axe des x 

SUB trnpoint (VAL xi!,VAL yi!,VAL zi!,xf!,yf!,zf!)
	xf!=xi!*cz!-yi!*sz!
	yf!=xi!*sz!+yi!*cz!
	zf!=zi!*cx!-yf!*sx!
	yf!=zi!*sx!+yf!*cx!
END SUB


' =======================================================================
' =                    Interpréteur de fonctions                        =
' =======================================================================


' Cherche, à partir de la position n de fc$, la présence d'un lexème.
' Si trouvé, renvoie la valeur liée à ce lexème (voir le tableau de 
' constantes).
' Sinon, renvoie 1 dans la variable globale 'erreur'.

FUNCTION decoupecaractere(f$,n,nombre!)
LOCAL schaine$,car$,anciencarac$
LOCAL nombrecar,pointfonc,bool
	nombrecar=Max_caracteres+1
	pointfonc=0
	DO
		DECR nombrecar
		schaine$=MID$(f$,n,nombrecar)
		bool=fonctions$(pointfonc)=schaine$
		DO UNTIL bool OR LEN(fonctions$(pointfonc))<nombrecar
			INCR pointfonc
			IF pointfonc<=UBOUND(fonctions$) THEN bool=fonctions$(pointfonc)= _
				schaine$
		LOOP WHILE pointfonc<=UBOUND(fonctions$)
	LOOP UNTIL bool OR pointfonc>UBOUND(fonctions$)
	IF bool THEN
		decoupecaractere=pointfonc+Min_fonction
		n=n+nombrecar
	ELSE
		IF MID$(f$,n,3)="inf" THEN
			 decoupecaractere=Nombre
			 nombre!=9e15
			 n=n+3
		ELSEIF MID$(f$,n,2)="pi" THEN
			decoupecaractere=Nombre
			nombre!=pi!
			n=n+2
		ELSE
			schaine$=MID$(f$,n,1)
			SELECT CASE schaine$
				CASE "0" TO "9",".","e"
				       nombrecar=1
					car$=schaine$
					anciencarac$=schaine$
					DO
						INCR n
						IF n>LEN(f$) THEN EXIT LOOP
						car$=MID$(f$,n,1)
						bool=(car$>="0" AND car$<="9") OR car$="e" OR _
							car$="." OR (car$="-" AND car$="e")
						IF bool THEN schaine$=schaine$+car$
						anciencarac$=car$
					LOOP WHILE bool
					decoupecaractere=Nombre
					nombre!=VAL(schaine$)
				CASE "("
					decoupecaractere=Par_ouverte
					INCR n
				CASE ")"
					decoupecaractere=Par_fermee
					INCR n
				CASE "x","y","r","t"
					SELECT CASE schaine$
						CASE "x"
							decoupecaractere=Var_x
						CASE "y"
							decoupecaractere=Var_y
						CASE "r"
							decoupecaractere=Var_r
						CASE "u"
							decoupecaractere=Var_u
						CASE "t"
							decoupecaractere=Var_t
					END SELECT
					INCR n
				CASE "+","-","*","/","^"
					SELECT CASE schaine$
						CASE "+"
							decoupecaractere=Op_plus
						CASE "-"
							decoupecaractere=Op_moins
						CASE "*"
							decoupecaractere=Op_mul
						CASE "/"
							decoupecaractere=Op_div
						CASE "^"
							decoupecaractere=Op_puiss
					END SELECT
					INCR n
				CASE ELSE
					erreur=1
			END SELECT
		END IF
	END IF
END FUNCTION


' Transforme la fonction fc$ en tableaux.

SUB traduitfonction (VAL fc$,tableau_fc%(1),tableau_nb!(1))
LOCAL n,indice_fc,indice_nb,pre_caractere,nextcar,nextnb!
	killcar fc$," "
	IF fc$="" THEN erreur=4 : EXIT SUB
	fc$=LCASE$(fc$)
	n=1
	indice_fc=0
	indice_nb=0
	Pre_Caractere=0
	DO WHILE indice_fc<=Max_Tblfc AND indice_nb<=Max_Tblnb
		NextCar=decoupecaractere(fc$,n,NextNb!)
		IF erreur>0 THEN EXIT FUNCTION
		SELECT CASE NextCar
			CASE Nombre
				tableau_fc(indice_fc)=NextCar
				IF Pre_Caractere=-3 THEN
					tableau_nb!(indice_nb)=-NextNb!
				ELSE
					tableau_nb!(indice_nb)=NextNb!
				END IF
				INCR indice_fc
				INCR indice_nb
				Pre_Caractere=-1
			CASE Par_ouverte,Par_fermee,Op_plus,Op_mul,Op_div, _
				Op_puiss,Min_fonction TO Max_fonction
				tableau_fc(indice_fc)=NextCar
				INCR indice_fc
				IF NextCar=Par_fermee THEN Pre_Caractere=1 ELSE Pre_Caractere=0
			CASE Min_variable TO Max_variable
				IF Pre_Caractere=-3 THEN
					tableau_fc(indice_fc)=NextCar+1
				ELSE
					tableau_fc(indice_fc)=NextCar
				END IF
				INCR indice_fc
				Pre_Caractere=-2
			CASE Op_moins
				SELECT CASE Pre_Caractere
					CASE -1,-2,1
						tableau_fc(indice_fc)=NextCar
						INCR indice_fc
					CASE ELSE
						Pre_Caractere=-3
				END SELECT
		END SELECT
	LOOP UNTIL n>LEN(fc$)
	IF indice_fc>Max_Tblfc THEN erreur=8 : EXIT SUB
	IF indice_nb>Max_Tblnb THEN erreur=9 : EXIT SUB
	tableau_fc(indice_fc)=Fin_de_chaine
END SUB


' Cherche les erreurs de syntaxe dans le tableau représentant une
' fonction (obtenu avec 'traduitfonction').
' Si trouvé, fixe 'erreur' à 1.

SUB verifiefonction (tblfc(1))
LOCAL i,nbpar,fc
	i=0:nbpar=0
	DO
		fc=tblfc(i)
		SELECT CASE fc
			CASE Par_ouverte: INCR nbpar
			CASE Par_fermee: DECR nbpar
			CASE Min_fonction TO Max_fonction
				IF tblfc(i+1)<>Par_ouverte THEN erreur=1: EXIT SUB
		END SELECT
		INCR i
	LOOP UNTIL tblfc(i)=Fin_de_chaine
	IF nbpar<>0 THEN erreur=1
END SUB


' Traitement des opérateurs

FUNCTION appliqueop! (VAL nombre1!,VAL nombre2!,VAL operateur%)
	SELECT CASE operateur%
	CASE 0: appliqueop!=nombre1!
	CASE Op_plus
		IF ABS(nombre1!)<maxadd! AND ABS(nombre2!)<maxadd! THEN
			appliqueop!=nombre1!+nombre2!
		ELSE
			erreur=3
		END IF
	CASE Op_moins
		IF ABS(nombre1!)<maxadd! AND ABS(nombre2!)<maxadd! THEN
			appliqueop!=nombre1!-nombre2!
		ELSE
			erreur=3
		END IF
	CASE Op_div
		IF ABS(nombre2!)>minv! THEN
			appliqueop!=nombre1!/nombre2!
		ELSE
			erreur=3
		END IF
	CASE Op_mul
		IF ABS(nombre1!)<maxproduit! AND ABS(nombre2!)<maxproduit! THEN
			appliqueop!=nombre1!*nombre2!
		ELSE
			erreur=3
		END IF
	CASE Op_puiss
		IF ABS(nombre1!)<minv! THEN
			appliqueop!=0!
		ELSE
			IF nombre2!=FIX(nombre2!) THEN
				IF (nombre2! MOD 2)=0 THEN
					appliqueop!=ABS(nombre1!)^nombre2!
				ELSE
					appliqueop!=SGN(nombre1!)*ABS(nombre1!)^nombre2!
				END IF
			ELSE
				IF nombre1!>0! THEN
					appliqueop!=nombre1!^nombre2!
				ELSE
					erreur=2
				END IF
			END IF
		END IF
	END SELECT
END FUNCTION


' Traitement des fonctions

FUNCTION appliquefc! (VAL nombre!,VAL fc%)
STATIC nombremod!
	SELECT CASE fc%
	CASE 0: appliquefc!=nombre!
	CASE Fc_abs
				 appliquefc!=ABS(nombre!)
	CASE Fc_sin
		appliquefc!=SIN(nombre!)
	CASE Fc_cos
		appliquefc!=COS(nombre!)
	CASE Fc_tan
		IF ABS(COS(nombre!))>mtan! THEN
			appliquefc!=TAN(nombre!)
		ELSE
			erreur=3
		END IF
	CASE Fc_log
		IF nombre!>0 THEN
			appliquefc!=LOG(nombre!)
		ELSE
			IF nombre!=0 THEN erreur=3 ELSE erreur=2
		END IF
	CASE Fc_log10
		IF nombre!>0 THEN
			appliquefc!=LOG10(nombre!)
		ELSE
			IF nombre!=0 THEN erreur=3 ELSE erreur=2
		END IF
	CASE Fc_exp
		IF nombre!<maxexponentielle! THEN
			appliquefc!=EXP(nombre!)
		ELSE
			erreur=3
		END IF
	CASE Fc_sqr
		IF nombre!>=0 THEN appliquefc!=SQR(nombre!) ELSE erreur=2
	CASE Fc_fix
		appliquefc!=FIX(nombre!)
	CASE Fc_cot
		nombremod!=nombre!-FIX((nombre!+pisur2!)/pi!)*pi!
		IF ABS(nombremod!)>minv! THEN
			appliquefc!=1/TAN(nombre!)
		ELSE
			erreur=3
		END IF
	CASE Fc_arcsin
		IF ABS(nombre!)<1.0 THEN
			appliquefc!=ATN(nombre!/SQR(-nombre!*nombre!+1))
		ELSEIF nombre!==1.0 THEN
			appliquefc!=pisur2!
		ELSEIF nombre!==-1.0 THEN
			appliquefc!=-pisur2!
		ELSE
			erreur=2
		END IF
	CASE Fc_arccos
		IF ABS(nombre!)<1.0 THEN
			appliquefc!=-ATN(nombre!/SQR(-nombre!*nombre!+1))+pisur2!
		ELSEIF nombre!==1.0 THEN
			appliquefc!=0
		ELSEIF nombre!==-1.0 THEN
			appliquefc!=pi!
		ELSE
			erreur=2
		END IF
	CASE Fc_arctan
		appliquefc!=ATN(nombre!)
	CASE Fc_arccot
		appliquefc!=ATN(nombre!)+pisur2!
	CASE Fc_sinh
		IF ABS(nombre!)<maxexponentielle! THEN
			appliquefc!=(EXP(nombre!)-EXP(-nombre!))/2
		ELSE
			erreur=3
		END IF
	CASE Fc_cosh
		IF ABS(nombre!)<maxexponentielle! THEN
			appliquefc!=(EXP(nombre!)+EXP(-nombre!))/2
		ELSE
			erreur=3
		END IF
	CASE Fc_tanh
		IF ABS(nombre!)<maxexponentielle! THEN
			appliquefc!=(EXP(2*nombre!)-1)/(EXP(2*nombre!)+1)
		ELSE
			erreur=3
		END IF
	CASE Fc_arcsinh:appliquefc!=LOG(nombre!+SQR(nombre!*nombre!+1))
	CASE Fc_arccosh
		IF nombre!>=1 THEN
			appliquefc!=LOG(nombre!+SQR(nombre!*nombre!-1))
		ELSE
			erreur=2
		END IF
	CASE Fc_arctanh:
		IF ABS(nombre!)<1 THEN
			appliquefc!=LOG((1+nombre!)/(1-nombre!))/2
		ELSE
			erreur=2
		END IF
	END SELECT
END FUNCTION


' Renvoie f(t). tblfc() et tblnb!() sont les tableaux obtenus avec
' 'traduitfonction'.

FUNCTION inter!(tblfc(1),tblnb!(1),xv!,yv!,uv!,tv!)
STATIC l,l(),niventree(),operateur(),fonction(),acc!(),dernierniv()
STATIC iniv,ifc,inb,ipar,fc,fcmd2,v!,x!
	IF NOT l THEN
		DIM l(Max_niveaux),niventree(Max_niveaux),operateur(Max_niveaux), _
			fonction(Max_niveaux),acc!(Max_niveaux)
		DIM dernierniv(Max_niveaux)
		l=-1
	END IF
	acc!(0)=0:operateur(0)=0:fonction(0)=0
	dernierniv(0)=0
	iniv=0:ifc=0:inb=0:ipar=0
	DO
		fc=tblfc(ifc)
		SELECT CASE fc
			CASE Min_fonction TO Max_fonction
				fonction(ipar)=fc
			CASE Par_ouverte
				INCR ipar
				INCR iniv
				IF ipar>Max_niveaux OR iniv>Max_niveaux THEN erreur=10 : _ 
					EXIT FUNCTION
				dernierniv(ipar)=iniv
				acc!(iniv)=0:operateur(iniv)=0:fonction(ipar)=0
			CASE Min_variable TO Max_variable
				fcmd2=fc-(fc MOD 2)
				SELECT CASE fcmd2
				CASE Var_x
					v!=xv!
				CASE Var_y
					v!=yv!
				CASE Var_r
					v!=SQR(xv!*xv!+yv!*yv!)
				CASE Var_u
					v!=uv!
				CASE Var_t
					v!=tv!
				END SELECT
				IF fc MOD 2=0 THEN x!=v! ELSE x!=-v!
				IF operateur(iniv)=0 THEN acc!(iniv)=x!
			CASE Nombre
				x!=tblnb!(inb)
				INCR inb
				IF operateur(iniv)=0 THEN acc!(iniv)=x!
			CASE Min_operateur TO Max_operateur
				IF operateur(iniv)=0 THEN
					operateur(iniv)=fc
				ELSEIF priorite(fc)>priorite(operateur(iniv)) THEN
					INCR iniv
					IF iniv>Max_niveaux THEN erreur=10 : EXIT FUNCTION
					acc!(iniv)=x!:operateur(iniv)=fc
				ELSEIF priorite(fc)<priorite(operateur(iniv)) THEN
					IF iniv=dernierniv(ipar) THEN
						acc!(iniv)=appliqueop!(acc!(iniv),x!,operateur(iniv))
						operateur(iniv)=fc
					ELSE
						x!=appliqueop!(acc!(iniv),x!,operateur(iniv))
						DECR iniv
						acc!(iniv)=appliqueop!(acc!(iniv),x!,operateur(iniv))
						operateur(iniv)=fc
					END IF
				ELSEIF priorite(fc)=priorite(operateur(iniv)) THEN
					acc!(iniv)=appliqueop!(acc!(iniv),x!,operateur(iniv))
					operateur(iniv)=fc
				END IF
			CASE Par_fermee
				DO WHILE iniv>=dernierniv(ipar)
					x!=appliqueop!(acc!(iniv),x!,operateur(iniv))
					DECR iniv
				LOOP
				DECR ipar
				x!=appliquefc!(x!,fonction(ipar))
				IF operateur(iniv)=0 THEN acc!(iniv)=x!
			CASE Fin_de_chaine
				DO WHILE iniv>=0
					x!=appliqueop!(acc!(iniv),x!,operateur(iniv))
					DECR iniv
				LOOP
		END SELECT
		INCR ifc
		IF erreur>0 THEN EXIT FUNCTION
	LOOP UNTIL fc=Fin_de_chaine
	inter!=x!
END FUNCTION


' Evaluation d'une expression mathématique constante.

FUNCTION interconst!(c$)
STATIC l,tblf(),tbln!()
	IF NOT l THEN
		DIM tblf(Max_tblfc),tbln!(Max_tblnb)
		l=-1
	END IF
	traduitfonction c$,tblf(),tbln!()
	IF erreur>0 THEN EXIT FUNCTION
	verifiefonction tblf()
	IF erreur>0 THEN EXIT FUNCTION
	interconst!=inter!(tblf(),tbln!(),0!,0!,0!,0!)
END FUNCTION


' ========================================================================
' =                       Procédures de tracé                            =
' ========================================================================


' Renvoie vrai si (x,y) est compris dans les limites de l'écran.

FUNCTION ptscreen(VAL x,VAL y)
	ptscreen=x>=0 AND x<=ScreenLarge AND y>=0 AND y<=screenhigh
END FUNCTION


' Calcule l'intersection de deux droites définie chacune par 
' deux points: (xa1,ya1) et (xb1,yb1) pour la première,
' (xa2,ya2) et (xb2,yb2) pour la seconde.

FUNCTION intersection (VAL xa1,VAL ya1,VAL xb1,VAL yb1,VAL xa2, _
	VAL ya2,VAL xb2,VAL yb2,x,y)
	STATIC a1!,b1!,a2!,b2!
	IF xa1<>xb1 THEN
		a1!=(yb1-ya1)/(xb1-xa1)
		IF a1!<>0 THEN
			b1!=ya1-a1!*xa1
			IF xa2<>xb2 THEN
				a2!=(yb2-ya2)/(xb2-xa2)
				IF a2!<>0 THEN
					b2!=ya2-a2!*xa2
					IF a2!<>a1! THEN
						x=(b2!-b1!)/(a1!-a2!)
						y=a1!*x+b1!
						intersection=-1
					ELSE
						intersection=0
					END IF
				ELSE
					y=ya2
					x=(y-b1!)/a1!
					intersection=-1
				END IF
			ELSE
				x=xa2
				y=a1!*x+b1!
				intersection=-1
			END IF
		ELSE
			IF xa2<>xb2 THEN
				a2!=(yb2-ya2)/(xb2-xa2)
				IF a2!<>0 THEN
					b2!=ya2-a2!*xa2
					y=ya1
					x=(y-b2!)/a2!
					intersection=-1
				ELSE
					intersection=0
				END IF
			ELSE
				x=xa2
				y=ya1
				intersection=-1
			END IF
		END IF
	ELSE
		x=xa1
		IF xa2<>xb2
			a2!=(yb2-ya2)/(xb2-xa2)
			b2!=ya2-a2!*xa2
			y=a2!*x+b2!
			intersection=-1
		ELSE
			intersection=0
		END IF
	END IF
END FUNCTION


' Fenêtre un segment par rapport à un autre segment.

SUB fenetresegment(VAL x1,VAL y1,VAL x2,VAL y2,VAL xs1, _
	VAL ys1,VAL xs2,VAL ys2,tblsortie(2),j)
	STATIC c1!,c2!,x,y,dummy
	c1!=CSNG(xs2-xs1)*CSNG(y1-ys1)-CSNG(ys2-ys1)*CSNG(x1-xs1)
	c2!=CSNG(xs2-xs1)*CSNG(y2-ys1)-CSNG(ys2-ys1)*CSNG(x2-xs1)
	IF c1!>=0 THEN
		IF j>Max_Polygons THEN erreur=6 : EXIT SUB
		tblsortie(j,0)=x1 : tblsortie(j,1)=y1
		INCR j
		IF c2!<0 THEN
			dummy=intersection(x1,y1,x2,y2,xs1,ys1,xs2,ys2,x,y)
			IF NOT dummy THEN erreur=7 : EXIT SUB
			IF j>Max_Polygons THEN erreur=6 : EXIT SUB
			tblsortie(j,0)=x : tblsortie(j,1)=y
			INCR j
		END IF
	ELSE
		IF c2!>=0 THEN
			dummy=intersection(x1,y1,x2,y2,xs1,ys1,xs2,ys2,x,y)
			IF NOT dummy THEN erreur=7 : EXIT SUB
			IF j>Max_Polygons THEN erreur=6 : EXIT SUB
			tblsortie(j,0)=x : tblsortie(j,1)=y
			INCR j
		END IF
	END IF
END SUB


' Fenêtre un polygone par rapport à un segment.

SUB fenetragepoly(tblpoly(2),tblsortie(2),nbpoints,VAL xs1, _
	VAL ys1,VAL xs2,VAL ys2)
	STATIC i,j
	j=0
	IF nbpoints>=3 THEN
		FOR i=0 TO nbpoints-2
			fenetresegment tblpoly(i,0),tblpoly(i,1),tblpoly(i+1,0), _
				tblpoly(i+1,1),xs1,ys1,xs2,ys2,tblsortie(),j
		NEXT i
	END IF
	IF nbpoints>=2 THEN
		fenetresegment tblpoly(nbpoints-1,0),tblpoly(nbpoints-1,1), _
			tblpoly(0,0),tblpoly(0,1),xs1,ys1,xs2,ys2,tblsortie(),j
	END IF
	nbpoints=j
END SUB


' Fenêtre un polygone par rapport à un rectangle.

SUB fenquadripoly(tblpoly(2),nbelements,VAL x1,VAL y1,VAL x2,VAL y2)
	STATIC ready
	STATIC tblbuffer()
	IF NOT ready THEN
		DIM tblbuffer(Max_Polygons,1)
		ready=-1
	END IF
	fenetragepoly tblpoly(),tblbuffer(),nbelements,x1,y1,x2,y1
	IF erreur>0 THEN EXIT SUB
	fenetragepoly tblbuffer(),tblpoly(),nbelements,x2,y1,x2,y2
	IF erreur>0 THEN EXIT SUB
	fenetragepoly tblpoly(),tblbuffer(),nbelements,x2,y2,x1,y2
	IF erreur>0 THEN EXIT SUB
	fenetragepoly tblbuffer(),tblpoly(),nbelements,x1,y2,x1,y1
END SUB


' Inverse l'intérieur d'un polygone et l'entoure de lignes.

SUB fillpolygon(VAL x1,VAL y1,VAL x2,VAL y2,VAL x3,VAL y3,VAL x4,VAL y4,VAL c)
	STATIC poly()
	STATIC ready,n,nombrepoints
	IF NOT ready THEN
		DIM poly(Max_Polygons,1)
		ready=-1
	END IF
	nombrepoints=4
	poly(0,0)=x1 : poly(0,1)=y1
	poly(1,0)=x2 : poly(1,1)=y2
	poly(2,0)=x3 : poly(2,1)=y3
	poly(3,0)=x4 : poly(3,1)=y4
	fenquadripoly poly(),nombrepoints,0,0,ScreenLarge,screenhigh
	IF nombrepoints>=3 THEN
		FOR n=0 TO nombrepoints-1
			IF ptscreen(poly(n,0),poly(n,1)) THEN AREA(poly(n,0),poly(n,1))
		NEXT n
		AREAFILL
	END IF
	IF nombrepoints>=2 THEN
		IF nombrepoints>=3 THEN
			FOR n=0 TO nombrepoints-2
				LINE(poly(n,0),poly(n,1))-(poly(n+1,0),poly(n+1,1)),c
			NEXT n
		END IF
		LINE(poly(nombrepoints-1,0),poly(nombrepoints-1,1))- _
			(poly(0,0),poly(0,1)),c
	END IF
END SUB


' Renvoie les coordonnées sur l'écran d'un point d'un coordonnées
' (x,y) dans le repère utilisé pour définir la courbe.

SUB represente(VAL x!,VAL y!,xr,yr)
	xr=ScreenLarge*(1-aspect!)\2+((x!-xmin!)/(xmax!-xmin!)*(ScreenLarge-9))* _
		aspect!
	yr=screenhigh-1-(y!-ymin!)/(ymax!-ymin!)*(screenhigh-14)
	IF yr>screenhigh THEN yr=screenhigh
END SUB


' Tracé des axes. xaxe! et yaxe! sont les longueurs séparant 2 graduations.

SUB traceaxes(VAL xaxe!,VAL yaxe!,VAL xmin!,VAL xmax!,VAL ymin!,VAL ymax!)
LOCAL xt,yt,xc,yc,x!,y!
	IF (xmax!-xmin!)/xaxe!>100 THEN xaxe!=(xmax!-xmin!)/100
	IF (ymax!-ymin!)/yaxe!>100 THEN yaxe!=(ymax!-ymin!)/100
	represente 0,0,xc,yc
	LINE (0,yc)-(ScreenLarge,yc),3
	LINE (xc,0)-(xc,screenhigh),3
	FOR x!=0 TO xmax! STEP xaxe!
		represente x!,0,xt,yc
		LINE (xt,yc-2)-(xt,yc+2),2
	NEXT x!
	FOR x!=0 TO xmin! STEP -xaxe!
		represente x!,0,xt,yc
		LINE (xt,yc-2)-(xt,yc+2),2
	NEXT x!
	FOR y!=0 TO ymax! STEP yaxe!
		represente 0,y!,xc,yt
		LINE (xc-4,yt)-(xc+4,yt),2
	NEXT y!
	FOR y!=0 TO ymin! STEP -yaxe!
		represente 0,y!,xc,yt
		LINE (xc-4,yt)-(xc+4,yt),2
	NEXT y!
END SUB


' Renvoie les coordonnées sur l'écran d'un point de coordonnées
' (xi,yi,zi) dans l'espace

SUB tdreppoint(VAL xi!,VAL yi!,VAL zi!,xs,ys)
	LOCAL xf!,yf!,zf!
	zi!=zi!*multhauteur!
	trnpoint xi!,yi!,zi!,xf!,yf!,zf!
	xs=ScreenLarge*(1-aspect!)\2+((xf!-xmins!)/(xmaxs!-xmins!)* _
		(ScreenLarge-9))*aspect!
	ys=ScreenHigh-1-(yf!-ymins!)/(ymaxs!-ymins!)*(ScreenHigh-14)
END SUB


' ========================================================================
' =                         Tracé des courbes                            =
' ========================================================================


' Trace une courbe y=f(x).
' - x$: fonction à représenter,
' - tracelignes: à -1 si les points doivent être joints par des
' - lignes, à 0 sinon.

SUB tracecourbe(x$,VAL tracelignes)
LOCAL tblfx(Max_tblfc),tblnx!(Max_tblnb)
LOCAL pas!,x1!,y1!,x2!,y2!
LOCAL xr1,yr1,xr2,yr2
	traduitfonction x$,tblfx(),tblnx!()
	IF erreur>0 THEN paramerr=0:EXIT SUB
	verifiefonction tblfx()
	IF erreur>0 THEN paramerr=0:EXIT SUB
	pas!=(xmax!-xmin!)/ScreenLarge
	x1!=xmin!
	y1!=inter!(tblfx(),tblnx!(),x1!,0!,0!,0!)
	IF erreur=1 OR erreur=2 THEN paramerr=0:EXIT SUB
	represente x1!,y1!,xr1,yr1
	IF yr1<screenhigh THEN PSET (xr1,yr1),1
	DO
		IF INKEY$=CHR$(27) THEN EXIT SUB
		x2!=x1!+pas!
		y2!=inter!(tblfx(),tblnx!(),x2!,0!,0!,0!)
		IF erreur=1 OR erreur=2 THEN paramerr=0:EXIT SUB
		IF erreur=3 THEN erreur=0
		represente x2!,y2!,xr2,yr2
		IF tracelignes AND ABS(yr2-yr1)>1 THEN
			IF continue(tblfx(),tblnx!(),x1!,y1!,x2!,y2!) THEN
				IF erreur=0 THEN LINE (xr1,yr1)-(xr2,yr2),1
			END IF
		ELSE
			IF yr2<screenhigh THEN PSET (xr2,yr2),1
		END IF
		x1!=x2!:y1!=y2!:xr1=xr2:yr1=yr2
	LOOP UNTIL(x2!>xmax!-pas!)
END SUB


' Trace une courbe paramétrée ou polaire.
' - x$: fonction x=f(t) pour les courbes paramêtrées, r=f(t) pour
'   les courbes polaires.
' - y$: fonction y=f(t) pour les courbes paramêtrées, inutilisé sinon.
' - type=1 pour une courbe paramêtrée, à 2 pour une courbe polaire.
' - tracelignes=-1 pour joindre les points tracés par des lignes,
'   à 0 sinon.

SUB tracecourbeparametree(x$,y$,VAL type,VAL tracelignes)
	LOCAL tblfx(Max_tblfc),tblnx!(Max_tblnb)
	IF type=1 THEN
		LOCAL tblfy(Max_tblfc),tblny!(Max_tblnb)
	END IF
	LOCAL t!,r!,pas!,x1!,x2!,y1!,y2!
	LOCAL xr1,yr1,xr2,yr2,precnonaccoles,accoles,eloignes
	traduitfonction x$,tblfx(),tblnx!()
	IF erreur=1 THEN paramerr=0:EXIT SUB
	verifiefonction tblfx()
	IF erreur=1 THEN paramerr=0:EXIT SUB
	IF type=1 THEN
		traduitfonction y$,tblfy(),tblny!()
		IF erreur=1 THEN paramerr=1:EXIT SUB
		verifiefonction tblfy()
		IF erreur=1 THEN paramerr=1:EXIT SUB
	END IF
	t!=tmin!
	pas!=(tmax!-tmin!)/Fraction_Initiale
	IF type=1 THEN
		x1!=inter!(tblfx(),tblnx!(),0!,0!,0!,t!)
		IF erreur=2 THEN paramerr=0:EXIT SUB
		y1!=inter!(tblfy(),tblny!(),0!,0!,0!,t!)
		IF erreur=2 THEN paramerr=1:EXIT SUB
	ELSE
		r!=inter!(tblfx(),tblnx!(),0!,0!,0!,t!)
		IF erreur=2 THEN paramerr=0:EXIT SUB
		x1!=r!*COS(t!)
		y1!=r!*SIN(t!)
	END IF
	represente x1!,y1!,xr1,yr1
	IF erreur=0 THEN
		IF yr1<screenhigh THEN PSET (xr1,yr1),1
	ELSE
		erreur=0
	END IF
	precnonaccoles=-1
	DO
		DO
			IF INKEY$=CHR$(27) THEN EXIT SUB
			t!=t!+pas!
			IF type=1 THEN
				x2!=inter!(tblfx(),tblnx!(),0!,0!,0!,t!)
				IF erreur=2 THEN paramerr=0:EXIT SUB
				y2!=inter!(tblfy(),tblny!(),0!,0!,0!,t!)
				IF erreur=2 THEN paramerr=1:EXIT SUB
			ELSE
				r!=inter!(tblfx(),tblnx!(),0!,0!,0!,t!)
				IF erreur=2 THEN paramerr=0:EXIT SUB
				x2!=r!*COS(t!)
				y2!=r!*SIN(t!)
			END IF
			represente x2!,y2!,xr2,yr2
			eloignes=ABS(xr2-xr1)>distance OR ABS(yr2-yr1)>distance
			accoles=(xr2=xr1) AND (yr2=yr1)
			IF accoles THEN
				t!=t!-pas!
				pas!=pas!*accpas!
				precnonaccoles=0
			END IF
			IF eloignes THEN
				IF pas!>=epsilon! AND precnonaccoles THEN
					t!=t!-pas!
					pas!=pas!/accpas!
				ELSE
					eloignes=0
				END IF
			END IF
		LOOP WHILE (accoles OR eloignes) AND (pas!>=epsilon!)
		precnonaccoles=-1
		IF distance=1 OR NOT(tracelignes) THEN
			IF yr2<screenhigh THEN PSET(xr2,yr2),1
		ELSE
			IF yr1<>screenhigh OR yr2<>screenhigh THEN
				LINE (xr1,yr1)-(xr2,yr2),1
			END IF
		END IF
		xr1=xr2 : yr1=yr2
	LOOP UNTIL t!>tmax!-pas!
END SUB


' Modifie les valeurs de xmin,xmax,ymin,ymax pour que (xmin,ymin)
' corresponde au point le plus éloigné de l'écran, et (xmax,ymax)
' au point le plus proche.

SUB echangeparametres(x1!,y1!,x2!,y2!)
	IF (az!<=pi!/2) THEN
		SWAP x1!,x2!
		SWAP y1!,y2!
	ELSEIF (az!>pi!/2) AND (az!<=pi!) THEN
		SWAP x1!,x2!
	ELSEIF (az!>3*pi!/2) AND (az!<=2*pi!) THEN
		SWAP y1!,y2!
	END IF
	IF ax!>pi! AND ax!<=2*pi! THEN
		SWAP x1!,x2!
		SWAP y1!,y2!
	END IF
END SUB


' Trace une surface.

SUB tracesurface(z$,VAL divx,VAL divy)
	LOCAL tblfc(Max_tblfc),tblnb!(Max_tblnb)
	LOCAL x!,y!,r!,xpas!,ypas!,xmint!,ymint!,xmaxt!,ymaxt!,z1!,z2!,z3!,z4!
	LOCAL pasxmult,pasymult,cotarr,i,xs1,ys1,xs2,ys2,xs3,ys3,xs4,ys4
	LOCAL sauvpoints(divx,1)
	paramerr=0
	r!=0!
	traduitfonction z$,tblfc(),tblnb!()
	IF erreur>0 THEN EXIT SUB
	verifiefonction tblfc()
	IF erreur>0 THEN EXIT SUB
	xmint!=xmin! : ymint!=ymin! : xmaxt!=xmax! : ymaxt!=ymax!
	echangeparametres xmint!,ymint!,xmaxt!,ymaxt!
	xpas!=(xmaxt!-xmint!)/divx : ypas!=(ymaxt!-ymint!)/divy
	x!=xmint! : y!=ymint! : i=0
	z1!=inter!(tblfc(),tblnb!(),x!,y!,r!,0!)
	IF erreur=2 THEN EXIT SUB
	IF erreur=3 THEN erreur=0
	z2!=inter!(tblfc(),tblnb!(),x!+xpas!,y!,r!,0!)
	IF erreur=2 THEN EXIT SUB
	IF erreur=3 THEN erreur=0
	z3!=inter!(tblfc(),tblnb!(),x!+xpas!,y!+ypas!,r!,0!)
	IF erreur=2 THEN EXIT SUB
	IF erreur=3 THEN erreur=0
	z4!=inter!(tblfc(),tblnb!(),x!,y!+ypas!,r!,0!)
	IF erreur=2 THEN EXIT SUB
	IF erreur=3 THEN erreur=0
	tdreppoint x!,y!,z1!,xs1,ys1
	tdreppoint x!+xpas!,y!,z2!,xs2,ys2
	tdreppoint x!+xpas!,y!+ypas!,z3!,xs3,ys3
	tdreppoint x!,y!+ypas!,z4!,xs4,ys4
	fillpolygon xs1,ys1,xs2,ys2,xs3,ys3,xs4,ys4,CouleurLignes
	IF erreur>0 THEN EXIT SUB
	sauvpoints(0,0)=xs4 : sauvpoints(0,1)=ys4
	x!=x!+xpas!
	FOR i=1 TO divx-1
		x!=x!+xpas!
		xs1=xs2 : ys1=ys2
		xs4=xs3 : ys4=ys3
		z2!=inter!(tblfc(),tblnb!(),x!,y!,r!,0!)
		IF erreur=2 THEN EXIT SUB
		IF erreur=3 THEN erreur=0
		z3!=inter!(tblfc(),tblnb!(),x!,y!+ypas!,r!,0!)
		IF erreur=2 THEN EXIT SUB
		IF erreur=3 THEN erreur=0
		tdreppoint x!,y!,z2!,xs2,ys2
		tdreppoint x!,y!+ypas!,z3!,xs3,ys3
		fillpolygon xs1,ys1,xs2,ys2,xs3,ys3,xs4,ys4,CouleurLignes
		IF erreur>0 THEN EXIT SUB
		sauvpoints(i,0)=xs4 : sauvpoints(i,1)=ys4
		IF INKEY$=CHR$(27) THEN paramerr=-1 : EXIT SUB
	NEXT i
	sauvpoints(divx,0)=xs3 : sauvpoints(divx,1)=ys3
	FOR y!=ymint!+ypas! TO ymaxt!-ypas! STEP ypas!
		x!=xmint!
		z3!=inter!(tblfc(),tblnb!(),x!+xpas!,y!+ypas!,r!,0!)
		IF erreur=2 THEN EXIT SUB
		IF erreur=3 THEN erreur=0
		z4!=inter!(tblfc(),tblnb!(),x!,y!+ypas!,r!,0!)
		IF erreur=2 THEN EXIT SUB
		IF erreur=3 THEN erreur=0
		tdreppoint x!+xpas!,y!+ypas!,z3!,xs3,ys3
		tdreppoint x!,y!+ypas!,z4!,xs4,ys4
		xs1=sauvpoints(0,0) : ys1=sauvpoints(0,1)
		xs2=sauvpoints(1,0) : ys2=sauvpoints(1,1)
		fillpolygon xs1,ys1,xs2,ys2,xs3,ys3,xs4,ys4,CouleurLignes
		IF erreur>0 THEN EXIT SUB
		sauvpoints(0,0)=xs4 : sauvpoints(0,1)=ys4
		x!=x!+xpas!
		FOR i=1 TO divx-1
			x!=x!+xpas!
			xs1=xs2 : ys1=ys2
			xs4=xs3 : ys4=ys3
			z3!=inter!(tblfc(),tblnb!(),x!,y!+ypas!,r!,0!)
			tdreppoint x!,y!+ypas!,z3!,xs3,ys3
			xs2=sauvpoints(i+1,0) : ys2=sauvpoints(i+1,1)
			fillpolygon xs1,ys1,xs2,ys2,xs3,ys3,xs4,ys4,CouleurLignes
			IF erreur>0 THEN EXIT SUB
			sauvpoints(i,0)=xs4 : sauvpoints(i,1)=ys4
			IF INKEY$=CHR$(27) THEN paramerr=-1 : EXIT SUB
		NEXT i
		sauvpoints(divx,0)=xs3 : sauvpoints(divx,1)=ys3
	NEXT y!
	IF erreur=3 THEN erreur=0
	paramerr=-1
END SUB


' Vérifie que les angles de rotation soient compris entre 0 et 2*pi
' et calcule leurs sinus et cosinus.

SUB inirotation
	ax!=modulo!(ax!,2*pi!) : az!=modulo!(az!,2*pi!)
	cx!=COS(ax!) : sx!=SIN(ax!)
	cz!=COS(az!) : sz!=SIN(az!)
END SUB


' Calcule les coordonnées du rectangle dans lequel est comprise
' la projection de la courbe.

SUB iniextremums
	LOCAL x1!,y1!,x2!,y2!,x3!,y3!,x4!,y4!
	LOCAL x5!,y5!,x6!,y6!,x7!,y7!,x8!,y8!
	LOCAL z!
	trnpoint xmin!,ymin!,zmin!*multhauteur!,x1!,y1!,z!
	trnpoint xmin!,ymin!,zmax!*multhauteur!,x2!,y2!,z!
	trnpoint xmin!,ymax!,zmin!*multhauteur!,x3!,y3!,z!
	trnpoint xmin!,ymax!,zmax!*multhauteur!,x4!,y4!,z!
	trnpoint xmax!,ymin!,zmin!*multhauteur!,x5!,y5!,z!
	trnpoint xmax!,ymin!,zmax!*multhauteur!,x6!,y6!,z!
	trnpoint xmax!,ymax!,zmin!*multhauteur!,x7!,y7!,z!
	trnpoint xmax!,ymax!,zmax!*multhauteur!,x8!,y8!,z!
	xmins!=min!(min!(min!(x1!,x2!),min!(x3!,x4!)),min!(min!(x5!,x6!), _
		min!(x7!,x8!)))
	ymins!=min!(min!(min!(y1!,y2!),min!(y3!,y4!)),min!(min!(y5!,y6!), _
		min!(y7!,y8!)))
	xmaxs!=max!(max!(max!(x1!,x2!),max!(x3!,x4!)),max!(max!(x5!,x6!), _
		max!(x7!,x8!)))
	ymaxs!=max!(max!(max!(y1!,y2!),max!(y3!,y4!)),max!(max!(y5!,y6!), _
		max!(y7!,y8!)))
END SUB


' =========================================================================
' =                          Messages d'erreur                            =
' =========================================================================


' Si mode=-1, affiche un message dans une boîte, aux coordonnées
' graphiques (x,y). Chaque élément de message$ contient une ligne.
' Si mode=0, l'efface.

SUB boxmessage(x,y,message$(1),VAL mode)
LOCAL xt,yt,m,n,lg,lgdemiligne,x1,y1
STATIC sauveimage()
	IF mode THEN
		xt=x\8:yt=y\8:x=xt*8:y=yt*8
		m=0:lg=LEN(message$(0))
		DO WHILE m<UBOUND(message$)
			INCR m
			IF LEN(message$(m))>lg THEN lg=LEN(message$(m))
		LOOP UNTIL message$(m)="" OR m=UBOUND(message$)
		IF message$(m)="" THEN DECR m
		x1=x+8*(lg+2):y1=y+8*(m+2)+8
		DIM sauveimage(2*(y1-y+1)*((x1-x)\16+1)+3)
		GET (x,y)-(x1,y1),sauveimage
		lgdemiligne=(x1-x)\16
		LINE (x,y)-(x1,y1),2,bf
		COLOR 1,2
		FOR n=0 TO m
			LOCATE yt+2+n,xt+1+lgdemiligne-LEN(message$(n))\2
			PRINT message$(n);
		NEXT n
	ELSE
		PUT (x,y),sauveimage,PSET
		ERASE sauveimage
	END IF
END SUB


' Si 'erreur'<>0, renvoie un numéro correspondant à sa nature.

FUNCTION erreur$
	SELECT CASE erreur
		CASE 1:erreur$="Erreur de syntaxe"
		CASE 2:erreur$="Fonction non définie"
		CASE 3:erreur$="Débordement"
		CASE 4:erreur$="Paramêtre manquant"
		CASE 5:erreur$="Mauvais paramêtre"
		CASE 6:erreur$="Bug: dimension de tableau pour fenêtrage trop petite!"
		CASE 7:erreur$="Bug: deux droites parallèles qui se coupent!"
		CASE 8:erreur$="Bug: tableau de fonctions trop petit!"
		CASE 9:erreur$="Bug: tableau de nombres trop petit!"
		CASE 10:erreur$="Bug: constantes Max_Niveaux trop petite!"
		CASE 11:erreur$="Bornes incorrectes"
		CASE 12:erreur$="Doit être positif"
		CASE 13:erreur$="Doit être un entier>=3"
	END SELECT
END FUNCTION


' =====================================================================
' =                       Tableau des paramêtres                      =
' =====================================================================


SUB parametres(epsilon!,distance,aspect!)
	LOCAL ok,n,paramerr,currentopt,gadgsortie,xmess,ymess
	LOCAL distance!
	LOCAL epsilon$,distance$,aspect$
	LOCAL positionx(4),positiony(4),longueur(4)
	LOCAL option$(4),messageerreur$(0)
	STATIC valeur$(1),ready
	IF NOT ready THEN
		DIM valeur$(4)
		ready=-1
	END IF
	paramerr=0 : currentopt=0
	RESTORE parametres_data
	FOR n=0 TO 4
		READ option$(n),positionx(n),positiony(n),longueur(n)
	NEXT n
	IF valeur$(0)="" THEN valeur$(0)="1/500"
	IF valeur$(1)="" THEN valeur$(1)="5"
	IF valeur$(2)="" THEN valeur$(2)="0.62"
	epsilon$=valeur$(0) : distance$=valeur$(1) : aspect$=valeur$(2)
	DO
		ok=-1
		boxtableauoptions 24*8,7*8,31*8,9*8,0,gadgsortie,option$(),valeur$(), _
			longueur(),positionx(),positiony(),3,4,currentopt
		IF gadgsortie=0 THEN
			epsilon!=interconst!(valeur$(0))
			IF erreur>0 THEN currentopt=0 : ok=0
			distance!=interconst!(valeur$(1))
			distance=distance!
			IF CSNG(distance)<>distance THEN erreur=14
			IF erreur>0 AND ok THEN currentopt=1 : ok=0
			aspect!=interconst!(valeur$(2))
			IF erreur>0 AND ok THEN currentopt=2 : ok=0
			IF erreur>0 THEN
				messageerreur$(0)=erreur$
				xmess=40 : ymess=18
				boxmessage xmess,ymess,messageerreur$(),-1
				effacemessage=-1
				erreur=0
			END IF
		ELSE
			ok=-1
			valeur$(0)=epsilon$
			valeur$(1)=distance$
			valeur$(2)=aspect$
		END IF
	LOOP UNTIL ok
	parametres_data:
	DATA "epsilon=",33,9,10
	DATA "distance=",32,11,10
	DATA "aspect=",34,13,10
	DATA "  Ok   ",27,15,0
	DATA "Annuler",46,15,0
END SUB


' =======================================================================
' =                                Aide                                 =
' =======================================================================


SUB aide
LOCAL aide$(15),x,y,n
	RESTORE aide_data
	FOR n=0 TO 15
		READ aide$(n)
	NEXT n
	x=16:y=16
	boxmessage x,y,aide$(),-1
	DO:LOOP UNTIL MOUSE(0)=0
	DO
		SLEEP
	LOOP UNTIL INKEY$<>"" OR MOUSE(0)<>0
	boxmessage x,y,aide$(),0
	aide_data:
	DATA "Zoom version 1.0"
	DATA "----------------"
	DATA " "
	DATA "Opérateurs:  +  -  *  /  ^"
	DATA " "
	DATA "Fonctions:"
	DATA " "
	DATA "fix(t)                ln(t) (t>=0)          log(t) (t>=0)        exp(t)   "
	DATA "sin(t)                cos(t)                tan(t)               cot(t)   "
	DATA "arcsin(t) (-1<=t<=1)  arccos(t) (-1<=t<=1)  arctan(t)            arccot(t)"
	DATA "sinh(t)               cosh(t)               tanh(t)                       "
	DATA "arcsinh               arccosh(t) (t>=1)     arctanh (-1<=t<=1)            "
	DATA "abs(t)                                                                    "
	DATA " "
	DATA "Constantes:  pi   inf"
	DATA ""
END SUB


' =======================================================================
' =                           Programme principal                       =
' =======================================================================


DIM option$(12),valeur$(12),longueur(12),positionx(12),positiony(12)
DIM messageerreur$(0)
iniaffichage
GOSUB tblcourbessimples
efface
inibox
tracelignes=-1
DO
	tableauoptions menuselect,icsortie,option$(),valeur$(),longueur(), _
		positionx(),positiony(),premieresortie,nboptions,currentopt
	IF icsortie=0 OR icsortie=1 OR icsortie=137 OR icsortie=138 THEN
		IF icsortie=138 OR icsortie=0 THEN CALL efface
		IF type=0 THEN
			GOSUB ini_courbes
			IF erreur<=0 THEN
				IF icsortie=138 OR icsortie=0 THEN
				    traceaxes axex!,axey!,xmin!,xmax!,ymin!,ymax!
				END IF
				disablemenus
				tracecourbe y$,tracelignes
				enablemenus
			END IF
		ELSEIF type=1 OR type=2 THEN
			IF type=1 THEN GOSUB ini_parametrees ELSE GOSUB ini_polaires
			IF erreur<=0 THEN
					  IF icsortie=138 OR icsortie=0 THEN
				      traceaxes axex!,axey!,xmin!,xmax!,ymin!,ymax!
				  END IF
				disablemenus
				tracecourbeparametree x$,y$,type,tracelignes
				enablemenus
			END IF
		ELSEIF type=3 THEN
			GOSUB ini_surfaces
			IF erreur<=0 THEN
				disablemenus
				tracesurface z$,divx,divy
				enablemenus
			END IF
			IF erreur=3 THEN erreur=0 : ' on ne tient pas compte des overflows
		END IF
		IF erreur>0 THEN
			currentopt=paramerr
			messageerreur$(0)=erreur$
			xmess=ScreenLarge\2-4*LEN(messageerreur$(0)):ymess=screenhigh\2-8
			boxmessage xmess,ymess,messageerreur$(),-1
			effacemessage=-1
			erreur=0
		END IF
	ELSEIF (icsortie=-1 AND menuselect=1) OR (icsortie>=129 AND icsortie<=132)  _
		THEN
		IF icsortie=-1 THEN mn=MENU(1) ELSE mn=icsortie-128
		SELECT CASE mn
		CASE 1
			MENU 1,1,2
			MENU 1,2,1
			MENU 1,3,1
			MENU 1,4,1
			GOSUB tblcourbessimples
			efface
			inibox
		CASE 2
			MENU 1,1,1
			MENU 1,2,2
			MENU 1,3,1
			MENU 1,4,1
			GOSUB tblcourbesparametrees
			efface
			inibox
		CASE 3
			MENU 1,1,1
			MENU 1,2,1
			MENU 1,3,2
			MENU 1,4,1
			GOSUB tblcourbespolaires
			efface
			inibox
		CASE 4
			MENU 1,1,1
			MENU 1,2,1
			MENU 1,3,1
			MENU 1,4,2
			GOSUB tblsurfaces
			efface
			inibox
		END SELECT
	ELSEIF icsortie=133 OR (menuselect=2 AND MENU(1)=1) THEN
		disablemenus
		parametres epsilon!,distance,aspect!
		enablemenus
	ELSEIF icsortie=134 OR (menuselect=2 AND MENU(1)=2) THEN
		IF tracelignes THEN
			MENU 2,2,1
			tracelignes=0
		ELSE
			MENU 2,2,2
			tracelignes=-1
		END IF
	ELSEIF icsortie=139 OR (menuselect=2 AND MENU(1)=3) THEN
		disablemenus
		aide
		enablemenus
	END IF
LOOP UNTIL menuselect=1 AND mn=5
WINDOW CLOSE 1
SCREEN CLOSE 1
DATA "Auteur: François Paulhiac, Saint-Avit Sénieur, 24 Novembre 1991."
END


' ========================================================================
' =                     Sous-programmes d'initialisation                 =
' ========================================================================


' Ré-initialise les paramêtres.

scratchtabl:
FOR m=0 TO 7
	valeur$(m)=""
NEXT m
currentopt=0
RETURN


' Rubriques pour les courbes paramêtrées 

tblcourbesparametrees:
RESTORE tblcourbesparametrees_data
FOR n=0 TO 11
	READ option$(n),positionx(n),positiony(n),longueur(n)
NEXT n
GOSUB scratchtabl
valeur$(8)="1" : valeur$(9)="1"
nboptions=11 : premieresortie=10
type=1
screenhigh=183
tblcourbesparametrees_data:
DATA "x=",2,25,52
DATA "y=",2,27,52
DATA "",8,29,10
DATA "<=t<= ",20,29,10
DATA "x min=",2,31,10
DATA "x max=",20,31,10
DATA "y min=",40,29,10
DATA "y max=",58,29,10
DATA "Axe x=",40,31,10
DATA "Axe y=",58,31,10
DATA "Tracer    (F10)",64,25,0
DATA "Superposer (F9)",64,27,0
RETURN


' Initialisations des paramêtres pour les courbes paramétrées

ini_parametrees:
paramerr=-1
x$=valeur$(0) : y$=valeur$(1)
IF x$="" THEN paramerr=0 : erreur=4 : RETURN
IF y$="" THEN paramerr=1 : erreur=4 : RETURN
tmin!=interconst!(valeur$(2))
IF erreur>0 THEN paramerr=2 : RETURN
tmax!=interconst!(valeur$(3))
IF erreur>0 THEN paramerr=3 : RETURN
IF tmax!<=tmin! THEN erreur=11 : paramerr=2 : RETURN
xmin!=interconst!(valeur$(4))
IF erreur>0 THEN paramerr=4 : RETURN
xmax!=interconst!(valeur$(5))
IF erreur>0 THEN paramerr=5 : RETURN
IF xmax!<=xmin! THEN erreur=11 : paramerr=4 : RETURN
ymin!=interconst!(valeur$(6))
IF erreur>0 THEN paramerr=6 : RETURN
ymax!=interconst!(valeur$(7))
IF ymax!<=ymin! THEN erreur=11 : paramerr=6 : RETURN
IF erreur>0 THEN paramerr=7 : RETURN
axex!=interconst!(valeur$(8))
IF axex!<=0 THEN erreur=12 : paramerr=8 : RETURN
IF erreur>0 THEN paramerr=8 : RETURN
axey!=interconst!(valeur$(9))
IF erreur>0 THEN paramerr=9
IF axey!<=0 THEN erreur=12 : paramerr=9
RETURN


' Rubriques pour les courbes polaires 

tblcourbespolaires:
RESTORE tblcourbespolaires_data
FOR n=0 TO 8
	READ option$(n),positionx(n),positiony(n),longueur(n)
NEXT n
type=2
screenhigh=199
GOSUB scratchtabl
valeur$(5)="1" : valeur$(6)="1"
nboptions=8 : premieresortie=7
tblcourbespolaires_data:
DATA "R=",2,27,52
DATA "",8,29,10
DATA "<=t<=",19,29,10
DATA "x max=",2,31,10
DATA "y max=",20,31,10
DATA "Axe X:",38,31,10
DATA "Axe Y:",56,31,10
DATA "Tracer     (F10)",64,27,0
DATA "Superposer  (F9)",64,29,0
RETURN


' Initialisations des paramêtres pour les courbes polaires

ini_polaires:
paramerr=-1
x$=valeur$(0)
IF x$="" THEN erreur=4 : paramerr=0 : RETURN
tmin!=interconst!(valeur$(1))
IF erreur>0 THEN paramerr=2 : RETURN
tmax!=interconst!(valeur$(2))
IF erreur>0 THEN paramerr=1 : RETURN
IF tmax!<=tmin! THEN erreur=11 : paramerr=2 : RETURN
xmax!=interconst!(valeur$(3))
IF erreur>0 THEN paramerr=3 : RETURN
IF xmax!<=0 THEN erreur=12 : paramerr=3 : RETURN
xmin!=-xmax!
ymax!=interconst!(valeur$(4))
IF erreur>0 THEN paramerr=4 : RETURN
IF ymax!<=0 THEN erreur=12 : paramerr=4 : RETURN
ymin!=-ymax!
axex!=interconst!(valeur$(5))
IF erreur>0 THEN paramerr=5 : RETURN
IF axex!<=0 THEN paramerr=5 : erreur=12 : RETURN
axey!=interconst!(valeur$(6))
IF erreur>0 THEN paramerr=6
IF axey!<=0 THEN paramerr=6 : erreur=12
RETURN


' Rubriques pour y=f(x)

tblcourbessimples:
RESTORE tblcourbessimples_data
FOR n=0 TO 8
	READ option$(n),positionx(n),positiony(n),longueur(n)
NEXT n
type=0
screenhigh=199
GOSUB scratchtabl
valeur$(5)="1" : valeur$(6)="1"
nboptions=8 : premieresortie=7
tblcourbessimples_data:
DATA "y=",2,27,52
DATA "x min=",2,29,10
DATA "x max=",20,29,10
DATA "y min=",2,31,10
DATA "y max=",20,31,10
DATA "Axe X:",38,31,10
DATA "Axe Y:",56,31,10
DATA "Tracer    (F10)",64,27,0
DATA "Superposer (F9)",64,29,0
RETURN


' Initialisations des paramêtres pour les courbes simples

ini_courbes:
paramerr=-1
y$=valeur$(0)
IF y$="" THEN paramerr=0 : erreur=4 : RETURN
xmin!=interconst!(valeur$(1))
IF erreur>0 THEN paramerr=1 : RETURN
xmax!=interconst!(valeur$(2))
IF erreur>0 THEN paramerr=2 : RETURN
IF xmax!<=xmin! THEN paramerr=1 : erreur=11 : RETURN
ymin!=interconst!(valeur$(3))
IF erreur>0 THEN paramerr=3 : RETURN
ymax!=interconst!(valeur$(4))
IF erreur>0 THEN paramerr=4 : RETURN
IF ymax!<=ymin! THEN paramerr=3 : erreur=11 : RETURN
axex!=interconst!(valeur$(5))
IF erreur>0 THEN paramerr=5 : RETURN
IF axex!<=0 THEN erreur=12 : paramerr=5 : RETURN
axey!=interconst!(valeur$(6))
IF erreur>0 THEN paramerr=6
IF axey!<=0 THEN erreur=12 : paramerr=6
RETURN


' Rubriques pour surfaces

tblsurfaces:
RESTORE tblsurfaces_data
FOR n=0 TO 12
	READ option$(n),positionx(n),positiony(n),longueur(n)
NEXT n
GOSUB scratchtabl
valeur$(1)="1"
valeur$(8)="30" : valeur$(9)="30"
valeur$(10)="pi/6" : valeur$(11)="pi/3"
type=3
screenhigh=183
nboptions=12 : premieresortie=12
tblsurfaces_data:
DATA "z=",2,25,52
DATA "Correction z=",57,25,10
DATA "x min=",2,27,10
DATA "x max=",20,27,10
DATA "y min=",2,29,10
DATA "y max=",20,29,10
DATA "z min=",2,31,10
DATA "z max=",20,31,10
DATA "divx=",40,27,10
DATA "divy=",40,29,10
DATA "Rotation Z=",57,27,10
DATA "Rotation X=",57,29,10
DATA "Tracer (F10)",68,31,0
RETURN


' Initialisations des paramêtres pour les surfaces

ini_surfaces:
paramerr=-1
z$=valeur$(0)
IF z$="" THEN paramerr=0 : erreur=4 : RETURN
multhauteur!=interconst!(valeur$(1))
IF erreur>0 THEN paramerr=1 : RETURN
xmin!=interconst!(valeur$(2))
IF erreur>0 THEN paramerr=2 : RETURN
xmax!=interconst!(valeur$(3))
IF erreur>0 THEN paramerr=3 : RETURN
IF xmax!<=xmin! THEN erreur=11 : paramerr=2 : RETURN
ymin!=interconst!(valeur$(4))
IF erreur>0 THEN paramerr=4 : RETURN
ymax!=interconst!(valeur$(5))
IF erreur>0 THEN paramerr=5 : RETURN
IF ymax!<=ymin! THEN paramerr=4 : erreur=11 : RETURN
zmin!=interconst!(valeur$(6))
IF erreur>0 THEN paramerr=6 : RETURN
zmax!=interconst!(valeur$(7))
IF erreur>0 THEN paramerr=7 : RETURN
IF zmax!<=zmin! THEN erreur=11 : paramerr=6 : RETURN
divx!=interconst!(valeur$(8))
IF erreur>0 THEN paramerr=8 : RETURN
divx=divx!
IF CSNG(divx)<>divx! OR divx<3 THEN erreur=13 : paramerr=8 : RETURN
divy!=interconst!(valeur$(9))
IF erreur>0 THEN paramerr=9 : RETURN
divy=divy!
IF CSNG(divy)<>divy! OR divy<3 THEN erreur=13 : paramerr=9 : RETURN
az!=interconst!(valeur$(10))
IF erreur>0 THEN paramerr=10 : RETURN
ax!=interconst!(valeur$(11))
IF erreur>0 THEN paramerr=11 : RETURN
inirotation
iniextremums
RETURN

