clipper 2.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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" */
|