core/vgl/vgl_clip.txx
Go to the documentation of this file.
00001 // This is core/vgl/vgl_clip.txx
00002 #ifndef vgl_clip_txx_
00003 #define vgl_clip_txx_
00004 //:
00005 // \file
00006 // \author fsm
00007 
00008 #include "vgl_clip.h"
00009 #include <vcl_cstdlib.h> // for vcl_malloc() and vcl_free()
00010 #include <vcl_cstdio.h> // for vcl_fprintf()
00011 #include <vcl_algorithm.h> // for swap
00012 
00013 template <class T>
00014 bool vgl_clip_lineseg_to_line(T &x1, T &y1,
00015                               T &x2, T &y2,
00016                               T a,T b,T c)
00017 {
00018   T f1 = a*x1+b*y1+c;
00019   T f2 = a*x2+b*y2+c;
00020   if (f1<0) {
00021     if (f2<0) // both out
00022       return false;
00023     // 1 out, 2 in
00024     x1 = (f2*x1 - f1*x2)/(f2-f1);
00025     y1 = (f2*y1 - f1*y2)/(f2-f1);
00026     return true;
00027   }
00028   else {
00029     if (f2<0)  // 1 in, 2 out
00030     {
00031       x2 = (f2*x1 - f1*x2)/(f2-f1);
00032       y2 = (f2*y1 - f1*y2)/(f2-f1);
00033     }
00034     // both in
00035     return true;
00036   }
00037 }
00038 
00039 template <class T>
00040 bool vgl_clip_line_to_box(T a, T b, T c, // line coefficients.
00041                           T x1, T y1,    // bounding
00042                           T x2, T y2,    // box.
00043                           T &bx, T &by,  // start and
00044                           T &ex, T &ey)  // end points.
00045 {
00046   if (x1>x2) vcl_swap(x1,x2);
00047   if (y1>y2) vcl_swap(y1,y2);
00048   // now x1 <= x2 and y1 <= y2
00049 
00050   if (a == 0 && b == 0) return false; // then ax+by+c=0 is the line at infinity
00051 
00052   bool b_set = false, // has the point (bx,by) been set to a valid point?
00053        e_set = false; // has the point (ex,ey) been set to a valid point?
00054 
00055   if (a != 0) // line is not horizontal
00056   {
00057     // Intersection point with the line y=y1:
00058     by = y1; bx = -(b*y1+c)/a;
00059     // Intersection point with the line y=y2:
00060     ey = y2; ex = -(b*y2+c)/a;
00061 
00062     b_set =  bx >= x1 && bx <= x2; // does this intersection point
00063     e_set =  ex >= x1 && ex <= x2; // lie on the bounding box?
00064   }
00065 
00066   if (b_set && e_set) return true;
00067   if (b_set) { vcl_swap(bx,ex); vcl_swap(by,ey); vcl_swap(b_set,e_set); }
00068   // now b_set is false
00069 
00070   if (b != 0) // line is not vertical
00071   {
00072     // Intersection point with the line x=x1:
00073     bx = x1; by = -(a*x1+c)/b;
00074     b_set =  by >= y1 && by <= y2;
00075     if (b_set && e_set) return true;
00076     if (b_set) { vcl_swap(bx,ex); vcl_swap(by,ey); e_set=true; }
00077 
00078     // Intersection point with the line x=x2:
00079     bx = x2; by = -(a*x2+c)/b;
00080     b_set =  by >= y1 && ey <= y2;
00081   }
00082 
00083   return b_set && e_set;
00084 }
00085 
00086 
00087 #ifdef BUILD_NONCOMMERCIAL
00088 
00089 extern "C" {
00090 #include "internals/gpc.h"
00091 }
00092 
00093 #define MALLOC(p, T, c, s) { if ((c) > 0) { \
00094                             p= (T*)vcl_malloc(c * sizeof(T)); if (!(p)) { \
00095                             vcl_fprintf(stderr, "vgl: gpc malloc failure: %s\n", s); \
00096                             vcl_exit(0);}} else p=NULL; }
00097 
00098 #define FREE(p)            { if (p) { vcl_free(p); (p)= NULL; } }
00099 
00100 namespace {
00101   //: Creates a gpc polygon from a vgl_polygon.
00102   // The caller is responsible for freeing the gpc_polygon.
00103   template <class T>
00104   gpc_polygon
00105   vgl_to_gpc( const vgl_polygon<T>& vgl_poly )
00106   {
00107     gpc_polygon gpc_poly;
00108     gpc_poly.num_contours = vgl_poly.num_sheets();
00109     MALLOC( gpc_poly.hole, int, gpc_poly.num_contours, "allocating hole array" );
00110     MALLOC( gpc_poly.contour, gpc_vertex_list, gpc_poly.num_contours, "allocating contour array" );
00111     for ( int s = 0; s < gpc_poly.num_contours; ++s ) {
00112       gpc_poly.hole[s] = 0;
00113       gpc_poly.contour[s].num_vertices = vgl_poly[s].size();
00114       MALLOC( gpc_poly.contour[s].vertex, gpc_vertex, vgl_poly[s].size(), "allocating vertex list" );
00115       for ( unsigned int p = 0; p < vgl_poly[s].size(); ++p ) {
00116         gpc_poly.contour[s].vertex[p].x = vgl_poly[s][p].x();
00117         gpc_poly.contour[s].vertex[p].y = vgl_poly[s][p].y();
00118       }
00119     }
00120 
00121     return gpc_poly;
00122   }
00123 
00124   //: Adds a gpc_polygon to a given vgl_polygon.
00125   template <class T>
00126   void
00127   add_gpc_to_vgl( vgl_polygon<T>& vgl_poly, const gpc_polygon& gpc_poly )
00128   {
00129     for ( int c=0; c < gpc_poly.num_contours; ++c ) {
00130       vgl_poly.new_sheet();
00131       for ( int p=0; p < gpc_poly.contour[c].num_vertices; ++p ) {
00132         vgl_poly.push_back( T(gpc_poly.contour[c].vertex[p].x),
00133                             T(gpc_poly.contour[c].vertex[p].y) );
00134       }
00135     }
00136   }
00137 }
00138 
00139 #endif // BUILD_NONCOMMERCIAL
00140 
00141 template <class T>
00142 vgl_polygon<T>
00143 vgl_clip(vgl_polygon<T> const& poly1, vgl_polygon<T> const& poly2, vgl_clip_type op, int *p_retval)
00144 {
00145   // Check for the null case
00146   if ( poly1.num_sheets() == 0 ) {
00147     *p_retval = 1;
00148     switch ( op )
00149     {
00150       case vgl_clip_type_intersect:    return poly1;
00151       case vgl_clip_type_difference:   return poly1;
00152       case vgl_clip_type_union:        return poly2;
00153       case vgl_clip_type_xor:          return poly2;
00154       default:                         *p_retval = -1; return vgl_polygon<T>(); // this should not happen...
00155     }
00156   }
00157   if ( poly2.num_sheets() == 0 ) {
00158     *p_retval = 1;
00159     switch ( op )
00160     {
00161       case vgl_clip_type_intersect:    return poly2;
00162       case vgl_clip_type_difference:   return poly1;
00163       case vgl_clip_type_union:        return poly1;
00164       case vgl_clip_type_xor:          return poly1;
00165       default:                         *p_retval = -1; return vgl_polygon<T>(); // this should not happen...
00166     }
00167   }
00168 
00169   vgl_polygon<T> result;
00170 
00171 #ifdef BUILD_NONCOMMERCIAL
00172   gpc_polygon p1 = vgl_to_gpc( poly1 );
00173   gpc_polygon p2 = vgl_to_gpc( poly2 );
00174   gpc_polygon p3;
00175 
00176   gpc_op g_op = GPC_INT;
00177   switch ( op )
00178   {
00179     case vgl_clip_type_intersect:    g_op = GPC_INT;   break;
00180     case vgl_clip_type_difference:   g_op = GPC_DIFF;  break;
00181     case vgl_clip_type_union:        g_op = GPC_UNION; break;
00182     case vgl_clip_type_xor:          g_op = GPC_XOR;   break;
00183     default:                         break;
00184   }
00185 
00186   int retval = gpc_polygon_clip( g_op, &p1, &p2, &p3 );
00187   *p_retval = retval;
00188 
00189   if (retval == 0) {
00190     gpc_free_polygon( &p1 );
00191     gpc_free_polygon( &p2 );
00192     return result;
00193   }
00194   add_gpc_to_vgl( result, p3 );
00195 
00196   gpc_free_polygon( &p1 );
00197   gpc_free_polygon( &p2 );
00198   gpc_free_polygon( &p3 );
00199 
00200 #else // BUILD_NONCOMMERCIAL
00201   *p_retval = -1;
00202   vcl_fprintf(stdout,"WARNING: GPC is only free for non-commercial use -- assuming disjoint polygons.\n");
00203   vcl_fprintf(stderr,"WARNING: GPC is only free for non-commercial use -- assuming disjoint polygons.\n");
00204   switch ( op )
00205   {
00206     default:
00207     case vgl_clip_type_intersect:    result = vgl_polygon<T>(); break; // empty
00208     case vgl_clip_type_difference:   result = poly1; break;
00209     case vgl_clip_type_union:
00210     case vgl_clip_type_xor:
00211       result = poly1;
00212       for (unsigned int i=0; i<poly2.num_sheets(); ++i)
00213         result.push_back(poly2[i]);
00214       break;
00215   }
00216   
00217 #endif // BUILD_NONCOMMERCIAL
00218 
00219   return result;
00220 }
00221 
00222 template <class T>
00223 vgl_polygon<T>
00224 vgl_clip(vgl_polygon<T> const& poly1, vgl_polygon<T> const& poly2, vgl_clip_type op )
00225 {
00226   int retval;
00227   return vgl_clip(poly1, poly2, op, &retval);
00228 }
00229 
00230 #undef VGL_CLIP_INSTANTIATE
00231 #define VGL_CLIP_INSTANTIATE(T) \
00232 template vgl_polygon<T > vgl_clip(vgl_polygon<T >const&,vgl_polygon<T >const&,vgl_clip_type); \
00233 template bool vgl_clip_lineseg_to_line(T&,T&,T&,T&,T,T,T); \
00234 template bool vgl_clip_line_to_box(T,T,T,T,T,T,T,T&,T&,T&,T&); \
00235 template vgl_line_segment_2d<T > vgl_clip_line_to_box(vgl_line_2d<T >const&,vgl_box_2d<T >const&)
00236 
00237 #endif // vgl_clip_txx_