| 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; |