perfect-shape 0.0.2 → 0.0.6

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: 27a7fef31137e74569d2a21ccb631fc968b0d1b78897d85a67f958c27833b910
4
- data.tar.gz: 2335d8343628c9b599ea20a25c83a8986ebdd45a9fcdfd027312ccf05d44bd0f
3
+ metadata.gz: 81aba6992bb9cb98b1ce01764cb4cd0ca8e88690c56066e8282b4c0876421925
4
+ data.tar.gz: c63f14e43dfa8adff2bd525a77ca25ded5d1381953abb4a728770b22dab43323
5
5
  SHA512:
6
- metadata.gz: 62a9db0050089a036fda899a076e8b5467519e03208a39f3da7faa11e940124c3b71738a3c6ed02bd2b15fc64723e8e851c844e63a727196200ab698f4f3c2fb
7
- data.tar.gz: 16ec103325e93f584f3c4831951da95e4f92e6489a20dfd23ced5ce6c05f7e9e508fd824b5f3daffd4b98f3b9a3fd6f26ec3d941cd111197bba0d043c5f26827
6
+ metadata.gz: 6ff01e388f4fadc337792f45ddfc598fecaeb3816fe13d04f5db4a13ecc78c7e978e2ef9683e33e32711bda62373c77dd1f5f4c07d69cfc23e4867bfbba9ccca
7
+ data.tar.gz: b32a4c65a4101ffa61cdab257fa1af05d59e7ee1f8e12ac8598dbad92a32dd33299bda92add7781e3f9028278051ebda36d9164cde116d79fc70f6d8b297f8ed
data/CHANGELOG.md CHANGED
@@ -1,5 +1,28 @@
1
1
  # Change Log
2
2
 
3
+ ## 0.0.6
4
+
5
+ - `PerfectShape::Circle`
6
+ - `PerfectShape::Circle#contain?(x_or_point, y=nil)`
7
+
8
+ ## 0.0.5
9
+
10
+ - `PerfectShape::Ellipse`
11
+ - `PerfectShape::Ellipse#contain?(x_or_point, y=nil)`
12
+
13
+ ## 0.0.4
14
+
15
+ - `PerfectShape::Arc#center_x` / `PerfectShape::Arc#center_y` / `PerfectShape::Arc#radius_x` / `PerfectShape::Arc#radius_y`
16
+ - `PerfectShape::Rectangle#center_x` / `PerfectShape::Arc#center_y`
17
+ - `PerfectShape::Square#center_x` / `PerfectShape::Square#center_y`
18
+ - `PerfectShape::Arc#initialize(center_x: , center_y: , radius_x: , radius_y: )`
19
+ - `PerfectShape::Math::normalize_degrees(degrees)` extracted from `PerfectShape::Arc`
20
+
21
+ ## 0.0.3
22
+
23
+ - `PerfectShape::Square`
24
+ - `PerfectShape::Square#contain?(x_or_point, y=nil)`
25
+
3
26
  ## 0.0.2
4
27
 
5
28
  - `PerfectShape::Rectangle`
data/README.md CHANGED
@@ -1,8 +1,8 @@
1
- # Perfect Shape 0.0.2
1
+ # Perfect Shape 0.0.6
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
 
5
- `PerfectShape` 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 in popular geometry shapes such as rectangle, square, arc, ellipse, circle, polygon, polyline, polybezier, and paths containing lines, bezier curves, and quadratic curves.
5
+ `PerfectShape` 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 in popular geometry shapes such as rectangle, square, arc (open, chord, and pie), ellipse, circle, polygon, polyline, polyquad, polycubic, and paths containing lines, bezier curves, and quadratic curves.
6
6
 
7
7
  Additionally, `PerfectShape::Math` contains some purely mathematical algorithms.
8
8
 
@@ -13,13 +13,13 @@ To ensure high accuracy, this library does all its mathematical operations with
13
13
  Run:
14
14
 
