perfect-shape 0.2.0 → 0.3.3

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: 42bff3742b2697349882d865b7c5da9c06ce4a259850996bb92f291e8a74130e
4
+ data.tar.gz: 5a2f007129f1e0f483a48ea607a7ee3e44cbdf01b400a656f406b412dc8e9524
5
5
  SHA512:
6
- metadata.gz: 26ec5bc87ec612ea07a1ec6c38277d92ed4e2ff08f08d7e091d4254bdfc70b7da0704fc5a93f68063a14faa67fee32c57bac54cc0496df34f098aac8d85b4770
7
- data.tar.gz: 9334103aa1ea12b3f6d2d5f611bdcb36a1f532061e1e22b3dd4783498527665a9851c6294778720d21fa221113526bdfbbe0e8d6208462568680a17df026b2b5
6
+ metadata.gz: 9bf87bebe682dfbab8a4b082caa321ac0b7051510d86e946e3f214337e818a18da7cee51bc12432510567deaa68f65a69cb3c7da10b7c9153045803e1d25f0b7
7
+ data.tar.gz: fa32aa79d500055b81b572e17ded38429503a3757430bba1c0fea021853e4377d7e025071cf52ed8c2f965c8bc8ecd35601276f2a1bcda847202c6f49c8422a0
data/CHANGELOG.md CHANGED
@@ -1,5 +1,36 @@
1
1
  # Change Log
2
2
 
3
+ ## 0.3.3
4
+
5
+ - 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
+ - `PerfectShape::QuadraticBezierCurve#curve_center_point`, `PerfectShape::QuadraticBezierCurve#curve_center_x`, `PerfectShape::QuadraticBezierCurve#curve_center_y`
7
+ - `PerfectShape::QuadraticBezierCurve#subdivisions(level=1)`
8
+ - `PerfectShape::QuadraticBezierCurve#point_segment_distance(x_or_point, y = nil, minimum_distance_threshold: OUTLINE_MINIMUM_DISTANCE_THRESHOLD)`
9
+ - `PerfectShape::Polygon#edges` returns edges of polygon as `PerfectShape::Line` objects
10
+ - `PerfectShape::Rectangle#edges` returns edges of rectangle as `PerfectShape::Line` objects
11
+ - `PerfectShape::Square#edges` returns edges of square as `PerfectShape::Line` objects
12
+ - Rename `number` arg to `level` in `CubicBezierCurve#subdivisions(level=1)`, making it signify the level of subdivision recursion to perform.
13
+
14
+ ## 0.3.2
15
+
16
+ - 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
+ - `PerfectShape::CubicBezierCurve#curve_center_point`, `PerfectShape::CubicBezierCurve#curve_center_x`, `PerfectShape::CubicBezierCurve#curve_center_y`
18
+ - `PerfectShape::CubicBezierCurve#subdivisions(level=1)`
19
+ - `PerfectShape::CubicBezierCurve#point_segment_distance(x_or_point, y = nil, minimum_distance_threshold: OUTLINE_MINIMUM_DISTANCE_THRESHOLD)`
20
+
21
+ ## 0.3.1
22
+
23
+ - 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)`)
24
+ - Check point containment in ellipse outline with distance tolerance (new method signature: `PerfectShape::Ellipse#contain?(x_or_point, y = nil, outline: false, distance_tolerance: 0)`)
25
+ - Check point containment in circle outline with distance tolerance (new method signature: `PerfectShape::Circle#contain?(x_or_point, y = nil, outline: false, distance_tolerance: 0)`)
26
+
27
+ ## 0.3.0
28
+
29
+ - Refactoring: rename `distance` option for `#contain?` on `Point`/`Line` into `distance_tolerance`
30
+ - Check point containment in rectangle outline with distance tolerance (new method signature: `PerfectShape::Rectangle#contain?(x_or_point, y = nil, outline: false, distance_tolerance: 0)`)
31
+ - Check point containment in square outline with distance tolerance (new method signature: `PerfectShape::Square#contain?(x_or_point, y = nil, outline: false, distance_tolerance: 0)`)
32
+ - Check point containment in polygon outline with distance tolerance (new method signature: `PerfectShape::Polygon#contain?(x_or_point, y = nil, outline: false, distance_tolerance: 0)`)
33
+
3
34
  ## 0.2.0
