forked from bolom009/go-clipper2
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcore.go
More file actions
297 lines (236 loc) · 5.58 KB
/
Copy pathcore.go
File metadata and controls
297 lines (236 loc) · 5.58 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
package go_clipper2
import "math"
// ClipType specifies the type of boolean operation
type ClipType uint8
const (
NoClip ClipType = iota
Intersection // intersect subject and clip polygons
Union // union (OR) subject and clip polygons
Difference // subtract clip polygons from subject polygons
Xor // exclusively or (XOR) subject and clip polygons
)
// FillRule specifies how to determine polygon interiors for self-intersecting polygons
type FillRule uint8
const (
EvenOdd FillRule = iota // odd numbered sub-regions are filled
NonZero // non-zero sub-regions are filled
Positive // positive sub-regions are filled
Negative // negative sub-regions are filled
)
type PathType uint8
const (
Subject PathType = iota
Clip
)
type MidpointRounding uint8
const (
ToEven = iota
AwayFromZero
)
// Point64 represents a point with 64-bit integer coordinates
type Point64 struct {
X, Y int64
}
func NewFloatPoint64(x, y float64) Point64 {
rX := 0.0
rY := 0.0
if x > 0 {
rX = math.Floor(x + 0.5)
} else {
rX = math.Ceil(x - 0.5)
}
if y > 0 {
rY = math.Floor(y + 0.5)
} else {
rY = math.Ceil(y - 0.5)
}
return Point64{X: int64(rX), Y: int64(rY)}
}
func (p *Point64) ToPointD() PointD {
return PointD{X: float64(p.X), Y: float64(p.Y)}
}
func (p *Point64) ToPointDScale(scale float64) PointD {
return PointD{X: float64(p.X) * scale, Y: float64(p.Y) * scale}
}
func (p *Point64) Equals(p2 Point64) bool {
return p.X == p2.X && p.Y == p2.Y
}
func (p *Point64) NEquals(p2 Point64) bool {
return p.X != p2.X || p.Y != p2.Y
}
func (p *Point64) Add(p2 Point64) {
p.X += p2.X
p.Y += p2.Y
}
func (p *Point64) Sub(p2 Point64) {
p.X -= p2.X
p.Y -= p2.Y
}
func (p *Point64) ToPoint64(pt PointD) Point64 {
rX := 0.0
rY := 0.0
if pt.X > 0 {
rX = math.Floor(pt.X + 0.5)
} else {
rX = math.Ceil(pt.X - 0.5)
}
if pt.Y > 0 {
rY = math.Floor(pt.Y + 0.5)
} else {
rY = math.Ceil(pt.Y - 0.5)
}
return Point64{X: int64(rX), Y: int64(rY)}
}
type PointD struct {
X, Y float64
}
func (p *PointD) ToPoint64() Point64 {
rX := 0.0
rY := 0.0
if p.X > 0 {
rX = math.Floor(p.X + 0.5)
} else {
rX = math.Ceil(p.X - 0.5)
}
if p.Y > 0 {
rY = math.Floor(p.Y + 0.5)
} else {
rY = math.Ceil(p.Y - 0.5)
}
return Point64{X: int64(rX), Y: int64(rY)}
}
func (p *PointD) ToPoint64Scale(scale float64) Point64 {
rX := 0.0
rY := 0.0
if p.X > 0 {
rX = math.Floor(p.X + 0.5)
} else {
rX = math.Ceil(p.X - 0.5)
}
if p.Y > 0 {
rY = math.Floor(p.Y + 0.5)
} else {
rY = math.Ceil(p.Y - 0.5)
}
return Point64{X: int64(rX * scale), Y: int64(rY * scale)}
}
func (p *PointD) Scale(scale float64) {
p.X *= scale
p.Y *= scale
}
func (p *PointD) Equals(p2 PointD) bool {
return isAlmostZero(p.X-p2.X) && isAlmostZero(p.Y-p2.Y)
}
func (p *PointD) NEquals(p2 PointD) bool {
return !isAlmostZero(p.X-p2.X) || !isAlmostZero(p.Y-p2.Y)
}
func (p *PointD) Negate() {
p.X *= -1
p.Y *= -1
}
type Rect64 struct {
left int64
top int64
right int64
bottom int64
}
func NewRect64(left, top, right, bottom int64) Rect64 {
return Rect64{
left: left,
top: top,
right: right,
bottom: bottom,
}
}
func NewRect64Invalid(isValid bool) Rect64 {
if isValid {
return Rect64{}
}
return Rect64{
left: math.MaxInt64,
top: math.MaxInt64,
right: math.MaxInt64,
bottom: math.MaxInt64,
}
}
func (r *Rect64) IsEmpty() bool {
return r.bottom <= r.top || r.right <= r.left
}
func (r *Rect64) IsInvalid() bool {
return r.left < math.MaxInt64
}
func (r *Rect64) MidPoint() Point64 {
return Point64{X: (r.left + r.right) / 2, Y: (r.top + r.bottom) / 2}
}
func (r *Rect64) Contains(rec Rect64) bool {
return rec.left >= r.left && rec.right <= r.right &&
rec.top >= r.top && rec.bottom <= r.bottom
}
func (r *Rect64) Intersects(rec Rect64) bool {
return max(r.left, rec.left) <= min(r.right, rec.right) && max(r.top, rec.top) <= min(r.bottom, rec.bottom)
}
func (r *Rect64) AsPath() Path64 {
return Path64{
Point64{X: r.left, Y: r.top},
Point64{X: r.right, Y: r.top},
Point64{X: r.right, Y: r.bottom},
Point64{X: r.left, Y: r.bottom},
}
}
type RectD struct {
left float64
top float64
right float64
bottom float64
}
func NewRectD(left, top, right, bottom float64) RectD {
return RectD{
left: left,
top: top,
right: right,
bottom: bottom,
}
}
func NewRectDInvalid(isValid bool) RectD {
if isValid {
return RectD{}
}
return RectD{
left: math.MaxFloat64,
top: math.MaxFloat64,
right: math.MaxFloat64,
bottom: math.MaxFloat64,
}
}
func (r *RectD) IsEmpty() bool {
return r.bottom <= r.top || r.right <= r.left
}
func (r *RectD) IsInvalid() bool {
return r.left < math.MaxInt64
}
func (r *RectD) MidPoint() PointD {
return PointD{X: (r.left + r.right) / 2, Y: (r.top + r.bottom) / 2}
}
func (r *RectD) Contains(rec RectD) bool {
return rec.left >= r.left && rec.right <= r.right &&
rec.top >= r.top && rec.bottom <= r.bottom
}
func (r *RectD) Intersects(rec RectD) bool {
return max(r.left, rec.left) <= min(r.right, rec.right) && max(r.top, rec.top) <= min(r.bottom, rec.bottom)
}
func (r *RectD) AsPath() PathD {
return PathD{
PointD{X: r.left, Y: r.top},
PointD{X: r.right, Y: r.top},
PointD{X: r.right, Y: r.bottom},
PointD{X: r.left, Y: r.bottom},
}
}
// Path64 represents a sequence of points forming a path
type Path64 []Point64
// Paths64 represents a collection of paths
type Paths64 []Path64
// PathD represents a sequence of points forming a path
type PathD []PointD
// PathsD represents a collection of paths
type PathsD []PathD