mirror of
https://github.com/kristov/ldraw2stl.git
synced 2025-05-15 06:10:11 -07:00
Introduce an optional cache
With no cache: $ time bin/dat2stl --ldrawdir=ldraw --file ldraw/parts/11295.dat > 11295.stl real 0m1.857s user 0m1.764s sys 0m0.092s $ time bin/dat2stl --ldrawdir=ldraw --file ldraw/parts/11295.dat > 11295.stl real 0m1.834s user 0m1.786s sys 0m0.048s With cache: $ time bin/dat2stl --cache --ldrawdir=ldraw --file ldraw/parts/11295.dat > 11295.stl real 0m1.084s user 0m1.044s sys 0m0.040s $ time bin/dat2stl --cache --ldrawdir=ldraw --file ldraw/parts/11295.dat > 11295.stl real 0m1.076s user 0m1.028s sys 0m0.048s
This commit is contained in:
parent
7965e9a890
commit
3b042dbb4e
45
bin/dat2stl
45
bin/dat2stl
@ -18,6 +18,7 @@ GetOptions(
|
|||||||
'json',
|
'json',
|
||||||
'nomodel',
|
'nomodel',
|
||||||
'invert',
|
'invert',
|
||||||
|
'cache',
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!keys %{$opts}) {
|
if (!keys %{$opts}) {
|
||||||
@ -74,16 +75,35 @@ Takes an ldraw part .dat file as input and converts it into an STL file.
|
|||||||
--invert
|
--invert
|
||||||
Invert the part. Used for debugging.
|
Invert the part. Used for debugging.
|
||||||
|
|
||||||
|
--cache
|
||||||
|
Use a cache to avoid repeated geneneration of the same geometry. Many geometric
|
||||||
|
primitives are repeated (eg: a stud), and are simply translated into different
|
||||||
|
locations in the model. A combination of the sub-part name and the invert flag is
|
||||||
|
used to build a cache key to store the generated triangles for the sub-part. When
|
||||||
|
this is stable I will change this to --nocache so it's on by default.
|
||||||
|
|
||||||
END
|
END
|
||||||
}
|
}
|
||||||
|
|
||||||
my $parser = LDraw::Parser->new({
|
my $parser_opts = {
|
||||||
file => $opts->{file},
|
file => $opts->{file},
|
||||||
$opts->{scale} ? ( scale => $opts->{scale} ) : (),
|
};
|
||||||
$opts->{ldrawdir} ? ( ldraw_path => $opts->{ldrawdir} ) : (),
|
if ($opts->{cache}) {
|
||||||
$opts->{debug} ? ( debug => 1 ) : (),
|
$parser_opts->{cache} = LDraw::Parser::Cache->new;
|
||||||
$opts->{invert} ? ( invert => 1 ) : (),
|
}
|
||||||
});
|
if ($opts->{scale}) {
|
||||||
|
$parser_opts->{scale} = $opts->{scale};
|
||||||
|
}
|
||||||
|
if ($opts->{ldrawdir}) {
|
||||||
|
$parser_opts->{ldraw_path} = $opts->{ldrawdir};
|
||||||
|
}
|
||||||
|
if ($opts->{debug}) {
|
||||||
|
$parser_opts->{debug} = 1;
|
||||||
|
}
|
||||||
|
if ($opts->{invert}) {
|
||||||
|
$parser_opts->{invert} = 1;
|
||||||
|
}
|
||||||
|
my $parser = LDraw::Parser->new($parser_opts);
|
||||||
|
|
||||||
$parser->parse;
|
$parser->parse;
|
||||||
if ($opts->{json}) {
|
if ($opts->{json}) {
|
||||||
@ -99,4 +119,15 @@ if ($opts->{json}) {
|
|||||||
if ($opts->{nomodel}) {
|
if ($opts->{nomodel}) {
|
||||||
exit 0;
|
exit 0;
|
||||||
}
|
}
|
||||||
print $parser->to_stl;
|
my $facets = $parser->stl_buffer;
|
||||||
|
printf("solid GiantLegoRocks\n");
|
||||||
|
for my $facet (@{$facets}) {
|
||||||
|
printf("facet normal %0.4f %0.4f %0.4f\n", @{$facet->{normal}});
|
||||||
|
printf(" outer loop\n");
|
||||||
|
for my $vertex (@{$facet->{vertexes}}) {
|
||||||
|
printf(" vertex %0.4f %0.4f %0.4f\n", @{$vertex});
|
||||||
|
}
|
||||||
|
printf(" endloop\n");
|
||||||
|
printf("endfacet\n");
|
||||||
|
}
|
||||||
|
printf("endsolid GiantLegoRocks\n");
|
||||||
|
@ -30,6 +30,7 @@ sub new {
|
|||||||
die "file required" unless $args->{file};
|
die "file required" unless $args->{file};
|
||||||
return bless({
|
return bless({
|
||||||
file => $args->{file},
|
file => $args->{file},
|
||||||
|
cache => $args->{cache},
|
||||||
ldraw_path => $args->{ldraw_path} // '/usr/share/ldraw',
|
ldraw_path => $args->{ldraw_path} // '/usr/share/ldraw',
|
||||||
scale => $args->{scale} // 1,
|
scale => $args->{scale} // 1,
|
||||||
mm_per_ldu => $args->{mm_per_ldu} // 0.4,
|
mm_per_ldu => $args->{mm_per_ldu} // 0.4,
|
||||||
@ -38,6 +39,7 @@ sub new {
|
|||||||
d_indent => $args->{d_indent} // 0,
|
d_indent => $args->{d_indent} // 0,
|
||||||
ccw_winding => 1,
|
ccw_winding => 1,
|
||||||
_invertnext => 0,
|
_invertnext => 0,
|
||||||
|
triangles => [],
|
||||||
}, $class);
|
}, $class);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -364,24 +366,37 @@ sub parse_sub_file_reference {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
my $subparser = __PACKAGE__->new( {
|
my $triangles;
|
||||||
file => $subpart_filename,
|
my $invert = $self->compute_inversion($mat);
|
||||||
ldraw_path => $self->ldraw_path,
|
if (defined $self->{cache}) {
|
||||||
debug => $self->debug,
|
$triangles = $self->{cache}->get($subpart_filename, $invert);
|
||||||
invert => $self->compute_inversion($mat),
|
}
|
||||||
d_indent => $self->d_indent + 2,
|
if (!$triangles) {
|
||||||
} );
|
# Not using a cache, or cache miss
|
||||||
$subparser->parse;
|
my $subparser = LDraw::Parser->new({
|
||||||
|
file => $subpart_filename,
|
||||||
|
ldraw_path => $self->ldraw_path,
|
||||||
|
debug => $self->debug,
|
||||||
|
invert => $invert,
|
||||||
|
d_indent => $self->d_indent + 2,
|
||||||
|
(defined $self->{cache}) ? (cache => $self->{cache}) : (),
|
||||||
|
});
|
||||||
|
$subparser->parse;
|
||||||
|
$triangles = $subparser->{triangles};
|
||||||
|
if (defined $self->{cache}) {
|
||||||
|
$self->{cache}->put($subpart_filename, $invert, $triangles);
|
||||||
|
}
|
||||||
|
}
|
||||||
$self->{_invertnext} = 0;
|
$self->{_invertnext} = 0;
|
||||||
|
|
||||||
for my $triangle ( @{ $subparser->{triangles} } ) {
|
for my $triangle (@{$triangles}) {
|
||||||
for my $vec ( @{ $triangle } ) {
|
my $n_triangle = [];
|
||||||
my @new_vec = mat4xv3( $mat, $vec );
|
for my $vec (@{$triangle}) {
|
||||||
$vec->[0] = $new_vec[0];
|
push @{$n_triangle}, mat4xv3($mat, $vec);
|
||||||
$vec->[1] = $new_vec[1];
|
|
||||||
$vec->[2] = $new_vec[2];
|
|
||||||
}
|
}
|
||||||
push @{ $self->{triangles} }, $triangle;
|
push @{$self->{triangles}}, $n_triangle;
|
||||||
|
#use Data::Dumper;
|
||||||
|
#warn Dumper($self->{triangles});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -513,7 +528,7 @@ sub mat4xv3 {
|
|||||||
my $y_new = $b1 * $u + $b2 * $v + $b3 * $z + $b4;
|
my $y_new = $b1 * $u + $b2 * $v + $b3 * $z + $b4;
|
||||||
my $z_new = $c1 * $u + $c2 * $v + $c3 * $z + $c4;
|
my $z_new = $c1 * $u + $c2 * $v + $c3 * $z + $c4;
|
||||||
|
|
||||||
return ($x_new, $y_new, $z_new);
|
return [$x_new, $y_new, $z_new];
|
||||||
}
|
}
|
||||||
|
|
||||||
sub mat4determinant {
|
sub mat4determinant {
|
||||||
@ -554,32 +569,6 @@ sub _transvec {
|
|||||||
return [map {sprintf('%0.4f', $_ * $mm_per_ldu * $scale)} @{$vec}];
|
return [map {sprintf('%0.4f', $_ * $mm_per_ldu * $scale)} @{$vec}];
|
||||||
}
|
}
|
||||||
|
|
||||||
sub to_stl {
|
|
||||||
my ($self) = @_;
|
|
||||||
|
|
||||||
my $scale = $self->scale || 1;
|
|
||||||
my $mm_per_ldu = $self->mm_per_ldu;
|
|
||||||
|
|
||||||
my $stl = "";
|
|
||||||
$stl .= "solid GiantLegoRocks\n";
|
|
||||||
|
|
||||||
for my $triangle (@{$self->{triangles}}) {
|
|
||||||
my ($p1, $p2, $p3) = map {_transvec($mm_per_ldu, $scale, $_)} @{$triangle};
|
|
||||||
my $n = $self->calc_surface_normal([$p1, $p2, $p3]);
|
|
||||||
$stl .= "facet normal " . join(' ', map {sprintf('%0.4f', $_)} @{$n}) . "\n";
|
|
||||||
$stl .= " outer loop\n";
|
|
||||||
for my $vec (($p1, $p2, $p3)) {
|
|
||||||
$stl .= " vertex " . join(' ', map {sprintf('%0.4f', $_)} @{$vec}) . "\n";
|
|
||||||
}
|
|
||||||
$stl .= " endloop\n";
|
|
||||||
$stl .= "endfacet\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
$stl .= "endsolid GiantLegoRocks\n";
|
|
||||||
|
|
||||||
return $stl;
|
|
||||||
}
|
|
||||||
|
|
||||||
sub stl_buffer {
|
sub stl_buffer {
|
||||||
my ($self) = @_;
|
my ($self) = @_;
|
||||||
|
|
||||||
@ -591,11 +580,11 @@ sub stl_buffer {
|
|||||||
my ($p1, $p2, $p3) = map {_transvec($mm_per_ldu, $scale, $_)} @{$triangle};
|
my ($p1, $p2, $p3) = map {_transvec($mm_per_ldu, $scale, $_)} @{$triangle};
|
||||||
my $n = $self->calc_surface_normal([$p1, $p2, $p3]);
|
my $n = $self->calc_surface_normal([$p1, $p2, $p3]);
|
||||||
my $facet = {
|
my $facet = {
|
||||||
normal => [map {sprintf('%0.4f', $_)} @{$n}],
|
normal => $n,
|
||||||
vertexes => [],
|
vertexes => [],
|
||||||
};
|
};
|
||||||
for my $vec (($p1, $p2, $p3)) {
|
for my $vec (($p1, $p2, $p3)) {
|
||||||
push @{$facet->{vertexes}}, map {sprintf('%0.4f', $_)} @{$vec};
|
push @{$facet->{vertexes}}, $vec;
|
||||||
}
|
}
|
||||||
push @facets, $facet;
|
push @facets, $facet;
|
||||||
}
|
}
|
||||||
@ -630,4 +619,30 @@ sub gl_buffer {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
package LDraw::Parser::Cache;
|
||||||
|
|
||||||
|
sub new {
|
||||||
|
my ($class) = @_;
|
||||||
|
return bless({_cache => {}}, $class);
|
||||||
|
}
|
||||||
|
|
||||||
|
sub get {
|
||||||
|
my ($self, $file, $invert) = @_;
|
||||||
|
my $key = sprintf("%s__%d", $file, $invert);
|
||||||
|
if (defined $self->{_cache}->{$key}) {
|
||||||
|
return $self->{_cache}->{$key};
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub put {
|
||||||
|
my ($self, $file, $invert, $trianges) = @_;
|
||||||
|
my $key = sprintf("%s__%d", $file, $invert);
|
||||||
|
if (defined $self->{_cache}->{$key}) {
|
||||||
|
die sprintf("repeated put for %s", $key);
|
||||||
|
}
|
||||||
|
$self->{_cache}->{$key} = $trianges;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
1;
|
1;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user