15
15
  ```
16
- gem install perfect-shape -v 0.0.2
16
+ gem install perfect-shape -v 0.0.6
17
17
  ```
18
18
 
19
19
  Or include in Bundler `Gemfile`:
20
20
 
21
21
  ```ruby
22
- gem 'perfect-shape', '~> 0.0.2'
22
+ gem 'perfect-shape', '~> 0.0.6'
23
23
  ```
24
24
 
25
25
  And, run:
@@ -32,33 +32,141 @@ bundle
32
32
 
33
33
  ### `PerfectShape::Math`
34
34
 
35
- - `::degrees_to_radians(angle)`
36
- - `::radians_to_degrees(angle)`
37
- - `::ieee_remainder(x, y)` (alias: `ieee754_remainder`)
35
+ Module
36
+
37
+ - `::degrees_to_radians(angle)`: converts degrees to radians
38
+ - `::radians_to_degrees(angle)`: converts radians to degrees
39
+ - `::normalize_degrees(angle)`: normalizes the specified angle into the range -180 to 180.
40
+ - `::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
+
42
+ ### `PerfectShape::Shape`
43
+
44
+ Class
45
+
46
+ - `#normalize_point(x_or_point, y = nil)`: normalizes point into an `Array` of (x,y) coordinates
47
+
48
+ ### `PerfectShape::RectangularShape`
49
+
50
+ Module
51
+
52
+ - `#initialize(x: 0, y: 0, width: 1, height: 1)`: initializes a rectangular shape
53
+ - `#x`: top-left x
54
+ - `#y`: top-left y
55
+ - `#width`: width
56
+ - `#height`: height
57
+ - `#center_x`: center x
58
+ - `#center_y`: center y
38
59
 
39
60
  ### `PerfectShape::Line`
40
61
 
62
+ Class
63
+ Extends `PerfectShape::Shape`
64
+
41
65
  - `::relative_ccw(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)”.
42
66
 
43
67
  ### `PerfectShape::Rectangle`
44
68
 
69
+ Class
70
+ Extends `PerfectShape::Shape`
71
+ Includes `PerfectShape::RectangularShape`
72
+
73
+ ![rectangle](images/rectangle.png)
74
+
45
75
  - `::new(x: 0, y: 0, width: 1, height: 1)`: constructs a rectangle
46
76
  - `#x`: top-left x
47
77
  - `#y`: top-left y
48
78
  - `#width`: width
49
79
  - `#height`: height
50
- - `#contain?(x_or_point, y=nil)`: checks if point inside
80
+ - `#center_x`: center x
81
+ - `#center_y`: center y
82
+ - `#contain?(x_or_point, y=nil)`: checks if point is inside
83
+
84
+ ### `PerfectShape::Square`
85
+
86
+ Class
87
+ Extends `PerfectShape::Rectangle`
88
+
89
+ ![square](images/square.png)
90
+
91
+ - `::new(x: 0, y: 0, length: 1)`: constructs a square
92
+ - `#x`: top-left x
93
+ - `#y`: top-left y
94
+ - `#length`: length
95
+ - `#width`: width (equal to length)
96
+ - `#height`: height (equal to length)
97
+ - `#center_x`: center x
98
+ - `#center_y`: center y
99
+ - `#contain?(x_or_point, y=nil)`: checks if point is inside
51
100
 
52
101
  ### `PerfectShape::Arc`
53
102
 
