triangular 0.0.1
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 +3 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +25 -0
- data/MIT-LICENSE +20 -0
- data/README.rdoc +31 -0
- data/Rakefile +11 -0
- data/examples/example_files/test_cube.stl +58 -0
- data/examples/example_files/y-axis-spacer.stl +310 -0
- data/examples/slice_example.rb +9 -0
- data/lib/triangular.rb +19 -0
- data/lib/triangular/facet.rb +81 -0
- data/lib/triangular/line.rb +38 -0
- data/lib/triangular/point.rb +33 -0
- data/lib/triangular/polyline.rb +24 -0
- data/lib/triangular/solid.rb +45 -0
- data/lib/triangular/vector.rb +4 -0
- data/lib/triangular/version.rb +3 -0
- data/lib/triangular/vertex.rb +44 -0
- data/spec/facet_spec.rb +257 -0
- data/spec/fixtures/test_cube.stl +58 -0
- data/spec/fixtures/y-axis-spacer.stl +310 -0
- data/spec/line_spec.rb +190 -0
- data/spec/point_spec.rb +67 -0
- data/spec/polyline_spec.rb +20 -0
- data/spec/solid_spec.rb +85 -0
- data/spec/spec_helper.rb +4 -0
- data/spec/triangular_spec.rb +22 -0
- data/spec/vertex_spec.rb +44 -0
- data/triangular.gemspec +23 -0
- metadata +104 -0
@@ -0,0 +1,9 @@
|
|
1
|
+
require "bundler/setup"
|
2
|
+
require "triangular"
|
3
|
+
|
4
|
+
solid = Triangular.parse_file("#{File.dirname(__FILE__)}/example_files/y-axis-spacer.stl")
|
5
|
+
polyline = solid.slice_at_z(-0.5)
|
6
|
+
|
7
|
+
File.open(File.expand_path("~/Desktop/slice.svg"), "w+") do |file|
|
8
|
+
file.puts polyline.to_svg(10, 10)
|
9
|
+
end
|
data/lib/triangular.rb
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'triangular/point'
|
2
|
+
require 'triangular/vertex'
|
3
|
+
require 'triangular/vector'
|
4
|
+
require 'triangular/line'
|
5
|
+
require 'triangular/polyline'
|
6
|
+
require 'triangular/facet'
|
7
|
+
require 'triangular/solid'
|
8
|
+
|
9
|
+
module Triangular
|
10
|
+
def self.parse(string)
|
11
|
+
Solid.parse(string)
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.parse_file(path)
|
15
|
+
File.open(path) do |file|
|
16
|
+
Solid.parse(file.read)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,81 @@
|
|
1
|
+
module Triangular
|
2
|
+
class Facet
|
3
|
+
|
4
|
+
attr_accessor :normal, :vertices
|
5
|
+
|
6
|
+
def initialize(normal = nil, *args)
|
7
|
+
@normal = normal
|
8
|
+
@vertices = args
|
9
|
+
end
|
10
|
+
|
11
|
+
def to_s
|
12
|
+
output = "facet normal #{@normal.to_s}\n"
|
13
|
+
output += "outer loop\n"
|
14
|
+
@vertices.each do |vertex|
|
15
|
+
output += vertex.to_s + "\n"
|
16
|
+
end
|
17
|
+
output += "endloop\n"
|
18
|
+
output += "endfacet\n"
|
19
|
+
|
20
|
+
output
|
21
|
+
end
|
22
|
+
|
23
|
+
def lines
|
24
|
+
[
|
25
|
+
Line.new(@vertices[0], @vertices[1]),
|
26
|
+
Line.new(@vertices[1], @vertices[2]),
|
27
|
+
Line.new(@vertices[2], @vertices[0])
|
28
|
+
]
|
29
|
+
end
|
30
|
+
|
31
|
+
def intersection_at_z(z_plane)
|
32
|
+
return nil if @vertices.count{|vertex| vertex.z == z_plane} > 2
|
33
|
+
|
34
|
+
intersection_points = []
|
35
|
+
lines.each do |line|
|
36
|
+
intersection_points << line.intersection_at_z(z_plane) unless line.start.z == z_plane && line.end.z == z_plane
|
37
|
+
end
|
38
|
+
|
39
|
+
intersection_points.compact!
|
40
|
+
if intersection_points.empty?
|
41
|
+
nil
|
42
|
+
elsif intersection_points.count == 2
|
43
|
+
Line.new(intersection_points[0], intersection_points[1])
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def self.parse(string)
|
48
|
+
facets = []
|
49
|
+
|
50
|
+
string.scan(self.pattern) do |match_data|
|
51
|
+
facet = self.new
|
52
|
+
|
53
|
+
facet.vertices << Vertex.parse(match_data[4])
|
54
|
+
facet.vertices << Vertex.parse(match_data[9])
|
55
|
+
facet.vertices << Vertex.parse(match_data[14])
|
56
|
+
|
57
|
+
facet.normal = Vector.parse(match_data[0])
|
58
|
+
|
59
|
+
facets << facet
|
60
|
+
end
|
61
|
+
|
62
|
+
if facets.length == 1
|
63
|
+
facets.first
|
64
|
+
else
|
65
|
+
facets
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def self.pattern
|
70
|
+
/
|
71
|
+
\s* facet\snormal\s (?<normal> #{Point.pattern})\s
|
72
|
+
\s* outer\sloop\s
|
73
|
+
\s* (?<vertex1> #{Vertex.pattern})
|
74
|
+
\s* (?<vertex2> #{Vertex.pattern})
|
75
|
+
\s* (?<vertex3> #{Vertex.pattern})
|
76
|
+
\s* endloop\s
|
77
|
+
\s* endfacet\s
|
78
|
+
/x
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
module Triangular
|
2
|
+
class Line
|
3
|
+
|
4
|
+
attr_accessor :start, :end
|
5
|
+
|
6
|
+
def initialize(line_start, line_end)
|
7
|
+
@start = line_start
|
8
|
+
@end = line_end
|
9
|
+
end
|
10
|
+
|
11
|
+
def ==(other)
|
12
|
+
return false unless other.is_a?(Line)
|
13
|
+
self.start == other.start && self.end == other.end
|
14
|
+
end
|
15
|
+
|
16
|
+
def intersects_z?(z_plane)
|
17
|
+
if (@start.z >= z_plane && @end.z <= z_plane) || (@start.z <= z_plane && @end.z >= z_plane)
|
18
|
+
true
|
19
|
+
else
|
20
|
+
false
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def intersection_at_z(z_plane)
|
25
|
+
return nil if !self.intersects_z?(z_plane)
|
26
|
+
raise "Cannot calculate intersection for line that lies on the target Z plane" if @start.z == z_plane && @end.z == z_plane
|
27
|
+
|
28
|
+
x_intersect = (@end.x - @start.x) / (@end.z - @start.z) * (z_plane - @start.z) + @start.x
|
29
|
+
y_intersect = (@end.y - @start.y) / (@end.z - @start.z) * (z_plane - @start.z) + @start.y
|
30
|
+
|
31
|
+
Point.new(x_intersect, y_intersect, z_plane)
|
32
|
+
end
|
33
|
+
|
34
|
+
def to_svg_path
|
35
|
+
"<path d=\"M #{@start.x} #{@start.y} L #{@end.x} #{@end.y}\" fill=\"none\" stroke=\"black\" stroke-width=\"1\" />"
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module Triangular
|
2
|
+
class Point
|
3
|
+
|
4
|
+
attr_accessor :x, :y, :z
|
5
|
+
|
6
|
+
def initialize(x, y, z)
|
7
|
+
@x = x
|
8
|
+
@y = y
|
9
|
+
@z = z
|
10
|
+
end
|
11
|
+
|
12
|
+
def to_s
|
13
|
+
"#{@x.to_f} #{@y.to_f} #{@z.to_f}"
|
14
|
+
end
|
15
|
+
|
16
|
+
def ==(other)
|
17
|
+
return false unless other.is_a?(Point)
|
18
|
+
self.x == other.x && self.y == other.y && self.z == other.z
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.parse(string)
|
22
|
+
string.strip!
|
23
|
+
match_data = string.match(self.pattern)
|
24
|
+
|
25
|
+
self.new(match_data[:x].to_f, match_data[:y].to_f, match_data[:z].to_f)
|
26
|
+
end
|
27
|
+
|
28
|
+
def self.pattern
|
29
|
+
/(?<x>-?\d+.\d+(e\-?\d+)?)\s(?<y>-?\d+.\d+(e\-?\d+)?)\s(?<z>-?\d+.\d+(e\-?\d+)?)/
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module Triangular
|
2
|
+
class Polyline
|
3
|
+
|
4
|
+
attr_accessor :lines
|
5
|
+
|
6
|
+
def initialize(lines)
|
7
|
+
@lines = lines
|
8
|
+
end
|
9
|
+
|
10
|
+
def to_svg(x_offset = 20, y_offset = 20)
|
11
|
+
output = '<?xml version="1.0" standalone="no"?>' + "\n"
|
12
|
+
output << '<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">' + "\n"
|
13
|
+
output << '<svg xmlns="http://www.w3.org/2000/svg" version="1.1">' + "\n"
|
14
|
+
output << " <g transform=\"translate(#{x_offset},#{y_offset})\">\n"
|
15
|
+
|
16
|
+
@lines.each do |line|
|
17
|
+
output << " " + line.to_svg_path + "\n"
|
18
|
+
end
|
19
|
+
|
20
|
+
output << ' </g>' + "\n"
|
21
|
+
output << '</svg>'
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
module Triangular
|
2
|
+
class Solid
|
3
|
+
|
4
|
+
attr_accessor :name, :facets
|
5
|
+
|
6
|
+
def initialize(name, *args)
|
7
|
+
@name = name
|
8
|
+
@facets = args
|
9
|
+
end
|
10
|
+
|
11
|
+
def to_s
|
12
|
+
output = "solid #{@name || ""}\n"
|
13
|
+
@facets.each do |facet|
|
14
|
+
output << "facet normal #{facet.normal.x.to_f} #{facet.normal.y.to_f} #{facet.normal.z.to_f}\n"
|
15
|
+
output << "outer loop\n"
|
16
|
+
facet.vertices.each do |vertex|
|
17
|
+
output <<"vertex #{vertex.x.to_f} #{vertex.y.to_f} #{vertex.z.to_f}\n"
|
18
|
+
end
|
19
|
+
output << "endloop\n"
|
20
|
+
output << "endfacet\n"
|
21
|
+
end
|
22
|
+
output << "endsolid #{@name || ""}\n"
|
23
|
+
|
24
|
+
output
|
25
|
+
end
|
26
|
+
|
27
|
+
def slice_at_z(z_plane)
|
28
|
+
lines = @facets.map {|facet| facet.intersection_at_z(z_plane) }
|
29
|
+
lines.compact!
|
30
|
+
|
31
|
+
Polyline.new(lines)
|
32
|
+
end
|
33
|
+
|
34
|
+
def self.parse(string)
|
35
|
+
partial_pattern = /\s* solid\s+ (?<name> [a-zA-Z0-9\-\_\.]+)?/x
|
36
|
+
match_data = string.match(partial_pattern)
|
37
|
+
|
38
|
+
solid = self.new(match_data[:name])
|
39
|
+
|
40
|
+
solid.facets = Facet.parse(string.gsub(partial_pattern, ""))
|
41
|
+
|
42
|
+
solid
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
require 'forwardable'
|
2
|
+
|
3
|
+
module Triangular
|
4
|
+
class Vertex
|
5
|
+
extend Forwardable
|
6
|
+
|
7
|
+
def_delegator :@point, :x, :x
|
8
|
+
def_delegator :@point, :y, :y
|
9
|
+
def_delegator :@point, :z, :z
|
10
|
+
|
11
|
+
attr_accessor :point
|
12
|
+
|
13
|
+
def initialize(*args)
|
14
|
+
if args.length == 1 && args.first.is_a?(Point)
|
15
|
+
@point = args.first
|
16
|
+
elsif args.length == 3
|
17
|
+
@point = Point.new(args[0], args[1], args[2])
|
18
|
+
else
|
19
|
+
raise "You must either supply the XYZ coordinates or a Point object to create a Vertex"
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def to_s
|
24
|
+
"vertex #{@point.to_s}"
|
25
|
+
end
|
26
|
+
|
27
|
+
def ==(other)
|
28
|
+
return false unless other.is_a?(Vertex)
|
29
|
+
self.x == other.x && self.y == other.y && self.z == other.z
|
30
|
+
end
|
31
|
+
|
32
|
+
def self.parse(string)
|
33
|
+
string.strip!
|
34
|
+
match_data = string.match(self.pattern)
|
35
|
+
|
36
|
+
self.new(Point.parse(match_data[:point]))
|
37
|
+
end
|
38
|
+
|
39
|
+
def self.pattern
|
40
|
+
/vertex\s+ (?<point>#{Point.pattern})/x
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
44
|
+
end
|
data/spec/facet_spec.rb
ADDED
@@ -0,0 +1,257 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Facet do
|
4
|
+
describe ".parse" do
|
5
|
+
context "with a correctly formatted facet" do
|
6
|
+
before do
|
7
|
+
@result = Facet.parse(<<-EOD)
|
8
|
+
facet normal 0.0 0.0 -1.0
|
9
|
+
outer loop
|
10
|
+
vertex 16.5 0.0 -0.75
|
11
|
+
vertex 0.0 -9.5 -0.75
|
12
|
+
vertex 0.0 0.0 -0.75
|
13
|
+
endloop
|
14
|
+
endfacet
|
15
|
+
EOD
|
16
|
+
end
|
17
|
+
|
18
|
+
it "should return a facet object" do
|
19
|
+
@result.should be_a Facet
|
20
|
+
end
|
21
|
+
|
22
|
+
it "should return a facet with 3 vertices" do
|
23
|
+
@result.vertices.length.should == 3
|
24
|
+
end
|
25
|
+
|
26
|
+
it "should return a facet with vertices of type Vertex" do
|
27
|
+
@result.vertices.each do |vertex|
|
28
|
+
vertex.should be_a Vertex
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
it "should return a facet with a normal of type Vector" do
|
33
|
+
@result.normal.should be_a Vector
|
34
|
+
end
|
35
|
+
|
36
|
+
it "should correctly set the normal values" do
|
37
|
+
@result.normal.x.should == 0
|
38
|
+
@result.normal.y.should == 0
|
39
|
+
@result.normal.z.should == -1
|
40
|
+
end
|
41
|
+
|
42
|
+
it "should correctly set the values for the first vertex" do
|
43
|
+
@result.vertices[0].x.should == 16.5
|
44
|
+
@result.vertices[0].y.should == 0
|
45
|
+
@result.vertices[0].z.should == -0.75
|
46
|
+
end
|
47
|
+
|
48
|
+
it "should correctly set the values for the second vertex" do
|
49
|
+
@result.vertices[1].x.should == 0
|
50
|
+
@result.vertices[1].y.should == -9.5
|
51
|
+
@result.vertices[1].z.should == -0.75
|
52
|
+
end
|
53
|
+
|
54
|
+
it "should correctly set the values for the third vertex" do
|
55
|
+
@result.vertices[2].x.should == 0
|
56
|
+
@result.vertices[2].y.should == 0
|
57
|
+
@result.vertices[2].z.should == -0.75
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
context "when passed multiple facets" do
|
62
|
+
before do
|
63
|
+
@result = Facet.parse(<<-EOD)
|
64
|
+
facet normal 0.0 0.0 -1.0
|
65
|
+
outer loop
|
66
|
+
vertex 16.5 0.0 -0.75
|
67
|
+
vertex 0.0 -9.5 -0.75
|
68
|
+
vertex 0.0 0.0 -0.75
|
69
|
+
endloop
|
70
|
+
endfacet
|
71
|
+
facet normal 0.0 0.0 -1.0
|
72
|
+
outer loop
|
73
|
+
vertex 16.5 0.0 -0.75
|
74
|
+
vertex 0.0 -9.5 -0.75
|
75
|
+
vertex 0.0 0.0 -0.75
|
76
|
+
endloop
|
77
|
+
endfacet
|
78
|
+
EOD
|
79
|
+
end
|
80
|
+
|
81
|
+
it "should return multiple facet objects" do
|
82
|
+
@result.should be_a Array
|
83
|
+
@result.each do |item|
|
84
|
+
item.should be_a Facet
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
describe "#to_s" do
|
91
|
+
it "should return the string representation for a facet" do
|
92
|
+
facet = Facet.new
|
93
|
+
facet.normal = Vector.new(0, 0, 1)
|
94
|
+
facet.vertices << Point.new(1, 2, 3)
|
95
|
+
facet.vertices << Point.new(1, 2, 3)
|
96
|
+
facet.vertices << Point.new(1, 2, 3)
|
97
|
+
|
98
|
+
expected_string = "facet normal 0.0 0.0 1.0\n"
|
99
|
+
expected_string += "outer loop\n"
|
100
|
+
expected_string += facet.vertices[0].to_s + "\n"
|
101
|
+
expected_string += facet.vertices[1].to_s + "\n"
|
102
|
+
expected_string += facet.vertices[2].to_s + "\n"
|
103
|
+
expected_string += "endloop\n"
|
104
|
+
expected_string += "endfacet\n"
|
105
|
+
|
106
|
+
facet.to_s.should == expected_string
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
describe "#intersection_at_z" do
|
111
|
+
context "for a facet that intersects the target Z plane" do
|
112
|
+
before do
|
113
|
+
vertex1 = Vertex.new(0.0, 0.0, 0.0)
|
114
|
+
vertex2 = Vertex.new(0.0, 0.0, 6.0)
|
115
|
+
vertex3 = Vertex.new(6.0, 0.0, 6.0)
|
116
|
+
|
117
|
+
@facet = Facet.new(nil, vertex1, vertex2, vertex3)
|
118
|
+
end
|
119
|
+
|
120
|
+
context "when the target Z plane is 3.0" do
|
121
|
+
it "should return a line object" do
|
122
|
+
@facet.intersection_at_z(3.0).should be_a Line
|
123
|
+
end
|
124
|
+
|
125
|
+
it "should return a line with the correct start value" do
|
126
|
+
@facet.intersection_at_z(3.0).start.x.should == 0.0
|
127
|
+
@facet.intersection_at_z(3.0).start.y.should == 0.0
|
128
|
+
@facet.intersection_at_z(3.0).start.z.should == 3.0
|
129
|
+
end
|
130
|
+
|
131
|
+
it "should return a line with the correct end value" do
|
132
|
+
@facet.intersection_at_z(3.0).end.x.should == 3.0
|
133
|
+
@facet.intersection_at_z(3.0).end.y.should == 0.0
|
134
|
+
@facet.intersection_at_z(3.0).end.z.should == 3.0
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
context "when the target Z plane is 6.0" do
|
139
|
+
it "should return a line object" do
|
140
|
+
@facet.intersection_at_z(6.0).should be_a Line
|
141
|
+
end
|
142
|
+
|
143
|
+
it "should return a line with the correct start value" do
|
144
|
+
@facet.intersection_at_z(6.0).start.x.should == 0.0
|
145
|
+
@facet.intersection_at_z(6.0).start.y.should == 0.0
|
146
|
+
@facet.intersection_at_z(6.0).start.z.should == 6.0
|
147
|
+
end
|
148
|
+
|
149
|
+
it "should return a line with the correct end value" do
|
150
|
+
@facet.intersection_at_z(6.0).end.x.should == 6.0
|
151
|
+
@facet.intersection_at_z(6.0).end.y.should == 0.0
|
152
|
+
@facet.intersection_at_z(6.0).end.z.should == 6.0
|
153
|
+
end
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
context "for a facet that intersects the target Z plane at an angle" do
|
158
|
+
before do
|
159
|
+
vertex1 = Vertex.new(0.0, 0.0, 0.0)
|
160
|
+
vertex2 = Vertex.new(0.0, 6.0, 6.0)
|
161
|
+
vertex3 = Vertex.new(6.0, 6.0, 6.0)
|
162
|
+
|
163
|
+
@facet = Facet.new(nil, vertex1, vertex2, vertex3)
|
164
|
+
end
|
165
|
+
|
166
|
+
context "when the target Z plane is 3.0" do
|
167
|
+
it "should return a line object" do
|
168
|
+
@facet.intersection_at_z(3.0).should be_a Line
|
169
|
+
end
|
170
|
+
|
171
|
+
it "should return a line with the correct start value" do
|
172
|
+
@facet.intersection_at_z(3.0).start.x.should == 0.0
|
173
|
+
@facet.intersection_at_z(3.0).start.y.should == 3.0
|
174
|
+
@facet.intersection_at_z(3.0).start.z.should == 3.0
|
175
|
+
end
|
176
|
+
|
177
|
+
it "should return a line with the correct end value" do
|
178
|
+
@facet.intersection_at_z(3.0).end.x.should == 3.0
|
179
|
+
@facet.intersection_at_z(3.0).end.y.should == 3.0
|
180
|
+
@facet.intersection_at_z(3.0).end.z.should == 3.0
|
181
|
+
end
|
182
|
+
end
|
183
|
+
|
184
|
+
context "when the target Z plane is 6.0" do
|
185
|
+
it "should return a line object" do
|
186
|
+
@facet.intersection_at_z(6.0).should be_a Line
|
187
|
+
end
|
188
|
+
|
189
|
+
it "should return a line with the correct start value" do
|
190
|
+
@facet.intersection_at_z(6.0).start.x.should == 0.0
|
191
|
+
@facet.intersection_at_z(6.0).start.y.should == 6.0
|
192
|
+
@facet.intersection_at_z(6.0).start.z.should == 6.0
|
193
|
+
end
|
194
|
+
|
195
|
+
it "should return a line with the correct end value" do
|
196
|
+
@facet.intersection_at_z(6.0).end.x.should == 6.0
|
197
|
+
@facet.intersection_at_z(6.0).end.y.should == 6.0
|
198
|
+
@facet.intersection_at_z(6.0).end.z.should == 6.0
|
199
|
+
end
|
200
|
+
end
|
201
|
+
end
|
202
|
+
|
203
|
+
context "with vertices in both positive and negative space" do
|
204
|
+
before do
|
205
|
+
@facet = Facet.parse(<<-EOD)
|
206
|
+
facet normal -0.0 1.0 -0.0
|
207
|
+
outer loop
|
208
|
+
vertex -1.0 1.0 1.0
|
209
|
+
vertex 1.0 1.0 -1.0
|
210
|
+
vertex -1.0 1.0 -1.0
|
211
|
+
endloop
|
212
|
+
endfacet
|
213
|
+
EOD
|
214
|
+
end
|
215
|
+
|
216
|
+
it "should return a line with the correct start value" do
|
217
|
+
@facet.intersection_at_z(0.0).start.x.should == 0.0
|
218
|
+
@facet.intersection_at_z(0.0).start.y.should == 1.0
|
219
|
+
@facet.intersection_at_z(0.0).start.z.should == 0.0
|
220
|
+
end
|
221
|
+
|
222
|
+
it "should return a line with the correct end value" do
|
223
|
+
@facet.intersection_at_z(0.0).end.x.should == -1.0
|
224
|
+
@facet.intersection_at_z(0.0).end.y.should == 1.0
|
225
|
+
@facet.intersection_at_z(0.0).end.z.should == 0.0
|
226
|
+
end
|
227
|
+
end
|
228
|
+
|
229
|
+
context "for a facet that lies on the target Z plane" do
|
230
|
+
before do
|
231
|
+
vertex1 = Vertex.new(0.0, 0.0, 1.0)
|
232
|
+
vertex2 = Vertex.new(2.0, 0.0, 1.0)
|
233
|
+
vertex3 = Vertex.new(2.0, 2.0, 1.0)
|
234
|
+
|
235
|
+
@facet = Facet.new(nil, vertex1, vertex2, vertex3)
|
236
|
+
end
|
237
|
+
|
238
|
+
it "should return nil" do
|
239
|
+
@facet.intersection_at_z(1.0).should == nil
|
240
|
+
end
|
241
|
+
end
|
242
|
+
|
243
|
+
context "for a facet that does not intersect the target Z plane" do
|
244
|
+
before do
|
245
|
+
vertex1 = Vertex.new(0.0, 0.0, 0.0)
|
246
|
+
vertex2 = Vertex.new(2.0, 0.0, 0.0)
|
247
|
+
vertex3 = Vertex.new(2.0, 2.0, 0.0)
|
248
|
+
|
249
|
+
@facet = Facet.new(nil, vertex1, vertex2, vertex3)
|
250
|
+
end
|
251
|
+
|
252
|
+
it "should return nil" do
|
253
|
+
@facet.intersection_at_z(1.0).should == nil
|
254
|
+
end
|
255
|
+
end
|
256
|
+
end
|
257
|
+
end
|