// Auteur D. Comin, décembre 2007. // Ce fichier est distribué sous licence GNU-GPL, je ne sais pas exactement ce que ça veut dire mais je trouve que ça a de la gueule. import math; import markers; import geometry; import patterns; import labelpath; //définit le type repere struct repere { pair origine ; pair abscisse; pair ordonnee; string originetxt ; string abscissetxt; string ordonneetxt; } //Définitions des constantes unitsize(1cm); real croix; pair basdroit,basgauche,hautdroit,hautgauche; path cadre; croix=0.08; bool mainlevee=false; srand(seconds(time("%a %b %d %H:%M:%S %Z %Y"))); repere canonique; canonique.origine=(0,0); canonique.abscisse=(1,0); canonique.ordonnee=(0,1); canonique.originetxt="$O$"; canonique.abscissetxt="$\vec{i}$"; canonique.ordonneetxt="$\vec{j}$"; repere reperecourant=canonique; //définit les directions pair nord,sud,est,ouest,nouest,nest,souest,sest; nord=(0,1); sud=(0,-1); est=(1,0); ouest=(-1,0); nouest=(-1,1); nest=(1,1); souest=(-1,-1); sest=(1,-1); //defaultpen(); //trace un cadre, invisible par defaut void figure(pair A,pair B, pen p=invisible){ draw(A--(xpart(B),ypart(A))--B--(xpart(A),ypart(B))--cycle,p); basgauche=A; basdroit=(xpart(B),ypart(A)); hautdroit=B; hautgauche=(xpart(A),ypart(B)); cadre=A--(xpart(B),ypart(A))--B--(xpart(A),ypart(B))--cycle; } // nombre aléatoire entre -a et a real eps(){ real x=rand()/randMax; //return a-2*x*a; if(x<=1/6){return 5;}else{ if(x<=1/3){return 6;}else{ if(x<=1/2){return 7;}else{ if(x<=2/3){return -5;}else{ if(x<=5/6){return -6;}else{return -7;}; }; }; }; }; } //trace le point (la croix) placé en A void pointe(pair A,pen sty=currentpen){ draw(A-(croix,croix)--A+(croix,croix),p=sty); draw(A+(-croix,croix)--A+(croix,-croix),p=sty); } //nomme et trace le point (la croix) placé en A //void nomme(picture pic=currentpicture, Label L, pair position,align align=NoAlign, pen p=currentpen, filltype //filltype=NoFill){ //draw(position-(croix,croix)--position+(croix,croix),p); //draw(position+(-croix,croix)--position+(croix,-croix),p); //label(pic, L, position,align,p,filltype); //} void nomme(Label L, pair A,pair direction , pen p=currentpen){ draw(A-(croix,croix)--A+(croix,croix),p); draw(A+(-croix,croix)--A+(croix,-croix),p); label(L, A+0.05*unit(direction),direction,p); } //retourne le point placer à distance cm de A et faisant un angle de angle degre avec l'horizontale pair pointdistant(pair A,real distance, real angle){ pair B ; B=A+distance*dir(angle); return B; } // retourne le point M à l cm de O et tel que angle MOA=a, ds le sens trigo pair point_angle_dist(pair O, pair A, real a, real l){ pair M; M=l*dir(a+degrees(A-O))+O; return M; } //retourne le point placer à a cm de A et b cm de B pair compas(pair A, pair B, real a, real b){ pair C; real c; real angle; c=abs(B-A); angle=(acos((a^2+c^2-b^2)/(2*a*c))+angle(B-A))/pi*180; C=pointdistant(A,a,angle); return C; } //retourne un point sur un chemin avec le paramètre r entre 0 et 1 pair pointsur(path chemin, real r) { return point(chemin,arctime(chemin,r*arclength(chemin))); } //retourne le milieu de [A,B]. pair milieu(pair A, pair B){ return pointsur(A--B,0.5); } //trace une flèche de cotation de A à B à d mm audessus du segment avec le texte au milieu. void cotemilieu(pair A,pair B, string texte, real d,pen sty=black){ draw(Label(texte,align=Center,Rotate(-dir(B--A)),filltype=UnFill),B+d/10*dir(degrees(B-A)+90)--A+d/10*dir(degrees(B-A)+90),Arrows(1.5mm),p=sty); } //place txt le long de AB void etiquette(pair A, pair B, string txt,bool dessus=true,pen sty=currentpen){ if (dessus==true){ label(rotate(degrees(B-A))*txt,0.5*B+0.5*A,dir(degrees(B-A)+90),sty); } else { label(rotate(degrees(B-A))*txt,0.5*B+0.5*A,dir(degrees(B-A)-90),sty); } } //trace une flèche de cotation de A à B à d mm audessus du segment avec le texte au dessus. void cote(pair A,pair B, string texte, real d,pen sty=black){ draw(Label(texte,Rotate(-dir(B--A))),B+d/10*dir(degrees(B-A)+90)--A+d/10*dir(degrees(B-A)+90),Arrows(1.5mm),p=sty); } //remplis avec des hachures espacées de espace mm, avec un angle de angle ° le chemin fermé p void hachurage(path p,real espace, real angle, pen pen=currentpen){ add("hachure",hatch(espace,dir(angle),pen)); fill(p,pattern("hachure")); } //code les segments définis par le tableau pair[] K={A,B,C,...} avec trait traits void code(pen sty=invisible,int trait ... pair[] K){ if(trait < 4) { for(int i=0; i <=(K.length-2); i=i+2) { draw(K[i]--K[i+1],sty,StickIntervalMarker(1,n=trait,angle=-30,size=3mm,space=1mm));} }else {if(trait ==4) { for(int i=0; i <=(K.length-2); i=i+2) { draw(K[i]--K[i+1],sty,TildeIntervalMarker(i=1,size=3mm));} }else {for(int i=0; i <=(K.length-2); i=i+2) {draw(K[i]--K[i+1],sty,CircleBarIntervalMarker(1,n=0));} } } if(trait==6){ for(int i=0; i <=(K.length-2); i=i+2) { draw(K[i]--K[i+1],sty,CrossIntervalMarker(1,4));}} } //code le milieu du segment [A,B] void codemilieu(pen sty=invisible,pair A, pair B, int trait){ if(trait < 4) { draw(A--milieu(A,B),sty,StickIntervalMarker(1,n=trait,angle=-30,size=3mm,space=1mm)); draw(milieu(A,B)--B,sty,StickIntervalMarker(1,n=trait,angle=-30,size=3mm,space=1mm)); } else {if(trait ==4) { draw(A--milieu(A,B),sty,TildeIntervalMarker(i=1,size=3mm)); draw(milieu(A,B)--B,sty,TildeIntervalMarker(i=1,size=3mm)); }else { draw(A--milieu(A,B),sty,CircleBarIntervalMarker(1,n=0)); draw(milieu(A,B)--B,sty,CircleBarIntervalMarker(1,n=0)); } } } //code les angles avec des traits et un nombre nbarc d'arcs void codeangle(pair A,pair B, pair C,string txt="", int trait,int nbarc=1,pen sty=currentpen,real rayon=10mm ){ markangle(txt,n=nbarc,A,B,C,radius=rayon,marker(markinterval(stickframe(n=trait,p=sty),true)),p=sty); } //code les angles droits void angledroit(pair A,pair B, pair C,real taille=0.3, pen p=black){ pair u,v; u=unit(C-B); v=unit(A-B); draw(B+taille*v--B+taille*(u+v)--B+taille*u,p); } //trace des droites graduées pour les inéquations void inequation(string txt="", real valeur, real crochet, real zone,pen pen=currentpen){ real h; h=0.1; draw(0.5*(basgauche+hautgauche)--0.5*(basdroit+hautdroit),Arrow(2mm)); draw((0,-h)--(0,h),linewidth(1.2bp)); label("0",(0,-h),S); draw((1,-h)--(1,h),linewidth(1.2bp)); label("1",(1,-h),S); label(txt,(valeur,-h-0.2),S); draw((valeur+crochet*0.2,0.3)--(valeur,0.3)--(valeur,-0.3)--(valeur+crochet*0.2,-0.3),linewidth(2bp)); add("hachure",hatch(1.5mm,NE,black)); if(zone==-1){ fill(0.5*(basgauche+hautgauche)+(0,0.2)--valeur+(0,0.2)--valeur+(0,-0.2)--0.5*(basgauche+hautgauche)+(0,-0.2)--cycle,pattern("hachure")); } else { fill(0.5*(basdroit+hautdroit)+(0,0.2)--valeur+(0,0.2)--valeur+(0,-0.2)--0.5*(basdroit+hautdroit)+(0,-0.2)--cycle,pattern("hachure")); } } // renvoie des segments dans le style "à main levée" path segmentML(pair A, pair B,real a=0){ real alpha,beta; pair M,N; M=A+(B-A)/3; N=A+(B-A)*2/3; //alpha=6*sin(degrees(A-B))-3; alpha=eps(); beta=eps(); //beta=6*sin(length(A--B)*50)-3; return a*unit(A-B)+A..A{dir(degrees(B-A)+alpha)}..{dir(degrees(M-A)+eps())}M{dir(degrees(M-A)+eps())}..{dir(degrees(N-M)+eps())}N{dir(degrees(N-M)+eps())}..{dir(degrees(B-N)+beta)}B..a*unit(B-A)+B; } //retourne le segment [AB] qui peut dépasser de a cm path segment(pair A, pair B,real a=0){ path segment; if (mainlevee==false){segment=a*unit(A-B)+A--B+a*unit(B-A);} else {segment=segmentML(A,B,a);}; return segment; } //renvoie un polygone définit par une matrice pair[] path polygone(... pair[] K){ path p; K.push(K[0]); for(int i=0;i0){ draw(dte[0]--dte[1],sty,Arrow(1.5mm));} else { draw(dte[1]--dte[0],sty,Arrow(1.5mm)); } ////////////////////////// tracer des graduations pair n=unit(dir(degrees(B-A)+90))*epaisseur; for(int i=0;inside(cadre,rep.origine+i*rep.abscisse);i=i+1) draw(rep.origine+i*rep.abscisse+n--rep.origine+i*rep.abscisse-n,sty); for(int i=-1;inside(cadre,rep.origine+i*rep.abscisse);i=i-1) draw(rep.origine+i*rep.abscisse+n--rep.origine+i*rep.abscisse-n,sty); if(graduation==2){ for(int i=0;inside(cadre,rep.origine+0.5*i*rep.abscisse);i=i+1) draw(rep.origine+0.5*i*rep.abscisse+n/2--rep.origine+0.5*i*rep.abscisse-n/2,sty); for(int i=-1;inside(cadre,rep.origine+0.5*i*rep.abscisse);i=i-1) draw(rep.origine+0.5*i*rep.abscisse+n/2--rep.origine+0.5*i*rep.abscisse-n/2,sty); } else { if(graduation==3){ for(int i=0;inside(cadre,rep.origine+0.1*i*rep.abscisse);i=i+1) draw(rep.origine+0.1*i*rep.abscisse+n/2--rep.origine+0.1*i*rep.abscisse-n/2,sty); for(int i=-1;inside(cadre,rep.origine+0.1*i*rep.abscisse);i=i-1) draw(rep.origine+0.1*i*rep.abscisse+n/2--rep.origine+0.1*i*rep.abscisse-n/2,sty); } } /////////////// trace l'axe des ordonnées A=rep.origine; B=rep.origine+rep.ordonnee; if(xpart(A)==xpart(B)){ s=(ypart(hautgauche)-ypart(B))/(ypart(A)-ypart(B)); u=(ypart(basgauche)-ypart(B))/(ypart(A)-ypart(B)); } else{ s=(xpart(basdroit)-xpart(B))/(xpart(A)-xpart(B)); u=(xpart(basgauche)-xpart(B))/(xpart(A)-xpart(B)); } ligne=s*A+(1-s)*B--u*A+(1-u)*B; dte=intersectionpoints(ligne,cadre); if((ypart(dte[1])-ypart(dte[0]))*(ypart(B)-ypart(A))>0){ draw(dte[0]--dte[1],sty,Arrow(1.5mm));} else { draw(dte[1]--dte[0],sty,Arrow(1.5mm)); } ////////////////////////// tracer des graduations pair n=unit(dir(degrees(B-A)+90))*epaisseur; for(int i=0;inside(cadre,rep.origine+i*rep.ordonnee);i=i+1) draw(rep.origine+i*rep.ordonnee+n--rep.origine+i*rep.ordonnee-n,sty); for(int i=-1;inside(cadre,rep.origine+i*rep.ordonnee);i=i-1) draw(rep.origine+i*rep.ordonnee+n--rep.origine+i*rep.ordonnee-n,sty); if(graduation==2){ for(int i=0;inside(cadre,rep.origine+0.5*i*rep.ordonnee);i=i+1) draw(rep.origine+0.5*i*rep.ordonnee+n/2--rep.origine+0.5*i*rep.ordonnee-n/2,sty); for(int i=-1;inside(cadre,rep.origine+0.5*i*rep.ordonnee);i=i-1) draw(rep.origine+0.5*i*rep.ordonnee+n/2--rep.origine+0.5*i*rep.ordonnee-n/2,sty); } else { if(graduation==3){ for(int i=0;inside(cadre,rep.origine+0.1*i*rep.ordonnee);i=i+1) draw(rep.origine+0.1*i*rep.ordonnee+n/2--rep.origine+0.1*i*rep.ordonnee-n/2,sty); for(int i=-1;inside(cadre,rep.origine+0.1*i*rep.ordonnee);i=i-1) draw(rep.origine+0.1*i*rep.ordonnee+n/2--rep.origine+0.1*i*rep.ordonnee-n/2,sty); } } ////////////////////////// tracer du nom de l'origine label(rep.originetxt,rep.origine,-rep.abscisse-rep.ordonnee); } //trace un repère avec les vecteurs de base; void base(repere rep,bool vecteur=true,pen sty=currentpen){ draw(rep.origine--rep.origine+rep.abscisse,sty+1.2,Arrow(1.5mm)); draw(rep.origine--rep.origine+rep.ordonnee,sty+1.2,Arrow(1.5mm)); if (vecteur==true){ label(rep.abscissetxt,rep.origine+0.5*rep.abscisse,-rep.ordonnee); label(rep.ordonneetxt,rep.origine+0.5*rep.ordonnee,-rep.abscisse); } } // définit et place un pair avec les coordonnées (x;y) dans le repère rep pair place(string nom,real x, real y,pair direction, repere rep=reperecourant, bool trait=false, pen sty=currentpen){ real epaisseur=croix; pair n=unit(rep.ordonnee)*epaisseur; pair m=unit(rep.abscisse)*epaisseur; label(nom,x*rep.abscisse+y*rep.ordonnee+rep.origine,direction,sty); pair P=x*rep.abscisse+y*rep.ordonnee+rep.origine; draw(P+n--P-n,sty); draw(P+m--P-m,sty); if (trait==true){ draw(P--(rep.origine+y*rep.ordonnee),linewidth(0.3)+sty+dashed); draw(P--(rep.origine+x*rep.abscisse),linewidth(0.3)+sty+dashed); } return P; } // définit un pair avec les coordonnées (x;y) dans le repère rep pair position(real x, real y,repere rep=reperecourant){ pair P; if(inside(cadre,x*rep.abscisse+y*rep.ordonnee+rep.origine)){ P=x*rep.abscisse+y*rep.ordonnee+rep.origine;} else {P=rep.origine;} return P; } //trace des fonctions ... void tracefonction (real f(real),real a, real b,repere rep=reperecourant,int precision=500 ,pen sty=currentpen+linewidth(0.5)){ int n=precision; real x (int i) {return a+i*(b-a)/n;} for(int i=0;i<=n;i=i+1){ if(inside(cadre,x(i)*rep.abscisse+f(x(i))*rep.ordonnee+rep.origine)&(inside(cadre,x(i+1)*rep.abscisse+f(x(i+1))*rep.ordonnee+rep.origine))) { draw(x(i)*rep.abscisse+f(x(i))*rep.ordonnee+rep.origine--x(i+1)*rep.abscisse+f(x(i+1))*rep.ordonnee+rep.origine,sty);}} } //trace des courbes paramètrées ... void tracepara (real f(real),real g(real),real a, real b,repere rep=reperecourant,int precision=500 ,pen sty=currentpen+linewidth(0.5)){ int n=precision; real t (int i) {return a+i*(b-a)/n;} for(int i=0;i<=n;i=i+1){ if(inside(cadre,f(t(i))*rep.abscisse+g(t(i))*rep.ordonnee+rep.origine)&(inside(cadre,f(t(i+1))*rep.abscisse+g(t(i+1))*rep.ordonnee+rep.origine))) { draw(f(t(i))*rep.abscisse+g(t(i))*rep.ordonnee+rep.origine--f(t(i+1))*rep.abscisse+g(t(i+1))*rep.ordonnee+rep.origine,sty);}} } //trace des courbes polaires ... void tracepolaire (real r(real),real a, real b,repere rep=reperecourant,int precision=500 ,pen sty=currentpen+linewidth(0.5)){ int n=precision; real f(real t){return r(t)*cos(t);} real g(real t){return r(t)*sin(t);} tracepara(f,g,a,b,rep,n,sty); } //trace la tangente en a à f path tangente(real a, real f(real), real h=0.01, repere rep=reperecourant){ real m=(f(a+h)-f(a-h))/(2*h); //le nombre dérivé return droite(position(a,f(a),rep),position(a,f(a),rep)+(1,m)); } //renvoie un morceau de courbe si tout le tracé est contenu dans le cadre ... path morceau (real f(real),real a, real b,repere rep=reperecourant,int precision=500){ int n=precision; path C; real x (int i) {return a+i*(b-a)/n;} for(int i=0;i<=n;i=i+1){ if(inside(cadre,x(i)*rep.abscisse+f(x(i))*rep.ordonnee+rep.origine)) { C=C..x(i)*rep.abscisse+f(x(i))*rep.ordonnee+rep.origine;} else {C=nullpath;}} return C; } // renvoie le triangle ABC path triangle(pair A, pair B, pair C){ path tABC; //if (mainlevee==false){ //tABC=A--B--C--cycle; } else { //tABC=A{dir(degrees(B-A)+a)}..{dir(degrees(B-A)+b)}B{dir(degrees(C-B)+c)}..{dir(degrees(C-B)+d)}C{dir(degrees(A-C)+e)}..{dir(degrees(A-C)+f)}A--cycle; tABC=polygone(A,B,C); //}; return tABC; } // // renvoie un path, le triangle dont les côtés sont a b et c en cm. path triangle3c(pair A, real a, real b, real c, bool dessus=true,real angle=0){ pair B, C,C1; B=pointdistant(A,c,angle); C1=compas(A,B,b,a); if (dessus==false){C=reflect(A,B)*C1;} else{C=C1;}; return triangle(A,B,C);} // renvoie un path, le triangle de côté c en cm.et d'angles adjacents alpha et beta path triangle1c(pair A, real c, real alpha, real beta, bool dessus=true,real angle=0){ pair B, C,C1; B=pointdistant(A,c,angle); C1=extension(A, point_angle_dist(A,B,alpha,1), B, point_angle_dist(B,A,-beta,1)); if (dessus==false){C=reflect(A,B)*C1;} else{C=C1;}; return triangle(A,B,C);} // renvoie un path, le triangle de côtés adjacents c et b en cm.et formant un angle alpha path triangle2c(pair A, real c, real b, real alpha, bool dessus=true,real angle=0){ pair B, C,C1; B=pointdistant(A,c,angle); C1=point_angle_dist(A,B,alpha,b); if (dessus==false){C=reflect(A,B)*C1;} else{C=C1;}; return triangle(A,B,C);} // renvoie un path, le rectangle de côtés adjacents a et b en cm. Si diagonale=true, b est la diagonale. path rectangle(pair A, real a, real b,bool diagonale=false,real angle=0){ pair B,C,D,E; B=pointdistant(A,a,angle); if(diagonale==false){D=point_angle_dist(A,B,90,b); C=B-A+D;} else {C=point_angle_dist(A,B,aCos(a/b),b); D=C+A-B;}; return polygone(A,B,C,D);} // renvoie un path, le parallelogramme de côtés adjacents a et b en cm formant un angle alpha. //Si diagonale vaut true, alpha est la diagonale en cm. path parallelogramme(pair A, real a, real b,real alpha, bool diagonale=false,real angle=0){ pair B,C,D,E; B=pointdistant(A,a,angle); if(diagonale==false){D=point_angle_dist(A,B,alpha,b); C=B-A+D;} else {C=compas(A,B,alpha,b); D=C+A-B;}; return polygone(A,B,C,D);} //renvoie un sommet d'un triangle ou un quadrilatère pair sommet(path c,int n){ int p; if(mainlevee==true){ if(n==0){p=0;} else{p=6*n-2;}; } else { if(n==0){p=0;} else{p=2*n-1;}; }; return point(c,p); } //les valeurs début et fin en multiple du vecteur unité, intermediaire en fraction du vecteur unité void graduation(pair origine, pair unite, real debut, real fin, string originetxt="$O$", string unitetxt="1", real intermediaire=0,pen sty=currentpen){ pair A,B; A=origine+unite*debut; B=origine+unite*fin; draw(A--B,sty,Arrow(2mm)); for (int i=ceil(debut);i<=floor(fin);i=i+1){ draw(origine+i*unite+0.1*dir(degrees(unite)-90)--origine+i*unite-0.1*dir(degrees(unite)-90));} if (intermediaire != 0){ for (int i=ceil(debut/intermediaire);i<=floor(fin/intermediaire);i=i+1){ draw(origine+i*unite*intermediaire+0.05*dir(degrees(unite)-90)--origine+i*unite*intermediaire-0.05*dir(degrees(unite)-90));} } label(originetxt,origine+0.1*dir(degrees(unite)-90),dir(degrees(unite)-90)); label(unitetxt,origine+unite+0.1*dir(degrees(unite)-90),dir(degrees(unite)-90)); }; //renvoie un pair qui correspond à une abscisse particulière sur un axe void abscisse(string txtdessous, string txtdessus="",pair origine, pair unite,real x,bool croix=false,pen sty=currentpen){ label(txtdessous,origine+x*unite+0.1*dir(degrees(unite)-90),dir(degrees(unite)-90),sty); label(txtdessus,origine+x*unite-0.1*dir(degrees(unite)-90),dir(degrees(unite)+90),sty); if (croix==true){pointe(origine+x*unite,sty);}; };