54
- - `::new(type: :open, x: 0, y: 0, width: 1, height: 1, start: 0, extent: 360)`: constructs an arc of type `:open` (default), `:chord`, or `:pie`
55
- - `#x`: top-left x of arc
56
- - `#y`: top-left y of arc
57
- - `#width`: width of arc
58
- - `#height`: height of arc
103
+ Class
104
+ Extends `PerfectShape::Shape`
105
+ Includes `PerfectShape::RectangularShape`
106
+
107
+ Arcs can be of type `:open`, `:chord`, or `:pie`
108
+
109
+ Open Arc | Chord Arc | Pie Arc
110
+ ---------|-----------|--------
111
+ ![arc-open](images/arc-open.png) | ![arc-chord](images/arc-chord.png) | ![arc-pie](images/arc-pie.png)
112
+
113
+ - `::new(type: :open, x: 0, y: 0, width: 1, height: 1, start: 0, extent: 360, center_x: nil, center_y: nil, radius_x: nil, radius_y: nil)`: constructs an arc of type `:open` (default), `:chord`, or `:pie`
114
+ - `#type`: `:open`, `:chord`, or `:pie`
115
+ - `#x`: top-left x
116
+ - `#y`: top-left y
117
+ - `#width`: width
118
+ - `#height`: height
59
119
  - `#start`: start angle in degrees
60
120
  - `#extent`: extent angle in degrees
61
- - `#contain?(x_or_point, y=nil)`: checks if point is in arc
121
+ - `#center_x`: center x
122
+ - `#center_y`: center y
123
+ - `#radius_x`: radius along the x-axis
124
+ - `#radius_y`: radius along the y-axis
125
+ - `#contain?(x_or_point, y=nil)`: checks if point is inside
126
+
127
+ ### `PerfectShape::Ellipse`
128
+
129
+ Class
130
+ Extends `PerfectShape::Arc`
131
+
132
+ ![ellipse](images/ellipse.png)
133
+
134
+ - `::new(x: 0, y: 0, width: 1, height: 1, center_x: nil, center_y: nil, radius_x: nil, radius_y: nil)`: constructs an ellipse
135
+ - `#x`: top-left x
136
+ - `#y`: top-left y
137
+ - `#width`: width
138
+ - `#height`: height
139
+ - `#center_x`: center x
140
+ - `#center_y`: center y
141
+ - `#radius_x`: radius along the x-axis
142
+ - `#radius_y`: radius along the y-axis
143
+ - `#type`: always `:open`
144
+ - `#start`: always `0`
145
+ - `#extent`: always `360`
146
+ - `#contain?(x_or_point, y=nil)`: checks if point is inside
147
+
148
+ ### `PerfectShape::Circle`
149
+
150
+ Class
151
+ Extends `PerfectShape::Ellipse`
152
+
153
+ ![circle](images/circle.png)
154
+
155
+ - `::new(x: 0, y: 0, diameter: 1, width: 1, height: 1, center_x: nil, center_y: nil, radius: nil, radius_x: nil, radius_y: nil)`: constructs a circle
156
+ - `#x`: top-left x
157
+ - `#y`: top-left y
158
+ - `#diameter`: diameter
159
+ - `#width`: width (equal to diameter)
160
+ - `#height`: height (equal to diameter)
161
+ - `#center_x`: center x
162
+ - `#center_y`: center y
163
+ - `#radius`: radius
164
+ - `#radius_x`: radius along the x-axis (equal to radius)
165
+ - `#radius_y`: radius along the y-axis (equal to radius)
166
+ - `#type`: always `:open`
167
+ - `#start`: always `0`
168
+ - `#extent`: always `360`
169
+ - `#contain?(x_or_point, y=nil)`: checks if point is inside
62
170
 
63
171
  ## Process
64
172
 
@@ -77,7 +185,7 @@ bundle
77
185
 
78
186
  [CHANGELOG.md](CHANGELOG.md)
79
187
 
80
- ## Contributing to perfect-shape
188
+ ## Contributing
81
189
 
82
190
  - Check out the latest master to make sure the feature hasn't been
83
191
  implemented or the bug hasn't been fixed yet.
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.0.2
1
+ 0.0.6
@@ -32,8 +32,15 @@ module PerfectShape
32
32
  attr_accessor :type
33
33
  attr_reader :start, :extent
34
34
 
