Class: RADMesh::STL
- Inherits:
-
Object
- Object
- RADMesh::STL
- Defined in:
- lib/radmesh/stl.rb
Overview
Class representing an STL file. It has factes and stats.
Instance Method Summary collapse
-
#[](idx) ⇒ Hash
Get a facet of given index.
-
#calculate_volume! ⇒ STL
Calculate volume and save it to the stats.
-
#check_facets_exact! ⇒ STL
Check each facet of the mesh for its 3 neighbors.
-
#check_facets_nearby!(tolerance) ⇒ STL
Checks each unconnected facet of the mesh for facets that are almost connected but not quite.
-
#clear_error! ⇒ STL
Clear the error flag on internal ADMesh’s STL structure.
-
#clone ⇒ STL
Crete a deep copy of the object.
-
#each_facet ⇒ Enumerator
get an enumerator for each facet.
-
#error? ⇒ Boolean
Checks if there is an error flag on internal ADMesh’s STL structure.
-
#fill_holes! ⇒ STL
Fill holes in the mesh by adding facets.
-
#fix_normal_directions! ⇒ STL
Check and fix if necessary the directions of the facets.
-
#fix_normal_values! ⇒ STL
Checks and fixes if necessary the normal vectors of every facet.
-
#generate_shared_vertices! ⇒ STL
Generates shared vertices.
-
#initialize(path = nil) ⇒ STL
constructor
A new instance of STL.
-
#mirror!(*args) ⇒ STL
Mirror the mesh about the specified plane.
-
#mirror_xy! ⇒ STL
Mirror the mesh about the XY plane.
-
#mirror_xz! ⇒ STL
Mirror the mesh about the XZ plane.
-
#mirror_yz! ⇒ STL
Mirror the mesh about the YZ plane.
-
#open_merge!(path) ⇒ STL
Merge the specified file with self.
-
#remove_unconnected_facets! ⇒ STL
Removes facets that have 0 neighbors.
-
#repair!(opts = {}) ⇒ STL
Complex repair of the mesh.
-
#reverse_all_facets! ⇒ STL
Reverses the directions of all of the facets and normals.
-
#rotate!(axis, angle) ⇒ STL
Rotate the entire mesh about the given axis by the given number of degrees.
-
#rotate_x!(angle) ⇒ STL
Rotate the entire mesh about the X axis by the given number of degrees.
-
#rotate_y!(angle) ⇒ STL
Rotate the entire mesh about the Y axis by the given number of degrees.
-
#rotate_z!(angle) ⇒ STL
Rotate the entire mesh about the Z axis by the given number of degrees.
-
#scale!(factor) ⇒ STL
Scale the mesh by the given factor.
-
#scale_versor!(*args) ⇒ STL
Scale the mesh by the given versor.
-
#size ⇒ Fixnum
Get the number of facets.
-
#stats ⇒ Hash
Get the statistics about the STL file.
-
#to_a ⇒ Array<Hash>
Get an array of facets.
-
#to_s ⇒ String
Get a String representation of STL.
-
#translate!(*args) ⇒ STL
Translate the mesh to the position x,y,z.
-
#translate_relative!(*args) ⇒ STL
Translate the mesh by a vector x,y,z.
-
#verify_neighbors! ⇒ STL
Returns itself.
-
#write_ascii(path, label = 'admesh') ⇒ STL
Save the contents of the instance to an ASCII STL file.
-
#write_binary(path, label = 'admesh') ⇒ STL
Save the contents of the instance to a binary STL file.
-
#write_dxf(path, label = 'admesh') ⇒ STL
Save the contents of the instance to a DXF file.
-
#write_obj(path) ⇒ STL
Save the contents of the instance to an OBJ file.
-
#write_off(path) ⇒ STL
Save the contents of the instance to an OFF file.
-
#write_vrml(path) ⇒ STL
Save the contents of the instance to a VRML file.
Constructor Details
#initialize(path = nil) ⇒ STL
Returns a new instance of STL.
32 33 34 35 36 37 38 39 40 |
# File 'lib/radmesh/stl.rb', line 32 def initialize(path = nil) @stl_ptr = FFI::MemoryPointer.new CADMesh::STLFile, 1 @stl_value = CADMesh::STLFile.new @stl_ptr init if path.nil? open path unless path.nil? ObjectSpace.define_finalizer self, self.class.finalize(@stl_ptr) @exact = false @shared = false end |
Instance Method Details
#[](idx) ⇒ Hash
Get a facet of given index
636 637 638 639 640 641 642 |
# File 'lib/radmesh/stl.rb', line 636 def [](idx) raise IndexError, "index #{idx} outside of STL bounds: 0..#{size - 1}" if idx >= size ptr = @stl_value[:facet_start].to_ptr + (idx * CADMesh::STLFacet.size) value = CADMesh::STLFacet.new ptr value.to_hash end |
#calculate_volume! ⇒ STL
There is also the same method without ! working as expected. It is not in this reference guide, because it is automatically generated.
Calculate volume and save it to the stats
98 99 100 101 |
# File 'lib/radmesh/stl.rb', line 98 def calculate_volume! CADMesh.stl_calculate_volume(@stl_ptr) self end |
#check_facets_exact! ⇒ STL
There is also the same method without ! working as expected. It is not in this reference guide, because it is automatically generated.
Check each facet of the mesh for its 3 neighbors.
Since each facet is a triangle, there should be exactly 3 neighboring facets for every facet in the mesh. Since the mesh defines a solid, there should be no unconnected edges in the mesh. When this option is specified, the 3 neighbors of every facet are searched for and, if found, the neighbors are added to an internal list that keeps track of the neighbors of each facet. A facet is only considered a neighbor if two of its vertices EXACTLY match two of the vertices of another facet. That means that there must be 0 difference between the x, y, and z coordinates of the two vertices of the first facet and the two vertices of the second facet.
Degenerate facets (facets with two or more vertices equal to each other) are removed during the exact check. No other changes are made to the mesh.
195 196 197 198 199 |
# File 'lib/radmesh/stl.rb', line 195 def check_facets_exact! CADMesh.stl_check_facets_exact(@stl_ptr) @exact = true self end |
#check_facets_nearby!(tolerance) ⇒ STL
There is also the same method without ! working as expected. It is not in this reference guide, because it is automatically generated.
Checks each unconnected facet of the mesh for facets that are almost connected but not quite.
Due to round-off errors and other factors, it is common for a mesh to have facets with neighbors that are very close but don’t match exactly. Often, this difference is only in the 8th decimal place of the vertices, but these facets will not show up as neighbors during the exact check. This option finds these nearby neighbors and it changes their vertices so that they match exactly. #check_facets_exact! should always be called before the nearby check, so only facets that remain unconnected after the exact check are candidates for the nearby check.
219 220 221 222 |
# File 'lib/radmesh/stl.rb', line 219 def check_facets_nearby!(tolerance) CADMesh.stl_check_facets_nearby(@stl_ptr, tolerance) self end |
#clear_error! ⇒ STL
Clear the error flag on internal ADMesh’s STL structure
Only use this, if you know what you are doing.
66 67 68 69 |
# File 'lib/radmesh/stl.rb', line 66 def clear_error! CADMesh.stl_clear_error(@stl_ptr) self end |
#clone ⇒ STL
Crete a deep copy of the object
708 709 710 711 712 713 714 715 716 |
# File 'lib/radmesh/stl.rb', line 708 def clone c = clone_props! self.class.new clone_stats! c CADMesh.stl_reallocate(c.stl_ptr) clone_facets! c clone_neighbors! c c.error_control_proc(NoMemoryError, 'could not clone').call c end |
#each_facet ⇒ Enumerator
get an enumerator for each facet
647 648 649 650 651 652 653 654 |
# File 'lib/radmesh/stl.rb', line 647 def each_facet return to_enum(:each_facet) unless block_given? idx = 0 while idx < size yield self[idx] idx += 1 end end |
#error? ⇒ Boolean
Checks if there is an error flag on internal ADMesh’s STL structure
57 58 59 |
# File 'lib/radmesh/stl.rb', line 57 def error? CADMesh.stl_get_error(@stl_ptr) == 1 end |
#fill_holes! ⇒ STL
There is also the same method without ! working as expected. It is not in this reference guide, because it is automatically generated.
Fill holes in the mesh by adding facets.
This should be called after #check_facets_exact! and #check_facets_nearby!. If there are still unconnected facets, then facets will be added to the mesh, connecting the unconnected facets, until all of the holes have been filled. This is guaranteed to completely fix all unconnected facets. However, the resulting mesh may or may not be what the user expects.
256 257 258 259 |
# File 'lib/radmesh/stl.rb', line 256 def fill_holes! CADMesh.stl_fill_holes(@stl_ptr) self end |
#fix_normal_directions! ⇒ STL
There is also the same method without ! working as expected. It is not in this reference guide, because it is automatically generated.
Check and fix if necessary the directions of the facets.
This only deals with whether the vertices of all the facets are oriented clockwise or counterclockwise, it doesn’t check or modify the value of the normal vector. Every facet should have its vertices defined in a counterclockwise order when looked at from the outside of the part. This option will orient all of the vertices so that they are all facing in the same direction. However, it it possible that this option will make all of the facets facet inwards instead of outwards. The algorithm tries to get a clue of which direction is inside and outside by checking the value of the normal vector so the chance is very good that the resulting mesh will be correct. However, it doesn’t explicitly check to find which direction is inside and which is outside.
277 278 279 280 |
# File 'lib/radmesh/stl.rb', line 277 def fix_normal_directions! CADMesh.stl_fix_normal_directions(@stl_ptr) self end |
#fix_normal_values! ⇒ STL
There is also the same method without ! working as expected. It is not in this reference guide, because it is automatically generated.
Checks and fixes if necessary the normal vectors of every facet.
The normal vector will point outward for a counterclockwise facet. The length of the normal vector will be 1.
289 290 291 292 |
# File 'lib/radmesh/stl.rb', line 289 def fix_normal_values! CADMesh.stl_fix_normal_values(@stl_ptr) self end |
#generate_shared_vertices! ⇒ STL
There is also the same method without ! working as expected. It is not in this reference guide, because it is automatically generated.
Generates shared vertices.
Those are needed for some of the output formats. No need to call this manually.
314 315 316 317 318 319 |
# File 'lib/radmesh/stl.rb', line 314 def generate_shared_vertices! check_facets_exact! unless @exact CADMesh.stl_generate_shared_vertices(@stl_ptr) @shared = true self end |
#mirror!(*args) ⇒ STL
There is also the same method without ! working as expected. It is not in this reference guide, because it is automatically generated.
Mirror the mesh about the specified plane.
Mirroring involves reversing the sign of all of the coordinates in a particular axis. For example, to mirror a mesh about the XY plane, the signs of all of the Z coordinates in the mesh are reversed.
519 520 521 522 523 524 525 526 527 528 529 |
# File 'lib/radmesh/stl.rb', line 519 def mirror!(*args) args = args[0] if args.size == 1 raise ArgumentError, "wrong number of arguments (#{args.size} for 2)" if args.size != 2 args.sort! begin send("mirror_#{args[0]}#{args[1]}!") rescue raise ArgumentError, "invalid axis pair #{args[0]}#{args[1]}" end end |
#mirror_xy! ⇒ STL
There is also the same method without ! working as expected. It is not in this reference guide, because it is automatically generated.
Mirror the mesh about the XY plane.
Mirroring involves reversing the sign of all of the coordinates in a particular axis. For example, to mirror a mesh about the XY plane, the signs of all of the Z coordinates in the mesh are reversed.
482 483 484 485 |
# File 'lib/radmesh/stl.rb', line 482 def mirror_xy! CADMesh.stl_mirror_xy(@stl_ptr) self end |
#mirror_xz! ⇒ STL
There is also the same method without ! working as expected. It is not in this reference guide, because it is automatically generated.
Mirror the mesh about the XZ plane.
Mirroring involves reversing the sign of all of the coordinates in a particular axis. For example, to mirror a mesh about the XY plane, the signs of all of the Z coordinates in the mesh are reversed.
504 505 506 507 |
# File 'lib/radmesh/stl.rb', line 504 def mirror_xz! CADMesh.stl_mirror_xz(@stl_ptr) self end |
#mirror_yz! ⇒ STL
There is also the same method without ! working as expected. It is not in this reference guide, because it is automatically generated.
Mirror the mesh about the YZ plane.
Mirroring involves reversing the sign of all of the coordinates in a particular axis. For example, to mirror a mesh about the XY plane, the signs of all of the Z coordinates in the mesh are reversed.
493 494 495 496 |
# File 'lib/radmesh/stl.rb', line 493 def mirror_yz! CADMesh.stl_mirror_yz(@stl_ptr) self end |
#open_merge!(path) ⇒ STL
There is also the same method without ! working as expected. It is not in this reference guide, because it is automatically generated.
Due to some limitations in the C ADMesh library, when the exception occurs it is no longer safe to touch the object. If you are not sure the file is readable and parsable, check before, or use the method without ! and throw the object away when necessary.
Merge the specified file with self.
No translation is done, so if, for example, a file was merged with itself, the resulting file would end up with two meshes exactly the same, occupying exactly the same space. So generally, translations need to be done to the files to be merged so that when the two meshes are merged into one, the two resulting parts are properly spaced. If you know the nature of the parts to be merged, it is possible to “nest” one part inside the other. Note, however, that no warnings will be given if one part intersects with the other.
It is possible to place one part against another, with no space in between, but you will still end up with two separately defined parts. If such a mesh was made on a rapid-prototyping machine, the result would depend on the nature of the machine. Machines that use a photopolymer would produce a single solid part because the two parts would be “bonded” during the build process. Machines that use a cutting process would yield two or more parts.
559 560 561 562 563 |
# File 'lib/radmesh/stl.rb', line 559 def open_merge!(path) CADMesh.stl_open_merge(@stl_ptr, path) error_control_proc(IOError, "Could not open #{path}").call self end |
#remove_unconnected_facets! ⇒ STL
There is also the same method without ! working as expected. It is not in this reference guide, because it is automatically generated.
Removes facets that have 0 neighbors.
You should probably call #check_facets_nearby! before to get better results.
231 232 233 234 |
# File 'lib/radmesh/stl.rb', line 231 def remove_unconnected_facets! CADMesh.stl_remove_unconnected_facets(@stl_ptr) self end |
#repair!(opts = {}) ⇒ STL
There is also the same method without ! working as expected. It is not in this reference guide, because it is automatically generated.
Complex repair of the mesh.
Does various repairing procedures on the mesh depending on the options.
617 618 619 620 621 622 623 624 |
# File 'lib/radmesh/stl.rb', line 617 def repair!(opts = {}) opts = self.class.default_repair_opts.merge(opts) CADMesh.stl_repair(@stl_ptr, *self.class.opts_to_int_array(opts)) error_control_proc(RuntimeError, 'something went wrong during repair').call @exact = true if self.class.exact? opts self end |
#reverse_all_facets! ⇒ STL
There is also the same method without ! working as expected. It is not in this reference guide, because it is automatically generated.
Reverses the directions of all of the facets and normals.
If #fix_normal_directions! ended up making all of the facets facing inwards instead of outwards, then this method can be used to reverse all of the facets
302 303 304 305 |
# File 'lib/radmesh/stl.rb', line 302 def reverse_all_facets! CADMesh.stl_reverse_all_facets(@stl_ptr) self end |
#rotate!(axis, angle) ⇒ STL
There is also the same method without ! working as expected. It is not in this reference guide, because it is automatically generated.
Rotate the entire mesh about the given axis by the given number of degrees.
The rotation is counter-clockwise about the axis as seen by looking along the positive axis towards the origin.
467 468 469 470 471 |
# File 'lib/radmesh/stl.rb', line 467 def rotate!(axis, angle) send("rotate_#{axis}!", angle) rescue raise ArgumentError, "invalid axis #{axis}" end |
#rotate_x!(angle) ⇒ STL
There is also the same method without ! working as expected. It is not in this reference guide, because it is automatically generated.
Rotate the entire mesh about the X axis by the given number of degrees.
The rotation is counter-clockwise about the axis as seen by looking along the positive axis towards the origin.
428 429 430 431 |
# File 'lib/radmesh/stl.rb', line 428 def rotate_x!(angle) CADMesh.stl_rotate_x(@stl_ptr, angle) self end |
#rotate_y!(angle) ⇒ STL
There is also the same method without ! working as expected. It is not in this reference guide, because it is automatically generated.
Rotate the entire mesh about the Y axis by the given number of degrees.
The rotation is counter-clockwise about the axis as seen by looking along the positive axis towards the origin.
440 441 442 443 |
# File 'lib/radmesh/stl.rb', line 440 def rotate_y!(angle) CADMesh.stl_rotate_y(@stl_ptr, angle) self end |
#rotate_z!(angle) ⇒ STL
There is also the same method without ! working as expected. It is not in this reference guide, because it is automatically generated.
Rotate the entire mesh about the Z axis by the given number of degrees.
The rotation is counter-clockwise about the axis as seen by looking along the positive axis towards the origin.
452 453 454 455 |
# File 'lib/radmesh/stl.rb', line 452 def rotate_z!(angle) CADMesh.stl_rotate_z(@stl_ptr, angle) self end |
#scale!(factor) ⇒ STL
There is also the same method without ! working as expected. It is not in this reference guide, because it is automatically generated.
Scale the mesh by the given factor.
This multiplies all of the coordinates by the specified number. This method could be used to change the “units” (there are no units explicitly specified in an STL file) of the mesh. For example, to change a part from inches to millimeters, just use factor 25.4.
393 394 395 396 |
# File 'lib/radmesh/stl.rb', line 393 def scale!(factor) CADMesh.stl_scale(@stl_ptr, factor) self end |
#scale_versor!(*args) ⇒ STL
There is also the same method without ! working as expected. It is not in this reference guide, because it is automatically generated.
Scale the mesh by the given versor.
This scales the mesh in different dimensions.
410 411 412 413 414 415 416 417 |
# File 'lib/radmesh/stl.rb', line 410 def scale_versor!(*args) vec = self.class.vector_probe args, 1 FFI::MemoryPointer.new(:float, 3) do |p| p.write_array_of_float(vec) CADMesh.stl_scale_versor(@stl_ptr, p) end self end |
#size ⇒ Fixnum
Get the number of facets
629 630 631 |
# File 'lib/radmesh/stl.rb', line 629 def size @stl_value[:stats][:number_of_facets] end |
#stats ⇒ Hash
Get the statistics about the STL file
90 91 92 |
# File 'lib/radmesh/stl.rb', line 90 def stats @stl_value[:stats].to_hash end |
#to_a ⇒ Array<Hash>
Get an array of facets
659 660 661 |
# File 'lib/radmesh/stl.rb', line 659 def to_a each_facet.to_a end |
#to_s ⇒ String
Get a String representation of STL
666 667 668 |
# File 'lib/radmesh/stl.rb', line 666 def to_s "#<RADMesh::STL header=\"#{stats[:header]}\">" end |
#translate!(*args) ⇒ STL
There is also the same method without ! working as expected. It is not in this reference guide, because it is automatically generated.
Translate the mesh to the position x,y,z.
This moves the minimum x, y, and z values of the mesh to the specified position.
359 360 361 362 363 |
# File 'lib/radmesh/stl.rb', line 359 def translate!(*args) vec = self.class.vector_probe args CADMesh.stl_translate(@stl_ptr, vec[0], vec[1], vec[2]) self end |
#translate_relative!(*args) ⇒ STL
There is also the same method without ! working as expected. It is not in this reference guide, because it is automatically generated.
Translate the mesh by a vector x,y,z.
This moves the mesh relatively to it’s current position.
377 378 379 380 381 |
# File 'lib/radmesh/stl.rb', line 377 def translate_relative!(*args) vec = self.class.vector_probe args CADMesh.stl_translate_relative(@stl_ptr, vec[0], vec[1], vec[2]) self end |
#verify_neighbors! ⇒ STL
Check what does this actually do :)
There is also the same method without ! working as expected. It is not in this reference guide, because it is automatically generated.
Returns itself
240 241 242 243 |
# File 'lib/radmesh/stl.rb', line 240 def verify_neighbors! CADMesh.stl_verify_neighbors(@stl_ptr) self end |
#write_ascii(path, label = 'admesh') ⇒ STL
Save the contents of the instance to an ASCII STL file
109 110 111 112 113 |
# File 'lib/radmesh/stl.rb', line 109 def write_ascii(path, label = 'admesh') CADMesh.stl_write_ascii(@stl_ptr, path, label) error_control_proc(IOError, "Could not write to #{path}").call self end |
#write_binary(path, label = 'admesh') ⇒ STL
Save the contents of the instance to a binary STL file
121 122 123 124 125 |
# File 'lib/radmesh/stl.rb', line 121 def write_binary(path, label = 'admesh') CADMesh.stl_write_binary(@stl_ptr, path, label) error_control_proc(IOError, "Could not write to #{path}").call self end |
#write_dxf(path, label = 'admesh') ⇒ STL
Save the contents of the instance to a DXF file
157 158 159 160 161 |
# File 'lib/radmesh/stl.rb', line 157 def write_dxf(path, label = 'admesh') CADMesh.stl_write_dxf(@stl_ptr, path, label) error_control_proc(IOError, "Could not write to #{path}").call self end |
#write_obj(path) ⇒ STL
Save the contents of the instance to an OBJ file
132 133 134 135 136 137 |
# File 'lib/radmesh/stl.rb', line 132 def write_obj(path) generate_shared_vertices! unless @shared CADMesh.stl_write_obj(@stl_ptr, path) error_control_proc(IOError, "Could not write to #{path}").call self end |
#write_off(path) ⇒ STL
Save the contents of the instance to an OFF file
144 145 146 147 148 149 |
# File 'lib/radmesh/stl.rb', line 144 def write_off(path) generate_shared_vertices! unless @shared CADMesh.stl_write_off(@stl_ptr, path) error_control_proc(IOError, "Could not write to #{path}").call self end |
#write_vrml(path) ⇒ STL
Save the contents of the instance to a VRML file
168 169 170 171 172 173 |
# File 'lib/radmesh/stl.rb', line 168 def write_vrml(path) generate_shared_vertices! unless @shared CADMesh.stl_write_vrml(@stl_ptr, path) error_control_proc(IOError, "Could not write to #{path}").call self end |