line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
#Written by Mark Winder, mark.winder4@btinternet.com
|
2
|
|
|
|
|
|
|
# Copyright 2004,2005
|
3
|
1
|
|
|
1
|
|
24185
|
use GD;
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
4
|
|
|
|
|
|
|
use strict;
|
5
|
|
|
|
|
|
|
|
6
|
|
|
|
|
|
|
package Profile;
|
7
|
|
|
|
|
|
|
use vars qw($VERSION @ISA @EXPORT);
|
8
|
|
|
|
|
|
|
$VERSION=0.061;
|
9
|
|
|
|
|
|
|
|
10
|
|
|
|
|
|
|
my $pi=4.0 * atan2(1, 1);
|
11
|
|
|
|
|
|
|
# profile
|
12
|
|
|
|
|
|
|
sub new
|
13
|
|
|
|
|
|
|
{
|
14
|
|
|
|
|
|
|
my ($class)=shift(@_);
|
15
|
|
|
|
|
|
|
my ($p)={};
|
16
|
|
|
|
|
|
|
|
17
|
|
|
|
|
|
|
if (ref($_[0]) eq $class)
|
18
|
|
|
|
|
|
|
{
|
19
|
|
|
|
|
|
|
$p=$_[0];
|
20
|
|
|
|
|
|
|
return $p->copy;
|
21
|
|
|
|
|
|
|
}
|
22
|
|
|
|
|
|
|
|
23
|
|
|
|
|
|
|
|
24
|
|
|
|
|
|
|
|
25
|
|
|
|
|
|
|
$p->{points}=[];
|
26
|
|
|
|
|
|
|
$p->{comments}=[];
|
27
|
|
|
|
|
|
|
|
28
|
|
|
|
|
|
|
while (@_)
|
29
|
|
|
|
|
|
|
{
|
30
|
|
|
|
|
|
|
push(@{$p->{points}},[shift(@_),shift(@_)]);
|
31
|
|
|
|
|
|
|
}
|
32
|
|
|
|
|
|
|
$#{$p->{comments}}=$#{$p->{points}};
|
33
|
|
|
|
|
|
|
return bless $p , $class;
|
34
|
|
|
|
|
|
|
}
|
35
|
|
|
|
|
|
|
#profile
|
36
|
|
|
|
|
|
|
sub comment
|
37
|
|
|
|
|
|
|
{
|
38
|
|
|
|
|
|
|
my($p,@c)=@_;
|
39
|
|
|
|
|
|
|
my $n=@{$p->{points}};
|
40
|
|
|
|
|
|
|
$p->{comments}->[$n].=join("\n",@c); # This creates a new comment entry, now @comments=@points+1;
|
41
|
|
|
|
|
|
|
}
|
42
|
|
|
|
|
|
|
# profile
|
43
|
|
|
|
|
|
|
sub copy
|
44
|
|
|
|
|
|
|
{
|
45
|
|
|
|
|
|
|
my ($p)=@_;
|
46
|
|
|
|
|
|
|
my $q={};
|
47
|
|
|
|
|
|
|
|
48
|
|
|
|
|
|
|
$q->{points}=[];
|
49
|
|
|
|
|
|
|
$q->{comments}=[];
|
50
|
|
|
|
|
|
|
|
51
|
|
|
|
|
|
|
for (@{$p->{points}})
|
52
|
|
|
|
|
|
|
{
|
53
|
|
|
|
|
|
|
push(@{$q->{points}},[@$_]);
|
54
|
|
|
|
|
|
|
}
|
55
|
|
|
|
|
|
|
@{$q->{comments}}=@{$p->{comments}};
|
56
|
|
|
|
|
|
|
|
57
|
|
|
|
|
|
|
return bless $q, ref($p);
|
58
|
|
|
|
|
|
|
}
|
59
|
|
|
|
|
|
|
|
60
|
|
|
|
|
|
|
# profile
|
61
|
|
|
|
|
|
|
# return all points, 1 point or a range of points as a 1 dimentional array (alternate x-y pairs. )
|
62
|
|
|
|
|
|
|
# eg allowed a,b are -3,-1 for last 3 points, oldest first.
|
63
|
|
|
|
|
|
|
# -1 for last point
|
64
|
|
|
|
|
|
|
# 0 for 1st point
|
65
|
|
|
|
|
|
|
# nothing for all points
|
66
|
|
|
|
|
|
|
|
67
|
|
|
|
|
|
|
sub points
|
68
|
|
|
|
|
|
|
{
|
69
|
|
|
|
|
|
|
my ($p,$a,$b)=@_;
|
70
|
|
|
|
|
|
|
|
71
|
|
|
|
|
|
|
if (!defined $a and !defined $b)
|
72
|
|
|
|
|
|
|
{
|
73
|
|
|
|
|
|
|
return map { ($$_[0],$$_[1]) } @{$p->{points}};
|
74
|
|
|
|
|
|
|
}
|
75
|
|
|
|
|
|
|
elsif (!defined $b)
|
76
|
|
|
|
|
|
|
{
|
77
|
|
|
|
|
|
|
return map { ($$_[0],$$_[1]) } ${$p->{points}}[$a];
|
78
|
|
|
|
|
|
|
}
|
79
|
|
|
|
|
|
|
else
|
80
|
|
|
|
|
|
|
{
|
81
|
|
|
|
|
|
|
my @pp=@{$p->{points}};
|
82
|
|
|
|
|
|
|
@pp=@pp[$a,$b];
|
83
|
|
|
|
|
|
|
return map { ($$_[0],$$_[1]) } @pp;
|
84
|
|
|
|
|
|
|
}
|
85
|
|
|
|
|
|
|
}
|
86
|
|
|
|
|
|
|
|
87
|
|
|
|
|
|
|
# profile
|
88
|
|
|
|
|
|
|
# Take 2 (for a move) or 4 (for an arc) points and add to end of the profile
|
89
|
|
|
|
|
|
|
# can also take an existing profile, adding it to the 1st.
|
90
|
|
|
|
|
|
|
sub ppush
|
91
|
|
|
|
|
|
|
{
|
92
|
|
|
|
|
|
|
my ($p)=shift(@_);
|
93
|
|
|
|
|
|
|
if (ref($_[0]) ne '')
|
94
|
|
|
|
|
|
|
{
|
95
|
|
|
|
|
|
|
my $q=shift(@_);
|
96
|
|
|
|
|
|
|
my $sp=@{$p->{points}};
|
97
|
|
|
|
|
|
|
|
98
|
|
|
|
|
|
|
$#{$q->{comments}}=$#{$q->{points}};
|
99
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
my @comments=@{$q->{comments}};
|
101
|
|
|
|
|
|
|
if ($#{$p->{comments}}>$#{$p->{points}}) # if we called comment in advance, we need to add the last comment on to 1st comment of new one.
|
102
|
|
|
|
|
|
|
{
|
103
|
|
|
|
|
|
|
$p->{comments}->[-1]=$p->{comments}->[-1].$q->{comments}->[0];
|
104
|
|
|
|
|
|
|
shift (@comments);
|
105
|
|
|
|
|
|
|
}
|
106
|
|
|
|
|
|
|
push(@{$p->{comments}},@comments);
|
107
|
|
|
|
|
|
|
push(@{$p->{points}},@{$q->{points}});
|
108
|
|
|
|
|
|
|
}
|
109
|
|
|
|
|
|
|
else
|
110
|
|
|
|
|
|
|
{
|
111
|
|
|
|
|
|
|
push(@{$p->{points}},[@_]);
|
112
|
|
|
|
|
|
|
}
|
113
|
|
|
|
|
|
|
$#{$p->{comments}}=$#{$p->{points}}; # if a comment has been added, this has no effect if 1 point added, otherwise it adds empty entries to the comments array.
|
114
|
|
|
|
|
|
|
return $p;
|
115
|
|
|
|
|
|
|
}
|
116
|
|
|
|
|
|
|
|
117
|
|
|
|
|
|
|
#profile
|
118
|
|
|
|
|
|
|
sub shift
|
119
|
|
|
|
|
|
|
{
|
120
|
|
|
|
|
|
|
my ($p)=shift(@_);
|
121
|
|
|
|
|
|
|
|
122
|
|
|
|
|
|
|
shift(@{$p->{comments}}); # Throw away this comment.
|
123
|
|
|
|
|
|
|
my $pp=shift @{$p->{points}};
|
124
|
|
|
|
|
|
|
return @$pp;
|
125
|
|
|
|
|
|
|
}
|
126
|
|
|
|
|
|
|
|
127
|
|
|
|
|
|
|
# profile
|
128
|
|
|
|
|
|
|
# insert a point backwards into the profile. n=1 means between last point and point before.
|
129
|
|
|
|
|
|
|
sub insertback
|
130
|
|
|
|
|
|
|
{
|
131
|
|
|
|
|
|
|
my ($p,$n,$x,$y,$r,$ccw)=@_; # set n to zero makes same as push, n=1 means 1 before latest point.
|
132
|
|
|
|
|
|
|
$#{$p->{comments}}=$#{$p->{points}};
|
133
|
|
|
|
|
|
|
splice(@{$p->{points}},@{$p->{points}}-$n,0,[$x,$y,$r,$ccw]);
|
134
|
|
|
|
|
|
|
splice(@{$p->{comments}},@{$p->{comments}}-$n,0,"");
|
135
|
|
|
|
|
|
|
|
136
|
|
|
|
|
|
|
return $p;
|
137
|
|
|
|
|
|
|
}
|
138
|
|
|
|
|
|
|
|
139
|
|
|
|
|
|
|
# profile
|
140
|
|
|
|
|
|
|
# This function deduplicates repeated points. These can arrise for example if you mirror or rotate a profile and then add them
|
141
|
|
|
|
|
|
|
# together. Because rounding errors can and do arrise, we need to have a fudge factor here that is the small amount
|
142
|
|
|
|
|
|
|
# used in comparison. Anything smaller than this is considered the same. I may have set this a little small,
|
143
|
|
|
|
|
|
|
# but it worked for me. Change $d if you need to.
|
144
|
|
|
|
|
|
|
#
|
145
|
|
|
|
|
|
|
# The reson duplicates are bad is that it confuses reference to particular points, eg 5 points before the
|
146
|
|
|
|
|
|
|
# present one when doing things like smoothing.
|
147
|
|
|
|
|
|
|
sub dedupe
|
148
|
|
|
|
|
|
|
{
|
149
|
|
|
|
|
|
|
my ($p)=@_;
|
150
|
|
|
|
|
|
|
|
151
|
|
|
|
|
|
|
my $d=1e-10; # How small before point is considered a duplicate ?
|
152
|
|
|
|
|
|
|
|
153
|
|
|
|
|
|
|
my @points;
|
154
|
|
|
|
|
|
|
my @comments;
|
155
|
|
|
|
|
|
|
|
156
|
|
|
|
|
|
|
my $old;
|
157
|
|
|
|
|
|
|
|
158
|
|
|
|
|
|
|
my $i=0;
|
159
|
|
|
|
|
|
|
for (@{$p->{points}})
|
160
|
|
|
|
|
|
|
{
|
161
|
|
|
|
|
|
|
|
162
|
|
|
|
|
|
|
if (abs($$_[0]-$$old[0])>$d or abs($$_[1]-$$old[1])>$d or !$old)
|
163
|
|
|
|
|
|
|
{
|
164
|
|
|
|
|
|
|
push(@points,$_);
|
165
|
|
|
|
|
|
|
push(@comments,$p->{comments}->[$i]);
|
166
|
|
|
|
|
|
|
}
|
167
|
|
|
|
|
|
|
else
|
168
|
|
|
|
|
|
|
{ # point is a duplicate, not including.
|
169
|
|
|
|
|
|
|
$comments[-1].=$p->{comments}->[$i];
|
170
|
|
|
|
|
|
|
}
|
171
|
|
|
|
|
|
|
$i++;
|
172
|
|
|
|
|
|
|
$old=$_;
|
173
|
|
|
|
|
|
|
}
|
174
|
|
|
|
|
|
|
# @{$p->{points}}=@points;
|
175
|
|
|
|
|
|
|
$p->{points}=\@points;
|
176
|
|
|
|
|
|
|
$p->{comments}=\@comments;
|
177
|
|
|
|
|
|
|
return $p;
|
178
|
|
|
|
|
|
|
}
|
179
|
|
|
|
|
|
|
|
180
|
|
|
|
|
|
|
# profile.
|
181
|
|
|
|
|
|
|
# reverse the cut direction of a profile. This also cleverly attempts to move both arc paramters and comments
|
182
|
|
|
|
|
|
|
# around to take account of the new cut order, so that the comments still get printed out in the
|
183
|
|
|
|
|
|
|
# right place. Bit academic really as if you are reversing round a bend comments about whats round the corner
|
184
|
|
|
|
|
|
|
# are probably misguided any way!
|
185
|
|
|
|
|
|
|
sub reverse
|
186
|
|
|
|
|
|
|
{
|
187
|
|
|
|
|
|
|
my ($pp)=@_;
|
188
|
|
|
|
|
|
|
|
189
|
|
|
|
|
|
|
$#{$pp->{comments}}=$#{$pp->{points}};
|
190
|
|
|
|
|
|
|
my $p=$pp->copy;
|
191
|
|
|
|
|
|
|
|
192
|
|
|
|
|
|
|
@{$p->{points}}=reverse @{$p->{points}};
|
193
|
|
|
|
|
|
|
@{$p->{comments}}=reverse @{$p->{comments}};
|
194
|
|
|
|
|
|
|
|
195
|
|
|
|
|
|
|
my @arc1=();
|
196
|
|
|
|
|
|
|
my @arc2=();
|
197
|
|
|
|
|
|
|
for (@{$p->{points}})
|
198
|
|
|
|
|
|
|
{
|
199
|
|
|
|
|
|
|
@arc2=($$_[2],$$_[3]==0);
|
200
|
|
|
|
|
|
|
@$_[2,3]=@arc1;
|
201
|
|
|
|
|
|
|
@arc1=@arc2;
|
202
|
|
|
|
|
|
|
}
|
203
|
|
|
|
|
|
|
|
204
|
|
|
|
|
|
|
|
205
|
|
|
|
|
|
|
return $p;
|
206
|
|
|
|
|
|
|
}
|
207
|
|
|
|
|
|
|
#profile
|
208
|
|
|
|
|
|
|
# replace the latest point or some point before it.
|
209
|
|
|
|
|
|
|
sub replaceback
|
210
|
|
|
|
|
|
|
{
|
211
|
|
|
|
|
|
|
my ($p,$n,$x,$y,$r,$ccw)=@_; # set n to zero to replace the latest point
|
212
|
|
|
|
|
|
|
splice(@{$p->{points}},@{$p->{points}}-$n-1,1,[$x,$y,$r,$ccw]);
|
213
|
|
|
|
|
|
|
return $p;
|
214
|
|
|
|
|
|
|
}
|
215
|
|
|
|
|
|
|
#profile
|
216
|
|
|
|
|
|
|
sub print # formatted debug
|
217
|
|
|
|
|
|
|
{
|
218
|
|
|
|
|
|
|
my ($p)=@_;
|
219
|
|
|
|
|
|
|
$"=",";
|
220
|
|
|
|
|
|
|
my $i=0;
|
221
|
|
|
|
|
|
|
for (@{$p->{points}})
|
222
|
|
|
|
|
|
|
{
|
223
|
|
|
|
|
|
|
my $c=$p->{comments}->[$i];
|
224
|
|
|
|
|
|
|
$c.="\n" if ($c and $c!~ m/\n$/s );
|
225
|
|
|
|
|
|
|
print "**** $c" if ($c);
|
226
|
|
|
|
|
|
|
print "[ @$_ ]\n";
|
227
|
|
|
|
|
|
|
$i++;
|
228
|
|
|
|
|
|
|
|
229
|
|
|
|
|
|
|
}
|
230
|
|
|
|
|
|
|
my $c=$p->{comments}->[$i];
|
231
|
|
|
|
|
|
|
$c.="\n" if ($c and $c!~ m/\n$/s );
|
232
|
|
|
|
|
|
|
print "**** $c" if ($c);
|
233
|
|
|
|
|
|
|
|
234
|
|
|
|
|
|
|
return $p;
|
235
|
|
|
|
|
|
|
}
|
236
|
|
|
|
|
|
|
|
237
|
|
|
|
|
|
|
|
238
|
|
|
|
|
|
|
# just so as I remember matric rotations are as follows:
|
239
|
|
|
|
|
|
|
# cw rotation, cos a sin a
|
240
|
|
|
|
|
|
|
# -sin a cos a
|
241
|
|
|
|
|
|
|
#
|
242
|
|
|
|
|
|
|
# ccw rotation cos a -sin a
|
243
|
|
|
|
|
|
|
# sin a cos a
|
244
|
|
|
|
|
|
|
|
245
|
|
|
|
|
|
|
|
246
|
|
|
|
|
|
|
|
247
|
|
|
|
|
|
|
# Gives ccw rotation about the supplied point by an angle $a in radians
|
248
|
|
|
|
|
|
|
# if xc,$yc ommitted, rotation about origin.
|
249
|
|
|
|
|
|
|
# profile
|
250
|
|
|
|
|
|
|
sub rotate
|
251
|
|
|
|
|
|
|
{
|
252
|
|
|
|
|
|
|
my ($pp,$a,$xc,$yc)=@_;
|
253
|
|
|
|
|
|
|
|
254
|
|
|
|
|
|
|
my $p=$pp->copy;
|
255
|
|
|
|
|
|
|
|
256
|
|
|
|
|
|
|
for (@{$p->{points}})
|
257
|
|
|
|
|
|
|
{
|
258
|
|
|
|
|
|
|
@$_=($$_[0]-$xc,$$_[1]-$yc,$$_[2],$$_[3]);
|
259
|
|
|
|
|
|
|
|
260
|
|
|
|
|
|
|
}
|
261
|
|
|
|
|
|
|
|
262
|
|
|
|
|
|
|
for (@{$p->{points}})
|
263
|
|
|
|
|
|
|
{
|
264
|
|
|
|
|
|
|
@$_=($$_[0]*cos($a)-$$_[1]*sin($a),$$_[0]*sin($a)+$$_[1]*cos($a),$$_[2],$$_[3]);
|
265
|
|
|
|
|
|
|
|
266
|
|
|
|
|
|
|
}
|
267
|
|
|
|
|
|
|
|
268
|
|
|
|
|
|
|
|
269
|
|
|
|
|
|
|
for (@{$p->{points}})
|
270
|
|
|
|
|
|
|
{
|
271
|
|
|
|
|
|
|
@$_=($$_[0]+$xc,$$_[1]+$yc,$$_[2],$$_[3]);
|
272
|
|
|
|
|
|
|
}
|
273
|
|
|
|
|
|
|
return $p;
|
274
|
|
|
|
|
|
|
}
|
275
|
|
|
|
|
|
|
|
276
|
|
|
|
|
|
|
# mirror about the y axis
|
277
|
|
|
|
|
|
|
# profile
|
278
|
|
|
|
|
|
|
sub mirrory
|
279
|
|
|
|
|
|
|
{
|
280
|
|
|
|
|
|
|
my ($pp)=@_;
|
281
|
|
|
|
|
|
|
|
282
|
|
|
|
|
|
|
my $p=$pp->copy;
|
283
|
|
|
|
|
|
|
|
284
|
|
|
|
|
|
|
for (@{$p->{points}})
|
285
|
|
|
|
|
|
|
{
|
286
|
|
|
|
|
|
|
@$_=(-$$_[0],$$_[1],$$_[2],$$_[3]==0);
|
287
|
|
|
|
|
|
|
|
288
|
|
|
|
|
|
|
}
|
289
|
|
|
|
|
|
|
|
290
|
|
|
|
|
|
|
return $p;
|
291
|
|
|
|
|
|
|
}
|
292
|
|
|
|
|
|
|
|
293
|
|
|
|
|
|
|
# A translation, all points moved by this vector.
|
294
|
|
|
|
|
|
|
# profile
|
295
|
|
|
|
|
|
|
sub move
|
296
|
|
|
|
|
|
|
{
|
297
|
|
|
|
|
|
|
my ($pp,$xc,$yc)=@_;
|
298
|
|
|
|
|
|
|
|
299
|
|
|
|
|
|
|
my $p=$pp->copy;
|
300
|
|
|
|
|
|
|
|
301
|
|
|
|
|
|
|
for (@{$p->{points}})
|
302
|
|
|
|
|
|
|
{
|
303
|
|
|
|
|
|
|
@$_=($$_[0]+$xc,$$_[1]+$yc,$$_[2],$$_[3]);
|
304
|
|
|
|
|
|
|
|
305
|
|
|
|
|
|
|
}
|
306
|
|
|
|
|
|
|
return $p;
|
307
|
|
|
|
|
|
|
}
|
308
|
|
|
|
|
|
|
|
309
|
|
|
|
|
|
|
# similar to smooth, which joints a line to an arc with another arc, this function
|
310
|
|
|
|
|
|
|
# takes two lines that join at an angle and generates an arc that joins them of radius r,
|
311
|
|
|
|
|
|
|
# chopping out a section of each line where the arc goes. Idea is to make a smooth transition
|
312
|
|
|
|
|
|
|
# so that on concave cuts it is possible to cut with a circular cutter of more than
|
313
|
|
|
|
|
|
|
# infinitely small diameter! and on conves cuts it just looks nicer, or can do.
|
314
|
|
|
|
|
|
|
# This could be incorporated into smooth so that smooth works even when lines rather
|
315
|
|
|
|
|
|
|
# than arcs are given, but havnt done that.
|
316
|
|
|
|
|
|
|
# profile
|
317
|
|
|
|
|
|
|
sub linesmooth
|
318
|
|
|
|
|
|
|
{
|
319
|
|
|
|
|
|
|
my ($p,$r,$n)=@_;
|
320
|
|
|
|
|
|
|
|
321
|
|
|
|
|
|
|
|
322
|
|
|
|
|
|
|
# assume 3 points l1,l2,l3, where l2 is the nth point in the profile, 0 means penultimate point though.
|
323
|
|
|
|
|
|
|
# want to insert circular section such that circle radius r is tangential.
|
324
|
|
|
|
|
|
|
|
325
|
|
|
|
|
|
|
# simple trig gives distance of the join points along each line as
|
326
|
|
|
|
|
|
|
# l=r/tan k where k is half the angle l1 l2 l3.
|
327
|
|
|
|
|
|
|
# calulate this as 0.5 * ( 180 -a1 -a3 ) where tan a1 = (x2-x1)/(y2-y1), tan a3=(x3-x2)/(y3-y2)
|
328
|
|
|
|
|
|
|
# from l we calculate the 2 new points parametrically sliding from l2 to l1, and l2 to l3.
|
329
|
|
|
|
|
|
|
|
330
|
|
|
|
|
|
|
my (@points)=@{$p->{points}};
|
331
|
|
|
|
|
|
|
|
332
|
|
|
|
|
|
|
|
333
|
|
|
|
|
|
|
$n=$#points if ($n==0);
|
334
|
|
|
|
|
|
|
|
335
|
|
|
|
|
|
|
my (@p1)=@{$points[$n-1]};
|
336
|
|
|
|
|
|
|
my (@p2)=@{$points[$n]};
|
337
|
|
|
|
|
|
|
my (@p3)=@{$points[$n+1]};
|
338
|
|
|
|
|
|
|
|
339
|
|
|
|
|
|
|
my (@extra)=(abs($r));
|
340
|
|
|
|
|
|
|
|
341
|
|
|
|
|
|
|
my $k=0.5*($pi-atan2(abs($p2[1]-$p1[1]),abs($p2[0]-$p1[0]))-atan2(abs($p3[1]-$p2[1]),abs($p3[0]-$p2[0])));
|
342
|
|
|
|
|
|
|
|
343
|
|
|
|
|
|
|
$extra[1]=($r>0);
|
344
|
|
|
|
|
|
|
$r=abs($r);
|
345
|
|
|
|
|
|
|
|
346
|
|
|
|
|
|
|
|
347
|
|
|
|
|
|
|
my $l=$r*cos($k)/sin($k);
|
348
|
|
|
|
|
|
|
|
349
|
|
|
|
|
|
|
|
350
|
|
|
|
|
|
|
# Find the start of arc by parametric substitution into p2,p1
|
351
|
|
|
|
|
|
|
my $ll=sqrt(($p2[0]-$p1[0])**2+($p2[1]-$p1[1])**2); # length of this line;
|
352
|
|
|
|
|
|
|
|
353
|
|
|
|
|
|
|
my $sax=$p2[0]*($ll-$l)/$ll+$p1[0]*($l/$ll);
|
354
|
|
|
|
|
|
|
my $say=$p2[1]*($ll-$l)/$ll+$p1[1]*($l/$ll);
|
355
|
|
|
|
|
|
|
|
356
|
|
|
|
|
|
|
# Find the end of arc by parametric substitution into line p2,p3
|
357
|
|
|
|
|
|
|
$ll=sqrt(($p3[0]-$p2[0])**2+($p3[1]-$p2[1])**2); # length of this line;
|
358
|
|
|
|
|
|
|
my $eax=$p2[0]*($ll-$l)/$ll+$p3[0]*($l/$ll);
|
359
|
|
|
|
|
|
|
my $eay=$p2[1]*($ll-$l)/$ll+$p3[1]*($l/$ll);
|
360
|
|
|
|
|
|
|
|
361
|
|
|
|
|
|
|
$p->replaceback(@points-$n-1,$sax,$say);
|
362
|
|
|
|
|
|
|
$p->insertback(@points-$n-1,$eax,$eay,@extra);
|
363
|
|
|
|
|
|
|
return $p;
|
364
|
|
|
|
|
|
|
}
|
365
|
|
|
|
|
|
|
# see wheel smooth.
|
366
|
|
|
|
|
|
|
# profile
|
367
|
|
|
|
|
|
|
# p the profile, smooth3e the last 3 points, which should be line then arc. Smooth with circle radius r.
|
368
|
|
|
|
|
|
|
# x, y is the center of the arc. joining last 2 points in profile
|
369
|
|
|
|
|
|
|
# profile
|
370
|
|
|
|
|
|
|
sub smooth
|
371
|
|
|
|
|
|
|
{
|
372
|
|
|
|
|
|
|
my ($p,$r,$x,$y)=@_;
|
373
|
|
|
|
|
|
|
$"=',';
|
374
|
|
|
|
|
|
|
my $c;
|
375
|
|
|
|
|
|
|
|
376
|
|
|
|
|
|
|
my $w=Wheel->new(); # actually, we know that no characteristics from wheel are used here, so use a new one.
|
377
|
|
|
|
|
|
|
# assume you call with last point is an arc,
|
378
|
|
|
|
|
|
|
|
379
|
|
|
|
|
|
|
$p=$p->move(-$x,-$y);
|
380
|
|
|
|
|
|
|
|
381
|
|
|
|
|
|
|
my @ps=@{$p->{points}};
|
382
|
|
|
|
|
|
|
|
383
|
|
|
|
|
|
|
my @last=grep { defined } @{$ps[-1]};
|
384
|
|
|
|
|
|
|
my @l2 =grep { defined } @{$ps[-2]};
|
385
|
|
|
|
|
|
|
my @l1 =grep { defined } @{$ps[-3]};
|
386
|
|
|
|
|
|
|
|
387
|
|
|
|
|
|
|
my $last="last";
|
388
|
|
|
|
|
|
|
my $l2='l2';
|
389
|
|
|
|
|
|
|
my $swap=0;
|
390
|
|
|
|
|
|
|
|
391
|
|
|
|
|
|
|
my @extra;
|
392
|
|
|
|
|
|
|
|
393
|
|
|
|
|
|
|
if (@last==2) # need to swap order.
|
394
|
|
|
|
|
|
|
{
|
395
|
|
|
|
|
|
|
my @tmp=@l1; @l1=@last; @last=@tmp;
|
396
|
|
|
|
|
|
|
@last[2,3]=@l2[2,3];
|
397
|
|
|
|
|
|
|
@extra=@l2[2,3];
|
398
|
|
|
|
|
|
|
@l2[2,3]=();
|
399
|
|
|
|
|
|
|
@l2=grep{ defined} @l2;
|
400
|
|
|
|
|
|
|
@last=grep { defined } @last;
|
401
|
|
|
|
|
|
|
$l2='last';
|
402
|
|
|
|
|
|
|
$last='l2';
|
403
|
|
|
|
|
|
|
$swap=1;
|
404
|
|
|
|
|
|
|
}
|
405
|
|
|
|
|
|
|
|
406
|
|
|
|
|
|
|
die "$last point needs to be arc is @last" if (@last==2);
|
407
|
|
|
|
|
|
|
die "$l2 must be line , is @l2" if (@l2 != 2);
|
408
|
|
|
|
|
|
|
|
409
|
|
|
|
|
|
|
@l1=@l1[0,1]; # not intrested in arc or line.
|
410
|
|
|
|
|
|
|
|
411
|
|
|
|
|
|
|
my $a1=180*atan2($last[1]-$l2[1],$last[0]-$l2[0])/$pi;
|
412
|
|
|
|
|
|
|
my $a2=180*atan2($l2[1]-$l1[1],$l2[0]-$l1[0])/$pi;
|
413
|
|
|
|
|
|
|
|
414
|
|
|
|
|
|
|
$c=0;
|
415
|
|
|
|
|
|
|
$c=1 if (($a1-$a2+360+180)%360-180<0); # This works round bugs. reverses circle.
|
416
|
|
|
|
|
|
|
|
417
|
|
|
|
|
|
|
my (undef,undef,$sax,$say,$eax,$eay)= $w->smooth(@l1,@l2,$last[2],-$r*(1-$c-$c) );
|
418
|
|
|
|
|
|
|
|
419
|
|
|
|
|
|
|
if ($swap)
|
420
|
|
|
|
|
|
|
{
|
421
|
|
|
|
|
|
|
my @tmp=@l1; @l1=@last; @last=@tmp;
|
422
|
|
|
|
|
|
|
@last[2,3]=();
|
423
|
|
|
|
|
|
|
($sax,$say,$eax,$eay)=($eax,$eay,$sax,$say);
|
424
|
|
|
|
|
|
|
}
|
425
|
|
|
|
|
|
|
|
426
|
|
|
|
|
|
|
$p->replaceback(1,$sax,$say,@extra);
|
427
|
|
|
|
|
|
|
$p->insertback(1,$eax,$eay,$r,($swap==0)!=$c);
|
428
|
|
|
|
|
|
|
$p=$p->move($x,$y);
|
429
|
|
|
|
|
|
|
return $p;
|
430
|
|
|
|
|
|
|
}
|
431
|
|
|
|
|
|
|
|
432
|
|
|
|
|
|
|
# profile
|
433
|
|
|
|
|
|
|
#
|
434
|
|
|
|
|
|
|
# move 1 point from start to finish. Used when we want to start cutting a profile in better place.
|
435
|
|
|
|
|
|
|
# move any comments also.
|
436
|
|
|
|
|
|
|
sub movestartfin
|
437
|
|
|
|
|
|
|
{
|
438
|
|
|
|
|
|
|
my ($p)=@_;
|
439
|
|
|
|
|
|
|
|
440
|
|
|
|
|
|
|
$#{$p->{comments}}=$#{$p->{points}};
|
441
|
|
|
|
|
|
|
my @points=@{$p->{points}};
|
442
|
|
|
|
|
|
|
my @comments=@{$p->{comments}};
|
443
|
|
|
|
|
|
|
|
444
|
|
|
|
|
|
|
|
445
|
|
|
|
|
|
|
@points=(@points[1..$#points,0]);
|
446
|
|
|
|
|
|
|
@comments=(@comments[1..$#points,0]);
|
447
|
|
|
|
|
|
|
|
448
|
|
|
|
|
|
|
# @{$p->{points}}=@points;
|
449
|
|
|
|
|
|
|
$p->{points}=\@points;
|
450
|
|
|
|
|
|
|
$p->{comments}=\@comments;
|
451
|
|
|
|
|
|
|
|
452
|
|
|
|
|
|
|
return $p;
|
453
|
|
|
|
|
|
|
|
454
|
|
|
|
|
|
|
}
|
455
|
|
|
|
|
|
|
|
456
|
|
|
|
|
|
|
# profile
|
457
|
|
|
|
|
|
|
#
|
458
|
|
|
|
|
|
|
# move 1 point from finish to start. Used when we want to start cutting a profile in better place.
|
459
|
|
|
|
|
|
|
# move any comments also.
|
460
|
|
|
|
|
|
|
sub movefinstart
|
461
|
|
|
|
|
|
|
{
|
462
|
|
|
|
|
|
|
my ($p)=@_;
|
463
|
|
|
|
|
|
|
|
464
|
|
|
|
|
|
|
$#{$p->{comments}}=$#{$p->{points}};
|
465
|
|
|
|
|
|
|
my @points=@{$p->{points}};
|
466
|
|
|
|
|
|
|
my @comments=@{$p->{comments}};
|
467
|
|
|
|
|
|
|
|
468
|
|
|
|
|
|
|
|
469
|
|
|
|
|
|
|
@points=(@points[-1..$#points-1]);
|
470
|
|
|
|
|
|
|
@comments=(@comments[-1..$#points-1]);
|
471
|
|
|
|
|
|
|
|
472
|
|
|
|
|
|
|
$p->{points}=\@points;
|
473
|
|
|
|
|
|
|
$p->{comments}=\@comments;
|
474
|
|
|
|
|
|
|
|
475
|
|
|
|
|
|
|
return $p;
|
476
|
|
|
|
|
|
|
|
477
|
|
|
|
|
|
|
}
|
478
|
|
|
|
|
|
|
|
479
|
|
|
|
|
|
|
# profile
|
480
|
|
|
|
|
|
|
sub plot
|
481
|
|
|
|
|
|
|
{
|
482
|
|
|
|
|
|
|
|
483
|
|
|
|
|
|
|
my ($p,$g,$z,$passes,$passdepth,$open)=@_;
|
484
|
|
|
|
|
|
|
|
485
|
|
|
|
|
|
|
my @points=@{$p->{points}};
|
486
|
|
|
|
|
|
|
my @point1=@{$points[0]};
|
487
|
|
|
|
|
|
|
my @point2=@{$points[1]};
|
488
|
|
|
|
|
|
|
my $point;
|
489
|
|
|
|
|
|
|
|
490
|
|
|
|
|
|
|
my $zup=0.05;
|
491
|
|
|
|
|
|
|
my $zdown=$z;
|
492
|
|
|
|
|
|
|
|
493
|
|
|
|
|
|
|
$z=$zup;
|
494
|
|
|
|
|
|
|
|
495
|
|
|
|
|
|
|
$g->gmove('z',$z);
|
496
|
|
|
|
|
|
|
$g->gmove('x',$point1[0],'y',$point1[1]);
|
497
|
|
|
|
|
|
|
|
498
|
|
|
|
|
|
|
my $i=0;
|
499
|
|
|
|
|
|
|
|
500
|
|
|
|
|
|
|
for my $pass ( 1..$passes)
|
501
|
|
|
|
|
|
|
{
|
502
|
|
|
|
|
|
|
# $z+=$passdepth;
|
503
|
|
|
|
|
|
|
$i=0;
|
504
|
|
|
|
|
|
|
for $point (@points,\@point1)
|
505
|
|
|
|
|
|
|
{
|
506
|
|
|
|
|
|
|
|
507
|
|
|
|
|
|
|
if ($point==\@point1 and $open ) # last point, return to start. Open if set, allows a non-closed profile to be cut. Debug ?
|
508
|
|
|
|
|
|
|
{
|
509
|
|
|
|
|
|
|
$z=0.1;
|
510
|
|
|
|
|
|
|
$g->gmove('z',$z);
|
511
|
|
|
|
|
|
|
}
|
512
|
|
|
|
|
|
|
|
513
|
|
|
|
|
|
|
$g->gcomment("Pass $pass of $passes ".$p->{comments}->[$i]) if ($p->{comments}->[$i]);
|
514
|
|
|
|
|
|
|
|
515
|
|
|
|
|
|
|
if ($$point[2] and $$point[3] and $i!=0) # radius of curveture, ccw , not cw for arc.
|
516
|
|
|
|
|
|
|
{
|
517
|
|
|
|
|
|
|
$g->garcccw('z',$z,'x',$$point[0],'y',$$point[1],'r',$$point[2]);
|
518
|
|
|
|
|
|
|
}
|
519
|
|
|
|
|
|
|
elsif ($$point[2] and $i!=0 ) # for cw arc
|
520
|
|
|
|
|
|
|
{
|
521
|
|
|
|
|
|
|
$g->garccw('z',$z,'x',$$point[0],'y',$$point[1],'r',$$point[2]);
|
522
|
|
|
|
|
|
|
}
|
523
|
|
|
|
|
|
|
else # for move. First point is always a move, since we're there already in fact.
|
524
|
|
|
|
|
|
|
{
|
525
|
|
|
|
|
|
|
$g->gmove('z',$z,'x',$$point[0],'y',$$point[1]);
|
526
|
|
|
|
|
|
|
}
|
527
|
|
|
|
|
|
|
|
528
|
|
|
|
|
|
|
$z=$zdown+$passdepth*$pass;
|
529
|
|
|
|
|
|
|
$i++;
|
530
|
|
|
|
|
|
|
|
531
|
|
|
|
|
|
|
}
|
532
|
|
|
|
|
|
|
}
|
533
|
|
|
|
|
|
|
# finally we repeat point 2 becasue z was being phased in during the this point and we want full depth.
|
534
|
|
|
|
|
|
|
$point=\@point2; $i=1;
|
535
|
|
|
|
|
|
|
$g->gcomment("Pass final ".$p->{comments}->[$i]) if ($p->{comments}->[$i]);
|
536
|
|
|
|
|
|
|
|
537
|
|
|
|
|
|
|
if ($$point[2] and $$point[3] and $i!=0) # radius of curveture, ccw , not cw for arc.
|
538
|
|
|
|
|
|
|
{
|
539
|
|
|
|
|
|
|
$g->garcccw('z',$z,'x',$$point[0],'y',$$point[1],'r',$$point[2]);
|
540
|
|
|
|
|
|
|
}
|
541
|
|
|
|
|
|
|
elsif ($$point[2] and $i!=0 ) # for cw arc
|
542
|
|
|
|
|
|
|
{
|
543
|
|
|
|
|
|
|
$g->garccw('z',$z,'x',$$point[0],'y',$$point[1],'r',$$point[2]);
|
544
|
|
|
|
|
|
|
}
|
545
|
|
|
|
|
|
|
else # for move. First point is always a move, since we're there already in fact.
|
546
|
|
|
|
|
|
|
{
|
547
|
|
|
|
|
|
|
$g->gmove('z',$z,'x',$$point[0],'y',$$point[1]);
|
548
|
|
|
|
|
|
|
}
|
549
|
|
|
|
|
|
|
|
550
|
|
|
|
|
|
|
|
551
|
|
|
|
|
|
|
$g->gmove('z',0.05);
|
552
|
|
|
|
|
|
|
}
|
553
|
|
|
|
|
|
|
#############################################
|
554
|
|
|
|
|
|
|
# end of package profile
|
555
|
|
|
|
|
|
|
#############################################
|
556
|
|
|
|
|
|
|
|
557
|
|
|
|
|
|
|
# This holds the information for a a single wheel: a pinion or spur gear.
|
558
|
|
|
|
|
|
|
package Wheel;
|
559
|
|
|
|
|
|
|
|
560
|
|
|
|
|
|
|
use vars qw($VERSION @ISA @EXPORT);
|
561
|
|
|
|
|
|
|
$VERSION=0.061;
|
562
|
|
|
|
|
|
|
|
563
|
|
|
|
|
|
|
my $mm;
|
564
|
|
|
|
|
|
|
$mm=$mm=1.0/25.4;; # 1mm is this inches;
|
565
|
|
|
|
|
|
|
|
566
|
|
|
|
|
|
|
sub hole
|
567
|
|
|
|
|
|
|
{
|
568
|
|
|
|
|
|
|
my ($w,$s,$x,$y)=@_;
|
569
|
|
|
|
|
|
|
|
570
|
|
|
|
|
|
|
if (!defined $x and !defined $y) # assume center
|
571
|
|
|
|
|
|
|
{
|
572
|
|
|
|
|
|
|
$w->{holesize}=$s;
|
573
|
|
|
|
|
|
|
}
|
574
|
|
|
|
|
|
|
else
|
575
|
|
|
|
|
|
|
{
|
576
|
|
|
|
|
|
|
die "x/y parameters to hole function not yet implemented. ";
|
577
|
|
|
|
|
|
|
my $h=Hole->new($w->{cuttersize},$w->{passes},$w->{passdepth},$s/2);
|
578
|
|
|
|
|
|
|
my @holes;
|
579
|
|
|
|
|
|
|
$w->{holes}=\@holes if (!$w->{holes});
|
580
|
|
|
|
|
|
|
push(@{$w->{holes}},$h);
|
581
|
|
|
|
|
|
|
}
|
582
|
|
|
|
|
|
|
}
|
583
|
|
|
|
|
|
|
# wheel
|
584
|
|
|
|
|
|
|
sub passes
|
585
|
|
|
|
|
|
|
{
|
586
|
|
|
|
|
|
|
my ($w)=@_;
|
587
|
|
|
|
|
|
|
|
588
|
|
|
|
|
|
|
return $w->{passes};
|
589
|
|
|
|
|
|
|
}
|
590
|
|
|
|
|
|
|
# wheel
|
591
|
|
|
|
|
|
|
# set the module and number of teeth.
|
592
|
|
|
|
|
|
|
sub new
|
593
|
|
|
|
|
|
|
{
|
594
|
|
|
|
|
|
|
my ($s,$m,$n)=@_;
|
595
|
|
|
|
|
|
|
$s={};
|
596
|
|
|
|
|
|
|
$s->{n}=$n;
|
597
|
|
|
|
|
|
|
$s->{m}=$m;
|
598
|
|
|
|
|
|
|
|
599
|
|
|
|
|
|
|
return bless $s;
|
600
|
|
|
|
|
|
|
}
|
601
|
|
|
|
|
|
|
# Trepan: - to cut a hole in. If you want holes in your wheels, call this functions. ( Ie you want spokes!)
|
602
|
|
|
|
|
|
|
# Known bugs: (1) As you increase the number of spokes, roe, spoke width or width at base factor or decreasethe boss radius there comes a time when there is
|
603
|
|
|
|
|
|
|
# "not enough room round the boss for the spokes. This is not handles well, instead of doing a little arc which is the circumference of the booss
|
604
|
|
|
|
|
|
|
# what happens is you get most of a circle in the other direction. Catastrophic of course.
|
605
|
|
|
|
|
|
|
sub trepan
|
606
|
|
|
|
|
|
|
{
|
607
|
|
|
|
|
|
|
my ($w, # pointer to self, a wheel.
|
608
|
|
|
|
|
|
|
$spoken, # number of spokes
|
609
|
|
|
|
|
|
|
$wos, # total width of spokes in inches
|
610
|
|
|
|
|
|
|
$bsf, # boss radius as a factor of pitch radius (dimentionless) : Now absolute in inches.
|
611
|
|
|
|
|
|
|
$rsf, # rim size in inches.
|
612
|
|
|
|
|
|
|
$roe, # radius of window edge (in inches, the curved radius of the join between a spoke and the rim or boss
|
613
|
|
|
|
|
|
|
# not that this must be more than the cutter size or you cant cut it! This is radius, not diameter.
|
614
|
|
|
|
|
|
|
$wobf, # width at base factor, > 1 for wider spoke base. Tapered spokes anyone ?
|
615
|
|
|
|
|
|
|
$srf # spoke rotation factor rotates spoke position this proportion of a full rotation
|
616
|
|
|
|
|
|
|
# on outer rim
|
617
|
|
|
|
|
|
|
# values 0 to 0.1 give good results.
|
618
|
|
|
|
|
|
|
)=@_;
|
619
|
|
|
|
|
|
|
|
620
|
|
|
|
|
|
|
# ($spoken,$wos,$bsf,$rsf,$roe,$wobf)=(6,0.5,0.25,0.35,0.075,1.0);
|
621
|
|
|
|
|
|
|
|
622
|
|
|
|
|
|
|
# for now we just store the values in the wheel.
|
623
|
|
|
|
|
|
|
$w->{spoken}=$spoken;
|
624
|
|
|
|
|
|
|
$w->{wos}=$w->dim($wos);
|
625
|
|
|
|
|
|
|
$w->{bsf}=$w->dim($bsf);
|
626
|
|
|
|
|
|
|
$w->{rsf}=$w->dim($rsf);
|
627
|
|
|
|
|
|
|
$w->{roe}=$w->dim($roe);
|
628
|
|
|
|
|
|
|
$w->{wobf}=$wobf;
|
629
|
|
|
|
|
|
|
$w->{srf}=$srf;
|
630
|
|
|
|
|
|
|
}
|
631
|
|
|
|
|
|
|
|
632
|
|
|
|
|
|
|
sub bossindent
|
633
|
|
|
|
|
|
|
{
|
634
|
|
|
|
|
|
|
my ($c,$sized,$passdepth,$passes,$feed)=@_;
|
635
|
|
|
|
|
|
|
# arguments are cog, diameter of indent, depth for each pass and number of passes, optional $feedrate
|
636
|
|
|
|
|
|
|
# note that these are different to the main cutting ones because it doesnt go all the way through material for a start.
|
637
|
|
|
|
|
|
|
|
638
|
|
|
|
|
|
|
$c->{bi_passdepth}=$c->dim($passdepth);
|
639
|
|
|
|
|
|
|
$c->{bi_passes}=$passes;
|
640
|
|
|
|
|
|
|
$c->{bi_feed}=$feed;
|
641
|
|
|
|
|
|
|
$c->{bi_sized}=$c->dim($sized); # diameter
|
642
|
|
|
|
|
|
|
|
643
|
|
|
|
|
|
|
}
|
644
|
|
|
|
|
|
|
|
645
|
|
|
|
|
|
|
# private function #
|
646
|
|
|
|
|
|
|
sub cutbossindent
|
647
|
|
|
|
|
|
|
{
|
648
|
|
|
|
|
|
|
my ($c,$g,$x,$y)=@_;
|
649
|
|
|
|
|
|
|
return if (!$c->{bi_sized});
|
650
|
|
|
|
|
|
|
|
651
|
|
|
|
|
|
|
$c->{bi_feed}||=$g->{feed};
|
652
|
|
|
|
|
|
|
$g->grapid('z',0.1);
|
653
|
|
|
|
|
|
|
$g->grapid('x',$x,'y',$y);
|
654
|
|
|
|
|
|
|
|
655
|
|
|
|
|
|
|
my $sized=$c->{bi_sized}-$c->{cuttersize};
|
656
|
|
|
|
|
|
|
|
657
|
|
|
|
|
|
|
my $pass=0;
|
658
|
|
|
|
|
|
|
my ($step)=$c->{cuttersize}/2;
|
659
|
|
|
|
|
|
|
$step==0 and die "Need a cuttersize set.";
|
660
|
|
|
|
|
|
|
|
661
|
|
|
|
|
|
|
my $z=0;
|
662
|
|
|
|
|
|
|
while ($pass++<$c->{bi_passes})
|
663
|
|
|
|
|
|
|
{
|
664
|
|
|
|
|
|
|
#print "pass=$pass cpasses =".$c->{bi_passes}."\n";
|
665
|
|
|
|
|
|
|
|
666
|
|
|
|
|
|
|
$z+=$c->{bi_passdepth};
|
667
|
|
|
|
|
|
|
$g->gcomment("Cutting indent pass $pass of ".$c->{bi_passes});
|
668
|
|
|
|
|
|
|
$g->gmove('x',$x,'y',$y,'z',$z,'f',$c->{bi_feed});
|
669
|
|
|
|
|
|
|
my $r=0;
|
670
|
|
|
|
|
|
|
while ($r+$step<0.5*$sized)
|
671
|
|
|
|
|
|
|
{
|
672
|
|
|
|
|
|
|
$r+=$step;
|
673
|
|
|
|
|
|
|
$g->gcomment("r is $r");
|
674
|
|
|
|
|
|
|
$g->gmove('x',$x+$r,'y',$y);
|
675
|
|
|
|
|
|
|
$g->garccw('x',$x-$r,'y',$y,'r',$r);
|
676
|
|
|
|
|
|
|
$g->garccw('x',$x+$r,'y',$y,'r',$r);
|
677
|
|
|
|
|
|
|
}
|
678
|
|
|
|
|
|
|
|
679
|
|
|
|
|
|
|
$step=0.5*$sized-$r;
|
680
|
|
|
|
|
|
|
if ($step>0)
|
681
|
|
|
|
|
|
|
{
|
682
|
|
|
|
|
|
|
$r+=$step;
|
683
|
|
|
|
|
|
|
$g->gcomment("final r is $r");
|
684
|
|
|
|
|
|
|
$g->gmove('x',$x+$r,'y',$y);
|
685
|
|
|
|
|
|
|
$g->garccw('x',$x-$r,'y',$y,'r',$r);
|
686
|
|
|
|
|
|
|
$g->garccw('x',$x+$r,'y',$y,'r',$r);
|
687
|
|
|
|
|
|
|
}
|
688
|
|
|
|
|
|
|
}
|
689
|
|
|
|
|
|
|
|
690
|
|
|
|
|
|
|
$g->grapid('z',0.1);
|
691
|
|
|
|
|
|
|
}
|
692
|
|
|
|
|
|
|
|
693
|
|
|
|
|
|
|
# actually cut the requested trepanning scheme
|
694
|
|
|
|
|
|
|
# note that the nasty smooth algorithmn only works if the circle is centered on origin 0,0.
|
695
|
|
|
|
|
|
|
# for the moment, easy way to correct this is to do all calculations assuming origin based wheel
|
696
|
|
|
|
|
|
|
# then offset just before plotting with xi yi, the initial position, which is the real wheel center.
|
697
|
|
|
|
|
|
|
# private function #
|
698
|
|
|
|
|
|
|
sub cuttrepan
|
699
|
|
|
|
|
|
|
{
|
700
|
|
|
|
|
|
|
my ($cp,
|
701
|
|
|
|
|
|
|
$gp, $xi,$yi,$zi) =@_;
|
702
|
|
|
|
|
|
|
|
703
|
|
|
|
|
|
|
my ($spoken, # number of spokes
|
704
|
|
|
|
|
|
|
$wos, # total width of spokes
|
705
|
|
|
|
|
|
|
# $bsf, # boss radius as a factor of pitch radius
|
706
|
|
|
|
|
|
|
$bossradius, # now absolute in inches
|
707
|
|
|
|
|
|
|
$rsf, # rim size factor as proportion of pitch radius. # Now absolute in inches, size of rim
|
708
|
|
|
|
|
|
|
$roe, # radius of window edge
|
709
|
|
|
|
|
|
|
$wobf, # width at base factor, > 1 for wider spoke base
|
710
|
|
|
|
|
|
|
$srf
|
711
|
|
|
|
|
|
|
)= map { $cp->{$_} } qw(spoken wos bsf rsf roe wobf srf);
|
712
|
|
|
|
|
|
|
|
713
|
|
|
|
|
|
|
$cp->{mm} or $cp->{mm}=1.0/25.4;
|
714
|
|
|
|
|
|
|
|
715
|
|
|
|
|
|
|
map{ eval '\$$_=$cp->{$_} ' } qw(spoken wos bsf rsf roe wobf);
|
716
|
|
|
|
|
|
|
$wobf ||= 1.0; # default to non-tapered spokes.
|
717
|
|
|
|
|
|
|
|
718
|
|
|
|
|
|
|
return if (!$spoken); # no spokes, no trepanning.
|
719
|
|
|
|
|
|
|
|
720
|
|
|
|
|
|
|
my $mm=$cp->{mm};
|
721
|
|
|
|
|
|
|
my $pi=4.0 * atan2(1, 1);
|
722
|
|
|
|
|
|
|
|
723
|
|
|
|
|
|
|
my $rr=$mm*(1-$rsf)*$cp->{dw}/2; # rim radius;
|
724
|
|
|
|
|
|
|
|
725
|
|
|
|
|
|
|
|
726
|
|
|
|
|
|
|
$wos=0.5*$wos/$spoken;
|
727
|
|
|
|
|
|
|
# $wosb=$wobf*$wos; # width at boss
|
728
|
|
|
|
|
|
|
|
729
|
|
|
|
|
|
|
my $wosb=$wos; # width of spoke base, near center of wheel.
|
730
|
|
|
|
|
|
|
$wos=$wos/$wobf; # width of spoke at the rim, less than base width if wid of base factor greater than 1.
|
731
|
|
|
|
|
|
|
|
732
|
|
|
|
|
|
|
$gp->grapid('z',0.1);
|
733
|
|
|
|
|
|
|
$gp->grapid('x',$xi,'y',$yi);
|
734
|
|
|
|
|
|
|
$srf=$srf*2*$pi;
|
735
|
|
|
|
|
|
|
my (@xy,@l2);
|
736
|
|
|
|
|
|
|
my ($tx,$ty); # temory x,y variables;
|
737
|
|
|
|
|
|
|
my ($x,$y);
|
738
|
|
|
|
|
|
|
my ($wsx,$wsy);
|
739
|
|
|
|
|
|
|
|
740
|
|
|
|
|
|
|
for my $w ( 0..$spoken-1) # for each window, we calculate all the points, and put them on a stack.
|
741
|
|
|
|
|
|
|
{ # before we plot, we process to radius the sharp edges.
|
742
|
|
|
|
|
|
|
my $t1=2*$pi*$w/$spoken;
|
743
|
|
|
|
|
|
|
my $t2=$t1+2*$pi/$spoken; # end of this window
|
744
|
|
|
|
|
|
|
my $d;
|
745
|
|
|
|
|
|
|
my $first=1; # This flag to control entry moves on 1st pass.
|
746
|
|
|
|
|
|
|
my $z=$zi;
|
747
|
|
|
|
|
|
|
$d=$wosb/$bossradius;
|
748
|
|
|
|
|
|
|
|
749
|
|
|
|
|
|
|
my $passno=0;
|
750
|
|
|
|
|
|
|
while ($passno++ < $cp->{passes})
|
751
|
|
|
|
|
|
|
{
|
752
|
|
|
|
|
|
|
|
753
|
|
|
|
|
|
|
$x=$bossradius*cos($t1+$pi/$spoken); # positioning for 2nd half of circle segment at bossradius.
|
754
|
|
|
|
|
|
|
$y=$bossradius*sin($t1+$pi/$spoken);
|
755
|
|
|
|
|
|
|
push(@xy,$x,$y);
|
756
|
|
|
|
|
|
|
|
757
|
|
|
|
|
|
|
$x+=$bossradius*(cos($t2-$d)-cos($t1+$pi/$spoken)); # rotation at boss radius
|
758
|
|
|
|
|
|
|
$y+=$bossradius*(sin($t2-$d)-sin($t1+$pi/$spoken));
|
759
|
|
|
|
|
|
|
my $t=$t2-$d;
|
760
|
|
|
|
|
|
|
push(@xy,$x,$y);
|
761
|
|
|
|
|
|
|
|
762
|
|
|
|
|
|
|
$d=$wos/$rr;
|
763
|
|
|
|
|
|
|
$x+=$rr*cos($t2-$d+$srf)-$bossradius*cos($t); # radial move to rim
|
764
|
|
|
|
|
|
|
$y+=$rr*sin($t2-$d+$srf)-$bossradius*sin($t);
|
765
|
|
|
|
|
|
|
push(@xy,$x,$y);
|
766
|
|
|
|
|
|
|
|
767
|
|
|
|
|
|
|
$x+=$rr*(cos($t1+$d+$srf)-cos($t2-$d+$srf)); # rotatin around rim
|
768
|
|
|
|
|
|
|
$y+=$rr*(sin($t1+$d+$srf)-sin($t2-$d+$srf));
|
769
|
|
|
|
|
|
|
$t=$t1+$d+$srf;
|
770
|
|
|
|
|
|
|
push(@xy,$x,$y);
|
771
|
|
|
|
|
|
|
|
772
|
|
|
|
|
|
|
$d=$wosb/$bossradius;
|
773
|
|
|
|
|
|
|
$x+=$bossradius*cos($t1+$d)-$rr*cos($t); # radial move back towards center
|
774
|
|
|
|
|
|
|
$y+=$bossradius*sin($t1+$d)-$rr*sin($t);
|
775
|
|
|
|
|
|
|
push(@xy,$x,$y);
|
776
|
|
|
|
|
|
|
|
777
|
|
|
|
|
|
|
$x=$bossradius*cos($t1+$pi/$spoken); # remaining half of rotation around boss.
|
778
|
|
|
|
|
|
|
$y=$bossradius*sin($t1+$pi/$spoken);
|
779
|
|
|
|
|
|
|
push(@xy,$x,$y);
|
780
|
|
|
|
|
|
|
|
781
|
|
|
|
|
|
|
if ($first)
|
782
|
|
|
|
|
|
|
{
|
783
|
|
|
|
|
|
|
$gp->gcompr('d',$gp->{toolnumber},$gp->gmove('x',$xi+shift(@xy),'y',$yi+shift(@xy)));
|
784
|
|
|
|
|
|
|
}
|
785
|
|
|
|
|
|
|
else
|
786
|
|
|
|
|
|
|
{
|
787
|
|
|
|
|
|
|
# $gp->gmove('x',$xi+shift(@xy),'y',$yi+shift(@xy),'z',$z)
|
788
|
|
|
|
|
|
|
shift(@xy); shift(@xy);
|
789
|
|
|
|
|
|
|
}
|
790
|
|
|
|
|
|
|
$gp->gcomment(sprintf "Trepanning - window %d pass %d of %d", $w+1,$passno,$cp->{passes});
|
791
|
|
|
|
|
|
|
$z+=$cp->{passdepth} ; # passdepth -ve
|
792
|
|
|
|
|
|
|
|
793
|
|
|
|
|
|
|
@l2=$cp->rsmooth(shift(@xy),shift(@xy),shift(@xy),shift(@xy),$bossradius,-$roe);
|
794
|
|
|
|
|
|
|
@xy=(@l2,@xy);
|
795
|
|
|
|
|
|
|
$gp->garcccw('x',$xi+($tx=shift(@xy)),'y',$yi+($ty=shift(@xy)),'r',$bossradius,'z',$z); # rotation at boss radius, add in z incremen
|
796
|
|
|
|
|
|
|
|
797
|
|
|
|
|
|
|
|
798
|
|
|
|
|
|
|
@l2=$cp->smooth(shift(@xy),shift(@xy),shift(@xy),shift(@xy),$rr,$roe);
|
799
|
|
|
|
|
|
|
@xy=(@l2,@xy);
|
800
|
|
|
|
|
|
|
$gp->garccw('x',$xi+shift(@xy),'y',$yi+shift(@xy),'r',$roe);
|
801
|
|
|
|
|
|
|
|
802
|
|
|
|
|
|
|
$gp->gmove('x',$xi+shift(@xy),'y',$yi+shift(@xy)); # line outwards
|
803
|
|
|
|
|
|
|
$gp->garccw('x',$xi+shift(@xy),'y',$yi+shift(@xy),'r',$roe);
|
804
|
|
|
|
|
|
|
|
805
|
|
|
|
|
|
|
|
806
|
|
|
|
|
|
|
@l2=$cp->rsmooth(shift(@xy),shift(@xy),shift(@xy),shift(@xy),$rr,-$roe);
|
807
|
|
|
|
|
|
|
@xy=(@l2,@xy);
|
808
|
|
|
|
|
|
|
$gp->garccw('x',$xi+shift(@xy),'y',$yi+shift(@xy),'r',$rr); # outer radius
|
809
|
|
|
|
|
|
|
|
810
|
|
|
|
|
|
|
@l2=$cp->smooth(shift(@xy),shift(@xy),shift(@xy),shift(@xy),$bossradius,$roe);
|
811
|
|
|
|
|
|
|
@xy=(@l2,@xy);
|
812
|
|
|
|
|
|
|
|
813
|
|
|
|
|
|
|
$gp->garccw('x',$xi+shift(@xy),'y',$yi+shift(@xy),'r',$roe);
|
814
|
|
|
|
|
|
|
#
|
815
|
|
|
|
|
|
|
$gp->gmove('x',$xi+shift(@xy),'y',$yi+shift(@xy)); # line inwards
|
816
|
|
|
|
|
|
|
$gp->garccw('x',$xi+shift(@xy),'y',$yi+shift(@xy),'r',$roe);
|
817
|
|
|
|
|
|
|
|
818
|
|
|
|
|
|
|
### Actually we dont want to do this! The next point is always on the same arc, so this sometimes causes
|
819
|
|
|
|
|
|
|
### problems if we've already gone past this point, get an arc in wrong direction. This mitigates known bug 1.
|
820
|
|
|
|
|
|
|
### $gp->garcccw('x',$xi+shift(@xy),'y',$yi+shift(@xy),'r',$bossradius);
|
821
|
|
|
|
|
|
|
shift(@xy), shift(@xy); ###
|
822
|
|
|
|
|
|
|
|
823
|
|
|
|
|
|
|
# $gp->gmove('z',0.1);
|
824
|
|
|
|
|
|
|
$first=0;
|
825
|
|
|
|
|
|
|
} # all passes complete.
|
826
|
|
|
|
|
|
|
# repeat 1st move as z was being ramped up during this move.
|
827
|
|
|
|
|
|
|
$gp->garcccw('x',$xi+$tx,'y',$yi+$ty,'r',$bossradius,'z',$z); # rotation at boss radius, add in z incremen
|
828
|
|
|
|
|
|
|
$gp->grapid('z',0.1);
|
829
|
|
|
|
|
|
|
($x,$y)=($tx,$ty);
|
830
|
|
|
|
|
|
|
# $x+=3*$cp->{cuttersize}*$tx/sqrt($tx**2+$ty**2);
|
831
|
|
|
|
|
|
|
# $y+=3*$cp->{cuttersize}*$ty/sqrt($tx**2+$ty**2);
|
832
|
|
|
|
|
|
|
|
833
|
|
|
|
|
|
|
|
834
|
|
|
|
|
|
|
# $gp->gcomment("This was designed to be where we take comp off but cant get it to work. so delay this till next move");
|
835
|
|
|
|
|
|
|
# $gp->garccw('x',$xi+$x,'y',$yi+$y,'r',1.5*$cp->{cuttersize}); # to avoid problems with imaginary gauginging
|
836
|
|
|
|
|
|
|
# we move avay in arc at this point of twice radius of cutter.
|
837
|
|
|
|
|
|
|
$x=0.75*$bossradius*cos($t2);
|
838
|
|
|
|
|
|
|
$y=0.75*$bossradius*sin($t2);
|
839
|
|
|
|
|
|
|
$gp->gcomp0($gp->gmove('x',$xi+$x,'y',$yi+$y)); #
|
840
|
|
|
|
|
|
|
}
|
841
|
|
|
|
|
|
|
}
|
842
|
|
|
|
|
|
|
# private #
|
843
|
|
|
|
|
|
|
sub cuthole
|
844
|
|
|
|
|
|
|
{ # diameter V
|
845
|
|
|
|
|
|
|
|
846
|
|
|
|
|
|
|
|
847
|
|
|
|
|
|
|
my ($cp,$gp,$x,$y,$z,$size,$feed,$cuttersize)=@_;
|
848
|
|
|
|
|
|
|
|
849
|
|
|
|
|
|
|
return if (!defined($size) or $size<=0);
|
850
|
|
|
|
|
|
|
|
851
|
|
|
|
|
|
|
my $holesize=$cp->{holesize};
|
852
|
|
|
|
|
|
|
$cuttersize ||= $cp->{cuttersize}; # can be optional, use wheel cutter if not supplied
|
853
|
|
|
|
|
|
|
$gp->gcomment("Positioning for Hole");
|
854
|
|
|
|
|
|
|
$gp->grapid('z',0.05);
|
855
|
|
|
|
|
|
|
$gp->grapid('x',$x,'y',$y);
|
856
|
|
|
|
|
|
|
$gp->grapid('z',$z);
|
857
|
|
|
|
|
|
|
$gp->gmove('x',$x,'y',$y,'z',$z,'f',$feed);
|
858
|
|
|
|
|
|
|
|
859
|
|
|
|
|
|
|
my ($passes,$passdepth)=($cp->{passes},$cp->{passdepth});
|
860
|
|
|
|
|
|
|
|
861
|
|
|
|
|
|
|
if ($cp->{holedepth})
|
862
|
|
|
|
|
|
|
{
|
863
|
|
|
|
|
|
|
$passes=abs($cp->{holedepth}/$passdepth+1);
|
864
|
|
|
|
|
|
|
$passdepth=$cp->{holedepth}/$passes;
|
865
|
|
|
|
|
|
|
}
|
866
|
|
|
|
|
|
|
if ($holesize>$cuttersize)
|
867
|
|
|
|
|
|
|
{
|
868
|
|
|
|
|
|
|
$gp->gcomment("Hole bigger than cutter");
|
869
|
|
|
|
|
|
|
$holesize-=$cuttersize; # because we want to compensate for the size of the tool.
|
870
|
|
|
|
|
|
|
$gp->gmove('x',$x+$holesize/2,'y',$y);
|
871
|
|
|
|
|
|
|
|
872
|
|
|
|
|
|
|
my $passn=0;
|
873
|
|
|
|
|
|
|
while ($passn++ < $passes)
|
874
|
|
|
|
|
|
|
{
|
875
|
|
|
|
|
|
|
$gp->gcomment(sprintf("pass %d",$passn));
|
876
|
|
|
|
|
|
|
$z+=$cp->{passdepth}; # passdepth negative
|
877
|
|
|
|
|
|
|
$gp->garcccw('x',$x-$holesize/2,'y',$y,'r',$holesize/2,'z',$z,'f',$feed);
|
878
|
|
|
|
|
|
|
$gp->garcccw ('x',$x+$holesize/2,'y',$y,'r',$holesize/2);
|
879
|
|
|
|
|
|
|
}
|
880
|
|
|
|
|
|
|
$gp->garcccw('x',$x-$holesize/2,'y',$y,'r',$holesize/2,'z',$z); # we always redo this as z depth was being faded in during this arc.
|
881
|
|
|
|
|
|
|
$gp->gmove('x',$x,'y',$y); # move into center to avoid withdrawal while still in contact with work.
|
882
|
|
|
|
|
|
|
}
|
883
|
|
|
|
|
|
|
else
|
884
|
|
|
|
|
|
|
{ # else if holesize eq or less than cutter size, just do a plunge.
|
885
|
|
|
|
|
|
|
$z=$passdepth*$passes;
|
886
|
|
|
|
|
|
|
$gp->gmove('z',$z,'f',$feed);
|
887
|
|
|
|
|
|
|
$gp->gdwell('p',0.75);
|
888
|
|
|
|
|
|
|
}
|
889
|
|
|
|
|
|
|
|
890
|
|
|
|
|
|
|
# $gp->gmove('z', 0.05,$xs,$ys);
|
891
|
|
|
|
|
|
|
$gp->gmove('z', 0.05); # return to surface
|
892
|
|
|
|
|
|
|
$gp->gcomment("Hole done");
|
893
|
|
|
|
|
|
|
}
|
894
|
|
|
|
|
|
|
|
895
|
|
|
|
|
|
|
# debug
|
896
|
|
|
|
|
|
|
sub makepoint
|
897
|
|
|
|
|
|
|
{
|
898
|
|
|
|
|
|
|
my ($gp,$x,$y,$d)=@_; # make a small arrow point.
|
899
|
|
|
|
|
|
|
$gp->gmove('x',$x+$d,'y',$y+$d,);
|
900
|
|
|
|
|
|
|
$gp->gmove('x',$x,'y',$y);
|
901
|
|
|
|
|
|
|
$gp->gmove('x',$x+$d,'y',$y-$d,);
|
902
|
|
|
|
|
|
|
$gp->gmove('x',$x,'y',$y);
|
903
|
|
|
|
|
|
|
}
|
904
|
|
|
|
|
|
|
|
905
|
|
|
|
|
|
|
# wheel - private
|
906
|
|
|
|
|
|
|
# Given any combination of $depth,$passes,$passdepth
|
907
|
|
|
|
|
|
|
# return a valid passes and passdepth.
|
908
|
|
|
|
|
|
|
# eg ($s->{holepassdepth},$s->{holepasses})=passdepth($s->{holepassdepth},$s->{holepasses},$s->{holedepth});
|
909
|
|
|
|
|
|
|
sub passdepth
|
910
|
|
|
|
|
|
|
{
|
911
|
|
|
|
|
|
|
my ($w,$passdepth,$passes,$depth)=@_;
|
912
|
|
|
|
|
|
|
if (!defined($depth)) # and !defined($passes and !defined($passdepth)
|
913
|
|
|
|
|
|
|
{
|
914
|
|
|
|
|
|
|
}
|
915
|
|
|
|
|
|
|
elsif (defined($depth) and !defined($passes)) # passdepth must be def
|
916
|
|
|
|
|
|
|
{
|
917
|
|
|
|
|
|
|
$passes=abs($depth/$passdepth);
|
918
|
|
|
|
|
|
|
$passes=int($passes)+1 if ($passes!=int($passes));
|
919
|
|
|
|
|
|
|
$passdepth=-abs($depth)/$passes;
|
920
|
|
|
|
|
|
|
}
|
921
|
|
|
|
|
|
|
elsif (defined($depth) and defined($passes)) # ignore passdepth even if provided. and !defined($passdepth)
|
922
|
|
|
|
|
|
|
{
|
923
|
|
|
|
|
|
|
$passdepth=-abs($depth)/$passes;
|
924
|
|
|
|
|
|
|
}
|
925
|
|
|
|
|
|
|
return ($passdepth,$passes);
|
926
|
|
|
|
|
|
|
}
|
927
|
|
|
|
|
|
|
|
928
|
|
|
|
|
|
|
sub cutset
|
929
|
|
|
|
|
|
|
{
|
930
|
|
|
|
|
|
|
my ($w,$cuttersize,$passes,$passdepth)=@_;
|
931
|
|
|
|
|
|
|
my ($depth,$holedepth);
|
932
|
|
|
|
|
|
|
my ($h)=$cuttersize;
|
933
|
|
|
|
|
|
|
|
934
|
|
|
|
|
|
|
if (ref($h) eq 'HASH')
|
935
|
|
|
|
|
|
|
{
|
936
|
|
|
|
|
|
|
|
937
|
|
|
|
|
|
|
($cuttersize,$passes,$passdepth,$depth,$holedepth)=map { $h->{$_} } split(',',"cuttersize,passes,passdepth,depth,holedepth");
|
938
|
|
|
|
|
|
|
$holedepth||=$depth;
|
939
|
|
|
|
|
|
|
($passdepth,$passes)=$w->passdepth($passdepth,$passes,$holedepth);
|
940
|
|
|
|
|
|
|
|
941
|
|
|
|
|
|
|
}
|
942
|
|
|
|
|
|
|
$w->{cuttersize}=$cuttersize;
|
943
|
|
|
|
|
|
|
$w->{passdepth}=$passdepth;
|
944
|
|
|
|
|
|
|
$w->{passes}=$passes;
|
945
|
|
|
|
|
|
|
return $w;
|
946
|
|
|
|
|
|
|
}
|
947
|
|
|
|
|
|
|
|
948
|
|
|
|
|
|
|
# previously cutwheel
|
949
|
|
|
|
|
|
|
# public
|
950
|
|
|
|
|
|
|
sub cut
|
951
|
|
|
|
|
|
|
{
|
952
|
|
|
|
|
|
|
# my ($x,$y,$z,
|
953
|
|
|
|
|
|
|
# $m,$np,$nw,
|
954
|
|
|
|
|
|
|
# $gr,$cp,$dd,$dw,
|
955
|
|
|
|
|
|
|
# $dp,$pf,$ad,$ar,$feed)=@_;
|
956
|
|
|
|
|
|
|
|
957
|
|
|
|
|
|
|
# 1 cut dededum.
|
958
|
|
|
|
|
|
|
|
959
|
|
|
|
|
|
|
my ($cp , # wheel
|
960
|
|
|
|
|
|
|
$gp, # graphics package, either generate graphics or gcode
|
961
|
|
|
|
|
|
|
$x,$y,$z, # where to put the wheel
|
962
|
|
|
|
|
|
|
)=@_;
|
963
|
|
|
|
|
|
|
|
964
|
|
|
|
|
|
|
$cp->{mm} or die;
|
965
|
|
|
|
|
|
|
$pi or die;
|
966
|
|
|
|
|
|
|
|
967
|
|
|
|
|
|
|
return $cp->cycut($gp,$x,$y,$z) if ($cp->{cycloidal});
|
968
|
|
|
|
|
|
|
|
969
|
|
|
|
|
|
|
my $t=0; # theta, angle of wheel;
|
970
|
|
|
|
|
|
|
my $ti=0.5*360/$cp->{n}; # half tooth increment.
|
971
|
|
|
|
|
|
|
$ti*= $pi/180; # in radians now.
|
972
|
|
|
|
|
|
|
|
973
|
|
|
|
|
|
|
|
974
|
|
|
|
|
|
|
|
975
|
|
|
|
|
|
|
# In some situations particularly pinions tooth and gap angles are not the same.
|
976
|
|
|
|
|
|
|
# define twf as factor extra for tooth, less than 1 for a wider gap
|
977
|
|
|
|
|
|
|
my $tig=$ti*(2-$cp->{twf}); # width of a gap in radians
|
978
|
|
|
|
|
|
|
$ti=$ti*$cp->{twf}; # this is now the width of a tooth. $tig+$ti is unchanged bu changes to $twf
|
979
|
|
|
|
|
|
|
|
980
|
|
|
|
|
|
|
|
981
|
|
|
|
|
|
|
my ($xs,$ys,$zs)=($x,$y,$z);
|
982
|
|
|
|
|
|
|
|
983
|
|
|
|
|
|
|
|
984
|
|
|
|
|
|
|
$gp->gmove('z',0.1,'f',$gp->{feed});
|
985
|
|
|
|
|
|
|
|
986
|
|
|
|
|
|
|
$cp->cutbossindent($gp,$x,$y);
|
987
|
|
|
|
|
|
|
$cp->cuthole($gp,$x,$y,$z,$cp->{holesize},$gp->{feed});
|
988
|
|
|
|
|
|
|
|
989
|
|
|
|
|
|
|
$cp->{ring}->cut($gp,$x,$y,$z) if ($cp->{ring});
|
990
|
|
|
|
|
|
|
|
991
|
|
|
|
|
|
|
$cp->cuttrepan($gp,$xs,$ys,$zs);
|
992
|
|
|
|
|
|
|
|
993
|
|
|
|
|
|
|
my $qtc=0.5*$cp->{mm}*$cp->{dw}*$pi/$cp->{n}; # quarter tooth circumference.
|
994
|
|
|
|
|
|
|
$x+=$cp->{mm}*$cp->{dw}*0.5;
|
995
|
|
|
|
|
|
|
$y+= -$qtc;
|
996
|
|
|
|
|
|
|
$gp->gcomment("Move Away From Work");
|
997
|
|
|
|
|
|
|
|
998
|
|
|
|
|
|
|
$gp->gmove('x',$x,'y',$y);
|
999
|
|
|
|
|
|
|
|
1000
|
|
|
|
|
|
|
# $x-= $qtc;
|
1001
|
|
|
|
|
|
|
$y+= $qtc;
|
1002
|
|
|
|
|
|
|
# $gp->gcompr('d',$gp->{toolnumber},$gp->garccw('x',$x,'y',$y,'r',$qtc));
|
1003
|
|
|
|
|
|
|
$gp->gcompr('d',$gp->{toolnumber},$gp->gmove('x',$x,'y',$y));
|
1004
|
|
|
|
|
|
|
|
1005
|
|
|
|
|
|
|
$gp->gcomment("Start Cutting");
|
1006
|
|
|
|
|
|
|
$gp->gmove('z',$z+$cp->{passdepth});
|
1007
|
|
|
|
|
|
|
|
1008
|
|
|
|
|
|
|
|
1009
|
|
|
|
|
|
|
my $passes=0;
|
1010
|
|
|
|
|
|
|
|
1011
|
|
|
|
|
|
|
|
1012
|
|
|
|
|
|
|
while ($passes++ < $cp->{passes})
|
1013
|
|
|
|
|
|
|
{
|
1014
|
|
|
|
|
|
|
my $tcount=0;
|
1015
|
|
|
|
|
|
|
my $t=0;
|
1016
|
|
|
|
|
|
|
$z+= $cp->{passdepth};
|
1017
|
|
|
|
|
|
|
while ($t/2.0/$pi<0.999 )
|
1018
|
|
|
|
|
|
|
{
|
1019
|
|
|
|
|
|
|
|
1020
|
|
|
|
|
|
|
$gp->gcomment(sprintf("Tooth number %d pass %d",++$tcount,$passes));
|
1021
|
|
|
|
|
|
|
|
1022
|
|
|
|
|
|
|
$x-=$cp->{mm}*$cp->{dd}*cos($t);
|
1023
|
|
|
|
|
|
|
$y-=$cp->{mm}*$cp->{dd}*sin($t);
|
1024
|
|
|
|
|
|
|
# printf "G1 X$f Y$f Z$f F$ff\n", $x,$y,$z, $gp->{feed}; # radial stroke towards center of wheel
|
1025
|
|
|
|
|
|
|
|
1026
|
|
|
|
|
|
|
$gp->gmove('x',$x,'y',$y,'z',$z,'f',$gp->{feed});
|
1027
|
|
|
|
|
|
|
|
1028
|
|
|
|
|
|
|
|
1029
|
|
|
|
|
|
|
# 1st attempt, flat tooth bottom:
|
1030
|
|
|
|
|
|
|
# $x+=$cp->{mm}*($cp->{dw}*0.5-$cp->{dd})*(cos($t+$tig)-cos($t));
|
1031
|
|
|
|
|
|
|
# $y+=$cp->{mm}*($cp->{dw}*0.5-$cp->{dd})*(sin($t+$tig)-sin($t));
|
1032
|
|
|
|
|
|
|
# printf "G3 X$f Y$f R$f F$ff\n",$x,$y,$mm*($dw*0.5-$dd),$gp->{feed}; # bottom of tooth, flat bottom
|
1033
|
|
|
|
|
|
|
# $gp->gmove('x',$x,'y',$y);
|
1034
|
|
|
|
|
|
|
|
1035
|
|
|
|
|
|
|
# 2nd attemt, circular bottom
|
1036
|
|
|
|
|
|
|
# $x+=$cp->{mm}*($cp->{dw}*0.5-$cp->{dd})*(cos($t+$tig)-cos($t));
|
1037
|
|
|
|
|
|
|
# $y+=$cp->{mm}*($cp->{dw}*0.5-$cp->{dd})*(sin($t+$tig)-sin($t));
|
1038
|
|
|
|
|
|
|
# $gp->garccw('x',$x,'y',$y,'r',$cp->{mm}*($cp->{dw}-2*$cp->{dd})*$tig/4,'f',$gp->{feed});
|
1039
|
|
|
|
|
|
|
|
1040
|
|
|
|
|
|
|
# last attempt 2 quarter circ arcs
|
1041
|
|
|
|
|
|
|
my $dx=$cp->{mm}*($cp->{dw}*0.5-$cp->{dd})*(cos($t+$tig)-cos($t));
|
1042
|
|
|
|
|
|
|
my $dy=$cp->{mm}*($cp->{dw}*0.5-$cp->{dd})*(sin($t+$tig)-sin($t));
|
1043
|
|
|
|
|
|
|
$dx/=2.0;
|
1044
|
|
|
|
|
|
|
$dy/=2.0;
|
1045
|
|
|
|
|
|
|
|
1046
|
|
|
|
|
|
|
my $dr=sqrt($dx*$dx+$dy*$dy);
|
1047
|
|
|
|
|
|
|
my $cr=$cp->{cuttersize}/2; # cutter radius
|
1048
|
|
|
|
|
|
|
|
1049
|
|
|
|
|
|
|
my $crx1=($cr/$dr)*$dx; # a vector in the direction of the end of the tooth bottom, the size of the cutterradius.
|
1050
|
|
|
|
|
|
|
my $cry1=($cr/$dr)*$dy;
|
1051
|
|
|
|
|
|
|
|
1052
|
|
|
|
|
|
|
my $crx2= -($cr/$dr)*$dy; # a vector normal to the other one, and roughly speaking inwards.
|
1053
|
|
|
|
|
|
|
my $cry2=($cr/$dr)*$dx;
|
1054
|
|
|
|
|
|
|
|
1055
|
|
|
|
|
|
|
$x+=$crx1+$crx2;
|
1056
|
|
|
|
|
|
|
$y+=$cry1+$cry2;
|
1057
|
|
|
|
|
|
|
|
1058
|
|
|
|
|
|
|
$gp->garccw('x',$x,'y',$y,'r',$cr);
|
1059
|
|
|
|
|
|
|
|
1060
|
|
|
|
|
|
|
$x+=((2*$dr-2*$cr)/$dr)*$dx;
|
1061
|
|
|
|
|
|
|
$y+=((2*$dr-2*$cr)/$dr)*$dy;
|
1062
|
|
|
|
|
|
|
$gp->gmove('x',$x,'y',$y); # This bit is the flat part of the tooth bottom, after we've subtracted the radius of the cutter from each corner
|
1063
|
|
|
|
|
|
|
# we have to program these moves as arcs to make the cutter move in this way because cutter compensation
|
1064
|
|
|
|
|
|
|
# is on.
|
1065
|
|
|
|
|
|
|
$x+=$crx1-$crx2; # reverse out the deth of the cutter extra that we went
|
1066
|
|
|
|
|
|
|
$y+=$cry1-$cry2;
|
1067
|
|
|
|
|
|
|
|
1068
|
|
|
|
|
|
|
$gp->garccw('x',$x,'y',$y,'r',$cr);
|
1069
|
|
|
|
|
|
|
|
1070
|
|
|
|
|
|
|
|
1071
|
|
|
|
|
|
|
# $x+=$dx+$dy
|
1072
|
|
|
|
|
|
|
# $y+=$;
|
1073
|
|
|
|
|
|
|
#
|
1074
|
|
|
|
|
|
|
# $x*= ($cp->{dw}*0.5-$cp->{dd}-$r)/($cp->{dw}*0.5-$cp->{dd});
|
1075
|
|
|
|
|
|
|
# $y*= ($cp->{dw}*0.5-$cp->{dd}-$r)/($cp->{dw}*0.5-$cp->{dd});
|
1076
|
|
|
|
|
|
|
|
1077
|
|
|
|
|
|
|
# $gp->garccw('x',$x,'y',$y,'r',$r,'f',$gp->{feed});
|
1078
|
|
|
|
|
|
|
|
1079
|
|
|
|
|
|
|
|
1080
|
|
|
|
|
|
|
$t+=$tig;
|
1081
|
|
|
|
|
|
|
$x+=$cp->{mm}*$cp->{dd}*cos($t); # radial stroke outwards
|
1082
|
|
|
|
|
|
|
$y+=$cp->{mm}*$cp->{dd}*sin($t);
|
1083
|
|
|
|
|
|
|
$gp->gmove('x',$x,'y',$y);
|
1084
|
|
|
|
|
|
|
|
1085
|
|
|
|
|
|
|
# addendum
|
1086
|
|
|
|
|
|
|
# add in addendum height.
|
1087
|
|
|
|
|
|
|
|
1088
|
|
|
|
|
|
|
$x+=$cp->{mm}*$cp->{ad}*cos($t);
|
1089
|
|
|
|
|
|
|
$y+=$cp->{mm}*$cp->{ad}*sin($t);
|
1090
|
|
|
|
|
|
|
# rotate to middle of tooth, 0.25 of full tooth+gap width.
|
1091
|
|
|
|
|
|
|
$x+=$cp->{mm}*($cp->{dw}*0.5+$cp->{ad})*(cos($t+0.5*$ti)-cos($t));
|
1092
|
|
|
|
|
|
|
$y+=$cp->{mm}*($cp->{dw}*0.5+$cp->{ad})*(sin($t+0.5*$ti)-sin($t));
|
1093
|
|
|
|
|
|
|
$gp->garcccw('x',$x,'y',$y,'r',$cp->{mm}*$cp->{ar},'f',$gp->{feed});
|
1094
|
|
|
|
|
|
|
|
1095
|
|
|
|
|
|
|
# back out the addendum height.
|
1096
|
|
|
|
|
|
|
$x-=$cp->{mm}*$cp->{ad}*cos($t+0.5*$ti);
|
1097
|
|
|
|
|
|
|
$y-=$cp->{mm}*$cp->{ad}*sin($t+0.5*$ti);
|
1098
|
|
|
|
|
|
|
# rotate a further half .25 tooth pitch
|
1099
|
|
|
|
|
|
|
$x+=$cp->{mm}*($cp->{dw}*0.5)*(cos($t+$ti)-cos($t+0.5*$ti));
|
1100
|
|
|
|
|
|
|
$y+=$cp->{mm}*($cp->{dw}*0.5)*(sin($t+$ti)-sin($t+0.5*$ti));
|
1101
|
|
|
|
|
|
|
$gp->garcccw('x',$x,'y',$y,'r',$cp->{mm}*$cp->{ar},'f',$gp->{feed});
|
1102
|
|
|
|
|
|
|
|
1103
|
|
|
|
|
|
|
$t+=$ti;
|
1104
|
|
|
|
|
|
|
|
1105
|
|
|
|
|
|
|
}
|
1106
|
|
|
|
|
|
|
}
|
1107
|
|
|
|
|
|
|
|
1108
|
|
|
|
|
|
|
$gp->gmove('z',0.1);
|
1109
|
|
|
|
|
|
|
$gp->gcomp0();
|
1110
|
|
|
|
|
|
|
$gp->gmove('x',$xs,'y',$ys,'f',$gp->{feed} );
|
1111
|
|
|
|
|
|
|
|
1112
|
|
|
|
|
|
|
|
1113
|
|
|
|
|
|
|
|
1114
|
|
|
|
|
|
|
$cp->cutfillet($gp,$xs,$ys,$zs,$gp->{feed},$cp->{fpasses},$cp->{fpassdepth}) if ($cp->{fillet});
|
1115
|
|
|
|
|
|
|
|
1116
|
|
|
|
|
|
|
# $gp->gend();
|
1117
|
|
|
|
|
|
|
}
|
1118
|
|
|
|
|
|
|
|
1119
|
|
|
|
|
|
|
sub dist
|
1120
|
|
|
|
|
|
|
{
|
1121
|
|
|
|
|
|
|
shift if (ref($_[0]));
|
1122
|
|
|
|
|
|
|
my ($x1,$y1,$x2,$y2)=@_;
|
1123
|
|
|
|
|
|
|
return sqrt(($x2-$x1)**2+($y2-$y1)**2);
|
1124
|
|
|
|
|
|
|
}
|
1125
|
|
|
|
|
|
|
|
1126
|
|
|
|
|
|
|
# public
|
1127
|
|
|
|
|
|
|
#wheel
|
1128
|
|
|
|
|
|
|
sub outerradius
|
1129
|
|
|
|
|
|
|
# return the radius of a circle that contains the wheel including teeth
|
1130
|
|
|
|
|
|
|
{
|
1131
|
|
|
|
|
|
|
|
1132
|
|
|
|
|
|
|
my ($w)=@_;
|
1133
|
|
|
|
|
|
|
my $r=($w->{dw}/2.0+$w->{ad})*$w->{mm};
|
1134
|
|
|
|
|
|
|
printf "dw=%f ad=%f outerrad is %f\n",$w->{dw},$w->{ad},$r;
|
1135
|
|
|
|
|
|
|
return $r;
|
1136
|
|
|
|
|
|
|
}
|
1137
|
|
|
|
|
|
|
# public
|
1138
|
|
|
|
|
|
|
sub innerradius
|
1139
|
|
|
|
|
|
|
# return the radius of a circle that contains the wheel including teeth
|
1140
|
|
|
|
|
|
|
{
|
1141
|
|
|
|
|
|
|
|
1142
|
|
|
|
|
|
|
my ($w)=@_;
|
1143
|
|
|
|
|
|
|
return ($w->{dw}/2.0-$w->{dd})*$w->{mm};
|
1144
|
|
|
|
|
|
|
}
|
1145
|
|
|
|
|
|
|
|
1146
|
|
|
|
|
|
|
sub fillet
|
1147
|
|
|
|
|
|
|
{
|
1148
|
|
|
|
|
|
|
my ($c , # wheel
|
1149
|
|
|
|
|
|
|
# optional parameters:
|
1150
|
|
|
|
|
|
|
$npasses,
|
1151
|
|
|
|
|
|
|
$passdepth,
|
1152
|
|
|
|
|
|
|
)=@_;
|
1153
|
|
|
|
|
|
|
|
1154
|
|
|
|
|
|
|
|
1155
|
|
|
|
|
|
|
$c->{fillet}=1; # flag to say do fillet;
|
1156
|
|
|
|
|
|
|
$c->{fpasses}=$npasses;
|
1157
|
|
|
|
|
|
|
$c->{fpassdepth}=$passdepth;
|
1158
|
|
|
|
|
|
|
}
|
1159
|
|
|
|
|
|
|
# Similar to cutwheel, except that this cuts away the little triangles left when the wheel has been cut out
|
1160
|
|
|
|
|
|
|
# If you are cutting from a sheet, then its not necessary, but where you are not cutting the full deth,
|
1161
|
|
|
|
|
|
|
# eg cutting 2 wheels on top of each other, you need this to remove the triangular fillets
|
1162
|
|
|
|
|
|
|
# theres scope for this to be much more comlex, and it may fail as it currently is.
|
1163
|
|
|
|
|
|
|
# (Ie its not a great algorithmn, but I've used it inthis form a couple of times. )
|
1164
|
|
|
|
|
|
|
sub cutfillet
|
1165
|
|
|
|
|
|
|
{
|
1166
|
|
|
|
|
|
|
my ($cp , # wheel
|
1167
|
|
|
|
|
|
|
$gp, # graphics package, either generate graphics or gcode
|
1168
|
|
|
|
|
|
|
$xi,$yi,$z, # where to put the wheel
|
1169
|
|
|
|
|
|
|
$feed,
|
1170
|
|
|
|
|
|
|
# optional parameters:
|
1171
|
|
|
|
|
|
|
$npasses,
|
1172
|
|
|
|
|
|
|
$passdepth
|
1173
|
|
|
|
|
|
|
)=@_;
|
1174
|
|
|
|
|
|
|
|
1175
|
|
|
|
|
|
|
my $cr=$cp->{mm}*$cp->{dw}/2-$cp->{cuttersize}*1.25; # radius to cut to. No attemt made to calcultate, its empirical
|
1176
|
|
|
|
|
|
|
my $t=0; # theta, angle of wheel;
|
1177
|
|
|
|
|
|
|
my $ti=0.5*360/$cp->{n}; # half tooth increment.
|
1178
|
|
|
|
|
|
|
$ti*= $pi/180; # in radians now.
|
1179
|
|
|
|
|
|
|
|
1180
|
|
|
|
|
|
|
|
1181
|
|
|
|
|
|
|
|
1182
|
|
|
|
|
|
|
# In some situations particularly pinions tooth and gap angles are not the same.
|
1183
|
|
|
|
|
|
|
# define twf as factor extra for tooth, less than 1 for a wider gap
|
1184
|
|
|
|
|
|
|
my $tig=$ti*(2-$cp->{twf}); # width of a gap in radians
|
1185
|
|
|
|
|
|
|
$ti=$ti*$cp->{twf}; # this is now the width of a tooth. $tig+$ti is unchanged bu changes to $twf
|
1186
|
|
|
|
|
|
|
|
1187
|
|
|
|
|
|
|
|
1188
|
|
|
|
|
|
|
|
1189
|
|
|
|
|
|
|
## my ($xs,$ys)=($x,$y);
|
1190
|
|
|
|
|
|
|
my ($x,$y);
|
1191
|
|
|
|
|
|
|
|
1192
|
|
|
|
|
|
|
$gp->gmove('z',0.1,'f',$feed);
|
1193
|
|
|
|
|
|
|
|
1194
|
|
|
|
|
|
|
$npasses||=$cp->{passes};
|
1195
|
|
|
|
|
|
|
$passdepth||=$cp->{passdepth};
|
1196
|
|
|
|
|
|
|
|
1197
|
|
|
|
|
|
|
my $passes=0;
|
1198
|
|
|
|
|
|
|
while ($passes++ < $npasses)
|
1199
|
|
|
|
|
|
|
{
|
1200
|
|
|
|
|
|
|
|
1201
|
|
|
|
|
|
|
my $tcount=0;
|
1202
|
|
|
|
|
|
|
my $t=-$ti/2;
|
1203
|
|
|
|
|
|
|
$z+= $passdepth;
|
1204
|
|
|
|
|
|
|
$x=($cp->{mm}*($cp->{dw}/2+$cp->{ad})+$cp->{cuttersize}/2)*cos($t);
|
1205
|
|
|
|
|
|
|
$y=($cp->{mm}*($cp->{dw}/2+$cp->{ad})+$cp->{cuttersize}/2)*sin($t); # takes us to adendum point, comensates for cuttersize
|
1206
|
|
|
|
|
|
|
|
1207
|
|
|
|
|
|
|
while ($t/2.0/$pi<0.999 )
|
1208
|
|
|
|
|
|
|
{
|
1209
|
|
|
|
|
|
|
|
1210
|
|
|
|
|
|
|
$gp->gcomment(sprintf("Filleting Tooth number %d pass %d of %d",++$tcount,$passes,$npasses));
|
1211
|
|
|
|
|
|
|
|
1212
|
|
|
|
|
|
|
$gp->gmove('x',$xi+$x,'y',$yi+$y);
|
1213
|
|
|
|
|
|
|
$gp->gmove('z',$z);
|
1214
|
|
|
|
|
|
|
|
1215
|
|
|
|
|
|
|
$t+=$ti/2+$tig/2;
|
1216
|
|
|
|
|
|
|
my $tx=$cr*cos($t);
|
1217
|
|
|
|
|
|
|
my $ty=$cr*sin($t);
|
1218
|
|
|
|
|
|
|
|
1219
|
|
|
|
|
|
|
$t+=$ti/2+$tig/2;
|
1220
|
|
|
|
|
|
|
|
1221
|
|
|
|
|
|
|
|
1222
|
|
|
|
|
|
|
my $dx=($cp->{mm}*($cp->{dw}/2+$cp->{ad})+$cp->{cuttersize}/2)*cos($t)-$x;
|
1223
|
|
|
|
|
|
|
my $dy=($cp->{mm}*($cp->{dw}/2+$cp->{ad})+$cp->{cuttersize}/2)*sin($t)-$y;
|
1224
|
|
|
|
|
|
|
|
1225
|
|
|
|
|
|
|
$x+=$dx/2; # this takes us to middle of gap, but by straight line, so cut off a bit more of that wedge
|
1226
|
|
|
|
|
|
|
$y+=$dy/2;
|
1227
|
|
|
|
|
|
|
$gp->gmove('x',$x+$xi,'y',$y+$yi,'z',$z,'f',$feed);
|
1228
|
|
|
|
|
|
|
|
1229
|
|
|
|
|
|
|
$gp->gmove('x',$tx+$xi,'y',$ty+$yi);
|
1230
|
|
|
|
|
|
|
|
1231
|
|
|
|
|
|
|
$gp->gmove('x',$x+$xi,'y',$y+$yi,'z',$z,'f',$feed);
|
1232
|
|
|
|
|
|
|
|
1233
|
|
|
|
|
|
|
$x+=$dx/2; # this takes us to next addendum point
|
1234
|
|
|
|
|
|
|
$y+=$dy/2;
|
1235
|
|
|
|
|
|
|
|
1236
|
|
|
|
|
|
|
}
|
1237
|
|
|
|
|
|
|
}
|
1238
|
|
|
|
|
|
|
|
1239
|
|
|
|
|
|
|
$gp->gmove('z',0.1);
|
1240
|
|
|
|
|
|
|
$gp->gmove('x',$xi,'y',$yi);
|
1241
|
|
|
|
|
|
|
|
1242
|
|
|
|
|
|
|
}
|
1243
|
|
|
|
|
|
|
|
1244
|
|
|
|
|
|
|
sub smooth
|
1245
|
|
|
|
|
|
|
{
|
1246
|
|
|
|
|
|
|
# given a circle radius b and a point on circumference l2
|
1247
|
|
|
|
|
|
|
# the plan is to smooth the join between the line l1/l2 (each of these are points) and the circle circumference by
|
1248
|
|
|
|
|
|
|
# replacing a bit of the line l1/l2 with a circle of radius r.
|
1249
|
|
|
|
|
|
|
# The following are supplied where x1 y1 is l1 point 1, x2, y2 point 2 or l2.
|
1250
|
|
|
|
|
|
|
|
1251
|
|
|
|
|
|
|
# so call with l1,l2,b ,r
|
1252
|
|
|
|
|
|
|
# what comes back is l1 (unchanged), ,replacement l2 point sa which is start of arc, l1,sa are on the line
|
1253
|
|
|
|
|
|
|
# l1,l2 but sa is nearer l1 than l2.
|
1254
|
|
|
|
|
|
|
# ea where ea is on the original arc radius b, like l2, but is moved away from original l2.
|
1255
|
|
|
|
|
|
|
# sa, ea can be joined with arc radius b.
|
1256
|
|
|
|
|
|
|
|
1257
|
|
|
|
|
|
|
|
1258
|
|
|
|
|
|
|
my ($w,$x1,$y1,$x2,$y2,$b,$r)=@_;
|
1259
|
|
|
|
|
|
|
|
1260
|
|
|
|
|
|
|
# print "smooth x1=$x1,y1=$y1,x2=$x2,y2=$y2,b=$b,r=$r\n";
|
1261
|
|
|
|
|
|
|
|
1262
|
|
|
|
|
|
|
#($x1,$y1,$x2,$y2,$b,$r)=(-0.2 , 0.2 , -0.707 , 0.707 , 1.0 , 0.1);
|
1263
|
|
|
|
|
|
|
# ($x1,$y1,$x2,$y2,$b,$r)= (-0.279378067455943, 0.65017874253593, 0.702760341741972, 0.0831408677831007, 0.9,0.1);
|
1264
|
|
|
|
|
|
|
|
1265
|
|
|
|
|
|
|
my $ks;
|
1266
|
|
|
|
|
|
|
|
1267
|
|
|
|
|
|
|
# straight line l1 l2 has eqn y=mx+c
|
1268
|
|
|
|
|
|
|
|
1269
|
|
|
|
|
|
|
my $m=($y2-$y1)/($x2-$x1);
|
1270
|
|
|
|
|
|
|
my $c=$y1-($y2-$y1)*$x1/($x2-$x1);
|
1271
|
|
|
|
|
|
|
$ks=$r>0?1:-1;
|
1272
|
|
|
|
|
|
|
# $ks=-$ks if ($y2>0);
|
1273
|
|
|
|
|
|
|
$r=abs($r);
|
1274
|
|
|
|
|
|
|
$ks=-$ks if ($x1<$x2);
|
1275
|
|
|
|
|
|
|
|
1276
|
|
|
|
|
|
|
|
1277
|
|
|
|
|
|
|
# line paralell to this and distance r away is y=mx+j where j=c+k or j=c-k
|
1278
|
|
|
|
|
|
|
|
1279
|
|
|
|
|
|
|
my $k = abs($r) * sqrt( (($x2-$x1)**2+($y2-$y1)**2)/($x2-$x1)**2);
|
1280
|
|
|
|
|
|
|
my $j=$c+$k*$ks; # ks is the sign of k from above.
|
1281
|
|
|
|
|
|
|
|
1282
|
|
|
|
|
|
|
# we need to solve this with the circle x^2+y^2=(b+r)^2
|
1283
|
|
|
|
|
|
|
# substituting for y in here gives
|
1284
|
|
|
|
|
|
|
#
|
1285
|
|
|
|
|
|
|
# x^2+y^2=(b+r)^2
|
1286
|
|
|
|
|
|
|
# y=mx+j
|
1287
|
|
|
|
|
|
|
# x^2+m^2x^2+2mxj+j^2=(b+r)^2
|
1288
|
|
|
|
|
|
|
# (1+m^2) x^2 + 2mj x +j^2-(b+r)^2=0
|
1289
|
|
|
|
|
|
|
# use quadratic equation formula to find x:
|
1290
|
|
|
|
|
|
|
# x=(-b+- sqrt(b^2-4ac)/2a
|
1291
|
|
|
|
|
|
|
#
|
1292
|
|
|
|
|
|
|
# x=(-2mj +- sqrt(4m^2j^2-4(1+m^2)(j^2-(b+r)^2)))/2(1+m^2)
|
1293
|
|
|
|
|
|
|
# This is the center point of the arc.
|
1294
|
|
|
|
|
|
|
|
1295
|
|
|
|
|
|
|
# s is the distance between c and l2, we now have x and y coords for both c and l2.
|
1296
|
|
|
|
|
|
|
# u^2=s^2-r^2 and is distance from l2 in direction of l1 for the new l2 point at start of smoothing arc.
|
1297
|
|
|
|
|
|
|
# The end of the arc is oc scaled such that distance is b, the radius of the circle.
|
1298
|
|
|
|
|
|
|
$r=-$r if (dist(0,0,$x1,$y1)<$b);
|
1299
|
|
|
|
|
|
|
|
1300
|
|
|
|
|
|
|
my $cxa=(-2*$m*$j + sqrt(abs(4*$m**2*$j**2-4*(1+$m**2)*($j**2-($b+$r)**2))))/2/(1+$m**2);
|
1301
|
|
|
|
|
|
|
my $cxb=(-2*$m*$j - sqrt(abs(4*$m**2*$j**2-4*(1+$m**2)*($j**2-($b+$r)**2))))/2/(1+$m**2); # This is the other root of the quadratic.
|
1302
|
|
|
|
|
|
|
# use the one closest to l2?
|
1303
|
|
|
|
|
|
|
my $cya=$m*$cxa+$j;
|
1304
|
|
|
|
|
|
|
my $cyb=$m*$cxb+$j;
|
1305
|
|
|
|
|
|
|
|
1306
|
|
|
|
|
|
|
($cxa,$cya,$cxb,$cyb)=($cxb,$cyb,$cxa,$cya) if (dist($x2,$y2,$cxb,$cyb)
|
1307
|
|
|
|
|
|
|
# swap rather than assign so that we still have the other root if we need to look at it for debug purposes.
|
1308
|
|
|
|
|
|
|
|
1309
|
|
|
|
|
|
|
my $s=dist($x2,$y2,$cxa,$cya);
|
1310
|
|
|
|
|
|
|
my $u=sqrt($s**2-$r**2);
|
1311
|
|
|
|
|
|
|
my $sax=$x2+($x1-$x2)*$u/dist($x1,$y1,$x2,$y2); #start of arc
|
1312
|
|
|
|
|
|
|
my $say=$y2+($y1-$y2)*$u/dist($x1,$y1,$x2,$y2);
|
1313
|
|
|
|
|
|
|
my $eax=$cxa*$b/dist(0,0,$cxa,$cya);
|
1314
|
|
|
|
|
|
|
my $eay=$cya*$b/dist(0,0,$cxa,$cya);
|
1315
|
|
|
|
|
|
|
|
1316
|
|
|
|
|
|
|
return ($x1,$y1,$sax,$say,$eax,$eay); #ending on the circle
|
1317
|
|
|
|
|
|
|
|
1318
|
|
|
|
|
|
|
# The code below is used for graphing out test cases. Its debug only.
|
1319
|
|
|
|
|
|
|
my $gd=gdcode::new(undef,"test.png",6.0,2500,2500);
|
1320
|
|
|
|
|
|
|
$gd->gmove('z',0.1);
|
1321
|
|
|
|
|
|
|
$gd->gmove('x',$x1,'y',$y1);
|
1322
|
|
|
|
|
|
|
$gd->gmove('z',-0.1);
|
1323
|
|
|
|
|
|
|
$gd->gmove('x',$x2,'y',$y2);
|
1324
|
|
|
|
|
|
|
|
1325
|
|
|
|
|
|
|
$gd->gmove('z',0.1);
|
1326
|
|
|
|
|
|
|
$gd->gmove('x',0,'y',$b);
|
1327
|
|
|
|
|
|
|
$gd->gmove('z',-0.1);
|
1328
|
|
|
|
|
|
|
$gd->garcccw('x',0,'y',-$b,'r',$b);
|
1329
|
|
|
|
|
|
|
$gd->garcccw('x',0,'y',$b,'r',$b);
|
1330
|
|
|
|
|
|
|
|
1331
|
|
|
|
|
|
|
|
1332
|
|
|
|
|
|
|
$gd->gmove('z',0.1);
|
1333
|
|
|
|
|
|
|
# ($cxa,$cya)=($cxb,$cyb); # want to see the other one ?
|
1334
|
|
|
|
|
|
|
$gd->gmove('x',$cxa+0.05,'y',$cya+0.05); # mark the center with an X
|
1335
|
|
|
|
|
|
|
$gd->gmove('x',$cxa-0.05,'y',$cya-0.05,'z',-0.1);
|
1336
|
|
|
|
|
|
|
$gd->gmove('x',$cxa+0.05,'y',$cya-0.05,'z',0.1);
|
1337
|
|
|
|
|
|
|
$gd->gmove('x',$cxa-0.05,'y',$cya+0.05,'z',-0.1);
|
1338
|
|
|
|
|
|
|
|
1339
|
|
|
|
|
|
|
# $gd->gmove('x',$cxa,'y',$cya+$r,'z',0.1);
|
1340
|
|
|
|
|
|
|
# $gd->garcccw('x',$cxa,'y',$cya-$r,'r',abs($r),'z',-0.1);
|
1341
|
|
|
|
|
|
|
# $gd->garcccw('x',$cxa,'y',$cya+$r,'r',abs($r),'z',-0.1);
|
1342
|
|
|
|
|
|
|
|
1343
|
|
|
|
|
|
|
|
1344
|
|
|
|
|
|
|
$gd->gmove('x',$sax,'y',$say,'z',0.1);
|
1345
|
|
|
|
|
|
|
$gd->garccw('x',$eax,'y',$eay,'r',abs($r),'z',-0.1);
|
1346
|
|
|
|
|
|
|
|
1347
|
|
|
|
|
|
|
|
1348
|
|
|
|
|
|
|
$gd->gend();
|
1349
|
|
|
|
|
|
|
die;
|
1350
|
|
|
|
|
|
|
}
|
1351
|
|
|
|
|
|
|
# This is a convienence wrapper funcion for smooth.
|
1352
|
|
|
|
|
|
|
# thing is parameter order depends on weather you are coming or going.
|
1353
|
|
|
|
|
|
|
# this function does the appropriate swap, both of the input parameters and the result
|
1354
|
|
|
|
|
|
|
sub rsmooth
|
1355
|
|
|
|
|
|
|
{
|
1356
|
|
|
|
|
|
|
my ($w,$x1,$y1,$x2,$y2,$br,$r)=@_; # params are point1, point 2, bossradius, radius
|
1357
|
|
|
|
|
|
|
my @xy=($x2,$y2,$x1,$y1); # point 1 and 2 given in wrong order for reverse smooth, so swap
|
1358
|
|
|
|
|
|
|
@xy=$w->smooth(@xy,$br,$r); # xy now is point, start of arc end of arc
|
1359
|
|
|
|
|
|
|
@xy=@xy[4,5,2,3,0,1]; # return start of arc, end of arc and point.
|
1360
|
|
|
|
|
|
|
return @xy; # need in order given which is reverse, so give end of arc first
|
1361
|
|
|
|
|
|
|
}
|
1362
|
|
|
|
|
|
|
|
1363
|
|
|
|
|
|
|
# this function returns dimentions in inches.
|
1364
|
|
|
|
|
|
|
# input can be a string such as 22mm, 72pt or 2.3i
|
1365
|
|
|
|
|
|
|
# output is somethig like 0.9, 1.0,2.3 as 22mm is about 0.9 inches, 72 points is exactly 1 inch and 2.3i means 2.3 inches.
|
1366
|
|
|
|
|
|
|
# t is thousandths of an inch.
|
1367
|
|
|
|
|
|
|
sub dim
|
1368
|
|
|
|
|
|
|
{
|
1369
|
|
|
|
|
|
|
my ($w)=shift; # self pointer to wheel
|
1370
|
|
|
|
|
|
|
my @a= map
|
1371
|
|
|
|
|
|
|
{
|
1372
|
|
|
|
|
|
|
|
1373
|
|
|
|
|
|
|
s/i//g;
|
1374
|
|
|
|
|
|
|
s/mm//g and $_=$_*$w->{mm};
|
1375
|
|
|
|
|
|
|
s/pt//g and $_=$_/72;
|
1376
|
|
|
|
|
|
|
s/t//g and $_=$_/1000;
|
1377
|
|
|
|
|
|
|
$_;
|
1378
|
|
|
|
|
|
|
|
1379
|
|
|
|
|
|
|
} @_;
|
1380
|
|
|
|
|
|
|
return $a[0] if (@a==1);
|
1381
|
|
|
|
|
|
|
return @a;
|
1382
|
|
|
|
|
|
|
}
|
1383
|
|
|
|
|
|
|
# this function returns dimentions in radians
|
1384
|
|
|
|
|
|
|
# input can be a string such as 0.01r 5d or 5
|
1385
|
|
|
|
|
|
|
# default units are degrees.
|
1386
|
|
|
|
|
|
|
# note that additional multipliers are allowd but ignore, so you can add an r to make the defult into radians,
|
1387
|
|
|
|
|
|
|
# but if degrees is specified, we get 5dr and this is interpreted as degrees as is 5dd.
|
1388
|
|
|
|
|
|
|
# Output is always in radians.
|
1389
|
|
|
|
|
|
|
|
1390
|
|
|
|
|
|
|
sub dimr
|
1391
|
|
|
|
|
|
|
{
|
1392
|
|
|
|
|
|
|
my ($w)=shift; # self pointer to wheel
|
1393
|
|
|
|
|
|
|
my @a= map
|
1394
|
|
|
|
|
|
|
{
|
1395
|
|
|
|
|
|
|
if (m/([dr])/i)
|
1396
|
|
|
|
|
|
|
{
|
1397
|
|
|
|
|
|
|
my $d=$1;
|
1398
|
|
|
|
|
|
|
s/[dr]//ig;
|
1399
|
|
|
|
|
|
|
if ($d eq 'd')
|
1400
|
|
|
|
|
|
|
{
|
1401
|
|
|
|
|
|
|
$_=$_*$pi/180.0;
|
1402
|
|
|
|
|
|
|
}
|
1403
|
|
|
|
|
|
|
}
|
1404
|
|
|
|
|
|
|
else
|
1405
|
|
|
|
|
|
|
{
|
1406
|
|
|
|
|
|
|
$_=$_*$pi/180.0;
|
1407
|
|
|
|
|
|
|
}
|
1408
|
|
|
|
|
|
|
$_;
|
1409
|
|
|
|
|
|
|
|
1410
|
|
|
|
|
|
|
} @_;
|
1411
|
|
|
|
|
|
|
return $a[0] if (@a==1); # for scalar context, need to return a scalar.
|
1412
|
|
|
|
|
|
|
return @a;
|
1413
|
|
|
|
|
|
|
}
|
1414
|
|
|
|
|
|
|
|
1415
|
|
|
|
|
|
|
# parameters:
|
1416
|
|
|
|
|
|
|
# toothradiuspc and toothradius used only when topshape is bicirc circlead circtrail
|
1417
|
|
|
|
|
|
|
package Grahamwheel;
|
1418
|
|
|
|
|
|
|
|
1419
|
|
|
|
|
|
|
use vars qw($VERSION @ISA @EXPORT);
|
1420
|
|
|
|
|
|
|
$VERSION=0.05;
|
1421
|
|
|
|
|
|
|
|
1422
|
|
|
|
|
|
|
@ISA=('Wheel');
|
1423
|
|
|
|
|
|
|
|
1424
|
|
|
|
|
|
|
sub new
|
1425
|
|
|
|
|
|
|
{
|
1426
|
|
|
|
|
|
|
my (
|
1427
|
|
|
|
|
|
|
$class, # self pointer;
|
1428
|
|
|
|
|
|
|
$n, # hash (now)
|
1429
|
|
|
|
|
|
|
)=@_;
|
1430
|
|
|
|
|
|
|
|
1431
|
|
|
|
|
|
|
#die "$d,$dd";
|
1432
|
|
|
|
|
|
|
|
1433
|
|
|
|
|
|
|
|
1434
|
|
|
|
|
|
|
my $s={};
|
1435
|
|
|
|
|
|
|
shift;
|
1436
|
|
|
|
|
|
|
if (ref($n)) # means we've been passed a hash ref
|
1437
|
|
|
|
|
|
|
{
|
1438
|
|
|
|
|
|
|
my $h=$n;
|
1439
|
|
|
|
|
|
|
|
1440
|
|
|
|
|
|
|
for my $key (qw(lift nteeth externald toothdepth toothtoppc toothtop toothbase toothbasepc offset holesize topshape toothradius toothradiuspc filletradius ))
|
1441
|
|
|
|
|
|
|
{
|
1442
|
|
|
|
|
|
|
$s->{$key}=$h->{$key};
|
1443
|
|
|
|
|
|
|
}
|
1444
|
|
|
|
|
|
|
$s->{n}=$s->{nteeth}; delete $s->{nteeth};
|
1445
|
|
|
|
|
|
|
$s->{d}=$s->{externald}; delete $s->{externald};
|
1446
|
|
|
|
|
|
|
$s->{dd}=$s->{toothdepth}; delete $s->{toothdepth};
|
1447
|
|
|
|
|
|
|
}
|
1448
|
|
|
|
|
|
|
else
|
1449
|
|
|
|
|
|
|
{
|
1450
|
|
|
|
|
|
|
die "You need to pass a hash reference to the Graham wheel constructor";
|
1451
|
|
|
|
|
|
|
# map { $s->{$_}=shift } qw(n d dd offset toothbase toothtop topshape topshape);
|
1452
|
|
|
|
|
|
|
}
|
1453
|
|
|
|
|
|
|
|
1454
|
|
|
|
|
|
|
|
1455
|
|
|
|
|
|
|
#$d=$s->dim($d);
|
1456
|
|
|
|
|
|
|
#$dd=$s->dim($dd);
|
1457
|
|
|
|
|
|
|
#$offset||=-6;
|
1458
|
|
|
|
|
|
|
#$offset=$s->dimr($offset);
|
1459
|
|
|
|
|
|
|
#$toothbase||=33.333; # in %
|
1460
|
|
|
|
|
|
|
#$toothbase/=100.0; # as a proportion .
|
1461
|
|
|
|
|
|
|
#$toothtop||=0.5; # in degrees
|
1462
|
|
|
|
|
|
|
#$toothtop=$s->dimr($toothtop);
|
1463
|
|
|
|
|
|
|
|
1464
|
|
|
|
|
|
|
bless $s, $class;
|
1465
|
|
|
|
|
|
|
|
1466
|
|
|
|
|
|
|
$s->{d}=$s->dim($s->{d});
|
1467
|
|
|
|
|
|
|
$s->{dd}=$s->dim($s->{dd});
|
1468
|
|
|
|
|
|
|
$s->{offset}||=-6;
|
1469
|
|
|
|
|
|
|
$s->{offset}=$s->dimr($s->{offset});
|
1470
|
|
|
|
|
|
|
$s->{toothbase}||=$s->{toothbasepc}; # synonym.
|
1471
|
|
|
|
|
|
|
$s->{toothbase}/=100.0; # convert to proportion.
|
1472
|
|
|
|
|
|
|
$s->{toothtop}||=0.5; # in degrees
|
1473
|
|
|
|
|
|
|
$s->{toothtop}=$s->dimr($s->{toothtop}); # now in radians.
|
1474
|
|
|
|
|
|
|
if ($s->{toothtoppc} > 0.01)
|
1475
|
|
|
|
|
|
|
{
|
1476
|
|
|
|
|
|
|
$s->{toothtop}=$s->{toothtoppc}*0.02*$pi/$s->{n};
|
1477
|
|
|
|
|
|
|
}
|
1478
|
|
|
|
|
|
|
|
1479
|
|
|
|
|
|
|
$s->{topshape}||='semi';
|
1480
|
|
|
|
|
|
|
|
1481
|
|
|
|
|
|
|
if (!grep { $s->{topshape} eq $_} qw(semi flat circ bicirc circlead circtrail))
|
1482
|
|
|
|
|
|
|
{
|
1483
|
|
|
|
|
|
|
die "unknown topshape '$s->{topshape}'";
|
1484
|
|
|
|
|
|
|
}
|
1485
|
|
|
|
|
|
|
$s->{dw}=($s->{d}-$s->{dd}*2)/$mm; # we set tis so trepanning works. This is a total fudge!
|
1486
|
|
|
|
|
|
|
|
1487
|
|
|
|
|
|
|
|
1488
|
|
|
|
|
|
|
return $s;
|
1489
|
|
|
|
|
|
|
}
|
1490
|
|
|
|
|
|
|
# given line p1,p2, and line p3, p4 find cross point.
|
1491
|
|
|
|
|
|
|
sub solve
|
1492
|
|
|
|
|
|
|
{
|
1493
|
|
|
|
|
|
|
my ($w,$x1,$y1,$x2,$y2,$x3,$y3,$x4,$y4)=@_;
|
1494
|
|
|
|
|
|
|
|
1495
|
|
|
|
|
|
|
my ($m1,$m2,$k1,$k2,$t1);
|
1496
|
|
|
|
|
|
|
|
1497
|
|
|
|
|
|
|
$m1=($x3-$x4)/($x1-$x2);
|
1498
|
|
|
|
|
|
|
$k1=($x4-$x2)/($x1-$x2);
|
1499
|
|
|
|
|
|
|
|
1500
|
|
|
|
|
|
|
$m2=($y3-$y4)/($y1-$y2);
|
1501
|
|
|
|
|
|
|
$k2=($y4-$y2)/($y1-$y2);
|
1502
|
|
|
|
|
|
|
|
1503
|
|
|
|
|
|
|
$t1=($k1-$k2*$m1/$m2)/(1-$m1/$m2);
|
1504
|
|
|
|
|
|
|
|
1505
|
|
|
|
|
|
|
|
1506
|
|
|
|
|
|
|
my ($x,$y);
|
1507
|
|
|
|
|
|
|
|
1508
|
|
|
|
|
|
|
$x=$t1*$x1+(1-$t1)*$x2;
|
1509
|
|
|
|
|
|
|
$y=$t1*$y1+(1-$t1)*$y2;
|
1510
|
|
|
|
|
|
|
|
1511
|
|
|
|
|
|
|
return ($x,$y);
|
1512
|
|
|
|
|
|
|
|
1513
|
|
|
|
|
|
|
}
|
1514
|
|
|
|
|
|
|
|
1515
|
|
|
|
|
|
|
sub ttr
|
1516
|
|
|
|
|
|
|
{
|
1517
|
|
|
|
|
|
|
my ($w,$gp,$pr)=@_;
|
1518
|
|
|
|
|
|
|
my ($x1,$y1,$x2,$y2,$x3,$y3,$x4,$y4)=@$pr;
|
1519
|
|
|
|
|
|
|
#
|
1520
|
|
|
|
|
|
|
# p2/ |p3 4 points with x y cords as in diagram. Calculating radius of circle
|
1521
|
|
|
|
|
|
|
# / | tat will join p2 p3.
|
1522
|
|
|
|
|
|
|
# p1/ |p4
|
1523
|
|
|
|
|
|
|
# _/ |_
|
1524
|
|
|
|
|
|
|
#
|
1525
|
|
|
|
|
|
|
#
|
1526
|
|
|
|
|
|
|
#
|
1527
|
|
|
|
|
|
|
|
1528
|
|
|
|
|
|
|
# calclate bisector point of angle p1 p2 p3
|
1529
|
|
|
|
|
|
|
# method, make unit vector in direction of lines, make point half way between ends of vectors. (half point for 2, hp2)
|
1530
|
|
|
|
|
|
|
# make vector from p2 to half way point.
|
1531
|
|
|
|
|
|
|
# repeat with p4p3p2
|
1532
|
|
|
|
|
|
|
# cross vectors to get circle center point
|
1533
|
|
|
|
|
|
|
|
1534
|
|
|
|
|
|
|
#solve($w,2.5,5.2,6.8,2.9,1.0,0,6.8,0);
|
1535
|
|
|
|
|
|
|
#exit;
|
1536
|
|
|
|
|
|
|
|
1537
|
|
|
|
|
|
|
$gp->gline($x1,$y1,$x2,$y2);
|
1538
|
|
|
|
|
|
|
$gp->gline($x3,$y3,$x4,$y4);
|
1539
|
|
|
|
|
|
|
|
1540
|
|
|
|
|
|
|
# This is a unit vector in the x1 x2 direction
|
1541
|
|
|
|
|
|
|
my $u21x=($x1-$x2)/sqrt(($x1-$x2)**2+($y1-$y2)**2);
|
1542
|
|
|
|
|
|
|
my $u21y=($y1-$y2)/sqrt(($x1-$x2)**2+($y1-$y2)**2);
|
1543
|
|
|
|
|
|
|
|
1544
|
|
|
|
|
|
|
# $gp->gline($x2,$y2,$x2+$u21x,$y2+$u21y);
|
1545
|
|
|
|
|
|
|
|
1546
|
|
|
|
|
|
|
|
1547
|
|
|
|
|
|
|
# This is a unit vector in the x3 x2 direction
|
1548
|
|
|
|
|
|
|
my $u23x=($x3-$x2)/sqrt(($x3-$x2)**2+($y3-$y2)**2);
|
1549
|
|
|
|
|
|
|
my $u23y=($y3-$y2)/sqrt(($x3-$x2)**2+($y3-$y2)**2);
|
1550
|
|
|
|
|
|
|
|
1551
|
|
|
|
|
|
|
#$gp->gline($x2,$y2,$x2+$u23x,$y2+$u23y);
|
1552
|
|
|
|
|
|
|
|
1553
|
|
|
|
|
|
|
# A point half way between unit vectors gives the angle bisector.
|
1554
|
|
|
|
|
|
|
my $hp2x=$x2+0.5*($u21x+$u23x); # gives angle bisecor point as absolute coord.
|
1555
|
|
|
|
|
|
|
my $hp2y=$y2+0.5*($u21y+$u23y);
|
1556
|
|
|
|
|
|
|
|
1557
|
|
|
|
|
|
|
#$gp->gline($x2,$y2,$hp2x,$hp2y);
|
1558
|
|
|
|
|
|
|
|
1559
|
|
|
|
|
|
|
|
1560
|
|
|
|
|
|
|
my $u34x=($x4-$x3)/sqrt(($x4-$x3)**2+($y4-$y3)**2);
|
1561
|
|
|
|
|
|
|
my $u34y=($y4-$y3)/sqrt(($x4-$x3)**2+($y4-$y3)**2);
|
1562
|
|
|
|
|
|
|
|
1563
|
|
|
|
|
|
|
my $u32x=-$u23x;
|
1564
|
|
|
|
|
|
|
my $u32y=-$u23y;
|
1565
|
|
|
|
|
|
|
|
1566
|
|
|
|
|
|
|
# The other angle bisected.
|
1567
|
|
|
|
|
|
|
my $hp3x=$x3+0.5*($u32x+$u34x); # gives angle bisecor point as absolute coord.
|
1568
|
|
|
|
|
|
|
my $hp3y=$y3+0.5*($u32y+$u34y);
|
1569
|
|
|
|
|
|
|
|
1570
|
|
|
|
|
|
|
|
1571
|
|
|
|
|
|
|
#$gp->gline($x3,$y3,$hp3x,$hp3y);
|
1572
|
|
|
|
|
|
|
|
1573
|
|
|
|
|
|
|
|
1574
|
|
|
|
|
|
|
# Where these two angle bisectors cross, gives us the circle center.
|
1575
|
|
|
|
|
|
|
my ($cx,$cy)=$w->solve($x2,$y2,$hp2x,$hp2y,$x3,$y3,$hp3x,$hp3y);
|
1576
|
|
|
|
|
|
|
|
1577
|
|
|
|
|
|
|
|
1578
|
|
|
|
|
|
|
|
1579
|
|
|
|
|
|
|
|
1580
|
|
|
|
|
|
|
# cosine of the angle at p1 by the cosine rule.
|
1581
|
|
|
|
|
|
|
my $ca1=(($cx-$x2)**2+($cy-$y2)**2-($x1-$x2)**2-($y1-$y2)**2-($cx-$x1)**2-($cy-$y1)**2)/
|
1582
|
|
|
|
|
|
|
(-2*sqrt((($x1-$x2)**2+($y1-$y2)**2)*(($cx-$x1)**2+($cy-$y1)**2)));
|
1583
|
|
|
|
|
|
|
|
1584
|
|
|
|
|
|
|
|
1585
|
|
|
|
|
|
|
# length from p1 to the normal point
|
1586
|
|
|
|
|
|
|
my $l1 =$ca1*sqrt((($cx-$x1)**2+($cy-$y1)**2));
|
1587
|
|
|
|
|
|
|
|
1588
|
|
|
|
|
|
|
# proportion down the line from x1 to normal point
|
1589
|
|
|
|
|
|
|
my $t=$l1/sqrt(($x1-$x2)**2+($y1-$y2)**2);
|
1590
|
|
|
|
|
|
|
|
1591
|
|
|
|
|
|
|
# this is the normal point, and we replace x2, y2 with this new point.
|
1592
|
|
|
|
|
|
|
my $mx2=$x1*(1-$t)+$x2*$t;
|
1593
|
|
|
|
|
|
|
my $my2=$y1*(1-$t)+$y2*$t;
|
1594
|
|
|
|
|
|
|
|
1595
|
|
|
|
|
|
|
|
1596
|
|
|
|
|
|
|
# do the same to calculate x3 y3 replacement oint
|
1597
|
|
|
|
|
|
|
my $ca2=(($cx-$x3)**2+($cy-$y3)**2-($x3-$x4)**2-($y3-$y4)**2-($cx-$x4)**2-($cy-$y4)**2)/
|
1598
|
|
|
|
|
|
|
(-2*sqrt((($x3-$x4)**2+($y3-$y4)**2)*(($cx-$x4)**2+($cy-$y4)**2)));
|
1599
|
|
|
|
|
|
|
|
1600
|
|
|
|
|
|
|
my $l2 =$ca2*sqrt((($cx-$x4)**2+($cy-$y4)**2));
|
1601
|
|
|
|
|
|
|
|
1602
|
|
|
|
|
|
|
$t=$l2/sqrt(($x3-$x4)**2+($y3-$y4)**2);
|
1603
|
|
|
|
|
|
|
|
1604
|
|
|
|
|
|
|
my $mx3=$x4*(1-$t)+$x3*$t;
|
1605
|
|
|
|
|
|
|
my $my3=$y4*(1-$t)+$y3*$t;
|
1606
|
|
|
|
|
|
|
|
1607
|
|
|
|
|
|
|
# calculate the radius. For best acuracy, we average these, probably not necessary.
|
1608
|
|
|
|
|
|
|
my $r=(sqrt(($cx-$mx2)**2+($cy-$my2)**2)+sqrt(($cx-$mx3)**2+($cy-$my3)**2))/2;
|
1609
|
|
|
|
|
|
|
|
1610
|
|
|
|
|
|
|
# replace the points
|
1611
|
|
|
|
|
|
|
@$pr=($x1,$y1,$mx2,$my2,$mx3,$my3,$x4,$y4);
|
1612
|
|
|
|
|
|
|
|
1613
|
|
|
|
|
|
|
# return the radius.
|
1614
|
|
|
|
|
|
|
return $r;
|
1615
|
|
|
|
|
|
|
}
|
1616
|
|
|
|
|
|
|
|
1617
|
|
|
|
|
|
|
|
1618
|
|
|
|
|
|
|
# grahamwheel cut
|
1619
|
|
|
|
|
|
|
sub cut
|
1620
|
|
|
|
|
|
|
{
|
1621
|
|
|
|
|
|
|
|
1622
|
|
|
|
|
|
|
my ($cp , # wheel
|
1623
|
|
|
|
|
|
|
$gp, # graphics package, either generate graphics or gcode
|
1624
|
|
|
|
|
|
|
$x,$y,$z,$theta # where to put the wheel
|
1625
|
|
|
|
|
|
|
)=@_;
|
1626
|
|
|
|
|
|
|
|
1627
|
|
|
|
|
|
|
|
1628
|
|
|
|
|
|
|
my $ti =2*$pi/$cp->{n}; # tooth and gap angular increment.
|
1629
|
|
|
|
|
|
|
my $tig=(1-$cp->{toothbase})*$ti; # tooth increment for gap (angular)
|
1630
|
|
|
|
|
|
|
my $tt = $cp->{toothbase}*$ti; # tooth angular increment.
|
1631
|
|
|
|
|
|
|
|
1632
|
|
|
|
|
|
|
|
1633
|
|
|
|
|
|
|
my $topshape=$cp->{topshape};
|
1634
|
|
|
|
|
|
|
my $toothtop=$cp->{toothtop}; # anglar size of toothtop
|
1635
|
|
|
|
|
|
|
my $filletradius;
|
1636
|
|
|
|
|
|
|
$filletradius=0.02;
|
1637
|
|
|
|
|
|
|
$filletradius=0.03125; # corresponds to exactly 1/16 inch cutter
|
1638
|
|
|
|
|
|
|
$filletradius=0.033; # in practice make slightly larger
|
1639
|
|
|
|
|
|
|
$filletradius=$cp->{filletradius}; # This is the radius used at the bottom of the tooth gap, needs to be as small as possible, but bigger than the cutter
|
1640
|
|
|
|
|
|
|
# radius used, or else it cant be cut!
|
1641
|
|
|
|
|
|
|
|
1642
|
|
|
|
|
|
|
$cp->{filletradius} or die;
|
1643
|
|
|
|
|
|
|
my $ccrunin=3*$cp->{cuttersize}; # distance used for compensation run in.
|
1644
|
|
|
|
|
|
|
|
1645
|
|
|
|
|
|
|
# printf "cos offset=%f offset=%f\n",cos($cp->{offset}),$cp->{offset};
|
1646
|
|
|
|
|
|
|
|
1647
|
|
|
|
|
|
|
$cp->{d}-=$cp->{d}*$toothtop*cos($cp->{offset}*$cp->{n}/5) if ($topshape eq 'semi');
|
1648
|
|
|
|
|
|
|
# 5 is an empiricle fudge factor in the above
|
1649
|
|
|
|
|
|
|
# purpose of this is to prevent the semicircle at the top of each tooth increasing diameter of wheel.
|
1650
|
|
|
|
|
|
|
|
1651
|
|
|
|
|
|
|
|
1652
|
|
|
|
|
|
|
my ($xs,$ys,$zs)=($x,$y,$z); # remember initial place.
|
1653
|
|
|
|
|
|
|
$gp->gcomment("Graham Wheel");
|
1654
|
|
|
|
|
|
|
$gp->gmove('z',0.1,'f',$gp->{feed});
|
1655
|
|
|
|
|
|
|
$cp->cutbossindent($gp,$x,$y);
|
1656
|
|
|
|
|
|
|
$cp->cuthole($gp,$x,$y,$z,$cp->{holesize},$gp->{feed});
|
1657
|
|
|
|
|
|
|
$cp->{ring}->cut($gp,$x,$y,$z) if ($cp->{ring});
|
1658
|
|
|
|
|
|
|
$cp->cuttrepan($gp,$xs,$ys,$zs);
|
1659
|
|
|
|
|
|
|
|
1660
|
|
|
|
|
|
|
|
1661
|
|
|
|
|
|
|
my $ri=$cp->{d}*0.5-$cp->{dd}; # inner radius
|
1662
|
|
|
|
|
|
|
my $ro=$cp->{d}*0.5; # outer radius
|
1663
|
|
|
|
|
|
|
|
1664
|
|
|
|
|
|
|
|
1665
|
|
|
|
|
|
|
my $passes=0;
|
1666
|
|
|
|
|
|
|
my $feed=3*$gp->{feed}; # faster for positioning, should really be grapid.
|
1667
|
|
|
|
|
|
|
my $offset=$cp->{offset};
|
1668
|
|
|
|
|
|
|
my $first=1;
|
1669
|
|
|
|
|
|
|
my $lift=$cp->{lift};
|
1670
|
|
|
|
|
|
|
|
1671
|
|
|
|
|
|
|
$theta=$cp->dimr($theta); # convert radians, default degrees.
|
1672
|
|
|
|
|
|
|
|
1673
|
|
|
|
|
|
|
$gp->gcomment("Graham Wheel - teeth");
|
1674
|
|
|
|
|
|
|
while ($passes++ < $cp->{passes})
|
1675
|
|
|
|
|
|
|
{
|
1676
|
|
|
|
|
|
|
my $tcount=0;
|
1677
|
|
|
|
|
|
|
my $t=$tig/2+$theta; # start half way through gap
|
1678
|
|
|
|
|
|
|
my (@toothgap);
|
1679
|
|
|
|
|
|
|
$z+= $cp->{passdepth};
|
1680
|
|
|
|
|
|
|
while ($t<2*$pi+$theta )
|
1681
|
|
|
|
|
|
|
{
|
1682
|
|
|
|
|
|
|
my @xy;
|
1683
|
|
|
|
|
|
|
|
1684
|
|
|
|
|
|
|
$gp->gcomment(sprintf("Tooth number %d pass %d",++$tcount,$passes));
|
1685
|
|
|
|
|
|
|
|
1686
|
|
|
|
|
|
|
|
1687
|
|
|
|
|
|
|
|
1688
|
|
|
|
|
|
|
$x=$ri*cos($t);
|
1689
|
|
|
|
|
|
|
$y=$ri*sin($t);
|
1690
|
|
|
|
|
|
|
|
1691
|
|
|
|
|
|
|
if ($first)
|
1692
|
|
|
|
|
|
|
{
|
1693
|
|
|
|
|
|
|
$first=0;
|
1694
|
|
|
|
|
|
|
$gp->gmove('x',$xs+$x,'y',$ys+$y-$ccrunin,$feed);
|
1695
|
|
|
|
|
|
|
$gp->gcompr('d',$gp->{toolnumber},$gp->gmove('x',$xs+$x,'y',$ys+$y,$feed));
|
1696
|
|
|
|
|
|
|
# $gp->gmove('z',$z,$gp->{feed}); # pen down, slow feed
|
1697
|
|
|
|
|
|
|
$first=0;
|
1698
|
|
|
|
|
|
|
}
|
1699
|
|
|
|
|
|
|
else
|
1700
|
|
|
|
|
|
|
{
|
1701
|
|
|
|
|
|
|
$gp->gmove('x',$xs+$x,'y',$ys+$y,'f',$gp->{feed}); # inner circumference, 1st point
|
1702
|
|
|
|
|
|
|
$gp->gmove('z',$z,$gp->{feed}); # pen down, slow feed
|
1703
|
|
|
|
|
|
|
}
|
1704
|
|
|
|
|
|
|
# $feed=$cp->{d}*0.5-$cp->{dd};
|
1705
|
|
|
|
|
|
|
# 2nd half of tooth gap
|
1706
|
|
|
|
|
|
|
$t+=$tig/2;
|
1707
|
|
|
|
|
|
|
$x=$ri*cos($t);
|
1708
|
|
|
|
|
|
|
$y=$ri*sin($t);
|
1709
|
|
|
|
|
|
|
|
1710
|
|
|
|
|
|
|
@xy=();
|
1711
|
|
|
|
|
|
|
push(@xy,$x,$y);
|
1712
|
|
|
|
|
|
|
# $gp->garcccw('x',$x,'y',$y,'r',$ri); # to end of toothgap
|
1713
|
|
|
|
|
|
|
|
1714
|
|
|
|
|
|
|
# $x+=($ro-$ri)*cos($t+$offset)/cos($offset); # top of tooth.
|
1715
|
|
|
|
|
|
|
# $y+=($ro-$ri)*sin($t+$offset)/cos($offset);
|
1716
|
|
|
|
|
|
|
|
1717
|
|
|
|
|
|
|
# to top of tooth:
|
1718
|
|
|
|
|
|
|
|
1719
|
|
|
|
|
|
|
|
1720
|
|
|
|
|
|
|
my $td=$tt-$toothtop; # Differencce in angular size of top and bott of tooth, ensures that a tapered tooth is symetric
|
1721
|
|
|
|
|
|
|
$x=($lift+$ro)*cos($t+$offset+$td/2);
|
1722
|
|
|
|
|
|
|
$y=($lift+$ro)*sin($t+$offset+$td/2);
|
1723
|
|
|
|
|
|
|
|
1724
|
|
|
|
|
|
|
|
1725
|
|
|
|
|
|
|
|
1726
|
|
|
|
|
|
|
|
1727
|
|
|
|
|
|
|
|
1728
|
|
|
|
|
|
|
push(@xy,$x,$y); # leading edge of tooth
|
1729
|
|
|
|
|
|
|
@toothgap=();
|
1730
|
|
|
|
|
|
|
push(@toothgap,@xy); # for toothgap calculation
|
1731
|
|
|
|
|
|
|
|
1732
|
|
|
|
|
|
|
|
1733
|
|
|
|
|
|
|
@xy=$cp->rsmooth(@xy,$ri, -1*$filletradius);
|
1734
|
|
|
|
|
|
|
|
1735
|
|
|
|
|
|
|
$gp->garcccw('x',$xs+shift(@xy),'y',$ys+shift(@xy),'z',$z,'r',$ri); # to end of toothgap
|
1736
|
|
|
|
|
|
|
$gp->garccw('x',$xs+shift(@xy),'y',$ys+shift(@xy),'r',$filletradius); # draw fillet
|
1737
|
|
|
|
|
|
|
|
1738
|
|
|
|
|
|
|
|
1739
|
|
|
|
|
|
|
$x=($ro)*cos($t+$toothtop+$offset+$td/2);
|
1740
|
|
|
|
|
|
|
$y=($ro)*sin($t+$toothtop+$offset+$td/2);
|
1741
|
|
|
|
|
|
|
# print "lift=$lift, ro=$ro ri=$ri\n";
|
1742
|
|
|
|
|
|
|
|
1743
|
|
|
|
|
|
|
|
1744
|
|
|
|
|
|
|
@xy=();
|
1745
|
|
|
|
|
|
|
push(@xy,$x,$y); # 1st point of trailing edge
|
1746
|
|
|
|
|
|
|
|
1747
|
|
|
|
|
|
|
|
1748
|
|
|
|
|
|
|
$t+=$tt;
|
1749
|
|
|
|
|
|
|
$x=$ri*cos($t);
|
1750
|
|
|
|
|
|
|
$y=$ri*sin($t);
|
1751
|
|
|
|
|
|
|
|
1752
|
|
|
|
|
|
|
#$gp->gmove('x',$x,'y',$y); # draw trailing edge of tooth
|
1753
|
|
|
|
|
|
|
push(@xy,$x,$y); # 2nd point of trailing edge
|
1754
|
|
|
|
|
|
|
push(@toothgap,@xy); # for toothgap calculation
|
1755
|
|
|
|
|
|
|
|
1756
|
|
|
|
|
|
|
my $toothtopradius=$cp->ttr($gp,\@toothgap) if ($topshape eq 'semi');
|
1757
|
|
|
|
|
|
|
|
1758
|
|
|
|
|
|
|
$t+=$tig/2;
|
1759
|
|
|
|
|
|
|
$x=$ri*cos($t);
|
1760
|
|
|
|
|
|
|
$y=$ri*sin($t);
|
1761
|
|
|
|
|
|
|
|
1762
|
|
|
|
|
|
|
@xy=$cp->smooth(@xy,$ri,$filletradius);
|
1763
|
|
|
|
|
|
|
|
1764
|
|
|
|
|
|
|
shift(@xy); shift(@xy);
|
1765
|
|
|
|
|
|
|
|
1766
|
|
|
|
|
|
|
my $toothtopdist=$cp->dist(@toothgap[2..5]);
|
1767
|
|
|
|
|
|
|
my $toothradius;
|
1768
|
|
|
|
|
|
|
$toothradius=0.005*$cp->{toothradiuspc}*$toothtopdist; # 100% means half the total width of tooth.
|
1769
|
|
|
|
|
|
|
$toothradius||=$cp->{toothradius};
|
1770
|
|
|
|
|
|
|
|
1771
|
|
|
|
|
|
|
# should be flat circ bicirc circlead circtrail semi
|
1772
|
|
|
|
|
|
|
if ($topshape eq 'flat')
|
1773
|
|
|
|
|
|
|
{
|
1774
|
|
|
|
|
|
|
$gp->gmove('x',$xs+$toothgap[2],'y',$ys+$toothgap[3]); # draw leading edge of tooth
|
1775
|
|
|
|
|
|
|
$gp->gmove('x',$xs+$toothgap[4],'y',$ys+$toothgap[5]); # draw toothtop flat
|
1776
|
|
|
|
|
|
|
}
|
1777
|
|
|
|
|
|
|
elsif ($topshape eq 'circ')
|
1778
|
|
|
|
|
|
|
{
|
1779
|
|
|
|
|
|
|
$gp->gmove('x',$xs+$toothgap[2],'y',$ys+$toothgap[3]); # draw leading edge of tooth
|
1780
|
|
|
|
|
|
|
$gp->garcccw('x',$xs+$toothgap[4],'y',$ys+$toothgap[5],'r',$ro); # draw circular shaped tooth top
|
1781
|
|
|
|
|
|
|
}
|
1782
|
|
|
|
|
|
|
elsif ($topshape eq 'bicirc')
|
1783
|
|
|
|
|
|
|
{
|
1784
|
|
|
|
|
|
|
my @bc;
|
1785
|
|
|
|
|
|
|
@bc=@toothgap[0..3];
|
1786
|
|
|
|
|
|
|
@bc=$cp->smooth(@bc,$ro,-$toothradius);
|
1787
|
|
|
|
|
|
|
shift(@bc);shift(@bc);
|
1788
|
|
|
|
|
|
|
|
1789
|
|
|
|
|
|
|
$gp->gmove('x',$xs+shift(@bc),'y',$ys+shift(@bc)); # draw leading edge of tooth
|
1790
|
|
|
|
|
|
|
$gp->garcccw('x',$xs+shift(@bc),'y',$ys+shift(@bc),'r',$toothradius); # draw rounded edge
|
1791
|
|
|
|
|
|
|
@bc=@toothgap[4..7];
|
1792
|
|
|
|
|
|
|
@bc=$cp->rsmooth(@bc,$ro,$toothradius);
|
1793
|
|
|
|
|
|
|
$gp->garcccw('x',$xs+shift(@bc),'y',$ys+shift(@bc),'r',$ro); # draw circular shaped tooth top
|
1794
|
|
|
|
|
|
|
# $gp->gmove('x',$xs+shift(@bc),'y',$ys+shift(@bc); # draw flat shaped tooth top
|
1795
|
|
|
|
|
|
|
$gp->garcccw('x',$xs+shift(@bc),'y',$ys+shift(@bc),'r',$toothradius); # draw rounded edge
|
1796
|
|
|
|
|
|
|
}
|
1797
|
|
|
|
|
|
|
elsif ($topshape eq 'circlead')
|
1798
|
|
|
|
|
|
|
{
|
1799
|
|
|
|
|
|
|
my @bc;
|
1800
|
|
|
|
|
|
|
|
1801
|
|
|
|
|
|
|
$gp->gmove('x',$xs+$toothgap[2],'y',$ys+$toothgap[3]); # draw leading edge of tooth
|
1802
|
|
|
|
|
|
|
|
1803
|
|
|
|
|
|
|
@bc=@toothgap[4..7];
|
1804
|
|
|
|
|
|
|
@bc=$cp->rsmooth(@bc,$ro,$toothradius);
|
1805
|
|
|
|
|
|
|
$gp->garcccw('x',$xs+shift(@bc),'y',$ys+shift(@bc),'r',$ro); # draw circular shaped tooth top
|
1806
|
|
|
|
|
|
|
# $gp->gmove('x',$xs+shift(@bc),'y',$ys+shift(@bc)); # draw flat shaped tooth top
|
1807
|
|
|
|
|
|
|
|
1808
|
|
|
|
|
|
|
$gp->garcccw('x',$xs+shift(@bc),'y',$ys+shift(@bc),'r',$toothradius); # draw rounded edge
|
1809
|
|
|
|
|
|
|
}
|
1810
|
|
|
|
|
|
|
elsif ($topshape eq 'circtrail')
|
1811
|
|
|
|
|
|
|
{
|
1812
|
|
|
|
|
|
|
my @bc;
|
1813
|
|
|
|
|
|
|
push(@bc,@toothgap[0..3]);
|
1814
|
|
|
|
|
|
|
@bc=$cp->smooth(@bc,$ro,-$toothradius);
|
1815
|
|
|
|
|
|
|
shift(@bc);shift(@bc);
|
1816
|
|
|
|
|
|
|
|
1817
|
|
|
|
|
|
|
|
1818
|
|
|
|
|
|
|
$gp->gmove('x',$xs+shift(@bc),'y',$ys+shift(@bc)); # draw leading edge of tooth
|
1819
|
|
|
|
|
|
|
$gp->garcccw('x',$xs+shift(@bc),'y',$ys+shift(@bc),'r',$toothradius); # to end of toothgap toothgap
|
1820
|
|
|
|
|
|
|
$gp->garcccw('x',$xs+$toothgap[4],'y',$ys+$toothgap[5],'r',$ro); # draw circular shaped tooth top flat
|
1821
|
|
|
|
|
|
|
}
|
1822
|
|
|
|
|
|
|
else # if semi
|
1823
|
|
|
|
|
|
|
{
|
1824
|
|
|
|
|
|
|
$gp->gmove('x',$xs+$toothgap[2],'y',$ys+$toothgap[3]); # draw leading edge of tooth
|
1825
|
|
|
|
|
|
|
$gp->garcccw('x',$xs+$toothgap[4],'y',$ys+$toothgap[5],'r',$toothtopradius); # draw semi-circulular-type tooth top
|
1826
|
|
|
|
|
|
|
}
|
1827
|
|
|
|
|
|
|
$gp->gmove('x',$xs+shift(@xy),'y',$ys+shift(@xy));
|
1828
|
|
|
|
|
|
|
$gp->garccw('x',$xs+shift(@xy),'y',$ys+shift(@xy),'r',$filletradius); # draw fillet
|
1829
|
|
|
|
|
|
|
|
1830
|
|
|
|
|
|
|
$gp->garcccw('x',$xs+$x,'y',$ys+$y,'r',$ri); # draw 2nd half of tooth gap
|
1831
|
|
|
|
|
|
|
# $gp->gend(); exit;
|
1832
|
|
|
|
|
|
|
|
1833
|
|
|
|
|
|
|
}
|
1834
|
|
|
|
|
|
|
}
|
1835
|
|
|
|
|
|
|
|
1836
|
|
|
|
|
|
|
$gp->gmove('z',0.1);
|
1837
|
|
|
|
|
|
|
$gp->gcomp0($gp->gmove('x',$xs+$x,'y',$ys+$y+$ccrunin)); # compensation off
|
1838
|
|
|
|
|
|
|
$gp->grapid('x',$xs,'y',$ys,'f',$gp->{feed} );
|
1839
|
|
|
|
|
|
|
# $cp->cutfillet($gp,$xs,$ys,$zs,$gp->{feed},$cp->{fpasses},$cp->{fpassdepth}) if ($cp->{fillet});
|
1840
|
|
|
|
|
|
|
}
|
1841
|
|
|
|
|
|
|
|
1842
|
|
|
|
|
|
|
package Grahamyoke;
|
1843
|
|
|
|
|
|
|
use vars qw($VERSION @ISA @EXPORT);
|
1844
|
|
|
|
|
|
|
$VERSION=0.05;
|
1845
|
|
|
|
|
|
|
|
1846
|
|
|
|
|
|
|
@ISA=('Wheel');
|
1847
|
|
|
|
|
|
|
|
1848
|
|
|
|
|
|
|
sub new
|
1849
|
|
|
|
|
|
|
{
|
1850
|
|
|
|
|
|
|
my (
|
1851
|
|
|
|
|
|
|
$class,
|
1852
|
|
|
|
|
|
|
$n, # a hash reference containing other parameters
|
1853
|
|
|
|
|
|
|
)=@_;
|
1854
|
|
|
|
|
|
|
# die "$s , $n,".ref($n);
|
1855
|
|
|
|
|
|
|
my $s={};
|
1856
|
|
|
|
|
|
|
if (ref($n) eq 'HASH') # means we've been passed a hash ref
|
1857
|
|
|
|
|
|
|
{
|
1858
|
|
|
|
|
|
|
my $h=$n;
|
1859
|
|
|
|
|
|
|
|
1860
|
|
|
|
|
|
|
# leradius - leading edge radius left and right, 0 or undef for none.
|
1861
|
|
|
|
|
|
|
# droopangle - angle from horizontal of main structure of each side eof the yoke.
|
1862
|
|
|
|
|
|
|
for my $key (qw(liftl liftr lift rl rr r armwidth width innerradius outerradius topradius botradius anglel
|
1863
|
|
|
|
|
|
|
angler angle holesize leradiusl leradiusr leradius droopanglel droopangler droopangle))
|
1864
|
|
|
|
|
|
|
{
|
1865
|
|
|
|
|
|
|
$s->{$key}=$h->{$key};
|
1866
|
|
|
|
|
|
|
}
|
1867
|
|
|
|
|
|
|
}
|
1868
|
|
|
|
|
|
|
else
|
1869
|
|
|
|
|
|
|
{
|
1870
|
|
|
|
|
|
|
die "A hash reference is required for new $class got ".ref($n);
|
1871
|
|
|
|
|
|
|
}
|
1872
|
|
|
|
|
|
|
|
1873
|
|
|
|
|
|
|
|
1874
|
|
|
|
|
|
|
# and check units of linear things
|
1875
|
|
|
|
|
|
|
for my $key ( qw(r armwidth width innerradius outerradius botradius topradius holesize leradius ))
|
1876
|
|
|
|
|
|
|
{
|
1877
|
|
|
|
|
|
|
$s->{$key}=Wheel::dim(undef,$s->{$key});
|
1878
|
|
|
|
|
|
|
}
|
1879
|
|
|
|
|
|
|
|
1880
|
|
|
|
|
|
|
$s->{droopangler}||=$s->{droopangle};
|
1881
|
|
|
|
|
|
|
$s->{droopanglel}||=$s->{droopangle};
|
1882
|
|
|
|
|
|
|
$s->{angler}||=$s->{angle};
|
1883
|
|
|
|
|
|
|
$s->{anglel}||=$s->{angle};
|
1884
|
|
|
|
|
|
|
$s->{liftr}||=$s->{lift};
|
1885
|
|
|
|
|
|
|
$s->{liftl}||=$s->{lift};
|
1886
|
|
|
|
|
|
|
$s->{rl}||=$s->{r};
|
1887
|
|
|
|
|
|
|
$s->{rr}||=$s->{r};
|
1888
|
|
|
|
|
|
|
$s->{leradiusl}||=$s->{leradius};
|
1889
|
|
|
|
|
|
|
$s->{leradiusr}||=$s->{leradius};
|
1890
|
|
|
|
|
|
|
|
1891
|
|
|
|
|
|
|
|
1892
|
|
|
|
|
|
|
|
1893
|
|
|
|
|
|
|
# make sure that things that are angles have default input in degrees, but can have radians if we want.
|
1894
|
|
|
|
|
|
|
for my $key ( qw(liftl liftr anglel angler angle droopanglel droopangler))
|
1895
|
|
|
|
|
|
|
{
|
1896
|
|
|
|
|
|
|
$s->{$key}=Wheel::dimr(undef,$s->{$key});
|
1897
|
|
|
|
|
|
|
}
|
1898
|
|
|
|
|
|
|
|
1899
|
|
|
|
|
|
|
|
1900
|
|
|
|
|
|
|
my $cos=""; # cosmetic check.
|
1901
|
|
|
|
|
|
|
for my $key (qw(innerradius outerradius topradius botradius)) # these are all cosmetic, and may be specified as % in which case it is % of width
|
1902
|
|
|
|
|
|
|
{
|
1903
|
|
|
|
|
|
|
$cos.=$s->{$key};
|
1904
|
|
|
|
|
|
|
$s->{$key}*=$s->{width}/100.0 if ($s->{$key}=~s/%//);
|
1905
|
|
|
|
|
|
|
}
|
1906
|
|
|
|
|
|
|
$s->{armwidth}==0 and $s->{armwidth}=$s->{width};
|
1907
|
|
|
|
|
|
|
$s->{width}==0 and $cos=~/%/ and die "You are using % and yet width is zero. % refer to width in new grahamyolk!";
|
1908
|
|
|
|
|
|
|
|
1909
|
|
|
|
|
|
|
for my $key (qw(innerradius outerradius topradius botradius)) # these are all cosmetic, and may be specified as % in which case it is % of width
|
1910
|
|
|
|
|
|
|
{
|
1911
|
|
|
|
|
|
|
$s->{$key}*=$s->{width}/100.0 if ($s->{$key}=~s/%//);
|
1912
|
|
|
|
|
|
|
}
|
1913
|
|
|
|
|
|
|
|
1914
|
|
|
|
|
|
|
|
1915
|
|
|
|
|
|
|
|
1916
|
|
|
|
|
|
|
|
1917
|
|
|
|
|
|
|
# correction for the width of the arm, increases the angle.
|
1918
|
|
|
|
|
|
|
my $ac=0;
|
1919
|
|
|
|
|
|
|
$ac=atan2($s->{armwidth}/2,($s->{rl}+$s->{width}));
|
1920
|
|
|
|
|
|
|
$s->{anglel}+=$ac;
|
1921
|
|
|
|
|
|
|
$s->{droopanglel}-=$ac;
|
1922
|
|
|
|
|
|
|
$ac=atan2($s->{armwidth}/2,($s->{rr}+$s->{width}));
|
1923
|
|
|
|
|
|
|
$s->{angler}+=$ac;
|
1924
|
|
|
|
|
|
|
$s->{droopangler}-=$ac;
|
1925
|
|
|
|
|
|
|
|
1926
|
|
|
|
|
|
|
bless $s, $class;
|
1927
|
|
|
|
|
|
|
|
1928
|
|
|
|
|
|
|
return $s;
|
1929
|
|
|
|
|
|
|
}
|
1930
|
|
|
|
|
|
|
|
1931
|
|
|
|
|
|
|
sub definehalfyoke
|
1932
|
|
|
|
|
|
|
{
|
1933
|
|
|
|
|
|
|
my ($cp,$gp,$x,$y,$z,$theta,
|
1934
|
|
|
|
|
|
|
$width,
|
1935
|
|
|
|
|
|
|
$armwidth,
|
1936
|
|
|
|
|
|
|
$droopangle,
|
1937
|
|
|
|
|
|
|
$liftouter,
|
1938
|
|
|
|
|
|
|
$liftinner,
|
1939
|
|
|
|
|
|
|
$angle,
|
1940
|
|
|
|
|
|
|
$innerpr,
|
1941
|
|
|
|
|
|
|
$outerpr,
|
1942
|
|
|
|
|
|
|
$innerradius,
|
1943
|
|
|
|
|
|
|
$outerradius,
|
1944
|
|
|
|
|
|
|
$innerlength
|
1945
|
|
|
|
|
|
|
|
1946
|
|
|
|
|
|
|
)=@_;
|
1947
|
|
|
|
|
|
|
|
1948
|
|
|
|
|
|
|
|
1949
|
|
|
|
|
|
|
my ($xs,$ys,$zs)=($x,$y,$z);
|
1950
|
|
|
|
|
|
|
my $p=Profile->new();
|
1951
|
|
|
|
|
|
|
|
1952
|
|
|
|
|
|
|
$y+=$armwidth/2/cos($droopangle);
|
1953
|
|
|
|
|
|
|
|
1954
|
|
|
|
|
|
|
$p->ppush($x,$y);
|
1955
|
|
|
|
|
|
|
$p=$p->rotate(-$droopangle,$xs,$ys);
|
1956
|
|
|
|
|
|
|
$y=$ys+$armwidth/2;
|
1957
|
|
|
|
|
|
|
|
1958
|
|
|
|
|
|
|
|
1959
|
|
|
|
|
|
|
$p->comment("Top left or right corner");
|
1960
|
|
|
|
|
|
|
$p->ppush($x-sqrt(($innerlength+$width)**2-$armwidth*$armwidth/4),$y); # locates extreme nw corner
|
1961
|
|
|
|
|
|
|
|
1962
|
|
|
|
|
|
|
$x-=$innerlength+$width;
|
1963
|
|
|
|
|
|
|
$y-=$armwidth/2; # back onto center line
|
1964
|
|
|
|
|
|
|
|
1965
|
|
|
|
|
|
|
|
1966
|
|
|
|
|
|
|
$p=$p->rotate(-$angle-$liftouter,$xs,$ys);
|
1967
|
|
|
|
|
|
|
|
1968
|
|
|
|
|
|
|
|
1969
|
|
|
|
|
|
|
$p->comment("Outermost arc of yoke");
|
1970
|
|
|
|
|
|
|
$p->ppush($x,$y,$innerlength+$width,1);
|
1971
|
|
|
|
|
|
|
$p=$p->smooth($outerradius,$xs,$ys) if ($outerradius);
|
1972
|
|
|
|
|
|
|
|
1973
|
|
|
|
|
|
|
$p=$p->rotate(+$liftouter-$liftinner,$xs,$ys);
|
1974
|
|
|
|
|
|
|
$x+=$width;
|
1975
|
|
|
|
|
|
|
|
1976
|
|
|
|
|
|
|
$p->comment("Pallete surface");
|
1977
|
|
|
|
|
|
|
$p->ppush($x,$y);
|
1978
|
|
|
|
|
|
|
|
1979
|
|
|
|
|
|
|
|
1980
|
|
|
|
|
|
|
my $a=$angle-atan2($armwidth,2*$innerlength)+$liftinner; # This is the angle to return.
|
1981
|
|
|
|
|
|
|
# Its less than angle because we need to take off half the arm width.
|
1982
|
|
|
|
|
|
|
$p=$p->rotate($a,$xs,$ys);
|
1983
|
|
|
|
|
|
|
$p=$p->smooth($outerpr,$xs,$ys) if ($outerpr);
|
1984
|
|
|
|
|
|
|
$p->comment("Innermost arc of yoke.");
|
1985
|
|
|
|
|
|
|
$p->ppush($x,$y,$innerlength,0); # draw inner surface, curved centered on xs,ys.
|
1986
|
|
|
|
|
|
|
$p=$p->smooth($innerpr,$xs,$ys) if ($innerpr);
|
1987
|
|
|
|
|
|
|
$p=$p->rotate(atan2($armwidth,2*$innerlength),$xs,$ys);
|
1988
|
|
|
|
|
|
|
$y-=$armwidth/2/cos($droopangle);
|
1989
|
|
|
|
|
|
|
$p=$p->rotate($droopangle,$xs,$ys);
|
1990
|
|
|
|
|
|
|
$p->ppush($xs,$y);
|
1991
|
|
|
|
|
|
|
$p=$p->smooth($innerradius,$xs,$ys) if ($innerradius);
|
1992
|
|
|
|
|
|
|
$p=$p->rotate($theta,$xs,$ys) if ($theta);
|
1993
|
|
|
|
|
|
|
return $p;
|
1994
|
|
|
|
|
|
|
|
1995
|
|
|
|
|
|
|
}
|
1996
|
|
|
|
|
|
|
# graham yoke
|
1997
|
|
|
|
|
|
|
sub cut
|
1998
|
|
|
|
|
|
|
{
|
1999
|
|
|
|
|
|
|
|
2000
|
|
|
|
|
|
|
my ($cp , # Wheel , the self pointer
|
2001
|
|
|
|
|
|
|
$gp, # graphics package, either generate graphics or gcode
|
2002
|
|
|
|
|
|
|
$x,$y,$z,$theta # where to put the Wheel, and an extra rotation cw in radians
|
2003
|
|
|
|
|
|
|
)=@_;
|
2004
|
|
|
|
|
|
|
|
2005
|
|
|
|
|
|
|
|
2006
|
|
|
|
|
|
|
my $ccrunin=3*$cp->{cuttersize}; # distance used for compensation run in.
|
2007
|
|
|
|
|
|
|
my $fastfeed=3*$gp->{feed}; # faster for positioning, should really be grapid.
|
2008
|
|
|
|
|
|
|
|
2009
|
|
|
|
|
|
|
my ($xs,$ys,$zs)=($x,$y,$z); # remember initial place.
|
2010
|
|
|
|
|
|
|
$gp->gcomment("Graham Yoke at $x,$y");
|
2011
|
|
|
|
|
|
|
$gp->gmove('z',0.05,'f',$gp->{feed});
|
2012
|
|
|
|
|
|
|
$cp->cuthole($gp,$x,$y,$z,$cp->{holesize},$gp->{feed});
|
2013
|
|
|
|
|
|
|
|
2014
|
|
|
|
|
|
|
$gp->gcomment("Graham Yoke at $x,$y");
|
2015
|
|
|
|
|
|
|
$theta=$cp->dimr($theta);
|
2016
|
|
|
|
|
|
|
|
2017
|
|
|
|
|
|
|
my $rl=$cp->{rl};
|
2018
|
|
|
|
|
|
|
my $width=$cp->{width};
|
2019
|
|
|
|
|
|
|
|
2020
|
|
|
|
|
|
|
|
2021
|
|
|
|
|
|
|
my $p=$cp->definehalfyoke($gp,$x,$y,$z,$theta,
|
2022
|
|
|
|
|
|
|
$cp->{width},
|
2023
|
|
|
|
|
|
|
$cp->{armwidth},
|
2024
|
|
|
|
|
|
|
$cp->{droopanglel},
|
2025
|
|
|
|
|
|
|
$cp->{liftl},
|
2026
|
|
|
|
|
|
|
0,
|
2027
|
|
|
|
|
|
|
$cp->{anglel},
|
2028
|
|
|
|
|
|
|
$cp->{leradiusl},
|
2029
|
|
|
|
|
|
|
0,
|
2030
|
|
|
|
|
|
|
$cp->{innerradius},
|
2031
|
|
|
|
|
|
|
$cp->{outerradius},
|
2032
|
|
|
|
|
|
|
$cp->{rl}
|
2033
|
|
|
|
|
|
|
);
|
2034
|
|
|
|
|
|
|
|
2035
|
|
|
|
|
|
|
|
2036
|
|
|
|
|
|
|
print "left hand side \n";
|
2037
|
|
|
|
|
|
|
$p->print();
|
2038
|
|
|
|
|
|
|
|
2039
|
|
|
|
|
|
|
my $q=$cp->definehalfyoke($gp,$x,$y,$z,-$theta,
|
2040
|
|
|
|
|
|
|
$cp->{width},
|
2041
|
|
|
|
|
|
|
$cp->{armwidth},
|
2042
|
|
|
|
|
|
|
$cp->{droopangler},
|
2043
|
|
|
|
|
|
|
0,
|
2044
|
|
|
|
|
|
|
$cp->{liftr},
|
2045
|
|
|
|
|
|
|
$cp->{angler},
|
2046
|
|
|
|
|
|
|
0,
|
2047
|
|
|
|
|
|
|
$cp->{leradiusr},
|
2048
|
|
|
|
|
|
|
$cp->{innerradius},
|
2049
|
|
|
|
|
|
|
$cp->{outerradius},
|
2050
|
|
|
|
|
|
|
$cp->{rr}
|
2051
|
|
|
|
|
|
|
);
|
2052
|
|
|
|
|
|
|
|
2053
|
|
|
|
|
|
|
print "right hand side \n";
|
2054
|
|
|
|
|
|
|
$q->print();
|
2055
|
|
|
|
|
|
|
$q=$q->move(-$xs,0)->mirrory()->reverse()->move($xs,0);
|
2056
|
|
|
|
|
|
|
print "After flip...\n";
|
2057
|
|
|
|
|
|
|
$q->print();
|
2058
|
|
|
|
|
|
|
$p->comment("Second half-yoke");
|
2059
|
|
|
|
|
|
|
$p->ppush($q);
|
2060
|
|
|
|
|
|
|
print "After add...\n";
|
2061
|
|
|
|
|
|
|
$p->print();
|
2062
|
|
|
|
|
|
|
|
2063
|
|
|
|
|
|
|
$p->movestartfin();
|
2064
|
|
|
|
|
|
|
$p->movestartfin();
|
2065
|
|
|
|
|
|
|
|
2066
|
|
|
|
|
|
|
$p->dedupe();
|
2067
|
|
|
|
|
|
|
|
2068
|
|
|
|
|
|
|
$p->linesmooth($cp->{topradius},@{$p->{points}}-2) if ($cp->{topradius});
|
2069
|
|
|
|
|
|
|
$p->linesmooth(-$cp->{botradius},(@{$p->{points}})/2-2) if ($cp->{botradius});
|
2070
|
|
|
|
|
|
|
|
2071
|
|
|
|
|
|
|
|
2072
|
|
|
|
|
|
|
#my @first=$p->shift();
|
2073
|
|
|
|
|
|
|
my @first=$p->points(0);
|
2074
|
|
|
|
|
|
|
$gp->gmove('x',$first[0]+$ccrunin,'y',$first[1]);
|
2075
|
|
|
|
|
|
|
$gp->gcompr('d',$gp->{toolnumber},$gp->gmove('x',$first[0],'y',$first[1]));
|
2076
|
|
|
|
|
|
|
$p->plot($gp,$z,$cp->{passes},$cp->{passdepth},0);
|
2077
|
|
|
|
|
|
|
$gp->gcomp0($gp->gmove('x',$first[0]+$ccrunin,'y',$first[1]));
|
2078
|
|
|
|
|
|
|
|
2079
|
|
|
|
|
|
|
return;
|
2080
|
|
|
|
|
|
|
}
|
2081
|
|
|
|
|
|
|
|
2082
|
|
|
|
|
|
|
# end of grahamyoke
|
2083
|
|
|
|
|
|
|
#################################
|
2084
|
|
|
|
|
|
|
|
2085
|
|
|
|
|
|
|
# This is used for creating one piece of metal with 2 or more components vertically stacked on top of each other.
|
2086
|
|
|
|
|
|
|
package Stack;
|
2087
|
|
|
|
|
|
|
use vars qw($VERSION @ISA @EXPORT);
|
2088
|
|
|
|
|
|
|
$VERSION=0.05;
|
2089
|
|
|
|
|
|
|
|
2090
|
|
|
|
|
|
|
|
2091
|
|
|
|
|
|
|
sub new
|
2092
|
|
|
|
|
|
|
{
|
2093
|
|
|
|
|
|
|
my ($t,$cuttersize,$passes,$passdepth,$facedepth)=@_;
|
2094
|
|
|
|
|
|
|
my $s={};
|
2095
|
|
|
|
|
|
|
my @c;
|
2096
|
|
|
|
|
|
|
$s->{c}=\@c;
|
2097
|
|
|
|
|
|
|
$s->{cuttersize}=$cuttersize;
|
2098
|
|
|
|
|
|
|
$s->{passdepth}=$passdepth;
|
2099
|
|
|
|
|
|
|
$s->{facedepth}=$facedepth if ($facedepth);
|
2100
|
|
|
|
|
|
|
$s->{passes}=$passes;
|
2101
|
|
|
|
|
|
|
return bless $s,$t;
|
2102
|
|
|
|
|
|
|
}
|
2103
|
|
|
|
|
|
|
|
2104
|
|
|
|
|
|
|
sub add
|
2105
|
|
|
|
|
|
|
{
|
2106
|
|
|
|
|
|
|
my ($s,@c)=@_;
|
2107
|
|
|
|
|
|
|
|
2108
|
|
|
|
|
|
|
my $c=$s->{c};
|
2109
|
|
|
|
|
|
|
|
2110
|
|
|
|
|
|
|
push(@$c,@c);
|
2111
|
|
|
|
|
|
|
|
2112
|
|
|
|
|
|
|
}
|
2113
|
|
|
|
|
|
|
sub insert
|
2114
|
|
|
|
|
|
|
{
|
2115
|
|
|
|
|
|
|
my ($s,@c)=@_;
|
2116
|
|
|
|
|
|
|
|
2117
|
|
|
|
|
|
|
my $c=$s->{c};
|
2118
|
|
|
|
|
|
|
unshift(@$c,@c);
|
2119
|
|
|
|
|
|
|
}
|
2120
|
|
|
|
|
|
|
|
2121
|
|
|
|
|
|
|
sub objects
|
2122
|
|
|
|
|
|
|
{
|
2123
|
|
|
|
|
|
|
my ($s)=@_;
|
2124
|
|
|
|
|
|
|
|
2125
|
|
|
|
|
|
|
return @{$s->{c}};
|
2126
|
|
|
|
|
|
|
}
|
2127
|
|
|
|
|
|
|
|
2128
|
|
|
|
|
|
|
sub objectcount
|
2129
|
|
|
|
|
|
|
{
|
2130
|
|
|
|
|
|
|
my ($s)=@_;
|
2131
|
|
|
|
|
|
|
my $n=scalar($s->objects());
|
2132
|
|
|
|
|
|
|
return $n;
|
2133
|
|
|
|
|
|
|
}
|
2134
|
|
|
|
|
|
|
# stack
|
2135
|
|
|
|
|
|
|
sub cut
|
2136
|
|
|
|
|
|
|
{
|
2137
|
|
|
|
|
|
|
my ($s,$g,$x,$y,$zi)=@_;
|
2138
|
|
|
|
|
|
|
my (@r);
|
2139
|
|
|
|
|
|
|
my (@s);
|
2140
|
|
|
|
|
|
|
my (@f) ;
|
2141
|
|
|
|
|
|
|
my ($z);
|
2142
|
|
|
|
|
|
|
|
2143
|
|
|
|
|
|
|
my @c=$s->objects();
|
2144
|
|
|
|
|
|
|
for my $i (0..$#c)
|
2145
|
|
|
|
|
|
|
{
|
2146
|
|
|
|
|
|
|
|
2147
|
|
|
|
|
|
|
if ($i !=$#c)
|
2148
|
|
|
|
|
|
|
{
|
2149
|
|
|
|
|
|
|
printf "i is $i type %s or is %f \n",ref($c[$i]),$c[$i]->outerradius();
|
2150
|
|
|
|
|
|
|
|
2151
|
|
|
|
|
|
|
my $r=$c[$i]->{ring}=Ring->new($s->{cuttersize},$c[$i]->passes(),
|
2152
|
|
|
|
|
|
|
$c[$i]->passdepth(),$c[$i]->outerradius(),$c[$i+1]->outerradius(),
|
2153
|
|
|
|
|
|
|
$z);
|
2154
|
|
|
|
|
|
|
$r->{name}="ring4item $i";
|
2155
|
|
|
|
|
|
|
|
2156
|
|
|
|
|
|
|
$z=$zi;
|
2157
|
|
|
|
|
|
|
}
|
2158
|
|
|
|
|
|
|
}
|
2159
|
|
|
|
|
|
|
|
2160
|
|
|
|
|
|
|
$z=$zi;
|
2161
|
|
|
|
|
|
|
for my $c ($s->objects())
|
2162
|
|
|
|
|
|
|
{
|
2163
|
|
|
|
|
|
|
$c->{z}=$z;
|
2164
|
|
|
|
|
|
|
$z+=$c->passes()*$c->passdepth();
|
2165
|
|
|
|
|
|
|
}
|
2166
|
|
|
|
|
|
|
|
2167
|
|
|
|
|
|
|
# resize the non-facing cuts.
|
2168
|
|
|
|
|
|
|
|
2169
|
|
|
|
|
|
|
for my $i (0..$#c-1)
|
2170
|
|
|
|
|
|
|
{
|
2171
|
|
|
|
|
|
|
printf "Outerradius is %f\n", $c[-1]->outerradius();
|
2172
|
|
|
|
|
|
|
$c[$i]->{ring}->widen($c[-1]->outerradius()+$s->{extra}) if ($c[$i]->{ring});
|
2173
|
|
|
|
|
|
|
|
2174
|
|
|
|
|
|
|
}
|
2175
|
|
|
|
|
|
|
|
2176
|
|
|
|
|
|
|
|
2177
|
|
|
|
|
|
|
for my $c (@r,@f,$s->objects())
|
2178
|
|
|
|
|
|
|
{
|
2179
|
|
|
|
|
|
|
$c->{ring}->cut($g,$x,$y,$c->{z}) if ($c->{ring});
|
2180
|
|
|
|
|
|
|
$c->{ring}="";
|
2181
|
|
|
|
|
|
|
if ($c->{holesize} )
|
2182
|
|
|
|
|
|
|
{
|
2183
|
|
|
|
|
|
|
$c->{holedepth}+=$zi;
|
2184
|
|
|
|
|
|
|
$c->cuthole($g,$x,$y,0,$c->{holesize},$g->{feed},$s->{cuttersize});
|
2185
|
|
|
|
|
|
|
$c->{holesize}=undef;
|
2186
|
|
|
|
|
|
|
$c->{holedepth}=0.0;
|
2187
|
|
|
|
|
|
|
}
|
2188
|
|
|
|
|
|
|
}
|
2189
|
|
|
|
|
|
|
|
2190
|
|
|
|
|
|
|
for my $c (@r,@f,$s->objects())
|
2191
|
|
|
|
|
|
|
{
|
2192
|
|
|
|
|
|
|
printf "stack cut object is %s cutting at z=$c->{z}\n", ref($c);
|
2193
|
|
|
|
|
|
|
$c->cut($g,$x,$y,$c->{z});
|
2194
|
|
|
|
|
|
|
}
|
2195
|
|
|
|
|
|
|
}
|
2196
|
|
|
|
|
|
|
package CNC::Cog;
|
2197
|
|
|
|
|
|
|
use vars qw($VERSION @ISA @EXPORT);
|
2198
|
|
|
|
|
|
|
@ISA=qw(Cog);
|
2199
|
|
|
|
|
|
|
|
2200
|
|
|
|
|
|
|
package Cog;
|
2201
|
|
|
|
|
|
|
use vars qw($VERSION @ISA @EXPORT);
|
2202
|
|
|
|
|
|
|
$VERSION=0.05;
|
2203
|
|
|
|
|
|
|
|
2204
|
|
|
|
|
|
|
|
2205
|
|
|
|
|
|
|
my $inches="inches";
|
2206
|
|
|
|
|
|
|
my $f="%9f ";
|
2207
|
|
|
|
|
|
|
my $ff="%2.1f"; # for feed rate;
|
2208
|
|
|
|
|
|
|
|
2209
|
|
|
|
|
|
|
sub newcogpair
|
2210
|
|
|
|
|
|
|
{
|
2211
|
|
|
|
|
|
|
my ($this,$m,$np,$nw)=@_;
|
2212
|
|
|
|
|
|
|
my ($dpi);
|
2213
|
|
|
|
|
|
|
|
2214
|
|
|
|
|
|
|
($m,$np,$nw,$dpi)=map { $m->{$_} } ('module','np','nw','pitch','dpi') if (ref($m) eq 'HASH');
|
2215
|
|
|
|
|
|
|
$m=1/($dpi*$mm) if (!defined($m) and defined ($dpi));
|
2216
|
|
|
|
|
|
|
|
2217
|
|
|
|
|
|
|
@_==4 or main::confess("wrong number of paremeters");
|
2218
|
|
|
|
|
|
|
my $cogpair=bless {};
|
2219
|
|
|
|
|
|
|
|
2220
|
|
|
|
|
|
|
my ($w,$p);
|
2221
|
|
|
|
|
|
|
|
2222
|
|
|
|
|
|
|
$w=$cogpair->{wheel}=Wheel->new($m,$nw);
|
2223
|
|
|
|
|
|
|
$p=$cogpair->{pinion}=Wheel->new($m,$np);
|
2224
|
|
|
|
|
|
|
my $af=$cogpair->{af}=addendumFactor($np,$nw);
|
2225
|
|
|
|
|
|
|
|
2226
|
|
|
|
|
|
|
$p->{pa}=$w->{pa}=$cogpair->{pa}=0.95*$af; #practical addendum factor
|
2227
|
|
|
|
|
|
|
$cogpair->{gr}=$np/$nw;#gear ratio
|
2228
|
|
|
|
|
|
|
$p->{cp}=$w->{cp}=$cogpair->{cp} = $m * $pi ; # circular pitch
|
2229
|
|
|
|
|
|
|
$w->{dd}=$cogpair->{dd} = $m * $pi/2 ;
|
2230
|
|
|
|
|
|
|
$p->{dd}=$m*($af*0.95+0.4); # BSI rule for dd height for pinion.
|
2231
|
|
|
|
|
|
|
$w->{dw}=$cogpair->{dw} = $m * $nw ;
|
2232
|
|
|
|
|
|
|
$p->{dw}=$cogpair->{dp} = $m * $np ;
|
2233
|
|
|
|
|
|
|
# $p->{ad}=$w->{ad}=$cogpair->{ad} = $m * 0.95 * $af ;
|
2234
|
|
|
|
|
|
|
$w->{ad}=$cogpair->{ad} = $m * 0.95 * $af ;
|
2235
|
|
|
|
|
|
|
$w->{ar}=$cogpair->{ar} = $m * 1.40 * $af ;
|
2236
|
|
|
|
|
|
|
$w->{twf}=1.0; # tooth width factor
|
2237
|
|
|
|
|
|
|
|
2238
|
|
|
|
|
|
|
if ($p->{n}>=10)
|
2239
|
|
|
|
|
|
|
{
|
2240
|
|
|
|
|
|
|
# pinion profile A
|
2241
|
|
|
|
|
|
|
$p->{ar}=$m*0.525 ;
|
2242
|
|
|
|
|
|
|
$p->{ad}=$m*0.525;
|
2243
|
|
|
|
|
|
|
}
|
2244
|
|
|
|
|
|
|
elsif ($p->{n}==8 or $p->{n}==9)
|
2245
|
|
|
|
|
|
|
{
|
2246
|
|
|
|
|
|
|
# profile B.
|
2247
|
|
|
|
|
|
|
$p->{ar}=$m*0.70 ;
|
2248
|
|
|
|
|
|
|
$p->{ad}=$m*0.67;
|
2249
|
|
|
|
|
|
|
}
|
2250
|
|
|
|
|
|
|
elsif ($p->{n}==6 or $p->{n}==7)
|
2251
|
|
|
|
|
|
|
{
|
2252
|
|
|
|
|
|
|
# profile C
|
2253
|
|
|
|
|
|
|
$p->{ar}=$m*1.05;
|
2254
|
|
|
|
|
|
|
$p->{ad}=$m*0.855;
|
2255
|
|
|
|
|
|
|
}
|
2256
|
|
|
|
|
|
|
if ($p->{n}>=11) # set up special tooth width profile for pinion.
|
2257
|
|
|
|
|
|
|
{
|
2258
|
|
|
|
|
|
|
$p->{twf}=1.25/1.57;
|
2259
|
|
|
|
|
|
|
}
|
2260
|
|
|
|
|
|
|
else
|
2261
|
|
|
|
|
|
|
{
|
2262
|
|
|
|
|
|
|
$p->{twf}=1.05/1.57;
|
2263
|
|
|
|
|
|
|
}
|
2264
|
|
|
|
|
|
|
|
2265
|
|
|
|
|
|
|
$w->{mm}=$p->{mm}=$cogpair->{mm} = 1.0/25.4; # 1.0/24.8;
|
2266
|
|
|
|
|
|
|
$cogpair->{nw}=$nw;
|
2267
|
|
|
|
|
|
|
$cogpair->{np}=$np;
|
2268
|
|
|
|
|
|
|
|
2269
|
|
|
|
|
|
|
return $cogpair;
|
2270
|
|
|
|
|
|
|
}
|
2271
|
|
|
|
|
|
|
|
2272
|
|
|
|
|
|
|
sub addendumFactor
|
2273
|
|
|
|
|
|
|
{
|
2274
|
|
|
|
|
|
|
my ($np,$nw)=@_;
|
2275
|
|
|
|
|
|
|
my $b = 0.0 ;
|
2276
|
|
|
|
|
|
|
my $t0 = 1.0 ;
|
2277
|
|
|
|
|
|
|
my $t1 = 0.0 ;
|
2278
|
|
|
|
|
|
|
my $r2 = 2 * $nw/$np ;
|
2279
|
|
|
|
|
|
|
my $errorLimit=0.000001;
|
2280
|
|
|
|
|
|
|
$pi or die "pi is not set!";
|
2281
|
|
|
|
|
|
|
while (abs($t1 - $t0) > $errorLimit)
|
2282
|
|
|
|
|
|
|
{ $t0 = $t1;
|
2283
|
|
|
|
|
|
|
$b = atan2(sin($t0), (1 + $r2 - cos($t0))) ;
|
2284
|
|
|
|
|
|
|
$t1 = $pi/$np + $r2 * $b ;
|
2285
|
|
|
|
|
|
|
}
|
2286
|
|
|
|
|
|
|
return 0.25 * $np * (sin($t1)/sin($b) - $r2);
|
2287
|
|
|
|
|
|
|
}
|
2288
|
|
|
|
|
|
|
# cog
|
2289
|
|
|
|
|
|
|
# set up some default parameters: carry these through to the individuel wheels.
|
2290
|
|
|
|
|
|
|
sub cutset
|
2291
|
|
|
|
|
|
|
{
|
2292
|
|
|
|
|
|
|
my ($cp)=shift(@_);
|
2293
|
|
|
|
|
|
|
|
2294
|
|
|
|
|
|
|
$cp->{wheel}->cutset(@_);
|
2295
|
|
|
|
|
|
|
$cp->{pinion}->cutset(@_);
|
2296
|
|
|
|
|
|
|
return $cp;
|
2297
|
|
|
|
|
|
|
}
|
2298
|
|
|
|
|
|
|
|
2299
|
|
|
|
|
|
|
##### end of package cog
|
2300
|
|
|
|
|
|
|
|
2301
|
|
|
|
|
|
|
package Ring;
|
2302
|
|
|
|
|
|
|
use vars qw($VERSION @ISA @EXPORT);
|
2303
|
|
|
|
|
|
|
$VERSION=0.05;
|
2304
|
|
|
|
|
|
|
|
2305
|
|
|
|
|
|
|
@ISA=qw(Wheel);
|
2306
|
|
|
|
|
|
|
sub outerradius
|
2307
|
|
|
|
|
|
|
{
|
2308
|
|
|
|
|
|
|
|
2309
|
|
|
|
|
|
|
my ($c) =@_;
|
2310
|
|
|
|
|
|
|
if ($c->{r1}<$c->{r2})
|
2311
|
|
|
|
|
|
|
{
|
2312
|
|
|
|
|
|
|
return $c->{r2};
|
2313
|
|
|
|
|
|
|
}
|
2314
|
|
|
|
|
|
|
else
|
2315
|
|
|
|
|
|
|
{
|
2316
|
|
|
|
|
|
|
return $c->{r1};
|
2317
|
|
|
|
|
|
|
}
|
2318
|
|
|
|
|
|
|
}
|
2319
|
|
|
|
|
|
|
sub innerradius
|
2320
|
|
|
|
|
|
|
{
|
2321
|
|
|
|
|
|
|
my ($c)=@_;
|
2322
|
|
|
|
|
|
|
if ($c->{r1}<$c->{r2})
|
2323
|
|
|
|
|
|
|
{
|
2324
|
|
|
|
|
|
|
return $c->{r1};
|
2325
|
|
|
|
|
|
|
}
|
2326
|
|
|
|
|
|
|
else
|
2327
|
|
|
|
|
|
|
{
|
2328
|
|
|
|
|
|
|
return $c->{r2};
|
2329
|
|
|
|
|
|
|
}
|
2330
|
|
|
|
|
|
|
}
|
2331
|
|
|
|
|
|
|
|
2332
|
|
|
|
|
|
|
# ring
|
2333
|
|
|
|
|
|
|
# cal as either t,$cuttersize,$passes,$passdepth,$r1,$r2,$z (pld style)
|
2334
|
|
|
|
|
|
|
# or hash containing
|
2335
|
|
|
|
|
|
|
sub new
|
2336
|
|
|
|
|
|
|
{
|
2337
|
|
|
|
|
|
|
my ($t,$cuttersize,$passes,$passdepth,$r1,$r2,$z)=@_; # die "$s , $n,".ref($n);
|
2338
|
|
|
|
|
|
|
|
2339
|
|
|
|
|
|
|
my $s={};
|
2340
|
|
|
|
|
|
|
|
2341
|
|
|
|
|
|
|
my $h=$cuttersize; # might be has or cuttersize at this stage, we dont know.
|
2342
|
|
|
|
|
|
|
|
2343
|
|
|
|
|
|
|
if (ref($h) eq 'HASH') # means we've been passed a hash ref
|
2344
|
|
|
|
|
|
|
{
|
2345
|
|
|
|
|
|
|
for my $key (qw(cuttersize passdepth r1 r2 z holesize holedepth holepassdepth))
|
2346
|
|
|
|
|
|
|
{
|
2347
|
|
|
|
|
|
|
$h->{$key}=Wheel::dim(undef,$h->{$key});
|
2348
|
|
|
|
|
|
|
}
|
2349
|
|
|
|
|
|
|
for my $key (qw(cuttersize passes passdepth r1 r2 z holesize holedepth holepasses holepassdepth))
|
2350
|
|
|
|
|
|
|
{
|
2351
|
|
|
|
|
|
|
$s->{$key}=$h->{$key};
|
2352
|
|
|
|
|
|
|
}
|
2353
|
|
|
|
|
|
|
|
2354
|
|
|
|
|
|
|
# if holesize is defined, there willl be a hole at the center.
|
2355
|
|
|
|
|
|
|
# need to get holepasses and holepassdepth which we actually use.
|
2356
|
|
|
|
|
|
|
|
2357
|
|
|
|
|
|
|
if (!defined($s->{holedepth})) # and !defined($s->{holepasses} and !defined($s->{holepassdepth})
|
2358
|
|
|
|
|
|
|
{
|
2359
|
|
|
|
|
|
|
$s->{holepassdepth}||=$s->{passdepth};
|
2360
|
|
|
|
|
|
|
$s->{holepasses}||=$s->{passes};
|
2361
|
|
|
|
|
|
|
}
|
2362
|
|
|
|
|
|
|
elsif (defined($s->{holedepth}) and !defined($s->{holepasses})) # holepassdepth def or undef
|
2363
|
|
|
|
|
|
|
{
|
2364
|
|
|
|
|
|
|
|
2365
|
|
|
|
|
|
|
$s->{holepassdepth}||=$s->{passdepth}; # provisional.
|
2366
|
|
|
|
|
|
|
$s->{holepasses}=abs($s->{holedepth}/$s->{holepassdepth});
|
2367
|
|
|
|
|
|
|
$s->{holepasses}=int($s->{holepasses})+1 if ($s->{holepasses}!=int($s->{holepasses}));
|
2368
|
|
|
|
|
|
|
$s->{holepassdepth}=-abs($s->{holedepth})/$s->{holepasses};
|
2369
|
|
|
|
|
|
|
}
|
2370
|
|
|
|
|
|
|
elsif (defined($s->{holedepth}) and defined($s->{holepasses})) # ignore passdepth even if provided. and !defined($s->{holepassdepth})
|
2371
|
|
|
|
|
|
|
{
|
2372
|
|
|
|
|
|
|
$s->{holepassdepth}=-abs($s->{holedepth})/$s->{holepasses};
|
2373
|
|
|
|
|
|
|
}
|
2374
|
|
|
|
|
|
|
|
2375
|
|
|
|
|
|
|
if ($s->{holesize})
|
2376
|
|
|
|
|
|
|
{
|
2377
|
|
|
|
|
|
|
my $hole=Hole->new($s->{cuttersize},$s->{holepasses},$s->{holepassdepth},$s->{holesize});
|
2378
|
|
|
|
|
|
|
$s->{hole}=$hole;
|
2379
|
|
|
|
|
|
|
map { delete $s->{$_} } qw( holesize holedepth holepasses holepassdepth );
|
2380
|
|
|
|
|
|
|
}
|
2381
|
|
|
|
|
|
|
|
2382
|
|
|
|
|
|
|
}
|
2383
|
|
|
|
|
|
|
else
|
2384
|
|
|
|
|
|
|
{
|
2385
|
|
|
|
|
|
|
$s->{cuttersize}=Wheel::dim(undef,$cuttersize);
|
2386
|
|
|
|
|
|
|
$s->{passes}=$passes;
|
2387
|
|
|
|
|
|
|
$s->{passdepth}=Wheel::dim(undef,$passdepth);
|
2388
|
|
|
|
|
|
|
$s->{r1}=Wheel::dim(undef,$r1);
|
2389
|
|
|
|
|
|
|
$s->{r2}=Wheel::dim(undef,$r2);
|
2390
|
|
|
|
|
|
|
print "ring new r1 is $r1 r2 is $r2\n";
|
2391
|
|
|
|
|
|
|
$s->{z}=$z if (defined($z));;
|
2392
|
|
|
|
|
|
|
}
|
2393
|
|
|
|
|
|
|
$s= bless $s,$t;
|
2394
|
|
|
|
|
|
|
print "new ring s is $s\n";
|
2395
|
|
|
|
|
|
|
return $s;
|
2396
|
|
|
|
|
|
|
}
|
2397
|
|
|
|
|
|
|
# ring
|
2398
|
|
|
|
|
|
|
sub widen
|
2399
|
|
|
|
|
|
|
{
|
2400
|
|
|
|
|
|
|
my ($s,$r)=@_;
|
2401
|
|
|
|
|
|
|
|
2402
|
|
|
|
|
|
|
if ($s->{r2}>$s->{r1} and $s->{r2}<$r)
|
2403
|
|
|
|
|
|
|
{
|
2404
|
|
|
|
|
|
|
$s->{r2}=$r;
|
2405
|
|
|
|
|
|
|
}
|
2406
|
|
|
|
|
|
|
elsif ($s->{r1}>$s->{r2} and $s->{r1}<$r)
|
2407
|
|
|
|
|
|
|
{
|
2408
|
|
|
|
|
|
|
$s->{r1}=$r;
|
2409
|
|
|
|
|
|
|
}
|
2410
|
|
|
|
|
|
|
return $r;
|
2411
|
|
|
|
|
|
|
}
|
2412
|
|
|
|
|
|
|
sub setr2
|
2413
|
|
|
|
|
|
|
{
|
2414
|
|
|
|
|
|
|
my ($s,$r)=@_;
|
2415
|
|
|
|
|
|
|
print "r2 on $s->{name} changed from $s->{r2} to $r\n";
|
2416
|
|
|
|
|
|
|
$s->{r2}=$r;
|
2417
|
|
|
|
|
|
|
return $r;
|
2418
|
|
|
|
|
|
|
}
|
2419
|
|
|
|
|
|
|
sub setr1
|
2420
|
|
|
|
|
|
|
{
|
2421
|
|
|
|
|
|
|
my ($s,$r)=@_;
|
2422
|
|
|
|
|
|
|
print "r2 on $s->{name} changed from $s->{r1} to $r\n";
|
2423
|
|
|
|
|
|
|
$s->{r1}=$r;
|
2424
|
|
|
|
|
|
|
return $r;
|
2425
|
|
|
|
|
|
|
}
|
2426
|
|
|
|
|
|
|
# ring
|
2427
|
|
|
|
|
|
|
sub cut
|
2428
|
|
|
|
|
|
|
# The purose of this function is to create an integral boss, and face off the material underneath os that the teeth can be cut.
|
2429
|
|
|
|
|
|
|
# Youll need a thick piece of material to use this as the material has to be thick enough both for the boss and the wheel.
|
2430
|
|
|
|
|
|
|
# Its appropriate particularly for pinions.
|
2431
|
|
|
|
|
|
|
# face off a circular area in steps of a half cutter radius
|
2432
|
|
|
|
|
|
|
{
|
2433
|
|
|
|
|
|
|
my ($c,$g,$x,$y,$z)=@_;
|
2434
|
|
|
|
|
|
|
# variables are
|
2435
|
|
|
|
|
|
|
# ring object
|
2436
|
|
|
|
|
|
|
# (graphics object),
|
2437
|
|
|
|
|
|
|
# where to center(x,y),
|
2438
|
|
|
|
|
|
|
# where to start in z plane, often z=0 is appropriate
|
2439
|
|
|
|
|
|
|
# what cut to take in z plane on each pass, normally negative
|
2440
|
|
|
|
|
|
|
# how many passes,
|
2441
|
|
|
|
|
|
|
# final radius,
|
2442
|
|
|
|
|
|
|
# initial radius, make bigger than final radius to start outside.
|
2443
|
|
|
|
|
|
|
# cuttersize (diameter) and
|
2444
|
|
|
|
|
|
|
# units are all inches.
|
2445
|
|
|
|
|
|
|
|
2446
|
|
|
|
|
|
|
|
2447
|
|
|
|
|
|
|
printf "calling cut on a %s name is %s r1 is %f r2 is %f\n",ref($c),$c->{name},$c->{r1},$c->{r2};
|
2448
|
|
|
|
|
|
|
|
2449
|
|
|
|
|
|
|
$g->grapid('z',0.1);
|
2450
|
|
|
|
|
|
|
|
2451
|
|
|
|
|
|
|
my $dd=abs($c->{r1}- $c->{r2});
|
2452
|
|
|
|
|
|
|
die "Anulus too narrow for toolsize r1 is $c->{r1} r2 is $c->{r2} \nanulus size is $dd toolsize is $c->{cuttersize}"
|
2453
|
|
|
|
|
|
|
if (abs($c->{r2}-$c->{r1})<$c->{cuttersize});
|
2454
|
|
|
|
|
|
|
die "Need to have a cuttersize" if ($c->{cuttersize}<=0);
|
2455
|
|
|
|
|
|
|
|
2456
|
|
|
|
|
|
|
my $step;
|
2457
|
|
|
|
|
|
|
my ($r1,$r2);
|
2458
|
|
|
|
|
|
|
$r1=$c->{r1};
|
2459
|
|
|
|
|
|
|
$r2=$c->{r2};
|
2460
|
|
|
|
|
|
|
if ($c->{r1}<$c->{r2})
|
2461
|
|
|
|
|
|
|
{
|
2462
|
|
|
|
|
|
|
$r2=$r2-$c->{cuttersize}/2; # calculate compensated radii, compensated for tool radius.
|
2463
|
|
|
|
|
|
|
$r1=$c->{r1}+$c->{cuttersize}/2;
|
2464
|
|
|
|
|
|
|
$step=$c->{cuttersize}/2;
|
2465
|
|
|
|
|
|
|
}
|
2466
|
|
|
|
|
|
|
else
|
2467
|
|
|
|
|
|
|
{
|
2468
|
|
|
|
|
|
|
$r2=$r2+$c->{cuttersize}/2; # calculate compensated radii, compensated for tool radius.
|
2469
|
|
|
|
|
|
|
$r1=$c->{r1}-$c->{cuttersize}/2;
|
2470
|
|
|
|
|
|
|
$step= -$c->{cuttersize}/2;
|
2471
|
|
|
|
|
|
|
}
|
2472
|
|
|
|
|
|
|
|
2473
|
|
|
|
|
|
|
$g->gcomment("cutting hole");
|
2474
|
|
|
|
|
|
|
$c->{hole}->cut($g,$x,$y,$z) if ($c->{hole});
|
2475
|
|
|
|
|
|
|
$g->gcomment("hole done");
|
2476
|
|
|
|
|
|
|
|
2477
|
|
|
|
|
|
|
my $pass=0;
|
2478
|
|
|
|
|
|
|
while ($pass++<$c->{passes})
|
2479
|
|
|
|
|
|
|
{
|
2480
|
|
|
|
|
|
|
$z+=$c->{passdepth};
|
2481
|
|
|
|
|
|
|
$g->gcomment("Cutting Anulus $pass of $c->{passes}");
|
2482
|
|
|
|
|
|
|
# $g->gmove('x',$x,'y',$y,'z',$z,'f',$feed);
|
2483
|
|
|
|
|
|
|
my $r=$r1-$step; # compensate for re-increment in 1st pass.
|
2484
|
|
|
|
|
|
|
while (($r+$step<$r2)==($r<$r2))
|
2485
|
|
|
|
|
|
|
{
|
2486
|
|
|
|
|
|
|
$r+=$step;
|
2487
|
|
|
|
|
|
|
$g->gcomment("Radius is $r ");
|
2488
|
|
|
|
|
|
|
$g->gmove('x',$x+$r,'y',$y,'f',$g->{feed});
|
2489
|
|
|
|
|
|
|
$g->gmove('z',$z);
|
2490
|
|
|
|
|
|
|
$g->garccw('x',$x-$r,'y',$y,'r',$r);
|
2491
|
|
|
|
|
|
|
$g->garccw('x',$x+$r,'y',$y,'r',$r);
|
2492
|
|
|
|
|
|
|
}
|
2493
|
|
|
|
|
|
|
|
2494
|
|
|
|
|
|
|
my $laststep=$r2-$r;
|
2495
|
|
|
|
|
|
|
if ($laststep>0)
|
2496
|
|
|
|
|
|
|
{
|
2497
|
|
|
|
|
|
|
$r+=$laststep;
|
2498
|
|
|
|
|
|
|
$g->gcomment("Final radius is $r");
|
2499
|
|
|
|
|
|
|
$g->gmove('x',$x+$r,'y',$y,'f',$g->{feed});
|
2500
|
|
|
|
|
|
|
$g->gmove('z',$z);
|
2501
|
|
|
|
|
|
|
$g->garccw('x',$x-$r,'y',$y,'r',$r);
|
2502
|
|
|
|
|
|
|
$g->garccw('x',$x+$r,'y',$y,'r',$r);
|
2503
|
|
|
|
|
|
|
}
|
2504
|
|
|
|
|
|
|
}
|
2505
|
|
|
|
|
|
|
$g->grapid('z',0.1);
|
2506
|
|
|
|
|
|
|
}
|
2507
|
|
|
|
|
|
|
|
2508
|
|
|
|
|
|
|
package Boss;
|
2509
|
|
|
|
|
|
|
use vars qw($VERSION @ISA @EXPORT);
|
2510
|
|
|
|
|
|
|
$VERSION=0.061;
|
2511
|
|
|
|
|
|
|
|
2512
|
|
|
|
|
|
|
|
2513
|
|
|
|
|
|
|
sub new
|
2514
|
|
|
|
|
|
|
{
|
2515
|
|
|
|
|
|
|
my ($t,$cuttersize,$passes,$passdepth,$radius)=@_;
|
2516
|
|
|
|
|
|
|
my $b={};
|
2517
|
|
|
|
|
|
|
print "boss new $radius, $cuttersize\n";
|
2518
|
|
|
|
|
|
|
$b->{ring}=Ring::new($t,$cuttersize,$passes,$passdepth,$radius,$radius+$cuttersize);
|
2519
|
|
|
|
|
|
|
return bless $b,$t;
|
2520
|
|
|
|
|
|
|
}
|
2521
|
|
|
|
|
|
|
sub passes
|
2522
|
|
|
|
|
|
|
{
|
2523
|
|
|
|
|
|
|
my ($b)=@_;
|
2524
|
|
|
|
|
|
|
return $b->{ring}->{passes};
|
2525
|
|
|
|
|
|
|
}
|
2526
|
|
|
|
|
|
|
sub passdepth
|
2527
|
|
|
|
|
|
|
{
|
2528
|
|
|
|
|
|
|
my ($b)=@_;
|
2529
|
|
|
|
|
|
|
return $b->{ring}->{passdepth};
|
2530
|
|
|
|
|
|
|
}
|
2531
|
|
|
|
|
|
|
# boss
|
2532
|
|
|
|
|
|
|
sub outerradius
|
2533
|
|
|
|
|
|
|
{
|
2534
|
|
|
|
|
|
|
my ($b)=@_;
|
2535
|
|
|
|
|
|
|
|
2536
|
|
|
|
|
|
|
return $b->{ring}->{r2}>$b->{ring}->{r1}?$b->{ring}->{r1}:$b->{ring}->{r2}; # size of remaining metal.
|
2537
|
|
|
|
|
|
|
}
|
2538
|
|
|
|
|
|
|
sub innerradius
|
2539
|
|
|
|
|
|
|
{
|
2540
|
|
|
|
|
|
|
my ($b)=@_;
|
2541
|
|
|
|
|
|
|
return $b->{ring}->{r2}>$b->{ring}->{r1}?$b->{ring}->{r1}:$b->{ring}->{r2}; # size of remaining metal.
|
2542
|
|
|
|
|
|
|
}
|
2543
|
|
|
|
|
|
|
# boss
|
2544
|
|
|
|
|
|
|
sub cut
|
2545
|
|
|
|
|
|
|
{
|
2546
|
|
|
|
|
|
|
my ($b,$g,$x,$y,$z)=@_;
|
2547
|
|
|
|
|
|
|
|
2548
|
|
|
|
|
|
|
$b->{ring}->cut($g,$x,$y,$z) if ($b->{ring});
|
2549
|
|
|
|
|
|
|
}
|
2550
|
|
|
|
|
|
|
|
2551
|
|
|
|
|
|
|
package Hole;
|
2552
|
|
|
|
|
|
|
use vars qw($VERSION @ISA @EXPORT);
|
2553
|
|
|
|
|
|
|
$VERSION=0.05;
|
2554
|
|
|
|
|
|
|
|
2555
|
|
|
|
|
|
|
@ISA=('Ring');
|
2556
|
|
|
|
|
|
|
sub new
|
2557
|
|
|
|
|
|
|
{
|
2558
|
|
|
|
|
|
|
my ($t,$cuttersize,$passes,$passdepth,$diameter)=@_;
|
2559
|
|
|
|
|
|
|
# return bless SUPER::new($t,$cuttersize,$passes,$passdepth,$bosssize,0),$t;
|
2560
|
|
|
|
|
|
|
return bless Ring::new($t,$cuttersize,$passes,$passdepth,$diameter/2,0),$t;
|
2561
|
|
|
|
|
|
|
}
|
2562
|
|
|
|
|
|
|
|
2563
|
|
|
|
|
|
|
1;
|
2564
|
|
|
|
|
|
|
__END__
|