import numpy as np
import sys

""" 
makegcode.py by John Wallin

This is relatively simple code to create the gcode needed to run
the scriber-bot on a CNC machine.  I opted not to use any fancy
g-code libraries to help other people write their own code.

The basically, the code reads in data from the dots file
created by the mhologram.py code.   You actually can use any
comma separated data file you want for the hologram, so you could
write your own code to create this file or just type them in 
by hand.

To run the code in Linux or on a Mac, type
python mhologram.py dotfile.txt

The output will go to the terminal.   Just past it into a file with the
"gcode".   You can also do this from the command line using:

python mhologram.py dotfile.txt > mygcodefile.gcode

Basically the gcode just does a simple pattern of commands:
1) move to the new xy location
2) lower the scriber to the plastic
3) trigger the M8 flood command- causing the servo to sweep clockwise
4) Add a short pause to let the scriber move
5) lift the scriber above the plastic
6) clear the M8 command - causing the servo to sweep counter-clockwise
7) pause and let the scriber arm return to its original position

It has a simple startup and end as well, but there isn't alot of complications
to the code.

This program is covered by the Creative Commons License along 
with the rest of the product.

I wrote this code in Python 2 - because I am a rebel.

"""


class makegcode:

  def __init__(self):
    self.gcmdList = []
    self.simulate = 0

  def setSimulate(self):
    self.simulate = 1

  def setup(self):
    self.gcmdList.append("G20")
    self.gcmdList.append("G90")
    if self.simulate == 1:
      self.moveZ(0.5)
      self.simulate = 0
    self.moveUp()
    
  def setSpeed(self, speed):
    self.speed = "{:3.1f}".format(speed)

  def setVspeed(self, vspeed):
    self.vspeed = "{:3.1f}".format(vspeed)

  def setVerticalDisplacement(self, verticalDisplacement):
    self.verticalDisplacement = verticalDisplacement

  def setPauseLength(self, pauseLength):
    self.pauseLength = pauseLength

  def setFinalPauseLength(self, finalPauseLength):
    self.finalPauseLength = finalPauseLength

  def setupXcarve(self):
    self.setSpeed(45)
    self.setVspeed(9)
    self.setVerticalDisplacement(0.25)
    self.setPauseLength(1.5)
    self.setFinalPauseLength(0.1) 

  def formatFloat(self, ff):
    s = str(ff)
    s = "{:6.4f}".format(ff)
    return s

  def moveXY(self, x, y):
    cmd = "G1"
    cmd = cmd + " X" + self.formatFloat(x)
    cmd = cmd + " Y" + self.formatFloat(y)
    cmd = cmd + " F" + self.speed

    self.gcmdList.append(cmd)
    
  def moveZ(self, z):
    cmd = "G1"
    cmd = cmd + " Z" + self.formatFloat(z)
    cmd = cmd + " F" + self.vspeed

    self.gcmdList.append(cmd)

  def moveUp(self):
    self.moveZ(self.verticalDisplacement)

  def moveDown(self):
    self.moveZ(-self.verticalDisplacement)

  def scratchPause(self):
    cmd = "G4"
    cmd = cmd + " P" + "{:6.4f}".format(self.pauseLength)
    self.gcmdList.append(cmd)
    
  def finalPause(self):
    cmd = "G4"
    cmd = cmd + " P" + "{:3.1f}".format(self.finalPauseLength)
    self.gcmdList.append(cmd)

  def mist(self):
    cmd = "M8"
    self.gcmdList.append(cmd)

  def endMist(self):
    cmd = "M9"
    self.gcmdList.append(cmd)

  def simpleScratchSequence(self, x, y):
    self.moveXY(x,y)
    self.moveDown()
    self.mist() 
    self.scratchPause()
    self.moveUp()
    self.endMist()
    self.scratchPause()
    
  def finalizeCommands(self):
    self.setup()
    self.moveXY(0,0)
    self.finalPause()

  def dumpCommands(self):
    for c in self.gcmdList:
      print c

  def simpleReadFile(self, fname):
    self.spoints = []
    f = open(fname,"r")
    for l in f:
      v = l.split(",")
      self.spoints.append( [float(v[0]), float(v[1]) ] )
    f.close()

  def simpleCreateScratchCode(self, fname):
    self.simpleReadFile(fname)
    pts = np.array(self.spoints)
    
    self.setupXcarve()
    self.setSimulate()  # raises the stylus so it does not scratch
    self.setup()
    for p in pts:
      x = p[0]
      y = p[1]
      self.simpleScratchSequence(x,y)
    self.finalizeCommands()

  def checkSystem(self):
    pts = np.array([[1,1], [1,2], [2,2], [2,1]])
    
    self.setupXcarve()
    self.setSimulate()  # raises the stylus so it does not scratch
    self.setup()
    for p in pts:
      x = p[0]
      y = p[1]
      self.simpleScratchSequence(x,y)
    self.finalizeCommands()

  def processInputParameters(self):
    args = sys.argv
    if len(args) == 1:
      gc.checkSystem()
    else:
      self.simpleCreateScratchCode(args[1])
    self.dumpCommands()

if __name__ == "__main__":



  gc = makegcode()
  gc.processInputParameters()


