clipper 2.9.0
Sign up to get free protection for your applications and to get access to all the features.
- data/Changelog +7 -0
- data/Gemfile +4 -0
- data/LICENSE.bindings +4 -0
- data/LICENSE.clipper +29 -0
- data/README.md +122 -0
- data/Rakefile +2 -0
- data/ext/clipper/clipper.cpp +2495 -0
- data/ext/clipper/clipper.hpp +247 -0
- data/ext/clipper/extconf.rb +6 -0
- data/ext/clipper/rbclipper.cpp +268 -0
- data/lib/clipper/version.rb +7 -0
- metadata +94 -0
@@ -0,0 +1,247 @@
|
|
1
|
+
/*******************************************************************************
|
2
|
+
* *
|
3
|
+
* Author : Angus Johnson *
|
4
|
+
* Version : 2.9 *
|
5
|
+
* Date : 7 December 2010 *
|
6
|
+
* Copyright : Angus Johnson *
|
7
|
+
* *
|
8
|
+
* License: *
|
9
|
+
* Use, modification & distribution is subject to Boost Software License Ver 1. *
|
10
|
+
* http://www.boost.org/LICENSE_1_0.txt *
|
11
|
+
* *
|
12
|
+
* Attributions: *
|
13
|
+
* The code in this library is an extension of Bala Vatti's clipping algorithm: *
|
14
|
+
* "A generic solution to polygon clipping" *
|
15
|
+
* Communications of the ACM, Vol 35, Issue 7 (July 1992) pp 56-63. *
|
16
|
+
* http://portal.acm.org/citation.cfm?id=129906 *
|
17
|
+
* *
|
18
|
+
* Computer graphics and geometric modeling: implementation and algorithms *
|
19
|
+
* By Max K. Agoston *
|
20
|
+
* Springer; 1 edition (January 4, 2005) *
|
21
|
+
* Pages 98 - 106. *
|
22
|
+
* http://books.google.com/books?q=vatti+clipping+agoston *
|
23
|
+
* *
|
24
|
+
*******************************************************************************/
|
25
|
+
|
26
|
+
/*******************************************************************************
|
27
|
+
* *
|
28
|
+
* This is a translation of my Delphi clipper code and is the very first stuff *
|
29
|
+
* I've written in C++ (or C). My apologies if the coding style is unorthodox. *
|
30
|
+
* Please see the accompanying Delphi Clipper library (clipper.pas) for a more *
|
31
|
+
* detailed explanation of the code algorithms. *
|
32
|
+
* *
|
33
|
+
*******************************************************************************/
|
34
|
+
|
35
|
+
#pragma once
|
36
|
+
#ifndef clipper_hpp
|
37
|
+
#define clipper_hpp
|
38
|
+
|
39
|
+
#include <vector>
|
40
|
+
#include <string>
|
41
|
+
|
42
|
+
namespace clipper {
|
43
|
+
|
44
|
+
typedef enum _ClipType { ctIntersection, ctUnion, ctDifference, ctXor } TClipType;
|
45
|
+
typedef enum _PolyType { ptSubject, ptClip } TPolyType;
|
46
|
+
typedef enum _PolyFillType { pftEvenOdd, pftNonZero} TPolyFillType;
|
47
|
+
|
48
|
+
struct TDoublePoint { double X; double Y; };
|
49
|
+
struct TDoubleRect { double left; double top; double right; double bottom; };
|
50
|
+
typedef std::vector< TDoublePoint > TPolygon;
|
51
|
+
typedef std::vector< TPolygon > TPolyPolygon;
|
52
|
+
|
53
|
+
TDoublePoint DoublePoint(const double &X, const double &Y);
|
54
|
+
TPolyPolygon OffsetPolygons(const TPolyPolygon &pts, const double &delta);
|
55
|
+
double Area(const TPolygon &poly);
|
56
|
+
TDoubleRect GetBounds(const TPolygon &poly);
|
57
|
+
bool IsClockwise(const TPolygon &poly);
|
58
|
+
|
59
|
+
//used internally ...
|
60
|
+
typedef enum _EdgeSide { esLeft, esRight } TEdgeSide;
|
61
|
+
typedef enum _IntersectProtects { ipNone = 0,
|
62
|
+
ipLeft = 1, ipRight = 2, ipBoth = 3 } TIntersectProtects;
|
63
|
+
typedef enum _TriState { sFalse, sTrue, sUndefined} TTriState;
|
64
|
+
|
65
|
+
struct TEdge {
|
66
|
+
double x;
|
67
|
+
double y;
|
68
|
+
double xbot;
|
69
|
+
double ybot;
|
70
|
+
double xtop;
|
71
|
+
double ytop;
|
72
|
+
double dx;
|
73
|
+
double tmpX;
|
74
|
+
bool nextAtTop;
|
75
|
+
TPolyType polyType;
|
76
|
+
TEdgeSide side;
|
77
|
+
int windDelta; //1 or -1 depending on winding direction
|
78
|
+
int windCnt;
|
79
|
+
int windCnt2; //winding count of the opposite polytype
|
80
|
+
int outIdx;
|
81
|
+
TEdge *next;
|
82
|
+
TEdge *prev;
|
83
|
+
TEdge *nextInLML;
|
84
|
+
TEdge *nextInAEL;
|
85
|
+
TEdge *prevInAEL;
|
86
|
+
TEdge *nextInSEL;
|
87
|
+
TEdge *prevInSEL;
|
88
|
+
};
|
89
|
+
|
90
|
+
struct TIntersectNode {
|
91
|
+
TEdge *edge1;
|
92
|
+
TEdge *edge2;
|
93
|
+
TDoublePoint pt;
|
94
|
+
TIntersectNode *next;
|
95
|
+
TIntersectNode *prev;
|
96
|
+
};
|
97
|
+
|
98
|
+
struct TLocalMinima {
|
99
|
+
double Y;
|
100
|
+
TEdge *leftBound;
|
101
|
+
TEdge *rightBound;
|
102
|
+
TLocalMinima *nextLm;
|
103
|
+
};
|
104
|
+
|
105
|
+
struct TScanbeam {
|
106
|
+
double Y;
|
107
|
+
TScanbeam *nextSb;
|
108
|
+
};
|
109
|
+
|
110
|
+
struct TPolyPt {
|
111
|
+
TDoublePoint pt;
|
112
|
+
TPolyPt *next;
|
113
|
+
TPolyPt *prev;
|
114
|
+
TTriState isHole;
|
115
|
+
};
|
116
|
+
|
117
|
+
struct TJoinRec {
|
118
|
+
TDoublePoint pt;
|
119
|
+
int idx1;
|
120
|
+
union {
|
121
|
+
int idx2;
|
122
|
+
TPolyPt* outPPt; //horiz joins only
|
123
|
+
};
|
124
|
+
};
|
125
|
+
|
126
|
+
typedef std::vector < TPolyPt * > PolyPtList;
|
127
|
+
typedef std::vector < TJoinRec > JoinList;
|
128
|
+
|
129
|
+
//ClipperBase is the ancestor to the Clipper class. It should not be
|
130
|
+
//instantiated directly. This class simply abstracts the conversion of sets of
|
131
|
+
//polygon coordinates into edge objects that are stored in a LocalMinima list.
|
132
|
+
class ClipperBase
|
133
|
+
{
|
134
|
+
public:
|
135
|
+
ClipperBase();
|
136
|
+
virtual ~ClipperBase();
|
137
|
+
void AddPolygon(const TPolygon &pg, TPolyType polyType);
|
138
|
+
void AddPolyPolygon( const TPolyPolygon &ppg, TPolyType polyType);
|
139
|
+
virtual void Clear();
|
140
|
+
TDoubleRect GetBounds();
|
141
|
+
protected:
|
142
|
+
void DisposeLocalMinimaList();
|
143
|
+
void InsertLocalMinima(TLocalMinima *newLm);
|
144
|
+
TEdge* AddBoundsToLML(TEdge *e);
|
145
|
+
void PopLocalMinima();
|
146
|
+
bool Reset();
|
147
|
+
TLocalMinima *m_CurrentLM;
|
148
|
+
private:
|
149
|
+
TLocalMinima *m_localMinimaList;
|
150
|
+
std::vector< TEdge * > m_edges;
|
151
|
+
};
|
152
|
+
|
153
|
+
class Clipper : public virtual ClipperBase
|
154
|
+
{
|
155
|
+
public:
|
156
|
+
Clipper();
|
157
|
+
~Clipper();
|
158
|
+
bool Execute(TClipType clipType,
|
159
|
+
TPolyPolygon &solution,
|
160
|
+
TPolyFillType subjFillType = pftEvenOdd,
|
161
|
+
TPolyFillType clipFillType = pftEvenOdd);
|
162
|
+
//The ForceOrientation property ensures that polygons that result from a
|
163
|
+
//TClipper.Execute() calls will have clockwise 'outer' and counter-clockwise
|
164
|
+
//'inner' (or 'hole') polygons. If ForceOrientation == false, then the
|
165
|
+
//polygons returned in the solution will have undefined orientation.<br>
|
166
|
+
//Setting ForceOrientation = true results in a minor penalty (~10%) in
|
167
|
+
//execution speed. (Default == true) ***DEPRICATED***
|
168
|
+
bool ForceOrientation();
|
169
|
+
void ForceOrientation(bool value);
|
170
|
+
private:
|
171
|
+
PolyPtList m_PolyPts;
|
172
|
+
JoinList m_Joins;
|
173
|
+
JoinList m_CurrentHorizontals;
|
174
|
+
TClipType m_ClipType;
|
175
|
+
TScanbeam *m_Scanbeam;
|
176
|
+
TEdge *m_ActiveEdges;
|
177
|
+
TEdge *m_SortedEdges;
|
178
|
+
TIntersectNode *m_IntersectNodes;
|
179
|
+
bool m_ExecuteLocked;
|
180
|
+
bool m_ForceOrientation;
|
181
|
+
TPolyFillType m_ClipFillType;
|
182
|
+
TPolyFillType m_SubjFillType;
|
183
|
+
double m_IntersectTolerance;
|
184
|
+
void UpdateHoleStates();
|
185
|
+
void DisposeScanbeamList();
|
186
|
+
void SetWindingDelta(TEdge *edge);
|
187
|
+
void SetWindingCount(TEdge *edge);
|
188
|
+
bool IsNonZeroFillType(TEdge *edge);
|
189
|
+
bool IsNonZeroAltFillType(TEdge *edge);
|
190
|
+
bool InitializeScanbeam();
|
191
|
+
void InsertScanbeam( const double &Y);
|
192
|
+
double PopScanbeam();
|
193
|
+
void InsertLocalMinimaIntoAEL( const double &botY);
|
194
|
+
void InsertEdgeIntoAEL(TEdge *edge);
|
195
|
+
void AddEdgeToSEL(TEdge *edge);
|
196
|
+
void CopyAELToSEL();
|
197
|
+
void DeleteFromSEL(TEdge *e);
|
198
|
+
void DeleteFromAEL(TEdge *e);
|
199
|
+
void UpdateEdgeIntoAEL(TEdge *&e);
|
200
|
+
void SwapPositionsInSEL(TEdge *edge1, TEdge *edge2);
|
201
|
+
bool Process1Before2(TIntersectNode *Node1, TIntersectNode *Node2);
|
202
|
+
bool TestIntersections();
|
203
|
+
bool IsContributing(TEdge *edge);
|
204
|
+
bool IsTopHorz(TEdge *horzEdge, const double &XPos);
|
205
|
+
void SwapPositionsInAEL(TEdge *edge1, TEdge *edge2);
|
206
|
+
void DoMaxima(TEdge *e, const double &topY);
|
207
|
+
void ProcessHorizontals();
|
208
|
+
void ProcessHorizontal(TEdge *horzEdge);
|
209
|
+
void AddLocalMaxPoly(TEdge *e1, TEdge *e2, const TDoublePoint &pt);
|
210
|
+
void AddLocalMinPoly(TEdge *e1, TEdge *e2, const TDoublePoint &pt);
|
211
|
+
void AppendPolygon(TEdge *e1, TEdge *e2);
|
212
|
+
void DoEdge1(TEdge *edge1, TEdge *edge2, const TDoublePoint &pt);
|
213
|
+
void DoEdge2(TEdge *edge1, TEdge *edge2, const TDoublePoint &pt);
|
214
|
+
void DoBothEdges(TEdge *edge1, TEdge *edge2, const TDoublePoint &pt);
|
215
|
+
void IntersectEdges(TEdge *e1, TEdge *e2,
|
216
|
+
const TDoublePoint &pt, TIntersectProtects protects);
|
217
|
+
TPolyPt* AddPolyPt(TEdge *e, const TDoublePoint &pt);
|
218
|
+
TPolyPt* InsertPolyPtBetween(const TDoublePoint &pt, TPolyPt* pp1, TPolyPt* pp2);
|
219
|
+
void DisposeAllPolyPts();
|
220
|
+
void ProcessIntersections( const double &topY);
|
221
|
+
void AddIntersectNode(TEdge *e1, TEdge *e2, const TDoublePoint &pt);
|
222
|
+
void BuildIntersectList(const double &topY);
|
223
|
+
void ProcessIntersectList();
|
224
|
+
TEdge *BubbleSwap(TEdge *edge);
|
225
|
+
void ProcessEdgesAtTopOfScanbeam( const double &topY);
|
226
|
+
void BuildResult(TPolyPolygon &polypoly);
|
227
|
+
void DisposeIntersectNodes();
|
228
|
+
void FixupJoins(int oldIdx, int newIdx);
|
229
|
+
void MergePolysWithCommonEdges();
|
230
|
+
void FixupJoins(int joinIdx);
|
231
|
+
};
|
232
|
+
|
233
|
+
class clipperException : public std::exception
|
234
|
+
{
|
235
|
+
public:
|
236
|
+
clipperException(const char* description = "Clipper exception")
|
237
|
+
throw(): std::exception(), m_description (description) {}
|
238
|
+
virtual ~clipperException() throw() {}
|
239
|
+
virtual const char* what() const throw() {return m_description.c_str();}
|
240
|
+
private:
|
241
|
+
std::string m_description;
|
242
|
+
};
|
243
|
+
|
244
|
+
} //clipper namespace
|
245
|
+
#endif //clipper_hpp
|
246
|
+
|
247
|
+
|
@@ -0,0 +1,268 @@
|
|
1
|
+
/*
|
2
|
+
* Clipper Ruby Bindings
|
3
|
+
* Copyright 2010 Mike Owens <http://mike.filespanker.com/>
|
4
|
+
*
|
5
|
+
* Released under the same terms as Clipper.
|
6
|
+
*
|
7
|
+
*/
|
8
|
+
|
9
|
+
#include <clipper.hpp>
|
10
|
+
#include <ruby.h>
|
11
|
+
|
12
|
+
#ifndef DBL2NUM
|
13
|
+
# define DBL2NUM rb_float_new
|
14
|
+
#endif
|
15
|
+
|
16
|
+
using namespace std;
|
17
|
+
using namespace clipper;
|
18
|
+
|
19
|
+
static ID id_even_odd;
|
20
|
+
static ID id_non_zero;
|
21
|
+
|
22
|
+
static inline Clipper*
|
23
|
+
XCLIPPER(VALUE x)
|
24
|
+
{
|
25
|
+
Clipper* clipper;
|
26
|
+
Data_Get_Struct(x, Clipper, clipper);
|
27
|
+
return clipper;
|
28
|
+
}
|
29
|
+
|
30
|
+
static inline TPolyFillType
|
31
|
+
sym_to_filltype(VALUE sym)
|
32
|
+
{
|
33
|
+
ID inp = rb_to_id(sym);
|
34
|
+
|
35
|
+
if (inp == id_even_odd) {
|
36
|
+
return pftEvenOdd;
|
37
|
+
} else if (inp == id_non_zero) {
|
38
|
+
return pftNonZero;
|
39
|
+
}
|
40
|
+
|
41
|
+
rb_raise(rb_eArgError, "%s", "Expected :even_odd or :non_zero");
|
42
|
+
}
|
43
|
+
|
44
|
+
extern "C" {
|
45
|
+
|
46
|
+
static void
|
47
|
+
ary_to_polygon(VALUE ary, TPolygon* poly)
|
48
|
+
{
|
49
|
+
const char* earg =
|
50
|
+
"Polygons have format: [[p0_x, p0_y], [p1_x, p1_y], ...]";
|
51
|
+
|
52
|
+
Check_Type(ary, T_ARRAY);
|
53
|
+
|
54
|
+
for(long i = 0; i != RARRAY_LEN(ary); i++) {
|
55
|
+
VALUE sub = rb_ary_entry(ary, i);
|
56
|
+
Check_Type(sub, T_ARRAY);
|
57
|
+
|
58
|
+
if(RARRAY_LEN(sub) != 2) {
|
59
|
+
rb_raise(rb_eArgError, "%s", earg);
|
60
|
+
}
|
61
|
+
|
62
|
+
VALUE px = rb_ary_entry(sub, 0);
|
63
|
+
VALUE py = rb_ary_entry(sub, 1);
|
64
|
+
poly->push_back(DoublePoint(NUM2DBL(px), NUM2DBL(py)));
|
65
|
+
}
|
66
|
+
}
|
67
|
+
|
68
|
+
static void
|
69
|
+
ary_to_polypolygon(VALUE ary, TPolyPolygon* polypoly)
|
70
|
+
{
|
71
|
+
Check_Type(ary, T_ARRAY);
|
72
|
+
for(long i = 0; i != RARRAY_LEN(ary); i++) {
|
73
|
+
TPolygon p;
|
74
|
+
VALUE sub = rb_ary_entry(ary, i);
|
75
|
+
Check_Type(sub, T_ARRAY);
|
76
|
+
ary_to_polygon(sub, &p);
|
77
|
+
polypoly->push_back(p);
|
78
|
+
}
|
79
|
+
}
|
80
|
+
|
81
|
+
static void
|
82
|
+
rbclipper_free(void* ptr)
|
83
|
+
{
|
84
|
+
delete (Clipper*) ptr;
|
85
|
+
}
|
86
|
+
|
87
|
+
static VALUE
|
88
|
+
rbclipper_new(VALUE klass)
|
89
|
+
{
|
90
|
+
Clipper* ptr = new Clipper;
|
91
|
+
VALUE r = Data_Wrap_Struct(klass, 0, rbclipper_free, ptr);
|
92
|
+
rb_obj_call_init(r, 0, 0);
|
93
|
+
return r;
|
94
|
+
}
|
95
|
+
|
96
|
+
static VALUE
|
97
|
+
rbclipper_add_polygon_internal(VALUE self, VALUE polygon,
|
98
|
+
TPolyType polytype)
|
99
|
+
{
|
100
|
+
TPolygon tmp;
|
101
|
+
ary_to_polygon(polygon, &tmp);
|
102
|
+
XCLIPPER(self)->AddPolygon(tmp, polytype);
|
103
|
+
return Qnil;
|
104
|
+
}
|
105
|
+
|
106
|
+
static VALUE
|
107
|
+
rbclipper_add_subject_polygon(VALUE self, VALUE polygon)
|
108
|
+
{
|
109
|
+
return rbclipper_add_polygon_internal(self, polygon, ptSubject);
|
110
|
+
}
|
111
|
+
|
112
|
+
static VALUE
|
113
|
+
rbclipper_add_clip_polygon(VALUE self, VALUE polygon)
|
114
|
+
{
|
115
|
+
return rbclipper_add_polygon_internal(self, polygon, ptClip);
|
116
|
+
}
|
117
|
+
|
118
|
+
|
119
|
+
static VALUE
|
120
|
+
rbclipper_add_poly_polygon_internal(VALUE self, VALUE polypoly,
|
121
|
+
TPolyType polytype)
|
122
|
+
{
|
123
|
+
TPolyPolygon tmp;
|
124
|
+
ary_to_polypolygon(polypoly, &tmp);
|
125
|
+
XCLIPPER(self)->AddPolyPolygon(tmp, polytype);
|
126
|
+
return Qnil;
|
127
|
+
}
|
128
|
+
|
129
|
+
static VALUE
|
130
|
+
rbclipper_add_subject_poly_polygon(VALUE self, VALUE polygon)
|
131
|
+
{
|
132
|
+
return rbclipper_add_poly_polygon_internal(self, polygon, ptSubject);
|
133
|
+
}
|
134
|
+
|
135
|
+
static VALUE
|
136
|
+
rbclipper_add_clip_poly_polygon(VALUE self, VALUE polygon)
|
137
|
+
{
|
138
|
+
return rbclipper_add_poly_polygon_internal(self, polygon, ptClip);
|
139
|
+
}
|
140
|
+
|
141
|
+
|
142
|
+
static VALUE
|
143
|
+
rbclipper_clear(VALUE self)
|
144
|
+
{
|
145
|
+
XCLIPPER(self)->Clear();
|
146
|
+
return Qnil;
|
147
|
+
}
|
148
|
+
|
149
|
+
static VALUE
|
150
|
+
rbclipper_force_orientation(VALUE self)
|
151
|
+
{
|
152
|
+
return XCLIPPER(self)->ForceOrientation() ? Qtrue : Qfalse;
|
153
|
+
}
|
154
|
+
|
155
|
+
static VALUE
|
156
|
+
rbclipper_force_orientation_eq(VALUE self, VALUE b)
|
157
|
+
{
|
158
|
+
XCLIPPER(self)->ForceOrientation(b == Qtrue);
|
159
|
+
return b;
|
160
|
+
}
|
161
|
+
|
162
|
+
static VALUE
|
163
|
+
rbclipper_execute_internal(VALUE self, TClipType cliptype,
|
164
|
+
VALUE subjfill, VALUE clipfill)
|
165
|
+
{
|
166
|
+
if (NIL_P(subjfill))
|
167
|
+
subjfill = ID2SYM(id_even_odd);
|
168
|
+
|
169
|
+
if (NIL_P(clipfill))
|
170
|
+
clipfill = ID2SYM(id_even_odd);
|
171
|
+
|
172
|
+
TPolyPolygon solution;
|
173
|
+
XCLIPPER(self)->Execute((TClipType) cliptype,
|
174
|
+
solution,
|
175
|
+
sym_to_filltype(subjfill),
|
176
|
+
sym_to_filltype(clipfill));
|
177
|
+
VALUE r = rb_ary_new();
|
178
|
+
for(TPolyPolygon::iterator i = solution.begin();
|
179
|
+
i != solution.end();
|
180
|
+
++i) {
|
181
|
+
VALUE sub = rb_ary_new();
|
182
|
+
for(TPolygon::iterator p = i->begin(); p != i->end(); ++p) {
|
183
|
+
rb_ary_push(sub, rb_ary_new3(2, DBL2NUM(p->X), DBL2NUM(p->Y)));
|
184
|
+
}
|
185
|
+
rb_ary_push(r, sub);
|
186
|
+
}
|
187
|
+
|
188
|
+
return r;
|
189
|
+
}
|
190
|
+
|
191
|
+
static VALUE
|
192
|
+
rbclipper_intersection(int argc, VALUE* argv, VALUE self)
|
193
|
+
{
|
194
|
+
VALUE subjfill, clipfill;
|
195
|
+
rb_scan_args(argc, argv, "02", &subjfill, &clipfill);
|
196
|
+
return rbclipper_execute_internal(self, ctIntersection, subjfill, clipfill);
|
197
|
+
}
|
198
|
+
|
199
|
+
static VALUE
|
200
|
+
rbclipper_union(int argc, VALUE* argv, VALUE self)
|
201
|
+
{
|
202
|
+
VALUE subjfill, clipfill;
|
203
|
+
|
204
|
+
rb_scan_args(argc, argv, "02", &subjfill, &clipfill);
|
205
|
+
|
206
|
+
return rbclipper_execute_internal(self, ctUnion, subjfill, clipfill);
|
207
|
+
}
|
208
|
+
|
209
|
+
|
210
|
+
static VALUE
|
211
|
+
rbclipper_difference(int argc, VALUE* argv, VALUE self)
|
212
|
+
{
|
213
|
+
VALUE subjfill, clipfill;
|
214
|
+
rb_scan_args(argc, argv, "02", &subjfill, &clipfill);
|
215
|
+
return rbclipper_execute_internal(self, ctDifference, subjfill, clipfill);
|
216
|
+
}
|
217
|
+
|
218
|
+
|
219
|
+
static VALUE
|
220
|
+
rbclipper_xor(int argc, VALUE* argv, VALUE self)
|
221
|
+
{
|
222
|
+
VALUE subjfill, clipfill;
|
223
|
+
rb_scan_args(argc, argv, "02", &subjfill, &clipfill);
|
224
|
+
return rbclipper_execute_internal(self, ctXor, subjfill, clipfill);
|
225
|
+
}
|
226
|
+
|
227
|
+
|
228
|
+
typedef VALUE (*ruby_method)(...);
|
229
|
+
|
230
|
+
void Init_clipper() {
|
231
|
+
id_even_odd = rb_intern("even_odd");
|
232
|
+
id_non_zero = rb_intern("non_zero");
|
233
|
+
|
234
|
+
VALUE mod = rb_define_module("Clipper");
|
235
|
+
|
236
|
+
VALUE k = rb_define_class_under(mod, "Clipper", rb_cObject);
|
237
|
+
rb_define_singleton_method(k, "new",
|
238
|
+
(ruby_method) rbclipper_new, 0);
|
239
|
+
|
240
|
+
rb_define_method(k, "add_subject_polygon",
|
241
|
+
(ruby_method) rbclipper_add_subject_polygon, 1);
|
242
|
+
rb_define_method(k, "add_clip_polygon",
|
243
|
+
(ruby_method) rbclipper_add_clip_polygon, 1);
|
244
|
+
|
245
|
+
rb_define_method(k, "add_subject_poly_polygon",
|
246
|
+
(ruby_method) rbclipper_add_subject_poly_polygon, 1);
|
247
|
+
rb_define_method(k, "add_clip_poly_polygon",
|
248
|
+
(ruby_method) rbclipper_add_clip_poly_polygon, 1);
|
249
|
+
|
250
|
+
|
251
|
+
rb_define_method(k, "clear!",
|
252
|
+
(ruby_method) rbclipper_clear, 0);
|
253
|
+
rb_define_method(k, "force_orientation",
|
254
|
+
(ruby_method) rbclipper_force_orientation, 0);
|
255
|
+
rb_define_method(k, "force_orientation=",
|
256
|
+
(ruby_method) rbclipper_force_orientation_eq, 1);
|
257
|
+
|
258
|
+
rb_define_method(k, "intersection",
|
259
|
+
(ruby_method) rbclipper_intersection, -1);
|
260
|
+
rb_define_method(k, "union",
|
261
|
+
(ruby_method) rbclipper_union, -1);
|
262
|
+
rb_define_method(k, "difference",
|
263
|
+
(ruby_method) rbclipper_difference, -1);
|
264
|
+
rb_define_method(k, "xor",
|
265
|
+
(ruby_method) rbclipper_xor, -1);
|
266
|
+
}
|
267
|
+
|
268
|
+
} /* extern "C" */
|