35
- def initialize(type: :open, x: 0, y: 0, width: 1, height: 1, start: 0, extent: 360)
36
- super(x: x, y: y, width: width, height: height)
35
+ def initialize(type: :open, x: 0, y: 0, width: 1, height: 1, start: 0, extent: 360, center_x: nil, center_y: nil, radius_x: nil, radius_y: nil)
36
+ if center_x && center_y && radius_x && radius_y
37
+ self.center_x = center_x
38
+ self.center_y = center_y
39
+ self.radius_x = radius_x
40
+ self.radius_y = radius_y
41
+ else
42
+ super(x: x, y: y, width: width, height: height)
43
+ end
37
44
  @type = type
38
45
  self.start = start
39
46
  self.extent = extent
@@ -47,6 +54,86 @@ module PerfectShape
47
54
  @extent = BigDecimal(value.to_s)
48
55
  end
49
56
 
57
+ def x
58
+ @center_x && @radius_x ? @center_x - @radius_x : super
59
+ end
60
+
61
+ def y
62
+ @center_y && @radius_y ? @center_y - @radius_y : super
63
+ end
64
+
65
+ def width
66
+ @radius_x ? @radius_x * BigDecimal('2.0') : super
67
+ end
68
+
69
+ def height
70
+ @radius_y ? @radius_y * BigDecimal('2.0') : super
71
+ end
72
+
73
+ # Sets x, normalizing to BigDecimal
74
+ def x=(value)
75
+ super
76
+ @center_x = nil
77
+ self.width = width if @radius_x
78
+ end
79
+
80
+ # Sets y, normalizing to BigDecimal
81
+ def y=(value)
82
+ super
83
+ @center_y = nil
84
+ self.height = height if @radius_y
85
+ end
86
+
87
+ # Sets width, normalizing to BigDecimal
88
+ def width=(value)
89
+ super
90
+ @radius_x = nil
91
+ end
92
+
93
+ # Sets height, normalizing to BigDecimal
94
+ def height=(value)
95
+ super
96
+ @radius_y = nil
97
+ end
98
+
99
+ def center_x
100
+ super || @center_x
101
+ end
102
+
103
+ def center_y
104
+ super || @center_y
105
+ end
106
+
107
+ def radius_x
108
+ @width ? @width/BigDecimal('2.0') : @radius_x
109
+ end
110
+
111
+ def radius_y
112
+ @height ? @height/BigDecimal('2.0') : @radius_y
113
+ end
114
+
115
+ def center_x=(value)
116
+ @center_x = BigDecimal(value.to_s)
117
+ @x = nil
118
+ self.radius_x = radius_x if @width
119
+ end
120
+
121
+ def center_y=(value)
122
+ @center_y = BigDecimal(value.to_s)
123
+ @y = nil
124
+ self.radius_y = radius_y if @height
125
+ end
126
+
127
+ def radius_x=(value)
128
+ @radius_x = BigDecimal(value.to_s)
129
+ @width = nil
130
+ end
131
+
132
+ def radius_y=(value)
133
+ @radius_y = BigDecimal(value.to_s)
134
+ @height = nil
135
+ end
136
+
50
137
  # Checks if arc contains point denoted by point (two-number Array or x, y args)
51
138
  #
52
139
  # @param x The X coordinate of the point to test.
@@ -103,34 +190,11 @@ module PerfectShape
103
190
  ang_ext = -ang_ext if backwards
104
191
  return true if ang_ext >= 360.0
105
192
 
106
- angle = normalize_degrees(angle) - normalize_degrees(start)
193
+ angle = Math.normalize_degrees(angle) - Math.normalize_degrees(start)
107
194
  angle = -angle if backwards
108
195
  angle += 360.0 if angle < 0.0
109
196
 
110
197
  (angle >= 0.0) && (angle < ang_ext)
111
198
  end
