1 /*! \file kbool/include/kbool/booleng.h
2     \author Klaas Holwerda
3 
4     Copyright: 2001-2004 (C) Klaas Holwerda
5 
6     Licence: see kboollicense.txt
7 
8     RCS-ID: $Id: booleng.h,v 1.3 2005/06/11 19:25:12 frm Exp $
9 */
10 
11 #ifndef BOOLENG_H
12 #define BOOLENG_H
13 
14 #if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
15 #pragma interface
16 #endif
17 
18 
19 #include <stdio.h>
20 #include <limits.h>
21 
22 
23 #ifdef A2DKBOOLMAKINGDLL
24 #define A2DKBOOLDLLEXP WXEXPORT
25 #define A2DKBOOLDLLEXP_DATA(type) WXEXPORT type
26 #define A2DKBOOLDLLEXP_CTORFN
27 #elif defined(WXUSINGDLL)
28 #define A2DKBOOLDLLEXP WXIMPORT
29 #define A2DKBOOLDLLEXP_DATA(type) WXIMPORT type
30 #define A2DKBOOLDLLEXP_CTORFN
31 #else // not making nor using DLL
32 #define A2DKBOOLDLLEXP
33 #define A2DKBOOLDLLEXP_DATA(type) type
34 #define A2DKBOOLDLLEXP_CTORFN
35 #endif
36 
37 #define KBOOL_VERSION "1.8"
38 
39 #define KBOOL_DEBUG 0
40 #define KBOOL_LOG 0
41 #define KBOOL_INT64 1
42 
43 class KBoolLink;
44 
45 #define LINELENGTH 200
46 
47 #ifdef  MAXDOUBLE
48 #undef  MAXDOUBLE
49 #endif
50 #define MAXDOUBLE 1.7976931348623158e+308
51 
52 #ifdef KBOOL_INT64
53 
54 #if defined(__UNIX__) || defined(__GNUG__)
55 
56 typedef long long B_INT;		   // 8 bytes integer
57 //#define MAXB_INT LONG_LONG_MAX
58 //#define MINB_INT LONG_LONG_MIN	// 8 bytes integer
59 #ifndef MAXB_INT
60  const B_INT MAXB_INT = (0x7fffffffffffffffLL);             // 8 bytes integer
61 #endif
62 #ifndef MINB_INT
63  const B_INT MINB_INT = (0x8000000000000000LL);
64 #endif
65 
66 #else //defined(__UNIX__) || defined(__GNUG__)
67 
68 typedef __int64 B_INT;		   // 8 bytes integer
69 #undef MAXB_INT
70 #undef MINB_INT
71 
72 const B_INT MAXB_INT = (0x7fffffffffffffff);             // 8 bytes integer
73 const B_INT MINB_INT = (0x8000000000000000);
74 
75 #endif //defined(__UNIX__) || defined(__GNUG__)
76 
77 #else //KBOOL_INT64
78 
79 #if defined(__UNIX__) || defined(__GNUG__)
80 typedef long B_INT;		   // 4 bytes integer
81 const B_INT MAXB_INT = (0x7fffffffL);             // 4 bytes integer
82 const B_INT MINB_INT = (0x80000000L);
83 #else
84 typedef long B_INT;		   // 4 bytes integer
85 const B_INT MAXB_INT = (0x7fffffff);             // 4 bytes integer
86 const B_INT MINB_INT = (0x80000000);
87 #endif
88 
89 #endif //KBOOL_INT64
90 
91 B_INT babs(B_INT);
92 
93 #ifdef  M_PI
94 #undef  M_PI
95 #endif
96 #define M_PI		(3.1415926535897932384626433832795028841972)
97 
98 #ifdef  M_PI_2
99 #undef  M_PI_2
100 #endif
101 #define M_PI_2      1.57079632679489661923
102 
103 #ifdef  M_PI_4
104 #undef  M_PI_4
105 #endif
106 #define M_PI_4      0.785398163397448309616
107 
108 #ifndef NULL
109 #define NULL 0
110 #endif
111 
112 B_INT bmin(B_INT const value1, B_INT const value2);
113 B_INT bmax(B_INT const value1, B_INT const value2);
114 
115 B_INT bmin(B_INT value1, B_INT value2);
116 B_INT bmax(B_INT value1, B_INT value2);
117 
118 #include <string.h>
119 
120 //! errors in the boolean algorithm will be thrown using this class
121 class A2DKBOOLDLLEXP Bool_Engine_Error
122 {
123 	public:
124 		Bool_Engine_Error(const char* message, const char* header=0, int degree = 9, int fatal = 0);
125 		Bool_Engine_Error(const Bool_Engine_Error& a);
126 		~Bool_Engine_Error();
127 		char*	GetErrorMessage();
128 		char* GetHeaderMessage();
129 		int	GetErrorDegree();
130 		int	GetFatal();
131 
132 	protected:
133 		char*	_message;
134 		char*	_header;
135 		int 	_degree;
136 		int 	_fatal;
137 };
138 
139 
140 #define KBOOL_LOGFILE "kbool.log"
141 
142 enum kbEdgeType
143 {
144    KB_OUTSIDE_EDGE, /*!< edge of the outside contour of a polygon */
145    KB_INSIDE_EDGE,  /*!< edge of the inside hole a polygon */
146    KB_FALSE_EDGE    /*!< edge to connect holes into polygons */
147 } ;
148 
149 enum GroupType
150 {
151    GROUP_A, /*!< to set Group A for polygons */
152    GROUP_B  /*!< to set Group A for polygons */
153 };
154 
155 enum BOOL_OP
156 {
157    BOOL_NON, /*!< No operation */
158    BOOL_OR, /*!< boolean OR operation */
159    BOOL_AND, /*!< boolean AND operation */
160    BOOL_EXOR, /*!< boolean EX_OR operation */
161    BOOL_A_SUB_B, /*!< boolean Group A - Group B operation */
162    BOOL_B_SUB_A, /*!< boolean Group B - Group A operation */
163    BOOL_CORRECTION, /*!< polygon correction/offset operation */
164    BOOL_SMOOTHEN, /*!< smooth operation */
165    BOOL_MAKERING /*!< create a ring on all polygons */
166 };
167 
168 class GraphList;
169 class Graph;
170 class KBoolLink;
171 class Node;
172 template<class Type> class TDLI;
173 
174 //! boolean engine to perform operation on two sets of polygons.
175 /*
176 	First the engine needs to be filled with polygons.
177 	The first operand in the operation is called group A polygons, the second group B.
178 	The boolean operation ( BOOL_OR, BOOL_AND, BOOL_EXOR, BOOL_A_SUB_B, BOOL_B_SUB_A )
179 	are based on the two sets of polygons in group A and B.
180 	The other operation on group A only.
181 
182     At the end of the operation the resulting polygons can be extracted.
183 */
184 class A2DKBOOLDLLEXP Bool_Engine {
185 
186   public:
187 
188    //! constructor
189    Bool_Engine();
190 
191    //! destructor
192    virtual ~Bool_Engine();
193 
GetVersion()194    const char* GetVersion() { return KBOOL_VERSION; }
195 
196 	//! reports progress of algorithm.
197    virtual void SetState( const char* = 0 );
198 
199 	//! called at an internal error.
200 	virtual void error(const char *text, const char *title);
201 
202 	//! called at an internal generated possible error.
203    virtual void info(const char *text, const char *title);
204 
205    bool Do_Operation(BOOL_OP operation);
206 
207 
208    //! distance within which points and lines will be snapped towards lines and other points
209    /*
210          The algorithm takes into account gaps and inaccuracies caused by rounding to integer coordinates
211          in the original data.
212          Imagine two rectangles one with a side ( 0,0 ) ( 2.0, 17.0 )
213          and the other has a side ( 0,0 ) ( 1.0, 8.5 )
214          If for some reason those coordinates where round to ( 0,0 ) ( 2, 17 ) ( 0,0 ) ( 1, 9 ),
215          there will be clearly a gap or overlap that was not intended.
216          Even without rounding this effect takes place since there is always a minimum significant bit
217          also when using doubles.
218 
219          If the user used as minimum accuracy 0.001, you need to choose Marge > 0.001
220          The boolean engine scales up the input data with GetDGrid() * GetGrid() and rounds the result to
221          integer, So (assuming GRID = 100 DGRID = 1000)  a vertex of 123.001 in the user data will
222          become 12300100 internal.
223          At the end of the algorithm the internal vertexes are scaled down again with GetDGrid() * GetGrid(),
224          so 12300103 becomes 123.00103 eventually.
225          So indeed the minimum accuracy might increase, you are free to round again if needed.
226    */
227    void SetMarge(double marge);
228    double GetMarge();
229 
230    //! input points are scaled up with GetDGrid() * GetGrid()
231    /*
232 		Grid makes sure that the integer data used within the algorithm has room for extra intersections
233 		smaller than the smallest number within the input data.
234 		The input data scaled up with DGrid is related to the accuracy the user has in his input data.
235         Another scaling with Grid is applied on top of it to create space in the integer number for
236 		even smaller numbers.
237    */
238    void SetGrid(B_INT grid);
239 
240 	//! See SetGrid
241    B_INT GetGrid();
242 
243    //! input points are scaled up with GetDGrid() * GetGrid()
244    /*
245       The input data scaled up with DGrid is related to the accuracy the user has in his input data.
246       User data with a minimum accuracy of 0.001, means set the DGrid to 1000.
247       The input data may contain data with a minimum accuracy much smaller, but by setting the DGrid
248       everything smaller than 1/DGrid is rounded.
249 
250       DGRID is only meant to make fractional parts of input data which can be
251       doubles, part of the integers used in vertexes within the boolean algorithm.
252       And therefore DGRID bigger than 1 is not usefull, you would only loose accuracy.
253       Within the algorithm all input data is multiplied with DGRID, and the result
254       is rounded to an integer.
255    */
256    void SetDGrid(double dgrid);
257 
258 	//! See SetDGrid
259    double GetDGrid();
260 
261    //! When doing a correction operation ( also known as process offset )
262 	//! this defines the detail in the rounded corners.
263 	/*
264 		Depending on the round factor the corners of the polygon may be rounding within the correction
265 		algorithm. The detail within this rounded corner is set here.
266 		It defines the deviation the generated segments in arc like polygon may have towards the ideal
267 		rounded corner using a perfect arc.
268     */
269    void SetCorrectionAber(double aber);
270 
271 	//! see SetCorrectionAber
272    double GetCorrectionAber();
273 
274    //! When doing a correction operation ( also known as process offset )
275 	//! this defines the amount of correction.
276    /*
277       The correction algorithm can apply positive and negative offset to polygons.
278       It takes into account closed in areas within a polygon, caused by overlapping/selfintersecting
279       polygons. So holes form that way are corrected proberly, but the overlapping parts itself
280       are left alone. An often used trick to present polygons with holes by linking to the outside
281       boundary, is therefore also handled properly.
282       The algoritm first does a boolean OR operation on the polygon, and seperates holes and
283       outside contours.
284       After this it creates a ring shapes on the above holes and outside contours.
285       This ring shape is added or subtracted from the holes and outside contours.
286       The result is the corrected polygon.
287       If the correction factor is > 0, the outside contours will become larger, while the hole contours
288       will become smaller.
289    */
290    void SetCorrectionFactor(double aber);
291 
292 	//! see SetCorrectionFactor
293    double GetCorrectionFactor();
294 
295 	//! used within the smooth algorithm to define how much the smoothed curve may deviate
296 	//! from the original.
297    void SetSmoothAber(double aber);
298 
299 	//! see SetSmoothAber
300    double GetSmoothAber();
301 
302 	//! segments of this size will be left alone in the smooth algorithm.
303    void SetMaxlinemerge(double maxline);
304 
305 	//! see SetMaxlinemerge
306    double GetMaxlinemerge();
307 
308 	//! Polygon may be filled in different ways (alternate and winding rule).
309 	//! This here defines which method will be assumed within the algorithm.
310    void SetWindingRule(bool rule);
311 
312 	//! see SetWindingRule
313    bool GetWindingRule();
314 
315 	//! the smallest accuracy used within the algorithm for comparing two real numbers.
316    double GetAccur();
317 
318     //! Used with in correction/offset algorithm.
319 	/*
320 		When the polygon contains sharp angles ( < 90 ), after a positive correction the
321 		extended parrallel constructed offset lines may leed to extreme offsets on the angles.
322 		The length of the crossing generated by the parrallel constructed offset lines
323 		towards the original point in the polygon is compared to the offset which needs to be applied.
324 		The Roundfactor then decides if this corner will be rounded.
325 		A Roundfactor of 1 means that the resulting offset will not be bigger then the correction factor
326 		set in the algorithm. Meaning even straight 90 degrees corners will be rounded.
327 		A Roundfactor of > sqrt(2) is where 90 corners will be left alone, and smaller corners will be rounded.
328 	*/
329 	void SetRoundfactor(double roundfac);
330 
331 	//! see SetRoundfactor
332    double GetRoundfactor();
333 
334 // the following are only be used within the algorithm,
335 // since they are scaled with m_DGRID
336 
337    //! only used internal.
338    void SetInternalMarge( B_INT marge );
339    //! only used internal.
340    B_INT GetInternalMarge();
341 
342    //! only used internal.
343    double GetInternalCorrectionAber();
344 
345    //! only used internal.
346    double GetInternalCorrectionFactor();
347 
348    //! only used internal.
349    double GetInternalSmoothAber();
350 
351    //! only used internal.
352    B_INT GetInternalMaxlinemerge();
353 
354    //! in this mode polygons add clockwise, or contours,
355    /*!
356        and polygons added counter clockwise or holes.
357    */
SetOrientationEntryMode(bool orientationEntryMode)358    void SetOrientationEntryMode( bool orientationEntryMode ) { m_orientationEntryMode = orientationEntryMode; }
359 
360 	//! see SetOrientationEntryMode()
GetOrientationEntryMode()361    bool GetOrientationEntryMode() { return m_orientationEntryMode; }
362 
363    //! if set true holes are linked into outer contours by double overlapping segments.
364    /*!
365        This mode is needed when the software using the boolean algorithm does
366        not understand hole polygons. In that case a contour and its holes form one
367        polygon. In cases where software understands the concept of holes, contours
368        are clockwise oriented, while holes are anticlockwise oriented.
369        The output of the boolean operations, is following those rules also.
370        But even if extracting the polygons from the engine, each segment is marked such
371        that holes and non holes and linksegments to holes can be recognized.
372    */
SetLinkHoles(bool doLinkHoles)373    void SetLinkHoles( bool doLinkHoles ) { m_doLinkHoles = doLinkHoles; }
374 
375 	//! see SetLinkHoles()
GetLinkHoles()376    bool GetLinkHoles() { return m_doLinkHoles; }
377 
378    //!lof file will be created when set True
379    void SetLog( bool OnOff );
380 
381    //! used to write to log file
382    void Write_Log(const char *);
383    //! used to write to log file
384    void Write_Log(const char *, const char *);
385    //! used to write to log file
386    void Write_Log(const char *, double);
387    //! used to write to log file
388    void Write_Log(const char *, B_INT);
389 
GetLogFile()390    FILE* GetLogFile() { return m_logfile; }
391 
392     // methods used to add polygons to the eng using points
393 
394    //! Start adding a polygon to the engine
395    /*
396       The boolean operation work on two groups of polygons ( group A or B ),
397       other algorithms are only using group A.
398 
399       You add polygons like this to the engine.
400 
401       // foreach point in a polygon ...
402       if (booleng->StartPolygonAdd(GROUP_A))
403       {
404 	      booleng->AddPoint(100,100);
405 	      booleng->AddPoint(-100,100);
406 	      booleng->AddPoint(-100,-100);
407 	      booleng->AddPoint(100,-100);
408       }
409       booleng->EndPolygonAdd();
410 
411       \param A_or_B defines if the new polygon will be of group A or B
412 
413       Holes or added by adding an inside polygons with opposite orientation compared
414       to another polygon added.
415       So the contour polygon ClockWise, then add counterclockwise polygons for holes, and visa versa.
416       BUT only if m_orientationEntryMode is set true, else all polygons are redirected, and become
417       individual areas without holes.
418       Holes in such a case must be linked into the contour using two extra segments.
419    */
420    bool StartPolygonAdd( GroupType A_or_B );
421 
422    //! see StartPolygonAdd
423    bool AddPoint(double x, double y, int user_data);
424 
425    //! see StartPolygonAdd
426    bool EndPolygonAdd();
427 
428     // methods used to extract polygons from the eng by getting its points
429 
430    //! Use after StartPolygonGet()
GetNumPointsInPolygon()431    int GetNumPointsInPolygon() { return m_numPtsInPolygon ; }
432 
433 	//! get resulting polygons at end of an operation
434 	/*!
435 		// foreach resultant polygon in the booleng ...
436 		while ( booleng->StartPolygonGet() )
437 		{
438 			// foreach point in the polygon
439 			while ( booleng->PolygonHasMorePoints() )
440 			{
441 				fprintf(stdout,"x = %f\t", booleng->GetPolygonXPoint());
442 				fprintf(stdout,"y = %f\n", booleng->GetPolygonYPoint());
443 			}
444 			booleng->EndPolygonGet();
445 		}
446    */
447 	bool StartPolygonGet();
448 
449    //! see StartPolygonGet
450    /*!
451       This iterates through the first graph in the graphlist.
452       Setting the current Node properly by following the links in the graph
453       through its nodes.
454    */
455    bool PolygonHasMorePoints();
456 
457    //! see StartPolygonGet
458    double GetPolygonXPoint();
459 
460    //! see StartPolygonGet
461    double GetPolygonYPoint();
462 
463 	//! in the resulting polygons this tells if the current polygon segment is one
464 	//! used to link holes into the outer contour of the surrounding polygon
465 	bool GetHoleConnectionSegment();
466 
467 	//! in the resulting polygons this tells if the current polygon segment is part
468 	//! of a hole within a polygon.
469 	bool GetHoleSegment();
470 
471    //! an other way to get the type of segment.
472    kbEdgeType GetPolygonPointEdgeType();
473 
474    int GetPolygonPointUserData();
475 
476 	//! see StartPolygonGet()
477    /*!
478       Removes a graph from the graphlist.
479       Called after an extraction of an output polygon was done.
480    */
481 	void EndPolygonGet();
482 
483   private:
484 
485    bool m_doLog;
486 
487    //! contains polygons in graph form
488    GraphList* m_graphlist;
489 
490    double m_MARGE;
491    B_INT  m_GRID;
492    double m_DGRID;
493    double m_CORRECTIONABER;
494    double m_CORRECTIONFACTOR;
495    double m_SMOOTHABER;
496    double m_MAXLINEMERGE;
497    bool   m_WINDINGRULE;
498    double m_ACCUR;
499    double m_ROUNDFACTOR;
500 
501    bool m_orientationEntryMode;
502 
503    bool m_doLinkHoles;
504 
505    //! used in the StartPolygonAdd, AddPt, EndPolygonAdd sequence
506    Graph*    m_GraphToAdd;
507    //! used in the StartPolygonAdd, AddPt, EndPolygonAdd sequence
508    Node*     m_lastNodeToAdd;
509    //! used in the StartPolygonAdd, AddPt, EndPolygonAdd sequence
510    Node*     m_firstNodeToAdd;
511 
512    //! the current group type ( group A or B )
513    GroupType m_groupType;
514 
515    //! used in extracting the points from the resultant polygons
516    Graph* m_getGraph;
517    //! used in extracting the points from the resultant polygons
518    KBoolLink* m_getLink;
519    //! used in extracting the points from the resultant polygons
520    Node* m_getNode;
521    //! used in extracting the points from the resultant polygons
522    double m_PolygonXPoint;
523    //! used in extracting the points from the resultant polygons
524    double m_PolygonYPoint;
525    //! used in extracting the points from the resultant polygons
526    int m_numPtsInPolygon;
527    //! used in extracting the points from the resultant polygons
528    int m_numNodesVisited;
529 
530    FILE* m_logfile;
531 
532 public:
533 
534    //! use in Node to iterate links.
535    TDLI<KBoolLink>* 	_linkiter;
536 
537    //! how many time run intersections fase.
538    unsigned int m_intersectionruns;
539 
540 };
541 
542 #endif
543