4
35
 
5
36
  - `PerfectShape::CompositeShape`: aggregate of multiple shapes
@@ -23,7 +54,7 @@
23
54
  ## 0.1.0
24
55
 
25
56
  - `PerfectShape::Path` (having points or lines)
26
- - `PerfectShape::Path#contain?(x_or_point, y=nil, distance: 0)`
57
+ - `PerfectShape::Path#contain?(x_or_point, y=nil, distance_tolerance: 0)`
27
58
  - `PerfectShape::Path#point_crossings(x_or_point, y=nil)`
28
59
  - `PerfectShape::Path#==`
29
60
 
@@ -37,12 +68,12 @@
37
68
 
38
69
  - `PerfectShape::Point`
39
70
  - `PerfectShape::Point#point_distance`
40
- - `PerfectShape::Point#contain?(x_or_point, y=nil, distance: 0)`
71
+ - `PerfectShape::Point#contain?(x_or_point, y=nil, distance_tolerance: 0)`
41
72
  - Refactor `PerfectShape::Point`,`PerfectShape::RectangularShape` to include shared `PerfectShape::PointLocation`
42
73
 
43
74
  ## 0.0.9
44
75
 
45
- - `PerfectShape::Line#contain?(x_or_point, y=nil, distance: 0)` (add a distance tolerance fuzz factor option)
76
+ - `PerfectShape::Line#contain?(x_or_point, y=nil, distance_tolerance: 0)` (add a distance tolerance fuzz factor option)
46
77
 
47
78
  ## 0.0.8
48
79
 
data/LICENSE.txt 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
data/README.md CHANGED
@@ -1,9 +1,9 @@
1
- # Perfect Shape 0.2.0
1
+ # Perfect Shape 0.3.3
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.3
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.3'
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 % modulo operator as it operates on floats and could return a negative result)
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
 
@@ -55,9 +55,9 @@ This is a base class for all shapes. It is not meant to be used directly. Subcla
55
55
  - `#center_x`: center x
56
56
  - `#center_y`: center y
57
57
  - `#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
58
  - `#==(other)`: Returns `true` if equal to `other` or `false` otherwise
59
+ - `#normalize_point(x_or_point, y = nil)`: normalizes point into an `Array` of `[x,y]` coordinates
60
+ - `#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
61
 
62
62
  ### `PerfectShape::PointLocation`
63
63
 
@@ -111,9 +111,9 @@ 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.
115
- - `#point_distance(x_or_point, y=nil)`: Returns the distance from a point to another point
116
114
  - `#==(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.
116
+ - `#point_distance(x_or_point, y=nil)`: Returns the distance from a point to another point
117
117
 
118
118
  Example:
119
119
 
@@ -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,10 +153,10 @@ 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
+ - `#==(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
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)”.
158
159
  - `#point_segment_distance(x_or_point, y=nil)`: Returns the distance from a point to a line segment.
159
- - `#==(other)`: Returns `true` if equal to `other` or `false` otherwise
160
160
 
161
161
  Example:
162
162
 
@@ -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`
@@ -194,8 +194,13 @@ Includes `PerfectShape::MultiPoint`
194
194
  - `#center_x`: center x
195
195
  - `#center_y`: center y
196
196
  - `#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
197
  - `#==(other)`: Returns `true` if equal to `other` or `false` otherwise
198
+ - `#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`)
202
+ - `#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
+ - `#point_segment_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
204
 
200
205
  Example:
201
206
 