112
-
113
- # Normalizes the specified angle into the range -180 to 180.
114
- # TODO refactor/extract to Math class
115
- def normalize_degrees(angle)
116
- if angle > 180.0
117
- if angle <= (180.0 + 360.0)
118
- angle = angle - 360.0
119
- else
120
- angle = Math.ieee_remainder(angle, 360.0)
121
- # IEEEremainder can return -180 here for some input values...
122
- angle = 180.0 if angle == -180.0
123
- end
124
- elsif angle <= -180.0
125
- if angle > (-180.0 - 360.0)
126
- angle = angle + 360.0
127
- else
128
- angle = Math.ieee_remainder(angle, 360.0)
129
- # IEEEremainder can return -180 here for some input values...
130
- angle = 180.0 if angle == -180.0
131
- end
132
- end
133
- angle
134
- end
135
199
  end
136
200
  end
@@ -0,0 +1,91 @@
1
+ # Copyright (c) 2021 Andy Maleh
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person obtaining
4
+ # a copy of this software and associated documentation files (the
5
+ # "Software"), to deal in the Software without restriction, including
6
+ # without limitation the rights to use, copy, modify, merge, publish,
7
+ # distribute, sublicense, and/or sell copies of the Software, and to
8
+ # permit persons to whom the Software is furnished to do so, subject to
9
+ # the following conditions:
10
+ #
11
+ # The above copyright notice and this permission notice shall be
12
+ # included in all copies or substantial portions of the Software.
13
+ #
14
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
+
22
+ require 'perfect_shape/ellipse'
23
+
24
+ module PerfectShape
25
+ class Circle < Ellipse
26
+ MESSAGE_WIDTH_AND_HEIGHT_AND_DIAMETER_NOT_EQUAL = 'Circle width, height, and diameter must all be equal if more than one is specified; or otherwise keep only one of them in arguments!'
27
+ MESSAGE_RADIUS_X_AND_RADIUS_Y_AND_RADIUS_NOT_EQUAL = 'Circle radius_x, radius_y, and radius must all be equal if more than one is specified; or otherwise keep only one of them in arguments!'
28
+
29
+ def initialize(x: 0, y: 0, width: nil, height: nil, diameter: nil, center_x: nil, center_y: nil, radius_x: nil, radius_y: nil, radius: nil)
30
+ raise MESSAGE_WIDTH_AND_HEIGHT_AND_DIAMETER_NOT_EQUAL if (diameter && width && diameter != width) || (diameter && height && diameter != height) || (width && height && width != height)
31
+ raise MESSAGE_RADIUS_X_AND_RADIUS_Y_AND_RADIUS_NOT_EQUAL if (radius && radius_x && radius != radius_x) || (radius && radius_y && radius != radius_y) || (radius_x && radius_y && radius_x != radius_y)
32
+ if center_x && center_y && (radius || radius_x || radius_y)
33
+ radius ||= radius_x || radius_y
34
+ self.radius = radius
35
+ super(center_x: center_x, center_y: center_y, radius_x: self.radius_x, radius_y: self.radius_y)
36
+ else
37
+ diameter ||= width || height || 1
38
+ self.diameter = diameter
39
+ super(x: x, y: y, width: self.width, height: self.height)
40
+ end
41
+ end
42
+
43
+ def diameter
44
+ @radius ? @radius * BigDecimal('2.0') : @diameter
45
+ end
46
+
47
+ def radius
48
+ @diameter ? @diameter / BigDecimal('2.0') : @radius
49
+ end
50
+
51
+ # Sets length, normalizing to BigDecimal
52
+ def diameter=(value)
53
+ @diameter = BigDecimal(value.to_s)
54
+ @radius = nil
55
+ self.width = value unless width == value
56
+ self.height = value unless height == value
57
+ end
58
+
59
+ # Sets radius, normalizing to BigDecimal
60
+ def radius=(value)
61
+ @radius = BigDecimal(value.to_s)
62
+ @diameter = nil
63
+ self.radius_x = value unless width == value
64
+ self.radius_y = value unless height == value
65
+ end
66
+
67
+ def width=(value)
68
+ super
69
+ self.diameter = value unless diameter == value
70
+ self.height = value unless height == value
71
+ end
72
+
73
+ def height=(value)
74
+ super
75
+ self.diameter = value unless diameter == value
76
+ self.width = value unless width == value
77
+ end
78
+
79
+ def radius_x=(value)
80
+ super
81
+ self.radius = value unless radius == value
82
+ self.radius_y = value unless radius_y == value
83
+ end
84
+
85
+ def radius_y=(value)
86
+ super
87
+ self.radius = value unless radius == value
88
+ self.radius_x = value unless radius_x == value
89
+ end
90
+ end
91
+ end
@@ -0,0 +1,78 @@
1
+ # Copyright (c) 2021 Andy Maleh
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person obtaining
4
+ # a copy of this software and associated documentation files (the
5
+ # "Software"), to deal in the Software without restriction, including
6
+ # without limitation the rights to use, copy, modify, merge, publish,
7
+ # distribute, sublicense, and/or sell copies of the Software, and to
8
+ # permit persons to whom the Software is furnished to do so, subject to
9
+ # the following conditions:
10
+ #
11
+ # The above copyright notice and this permission notice shall be
12
+ # included in all copies or substantial portions of the Software.
13
+ #
14
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
+
22
+ require 'perfect_shape/arc'
23
+
24
+ module PerfectShape
25
+ # Mostly ported from java.awt.geom: https://docs.oracle.com/javase/8/docs/api/java/awt/geom/Ellipse2D.html
26
+ class Ellipse < Arc
27
+ MESSAGE_CANNOT_UPDATE_ATTRIUBTE = "Ellipse %s cannot be updated. If you want to update type, use Arc instead!"
28
+
29
+ def initialize(x: 0, y: 0, width: 1, height: 1, center_x: nil, center_y: nil, radius_x: nil, radius_y: nil)
30
+ super
31
+ @initialized = true
32
+ end
33
+
34
+ def type=(value)
35
+ if @initialized
36
+ raise MESSAGE_CANNOT_UPDATE_ATTRIUBTE % 'type'
37
+ else
38
+ super
39
+ end
40
+ end
41
+
42
+ def start=(value)
43
+ if @initialized
44
+ raise MESSAGE_CANNOT_UPDATE_ATTRIUBTE % 'start'
45
+ else
46
+ super
47
+ end
48
+ end
49
+
50
+ def extent=(value)
51
+ if @initialized
52
+ raise MESSAGE_CANNOT_UPDATE_ATTRIUBTE % 'extent'
53
+ else
54
+ super
55
+ end
56
+ end
57
+
58
+ # Checks if ellipse contains point denoted by point (two-number Array or x, y args)
59
+ #
60
+ # @param x The X coordinate of the point to test.
61
+ # @param y The Y coordinate of the point to test.
62
+ #
63
+ # @return {@code true} if the point lies within the bound of
64
+ # the ellipse, {@code false} if the point lies outside of the
65
+ # ellipse's bounds.
66
+ def contain?(x_or_point, y = nil)
67
+ x, y = normalize_point(x_or_point, y)
68
+ return unless x && y
69
+ ellw = self.width
70
+ return false if ellw <= 0.0
71
+ normx = (x - self.x) / ellw - 0.5
72
+ ellh = self.height
73
+ return false if ellh <= 0.0
74
+ normy = (y - self.y) / ellh - 0.5
75
+ (normx * normx + normy * normy) < 0.25
76
+ end
77
+ end
78
+ end
@@ -15,6 +15,28 @@ module PerfectShape
15
15
  def degrees_to_radians(degrees)
