1 /******************************************************************************* 2 * * 3 * Author : Angus Johnson * 4 * Version : 1.1 * 5 * Date : 4 April 2011 * 6 * Website : http://www.angusj.com * 7 * Copyright : Angus Johnson 2010-2011 * 8 * * 9 * License: * 10 * Use, modification & distribution is subject to Boost Software License Ver 1. * 11 * http://www.boost.org/LICENSE_1_0.txt * 12 * * 13 *******************************************************************************/ 14 15 #ifndef AGG_CONV_CLIPPER_INCLUDED 16 #define AGG_CONV_CLIPPER_INCLUDED 17 18 #if defined(_MSC_VER) && (_MSC_VER >= 1800) 19 #include <algorithm> 20 #endif 21 22 #include <cmath> 23 #include "agg_basics.h" 24 #include "agg_array.h" 25 #include "clipper.hpp" 26 27 namespace mapserver 28 { 29 enum clipper_op_e { clipper_or, 30 clipper_and, clipper_xor, clipper_a_minus_b, clipper_b_minus_a }; 31 enum clipper_PolyFillType {clipper_even_odd, clipper_non_zero, clipper_positive, clipper_negative}; 32 33 template<class VSA, class VSB> class conv_clipper 34 { 35 enum status { status_move_to, status_line_to, status_stop }; 36 typedef VSA source_a_type; 37 typedef VSB source_b_type; 38 typedef conv_clipper<source_a_type, source_b_type> self_type; 39 40 private: 41 source_a_type* m_src_a; 42 source_b_type* m_src_b; 43 status m_status; 44 int m_vertex; 45 int m_contour; 46 int m_scaling_factor; 47 clipper_op_e m_operation; 48 pod_bvector<ClipperLib::IntPoint, 8> m_vertex_accumulator; 49 ClipperLib::Polygons m_poly_a; 50 ClipperLib::Polygons m_poly_b; 51 ClipperLib::Polygons m_result; 52 ClipperLib::Clipper m_clipper; 53 clipper_PolyFillType m_subjFillType; 54 clipper_PolyFillType m_clipFillType; 55 Round(double val)56 int Round(double val) 57 { 58 if ((val < 0)) return (int)(val - 0.5); else return (int)(val + 0.5); 59 } 60 61 public: 62 conv_clipper(source_a_type &a, source_b_type &b, 63 clipper_op_e op = clipper_or, 64 clipper_PolyFillType subjFillType = clipper_even_odd, 65 clipper_PolyFillType clipFillType = clipper_even_odd, 66 int scaling_factor = 2) : 67 m_src_a(&a), 68 m_src_b(&b), 69 m_status(status_move_to), 70 m_vertex(-1), 71 m_contour(-1), 72 m_operation(op), 73 m_subjFillType(subjFillType), 74 m_clipFillType(clipFillType) 75 { 76 m_scaling_factor = std::max(std::min(scaling_factor, 6),0); 77 m_scaling_factor = Round(std::pow((double)10, m_scaling_factor)); 78 } 79 ~conv_clipper()80 ~conv_clipper() 81 { 82 } 83 84 void attach1(VSA &source, clipper_PolyFillType subjFillType = clipper_even_odd) 85 { m_src_a = &source; m_subjFillType = subjFillType; } 86 void attach2(VSB &source, clipper_PolyFillType clipFillType = clipper_even_odd) 87 { m_src_b = &source; m_clipFillType = clipFillType; } 88 operation(clipper_op_e v)89 void operation(clipper_op_e v) { m_operation = v; } 90 91 void rewind(unsigned path_id); 92 unsigned vertex(double* x, double* y); 93 94 bool next_contour(); 95 bool next_vertex(double* x, double* y); 96 void start_extracting(); 97 void add_vertex_(double &x, double &y); 98 void end_contour(ClipperLib::Polygons &p); 99 add(VS & src,ClipperLib::Polygons & p)100 template<class VS> void add(VS &src, ClipperLib::Polygons &p){ 101 unsigned cmd; 102 double x; double y; double start_x; double start_y; 103 bool starting_first_line; 104 105 start_x = 0.0; 106 start_y = 0.0; 107 starting_first_line = true; 108 p.resize(0); 109 110 cmd = src->vertex( &x , &y ); 111 while(!is_stop(cmd)) 112 { 113 if(is_vertex(cmd)) 114 { 115 if(is_move_to(cmd)) 116 { 117 if(!starting_first_line ) end_contour(p); 118 start_x = x; 119 start_y = y; 120 } 121 add_vertex_( x, y ); 122 starting_first_line = false; 123 } 124 else if(is_end_poly(cmd)) 125 { 126 if(!starting_first_line && is_closed(cmd)) 127 add_vertex_( start_x, start_y ); 128 } 129 cmd = src->vertex( &x, &y ); 130 } 131 end_contour(p); 132 } 133 }; 134 135 //------------------------------------------------------------------------ 136 137 template<class VSA, class VSB> start_extracting()138 void conv_clipper<VSA, VSB>::start_extracting() 139 { 140 m_status = status_move_to; 141 m_contour = -1; 142 m_vertex = -1; 143 } 144 //------------------------------------------------------------------------------ 145 146 template<class VSA, class VSB> rewind(unsigned path_id)147 void conv_clipper<VSA, VSB>::rewind(unsigned path_id) 148 { 149 m_src_a->rewind( path_id ); 150 m_src_b->rewind( path_id ); 151 152 add( m_src_a , m_poly_a ); 153 add( m_src_b , m_poly_b ); 154 m_result.resize(0); 155 156 ClipperLib::PolyFillType pftSubj, pftClip; 157 switch (m_subjFillType) 158 { 159 case clipper_even_odd: pftSubj = ClipperLib::pftEvenOdd; break; 160 case clipper_non_zero: pftSubj = ClipperLib::pftNonZero; break; 161 case clipper_positive: pftSubj = ClipperLib::pftPositive; break; 162 default: pftSubj = ClipperLib::pftNegative; 163 } 164 switch (m_clipFillType) 165 { 166 case clipper_even_odd: pftClip = ClipperLib::pftEvenOdd; break; 167 case clipper_non_zero: pftClip = ClipperLib::pftNonZero; break; 168 case clipper_positive: pftClip = ClipperLib::pftPositive; break; 169 default: pftClip = ClipperLib::pftNegative; 170 } 171 172 m_clipper.Clear(); 173 switch( m_operation ) { 174 case clipper_or: 175 { 176 m_clipper.AddPolygons( m_poly_a , ClipperLib::ptSubject ); 177 m_clipper.AddPolygons( m_poly_b , ClipperLib::ptClip ); 178 m_clipper.Execute( ClipperLib::ctUnion , m_result , pftSubj, pftClip); 179 break; 180 } 181 case clipper_and: 182 { 183 m_clipper.AddPolygons( m_poly_a , ClipperLib::ptSubject ); 184 m_clipper.AddPolygons( m_poly_b , ClipperLib::ptClip ); 185 m_clipper.Execute( ClipperLib::ctIntersection , m_result, pftSubj, pftClip ); 186 break; 187 } 188 case clipper_xor: 189 { 190 m_clipper.AddPolygons( m_poly_a , ClipperLib::ptSubject ); 191 m_clipper.AddPolygons( m_poly_b , ClipperLib::ptClip ); 192 m_clipper.Execute( ClipperLib::ctXor , m_result, pftSubj, pftClip ); 193 break; 194 } 195 case clipper_a_minus_b: 196 { 197 m_clipper.AddPolygons( m_poly_a , ClipperLib::ptSubject ); 198 m_clipper.AddPolygons( m_poly_b , ClipperLib::ptClip ); 199 m_clipper.Execute( ClipperLib::ctDifference , m_result, pftSubj, pftClip ); 200 break; 201 } 202 case clipper_b_minus_a: 203 { 204 m_clipper.AddPolygons( m_poly_b , ClipperLib::ptSubject ); 205 m_clipper.AddPolygons( m_poly_a , ClipperLib::ptClip ); 206 m_clipper.Execute( ClipperLib::ctDifference , m_result, pftSubj, pftClip ); 207 break; 208 } 209 } 210 start_extracting(); 211 } 212 //------------------------------------------------------------------------------ 213 214 template<class VSA, class VSB> end_contour(ClipperLib::Polygons & p)215 void conv_clipper<VSA, VSB>::end_contour( ClipperLib::Polygons &p) 216 { 217 unsigned i, len; 218 219 if( m_vertex_accumulator.size() < 3 ) return; 220 len = p.size(); 221 p.resize(len+1); 222 p[len].resize(m_vertex_accumulator.size()); 223 for( i = 0 ; i < m_vertex_accumulator.size() ; i++ ) 224 p[len][i] = m_vertex_accumulator[i]; 225 m_vertex_accumulator.remove_all(); 226 } 227 //------------------------------------------------------------------------------ 228 229 template<class VSA, class VSB> add_vertex_(double & x,double & y)230 void conv_clipper<VSA, VSB>::add_vertex_(double &x, double &y) 231 { 232 ClipperLib::IntPoint v; 233 234 v.X = Round(x * m_scaling_factor); 235 v.Y = Round(y * m_scaling_factor); 236 m_vertex_accumulator.add( v ); 237 } 238 //------------------------------------------------------------------------------ 239 240 template<class VSA, class VSB> next_contour()241 bool conv_clipper<VSA, VSB>::next_contour() 242 { 243 m_contour++; 244 if(m_contour >= (int)m_result.size()) return false; 245 m_vertex =-1; 246 return true; 247 } 248 //------------------------------------------------------------------------------ 249 250 template<class VSA, class VSB> next_vertex(double * x,double * y)251 bool conv_clipper<VSA, VSB>::next_vertex(double *x, double *y) 252 { 253 m_vertex++; 254 if(m_vertex >= (int)m_result[m_contour].size()) return false; 255 *x = (double)m_result[ m_contour ][ m_vertex ].X / m_scaling_factor; 256 *y = (double)m_result[ m_contour ][ m_vertex ].Y / m_scaling_factor; 257 return true; 258 } 259 //------------------------------------------------------------------------------ 260 261 template<class VSA, class VSB> vertex(double * x,double * y)262 unsigned conv_clipper<VSA, VSB>::vertex(double *x, double *y) 263 { 264 if( m_status == status_move_to ) 265 { 266 if( next_contour() ) 267 { 268 if( next_vertex( x, y ) ) 269 { 270 m_status =status_line_to; 271 return path_cmd_move_to; 272 } 273 else 274 { 275 m_status = status_stop; 276 return path_cmd_end_poly | path_flags_close; 277 } 278 } 279 else 280 return path_cmd_stop; 281 } 282 else 283 { 284 if( next_vertex( x, y ) ) 285 { 286 return path_cmd_line_to; 287 } 288 else 289 { 290 m_status = status_move_to; 291 return path_cmd_end_poly | path_flags_close; 292 } 293 } 294 } 295 //------------------------------------------------------------------------------ 296 297 298 } //namespace agg 299 #endif //AGG_CONV_CLIPPER_INCLUDED 300