wxArt2D
booloper.cpp
Go to the documentation of this file.
1 /*! \file canvas/src/booloper.cpp
2  \author Klaas Holwerda
3 
4  Copyright: 2000-2004 (c) Klaas Holwerda
5 
6  Licence: wxWidgets Licence
7 
8  RCS-ID: $Id: booloper.cpp,v 1.39 2009/04/23 19:35:23 titato Exp $
9 */
10 
11 #include "a2dprec.h"
12 
13 #ifdef __BORLANDC__
14 #pragma hdrstop
15 #endif
16 
17 #ifndef WX_PRECOMP
18 #include "wx/wx.h"
19 #endif
20 
21 #include "a2dprivate.h"
22 
23 #if wxART2D_USE_KBOOL
24 
25 #include "wx/canvas/canmod.h"
26 #include "wx/canvas/booloper.h"
27 
39 
40 //IMPLEMENT_CLASS(a2dBooleanWalkerHandler, a2dWalkerIOHandler)
41 
42 a2dBooleanWalkerHandler::a2dBooleanWalkerHandler( a2dCanvasObjectFlagsMask mask )
44 {
45  Initialize();
46  m_mask = mask;
47 }
48 
49 a2dBooleanWalkerHandler::~a2dBooleanWalkerHandler()
50 {
51  delete m_booleng;
52 }
53 
55 {
57 
58  m_useCheck = true;
59  m_depthFirst = true;
60  m_clearTarget = true;
61  m_resultOnSameLayer = false;
62  m_releaseOrignals = false;
63  m_firstLevelChild = false;
64 
67  m_useFirstChildStyle = false;//true;
68 
69  m_booleng = new Bool_Engine();
70 
71  // set some global values to arm the boolean engine
72  double DGRID = 0.01; // round coordinate X or Y value in calculations to this
73  double MARGE = 0.1; // snap with in this range points to lines in the intersection routines
74  // should always be > DGRID a MARGE >= 10*DGRID is oke
75  // this is also used to remove small segments and to decide when
76  // two segments are in line.
77  double CORRECTIONFACTOR = 500.0; // correct the polygons by this number
78  double CORRECTIONABER = 1.0; // the accuracy for the rounded shapes used in correction
79  double ROUNDFACTOR = 1.5; // when will we round the correction shape to a circle
80  double SMOOTHABER = 0.001; // accuracy when smoothing a polygon
81  double MAXLINEMERGE = 1000.0; // leave as is, segments of this length in smoothen
82 
83  if ( MARGE <= DGRID )
84  {
85  MARGE = DGRID * 10;
86  }
87 
88  // DGRID is only meant to make fractional parts of input data which
89  // are doubles, part of the integers used in vertexes within the boolean algorithm.
90  // And therefore bigger than 1 is not usefull.
91  // Within the algorithm all input data is multiplied with DGRID
92  if ( DGRID < 1 )
93  DGRID = 1 / DGRID;
94  else
95  DGRID = 1;
96 
97  // space for extra intersection inside the boolean algorithms
98  // only change this if there are problems
99  int GRID = 100;
100 
101  m_booleng->SetMarge( MARGE );
102  m_booleng->SetGrid( GRID );
103  m_booleng->SetDGrid( DGRID );
104 
105  // each 64 bit integer coordinate is calculated from the document it dataunits by:
106  //B_INT intXorY = ( ( B_INT ) ( XorY * m_DGRID ) ) * m_GRID;
107  // all the rest of the factor down here, are in the same unit as the document.
108 
109  m_booleng->SetCorrectionFactor( CORRECTIONFACTOR );
110  m_booleng->SetCorrectionAber( CORRECTIONABER );
111  m_booleng->SetSmoothAber( SMOOTHABER );
112  m_booleng->SetMaxlinemerge( MAXLINEMERGE );
113  m_booleng->SetRoundfactor( ROUNDFACTOR );
114  m_booleng->SetOrientationEntryMode( false );
115 }
116 
118 {
119  m_lastdepth = 0;
120 
121  a2dWalker_SetCheck setp( false );
122  setp.Start( object );
124  setflags.SetSkipNotRenderedInDrawing( true );
125  setflags.Start( object, false );
126 
127  try
128  {
129  object->Walker( NULL, *this );
130  }
131  catch ( Bool_Engine_Error& error )
132  {
133  wxString str( error.GetErrorMessage().data(), wxConvUTF8, error.GetErrorMessage().size() );
134  a2dGeneralGlobals->ReportErrorF( a2dError_CommandError, str );
135  }
136  catch ( ... )
137  {
138  a2dGeneralGlobals->ReportErrorF( a2dError_CommandError, _( "Problem performing boolean operation" ) );
139  return false;
140  }
141  return true;
142 }
143 
144 bool a2dBooleanWalkerHandler::WalkTask( wxObject* parent, wxObject* object, a2dWalkEvent event )
145 {
146 
148  SetStopWalking( true );
149 
150  if ( event == a2dWalker_a2dObjectStart )
151  {
152  //wxLogDebug(_T("a2dobj start %s"), wxDynamicCast( object, a2dObject )->GetName() );
153 
155  if ( obj && m_currentDepth == 2 && ObjectOke( obj ) && !obj->GetCheck() )
156  {
157  if ( !m_selectedOnlyA || ( m_selectedOnlyA && obj->GetSelected() ) )
158  m_firstLevelChild = true;
159  if ( !m_selectedOnlyB || ( m_selectedOnlyB && obj->GetSelected() ) )
160  m_firstLevelChild = true;
161  obj->SetCheck( true );
162  }
163  }
164 
165  // every canvas object is tested at the start of its walk, if it is oke, it will be stored in m_foundA or m_foundB
166  // Next when all canvas objects at that level are checked, we go one level up where m_foundA/B will be processed.
167  if ( event == a2dWalker_a2dCanvasObjectStart )
168  {
170 
171  a2dCanvasObject* canobj = ( a2dCanvasObject* ) object;
172 
173  //wxLogDebug( wxT( "a2dWalker_a2dCanvasObjectStart classname = %s depth = %d" ), canobj->GetClassInfo()->GetClassName(), m_currentDepth );
174  //wxLogDebug( wxT( "name = %s" ), canobj->GetName().c_str() );
175  if ( canobj && parent && !canobj->GetBin() && !canobj->GetIgnoreLayer() && m_firstLevelChild )
176  {
177  // check if obj is in one of the group arrays (A or B)
178  bool hasLayer = false;
180  {
181  wxUint16 layer = *iter;
182  // if one of the layers in the group is wxLAYER_ALL, that means all available layers in document
183  if ( wxLAYER_ALL == layer )
184  {
185  hasLayer = true;
186  break;
187  }
188  if ( canobj->GetLayer() == layer )
189  hasLayer = true;
190  }
191 
192  // if in group A, we want this object for the boolean operation
193  if ( hasLayer )
194  m_foundA.push_back( canobj );
195 
196  {
197  hasLayer = false;
199  {
200  wxUint16 layer = *iter;
201  // if one of the layers in the group is wxLAYER_ALL, that means all available layers in document
202  if ( wxLAYER_ALL == layer )
203  {
204  hasLayer = true;
205  break;
206  }
207  if ( canobj->GetLayer() == layer )
208  hasLayer = true;
209  }
210 
211  // if in group B, we want this object for the boolean operation
212  if ( hasLayer )
213  m_foundB.push_back( canobj );
214  }
215  }
216 
217 
218  if ( ( !m_foundA.empty() || !m_foundB.empty() ) &&
220  {
221  a2dCanvasObject* canobjToAddTo = ( a2dCanvasObject* ) parent;
222  CallEngine( canobjToAddTo );
223  }
224  }
225 
226  if ( !m_foundA.empty() || !m_foundB.empty() )
227  {
229  {
230  a2dCanvasObject* canobj = ( a2dCanvasObject* ) object;
231 #if defined(_DEBUG)
232  wxString name = canobj->GetName();
233 #endif
234  // the m_foundA and m_foundB can now be processed.
235  CallEngine( canobj );
236  // the result is available, and even if target is the same layer as originals, we can delete
237  // the objects which were used in the boolean operation now if they are on the target layer.
238  if ( m_clearTarget )
239  {
241  {
242  a2dCanvasObject* obj = ( *iter );
243  if ( !obj->GetBin2() && obj->GetLayer() == m_target && !obj->GetIgnoreLayer() )
244  obj->SetRelease( true );
245  }
246  }
247  }
248  }
249  else if ( m_clearTarget &&
251  {
253  {
254  a2dCanvasObject* canobj = ( a2dCanvasObject* ) object;
256  {
257  a2dCanvasObject* obj = ( *iter );
258  if ( !obj->GetBin2() && obj->GetLayer() == m_target && !obj->GetIgnoreLayer() )
259  obj->SetRelease( true );
260  }
261  }
262  }
263 
265  {
266  a2dCanvasObject* canobj = ( a2dCanvasObject* ) object;
267  //wxLogDebug( wxT( "a2dWalker_a2dCanvasObjectEnd classname = %s depth = %d" ), canobj->GetClassInfo()->GetClassName(), m_currentDepth );
268  //wxLogDebug( wxT( "name = %s" ), canobj->GetName().c_str() );
270  }
271 
272  if ( event == a2dWalker_a2dObjectEnd )
273  {
274  //wxLogDebug(_T("a2dobj end %s"), wxDynamicCast( object, a2dObject )->GetName() );
275  if ( m_currentDepth <= 2 )
276  {
277  m_firstLevelChild = false;
278  }
279  }
280 
281  if ( m_currentDepth <= m_depth && event == a2dWalker_a2dPropertyEnd )
282  SetStopWalking( false );
283 
284  if ( event == a2dWalker_a2dCanvasObjectPostChild )
285  return false; //do not go here
286 
287  return true;
288 }
289 
290 bool a2dBooleanWalkerHandler::GetObjectsForSurface( a2dCanvasObject* booleanobject, GroupType A_or_B )
291 {
293  if ( 0 != wxDynamicCast( booleanobject, a2dRect ) && booleanobject->GetContourWidth() )
294  {
295  a2dRect* obj = wxDynamicCast( booleanobject, a2dRect );
296  vpath = obj->GetAsCanvasVpaths();
297  }
298  else if ( 0 != wxDynamicCast( booleanobject, a2dCircle ) && booleanobject->GetContourWidth() )
299  {
300  a2dCircle* obj = wxDynamicCast( booleanobject, a2dCircle );
301  vpath = obj->GetAsCanvasVpaths();
302  }
303  else if ( 0 != wxDynamicCast( booleanobject, a2dEllipse ) && booleanobject->GetContourWidth() )
304  {
305  a2dEllipse* obj = wxDynamicCast( booleanobject, a2dEllipse );
306  vpath = obj->GetAsCanvasVpaths();
307  }
308  else if ( 0 != wxDynamicCast( booleanobject, a2dEllipticArc ) && booleanobject->GetContourWidth() )
309  {
310  a2dEllipticArc* obj = wxDynamicCast( booleanobject, a2dEllipticArc );
311  vpath = obj->GetAsCanvasVpaths();
312  }
313  else if ( 0 != wxDynamicCast( booleanobject, a2dArc ) && booleanobject->GetContourWidth() )
314  {
315  a2dArc* obj = wxDynamicCast( booleanobject, a2dArc );
316  vpath = obj->GetAsCanvasVpaths();
317  }
318  else if ( 0 != wxDynamicCast( booleanobject, a2dEndsLine ) && booleanobject->GetContourWidth() )
319  {
320  a2dEndsLine* obj = wxDynamicCast( booleanobject, a2dEndsLine );
321  vpath = obj->GetAsCanvasVpaths();
322  }
323  else if ( 0 != wxDynamicCast( booleanobject, a2dSLine ) && booleanobject->GetContourWidth() )
324  {
325  a2dSLine* obj = wxDynamicCast( booleanobject, a2dSLine );
326  vpath = obj->GetAsCanvasVpaths();
327  }
328  else if ( 0 != wxDynamicCast( booleanobject, a2dPolylineL ) && booleanobject->GetContourWidth() )
329  {
330  a2dPolylineL* obj = wxDynamicCast( booleanobject, a2dPolylineL );
331  vpath = obj->GetAsCanvasVpaths();
332  }
333  else if ( 0 != wxDynamicCast( booleanobject, a2dSurface ) )
334  {
335  // we must intercept a2dSurface before a2dPolygonL from which it is derived.
336  a2dSurface* obj = wxDynamicCast( booleanobject, a2dSurface );
337  // nothing to do, is already a surface
338  obj->SetBin( true );
339  obj->SetBin2( true );
340  obj->SetLayer( !m_resultOnSameLayer ? m_target : m_useFirstChildLayer );
341  }
342  else if ( 0 != wxDynamicCast( booleanobject, a2dPolygonL ) )
343  {
344  a2dPolygonL* obj = wxDynamicCast( booleanobject, a2dPolygonL );
345  vpath = obj->GetAsCanvasVpaths();
346  }
347  else if ( 0 != wxDynamicCast( booleanobject, a2dVectorPath ) )
348  {
349  a2dVectorPath* obj = wxDynamicCast( booleanobject, a2dVectorPath );
350  vpath = obj->GetAsCanvasVpaths();
351  }
352  else if ( 0 != wxDynamicCast( booleanobject, a2dText ) )
353  {
354  a2dText* obj = wxDynamicCast( booleanobject, a2dText );
355  vpath = obj->GetAsCanvasVpaths();
356  }
357  else
358  {
359  // rest does not have surface and go to result as is.
360  booleanobject->SetBin( true );
361  booleanobject->SetBin2( true );
362  booleanobject->SetLayer( !m_resultOnSameLayer ? m_target : m_useFirstChildLayer );
363  }
364  // now we have vector path, which we will convert to polygons and polylines.
365  // Next only the polygons will be used for boolean operations.
366  if ( vpath != wxNullCanvasObjectList )
367  {
368  bool ret = VectorPathPolygonsToEngine( vpath, A_or_B );
369  delete vpath;
370  return ret;
371  }
372  return false;
373 }
374 
375 bool a2dBooleanWalkerHandler::GetObjectsSurface( a2dCanvasObject* booleanobject, GroupType A_or_B )
376 {
378  if ( 0 != wxDynamicCast( booleanobject, a2dSurface ) )
379  {
380  // treat surfaces without conversion to vector paths
381  a2dSmrtPtr<a2dSurface> poly = wxDynamicCast( booleanobject, a2dSurface );
382  poly = wxDynamicCast( poly->Clone( a2dObject::clone_deep ), a2dSurface );
383 
384  if ( poly && poly->GetSegments()->HasArcs() )
385  poly->GetSegments()->ConvertToLines();
386 
387  double tx, ty;
388  if ( poly && poly->GetNumberOfSegments() > 2 && m_booleng->StartPolygonAdd( A_or_B ) )
389  {
390  for( a2dVertexList::const_iterator iter = poly->GetSegments()->begin(); iter != poly->GetSegments()->end(); ++iter )
391  {
392  a2dLineSegment* seg = *iter;
393  poly->GetTransformMatrix().TransformPoint( seg->m_x, seg->m_y, tx, ty );
394  m_booleng->AddPoint( tx, ty );
395  }
396  m_booleng->EndPolygonAdd();
397  }
398  a2dListOfa2dVertexList& holes = poly->GetHoles();
399  for( a2dListOfa2dVertexList::iterator iterp = holes.begin(); iterp != holes.end(); iterp++ )
400  {
401  a2dVertexListPtr vlist = ( *iterp );
402  if ( vlist->HasArcs() )
403  vlist->ConvertToLines();
404  if ( vlist->size() > 2 && m_booleng->StartHolePolygonAdd( A_or_B ) )
405  {
406  for( a2dVertexList::iterator iter = vlist->begin(); iter != vlist->end(); ++iter )
407  {
408  a2dLineSegment* seg = *iter;
409  poly->GetTransformMatrix().TransformPoint( seg->m_x, seg->m_y, tx, ty );
410  m_booleng->AddPoint( tx, ty );
411  }
412  }
413  m_booleng->EndPolygonAdd();
414  }
415  return true;
416  }
417  return false;
418 }
419 
420 bool a2dBooleanWalkerHandler::ConvertToPolygons( a2dCanvasObject* booleanobject, GroupType A_or_B )
421 {
422  //wxLogDebug( wxT( "classname = %s" ), booleanobject->GetClassInfo()->GetClassName() );
423 
425 
426  if ( 0 != wxDynamicCast( booleanobject, a2dRect ) )
427  {
428  a2dRect* obj = wxDynamicCast( booleanobject, a2dRect );
429  vpath = obj->GetAsCanvasVpaths();
430  }
431  else if ( 0 != wxDynamicCast( booleanobject, a2dRectC ) )
432  {
433  a2dRectC* obj = wxDynamicCast( booleanobject, a2dRectC );
434  vpath = obj->GetAsCanvasVpaths();
435  }
436  else if ( 0 != wxDynamicCast( booleanobject, a2dArrow ) )
437  {
438  a2dArrow* obj = wxDynamicCast( booleanobject, a2dArrow );
439  vpath = obj->GetAsCanvasVpaths();
440  }
441  else if ( 0 != wxDynamicCast( booleanobject, a2dCircle ) )
442  {
443  a2dCircle* obj = wxDynamicCast( booleanobject, a2dCircle );
444  vpath = obj->GetAsCanvasVpaths();
445  }
446  else if ( 0 != wxDynamicCast( booleanobject, a2dEllipse ) )
447  {
448  a2dEllipse* obj = wxDynamicCast( booleanobject, a2dEllipse );
449  vpath = obj->GetAsCanvasVpaths();
450  }
451  else if ( 0 != wxDynamicCast( booleanobject, a2dEllipticArc ) )
452  {
453  a2dEllipticArc* obj = wxDynamicCast( booleanobject, a2dEllipticArc );
454  vpath = obj->GetAsCanvasVpaths();
455  }
456  else if ( 0 != wxDynamicCast( booleanobject, a2dArc ) )
457  {
458  a2dArc* obj = wxDynamicCast( booleanobject, a2dArc );
459  vpath = obj->GetAsCanvasVpaths();
460  }
461  else if ( 0 != wxDynamicCast( booleanobject, a2dEndsLine ) && booleanobject->GetContourWidth() )
462  {
463  a2dEndsLine* obj = wxDynamicCast( booleanobject, a2dEndsLine );
464  vpath = obj->GetAsCanvasVpaths();
465  }
466  else if ( 0 != wxDynamicCast( booleanobject, a2dSLine ) && booleanobject->GetContourWidth() )
467  {
468  a2dSLine* obj = wxDynamicCast( booleanobject, a2dSLine );
469  vpath = obj->GetAsCanvasVpaths();
470  }
471  else if ( 0 != wxDynamicCast( booleanobject, a2dPolylineL ) && booleanobject->GetContourWidth() )
472  {
473  a2dPolylineL* obj = wxDynamicCast( booleanobject, a2dPolylineL );
474  vpath = obj->GetAsCanvasVpaths();
475  }
476  else if ( 0 != wxDynamicCast( booleanobject, a2dSurface ) )
477  {
478  // treat surfaces without conversion to vector paths
479  a2dSmrtPtr<a2dSurface> poly = wxDynamicCast( booleanobject, a2dSurface );
480  poly = wxDynamicCast( poly->Clone( a2dObject::clone_deep ), a2dSurface );
481 
482  if ( poly && poly->GetSegments()->HasArcs() )
483  poly->GetSegments()->ConvertToLines();
484 
485  double tx, ty;
486  if ( poly && poly->GetNumberOfSegments() > 2 && m_booleng->StartPolygonAdd( A_or_B ) )
487  {
488  for( a2dVertexList::const_iterator iter = poly->GetSegments()->begin(); iter != poly->GetSegments()->end(); ++iter )
489  {
490  a2dLineSegment* seg = *iter;
491  poly->GetTransformMatrix().TransformPoint( seg->m_x, seg->m_y, tx, ty );
492  m_booleng->AddPoint( tx, ty );
493  }
494  m_booleng->EndPolygonAdd();
495  }
496  a2dListOfa2dVertexList& holes = poly->GetHoles();
497  for( a2dListOfa2dVertexList::iterator iterp = holes.begin(); iterp != holes.end(); iterp++ )
498  {
499  a2dVertexListPtr vlist = ( *iterp );
500  if ( vlist->HasArcs() )
501  vlist->ConvertToLines();
502  if ( vlist->size() > 2 && m_booleng->StartHolePolygonAdd( A_or_B ) )
503  {
504  for( a2dVertexList::iterator iter = vlist->begin(); iter != vlist->end(); ++iter )
505  {
506  a2dLineSegment* seg = *iter;
507  poly->GetTransformMatrix().TransformPoint( seg->m_x, seg->m_y, tx, ty );
508  m_booleng->AddPoint( tx, ty );
509  }
510  }
511  m_booleng->EndPolygonAdd();
512  }
513  return true;
514  }
515  else if ( 0 != wxDynamicCast( booleanobject, a2dPolygonL ) )
516  {
517  a2dPolygonL* obj = wxDynamicCast( booleanobject, a2dPolygonL );
518  vpath = obj->GetAsCanvasVpaths();
519  }
520  else if ( 0 != wxDynamicCast( booleanobject, a2dVectorPath ) )
521  {
522  a2dVectorPath* obj = wxDynamicCast( booleanobject, a2dVectorPath );
523  vpath = obj->GetAsCanvasVpaths();
524  }
525  else if ( 0 != wxDynamicCast( booleanobject, a2dText ) )
526  {
527  a2dText* obj = wxDynamicCast( booleanobject, a2dText );
528  vpath = obj->GetAsCanvasVpaths();
529  }
530 
531  // now we have vector path, which we will convert to polygons and polylines.
532  // Next only the polygons will be used for boolean operations.
533  if ( vpath != wxNullCanvasObjectList )
534  {
535  bool ret = VectorPathPolygonsToEngine( vpath, A_or_B );
536  delete vpath;
537  return ret;
538  }
539  return false;
540 }
541 
543 {
544  if ( vpath != wxNullCanvasObjectList )
545  {
546  a2dCanvasObjectList::iterator iter = vpath->begin();
547  while ( iter != vpath->end() )
548  {
549  a2dCanvasObjectList* polylist = NULL;
550  a2dVectorPath* obj = ( a2dVectorPath* ) ( *iter ).Get();
551  polylist = obj->GetAsPolygons();
552 
553  for( a2dCanvasObjectList::iterator iterp = polylist->begin(); iterp != polylist->end(); ++iterp )
554  {
555  a2dSmrtPtr<a2dPolylineL> polyl = wxDynamicCast( ( *iterp ).Get(), a2dPolylineL );
556  if ( polyl )
557  {
558  bool returnIsPolygon;
559  a2dSmrtPtr<a2dPolygonL> poly = new a2dPolygonL( polyl->GetAsVertexList( returnIsPolygon ) );
560  if ( poly && poly->GetSegments()->HasArcs() )
561  poly->GetSegments()->ConvertToLines();
562 
563  if ( poly )
564  {
565  if ( poly->GetNumberOfSegments() > 2 && m_booleng->StartPolygonAdd( A_or_B ) )
566  {
567  for( a2dVertexList::const_iterator iter = poly->GetSegments()->begin(); iter != poly->GetSegments()->end(); ++iter )
568  {
569  a2dLineSegment* seg = *iter;
570  m_booleng->AddPoint( seg->m_x, seg->m_y );
571  }
572  m_booleng->EndPolygonAdd();
573  }
574  }
575  }
576  else
577  {
578  a2dPolygonL* poly = wxDynamicCast( ( *iterp ).Get(), a2dPolygonL );
579  if ( poly && poly->GetSegments()->HasArcs() )
580  poly->GetSegments()->ConvertToLines();
581 
582  if ( poly && poly->GetNumberOfSegments() > 2 && m_booleng->StartPolygonAdd( A_or_B ) )
583  {
584  for( a2dVertexList::const_iterator iter = poly->GetSegments()->begin(); iter != poly->GetSegments()->end(); ++iter )
585  {
586  a2dLineSegment* seg = *iter;
587  m_booleng->AddPoint( seg->m_x, seg->m_y );
588  }
589  m_booleng->EndPolygonAdd();
590  }
591  }
592  }
593  delete polylist;
594 
595  iter = vpath->erase( iter );
596  iter = vpath->begin();
597  }
598  return true;
599  }
600  return false;
601 }
602 
603 bool a2dBooleanWalkerHandler::CallEngine( a2dCanvasObject* canobjToAddChildren )
604 {
605  bool foundfirst = false;
606  if ( !m_foundA.empty() || !m_foundB.empty() )
607  {
608  //add all objects which are convertable to polygons, to the boolean engine.
610  {
611  a2dCanvasObject* obj = ( *iter );
612  bool foundObjects = false;
614  foundObjects = GetObjectsForSurface( obj, GROUP_A );
615  else if ( m_operation == Boolean_Surface2Polygon )
616  foundObjects = GetObjectsSurface( obj, GROUP_A );
617  else
618  foundObjects = ConvertToPolygons( obj, GROUP_A );
619  if ( foundObjects )
620  {
621  if ( !foundfirst )
622  {
623  m_useFirstChildStyleStroke = obj->GetStroke();
624  m_useFirstChildStyleFill = obj->GetFill();
625  m_useFirstChildLayer = obj->GetLayer();
626  foundfirst = true;
627  }
628 
629  // if this object has itself children too, preserve those childs by creating
630  // a new object at the end containing those childs.
631  wxString classname = obj->GetClassInfo()->GetClassName();
632  if ( classname != wxT( "a2dCanvasObject" ) && obj->GetChildObjectsCount() )
633  {
634  a2dCanvasObject* holdChildRes = new a2dCanvasObject();
635  holdChildRes->SetTransformMatrix( obj->GetTransformMatrix() );
636  holdChildRes->CreateChildObjectList()->TakeOverFrom( obj->GetChildObjectList() );
637  canobjToAddChildren->Prepend( holdChildRes );
638  }
639 
640  if ( m_releaseOrignals )
641  //now the old object can be released.
642  obj->SetRelease( true );
643  //canobjToAddChildren->ReleaseChild( obj, false, false, false );
644  }
645  }
646 
647  {
648  //scope
650  {
651  a2dCanvasObject* obj = ( *iter );
652  bool foundObjects = false;
654  foundObjects = ConvertToPolygons( obj, GROUP_B );
655  if ( foundObjects )
656  {
657  if ( !foundfirst )
658  {
659  m_useFirstChildStyleStroke = obj->GetStroke();
660  m_useFirstChildStyleFill = obj->GetFill();
661  m_useFirstChildLayer = obj->GetLayer();
662  foundfirst = true;
663  }
664 
665  // if this object has itself children too, preserve those childs by creating
666  // a new object at the end containing those childs.
667  wxString classname = obj->GetClassInfo()->GetClassName();
668  if ( classname != wxT( "a2dCanvasObject" ) && obj->GetChildObjectsCount() )
669  {
670  a2dCanvasObject* holdChildRes = new a2dCanvasObject();
671  holdChildRes->SetTransformMatrix( obj->GetTransformMatrix() );
672  holdChildRes->CreateChildObjectList()->TakeOverFrom( obj->GetChildObjectList() );
673  canobjToAddChildren->Prepend( holdChildRes );
674  }
675 
676  if ( m_releaseOrignals )
677  //now the old object can be released.
678  obj->SetRelease( true );
679  //canobjToAddChildren->ReleaseChild( obj, false, false, false );
680  }
681  }
682  }//endscope
683 
684 
685 
686  BOOL_OP boolOp = BOOL_NON;
687  if ( m_operation == Boolean_NON )
688  {
689  }
690  else if ( m_operation == Boolean_OR )
691  boolOp = BOOL_OR;
692  else if ( m_operation == Boolean_AND )
693  boolOp = BOOL_AND;
694  else if ( m_operation == Boolean_EXOR )
695  boolOp = BOOL_EXOR;
696  else if ( m_operation == Boolean_A_SUB_B )
697  boolOp = BOOL_A_SUB_B;
698  else if ( m_operation == Boolean_B_SUB_A )
699  boolOp = BOOL_B_SUB_A;
700  else if ( m_operation == Boolean_CORRECTION )
701  boolOp = BOOL_CORRECTION;
702  else if ( m_operation == Boolean_SMOOTHEN )
703  boolOp = BOOL_SMOOTHEN;
704  else if ( m_operation == Boolean_MAKERING )
705  boolOp = BOOL_MAKERING;
706  else if ( m_operation == Boolean_Polygon2Surface )
707  {
708  // this merges the polygons and gives non linked holes, leading too surfaces in the end.
709  boolOp = BOOL_OR;
710  m_booleng->SetLinkHoles( false );
711  }
712  else if ( m_operation == Boolean_Surface2Polygon )
713  boolOp = BOOL_OR;
714 
715  m_booleng->Do_Operation( boolOp );
716 
717  // foreach resultant polygon in the booleng ...
718  // When we want surfaces, that will only work if holes were not linked by engine.
719  if ( m_booleng->GetLinkHoles() )
720  {
721  while ( m_booleng->StartPolygonGet() )
722  {
723  a2dVertexList* points = new a2dVertexList;
724  // foreach point in the polygon
725  while ( m_booleng->PolygonHasMorePoints() )
726  {
727  a2dLineSegment* seg = new a2dLineSegment( m_booleng->GetPolygonXPoint(), m_booleng->GetPolygonYPoint() );
728  points->push_back( seg );
729  if ( m_booleng->GetHoleConnectionSegment() )
730  {
731  seg->SetSegType( a2dLINK_SEG );
732  }
733  else if ( m_booleng->GetHoleSegment() )
734  {
735  seg->SetSegType( a2dHOLE_SEG );
736  }
737  }
738  m_booleng->EndPolygonGet();
739 
740  a2dPolygonL* polygon = new a2dPolygonL( points );
741  polygon->SetLayer( !m_resultOnSameLayer ? m_target : m_useFirstChildLayer );
742  if ( !m_resultStroke.IsNoStroke() )
743  polygon->SetStroke( m_resultStroke );
744  else if ( m_useFirstChildStyle )
745  polygon->SetStroke( m_useFirstChildStyleStroke );
746 
747  if ( !m_resultFill.IsNoFill() )
748  polygon->SetFill( m_resultFill );
749  else if ( m_useFirstChildStyle )
750  polygon->SetFill( m_useFirstChildStyleFill );
751  polygon->SetBin( true );
752  polygon->SetBin2( true );
753 
754  // prepend, because object with children are appended at the end, and will still be processed
755  canobjToAddChildren->Prepend( polygon );
756  }
757  }
758  else
759  {
760  bool hole = false;
761  bool normal = false;
762  a2dSurface* surface = NULL;
763  a2dVertexListPtr points;
764  a2dVertexListPtr holepoints;
765  while ( m_booleng->StartPolygonGet() )
766  {
767  hole = false;
768  normal = false;
769  // foreach point in the polygon
770  while ( m_booleng->PolygonHasMorePoints() )
771  {
772  if ( m_booleng->GetHoleConnectionSegment() )
773  {
774  wxFAIL_MSG( wxT( "this type should not be here" ) );
775  }
776  else if ( m_booleng->GetHoleSegment() )
777  {
778  if ( !hole )
779  {
780  hole = true;
781  holepoints = new a2dVertexList;
782  }
783  a2dLineSegment* seg = new a2dLineSegment( m_booleng->GetPolygonXPoint(), m_booleng->GetPolygonYPoint() );
784  seg->SetSegType( a2dHOLE_SEG );
785  holepoints->push_back( seg );
786  }
787  else //normal
788  {
789  if ( !normal )
790  {
791  normal = true;
792  points = new a2dVertexList;
793  }
794  a2dLineSegment* seg = new a2dLineSegment( m_booleng->GetPolygonXPoint(), m_booleng->GetPolygonYPoint() );
795  points->push_back( seg );
796  }
797  }
798  m_booleng->EndPolygonGet();
799  if ( normal )
800  {
801  surface = new a2dSurface( points );
802  surface->SetLayer( !m_resultOnSameLayer ? m_target : m_useFirstChildLayer );
803  if ( !m_resultStroke.IsNoStroke() )
804  surface->SetStroke( m_resultStroke );
805  else if ( m_useFirstChildStyle )
806  surface->SetStroke( m_useFirstChildStyleStroke );
807 
808  if ( !m_resultFill.IsNoFill() )
809  surface->SetFill( m_resultFill );
810  else if ( m_useFirstChildStyle )
811  surface->SetFill( m_useFirstChildStyleFill );
812  surface->SetBin( true );
813  surface->SetBin2( true );
814 
815  // prepend, because object with children are appended at the end, and will still be processed
816  canobjToAddChildren->Prepend( surface );
817  }
818  if ( hole )
819  {
820  wxASSERT_MSG( surface, wxT( "need surface first to place holes within" ) );
821  surface->AddHole( holepoints );
822  }
823  }
824  }
825 
826  // not of use anymore.
827  m_foundA.clear();
828  m_foundB.clear();
829  canobjToAddChildren->SetBin( true );
830  }
831  return true;
832 }
833 #endif //wxART2D_USE_KBOOL
bool GetObjectsSurface(a2dCanvasObject *booleanobject, GroupType A_or_B)
search objects that are Surface and add them to m_foundA
Definition: booloper.cpp:375
set check on a2dObject flag false or true
Definition: algos.h:665
a2dCircle at x,y, and with radius
Definition: canprim.h:554
static const a2dCanvasObjectFlagsMask BIN
Definition: candefs.h:192
A2DGENERALDLLEXP long wxGenNewId()
This function is like wxNewId, but it has its own ID set.
Definition: gen.cpp:92
#define wxDynamicCast(obj, className)
Define wxDynamicCast so that it will give a compiler error for unrelated types.
Definition: gen.h:75
bool IsNoStroke() const
Definition: stylebase.h:510
a2dCanvasObjectList * CreateChildObjectList()
create and get the list where the child objects are stored in.
Definition: canobj.cpp:2561
void SetSegType(a2dSegType type)
Set the type of the segment.
Definition: polyver.h:224
const a2dError a2dError_CommandError
a2dCanvasObjectList * GetAsCanvasVpaths(bool transform=true) const
when implemented the object without its children, is converted to
Definition: canprim.cpp:2075
virtual wxString GetName() const
Returns the name of this object, if no name is given the internal id will be returned.
Definition: gen.cpp:1310
const a2dAffineMatrix & GetTransformMatrix() const
get the matrix used to position the object
Definition: canobj.h:500
void SetRelease(bool value)
set release flag
Definition: gen.h:1346
a2dCanvasObjectList * GetAsCanvasVpaths(bool transform=true) const
when implemented the object without its children, is converted to
Definition: canprim.cpp:1211
void ConvertToLines(double aberation=0)
Convert complex segments to line segments.
Definition: polyver.cpp:1948
unsigned int GetChildObjectsCount() const
get number of child objects
Definition: canobj.cpp:2570
static const a2dCanvasObjectFlagsMask BIN2
Definition: candefs.h:193
static const long Boolean_Surface2Polygon
Definition: booloper.h:54
Bool_Engine * m_booleng
the boolean engine
Definition: booloper.h:142
a2dCanvasObjectList * GetAsCanvasVpaths(bool transform=true) const
when implemented the object without its children, is converted to
Definition: canprim.cpp:408
polygon defined with list of points.
Definition: polygon.h:45
virtual bool Start(a2dCanvasObject *object)
called for boolean operation
Definition: booloper.cpp:117
a2dCanvasObjectList * GetAsPolygons()
convert to a list of a2dPolygonL and a2dPolylineL
Definition: vpath.cpp:116
void SetTransformMatrix(const a2dAffineMatrix &mat=a2dIDENTITY_MATRIX)
Returns the matrix used to position the object.
Definition: canobj.h:509
a2dCanvasObjectList * GetAsCanvasVpaths(bool transform=true) const
when implemented the object without its children, is converted to
Definition: vpath.cpp:67
a2dObject * Clone(CloneOptions options, a2dRefMap *refs=NULL) const
create an exact copy of this property
Definition: gen.cpp:1199
bool m_releaseOrignals
when an object takes part in operation, and this flag is true, the original is removed.
Definition: booloper.h:157
bool IsNoFill() const
Definition: stylebase.h:273
a2dCanvasObjectList * GetAsCanvasVpaths(bool transform=true) const
return the arrow converted to a vector path.
Definition: canprim.cpp:216
a2dRectC is a centered rectangle
Definition: canprim.h:99
a2dCanvasObjectList m_foundB
objects found for groupB
Definition: booloper.h:163
static const long Boolean_MAKERING
Definition: booloper.h:52
const long a2dWalkEvent
Definition: gen.h:3842
void Initialize()
used from constructors
Definition: algos.cpp:386
a2dCanvasObjectList m_foundA
objects found for groupA
Definition: booloper.h:160
wxUint16 m_lastdepth
to keep track of levels to do boolean operations
Definition: booloper.h:166
a2dLayerGroup m_groupB
group B layers operand
Definition: algos.h:887
a2dStroke m_resultStroke
Definition: booloper.h:145
a2dCanvasObject is the base class for Canvas Objects.
Definition: canobj.h:371
this segmnet is part of a hole
Definition: polyver.h:152
bool m_depthFirst
Definition: gen.h:4000
a2dCanvasObjectList * GetChildObjectList()
get the list where the child objects are stored in.
Definition: canobj.cpp:2551
vertex list of line and arc segments.
Definition: polyver.h:600
void TransformPoint(double x, double y, double &tx, double &ty) const
Transform a point.
Definition: afmatrix.cpp:559
bool WalkTask(wxObject *parent, wxObject *object, a2dWalkEvent event)
called from within a2dCanvasDocument
Definition: booloper.cpp:144
bool GetSelected() const
is the object selected flag set
Definition: canobj.h:1603
a2dCanvasObjectList * GetAsCanvasVpaths(bool transform=true) const
when implemented the object without its children, is converted to
Definition: polygon.cpp:133
static const long Boolean_NON
Definition: booloper.h:44
virtual a2dVertexList * GetAsVertexList(bool &returnIsPolygon) const
convert to a polygon.
Definition: polygon.cpp:1853
void SetBin(bool bin)
general flag use at will.
Definition: canobj.h:2259
A2DGENERALDLLEXP a2dWalkEvent a2dWalker_a2dObjectStart
id for a2dWalkEvent issued from within a2dWalkerIOHandler
A2DGENERALDLLEXP a2dWalkEvent a2dWalker_a2dCanvasObjectPostChild
id for a2dWalkEvent issued from within a2dWalkerIOHandler
wxUint64 a2dCanvasObjectFlagsMask
mask flags for a2dCanvasObject
Definition: candefs.h:152
bool GetCheck() const
general flag use at will.
Definition: gen.h:1342
a2dText is an abstract base class.
Definition: cantext.h:93
a2dCanvasObjectList * wxNullCanvasObjectList
define a NON a2dCanvasObjectList
Definition: objlist.cpp:53
bool HasArcs() const
return true if there are a2dArcSegment segments.
Definition: polyver.cpp:1761
a2dCanvasObjectList * GetAsCanvasVpaths(bool transform=true) const
when implemented the object without its children, is converted to
Definition: canprim.cpp:2390
#define forEachIn(listtype, list)
easy iteration for a2dlist
Definition: a2dlist.h:111
a2dEllipse centered at x,y.
Definition: canprim.h:635
polyline defined with list of points.
Definition: polygon.h:332
a2dVertexListPtr GetSegments()
Get the list of points ( this is not a copy! )
Definition: polygon.h:219
Normal straight line segment in a2dVertexList and a2dVertexArray.
Definition: polyver.h:163
a2dSLine
Definition: canprim.h:987
static const long Boolean_AND
Definition: booloper.h:46
Operation m_operation
id for operation
Definition: algos.h:998
A2DGENERALDLLEXP a2dSmrtPtr< a2dGeneralGlobal > a2dGeneralGlobals
a global pointer to get to global instance of important classes.
Definition: comevt.cpp:1148
a2dCanvasObjectList * GetAsCanvasVpaths(bool transform=true) const
return text as a vector path, where text outline is converted to polyline or polygons.
Definition: cantext.cpp:247
wxUint16 GetLayer() const
Returns the layer index where this object is drawn upon.
Definition: canobj.h:2368
void Prepend(a2dCanvasObject *obj)
prepend a a2dCanvasObject to the childobjects
Definition: canobj.cpp:6209
bool GetBin() const
general flag use at will.
Definition: canobj.h:2262
A2DGENERALDLLEXP a2dWalkEvent a2dWalker_a2dObjectEnd
id for a2dWalkEvent issued from within a2dWalkerIOHandler
const a2dFill * a2dNullFILL
global a2dFill stock object for defining NO filling
bool GetObjectsForSurface(a2dCanvasObject *booleanobject, GroupType A_or_B)
search objects that are convertable to Surface and add them to m_foundA
Definition: booloper.cpp:290
A2DGENERALDLLEXP a2dWalkEvent a2dWalker_a2dPropertyStart
id for a2dWalkEvent issued from within a2dWalkerIOHandler
a2dArrow is used for having line begin and ends on specific objects.
Definition: canprim.h:198
set a2dCanvasObjects flags in a hierarchy of a a2dCanvasDocument
Definition: algos.h:486
A2DGENERALDLLEXP a2dWalkEvent a2dWalker_a2dCanvasObjectStart
id for a2dWalkEvent issued from within a2dWalkerIOHandler
void SetCheck(bool check)
general flag use at will.
Definition: gen.h:1339
bool ConvertToPolygons(a2dCanvasObject *booleanobject, GroupType A_or_B)
convert obj to polygons and add to m_foundA and m_foundB
Definition: booloper.cpp:420
a2dCanvasObjectList * GetAsCanvasVpaths(bool transform=true) const
when implemented the object without its children, is converted to
Definition: canprim.cpp:1762
void Initialize()
used from constructor
Definition: booloper.cpp:54
boolean operation on primitives in a a2dDocument.
const a2dStroke * a2dNullSTROKE
global a2dStroke stock object for NO stroking
A2DGENERALDLLEXP a2dWalkEvent a2dWalker_a2dCanvasObjectEnd
id for a2dWalkEvent issued from within a2dWalkerIOHandler
int m_currentDepth
contour to be used by algorithm, to decide on how deep recursing is to be.
Definition: gen.h:3996
virtual double GetContourWidth() const
get the Contour width of the shape
Definition: canobj.h:1411
double m_x
x endpoint of line
Definition: polyver.h:232
polygon defined with list of points for outer contour plus a list of hole polygons ...
Definition: polygon.h:502
a2dVertexListPtr GetSegments()
Get the list of points ( this is not a copy! )
Definition: polygon.h:546
a2dCanvasObjectList * GetAsCanvasVpaths(bool transform=true) const
when implemented the object without its children, is converted to
Definition: polygon.cpp:1869
double m_y
y endpoint of line
Definition: polyver.h:235
void SetStroke(const wxColour &strokecolor, double width=0, a2dStrokeStyle style=a2dSTROKE_SOLID)
Set a stroke for the object which will be used instead of the layer stroke.
Definition: canobj.cpp:2924
int TakeOverFrom(a2dCanvasObjectList *total, const wxString &type=wxT(""), a2dCanvasObjectFlagsMask mask=a2dCanvasOFlags::ALL, const a2dPropertyId *id=NULL)
Move objects fitting the given filter from the total list to this list.
Definition: objlist.cpp:724
static const long Boolean_B_SUB_A
Definition: booloper.h:49
static const long Boolean_A_SUB_B
Definition: booloper.h:48
bool VectorPathPolygonsToEngine(a2dCanvasObjectList *vpath, GroupType A_or_B)
vector path split ino polygons, and added to engine
Definition: booloper.cpp:542
A2DGENERALDLLEXP a2dWalkEvent a2dWalker_a2dPropertyEnd
id for a2dWalkEvent issued from within a2dWalkerIOHandler
static const long Boolean_CORRECTION
Definition: booloper.h:50
a2dCanvasObjectList * GetAsCanvasVpaths(bool transform=true) const
when implemented the object without its children, is converted to
Definition: canprim.cpp:3222
a2dEndsLine with begin and/or end object.
Definition: canprim.h:1174
a2dLayerGroup m_groupA
group A layers operand
Definition: algos.h:884
bool Start(a2dCanvasObject *object, bool setTo)
start removing properties from the object given, and down.
Definition: algos.cpp:784
size_t GetNumberOfSegments()
get the number of points in the pointlist
Definition: polygon.h:556
bool m_useCheck
if set a2dObject are only walked if not m_check is set
Definition: gen.h:4003
bool m_useFirstChildStyle
use first child style or not.
Definition: booloper.h:151
holds a list of layers numbers
Definition: canglob.h:60
static const long Boolean_OR
Definition: booloper.h:45
a2dRect
Definition: canprim.h:440
bool ObjectOke(a2dCanvasObject *obj)
return true if object fits the filter
Definition: algos.cpp:427
a2dArc centered at x,y
Definition: canprim.h:823
int m_depth
wanted depth
Definition: algos.h:318
all headers of the canvas module
a2dCanvasObject for a Vector Path
Definition: vpath.h:55
size_t GetNumberOfSegments()
get the number of points in the pointlist
Definition: polygon.h:229
algorithm to delete a2dCanvasObjects on layers or to move, copy to other layers
Definition: algos.h:911
links an outside contour with a hole
Definition: polyver.h:150
virtual void SetLayer(wxUint16 layer)
set layer index where this object is drawn upon.
Definition: canobj.cpp:5920
bool m_clearTarget
clear the target layer before adding result.
Definition: booloper.h:154
a2dCanvasObjectList * GetAsCanvasVpaths(bool transform=true) const
when implemented the object without its children, is converted to
Definition: canprim.cpp:3950
wxUint16 m_target
result into this layer
Definition: algos.h:890
static const long Boolean_Polygon2Surface
Definition: booloper.h:53
A pointer class, that automatically calls SmrtPtrOwn/SmrtPtrRelease.
Definition: a2dlist.h:20
void SetStopWalking(bool stopWalking)
to further recursion, e.g. in a2dObject::Walker()
Definition: gen.h:3931
bool Start(a2dObject *object)
start removing properties from the object given, and down.
Definition: algos.h:634
static const long Boolean_EXOR
Definition: booloper.h:47
bool m_selectedOnlyB
work only on selected object in group B
Definition: algos.h:895
bool m_selectedOnlyA
work only on selected object in group A
Definition: algos.h:893
void SetFill(const a2dFill &fill)
Set a fill for the object which will be used instead of the layer fill.
Definition: canobj.cpp:2874
a2dEllipticArc centered at x,y
Definition: canprim.h:697
static const long Boolean_SMOOTHEN
Definition: booloper.h:51
booloper.cpp Source File -- Sun Oct 12 2014 17:04:12 -- Sun Oct 12 2014 -- 1.8.5 -- wxArt2D -- . -- Main Page Reference Documentation