perfect-shape 0.0.9 → 0.0.10

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: 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