line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package CAD::Drawing::Calculate; |
2
|
|
|
|
|
|
|
our $VERSION = '0.12'; |
3
|
|
|
|
|
|
|
|
4
|
|
|
|
|
|
|
# use CAD::Drawing; |
5
|
3
|
|
|
3
|
|
19
|
use CAD::Drawing::Defined; |
|
3
|
|
|
|
|
7
|
|
|
3
|
|
|
|
|
653
|
|
6
|
3
|
|
|
3
|
|
1975
|
use CAD::Drawing::Calculate::Finite; |
|
3
|
|
|
|
|
7
|
|
|
3
|
|
|
|
|
150
|
|
7
|
|
|
|
|
|
|
|
8
|
|
|
|
|
|
|
our @ISA = qw( |
9
|
|
|
|
|
|
|
CAD::Drawing::Calculate::Finite |
10
|
|
|
|
|
|
|
); |
11
|
|
|
|
|
|
|
|
12
|
3
|
|
|
|
|
29
|
use CAD::Calc qw( |
13
|
|
|
|
|
|
|
dist2d |
14
|
|
|
|
|
|
|
line_intersection |
15
|
3
|
|
|
3
|
|
21
|
); |
|
3
|
|
|
|
|
6
|
|
16
|
|
|
|
|
|
|
|
17
|
3
|
|
|
3
|
|
1587
|
use Math::Vec qw(NewVec); |
|
3
|
|
|
|
|
6
|
|
|
3
|
|
|
|
|
165
|
|
18
|
|
|
|
|
|
|
|
19
|
3
|
|
|
|
|
136
|
use vars qw( |
20
|
|
|
|
|
|
|
@orthfunc |
21
|
3
|
|
|
3
|
|
17
|
); |
|
3
|
|
|
|
|
6
|
|
22
|
|
|
|
|
|
|
|
23
|
3
|
|
|
3
|
|
15
|
use warnings; |
|
3
|
|
|
|
|
6
|
|
|
3
|
|
|
|
|
94
|
|
24
|
3
|
|
|
3
|
|
54
|
use strict; |
|
3
|
|
|
|
|
3
|
|
|
3
|
|
|
|
|
94
|
|
25
|
3
|
|
|
3
|
|
16
|
use Carp; |
|
3
|
|
|
|
|
7
|
|
|
3
|
|
|
|
|
7329
|
|
26
|
|
|
|
|
|
|
######################################################################## |
27
|
|
|
|
|
|
|
=pod |
28
|
|
|
|
|
|
|
|
29
|
|
|
|
|
|
|
=head1 NAME |
30
|
|
|
|
|
|
|
|
31
|
|
|
|
|
|
|
CAD::Drawing::Calculate - Calculations for CAD::Drawing |
32
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
=head1 DESCRIPTION |
34
|
|
|
|
|
|
|
|
35
|
|
|
|
|
|
|
This module provides calculation functions for the CAD::Drawing family |
36
|
|
|
|
|
|
|
of modules. |
37
|
|
|
|
|
|
|
|
38
|
|
|
|
|
|
|
=head1 AUTHOR |
39
|
|
|
|
|
|
|
|
40
|
|
|
|
|
|
|
Eric L. Wilhelm |
41
|
|
|
|
|
|
|
|
42
|
|
|
|
|
|
|
http://scratchcomputing.com |
43
|
|
|
|
|
|
|
|
44
|
|
|
|
|
|
|
=head1 COPYRIGHT |
45
|
|
|
|
|
|
|
|
46
|
|
|
|
|
|
|
This module is copyright (C) 2004-2006 by Eric L. Wilhelm. Portions |
47
|
|
|
|
|
|
|
copyright (C) 2003 by Eric L. Wilhelm and A. Zahner Co. |
48
|
|
|
|
|
|
|
|
49
|
|
|
|
|
|
|
=head1 LICENSE |
50
|
|
|
|
|
|
|
|
51
|
|
|
|
|
|
|
This module is distributed under the same terms as Perl. See the Perl |
52
|
|
|
|
|
|
|
source package for details. |
53
|
|
|
|
|
|
|
|
54
|
|
|
|
|
|
|
You may use this software under one of the following licenses: |
55
|
|
|
|
|
|
|
|
56
|
|
|
|
|
|
|
(1) GNU General Public License |
57
|
|
|
|
|
|
|
(found at http://www.gnu.org/copyleft/gpl.html) |
58
|
|
|
|
|
|
|
(2) Artistic License |
59
|
|
|
|
|
|
|
(found at http://www.perl.com/pub/language/misc/Artistic.html) |
60
|
|
|
|
|
|
|
|
61
|
|
|
|
|
|
|
=head1 NO WARRANTY |
62
|
|
|
|
|
|
|
|
63
|
|
|
|
|
|
|
This software is distributed with ABSOLUTELY NO WARRANTY. The author, |
64
|
|
|
|
|
|
|
his former employer, and any other contributors will in no way be held |
65
|
|
|
|
|
|
|
liable for any loss or damages resulting from its use. |
66
|
|
|
|
|
|
|
|
67
|
|
|
|
|
|
|
=head1 Modifications |
68
|
|
|
|
|
|
|
|
69
|
|
|
|
|
|
|
The source code of this module is made freely available and |
70
|
|
|
|
|
|
|
distributable under the GPL or Artistic License. Modifications to and |
71
|
|
|
|
|
|
|
use of this software must adhere to one of these licenses. Changes to |
72
|
|
|
|
|
|
|
the code should be noted as such and this notification (as well as the |
73
|
|
|
|
|
|
|
above copyright information) must remain intact on all copies of the |
74
|
|
|
|
|
|
|
code. |
75
|
|
|
|
|
|
|
|
76
|
|
|
|
|
|
|
Additionally, while the author is actively developing this code, |
77
|
|
|
|
|
|
|
notification of any intended changes or extensions would be most helpful |
78
|
|
|
|
|
|
|
in avoiding repeated work for all parties involved. Please contact the |
79
|
|
|
|
|
|
|
author with any such development plans. |
80
|
|
|
|
|
|
|
|
81
|
|
|
|
|
|
|
=head1 SEE ALSO |
82
|
|
|
|
|
|
|
|
83
|
|
|
|
|
|
|
CAD::Drawing |
84
|
|
|
|
|
|
|
CAD::Calc |
85
|
|
|
|
|
|
|
Math::Vec |
86
|
|
|
|
|
|
|
|
87
|
|
|
|
|
|
|
=cut |
88
|
|
|
|
|
|
|
######################################################################## |
89
|
|
|
|
|
|
|
|
90
|
|
|
|
|
|
|
=head1 Methods |
91
|
|
|
|
|
|
|
|
92
|
|
|
|
|
|
|
=cut |
93
|
|
|
|
|
|
|
######################################################################## |
94
|
|
|
|
|
|
|
|
95
|
|
|
|
|
|
|
=head1 Extents Calculations |
96
|
|
|
|
|
|
|
|
97
|
|
|
|
|
|
|
=head2 OrthExtents |
98
|
|
|
|
|
|
|
|
99
|
|
|
|
|
|
|
Calculates the extents of a group of objects (selected according to select_addr()) and returns an array: [xmin,xmax],[ymin,ymax]. |
100
|
|
|
|
|
|
|
|
101
|
|
|
|
|
|
|
@extents = $drw->OrthExtents(\%opts); |
102
|
|
|
|
|
|
|
|
103
|
|
|
|
|
|
|
=cut |
104
|
|
|
|
|
|
|
sub OrthExtents { |
105
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
106
|
0
|
|
|
|
|
|
my($opts) = @_; |
107
|
0
|
|
|
|
|
|
my $retref = $self->select_addr($opts); |
108
|
0
|
|
|
|
|
|
my @worklist = @{$retref}; |
|
0
|
|
|
|
|
|
|
109
|
0
|
|
|
|
|
|
my(@xvals, @yvals); |
110
|
0
|
|
|
|
|
|
foreach my $addr (@worklist) { |
111
|
0
|
|
|
|
|
|
my ($xdata, $ydata) = $self->EntOrthExtents($addr); |
112
|
0
|
|
|
|
|
|
push(@xvals, @$xdata); |
113
|
0
|
|
|
|
|
|
push(@yvals, @$ydata); |
114
|
|
|
|
|
|
|
} |
115
|
0
|
|
|
|
|
|
@xvals = sort({$a<=>$b} @xvals); |
|
0
|
|
|
|
|
|
|
116
|
0
|
|
|
|
|
|
@yvals = sort({$a<=>$b} @yvals); |
|
0
|
|
|
|
|
|
|
117
|
0
|
|
|
|
|
|
return([ $xvals[0], $xvals[-1] ], [$yvals[0], $yvals[-1] ] ); |
118
|
|
|
|
|
|
|
} # end subroutine OrthExtents definition |
119
|
|
|
|
|
|
|
######################################################################## |
120
|
|
|
|
|
|
|
|
121
|
|
|
|
|
|
|
=head2 getExtentsRec |
122
|
|
|
|
|
|
|
|
123
|
|
|
|
|
|
|
Alias to OrthExtents() which returns a polyline-form array of points |
124
|
|
|
|
|
|
|
(counter clockwise from lower-left) describing a rectangle. |
125
|
|
|
|
|
|
|
|
126
|
|
|
|
|
|
|
@rec = $drw->getExtentsRec(\%opts); |
127
|
|
|
|
|
|
|
|
128
|
|
|
|
|
|
|
=cut |
129
|
|
|
|
|
|
|
sub getExtentsRec { |
130
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
131
|
0
|
|
|
|
|
|
my($opts) = @_; |
132
|
0
|
|
|
|
|
|
my ($x, $y) = $self->OrthExtents($opts); |
133
|
|
|
|
|
|
|
return( |
134
|
0
|
|
|
|
|
|
[$x->[0], $y->[0]], |
135
|
|
|
|
|
|
|
[$x->[1], $y->[0]], |
136
|
|
|
|
|
|
|
[$x->[1], $y->[1]], |
137
|
|
|
|
|
|
|
[$x->[0], $y->[1]], |
138
|
|
|
|
|
|
|
); |
139
|
|
|
|
|
|
|
} # end subroutine getExtentsRec definition |
140
|
|
|
|
|
|
|
######################################################################## |
141
|
|
|
|
|
|
|
|
142
|
|
|
|
|
|
|
=head2 EntOrthExtents |
143
|
|
|
|
|
|
|
|
144
|
|
|
|
|
|
|
Gets the orthographic extents of the object at $addr. Returns |
145
|
|
|
|
|
|
|
[\@xpts,\@y_pts] (leaving you to sort through them and find which |
146
|
|
|
|
|
|
|
is min or max.) |
147
|
|
|
|
|
|
|
|
148
|
|
|
|
|
|
|
@extents = $drw->EntOrthExtents($addr); |
149
|
|
|
|
|
|
|
|
150
|
|
|
|
|
|
|
=cut |
151
|
|
|
|
|
|
|
sub EntOrthExtents { |
152
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
153
|
0
|
|
|
|
|
|
my ($addr) = @_; |
154
|
0
|
|
|
|
|
|
my $obj = $self->getobj($addr); |
155
|
|
|
|
|
|
|
# FIXME: this will only get the point items |
156
|
0
|
|
|
|
|
|
my $stg = $call_syntax{$addr->{type}}[1]; |
157
|
0
|
|
|
|
|
|
my ($xpts, $ypts) = $orthfunc[0]{$stg}->($obj->{$stg}); |
158
|
|
|
|
|
|
|
} # end subroutine EntOrthExtents definition |
159
|
|
|
|
|
|
|
######################################################################## |
160
|
|
|
|
|
|
|
|
161
|
|
|
|
|
|
|
=head2 @orthfunc |
162
|
|
|
|
|
|
|
|
163
|
|
|
|
|
|
|
List of hash references containing code references to reduce |
164
|
|
|
|
|
|
|
duplication and facilitate natural flow (rather than ifififif |
165
|
|
|
|
|
|
|
statements.) |
166
|
|
|
|
|
|
|
|
167
|
|
|
|
|
|
|
=cut |
168
|
|
|
|
|
|
|
|
169
|
|
|
|
|
|
|
@orthfunc = ( |
170
|
|
|
|
|
|
|
{ # stage one hash ref |
171
|
|
|
|
|
|
|
"pt" => sub { |
172
|
|
|
|
|
|
|
my($pt) = @_; |
173
|
|
|
|
|
|
|
return([$pt->[0]], [$pt->[1]]); |
174
|
|
|
|
|
|
|
}, # end subroutine $orthfunc[0]{pt} definition |
175
|
|
|
|
|
|
|
"pts" => sub { |
176
|
|
|
|
|
|
|
my($pts) = @_; |
177
|
|
|
|
|
|
|
my @vals = ([], []); |
178
|
|
|
|
|
|
|
for(my $i = 0; $i < @$pts; $i++) { |
179
|
|
|
|
|
|
|
foreach my $c (0,1) { |
180
|
|
|
|
|
|
|
push(@{$vals[$c]}, $pts->[$i][$c]); |
181
|
|
|
|
|
|
|
} |
182
|
|
|
|
|
|
|
} |
183
|
|
|
|
|
|
|
return(@vals); |
184
|
|
|
|
|
|
|
}, # end subroutine $orthfunc[0]{pts} definition |
185
|
|
|
|
|
|
|
}, # end stage one hash ref |
186
|
|
|
|
|
|
|
{ # stage two hash ref |
187
|
|
|
|
|
|
|
# FIXME: here we put the fun stuff about rad and text |
188
|
|
|
|
|
|
|
}, # end stage two hash ref |
189
|
|
|
|
|
|
|
); # end @orthfunc bundle |
190
|
|
|
|
|
|
|
######################################################################## |
191
|
|
|
|
|
|
|
|
192
|
|
|
|
|
|
|
=head1 Planar Geometry Methods |
193
|
|
|
|
|
|
|
|
194
|
|
|
|
|
|
|
=head2 offset |
195
|
|
|
|
|
|
|
|
196
|
|
|
|
|
|
|
Intended as any-object offset function (not easy). |
197
|
|
|
|
|
|
|
|
198
|
|
|
|
|
|
|
$dist is negative to offset outward |
199
|
|
|
|
|
|
|
|
200
|
|
|
|
|
|
|
$drw->offset($object, $dist); |
201
|
|
|
|
|
|
|
|
202
|
|
|
|
|
|
|
=cut |
203
|
|
|
|
|
|
|
sub offset { |
204
|
0
|
|
|
0
|
1
|
|
carp("no offset function yet"); |
205
|
|
|
|
|
|
|
} # end subroutine offset definition |
206
|
|
|
|
|
|
|
######################################################################## |
207
|
|
|
|
|
|
|
|
208
|
|
|
|
|
|
|
=head2 divide |
209
|
|
|
|
|
|
|
|
210
|
|
|
|
|
|
|
$drw->divide(); |
211
|
|
|
|
|
|
|
|
212
|
|
|
|
|
|
|
=cut |
213
|
|
|
|
|
|
|
sub divide { |
214
|
0
|
|
|
0
|
1
|
|
carp("no divide function yet"); |
215
|
|
|
|
|
|
|
} # end subroutine divide definition |
216
|
|
|
|
|
|
|
######################################################################## |
217
|
|
|
|
|
|
|
|
218
|
|
|
|
|
|
|
=head2 area |
219
|
|
|
|
|
|
|
|
220
|
|
|
|
|
|
|
$drw->area($addr); |
221
|
|
|
|
|
|
|
|
222
|
|
|
|
|
|
|
=cut |
223
|
|
|
|
|
|
|
sub area { |
224
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
225
|
0
|
|
|
|
|
|
my $addr = shift; |
226
|
0
|
0
|
|
|
|
|
($addr->{type} eq "plines") or croak "only calc area for plines"; |
227
|
0
|
|
|
|
|
|
my @pgon = $self->Get("pts", $addr); |
228
|
0
|
|
|
|
|
|
my $tw_area = 0; |
229
|
0
|
|
|
|
|
|
my $x = 0; |
230
|
0
|
|
|
|
|
|
my $y = 1; |
231
|
0
|
|
|
|
|
|
for(my $i = 0; $i < @pgon; $i++) { |
232
|
0
|
|
|
|
|
|
$tw_area += ($pgon[$i][$y] + $pgon[$i-1][$y]) * |
233
|
|
|
|
|
|
|
($pgon[$i][$x] - $pgon[$i-1][$x]); |
234
|
|
|
|
|
|
|
} |
235
|
0
|
|
|
|
|
|
return( abs($tw_area / 2) ); |
236
|
|
|
|
|
|
|
} # end subroutine area definition |
237
|
|
|
|
|
|
|
######################################################################## |
238
|
|
|
|
|
|
|
|
239
|
|
|
|
|
|
|
=head1 Line Manipulations |
240
|
|
|
|
|
|
|
|
241
|
|
|
|
|
|
|
=head2 pline_to_ray |
242
|
|
|
|
|
|
|
|
243
|
|
|
|
|
|
|
Transforms a polyline with a nubbin into a ray (line with direction.) |
244
|
|
|
|
|
|
|
|
245
|
|
|
|
|
|
|
$line_addr = $drw->pline_to_ray($pline_addr); |
246
|
|
|
|
|
|
|
|
247
|
|
|
|
|
|
|
=cut |
248
|
|
|
|
|
|
|
sub pline_to_ray { |
249
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
250
|
0
|
|
|
|
|
|
my ($pl_addr) = @_; |
251
|
0
|
0
|
|
|
|
|
($pl_addr->{type} eq "plines") || carp("not a polyline"); |
252
|
0
|
|
|
|
|
|
my @pts = $self->Get("pts", $pl_addr); |
253
|
0
|
0
|
|
|
|
|
(@pts == 3) || croak("not 3 points to polyline"); |
254
|
|
|
|
|
|
|
# print "checking: ", dist2d($pts[0], $pts[1]) , |
255
|
|
|
|
|
|
|
# "<=>", |
256
|
|
|
|
|
|
|
# dist2d($pts[1], $pts[2]), |
257
|
|
|
|
|
|
|
# "\n"; |
258
|
0
|
|
|
|
|
|
my $dir = dist2d($pts[0], $pts[1]) <=> dist2d($pts[1], $pts[2]); |
259
|
0
|
0
|
|
|
|
|
($dir > 0) || (@pts = reverse(@pts)); |
260
|
0
|
|
|
|
|
|
my $obj = $self->getobj($pl_addr); |
261
|
0
|
|
|
|
|
|
my %lineopts = ( |
262
|
|
|
|
|
|
|
"layer" => $pl_addr->{layer}, |
263
|
|
|
|
|
|
|
"color" => $obj->{color}, |
264
|
|
|
|
|
|
|
"linetype" => $obj->{linetype}, |
265
|
|
|
|
|
|
|
); |
266
|
0
|
|
|
|
|
|
return($self->addline([@pts[0,1]], \%lineopts) ); |
267
|
|
|
|
|
|
|
} # end subroutine pline_to_ray definition |
268
|
|
|
|
|
|
|
######################################################################## |
269
|
|
|
|
|
|
|
|
270
|
|
|
|
|
|
|
=head2 trim_both |
271
|
|
|
|
|
|
|
|
272
|
|
|
|
|
|
|
Trims two lines to their intersection. |
273
|
|
|
|
|
|
|
|
274
|
|
|
|
|
|
|
$drw->trim_both($addr1, $addr2, $tol, \@keep_ends); |
275
|
|
|
|
|
|
|
|
276
|
|
|
|
|
|
|
See CAD::Calc::line_intersection() |
277
|
|
|
|
|
|
|
|
278
|
|
|
|
|
|
|
=cut |
279
|
|
|
|
|
|
|
sub trim_both { |
280
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
281
|
0
|
|
|
|
|
|
my @items = (shift,shift); |
282
|
0
|
|
|
|
|
|
my $tol = shift; |
283
|
0
|
|
|
|
|
|
my $ends = shift; |
284
|
0
|
|
|
|
|
|
my @keep_ends; |
285
|
0
|
0
|
|
|
|
|
if($ends) { |
286
|
0
|
0
|
|
|
|
|
(ref($ends) eq "ARRAY") or croak( |
287
|
|
|
|
|
|
|
'CAD::Drawing::Calculate::trim_both() ' . |
288
|
|
|
|
|
|
|
'\@keep_ends arg must be array' |
289
|
|
|
|
|
|
|
); |
290
|
0
|
|
|
|
|
|
@keep_ends = @$ends; |
291
|
|
|
|
|
|
|
} |
292
|
0
|
|
|
|
|
|
my @lines; |
293
|
|
|
|
|
|
|
my @vecs; |
294
|
0
|
|
|
|
|
|
my @mids; |
295
|
0
|
|
|
|
|
|
foreach my $item (@items) { |
296
|
0
|
0
|
|
|
|
|
$item or die "no item\n"; |
297
|
0
|
|
|
|
|
|
my @pts = $self->Get("pts", $item); |
298
|
|
|
|
|
|
|
# @pts or die "problem with $item\n"; |
299
|
|
|
|
|
|
|
# print "points: @{$pts[0]}, @{$pts[1]}\n"; |
300
|
0
|
|
|
|
|
|
my $vec = NewVec(NewVec(@{$pts[1]})->Minus($pts[0])); |
|
0
|
|
|
|
|
|
|
301
|
0
|
|
|
|
|
|
my $mid = [NewVec($vec->ScalarMult(0.5))->Plus($pts[0])]; |
302
|
0
|
|
|
|
|
|
push(@mids, $mid); |
303
|
0
|
|
|
|
|
|
push(@vecs, $vec); |
304
|
0
|
|
|
|
|
|
push(@lines, [@pts]); |
305
|
|
|
|
|
|
|
} |
306
|
0
|
|
|
|
|
|
my @int = line_intersection(@lines, $tol); |
307
|
|
|
|
|
|
|
## defined($int[0]) or print("no int\n"); |
308
|
0
|
0
|
|
|
|
|
defined($int[0]) or return(); |
309
|
|
|
|
|
|
|
## defined($int[1]) or print("paralell (no)\n"); |
310
|
0
|
0
|
|
|
|
|
defined($int[1]) or return(); #parallel |
311
|
|
|
|
|
|
|
# print "making vec from @int\n"; |
312
|
0
|
|
|
|
|
|
my $pt = NewVec(@int); |
313
|
|
|
|
|
|
|
# print "got point: @$pt\n"; |
314
|
0
|
|
|
|
|
|
foreach my $i (0,1) { |
315
|
0
|
|
|
|
|
|
my $end; |
316
|
0
|
0
|
|
|
|
|
if(@keep_ends) { |
317
|
0
|
|
|
|
|
|
$end = ! $keep_ends[$i]; |
318
|
|
|
|
|
|
|
} |
319
|
|
|
|
|
|
|
else { |
320
|
0
|
|
|
|
|
|
my $dot = $vecs[$i]->Dot([$pt->Minus($mids[$i])]); |
321
|
|
|
|
|
|
|
# print "dot product: $dot\n"; |
322
|
|
|
|
|
|
|
# if the dot product is positive, |
323
|
|
|
|
|
|
|
# intersection is in front of midpoint. |
324
|
0
|
|
|
|
|
|
$end = ($dot > 0); |
325
|
|
|
|
|
|
|
} |
326
|
|
|
|
|
|
|
# print "end is $end\n"; |
327
|
0
|
|
|
|
|
|
$lines[$i][$end] = $pt; |
328
|
0
|
|
|
|
|
|
$self->Set({pts => $lines[$i]}, $items[$i]); |
329
|
|
|
|
|
|
|
} |
330
|
|
|
|
|
|
|
|
331
|
0
|
|
|
|
|
|
return($pt); |
332
|
|
|
|
|
|
|
|
333
|
|
|
|
|
|
|
|
334
|
|
|
|
|
|
|
|
335
|
|
|
|
|
|
|
} # end subroutine trim_both definition |
336
|
|
|
|
|
|
|
######################################################################## |
337
|
|
|
|
|
|
|
|
338
|
|
|
|
|
|
|
=head1 Coordinate Transforms |
339
|
|
|
|
|
|
|
|
340
|
|
|
|
|
|
|
Switch between coordinate system representations. |
341
|
|
|
|
|
|
|
|
342
|
|
|
|
|
|
|
=head2 to_ocs |
343
|
|
|
|
|
|
|
|
344
|
|
|
|
|
|
|
Change the objects coordinates into the object coordinate system. |
345
|
|
|
|
|
|
|
|
346
|
|
|
|
|
|
|
Both of these are relatively quick. A simple test shows that one point |
347
|
|
|
|
|
|
|
can be taken back and forth at about 2KHz, so don't be afraid to use |
348
|
|
|
|
|
|
|
them. |
349
|
|
|
|
|
|
|
|
350
|
|
|
|
|
|
|
$drw->to_ocs($addr); |
351
|
|
|
|
|
|
|
|
352
|
|
|
|
|
|
|
=cut |
353
|
|
|
|
|
|
|
sub to_ocs { |
354
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
355
|
0
|
|
|
|
|
|
my ($addr) = @_; |
356
|
0
|
|
|
|
|
|
my $obj = $self->getobj($addr); |
357
|
0
|
0
|
|
|
|
|
if(my $n = $obj->{normal}) { |
358
|
|
|
|
|
|
|
# FIXME: if direction is Z, kill the flags |
359
|
|
|
|
|
|
|
# print "normal is @$n\n"; |
360
|
0
|
0
|
|
|
|
|
if($ac_storage_method{$addr->{type}} eq "ocs") { |
361
|
|
|
|
|
|
|
# need to translate |
362
|
0
|
|
|
|
|
|
my @ocs = _ocs_axes(@{$n}); |
|
0
|
|
|
|
|
|
|
363
|
|
|
|
|
|
|
# print "ocs is: ", join("\n", map({join(",", @{$_})} @ocs)), "\n"; |
364
|
0
|
0
|
|
|
|
|
if($obj->{pts}) { |
365
|
0
|
|
|
|
|
|
foreach my $pt (@{$obj->{pts}}) { |
|
0
|
|
|
|
|
|
|
366
|
0
|
|
|
|
|
|
@{$pt} = map({$ocs[$_]->Comp($pt)} 0..2); |
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
367
|
|
|
|
|
|
|
} |
368
|
|
|
|
|
|
|
} |
369
|
|
|
|
|
|
|
else { |
370
|
|
|
|
|
|
|
# safe to assume it is a point? |
371
|
0
|
|
|
|
|
|
@{$obj->{pt}} = map({$ocs[$_]->Comp($obj->{pt})} 0..2); |
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
372
|
|
|
|
|
|
|
} |
373
|
|
|
|
|
|
|
} # end if stored in ocs |
374
|
0
|
|
|
|
|
|
$obj->{extrusion} = $n; |
375
|
0
|
|
|
|
|
|
delete($obj->{normal}); |
376
|
|
|
|
|
|
|
} |
377
|
|
|
|
|
|
|
else { # object is in xy coords with normal in [0,0,1] direction |
378
|
0
|
|
|
|
|
|
return(); |
379
|
|
|
|
|
|
|
} |
380
|
|
|
|
|
|
|
|
381
|
|
|
|
|
|
|
} # end subroutine to_ocs definition |
382
|
|
|
|
|
|
|
######################################################################## |
383
|
|
|
|
|
|
|
|
384
|
|
|
|
|
|
|
=head2 to_wcs |
385
|
|
|
|
|
|
|
|
386
|
|
|
|
|
|
|
Change the object's coordinates into the world coordinate system. |
387
|
|
|
|
|
|
|
|
388
|
|
|
|
|
|
|
$drw->to_wcs($addr); |
389
|
|
|
|
|
|
|
|
390
|
|
|
|
|
|
|
=cut |
391
|
|
|
|
|
|
|
sub to_wcs { |
392
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
393
|
0
|
|
|
|
|
|
my ($addr) = @_; |
394
|
0
|
|
|
|
|
|
my $obj = $self->getobj($addr); |
395
|
0
|
0
|
|
|
|
|
if(my $n = $obj->{extrusion}) { |
396
|
|
|
|
|
|
|
# FIXME: if direction is Z, kill the flags |
397
|
|
|
|
|
|
|
|
398
|
|
|
|
|
|
|
# also have to check if this object is stored as WCS or OCS? |
399
|
0
|
0
|
|
|
|
|
if($ac_storage_method{$addr->{type}} eq "ocs") { |
400
|
|
|
|
|
|
|
# need to translate |
401
|
0
|
|
|
|
|
|
my @ocs = _ocs_axes(@{$n}); |
|
0
|
|
|
|
|
|
|
402
|
0
|
|
|
|
|
|
my @tcs = _wcs_axes(@ocs); |
403
|
0
|
0
|
|
|
|
|
if($obj->{pts}) { |
404
|
0
|
|
|
|
|
|
foreach my $pt (@{$obj->{pts}}) { |
|
0
|
|
|
|
|
|
|
405
|
|
|
|
|
|
|
# warn("pt was: ", join(",", @{$pt}), "\n"); |
406
|
0
|
|
|
|
|
|
@{$pt} = map({$tcs[$_]->Comp($pt)} 0..2); |
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
407
|
|
|
|
|
|
|
# warn("pts being transformed for $addr->{type} ", |
408
|
|
|
|
|
|
|
# join(",", @{$pt}), "\n"); |
409
|
|
|
|
|
|
|
} |
410
|
|
|
|
|
|
|
} |
411
|
|
|
|
|
|
|
else { |
412
|
|
|
|
|
|
|
# safe to assume it is a point? |
413
|
|
|
|
|
|
|
# warn("pt was: ", join(",", @{$obj->{pt}}), "\n"); |
414
|
0
|
|
|
|
|
|
@{$obj->{pt}} = map({$tcs[$_]->Comp($obj->{pt})} 0..2); |
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
415
|
|
|
|
|
|
|
# warn("pt being transformed for $addr->{type} ", |
416
|
|
|
|
|
|
|
# join(",", @{$obj->{pt}}), "\n"); |
417
|
|
|
|
|
|
|
} |
418
|
|
|
|
|
|
|
} # end if stored in ocs |
419
|
0
|
|
|
|
|
|
$obj->{normal} = $n; |
420
|
0
|
|
|
|
|
|
delete($obj->{extrusion}); |
421
|
|
|
|
|
|
|
} |
422
|
|
|
|
|
|
|
else { # object is in xy coords with normal in [0,0,1] direction |
423
|
0
|
|
|
|
|
|
return(); |
424
|
|
|
|
|
|
|
} |
425
|
|
|
|
|
|
|
} # end subroutine to_wcs definition |
426
|
|
|
|
|
|
|
######################################################################## |
427
|
|
|
|
|
|
|
|
428
|
|
|
|
|
|
|
=head2 flatten |
429
|
|
|
|
|
|
|
|
430
|
|
|
|
|
|
|
Puts the object in the wcs, zeros all z-coordinates and deletes the |
431
|
|
|
|
|
|
|
normal vector. Note that this is fine for projecting polylines and |
432
|
|
|
|
|
|
|
lines, but may not be what you want if you are trying to make a circle |
433
|
|
|
|
|
|
|
into an ellipse (at least not yet.) |
434
|
|
|
|
|
|
|
|
435
|
|
|
|
|
|
|
$drw->flatten($addr); |
436
|
|
|
|
|
|
|
|
437
|
|
|
|
|
|
|
=cut |
438
|
|
|
|
|
|
|
sub flatten { |
439
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
440
|
0
|
|
|
|
|
|
my ($addr) = @_; |
441
|
0
|
|
|
|
|
|
$self->to_wcs($addr); |
442
|
0
|
|
|
|
|
|
my $obj = $self->getobj($addr); |
443
|
0
|
0
|
|
|
|
|
if($obj->{pts}) { |
444
|
0
|
|
|
|
|
|
foreach my $pt (@{$obj->{pts}}) { |
|
0
|
|
|
|
|
|
|
445
|
0
|
|
|
|
|
|
$pt->[2] = 0; |
446
|
|
|
|
|
|
|
} |
447
|
|
|
|
|
|
|
} |
448
|
|
|
|
|
|
|
else { |
449
|
0
|
|
|
|
|
|
$obj->{pt}[2] = 0; |
450
|
|
|
|
|
|
|
} |
451
|
0
|
|
|
|
|
|
delete($obj->{normal}); |
452
|
|
|
|
|
|
|
} # end subroutine flatten definition |
453
|
|
|
|
|
|
|
######################################################################## |
454
|
|
|
|
|
|
|
|
455
|
|
|
|
|
|
|
=head1 Functions |
456
|
|
|
|
|
|
|
|
457
|
|
|
|
|
|
|
Non-OO internal-use functions. |
458
|
|
|
|
|
|
|
|
459
|
|
|
|
|
|
|
=head2 _ocs_axes |
460
|
|
|
|
|
|
|
|
461
|
|
|
|
|
|
|
Returns the x,y, and z axes for the ocs described by @normal. These |
462
|
|
|
|
|
|
|
will have arbitrary lengths. |
463
|
|
|
|
|
|
|
|
464
|
|
|
|
|
|
|
@local_axes = _ocs_axes(@normal); |
465
|
|
|
|
|
|
|
|
466
|
|
|
|
|
|
|
=cut |
467
|
|
|
|
|
|
|
sub _ocs_axes { |
468
|
0
|
|
|
0
|
|
|
my $z = NewVec(@_); |
469
|
0
|
|
|
|
|
|
my $x = NewVec(NewVec(0,0,1)->Cross($z)); |
470
|
0
|
0
|
|
|
|
|
($x->Length()) || ($x = NewVec($z->[2],0,0)); |
471
|
0
|
|
|
|
|
|
my $y = NewVec($z->Cross($x)); |
472
|
0
|
|
|
|
|
|
return($x,$y,$z); |
473
|
|
|
|
|
|
|
} # end subroutine _ocs_axes definition |
474
|
|
|
|
|
|
|
######################################################################## |
475
|
|
|
|
|
|
|
|
476
|
|
|
|
|
|
|
=head2 _wcs_axes |
477
|
|
|
|
|
|
|
|
478
|
|
|
|
|
|
|
Returns the x,y, and z axes for the world coordinate system in terms of |
479
|
|
|
|
|
|
|
the @ocs_axes. |
480
|
|
|
|
|
|
|
|
481
|
|
|
|
|
|
|
@trs_axes = _wcs_axes(@ocs_axes); |
482
|
|
|
|
|
|
|
|
483
|
|
|
|
|
|
|
=cut |
484
|
|
|
|
|
|
|
sub _wcs_axes { |
485
|
0
|
|
|
0
|
|
|
my (@ocs) = map({NewVec(@$_)} @_); |
|
0
|
|
|
|
|
|
|
486
|
0
|
|
|
|
|
|
my @tcs; |
487
|
0
|
|
|
|
|
|
my @wcs = map({NewVec(@$_)} [1,0,0],[0,1,0],[0,0,1]); |
|
0
|
|
|
|
|
|
|
488
|
0
|
|
|
|
|
|
foreach my $i (0..2) { |
489
|
0
|
|
|
|
|
|
$tcs[$i] = NewVec(map({$ocs[$_]->Comp($wcs[$i])} 0..2)); |
|
0
|
|
|
|
|
|
|
490
|
|
|
|
|
|
|
} |
491
|
0
|
|
|
|
|
|
return(@tcs); |
492
|
|
|
|
|
|
|
} # end subroutine _wcs_axes definition |
493
|
|
|
|
|
|
|
######################################################################## |
494
|
|
|
|
|
|
|
1; |