#!/usr/bin/perl -w
#
# Given an SVG where each path is a cut line, convert to simple gcode.
#$fNam = $ARGV[0];
#$tNam = $fNam . "~";

$CutFeedRate = 3456;  # change this to alter cutting speed.
# oddly specific to make it easier to search and replace as necessary in gcode

&mainHeader();

&parseViewBox();

&convertPaths();

&mainFooter();

##########################################################################################

sub mainHeader() {
    print "G92 X0 Y0  (set current position to 0,0.  our plasma cutter has no home)
S1200  (arbitrary high spindle rate.  make sure M3 or M4 set pin 12 high)
M5  (make sure plasma is off)
";}
sub mainFooter() { print "
%M5 (make sure plasma off)
G0 X0 Y0 (return to origin)
"; }
sub startCut() {
    local ($_) = @_;

    local ($key,@vals) = &parseSVGpoint($_);
    local $loc = sprintf("X%g Y%g",$vals[0],$vals[1]-$Y0);
    if ($key =~ m/^M/) {
	print "G0 $loc\nM3 (start cutter)\nG04 P0.3 (pause to pierce)\n";
	return(@vals);
    }
    print "% initial point in path <$key $val> not supported\n";
    return("X0 Y0");
}

sub endCut() {
    print "M5 (cutter off)\nG04 P0.5 (pause to cool down)\n";
}


sub convertPaths() {
    while(1) {
	local ($stroke,@points) = &loadNextPath();
	return if ($#points <= 0);
	foreach(@points) { print STDERR "% $_\n"; }
	local $absolute=1;
	@startLoc = &startCut($points[0]);  # starting path relative not yet supported
	local @loc = @startLoc;
	for (local $k=1; $k <= $#points; $k++) {
	    ($absolute,@loc) = &nextWaypoint($points[$k],$absolute,@loc);
	}
	&endCut(@loc);
    }
}

sub parseSVGpoint() {
    ($_) = @_;
    s/\s+/ /;
    s/^\s+//;
    s/\s+$//;
    local $key = substr($_,0,1);
    local $val = substr($_,1);
    #print STDERR "key=$key val=$val\n";
    local @vals = split(/ |,/,$val);
    return($key,@vals);
}

sub nextWaypoint() {
    local ($point,$absolute,@prevLoc) = @_;
    local ($key,@loc) = &parseSVGpoint($point);
    local $loc;
    
    if ($key =~ m/^Z/i) {
	print "G90 (switch to absolute position mode)\n" if (!$absolute);
	$loc = sprintf("X%g Y%g",$startLoc[0],$startLoc[1]-$Y0);
	print "G1 $loc F$CutFeedRate\n";
	return(1,@startLoc);
    }
    $loc = sprintf("X%g Y%g",$loc[0],$loc[1]-$Y0);  # shift svg quadrant
    # current svg is one path per cut.  don't worry about inside Ms
    if ($key =~ m/^L/) {
	print "G90 (switch to absolute position mode)\n" if (!$absolute);
	print "G1 $loc F$CutFeedRate\n";
	return(1,@loc);
    } elsif ($key =~ m/^l/) {
	print "G91 (switch to relative position mode)\n";
	print "G1 $loc F$CutFeedRate\n";
	$loc[0] += $prevLoc[0];
	$loc[1] += $prevLoc[1];
	return(0,@loc);
    } else {
	print "% key %key not yet supported for internal path waypoint\n";
	return($absolute,@prevLoc);
    }
}
	    


	
	
    
sub loadNextPath() {
    local $pathStr = &loadNextPathTag();
    print STDERR "Next Path : $pathStr \n";
    return("","") if (length($pathStr) < 10);
    local $stroke = &parseStrokeFromPath($pathStr);
    print STDERR "% stroke=$stroke\n";
    local @points = &parsePointsFromPath($pathStr);
    return($stroke,@points);
}
sub loadNextPathTag() {
    local ($line,$pathStr,$done) = ("","",0);
    while($line = <STDIN>) {
	#print STDERR "looking for <path in : $line\n";
	if ($line =~ m/\<path /i) {
	    $line =~ s/^.*\<path //i;
	    #print STDERR "start of path tags : $line\n";
	    ($pathStr,$done) = &chompEndBracket($line);
	    #print STDERR "initial path $done : $pathStr\n";
	    return($pathStr) if ($done);
	    while ($line = <STDIN>) {
		($line,$done) = &chompEndBracket($line);
		$pathStr .= $line;
		return ($pathStr) if ($done);
	    }
	} else {
	    chomp($line);
	    print STDERR "$line skipped looking for <path\n";
	}
    }
    return(""); # incomplete path definition
}
sub chompEndBracket() {
    local ($_) = @_;
    local $done=0;
    #print STDERR "looking for closing bracket in : $_\n";
    if (m/\/\>/) {
	s/\/\>.*//;
	$done=1;
	#print STDERR "closing bracket found and removed : $_\n";
    }
    s/\s+$//;
    return($_,$done);
}



sub parseStrokeFromPath() {
    local ($_) = @_;
    #print STDERR "looking for stroke in : $_\n";
    return("") if (!m/stroke=/i);
    s/^.*stroke="//i;
    local ($stroke,$restOfPath) = &extractToQuote($_);
    print STDERR "stuff after stroke : $restOfPath\n" if(0);
    return($stroke);
}
sub parsePointsFromPath() {
    local ($_) = @_;
    #print STDERR "looking for points in : $_\n";
    s/^.*d=\"//;
    #print STDERR "start of points data : $_\n";
    s/\".*$//;  #    $_ = &extractToQuote($_);
    s/^\s+//;
    s/\s+$//;
    s/\s+/ /;
    #print "% $_\n";
    local @words = split(/ /);
    local @points;
    for (local $k = 0; $k <= $#words; $k++) {
	$_ = $words[$k];
	if (m/M|L/i) {
	    if ($k < $#words) {
		$points[$#points+1] = $_ . $words[$k+1];
		$k++;
	    } else {
		print STDERR "\tpremature end of points\n";
		return(@points);
	    }
	} elsif(m/z/i) { $points[$#points+1] = $words[$k]; }
    }
    return(@points);
}

sub parseViewBox() {
    while (my $line = <STDIN>) {
	print STDERR $line;
	chomp($line);
	if ($line =~ m/^<svg/) {
	    print STDERR "^^^^^ svg line identified\n";
	    ($width,$height,$X0,$Y0,$DX,$DY)=(0,0,0,0,0,0);
	    $line =~ s/^.+svg +//;
	    $line =~ s/\>//;
	    while($line) {
		if ($line =~ m/^width=/) {
		    #print STDERR "next tag width : $line \n";
		    $line =~ s/^width="//;
		    ($width,$line) = &extractToQuote($line);
		    $width =~ s/mm//;
		    print STDERR "\twidth=$width"; # rest of line: $line \n";
		} elsif ($line =~ m/^height=/) {
		    $line =~ s/^height="//;
		    ($height,$line) = &extractToQuote($line);
		    $height =~ s/mm//;
		    print STDERR "\theight=$height"; # rest of line: $line \n";
		} elsif ($line =~ m/^viewBox=/) {
		    $line =~ s/^viewBox="//;
		    ($vbStr,$line) = &extractToQuote($line);
		    #print STDERR "viewBox=$vbStr rest of line: $line \n";
		    ($X0,$Y0,$DX,$DY) = split(/ +/,$vbStr);
		    print STDERR "\tLLC=$X0,$Y0  Size=$DX x $DY\n";
		    print "\n% ++++++++++\tLLC=$X0,$Y0  Size=$DX x $DY\n";
		} else {
		    print STDERR "skipping $line in svg tag\n";
		    ($_,$line) = &extractToQuote($line);
		    #print STDERR "skipped keyword : $line \n";
		    ($_,$line) = &extractToQuote($line);
		    #print STDERR "skipped val : $line \n";
		    $line =~ s/^\s+//;
		    #print STDERR "$line remaining\n";
		}

	    }
	    print STDERR "vvvvv svg line parsed\n";
	    return;
	}
    }
}

sub extractToQuote() {
    local ($line) = @_;
		    
    #print STDERR "tag removed : $line \n";
    local $iQuot = index($line,"\"");
    #print STDERR "quote at $iQuot\n";
    local $val = substr($line,0,$iQuot);
    $line = substr($line,$iQuot+1);
    $line =~ s/\s+//;
    return($val,$line);
}

__END__
