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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 78cfa9540ff6b960663bc61054940f3699a2fc12d4a9c45a84811eeea2db8872
4
- data.tar.gz: e8a7d1536b02fe49e6e32ef64baced2ca74f612a944ef1fcc452441b9e351ca2
3
+ metadata.gz: 4e7efc4e2333e43b5e4d034e7fa3a3dddbdc9c6fd392e9d2ae1a409995122eb5
4
+ data.tar.gz: 07f098098f6e42d6d71bdab33b44d3250c05c79ee48b2304b60784fba7de3f75
5
5
  SHA512:
6
- metadata.gz: 26ec5bc87ec612ea07a1ec6c38277d92ed4e2ff08f08d7e091d4254bdfc70b7da0704fc5a93f68063a14faa67fee32c57bac54cc0496df34f098aac8d85b4770
7
- data.tar.gz: 9334103aa1ea12b3f6d2d5f611bdcb36a1f532061e1e22b3dd4783498527665a9851c6294778720d21fa221113526bdfbbe0e8d6208462568680a17df026b2b5
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, distance: 0)`
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, distance: 0)`
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, distance: 0)` (add a distance tolerance fuzz factor option)
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.2.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 bézier 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)).
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.2.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.2.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, distance: 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.
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, distance: 5) # => false
130
- shape.contain?([200, 151], distance: 5) # => false
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, distance: 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.
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, distance: 5) # => true
173
- shape.contain?([50, 51], distance: 5) # => true
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 path is composed of
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.2.0
1
+ 0.3.0
@@ -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 distance The distance from line to tolerate (0 by default)
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, distance: 0)
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
- distance = BigDecimal(distance.to_s)
219
- point_segment_distance(x, y) <= distance
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)
@@ -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 distance The distance from point to tolerate (0 by default)
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, distance: 0)
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
- distance = BigDecimal(distance.to_s)
74
- point_distance(x, y) <= distance
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
- npoints = points.count
44
- xpoints = points.map(&:first)
45
- ypoints = points.map(&:last)
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
- if cury < lasty
80
- if y < cury || y >= lasty
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
- if x < leftx
86
- hits += 1
87
- lastx = curx
88
- lasty = cury
89
- next
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
- test1 = x - curx
92
- test2 = y - cury
93
- else
94
- if y < lasty || y >= cury
95
- lastx = curx
96
- lasty = cury
97
- next
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
- if x < leftx
100
- hits += 1
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 += 1 if (test1 < (test2 / (lasty - cury) * (lastx - curx)))
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
- x.between?(self.x, self.x + self.width) && y.between?(self.y, self.y + self.height)
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
@@ -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.2.0 ruby lib
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.2.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-07"
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 b\u00E9zier 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
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.2.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-07 00:00:00.000000000 Z
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 bézier curves (including both Ray Casting Algorithm, aka Even-odd Rule,
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