16
16
  (Math::PI/180)*degrees
17
17
  end
18
+
19
+ # Normalizes the specified angle into the range -180 to 180.
20
+ def normalize_degrees(angle)
21
+ if angle > 180.0
22
+ if angle <= (180.0 + 360.0)
23
+ angle = angle - 360.0
24
+ else
25
+ angle = Math.ieee_remainder(angle, 360.0)
26
+ # IEEEremainder can return -180 here for some input values...
27
+ angle = 180.0 if angle == -180.0
28
+ end
29
+ elsif angle <= -180.0
30
+ if angle > (-180.0 - 360.0)
31
+ angle = angle + 360.0
32
+ else
33
+ angle = Math.ieee_remainder(angle, 360.0)
34
+ # IEEEremainder can return -180 here for some input values...
35
+ angle = 180.0 if angle == -180.0
36
+ end
37
+ end
38
+ angle
39
+ end
18
40
 
19
41
  # Computes the remainder operation on two arguments as prescribed by the IEEE 754 standard.
20
42
  #
@@ -38,7 +38,7 @@ module PerfectShape
38
38
  def contain?(x_or_point, y = nil)
39
39
  x, y = normalize_point(x_or_point, y)
40
40
  return unless x && y
41
- x.between?(@x, @x + @width) && y.between?(@y, @y + @height)
41
+ x.between?(self.x, self.x + self.width) && y.between?(self.y, self.y + self.height)
42
42
  end
