![]() |
/* About the used algorithms look at: http://cgafaq.info/wiki/Simple_Polygon_Orientation */ size(8cm, false); real signedArea(pair [] pt) { // Return the signed area of a simple (NON CROSSED) polygon of vertex "pt" // Retourne l'aire algébrique d'un polygone NON CROIÉ pair [] pt_= copy(pt); real n=pt.length, sa=0; pt_.push(pt_[0]); pt_.push(pt_[1]); for (int i=1; i<=n; ++i) sa +=pt_[i].x * (pt_[i+1].y - pt_[i-1].y); return sa/2; } bool counterclockwise(pair [] pt) { // Return "true" if the polygon (SIMPLE CURVE i.e. NON CROSSED) // of vertex "pt" is counterclockwise // Retourne "true" si le polygone (NON CROISÉ) de sommets "pt" // est dans le sens des aiguilles d'une montre return (signedArea(pt) > 0); } pair [] reverse(pair [] pt) { pair [] pt_=copy(pt); int begin=0, end=pt.length-1; while (begin<end) { pair temp=pt_[begin]; pt_[begin]=pt_[end]; pt_[end]=temp; ++begin; --end; } return pt_; } pair [] counterclockdirected(pair [] pt) { if (counterclockwise(pt)) return pt; else return reverse(pt); } path polygon(pair [] pt) { int l=pt.length; guide opath; for (int i=0; i<l; ++i) { opath = opath--pt[i]; } return opath; } pair [] pg = {(0,0), (1,0), (1,1), (2,2), (-1,1)}; draw(polygon(pg)--cycle, Arrow(Relative(.1)), BeginBar); draw(polygon(counterclockdirected(reverse(pg)))--cycle, Arrow(position=Relative(.2), FillDraw(red)), BeginBar);
![]() |
size(6cm); bool counterclockwise(path g, int n=10^3) { // Return "true" if "g" (SIMPLE CURVE i.e. NON CROSSED) is counterclockwise // Retounre "true" si "g" (NON CROISÉ) est dans le sens contraire des aiguilles d'une montre if (!cyclic(g) || length(g)==0) abort("The function 'clocksize' needs cyclic path."); pair [] pt; real l=length(g), step=1/n, t=0, sa=0; do { sa +=point(g,t).x * (point(g,t+step).y - point(g,t-step).y); t+=step; } while (t<l); return (sgn(sa) > 0); } path counterclockdirected(path g,int n=10^3) { // Return "g" (SIMPLE CURVE i.e. NON CROSSED) counterclockwise // Retourne "g" (NON CROISÉ) dans le sens des aiguilles d'une montre if (counterclockwise(g,n)) return g; else return reverse(g); } path p=unitcircle; draw(counterclockdirected(reverse(p)), Arrow(Relative(.1)), BeginBar); draw(counterclockdirected(p), Arrow(position=Relative(.2),FillDraw(red)), BeginBar);
![]() |
/* Explanations are here: http://mathworld.wolfram.com/ContourWindingNumber.html */ size(6cm,0, false); bool counterclockwise(path g, pair z) {return windingnumber(g,z) > 0;} path counterclockdirected(path g,pair z) { if (counterclockwise(g,z)) return g; else return reverse(g); } pair z=(1,0); dot(z); path p=(0,0){N}..(4,0){N}..cycle; draw(counterclockdirected(reverse(p),z),Arrow(Relative(.1)), BeginBar); draw(counterclockdirected(p,z),Arrow(position=Relative(.2),FillDraw(red)), BeginBar); pair z=(3,-2); dot(z); path p=(4,-2){N}..(0,-2){N}..cycle; draw(counterclockdirected(reverse(p),z),Arrow(Relative(.1)), BeginBar); draw(counterclockdirected(p,z),Arrow(position=Relative(.2),FillDraw(red)), BeginBar); pair z=(1,-4.5); dot(z); path p=yscale(.75)*((0,-6){N}..(2,-6){S}..(0,-6){N}..(4,-6){S}..cycle); draw(counterclockdirected(reverse(p),z),Arrow(Relative(.1)), BeginBar); draw(counterclockdirected(p,z),Arrow(position=Relative(.2),FillDraw(red)), BeginBar); pair z=(3,-8); dot(z); path p=shift((0,-3.5))*p; draw(counterclockdirected(reverse(p),z),Arrow(Relative(.1)), BeginBar); draw(counterclockdirected(p,z),Arrow(position=Relative(.2),FillDraw(red)), BeginBar);
![]() |
// Use of the windingnumber for simple curves (NON CROSSED) // The most fast and robust with Asymptote. // Utilisation du nombre d'enroulement pour des courbes NON CROISÉES // Le plus rapide et robuste avec Asymptote. size(6cm,0, false); import math; import roundedpath; bool counterclockwise(path g) { // Return "true" if "g" (SIMPLE CURVE i.e. NON CROSSED) is counterclockwise // Retounre "true" si "g" (NON CROISÉ) est dans le sens contraire des aiguilles d'une montre return windingnumber(g,inside(g)) > 0; } path counterclockdirected(path g) { if (counterclockwise(g)) return g; else return reverse(g); } path p = (0,1)..(.8,1)..(.8,.6)..(.4,.6)..(.4,.2)..(.8,.2)..(.8,-.2)..(.4,-.2)..(.4,-.6)..(.8,-.6)..(.8,-1)..(0,-1)..cycle; draw(counterclockdirected(reverse(p)), Arrow(Relative(.1)), BeginBar); draw(counterclockdirected(p), Arrow(position=Relative(.2),FillDraw(red)), BeginBar);
![]() |
size(8cm,10cm,false); import math; bool counterclockwise(path g) { // Return "true" if "g" (SIMPLE CURVE i.e. NON CROSSED) is counterclockwise // Retounre "true" si "g" (NON CROISÉ) est dans le sens contraire des aiguilles d'une montre return (windingnumber(g,inside(g)) > 0); } path counterclockdirected(path g) { if (counterclockwise(g)) return g; else return reverse(g); } guide randompath(int pt, real u=1) { guide rpath; pair ptl; for(int i=1; i<=pt; ++i) { pair ptt=ptl+u*(rand()/randMax-0.5,rand()/randMax-0.5); rpath=rpath..ptt; ptl=ptt; } return rpath; } guide p=randompath(50,4)..cycle; draw(counterclockdirected(reverse(p)),Arrow(Relative(0.005)), BeginBar); draw(counterclockdirected(p),Arrow(position=Relative(.005),FillDraw(red)), BeginBar); label("Attention - Caution",(xpart(.5(max(p)+min(p))),ypart(min(p))));
Dernière modification/Last modified: lun avr 2 13:26:07 CEST 2007
Philippe Ivaldi