perfect-shape 0.2.0 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +10 -3
- data/README.md +40 -14
- data/VERSION +1 -1
- data/lib/perfect_shape/line.rb +4 -4
- data/lib/perfect_shape/point.rb +4 -4
- data/lib/perfect_shape/polygon.rb +68 -62
- data/lib/perfect_shape/rectangle.rb +10 -2
- data/perfect-shape.gemspec +4 -4
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4e7efc4e2333e43b5e4d034e7fa3a3dddbdc9c6fd392e9d2ae1a409995122eb5
|
4
|
+
data.tar.gz: 07f098098f6e42d6d71bdab33b44d3250c05c79ee48b2304b60784fba7de3f75
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a69ec76140e777f303724c2db8d7dd904b2f679b11ce6380629c27ae0f3feb1cc0be0d615b79c085cd276e9a96b9a5842fbf8eb4d810398ae1329a3598b37592
|
7
|
+
data.tar.gz: d87a97b80e155939e380024653b01fe7a230660c0b58957d96f6d3d9392b113996f051bf55dbbc3b935c7d44a763cd686716dc9cb568d7ff85580aa1ca955c9d
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,12 @@
|
|
1
1
|
# Change Log
|
2
2
|
|
3
|
+
## 0.3.0
|
4
|
+
|
5
|
+
- Refactoring: rename `distance` option for `#contain?` on `Point`/`Line` into `distance_tolerance`
|
6
|
+
- Check point containment in rectangle outline with distance tolerance: `PerfectShape::Rectangle#contain?(x_or_point, y = nil, outline: false, distance_tolerance: 0)`
|
7
|
+
- Check point containment in square outline with distance tolerance: `PerfectShape::Square#contain?(x_or_point, y = nil, outline: false, distance_tolerance: 0)`
|
8
|
+
- Check point containment in polygon outline with distance tolerance: `PerfectShape::Polygon#contain?(x_or_point, y = nil, outline: false, distance_tolerance: 0)`
|
9
|
+
|
3
10
|
## 0.2.0
|
4
11
|
|
5
12
|
- `PerfectShape::CompositeShape`: aggregate of multiple shapes
|
@@ -23,7 +30,7 @@
|
|
23
30
|
## 0.1.0
|
24
31
|
|
25
32
|
- `PerfectShape::Path` (having points or lines)
|
26
|
-
- `PerfectShape::Path#contain?(x_or_point, y=nil,
|
33
|
+
- `PerfectShape::Path#contain?(x_or_point, y=nil, distance_tolerance: 0)`
|
27
34
|
- `PerfectShape::Path#point_crossings(x_or_point, y=nil)`
|
28
35
|
- `PerfectShape::Path#==`
|
29
36
|
|
@@ -37,12 +44,12 @@
|
|
37
44
|
|
38
45
|
- `PerfectShape::Point`
|
39
46
|
- `PerfectShape::Point#point_distance`
|
40
|
-
- `PerfectShape::Point#contain?(x_or_point, y=nil,
|
47
|
+
- `PerfectShape::Point#contain?(x_or_point, y=nil, distance_tolerance: 0)`
|
41
48
|
- Refactor `PerfectShape::Point`,`PerfectShape::RectangularShape` to include shared `PerfectShape::PointLocation`
|
42
49
|
|
43
50
|
## 0.0.9
|
44
51
|
|
45
|
-
- `PerfectShape::Line#contain?(x_or_point, y=nil,
|
52
|
+
- `PerfectShape::Line#contain?(x_or_point, y=nil, distance_tolerance: 0)` (add a distance tolerance fuzz factor option)
|
46
53
|
|
47
54
|
## 0.0.8
|
48
55
|
|
data/README.md
CHANGED
@@ -1,9 +1,9 @@
|
|
1
|
-
# Perfect Shape 0.
|
1
|
+
# Perfect Shape 0.3.0
|
2
2
|
## Geometric Algorithms
|
3
3
|
[![Gem Version](https://badge.fury.io/rb/perfect-shape.svg)](http://badge.fury.io/rb/perfect-shape)
|
4
4
|
[![Test](https://github.com/AndyObtiva/perfect-shape/actions/workflows/ruby.yml/badge.svg)](https://github.com/AndyObtiva/perfect-shape/actions/workflows/ruby.yml)
|
5
5
|
|
6
|
-
[`PerfectShape`](https://rubygems.org/gems/perfect-shape) is a collection of pure Ruby geometric algorithms that are mostly useful for GUI (Graphical User Interface) manipulation like checking containment of a mouse click [point](#perfectshapepoint) in popular geometry shapes such as [rectangle](#perfectshaperectangle), [square](#perfectshapesquare), [arc](#perfectshapearc) (open, chord, and pie), [ellipse](#perfectshapeellipse), [circle](#perfectshapecircle), [polygon](#perfectshapepolygon), and [paths](#perfectshapepath) containing [lines](#perfectshapeline), [quadratic bézier curves](#perfectshapequadraticbeziercurve), and [cubic
|
6
|
+
[`PerfectShape`](https://rubygems.org/gems/perfect-shape) is a collection of pure Ruby geometric algorithms that are mostly useful for GUI (Graphical User Interface) manipulation like checking containment of a mouse click [point](#perfectshapepoint) in popular geometry shapes such as [rectangle](#perfectshaperectangle), [square](#perfectshapesquare), [arc](#perfectshapearc) (open, chord, and pie), [ellipse](#perfectshapeellipse), [circle](#perfectshapecircle), [polygon](#perfectshapepolygon), and [paths](#perfectshapepath) containing [lines](#perfectshapeline), [quadratic bézier curves](#perfectshapequadraticbeziercurve), and [cubic bezier curves](#perfectshapecubicbeziercurve) (including both [Ray Casting Algorithm](https://en.wikipedia.org/wiki/Point_in_polygon#Ray_casting_algorithm), aka [Even-odd Rule](https://en.wikipedia.org/wiki/Even%E2%80%93odd_rule), and [Winding Number Algorithm](https://en.wikipedia.org/wiki/Point_in_polygon#Winding_number_algorithm), aka [Nonzero Rule](https://en.wikipedia.org/wiki/Nonzero-rule)).
|
7
7
|
|
8
8
|
Additionally, [`PerfectShape::Math`](#perfectshapemath) contains some purely mathematical algorithms, like [IEEE 754-1985 Remainder](https://en.wikipedia.org/wiki/IEEE_754-1985).
|
9
9
|
|
@@ -14,13 +14,13 @@ To ensure high accuracy, this library does all its mathematical operations with
|
|
14
14
|
Run:
|
15
15
|
|
16
16
|
```
|
17
|
-
gem install perfect-shape -v 0.
|
17
|
+
gem install perfect-shape -v 0.3.0
|
18
18
|
```
|
19
19
|
|
20
20
|
Or include in Bundler `Gemfile`:
|
21
21
|
|
22
22
|
```ruby
|
23
|
-
gem 'perfect-shape', '~> 0.
|
23
|
+
gem 'perfect-shape', '~> 0.3.0'
|
24
24
|
```
|
25
25
|
|
26
26
|
And, run:
|
@@ -111,7 +111,7 @@ Points are simply represented by an `Array` of `[x,y]` coordinates when used wit
|
|
111
111
|
- `#center_x`: center x (always x)
|
112
112
|
- `#center_y`: center y (always y)
|
113
113
|
- `#bounding_box`: bounding box is a rectangle with x = min x, y = min y, and width/height of shape
|
114
|
-
- `#contain?(x_or_point, y=nil,
|
114
|
+
- `#contain?(x_or_point, y=nil, distance_tolerance: 0)`: checks if point matches self, with a distance tolerance (0 by default). Distance tolerance provides a fuzz factor that for example enables GUI users to mouse-click-select a point shape in a GUI more successfully.
|
115
115
|
- `#point_distance(x_or_point, y=nil)`: Returns the distance from a point to another point
|
116
116
|
- `#==(other)`: Returns `true` if equal to `other` or `false` otherwise
|
117
117
|
|
@@ -126,8 +126,8 @@ shape.contain?(200, 150) # => true
|
|
126
126
|
shape.contain?([200, 150]) # => true
|
127
127
|
shape.contain?(200, 151) # => false
|
128
128
|
shape.contain?([200, 151]) # => false
|
129
|
-
shape.contain?(200, 151,
|
130
|
-
shape.contain?([200, 151],
|
129
|
+
shape.contain?(200, 151, distance_tolerance: 5) # => true
|
130
|
+
shape.contain?([200, 151], distance_tolerance: 5) # => true
|
131
131
|
```
|
132
132
|
|
133
133
|
### `PerfectShape::Line`
|
@@ -153,7 +153,7 @@ Includes `PerfectShape::MultiPoint`
|
|
153
153
|
- `#center_x`: center x
|
154
154
|
- `#center_y`: center y
|
155
155
|
- `#bounding_box`: bounding box is a rectangle with x = min x, y = min y, and width/height of shape
|
156
|
-
- `#contain?(x_or_point, y=nil,
|
156
|
+
- `#contain?(x_or_point, y=nil, distance_tolerance: 0)`: checks if point lies on line, with a distance tolerance (0 by default). Distance tolerance provides a fuzz factor that for example enables GUI users to mouse-click-select a line shape in a GUI more successfully.
|
157
157
|
- `#relative_counterclockwise(x_or_point, y=nil)`: Returns an indicator of where the specified point (px,py) lies with respect to the line segment from (x1,y1) to (x2,y2). The return value can be either 1, -1, or 0 and indicates in which direction the specified line must pivot around its first end point, (x1,y1), in order to point at the specified point (px,py). A return value of 1 indicates that the line segment must turn in the direction that takes the positive X axis towards the negative Y axis. In the default coordinate system used by Java 2D, this direction is counterclockwise. A return value of -1 indicates that the line segment must turn in the direction that takes the positive X axis towards the positive Y axis. In the default coordinate system, this direction is clockwise. A return value of 0 indicates that the point lies exactly on the line segment. Note that an indicator value of 0 is rare and not useful for determining collinearity because of floating point rounding issues. If the point is colinear with the line segment, but not between the end points, then the value will be -1 if the point lies “beyond (x1,y1)” or 1 if the point lies “beyond (x2,y2)”.
|
158
158
|
- `#point_segment_distance(x_or_point, y=nil)`: Returns the distance from a point to a line segment.
|
159
159
|
- `#==(other)`: Returns `true` if equal to `other` or `false` otherwise
|
@@ -169,8 +169,8 @@ shape.contain?(50, 50) # => true
|
|
169
169
|
shape.contain?([50, 50]) # => true
|
170
170
|
shape.contain?(50, 51) # => false
|
171
171
|
shape.contain?([50, 51]) # => false
|
172
|
-
shape.contain?(50, 51,
|
173
|
-
shape.contain?([50, 51],
|
172
|
+
shape.contain?(50, 51, distance_tolerance: 5) # => true
|
173
|
+
shape.contain?([50, 51], distance_tolerance: 5) # => true
|
174
174
|
```
|
175
175
|
|
176
176
|
### `PerfectShape::QuadraticBezierCurve`
|
@@ -265,7 +265,7 @@ Includes `PerfectShape::RectangularShape`
|
|
265
265
|
- `#max_x`: max x
|
266
266
|
- `#max_y`: max y
|
267
267
|
- `#bounding_box`: bounding box is a rectangle with x = min x, y = min y, and width/height of shape
|
268
|
-
- `#contain?(x_or_point, y=nil)`: checks if point is inside
|
268
|
+
- `#contain?(x_or_point, y=nil, outline: false, distance_tolerance: 0)`: checks if point is inside when `outline` is `false` or if point is on the outline when `outline` is `true`. `distance_tolerance` can be used as a fuzz factor when `outline` is `true`, for example, to help users mouse-click-select a rectangle shape from its edges in a GUI more successfully
|
269
269
|
- `#==(other)`: Returns `true` if equal to `other` or `false` otherwise
|
270
270
|
|
271
271
|
Example:
|
@@ -277,6 +277,14 @@ shape = PerfectShape::Rectangle.new(x: 15, y: 30, width: 200, height: 100)
|
|
277
277
|
|
278
278
|
shape.contain?(115, 80) # => true
|
279
279
|
shape.contain?([115, 80]) # => true
|
280
|
+
shape.contain?(115, 80, outline: true) # => false
|
281
|
+
shape.contain?([115, 80], outline: true) # => false
|
282
|
+
shape.contain?(115, 30, outline: true) # => true
|
283
|
+
shape.contain?([115, 30], outline: true) # => true
|
284
|
+
shape.contain?(115, 31, outline: true) # => false
|
285
|
+
shape.contain?([115, 31], outline: true) # => false
|
286
|
+
shape.contain?(115, 31, outline: true, distance_tolerance: 1) # => true
|
287
|
+
shape.contain?([115, 31], outline: true, distance_tolerance: 1) # => true
|
280
288
|
```
|
281
289
|
|
282
290
|
### `PerfectShape::Square`
|
@@ -300,7 +308,7 @@ Extends `PerfectShape::Rectangle`
|
|
300
308
|
- `#max_x`: max x
|
301
309
|
- `#max_y`: max y
|
302
310
|
- `#bounding_box`: bounding box is a rectangle with x = min x, y = min y, and width/height of shape
|
303
|
-
- `#contain?(x_or_point, y=nil)`: checks if point is inside
|
311
|
+
- `#contain?(x_or_point, y=nil, outline: false, distance_tolerance: 0)`: checks if point is inside when `outline` is `false` or if point is on the outline when `outline` is `true`. `distance_tolerance` can be used as a fuzz factor when `outline` is `true`, for example, to help users mouse-click-select a square shape from its edges in a GUI more successfully
|
304
312
|
- `#==(other)`: Returns `true` if equal to `other` or `false` otherwise
|
305
313
|
|
306
314
|
Example:
|
@@ -312,6 +320,14 @@ shape = PerfectShape::Square.new(x: 15, y: 30, length: 200)
|
|
312
320
|
|
313
321
|
shape.contain?(115, 130) # => true
|
314
322
|
shape.contain?([115, 130]) # => true
|
323
|
+
shape.contain?(115, 130, outline: true) # => false
|
324
|
+
shape.contain?([115, 130], outline: true) # => false
|
325
|
+
shape.contain?(115, 30, outline: true) # => true
|
326
|
+
shape.contain?([115, 30], outline: true) # => true
|
327
|
+
shape.contain?(115, 31, outline: true) # => false
|
328
|
+
shape.contain?([115, 31], outline: true) # => false
|
329
|
+
shape.contain?(115, 31, outline: true, distance_tolerance: 1) # => true
|
330
|
+
shape.contain?([115, 31], outline: true, distance_tolerance: 1) # => true
|
315
331
|
```
|
316
332
|
|
317
333
|
### `PerfectShape::Arc`
|
@@ -490,7 +506,7 @@ A polygon can be thought of as a special case of [path](#perfectshapepath) that
|
|
490
506
|
- `#center_x`: center x
|
491
507
|
- `#center_y`: center y
|
492
508
|
- `#bounding_box`: bounding box is a rectangle with x = min x, y = min y, and width/height of shape
|
493
|
-
- `#contain?(x_or_point, y=nil)`: checks if point is inside using the [Ray Casting Algorithm](https://en.wikipedia.org/wiki/Point_in_polygon) (aka [Even-Odd Rule](https://en.wikipedia.org/wiki/Even%E2%80%93odd_rule))
|
509
|
+
- `#contain?(x_or_point, y=nil, outline: false, distance_tolerance: 0)`: When `outline` is `false`, it checks if point is inside using the [Ray Casting Algorithm](https://en.wikipedia.org/wiki/Point_in_polygon) (aka [Even-Odd Rule](https://en.wikipedia.org/wiki/Even%E2%80%93odd_rule)). Otherwise, when `outline` is `true`, it checks if point is on the outline. `distance_tolerance` can be used as a fuzz factor when `outline` is `true`, for example, to help users mouse-click-select a polygon shape from its edges in a GUI more successfully
|
494
510
|
- `#==(other)`: Returns `true` if equal to `other` or `false` otherwise
|
495
511
|
|
496
512
|
Example:
|
@@ -502,6 +518,14 @@ shape = PerfectShape::Polygon.new(points: [[200, 150], [270, 170], [250, 220], [
|
|
502
518
|
|
503
519
|
shape.contain?(225, 185) # => true
|
504
520
|
shape.contain?([225, 185]) # => true
|
521
|
+
shape.contain?(225, 185, outline: true) # => false
|
522
|
+
shape.contain?([225, 185], outline: true) # => false
|
523
|
+
shape.contain?(200, 150, outline: true) # => true
|
524
|
+
shape.contain?([200, 150], outline: true) # => true
|
525
|
+
shape.contain?(200, 151, outline: true) # => false
|
526
|
+
shape.contain?([200, 151], outline: true) # => false
|
527
|
+
shape.contain?(200, 151, outline: true, distance_tolerance: 1) # => true
|
528
|
+
shape.contain?([200, 151], outline: true, distance_tolerance: 1) # => true
|
505
529
|
```
|
506
530
|
|
507
531
|
### `PerfectShape::Path`
|
@@ -555,10 +579,12 @@ Class
|
|
555
579
|
|
556
580
|
Extends `PerfectShape::Shape`
|
557
581
|
|
582
|
+
A composite shape is simply an aggregate of multiple shapes (e.g. square and polygon)
|
583
|
+
|
558
584
|
![composite shape](https://raw.githubusercontent.com/AndyObtiva/perfect-shape/master/images/composite-shape.png)
|
559
585
|
|
560
586
|
- `::new(shapes: [])`: constructs a composite shape with `shapes` as `Array` of `PerfectShape::Shape` objects
|
561
|
-
- `#shapes`: the shapes that the
|
587
|
+
- `#shapes`: the shapes that the composite shape is composed of
|
562
588
|
- `#min_x`: min x
|
563
589
|
- `#min_y`: min y
|
564
590
|
- `#max_x`: max x
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.3.0
|
data/lib/perfect_shape/line.rb
CHANGED
@@ -207,16 +207,16 @@ module PerfectShape
|
|
207
207
|
#
|
208
208
|
# @param x The X coordinate of the point to test.
|
209
209
|
# @param y The Y coordinate of the point to test.
|
210
|
-
# @param
|
210
|
+
# @param distance_tolerance The distance from line to tolerate (0 by default)
|
211
211
|
#
|
212
212
|
# @return {@code true} if the point lies within the bound of
|
213
213
|
# the line, {@code false} if the point lies outside of the
|
214
214
|
# line's bounds.
|
215
|
-
def contain?(x_or_point, y = nil,
|
215
|
+
def contain?(x_or_point, y = nil, outline: false, distance_tolerance: 0)
|
216
216
|
x, y = normalize_point(x_or_point, y)
|
217
217
|
return unless x && y
|
218
|
-
|
219
|
-
point_segment_distance(x, y) <=
|
218
|
+
distance_tolerance = BigDecimal(distance_tolerance.to_s)
|
219
|
+
point_segment_distance(x, y) <= distance_tolerance
|
220
220
|
end
|
221
221
|
|
222
222
|
def point_segment_distance(x_or_point, y = nil)
|
data/lib/perfect_shape/point.rb
CHANGED
@@ -63,15 +63,15 @@ module PerfectShape
|
|
63
63
|
#
|
64
64
|
# @param x The X coordinate of the point to test.
|
65
65
|
# @param y The Y coordinate of the point to test.
|
66
|
-
# @param
|
66
|
+
# @param distance_tolerance The distance from point to tolerate (0 by default)
|
67
67
|
#
|
68
68
|
# @return {@code true} if the point is close enough within distance tolerance,
|
69
69
|
# {@code false} if the point is too far.
|
70
|
-
def contain?(x_or_point, y = nil,
|
70
|
+
def contain?(x_or_point, y = nil, outline: false, distance_tolerance: 0)
|
71
71
|
x, y = normalize_point(x_or_point, y)
|
72
72
|
return unless x && y
|
73
|
-
|
74
|
-
point_distance(x, y) <=
|
73
|
+
distance_tolerance = BigDecimal(distance_tolerance.to_s)
|
74
|
+
point_distance(x, y) <= distance_tolerance
|
75
75
|
end
|
76
76
|
|
77
77
|
def point_distance(x_or_point, y = nil)
|
@@ -37,79 +37,85 @@ module PerfectShape
|
|
37
37
|
# @return {@code true} if the point lies within the bound of
|
38
38
|
# the polygon, {@code false} if the point lies outside of the
|
39
39
|
# polygon's bounds.
|
40
|
-
def contain?(x_or_point, y = nil)
|
40
|
+
def contain?(x_or_point, y = nil, outline: false, distance_tolerance: 0)
|
41
41
|
x, y = normalize_point(x_or_point, y)
|
42
42
|
return unless x && y
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
return false if npoints <= 2 || !bounding_box.contain?(x, y)
|
47
|
-
hits = 0
|
48
|
-
|
49
|
-
lastx = xpoints[npoints - 1]
|
50
|
-
lasty = ypoints[npoints - 1]
|
51
|
-
|
52
|
-
# Walk the edges of the polygon
|
53
|
-
npoints.times do |i|
|
54
|
-
curx = xpoints[i]
|
55
|
-
cury = ypoints[i]
|
56
|
-
|
57
|
-
if cury == lasty
|
58
|
-
lastx = curx
|
59
|
-
lasty = cury
|
60
|
-
next
|
61
|
-
end
|
62
|
-
|
63
|
-
if curx < lastx
|
64
|
-
if x >= lastx
|
65
|
-
lastx = curx
|
66
|
-
lasty = cury
|
67
|
-
next
|
68
|
-
end
|
69
|
-
leftx = curx
|
70
|
-
else
|
71
|
-
if x >= curx
|
72
|
-
lastx = curx
|
73
|
-
lasty = cury
|
74
|
-
next
|
75
|
-
end
|
76
|
-
leftx = lastx
|
43
|
+
if outline
|
44
|
+
points.zip(points.rotate(1)).any? do |point1, point2|
|
45
|
+
Line.new(points: [[point1.first, point1.last], [point2.first, point2.last]]).contain?(x, y, distance_tolerance: distance_tolerance)
|
77
46
|
end
|
78
|
-
|
79
|
-
|
80
|
-
|
47
|
+
else
|
48
|
+
npoints = points.count
|
49
|
+
xpoints = points.map(&:first)
|
50
|
+
ypoints = points.map(&:last)
|
51
|
+
return false if npoints <= 2 || !bounding_box.contain?(x, y)
|
52
|
+
hits = 0
|
53
|
+
|
54
|
+
lastx = xpoints[npoints - 1]
|
55
|
+
lasty = ypoints[npoints - 1]
|
56
|
+
|
57
|
+
# Walk the edges of the polygon
|
58
|
+
npoints.times do |i|
|
59
|
+
curx = xpoints[i]
|
60
|
+
cury = ypoints[i]
|
61
|
+
|
62
|
+
if cury == lasty
|
81
63
|
lastx = curx
|
82
64
|
lasty = cury
|
83
65
|
next
|
84
66
|
end
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
67
|
+
|
68
|
+
if curx < lastx
|
69
|
+
if x >= lastx
|
70
|
+
lastx = curx
|
71
|
+
lasty = cury
|
72
|
+
next
|
73
|
+
end
|
74
|
+
leftx = curx
|
75
|
+
else
|
76
|
+
if x >= curx
|
77
|
+
lastx = curx
|
78
|
+
lasty = cury
|
79
|
+
next
|
80
|
+
end
|
81
|
+
leftx = lastx
|
90
82
|
end
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
83
|
+
|
84
|
+
if cury < lasty
|
85
|
+
if y < cury || y >= lasty
|
86
|
+
lastx = curx
|
87
|
+
lasty = cury
|
88
|
+
next
|
89
|
+
end
|
90
|
+
if x < leftx
|
91
|
+
hits += 1
|
92
|
+
lastx = curx
|
93
|
+
lasty = cury
|
94
|
+
next
|
95
|
+
end
|
96
|
+
test1 = x - curx
|
97
|
+
test2 = y - cury
|
98
|
+
else
|
99
|
+
if y < lasty || y >= cury
|
100
|
+
lastx = curx
|
101
|
+
lasty = cury
|
102
|
+
next
|
103
|
+
end
|
104
|
+
if x < leftx
|
105
|
+
hits += 1
|
106
|
+
lastx = curx
|
107
|
+
lasty = cury
|
108
|
+
next
|
109
|
+
end
|
110
|
+
test1 = x - lastx
|
111
|
+
test2 = y - lasty
|
98
112
|
end
|
99
|
-
|
100
|
-
|
101
|
-
lastx = curx
|
102
|
-
lasty = cury
|
103
|
-
next
|
104
|
-
end
|
105
|
-
test1 = x - lastx
|
106
|
-
test2 = y - lasty
|
113
|
+
|
114
|
+
hits += 1 if (test1 < (test2 / (lasty - cury) * (lastx - curx)))
|
107
115
|
end
|
108
|
-
|
109
|
-
hits
|
116
|
+
|
117
|
+
(hits & 1) != 0
|
110
118
|
end
|
111
|
-
|
112
|
-
(hits & 1) != 0
|
113
119
|
end
|
114
120
|
end
|
115
121
|
end
|
@@ -21,6 +21,7 @@
|
|
21
21
|
|
22
22
|
require 'perfect_shape/shape'
|
23
23
|
require 'perfect_shape/rectangular_shape'
|
24
|
+
require 'perfect_shape/line'
|
24
25
|
|
25
26
|
module PerfectShape
|
26
27
|
# Mostly ported from java.awt.geom: https://docs.oracle.com/javase/8/docs/api/java/awt/geom/Rectangle2D.html
|
@@ -36,10 +37,17 @@ module PerfectShape
|
|
36
37
|
# @return {@code true} if the point lies within the bound of
|
37
38
|
# the rectangle, {@code false} if the point lies outside of the
|
38
39
|
# rectangle's bounds.
|
39
|
-
def contain?(x_or_point, y = nil)
|
40
|
+
def contain?(x_or_point, y = nil, outline: false, distance_tolerance: 0)
|
40
41
|
x, y = normalize_point(x_or_point, y)
|
41
42
|
return unless x && y
|
42
|
-
|
43
|
+
if outline
|
44
|
+
Line.new(points: [[self.x, self.y], [self.x + width, self.y]]).contain?(x, y, distance_tolerance: distance_tolerance) or
|
45
|
+
Line.new(points: [[self.x + width, self.y], [self.x + width, self.y + height]]).contain?(x, y, distance_tolerance: distance_tolerance) or
|
46
|
+
Line.new(points: [[self.x + width, self.y + height], [self.x, self.y + height]]).contain?(x, y, distance_tolerance: distance_tolerance) or
|
47
|
+
Line.new(points: [[self.x, self.y + height], [self.x, self.y]]).contain?(x, y, distance_tolerance: distance_tolerance)
|
48
|
+
else
|
49
|
+
x.between?(self.x, self.x + width) && y.between?(self.y, self.y + height)
|
50
|
+
end
|
43
51
|
end
|
44
52
|
end
|
45
53
|
end
|
data/perfect-shape.gemspec
CHANGED
@@ -2,17 +2,17 @@
|
|
2
2
|
# DO NOT EDIT THIS FILE DIRECTLY
|
3
3
|
# Instead, edit Juwelier::Tasks in Rakefile, and run 'rake gemspec'
|
4
4
|
# -*- encoding: utf-8 -*-
|
5
|
-
# stub: perfect-shape 0.
|
5
|
+
# stub: perfect-shape 0.3.0 ruby lib
|
6
6
|
|
7
7
|
Gem::Specification.new do |s|
|
8
8
|
s.name = "perfect-shape".freeze
|
9
|
-
s.version = "0.
|
9
|
+
s.version = "0.3.0"
|
10
10
|
|
11
11
|
s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version=
|
12
12
|
s.require_paths = ["lib".freeze]
|
13
13
|
s.authors = ["Andy Maleh".freeze]
|
14
|
-
s.date = "2022-01-
|
15
|
-
s.description = "Perfect Shape is a collection of pure Ruby geometric algorithms that are mostly useful for GUI manipulation like checking containment of a mouse click point in popular geometry shapes such as rectangle, square, arc (open, chord, and pie), ellipse, circle, polygon, and paths containing lines, quadratic b\u00E9zier curves, and cubic
|
14
|
+
s.date = "2022-01-08"
|
15
|
+
s.description = "Perfect Shape is a collection of pure Ruby geometric algorithms that are mostly useful for GUI manipulation like checking containment of a mouse click point in popular geometry shapes such as rectangle, square, arc (open, chord, and pie), ellipse, circle, polygon, and paths containing lines, quadratic b\u00E9zier curves, and cubic bezier curves (including both Ray Casting Algorithm, aka Even-odd Rule, and Winding Number Algorithm, aka Nonzero Rule). Additionally, it contains some purely mathematical algorithms like IEEEremainder (also known as IEEE-754 remainder).".freeze
|
16
16
|
s.email = "andy.am@gmail.com".freeze
|
17
17
|
s.extra_rdoc_files = [
|
18
18
|
"CHANGELOG.md",
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: perfect-shape
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Andy Maleh
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-01-
|
11
|
+
date: 2022-01-08 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: equalizer
|
@@ -98,7 +98,7 @@ description: Perfect Shape is a collection of pure Ruby geometric algorithms tha
|
|
98
98
|
are mostly useful for GUI manipulation like checking containment of a mouse click
|
99
99
|
point in popular geometry shapes such as rectangle, square, arc (open, chord, and
|
100
100
|
pie), ellipse, circle, polygon, and paths containing lines, quadratic bézier curves,
|
101
|
-
and cubic
|
101
|
+
and cubic bezier curves (including both Ray Casting Algorithm, aka Even-odd Rule,
|
102
102
|
and Winding Number Algorithm, aka Nonzero Rule). Additionally, it contains some
|
103
103
|
purely mathematical algorithms like IEEEremainder (also known as IEEE-754 remainder).
|
104
104
|
email: andy.am@gmail.com
|