line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package CAD::Drawing::Calculate::Finite; |
2
|
|
|
|
|
|
|
our $VERSION = '0.06'; |
3
|
|
|
|
|
|
|
|
4
|
|
|
|
|
|
|
# use CAD::Drawing; |
5
|
3
|
|
|
3
|
|
36
|
use CAD::Drawing::Defined; |
|
3
|
|
|
|
|
6
|
|
|
3
|
|
|
|
|
570
|
|
6
|
|
|
|
|
|
|
|
7
|
|
|
|
|
|
|
|
8
|
3
|
|
|
3
|
|
16
|
use warnings; |
|
3
|
|
|
|
|
6
|
|
|
3
|
|
|
|
|
92
|
|
9
|
3
|
|
|
3
|
|
19
|
use strict; |
|
3
|
|
|
|
|
7
|
|
|
3
|
|
|
|
|
103
|
|
10
|
3
|
|
|
3
|
|
16
|
use Carp; |
|
3
|
|
|
|
|
6
|
|
|
3
|
|
|
|
|
4699
|
|
11
|
|
|
|
|
|
|
######################################################################## |
12
|
|
|
|
|
|
|
=pod |
13
|
|
|
|
|
|
|
|
14
|
|
|
|
|
|
|
=head1 NAME |
15
|
|
|
|
|
|
|
|
16
|
|
|
|
|
|
|
CAD::Drawing::Calculate::Finite - Vector graphics and limited space. |
17
|
|
|
|
|
|
|
|
18
|
|
|
|
|
|
|
=head1 Description |
19
|
|
|
|
|
|
|
|
20
|
|
|
|
|
|
|
This module is intended as a back-end to CAD::Drawing for methods |
21
|
|
|
|
|
|
|
specific to finite formats (and entities) like images and postscript. |
22
|
|
|
|
|
|
|
|
23
|
|
|
|
|
|
|
=head1 AUTHOR |
24
|
|
|
|
|
|
|
|
25
|
|
|
|
|
|
|
Eric L. Wilhelm |
26
|
|
|
|
|
|
|
|
27
|
|
|
|
|
|
|
http://scratchcomputing.com |
28
|
|
|
|
|
|
|
|
29
|
|
|
|
|
|
|
=head1 COPYRIGHT |
30
|
|
|
|
|
|
|
|
31
|
|
|
|
|
|
|
This module is copyright (C) 2004-2006 by Eric L. Wilhelm. Portions |
32
|
|
|
|
|
|
|
copyright (C) 2003 by Eric L. Wilhelm and A. Zahner Co. |
33
|
|
|
|
|
|
|
|
34
|
|
|
|
|
|
|
=head1 LICENSE |
35
|
|
|
|
|
|
|
|
36
|
|
|
|
|
|
|
This module is distributed under the same terms as Perl. See the Perl |
37
|
|
|
|
|
|
|
source package for details. |
38
|
|
|
|
|
|
|
|
39
|
|
|
|
|
|
|
You may use this software under one of the following licenses: |
40
|
|
|
|
|
|
|
|
41
|
|
|
|
|
|
|
(1) GNU General Public License |
42
|
|
|
|
|
|
|
(found at http://www.gnu.org/copyleft/gpl.html) |
43
|
|
|
|
|
|
|
(2) Artistic License |
44
|
|
|
|
|
|
|
(found at http://www.perl.com/pub/language/misc/Artistic.html) |
45
|
|
|
|
|
|
|
|
46
|
|
|
|
|
|
|
=head1 NO WARRANTY |
47
|
|
|
|
|
|
|
|
48
|
|
|
|
|
|
|
This software is distributed with ABSOLUTELY NO WARRANTY. The author, |
49
|
|
|
|
|
|
|
his former employer, and any other contributors will in no way be held |
50
|
|
|
|
|
|
|
liable for any loss or damages resulting from its use. |
51
|
|
|
|
|
|
|
|
52
|
|
|
|
|
|
|
=head1 Modifications |
53
|
|
|
|
|
|
|
|
54
|
|
|
|
|
|
|
The source code of this module is made freely available and |
55
|
|
|
|
|
|
|
distributable under the GPL or Artistic License. Modifications to and |
56
|
|
|
|
|
|
|
use of this software must adhere to one of these licenses. Changes to |
57
|
|
|
|
|
|
|
the code should be noted as such and this notification (as well as the |
58
|
|
|
|
|
|
|
above copyright information) must remain intact on all copies of the |
59
|
|
|
|
|
|
|
code. |
60
|
|
|
|
|
|
|
|
61
|
|
|
|
|
|
|
Additionally, while the author is actively developing this code, |
62
|
|
|
|
|
|
|
notification of any intended changes or extensions would be most helpful |
63
|
|
|
|
|
|
|
in avoiding repeated work for all parties involved. Please contact the |
64
|
|
|
|
|
|
|
author with any such development plans. |
65
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
|
=head1 SEE ALSO |
67
|
|
|
|
|
|
|
|
68
|
|
|
|
|
|
|
CAD::Drawing |
69
|
|
|
|
|
|
|
|
70
|
|
|
|
|
|
|
=cut |
71
|
|
|
|
|
|
|
######################################################################## |
72
|
|
|
|
|
|
|
|
73
|
|
|
|
|
|
|
=head1 Methods |
74
|
|
|
|
|
|
|
|
75
|
|
|
|
|
|
|
=head2 fit_to_bound |
76
|
|
|
|
|
|
|
|
77
|
|
|
|
|
|
|
Performs extents and scaling to fit entire drawing within a |
78
|
|
|
|
|
|
|
bound. Returns the scale which is required to create the fit. |
79
|
|
|
|
|
|
|
|
80
|
|
|
|
|
|
|
$scale = $drw->fit_to_bound(\@bound, \@border, \%opts); |
81
|
|
|
|
|
|
|
|
82
|
|
|
|
|
|
|
NOTE: |
83
|
|
|
|
|
|
|
|
84
|
|
|
|
|
|
|
@bound arg is a rectangle ([0,0],[11,8.5]) |
85
|
|
|
|
|
|
|
|
86
|
|
|
|
|
|
|
@border is ([$left_sp, $bottom_sp], [$right_sp, $top_sp]) |
87
|
|
|
|
|
|
|
|
88
|
|
|
|
|
|
|
%opts are weird |
89
|
|
|
|
|
|
|
|
90
|
|
|
|
|
|
|
=cut |
91
|
|
|
|
|
|
|
sub fit_to_bound { |
92
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
93
|
0
|
|
|
|
|
|
my ($bound, $border, $opt) = @_; |
94
|
0
|
|
|
|
|
|
my @bound = @$bound; # required argument |
95
|
0
|
|
|
|
|
|
my @border; |
96
|
0
|
0
|
|
|
|
|
if(ref($border) eq "ARRAY") { |
97
|
0
|
|
|
|
|
|
@border = @$border; |
98
|
|
|
|
|
|
|
# print "calculating adjustment for border @border\n"; |
99
|
|
|
|
|
|
|
# print "working with bound of @bound\n"; |
100
|
|
|
|
|
|
|
# print "border consists of $border[0][0], $border[0][1],", |
101
|
|
|
|
|
|
|
# "as well as $border[1][0] and $border[1][1]\n";exit; |
102
|
0
|
|
|
|
|
|
for(my $pt =0; $pt
|
103
|
0
|
|
|
|
|
|
foreach my $c (0,1) { |
104
|
0
|
|
|
|
|
|
$bound[$pt][$c] += $border[$pt][$c]; |
105
|
|
|
|
|
|
|
} |
106
|
|
|
|
|
|
|
} |
107
|
|
|
|
|
|
|
} |
108
|
0
|
|
|
|
|
|
my (@just_pt, @center, @from_pt, @use_ext); |
109
|
0
|
|
|
|
|
|
my ($world_ptx, $world_pty, $scale); |
110
|
0
|
|
|
|
|
|
my %opts; |
111
|
0
|
0
|
|
|
|
|
if(ref($opt) eq "HASH") { |
112
|
0
|
|
|
|
|
|
%opts = %$opt; |
113
|
0
|
0
|
|
|
|
|
if($opts{scale}) { |
114
|
0
|
|
|
|
|
|
$scale = $opts{scale}; |
115
|
|
|
|
|
|
|
# print "got scale option $scale\n"; |
116
|
|
|
|
|
|
|
} |
117
|
0
|
0
|
|
|
|
|
if($opts{justify}) { |
118
|
0
|
|
|
|
|
|
@just_pt = @{$opts{justify}}; |
|
0
|
|
|
|
|
|
|
119
|
|
|
|
|
|
|
} |
120
|
0
|
0
|
|
|
|
|
if($opts{from}) { |
121
|
0
|
|
|
|
|
|
@from_pt = @{$opts{from}}; |
|
0
|
|
|
|
|
|
|
122
|
0
|
0
|
|
|
|
|
$scale or croak("must have scale to use", |
123
|
|
|
|
|
|
|
"\"from\" option in fit_to_bound\n"); |
124
|
|
|
|
|
|
|
} |
125
|
0
|
0
|
|
|
|
|
if($opts{center}) { |
126
|
0
|
|
|
|
|
|
@center = @{$opts{center}}; |
|
0
|
|
|
|
|
|
|
127
|
|
|
|
|
|
|
} |
128
|
0
|
0
|
|
|
|
|
if($opts{use_extents}) { |
129
|
|
|
|
|
|
|
# XXX experimental and undocumented |
130
|
0
|
|
|
|
|
|
@use_ext = @{$opts{use_extents}}; |
|
0
|
|
|
|
|
|
|
131
|
|
|
|
|
|
|
} |
132
|
|
|
|
|
|
|
|
133
|
|
|
|
|
|
|
} |
134
|
|
|
|
|
|
|
# Method is to scale and then move to fit into the given boundary |
135
|
|
|
|
|
|
|
# Calculate orthographic extents of real-world geometry |
136
|
0
|
0
|
0
|
|
|
|
unless($scale && (@from_pt)) { |
137
|
|
|
|
|
|
|
# XXX undocumented config: |
138
|
0
|
0
|
|
|
|
|
my @realbound = (@use_ext ? @use_ext : $self->OrthExtents()); |
139
|
|
|
|
|
|
|
# print "got boundary of @realbound\n"; |
140
|
|
|
|
|
|
|
# print "this translates to @{$realbound[0]} and @{$realbound[1]}\n"; |
141
|
|
|
|
|
|
|
# Calculate height and width of real-world bounding box |
142
|
0
|
|
|
|
|
|
my $width_world = $realbound[0][1] - $realbound[0][0]; |
143
|
0
|
|
|
|
|
|
$world_ptx = $realbound[0][0] + $width_world / 2; |
144
|
0
|
|
|
|
|
|
my $height_world = $realbound[1][1] - $realbound[1][0]; |
145
|
0
|
|
|
|
|
|
$world_pty = $realbound[1][0] + $height_world / 2; |
146
|
|
|
|
|
|
|
# print "calculated world size of $width_world,$height_world\n"; |
147
|
|
|
|
|
|
|
# print "calculated world center of $world_ptx,$world_pty\n"; |
148
|
0
|
0
|
|
|
|
|
unless($scale) { |
149
|
|
|
|
|
|
|
# Calculate height and width of finite-space (given) bounding box |
150
|
0
|
|
|
|
|
|
my $width_finite = $bound[1][0] - $bound[0][0]; |
151
|
0
|
|
|
|
|
|
my $height_finite = $bound[1][1] - $bound[0][1]; |
152
|
|
|
|
|
|
|
# Calculate scale factor (least of the two quotients) |
153
|
0
|
|
|
|
|
|
$scale = (sort({$a<=>$b} |
|
0
|
|
|
|
|
|
|
154
|
|
|
|
|
|
|
($width_finite / $width_world), |
155
|
|
|
|
|
|
|
($height_finite / $height_world) ) )[0]; |
156
|
|
|
|
|
|
|
} |
157
|
|
|
|
|
|
|
} |
158
|
|
|
|
|
|
|
else { |
159
|
0
|
|
|
|
|
|
($world_ptx, $world_pty) = @from_pt; |
160
|
|
|
|
|
|
|
} |
161
|
|
|
|
|
|
|
# Apply scaling |
162
|
|
|
|
|
|
|
# print "scaling by factor of $scale using point $world_ptx, $world_pty\n"; |
163
|
0
|
|
|
|
|
|
$self->GroupScale($scale, [$world_ptx, $world_pty]); |
164
|
|
|
|
|
|
|
# Apply movement: |
165
|
0
|
0
|
|
|
|
|
unless(@center) { |
166
|
0
|
|
|
|
|
|
@center = map({($bound[0][$_] + $bound[1][$_]) / 2} 0,1); |
|
0
|
|
|
|
|
|
|
167
|
|
|
|
|
|
|
} |
168
|
0
|
|
|
|
|
|
my $movex = $center[0] - $world_ptx; |
169
|
0
|
|
|
|
|
|
my $movey = $center[1] - $world_pty; |
170
|
|
|
|
|
|
|
# print "moving by $movex, $movey\n"; |
171
|
|
|
|
|
|
|
# print "trying to reach center @center\n"; |
172
|
0
|
0
|
|
|
|
|
if(@just_pt) { # paper covers rock |
173
|
0
|
|
|
|
|
|
$movex = $just_pt[0] - $world_ptx; |
174
|
0
|
|
|
|
|
|
$movey = $just_pt[1] - $world_pty; |
175
|
|
|
|
|
|
|
} |
176
|
0
|
|
|
|
|
|
$self->GroupMove([$movex, $movey]); |
177
|
0
|
|
|
|
|
|
return($scale); |
178
|
|
|
|
|
|
|
} # end subroutine fit_to_bound definition |
179
|
|
|
|
|
|
|
######################################################################## |
180
|
|
|
|
|
|
|
|
181
|
|
|
|
|
|
|
=head2 get_clip_points |
182
|
|
|
|
|
|
|
|
183
|
|
|
|
|
|
|
Returns a polyline in terms of image pixels. If a rectangle was stored |
184
|
|
|
|
|
|
|
in the image, translates this to a polyline that will be clockwise from |
185
|
|
|
|
|
|
|
lower-left after being switched to world coordinates. |
186
|
|
|
|
|
|
|
|
187
|
|
|
|
|
|
|
If there are no clip points, the image boundary will be returned. |
188
|
|
|
|
|
|
|
|
189
|
|
|
|
|
|
|
$drw->get_clip_points($addr); |
190
|
|
|
|
|
|
|
|
191
|
|
|
|
|
|
|
=cut |
192
|
|
|
|
|
|
|
sub get_clip_points { |
193
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
194
|
0
|
|
|
|
|
|
my ($addr) = @_; |
195
|
0
|
0
|
|
|
|
|
($addr->{type} eq "images") or croak("not an image\n"); |
196
|
0
|
|
|
|
|
|
my $obj = $self->getobj($addr); |
197
|
0
|
0
|
|
|
|
|
if($obj->{clipping}) { |
198
|
0
|
|
|
|
|
|
my @imgpoints = @{$obj->{clipping}}; |
|
0
|
|
|
|
|
|
|
199
|
0
|
|
|
|
|
|
my @points; |
200
|
0
|
|
|
|
|
|
my $num = scalar(@imgpoints); |
201
|
0
|
0
|
|
|
|
|
if($num == 2) { |
|
|
0
|
|
|
|
|
|
202
|
0
|
|
|
|
|
|
my @x = sort({$a<=>$b} $imgpoints[0][0], $imgpoints[1][0]); |
|
0
|
|
|
|
|
|
|
203
|
0
|
|
|
|
|
|
my @y = sort({$a<=>$b} $imgpoints[0][1], $imgpoints[1][1]); |
|
0
|
|
|
|
|
|
|
204
|
0
|
|
|
|
|
|
@points = ( # make a polyline that is ccw from lower left |
205
|
|
|
|
|
|
|
[ $x[0], $y[1] ], |
206
|
|
|
|
|
|
|
[ $x[1], $y[1] ], |
207
|
|
|
|
|
|
|
[ $x[1], $y[0] ], |
208
|
|
|
|
|
|
|
[ $x[0], $y[0] ] |
209
|
|
|
|
|
|
|
); |
210
|
|
|
|
|
|
|
} |
211
|
|
|
|
|
|
|
elsif($num > 2) { |
212
|
0
|
|
|
|
|
|
for(my $pt = 0; $pt < $num; $pt++) { |
213
|
0
|
|
|
|
|
|
$points[$pt] = [@{$imgpoints[$pt]}]; |
|
0
|
|
|
|
|
|
|
214
|
|
|
|
|
|
|
} |
215
|
|
|
|
|
|
|
} |
216
|
|
|
|
|
|
|
else { |
217
|
0
|
|
|
|
|
|
return(); |
218
|
|
|
|
|
|
|
} |
219
|
|
|
|
|
|
|
# $image_debug && print "yes have points @points\n"; |
220
|
0
|
|
|
|
|
|
return(@points); |
221
|
|
|
|
|
|
|
} |
222
|
|
|
|
|
|
|
else { |
223
|
|
|
|
|
|
|
# just give the extents pixels |
224
|
0
|
|
|
|
|
|
my @points = $self->get_image_rectangle($addr); |
225
|
0
|
|
|
|
|
|
return(@points); |
226
|
|
|
|
|
|
|
} |
227
|
|
|
|
|
|
|
} # end subroutine get_clip_points definition |
228
|
|
|
|
|
|
|
######################################################################## |
229
|
|
|
|
|
|
|
|
230
|
|
|
|
|
|
|
=head2 get_world_clip_points |
231
|
|
|
|
|
|
|
|
232
|
|
|
|
|
|
|
$drw->get_world_clip_points($addr); |
233
|
|
|
|
|
|
|
|
234
|
|
|
|
|
|
|
=cut |
235
|
|
|
|
|
|
|
sub get_world_clip_points { |
236
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
237
|
0
|
|
|
|
|
|
my ($addr) = @_; |
238
|
0
|
|
|
|
|
|
my @points = $self->get_clip_points($addr); |
239
|
0
|
0
|
|
|
|
|
if(@points) { |
240
|
0
|
|
|
|
|
|
@points = map({[$self->img_to_drw($_, $addr)]} @points); |
|
0
|
|
|
|
|
|
|
241
|
0
|
|
|
|
|
|
return(@points); |
242
|
|
|
|
|
|
|
} |
243
|
0
|
|
|
|
|
|
return(); |
244
|
|
|
|
|
|
|
} # end subroutine get_world_clip_points definition |
245
|
|
|
|
|
|
|
######################################################################## |
246
|
|
|
|
|
|
|
|
247
|
|
|
|
|
|
|
=head2 get_image_rectangle |
248
|
|
|
|
|
|
|
|
249
|
|
|
|
|
|
|
$drw->get_image_rectangle($addr); |
250
|
|
|
|
|
|
|
|
251
|
|
|
|
|
|
|
=cut |
252
|
|
|
|
|
|
|
sub get_image_rectangle { |
253
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
254
|
0
|
|
|
|
|
|
my $addr = shift; |
255
|
0
|
0
|
|
|
|
|
($addr->{type} eq "images") or croak("not an image\n"); |
256
|
0
|
|
|
|
|
|
my $obj = $self->getobj($addr); |
257
|
0
|
|
|
|
|
|
my @points = ( |
258
|
|
|
|
|
|
|
[0, $obj->{size}[1]], |
259
|
0
|
|
|
|
|
|
[@{$obj->{size}}], |
260
|
|
|
|
|
|
|
[$obj->{size}[0], 0], |
261
|
|
|
|
|
|
|
[0,0] |
262
|
|
|
|
|
|
|
); |
263
|
0
|
|
|
|
|
|
return(@points); |
264
|
|
|
|
|
|
|
} # end subroutine get_image_rectangle definition |
265
|
|
|
|
|
|
|
######################################################################## |
266
|
|
|
|
|
|
|
|
267
|
|
|
|
|
|
|
=head2 get_world_image_rectangle |
268
|
|
|
|
|
|
|
|
269
|
|
|
|
|
|
|
$drw->get_world_image_rectangle(); |
270
|
|
|
|
|
|
|
|
271
|
|
|
|
|
|
|
=cut |
272
|
|
|
|
|
|
|
sub get_world_image_rectangle { |
273
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
274
|
0
|
|
|
|
|
|
my $addr = shift; |
275
|
0
|
0
|
|
|
|
|
($addr->{type} eq "images") or croak("not an image\n"); |
276
|
0
|
|
|
|
|
|
my @points = map({[$self->img_to_drw($_, $addr)]} |
|
0
|
|
|
|
|
|
|
277
|
|
|
|
|
|
|
$self->get_image_rectangle($addr) |
278
|
|
|
|
|
|
|
); |
279
|
0
|
|
|
|
|
|
return(@points); |
280
|
|
|
|
|
|
|
} # end subroutine get_world_image_rectangle definition |
281
|
|
|
|
|
|
|
######################################################################## |
282
|
|
|
|
|
|
|
|
283
|
|
|
|
|
|
|
=head1 Image Pixel Calculations |
284
|
|
|
|
|
|
|
|
285
|
|
|
|
|
|
|
These allow you to translate between drawing space and image space. |
286
|
|
|
|
|
|
|
|
287
|
|
|
|
|
|
|
=head2 drw_to_img |
288
|
|
|
|
|
|
|
|
289
|
|
|
|
|
|
|
Returns the ($i,$j) pixel in (left-handed (typical)) image coordinates |
290
|
|
|
|
|
|
|
corresponding to the [$x,$y] value of @point. |
291
|
|
|
|
|
|
|
|
292
|
|
|
|
|
|
|
Floating point values will be returned. Do your own rounding! |
293
|
|
|
|
|
|
|
|
294
|
|
|
|
|
|
|
$drw->drw_to_img(\@point, $addr); |
295
|
|
|
|
|
|
|
|
296
|
|
|
|
|
|
|
=cut |
297
|
|
|
|
|
|
|
sub drw_to_img { |
298
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
299
|
0
|
|
|
|
|
|
my ($pt, $addr) = @_; |
300
|
0
|
|
|
|
|
|
my $obj = $self->getobj($addr); |
301
|
0
|
0
|
|
|
|
|
$obj or croak ("no image at $addr->{layer}, $addr->{id}"); |
302
|
0
|
|
|
|
|
|
my @point = @$pt; |
303
|
0
|
|
|
|
|
|
my $nx = ($point[0] - $obj->{pt}[0] ) / $obj->{vector}[0][0]; |
304
|
0
|
|
|
|
|
|
my $ny = $obj->{size}[1] - |
305
|
|
|
|
|
|
|
($point[1] - $obj->{pt}[1] ) / $obj->{vector}[1][1]; |
306
|
0
|
|
|
|
|
|
return($nx, $ny); |
307
|
|
|
|
|
|
|
} # end subroutine drw_to_img definition |
308
|
|
|
|
|
|
|
######################################################################## |
309
|
|
|
|
|
|
|
|
310
|
|
|
|
|
|
|
=head2 img_to_drw |
311
|
|
|
|
|
|
|
|
312
|
|
|
|
|
|
|
Returns the world ($x, $y) location corresponding to the image pixels in |
313
|
|
|
|
|
|
|
@pixel. |
314
|
|
|
|
|
|
|
|
315
|
|
|
|
|
|
|
$drw->img_to_drw(\@pixel, $addr); |
316
|
|
|
|
|
|
|
|
317
|
|
|
|
|
|
|
=cut |
318
|
|
|
|
|
|
|
sub img_to_drw { |
319
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
320
|
0
|
|
|
|
|
|
my ($pixel, $addr) = @_; |
321
|
0
|
|
|
|
|
|
my $obj = $self->getobj($addr); |
322
|
0
|
0
|
|
|
|
|
$obj or croak ("no image at $addr->{layer}, $addr->{id}"); |
323
|
0
|
|
|
|
|
|
my @point = @$pixel; |
324
|
0
|
|
|
|
|
|
my $px = ($point[0] - 0.5) * $obj->{vector}[0][0] + $obj->{pt}[0]; |
325
|
0
|
|
|
|
|
|
my $py = $obj->{pt}[1] + |
326
|
|
|
|
|
|
|
($obj->{size}[1] - $point[1]+0.5) * $obj->{vector}[1][1]; |
327
|
0
|
|
|
|
|
|
return($px,$py); |
328
|
|
|
|
|
|
|
} # end subroutine img_to_drw definition |
329
|
|
|
|
|
|
|
######################################################################## |
330
|
|
|
|
|
|
|
1; |