43
43
  end
44
44
  end
@@ -53,5 +53,13 @@ module PerfectShape
53
53
  def height=(value)
54
54
  @height = BigDecimal(value.to_s)
55
55
  end
56
+
57
+ def center_x
58
+ @x + (@width/BigDecimal('2.0')) if @x && @width
59
+ end
60
+
61
+ def center_y
62
+ @y + (@height/BigDecimal('2.0')) if @y && @height
63
+ end
56
64
  end
57
65
  end
@@ -20,6 +20,7 @@
20
20
  # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
21
 
22
22
  module PerfectShape
23
+ # Superclass of all shapes
23
24
  class Shape
24
25
  # Normalizes point args whether two-number Array or x, y args returning
25
26
  # normalized point array of two BigDecimal's
@@ -0,0 +1,56 @@
1
+ # Copyright (c) 2021 Andy Maleh
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person obtaining
4
+ # a copy of this software and associated documentation files (the
5
+ # "Software"), to deal in the Software without restriction, including
6
+ # without limitation the rights to use, copy, modify, merge, publish,
7
+ # distribute, sublicense, and/or sell copies of the Software, and to
8
+ # permit persons to whom the Software is furnished to do so, subject to
9
+ # the following conditions:
10
+ #
11
+ # The above copyright notice and this permission notice shall be
12
+ # included in all copies or substantial portions of the Software.
13
+ #
14
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
+
22
+ require 'perfect_shape/rectangle'
23
+
24
+ module PerfectShape
25
+ class Square < Rectangle
26
+ MESSAGE_WIDTH_AND_HEIGHT_AND_LENGTH_NOT_EQUAL = 'Square width, height, and length must all be equal if more than one is specified; or otherwise keep only one of them in arguments!'
27
+
28
+ attr_reader :length
29
+
30
+ # Constructs with x, y, length (optionally width or height can be passed as alias for length)
31
+ def initialize(x: 0, y: 0, length: nil, width: nil, height: nil)
32
+ raise MESSAGE_WIDTH_AND_HEIGHT_AND_LENGTH_NOT_EQUAL if (length && width && length != width) || (length && height && length != height) || (width && height && width != height)
33
+ length ||= width || height || 1
34
+ super(x: x, y: y, width: length, height: length)
35
+ end
36
+
37
+ # Sets length, normalizing to BigDecimal
38
+ def length=(value)
39
+ @length = BigDecimal(value.to_s)
40
+ self.width = value unless width == value
41
+ self.height = value unless height == value
42
+ end
43
+
44
+ def width=(value)
45
+ super
46
+ self.length = value unless length == value
47
+ self.height = value unless height == value
48
+ end
49
+
50
+ def height=(value)
51
+ super
52
+ self.length = value unless length == value
53
+ self.width = value unless width == value
54
+ end
55
+ end
56
+ end
@@ -2,17 +2,17 @@
2
2
  # DO NOT EDIT THIS FILE DIRECTLY
3
3
  # Instead, edit Juwelier::Tasks in Rakefile, and run 'rake gemspec'
4
4
  # -*- encoding: utf-8 -*-
5
- # stub: perfect-shape 0.0.2 ruby lib
5
+ # stub: perfect-shape 0.0.6 ruby lib
6
6
 
7
7
  Gem::Specification.new do |s|
8
8
  s.name = "perfect-shape".freeze
9
- s.version = "0.0.2"
9
+ s.version = "0.0.6"
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 = "2021-12-11"
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, ellipse, circle, polygon, polyline, polybezier, and paths containing lines, bezier curves, and quadratic curves. Additionally, it contains some purely mathematical algorithms like IEEEremainder (also known as IEEE-754 remainder).".freeze
14
+ s.date = "2021-12-16"
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, polyline, polyquad, polycubic, and paths containing lines, bezier curves, and quadratic curves. Additionally, it contains some purely mathematical algorithms like IEEEremainder (also known as IEEE-754 remainder).".freeze
16
16
  s.email = "andy.am@gmail.com".freeze
17
17
  s.extra_rdoc_files = [
18
18
  "CHANGELOG.md",
@@ -26,11 +26,14 @@ Gem::Specification.new do |s|
26
26
  "VERSION",
27
27
  "lib/perfect-shape.rb",
28
28
  "lib/perfect_shape/arc.rb",
29
+ "lib/perfect_shape/circle.rb",
30
+ "lib/perfect_shape/ellipse.rb",
29
31
  "lib/perfect_shape/line.rb",
30
32
  "lib/perfect_shape/math.rb",
31
33
  "lib/perfect_shape/rectangle.rb",
32
34
  "lib/perfect_shape/rectangular_shape.rb",
33
35
  "lib/perfect_shape/shape.rb",
36
+ "lib/perfect_shape/square.rb",
34
37
  "perfect-shape.gemspec"
35
38
  ]
36
39
  s.homepage = "http://github.com/AndyObtiva/perfect-shape".freeze
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.0.2
4
+ version: 0.0.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andy Maleh
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-12-11 00:00:00.000000000 Z
11
+ date: 2021-12-16 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rdoc
@@ -82,10 +82,10 @@ dependencies:
82
82
  version: '0'
83
83
  description: Perfect Shape is a collection of pure Ruby geometric algorithms that
84
84
  are mostly useful for GUI manipulation like checking containment of a mouse click
85
- point in popular geometry shapes such as rectangle, square, arc, ellipse, circle,
86
- polygon, polyline, polybezier, and paths containing lines, bezier curves, and quadratic
87
- curves. Additionally, it contains some purely mathematical algorithms like IEEEremainder
88
- (also known as IEEE-754 remainder).
85
+ point in popular geometry shapes such as rectangle, square, arc (open, chord, and
86
+ pie), ellipse, circle, polygon, polyline, polyquad, polycubic, and paths containing
87
+ lines, bezier curves, and quadratic curves. Additionally, it contains some purely
88
+ mathematical algorithms like IEEEremainder (also known as IEEE-754 remainder).
89
89
  email: andy.am@gmail.com
90
90
  executables: []
91
91
  extensions: []
@@ -100,11 +100,14 @@ files:
100
100
  - VERSION
101
101
  - lib/perfect-shape.rb
102
102
  - lib/perfect_shape/arc.rb
103
+ - lib/perfect_shape/circle.rb
104
+ - lib/perfect_shape/ellipse.rb
103
105
  - lib/perfect_shape/line.rb
104
106
  - lib/perfect_shape/math.rb
105
107
  - lib/perfect_shape/rectangle.rb
106
108
  - lib/perfect_shape/rectangular_shape.rb
107
109
  - lib/perfect_shape/shape.rb
110
+ - lib/perfect_shape/square.rb
108
111
  - perfect-shape.gemspec
109
112
  homepage: http://github.com/AndyObtiva/perfect-shape
110
113
  licenses: