File Coverage

blib/lib/CAD/Drawing/Calculate/Finite.pm
Criterion Covered Total %
statement 12 123 9.7
branch 0 44 0.0
condition 0 3 0.0
subroutine 4 11 36.3
pod 7 7 100.0
total 23 188 12.2


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;