mirror of
				https://github.com/SoftFever/OrcaSlicer.git
				synced 2025-11-02 20:51:23 -07:00 
			
		
		
		
	Refactoring: moved Slic3r::STL and Slic3r::AMF to Slic3r::Format::*
This commit is contained in:
		
							parent
							
								
									2a86932cfe
								
							
						
					
					
						commit
						959230b099
					
				
					 9 changed files with 18 additions and 18 deletions
				
			
		
							
								
								
									
										210
									
								
								lib/Slic3r/Format/STL.pm
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										210
									
								
								lib/Slic3r/Format/STL.pm
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,210 @@
 | 
			
		|||
package Slic3r::Format::STL;
 | 
			
		||||
use Moo;
 | 
			
		||||
 | 
			
		||||
use Slic3r::Geometry qw(X Y Z triangle_normal);
 | 
			
		||||
use XXX;
 | 
			
		||||
 | 
			
		||||
sub read_file {
 | 
			
		||||
    my $self = shift;
 | 
			
		||||
    my ($file) = @_;
 | 
			
		||||
    
 | 
			
		||||
    open my $fh, '<', $file or die "Failed to open $file\n";
 | 
			
		||||
    
 | 
			
		||||
    # let's detect whether file is ASCII or binary
 | 
			
		||||
    my $mode;
 | 
			
		||||
    {
 | 
			
		||||
        my $size = +(stat $fh)[7];
 | 
			
		||||
        $mode = 'ascii' if $size < 80 + 4;
 | 
			
		||||
        
 | 
			
		||||
        # skip binary header
 | 
			
		||||
        seek $fh, 80, 0;
 | 
			
		||||
        read $fh, my $buf, 4;
 | 
			
		||||
        my $triangle_count = unpack 'L', $buf;
 | 
			
		||||
        die "STL file seems invalid, could not read facet count\n" if !defined $triangle_count;
 | 
			
		||||
        my $expected_size =
 | 
			
		||||
            + 80 # header
 | 
			
		||||
            +  4 # count
 | 
			
		||||
            + $triangle_count * (
 | 
			
		||||
                + 4   # normal, pt,pt,pt (vectors)
 | 
			
		||||
                  * 4   # bytes per value
 | 
			
		||||
                  * 3   # values per vector
 | 
			
		||||
                + 2 # the trailing 'short'
 | 
			
		||||
            );
 | 
			
		||||
        $mode = ($size == $expected_size) ? 'binary' : 'ascii';
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    my $facets = [];
 | 
			
		||||
    $mode eq 'ascii'
 | 
			
		||||
        ? _read_ascii($fh, $facets)
 | 
			
		||||
        : _read_binary($fh, $facets);
 | 
			
		||||
    close $fh;
 | 
			
		||||
    
 | 
			
		||||
    my $vertices = [];
 | 
			
		||||
    {
 | 
			
		||||
        my %vertices_map = ();    # given a vertex's coordinates, what's its index?
 | 
			
		||||
        my @vertices_facets = (); # given a vertex index, what are the indexes of its tangent facets?
 | 
			
		||||
        for (my $f = 0; $f <= $#$facets; $f++) {
 | 
			
		||||
            for (1..3) {
 | 
			
		||||
                my $point_id = join ',', @{$facets->[$f][$_]};
 | 
			
		||||
                if (exists $vertices_map{$point_id}) {
 | 
			
		||||
                    $facets->[$f][$_] = $vertices_map{$point_id};
 | 
			
		||||
                    push @{$vertices_facets[$facets->[$f][$_]]}, $f;
 | 
			
		||||
                } else {
 | 
			
		||||
                    push @$vertices, $facets->[$f][$_];
 | 
			
		||||
                    $facets->[$f][$_] = $vertices_map{$point_id} = $#$vertices;
 | 
			
		||||
                    $vertices_facets[$#$vertices] = [$f];
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        # The following loop checks that @vertices_facets only groups facets that
 | 
			
		||||
        # are really connected together (i.e. neighbors or sharing neighbors);
 | 
			
		||||
        # in other words it takes care of multiple vertices occupying the same
 | 
			
		||||
        # point in space. It enforces topological correctness which is needed by
 | 
			
		||||
        # the slicing algorithm.
 | 
			
		||||
        # I'm keeping it disabled until I find a good test case.
 | 
			
		||||
        if (0) {
 | 
			
		||||
            my $vertices_count = $#$vertices; # store it to avoid processing newly created vertices
 | 
			
		||||
            for (my $v = 0; $v <= $vertices_count; $v++) {
 | 
			
		||||
                my $more_than_one_vertex_in_this_point = 0;
 | 
			
		||||
                while (@{$vertices_facets[$v]}) {
 | 
			
		||||
                    my @facets_indexes = @{$vertices_facets[$v]};
 | 
			
		||||
                    @{$vertices_facets[$v]} = ();
 | 
			
		||||
                    
 | 
			
		||||
                    my @this_f = shift @facets_indexes;
 | 
			
		||||
                    CYCLE: while (@facets_indexes && @this_f) {
 | 
			
		||||
                        
 | 
			
		||||
                        # look for a facet that is connected to $this_f[-1] and whose common line contains $v
 | 
			
		||||
                        my @other_vertices_indexes = grep $_ != $v, @{$facets->[$this_f[-1]]}[1..3];
 | 
			
		||||
                        
 | 
			
		||||
                        OTHER: for my $other_f (@facets_indexes) {
 | 
			
		||||
                            # facet is connected if it shares one more point
 | 
			
		||||
                            for (grep $_ != $v, @{$facets->[$other_f]}[1..3]) {
 | 
			
		||||
                                if ($_ ~~ @other_vertices_indexes) {
 | 
			
		||||
                                    #printf "facet %d is connected to $other_f (sharing vertices $v and $_)\n", $this_f[-1];
 | 
			
		||||
                                    
 | 
			
		||||
                                    # TODO: we should ensure that the common edge has a different orientation
 | 
			
		||||
                                    # for each of the two adjacent facets
 | 
			
		||||
                                    
 | 
			
		||||
                                    push @this_f, $other_f;
 | 
			
		||||
                                    @facets_indexes = grep $_ != $other_f, @facets_indexes;
 | 
			
		||||
                                    next CYCLE;
 | 
			
		||||
                                }
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                        # if we're here, then we couldn't find any facet connected to $this_f[-1]
 | 
			
		||||
                        # so we should move this one to a different cluster (that is, a new vertex)
 | 
			
		||||
                        # (or ignore it if it turns to be a non-manifold facet)
 | 
			
		||||
                        if (@this_f > 1) {
 | 
			
		||||
                            push @{$vertices_facets[$v]}, $this_f[-1];
 | 
			
		||||
                            pop @this_f;
 | 
			
		||||
                            $more_than_one_vertex_in_this_point++;
 | 
			
		||||
                        } else {
 | 
			
		||||
                            last CYCLE;
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                    
 | 
			
		||||
                    if ($more_than_one_vertex_in_this_point) {
 | 
			
		||||
                        Slic3r::debugf "  more than one vertex in the same point\n";
 | 
			
		||||
                        push @$vertices, $vertices->[$v];
 | 
			
		||||
                        for my $f (@this_f) {
 | 
			
		||||
                            $facets->[$f][$_] = $#$vertices for grep $facets->[$f][$_] == $v, 1..3;
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    return Slic3r::TriangleMesh->new(vertices => $vertices, facets => $facets);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
sub _read_ascii {
 | 
			
		||||
    my ($fh, $facets) = @_;
 | 
			
		||||
    
 | 
			
		||||
    my $point_re = qr/([^ ]+)\s+([^ ]+)\s+([^ ]+)\s*$/;
 | 
			
		||||
    
 | 
			
		||||
    my $facet;
 | 
			
		||||
    seek $fh, 0, 0;
 | 
			
		||||
    while (my $_ = <$fh>) {
 | 
			
		||||
        s/\R+$//;
 | 
			
		||||
        if (!$facet) {
 | 
			
		||||
            /^\s*facet\s+normal\s+$point_re/ or next;
 | 
			
		||||
            $facet = [ [$1, $2, $3] ];
 | 
			
		||||
        } else {
 | 
			
		||||
            if (/^\s*endfacet/) {
 | 
			
		||||
                push @$facets, $facet;
 | 
			
		||||
                undef $facet;
 | 
			
		||||
            } else {
 | 
			
		||||
                /^\s*vertex\s+$point_re/ or next;
 | 
			
		||||
                push @$facet, [map $_ * 1, $1, $2, $3];
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    if ($facet) {
 | 
			
		||||
        die "STL file seems invalid\n";
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
sub _read_binary {
 | 
			
		||||
    my ($fh, $facets) = @_;
 | 
			
		||||
    
 | 
			
		||||
    die "bigfloat" unless length(pack "f", 1) == 4;
 | 
			
		||||
    
 | 
			
		||||
    binmode $fh;
 | 
			
		||||
    seek $fh, 80 + 4, 0;
 | 
			
		||||
    while (read $fh, my $_, 4*4*3+2) {
 | 
			
		||||
        my @v = unpack '(f<3)4';
 | 
			
		||||
        push @$facets, [ [@v[0..2]], [@v[3..5]], [@v[6..8]], [@v[9..11]] ];
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
sub write_file {
 | 
			
		||||
    my $self = shift;
 | 
			
		||||
    my ($file, $mesh, $binary) = @_;
 | 
			
		||||
    
 | 
			
		||||
    open my $fh, '>', $file;
 | 
			
		||||
    
 | 
			
		||||
    $binary
 | 
			
		||||
        ? _write_binary($fh, $mesh)
 | 
			
		||||
        : _write_ascii($fh, $mesh);
 | 
			
		||||
    
 | 
			
		||||
    close $fh;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
sub _write_binary {
 | 
			
		||||
    my ($fh, $mesh) = @_;
 | 
			
		||||
    
 | 
			
		||||
    die "bigfloat" unless length(pack "f", 1) == 4;
 | 
			
		||||
    
 | 
			
		||||
    binmode $fh;
 | 
			
		||||
    print $fh pack 'x80';
 | 
			
		||||
    print $fh pack 'L', scalar(@{$mesh->facets});
 | 
			
		||||
    foreach my $facet (@{$mesh->facets}) {
 | 
			
		||||
        print $fh pack '(f<3)4S',
 | 
			
		||||
            @{_facet_normal($mesh, $facet)},
 | 
			
		||||
            (map @{$mesh->vertices->[$_]}, @$facet[1,2,3]),
 | 
			
		||||
            0;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
sub _write_ascii {
 | 
			
		||||
    my ($fh, $mesh) = @_;
 | 
			
		||||
    
 | 
			
		||||
    printf $fh "solid\n";
 | 
			
		||||
    foreach my $facet (@{$mesh->facets}) {
 | 
			
		||||
        printf $fh "   facet normal %f %f %f\n", @{_facet_normal($mesh, $facet)};
 | 
			
		||||
        printf $fh "      outer loop\n";
 | 
			
		||||
        printf $fh "         vertex %f %f %f\n", @{$mesh->vertices->[$_]} for @$facet[1,2,3];
 | 
			
		||||
        printf $fh "      endloop\n";
 | 
			
		||||
        printf $fh "   endfacet\n";
 | 
			
		||||
    }
 | 
			
		||||
    printf $fh "endsolid\n";
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
sub _facet_normal {
 | 
			
		||||
    my ($mesh, $facet) = @_;
 | 
			
		||||
    return triangle_normal(map $mesh->vertices->[$_], @$facet[1,2,3]);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
1;
 | 
			
		||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue