CNC-Cog
view release on metacpan or search on metacpan
$gp->gmove('x',$tx+$xi,'y',$ty+$yi);
$gp->gmove('x',$x+$xi,'y',$y+$yi,'z',$z,'f',$feed);
$x+=$dx/2; # this takes us to next addendum point
$y+=$dy/2;
}
}
$gp->gmove('z',0.1);
$gp->gmove('x',$xi,'y',$yi);
}
sub smooth
{
# given a circle radius b and a point on circumference l2
# the plan is to smooth the join between the line l1/l2 (each of these are points) and the circle circumference by
# replacing a bit of the line l1/l2 with a circle of radius r.
# The following are supplied where x1 y1 is l1 point 1, x2, y2 point 2 or l2.
# so call with l1,l2,b ,r
# what comes back is l1 (unchanged), ,replacement l2 point sa which is start of arc, l1,sa are on the line
# l1,l2 but sa is nearer l1 than l2.
# ea where ea is on the original arc radius b, like l2, but is moved away from original l2.
# sa, ea can be joined with arc radius b.
my ($w,$x1,$y1,$x2,$y2,$b,$r)=@_;
# print "smooth x1=$x1,y1=$y1,x2=$x2,y2=$y2,b=$b,r=$r\n";
#($x1,$y1,$x2,$y2,$b,$r)=(-0.2 , 0.2 , -0.707 , 0.707 , 1.0 , 0.1);
# ($x1,$y1,$x2,$y2,$b,$r)= (-0.279378067455943, 0.65017874253593, 0.702760341741972, 0.0831408677831007, 0.9,0.1);
my $ks;
# straight line l1 l2 has eqn y=mx+c
my $m=($y2-$y1)/($x2-$x1);
my $c=$y1-($y2-$y1)*$x1/($x2-$x1);
$ks=$r>0?1:-1;
# $ks=-$ks if ($y2>0);
$r=abs($r);
$ks=-$ks if ($x1<$x2);
# line paralell to this and distance r away is y=mx+j where j=c+k or j=c-k
my $k = abs($r) * sqrt( (($x2-$x1)**2+($y2-$y1)**2)/($x2-$x1)**2);
my $j=$c+$k*$ks; # ks is the sign of k from above.
# we need to solve this with the circle x^2+y^2=(b+r)^2
# substituting for y in here gives
#
# x^2+y^2=(b+r)^2
# y=mx+j
# x^2+m^2x^2+2mxj+j^2=(b+r)^2
# (1+m^2) x^2 + 2mj x +j^2-(b+r)^2=0
# use quadratic equation formula to find x:
# x=(-b+- sqrt(b^2-4ac)/2a
#
# x=(-2mj +- sqrt(4m^2j^2-4(1+m^2)(j^2-(b+r)^2)))/2(1+m^2)
# This is the center point of the arc.
# s is the distance between c and l2, we now have x and y coords for both c and l2.
# 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.
# The end of the arc is oc scaled such that distance is b, the radius of the circle.
$r=-$r if (dist(0,0,$x1,$y1)<$b);
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);
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.
# use the one closest to l2?
my $cya=$m*$cxa+$j;
my $cyb=$m*$cxb+$j;
($cxa,$cya,$cxb,$cyb)=($cxb,$cyb,$cxa,$cya) if (dist($x2,$y2,$cxb,$cyb)<dist($x2,$y2,$cxa,$cya)); # want nearest root to l2 .
# swap rather than assign so that we still have the other root if we need to look at it for debug purposes.
my $s=dist($x2,$y2,$cxa,$cya);
my $u=sqrt($s**2-$r**2);
my $sax=$x2+($x1-$x2)*$u/dist($x1,$y1,$x2,$y2); #start of arc
my $say=$y2+($y1-$y2)*$u/dist($x1,$y1,$x2,$y2);
my $eax=$cxa*$b/dist(0,0,$cxa,$cya);
my $eay=$cya*$b/dist(0,0,$cxa,$cya);
return ($x1,$y1,$sax,$say,$eax,$eay); #ending on the circle
# The code below is used for graphing out test cases. Its debug only.
my $gd=gdcode::new(undef,"test.png",6.0,2500,2500);
$gd->gmove('z',0.1);
$gd->gmove('x',$x1,'y',$y1);
$gd->gmove('z',-0.1);
$gd->gmove('x',$x2,'y',$y2);
$gd->gmove('z',0.1);
$gd->gmove('x',0,'y',$b);
$gd->gmove('z',-0.1);
$gd->garcccw('x',0,'y',-$b,'r',$b);
$gd->garcccw('x',0,'y',$b,'r',$b);
$gd->gmove('z',0.1);
# ($cxa,$cya)=($cxb,$cyb); # want to see the other one ?
$gd->gmove('x',$cxa+0.05,'y',$cya+0.05); # mark the center with an X
$gd->gmove('x',$cxa-0.05,'y',$cya-0.05,'z',-0.1);
$gd->gmove('x',$cxa+0.05,'y',$cya-0.05,'z',0.1);
$gd->gmove('x',$cxa-0.05,'y',$cya+0.05,'z',-0.1);
# $gd->gmove('x',$cxa,'y',$cya+$r,'z',0.1);
# $gd->garcccw('x',$cxa,'y',$cya-$r,'r',abs($r),'z',-0.1);
# $gd->garcccw('x',$cxa,'y',$cya+$r,'r',abs($r),'z',-0.1);
$gd->gmove('x',$sax,'y',$say,'z',0.1);
$gd->garccw('x',$eax,'y',$eay,'r',abs($r),'z',-0.1);
$gd->gend();
die;
( run in 0.941 second using v1.01-cache-2.11-cpan-870870ed90f )