geometry 4 → 5
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +0 -3
- data/README.markdown +4 -2
- data/Rakefile +0 -8
- data/geometry.gemspec +1 -1
- data/lib/geometry.rb +3 -0
- data/lib/geometry/arc.rb +59 -0
- data/lib/geometry/circle.rb +72 -6
- data/lib/geometry/cluster_factory.rb +15 -0
- data/lib/geometry/edge.rb +61 -0
- data/lib/geometry/path.rb +55 -0
- data/lib/geometry/point.rb +21 -10
- data/lib/geometry/point_zero.rb +4 -4
- data/lib/geometry/polygon.rb +145 -46
- data/lib/geometry/polyline.rb +212 -0
- data/lib/geometry/rectangle.rb +3 -12
- data/lib/geometry/rotation.rb +29 -2
- data/lib/geometry/size_zero.rb +4 -4
- data/lib/geometry/square.rb +7 -7
- data/lib/geometry/triangle.rb +78 -0
- data/lib/geometry/vector.rb +18 -2
- data/test/geometry/arc.rb +9 -0
- data/test/geometry/circle.rb +49 -13
- data/test/geometry/edge.rb +53 -0
- data/test/geometry/path.rb +67 -0
- data/test/geometry/point.rb +27 -2
- data/test/geometry/polygon.rb +101 -0
- data/test/geometry/polyline.rb +91 -0
- data/test/geometry/rotation.rb +5 -0
- data/test/geometry/triangle.rb +32 -0
- data/test/geometry/vector.rb +6 -0
- metadata +12 -3
data/lib/geometry/rectangle.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
require_relative 'cluster_factory'
|
1
2
|
require_relative 'edge'
|
2
3
|
require_relative 'point'
|
3
4
|
require_relative 'size'
|
@@ -19,6 +20,8 @@ The {Rectangle} class cluster represents your typical arrangement of 4 corners a
|
|
19
20
|
=end
|
20
21
|
|
21
22
|
class Rectangle
|
23
|
+
include ClusterFactory
|
24
|
+
|
22
25
|
# @return [Point] The {Rectangle}'s center
|
23
26
|
attr_reader :center
|
24
27
|
# @return [Number] Height of the {Rectangle}
|
@@ -30,10 +33,6 @@ The {Rectangle} class cluster represents your typical arrangement of 4 corners a
|
|
30
33
|
# @return [Number] Width of the {Rectangle}
|
31
34
|
attr_reader :width
|
32
35
|
|
33
|
-
class << self
|
34
|
-
alias :original_new :new
|
35
|
-
end
|
36
|
-
|
37
36
|
# @overload new(width, height)
|
38
37
|
# Creates a {Rectangle} of the given width and height, centered on the origin
|
39
38
|
# @param [Number] height Height
|
@@ -151,10 +150,6 @@ The {Rectangle} class cluster represents your typical arrangement of 4 corners a
|
|
151
150
|
# @return [Size] The {Size} of the {Rectangle}
|
152
151
|
attr_accessor :size
|
153
152
|
|
154
|
-
def self.new(*args)
|
155
|
-
original_new(*args)
|
156
|
-
end
|
157
|
-
|
158
153
|
# @overload new(width, height)
|
159
154
|
# Creates a {Rectangle} of the given width and height, centered on the origin
|
160
155
|
# @param [Number] height Height
|
@@ -220,10 +215,6 @@ The {Rectangle} class cluster represents your typical arrangement of 4 corners a
|
|
220
215
|
# @return [Size] The {Size} of the {Rectangle}
|
221
216
|
attr_accessor :size
|
222
217
|
|
223
|
-
def self.new(*args)
|
224
|
-
original_new(*args)
|
225
|
-
end
|
226
|
-
|
227
218
|
# @overload new(width, height)
|
228
219
|
# Creates a {Rectangle} of the given width and height with its origin at [0,0]
|
229
220
|
# @param [Number] height Height
|
data/lib/geometry/rotation.rb
CHANGED
@@ -1,9 +1,11 @@
|
|
1
|
+
require 'matrix'
|
2
|
+
|
1
3
|
module Geometry
|
2
4
|
=begin
|
3
5
|
A generalized representation of a rotation transformation.
|
4
6
|
=end
|
5
7
|
class Rotation
|
6
|
-
#
|
8
|
+
# @attribute [r] dimensions
|
7
9
|
# @return [Integer]
|
8
10
|
attr_reader :dimensions
|
9
11
|
attr_reader :x, :y, :z
|
@@ -34,13 +36,38 @@ A generalized representation of a rotation transformation.
|
|
34
36
|
|
35
37
|
raise ArgumentError, "Dimensionality mismatch" unless all_axes_options.first.size <= @dimensions
|
36
38
|
if all_axes_options.first.size < @dimensions
|
37
|
-
@x, @y, @z = [@x, @y, @z].map {|a| (a && (a.size < @dimensions)) ? Array.new(@dimensions) {|i| a[i] || 0 } : a }
|
39
|
+
@x, @y, @z = [@x, @y, @z].map {|a| (a && (a.size != 0) && (a.size < @dimensions)) ? Array.new(@dimensions) {|i| a[i] || 0 } : a }
|
38
40
|
end
|
41
|
+
|
42
|
+
raise ArgumentError, "Too many axes specified (expected #{@dimensions - 1} but got #{all_axes_options.size}" unless all_axes_options.size == (@dimensions - 1)
|
39
43
|
end
|
40
44
|
end
|
41
45
|
|
42
46
|
def identity?
|
43
47
|
(!@x && !@y && !@z) || ([@x, @y, @z].select {|a| a}.all? {|a| a.respond_to?(:magnitude) ? (1 == a.magnitude) : (1 == a.size)})
|
44
48
|
end
|
49
|
+
|
50
|
+
# @attribute [r] matrix
|
51
|
+
# @return [Matrix]
|
52
|
+
def matrix
|
53
|
+
# Force all axes to be Vectors
|
54
|
+
x,y,z = [@x, @y, @z].map {|a| a.is_a?(Array) ? Vector[*a] : a}
|
55
|
+
|
56
|
+
# Force all axes to exist
|
57
|
+
if x and y
|
58
|
+
z = x ** y
|
59
|
+
elsif x and z
|
60
|
+
y = x ** z
|
61
|
+
elsif y and z
|
62
|
+
x = y ** z
|
63
|
+
end
|
64
|
+
|
65
|
+
rows = []
|
66
|
+
[x, y, z].each_with_index {|a, i| rows.push(a.to_a) if i < @dimensions }
|
67
|
+
|
68
|
+
raise ArgumentError, "Number of axes must match the dimensions of each axis" unless @dimensions == rows.size
|
69
|
+
|
70
|
+
Matrix[*rows]
|
71
|
+
end
|
45
72
|
end
|
46
73
|
end
|
data/lib/geometry/size_zero.rb
CHANGED
@@ -29,9 +29,9 @@ everything else, regardless of dimensionality.
|
|
29
29
|
end
|
30
30
|
end
|
31
31
|
|
32
|
-
#
|
32
|
+
# @group Arithmetic
|
33
33
|
|
34
|
-
#
|
34
|
+
# @group Unary operators
|
35
35
|
def +@
|
36
36
|
self
|
37
37
|
end
|
@@ -39,7 +39,7 @@ everything else, regardless of dimensionality.
|
|
39
39
|
def -@
|
40
40
|
self
|
41
41
|
end
|
42
|
-
#
|
42
|
+
# @endgroup
|
43
43
|
|
44
44
|
def +(other)
|
45
45
|
other
|
@@ -62,7 +62,7 @@ everything else, regardless of dimensionality.
|
|
62
62
|
raise ZeroDivisionError if 0 == other
|
63
63
|
self
|
64
64
|
end
|
65
|
-
#
|
65
|
+
# @endgroup
|
66
66
|
|
67
67
|
end
|
68
68
|
end
|
data/lib/geometry/square.rb
CHANGED
@@ -31,7 +31,7 @@ The {Square} class cluster is like the {Rectangle} class cluster, but not longer
|
|
31
31
|
end
|
32
32
|
|
33
33
|
# !@group Accessors
|
34
|
-
#
|
34
|
+
# @attribute [r] origin
|
35
35
|
# @return [Point] The lower left corner
|
36
36
|
def origin
|
37
37
|
@points.first
|
@@ -46,12 +46,12 @@ The {Square} class cluster is like the {Rectangle} class cluster, but not longer
|
|
46
46
|
min, max = @points.minmax {|a,b| a.x <=> b.x}
|
47
47
|
max.x - min.x
|
48
48
|
end
|
49
|
-
#
|
49
|
+
# @endgroup
|
50
50
|
end
|
51
51
|
|
52
52
|
# A {Square} created with a center point and a size
|
53
53
|
class CenteredSquare < Square
|
54
|
-
#
|
54
|
+
# @attribute [r] center
|
55
55
|
# @return [Point] The center of the {Square}
|
56
56
|
attr_reader :center
|
57
57
|
|
@@ -62,14 +62,14 @@ The {Square} class cluster is like the {Rectangle} class cluster, but not longer
|
|
62
62
|
@size = size
|
63
63
|
end
|
64
64
|
|
65
|
-
#
|
66
|
-
#
|
65
|
+
# @group Accessors
|
66
|
+
# @attribute [r] origin
|
67
67
|
# @return [Point] The lower left corner
|
68
68
|
def origin
|
69
69
|
Point[@center.x - size/2, @center.y - size/2]
|
70
70
|
end
|
71
71
|
|
72
|
-
#
|
72
|
+
# @attribute [r] points
|
73
73
|
# @return [Array<Point>] The {Square}'s four points (clockwise)
|
74
74
|
def points
|
75
75
|
half_size = @size/2
|
@@ -88,7 +88,7 @@ The {Square} class cluster is like the {Rectangle} class cluster, but not longer
|
|
88
88
|
def width
|
89
89
|
@size
|
90
90
|
end
|
91
|
-
#
|
91
|
+
# @endgroup
|
92
92
|
end
|
93
93
|
|
94
94
|
# A {Square} created with an origin point and a size
|
@@ -0,0 +1,78 @@
|
|
1
|
+
require_relative 'cluster_factory'
|
2
|
+
require_relative 'point'
|
3
|
+
|
4
|
+
module Geometry
|
5
|
+
=begin rdoc
|
6
|
+
A {http://en.wikipedia.org/wiki/Triangle Triangle} is not a square.
|
7
|
+
|
8
|
+
== Usage
|
9
|
+
A right {Triangle} with its right angle at the origin and sides of length 1
|
10
|
+
triangle = Geometry::Triangle.new [0,0], [1,0], [0,1]
|
11
|
+
|
12
|
+
An isoscoles right {Triangle} created with an origin and leg length
|
13
|
+
triangle = Geometry::Triangle.new [0,0], 1
|
14
|
+
=end
|
15
|
+
|
16
|
+
# @abstract Factory class that instantiates the appropriate subclasses
|
17
|
+
class Triangle
|
18
|
+
|
19
|
+
include ClusterFactory
|
20
|
+
|
21
|
+
# @overload new(point0, point1, point2)
|
22
|
+
# Contruct a {ScaleneTriangle} using three {Point}s
|
23
|
+
# @param [Point] point0 The first vertex of the {Triangle}
|
24
|
+
# @param [Point] point1 Another vertex of the {Triangle}
|
25
|
+
# @param [Point] point2 The final vertex of the {Triangle}
|
26
|
+
# @overload new(point, length)
|
27
|
+
# Construct a {RightTriangle} using a {Point} and the lengths of the sides
|
28
|
+
# @param [Point] point The location of the vertex at {Triangle}'s right angle
|
29
|
+
# @param [Number] base The length of the {Triangle}'s base leg
|
30
|
+
# @param [Number] height The length of the {Triangle}'s vertical leg
|
31
|
+
def self.new(*args)
|
32
|
+
if args.size == 3
|
33
|
+
ScaleneTriangle.new *args
|
34
|
+
elsif args.size == 2
|
35
|
+
RightTriangle.new args[0], args[1], args[1]
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
# {http://en.wikipedia.org/wiki/Equilateral_triangle Equilateral Triangle}
|
41
|
+
class EquilateralTriangle < Triangle
|
42
|
+
def self.new(*args)
|
43
|
+
original_new(*args)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
class IsoscelesTriangle < Triangle
|
48
|
+
def self.new(*args)
|
49
|
+
original_new(*args)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
# {http://en.wikipedia.org/wiki/Right_triangle Right Triangle}
|
54
|
+
class RightTriangle < Triangle
|
55
|
+
attr_reader :origin, :base, :height
|
56
|
+
|
57
|
+
# Construct a Right Triangle given a {Point} and the leg lengths
|
58
|
+
def initialize(origin, base, height)
|
59
|
+
@origin = Point[origin]
|
60
|
+
@base, @height = base, height
|
61
|
+
end
|
62
|
+
|
63
|
+
# An array of points corresponding to the vertices of the {Triangle} (clockwise)
|
64
|
+
# @return [Array<Point>] Vertices
|
65
|
+
def points
|
66
|
+
[@origin, @origin + Point[0,@height], @origin + Point[@base,0]]
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
class ScaleneTriangle < Triangle
|
71
|
+
attr_reader :points
|
72
|
+
|
73
|
+
# Construct a scalene {Triangle}
|
74
|
+
def initialize(point0, point1, point2)
|
75
|
+
@points = [point0, point1, point2].map {|p| Point[p] }
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
data/lib/geometry/vector.rb
CHANGED
@@ -2,7 +2,7 @@ require 'matrix'
|
|
2
2
|
|
3
3
|
# Monkeypatch Vector to overcome some deficiencies
|
4
4
|
class Vector
|
5
|
-
#
|
5
|
+
# @group Unary operators
|
6
6
|
def +@
|
7
7
|
self
|
8
8
|
end
|
@@ -10,5 +10,21 @@ class Vector
|
|
10
10
|
def -@
|
11
11
|
Vector[*(@elements.map {|e| -e })]
|
12
12
|
end
|
13
|
-
#
|
13
|
+
# @endgroup
|
14
|
+
|
15
|
+
# Cross-product of two {Vector}s
|
16
|
+
# @return [Vector]
|
17
|
+
def cross(other)
|
18
|
+
Vector.Raise ErrDimensionMismatch unless @elements.size == other.size
|
19
|
+
|
20
|
+
case @elements.size
|
21
|
+
when 0 then raise ArgumentError, "Can't multply zero-length Vectors"
|
22
|
+
when 1 then @elements.first * other.first
|
23
|
+
when 2 then @elements.first * other[1] - @elements.last * other.first
|
24
|
+
when 3 then Vector[ @elements[1]*other[2] - @elements[2]*other[1],
|
25
|
+
@elements[2]*other[0] - @elements[0]*other[2],
|
26
|
+
@elements[0]*other[1] - @elements[1]*other[0]]
|
27
|
+
end
|
28
|
+
end
|
29
|
+
alias ** cross
|
14
30
|
end
|
data/test/geometry/arc.rb
CHANGED
@@ -10,4 +10,13 @@ describe Geometry::Arc do
|
|
10
10
|
arc.start_angle.must_equal 0
|
11
11
|
arc.end_angle.must_equal 90
|
12
12
|
end
|
13
|
+
|
14
|
+
it "must create an Arc from center, start and end points" do
|
15
|
+
arc = Geometry::Arc.new [1,2], [3,4], [5,6]
|
16
|
+
arc.must_be_kind_of Geometry::Arc
|
17
|
+
arc.center.must_equal Point[1,2]
|
18
|
+
arc.first.must_equal Point[3,4]
|
19
|
+
arc.last.must_equal Point[5,6]
|
20
|
+
end
|
21
|
+
|
13
22
|
end
|
data/test/geometry/circle.rb
CHANGED
@@ -1,23 +1,59 @@
|
|
1
1
|
require 'minitest/autorun'
|
2
2
|
require 'geometry/circle'
|
3
3
|
|
4
|
-
def Circle(*args)
|
5
|
-
Geometry::Circle.new(*args)
|
6
|
-
end
|
7
|
-
|
8
4
|
describe Geometry::Circle do
|
9
|
-
|
10
|
-
|
11
|
-
|
5
|
+
Circle = Geometry::Circle
|
6
|
+
|
7
|
+
describe "when constructed with center and radius arguments" do
|
8
|
+
let(:circle) { Circle.new [1,2], 3 }
|
9
|
+
|
10
|
+
it "must create a Circle" do
|
11
|
+
circle.must_be_instance_of(Circle)
|
12
|
+
end
|
13
|
+
|
14
|
+
it "must have a center point accessor" do
|
15
|
+
circle.center.must_equal Point[1,2]
|
16
|
+
end
|
17
|
+
|
18
|
+
it "must have a radius accessor" do
|
19
|
+
circle.radius.must_equal 3
|
20
|
+
end
|
12
21
|
end
|
13
22
|
|
14
|
-
|
15
|
-
circle
|
16
|
-
|
23
|
+
describe "when constructed with named center and radius arguments" do
|
24
|
+
let(:circle) { Circle.new :center => [1,2], :radius => 3 }
|
25
|
+
|
26
|
+
it "must create a Circle" do
|
27
|
+
circle.must_be_instance_of(Circle)
|
28
|
+
end
|
29
|
+
|
30
|
+
it "must have a center point accessor" do
|
31
|
+
circle.center.must_equal Point[1,2]
|
32
|
+
end
|
33
|
+
|
34
|
+
it "must have a radius accessor" do
|
35
|
+
circle.radius.must_equal 3
|
36
|
+
end
|
17
37
|
end
|
18
38
|
|
19
|
-
|
20
|
-
circle
|
21
|
-
|
39
|
+
describe "when constructed with a center and diameter" do
|
40
|
+
let(:circle) { Circle.new [1,2], :diameter => 4 }
|
41
|
+
|
42
|
+
it "must be a CenterDiameterCircle" do
|
43
|
+
circle.must_be_instance_of(Geometry::CenterDiameterCircle)
|
44
|
+
circle.must_be_kind_of(Circle)
|
45
|
+
end
|
46
|
+
|
47
|
+
it "must have a center" do
|
48
|
+
circle.center.must_equal Point[1,2]
|
49
|
+
end
|
50
|
+
|
51
|
+
it "must have a diameter" do
|
52
|
+
circle.diameter.must_equal 4
|
53
|
+
end
|
54
|
+
|
55
|
+
it "must calculate the correct radius" do
|
56
|
+
circle.radius.must_equal 2
|
57
|
+
end
|
22
58
|
end
|
23
59
|
end
|
data/test/geometry/edge.rb
CHANGED
@@ -38,4 +38,57 @@ describe Geometry::Edge do
|
|
38
38
|
edge = Edge([0,0], [1,1])
|
39
39
|
assert_equal(1, edge.width)
|
40
40
|
end
|
41
|
+
|
42
|
+
it "must convert an Edge to a Vector" do
|
43
|
+
Edge.new([0,0], [1,0]).vector.must_equal Vector[1,0]
|
44
|
+
end
|
45
|
+
|
46
|
+
it "must return the normalized direction of a vector" do
|
47
|
+
Edge.new([0,0], [1,0]).direction.must_equal Vector[1,0]
|
48
|
+
end
|
49
|
+
|
50
|
+
it "must return true for parallel edges" do
|
51
|
+
Edge.new([0,0], [1,0]).parallel?(Edge.new([0,0], [1,0])).must_equal 1
|
52
|
+
Edge.new([0,0], [1,0]).parallel?(Edge.new([1,0], [2,0])).must_equal 1
|
53
|
+
Edge.new([0,0], [1,0]).parallel?(Edge.new([3,0], [4,0])).must_equal 1
|
54
|
+
Edge.new([0,0], [1,0]).parallel?(Edge.new([3,1], [4,1])).must_equal 1
|
55
|
+
end
|
56
|
+
|
57
|
+
it "must return false for non-parallel edges" do
|
58
|
+
Edge.new([0,0], [2,0]).parallel?(Edge.new([1,-1], [1,1])).must_equal false
|
59
|
+
end
|
60
|
+
|
61
|
+
describe "when finding an intersection" do
|
62
|
+
it "must find the intersection of two end-intersecting Edges" do
|
63
|
+
intersection = Edge.new([0,0],[1,1]).intersection(Edge.new([0,1],[1,1]))
|
64
|
+
intersection.must_be_kind_of Geometry::Point
|
65
|
+
intersection.must_equal Geometry::Point[1,1]
|
66
|
+
end
|
67
|
+
|
68
|
+
it "must find the itersection of two crossed Edges" do
|
69
|
+
edge1 = Edge.new [0.0, 0], [2.0, 2.0]
|
70
|
+
edge2 = Edge.new [2.0, 0], [0.0, 2.0]
|
71
|
+
intersection = edge1.intersection edge2
|
72
|
+
intersection.must_be_kind_of Geometry::Point
|
73
|
+
intersection.must_equal Geometry::Point[1,1]
|
74
|
+
end
|
75
|
+
|
76
|
+
it "must return nil for two edges that do not intersect" do
|
77
|
+
Edge.new([0,0],[1,0]).intersection(Edge.new([0,1],[1,1])).must_equal nil
|
78
|
+
end
|
79
|
+
|
80
|
+
it "must return true for two collinear and overlapping edges" do
|
81
|
+
Edge.new([0,0],[2,0]).intersection(Edge.new([1,0],[3,0])).must_equal true
|
82
|
+
end
|
83
|
+
|
84
|
+
it "must return false for collinear but non-overlapping edges" do
|
85
|
+
Edge.new([0,0],[2,0]).intersection(Edge.new([3,0],[4,0])).must_equal false
|
86
|
+
Edge.new([0,0],[0,2]).intersection(Edge.new([0,3],[0,4])).must_equal false
|
87
|
+
end
|
88
|
+
|
89
|
+
it "must return nil for two parallel but not collinear edges" do
|
90
|
+
Edge.new([0,0],[2,0]).intersection(Edge.new([1,1],[3,1])).must_equal nil
|
91
|
+
end
|
92
|
+
|
93
|
+
end
|
41
94
|
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
require 'minitest/autorun'
|
2
|
+
require 'geometry/path'
|
3
|
+
|
4
|
+
describe Geometry::Path do
|
5
|
+
describe "construction" do
|
6
|
+
it "must create a Path with no arguments" do
|
7
|
+
path = Geometry::Path.new
|
8
|
+
path.must_be_kind_of Geometry::Path
|
9
|
+
path.elements.wont_be_nil
|
10
|
+
path.elements.size.must_equal 0
|
11
|
+
end
|
12
|
+
|
13
|
+
it "must create a Path from Points" do
|
14
|
+
path = Geometry::Path.new Point[1,1], Point[2,2], Point[3,3]
|
15
|
+
path.elements.size.must_equal 2
|
16
|
+
path.elements.each {|a| a.must_be_kind_of Geometry::Edge }
|
17
|
+
end
|
18
|
+
|
19
|
+
it "with connected Edges" do
|
20
|
+
path = Geometry::Path.new Edge.new([1,1], [2,2]), Edge.new([2,2], [3,3])
|
21
|
+
path.elements.size.must_equal 2
|
22
|
+
path.elements.each {|a| a.must_be_kind_of Geometry::Edge }
|
23
|
+
end
|
24
|
+
|
25
|
+
it "with disjoint Edges" do
|
26
|
+
path = Geometry::Path.new Edge.new([1,1], [2,2]), Edge.new([3,3], [4,4])
|
27
|
+
path.elements.size.must_equal 3
|
28
|
+
path.elements.each {|a| a.must_be_kind_of Geometry::Edge }
|
29
|
+
end
|
30
|
+
|
31
|
+
it "with Points and Arcs" do
|
32
|
+
path = Geometry::Path.new [0,0], [1.0,0.0], Geometry::Arc.new([1,1], 1, -90*Math::PI/180, 0), [2.0,1.0], [1,2]
|
33
|
+
path.elements.size.must_equal 3
|
34
|
+
path.elements[0].must_be_kind_of Geometry::Edge
|
35
|
+
path.elements[1].must_be_kind_of Geometry::Arc
|
36
|
+
path.elements[2].must_be_kind_of Geometry::Edge
|
37
|
+
end
|
38
|
+
|
39
|
+
it "with Edges and Arcs" do
|
40
|
+
path = Geometry::Path.new Edge.new([0,0], [1.0,0.0]), Geometry::Arc.new([1,1], 1, -90*Math::PI/180, 0), Edge.new([2.0,1.0], [1,2])
|
41
|
+
path.elements.size.must_equal 3
|
42
|
+
path.elements[0].must_be_kind_of Geometry::Edge
|
43
|
+
path.elements[1].must_be_kind_of Geometry::Arc
|
44
|
+
path.elements[2].must_be_kind_of Geometry::Edge
|
45
|
+
end
|
46
|
+
|
47
|
+
it "with disjoint Edges and Arcs" do
|
48
|
+
path = Geometry::Path.new Edge.new([0,0], [1,0]), Geometry::Arc.new([2,1], 1, -90*Math::PI/180, 0), Edge.new([3,1], [1,2])
|
49
|
+
path.elements.size.must_equal 4
|
50
|
+
path.elements[0].must_be_kind_of Geometry::Edge
|
51
|
+
path.elements[1].must_be_kind_of Geometry::Edge
|
52
|
+
path.elements[2].must_be_kind_of Geometry::Arc
|
53
|
+
path.elements[3].must_be_kind_of Geometry::Edge
|
54
|
+
end
|
55
|
+
|
56
|
+
it "with disjoint Arcs" do
|
57
|
+
path = Geometry::Path.new Geometry::Arc.new([2,1], 1, -90*Math::PI/180, 0), Geometry::Arc.new([3,1], 1, -90*Math::PI/180, 0)
|
58
|
+
path.elements.size.must_equal 3
|
59
|
+
path.elements[0].must_be_kind_of Geometry::Arc
|
60
|
+
path.elements[1].must_be_kind_of Geometry::Edge
|
61
|
+
path.elements[2].must_be_kind_of Geometry::Arc
|
62
|
+
|
63
|
+
path.elements[0].last.must_equal path.elements[1].first
|
64
|
+
end
|
65
|
+
|
66
|
+
end
|
67
|
+
end
|