Institut de Robòtica i Informàtica Industrial
KRD Group

The CuikSuite Project

interval.c

Go to the documentation of this file.
00001 #include "interval.h"
00002 
00003 #include "error.h"
00004 #include "defines.h"
00005 #include "geom.h"
00006 
00007 #include <math.h>
00008 
00026 double NormalizeAngle(double a);
00027 
00028 /*
00029  * moves the angle 'a' but in the interval [0,2pi]
00030  */
00031 double NormalizeAngle(double a)
00032 {
00033   double new_a;
00034 
00035   new_a=a;
00036   if ((new_a>M_PI)||(new_a<-M_PI))
00037     new_a=atan2(sin(new_a),cos(new_a));
00038 
00039   if (new_a<0.0) new_a+=M_2PI;
00040 
00041   return(new_a);
00042 }
00043 
00044 /*
00045  * Defines a new interval with limits: lower and upper
00046  */
00047 void NewInterval(double lower,      /*lower limit of the new interval*/
00048                  double upper,      /*upper limit of the new interval*/
00049                  Tinterval *i       /*new interval*/
00050                  )
00051 {
00052   i->lower_limit=lower;
00053   i->upper_limit=upper;
00054 }
00055 
00056 /*
00057  * Copies i_org into i_dst.
00058  */
00059 void CopyInterval(Tinterval *i_dst,Tinterval *i_org)
00060 {
00061   i_dst->lower_limit=i_org->lower_limit;
00062   i_dst->upper_limit=i_org->upper_limit;
00063 }
00064 
00065 
00066 
00067 /*
00068  * Returns true if i1 and i2 are exactly the same.
00069  * This only works for intervals that are exactly the same (copies, the same
00070  * initialization,....)
00071  */
00072 boolean CmpIntervals(Tinterval *i1,Tinterval *i2)
00073 {
00074   return((i1->lower_limit==i2->lower_limit)&&
00075          (i1->upper_limit==i2->upper_limit));
00076 }
00077 
00078 /*
00079  * Returns the lower limit of interval 'i'.
00080  */
00081 double LowerLimit(Tinterval *i)
00082 {
00083   return(i->lower_limit);
00084 }
00085 
00086 /*
00087  * Returns the upper limit of interval 'i'.
00088  */
00089 double UpperLimit(Tinterval *i)
00090 {
00091   return(i->upper_limit);
00092 }
00093 
00094 /*
00095  * Returns the size of interval 'i'.
00096  * NOTE: For empty intervals it can return a negative size
00097  */
00098 double IntervalSize(Tinterval *i)
00099 {
00100   double s;
00101 
00102   ROUNDUP;
00103   s=i->upper_limit-i->lower_limit;
00104   ROUNDNEAR;
00105   
00106   return(s);
00107 }
00108 
00109 /*
00110  * Returns the center of the interval
00111  */
00112 double IntervalCenter(Tinterval *i)
00113 {
00114   double c;
00115 
00116   if (i->upper_limit==i->lower_limit)
00117     c=i->upper_limit;
00118   else
00119     { 
00120       if ((i->lower_limit==-INF)&&(i->upper_limit==INF))
00121         c=0.0;
00122       else
00123         {
00124           c=(i->upper_limit+i->lower_limit)/2.0;
00125       
00126           /* Conditions below can occur because of roundings */
00127           if (c<i->lower_limit) c=i->lower_limit;
00128           if (c>i->upper_limit) c=i->upper_limit;
00129         }
00130     }
00131   return(c);
00132 }
00133 
00134 void SetLowerLimit(double v,Tinterval *i)
00135 {
00136   i->lower_limit=v;
00137 }
00138 
00139 void SetUpperLimit(double v,Tinterval *i)
00140 {
00141   i->upper_limit=v;
00142 }
00143 
00144 /*
00145  * Returns TRUE if i1 is fully included in i2
00146  */
00147 boolean IntervalInclusion(Tinterval *i1,Tinterval *i2)
00148 {
00149   return((i2->lower_limit<i1->lower_limit)&&(i1->upper_limit<i2->upper_limit));
00150 }
00151 
00152 /*
00153  * Returns TRUE if intervals 'i1' and 'i2' actually intersect.
00154  * NOTE: This rutine is only valid for intervals where lower_limit<upper_limit
00155  * and thus it fails in the intersection between certain rotational intervals.
00156  */
00157 boolean Intersect(Tinterval *i1,Tinterval *i2)
00158 {
00159   Tinterval i3;
00160 
00161   return(Intersection(i1,i2,&i3));
00162 }
00163 
00164 /*
00165  * Returns in 'i_out' the intersection of intervals 'i1' and 'i2'.
00166  * NOTE: This rutine is only valid for intervals where lower_limit<upper_limit
00167  * and thus it can fail for intersection between certain rotational intervals.
00168  * RETURNS true if the intersection is NOT EMPTY
00169  */
00170 boolean Intersection(Tinterval *i1,Tinterval *i2,Tinterval *i_out)
00171 {
00172   i_out->lower_limit=(i1->lower_limit>i2->lower_limit?i1->lower_limit:i2->lower_limit);
00173   i_out->upper_limit=(i1->upper_limit<i2->upper_limit?i1->upper_limit:i2->upper_limit);
00174   
00175   return(i_out->lower_limit<=i_out->upper_limit);
00176 }
00177 
00178 /*
00179  * Returns in i_out the union of i1 and i2
00180  * Returns false if the the input intervals are empty
00181 */
00182 boolean Union(Tinterval *i1,Tinterval *i2,Tinterval *i_out)
00183 { 
00184   boolean full;
00185 
00186   full=TRUE;
00187 
00188   if (i1->lower_limit>i1->upper_limit) /*i1 empty*/
00189     {
00190       if (i2->lower_limit>i2->upper_limit)/*i2 empty*/
00191         full=FALSE;
00192       else
00193         {
00194           i_out->lower_limit=i2->lower_limit;
00195           i_out->upper_limit=i2->upper_limit;
00196         }
00197     }
00198   else
00199     {
00200       if (i2->lower_limit>i2->upper_limit) /*i2 empty*/
00201         {
00202           i_out->lower_limit=i1->lower_limit;
00203           i_out->upper_limit=i1->upper_limit;
00204         }
00205       else
00206         {  
00207           i_out->lower_limit=(i1->lower_limit<i2->lower_limit?i1->lower_limit:i2->lower_limit);
00208           i_out->upper_limit=(i1->upper_limit>i2->upper_limit?i1->upper_limit:i2->upper_limit);
00209         }
00210     }
00211   return(full);
00212 }
00213 
00214 
00215 /*
00216  * Returns TRUE if interval 'i' is empty
00217  * NOTE: This rutine is only valid for intervals where lower_limit<upper_limit
00218  * and thus it can return wrong results for certain rotational intervals.
00219  */
00220 boolean EmptyInterval(Tinterval *i)
00221 {
00222   return(i->lower_limit>i->upper_limit);
00223 }
00224 
00225 /*
00226  * returns true if p is inside the interval i
00227  */ 
00228 boolean IsInside(double p,Tinterval *i)
00229 {
00230   return((p>=i->lower_limit)&&(p<=i->upper_limit));
00231 }
00232 
00233 /*
00234  * Products and interval and a scalar
00235  * Be carefull i_out can be i1 or i2!!!!!
00236  */
00237 void IntervalScale(Tinterval *i1,double e,Tinterval *i_out)
00238 {
00239   double e1,e2;
00240       
00241   if (e>0)
00242     {
00243       /*The sign is preserved: extremes are keept */
00244       ROUNDDOWN;
00245       e1=i1->lower_limit*e;
00246       
00247       ROUNDUP; 
00248       e2=i1->upper_limit*e;
00249     }
00250   else
00251     {
00252       /*The sign is changed: extremes are swap */
00253       ROUNDDOWN;
00254       e1=i1->upper_limit*e;
00255       
00256       ROUNDUP; 
00257       e2=i1->lower_limit*e;
00258     }
00259   ROUNDNEAR;
00260 
00261   i_out->lower_limit=e1;
00262   i_out->upper_limit=e2;
00263 }
00264 
00265 /*
00266  * Product of two intervals
00267  * Be carefull i_out can be i1 or i2!!!!!
00268  */
00269 void IntervalProduct(Tinterval *i1,Tinterval *i2,Tinterval *i_out)
00270 {
00271   double e[3];
00272   unsigned int i;
00273   double a,b;
00274 
00275   ROUNDDOWN;
00276   e[0]=i1->lower_limit*i2->upper_limit;
00277   e[1]=i1->upper_limit*i2->lower_limit;
00278   e[2]=i1->upper_limit*i2->upper_limit;
00279 
00280   a=i1->lower_limit*i2->lower_limit;
00281   for(i=0;i<3;i++)
00282     if (e[i]<a) a=e[i];
00283 
00284   ROUNDUP; 
00285   e[0]=i1->lower_limit*i2->upper_limit;
00286   e[1]=i1->upper_limit*i2->lower_limit;
00287   e[2]=i1->upper_limit*i2->upper_limit;
00288 
00289   b=i1->lower_limit*i2->lower_limit;
00290   for(i=0;i<3;i++)
00291     if (e[i]>b) b=e[i];
00292    
00293   ROUNDNEAR;
00294 
00295   i_out->lower_limit=a;
00296   i_out->upper_limit=b;
00297 }
00298 
00299 /*
00300  * Additon of two intervals
00301  * Be carefull i_out can be i1 or i2!!!!!
00302  */
00303 void IntervalAdd(Tinterval *i1,Tinterval *i2,Tinterval *i_out)
00304 {
00305   double a,b;
00306 
00307   ROUNDDOWN;
00308   a=i1->lower_limit+i2->lower_limit;
00309          
00310   ROUNDUP;
00311   b=i1->upper_limit+i2->upper_limit;
00312 
00313   ROUNDNEAR;
00314 
00315   i_out->lower_limit=a;
00316   i_out->upper_limit=b;
00317 }
00318 
00319 /*
00320  * i_out=i1-i2;
00321  */
00322 void IntervalSubstract(Tinterval *i1,Tinterval *i2,Tinterval *i_out)
00323 { 
00324   double a,b;
00325 
00326   ROUNDDOWN;
00327   a=i1->lower_limit-i2->upper_limit;
00328   
00329   ROUNDUP;
00330   b=i1->upper_limit-i2->lower_limit;
00331 
00332   ROUNDNEAR;
00333 
00334   i_out->lower_limit=a;
00335   i_out->upper_limit=b;
00336 }
00337 
00338 /*
00339  * Changes the sign of a given interval
00340  */
00341 void IntervalInvert(Tinterval *i,Tinterval *i_out)
00342 {  
00343   double a,b;
00344   
00345   a=-i->upper_limit;
00346   b=-i->lower_limit;
00347 
00348   i_out->lower_limit=a;
00349   i_out->upper_limit=b;
00350 }
00351 
00352 void IntervalPow(Tinterval *i,unsigned int p,Tinterval *i_out)
00353 {
00354   double a,b,e1,e2;
00355 
00356   ROUNDDOWN;
00357   e1=pow(i->lower_limit,(double)p);
00358   e2=pow(i->upper_limit,(double)p);
00359 
00360   if (e1<e2)
00361     a=e1;
00362   else
00363     a=e2;
00364  
00365   ROUNDUP;
00366   e1=pow(i->lower_limit,(double)p);
00367   e2=pow(i->upper_limit,(double)p);
00368 
00369   if (e1>e2)
00370     b=e1;
00371   else
00372     b=e2;
00373 
00374   ROUNDNEAR;
00375 
00376   if (((p%2)==0)&&(IsInside(0,i)))
00377     a=0;  /*x^p with p=2*n always have a minimum at 0  (if included in the input interval)*/
00378 
00379   i_out->lower_limit=a;
00380   i_out->upper_limit=b;
00381 }
00382 
00383 /*
00384  * Square root 
00385  */
00386 boolean IntervalSqrt(Tinterval *i,Tinterval *i_out)
00387 {
00388   double a,b;
00389 
00390   if (i->upper_limit<0.0)
00391     return(FALSE);
00392 
00393   ROUNDDOWN;
00394   if (i->lower_limit<=0.0)
00395     a=0.0;
00396   else
00397     a=sqrt(i->lower_limit);
00398 
00399   ROUNDUP;
00400   b=sqrt(i->upper_limit);
00401 
00402   ROUNDNEAR;
00403   
00404   i_out->lower_limit=a;
00405   i_out->upper_limit=b;
00406 
00407   return(TRUE);
00408 }
00409 
00410 /*
00411 */
00412 void IntervalDivision(Tinterval *i1,Tinterval *i2,Tinterval *i_out)
00413 {
00414   double e[3];
00415   unsigned int i;
00416   double a,b;
00417   
00418   if ((i2->lower_limit<=0.0)&&(i2->upper_limit>=0.0)) 
00419     Error("Interval division by Zero");
00420 
00421   ROUNDDOWN;
00422   e[0]=i1->lower_limit/i2->upper_limit;
00423   e[1]=i1->upper_limit/i2->lower_limit;
00424   e[2]=i1->upper_limit/i2->upper_limit;
00425 
00426   a=i1->lower_limit/i2->lower_limit;
00427   for(i=0;i<3;i++)
00428     if (e[i]<a) a=e[i];
00429 
00430   ROUNDUP;
00431   e[0]=i1->lower_limit/i2->upper_limit;
00432   e[1]=i1->upper_limit/i2->lower_limit;
00433   e[2]=i1->upper_limit/i2->upper_limit;
00434 
00435   b=i1->lower_limit/i2->lower_limit;
00436   for(i=0;i<3;i++)
00437     if (e[i]>b) b=e[i];
00438 
00439   ROUNDNEAR;
00440 
00441   i_out->lower_limit=a;
00442   i_out->upper_limit=b;
00443 }
00444 
00445 /*
00446  * Shifts a interval
00447 */
00448 void IntervalOffset(Tinterval *i,double offset,Tinterval *i_out)
00449 {
00450   double a,b;
00451 
00452   ROUNDDOWN;
00453   a=i->lower_limit+offset;
00454 
00455   ROUNDUP;
00456   b=i->upper_limit+offset;
00457 
00458   ROUNDNEAR;
00459 
00460   i_out->lower_limit=a;
00461   i_out->upper_limit=b;
00462 }
00463 
00464 
00465 /*
00466  * Computes the sinus of an interval
00467  */
00468 void IntervalSinus(Tinterval *i,Tinterval *i_out)
00469 {
00470   double l,u;
00471 
00472   if (IntervalSize(i)>=M_2PI)
00473     NewInterval(-1,1,i_out);
00474   else
00475     {
00476       l=NormalizeAngle(i->lower_limit);
00477       u=NormalizeAngle(i->upper_limit);
00478   
00479       if (u<l)
00480         {
00481           Tinterval i_in;
00482           Tinterval i_out1,i_out2;
00483 
00484           i_in.lower_limit=l;
00485           i_in.upper_limit=M_2PI;
00486 
00487           IntervalSinus(&i_in,&i_out1);
00488 
00489           i_in.lower_limit=0.0;
00490           i_in.upper_limit=u;
00491 
00492           IntervalSinus(&i_in,&i_out2);
00493 
00494           i_out->lower_limit=(i_out1.lower_limit<i_out2.lower_limit?i_out1.lower_limit:i_out2.lower_limit);
00495           i_out->upper_limit=(i_out1.upper_limit>i_out2.upper_limit?i_out1.upper_limit:i_out2.upper_limit);
00496         }
00497       else
00498         {
00499           /*this is only valid for*/
00500           double a,b;
00501 
00502           ROUNDUP;
00503           a=sin(l);
00504           b=sin(u);
00505           ROUNDNEAR;
00506 
00507           if ((l<=M_PI_2)&&(M_PI_2<=u))
00508             i_out->upper_limit=1.0;
00509           else
00510             i_out->upper_limit=(a>b?a:b);
00511 
00512           ROUNDDOWN;
00513           a=sin(l);
00514           b=sin(u);
00515           ROUNDNEAR;
00516 
00517           if ((l<=(3.0*M_PI_2))&&((3.0*M_PI_2)<=u))
00518             i_out->lower_limit=-1.0;
00519           else
00520             i_out->lower_limit=(a<b?a:b);
00521         }
00522     }
00523 }
00524 
00525 /*
00526  * Computes the cosinus of an interval
00527  */
00528 void IntervalCosinus(Tinterval *i,Tinterval *i_out)
00529 {
00530   double l,u;
00531 
00532   if (IntervalSize(i)>=M_2PI)
00533     NewInterval(-1,1,i_out);
00534   else
00535     {
00536       l=NormalizeAngle(i->lower_limit);
00537       u=NormalizeAngle(i->upper_limit);
00538   
00539       if (u<l)
00540         {
00541           Tinterval i_in;
00542           Tinterval i_out1,i_out2;
00543 
00544           i_in.lower_limit=l;
00545           i_in.upper_limit=M_2PI;
00546 
00547           IntervalCosinus(&i_in,&i_out1);
00548 
00549           i_in.lower_limit=0.0;
00550           i_in.upper_limit=u;
00551 
00552           IntervalCosinus(&i_in,&i_out2);
00553 
00554           i_out->lower_limit=(i_out1.lower_limit<i_out2.lower_limit?i_out1.lower_limit:i_out2.lower_limit);
00555           i_out->upper_limit=(i_out1.upper_limit>i_out2.upper_limit?i_out1.upper_limit:i_out2.upper_limit);
00556         }
00557       else
00558         {
00559           double a,b;
00560 
00561           a=cos(l);
00562           b=cos(u);
00563 
00564           if ((l<=0.0)&&(0.0<=u))
00565             i_out->upper_limit=1.0;
00566           else
00567             i_out->upper_limit=(a>b?a:b);
00568 
00569           if ((l<=M_PI)&&(M_PI<=u))
00570             i_out->lower_limit=-1.0;
00571           else
00572             i_out->lower_limit=(a<b?a:b);
00573         }
00574     }
00575 }
00576 
00577 
00578 void IntervalAtan2(Tinterval *is,Tinterval *ic,Tinterval *i_out)
00579 {
00580   double a[4];
00581   unsigned int i;  
00582   double t1,t2;
00583 
00584   if ((IntervalSize(is)>0.5)||(IntervalSize(ic)>0.5)) 
00585     Error ("Interval atan2 only works for small intervals");
00586 
00587   a[0]=atan2(is->lower_limit,ic->lower_limit);
00588   a[1]=atan2(is->lower_limit,ic->upper_limit);
00589   a[2]=atan2(is->upper_limit,ic->lower_limit);
00590   a[3]=atan2(is->upper_limit,ic->upper_limit);
00591     
00592   t1=t2=a[0];
00593   for(i=1;i<4;i++)
00594     {
00595       if (a[i]<t1) t1=a[i];
00596       else {if (a[i]>t2) t2=a[i];}
00597     }
00598   
00599   i_out->lower_limit=t1;
00600   i_out->upper_limit=t2;
00601 
00602   if ((i_out->upper_limit-i_out->lower_limit)>M_PI) 
00603     {
00604       double d;
00605       
00606       d=i_out->lower_limit;
00607       i_out->lower_limit=i_out->upper_limit;
00608       i_out->upper_limit=d+M_2PI;
00609     }
00610 }
00611 
00612 
00613 /*
00614  * Prints the contents of interval 'i' on file 'f'.
00615  */
00616 void PrintInterval(FILE *f,Tinterval *i)
00617 {
00618   if (EmptyInterval(i))
00619     fprintf(f,"(Empty Interval)");
00620 
00621   fprintf(f,"[");
00622 
00623   if (i->lower_limit==-INF) fprintf(f,"-inf");
00624   else fprintf(f,"%.12g",i->lower_limit);
00625 
00626   fprintf(f,",");
00627 
00628   if (i->upper_limit==+INF) fprintf(f,"+inf");
00629   else fprintf(f,"%.12g",i->upper_limit);
00630 
00631   fprintf(f,"]");
00632 }
00633 
00634 /*
00635  * Deletes the internal structures of interval 'i'.
00636  */
00637 void DeleteInterval(Tinterval *i)
00638 {
00639 }