triangular 0.0.2 → 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.github/workflows/build.yml +30 -0
- data/.gitignore +3 -0
- data/.rspec +2 -0
- data/.rubocop.yml +31 -0
- data/Gemfile +3 -1
- data/Gemfile.lock +51 -12
- data/MIT-LICENSE +1 -1
- data/README.md +98 -0
- data/examples/slice_example.rb +6 -4
- data/lib/triangular/facet.rb +32 -42
- data/lib/triangular/line.rb +42 -16
- data/lib/triangular/point.rb +15 -15
- data/lib/triangular/polyline.rb +13 -12
- data/lib/triangular/ray.rb +41 -0
- data/lib/triangular/solid.rb +34 -36
- data/lib/triangular/units.rb +18 -14
- data/lib/triangular/vector.rb +8 -1
- data/lib/triangular/version.rb +3 -1
- data/lib/triangular/vertex.rb +17 -16
- data/lib/triangular.rb +4 -1
- data/spec/benchmark/benchmark_spec.rb +23 -0
- data/spec/profile/profile_spec.rb +20 -0
- data/spec/spec_helper.rb +17 -3
- data/spec/triangular/facet_spec.rb +235 -0
- data/spec/triangular/line_spec.rb +285 -0
- data/spec/triangular/point_spec.rb +108 -0
- data/spec/triangular/polyline_spec.rb +22 -0
- data/spec/triangular/ray_spec.rb +63 -0
- data/spec/{solid_spec.rb → triangular/solid_spec.rb} +71 -70
- data/spec/triangular/triangular_spec.rb +24 -0
- data/spec/triangular/units_spec.rb +77 -0
- data/spec/triangular/vector_spec.rb +23 -0
- data/spec/triangular/vertex_spec.rb +46 -0
- data/triangular.gemspec +22 -18
- metadata +114 -65
- data/README.rdoc +0 -64
- data/Rakefile +0 -11
- data/spec/facet_spec.rb +0 -233
- data/spec/line_spec.rb +0 -108
- data/spec/point_spec.rb +0 -88
- data/spec/polyline_spec.rb +0 -20
- data/spec/triangular_spec.rb +0 -22
- data/spec/units_spec.rb +0 -75
- data/spec/vertex_spec.rb +0 -44
data/lib/triangular/solid.rb
CHANGED
@@ -1,90 +1,88 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Triangular
|
2
4
|
class Solid
|
3
|
-
|
4
5
|
attr_accessor :name, :facets, :units
|
5
|
-
|
6
|
+
|
6
7
|
def initialize(name, *args)
|
7
8
|
@name = name
|
8
9
|
@facets = args
|
9
10
|
@units = units
|
10
11
|
end
|
11
|
-
|
12
|
+
|
12
13
|
def to_s
|
13
|
-
output = "solid #{@name ||
|
14
|
+
output = "solid #{@name || ''}\n"
|
14
15
|
@facets.each do |facet|
|
15
|
-
output
|
16
|
-
output
|
16
|
+
output += "facet normal #{facet.normal.x.to_f} #{facet.normal.y.to_f} #{facet.normal.z.to_f}\n"
|
17
|
+
output += "outer loop\n"
|
17
18
|
facet.vertices.each do |vertex|
|
18
|
-
output
|
19
|
+
output += "vertex #{vertex.x.to_f} #{vertex.y.to_f} #{vertex.z.to_f}\n"
|
19
20
|
end
|
20
|
-
output
|
21
|
-
output
|
21
|
+
output += "endloop\n"
|
22
|
+
output += "endfacet\n"
|
22
23
|
end
|
23
|
-
output
|
24
|
-
|
24
|
+
output += "endsolid #{@name || ''}\n"
|
25
|
+
|
25
26
|
output
|
26
27
|
end
|
27
|
-
|
28
|
-
def
|
28
|
+
|
29
|
+
def bounds
|
29
30
|
largest_x = @facets[0].vertices[0].x
|
30
31
|
largest_y = @facets[0].vertices[0].y
|
31
32
|
largest_z = @facets[0].vertices[0].z
|
32
|
-
|
33
|
+
|
33
34
|
smallest_x = @facets[0].vertices[0].x
|
34
35
|
smallest_y = @facets[0].vertices[0].y
|
35
36
|
smallest_z = @facets[0].vertices[0].z
|
36
|
-
|
37
|
+
|
37
38
|
@facets.each do |facet|
|
38
39
|
facet.vertices.each do |vertex|
|
39
40
|
largest_x = vertex.x if vertex.x > largest_x
|
40
41
|
largest_y = vertex.y if vertex.y > largest_y
|
41
42
|
largest_z = vertex.z if vertex.z > largest_z
|
42
|
-
|
43
|
+
|
43
44
|
smallest_x = vertex.x if vertex.x < smallest_x
|
44
45
|
smallest_y = vertex.y if vertex.y < smallest_y
|
45
46
|
smallest_z = vertex.z if vertex.z < smallest_z
|
46
47
|
end
|
47
48
|
end
|
48
|
-
|
49
|
+
|
49
50
|
[Point.new(smallest_x, smallest_y, smallest_z), Point.new(largest_x, largest_y, largest_z)]
|
50
51
|
end
|
51
|
-
|
52
|
+
|
52
53
|
def align_to_origin!
|
53
|
-
bounds
|
54
|
-
self.translate!(-bounds[0].x, -bounds[0].y, -bounds[0].z)
|
54
|
+
translate!(-bounds[0].x, -bounds[0].y, -bounds[0].z)
|
55
55
|
end
|
56
|
-
|
56
|
+
|
57
57
|
def center!
|
58
|
-
bounds = self.get_bounds
|
59
|
-
|
60
58
|
x_translation = ((bounds[1].x - bounds[0].x).abs / 2) + -bounds[1].x
|
61
59
|
y_translation = ((bounds[1].y - bounds[0].y).abs / 2) + -bounds[1].y
|
62
60
|
z_translation = ((bounds[1].z - bounds[0].z).abs / 2) + -bounds[1].z
|
63
|
-
|
64
|
-
|
61
|
+
|
62
|
+
translate!(x_translation, y_translation, z_translation)
|
65
63
|
end
|
66
|
-
|
64
|
+
|
67
65
|
def slice_at_z(z_plane)
|
68
|
-
lines = @facets.map {|facet| facet.intersection_at_z(z_plane) }
|
66
|
+
lines = @facets.map { |facet| facet.intersection_at_z(z_plane) }
|
69
67
|
lines.compact!
|
70
|
-
|
68
|
+
|
71
69
|
Polyline.new(lines)
|
72
70
|
end
|
73
|
-
|
71
|
+
|
74
72
|
def translate!(x, y, z)
|
75
73
|
@facets.each do |facet|
|
76
74
|
facet.translate!(x, y, z)
|
77
75
|
end
|
78
76
|
end
|
79
|
-
|
77
|
+
|
80
78
|
def self.parse(string)
|
81
|
-
partial_pattern = /\s* solid\s+ (?<name> [a-zA-Z0-9
|
79
|
+
partial_pattern = /\s* solid\s+ (?<name> [a-zA-Z0-9\-_.]+)?/x
|
82
80
|
match_data = string.match(partial_pattern)
|
83
|
-
|
84
|
-
solid =
|
85
|
-
|
86
|
-
solid.facets = Facet.parse(string.gsub(partial_pattern,
|
87
|
-
|
81
|
+
|
82
|
+
solid = new(match_data[:name])
|
83
|
+
|
84
|
+
solid.facets = Facet.parse(string.gsub(partial_pattern, ''))
|
85
|
+
|
88
86
|
solid
|
89
87
|
end
|
90
88
|
end
|
data/lib/triangular/units.rb
CHANGED
@@ -1,30 +1,34 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'forwardable'
|
2
4
|
|
3
5
|
module Triangular
|
6
|
+
class UnknownUnitError < RuntimeError; end
|
7
|
+
|
4
8
|
class Units
|
5
|
-
|
6
9
|
UNITS = {
|
7
|
-
:
|
8
|
-
:
|
9
|
-
:
|
10
|
-
:
|
11
|
-
}
|
12
|
-
|
10
|
+
inches: { name: 'inches', svg_name: 'in', stroke_width: 0.005 },
|
11
|
+
centimeters: { name: 'centimeters', svg_name: 'cm', stroke_width: 0.01 },
|
12
|
+
millimeters: { name: 'millimeters', svg_name: 'mm', stroke_width: 0.1 },
|
13
|
+
none: { name: 'none', svg_name: '', stroke_width: 0.1 }
|
14
|
+
}.freeze
|
15
|
+
|
13
16
|
def self.get_property(unit, name)
|
14
|
-
raise "Unknown unit: #{unit}" unless UNITS.
|
17
|
+
raise UnknownUnitError, "Unknown unit: #{unit}" unless UNITS.key?(unit)
|
18
|
+
|
15
19
|
UNITS[unit][name]
|
16
20
|
end
|
17
|
-
|
21
|
+
|
18
22
|
def self.name(unit)
|
19
|
-
|
23
|
+
get_property(unit, :name)
|
20
24
|
end
|
21
|
-
|
25
|
+
|
22
26
|
def self.svg_name(unit)
|
23
|
-
|
27
|
+
get_property(unit, :svg_name)
|
24
28
|
end
|
25
|
-
|
29
|
+
|
26
30
|
def self.stroke_width(unit)
|
27
|
-
|
31
|
+
get_property(unit, :stroke_width)
|
28
32
|
end
|
29
33
|
end
|
30
34
|
end
|
data/lib/triangular/vector.rb
CHANGED
@@ -1,4 +1,11 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Triangular
|
2
|
-
class Vector < Point
|
4
|
+
class Vector < Point
|
5
|
+
def angle_to(other_vector)
|
6
|
+
dot_product = @x * other_vector.x + @y * other_vector.y + @z * other_vector.z
|
7
|
+
radians = Math.acos(dot_product)
|
8
|
+
radians * (180.0 / Math::PI)
|
9
|
+
end
|
3
10
|
end
|
4
11
|
end
|
data/lib/triangular/version.rb
CHANGED
data/lib/triangular/vertex.rb
CHANGED
@@ -1,45 +1,46 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'forwardable'
|
2
4
|
|
3
5
|
module Triangular
|
4
6
|
class Vertex
|
5
7
|
extend Forwardable
|
6
|
-
|
8
|
+
|
7
9
|
def_delegator :@point, :x, :x
|
8
10
|
def_delegator :@point, :y, :y
|
9
11
|
def_delegator :@point, :z, :z
|
10
12
|
def_delegator :@point, :translate!, :translate!
|
11
|
-
|
13
|
+
|
12
14
|
attr_accessor :point
|
13
|
-
|
15
|
+
|
14
16
|
def initialize(*args)
|
15
17
|
if args.length == 1 && args.first.is_a?(Point)
|
16
18
|
@point = args.first
|
17
19
|
elsif args.length == 3
|
18
|
-
@point = Point.new(args[0], args[1], args[2])
|
20
|
+
@point = Point.new(args[0], args[1], args[2])
|
19
21
|
else
|
20
|
-
raise
|
22
|
+
raise 'You must either supply the XYZ coordinates or a Point object to create a Vertex'
|
21
23
|
end
|
22
24
|
end
|
23
|
-
|
25
|
+
|
24
26
|
def to_s
|
25
|
-
"vertex #{@point
|
27
|
+
"vertex #{@point}"
|
26
28
|
end
|
27
|
-
|
29
|
+
|
28
30
|
def ==(other)
|
29
31
|
return false unless other.is_a?(Vertex)
|
30
|
-
|
32
|
+
|
33
|
+
x == other.x && y == other.y && z == other.z
|
31
34
|
end
|
32
|
-
|
35
|
+
|
33
36
|
def self.parse(string)
|
34
|
-
string.strip
|
35
|
-
|
36
|
-
|
37
|
-
self.new(Point.parse(match_data[:point]))
|
37
|
+
match_data = string.strip.match(pattern)
|
38
|
+
|
39
|
+
new(Point.parse(match_data[:point]))
|
38
40
|
end
|
39
|
-
|
41
|
+
|
40
42
|
def self.pattern
|
41
43
|
/vertex\s+ (?<point>#{Point.pattern})/x
|
42
44
|
end
|
43
|
-
|
44
45
|
end
|
45
46
|
end
|
data/lib/triangular.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'triangular/point'
|
2
4
|
require 'triangular/vertex'
|
3
5
|
require 'triangular/vector'
|
@@ -6,12 +8,13 @@ require 'triangular/polyline'
|
|
6
8
|
require 'triangular/facet'
|
7
9
|
require 'triangular/units'
|
8
10
|
require 'triangular/solid'
|
11
|
+
require 'triangular/ray'
|
9
12
|
|
10
13
|
module Triangular
|
11
14
|
def self.parse(string)
|
12
15
|
Solid.parse(string)
|
13
16
|
end
|
14
|
-
|
17
|
+
|
15
18
|
def self.parse_file(path)
|
16
19
|
File.open(path) do |file|
|
17
20
|
Solid.parse(file.read)
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
RSpec.configure do |config|
|
6
|
+
config.after(:suite) do
|
7
|
+
benchmarks = {}
|
8
|
+
|
9
|
+
benchmarks['Triangular.parse_file'] = Benchmark.measure do
|
10
|
+
Triangular.parse_file(File.expand_path("#{File.dirname(__FILE__)}/../fixtures/y-axis-spacer.stl"))
|
11
|
+
end
|
12
|
+
|
13
|
+
puts "\n\n\n"
|
14
|
+
puts '--------------------------------------------------------------------------------'
|
15
|
+
puts '- Benchmark Results: -'
|
16
|
+
puts '--------------------------------------------------------------------------------'
|
17
|
+
puts "\n"
|
18
|
+
|
19
|
+
benchmarks.each do |test_name, result|
|
20
|
+
puts test_name.ljust(34) + ": #{result}"
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
RSpec.configure do |config|
|
6
|
+
config.after(:suite) do
|
7
|
+
profile = RubyProf.profile do
|
8
|
+
Triangular.parse_file(File.expand_path("#{File.dirname(__FILE__)}/../fixtures/y-axis-spacer.stl"))
|
9
|
+
end
|
10
|
+
|
11
|
+
puts "\n\n\n"
|
12
|
+
puts '--------------------------------------------------------------------------------'
|
13
|
+
puts '- Profile Results: -'
|
14
|
+
puts '--------------------------------------------------------------------------------'
|
15
|
+
puts "\n"
|
16
|
+
|
17
|
+
printer = RubyProf::FlatPrinter.new(profile)
|
18
|
+
printer.print($stdout, min_percent: 2)
|
19
|
+
end
|
20
|
+
end
|
data/spec/spec_helper.rb
CHANGED
@@ -1,4 +1,18 @@
|
|
1
|
-
|
2
|
-
require "triangular"
|
1
|
+
# frozen_string_literal: true
|
3
2
|
|
4
|
-
|
3
|
+
require 'simplecov'
|
4
|
+
SimpleCov.start
|
5
|
+
|
6
|
+
require 'bundler/setup'
|
7
|
+
require 'triangular'
|
8
|
+
require 'benchmark'
|
9
|
+
require 'ruby-prof'
|
10
|
+
|
11
|
+
RSpec.configure do |config|
|
12
|
+
# Enable flags like --only-failures and --next-failure
|
13
|
+
config.example_status_persistence_file_path = '.rspec_status'
|
14
|
+
|
15
|
+
config.expect_with :rspec do |c|
|
16
|
+
c.syntax = :expect
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,235 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
describe Triangular::Facet do
|
6
|
+
describe '.parse' do
|
7
|
+
context 'with a correctly formatted facet' do
|
8
|
+
before :each do
|
9
|
+
@result = Triangular::Facet.parse(<<-FACET)
|
10
|
+
facet normal 0.0 0.0 -1.0
|
11
|
+
outer loop
|
12
|
+
vertex 16.5 0.0 -0.75
|
13
|
+
vertex 0.0 -9.5 -0.75
|
14
|
+
vertex 0.0 0.0 -0.75
|
15
|
+
endloop
|
16
|
+
endfacet
|
17
|
+
FACET
|
18
|
+
end
|
19
|
+
|
20
|
+
it 'should return a facet object' do
|
21
|
+
expect(@result).to be_a Triangular::Facet
|
22
|
+
end
|
23
|
+
|
24
|
+
it 'should return a facet with 3 vertices' do
|
25
|
+
expect(@result.vertices.length).to eq(3)
|
26
|
+
end
|
27
|
+
|
28
|
+
it 'should return a facet with vertices of type Vertex' do
|
29
|
+
@result.vertices.each do |vertex|
|
30
|
+
expect(vertex).to be_a Triangular::Vertex
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
it 'should return a facet with a normal of type Vector' do
|
35
|
+
expect(@result.normal).to be_a Triangular::Vector
|
36
|
+
end
|
37
|
+
|
38
|
+
it 'should correctly set the normal values' do
|
39
|
+
expect(@result.normal.x).to eq(0)
|
40
|
+
expect(@result.normal.y).to eq(0)
|
41
|
+
expect(@result.normal.z).to eq(-1)
|
42
|
+
end
|
43
|
+
|
44
|
+
it 'should correctly set the values for the first vertex' do
|
45
|
+
expect(@result.vertices[0].x).to eq(16.5)
|
46
|
+
expect(@result.vertices[0].y).to eq(0)
|
47
|
+
expect(@result.vertices[0].z).to eq(-0.75)
|
48
|
+
end
|
49
|
+
|
50
|
+
it 'should correctly set the values for the second vertex' do
|
51
|
+
expect(@result.vertices[1].x).to eq(0)
|
52
|
+
expect(@result.vertices[1].y).to eq(-9.5)
|
53
|
+
expect(@result.vertices[1].z).to eq(-0.75)
|
54
|
+
end
|
55
|
+
|
56
|
+
it 'should correctly set the values for the third vertex' do
|
57
|
+
expect(@result.vertices[2].x).to eq(0)
|
58
|
+
expect(@result.vertices[2].y).to eq(0)
|
59
|
+
expect(@result.vertices[2].z).to eq(-0.75)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
context 'when passed multiple facets' do
|
64
|
+
before do
|
65
|
+
@result = Triangular::Facet.parse(<<-FACET)
|
66
|
+
facet normal 0.0 0.0 -1.0
|
67
|
+
outer loop
|
68
|
+
vertex 16.5 0.0 -0.75
|
69
|
+
vertex 0.0 -9.5 -0.75
|
70
|
+
vertex 0.0 0.0 -0.75
|
71
|
+
endloop
|
72
|
+
endfacet
|
73
|
+
facet normal 0.0 0.0 -1.0
|
74
|
+
outer loop
|
75
|
+
vertex 16.5 0.0 -0.75
|
76
|
+
vertex 0.0 -9.5 -0.75
|
77
|
+
vertex 0.0 0.0 -0.75
|
78
|
+
endloop
|
79
|
+
endfacet
|
80
|
+
FACET
|
81
|
+
end
|
82
|
+
|
83
|
+
it 'should return multiple facet objects' do
|
84
|
+
expect(@result).to be_a Array
|
85
|
+
@result.each do |item|
|
86
|
+
expect(item).to be_a Triangular::Facet
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
describe '#to_s' do
|
93
|
+
it 'should return the string representation for a facet' do
|
94
|
+
facet = Triangular::Facet.new
|
95
|
+
facet.normal = Triangular::Vector.new(0, 0, 1)
|
96
|
+
facet.vertices << Triangular::Point.new(1, 2, 3)
|
97
|
+
facet.vertices << Triangular::Point.new(1, 2, 3)
|
98
|
+
facet.vertices << Triangular::Point.new(1, 2, 3)
|
99
|
+
|
100
|
+
expected_string = "facet normal 0.0 0.0 1.0\n"
|
101
|
+
expected_string += "outer loop\n"
|
102
|
+
expected_string += "#{facet.vertices[0]}\n"
|
103
|
+
expected_string += "#{facet.vertices[1]}\n"
|
104
|
+
expected_string += "#{facet.vertices[2]}\n"
|
105
|
+
expected_string += "endloop\n"
|
106
|
+
expected_string += "endfacet\n"
|
107
|
+
|
108
|
+
expect(facet.to_s).to eq(expected_string)
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
describe '#intersection_at_z' do
|
113
|
+
context 'for a facet that intersects the target Z plane' do
|
114
|
+
before do
|
115
|
+
vertex1 = Triangular::Vertex.new(0.0, 0.0, 0.0)
|
116
|
+
vertex2 = Triangular::Vertex.new(0.0, 0.0, 6.0)
|
117
|
+
vertex3 = Triangular::Vertex.new(6.0, 0.0, 6.0)
|
118
|
+
|
119
|
+
@facet = Triangular::Facet.new(nil, vertex1, vertex2, vertex3)
|
120
|
+
end
|
121
|
+
|
122
|
+
context 'when the target Z plane is 3.0' do
|
123
|
+
it 'should return a line object' do
|
124
|
+
expect(@facet.intersection_at_z(3.0)).to be_a Triangular::Line
|
125
|
+
end
|
126
|
+
|
127
|
+
it 'should return a line with the correct start value' do
|
128
|
+
expect(@facet.intersection_at_z(3.0).start.x).to eq(0.0)
|
129
|
+
expect(@facet.intersection_at_z(3.0).start.y).to eq(0.0)
|
130
|
+
expect(@facet.intersection_at_z(3.0).start.z).to eq(3.0)
|
131
|
+
end
|
132
|
+
|
133
|
+
it 'should return a line with the correct end value' do
|
134
|
+
expect(@facet.intersection_at_z(3.0).end.x).to eq(3.0)
|
135
|
+
expect(@facet.intersection_at_z(3.0).end.y).to eq(0.0)
|
136
|
+
expect(@facet.intersection_at_z(3.0).end.z).to eq(3.0)
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
context 'when the target Z plane is 6.0' do
|
141
|
+
it 'should return a line object' do
|
142
|
+
expect(@facet.intersection_at_z(6.0)).to be_a Triangular::Line
|
143
|
+
end
|
144
|
+
|
145
|
+
it 'should return a line with the correct start value' do
|
146
|
+
expect(@facet.intersection_at_z(6.0).start.x).to eq(0.0)
|
147
|
+
expect(@facet.intersection_at_z(6.0).start.y).to eq(0.0)
|
148
|
+
expect(@facet.intersection_at_z(6.0).start.z).to eq(6.0)
|
149
|
+
end
|
150
|
+
|
151
|
+
it 'should return a line with the correct end value' do
|
152
|
+
expect(@facet.intersection_at_z(6.0).end.x).to eq(6.0)
|
153
|
+
expect(@facet.intersection_at_z(6.0).end.y).to eq(0.0)
|
154
|
+
expect(@facet.intersection_at_z(6.0).end.z).to eq(6.0)
|
155
|
+
end
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
context 'with vertices in both positive and negative space' do
|
160
|
+
before do
|
161
|
+
@facet = Triangular::Facet.parse(<<-FACET)
|
162
|
+
facet normal -0.0 1.0 -0.0
|
163
|
+
outer loop
|
164
|
+
vertex -1.0 1.0 1.0
|
165
|
+
vertex 1.0 1.0 -1.0
|
166
|
+
vertex -1.0 1.0 -1.0
|
167
|
+
endloop
|
168
|
+
endfacet
|
169
|
+
FACET
|
170
|
+
end
|
171
|
+
|
172
|
+
it 'should return a line with the correct start value' do
|
173
|
+
expect(@facet.intersection_at_z(0.0).start.x).to eq(0.0)
|
174
|
+
expect(@facet.intersection_at_z(0.0).start.y).to eq(1.0)
|
175
|
+
expect(@facet.intersection_at_z(0.0).start.z).to eq(0.0)
|
176
|
+
end
|
177
|
+
|
178
|
+
it 'should return a line with the correct end value' do
|
179
|
+
expect(@facet.intersection_at_z(0.0).end.x).to eq(-1.0)
|
180
|
+
expect(@facet.intersection_at_z(0.0).end.y).to eq(1.0)
|
181
|
+
expect(@facet.intersection_at_z(0.0).end.z).to eq(0.0)
|
182
|
+
end
|
183
|
+
end
|
184
|
+
|
185
|
+
context 'for a facet that lies on the target Z plane' do
|
186
|
+
before do
|
187
|
+
vertex1 = Triangular::Vertex.new(0.0, 0.0, 1.0)
|
188
|
+
vertex2 = Triangular::Vertex.new(2.0, 0.0, 1.0)
|
189
|
+
vertex3 = Triangular::Vertex.new(2.0, 2.0, 1.0)
|
190
|
+
|
191
|
+
@facet = Triangular::Facet.new(nil, vertex1, vertex2, vertex3)
|
192
|
+
end
|
193
|
+
|
194
|
+
it 'should return nil' do
|
195
|
+
expect(@facet.intersection_at_z(1.0)).to eq(nil)
|
196
|
+
end
|
197
|
+
end
|
198
|
+
|
199
|
+
context 'for a facet that does not intersect the target Z plane' do
|
200
|
+
before do
|
201
|
+
vertex1 = Triangular::Vertex.new(0.0, 0.0, 0.0)
|
202
|
+
vertex2 = Triangular::Vertex.new(2.0, 0.0, 0.0)
|
203
|
+
vertex3 = Triangular::Vertex.new(2.0, 2.0, 0.0)
|
204
|
+
|
205
|
+
@facet = Triangular::Facet.new(nil, vertex1, vertex2, vertex3)
|
206
|
+
end
|
207
|
+
|
208
|
+
it 'should return nil' do
|
209
|
+
expect(@facet.intersection_at_z(1.0)).to eq(nil)
|
210
|
+
end
|
211
|
+
end
|
212
|
+
end
|
213
|
+
|
214
|
+
describe '#translate!' do
|
215
|
+
before do
|
216
|
+
@facet = Triangular::Facet.parse(<<-FACET)
|
217
|
+
facet normal 0.0 0.0 -1.0
|
218
|
+
outer loop
|
219
|
+
vertex -16.5 0.0 -0.75
|
220
|
+
vertex 0.0 -9.5 -0.75
|
221
|
+
vertex 0.0 0.0 -0.75
|
222
|
+
endloop
|
223
|
+
endfacet
|
224
|
+
FACET
|
225
|
+
end
|
226
|
+
|
227
|
+
it "should call translate on each of it's Vertices" do
|
228
|
+
expect(@facet.vertices[0]).to receive(:translate!).with(16.5, 9.5, 0.75)
|
229
|
+
expect(@facet.vertices[1]).to receive(:translate!).with(16.5, 9.5, 0.75)
|
230
|
+
expect(@facet.vertices[2]).to receive(:translate!).with(16.5, 9.5, 0.75)
|
231
|
+
|
232
|
+
@facet.translate!(16.5, 9.5, 0.75)
|
233
|
+
end
|
234
|
+
end
|
235
|
+
end
|