@@ -206,6 +211,14 @@ shape = PerfectShape::QuadraticBezierCurve.new(points: [[200, 150], [270, 320],
206
211
 
207
212
  shape.contain?(270, 220) # => true
208
213
  shape.contain?([270, 220]) # => true
214
+ shape.contain?(270, 220, outline: true) # => false
215
+ shape.contain?([270, 220], outline: true) # => false
216
+ shape.contain?(280, 235, outline: true) # => true
217
+ shape.contain?([280, 235], outline: true) # => true
218
+ shape.contain?(281, 235, outline: true) # => false
219
+ shape.contain?([281, 235], outline: true) # => false
220
+ shape.contain?(281, 235, outline: true, distance_tolerance: 1) # => true
221
+ shape.contain?([281, 235], outline: true, distance_tolerance: 1) # => true
209
222
  ```
210
223
 
211
224
  ### `PerfectShape::CubicBezierCurve`
@@ -229,8 +242,13 @@ Includes `PerfectShape::MultiPoint`
229
242
  - `#center_x`: center x
230
243
  - `#center_y`: center y
231
244
  - `#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
245
  - `#==(other)`: Returns `true` if equal to `other` or `false` otherwise
246
+ - `#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`)
250
+ - `#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
+ - `#point_segment_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
252
 
235
253
  Example:
236
254
 
@@ -241,6 +259,14 @@ shape = PerfectShape::CubicBezierCurve.new(points: [[200, 150], [235, 235], [270
241
259
 
242
260
  shape.contain?(270, 220) # => true
243
261
  shape.contain?([270, 220]) # => true
262
+ shape.contain?(270, 220, outline: true) # => false
263
+ shape.contain?([270, 220], outline: true) # => false
264
+ shape.contain?(261.875, 245.625, outline: true) # => true
265
+ shape.contain?([261.875, 245.625], outline: true) # => true
266
+ shape.contain?(261.875, 246.625, outline: true) # => false
267
+ shape.contain?([261.875, 246.625], outline: true) # => false
268
+ shape.contain?(261.875, 246.625, outline: true, distance_tolerance: 1) # => true
269
+ shape.contain?([261.875, 246.625], outline: true, distance_tolerance: 1) # => true
244
270
  ```
245
271
 
246
272
  ### `PerfectShape::Rectangle`
@@ -265,8 +291,9 @@ Includes `PerfectShape::RectangularShape`
265
291
  - `#max_x`: max x
266
292
  - `#max_y`: max y
267
293
  - `#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
269
294
  - `#==(other)`: Returns `true` if equal to `other` or `false` otherwise
295
+ - `#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
296
+ - `#edges`: edges of rectangle as `PerfectShape::Line` objects
270
297
 
271
298
  Example:
272
299
 
@@ -277,6 +304,14 @@ shape = PerfectShape::Rectangle.new(x: 15, y: 30, width: 200, height: 100)
277
304
 
278
305
  shape.contain?(115, 80) # => true
279
306
  shape.contain?([115, 80]) # => true
307
+ shape.contain?(115, 80, outline: true) # => false
308
+ shape.contain?([115, 80], outline: true) # => false
309
+ shape.contain?(115, 30, outline: true) # => true
310
+ shape.contain?([115, 30], outline: true) # => true
311
+ shape.contain?(115, 31, outline: true) # => false
312
+ shape.contain?([115, 31], outline: true) # => false
313
+ shape.contain?(115, 31, outline: true, distance_tolerance: 1) # => true
314
+ shape.contain?([115, 31], outline: true, distance_tolerance: 1) # => true
280
315
  ```
281
316
 
282
317
  ### `PerfectShape::Square`
@@ -300,8 +335,9 @@ Extends `PerfectShape::Rectangle`
300
335
  - `#max_x`: max x
301
336
  - `#max_y`: max y
302
337
  - `#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
304
338
  - `#==(other)`: Returns `true` if equal to `other` or `false` otherwise
339
+ - `#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
340
+ - `#edges`: edges of square as `PerfectShape::Line` objects
305
341
 
306
342
  Example:
307
343
 
@@ -312,6 +348,14 @@ shape = PerfectShape::Square.new(x: 15, y: 30, length: 200)
312
348
 
313
349
  shape.contain?(115, 130) # => true
314
350
  shape.contain?([115, 130]) # => true
351
+ shape.contain?(115, 130, outline: true) # => false
352
+ shape.contain?([115, 130], outline: true) # => false
353
+ shape.contain?(115, 30, outline: true) # => true
354
+ shape.contain?([115, 30], outline: true) # => true
355
+ shape.contain?(115, 31, outline: true) # => false
356
+ shape.contain?([115, 31], outline: true) # => false
357
+ shape.contain?(115, 31, outline: true, distance_tolerance: 1) # => true
358
+ shape.contain?([115, 31], outline: true, distance_tolerance: 1) # => true
315
359
  ```
316
360
 
317
361
  ### `PerfectShape::Arc`
@@ -345,8 +389,8 @@ Open Arc | Chord Arc | Pie Arc
345
389
  - `#max_x`: max x
346
390
  - `#max_y`: max y
347
391
  - `#bounding_box`: bounding box is a rectangle with x = min x, y = min y, and width/height of shape
348
- - `#contain?(x_or_point, y=nil)`: checks if point is inside
349
392
  - `#==(other)`: Returns `true` if equal to `other` or `false` otherwise
393
+ - `#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
350
394
 
351
395
  Example:
352
396
 
@@ -354,23 +398,63 @@ Example:
354
398
  require 'perfect-shape'
355
399
 
356
400
  shape = PerfectShape::Arc.new(type: :open, x: 2, y: 3, width: 50, height: 60, start: 45, extent: 270)
357
- shape2 = PerfectShape::Arc.new(type: :open, center_x: 2 + 25, center_y: 3 + 30, radius_x: 25, radius_y: 30, start: 30, extent: 90)
401
+ shape2 = PerfectShape::Arc.new(type: :open, center_x: 2 + 25, center_y: 3 + 30, radius_x: 25, radius_y: 30, start: 45, extent: 270)
358
402
 
359
403
  shape.contain?(39.5, 33.0) # => true
360
404
  shape.contain?([39.5, 33.0]) # => true
361
405
  shape2.contain?(39.5, 33.0) # => true
362
406
  shape2.contain?([39.5, 33.0]) # => true
407
+ shape.contain?(39.5, 33.0, outline: true) # => false
408
+ shape.contain?([39.5, 33.0], outline: true) # => false
409
+ shape2.contain?(39.5, 33.0, outline: true) # => false
410
+ shape2.contain?([39.5, 33.0], outline: true) # => false
411
+ shape.contain?(2.0, 33.0, outline: true) # => true
412
+ shape.contain?([2.0, 33.0], outline: true) # => true
413
+ shape2.contain?(2.0, 33.0, outline: true) # => true
414
+ shape2.contain?([2.0, 33.0], outline: true) # => true
415
+ shape.contain?(3.0, 33.0, outline: true) # => false
416
+ shape.contain?([3.0, 33.0], outline: true) # => false
417
+ shape2.contain?(3.0, 33.0, outline: true) # => false
418
+ shape2.contain?([3.0, 33.0], outline: true) # => false
419
+ shape.contain?(3.0, 33.0, outline: true, distance_tolerance: 1.0) # => true
420
+ shape.contain?([3.0, 33.0], outline: true, distance_tolerance: 1.0) # => true
421
+ shape2.contain?(3.0, 33.0, outline: true, distance_tolerance: 1.0) # => true
422
+ shape2.contain?([3.0, 33.0], outline: true, distance_tolerance: 1.0) # => true
423
+ shape.contain?(shape.center_x, shape.center_y, outline: true) # => false
424
+ shape.contain?([shape.center_x, shape.center_y], outline: true) # => false
425
+ shape2.contain?(shape2.center_x, shape2.center_y, outline: true) # => false
426
+ shape2.contain?([shape2.center_x, shape2.center_y], outline: true) # => false
363
427
 
364
428
  shape3 = PerfectShape::Arc.new(type: :chord, x: 2, y: 3, width: 50, height: 60, start: 45, extent: 270)
365
- shape4 = PerfectShape::Arc.new(type: :chord, center_x: 2 + 25, center_y: 3 + 30, radius_x: 25, radius_y: 30, start: 30, extent: 90)
429
+ shape4 = PerfectShape::Arc.new(type: :chord, center_x: 2 + 25, center_y: 3 + 30, radius_x: 25, radius_y: 30, start: 45, extent: 270)
366
430
 
367
431
  shape3.contain?(39.5, 33.0) # => true
368
432
  shape3.contain?([39.5, 33.0]) # => true
369
433
  shape4.contain?(39.5, 33.0) # => true
370
434
  shape4.contain?([39.5, 33.0]) # => true
435
+ shape3.contain?(39.5, 33.0, outline: true) # => false
436
+ shape3.contain?([39.5, 33.0], outline: true) # => false
437
+ shape4.contain?(39.5, 33.0, outline: true) # => false
438
+ shape4.contain?([39.5, 33.0], outline: true) # => false
439
+ shape3.contain?(2.0, 33.0, outline: true) # => true
440
+ shape3.contain?([2.0, 33.0], outline: true) # => true
441
+ shape4.contain?(2.0, 33.0, outline: true) # => true
442
+ shape4.contain?([2.0, 33.0], outline: true) # => true
443
+ shape3.contain?(3.0, 33.0, outline: true) # => false
444
+ shape3.contain?([3.0, 33.0], outline: true) # => false
445
+ shape4.contain?(3.0, 33.0, outline: true) # => false
446
+ shape4.contain?([3.0, 33.0], outline: true) # => false
447
+ shape3.contain?(3.0, 33.0, outline: true, distance_tolerance: 1.0) # => true
448
+ shape3.contain?([3.0, 33.0], outline: true, distance_tolerance: 1.0) # => true
449
+ shape4.contain?(3.0, 33.0, outline: true, distance_tolerance: 1.0) # => true
450
+ shape4.contain?([3.0, 33.0], outline: true, distance_tolerance: 1.0) # => true
451
+ shape3.contain?(shape3.center_x, shape3.center_y, outline: true) # => false
452
+ shape3.contain?([shape3.center_x, shape3.center_y], outline: true) # => false
453
+ shape4.contain?(shape4.center_x, shape4.center_y, outline: true) # => false
454
+ shape4.contain?([shape4.center_x, shape4.center_y], outline: true) # => false
371
455
 
372
456
  shape5 = PerfectShape::Arc.new(type: :pie, x: 2, y: 3, width: 50, height: 60, start: 45, extent: 270)
373
- shape6 = PerfectShape::Arc.new(type: :pie, center_x: 2 + 25, center_y: 3 + 30, radius_x: 25, radius_y: 30, start: 30, extent: 90)
457
+ shape6 = PerfectShape::Arc.new(type: :pie, center_x: 2 + 25, center_y: 3 + 30, radius_x: 25, radius_y: 30, start: 45, extent: 270)
374
458
 
375
459
  shape5.contain?(39.5, 33.0) # => false
376
460
  shape5.contain?([39.5, 33.0]) # => false
@@ -380,6 +464,26 @@ shape5.contain?(9.5, 33.0) # => true
380
464
  shape5.contain?([9.5, 33.0]) # => true
381
465
  shape6.contain?(9.5, 33.0) # => true
382
466
  shape6.contain?([9.5, 33.0]) # => true
467
+ shape5.contain?(39.5, 33.0, outline: true) # => false
468
+ shape5.contain?([39.5, 33.0], outline: true) # => false
469
+ shape6.contain?(39.5, 33.0, outline: true) # => false
470
+ shape6.contain?([39.5, 33.0], outline: true) # => false
471
+ shape5.contain?(2.0, 33.0, outline: true) # => true
472
+ shape5.contain?([2.0, 33.0], outline: true) # => true
473
+ shape6.contain?(2.0, 33.0, outline: true) # => true
474
+ shape6.contain?([2.0, 33.0], outline: true) # => true
475
+ shape5.contain?(3.0, 33.0, outline: true) # => false
476
+ shape5.contain?([3.0, 33.0], outline: true) # => false
477
+ shape6.contain?(3.0, 33.0, outline: true) # => false
478
+ shape6.contain?([3.0, 33.0], outline: true) # => false
479
+ shape5.contain?(3.0, 33.0, outline: true, distance_tolerance: 1.0) # => true
480
+ shape5.contain?([3.0, 33.0], outline: true, distance_tolerance: 1.0) # => true
481
+ shape6.contain?(3.0, 33.0, outline: true, distance_tolerance: 1.0) # => true
482
+ shape6.contain?([3.0, 33.0], outline: true, distance_tolerance: 1.0) # => true
483
+ shape5.contain?(shape5.center_x, shape5.center_y, outline: true) # => true
484
+ shape5.contain?([shape5.center_x, shape5.center_y], outline: true) # => true
485
+ shape6.contain?(shape6.center_x, shape6.center_y, outline: true) # => true
486
+ shape6.contain?([shape6.center_x, shape6.center_y], outline: true) # => true
383
487
  ```
384
488
 
385
489
  ### `PerfectShape::Ellipse`
@@ -407,8 +511,8 @@ Extends `PerfectShape::Arc`
407
511
  - `#max_x`: max x
408
512
  - `#max_y`: max y
409
513
  - `#bounding_box`: bounding box is a rectangle with x = min x, y = min y, and width/height of shape
410
- - `#contain?(x_or_point, y=nil)`: checks if point is inside
411
514
  - `#==(other)`: Returns `true` if equal to `other` or `false` otherwise
515
+ - `#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
412
516
 
413
517
  Example:
414
518
 
@@ -422,6 +526,22 @@ shape.contain?(27, 33) # => true
422
526
  shape.contain?([27, 33]) # => true
423
527
  shape2.contain?(27, 33) # => true
424
528
  shape2.contain?([27, 33]) # => true
529
+ shape.contain?(27, 33, outline: true) # => false
530
+ shape.contain?([27, 33], outline: true) # => false
531
+ shape2.contain?(27, 33, outline: true) # => false
532
+ shape2.contain?([27, 33], outline: true) # => false
533
+ shape.contain?(2, 33, outline: true) # => true
534
+ shape.contain?([2, 33], outline: true) # => true
535
+ shape2.contain?(2, 33, outline: true) # => true
536
+ shape2.contain?([2, 33], outline: true) # => true
537
+ shape.contain?(1, 33, outline: true) # => false
538
+ shape.contain?([1, 33], outline: true) # => false
539
+ shape2.contain?(1, 33, outline: true) # => false
540
+ shape2.contain?([1, 33], outline: true) # => false
541
+ shape.contain?(1, 33, outline: true, distance_tolerance: 1) # => true
542
+ shape.contain?([1, 33], outline: true, distance_tolerance: 1) # => true
543
+ shape2.contain?(1, 33, outline: true, distance_tolerance: 1) # => true
544
+ shape2.contain?([1, 33], outline: true, distance_tolerance: 1) # => true
425
545
  ```
426
546
 
427
547
  ### `PerfectShape::Circle`
@@ -451,8 +571,8 @@ Extends `PerfectShape::Ellipse`
451
571
  - `#max_x`: max x
452
572
  - `#max_y`: max y
453
573
  - `#bounding_box`: bounding box is a rectangle with x = min x, y = min y, and width/height of shape
454
- - `#contain?(x_or_point, y=nil)`: checks if point is inside
455
574
  - `#==(other)`: Returns `true` if equal to `other` or `false` otherwise
575
+ - `#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
456
576
 
457
577
  Example:
458
578
 
@@ -466,6 +586,22 @@ shape.contain?(32, 33) # => true
466
586
  shape.contain?([32, 33]) # => true
467
587
  shape2.contain?(32, 33) # => true
468
588
  shape2.contain?([32, 33]) # => true
589
+ shape.contain?(32, 33, outline: true) # => false
590
+ shape.contain?([32, 33], outline: true) # => false
591
+ shape2.contain?(32, 33, outline: true) # => false
592
+ shape2.contain?([32, 33], outline: true) # => false
593
+ shape.contain?(2, 33, outline: true) # => true
594
+ shape.contain?([2, 33], outline: true) # => true
595
+ shape2.contain?(2, 33, outline: true) # => true
596
+ shape2.contain?([2, 33], outline: true) # => true
597
+ shape.contain?(1, 33, outline: true) # => false
598
+ shape.contain?([1, 33], outline: true) # => false
599
+ shape2.contain?(1, 33, outline: true) # => false
600
+ shape2.contain?([1, 33], outline: true) # => false
601
+ shape.contain?(1, 33, outline: true, distance_tolerance: 1) # => true
602
+ shape.contain?([1, 33], outline: true, distance_tolerance: 1) # => true
603
+ shape2.contain?(1, 33, outline: true, distance_tolerance: 1) # => true
604
+ shape2.contain?([1, 33], outline: true, distance_tolerance: 1) # => true
469
605
  ```
470
606
 
471
607
  ### `PerfectShape::Polygon`
@@ -490,8 +626,9 @@ A polygon can be thought of as a special case of [path](#perfectshapepath) that
490
626
  - `#center_x`: center x
491
627
  - `#center_y`: center y
492
628
  - `#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))
494
629
  - `#==(other)`: Returns `true` if equal to `other` or `false` otherwise
630
+ - `#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
631
+ - `#edges`: edges of polygon as `PerfectShape::Line` objects
495
632
 
496
633
  Example:
497
634
 
@@ -502,6 +639,14 @@ shape = PerfectShape::Polygon.new(points: [[200, 150], [270, 170], [250, 220], [
502
639
 
503
640
  shape.contain?(225, 185) # => true
504
641
  shape.contain?([225, 185]) # => true
642
+ shape.contain?(225, 185, outline: true) # => false
643
+ shape.contain?([225, 185], outline: true) # => false
644
+ shape.contain?(200, 150, outline: true) # => true
645
+ shape.contain?([200, 150], outline: true) # => true
646
+ shape.contain?(200, 151, outline: true) # => false
647
+ shape.contain?([200, 151], outline: true) # => false
648
+ shape.contain?(200, 151, outline: true, distance_tolerance: 1) # => true
649
+ shape.contain?([200, 151], outline: true, distance_tolerance: 1) # => true
505
650
  ```
506
651
 
507
652
  ### `PerfectShape::Path`
@@ -528,9 +673,9 @@ Includes `PerfectShape::MultiPoint`
528
673
  - `#center_x`: center x
529
674
  - `#center_y`: center y
530
675
  - `#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
+ - `#==(other)`: Returns `true` if equal to `other` or `false` otherwise
531
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))
532
678
  - `#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)
533
- - `#==(other)`: Returns `true` if equal to `other` or `false` otherwise
534
679
 
535
680
  Example:
536
681
 
@@ -555,10 +700,12 @@ Class
555
700
 
556
701
  Extends `PerfectShape::Shape`
557
702
 
703
+ A composite shape is simply an aggregate of multiple shapes (e.g. square and polygon)
704
+
558
705
  ![composite shape](https://raw.githubusercontent.com/AndyObtiva/perfect-shape/master/images/composite-shape.png)
559
706
 
560
707
  - `::new(shapes: [])`: constructs a composite shape with `shapes` as `Array` of `PerfectShape::Shape` objects
561
- - `#shapes`: the shapes that the path is composed of
708
+ - `#shapes`: the shapes that the composite shape is composed of
562
709
  - `#min_x`: min x
563
710
  - `#min_y`: min y
564
711
  - `#max_x`: max x
@@ -568,8 +715,8 @@ Extends `PerfectShape::Shape`
568
715
  - `#center_x`: center x
569
716
  - `#center_y`: center y
570
717
  - `#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)
571
- - `#contain?(x_or_point, y=nil)`: checks if point is inside any of the shapes owned by the composite shape
572
718
  - `#==(other)`: Returns `true` if equal to `other` or `false` otherwise
719
+ - `#contain?(x_or_point, y=nil)`: checks if point is inside any of the shapes owned by the composite shape
573
720
 
574
721
  Example:
575
722
 
@@ -595,7 +742,7 @@ shape.contain?([170, 190]) # => true
595
742
  ## Resources
596
743
 
597
744
  - Rubydoc: https://www.rubydoc.info/gems/perfect-shape
598
- - AWT Geom JavaDoc (inspiration): https://docs.oracle.com/javase/8/docs/api/java/awt/geom/package-summary.html
745
+ - AWT Geom Javadoc (inspiration): https://docs.oracle.com/javase/8/docs/api/java/awt/geom/package-summary.html
599
746
 
600
747
  ## TODO
601
748
 
@@ -625,5 +772,5 @@ shape.contain?([170, 190]) # => true
625
772
 
626
773
  [MIT](LICENSE.txt)
627
774
 
628
- Copyright (c) 2021 Andy Maleh. See
775
+ Copyright (c) 2021-2022 Andy Maleh. See
629
776
  [LICENSE.txt](LICENSE.txt) for further details.
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.2.0
1
+ 0.3.3
data/lib/perfect-shape.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
@@ -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
 
@@ -143,44 +144,58 @@ module PerfectShape
143
144
  # @return {@code true} if the point lies within the bound of
144
145
  # the arc, {@code false} if the point lies outside of the
145
146
  # arc's bounds.
146
- def contain?(x_or_point, y = nil)
147
+ def contain?(x_or_point, y = nil, outline: false, distance_tolerance: 0)
147
148
  x, y = normalize_point(x_or_point, y)
148
149
  return unless x && y
149
- # Normalize the coordinates compared to the ellipse
150
- # having a center at 0,0 and a radius of 0.5.
151
- ellw = width
152
- return false if (ellw <= 0.0)
153
- normx = (x - self.x) / ellw - 0.5
154
- ellh = height
155
- return false if (ellh <= 0.0)
156
- normy = (y - self.y) / ellh - 0.5
157
- dist_sq = (normx * normx) + (normy * normy)
158
- return false if (dist_sq >= 0.25)
159
- ang_ext = self.extent.abs
160
- return true if (ang_ext >= 360.0)
161
- inarc = contain_angle?(-1*Math.radians_to_degrees(Math.atan2(normy, normx)))
162
-
163
- return inarc if type == :pie
164
- # CHORD and OPEN behave the same way
165
- if inarc
166
- return true if ang_ext >= 180.0
167
- # point must be outside the "pie triangle"
150
+ if outline
151
+ if type == :pie && x == center_x && y == center_y
152
+ true
153
+ else
154
+ distance_tolerance = BigDecimal(distance_tolerance.to_s)
155
+ outside_inside_radius_difference = DEFAULT_OUTLINE_RADIUS + distance_tolerance * 2.0
156
+ outside_radius_difference = inside_radius_difference = outside_inside_radius_difference / 2.0
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
+ 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
+ outside_shape.contain?(x, y, outline: false) and
160
+ !inside_shape.contain?(x, y, outline: false)
161
+ end
168
162
  else
169
- return false if ang_ext <= 180.0
170
- # point must be inside the "pie triangle"
163
+ # Normalize the coordinates compared to the ellipse
164
+ # having a center at 0,0 and a radius of 0.5.
165
+ ellw = width
166
+ return false if (ellw <= 0.0)
167
+ normx = (x - self.x) / ellw - 0.5
168
+ ellh = height
169
+ return false if (ellh <= 0.0)
170
+ normy = (y - self.y) / ellh - 0.5
171
+ dist_sq = (normx * normx) + (normy * normy)
172
+ return false if (dist_sq >= 0.25)
173
+ ang_ext = self.extent.abs
174
+ return true if (ang_ext >= 360.0)
175
+ inarc = contain_angle?(-1*Math.radians_to_degrees(Math.atan2(normy, normx)))
176
+
177
+ return inarc if type == :pie
178
+ # CHORD and OPEN behave the same way
179
+ if inarc
180
+ return true if ang_ext >= 180.0
181
+ # point must be outside the "pie triangle"
182
+ else
183
+ return false if ang_ext <= 180.0
184
+ # point must be inside the "pie triangle"
185
+ end
186
+
187
+ # The point is inside the pie triangle iff it is on the same
188
+ # side of the line connecting the ends of the arc as the center.
189
+ angle = Math.degrees_to_radians(-start)
190
+ x1 = Math.cos(angle)
191
+ y1 = Math.sin(angle)
192
+ angle += Math.degrees_to_radians(-extent)
193
+ x2 = Math.cos(angle)
194
+ y2 = Math.sin(angle)
195
+ inside = (Line.relative_counterclockwise(x1, y1, x2, y2, 2*normx, 2*normy) *
196
+ Line.relative_counterclockwise(x1, y1, x2, y2, 0, 0) >= 0)
197
+ inarc ? !inside : inside
171
198
  end
172
-
173
- # The point is inside the pie triangle iff it is on the same
174
- # side of the line connecting the ends of the arc as the center.
175
- angle = Math.degrees_to_radians(-start)
176
- x1 = Math.cos(angle)
177
- y1 = Math.sin(angle)
178
- angle += Math.degrees_to_radians(-extent)
179
- x2 = Math.cos(angle)
180
- y2 = Math.sin(angle)
181
- inside = (Line.relative_counterclockwise(x1, y1, x2, y2, 2*normx, 2*normy) *
182
- Line.relative_counterclockwise(x1, y1, x2, y2, 0, 0) >= 0)
183
- inarc ? !inside : inside
184
199
  end
185
200
 
186
201
  # Determines whether or not the specified angle is within the