geometry 4 → 5
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 +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
|