#!/usr/bin/python3
# -*- coding: utf-8 -*-

# par X. HINAULT - Mai 2013 - 2017- Tous droits réservés
# GPLv3 - www.mon-club-elec.fr | www.mon-fablab.fr

# modules a importer - PyQt4
#from PyQt4.QtGui import *
#from PyQt4.QtCore import *  # inclut QTimer..
#from PyQt4.QtSvg import *

# modules a importer - PyQt5
from PyQt5.QtGui import *
from PyQt5.QtCore import *  
from PyQt5.QtWidgets import *
from PyQt5.QtSvg import *

import os,sys
from xml.dom import minidom
from shapely.geometry import *
# dépendance : sudo apt-get install python3-shapely


# import séfcifique pour appli Qt... à la place du classique from pylab import * 
#from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg as FigureCanvas
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
from matplotlib.figure import Figure
# nécessite la création d'un Qwidget dans QtDesigner

from numpy import * # math

from  simple_gcode_generator_svg_to_gcode import * # fichier obtenu à partir QtDesigner et pyuic4

# +/- variables et objets globaux 

class myApp(QWidget, Ui_Form): # la classe reçoit le Qwidget principal ET la classe définie dans test.py obtenu avec pyuic4
	def __init__(self, parent=None):
		QWidget.__init__(self) # initialise le Qwidget principal 
		self.setupUi(parent) # Obligatoire 

		# --- Variables de classe

		# --- Paramétrage des widgets de l'interface GUI si nécessaire ---

		# --- Connexions entre signaux des widgets et fonctions
		# connecte chaque signal utilisé des objets à l'appel de la fonction voulue 

		#--- fichier SVG --
		#self.connect(self.pushButtonOuvrirSvg, SIGNAL("clicked()"), self.pushButtonOuvrirSvgClicked)  # connecte le signal Clicked de l'objet à l'appel de la fonction voulue 
		self.pushButtonOuvrirSvg.clicked.connect(self.pushButtonOuvrirSvgClicked)
		
		#self.connect(self.pushButtonEnregistrerSvg, SIGNAL("clicked()"), self.pushButtonEnregistrerSvgClicked) # connecte le signal Clicked de l'objet bouton à l'appel de la fonction voulue 
		self.pushButtonEnregistrerSvg.clicked.connect(self.pushButtonEnregistrerSvgClicked)
		
		#self.connect(self.pushButtonNouveauSvg, SIGNAL("clicked()"), self.pushButtonNouveauSvgClicked) # connecte le signal Clicked de l'objet bouton à l'appel de la fonction voulue 
		self.pushButtonNouveauSvg.clicked.connect(self.pushButtonNouveauSvgClicked)
		
		#--- GCode --
		#self.connect(self.pushButtonGCodeUnePasse, SIGNAL("clicked()"), self.pushButtonGCodeUnePasseClicked)  # connecte le signal Clicked de l'objet à l'appel de la fonction voulue 
		self.pushButtonGCodeUnePasse.clicked.connect(self.pushButtonGCodeUnePasseClicked)
		
		# --- Code actif initial  --- 


		# Dessin avec QPixmap (affichage) et QImage (I/O, accès pixels) 
		
		# création d'un QImage permettant l'accès aux pixels
		self.image=QImage(self.labelSvg.size(),QImage.Format_RGB32) # crée image RGB 32 bits même taille que label
		
		#-- initialisation du QImage
		self.image.fill(QColor(255,255,255)) # fond blanc

		# coordonnées centre du QPixmap (même taille que label)
		xo=self.image.width()/2
		yo=self.image.height()/2
		
		#trace le point 
		#self.image.setPixel(xo,yo,qRgb(0,0,0)) # modifie la couleur du pixel x,y - noter qRgb renvoie valeur RGB 0xFFRRGGBB

		#--- objet de rendu SVG
		#self.svg=QSvgRenderer("triskel.svg")
		self.svg=QSvgRenderer()
		
		#--- dessin initial sur QImage --
		self.painterImage=QPainter(self.image) # associe QPainter (classe de dessin) au Qimage - equivaut begin(self.image) ? 

		self.svg.render(self.painterImage) # rendu du SVG via l'objet painter

		"""
		# tracé de formes 
		self.painterImage.setPen(QPen(QColor(0,0,255),2)) # fixe la couleur du crayon et la largeur pour le dessin - forme compactée		
		self.painterImage.drawRect(10,10,50,50) # dessin rectangle : drawRect (self, int x, int y, int w, int h)
		#self.painterImage.drawPoint(xo,yo) # trace un point drawPoint (self, int x, int y)
		#self.painterImage.fillRect(150,150,30,30,QColor(255,255,0)) # fillRect (self, int x, int y, int w, int h, QColor b)
		self.painterImage.drawEllipse(xo,yo,50,50) # dessin cercle - x-y = coin sup gauche rect encadrant : drawEllipse (self, int x, int y, int w, int h)
		#self.painterImage.drawEllipse(QPointF(xo,yo),50,50) # dessin cercle avec x,y centre et rayon : drawEllipse (self, QPointF center, float rx, float ry)
		self.painterImage.drawLine(0,0,xo*2,yo) # trace une ligne : drawLine (self, int x1, int y1, int x2, int y2)
		#self.painterImage.drawText(QPointF(xo/2, yo/2), "Hello") # drawText (self, QPointF p, QString s)
		"""
		# il existe d'autres possibilités de dessin (polygone, chemin, etc..) voir : http://pyqt.sourceforge.net/Docs/PyQt4/qpainter.html
		
		self.painterImage.end() # ferme le painter - n'est plus accessible après
		
		# -- fin dessin sur QImage

		#-- Initialisation du QPixmap
		self.pixmap=QPixmap.fromImage(self.image) # initialise  le QPixmap... 

		self.updatePixmap()
		
		#------ initialisation du graphique matplotlib --------- 
				# initialisation figure matplotlib
		self.dpi = 75
		#self.fig = Figure((4.0, 2.0), dpi=self.dpi)
		wInch=self.widget.width()*1.1/self.dpi
		hInch=self.widget.height()/self.dpi
		self.fig = Figure((wInch, hInch), dpi=self.dpi)		
		self.figCanvas = FigureCanvas(self.fig)
		self.figCanvas.setParent(self.widget) # le Qwidget existe et a été créé avec QDesigner
		# figCanvas est un FigureCanvasQTAgg : http://matplotlib.org/api/backend_qt4agg_api.html#module-matplotlib.backends.backend_qt4agg
		
		self.figGraph = self.fig.add_subplot(1,1,1) # 2D - subdivise tracé en 1 ligne x 1 colonne - position 1
		#self.figGraph.invert_xaxis() # inverse sens axe X
		self.figGraph.invert_yaxis() # inverse sens axe Y 
		#figGraph est un objet appelé Axes... qui contient tous les éléments du graphique : les axes, la courbe, etc.. 
		# http://matplotlib.org/api/axes_api.html#matplotlib.axes.Axes
		
		#self.figAxes = self.fig.add_subplot(1,1,1,projection='3d') # 3D - subdivise tracé en 1 ligne x 1 colonne - position 1
		
		# pour dessiner : self.figGraph.plot(self.x, self.y)
		
		"""
		# -- axe X
		self.Xmin=0
		self.Xmax=360
		self.figGraph.set_xlim((self.Xmin, self.Xmax)) # fixe Xmin et XMax 
		
		# -- axe Y 
		self.Ymin=-10
		self.Ymax=10
		self.figGraph.set_ylim((self.Ymin, self.Ymax)) # fixe Ymin et YMax 
		
		#-- initialise données -- 
		self.x = arange(0.0, 361.0, 1.0) # crée un vecteur de n valeurs à intervalle régulier pour les x
		print(self.x) # debug - affiche les valeurs x
		
		#self.y = zeros(len(self.x), Float) # debug - crée un tableau rempli de 0 de la taille voulue pour les y	
		#-- calcul des y : courbe y=sin(x).cos(3x)
		self.y=sin(radians(self.x)) * cos(radians(8*self.x))# crée un tableau de valeur y basé sur x
		print(self.y) # debug - affiche les valeurs y
		
		
		#-- initialise la courbe -- 
		#self.courbe.setData(self.x,self.y) # initialisation valeurs courbe
		self.courbe1,= self.figGraph.plot(self.x, self.y) # initialisation valeurs courbe - matplotlib - memorise l'objet ligne 2D
		# , car renvoie un tuple de 'd'objet ligne
		# courbe1 est un objet ligne : http://matplotlib.org/api/artist_api.html?highlight=set_y#module-matplotlib.lines 
		"""

	# --- les fonctions appelées, utilisées par les signaux des widgets --- 

	def pushButtonOuvrirSvgClicked(self):
		print("Bouton <Sélectionner Fichier> appuyé")

		# ouvre fichier en tenant compte du chemin déjà saisi dans le champ 
		if self.lineEditCheminSvg.text()=="":
			self.filenameSvg=QFileDialog.getOpenFileName(self, 'Ouvrir fichier', os.getenv('HOME'))[0] # ouvre l'interface fichier - home par défaut
			#self.filename=QFileDialog.getOpenFileName(self, 'Ouvrir fichier', QDir.currentPath()) # ouvre l'interface fichier - chemin courant par défaut
		else:
			info=QFileInfo(self.lineEditCheminSvg.text()) # définit un objet pour manipuler info sur fichier à partir chaine champ
			print (info.absoluteFilePath()) # debug	
			self.filenameSvg=QFileDialog.getOpenFileName(self, 'Ouvrir fichier', info.absoluteFilePath())[0] # ouvre l'interface fichier - à partir chemin 
	
		#self.filename=QFileDialog.getOpenFileName(self, 'Ouvrir fichier', os.getenv('HOME')) # ouvre l'interface fichier - home par défaut
		#self.filename=QFileDialog.getOpenFileName(self, 'Ouvrir fichier', QDir.currentPath()) # ouvre l'interface fichier - chemin courant par défaut
		# getOpenFileName ouvre le fichier sans l'effacer
		
		print(self.filenameSvg) # affiche le chemin obtenu dans la console
		self.lineEditCheminSvg.setText(self.filenameSvg) # affiche le chemin obtenu dans le champ texte

		#-- affichage du contenu fichier svg
		self.filenameSvg=self.lineEditCheminSvg.text() # récupère chemin champ *.svg
		
		#-- ouverture du fichier Svg et récupération du contenu 
		myFileSvg=open(self.filenameSvg,"r") # ouvre le fichier en lecture
		myFileSvgContent=myFileSvg.read() # lit le contenu du fichier
		myFileSvg.close() # ferme le fichier - tant que le fichier reste ouvert, il est inacessible à d'autres ressources
		
		self.textEditSvg.setText(myFileSvgContent) # copie le contenu dans la zone texte 


		#-- rendu du SVG
		"""
		self.image.load(self.filenameImage)
		"""
		#efface le QImage
		self.image.fill(QColor(255,255,255)) # fond blanc
		
		#--- objet de rendu SVG
		self.svg=QSvgRenderer(self.filenameSvg) # ouvre le fichier
		
		#--- dessin initial sur QImage --
		self.painterImage=QPainter(self.image) # associe QPainter (classe de dessin) au Qimage - equivaut begin(self.image) ? 

		self.svg.render(self.painterImage) # rendu du SVG via l'objet painter - le svg est de la taille de l'image... couleur sont respectées, etc.. 

		self.painterImage.end() # ferme le painter - n'est plus accessible après


		# affiche image
		self.image=self.image.scaled(self.labelSvg.size()) # redimensionne l'image
		self.updatePixmap() # met à jour le pixmap et qlabel
				
		
	def pushButtonNouveauSvgClicked(self):
		print("Bouton NOUVEAU appuyé")
		
		# ouvre fichier en tenant compte du chemin déjà saisi dans le champ 
		if self.lineEditCheminSvg.text()=="":
			#self.filename=QFileDialog.getSaveFileName(self, 'Ouvrir fichier', os.getenv('HOME')) # ouvre l'interface fichier - home par défaut
			self.filenameSvg=QFileDialog.getSaveFileName(self, 'Ouvrir fichier', os.getenv('HOME'), "*.png *.jpg;; *.gif") # ouvre l'interface fichier - avec sélection 
			#self.filename=QFileDialog.getOpenFileName(self, 'Ouvrir fichier', QDir.currentPath()) # ouvre l'interface fichier - chemin courant par défaut
		else:
			info=QFileInfo(self.lineEditCheminSvg.text()) # définit un objet pour manipuler info sur fichier à partir chaine champ
			print (info.absoluteFilePath()) # debug	
			self.filenameSvg=QFileDialog.getSaveFileName(self, 'Ouvrir fichier', info.absoluteFilePath(), "*.png *.jpg;; *.gif") # ouvre l'interface fichier - à partir chemin - avec sélection
			# ;; pour avoir choix de sélection sur plusieurs lignes ex : "Images (*.png *.xpm *.jpg);;Text files (*.txt);;XML files (*.xml)"
		
		print(self.filenameSvg)
		self.lineEditCheminSvg.setText(self.filenameSvg)
		

	def pushButtonEnregistrerSvgClicked(self):		
		print("Bouton <ENREGISTRE> appuyé")			
	
		if self.lineEditCheminSvg.text()!="":
			
			self.image.save(self.filenameImage) # le suffixe utilisé est celui du nom de fichier
					



	def pushButtonGCodeUnePasseClicked(self):
		print("Bouton <GCode 1 Passe> appuyé")
		
		diam_outil=self.doubleSpinBoxDiamOutil.value() # le diametre d'outil à utiliser
		self.figGraph.cla() # RAZ les axes du graphique
		self.figCanvas.draw() # MAJ graphique - redessine le canvas... 

		#svg_filename="/home/xavier072/myCloud/files_svg_cnc/B_georgia_40mm.svg"
		
		# ouvre fichier en tenant compte du chemin déjà saisi dans le champ 
		if self.lineEditCheminSvg.text()=="":
			svg_filename=os.getenv('HOME') # ouvre l'interface fichier - home par défaut
		else:
			svg_filename=self.lineEditCheminSvg.text() # définit un objet pour manipuler info sur fichier à partir chaine champ

		print (svg_filename)

		#### extraction des données du SVG = coordonnées des path du SVG
		doc=minidom.parse(str(svg_filename)) # ouverture / parsing du fichier SVG
		
		path_strings=[path.getAttribute('d') for path in doc.getElementsByTagName('path')]
		
		points_list=[] # liste des listes de points 
		closed_paths_list=[]
		
		for path_string in path_strings: # défile les path obtenus
			print (path_string+"\n")
			
			points_str=path_string.split(' ') # obtention list de chaines des 2 coordonnées des points
			print (str(points_str)+"\n")
			
			# on enlève dernier élément si Z = chemin fermé
			if points_str[-1]=='Z': 
				points_str_list=[p.split(',') for p in points_str[1:-1]] # enlève premier et dernier élément 
				closed_paths_list.append(True) # mémorise chemin fermé
			else :
				points_str_list=[p.split(',') for p in points_str[1:]] # enlève premier et on garde le dernier élément 
				closed_paths_list.append(False) # mémorise chemin ouvert
				
			print (str(points_str_list)+"\n")
			
			points=[(float(p[0]),float(p[1])) for p in points_str_list ] # récupère les points sous forme de list
			print (points)

			points_list.append(points) # ajoute la liste de points courante à la liste des listes de points
			

		doc.unlink() # fin du traitement du fichier xml

		#Vérification des listes de points obtenus
		for points in points_list:
			print (points)

		for closed_path in closed_paths_list:
			print (closed_path)
			
		# Création de Polygon shapely à partir des points 
		
		polygon_list=[]
		
		for index, points in enumerate(points_list):
			
			polygon = Polygon(points) # http://toblerity.org/shapely/manual.html#polygons
			
			print (polygon.exterior.coords[:]) # affichage des coordonnées externes du polygon 
			# note : le polygon ajoute la connexion dernier point -->  premier point
			
			#-- dessin du polygon 
			if closed_paths_list[index]==False : # si le chemin est ouvert - on ne prend pas le dernier point du polygon idem 1er
				x=[point[0] for point in polygon.exterior.coords[:]] # on prend aussi le dernier...
				y=[point[1] for point in polygon.exterior.coords[:]] # on prend aussi le dernier...
			else:
				x=[point[0] for point in polygon.exterior.coords[:]]
				y=[point[1] for point in polygon.exterior.coords[:]]

			#plot(x,y)
			self.figGraph.plot(x, y)
			
			polygon_list.append(polygon)
			
		# fin for

		# Vérification des Polygon obtenus et génération G-code

		#speed_down=50 # mm/sec
		#speed_up=600 #mm/sec
		#speed_cut=250 #mm/sec
		#speed_travel=600 #mm/sec
		
		speed_down=self.doubleSpinBoxVitesse_descente.value() # mm/sec
		speed_up=self.doubleSpinBoxVitesse_remontee.value() #mm/sec
		speed_cut=self.doubleSpinBoxVitesse_decoupe.value() #mm/sec
		speed_travel=self.doubleSpinBoxVitesse_trajets.value() #mm/sec
		coeff_coord=3.54 # correction coord pixels vers mm
		profondeur_passe=self.doubleSpinBoxProfondeur.value() # profondeur de la passe

		# début commun aux différents mode (découpe, gravure)
		gcode="G01 X0.0 Y0.0 F"+str(speed_travel)+" \n" # pour fixer vitesse initiale

		################## --- generation GCode mode gravure --- ####################
		# par définition le mode gravure ne peut pas gérer des chemins non fermés... donc pas implémenté ici 
		if self.checkBoxGravure.isChecked()==True : # si mode gravure
			
			print ("Mode Gravure")
			
			# Vérification des Polygon obtenus
			for polygon in polygon_list:
				print (polygon)
			
			containers=[] # liste de polygones conteneurs
			inside_lists=[] # list de list destinee à lister les polygones intérieurs des conteneurs
			
			# Teste pour chaque polygone si il contient un des autres 
			for index, current_polygon in enumerate(polygon_list):
				
				test_list=[ elt for idx,elt in enumerate(polygon_list) if idx!=index ] # liste des autres polygones sans le polygone courant
				print (test_list)
				
				isContainer=False # variable flag
				
				for test_polygon in test_list: # défile les autres polygones
					
					#inside=test_polygon.contains(current_polygon) # test si le polygon courant est contenu dans un des autres
					isContainer=isContainer+current_polygon.contains(test_polygon) # test si le polygon courant contient un des autres
					# on ajoute les isContainer car si True au moins une fois alors est un polygone contenu dans un autre
					print ("isContainer="+str(isContainer))
				
				# on crée la liste des polygone contenus - après le test de tous les polygones
				if isContainer>0: # si isContainer est True, le current_polygon est un conteneur
					containers.append(current_polygon)
					
					insiders=[]
					
					for test_polygon in test_list: # défile les autres polygones
						if current_polygon.contains(test_polygon): # test si le polygon courant contient l'un des autres
							insiders.append(test_polygon) # on ajoute le polygone contenu dans la liste des insiders
					
					inside_lists.append(insiders) # ajoute la list à la list
					print (inside_lists)
					
					#continue # on passe au suivant
				
				if isContainer==False: # si isContainer est toujours False après le test, le polygon est vide : 
					# on teste si il n'est pas lui-même à l'intérieur d'un autre : si False, on le retient comme un extérieur
					
					isInside=False # variable flag
					
					for test_polygon in test_list: # défile les autres polygones
					
						#inside=test_polygon.contains(current_polygon) # test si le polygon courant est contenu dans un des autres
						isInside=isInside+test_polygon.contains(current_polygon) # test si le polygon courant est à l'intérieur de un des autres
						# on ajoute les isInside car si True au moins une fois alors est un polygone contenu dans un autre
						print ("isInside="+str(isInside))
						
					
					if isInside==False: # si il n'est pas non plus à l'intérieur d'un autre = on le garde comme un extérieur
						containers.append(current_polygon)
						inside_lists.append([]) # ajoute list vide à la list des insiders
					
				# fin for test_polygon 
				
				
			
			# fin for current_polygon
			
			print (containers)
			
			# défile les containers
			for index, current_container in enumerate(containers):
				print (current_container)
				
				x=[point[0] for point in current_container.exterior.coords[:]]
				y=[point[1] for point in current_container.exterior.coords[:]]
				
				#plot(x,y,'b-')
				self.figGraph.plot(x,y,'b-')
				
				insiders=inside_lists[index]
				
				for insider in insiders: # défile les insiders associés
					x=[point[0] for point in insider.exterior.coords[:]]
					y=[point[1] for point in insider.exterior.coords[:]]
					#plot(x,y,'b-') # debug
					self.figGraph.plot(x,y,'b-')
					#print insider.exterior.coords[:] # debug
					

				# show
				
				#-- calcul d'un eroded de l'extérieur 
				container_eroded=current_container.buffer(-diam_outil/2*3.54, cap_style=CAP_STYLE.round, join_style=JOIN_STYLE.mitre)
				
				x=[point[0] for point in container_eroded.exterior.coords[:]]
				y=[point[1] for point in container_eroded.exterior.coords[:]]
				
				gcode=gcode+self.gcodeFromPoints(container_eroded.exterior.coords[:]) # gcode correspondant

				#plot(x,y,'g-')
				
				# ... et d'un / des dilated des intérieurs
				insiders_dilated=[] # list pour contenir les insiders dilatés
				for insider in insiders: # défile les insiders associés
					
					insider_dilated=insider.buffer(diam_outil/2*3.54, cap_style=CAP_STYLE.round, join_style=JOIN_STYLE.mitre)
					x=[point[0] for point in insider_dilated.exterior.coords[:]]
					y=[point[1] for point in insider_dilated.exterior.coords[:]]
					#plot(x,y,'g-') # debug
					
					gcode=gcode+self.gcodeFromPoints(insider_dilated.exterior.coords[:]) # gcode correspondant
					
					insiders_dilated.append(insider_dilated) # ajoute le insider dilaté à la liste des insiders dilatés
					
				# création d'un polygon incluant les intérieurs = ajouter l'insider courant aux interiors du polygon
				#current_container.interiors=insiders
				
				#interiors=[insider.exterior.coords[:] for insider in insiders ]
				#new_polygon=Polygon(current_container.exterior.coords[:], interiors) 
				
				interiors=[insider_dilated.exterior.coords[:] for insider_dilated in insiders_dilated ]
				new_polygon=Polygon(container_eroded.exterior.coords[:], interiors) # objet polygon constitué de l'extérieur + intérieurs
				
				print (new_polygon.exterior.coords[:])
				
				# dessine exteriors du newpolygon
				x=[point[0] for point in new_polygon.exterior.coords[:]]
				y=[point[1] for point in new_polygon.exterior.coords[:]]
				#plot(x,y,'g')
				self.figGraph.plot(x,y,'g')
				
				#interior_coords_list=[interior.coords[:] for interior in new_polygon.interiors[:]] # defile la liste des interieur et récupère coord de chaque
				#print(interior_coords_list)
				
				# dessine interiors du newpolygon 
				for interior in new_polygon.interiors[:]:
					x=[point[0] for point in interior.coords[:]]
					y=[point[1] for point in interior.coords[:]]
					#plot(x,y,'r')
					self.figGraph.plot(x,y,'r')
					
				#--- calcul intersection lignes avec le new_polygon
				# on cherche à réaliser un "balayage" de l'objet de haut en bas par lignes horizontales
				
				# la première chose : connaître le rectangle encadrant 
				print (new_polygon.bounds)
				
				#plot(new_polygon.bounds[0],new_polygon.bounds[1], 'p') # point depart
				#plot(new_polygon.bounds[2],new_polygon.bounds[3], 'p') # point diagonale
				#plot(new_polygon.bounds[0],new_polygon.bounds[3], 'p') # intermed x idem = vertical
				#plot(new_polygon.bounds[2],new_polygon.bounds[1], 'p') # intermed y idem = horizontal
				
				linestring_list=[]
				for y in arange (new_polygon.bounds[1]+diam_outil*0.75*3.54, new_polygon.bounds[3], diam_outil*0.75*3.54):
					# coeff réduc sur diam outil pour avoir un petit chevanchement entre 2 passages
					#plot(new_polygon.bounds[0],y, 'p')
					#plot(new_polygon.bounds[2],y, 'p') # intermed y idem = horizontal
					
					line=LineString([(new_polygon.bounds[0],y),(new_polygon.bounds[2],y)])
					linestring_list.append(line)
					
					# calcul intersection avec le polygon
					#print(new_polygon.intersects(line))# ne fait que tester si intersection
					intersect_line=new_polygon.intersection(line)# renvoie l'objet résulant intersection
					print(intersect_line) 
					
					if type(intersect_line)==LineString:
						x=[point[0] for point in intersect_line.coords[:]]
						y=[point[1] for point in intersect_line.coords[:]]
						#plot(x,y,'b-')
						
						gcode=gcode+self.gcodeFromPoints(intersect_line.coords[:], closeFlagIn=False) # gcode correspondant
						
						self.figGraph.plot(x,y,'b-')
					elif type(intersect_line)==MultiLineString: # si série de lignes d'intersection
						for current_line in intersect_line: # defile chaque ligne d'intersection
							x=[point[0] for point in current_line.coords[:]]
							y=[point[1] for point in current_line.coords[:]]
							#plot(x,y,'b-')
							gcode=gcode+self.gcodeFromPoints(current_line.coords[:], closeFlagIn=False) # gcode correspondant
							
							self.figGraph.plot(x,y,'b-')
							
				gcode=gcode+"G01 X0 Y0 F1000\n" # retour origine final 

		### fin if checked = mode gravure

		######################### --- generation GCode mode découpe ---  #############################
		else : 
			for polygon in polygon_list:
				print (polygon)
			
			# Teste pour chaque polygone si il est contenu dans un autre - en pratique à faire seulement si outil >0

			for index, current_polygon in enumerate(polygon_list):
				# index est idem points_list et closed_paths_list
				test_list=[ elt for idx,elt in enumerate(polygon_list) if idx!=index ] # liste des autres polygones sans le polygone courant
				print (test_list)
				
				test=False # variable flag
				
				for test_polygon in test_list:
					
					#test=test_polygon.contains(current_polygon) # test si le polygon courant est contenu dans un des autres
					test=test+test_polygon.contains(current_polygon) # test si le polygon courant est contenu dans un des autres
					# addition pour mémoriser si au moins 1 True
					print (test)
				
				###---- mode "dessin au trait" = chemins non fermés ----
				if closed_paths_list[index]==False : # si le chemin est ouvert
				
					#-- dessin du polygon - on ne prend pas le dernier point du polygon idem 1er
					x=[point[0] for point in current_polygon.exterior.coords[:-1]]
					y=[point[1] for point in current_polygon.exterior.coords[:-1]]
					
					self.figGraph.plot(x, y)

					#-- gcode correspondant 
					points=current_polygon.exterior.coords[:]
					print ("Chemin:")
					print (points) 
					
					for passe in range(1,self.spinBoxNombrePasses.value()+1): # on répète le nombre de fois voulu le chemin - passe 1 = 1
						
						if passe==self.spinBoxNombrePasses.value():
							profondeur_passe = (self.doubleSpinBoxProfondeur.value() * passe) + self.doubleSpinBoxDernierePasse.value() # ajoute 0.5 à dernière pour bien découper
						else:
							profondeur_passe = self.doubleSpinBoxProfondeur.value() * passe # profondeur courante = passe x profondeur passe

						# première ligne = goto simple
						if passe==1: # levage du Z que pour la premiere passe
							gcode=gcode+"G01 X"+"%.2f"%(points[0][0]/coeff_coord)+" Y"+"%.2f"%(points[0][1]/coeff_coord)+" Z5.0 F"+str(speed_travel)+"\n" # x,y => GO1 X00.00 Y00.00 Z5.00 \n (- Z=5 donc au dessus outil
						else: # les passes suivantes 
							gcode=gcode+"G01 X"+"%.2f"%(points[0][0]/coeff_coord)+" Y"+"%.2f"%(points[0][1]/coeff_coord)+"\n" # x,y => GO1 X00.00 Y00.00 Z5.00 \n (- Z=5 donc au dessus outil
						
						# descente outil à vitesse descente
						gcode=gcode+"G01 Z-"+str(profondeur_passe)+" F"+str(speed_down)+"\n" 
						
						# premiere ordre decoupe avec vitesse pour fixer la vitesse pour tous les points suivants
						gcode=gcode+"G01 X"+"%.2f"%(points[1][0]/coeff_coord)+" Y"+"%.2f"%(points[1][1]/coeff_coord)+" F"+str(speed_cut)+"\n"
						
						#--- gcode pour chemin ouvert ---
						for point in points[2:-1]: # jusqu'au -1 pour traiter séparément le dernier point qui est aussi premier dans polygon
						#for point in points[1:]: # si centre
						#for point in points[2:]: # si pas centre 
							gcode=gcode+"G01 X"+"%.2f"%(point[0]/coeff_coord)+" Y"+"%.2f"%(point[1]/coeff_coord)+"\n"#+" Z0.0 \n" # x,y => GO1 X00.00 Y00.00 \n
							
						#relevé outil.. ici pour toutes les passes car chemin ouvert ++
						#if passe==self.spinBoxNombrePasses.value(): 
							#gcode=gcode+"G01 Z5.0 F"+str(speed_up)+"\n" # relevage outil entre chaque passe 
						gcode=gcode+"G01 Z5.0 F"+str(speed_up)+"\n" # relevage outil entre chaque passe 

				###---- mode sans décalage d'outil ----
				elif  diam_outil==0 : # si pas de décalage d'outil et chemin fermé donc
					
					print ("diam outil =0")
					
					#-- dessin du polygon - on ne prend pas le dernier point du polygon idem 1er
					x=[point[0] for point in current_polygon.exterior.coords[:]]
					y=[point[1] for point in current_polygon.exterior.coords[:]]
					
					self.figGraph.plot(x, y)

					#-- gcode correspondant 
					points=current_polygon.exterior.coords[:]
					print ("Chemin:")
					print (points) 
					
					for passe in range(1,self.spinBoxNombrePasses.value()+1): # on répète le nombre de fois voulu le chemin - passe 1 = 1
						
						if passe==self.spinBoxNombrePasses.value():
							profondeur_passe = (self.doubleSpinBoxProfondeur.value() * passe) + self.doubleSpinBoxDernierePasse.value() # ajoute 0.5 à dernière pour bien découper
						else:
							profondeur_passe = self.doubleSpinBoxProfondeur.value() * passe # profondeur courante = passe x profondeur passe

						# première ligne = goto simple
						if passe==1: # levage du Z que pour la premiere passe
							gcode=gcode+"G01 X"+"%.2f"%(points[0][0]/coeff_coord)+" Y"+"%.2f"%(points[0][1]/coeff_coord)+" Z5.0 F"+str(speed_travel)+"\n" # x,y => GO1 X00.00 Y00.00 Z5.00 \n (- Z=5 donc au dessus outil
						else: # les passes suivantes 
							gcode=gcode+"G01 X"+"%.2f"%(points[0][0]/coeff_coord)+" Y"+"%.2f"%(points[0][1]/coeff_coord)+"\n" # x,y => GO1 X00.00 Y00.00 Z5.00 \n (- Z=5 donc au dessus outil
						
						# descente outil à vitesse descente
						gcode=gcode+"G01 Z-"+str(profondeur_passe)+" F"+str(speed_down)+"\n" 
						
						# premiere ordre decoupe avec vitesse pour fixer la vitesse pour tous les points suivants
						gcode=gcode+"G01 X"+"%.2f"%(points[1][0]/coeff_coord)+" Y"+"%.2f"%(points[1][1]/coeff_coord)+" F"+str(speed_cut)+"\n"
						
						#--- gcode pour chemin fermé ---
						for point in points[2:]: # jusqu'au dernier point qui est aussi premier dans polygon
						#for point in points[1:]: # si centre
						#for point in points[2:]: # si pas centre 
							gcode=gcode+"G01 X"+"%.2f"%(point[0]/coeff_coord)+" Y"+"%.2f"%(point[1]/coeff_coord)+"\n"#+" Z0.0 \n" # x,y => GO1 X00.00 Y00.00 \n

										#relevé outil.. seulement à la dernière passe 
						if passe==self.spinBoxNombrePasses.value(): 
							gcode=gcode+"G01 Z5.0 F"+str(speed_up)+"\n" # relevage final outil 
						
				###---- mode érosion ----
				elif test==True or self.checkBoxTrousSansPourtour.isChecked() : # si le polygone est contenu ou si mode "trous sans pourtour" => on fait une érosion et +/- on démarre la découpe au centre du polygon
					
					eroded=current_polygon.buffer(-diam_outil/2*coeff_coord, cap_style=CAP_STYLE.round, join_style=JOIN_STYLE.mitre)
					print (eroded.exterior.coords[:])
					
					
					#-- dessin du polygon 
					x=[point[0] for point in eroded.exterior.coords[:]]
					y=[point[1] for point in eroded.exterior.coords[:]]
						
					#plot(x,y)
					self.figGraph.plot(x, y)
					
					# centre
					centroid_point=eroded.centroid.coords[:][0] # c'est une list contenant 1 tuple donc on prend que le 1er élé pour avoir le point
					print ("centre : " + str(centroid_point))
					
					x_centroid=centroid_point[0]
					y_centroid=centroid_point[1]
					
					print (eroded.centroid.coords[:]) # voir http://toblerity.org/shapely/manual.html#object.centroid
					# le centroid est un objet Point 
					
					#-- gcode correspondant 
					points=eroded.exterior.coords[:]
					print ("Chemin:")
					print (points) 
					
					for passe in range(1,self.spinBoxNombrePasses.value()+1): # on répète le nombre de fois voulu le chemin - passe 1 = 1
						
						if passe==self.spinBoxNombrePasses.value():
							profondeur_passe = (self.doubleSpinBoxProfondeur.value() * passe) + self.doubleSpinBoxDernierePasse.value() # ajoute 0.5 à dernière pour bien découper
						else:
							profondeur_passe = self.doubleSpinBoxProfondeur.value() * passe # profondeur courante = passe x profondeur passe
						
						# première ligne = goto simple
						if passe==1: # levage du Z que pour la premiere passe
							
							# si checkbox coché : 
							if self.checkBoxDebuterCentre.isChecked() :
								# on va au centre 
								gcode=gcode+"G01 X"+"%.2f"%(x_centroid/coeff_coord)+" Y"+"%.2f"%(y_centroid/coeff_coord)+" Z5.0 F"+str(speed_travel)+"\n" 
								#gcode=gcode+"G01 X"+"%.2f"%(points[0][0]/coeff_coord)+" Y"+"%.2f"%(points[0][1]/coeff_coord)+" Z5.0 F"+str(speed_travel)+"\n" # si pas centre
								
								start=0 # indice pour debut boucle for des points suivants - le premier est le centre
								
							else: # si checkbox pas coché = pas début au centre  
								
								gcode=gcode+"G01 X"+"%.2f"%(points[0][0]/coeff_coord)+" Y"+"%.2f"%(points[0][1]/coeff_coord)+" Z5.0 F"+str(speed_travel)+"\n" # si pas centre
								start=1 # indice debut boucle for des points suivants - le premier est le 0

						else: # les passes suivantes sans lever du Z et sans aller au centre
							
							#gcode=gcode+"G01 X"+"%.2f"%(x_centroid/coeff_coord)+" Y"+"%.2f"%(y_centroid/coeff_coord)+" Z5.0 F"+str(speed_travel)+"\n" 

							gcode=gcode+"G01 X"+"%.2f"%(points[0][0]/coeff_coord)+" Y"+"%.2f"%(points[0][1]/coeff_coord)+"\n" # x,y => GO1 X00.00 Y00.00  \n 
							
							start=1 # indice debut boucle for des points suivants - le premier est le 0
						
						# descente outil à vitesse descente
						gcode=gcode+"G01 Z-"+str(profondeur_passe)+" F"+str(speed_down)+"\n" 
						
						# premiere ordre decoupe avec vitesse pour fixer la vitesse pour tous les points suivants
						gcode=gcode+"G01 X"+"%.2f"%(points[start][0]/coeff_coord)+" Y"+"%.2f"%(points[start][1]/coeff_coord)+" F"+str(speed_cut)+"\n" # si centre, on utilise le 1er point et sinon le 2ème - cf start
						#gcode=gcode+"G01 X"+"%.2f"%(points[1][0]/coeff_coord)+" Y"+"%.2f"%(points[1][1]/coeff_coord)+" F"+str(speed_cut)+"\n" # si pas le centre, on utilise le 2ème point
						
						
						# defile les points de la 3ème ligne à la fin - ler dernier est idem premier dans le polygon
						for point in points[start+1:]: # jusqu'au dernier car dernier point est aussi premier dans polygon
						#for point in points[1:]: # si centre
						#for point in points[2:]: # si pas centre 
							gcode=gcode+"G01 X"+"%.2f"%(point[0]/coeff_coord)+" Y"+"%.2f"%(point[1]/coeff_coord)+"\n"#+" Z0.0 \n" # x,y => GO1 X00.00 Y00.00 \n

						# dernière ligne entre dernier et premier point - nécessaire à priori que pour la dernière passe 
						#gcode=gcode+"G01 X"+"%.2f"%(points[0][0]/coeff_coord)+" Y"+"%.2f"%(points[0][1]/coeff_coord)+"\n" # x,y => GO1 X00.00 Y00.00 

						#relevé outil.. seulement à la dernière passe 
						if passe==self.spinBoxNombrePasses.value(): 
							gcode=gcode+"G01 Z5.0 F"+str(speed_up)+"\n" # relevage final outil 
							
						
					# fin for passe
					
					# fin for points
				
				#### ----- mode dilatation ---
				else: # si le polygone n'est pas contenu => c'est un pourtour => on fait une dilatation 
					
					print ("Dilatation")
					dilated=current_polygon.buffer(diam_outil/2*coeff_coord, cap_style=CAP_STYLE.round, join_style=JOIN_STYLE.mitre)
					print (dilated.exterior.coords[:])
					
					#-- dessin du polygon 
					x=[point[0] for point in dilated.exterior.coords[:]]
					y=[point[1] for point in dilated.exterior.coords[:]]
					
					#plot(x,y)
					self.figGraph.plot(x, y)

					
					#-- gcode correspondant 
					points=dilated.exterior.coords[:]
					print ("Chemin:")
					print (points) 
					
					for passe in range(1,self.spinBoxNombrePasses.value()+1): # on répète le nombre de fois voulu le chemin - passe 1 = 1
						
						if passe==self.spinBoxNombrePasses.value():
							profondeur_passe = (self.doubleSpinBoxProfondeur.value() * passe) + self.doubleSpinBoxDernierePasse.value() # ajoute 0.5 à dernière pour bien découper
						else:
							profondeur_passe = self.doubleSpinBoxProfondeur.value() * passe # profondeur courante = passe x profondeur passe

						# première ligne = goto simple
						if passe==1: # levage du Z que pour la premiere passe
							gcode=gcode+"G01 X"+"%.2f"%(points[0][0]/coeff_coord)+" Y"+"%.2f"%(points[0][1]/coeff_coord)+" Z5.0 F"+str(speed_travel)+"\n" # x,y => GO1 X00.00 Y00.00 Z5.00 \n (- Z=5 donc au dessus outil
						else: # les passes suivantes 
							gcode=gcode+"G01 X"+"%.2f"%(points[0][0]/coeff_coord)+" Y"+"%.2f"%(points[0][1]/coeff_coord)+"\n" # x,y => GO1 X00.00 Y00.00 Z5.00 \n (- Z=5 donc au dessus outil
						
						# descente outil à vitesse descente
						gcode=gcode+"G01 Z-"+str(profondeur_passe)+" F"+str(speed_down)+"\n" 
						
						# premiere ordre decoupe avec vitesse pour fixer la vitesse pour tous les points suivants
						gcode=gcode+"G01 X"+"%.2f"%(points[1][0]/coeff_coord)+" Y"+"%.2f"%(points[1][1]/coeff_coord)+" F"+str(speed_cut)+"\n"
						
						# defile les points de la 3ème ligne à la fin - ler dernier est idem premier dans le polygon
						for point in points[2:]: # jusqu'au -1 pour traiter séparément le dernier point qui est aussi premier dans polygon
							gcode=gcode+"G01 X"+"%.2f"%(point[0]/coeff_coord)+" Y"+"%.2f"%(point[1]/coeff_coord)+"\n"#+" Z0.0 \n" # x,y => GO1 X00.00 Y00.00 \n

						# dernière ligne entre dernier et premier point
						#gcode=gcode+"G01 X"+"%.2f"%(points[0][0]/coeff_coord)+" Y"+"%.2f"%(points[0][1]/coeff_coord)+"\n" # x,y => GO1 X00.00 Y00.00 

						
						#relevé outil.. seulement à la dernière passe 
						if passe==self.spinBoxNombrePasses.value(): 
							gcode=gcode+"G01 Z5.0 F"+str(speed_up)+"\n" # relevage final outil 
					
					"""
					# première ligne = goto simple
					gcode=gcode+"G01 X"+"%.2f"%(points[0][0]/coeff_coord)+" Y"+"%.2f"%(points[0][1]/coeff_coord)+" Z5.0 \n" # x,y => GO1 X00.00 Y00.00 Z5.00 \n (- Z=5 donc au dessus outil
					
					gcode=gcode+"G01 Z-"+str(profondeur_passe)+" \n" # descente outil
					
					for point in points[1:]: # de la 2ème ligne à la fin
						gcode=gcode+"G01 X"+"%.2f"%(point[0]/coeff_coord)+" Y"+"%.2f"%(point[1]/coeff_coord)+" \n"#+" Z0.0 \n" # x,y => GO1 X00.00 Y00.00 \n

					# dernière ligne entre dernier et premier point
					gcode=gcode+"G01 X"+"%.2f"%(points[0][0]/coeff_coord)+" Y"+"%.2f"%(points[0][1]/coeff_coord)+" \n" # x,y => GO1 X00.00 Y00.00 

					
					#relevé outil.. 
					gcode=gcode+"G01 Z5.0 \n" # relevage final outil 
					"""
					
					# fin for points
					
				# fin for
			
			# fin for index, current_polygon in enumerate(polygon_list):
		
		### fin else = mode découpe
		
		self.figCanvas.draw() # MAJ graphique - redessine le canvas... 
		
		""" # version 2 précédente = sans analyse des chemins internes
		points_list=[] # liste des listes de points 
		for path_string in path_strings: # défile les path obtenus
			print (path_string+"\n")
			
			points_str=path_string.split(' ') # obtention list de chaines des 2 coordonnées des points
			print (str(points_str)+"\n")
			
			points_str_list=[p.split(',') for p in points_str[1:-1]] # enlève premier et dernier élément 
			print (str(points_str_list)+"\n")
			
			points=[(float(p[0]),float(p[1])) for p in points_str_list ] # récupère les points sous forme de list
			print (points)
			
			points_list.append(points) # ajoute la liste de points courante à la liste des listes de points

		doc.unlink() # fin du traitement du fichier xml
		
		# génération du G-Code simple sans décalage d'outil
		
		print points_list
		self.textEditPoints.setText(str(points_list)) # copie le contenu dans la zone texte 
		
		gcode=""
		coeff_coord=3.54 # correction coord pixels vers mm
		
		for points in points_list: # défile la liste des liste de points
			print ("Chemin:")
			print (points) 
			
			# première ligne = goto simple
			gcode=gcode+"G01 X"+"%.2f"%(points[0][0]/coeff_coord)+" Y"+"%.2f"%(points[0][1]/coeff_coord)+" Z5.0 \n" # x,y => GO1 X00.00 Y00.00 Z5.00 \n (- Z=5 donc au dessus outil
			
			gcode=gcode+"G01 Z0 \n" # descente outil
			
			for point in points[1:]: # de la 2ème ligne à la fin
				gcode=gcode+"G01 X"+"%.2f"%(point[0]/coeff_coord)+" Y"+"%.2f"%(point[1]/coeff_coord)+" \n"#+" Z0.0 \n" # x,y => GO1 X00.00 Y00.00 \n

			# dernière ligne entre dernier et premier point
			gcode=gcode+"G01 X"+"%.2f"%(points[0][0]/coeff_coord)+" Y"+"%.2f"%(points[0][1]/coeff_coord)+" \n" # x,y => GO1 X00.00 Y00.00 

			
			#relevé outil.. 
			gcode=gcode+"G01 Z5.0 \n" # relevage final outil 
				
			# fin for points
			
		# fin for points_list
		"""
		
		#-- enregistre le G-Code obtenu
		
		print (gcode)
		self.textEditGCode.setText(gcode) # copie le contenu dans la zone texte 
		
		# enregistrement du G-code obtenu
		if self.checkBoxGravure.isChecked()==True : # si mode gravure
			gcode_filename=svg_filename[:-4]+"_gravure.gcode" # nom idem SVG+_gravure mais en *.gcode
		else:
			gcode_filename=svg_filename[:-4]+".gcode" # nom idem SVG mais en *.gcode

		print (gcode_filename)
		
		gcode_file=open(gcode_filename, 'w') # mode écriture = efface contenu précédent
		gcode_file.write(gcode)
		gcode_file.close()
		
		print ("Fichier de G-Code créé")
		
		""" # version 1 -- appel fonction blender --- 
		#chaineCommande=str("pyuic4 -o "+ self.lineEditCheminPy.text() + " -x " + 		self.lineEditCheminUi.text()) # défini commande 
		#chaineCommande=str("pwd")

		#blender -b -P blender_scripting_svg_points.py -- file.svg

		chaineCommande=str("blender -b -P blender_scripting_svg_points.py " + "-- " + self.lineEditCheminSvg.text()) # la commande à exécuter
		
		print("Commande à exécuter : " + chaineCommande)
		self.textEditConsole.append(QString.fromUtf8("Commande à exécuter : " + chaineCommande)) # message dans console GUI 
		
		#-- mise à jour des noms des fichiers à partir contenu des champs (au cas où modification manuelle) 
		self.filenameSvg=self.lineEditCheminSvg.text()

		#--- extraction de la commande à exécuter --- 		
		commandeList=chaineCommande.split() # récupère la liste des éléments séparés par 1 ou plusieurs " "
		print ("Liste = " + str(commandeList)) # affiche la liste 
		self.textEditConsole.append(QString.fromUtf8("Liste = " + str(commandeList))) # message dans console GUI 
		
		if len(commandeList)>0 : # si la liste n'est pas vide 
			cmd=commandeList[0] # extrait la commande si existe 
			print ("Commande : " + cmd) # affiche la commande
			self.textEditConsole.append(QString.fromUtf8("Commande : " + cmd)) # message dans console GUI 
			
			del(commandeList[0]) # enlève 1er élément de la liste donc la commande pour ne garder que paramètres 
			args=commandeList # copie les arguments			
			
			if args==[]: args="" # chaine vide si Args=None 
			print ("Arguments : " + str(args))
			self.textEditConsole.append(QString.fromUtf8("Arguments : " + str(args))) # message dans console GUI 

		
		#-- exécution de la commande --
		process=QProcess() # crée le QProcess
		
		#process.start("ls -a") # exemple de commande simple
		print ("Lance la commande :" + str(cmd) + str(args)) # affiche la commande dans la console
		self.textEditConsole.append(QString.fromUtf8("Lance la commande :" + str(cmd) + str(args))) # message dans console GUI 
		process.start(cmd,args) # lance la commande
		
		#-- attend fin exécution 
		print ("Attend la fin de l'exécution...")
		self.textEditConsole.append(QString.fromUtf8("Attend la fin de l'exécution...")) # message dans console GUI 

		process.waitForFinished(-1) # attend la fin sans limite de temps

		print ("Exécution terminée...")
		self.textEditConsole.append(QString.fromUtf8("Exécution terminée...")) # message dans console GUI 

		#-- récupère et affiche la sortie console 
		output=process.readAllStandardOutput() # lit la sortie
		print(output)
		self.textEditConsole.append(QString.fromUtf8(output)) # message dans console GUI 

		outputErr=process.readAllStandardError() # lit la sortie
		print(outputErr)
		self.textEditConsole.append(QString.fromUtf8(outputErr)) # message dans console GUI 

		#-- ouverture du fichier de Points et récupération du contenu 
		myFilePoints=open(self.filenameSvg[:-4]+".txt","r") # ouvre le fichier créé par le script blender en lecture (idem name.svg en name.txt)
		myFilePointsContent=myFilePoints.read() # lit le contenu du fichier
		myFilePoints.close() # ferme le fichier - tant que le fichier reste ouvert, il est inacessible à d'autres ressources
		
		
		self.textEditPoints.setText(myFilePointsContent) # copie le contenu dans la zone texte 
		
		#-- génération du GCode correspondant --
		myFilePointsLines=myFilePointsContent.splitlines()

		gcode=""

		# première ligne = goto simple
		line=myFilePointsLines[0] 
		data=line.split(',')
		gcode=gcode+"G01 X"+data[0]+" Y"+data[1]+" Z5.0 \n" # x,y => GO1 X00.00 Y00.00 Z5.00 \n (- Z=5 donc au dessus outil
		gcode=gcode+"G01 Z0 \n" # descente outil
		
		for line in myFilePointsLines[1:]: # de la 2ème ligne à la fin
			data=line.split(',')
			gcode=gcode+"G01 X"+data[0]+" Y"+data[1]+" \n"#+" Z0.0 \n" # x,y => GO1 X00.00 Y00.00 \n

		# plutôt dans le script blender... 
		# dernière ligne entre dernier et premier point
		line=myFilePointsLines[0] 
		data=line.split(',')
		gcode=gcode+"G01 X"+data[0]+" Y"+data[1]+" Z5.0 \n" # x,y => GO1 X00.00 Y00.00 Z5.00 \n (- Z=5 donc au dessus outil
		
		
		#relevé outil.. 
		gcode=gcode+"G01 Z5.0" # relevage final outil 
			
			
		print gcode
		self.textEditGCode.setText(gcode) # copie le contenu dans la zone texte 
		"""

	# --- les fonctions appelées, utilisées par les signaux hors widgets --- 




	# --- fonctions de classes autres--- 	
		
	# fonction de MAJ du QPixmap : chargement QImage +/- dessin + affichage dans QLabel 
	def updatePixmap(self):
	
		# chargement du QImage dans le QPixmap 
		self.pixmap.convertFromImage(self.image) # recharge le QImage dans le QPixmap existant - met à jour le QPixmap
		
		#-- affichage du QPixmap dans QLabel
		self.labelSvg.setPixmap(self.pixmap) # met à jour le qpixmap affiché dans le qlabel	


	def gcodeFromPoints(self, pointsListIn, closeFlagIn=True, deltaLastIn=0):
		# fonction générant le GCode à partir d'une liste de point reliés entre eux
		
		#-- gcode correspondant 
		points=pointsListIn
		gcodeOut=""
		
		# variables utiles 
		speed_down=self.doubleSpinBoxVitesse_descente.value() # mm/sec
		speed_up=self.doubleSpinBoxVitesse_remontee.value() #mm/sec
		speed_cut=self.doubleSpinBoxVitesse_decoupe.value() #mm/sec
		speed_travel=self.doubleSpinBoxVitesse_trajets.value() #mm/sec
		coeff_coord=3.54 # correction coord pixels vers mm
		profondeur_passe=self.doubleSpinBoxProfondeur.value() # profondeur de la passe

		
		print ("Chemin:")
		print (points) 
		
		for passe in range(1,self.spinBoxNombrePasses.value()+1): # on répète le nombre de fois voulu le chemin - passe 1 = 1
			
			if passe==self.spinBoxNombrePasses.value():
				profondeur_passe = (self.doubleSpinBoxProfondeur.value() * passe) + deltaLastIn # ajoute delta à dernière pour bien découper
			else:
				profondeur_passe = self.doubleSpinBoxProfondeur.value() * passe # profondeur courante = passe x profondeur passe

			# première ligne = goto simple
			if passe==1: # levage du Z que pour la premiere passe
				gcodeOut=gcodeOut+"G01 X"+"%.2f"%(points[0][0]/coeff_coord)+" Y"+"%.2f"%(points[0][1]/coeff_coord)+" Z5.0 F"+str(speed_travel)+"\n" # x,y => GO1 X00.00 Y00.00 Z5.00 \n (- Z=5 donc au dessus outil
			else: # les passes suivantes 
				gcodeOut=gcodeOut+"G01 X"+"%.2f"%(points[0][0]/coeff_coord)+" Y"+"%.2f"%(points[0][1]/coeff_coord)+"\n" # x,y => GO1 X00.00 Y00.00 Z5.00 \n (- Z=5 donc au dessus outil
			
			# descente outil à vitesse descente
			gcodeOut=gcodeOut+"G01 Z-"+str(profondeur_passe)+" F"+str(speed_down)+"\n" 
			
			# premiere ordre decoupe avec vitesse pour fixer la vitesse pour tous les points suivants
			gcodeOut=gcodeOut+"G01 X"+"%.2f"%(points[1][0]/coeff_coord)+" Y"+"%.2f"%(points[1][1]/coeff_coord)+" F"+str(speed_cut)+"\n"
			
			# defile les points de la 3ème ligne à la fin
			for point in points[2:]: 
				gcodeOut=gcodeOut+"G01 X"+"%.2f"%(point[0]/coeff_coord)+" Y"+"%.2f"%(point[1]/coeff_coord)+"\n"#+" Z0.0 \n" # x,y => GO1 X00.00 Y00.00 \n

			# dernière ligne entre dernier et premier point si flag Close est True
			if closeFlagIn:
				gcodeOut=gcodeOut+"G01 X"+"%.2f"%(points[0][0]/coeff_coord)+" Y"+"%.2f"%(points[0][1]/coeff_coord)+"\n" # x,y => GO1 X00.00 Y00.00 

			
			#relevé outil.. seulement à la dernière passe 
			if passe==self.spinBoxNombrePasses.value(): 
				gcodeOut=gcodeOut+"G01 Z5.0 F"+str(speed_up)+"\n" # relevage final outil 

		return gcodeOut

# -- Autres Classes utiles --

# -- Classe principale (lancement)  --
def main(args):
	a=QApplication(args) # crée l'objet application 
	f=QWidget() # crée le QWidget racine
	c=myApp(f) # appelle la classe contenant le code de l'application 
	f.show() # affiche la fenêtre QWidget
	r=a.exec_() # lance l'exécution de l'application 
	return r
	
if __name__=="__main__": # pour rendre le code exécutable 
	main(sys.argv) # appelle la fonction main
