line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Lego::Ldraw;
|
2
|
|
|
|
|
|
|
|
3
|
1
|
|
|
1
|
|
20273
|
use 5.008004;
|
|
1
|
|
|
|
|
3
|
|
4
|
1
|
|
|
1
|
|
4
|
use strict;
|
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
31
|
|
5
|
1
|
|
|
1
|
|
5
|
use warnings; no warnings qw/uninitialized/;
|
|
1
|
|
|
1
|
|
6
|
|
|
1
|
|
|
|
|
44
|
|
|
1
|
|
|
|
|
8
|
|
|
1
|
|
|
|
|
3
|
|
|
1
|
|
|
|
|
28
|
|
6
|
|
|
|
|
|
|
|
7
|
1
|
|
|
1
|
|
4
|
use Carp;
|
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
79
|
|
8
|
1
|
|
|
1
|
|
498
|
use Lego::Ldraw::Line;
|
|
1
|
|
|
|
|
3
|
|
|
1
|
|
|
|
|
32
|
|
9
|
|
|
|
|
|
|
|
10
|
1
|
|
|
1
|
|
6
|
use File::Basename;
|
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
71
|
|
11
|
|
|
|
|
|
|
|
12
|
|
|
|
|
|
|
use overload
|
13
|
1
|
|
|
|
|
9
|
'@{}' => \&lines,
|
14
|
1
|
|
|
1
|
|
4
|
'""' => \&stringify;
|
|
1
|
|
|
|
|
2
|
|
15
|
|
|
|
|
|
|
|
16
|
|
|
|
|
|
|
our $VERSION = "0.5.7.1";
|
17
|
|
|
|
|
|
|
|
18
|
|
|
|
|
|
|
sub new {
|
19
|
0
|
|
|
0
|
1
|
|
my $proto = shift;
|
20
|
0
|
|
0
|
|
|
|
my $class = ref($proto) || $proto;
|
21
|
0
|
|
|
|
|
|
my $self = {};
|
22
|
|
|
|
|
|
|
|
23
|
0
|
|
|
|
|
|
$self->{lines} = [];
|
24
|
0
|
|
|
|
|
|
$self->{file} = undef;
|
25
|
0
|
|
|
|
|
|
$self->{name} = undef;
|
26
|
0
|
|
|
|
|
|
$self->{description} = undef;
|
27
|
0
|
|
|
|
|
|
$self->{dir} = undef;
|
28
|
|
|
|
|
|
|
|
29
|
0
|
|
|
|
|
|
bless ($self, $class);
|
30
|
0
|
|
|
|
|
|
return $self;
|
31
|
|
|
|
|
|
|
}
|
32
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
sub DESTROY {
|
34
|
0
|
|
|
0
|
|
|
my $self = shift;
|
35
|
0
|
|
|
|
|
|
$_->{model} = undef for @{$self->lines};
|
|
0
|
|
|
|
|
|
|
36
|
0
|
|
|
|
|
|
$self = undef;
|
37
|
|
|
|
|
|
|
}
|
38
|
|
|
|
|
|
|
|
39
|
|
|
|
|
|
|
sub new_from_file {
|
40
|
0
|
|
|
0
|
1
|
|
my $self = shift->new;
|
41
|
0
|
|
0
|
|
|
|
my $file = shift || \*STDIN;
|
42
|
|
|
|
|
|
|
|
43
|
0
|
0
|
|
|
|
|
unless (ref $file eq 'GLOB') {
|
44
|
0
|
0
|
|
|
|
|
croak "Error $? opening $file" unless -e $file;
|
45
|
0
|
0
|
|
|
|
|
open LDRAW, $file or croak "Error $? opening $file";
|
46
|
0
|
|
|
|
|
|
$self->{file} = $file;
|
47
|
0
|
|
|
|
|
|
$self->{name} = basename($file);
|
48
|
0
|
|
|
|
|
|
$self->{dir} = dirname($file);
|
49
|
0
|
|
|
|
|
|
$file = \*LDRAW;
|
50
|
|
|
|
|
|
|
}
|
51
|
|
|
|
|
|
|
|
52
|
0
|
|
|
|
|
|
while (<$file>) {
|
53
|
0
|
|
|
|
|
|
chomp;
|
54
|
0
|
0
|
|
|
|
|
unless (/^\s*$/) {
|
55
|
0
|
|
|
|
|
|
my $line = Lego::Ldraw::Line->new_from_string($_);
|
56
|
0
|
0
|
|
|
|
|
$self->{description} = $line->command unless $.;
|
57
|
0
|
|
|
|
|
|
$self->add($line);
|
58
|
|
|
|
|
|
|
}
|
59
|
|
|
|
|
|
|
}
|
60
|
0
|
0
|
|
|
|
|
close $file unless ref $file;
|
61
|
0
|
|
|
|
|
|
return $self;
|
62
|
|
|
|
|
|
|
}
|
63
|
|
|
|
|
|
|
|
64
|
|
|
|
|
|
|
sub copy {
|
65
|
0
|
|
|
0
|
1
|
|
my $self = shift;
|
66
|
0
|
|
|
|
|
|
my $copy = Lego::Ldraw->new;
|
67
|
|
|
|
|
|
|
|
68
|
0
|
|
|
|
|
|
$copy->{file} = $self->{file};
|
69
|
0
|
|
|
|
|
|
$copy->{name} = $self->{name};
|
70
|
0
|
|
|
|
|
|
$copy->{dir} = $self->{dir};
|
71
|
|
|
|
|
|
|
|
72
|
0
|
|
|
|
|
|
for (@$self) {
|
73
|
0
|
|
|
|
|
|
my $line = Lego::Ldraw::Line->new_from_string("$_");
|
74
|
0
|
|
|
|
|
|
$copy->add($line);
|
75
|
|
|
|
|
|
|
}
|
76
|
0
|
|
|
|
|
|
return $copy;
|
77
|
|
|
|
|
|
|
}
|
78
|
|
|
|
|
|
|
|
79
|
|
|
|
|
|
|
sub add {
|
80
|
0
|
|
|
0
|
1
|
|
my $self = shift;
|
81
|
0
|
|
|
|
|
|
my $line = shift;
|
82
|
0
|
|
|
|
|
|
my $pos = shift;
|
83
|
|
|
|
|
|
|
|
84
|
0
|
0
|
|
|
|
|
$pos = 0 unless @{$self->{lines}};
|
|
0
|
|
|
|
|
|
|
85
|
|
|
|
|
|
|
|
86
|
0
|
0
|
|
|
|
|
if ($pos) {
|
87
|
0
|
|
|
|
|
|
splice @{$self->{lines}}, $pos, 0, $line;
|
|
0
|
|
|
|
|
|
|
88
|
|
|
|
|
|
|
} else {
|
89
|
0
|
|
|
|
|
|
push @{$self->{lines}}, $line;
|
|
0
|
|
|
|
|
|
|
90
|
|
|
|
|
|
|
}
|
91
|
0
|
|
|
|
|
|
$self->{tree}->{$line->part}->{$line->color}++;
|
92
|
0
|
|
|
|
|
|
$line->dir($self->dir);
|
93
|
|
|
|
|
|
|
}
|
94
|
|
|
|
|
|
|
|
95
|
|
|
|
|
|
|
sub splice {
|
96
|
0
|
|
|
0
|
1
|
|
my $self = shift;
|
97
|
0
|
|
|
|
|
|
my ($what, $offset, $length) = @_;
|
98
|
|
|
|
|
|
|
|
99
|
0
|
|
|
|
|
|
for (ref $what) {
|
100
|
0
|
0
|
|
|
|
|
/^Lego::Ldraw::Line$/ && do {
|
101
|
0
|
|
|
|
|
|
splice @{$self->{lines}}, $offset, $length, $what;
|
|
0
|
|
|
|
|
|
|
102
|
0
|
|
|
|
|
|
last;
|
103
|
|
|
|
|
|
|
};
|
104
|
0
|
0
|
|
|
|
|
/^Lego::Ldraw$/ && do {
|
105
|
0
|
|
|
|
|
|
splice @{$self->{lines}}, $offset, $length, @{$what->{lines}};
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
106
|
0
|
|
|
|
|
|
last;
|
107
|
|
|
|
|
|
|
};
|
108
|
|
|
|
|
|
|
}
|
109
|
|
|
|
|
|
|
}
|
110
|
|
|
|
|
|
|
|
111
|
|
|
|
|
|
|
sub lines {
|
112
|
0
|
|
|
0
|
1
|
|
my $self = shift;
|
113
|
0
|
0
|
|
|
|
|
return wantarray ? @{$self->{lines}} : $self->{lines};
|
|
0
|
|
|
|
|
|
|
114
|
|
|
|
|
|
|
}
|
115
|
|
|
|
|
|
|
|
116
|
|
|
|
|
|
|
sub stringify {
|
117
|
0
|
|
|
0
|
1
|
|
my $self = shift;
|
118
|
0
|
|
|
|
|
|
return join "\n", @{$self};
|
|
0
|
|
|
|
|
|
|
119
|
|
|
|
|
|
|
}
|
120
|
|
|
|
|
|
|
|
121
|
|
|
|
|
|
|
sub length {
|
122
|
0
|
|
|
0
|
1
|
|
my $self = shift;
|
123
|
0
|
|
|
|
|
|
return scalar @{$self->{lines}};
|
|
0
|
|
|
|
|
|
|
124
|
|
|
|
|
|
|
}
|
125
|
|
|
|
|
|
|
|
126
|
|
|
|
|
|
|
sub subparts {
|
127
|
0
|
|
|
0
|
1
|
|
my $self = shift;
|
128
|
0
|
|
|
|
|
|
return grep { $_->type == 1 } @{ $self };
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
129
|
|
|
|
|
|
|
}
|
130
|
|
|
|
|
|
|
|
131
|
|
|
|
|
|
|
sub colors {
|
132
|
0
|
|
|
0
|
1
|
|
my $self = shift;
|
133
|
0
|
|
|
|
|
|
my %colors;
|
134
|
0
|
|
|
|
|
|
for ($self->lines) {
|
135
|
0
|
0
|
|
|
|
|
next unless my $c = $_->color;
|
136
|
0
|
|
|
|
|
|
$colors{$c}++;
|
137
|
|
|
|
|
|
|
}
|
138
|
0
|
|
|
|
|
|
return sort keys %colors;
|
139
|
|
|
|
|
|
|
}
|
140
|
|
|
|
|
|
|
|
141
|
|
|
|
|
|
|
###################################################
|
142
|
|
|
|
|
|
|
# quick fixes for file, name, tree
|
143
|
|
|
|
|
|
|
###################################################
|
144
|
|
|
|
|
|
|
|
145
|
|
|
|
|
|
|
sub file {
|
146
|
0
|
|
|
0
|
1
|
|
return shift->{file};
|
147
|
|
|
|
|
|
|
}
|
148
|
|
|
|
|
|
|
|
149
|
|
|
|
|
|
|
sub name {
|
150
|
0
|
|
|
0
|
1
|
|
return shift->{name};
|
151
|
|
|
|
|
|
|
}
|
152
|
|
|
|
|
|
|
|
153
|
|
|
|
|
|
|
sub tree {
|
154
|
|
|
|
|
|
|
return shift->{tree}
|
155
|
0
|
|
|
0
|
1
|
|
}
|
156
|
|
|
|
|
|
|
|
157
|
|
|
|
|
|
|
sub parts {
|
158
|
0
|
|
|
0
|
1
|
|
return sort keys %{ shift->{tree} };
|
|
0
|
|
|
|
|
|
|
159
|
|
|
|
|
|
|
}
|
160
|
|
|
|
|
|
|
|
161
|
|
|
|
|
|
|
sub dir {
|
162
|
|
|
|
|
|
|
return shift->{dir}
|
163
|
0
|
|
|
0
|
1
|
|
}
|
164
|
|
|
|
|
|
|
|
165
|
|
|
|
|
|
|
sub description {
|
166
|
0
|
|
|
0
|
1
|
|
my $self = shift;
|
167
|
0
|
0
|
|
|
|
|
$self->{description} = shift if @_;
|
168
|
|
|
|
|
|
|
return $self->{description}
|
169
|
0
|
|
|
|
|
|
}
|
170
|
|
|
|
|
|
|
|
171
|
|
|
|
|
|
|
sub partsdirs {
|
172
|
0
|
|
|
0
|
1
|
|
return Lego::Ldraw::Line->partsdirs;
|
173
|
|
|
|
|
|
|
}
|
174
|
|
|
|
|
|
|
|
175
|
|
|
|
|
|
|
sub basedir {
|
176
|
0
|
|
|
0
|
1
|
|
return Lego::Ldraw::Line->basedir;
|
177
|
|
|
|
|
|
|
}
|
178
|
|
|
|
|
|
|
|
179
|
|
|
|
|
|
|
|
180
|
|
|
|
|
|
|
##################################################
|
181
|
|
|
|
|
|
|
# experimental part: build tree with callback
|
182
|
|
|
|
|
|
|
##################################################
|
183
|
|
|
|
|
|
|
|
184
|
|
|
|
|
|
|
sub Lego::Ldraw::build_tree {
|
185
|
0
|
|
|
0
|
1
|
|
my $ldraw = shift;
|
186
|
0
|
|
|
|
|
|
my $callback = shift;
|
187
|
0
|
|
|
|
|
|
my $test = shift;
|
188
|
|
|
|
|
|
|
|
189
|
0
|
|
|
|
|
|
my $b; # part tree: $d->{$part}->{$subpart} means $subpart is used in $part;
|
190
|
|
|
|
|
|
|
my $d; # reverse part tree: $d->{$subpart}->{$part} means $subpart is used in $part;
|
191
|
0
|
|
|
|
|
|
my $s; # recursed parts list. Value is 1 if list is ready to be built for subpart
|
192
|
|
|
|
|
|
|
|
193
|
0
|
|
|
|
|
|
$ldraw->recurse_part_tree(\$b, \$d, \$s, $test);
|
194
|
|
|
|
|
|
|
|
195
|
|
|
|
|
|
|
# while there are parts ready for list building
|
196
|
0
|
|
|
|
|
|
while (my @l = grep { $d->{$_} } keys %{$s}) {
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
197
|
0
|
|
|
|
|
|
for my $p (@l) {
|
198
|
|
|
|
|
|
|
# if part has no subparts
|
199
|
0
|
0
|
|
|
|
|
if ($s->{$p}) {
|
200
|
|
|
|
|
|
|
# build a list for the part
|
201
|
0
|
|
|
|
|
|
print STDERR "traversing tree for $p";
|
202
|
|
|
|
|
|
|
# Lego::Ldraw::Display->build_list($p);
|
203
|
0
|
|
|
|
|
|
&{$callback}($p);
|
|
0
|
|
|
|
|
|
|
204
|
|
|
|
|
|
|
# delete part from list of parts that need building lists
|
205
|
|
|
|
|
|
|
# delete $s->{$p}; # = 0;
|
206
|
|
|
|
|
|
|
# set parts that use it as ready for list building
|
207
|
0
|
|
|
|
|
|
my @r = keys %{$d->{$p}}; # all parts that use this subpart
|
|
0
|
|
|
|
|
|
|
208
|
0
|
|
|
|
|
|
for (@r) {
|
209
|
0
|
|
|
|
|
|
delete $b->{$_}->{$p}; # delete subpart from part tree
|
210
|
0
|
0
|
|
|
|
|
$s->{$_} = 1 unless keys %{$b->{$_}} # is there are no subparts list can be built
|
|
0
|
|
|
|
|
|
|
211
|
|
|
|
|
|
|
}
|
212
|
|
|
|
|
|
|
# delete part reverse tree
|
213
|
0
|
|
|
|
|
|
delete $d->{$p};
|
214
|
|
|
|
|
|
|
}
|
215
|
|
|
|
|
|
|
}
|
216
|
|
|
|
|
|
|
}
|
217
|
0
|
|
|
|
|
|
my $t;
|
218
|
0
|
|
|
|
|
|
$b = undef;
|
219
|
0
|
|
|
|
|
|
$d = undef;
|
220
|
0
|
|
|
|
|
|
$s = undef;
|
221
|
|
|
|
|
|
|
}
|
222
|
|
|
|
|
|
|
|
223
|
|
|
|
|
|
|
sub Lego::Ldraw::recurse_part_tree {
|
224
|
0
|
|
|
0
|
0
|
|
my $tree = shift->copy;
|
225
|
0
|
|
|
|
|
|
my ($b, $d, $s, $test) = @_;
|
226
|
0
|
|
0
|
0
|
|
|
$test = $test || sub { shift->type == 1 };
|
|
0
|
|
|
|
|
|
|
227
|
|
|
|
|
|
|
|
228
|
0
|
|
|
|
|
|
$$s->{$tree->name} = 1;
|
229
|
0
|
|
|
|
|
|
for (@$tree) {
|
230
|
0
|
0
|
|
|
|
|
if (&{$test}($_)) {
|
|
0
|
|
|
|
|
|
|
231
|
0
|
|
|
|
|
|
$$b->{$tree->name}->{$_->name}++;
|
232
|
0
|
|
|
|
|
|
$$d->{$_->name}->{$tree->name}++;
|
233
|
0
|
|
|
|
|
|
$$s->{$tree->name} = 0;
|
234
|
0
|
0
|
|
|
|
|
unless (defined $$s->{$_->name}) {
|
235
|
0
|
|
|
|
|
|
my $x = $_->explode;
|
236
|
0
|
|
|
|
|
|
$x->recurse_part_tree($b, $d, $s);
|
237
|
|
|
|
|
|
|
}
|
238
|
|
|
|
|
|
|
}
|
239
|
|
|
|
|
|
|
}
|
240
|
0
|
|
|
|
|
|
$b = undef;
|
241
|
0
|
|
|
|
|
|
$d = undef;
|
242
|
0
|
|
|
|
|
|
$s = undef;
|
243
|
0
|
|
|
|
|
|
$tree = undef;
|
244
|
|
|
|
|
|
|
}
|
245
|
|
|
|
|
|
|
|
246
|
|
|
|
|
|
|
1;
|
247
|
|
|
|
|
|
|
__END__
|