perfect-shape 0.0.9 → 0.0.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 934071723ece0f7ebe64e6e67880b5a1f4ec6781517d2ee2a7dea70ceae4a9be
4
- data.tar.gz: d436da8745d7f4d971a7df04b5d54701e6e89abb9f8624273f79a6ac1d28ea77
3
+ metadata.gz: 373846069228dba8331891ba808511bfdb306bb8e3e29fad2cf053ab6c69fbaf
4
+ data.tar.gz: ccbc6e998e1f9809ebebd126ed6c613076fc8ad92cea012c08796e8e129ead28
5
5
  SHA512:
6
- metadata.gz: bcea5c4c02f2e056c0e18a857404bbef4b411420c2c3a7e438a2f122df90a30466979c60cc7804c61b5d454ed2879cd81fd1fc750360839393c20a4561aebce6
7
- data.tar.gz: c321b5b1697b28e9608c11d4bc5e04038c3e269df311b9c7263e468c6f952c60bec6ecf4244ff044eb8fb33cf68462e9d362326962c0473bbd72150847181e0e
6
+ metadata.gz: 66d9b3a6420a142bc35eaf1dbf80536f743b713eec9dc509764d8bc4dc87d528e214703e24c256977f38263df55cac715db8c6f1366c3d7a05d97fd0d892722c
7
+ data.tar.gz: 41c7ea46f7f9607e889f9ec04187a286333e593af6012099b74b19593806ae14e1b9d01e406bc1a4efa2e21035a096b0ca10ba53d9f74ab51721fd50a5ed44c5
data/CHANGELOG.md CHANGED
@@ -1,5 +1,12 @@
1
1
  # Change Log
2
2
 
3
+ ## 0.0.10
4
+
5
+ - `PerfectShape::Point`
6
+ - `PerfectShape::Point#point_distance`
7
+ - `PerfectShape::Point#contain?(x_or_point, y=nil, distance: 0)`
8
+ - Refactor `PerfectShape::Point`,`PerfectShape::RectangularShape` to include shared `PerfectShape::PointLocation`
9
+
3
10
  ## 0.0.9
4
11
 
5
12
  - `PerfectShape::Line#contain?(x_or_point, y=nil, distance: 0)` (add a distance tolerance fuzz factor option)
data/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # Perfect Shape 0.0.9
1
+ # Perfect Shape 0.0.10
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
 
@@ -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.9
16
+ gem install perfect-shape -v 0.0.10
17
17
  ```
18
18
 
19
19
  Or include in Bundler `Gemfile`:
20
20
 
21
21
  ```ruby
22
- gem 'perfect-shape', '~> 0.0.9'
22
+ gem 'perfect-shape', '~> 0.0.10'
23
23
  ```
24
24
 
25
25
  And, run:
@@ -54,6 +54,16 @@ Class
54
54
  - `#bounding_box`: bounding box is a rectangle with x = min x, y = min y, and width/height just as those of shape
55
55
  - `#normalize_point(x_or_point, y = nil)`: normalizes point into an `Array` of (x,y) coordinates
56
56
 
57
+ ### `PerfectShape::PointLocation`
58
+
59
+ Module
60
+
61
+ - `#initialize(x: 0, y: 0)`: initializes a point location, usually representing the top-left point in a shape
62
+ - `#x`: top-left x
63
+ - `#y`: top-left y
64
+ - `#min_x`: min x (x by default)
65
+ - `#min_y`: min y (y by default)
66
+
57
67
  ### `PerfectShape::RectangularShape`
58
68
 
59
69
  Module
@@ -71,6 +81,30 @@ Module
71
81
  - `#center_y`: center y
72
82
  - `#bounding_box`: bounding box is a rectangle with x = min x, y = min y, and width/height of shape
73
83
 
84
+ ### `PerfectShape::Point`
85
+
86
+ Class
87
+
88
+ Extends `PerfectShape::Shape`
89
+
90
+ ![point](images/point.png)
91
+
92
+ Points are simply represented by an `Array` of (x,y) coordinates when used within other shapes, but when needing point-specific operations like `point_distance`, the `PerfectShape::Point` class can come in handy.
93
+
94
+ - `::point_distance(x, y, px, py)`: Returns the distance from a point to another point
95
+ - `::new(x_or_point=0, y=0, x: nil, y: nil)`: constructs a point with (x,y) pair whether specified as `Array` of (x,y) pair, flat `x,y` args, or `x:, y:` kwargs.
96
+ - `#min_x`: min x (always x)
97
+ - `#min_y`: min y (always y)
98
+ - `#max_x`: max x (always x)
99
+ - `#max_y`: max y (always y)
100
+ - `#width`: width (always 0)
101
+ - `#height`: height (always 0)
102
+ - `#center_x`: center x (always x)
103
+ - `#center_y`: center y (always y)
104
+ - `#bounding_box`: bounding box is a rectangle with x = min x, y = min y, and width/height of shape
105
+ - `#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.
106
+ - `#point_distance(x_or_point, y=nil)`: Returns the distance from a point to another point
107
+
74
108
  ### `PerfectShape::Line`
75
109
 
76
110
  Class
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.0.9
1
+ 0.0.10
@@ -135,7 +135,7 @@ module PerfectShape
135
135
  @height = nil
136
136
  end
137
137
 
138
- # Checks if arc contains point denoted by point (two-number Array or x, y args)
138
+ # Checks if arc contains point (two-number Array or x, y args)
139
139
  #
140
140
  # @param x The X coordinate of the point to test.
141
141
  # @param y The Y coordinate of the point to test.
@@ -55,7 +55,7 @@ module PerfectShape
55
55
  end
56
56
  end
57
57
 
58
- # Checks if ellipse contains point denoted by point (two-number Array or x, y args)
58
+ # Checks if ellipse contains point (two-number Array or x, y args)
59
59
  #
60
60
  # @param x The X coordinate of the point to test.
61
61
  # @param y The Y coordinate of the point to test.
@@ -186,21 +186,20 @@ module PerfectShape
186
186
 
187
187
  include MultiPoint
188
188
 
189
- # Checks if polygon contains point denoted by point (two-number Array or x, y args)
190
- # using the Ray Casting Algorithm (aka Even-Odd Rule): https://en.wikipedia.org/wiki/Point_in_polygon
189
+ # Checks if line contains point (two-number Array or x, y args), with distance tolerance (0 by default)
191
190
  #
192
191
  # @param x The X coordinate of the point to test.
193
192
  # @param y The Y coordinate of the point to test.
193
+ # @param distance The distance from line to tolerate (0 by default)
194
194
  #
195
195
  # @return {@code true} if the point lies within the bound of
196
- # the polygon, {@code false} if the point lies outside of the
197
- # polygon's bounds.
196
+ # the line, {@code false} if the point lies outside of the
197
+ # line's bounds.
198
198
  def contain?(x_or_point, y = nil, distance: 0)
199
199
  x, y = normalize_point(x_or_point, y)
200
200
  return unless x && y
201
201
  distance = BigDecimal(distance.to_s)
202
- # TODO implement contain?(point) with a fuzz factor to enable successfully selecting a line in a GUI application
203
- Line.point_segment_distance(points[0][0], points[0][1], points[1][0], points[1][1], x, y) <= distance
202
+ point_segment_distance(x, y) <= distance
204
203
  end
205
204
 
206
205
  def point_segment_distance(x_or_point, y = nil)
@@ -55,13 +55,5 @@ module PerfectShape
55
55
  def max_y
56
56
  points.map(&:last).max
57
57
  end
58
-
59
- def width
60
- max_x - min_x if min_x && max_x
61
- end
62
-
63
- def height
64
- max_y - min_y if min_y && max_y
65
- end
66
58
  end
67
59
  end
@@ -0,0 +1,81 @@
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/shape'
23
+ require 'perfect_shape/point_location'
24
+
25
+ module PerfectShape
26
+ class Point < Shape
27
+ class << self
28
+ def point_distance(x, y, px, py)
29
+ x = BigDecimal(x.to_s)
30
+ y = BigDecimal(y.to_s)
31
+ px = BigDecimal(px.to_s)
32
+ py = BigDecimal(py.to_s)
33
+ BigDecimal(Math.sqrt((px - x)**2 + (py - y)**2).to_s)
34
+ end
35
+ end
36
+
37
+ include PointLocation
38
+
39
+ def initialize(x_or_point = nil, y_arg = nil, x: nil, y: nil)
40
+ if x_or_point.is_a?(Array)
41
+ x, y = x_or_point
42
+ super(x: x, y: y)
43
+ elsif x_or_point && y_arg
44
+ super(x: x_or_point, y: y_arg)
45
+ else
46
+ x ||= 0
47
+ y ||= 0
48
+ super(x: x, y: y)
49
+ end
50
+ end
51
+
52
+ def max_x
53
+ x
54
+ end
55
+
56
+ def max_y
57
+ y
58
+ end
59
+
60
+ # Checks if points match, with distance tolerance (0 by default)
61
+ #
62
+ # @param x The X coordinate of the point to test.
63
+ # @param y The Y coordinate of the point to test.
64
+ # @param distance The distance from point to tolerate (0 by default)
65
+ #
66
+ # @return {@code true} if the point is close enough within distance tolerance,
67
+ # {@code false} if the point is too far.
68
+ def contain?(x_or_point, y = nil, distance: 0)
69
+ x, y = normalize_point(x_or_point, y)
70
+ return unless x && y
71
+ distance = BigDecimal(distance.to_s)
72
+ point_distance(x, y) <= distance
73
+ end
74
+
75
+ def point_distance(x_or_point, y = nil)
76
+ x, y = normalize_point(x_or_point, y)
77
+ return unless x && y
78
+ Point.point_distance(self.x, self.y, x, y)
79
+ end
80
+ end
81
+ end
@@ -0,0 +1,53 @@
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
+ module PerfectShape
23
+ module PointLocation
24
+ attr_reader :x, :y
25
+
26
+ # Calls super before setting x,y (default: 0,0)
27
+ def initialize(x: 0, y: 0)
28
+ super()
29
+ self.x = x
30
+ self.y = y
31
+ end
32
+
33
+ # Sets x, normalizing to BigDecimal
34
+ def x=(value)
35
+ @x = BigDecimal(value.to_s)
36
+ end
37
+
38
+ # Sets y, normalizing to BigDecimal
39
+ def y=(value)
40
+ @y = BigDecimal(value.to_s)
41
+ end
42
+
43
+ # Returns x by default. Subclasses may override.
44
+ def min_x
45
+ x
46
+ end
47
+
48
+ # Returns y by default. Subclasses may override.
49
+ def min_y
50
+ y
51
+ end
52
+ end
53
+ end
@@ -27,7 +27,7 @@ module PerfectShape
27
27
  class Polygon < Shape
28
28
  include MultiPoint
29
29
 
30
- # Checks if polygon contains point denoted by point (two-number Array or x, y args)
30
+ # Checks if polygon contains point (two-number Array or x, y args)
31
31
  # using the Ray Casting Algorithm (aka Even-Odd Rule): https://en.wikipedia.org/wiki/Point_in_polygon
32
32
  #
33
33
  # @param x The X coordinate of the point to test.
@@ -28,7 +28,7 @@ module PerfectShape
28
28
  include RectangularShape
29
29
  include Equalizer.new(:x, :y, :width, :height)
30
30
 
31
- # Checks if rectangle contains point denoted by point (two-number Array or x, y args)
31
+ # Checks if rectangle contains point (two-number Array or x, y args)
32
32
  #
33
33
  # @param x The X coordinate of the point to test.
34
34
  # @param y The Y coordinate of the point to test.
@@ -19,31 +19,23 @@
19
19
  # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
20
  # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
21
 
22
+ require 'perfect_shape/point_location'
23
+
22
24
  module PerfectShape
23
25
  # Mixin Module for Rectangular Shapes (having x, y, width, height)
24
26
  # Can only be mixed into a class extending Shape or another module
25
27
  module RectangularShape
26
- attr_reader :x, :y, :width, :height
28
+ include PointLocation
29
+
30
+ attr_reader :width, :height
27
31
 
28
32
  # Calls super before setting x, y, width, height
29
33
  def initialize(x: 0, y: 0, width: 1, height: 1)
30
- super()
31
- self.x = x
32
- self.y = y
34
+ super(x: x, y: y)
33
35
  self.width = width
34
36
  self.height = height
35
37
  end
36
38
 
37
- # Sets x, normalizing to BigDecimal
38
- def x=(value)
39
- @x = BigDecimal(value.to_s)
40
- end
41
-
42
- # Sets y, normalizing to BigDecimal
43
- def y=(value)
44
- @y = BigDecimal(value.to_s)
45
- end
46
-
47
39
  # Sets width, normalizing to BigDecimal
48
40
  def width=(value)
49
41
  @width = BigDecimal(value.to_s)
@@ -54,14 +46,6 @@ module PerfectShape
54
46
  @height = BigDecimal(value.to_s)
55
47
  end
56
48
 
57
- def min_x
58
- @x
59
- end
60
-
61
- def min_y
62
- @y
63
- end
64
-
65
49
  def max_x
66
50
  @x + width if @x && width
67
51
  end
@@ -38,12 +38,16 @@ module PerfectShape
38
38
  def max_y
39
39
  end
40
40
 
41
- # Subclasses must implement
41
+ # Default implementation is max_x - min_x
42
+ # Subclasses can override
42
43
  def width
44
+ max_x - min_x if max_x && min_x
43
45
  end
44
46
 
45
- # Subclasses must implement
47
+ # Default implementation is max_y - min_y
48
+ # Subclasses can override
46
49
  def height
50
+ max_y - min_y if max_y && min_y
47
51
  end
48
52
 
49
53
  # center_x is min_x + width/2.0 by default
@@ -2,11 +2,11 @@
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.9 ruby lib
5
+ # stub: perfect-shape 0.0.10 ruby lib
6
6
 
7
7
  Gem::Specification.new do |s|
8
8
  s.name = "perfect-shape".freeze
9
- s.version = "0.0.9"
9
+ s.version = "0.0.10"
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]
@@ -31,6 +31,8 @@ Gem::Specification.new do |s|
31
31
  "lib/perfect_shape/line.rb",
32
32
  "lib/perfect_shape/math.rb",
33
33
  "lib/perfect_shape/multi_point.rb",
34
+ "lib/perfect_shape/point.rb",
35
+ "lib/perfect_shape/point_location.rb",
34
36
  "lib/perfect_shape/polygon.rb",
35
37
  "lib/perfect_shape/rectangle.rb",
36
38
  "lib/perfect_shape/rectangular_shape.rb",
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: perfect-shape
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.9
4
+ version: 0.0.10
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andy Maleh
@@ -120,6 +120,8 @@ files:
120
120
  - lib/perfect_shape/line.rb
121
121
  - lib/perfect_shape/math.rb
122
122
  - lib/perfect_shape/multi_point.rb
123
+ - lib/perfect_shape/point.rb
124
+ - lib/perfect_shape/point_location.rb
123
125
  - lib/perfect_shape/polygon.rb
124
126
  - lib/perfect_shape/rectangle.rb
125
127
  - lib/perfect_shape/rectangular_shape.rb