geometry 1 → 2

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.
data/.gitignore CHANGED
@@ -1,5 +1,6 @@
1
1
  *.gem
2
2
  .bundle
3
+ .yardoc
3
4
  Gemfile.lock
4
5
  pkg/*
5
6
  doc
@@ -20,6 +20,7 @@ Primitives
20
20
 
21
21
  - Point
22
22
  - Line
23
+ - Circle
23
24
 
24
25
  Examples
25
26
  --------
@@ -27,7 +28,7 @@ Examples
27
28
  ### Point
28
29
  ```ruby
29
30
  point = Geometry::Point[3,4] # 2D Point at coordinate 3, 4
30
- point = Geometry.Point(1,2) # Functional constructor
31
+ point = Geometry.point(1,2) # Functional constructor
31
32
 
32
33
  # Copy constructors
33
34
  point2 = Geometry::Point[point]
@@ -57,4 +58,10 @@ Examples
57
58
  # Special constructors (2D only)
58
59
  Geometry::Line.horizontal(y=0)
59
60
  Geometry::Line.vertical(x=0)
60
- ```
61
+ ```
62
+
63
+ ### Circle
64
+ ```ruby
65
+ # A circle at Point[1,2] with a radius of 3
66
+ circle = Geometry::Circle [1,2], 3
67
+ ```
data/Rakefile CHANGED
@@ -1 +1,19 @@
1
1
  require "bundler/gem_tasks"
2
+
3
+ task :fixdates do
4
+ branch = `git branch --no-color -r --merged`.strip
5
+ `git fix-dates #{branch}..HEAD`
6
+ end
7
+
8
+ task :fixdates_f do
9
+ branch = `git branch --no-color -r --merged`.strip
10
+ `git fix-dates -f #{branch}..HEAD`
11
+ end
12
+
13
+ task :trim_whitespace do
14
+ system(%Q[git status --short | awk '{if ($1 != "D" && $1 != "R") print $2}' | grep -e '.*\.rb$' | xargs sed -i '' -e 's/[ \t]*$//g;'])
15
+ end
16
+
17
+ task :uninstall do
18
+ `gem uninstall geometry`
19
+ end
@@ -3,7 +3,7 @@ $:.push File.expand_path("../lib", __FILE__)
3
3
 
4
4
  Gem::Specification.new do |s|
5
5
  s.name = "geometry"
6
- s.version = '1'
6
+ s.version = '2'
7
7
  s.authors = ["Brandon Fosdick"]
8
8
  s.email = ["bfoz@bfoz.net"]
9
9
  s.homepage = "http://github.com/bfoz/geometry"
@@ -1,22 +1,40 @@
1
+ require_relative 'geometry/circle'
1
2
  require_relative 'geometry/point'
2
3
  require_relative 'geometry/line'
4
+ require_relative 'geometry/polygon'
3
5
 
4
6
  module Geometry
5
- # :call-seq:
6
- # Line[Array, Array] -> TwoPointLine
7
- # Line[Point, Point] -> TwoPointLine
8
- # Line[Vector, Vector] -> TwoPointLine
9
- # Line[y-intercept, slope] -> SlopeInterceptLine
10
- # Line[point, slope] -> PointSlopeLine
11
- def self.Line(*args)
12
- Geometry::Line[*args]
7
+ # @overload Line(array0, array1)
8
+ # @param [Array] array0 First endpoint
9
+ # @param [Array] array1 Second endpoint
10
+ # @return [TwoPointLine]
11
+ # @overload Line(point0, point1)
12
+ # @param [Point] point0 First endpoint
13
+ # @param [Point] point1 Second endpoint
14
+ # @return [TwoPointLine]
15
+ # @overload Line(vector0, vector1)
16
+ # @param [Vector] vector0 First endpoint
17
+ # @param [Vector] vector1 Second endpoint
18
+ # @return [TwoPointLine]
19
+ # @overload Line(y_intercept, slope)
20
+ # @param [Numeric] y_intercept Y-intercept
21
+ # @param [Numeric] slope Slope
22
+ # @return [SlopeInterceptLine]
23
+ # @overload Line(point, slope)
24
+ # @param [Point] point Starting point
25
+ # @param [Numeric] slope Slope
26
+ # @return [PointSlopeLine]
27
+ def self.line(*args)
28
+ Line[*args]
13
29
  end
14
30
 
15
- # :call-seq:
16
- # Point[x,y,z,...]
17
- # Point[Point]
18
- # Point[Vector]
19
- def self.Point(*args)
20
- Geometry::Point[*args]
31
+ # @overload Point(x,y,z,...)
32
+ # @return [Point]
33
+ # @overload Point(Point)
34
+ # @return [Point]
35
+ # @overload Point(Vector)
36
+ # @return [Point]
37
+ def self.point(*args)
38
+ Point[*args]
21
39
  end
22
40
  end
@@ -0,0 +1,24 @@
1
+ require_relative 'point'
2
+
3
+ module Geometry
4
+
5
+ =begin rdoc
6
+ Circles come in all shapes and sizes, but they're usually round.
7
+
8
+ == Usage
9
+ circle = Geometry::Circle [1,1], 2
10
+ =end
11
+
12
+ class Circle
13
+ attr_reader :center, :radius
14
+
15
+ # Construct a new {Circle} from a centerpoint and radius
16
+ # @param [Point] center The center point of the Circle
17
+ # @param [Number] radius The radius of the Circle
18
+ # @return [Circle] A new Circle object
19
+ def initialize(center, radius)
20
+ @center = center.is_a?(Point) ? center : Point[center]
21
+ @radius = radius
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,57 @@
1
+ require_relative 'point'
2
+
3
+ module Geometry
4
+
5
+ =begin rdoc
6
+ An edge. It's a line segment between 2 points. Generally part of a {Polygon}.
7
+
8
+ == Usage
9
+ edge = Geometry::Edge([1,1], [2,2])
10
+
11
+ =end
12
+
13
+ class Edge
14
+ attr_reader :first, :last
15
+
16
+ # Construct a new {Edge} object from any two things that can be converted
17
+ # to a {Point}.
18
+ def initialize(point0, point1)
19
+ @first, @last = [point0, point1].map {|p| p.is_a?(Point) ? p : Point[p] }
20
+ end
21
+
22
+ # Two Edges are equal if both have equal {Point}s in the same order
23
+ def ==(other)
24
+ (@first == other.first) && (@last == other.last)
25
+ end
26
+
27
+ # Return a new {Edge} with swapped endpoints
28
+ def reverse
29
+ Edge.new(@last, @first)
30
+ end
31
+
32
+ # In-place swap the endpoints
33
+ def reverse!
34
+ @first, @last = @last, @first
35
+ self
36
+ end
37
+
38
+ # Return the {Edge}'s length along the Y axis
39
+ def height
40
+ (@first.y - @last.y).abs
41
+ end
42
+
43
+ # Return the {Edge}'s length along the X axis
44
+ def width
45
+ (@first.x - @last.x).abs
46
+ end
47
+
48
+ def inspect
49
+ 'Edge(' + @first.inspect + ', ' + @last.inspect + ')'
50
+ end
51
+ alias :to_s :inspect
52
+
53
+ def to_a
54
+ [@first, @last]
55
+ end
56
+ end
57
+ end
@@ -26,14 +26,19 @@ Supports two-point, slope-intercept, and point-slope initializer forms
26
26
  Geometry::Line.horizontal(y=0)
27
27
  Geometry::Line.vertical(x=0)
28
28
  =end
29
+
29
30
  class Line
30
31
 
31
- # :call-seq:
32
- # Line[Array, Array] -> TwoPointLine
33
- # Line[Point, Point] -> TwoPointLine
34
- # Line[Vector, Vector] -> TwoPointLine
35
- # Line[y-intercept, slope] -> SlopeInterceptLine
36
- # Line[point, slope] -> PointSlopeLine
32
+ # @overload [](Array, Array)
33
+ # @return [TwoPointLine]
34
+ # @overload [](Point, Point)
35
+ # @return [TwoPointLine]
36
+ # @overload [](Vector, Vector)
37
+ # @return [TwoPointLine]
38
+ # @overload [](y-intercept, slope)
39
+ # @return [SlopeInterceptLine]
40
+ # @overload [](point, slope)
41
+ # @return [PointSlopeLine]
37
42
  def self.[](*args)
38
43
  if( 2 == args.size )
39
44
  args.map! {|x| x.is_a?(Array) ? Point[*x] : x}
@@ -59,7 +64,8 @@ Supports two-point, slope-intercept, and point-slope initializer forms
59
64
  end
60
65
  end
61
66
 
62
- class PointSlopeLine < Line # :nodoc:
67
+ # @private
68
+ class PointSlopeLine < Line
63
69
  def initialize(point, slope)
64
70
  @point = point.is_a?(Geometry::Point) ? point : Geometry.Point(point)
65
71
  @slope = slope
@@ -69,7 +75,8 @@ Supports two-point, slope-intercept, and point-slope initializer forms
69
75
  end
70
76
  end
71
77
 
72
- class SlopeInterceptLine < Line # :nodoc:
78
+ # @private
79
+ class SlopeInterceptLine < Line
73
80
  def initialize(slope, intercept)
74
81
  @slope = slope
75
82
  @intercept = intercept
@@ -99,14 +106,15 @@ Supports two-point, slope-intercept, and point-slope initializer forms
99
106
  end
100
107
  end
101
108
 
102
- class TwoPointLine < Line # :nodoc:
109
+ # @private
110
+ class TwoPointLine < Line
103
111
  attr_reader :first, :last
104
112
 
105
113
  def initialize(point0, point1)
106
114
  @first, @last = [point0, point1].map {|p| p.is_a?(Point) ? p : Point[p] }
107
115
  end
108
116
  def inspect
109
- 'Line(' + @first.to_s + ', ' + @last.to_s + ')'
117
+ 'Line(' + @first.inspect + ', ' + @last.inspect + ')'
110
118
  end
111
119
  alias :to_s :inspect
112
120
  end
@@ -1,43 +1,57 @@
1
1
  require 'matrix'
2
2
 
3
3
  module Geometry
4
+ =begin rdoc
5
+ An object repesenting a Point in N-dimensional space
6
+
7
+ Supports all of the familiar Vector methods and adds convenience
8
+ accessors for those variables you learned to hate in your high school
9
+ geometry class (x, y, z).
10
+
11
+ == Usage
12
+
13
+ === Constructor
14
+ point = Geometry::Point[x,y]
15
+ =end
4
16
  class Point < Vector
5
- # An object repesenting a Point in N-dimensional space
6
- #
7
- # Supports all of the familiar Vector methods and adds convenience
8
- # accessors for those variables you learned to hate in your high school
9
- # geometry class (x, y, z).
10
- #
11
- # *Usage*
12
- #
13
- # point = Geometry::Point[x,y]
17
+ attr_reader :x, :y, :z
14
18
 
15
- # :call-seq:
16
- # Point[x,y,z,...]
17
- # Point[Point]
18
- # Point[Vector]
19
- #
20
19
  # Allow vector-style initialization, but override to support copy-init
21
20
  # from Vector or another Point
21
+ #
22
+ # @overload [](x,y,z,...)
23
+ # @overload [](Point)
24
+ # @overload [](Vector)
22
25
  def self.[](*array)
23
26
  array = array[0] if array[0].is_a?(Array)
24
27
  array = array[0].to_a if array[0].is_a?(Vector)
25
28
  super *array
26
29
  end
27
30
 
28
- def inspect # :nodoc:
31
+ # Allow comparison with an Array, otherwise do the normal thing
32
+ def ==(other)
33
+ return @elements == other if other.is_a?(Array)
34
+ super other
35
+ end
36
+
37
+ def inspect
29
38
  'Point' + @elements.inspect
30
39
  end
31
- def to_s # :nodoc:
40
+ def to_s
32
41
  'Point' + @elements.to_s
33
42
  end
34
43
 
44
+ # @return [Numeric] X-component
35
45
  def x
36
46
  @elements[0]
37
47
  end
48
+
49
+ # @return [Numeric] Y-component
38
50
  def y
39
51
  @elements[1]
40
52
  end
53
+
54
+ # @return [Numeric] Z-component
41
55
  def z
42
56
  @elements[2]
43
57
  end
@@ -0,0 +1,82 @@
1
+ require_relative 'edge'
2
+
3
+ module Geometry
4
+
5
+ =begin rdoc
6
+ An object representing a closed set of vertices and edges.
7
+
8
+ {http://en.wikipedia.org/wiki/Polygon}
9
+
10
+ == Usage
11
+
12
+ =end
13
+
14
+ class Polygon
15
+ attr_reader :edges, :vertices
16
+
17
+ # Construct a new Polygon from Points and/or Edges
18
+ # The constructor will try to convert all of its arguments into Points and
19
+ # Edges. Then successive Points will be collpased into Edges. Successive
20
+ # Edges that share a common vertex will be added to the new Polygon. If
21
+ # there's a gap between Edges it will be automatically filled with a new
22
+ # Edge. The resulting Polygon will then be closed if it isn't already.
23
+ # @overload new(Array, Array, ...)
24
+ # @return [Polygon]
25
+ # @overload new(Edge, Edge, ...)
26
+ # @return [Polygon]
27
+ # @overload new(Point, Point, ...)
28
+ # @return [Polygon]
29
+ # @overload new(Vector, Vector, ...)
30
+ # @return [Polygon]
31
+ def initialize(*args)
32
+ args.map! {|a| (a.is_a?(Array) || a.is_a?(Vector)) ? Point[a] : a}
33
+ raise(ArgumentError,'Unknown argument type') unless args.all? {|a| a.is_a?(Point) || a.is_a?(Edge) }
34
+
35
+ @edges = [];
36
+ @vertices = [];
37
+
38
+ first = args.shift
39
+ if first.is_a?(Point)
40
+ @vertices.push first
41
+ elsif first.is_a?(Edge)
42
+ @edges.push first
43
+ @vertices.push *(first.to_a)
44
+ end
45
+
46
+ args.reduce(@vertices.last) do |previous,n|
47
+ if n.is_a?(Point)
48
+ push_edge Edge.new(previous, n)
49
+ push_vertex n
50
+ n
51
+ elsif n.is_a?(Edge)
52
+ if previous == n.first
53
+ push_edge n
54
+ push_vertex n.last
55
+ elsif previous == n.last
56
+ push_edge n.reverse!
57
+ push_vertex n.last
58
+ else
59
+ e = Edge.new(previous, n.first)
60
+ push_edge e, n
61
+ push_vertex *(e.to_a), *(n.to_a)
62
+ end
63
+ n.last
64
+ end
65
+ end
66
+
67
+ # Close the polygon if needed
68
+ @edges.push Edge.new(@edges.last.last, @edges.first.first) unless @edges.empty? || (@edges.last.last == @edges.first.first)
69
+ end
70
+
71
+ private
72
+
73
+ def push_edge(*e)
74
+ @edges.push *e
75
+ @edges.uniq!
76
+ end
77
+ def push_vertex(*v)
78
+ @vertices.push *v
79
+ @vertices.uniq!
80
+ end
81
+ end
82
+ end
@@ -0,0 +1,23 @@
1
+ require_relative '../helper'
2
+ require_relative '../../lib/geometry/circle'
3
+
4
+ def Circle(*args)
5
+ Geometry::Circle.new(*args)
6
+ end
7
+
8
+ class CircleTest < Test::Unit::TestCase
9
+ must "create a Circle object from a Point and a radius" do
10
+ circle = Circle [1,2], 3
11
+ assert_kind_of(Geometry::Circle, circle)
12
+ end
13
+
14
+ must "have a center point accessor" do
15
+ circle = Circle [1,2], 3
16
+ assert_equal(circle.center, [1,2])
17
+ end
18
+
19
+ must "have a radius accessor" do
20
+ circle = Circle [1,2], 3
21
+ assert_equal(3, circle.radius)
22
+ end
23
+ end
@@ -0,0 +1,41 @@
1
+ require_relative '../helper'
2
+ require_relative '../../lib/geometry/edge'
3
+
4
+ def Edge(*args)
5
+ Geometry::Edge.new(*args)
6
+ end
7
+
8
+ class EdgeTest < Test::Unit::TestCase
9
+ Edge = Geometry::Edge
10
+
11
+ must "create an Edge object" do
12
+ edge = Geometry::Edge.new([0,0], [1,0])
13
+ assert_kind_of(Geometry::Edge, edge)
14
+ assert_equal(Geometry::Point[0,0], edge.first)
15
+ assert_equal(Geometry::Point[1,0], edge.last)
16
+ end
17
+ must "create swap endpoints in place" do
18
+ edge = Geometry::Edge.new([0,0], [1,0])
19
+ assert_kind_of(Geometry::Edge, edge)
20
+ edge.reverse!
21
+ assert_equal(Geometry::Point[1,0], edge.first)
22
+ assert_equal(Geometry::Point[0,0], edge.last)
23
+ end
24
+ must "handle equality" do
25
+ edge1 = Geometry::Edge.new([1,0], [0,1])
26
+ edge2 = Geometry::Edge.new([1,0], [0,1])
27
+ edge3 = Geometry::Edge.new([1,1], [5,5])
28
+ assert_equal(edge1, edge2)
29
+ assert_not_equal(edge1, edge3)
30
+ end
31
+
32
+ must "return the height of the edge" do
33
+ edge = Edge([0,0], [1,1])
34
+ assert_equal(1, edge.height)
35
+ end
36
+
37
+ must "return the width of the edge" do
38
+ edge = Edge([0,0], [1,1])
39
+ assert_equal(1, edge.width)
40
+ end
41
+ end
@@ -1,8 +1,9 @@
1
- require 'test/unit'
2
- require_relative 'test_unit_extensions'
1
+ require_relative 'helper'
3
2
  require_relative '../lib/geometry/point'
4
3
 
5
4
  class PointTest < Test::Unit::TestCase
5
+ Point = Geometry::Point
6
+
6
7
  must "create a Point object using list syntax" do
7
8
  point = Geometry::Point[2,1]
8
9
  assert_equal(2, point.size)
@@ -58,6 +59,24 @@ class PointTest < Test::Unit::TestCase
58
59
  assert_equal(6, point.y)
59
60
  assert_equal(7, point.z)
60
61
  end
62
+ must "compare equal" do
63
+ point1 = Geometry::Point[1,2]
64
+ point2 = Geometry::Point[1,2]
65
+ point3 = Geometry::Point[3,4]
66
+ assert_equal(point1, point2)
67
+ assert_not_equal(point2, point3)
68
+ end
69
+
70
+ must "compare equal to an array with equal elements" do
71
+ point1 = Point[1,2]
72
+ assert_equal(point1, [1,2])
73
+ end
74
+
75
+ must "not compare equal to an array with unequal elements" do
76
+ point1 = Point[1,2]
77
+ assert_not_equal(point1, [3,2])
78
+ end
79
+
61
80
  must "implement inspect" do
62
81
  point = Geometry::Point[8,9]
63
82
  assert_equal('Point[8, 9]', point.inspect)
@@ -0,0 +1,28 @@
1
+ require_relative '../helper'
2
+ require_relative '../../lib/geometry/polygon'
3
+
4
+ class PolygonTest < Test::Unit::TestCase
5
+ must "create a Polygon object with no arguments" do
6
+ polygon = Geometry::Polygon.new
7
+ assert_kind_of(Geometry::Polygon, polygon)
8
+ assert_equal(0, polygon.edges.size)
9
+ assert_equal(0, polygon.vertices.size)
10
+ end
11
+ must "create a Polygon object from array arguments" do
12
+ polygon = Geometry::Polygon.new([0,0], [1,0], [1,1], [0,1])
13
+ assert_kind_of(Geometry::Polygon, polygon)
14
+ assert_equal(4, polygon.edges.size)
15
+ assert_equal(4, polygon.vertices.size)
16
+ end
17
+ must "create closed polygons" do
18
+ polygon = Geometry::Polygon.new([0,0], [1,0], [1,1], [0,1])
19
+ assert_equal(polygon.edges.first.first, polygon.edges.last.last)
20
+ end
21
+ must "handle already closed polygons" do
22
+ polygon = Geometry::Polygon.new([0,0], [1,0], [1,1], [0,1], [0,0])
23
+ assert_kind_of(Geometry::Polygon, polygon)
24
+ assert_equal(4, polygon.edges.size)
25
+ assert_equal(4, polygon.vertices.size)
26
+ assert_equal(polygon.edges.first.first, polygon.edges.last.last)
27
+ end
28
+ end
@@ -0,0 +1,2 @@
1
+ require 'test/unit'
2
+ require_relative 'test_unit_extensions'
@@ -1,14 +1,13 @@
1
- require 'test/unit'
2
- require_relative 'test_unit_extensions'
1
+ require_relative 'helper'
3
2
  require_relative '../lib/geometry'
4
3
 
5
4
  class GeometryTest < Test::Unit::TestCase
6
5
  must "create a Point object" do
7
- point = Geometry.Point(2,1)
6
+ point = Geometry.point(2,1)
8
7
  assert_kind_of(Geometry::Point, point)
9
8
  end
10
9
  must "create a Line object" do
11
- line = Geometry.Line([0,0], [10,10])
10
+ line = Geometry.line([0,0], [10,10])
12
11
  assert_kind_of(Geometry::Line, line)
13
12
  assert_kind_of(Geometry::TwoPointLine, line)
14
13
  end
@@ -1,5 +1,4 @@
1
- require 'test/unit'
2
- require_relative 'test_unit_extensions'
1
+ require_relative 'helper'
3
2
  require_relative '../lib/geometry/line'
4
3
 
5
4
  class PointTest < Test::Unit::TestCase
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: geometry
3
3
  version: !ruby/object:Gem::Version
4
- version: '1'
4
+ version: '2'
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-03-09 00:00:00.000000000 Z
12
+ date: 2012-04-22 00:00:00.000000000 Z
13
13
  dependencies: []
14
14
  description: Geometric primitives and algorithms for Ruby
15
15
  email:
@@ -25,11 +25,18 @@ files:
25
25
  - Rakefile
26
26
  - geometry.gemspec
27
27
  - lib/geometry.rb
28
+ - lib/geometry/circle.rb
29
+ - lib/geometry/edge.rb
28
30
  - lib/geometry/line.rb
29
31
  - lib/geometry/point.rb
32
+ - lib/geometry/polygon.rb
33
+ - test/geometry/circle.rb
34
+ - test/geometry/edge.rb
35
+ - test/geometry/point.rb
36
+ - test/geometry/polygon.rb
37
+ - test/helper.rb
30
38
  - test/test_geometry.rb
31
39
  - test/test_line.rb
32
- - test/test_point.rb
33
40
  - test/test_unit_extensions.rb
34
41
  homepage: http://github.com/bfoz/geometry
35
42
  licenses: []
@@ -56,7 +63,12 @@ signing_key:
56
63
  specification_version: 3
57
64
  summary: Geometric primitives and algoritms
58
65
  test_files:
66
+ - test/geometry/circle.rb
67
+ - test/geometry/edge.rb
68
+ - test/geometry/point.rb
69
+ - test/geometry/polygon.rb
70
+ - test/helper.rb
59
71
  - test/test_geometry.rb
60
72
  - test/test_line.rb
61
- - test/test_point.rb
62
73
  - test/test_unit_extensions.rb
74
+ has_rdoc: