triangular 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|