perfect-shape 0.3.1 → 0.3.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +30 -1
- data/LICENSE.txt +1 -1
- data/README.md +99 -34
- data/VERSION +1 -1
- data/lib/perfect-shape.rb +1 -1
- data/lib/perfect_shape/arc.rb +4 -3
- data/lib/perfect_shape/circle.rb +1 -1
- data/lib/perfect_shape/composite_shape.rb +4 -3
- data/lib/perfect_shape/cubic_bezier_curve.rb +123 -28
- data/lib/perfect_shape/ellipse.rb +1 -1
- data/lib/perfect_shape/line.rb +8 -8
- data/lib/perfect_shape/math.rb +21 -0
- data/lib/perfect_shape/multi_point.rb +8 -2
- data/lib/perfect_shape/path.rb +63 -13
- data/lib/perfect_shape/point.rb +7 -6
- data/lib/perfect_shape/point_location.rb +1 -1
- data/lib/perfect_shape/polygon.rb +8 -4
- data/lib/perfect_shape/quadratic_bezier_curve.rb +173 -86
- data/lib/perfect_shape/rectangle.rb +12 -5
- data/lib/perfect_shape/rectangular_shape.rb +1 -1
- data/lib/perfect_shape/shape.rb +13 -3
- data/lib/perfect_shape/square.rb +1 -1
- data/perfect-shape.gemspec +3 -3
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ab1f48d0551ed07a6a2b5f2d51abba6c6596eef82e156e68df57489319104e4c
|
4
|
+
data.tar.gz: bb67e137bbf23df2ed291a574ef45ae97113dd140d0a17269c9b60c27b7261e9
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6d365e47635c7daa094f02849df24696784b667c55bffa479bdbaacc41abf1b9ad1114084a4ed7bd0145e6dd18ad233f9b09e6bad8792828417aca49db2076c4
|
7
|
+
data.tar.gz: d8440bb0d35e1539dcf5c8cad79e2930d74e10e32a408391085027d773c0ea7e4272a6011a7244677c035c8f6a7954606065611282ae8cd14aab71cbbe6b2bba
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,34 @@
|
|
1
1
|
# Change Log
|
2
2
|
|
3
|
+
## 0.3.5
|
4
|
+
|
5
|
+
- Check point containment in composite shape outline with distance tolerance (new method signature: `PerfectShape::CompositeShape#contain?(x_or_point, y = nil, outline: false, distance_tolerance: 0)`)
|
6
|
+
|
7
|
+
## 0.3.4
|
8
|
+
|
9
|
+
- Check point containment in path outline with distance tolerance (new method signature: `PerfectShape::Path#contain?(x_or_point, y = nil, outline: false, distance_tolerance: 0)`)
|
10
|
+
- `PerfectShape::Path#disconnected_shapes`: Disconnected shapes have their start point filled in so that each shape does not depend on the previous shape to determine its start point.
|
11
|
+
- `Shape#center_point` as `[center_x, center_y]`
|
12
|
+
- Rename `#point_segment_distance` to `#point_distance` everywhere
|
13
|
+
|
14
|
+
## 0.3.3
|
15
|
+
|
16
|
+
- Check point containment in quadratic bezier curve outline with distance tolerance (new method signature: `PerfectShape::QuadraticBezierCurve#contain?(x_or_point, y = nil, outline: false, distance_tolerance: 0)`)
|
17
|
+
- `PerfectShape::QuadraticBezierCurve#curve_center_point`, `PerfectShape::QuadraticBezierCurve#curve_center_x`, `PerfectShape::QuadraticBezierCurve#curve_center_y`
|
18
|
+
- `PerfectShape::QuadraticBezierCurve#subdivisions(level=1)`
|
19
|
+
- `PerfectShape::QuadraticBezierCurve#point_distance(x_or_point, y = nil, minimum_distance_threshold: OUTLINE_MINIMUM_DISTANCE_THRESHOLD)`
|
20
|
+
- `PerfectShape::Polygon#edges` returns edges of polygon as `PerfectShape::Line` objects
|
21
|
+
- `PerfectShape::Rectangle#edges` returns edges of rectangle as `PerfectShape::Line` objects
|
22
|
+
- `PerfectShape::Square#edges` returns edges of square as `PerfectShape::Line` objects
|
23
|
+
- Rename `number` arg to `level` in `CubicBezierCurve#subdivisions(level=1)`, making it signify the level of subdivision recursion to perform.
|
24
|
+
|
25
|
+
## 0.3.2
|
26
|
+
|
27
|
+
- Check point containment in cubic bezier curve outline with distance tolerance (new method signature: `PerfectShape::CubicBezierCurve#contain?(x_or_point, y = nil, outline: false, distance_tolerance: 0)`)
|
28
|
+
- `PerfectShape::CubicBezierCurve#curve_center_point`, `PerfectShape::CubicBezierCurve#curve_center_x`, `PerfectShape::CubicBezierCurve#curve_center_y`
|
29
|
+
- `PerfectShape::CubicBezierCurve#subdivisions(level=1)`
|
30
|
+
- `PerfectShape::CubicBezierCurve#point_distance(x_or_point, y = nil, minimum_distance_threshold: OUTLINE_MINIMUM_DISTANCE_THRESHOLD)`
|
31
|
+
|
3
32
|
## 0.3.1
|
4
33
|
|
5
34
|
- Check point containment in arc outline with distance tolerance (new method signature: `PerfectShape::Arc#contain?(x_or_point, y = nil, outline: false, distance_tolerance: 0)`)
|
@@ -62,7 +91,7 @@
|
|
62
91
|
- `PerfectShape::Line`
|
63
92
|
- `PerfectShape::Line#contain?(x_or_point, y=nil)`
|
64
93
|
- `PerfectShape::Line#relative_counterclockwise`
|
65
|
-
- `PerfectShape::Line#
|
94
|
+
- `PerfectShape::Line#point_distance`
|
66
95
|
- Update `PerfectShape::Math::radians_to_degrees`, `PerfectShape::Math::degrees_to_radians`, and `PerfectShape::Math::normalize_degrees` to normalize numbers to `BigDecimal`
|
67
96
|
|
68
97
|
## 0.0.7
|
data/LICENSE.txt
CHANGED
data/README.md
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# Perfect Shape 0.3.
|
1
|
+
# Perfect Shape 0.3.5
|
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)
|
@@ -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.3.
|
17
|
+
gem install perfect-shape -v 0.3.5
|
18
18
|
```
|
19
19
|
|
20
20
|
Or include in Bundler `Gemfile`:
|
21
21
|
|
22
22
|
```ruby
|
23
|
-
gem 'perfect-shape', '~> 0.3.
|
23
|
+
gem 'perfect-shape', '~> 0.3.5'
|
24
24
|
```
|
25
25
|
|
26
26
|
And, run:
|
@@ -38,7 +38,7 @@ Module
|
|
38
38
|
- `::degrees_to_radians(angle)`: converts degrees to radians
|
39
39
|
- `::radians_to_degrees(angle)`: converts radians to degrees
|
40
40
|
- `::normalize_degrees(angle)`: normalizes the specified angle into the range -180 to 180.
|
41
|
-
- `::ieee_remainder(x, y)` (alias: `ieee754_remainder`): [IEEE 754-1985 Remainder](https://en.wikipedia.org/wiki/IEEE_754-1985) (different from standard
|
41
|
+
- `::ieee_remainder(x, y)` (alias: `ieee754_remainder`): [IEEE 754-1985 Remainder](https://en.wikipedia.org/wiki/IEEE_754-1985) (different from standard `%` modulo operator as it operates on floats and could return a negative result)
|
42
42
|
|
43
43
|
### `PerfectShape::Shape`
|
44
44
|
|
@@ -52,12 +52,13 @@ This is a base class for all shapes. It is not meant to be used directly. Subcla
|
|
52
52
|
- `#max_y`: max y
|
53
53
|
- `#width`: width
|
54
54
|
- `#height`: height
|
55
|
+
- `#center_point`: center point as `Array` of `[center_x, center_y]` coordinates
|
55
56
|
- `#center_x`: center x
|
56
57
|
- `#center_y`: center y
|
57
58
|
- `#bounding_box`: bounding box is a rectangle with x = min x, y = min y, and width/height just as those of shape
|
58
|
-
- `#normalize_point(x_or_point, y = nil)`: normalizes point into an `Array` of `[x,y]` coordinates
|
59
|
-
- `#contain?(x_or_point, y=nil)`: checks if point is inside
|
60
59
|
- `#==(other)`: Returns `true` if equal to `other` or `false` otherwise
|
60
|
+
- `#normalize_point(x_or_point, y = nil)`: normalizes point into an `Array` of `[x,y]` coordinates
|
61
|
+
- `#contain?(x_or_point, y=nil, outline: false, distance_tolerance: 0)`: checks if point is inside if `outline` is `false` or if point is on the outline if `outline` is `true`. `distance_tolerance` can be used as a fuzz factor when `outline` is `true`, for example, to help GUI users mouse-click-select a shape from its outline more successfully
|
61
62
|
|
62
63
|
### `PerfectShape::PointLocation`
|
63
64
|
|
@@ -84,9 +85,6 @@ Includes `PerfectShape::PointLocation`
|
|
84
85
|
- `#min_y`: min y
|
85
86
|
- `#max_x`: max x
|
86
87
|
- `#max_y`: max y
|
87
|
-
- `#center_x`: center x
|
88
|
-
- `#center_y`: center y
|
89
|
-
- `#bounding_box`: bounding box is a rectangle with x = min x, y = min y, and width/height of shape
|
90
88
|
|
91
89
|
### `PerfectShape::Point`
|
92
90
|
|
@@ -108,12 +106,13 @@ Points are simply represented by an `Array` of `[x,y]` coordinates when used wit
|
|
108
106
|
- `#max_y`: max y (always y)
|
109
107
|
- `#width`: width (always 0)
|
110
108
|
- `#height`: height (always 0)
|
109
|
+
- `#center_point`: center point as `Array` of `[center_x, center_y]` coordinates
|
111
110
|
- `#center_x`: center x (always x)
|
112
111
|
- `#center_y`: center y (always y)
|
113
112
|
- `#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_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 more successfully.
|
115
|
-
- `#point_distance(x_or_point, y=nil)`: Returns the distance from a point to another point
|
116
113
|
- `#==(other)`: Returns `true` if equal to `other` or `false` otherwise
|
114
|
+
- `#contain?(x_or_point, y=nil, outline: true, 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 more successfully. `outline` option makes no difference on point
|
115
|
+
- `#point_distance(x_or_point, y=nil)`: Returns the distance from a point to another point
|
117
116
|
|
118
117
|
Example:
|
119
118
|
|
@@ -141,8 +140,8 @@ Includes `PerfectShape::MultiPoint`
|
|
141
140
|
![line](https://raw.githubusercontent.com/AndyObtiva/perfect-shape/master/images/line.png)
|
142
141
|
|
143
142
|
- `::relative_counterclockwise(x1, y1, x2, y2, px, py)`: 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)”.
|
144
|
-
- `::
|
145
|
-
- `::
|
143
|
+
- `::point_distance_square(x1, y1, x2, y2, px, py)`: Returns the square of distance from a point to a line segment.
|
144
|
+
- `::point_distance(x1, y1, x2, y2, px, py)`: Returns the distance from a point to a line segment.
|
146
145
|
- `::new(points: [])`: constructs a line with two `points` as `Array` of `Array`s of `[x,y]` pairs or flattened `Array` of alternating x and y coordinates
|
147
146
|
- `#min_x`: min x
|
148
147
|
- `#min_y`: min y
|
@@ -150,13 +149,14 @@ Includes `PerfectShape::MultiPoint`
|
|
150
149
|
- `#max_y`: max y
|
151
150
|
- `#width`: width (from min x to max x)
|
152
151
|
- `#height`: height (from min y to max y)
|
152
|
+
- `#center_point`: center point as `Array` of `[center_x, center_y]` coordinates
|
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_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 more successfully.
|
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
|
-
- `#point_segment_distance(x_or_point, y=nil)`: Returns the distance from a point to a line segment.
|
159
156
|
- `#==(other)`: Returns `true` if equal to `other` or `false` otherwise
|
157
|
+
- `#contain?(x_or_point, y=nil, outline: true, 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 more successfully. `outline` option makes no difference on line
|
158
|
+
- `#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)”.
|
159
|
+
- `#point_distance(x_or_point, y=nil)`: Returns the distance from a point to a line segment.
|
160
160
|
|
161
161
|
Example:
|
162
162
|
|
@@ -191,11 +191,17 @@ Includes `PerfectShape::MultiPoint`
|
|
191
191
|
- `#max_y`: max y
|
192
192
|
- `#width`: width (from min x to max x)
|
193
193
|
- `#height`: height (from min y to max y)
|
194
|
+
- `#center_point`: center point as `Array` of `[center_x, center_y]` coordinates
|
194
195
|
- `#center_x`: center x
|
195
196
|
- `#center_y`: center y
|
196
197
|
- `#bounding_box`: bounding box is a rectangle with x = min x, y = min y, and width/height of shape (bounding box only guarantees that the shape is within it, but it might be bigger than the shape)
|
197
|
-
- `#contain?(x_or_point, y=nil)`: checks if point is inside
|
198
198
|
- `#==(other)`: Returns `true` if equal to `other` or `false` otherwise
|
199
|
+
- `#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 GUI users mouse-click-select a quadratic bezier curve shape from its outline more successfully
|
200
|
+
- `#curve_center_point`: point at the center of the curve outline (not the center of the bounding box area like `center_x` and `center_y`)
|
201
|
+
- `#curve_center_x`: point x coordinate at the center of the curve outline (not the center of the bounding box area like `center_x` and `center_y`)
|
202
|
+
- `#curve_center_y`: point y coordinate at the center of the curve outline (not the center of the bounding box area like `center_x` and `center_y`)
|
203
|
+
- `#subdivisions(level=1)`: subdivides quadratic bezier curve at its center into into 2 quadratic bezier curves by default, or more if `level` of recursion is specified. The resulting number of subdivisions is `2` to the power of `level`.
|
204
|
+
- `#point_distance(x_or_point, y=nil, minimum_distance_threshold: OUTLINE_MINIMUM_DISTANCE_THRESHOLD)`: calculates distance from point to curve segment. It does so by subdividing curve into smaller curves and checking against the curve center points until the distance is less than `minimum_distance_threshold`, to avoid being an overly costly operation.
|
199
205
|
|
200
206
|
Example:
|
201
207
|
|
@@ -206,6 +212,14 @@ shape = PerfectShape::QuadraticBezierCurve.new(points: [[200, 150], [270, 320],
|
|
206
212
|
|
207
213
|
shape.contain?(270, 220) # => true
|
208
214
|
shape.contain?([270, 220]) # => true
|
215
|
+
shape.contain?(270, 220, outline: true) # => false
|
216
|
+
shape.contain?([270, 220], outline: true) # => false
|
217
|
+
shape.contain?(280, 235, outline: true) # => true
|
218
|
+
shape.contain?([280, 235], outline: true) # => true
|
219
|
+
shape.contain?(281, 235, outline: true) # => false
|
220
|
+
shape.contain?([281, 235], outline: true) # => false
|
221
|
+
shape.contain?(281, 235, outline: true, distance_tolerance: 1) # => true
|
222
|
+
shape.contain?([281, 235], outline: true, distance_tolerance: 1) # => true
|
209
223
|
```
|
210
224
|
|
211
225
|
### `PerfectShape::CubicBezierCurve`
|
@@ -226,11 +240,17 @@ Includes `PerfectShape::MultiPoint`
|
|
226
240
|
- `#max_y`: max y
|
227
241
|
- `#width`: width (from min x to max x)
|
228
242
|
- `#height`: height (from min y to max y)
|
243
|
+
- `#center_point`: center point as `Array` of `[center_x, center_y]` coordinates
|
229
244
|
- `#center_x`: center x
|
230
245
|
- `#center_y`: center y
|
231
246
|
- `#bounding_box`: bounding box is a rectangle with x = min x, y = min y, and width/height of shape (bounding box only guarantees that the shape is within it, but it might be bigger than the shape)
|
232
|
-
- `#contain?(x_or_point, y=nil)`: checks if point is inside
|
233
247
|
- `#==(other)`: Returns `true` if equal to `other` or `false` otherwise
|
248
|
+
- `#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 GUI users mouse-click-select a cubic bezier curve shape from its outline more successfully
|
249
|
+
- `#curve_center_point`: point at the center of the curve outline (not the center of the bounding box area like `center_x` and `center_y`)
|
250
|
+
- `#curve_center_x`: point x coordinate at the center of the curve outline (not the center of the bounding box area like `center_x` and `center_y`)
|
251
|
+
- `#curve_center_y`: point y coordinate at the center of the curve outline (not the center of the bounding box area like `center_x` and `center_y`)
|
252
|
+
- `#subdivisions(level=1)`: subdivides cubic bezier curve at its center into into 2 cubic bezier curves by default, or more if `level` of recursion is specified. The resulting number of subdivisions is `2` to the power of `level`.
|
253
|
+
- `#point_distance(x_or_point, y=nil, minimum_distance_threshold: OUTLINE_MINIMUM_DISTANCE_THRESHOLD)`: calculates distance from point to curve segment. It does so by subdividing curve into smaller curves and checking against the curve center points until the distance is less than `minimum_distance_threshold`, to avoid being an overly costly operation.
|
234
254
|
|
235
255
|
Example:
|
236
256
|
|
@@ -241,6 +261,14 @@ shape = PerfectShape::CubicBezierCurve.new(points: [[200, 150], [235, 235], [270
|
|
241
261
|
|
242
262
|
shape.contain?(270, 220) # => true
|
243
263
|
shape.contain?([270, 220]) # => true
|
264
|
+
shape.contain?(270, 220, outline: true) # => false
|
265
|
+
shape.contain?([270, 220], outline: true) # => false
|
266
|
+
shape.contain?(261.875, 245.625, outline: true) # => true
|
267
|
+
shape.contain?([261.875, 245.625], outline: true) # => true
|
268
|
+
shape.contain?(261.875, 246.625, outline: true) # => false
|
269
|
+
shape.contain?([261.875, 246.625], outline: true) # => false
|
270
|
+
shape.contain?(261.875, 246.625, outline: true, distance_tolerance: 1) # => true
|
271
|
+
shape.contain?([261.875, 246.625], outline: true, distance_tolerance: 1) # => true
|
244
272
|
```
|
245
273
|
|
246
274
|
### `PerfectShape::Rectangle`
|
@@ -258,6 +286,7 @@ Includes `PerfectShape::RectangularShape`
|
|
258
286
|
- `#y`: top-left y
|
259
287
|
- `#width`: width
|
260
288
|
- `#height`: height
|
289
|
+
- `#center_point`: center point as `Array` of `[center_x, center_y]` coordinates
|
261
290
|
- `#center_x`: center x
|
262
291
|
- `#center_y`: center y
|
263
292
|
- `#min_x`: min x
|
@@ -265,8 +294,9 @@ Includes `PerfectShape::RectangularShape`
|
|
265
294
|
- `#max_x`: max x
|
266
295
|
- `#max_y`: max y
|
267
296
|
- `#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, 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 GUI users mouse-click-select a rectangle shape from its outline more successfully
|
269
297
|
- `#==(other)`: Returns `true` if equal to `other` or `false` otherwise
|
298
|
+
- `#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 GUI users mouse-click-select a rectangle shape from its outline more successfully
|
299
|
+
- `#edges`: edges of rectangle as `PerfectShape::Line` objects
|
270
300
|
|
271
301
|
Example:
|
272
302
|
|
@@ -301,6 +331,7 @@ Extends `PerfectShape::Rectangle`
|
|
301
331
|
- `#length`: length
|
302
332
|
- `#width`: width (equal to length)
|
303
333
|
- `#height`: height (equal to length)
|
334
|
+
- `#center_point`: center point as `Array` of `[center_x, center_y]` coordinates
|
304
335
|
- `#center_x`: center x
|
305
336
|
- `#center_y`: center y
|
306
337
|
- `#min_x`: min x
|
@@ -308,8 +339,9 @@ Extends `PerfectShape::Rectangle`
|
|
308
339
|
- `#max_x`: max x
|
309
340
|
- `#max_y`: max y
|
310
341
|
- `#bounding_box`: bounding box is a rectangle with x = min x, y = min y, and width/height of shape
|
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 GUI users mouse-click-select a square shape from its outline more successfully
|
312
342
|
- `#==(other)`: Returns `true` if equal to `other` or `false` otherwise
|
343
|
+
- `#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 GUI users mouse-click-select a square shape from its outline more successfully
|
344
|
+
- `#edges`: edges of square as `PerfectShape::Line` objects
|
313
345
|
|
314
346
|
Example:
|
315
347
|
|
@@ -352,6 +384,7 @@ Open Arc | Chord Arc | Pie Arc
|
|
352
384
|
- `#height`: height
|
353
385
|
- `#start`: start angle in degrees
|
354
386
|
- `#extent`: extent angle in degrees
|
387
|
+
- `#center_point`: center point as `Array` of `[center_x, center_y]` coordinates
|
355
388
|
- `#center_x`: center x
|
356
389
|
- `#center_y`: center y
|
357
390
|
- `#radius_x`: radius along the x-axis
|
@@ -361,8 +394,8 @@ Open Arc | Chord Arc | Pie Arc
|
|
361
394
|
- `#max_x`: max x
|
362
395
|
- `#max_y`: max y
|
363
396
|
- `#bounding_box`: bounding box is a rectangle with x = min x, y = min y, and width/height of shape
|
364
|
-
- `#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 GUI users mouse-click-select an arc shape from its outline more successfully
|
365
397
|
- `#==(other)`: Returns `true` if equal to `other` or `false` otherwise
|
398
|
+
- `#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 GUI users mouse-click-select an arc shape from its outline more successfully
|
366
399
|
|
367
400
|
Example:
|
368
401
|
|
@@ -471,6 +504,7 @@ Extends `PerfectShape::Arc`
|
|
471
504
|
- `#y`: top-left y
|
472
505
|
- `#width`: width
|
473
506
|
- `#height`: height
|
507
|
+
- `#center_point`: center point as `Array` of `[center_x, center_y]` coordinates
|
474
508
|
- `#center_x`: center x
|
475
509
|
- `#center_y`: center y
|
476
510
|
- `#radius_x`: radius along the x-axis
|
@@ -483,8 +517,8 @@ Extends `PerfectShape::Arc`
|
|
483
517
|
- `#max_x`: max x
|
484
518
|
- `#max_y`: max y
|
485
519
|
- `#bounding_box`: bounding box is a rectangle with x = min x, y = min y, and width/height of shape
|
486
|
-
- `#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 GUI users mouse-click-select an ellipse shape from its outline more successfully
|
487
520
|
- `#==(other)`: Returns `true` if equal to `other` or `false` otherwise
|
521
|
+
- `#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 GUI users mouse-click-select an ellipse shape from its outline more successfully
|
488
522
|
|
489
523
|
Example:
|
490
524
|
|
@@ -530,6 +564,7 @@ Extends `PerfectShape::Ellipse`
|
|
530
564
|
- `#diameter`: diameter
|
531
565
|
- `#width`: width (equal to diameter)
|
532
566
|
- `#height`: height (equal to diameter)
|
567
|
+
- `#center_point`: center point as `Array` of `[center_x, center_y]` coordinates
|
533
568
|
- `#center_x`: center x
|
534
569
|
- `#center_y`: center y
|
535
570
|
- `#radius`: radius
|
@@ -543,8 +578,8 @@ Extends `PerfectShape::Ellipse`
|
|
543
578
|
- `#max_x`: max x
|
544
579
|
- `#max_y`: max y
|
545
580
|
- `#bounding_box`: bounding box is a rectangle with x = min x, y = min y, and width/height of shape
|
546
|
-
- `#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 GUI users mouse-click-select a circle shape from its outline more successfully
|
547
581
|
- `#==(other)`: Returns `true` if equal to `other` or `false` otherwise
|
582
|
+
- `#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 GUI users mouse-click-select a circle shape from its outline more successfully
|
548
583
|
|
549
584
|
Example:
|
550
585
|
|
@@ -595,11 +630,13 @@ A polygon can be thought of as a special case of [path](#perfectshapepath) that
|
|
595
630
|
- `#max_y`: max y
|
596
631
|
- `#width`: width (from min x to max x)
|
597
632
|
- `#height`: height (from min y to max y)
|
633
|
+
- `#center_point`: center point as `Array` of `[center_x, center_y]` coordinates
|
598
634
|
- `#center_x`: center x
|
599
635
|
- `#center_y`: center y
|
600
636
|
- `#bounding_box`: bounding box is a rectangle with x = min x, y = min y, and width/height of shape
|
601
|
-
- `#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 GUI users mouse-click-select a polygon shape from its outline more successfully
|
602
637
|
- `#==(other)`: Returns `true` if equal to `other` or `false` otherwise
|
638
|
+
- `#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 GUI users mouse-click-select a polygon shape from its outline more successfully
|
639
|
+
- `#edges`: edges of polygon as `PerfectShape::Line` objects
|
603
640
|
|
604
641
|
Example:
|
605
642
|
|
@@ -641,12 +678,14 @@ Includes `PerfectShape::MultiPoint`
|
|
641
678
|
- `#max_y`: max y
|
642
679
|
- `#width`: width (from min x to max x)
|
643
680
|
- `#height`: height (from min y to max y)
|
681
|
+
- `#center_point`: center point as `Array` of `[center_x, center_y]` coordinates
|
644
682
|
- `#center_x`: center x
|
645
683
|
- `#center_y`: center y
|
646
684
|
- `#bounding_box`: bounding box is a rectangle with x = min x, y = min y, and width/height of shape (bounding box only guarantees that the shape is within it, but it might be bigger than the shape)
|
647
|
-
- `#contain?(x_or_point, y=nil)`: checks if point is inside path utilizing the configured winding rule, which can be the [Nonzero-Rule](https://en.wikipedia.org/wiki/Nonzero-rule) (aka [Winding Number Algorithm](https://en.wikipedia.org/wiki/Point_in_polygon#Winding_number_algorithm)) or the [Even-Odd Rule](https://en.wikipedia.org/wiki/Even%E2%80%93odd_rule) (aka [Ray Casting Algorithm](https://en.wikipedia.org/wiki/Point_in_polygon#Ray_casting_algorithm))
|
648
|
-
- `#point_crossings(x_or_point, y=nil)`: calculates the number of times the given path crosses the ray extending to the right from (x,y)
|
649
685
|
- `#==(other)`: Returns `true` if equal to `other` or `false` otherwise
|
686
|
+
- `#contain?(x_or_point, y=nil, outline: false, distance_tolerance: 0)`: When `outline` is `false`, it checks if point is inside path utilizing the configured winding rule, which can be the [Nonzero-Rule](https://en.wikipedia.org/wiki/Nonzero-rule) (aka [Winding Number Algorithm](https://en.wikipedia.org/wiki/Point_in_polygon#Winding_number_algorithm)) or the [Even-Odd Rule](https://en.wikipedia.org/wiki/Even%E2%80%93odd_rule) (aka [Ray Casting Algorithm](https://en.wikipedia.org/wiki/Point_in_polygon#Ray_casting_algorithm)). 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 GUI users mouse-click-select a path shape from its outline more successfully
|
687
|
+
- `#point_crossings(x_or_point, y=nil)`: calculates the number of times the given path crosses the ray extending to the right from (x,y)
|
688
|
+
- `#disconnected_shapes`: Disconnected shapes have their start point filled in so that each shape does not depend on the previous shape to determine its start point. Also, if a point is followed by a non-point shape, it is removed since it is augmented to the following shape as its start point. Lastly, if the path is closed, an extra shape is added to represent the line connecting the last point to the first
|
650
689
|
|
651
690
|
Example:
|
652
691
|
|
@@ -661,8 +700,16 @@ path_shapes << PerfectShape::CubicBezierCurve.new(points: [[370, 50], [430, 220]
|
|
661
700
|
|
662
701
|
shape = PerfectShape::Path.new(shapes: path_shapes, closed: false, winding_rule: :wind_even_odd)
|
663
702
|
|
664
|
-
shape.contain?(
|
665
|
-
shape.contain?([
|
703
|
+
shape.contain?(275, 165) # => true
|
704
|
+
shape.contain?([275, 165]) # => true
|
705
|
+
shape.contain?(275, 165, outline: true) # => false
|
706
|
+
shape.contain?([275, 165], outline: true) # => false
|
707
|
+
shape.contain?(shape.disconnected_shapes[1].curve_center_x, shape.disconnected_shapes[1].curve_center_y, outline: true) # => true
|
708
|
+
shape.contain?([shape.disconnected_shapes[1].curve_center_x, shape.disconnected_shapes[1].curve_center_y], outline: true) # => true
|
709
|
+
shape.contain?(shape.disconnected_shapes[1].curve_center_x + 1, shape.disconnected_shapes[1].curve_center_y, outline: true) # => false
|
710
|
+
shape.contain?([shape.disconnected_shapes[1].curve_center_x + 1, shape.disconnected_shapes[1].curve_center_y], outline: true) # => false
|
711
|
+
shape.contain?(shape.disconnected_shapes[1].curve_center_x + 1, shape.disconnected_shapes[1].curve_center_y, outline: true, distance_tolerance: 1) # => true
|
712
|
+
shape.contain?([shape.disconnected_shapes[1].curve_center_x + 1, shape.disconnected_shapes[1].curve_center_y], outline: true, distance_tolerance: 1) # => true
|
666
713
|
```
|
667
714
|
|
668
715
|
### `PerfectShape::CompositeShape`
|
@@ -683,11 +730,12 @@ A composite shape is simply an aggregate of multiple shapes (e.g. square and pol
|
|
683
730
|
- `#max_y`: max y
|
684
731
|
- `#width`: width (from min x to max x)
|
685
732
|
- `#height`: height (from min y to max y)
|
733
|
+
- `#center_point`: center point as `Array` of `[center_x, center_y]` coordinates
|
686
734
|
- `#center_x`: center x
|
687
735
|
- `#center_y`: center y
|
688
736
|
- `#bounding_box`: bounding box is a rectangle with x = min x, y = min y, and width/height of shape (bounding box only guarantees that the shape is within it, but it might be bigger than the shape)
|
689
|
-
- `#contain?(x_or_point, y=nil)`: checks if point is inside any of the shapes owned by the composite shape
|
690
737
|
- `#==(other)`: Returns `true` if equal to `other` or `false` otherwise
|
738
|
+
- `#contain?(x_or_point, y=nil)`: When `outline` is `false`, it checks if point is inside any of the shapes owned by the composite shape. Otherwise, when `outline` is `true`, it checks if point is on the outline of any of the shapes owned by the composite shape. `distance_tolerance` can be used as a fuzz factor when `outline` is `true`, for example, to help GUI users mouse-click-select a composite shape from its outline more successfully
|
691
739
|
|
692
740
|
Example:
|
693
741
|
|
@@ -700,10 +748,27 @@ shapes << PerfectShape::Polygon.new(points: [[120, 215], [170, 165], [220, 215]]
|
|
700
748
|
|
701
749
|
shape = PerfectShape::CompositeShape.new(shapes: shapes)
|
702
750
|
|
703
|
-
shape.contain?(170, 265) # => true
|
704
|
-
shape.contain?([170, 265]) # => true
|
705
|
-
shape.contain?(170,
|
706
|
-
shape.contain?([170,
|
751
|
+
shape.contain?(170, 265) # => true inside square
|
752
|
+
shape.contain?([170, 265]) # => true inside square
|
753
|
+
shape.contain?(170, 265, outline: true) # => false
|
754
|
+
shape.contain?([170, 265], outline: true) # => false
|
755
|
+
shape.contain?(170, 315, outline: true) # => true
|
756
|
+
shape.contain?([170, 315], outline: true) # => true
|
757
|
+
shape.contain?(170, 316, outline: true) # => false
|
758
|
+
shape.contain?([170, 316], outline: true) # => false
|
759
|
+
shape.contain?(170, 316, outline: true, distance_tolerance: 1) # => true
|
760
|
+
shape.contain?([170, 316], outline: true, distance_tolerance: 1) # => true
|
761
|
+
|
762
|
+
shape.contain?(170, 190) # => true inside polygon
|
763
|
+
shape.contain?([170, 190]) # => true inside polygon
|
764
|
+
shape.contain?(170, 190, outline: true) # => false
|
765
|
+
shape.contain?([170, 190], outline: true) # => false
|
766
|
+
shape.contain?(145, 190, outline: true) # => true
|
767
|
+
shape.contain?([145, 190], outline: true) # => true
|
768
|
+
shape.contain?(145, 189, outline: true) # => false
|
769
|
+
shape.contain?([145, 189], outline: true) # => false
|
770
|
+
shape.contain?(145, 189, outline: true, distance_tolerance: 1) # => true
|
771
|
+
shape.contain?([145, 189], outline: true, distance_tolerance: 1) # => true
|
707
772
|
```
|
708
773
|
|
709
774
|
## Process
|
@@ -743,5 +808,5 @@ shape.contain?([170, 190]) # => true
|
|
743
808
|
|
744
809
|
[MIT](LICENSE.txt)
|
745
810
|
|
746
|
-
Copyright (c) 2021 Andy Maleh. See
|
811
|
+
Copyright (c) 2021-2022 Andy Maleh. See
|
747
812
|
[LICENSE.txt](LICENSE.txt) for further details.
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.3.
|
1
|
+
0.3.5
|
data/lib/perfect-shape.rb
CHANGED
data/lib/perfect_shape/arc.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# Copyright (c) 2021 Andy Maleh
|
1
|
+
# Copyright (c) 2021-2022 Andy Maleh
|
2
2
|
#
|
3
3
|
# Permission is hereby granted, free of charge, to any person obtaining
|
4
4
|
# a copy of this software and associated documentation files (the
|
@@ -30,6 +30,7 @@ module PerfectShape
|
|
30
30
|
include Equalizer.new(:type, :x, :y, :width, :height, :start, :extent)
|
31
31
|
|
32
32
|
TYPES = [:open, :chord, :pie]
|
33
|
+
DEFAULT_OUTLINE_RADIUS = BigDecimal('0.001')
|
33
34
|
attr_accessor :type
|
34
35
|
attr_reader :start, :extent
|
35
36
|
|
@@ -151,8 +152,8 @@ module PerfectShape
|
|
151
152
|
true
|
152
153
|
else
|
153
154
|
distance_tolerance = BigDecimal(distance_tolerance.to_s)
|
154
|
-
outside_inside_radius_difference =
|
155
|
-
outside_radius_difference = inside_radius_difference = outside_inside_radius_difference / 2
|
155
|
+
outside_inside_radius_difference = DEFAULT_OUTLINE_RADIUS + distance_tolerance * 2
|
156
|
+
outside_radius_difference = inside_radius_difference = outside_inside_radius_difference / 2
|
156
157
|
outside_shape = Arc.new(type: type, center_x: center_x, center_y: center_y, radius_x: radius_x + outside_radius_difference, radius_y: radius_y + outside_radius_difference, start: start, extent: extent)
|
157
158
|
inside_shape = Arc.new(type: type, center_x: center_x, center_y: center_y, radius_x: radius_x - inside_radius_difference, radius_y: radius_y - inside_radius_difference, start: start, extent: extent)
|
158
159
|
outside_shape.contain?(x, y, outline: false) and
|
data/lib/perfect_shape/circle.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# Copyright (c) 2021 Andy Maleh
|
1
|
+
# Copyright (c) 2021-2022 Andy Maleh
|
2
2
|
#
|
3
3
|
# Permission is hereby granted, free of charge, to any person obtaining
|
4
4
|
# a copy of this software and associated documentation files (the
|
@@ -63,10 +63,11 @@ module PerfectShape
|
|
63
63
|
# @return true if the point lies within the bound of
|
64
64
|
# the composite shape or false if the point lies outside of the
|
65
65
|
# path's bounds.
|
66
|
-
def contain?(x_or_point, y = nil)
|
66
|
+
def contain?(x_or_point, y = nil, outline: false, distance_tolerance: 0)
|
67
67
|
x, y = normalize_point(x_or_point, y)
|
68
68
|
return unless x && y
|
69
|
-
|
69
|
+
|
70
|
+
shapes.any? { |shape| shape.contain?(x, y, outline: outline, distance_tolerance: distance_tolerance) }
|
70
71
|
end
|
71
72
|
end
|
72
73
|
end
|