perfect-shape 0.3.3 → 0.3.4
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 +39 -20
- data/VERSION +1 -1
- data/lib/perfect_shape/arc.rb +2 -2
- data/lib/perfect_shape/cubic_bezier_curve.rb +38 -33
- data/lib/perfect_shape/line.rb +7 -7
- data/lib/perfect_shape/multi_point.rb +7 -1
- data/lib/perfect_shape/path.rb +62 -12
- data/lib/perfect_shape/point.rb +6 -5
- data/lib/perfect_shape/quadratic_bezier_curve.rb +10 -9
- data/lib/perfect_shape/shape.rb +8 -2
- 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: 4dc25ad218f1860bfff0fccc88b81ea4b6ef71795c737b740b998385f4c7bf7d
|
4
|
+
data.tar.gz: 31b52e8b765db80edde7ede8487f579a5de33b51fa1939bc1601dbad093741b1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 949d9a223e08cf4b9154f63f575908707c257620e18fdcd4a2820855c305400f418038b5ec53b56c4a4baea7c38065df8da71158dc29c76a5a19a809bf38da33
|
7
|
+
data.tar.gz: '049d0fb36f1b633ebb20cf9fae4731688a19197a4bcbf29cbf55a7f837a5e4a9916b9b3a396a2f859387d3f80fcc7d8ebb9c6a23757dc3b389b0c70e79c7b845'
|
data/CHANGELOG.md
CHANGED
@@ -1,11 +1,18 @@
|
|
1
1
|
# Change Log
|
2
2
|
|
3
|
+
## 0.3.4
|
4
|
+
|
5
|
+
- 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)`)
|
6
|
+
- `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.
|
7
|
+
- `Shape#center_point` as `[center_x, center_y]`
|
8
|
+
- Rename `#point_segment_distance` to `#point_distance` everywhere
|
9
|
+
|
3
10
|
## 0.3.3
|
4
11
|
|
5
12
|
- 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)`)
|
6
13
|
- `PerfectShape::QuadraticBezierCurve#curve_center_point`, `PerfectShape::QuadraticBezierCurve#curve_center_x`, `PerfectShape::QuadraticBezierCurve#curve_center_y`
|
7
14
|
- `PerfectShape::QuadraticBezierCurve#subdivisions(level=1)`
|
8
|
-
- `PerfectShape::QuadraticBezierCurve#
|
15
|
+
- `PerfectShape::QuadraticBezierCurve#point_distance(x_or_point, y = nil, minimum_distance_threshold: OUTLINE_MINIMUM_DISTANCE_THRESHOLD)`
|
9
16
|
- `PerfectShape::Polygon#edges` returns edges of polygon as `PerfectShape::Line` objects
|
10
17
|
- `PerfectShape::Rectangle#edges` returns edges of rectangle as `PerfectShape::Line` objects
|
11
18
|
- `PerfectShape::Square#edges` returns edges of square as `PerfectShape::Line` objects
|
@@ -16,7 +23,7 @@
|
|
16
23
|
- 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)`)
|
17
24
|
- `PerfectShape::CubicBezierCurve#curve_center_point`, `PerfectShape::CubicBezierCurve#curve_center_x`, `PerfectShape::CubicBezierCurve#curve_center_y`
|
18
25
|
- `PerfectShape::CubicBezierCurve#subdivisions(level=1)`
|
19
|
-
- `PerfectShape::CubicBezierCurve#
|
26
|
+
- `PerfectShape::CubicBezierCurve#point_distance(x_or_point, y = nil, minimum_distance_threshold: OUTLINE_MINIMUM_DISTANCE_THRESHOLD)`
|
20
27
|
|
21
28
|
## 0.3.1
|
22
29
|
|
@@ -80,7 +87,7 @@
|
|
80
87
|
- `PerfectShape::Line`
|
81
88
|
- `PerfectShape::Line#contain?(x_or_point, y=nil)`
|
82
89
|
- `PerfectShape::Line#relative_counterclockwise`
|
83
|
-
- `PerfectShape::Line#
|
90
|
+
- `PerfectShape::Line#point_distance`
|
84
91
|
- Update `PerfectShape::Math::radians_to_degrees`, `PerfectShape::Math::degrees_to_radians`, and `PerfectShape::Math::normalize_degrees` to normalize numbers to `BigDecimal`
|
85
92
|
|
86
93
|
## 0.0.7
|
data/README.md
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# Perfect Shape 0.3.
|
1
|
+
# Perfect Shape 0.3.4
|
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.4
|
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.4'
|
24
24
|
```
|
25
25
|
|
26
26
|
And, run:
|
@@ -52,6 +52,7 @@ 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
|
@@ -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,11 +106,12 @@ 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
113
|
- `#==(other)`: Returns `true` if equal to `other` or `false` otherwise
|
115
|
-
- `#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.
|
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
|
116
115
|
- `#point_distance(x_or_point, y=nil)`: Returns the distance from a point to another point
|
117
116
|
|
118
117
|
Example:
|
@@ -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
156
|
- `#==(other)`: Returns `true` if equal to `other` or `false` otherwise
|
157
|
-
- `#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
|
+
- `#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
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
|
-
- `#
|
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,16 +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
198
|
- `#==(other)`: Returns `true` if equal to `other` or `false` otherwise
|
198
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
|
199
|
-
- `#curve_center_point`: point at the center of the curve (not the center of the bounding box area like `center_x` and `center_y`)
|
200
|
-
- `#curve_center_x`: point x coordinate at the center of the curve (not the center of the bounding box area like `center_x` and `center_y`)
|
201
|
-
- `#curve_center_y`: point y coordinate at the center of the curve (not the center of the bounding box area like `center_x` and `center_y`)
|
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`)
|
202
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`.
|
203
|
-
- `#
|
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.
|
204
205
|
|
205
206
|
Example:
|
206
207
|
|
@@ -239,16 +240,17 @@ Includes `PerfectShape::MultiPoint`
|
|
239
240
|
- `#max_y`: max y
|
240
241
|
- `#width`: width (from min x to max x)
|
241
242
|
- `#height`: height (from min y to max y)
|
243
|
+
- `#center_point`: center point as `Array` of `[center_x, center_y]` coordinates
|
242
244
|
- `#center_x`: center x
|
243
245
|
- `#center_y`: center y
|
244
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)
|
245
247
|
- `#==(other)`: Returns `true` if equal to `other` or `false` otherwise
|
246
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
|
247
|
-
- `#curve_center_point`: point at the center of the curve (not the center of the bounding box area like `center_x` and `center_y`)
|
248
|
-
- `#curve_center_x`: point x coordinate at the center of the curve (not the center of the bounding box area like `center_x` and `center_y`)
|
249
|
-
- `#curve_center_y`: point y coordinate at the center of the curve (not the center of the bounding box area like `center_x` and `center_y`)
|
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`)
|
250
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`.
|
251
|
-
- `#
|
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.
|
252
254
|
|
253
255
|
Example:
|
254
256
|
|
@@ -284,6 +286,7 @@ Includes `PerfectShape::RectangularShape`
|
|
284
286
|
- `#y`: top-left y
|
285
287
|
- `#width`: width
|
286
288
|
- `#height`: height
|
289
|
+
- `#center_point`: center point as `Array` of `[center_x, center_y]` coordinates
|
287
290
|
- `#center_x`: center x
|
288
291
|
- `#center_y`: center y
|
289
292
|
- `#min_x`: min x
|
@@ -328,6 +331,7 @@ Extends `PerfectShape::Rectangle`
|
|
328
331
|
- `#length`: length
|
329
332
|
- `#width`: width (equal to length)
|
330
333
|
- `#height`: height (equal to length)
|
334
|
+
- `#center_point`: center point as `Array` of `[center_x, center_y]` coordinates
|
331
335
|
- `#center_x`: center x
|
332
336
|
- `#center_y`: center y
|
333
337
|
- `#min_x`: min x
|
@@ -380,6 +384,7 @@ Open Arc | Chord Arc | Pie Arc
|
|
380
384
|
- `#height`: height
|
381
385
|
- `#start`: start angle in degrees
|
382
386
|
- `#extent`: extent angle in degrees
|
387
|
+
- `#center_point`: center point as `Array` of `[center_x, center_y]` coordinates
|
383
388
|
- `#center_x`: center x
|
384
389
|
- `#center_y`: center y
|
385
390
|
- `#radius_x`: radius along the x-axis
|
@@ -499,6 +504,7 @@ Extends `PerfectShape::Arc`
|
|
499
504
|
- `#y`: top-left y
|
500
505
|
- `#width`: width
|
501
506
|
- `#height`: height
|
507
|
+
- `#center_point`: center point as `Array` of `[center_x, center_y]` coordinates
|
502
508
|
- `#center_x`: center x
|
503
509
|
- `#center_y`: center y
|
504
510
|
- `#radius_x`: radius along the x-axis
|
@@ -558,6 +564,7 @@ Extends `PerfectShape::Ellipse`
|
|
558
564
|
- `#diameter`: diameter
|
559
565
|
- `#width`: width (equal to diameter)
|
560
566
|
- `#height`: height (equal to diameter)
|
567
|
+
- `#center_point`: center point as `Array` of `[center_x, center_y]` coordinates
|
561
568
|
- `#center_x`: center x
|
562
569
|
- `#center_y`: center y
|
563
570
|
- `#radius`: radius
|
@@ -623,6 +630,7 @@ A polygon can be thought of as a special case of [path](#perfectshapepath) that
|
|
623
630
|
- `#max_y`: max y
|
624
631
|
- `#width`: width (from min x to max x)
|
625
632
|
- `#height`: height (from min y to max y)
|
633
|
+
- `#center_point`: center point as `Array` of `[center_x, center_y]` coordinates
|
626
634
|
- `#center_x`: center x
|
627
635
|
- `#center_y`: center y
|
628
636
|
- `#bounding_box`: bounding box is a rectangle with x = min x, y = min y, and width/height of shape
|
@@ -670,12 +678,14 @@ Includes `PerfectShape::MultiPoint`
|
|
670
678
|
- `#max_y`: max y
|
671
679
|
- `#width`: width (from min x to max x)
|
672
680
|
- `#height`: height (from min y to max y)
|
681
|
+
- `#center_point`: center point as `Array` of `[center_x, center_y]` coordinates
|
673
682
|
- `#center_x`: center x
|
674
683
|
- `#center_y`: center y
|
675
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)
|
676
685
|
- `#==(other)`: Returns `true` if equal to `other` or `false` otherwise
|
677
|
-
- `#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))
|
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
|
678
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
|
679
689
|
|
680
690
|
Example:
|
681
691
|
|
@@ -692,6 +702,14 @@ shape = PerfectShape::Path.new(shapes: path_shapes, closed: false, winding_rule:
|
|
692
702
|
|
693
703
|
shape.contain?(225, 160) # => true
|
694
704
|
shape.contain?([225, 160]) # => true
|
705
|
+
shape.contain?(225, 160, outline: true) # => false
|
706
|
+
shape.contain?([225, 160], 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
|
695
713
|
```
|
696
714
|
|
697
715
|
### `PerfectShape::CompositeShape`
|
@@ -712,6 +730,7 @@ A composite shape is simply an aggregate of multiple shapes (e.g. square and pol
|
|
712
730
|
- `#max_y`: max y
|
713
731
|
- `#width`: width (from min x to max x)
|
714
732
|
- `#height`: height (from min y to max y)
|
733
|
+
- `#center_point`: center point as `Array` of `[center_x, center_y]` coordinates
|
715
734
|
- `#center_x`: center x
|
716
735
|
- `#center_y`: center y
|
717
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)
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.3.
|
1
|
+
0.3.4
|
data/lib/perfect_shape/arc.rb
CHANGED
@@ -152,8 +152,8 @@ module PerfectShape
|
|
152
152
|
true
|
153
153
|
else
|
154
154
|
distance_tolerance = BigDecimal(distance_tolerance.to_s)
|
155
|
-
outside_inside_radius_difference = DEFAULT_OUTLINE_RADIUS + distance_tolerance * 2
|
156
|
-
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
|
157
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)
|
158
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)
|
159
159
|
outside_shape.contain?(x, y, outline: false) and
|
@@ -51,18 +51,18 @@ module PerfectShape
|
|
51
51
|
end
|
52
52
|
# double precision only has 52 bits of mantissa
|
53
53
|
return PerfectShape::Line.point_crossings(x1, y1, x2, y2, px, py) if (level > 52)
|
54
|
-
xmid = BigDecimal((xc1 + xc2).to_s) / 2
|
55
|
-
ymid = BigDecimal((yc1 + yc2).to_s) / 2
|
56
|
-
xc1 = BigDecimal((x1 + xc1).to_s) / 2
|
57
|
-
yc1 = BigDecimal((y1 + yc1).to_s) / 2
|
58
|
-
xc2 = BigDecimal((xc2 + x2).to_s) / 2
|
59
|
-
yc2 = BigDecimal((yc2 + y2).to_s) / 2
|
60
|
-
xc1m = BigDecimal((xc1 + xmid).to_s) / 2
|
61
|
-
yc1m = BigDecimal((yc1 + ymid).to_s) / 2
|
62
|
-
xmc1 = BigDecimal((xmid + xc2).to_s) / 2
|
63
|
-
ymc1 = BigDecimal((ymid + yc2).to_s) / 2
|
64
|
-
xmid = BigDecimal((xc1m + xmc1).to_s) / 2
|
65
|
-
ymid = BigDecimal((yc1m + ymc1).to_s) / 2
|
54
|
+
xmid = BigDecimal((xc1 + xc2).to_s) / 2
|
55
|
+
ymid = BigDecimal((yc1 + yc2).to_s) / 2
|
56
|
+
xc1 = BigDecimal((x1 + xc1).to_s) / 2
|
57
|
+
yc1 = BigDecimal((y1 + yc1).to_s) / 2
|
58
|
+
xc2 = BigDecimal((xc2 + x2).to_s) / 2
|
59
|
+
yc2 = BigDecimal((yc2 + y2).to_s) / 2
|
60
|
+
xc1m = BigDecimal((xc1 + xmid).to_s) / 2
|
61
|
+
yc1m = BigDecimal((yc1 + ymid).to_s) / 2
|
62
|
+
xmc1 = BigDecimal((xmid + xc2).to_s) / 2
|
63
|
+
ymc1 = BigDecimal((ymid + yc2).to_s) / 2
|
64
|
+
xmid = BigDecimal((xc1m + xmc1).to_s) / 2
|
65
|
+
ymid = BigDecimal((yc1m + ymc1).to_s) / 2
|
66
66
|
# [xy]mid are NaN if any of [xy]c0m or [xy]mc1 are NaN
|
67
67
|
# [xy]c0m or [xy]mc1 are NaN if any of [xy][c][01] are NaN
|
68
68
|
# These values are also NaN if opposing infinities are added
|
@@ -90,8 +90,9 @@ module PerfectShape
|
|
90
90
|
return unless x && y
|
91
91
|
|
92
92
|
if outline
|
93
|
+
distance_tolerance = BigDecimal(distance_tolerance.to_s)
|
93
94
|
minimum_distance_threshold = OUTLINE_MINIMUM_DISTANCE_THRESHOLD + distance_tolerance
|
94
|
-
|
95
|
+
point_distance(x, y, minimum_distance_threshold: minimum_distance_threshold) < minimum_distance_threshold
|
95
96
|
else
|
96
97
|
# Either x or y was infinite or NaN.
|
97
98
|
# A NaN always produces a negative response to any test
|
@@ -105,7 +106,7 @@ module PerfectShape
|
|
105
106
|
x2 = points[3][0]
|
106
107
|
y2 = points[3][1]
|
107
108
|
line = PerfectShape::Line.new(points: [[x1, y1], [x2, y2]])
|
108
|
-
crossings = line.point_crossings(x, y) + point_crossings(x, y)
|
109
|
+
crossings = line.point_crossings(x, y) + point_crossings(x, y)
|
109
110
|
(crossings & 1) == 1
|
110
111
|
end
|
111
112
|
end
|
@@ -148,6 +149,7 @@ module PerfectShape
|
|
148
149
|
# for level=1, 4 subdivisions for level=2, and 8 subdivisions for level=3)
|
149
150
|
def subdivisions(level = 1)
|
150
151
|
level -= 1 # consume 1 level
|
152
|
+
|
151
153
|
x1 = points[0][0]
|
152
154
|
y1 = points[0][1]
|
153
155
|
ctrlx1 = points[1][0]
|
@@ -156,22 +158,23 @@ module PerfectShape
|
|
156
158
|
ctrly2 = points[2][1]
|
157
159
|
x2 = points[3][0]
|
158
160
|
y2 = points[3][1]
|
159
|
-
centerx = (ctrlx1 + ctrlx2) / 2
|
160
|
-
centery = (ctrly1 + ctrly2) / 2
|
161
|
-
ctrlx1 = (x1 + ctrlx1) / 2
|
162
|
-
ctrly1 = (y1 + ctrly1) / 2
|
163
|
-
ctrlx2 = (x2 + ctrlx2) / 2
|
164
|
-
ctrly2 = (y2 + ctrly2) / 2
|
165
|
-
ctrlx12 = (ctrlx1 + centerx) / 2
|
166
|
-
ctrly12 = (ctrly1 + centery) / 2
|
167
|
-
ctrlx21 = (ctrlx2 + centerx) / 2
|
168
|
-
ctrly21 = (ctrly2 + centery) / 2
|
169
|
-
centerx = (ctrlx12 + ctrlx21) / 2
|
170
|
-
centery = (ctrly12 + ctrly21) / 2
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
]
|
161
|
+
centerx = BigDecimal((ctrlx1 + ctrlx2).to_s) / 2
|
162
|
+
centery = BigDecimal((ctrly1 + ctrly2).to_s) / 2
|
163
|
+
ctrlx1 = BigDecimal((x1 + ctrlx1).to_s) / 2
|
164
|
+
ctrly1 = BigDecimal((y1 + ctrly1).to_s) / 2
|
165
|
+
ctrlx2 = BigDecimal((x2 + ctrlx2).to_s) / 2
|
166
|
+
ctrly2 = BigDecimal((y2 + ctrly2).to_s) / 2
|
167
|
+
ctrlx12 = BigDecimal((ctrlx1 + centerx).to_s) / 2
|
168
|
+
ctrly12 = BigDecimal((ctrly1 + centery).to_s) / 2
|
169
|
+
ctrlx21 = BigDecimal((ctrlx2 + centerx).to_s) / 2
|
170
|
+
ctrly21 = BigDecimal((ctrly2 + centery).to_s) / 2
|
171
|
+
centerx = BigDecimal((ctrlx12 + ctrlx21).to_s) / 2
|
172
|
+
centery = BigDecimal((ctrly12 + ctrly21).to_s) / 2
|
173
|
+
|
174
|
+
first_curve = CubicBezierCurve.new(points: [x1, y1, ctrlx1, ctrly1, ctrlx12, ctrly12, centerx, centery])
|
175
|
+
second_curve = CubicBezierCurve.new(points: [centerx, centery, ctrlx21, ctrly21, ctrlx2, ctrly2, x2, y2])
|
176
|
+
default_subdivisions = [first_curve, second_curve]
|
177
|
+
|
175
178
|
if level == 0
|
176
179
|
default_subdivisions
|
177
180
|
else
|
@@ -179,7 +182,7 @@ module PerfectShape
|
|
179
182
|
end
|
180
183
|
end
|
181
184
|
|
182
|
-
def
|
185
|
+
def point_distance(x_or_point, y = nil, minimum_distance_threshold: OUTLINE_MINIMUM_DISTANCE_THRESHOLD)
|
183
186
|
x, y = normalize_point(x_or_point, y)
|
184
187
|
return unless x && y
|
185
188
|
|
@@ -189,8 +192,10 @@ module PerfectShape
|
|
189
192
|
last_minimum_distance = minimum_distance + 1 # start bigger to ensure going through loop once at least
|
190
193
|
while minimum_distance >= minimum_distance_threshold && minimum_distance < last_minimum_distance
|
191
194
|
curve1, curve2 = current_curve.subdivisions
|
192
|
-
|
193
|
-
|
195
|
+
curve1_center_point = curve1.curve_center_point
|
196
|
+
distance1 = point.point_distance(curve1_center_point)
|
197
|
+
curve2_center_point = curve2.curve_center_point
|
198
|
+
distance2 = point.point_distance(curve2_center_point)
|
194
199
|
last_minimum_distance = minimum_distance
|
195
200
|
if distance1 < distance2
|
196
201
|
minimum_distance = distance1
|
data/lib/perfect_shape/line.rb
CHANGED
@@ -104,7 +104,7 @@ module PerfectShape
|
|
104
104
|
# measured against the specified line segment
|
105
105
|
# @return a double value that is the square of the distance from the
|
106
106
|
# specified point to the specified line segment.
|
107
|
-
def
|
107
|
+
def point_distance_square(x1, y1,
|
108
108
|
x2, y2,
|
109
109
|
px, py)
|
110
110
|
x1 = BigDecimal(x1.to_s)
|
@@ -177,10 +177,10 @@ module PerfectShape
|
|
177
177
|
# measured against the specified line segment
|
178
178
|
# @return a double value that is the distance from the specified point
|
179
179
|
# to the specified line segment.
|
180
|
-
def
|
180
|
+
def point_distance(x1, y1,
|
181
181
|
x2, y2,
|
182
182
|
px, py)
|
183
|
-
BigDecimal(::Math.sqrt(
|
183
|
+
BigDecimal(::Math.sqrt(point_distance_square(x1, y1, x2, y2, px, py)).to_s)
|
184
184
|
end
|
185
185
|
|
186
186
|
# Calculates the number of times the line from (x1,y1) to (x2,y2)
|
@@ -212,17 +212,17 @@ module PerfectShape
|
|
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, outline:
|
215
|
+
def contain?(x_or_point, y = nil, outline: true, distance_tolerance: 0)
|
216
216
|
x, y = normalize_point(x_or_point, y)
|
217
217
|
return unless x && y
|
218
218
|
distance_tolerance = BigDecimal(distance_tolerance.to_s)
|
219
|
-
|
219
|
+
point_distance(x, y) <= distance_tolerance
|
220
220
|
end
|
221
221
|
|
222
|
-
def
|
222
|
+
def point_distance(x_or_point, y = nil)
|
223
223
|
x, y = normalize_point(x_or_point, y)
|
224
224
|
return unless x && y
|
225
|
-
Line.
|
225
|
+
Line.point_distance(points[0][0], points[0][1], points[1][0], points[1][1], x, y)
|
226
226
|
end
|
227
227
|
|
228
228
|
def relative_counterclockwise(x_or_point, y = nil)
|
@@ -37,7 +37,13 @@ module PerfectShape
|
|
37
37
|
ys = the_points.each_with_index.select {|n, i| i.odd?}.map(&:first)
|
38
38
|
the_points = xs.zip(ys)
|
39
39
|
end
|
40
|
-
@points = the_points.map
|
40
|
+
@points = the_points.map do |pair|
|
41
|
+
[
|
42
|
+
pair.first.is_a?(BigDecimal) ? pair.first : BigDecimal(pair.first.to_s),
|
43
|
+
pair.last.is_a?(BigDecimal) ? pair.last : BigDecimal(pair.last.to_s)
|
44
|
+
]
|
45
|
+
end
|
46
|
+
@points
|
41
47
|
end
|
42
48
|
|
43
49
|
def min_x
|
data/lib/perfect_shape/path.rb
CHANGED
@@ -114,21 +114,26 @@ module PerfectShape
|
|
114
114
|
# @return true if the point lies within the bound of
|
115
115
|
# the path or false if the point lies outside of the
|
116
116
|
# path's bounds.
|
117
|
-
def contain?(x_or_point, y = nil)
|
117
|
+
def contain?(x_or_point, y = nil, outline: false, distance_tolerance: 0)
|
118
118
|
x, y = normalize_point(x_or_point, y)
|
119
119
|
return unless x && y
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
return false if shapes.count < 2
|
124
|
-
mask = winding_rule == :wind_non_zero ? -1 : 1
|
125
|
-
(point_crossings(x, y) & mask) != 0
|
120
|
+
|
121
|
+
if outline
|
122
|
+
disconnected_shapes.any? {|shape| shape.contain?(x, y, outline: true, distance_tolerance: distance_tolerance) }
|
126
123
|
else
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
124
|
+
if (x * 0.0 + y * 0.0) == 0.0
|
125
|
+
# N * 0.0 is 0.0 only if N is finite.
|
126
|
+
# Here we know that both x and y are finite.
|
127
|
+
return false if shapes.count < 2
|
128
|
+
mask = winding_rule == :wind_non_zero ? -1 : 1
|
129
|
+
(point_crossings(x, y) & mask) != 0
|
130
|
+
else
|
131
|
+
# Either x or y was infinite or NaN.
|
132
|
+
# A NaN always produces a negative response to any test
|
133
|
+
# and Infinity values cannot be "inside" any path so
|
134
|
+
# they should return false as well.
|
135
|
+
false
|
136
|
+
end
|
132
137
|
end
|
133
138
|
end
|
134
139
|
|
@@ -218,5 +223,50 @@ module PerfectShape
|
|
218
223
|
end
|
219
224
|
crossings
|
220
225
|
end
|
226
|
+
|
227
|
+
# Disconnected shapes have their start point filled in
|
228
|
+
# so that each shape does not depend on the previous shape
|
229
|
+
# to determine its start point.
|
230
|
+
#
|
231
|
+
# Also, if a point is followed by a non-point shape, it is removed
|
232
|
+
# since it is augmented to the following shape as its start point.
|
233
|
+
#
|
234
|
+
# Lastly, if the path is closed, an extra shape is
|
235
|
+
# added to represent the line connecting the last point to the first
|
236
|
+
def disconnected_shapes
|
237
|
+
initial_point = start_point = @shapes.first.to_a.map {|n| BigDecimal(n.to_s)}
|
238
|
+
final_point = nil
|
239
|
+
the_disconnected_shapes = @shapes.drop(1).map do |shape|
|
240
|
+
case shape
|
241
|
+
when Point
|
242
|
+
disconnected_shape = Point.new(*shape.to_a)
|
243
|
+
start_point = shape.to_a
|
244
|
+
final_point = disconnected_shape.to_a
|
245
|
+
nil
|
246
|
+
when Array
|
247
|
+
disconnected_shape = Point.new(*shape.map {|n| BigDecimal(n.to_s)})
|
248
|
+
start_point = shape.map {|n| BigDecimal(n.to_s)}
|
249
|
+
final_point = disconnected_shape.to_a
|
250
|
+
nil
|
251
|
+
when Line
|
252
|
+
disconnected_shape = Line.new(points: [start_point.to_a, shape.points.last])
|
253
|
+
start_point = shape.points.last.to_a
|
254
|
+
final_point = disconnected_shape.points.last.to_a
|
255
|
+
disconnected_shape
|
256
|
+
when QuadraticBezierCurve
|
257
|
+
disconnected_shape = QuadraticBezierCurve.new(points: [start_point.to_a] + shape.points)
|
258
|
+
start_point = shape.points.last.to_a
|
259
|
+
final_point = disconnected_shape.points.last.to_a
|
260
|
+
disconnected_shape
|
261
|
+
when CubicBezierCurve
|
262
|
+
disconnected_shape = CubicBezierCurve.new(points: [start_point.to_a] + shape.points)
|
263
|
+
start_point = shape.points.last.to_a
|
264
|
+
final_point = disconnected_shape.points.last.to_a
|
265
|
+
disconnected_shape
|
266
|
+
end
|
267
|
+
end
|
268
|
+
the_disconnected_shapes << Line.new(points: [final_point, initial_point]) if closed?
|
269
|
+
the_disconnected_shapes.compact
|
270
|
+
end
|
221
271
|
end
|
222
272
|
end
|
data/lib/perfect_shape/point.rb
CHANGED
@@ -27,10 +27,10 @@ module PerfectShape
|
|
27
27
|
class Point < Shape
|
28
28
|
class << self
|
29
29
|
def point_distance(x, y, px, py)
|
30
|
-
x = BigDecimal(x.to_s)
|
31
|
-
y = BigDecimal(y.to_s)
|
32
|
-
px = BigDecimal(px.to_s)
|
33
|
-
py = BigDecimal(py.to_s)
|
30
|
+
x = x.is_a?(BigDecimal) ? x : BigDecimal(x.to_s)
|
31
|
+
y = y.is_a?(BigDecimal) ? y : BigDecimal(y.to_s)
|
32
|
+
px = px.is_a?(BigDecimal) ? px : BigDecimal(px.to_s)
|
33
|
+
py = py.is_a?(BigDecimal) ? py : BigDecimal(py.to_s)
|
34
34
|
BigDecimal(Math.sqrt((px - x)**2 + (py - y)**2).to_s)
|
35
35
|
end
|
36
36
|
end
|
@@ -67,7 +67,7 @@ module PerfectShape
|
|
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, outline:
|
70
|
+
def contain?(x_or_point, y = nil, outline: true, distance_tolerance: 0)
|
71
71
|
x, y = normalize_point(x_or_point, y)
|
72
72
|
return unless x && y
|
73
73
|
distance_tolerance = BigDecimal(distance_tolerance.to_s)
|
@@ -77,6 +77,7 @@ module PerfectShape
|
|
77
77
|
def point_distance(x_or_point, y = nil)
|
78
78
|
x, y = normalize_point(x_or_point, y)
|
79
79
|
return unless x && y
|
80
|
+
|
80
81
|
Point.point_distance(self.x, self.y, x, y)
|
81
82
|
end
|
82
83
|
|
@@ -91,8 +91,9 @@ module PerfectShape
|
|
91
91
|
y2 = points[2][1]
|
92
92
|
|
93
93
|
if outline
|
94
|
+
distance_tolerance = BigDecimal(distance_tolerance.to_s)
|
94
95
|
minimum_distance_threshold = OUTLINE_MINIMUM_DISTANCE_THRESHOLD + distance_tolerance
|
95
|
-
|
96
|
+
point_distance(x, y, minimum_distance_threshold: minimum_distance_threshold) < minimum_distance_threshold
|
96
97
|
else
|
97
98
|
# We have a convex shape bounded by quad curve Pc(t)
|
98
99
|
# and ine Pl(t).
|
@@ -194,8 +195,8 @@ module PerfectShape
|
|
194
195
|
QuadraticBezierCurve.point_crossings(points[0][0], points[0][1], points[1][0], points[1][1], points[2][0], points[2][1], x, y, level)
|
195
196
|
end
|
196
197
|
|
197
|
-
|
198
198
|
# The center point on the outline of the curve
|
199
|
+
# in Array format as pair of (x, y) coordinates
|
199
200
|
def curve_center_point
|
200
201
|
subdivisions.last.points[0]
|
201
202
|
end
|
@@ -226,12 +227,12 @@ module PerfectShape
|
|
226
227
|
ctrly = points[1][1]
|
227
228
|
x2 = points[2][0]
|
228
229
|
y2 = points[2][1]
|
229
|
-
ctrlx1 = (x1 + ctrlx) / 2
|
230
|
-
ctrly1 = (y1 + ctrly) / 2
|
231
|
-
ctrlx2 = (x2 + ctrlx) / 2
|
232
|
-
ctrly2 = (y2 + ctrly) / 2
|
233
|
-
centerx = (ctrlx1 + ctrlx2) / 2
|
234
|
-
centery = (ctrly1 + ctrly2) / 2
|
230
|
+
ctrlx1 = BigDecimal((x1 + ctrlx).to_s) / 2
|
231
|
+
ctrly1 = BigDecimal((y1 + ctrly).to_s) / 2
|
232
|
+
ctrlx2 = BigDecimal((x2 + ctrlx).to_s) / 2
|
233
|
+
ctrly2 = BigDecimal((y2 + ctrly).to_s) / 2
|
234
|
+
centerx = BigDecimal((ctrlx1 + ctrlx2).to_s) / 2
|
235
|
+
centery = BigDecimal((ctrly1 + ctrly2).to_s) / 2
|
235
236
|
|
236
237
|
default_subdivisions = [
|
237
238
|
QuadraticBezierCurve.new(points: [x1, y1, ctrlx1, ctrly1, centerx, centery]),
|
@@ -245,7 +246,7 @@ module PerfectShape
|
|
245
246
|
end
|
246
247
|
end
|
247
248
|
|
248
|
-
def
|
249
|
+
def point_distance(x_or_point, y = nil, minimum_distance_threshold: OUTLINE_MINIMUM_DISTANCE_THRESHOLD)
|
249
250
|
x, y = normalize_point(x_or_point, y)
|
250
251
|
return unless x && y
|
251
252
|
|
data/lib/perfect_shape/shape.rb
CHANGED
@@ -51,6 +51,12 @@ module PerfectShape
|
|
51
51
|
max_y - min_y if max_y && min_y
|
52
52
|
end
|
53
53
|
|
54
|
+
# Center point is `[center_x, center_y]`
|
55
|
+
# Returns `nil` if either center_x or center_y are `nil`
|
56
|
+
def center_point
|
57
|
+
[center_x, center_y] unless center_x.nil? || center_y.nil?
|
58
|
+
end
|
59
|
+
|
54
60
|
# center_x is min_x + width/2.0 by default
|
55
61
|
# Returns nil if min_x or width are nil
|
56
62
|
def center_x
|
@@ -79,8 +85,8 @@ module PerfectShape
|
|
79
85
|
def normalize_point(x_or_point, y = nil)
|
80
86
|
x = x_or_point
|
81
87
|
x, y = x if y.nil? && x_or_point.is_a?(Array) && x_or_point.size == 2
|
82
|
-
x = BigDecimal(x.to_s)
|
83
|
-
y = BigDecimal(y.to_s)
|
88
|
+
x = x.is_a?(BigDecimal) ? x : BigDecimal(x.to_s)
|
89
|
+
y = y.is_a?(BigDecimal) ? y : BigDecimal(y.to_s)
|
84
90
|
[x, y]
|
85
91
|
end
|
86
92
|
|
data/perfect-shape.gemspec
CHANGED
@@ -2,16 +2,16 @@
|
|
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.3.
|
5
|
+
# stub: perfect-shape 0.3.4 ruby lib
|
6
6
|
|
7
7
|
Gem::Specification.new do |s|
|
8
8
|
s.name = "perfect-shape".freeze
|
9
|
-
s.version = "0.3.
|
9
|
+
s.version = "0.3.4"
|
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-
|
14
|
+
s.date = "2022-01-11"
|
15
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 = [
|
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.3.
|
4
|
+
version: 0.3.4
|
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-11 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: equalizer
|