triangular 0.0.1 → 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- data/README.rdoc +37 -4
- data/examples/slice_example.rb +7 -2
- data/lib/triangular.rb +1 -0
- data/lib/triangular/facet.rb +6 -0
- data/lib/triangular/line.rb +2 -2
- data/lib/triangular/point.rb +6 -0
- data/lib/triangular/polyline.rb +4 -4
- data/lib/triangular/solid.rb +47 -1
- data/lib/triangular/units.rb +30 -0
- data/lib/triangular/version.rb +1 -1
- data/lib/triangular/vertex.rb +1 -0
- data/spec/facet_spec.rb +22 -46
- data/spec/line_spec.rb +11 -93
- data/spec/point_spec.rb +21 -0
- data/spec/polyline_spec.rb +4 -4
- data/spec/solid_spec.rb +123 -0
- data/spec/units_spec.rb +75 -0
- metadata +4 -2
data/README.rdoc
CHANGED
@@ -7,25 +7,58 @@ The main purpose of Triangular is to enable its users to quickly create new soft
|
|
7
7
|
Please note that Triangular requires Ruby 1.9+. Triangular is currently in the Alpha stage of development which means that the API can and will change, and that new features will be added often!
|
8
8
|
|
9
9
|
=== A Quick Example
|
10
|
+
|
11
|
+
require "rubygems"
|
12
|
+
require "triangular"
|
10
13
|
|
11
14
|
# Open and parse an STL file
|
12
15
|
solid = Triangular.parse_file("test.stl")
|
13
16
|
|
14
|
-
#
|
15
|
-
|
17
|
+
# Set the units of measurement for the resulting solid to inches
|
18
|
+
solid.units = :inches
|
19
|
+
|
20
|
+
# Move the solid so that all of it's coordinates are in positive space (ie: greater than 0)
|
21
|
+
solid.align_to_origin!
|
22
|
+
|
23
|
+
# Get the bounding box of the solid
|
24
|
+
bounds = solid.get_bounds
|
25
|
+
|
26
|
+
# Create a section plane ('slice') through the solid on the XY plane at a Z height of 0.7
|
27
|
+
slice = solid.slice_at_z(0.7)
|
28
|
+
|
29
|
+
# Open a file for SVG output
|
30
|
+
File.open("slice.svg", "w+") do |file|
|
16
31
|
|
17
|
-
|
18
|
-
|
32
|
+
# Output the slice as an SVG document (correctly scaled according to the solid's units)
|
33
|
+
file.puts slice.to_svg(bounds[1].x, bounds[1].y, solid.units)
|
34
|
+
end
|
19
35
|
|
20
36
|
=== Installation
|
21
37
|
|
22
38
|
For ease of use the Triangular is packaged as a RubyGem. Providing you already have Ruby and RubyGems installing Triangular is as easy as entering the following command in a terminal:
|
23
39
|
|
24
40
|
gem install triangular
|
41
|
+
|
42
|
+
=== Performance
|
43
|
+
|
44
|
+
At the moment Triangular has not been optimized at all. The parser is a relatively naive one that was designed to be easy to read rather than performant. Once the feature-set of Triangular has stabilized I will be doing a pass over it in order to make it fast enough for production use. Right now it could definitely be improved.
|
45
|
+
|
46
|
+
For example here is some information about run-times when processing a 51Mb STL file:
|
47
|
+
|
48
|
+
solid = Triangular.parse("big_file.stl")
|
49
|
+
# 65 seconds
|
50
|
+
|
51
|
+
solid.align_to_origin!
|
52
|
+
# 8 seconds
|
53
|
+
|
54
|
+
solid.slice_at_z(1.0)
|
55
|
+
# 2 seconds
|
25
56
|
|
26
57
|
=== Author & Credits
|
27
58
|
|
28
59
|
Author:: {Aaron Gough}[mailto:aaron@aarongough.com]
|
29
60
|
|
61
|
+
Special thanks go out to {Alkas Baybas}[https://github.com/abaybas] for lending me his massive brain!
|
62
|
+
|
30
63
|
Copyright (c) 2011 {Aaron Gough}[http://thingsaaronmade.com/] ({thingsaaronmade.com}[http://thingsaaronmade.com/]), released under the MIT license
|
31
64
|
|
data/examples/slice_example.rb
CHANGED
@@ -2,8 +2,13 @@ require "bundler/setup"
|
|
2
2
|
require "triangular"
|
3
3
|
|
4
4
|
solid = Triangular.parse_file("#{File.dirname(__FILE__)}/example_files/y-axis-spacer.stl")
|
5
|
-
|
5
|
+
solid.units = :inches
|
6
|
+
|
7
|
+
solid.align_to_origin!
|
8
|
+
bounds = solid.get_bounds
|
9
|
+
|
10
|
+
polyline = solid.slice_at_z(0.7)
|
6
11
|
|
7
12
|
File.open(File.expand_path("~/Desktop/slice.svg"), "w+") do |file|
|
8
|
-
file.puts polyline.to_svg(
|
13
|
+
file.puts polyline.to_svg(bounds[1].x, bounds[1].y, solid.units)
|
9
14
|
end
|
data/lib/triangular.rb
CHANGED
data/lib/triangular/facet.rb
CHANGED
data/lib/triangular/line.rb
CHANGED
@@ -31,8 +31,8 @@ module Triangular
|
|
31
31
|
Point.new(x_intersect, y_intersect, z_plane)
|
32
32
|
end
|
33
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=\"
|
34
|
+
def to_svg_path(units)
|
35
|
+
"<path d=\"M #{@start.x} #{@start.y} L #{@end.x} #{@end.y}\" fill=\"none\" stroke=\"black\" stroke-width=\"#{Units.stroke_width(units)}\" />"
|
36
36
|
end
|
37
37
|
end
|
38
38
|
end
|
data/lib/triangular/point.rb
CHANGED
@@ -13,6 +13,12 @@ module Triangular
|
|
13
13
|
"#{@x.to_f} #{@y.to_f} #{@z.to_f}"
|
14
14
|
end
|
15
15
|
|
16
|
+
def translate!(x, y, z)
|
17
|
+
@x += x
|
18
|
+
@y += y
|
19
|
+
@z += z
|
20
|
+
end
|
21
|
+
|
16
22
|
def ==(other)
|
17
23
|
return false unless other.is_a?(Point)
|
18
24
|
self.x == other.x && self.y == other.y && self.z == other.z
|
data/lib/triangular/polyline.rb
CHANGED
@@ -7,14 +7,14 @@ module Triangular
|
|
7
7
|
@lines = lines
|
8
8
|
end
|
9
9
|
|
10
|
-
def to_svg(x_offset =
|
10
|
+
def to_svg(width, height, units, x_offset = 0, y_offset = 0)
|
11
11
|
output = '<?xml version="1.0" standalone="no"?>' + "\n"
|
12
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 <<
|
14
|
-
output << " <g transform=\"translate(#{x_offset},#{y_offset})\">\n"
|
13
|
+
output << "<svg x=\"0\" y=\"0\" width=\"#{width}#{Units.svg_name(units)}\" height=\"#{height}#{Units.svg_name(units)}\" viewBox=\"0 0 #{width} #{height}\" xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\">\n"
|
14
|
+
output << " <g transform=\"translate(#{x_offset}#{Units.svg_name(units)},#{y_offset}#{Units.svg_name(units)})\">\n"
|
15
15
|
|
16
16
|
@lines.each do |line|
|
17
|
-
output << " " + line.to_svg_path + "\n"
|
17
|
+
output << " " + line.to_svg_path(units) + "\n"
|
18
18
|
end
|
19
19
|
|
20
20
|
output << ' </g>' + "\n"
|
data/lib/triangular/solid.rb
CHANGED
@@ -1,11 +1,12 @@
|
|
1
1
|
module Triangular
|
2
2
|
class Solid
|
3
3
|
|
4
|
-
attr_accessor :name, :facets
|
4
|
+
attr_accessor :name, :facets, :units
|
5
5
|
|
6
6
|
def initialize(name, *args)
|
7
7
|
@name = name
|
8
8
|
@facets = args
|
9
|
+
@units = units
|
9
10
|
end
|
10
11
|
|
11
12
|
def to_s
|
@@ -24,6 +25,45 @@ module Triangular
|
|
24
25
|
output
|
25
26
|
end
|
26
27
|
|
28
|
+
def get_bounds
|
29
|
+
largest_x = @facets[0].vertices[0].x
|
30
|
+
largest_y = @facets[0].vertices[0].y
|
31
|
+
largest_z = @facets[0].vertices[0].z
|
32
|
+
|
33
|
+
smallest_x = @facets[0].vertices[0].x
|
34
|
+
smallest_y = @facets[0].vertices[0].y
|
35
|
+
smallest_z = @facets[0].vertices[0].z
|
36
|
+
|
37
|
+
@facets.each do |facet|
|
38
|
+
facet.vertices.each do |vertex|
|
39
|
+
largest_x = vertex.x if vertex.x > largest_x
|
40
|
+
largest_y = vertex.y if vertex.y > largest_y
|
41
|
+
largest_z = vertex.z if vertex.z > largest_z
|
42
|
+
|
43
|
+
smallest_x = vertex.x if vertex.x < smallest_x
|
44
|
+
smallest_y = vertex.y if vertex.y < smallest_y
|
45
|
+
smallest_z = vertex.z if vertex.z < smallest_z
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
[Point.new(smallest_x, smallest_y, smallest_z), Point.new(largest_x, largest_y, largest_z)]
|
50
|
+
end
|
51
|
+
|
52
|
+
def align_to_origin!
|
53
|
+
bounds = self.get_bounds
|
54
|
+
self.translate!(-bounds[0].x, -bounds[0].y, -bounds[0].z)
|
55
|
+
end
|
56
|
+
|
57
|
+
def center!
|
58
|
+
bounds = self.get_bounds
|
59
|
+
|
60
|
+
x_translation = ((bounds[1].x - bounds[0].x).abs / 2) + -bounds[1].x
|
61
|
+
y_translation = ((bounds[1].y - bounds[0].y).abs / 2) + -bounds[1].y
|
62
|
+
z_translation = ((bounds[1].z - bounds[0].z).abs / 2) + -bounds[1].z
|
63
|
+
|
64
|
+
self.translate!(x_translation, y_translation, z_translation)
|
65
|
+
end
|
66
|
+
|
27
67
|
def slice_at_z(z_plane)
|
28
68
|
lines = @facets.map {|facet| facet.intersection_at_z(z_plane) }
|
29
69
|
lines.compact!
|
@@ -31,6 +71,12 @@ module Triangular
|
|
31
71
|
Polyline.new(lines)
|
32
72
|
end
|
33
73
|
|
74
|
+
def translate!(x, y, z)
|
75
|
+
@facets.each do |facet|
|
76
|
+
facet.translate!(x, y, z)
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
34
80
|
def self.parse(string)
|
35
81
|
partial_pattern = /\s* solid\s+ (?<name> [a-zA-Z0-9\-\_\.]+)?/x
|
36
82
|
match_data = string.match(partial_pattern)
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'forwardable'
|
2
|
+
|
3
|
+
module Triangular
|
4
|
+
class Units
|
5
|
+
|
6
|
+
UNITS = {
|
7
|
+
:inches => {:name => 'inches', :svg_name => 'in', :stroke_width => 0.005},
|
8
|
+
:centimeters => {:name => 'centimeters', :svg_name => 'cm', :stroke_width => 0.01},
|
9
|
+
:millimeters => {:name => 'millimeters', :svg_name => 'mm', :stroke_width => 0.1},
|
10
|
+
:none => {:name => 'none', :svg_name => '', :stroke_width => 0.1}
|
11
|
+
}
|
12
|
+
|
13
|
+
def self.get_property(unit, name)
|
14
|
+
raise "Unknown unit: #{unit}" unless UNITS.has_key?(unit)
|
15
|
+
UNITS[unit][name]
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.name(unit)
|
19
|
+
self.get_property(unit, :name)
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.svg_name(unit)
|
23
|
+
self.get_property(unit, :svg_name)
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.stroke_width(unit)
|
27
|
+
self.get_property(unit, :stroke_width)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
data/lib/triangular/version.rb
CHANGED
data/lib/triangular/vertex.rb
CHANGED
data/spec/facet_spec.rb
CHANGED
@@ -154,52 +154,6 @@ describe Facet do
|
|
154
154
|
end
|
155
155
|
end
|
156
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
157
|
context "with vertices in both positive and negative space" do
|
204
158
|
before do
|
205
159
|
@facet = Facet.parse(<<-EOD)
|
@@ -254,4 +208,26 @@ describe Facet do
|
|
254
208
|
end
|
255
209
|
end
|
256
210
|
end
|
211
|
+
|
212
|
+
describe "#translate!" do
|
213
|
+
before do
|
214
|
+
@facet = Facet.parse(<<-EOD)
|
215
|
+
facet normal 0.0 0.0 -1.0
|
216
|
+
outer loop
|
217
|
+
vertex -16.5 0.0 -0.75
|
218
|
+
vertex 0.0 -9.5 -0.75
|
219
|
+
vertex 0.0 0.0 -0.75
|
220
|
+
endloop
|
221
|
+
endfacet
|
222
|
+
EOD
|
223
|
+
end
|
224
|
+
|
225
|
+
it "should call translate on each of it's Vertices" do
|
226
|
+
@facet.vertices[0].should_receive(:translate!).with(16.5, 9.5, 0.75)
|
227
|
+
@facet.vertices[1].should_receive(:translate!).with(16.5, 9.5, 0.75)
|
228
|
+
@facet.vertices[2].should_receive(:translate!).with(16.5, 9.5, 0.75)
|
229
|
+
|
230
|
+
@facet.translate!(16.5, 9.5, 0.75)
|
231
|
+
end
|
232
|
+
end
|
257
233
|
end
|
data/spec/line_spec.rb
CHANGED
@@ -37,115 +37,33 @@ describe Line do
|
|
37
37
|
|
38
38
|
describe "#intersection_at_z" do
|
39
39
|
context "for a line that intersects the target Z plane" do
|
40
|
-
context "and
|
40
|
+
context "and spans both positive and negative space" do
|
41
41
|
context "with a positive Z vector" do
|
42
42
|
before do
|
43
|
-
@line = Line.new(Vertex.new(
|
44
|
-
end
|
45
|
-
|
46
|
-
it "should return a a Point" do
|
47
|
-
@line.intersection_at_z(3.0).should be_a Point
|
43
|
+
@line = Line.new(Vertex.new(-1.0, 1.0, 1.0), Vertex.new(1.0, 1.0, -1.0))
|
48
44
|
end
|
49
45
|
|
50
46
|
it "should return a Point representing the intersection" do
|
51
|
-
@line.intersection_at_z(
|
52
|
-
@line.intersection_at_z(
|
53
|
-
@line.intersection_at_z(
|
47
|
+
@line.intersection_at_z(0).x.should == 0.0
|
48
|
+
@line.intersection_at_z(0).y.should == 1.0
|
49
|
+
@line.intersection_at_z(0).z.should == 0.0
|
54
50
|
end
|
55
51
|
end
|
56
52
|
|
57
53
|
context "with a negative Z vector" do
|
58
54
|
before do
|
59
|
-
@line = Line.new(Vertex.new(
|
55
|
+
@line = Line.new(Vertex.new(1.0, 1.0, 1.0), Vertex.new(-1.0, -1.0, -1.0))
|
60
56
|
end
|
61
57
|
|
62
58
|
it "should return a Point representing the intersection" do
|
63
|
-
@line.intersection_at_z(
|
64
|
-
@line.intersection_at_z(
|
65
|
-
@line.intersection_at_z(
|
66
|
-
end
|
67
|
-
end
|
68
|
-
end
|
69
|
-
|
70
|
-
context "and is located away from the origin" do
|
71
|
-
context "with a positive Z vector" do
|
72
|
-
before do
|
73
|
-
@line = Line.new(Vertex.new(7.0, 7.0, 1.0), Vertex.new(7.0, 7.0, 7.0))
|
74
|
-
end
|
75
|
-
|
76
|
-
it "should return a Point representing the intersection" do
|
77
|
-
@line.intersection_at_z(4.0).x.should == 7.0
|
78
|
-
@line.intersection_at_z(4.0).y.should == 7.0
|
79
|
-
@line.intersection_at_z(4.0).z.should == 4.0
|
80
|
-
end
|
81
|
-
end
|
82
|
-
|
83
|
-
context "with a negative Z vector" do
|
84
|
-
before do
|
85
|
-
@line = Line.new(Vertex.new(7.0, 7.0, 7.0), Vertex.new(1.0, 1.0, 1.0))
|
86
|
-
end
|
87
|
-
|
88
|
-
it "should return a Point representing the intersection" do
|
89
|
-
@line.intersection_at_z(4.0).x.should == 4.0
|
90
|
-
@line.intersection_at_z(4.0).y.should == 4.0
|
91
|
-
@line.intersection_at_z(4.0).z.should == 4.0
|
59
|
+
@line.intersection_at_z(0).x.should == 0
|
60
|
+
@line.intersection_at_z(0).y.should == 0
|
61
|
+
@line.intersection_at_z(0).z.should == 0
|
92
62
|
end
|
93
63
|
end
|
94
64
|
end
|
95
65
|
end
|
96
|
-
|
97
|
-
context "and is located in negative space" do
|
98
|
-
context "with a negative Z vector" do
|
99
|
-
before do
|
100
|
-
@line = Line.new(Vertex.new(-1.0, -1.0, -1.0), Vertex.new(-7.0, -7.0, -7.0))
|
101
|
-
end
|
102
|
-
|
103
|
-
it "should return a Point representing the intersection" do
|
104
|
-
@line.intersection_at_z(-4.0).x.should == -4.0
|
105
|
-
@line.intersection_at_z(-4.0).y.should == -4.0
|
106
|
-
@line.intersection_at_z(-4.0).z.should == -4.0
|
107
|
-
end
|
108
|
-
end
|
109
|
-
|
110
|
-
context "with a positive Z vector" do
|
111
|
-
before do
|
112
|
-
@line = Line.new(Vertex.new(-7.0, -7.0, -7.0), Vertex.new(-1.0, -1.0, -1.0))
|
113
|
-
end
|
114
|
-
|
115
|
-
it "should return a Point representing the intersection" do
|
116
|
-
@line.intersection_at_z(-4.0).x.should == -4.0
|
117
|
-
@line.intersection_at_z(-4.0).y.should == -4.0
|
118
|
-
@line.intersection_at_z(-4.0).z.should == -4.0
|
119
|
-
end
|
120
|
-
end
|
121
|
-
end
|
122
|
-
|
123
|
-
context "and spans both positive and negative space" do
|
124
|
-
context "with a positive Z vector" do
|
125
|
-
before do
|
126
|
-
@line = Line.new(Vertex.new(-1.0, 1.0, 1.0), Vertex.new(1.0, 1.0, -1.0))
|
127
|
-
end
|
128
|
-
|
129
|
-
it "should return a Point representing the intersection" do
|
130
|
-
@line.intersection_at_z(0).x.should == 0.0
|
131
|
-
@line.intersection_at_z(0).y.should == 1.0
|
132
|
-
@line.intersection_at_z(0).z.should == 0.0
|
133
|
-
end
|
134
|
-
end
|
135
66
|
|
136
|
-
context "with a negative Z vector" do
|
137
|
-
before do
|
138
|
-
@line = Line.new(Vertex.new(1.0, 1.0, 1.0), Vertex.new(-1.0, -1.0, -1.0))
|
139
|
-
end
|
140
|
-
|
141
|
-
it "should return a Point representing the intersection" do
|
142
|
-
@line.intersection_at_z(0).x.should == 0
|
143
|
-
@line.intersection_at_z(0).y.should == 0
|
144
|
-
@line.intersection_at_z(0).z.should == 0
|
145
|
-
end
|
146
|
-
end
|
147
|
-
end
|
148
|
-
|
149
67
|
context "for a line that lies on the target Z plane" do
|
150
68
|
before do
|
151
69
|
@line = Line.new(Vertex.new(0.0, 0.0, 3.0), Vertex.new(0.0, 6.0, 3.0))
|
@@ -182,9 +100,9 @@ describe Line do
|
|
182
100
|
describe "#to_svg_path" do
|
183
101
|
it "should return a string containing an SVG path" do
|
184
102
|
line = Line.new(Vertex.new(0.0, 0.0, 0.0), Vertex.new(1.0, 1.0, 1.0))
|
185
|
-
expected_output = '<path d="M 0.0 0.0 L 1.0 1.0" fill="none" stroke="black" stroke-width="
|
103
|
+
expected_output = '<path d="M 0.0 0.0 L 1.0 1.0" fill="none" stroke="black" stroke-width="0.005" />'
|
186
104
|
|
187
|
-
line.to_svg_path.should == expected_output
|
105
|
+
line.to_svg_path(:inches).should == expected_output
|
188
106
|
end
|
189
107
|
end
|
190
108
|
end
|
data/spec/point_spec.rb
CHANGED
@@ -64,4 +64,25 @@ describe Point do
|
|
64
64
|
(Point.new(1.0, 2.0, -3.1) == Point.new(1.0, 2.0, -3.2)).should be_false
|
65
65
|
end
|
66
66
|
end
|
67
|
+
|
68
|
+
describe "#translate!" do
|
69
|
+
before do
|
70
|
+
@point = Point.new(1.0, 1.0, 1.0)
|
71
|
+
end
|
72
|
+
|
73
|
+
it "should add the supplied value to X" do
|
74
|
+
@point.translate!(16.5, 9.5, 0.75)
|
75
|
+
@point.x.should == 17.5
|
76
|
+
end
|
77
|
+
|
78
|
+
it "should add the supplied value to Y" do
|
79
|
+
@point.translate!(16.5, 9.5, 0.75)
|
80
|
+
@point.y.should == 10.5
|
81
|
+
end
|
82
|
+
|
83
|
+
it "should add the supplied value to Z" do
|
84
|
+
@point.translate!(16.5, 9.5, 0.75)
|
85
|
+
@point.z.should == 1.75
|
86
|
+
end
|
87
|
+
end
|
67
88
|
end
|
data/spec/polyline_spec.rb
CHANGED
@@ -8,13 +8,13 @@ describe Polyline do
|
|
8
8
|
|
9
9
|
expected_svg = '<?xml version="1.0" standalone="no"?>' + "\n"
|
10
10
|
expected_svg += '<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">' + "\n"
|
11
|
-
expected_svg += '<svg xmlns="http://www.w3.org/2000/svg" version="1.1">' + "\n"
|
12
|
-
expected_svg += ' <g transform="translate(
|
13
|
-
expected_svg += " #{line.to_svg_path}\n"
|
11
|
+
expected_svg += '<svg x="0" y="0" width="20in" height="30in" viewBox="0 0 20 30" xmlns="http://www.w3.org/2000/svg" version="1.1">' + "\n"
|
12
|
+
expected_svg += ' <g transform="translate(1in,2in)">' + "\n"
|
13
|
+
expected_svg += " #{line.to_svg_path(:inches)}\n"
|
14
14
|
expected_svg += ' </g>' + "\n"
|
15
15
|
expected_svg += '</svg>'
|
16
16
|
|
17
|
-
polyline.to_svg(
|
17
|
+
polyline.to_svg(20, 30, :inches, 1, 2).should == expected_svg
|
18
18
|
end
|
19
19
|
end
|
20
20
|
end
|
data/spec/solid_spec.rb
CHANGED
@@ -79,7 +79,130 @@ describe Solid do
|
|
79
79
|
it "should return a Polyline" do
|
80
80
|
@solid.slice_at_z(0).should be_a Polyline
|
81
81
|
end
|
82
|
+
end
|
83
|
+
|
84
|
+
describe "#get_bounds" do
|
85
|
+
before do
|
86
|
+
@solid = Solid.parse(<<-EOD)
|
87
|
+
solid y-axis-spacer
|
88
|
+
facet normal 0.0 0.0 -1.0
|
89
|
+
outer loop
|
90
|
+
vertex -16.5 0.0 -0.75
|
91
|
+
vertex 0.0 -9.5 -0.75
|
92
|
+
vertex 0.0 0.0 -0.75
|
93
|
+
endloop
|
94
|
+
endfacet
|
95
|
+
facet normal -0.0 1.0 0.0
|
96
|
+
outer loop
|
97
|
+
vertex 0.0 -1.87 0.0
|
98
|
+
vertex 16.5 -1.87 -0.13
|
99
|
+
vertex 0.0 1.87 -0.13
|
100
|
+
endloop
|
101
|
+
endfacet
|
102
|
+
endsolid y-axis-spacer
|
103
|
+
EOD
|
104
|
+
end
|
105
|
+
|
106
|
+
it "should return an array" do
|
107
|
+
@solid.get_bounds.should be_a Array
|
108
|
+
end
|
109
|
+
|
110
|
+
it "should return a point with the smallest bounds" do
|
111
|
+
@solid.get_bounds[0].x.should == -16.5
|
112
|
+
@solid.get_bounds[0].y.should == -9.5
|
113
|
+
@solid.get_bounds[0].z.should == -0.75
|
114
|
+
end
|
82
115
|
|
116
|
+
it "should return a point with the largest bounds" do
|
117
|
+
@solid.get_bounds[1].x.should == 16.5
|
118
|
+
@solid.get_bounds[1].y.should == 1.87
|
119
|
+
@solid.get_bounds[1].z.should == 0.0
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
describe "#translate!" do
|
124
|
+
before do
|
125
|
+
@solid = Solid.parse(<<-EOD)
|
126
|
+
solid y-axis-spacer
|
127
|
+
facet normal 0.0 0.0 -1.0
|
128
|
+
outer loop
|
129
|
+
vertex -16.5 0.0 -0.75
|
130
|
+
vertex 0.0 -9.5 -0.75
|
131
|
+
vertex 0.0 0.0 -0.75
|
132
|
+
endloop
|
133
|
+
endfacet
|
134
|
+
facet normal -0.0 1.0 0.0
|
135
|
+
outer loop
|
136
|
+
vertex 0.0 -1.87 0.0
|
137
|
+
vertex 16.5 -1.87 -0.13
|
138
|
+
vertex 0.0 1.87 -0.13
|
139
|
+
endloop
|
140
|
+
endfacet
|
141
|
+
endsolid y-axis-spacer
|
142
|
+
EOD
|
143
|
+
end
|
83
144
|
|
145
|
+
it "should call translate on each of it's Facets" do
|
146
|
+
@solid.facets[0].should_receive(:translate!).with(16.5, 9.5, 0.75)
|
147
|
+
@solid.facets[1].should_receive(:translate!).with(16.5, 9.5, 0.75)
|
148
|
+
|
149
|
+
@solid.translate!(16.5, 9.5, 0.75)
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
describe "#align_to_origin!" do
|
154
|
+
before do
|
155
|
+
@solid = Solid.parse(<<-EOD)
|
156
|
+
solid y-axis-spacer
|
157
|
+
facet normal 0.0 0.0 -1.0
|
158
|
+
outer loop
|
159
|
+
vertex -16.5 0.0 5.0
|
160
|
+
vertex 0.0 -9.5 10.0
|
161
|
+
vertex 0.0 0.0 5.0
|
162
|
+
endloop
|
163
|
+
endfacet
|
164
|
+
facet normal -0.0 1.0 0.0
|
165
|
+
outer loop
|
166
|
+
vertex 0.0 -1.87 5.0
|
167
|
+
vertex 16.5 -1.87 11.0
|
168
|
+
vertex 0.0 1.87 6.0
|
169
|
+
endloop
|
170
|
+
endfacet
|
171
|
+
endsolid y-axis-spacer
|
172
|
+
EOD
|
173
|
+
end
|
174
|
+
|
175
|
+
it "should translate solid so the lowermost XYZ edges are all 0.0" do
|
176
|
+
@solid.should_receive(:translate!).with(16.5, 9.5, -5.0)
|
177
|
+
@solid.align_to_origin!
|
178
|
+
end
|
179
|
+
end
|
180
|
+
|
181
|
+
describe "#center!" do
|
182
|
+
before do
|
183
|
+
@solid = Solid.parse(<<-EOD)
|
184
|
+
solid y-axis-spacer
|
185
|
+
facet normal 0.0 0.0 -1.0
|
186
|
+
outer loop
|
187
|
+
vertex -16.5 0.0 5.0
|
188
|
+
vertex 0.0 -9.5 10.0
|
189
|
+
vertex 0.0 0.0 5.0
|
190
|
+
endloop
|
191
|
+
endfacet
|
192
|
+
facet normal -0.0 1.0 0.0
|
193
|
+
outer loop
|
194
|
+
vertex 0.0 -1.87 5.0
|
195
|
+
vertex 17.5 -1.87 11.0
|
196
|
+
vertex 0.0 1.5 6.0
|
197
|
+
endloop
|
198
|
+
endfacet
|
199
|
+
endsolid y-axis-spacer
|
200
|
+
EOD
|
201
|
+
end
|
202
|
+
|
203
|
+
it "should translate solid so the lowermost XYZ edges are all 0.0" do
|
204
|
+
@solid.should_receive(:translate!).with(-0.5, 4.0, -8.0)
|
205
|
+
@solid.center!
|
206
|
+
end
|
84
207
|
end
|
85
208
|
end
|
data/spec/units_spec.rb
ADDED
@@ -0,0 +1,75 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Units do
|
4
|
+
describe ".name" do
|
5
|
+
it "should return 'inches' for :inches" do
|
6
|
+
Units.name(:inches).should == 'inches'
|
7
|
+
end
|
8
|
+
|
9
|
+
it "should return 'centimeters' for :centimeters" do
|
10
|
+
Units.name(:centimeters).should == 'centimeters'
|
11
|
+
end
|
12
|
+
|
13
|
+
it "should return 'millimeters' for :millimeters" do
|
14
|
+
Units.name(:millimeters).should == 'millimeters'
|
15
|
+
end
|
16
|
+
|
17
|
+
it "should return 'none' for :none" do
|
18
|
+
Units.name(:none).should == 'none'
|
19
|
+
end
|
20
|
+
|
21
|
+
it "should raise an exception if called with an unknown unit" do
|
22
|
+
lambda {
|
23
|
+
Units.name(:error)
|
24
|
+
}.should raise_error
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
describe ".svg_name" do
|
29
|
+
it "should return 'in' for :inches" do
|
30
|
+
Units.svg_name(:inches).should == 'in'
|
31
|
+
end
|
32
|
+
|
33
|
+
it "should return 'cm' for :centimeters" do
|
34
|
+
Units.svg_name(:centimeters).should == 'cm'
|
35
|
+
end
|
36
|
+
|
37
|
+
it "should return 'mm' for :millimeters" do
|
38
|
+
Units.svg_name(:millimeters).should == 'mm'
|
39
|
+
end
|
40
|
+
|
41
|
+
it "should return '' for :none" do
|
42
|
+
Units.svg_name(:none).should == ''
|
43
|
+
end
|
44
|
+
|
45
|
+
it "should raise an exception if called with an unknown unit" do
|
46
|
+
lambda {
|
47
|
+
Units.svg_name(:error)
|
48
|
+
}.should raise_error
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
describe ".stroke_width" do
|
53
|
+
it "should return 'in' for :inches" do
|
54
|
+
Units.stroke_width(:inches).should == 0.005
|
55
|
+
end
|
56
|
+
|
57
|
+
it "should return 'cm' for :centimeters" do
|
58
|
+
Units.stroke_width(:centimeters).should == 0.01
|
59
|
+
end
|
60
|
+
|
61
|
+
it "should return 'mm' for :millimeters" do
|
62
|
+
Units.stroke_width(:millimeters).should == 0.1
|
63
|
+
end
|
64
|
+
|
65
|
+
it "should return '' for :none" do
|
66
|
+
Units.stroke_width(:none).should == 0.1
|
67
|
+
end
|
68
|
+
|
69
|
+
it "should raise an exception if called with an unknown unit" do
|
70
|
+
lambda {
|
71
|
+
Units.stroke_width(:error)
|
72
|
+
}.should raise_error
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
metadata
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
name: triangular
|
3
3
|
version: !ruby/object:Gem::Version
|
4
4
|
prerelease:
|
5
|
-
version: 0.0.
|
5
|
+
version: 0.0.2
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
8
8
|
- Aaron Gough
|
@@ -10,7 +10,7 @@ autorequire:
|
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
12
|
|
13
|
-
date: 2011-10-
|
13
|
+
date: 2011-10-19 00:00:00 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: bundler
|
@@ -59,6 +59,7 @@ files:
|
|
59
59
|
- lib/triangular/point.rb
|
60
60
|
- lib/triangular/polyline.rb
|
61
61
|
- lib/triangular/solid.rb
|
62
|
+
- lib/triangular/units.rb
|
62
63
|
- lib/triangular/vector.rb
|
63
64
|
- lib/triangular/version.rb
|
64
65
|
- lib/triangular/vertex.rb
|
@@ -71,6 +72,7 @@ files:
|
|
71
72
|
- spec/solid_spec.rb
|
72
73
|
- spec/spec_helper.rb
|
73
74
|
- spec/triangular_spec.rb
|
75
|
+
- spec/units_spec.rb
|
74
76
|
- spec/vertex_spec.rb
|
75
77
|
- triangular.gemspec
|
76
78
|
homepage: http://rubygems.org/gems/triangular
|