#!/usr/bin/perl # helper package for gdcode Does scaling etc. # note that this is not used when generating gcode, only when generating jpegs. package scale; $VERSION=0.01; my $pi=3.1415926; sub new { my $s={}; $s->{ox}=$s->{oy}=0; $s->{s}=1.0; return bless $s; } sub setorigin { my ($s,$x,$y)=@_; $s->{ox}=$x; $s->{oy}=$y; } sub setpixelorigin { my ($s,$x,$y)=@_; $s->{pox}=$x; $s->{poy}=$y; } sub setscale { my ($s,$scale,$xsize,$ysize)=@_; $s->{s}=$xsize/$scale; $s->{xsize}=$xsize; $s->{ysize}=$ysize; $s->{pox}=$xsize/2; $s->{poy}=$ysize/2; } sub scalexy { my $s=shift(@_); my (@xyus)=@_; # unscaled xy pairs my @xys; # scaled xy pairs # print "scalexy b4 is @xyus\n"; while (@xyus) { my $x=$xyus[0]; my $y=$xyus[1]; push(@xys, (int(0.5+($x-$s->{ox})*$s->{s})+$s->{pox}),int(0.5+(($y-$s->{oy})*$s->{s})+$s->{poy})); shift(@xyus); shift(@xyus); } # print "scalexy after is @xys\n"; return (@xys); } sub scaled # scale a distance only, no origin offset, use for things like diameters { my $s=shift(@_); return map { int(0.5+$_*$s->{s}) } @_; } # graphical routine. Has same interface as gcode pretty much. package gdcode; use GD; @ISA=qw(Exporter); @EXPORT=qw( x y z d f r ); my $f="%9f "; my $ff="%2.1f"; sub x {'x'} sub y {'y'} sub z {'z'} sub f {'f'} sub r {'r'} sub d {'d'} sub new { my ($self,$file,$scale,$xsize,$ysize)=@_; my $g={}; my $i = new GD::Image($xsize,$ysize); my $s=new scale; $s->setscale($scale,$xsize,$ysize); $s->setorigin(0,0); $g->{i}=$i; $g->{x}=0; $g->{y}=0; $g->{z}=0; $g->{s}=$s; $g->{file}=$file; # allocate some colors $g->{col}->{white} = $i->colorAllocate(255,255,255); $g->{col}->{black} = $i->colorAllocate(0,0,0); $g->{col}->{blue} = $i->colorAllocate(0,0,255); $g->{col}->{red} = $i->colorAllocate(255,0,0); #$red = $i->colorAllocate(255,0,0); #$blue = $i->colorAllocate(0,0,255); #$green=$i->colorAllocate(0,255,0); #$turk=$i->colorAllocate(0,255,255); #$beig=$i->colorAllocate(196,128,0); #$purp=$i->colorAllocate(128,0,128); return bless $g; } # internal function. used for all circular arcs, emulates the # gcode arc command. sub arcpath { my ($i,$s,$x1,$y1,$x2,$y2,$r,$col)=@_; my $l=sqrt((($x2-$x1)**2)+(($y2-$y1)**2)); # dist between supplied points printf "%f %f\n",$r,$l/2; my $l2=sqrt(abs($r**2-($l/2)**2)); # dist from center of normal to arc center my $a=2*atan2($l/2,$l2); # vertex angle $ra=0.5*($pi-$a); # radial line line 1/2 angle my $cata=atan2($y2-$y1,$x2-$x1); my $a2=-($pi-$cata-$ra); my ($cx,$cy)=($x1-$r*cos($a2),$y1-$r*sin($a2)); $i->arc($s->scalexy($cx,$cy),$s->scaled($r*2,$r*2),($a2)*180/$pi+360,($a2+$a)*180/$pi+360,$col); } sub ginit { my ($g)=@_; } sub gcomment { shift if (ref($_[0]) eq 'gdcode'); my ($c)=@_; print "*** $c \n"; return; } sub gmove { my ($g)=shift; my (@xy)=($g->{x},$g->{y}); while (@_) { $g->{$_[0]}=$_[1] if ($_[0] =~/^[xyz]$/i); shift; shift; } push(@xy,$g->{x},$g->{y}); my $col=$g->{z}>=0?$g->{col}->{red}:$g->{col}->{blue}; $g->{i}->line($g->{s}->scalexy(@xy),$col); } sub garcccw { my ($g)=shift; my (@xy)=($g->{x},$g->{y}); my ($r); while (@_) { $g->{$_[0]}=$_[1] if ($_[0] =~/^[xyz]$/i); # i,j not implemented $r=$_[1] if ($_[0] =~/^[r]$/i); shift; shift; } @xy=(@xy,$g->{x},$g->{y}); my $col=$g->{z}>=0?$g->{col}->{red}:$g->{col}->{blue}; arcpath($g->{i},$g->{s},@xy,$r,$col); } sub garccw { my ($g)=shift; my (@xy)=($g->{x},$g->{y}); my ($r); while (@_) { $g->{$_[0]}=$_[1] if ($_[0] =~/^[xyz]$/i); # i,j not implemented $r=$_[1] if ($_[0] =~/^[r]$/i); shift; shift; } @xy=($g->{x},$g->{y},@xy); my $col=$g->{z}>=0?$g->{col}->{red}:$g->{col}->{blue}; arcpath($g->{i},$g->{s},@xy,$r,$col); } # although cutter compensation changes the path plotted by, roughly speaking # the radius of the tool, we dont show this here, all we show # is the actual path plotted. These functions therefore do nothing sub gcompr { } sub gcompl { } sub gcomp0 { } # generate the output sub gend { my ($g)=@_; open(F,">".$g->{file}) or die "Cannot open file ".$g->{file}; binmode F; print F $g->{i}->png; close F; } 1;