class SurafaceTriangulationDialogTest(unittest.TestCase):
    """Test dialog works."""

    def setUp(self):
        """Runs before each test."""
        self.dialog = SurafaceTriangulationDialog(None)

    def tearDown(self):
        """Runs after each test."""
        self.dialog = None

    def test_dialog_ok(self):
        """Test we can click OK."""

        button = self.dialog.button_box.button(QDialogButtonBox.Ok)
        button.click()
        result = self.dialog.result()
        self.assertEqual(result, QDialog.Accepted)

    def test_dialog_cancel(self):
        """Test we can click cancel."""
        button = self.dialog.button_box.button(QDialogButtonBox.Cancel)
        button.click()
        result = self.dialog.result()
        self.assertEqual(result, QDialog.Rejected)
    def __init__(self, iface):
        """Constructor.

        :param iface: An interface instance that will be passed to this class
            which provides the hook by which you can manipulate the QGIS
            application at run time.
        :type iface: QgsInterface
        """
        # Save reference to the QGIS interface
        self.iface = iface
        # initialize plugin directory
        self.plugin_dir = os.path.dirname(__file__)
        # initialize locale
        locale = QSettings().value('locale/userLocale')[0:2]
        locale_path = os.path.join(
            self.plugin_dir,
            'i18n',
            'SurafaceTriangulation_{}.qm'.format(locale))

        if os.path.exists(locale_path):
            self.translator = QTranslator()
            self.translator.load(locale_path)

            if qVersion() > '4.3.3':
                QCoreApplication.installTranslator(self.translator)

        # Create the dialog (after translation) and keep reference
        self.dlg = SurafaceTriangulationDialog()

        # Declare instance attributes
        self.actions = []
        self.menu = self.tr(u'&Surface Triangulation')
        # TODO: We are going to let the user set this up in a future iteration
        self.toolbar = self.iface.addToolBar(u'SurafaceTriangulation')
        self.toolbar.setObjectName(u'SurafaceTriangulation')

        self.dlg.lineEdit.clear()
        self.dlg.pushButton.clicked.connect(self.select_output_file)
        self.dlg.rbVECTOR.clicked.connect(self.inputSwitch)
        self.dlg.rbASC.clicked.connect(self.inputSwitch)
        self.dlg.rbTXT.clicked.connect(self.outputSwitch)
        self.dlg.rbSTLASCII.clicked.connect(self.outputSwitch)
        self.dlg.rbSTLbinary.clicked.connect(self.outputSwitch)
        self.dlg.spinBox.setMaximum(100000)
class SurafaceTriangulation:
    """QGIS Plugin Implementation."""

    def __init__(self, iface):
        """Constructor.

        :param iface: An interface instance that will be passed to this class
            which provides the hook by which you can manipulate the QGIS
            application at run time.
        :type iface: QgsInterface
        """
        # Save reference to the QGIS interface
        self.iface = iface
        # initialize plugin directory
        self.plugin_dir = os.path.dirname(__file__)
        # initialize locale
        locale = QSettings().value('locale/userLocale')[0:2]
        locale_path = os.path.join(
            self.plugin_dir,
            'i18n',
            'SurafaceTriangulation_{}.qm'.format(locale))

        if os.path.exists(locale_path):
            self.translator = QTranslator()
            self.translator.load(locale_path)

            if qVersion() > '4.3.3':
                QCoreApplication.installTranslator(self.translator)

        # Create the dialog (after translation) and keep reference
        self.dlg = SurafaceTriangulationDialog()

        # Declare instance attributes
        self.actions = []
        self.menu = self.tr(u'&Surface Triangulation')
        # TODO: We are going to let the user set this up in a future iteration
        self.toolbar = self.iface.addToolBar(u'SurafaceTriangulation')
        self.toolbar.setObjectName(u'SurafaceTriangulation')

        self.dlg.lineEdit.clear()
        self.dlg.pushButton.clicked.connect(self.select_output_file)
        self.dlg.rbVECTOR.clicked.connect(self.inputSwitch)
        self.dlg.rbASC.clicked.connect(self.inputSwitch)
        self.dlg.rbTXT.clicked.connect(self.outputSwitch)
        self.dlg.rbSTLASCII.clicked.connect(self.outputSwitch)
        self.dlg.rbSTLbinary.clicked.connect(self.outputSwitch)
        self.dlg.spinBox.setMaximum(100000)
    # noinspection PyMethodMayBeStatic
    def tr(self, message):
        """Get the translation for a string using Qt translation API.

        We implement this ourselves since we do not inherit QObject.

        :param message: String for translation.
        :type message: str, QString

        :returns: Translated version of message.
        :rtype: QString
        """
        # noinspection PyTypeChecker,PyArgumentList,PyCallByClass
        return QCoreApplication.translate('SurafaceTriangulation', message)


    def add_action(
        self,
        icon_path,
        text,
        callback,
        enabled_flag=True,
        add_to_menu=True,
        add_to_toolbar=True,
        status_tip=None,
        whats_this=None,
        parent=None):
        """Add a toolbar icon to the toolbar.

        :param icon_path: Path to the icon for this action. Can be a resource
            path (e.g. ':/plugins/foo/bar.png') or a normal file system path.
        :type icon_path: str

        :param text: Text that should be shown in menu items for this action.
        :type text: str

        :param callback: Function to be called when the action is triggered.
        :type callback: function

        :param enabled_flag: A flag indicating if the action should be enabled
            by default. Defaults to True.
        :type enabled_flag: bool

        :param add_to_menu: Flag indicating whether the action should also
            be added to the menu. Defaults to True.
        :type add_to_menu: bool

        :param add_to_toolbar: Flag indicating whether the action should also
            be added to the toolbar. Defaults to True.
        :type add_to_toolbar: bool

        :param status_tip: Optional text to show in a popup when mouse pointer
            hovers over the action.
        :type status_tip: str

        :param parent: Parent widget for the new action. Defaults None.
        :type parent: QWidget

        :param whats_this: Optional text to show in the status bar when the
            mouse pointer hovers over the action.

        :returns: The action that was created. Note that the action is also
            added to self.actions list.
        :rtype: QAction
        """

        icon = QIcon(icon_path)
        action = QAction(icon, text, parent)
        action.triggered.connect(callback)
        action.setEnabled(enabled_flag)

        if status_tip is not None:
            action.setStatusTip(status_tip)

        if whats_this is not None:
            action.setWhatsThis(whats_this)

        if add_to_toolbar:
            self.toolbar.addAction(action)

        if add_to_menu:
            self.iface.addPluginToMenu(
                self.menu,
                action)

        self.actions.append(action)

        return action

    def initGui(self):
        """Create the menu entries and toolbar icons inside the QGIS GUI."""

        icon_path = ':/plugins/SurafaceTriangulation/icon.png'
        self.add_action(
            icon_path,
            text=self.tr(u'Create triangulation'),
            callback=self.run,
            parent=self.iface.mainWindow())


    def unload(self):
        """Removes the plugin menu item and icon from QGIS GUI."""
        for action in self.actions:
            self.iface.removePluginMenu(
                self.tr(u'&Surface Triangulation'),
                action)
            self.iface.removeToolBarIcon(action)
        # remove the toolbar
        del self.toolbar
        
    def select_output_file(self):
		if self.dlg.rbSTLASCII.isChecked() or self.dlg.rbSTLbinary.isChecked():
			filename = QFileDialog.getSaveFileName(self.dlg, "Select output file ", QDesktopServices.storageLocation(QDesktopServices.DocumentsLocation) , '*.stl')
			self.dlg.lineEdit.setText(filename)
		elif self.dlg.rbTXT.isChecked():
			filename = QFileDialog.getSaveFileName(self.dlg, "Select output file ", QDesktopServices.storageLocation(QDesktopServices.DocumentsLocation) , '*.txt')
			self.dlg.lineEdit.setText(filename)
			
    def inputSwitch(self):
		if self.dlg.rbVECTOR.isChecked():
			#self.dlg.rbSTLASCII.setDisabled(True)
			#self.dlg.rbSTLbinary.setDisabled(True)
			#self.dlg.rbTXT.setChecked(True)
			self.dlg.lineEdit.clear()
			#self.dlg.spinBox.setDisabled(True)
		#if self.dlg.rbASC.isChecked():
			#self.dlg.spinBox.setDisabled(False)
			#self.dlg.rbSTLASCII.setDisabled(False)
			#self.dlg.rbSTLbinary.setDisabled(False)
    def outputSwitch(self):
        self.dlg.lineEdit.clear()
		
    def run(self):
        """Run method that performs all the real work"""
        layers = self.iface.legendInterface().layers()
        layer_list = []
        for layer in layers:
            layer_list.append(layer.name())
        self.dlg.comboBox.clear()
        self.dlg.comboBox.addItems(layer_list)
        # show the dialog
        self.dlg.show()
        # Run the dialog event loop
        result = self.dlg.exec_()
        # See if OK was pressed
        if result:
            #Ciccia is here
            filename = str(self.dlg.lineEdit.text())
            selectedLayerIndex = self.dlg.comboBox.currentIndex()
            selectedLayer = layers[selectedLayerIndex]
			##=======CASE VECTOR LAYER=======##
            if self.dlg.rbVECTOR.isChecked():
				iter = selectedLayer.getFeatures()
				myList=[]
				##=======Reading feature 'ELEV' from vector contour layer=======##
				for feature in iter:
					entry=[]
					entry.append(feature['ELEV'])
					geom = feature.geometry()
					entry.append(geom.asPolyline())
					myList.append(entry)
					
				##=======Fitting data into variables=======##
				z=np.empty(0)
				xy=np.empty([0,2])
				n=self.dlg.spinBox.value()+1
				for i in range(0,len(myList)):
					index=0
					L=range(0,len(myList[i][1]),n)
					zz=np.zeros(len(L))
					xxyy=np.zeros((len(L),2))
					for j in L:
						zz[index]=myList[i][0]
						xxyy[index][0]=myList[i][1][j][0]
						xxyy[index][1]=myList[i][1][j][1]
						index+=1
					#xx=np.asarray(myList[i][1])[:,0]
					#yy=np.asarray(myList[i][1])[:,1]
					#xxyy=np.asarray(myList[i][1])
					#zz=np.empty(len(myList[i][1]))
					#zz.fill(myList[i][0])
					#x=np.hstack([x,xx])
					#y=np.hstack([y,yy])
					z=np.hstack([z,zz])
					xy=np.vstack([xy,xxyy])
				#Creating the scipy Spatial object
				#xyz=np.zeros((len(z),3))
				#xyz[:,0]=xy[:,0]
				#xyz[:,1]=xy[:,1]
				#xyz[:,2]=z
				tess = scipy.spatial.Delaunay(xy)
				xmin=tess.points[:, 0].min()
				ymin=tess.points[:, 1].min()
				#To avoid large numbers
				for i in range(0,len(tess.points)):
					tess.points[i, 0]=tess.points[ i, 0]-xmin
					tess.points[i, 1]=tess.points[i, 1]-ymin
				x=tess.points[:,0]
				y=tess.points[:,1]
				#Creating the matplotlib Triangulation object
				tri = tess.simplices # tess.vertices is deprecated
				triang = mtri.Triangulation(x, y, triangles=tri)
				##=======Eliminating excessively flat border triangles from the triangulation=======##
				filteringMask=mtri.TriAnalyzer(triang).get_flat_tri_mask(min_circle_ratio=0.01, rescale=True)
				triang.set_mask(filteringMask)
				triangFiltered=triang.get_masked_triangles()
				##triangFiltered is not a mtri object, but numpy.ndarray
				##=======Writing TXT file=======##
				if self.dlg.rbTXT.isChecked():
					with open(filename, 'w') as myFile:
						for i in range(0,len(x)):
							##??Print only useful points??##
							s="{0} {1:.2f} {2:.2f} {3:.2f}\n".format(i, x[i], y[i], z[i])
							myFile.write(s)
						for i in range(0,len(triangFiltered)):
							myFile.write(np.array_str(triangFiltered[i]))
							myFile.write("\n")
						
				##=======Writing STL file (Itasca)=======##
				if self.dlg.rbSTLASCII.isChecked() or self.dlg.rbSTLbinary.isChecked():
					data = np.zeros(len(triangFiltered), dtype=mesh.Mesh.dtype)
					for i in range(0,len(triangFiltered)):
						data['vectors'][i]=np.array([[x[triangFiltered[i][0]],y[triangFiltered[i][0]],z[triangFiltered[i][0]]],
													 [x[triangFiltered[i][1]],y[triangFiltered[i][1]],z[triangFiltered[i][1]]],
													 [x[triangFiltered[i][2]],y[triangFiltered[i][2]],z[triangFiltered[i][2]]]])
					your_mesh = mesh.Mesh(data, remove_empty_areas=False)
					your_mesh.normals
					##!!!!!mode=1 forces to ASCII mode=2 BINARY mode = 0 AUTOMATIC!!!!!##
					if self.dlg.rbSTLASCII.isChecked():
						userChooses=1
					elif self.dlg.rbSTLbinary.isChecked():
						userChooses=2
					your_mesh.save(filename,mode=userChooses)
				##=======Plotting with matplotlib=======##
				if self.dlg.checkBox.isChecked():
					fig = plt.figure()
					ax = fig.gca(projection='3d')
					ax.plot_trisurf(triang, z, cmap=cm.Spectral, linewidth=0.05)
					ax.view_init(elev=20, azim=45)
					#TG
					#elev=10 azim=120
					#ROASCHIA
					#elev=20, azim=45
					plt.show()
					

			##=======CASE ASC LAYER=======#
            elif self.dlg.rbASC.isChecked():
				##Reading all ASC file
				layerPath=selectedLayer.source()
				altitude = np.loadtxt(layerPath, skiprows=6)
				ncol=int(re.findall("[-+]?\d+[\.]?\d*", linecache.getline(layerPath,1))[0])
				nrow=int(re.findall("[-+]?\d+[\.]?\d*", linecache.getline(layerPath,2))[0])
				xllcorner=float(re.findall("[-+]?\d+[\.]?\d*", linecache.getline(layerPath,3))[0])
				yllcorner=float(re.findall("[-+]?\d+[\.]?\d*", linecache.getline(layerPath,4))[0])
				cellsize=float(re.findall("[-+]?\d+[\.]?\d*", linecache.getline(layerPath,5))[0])
				NODATA=float(re.findall("[-+]?\d+[\.]?\d*", linecache.getline(layerPath,6))[0])
				##Properly matrix reshape: otherwise EST and WEST would be swapped
				altitude=np.flipud(altitude)
				##=======Initializing variables and reshaping data read before=======##
				##Reading data every n cells
				##e.g. n=2 
				##  read skip read skip...
				##  skip skip skip skip...
				##  read skip read skip...
				##  ...
				##Remember, in the interface we are asking the user to specify the entries to skip,
				##so n=readValue+1
				n=self.dlg.spinBox.value()+1
				if n>ncol-1 or n>nrow-1:
					raise IOError, "Cant read the grid, n must be lower"
				numOfX=len(range(0,nrow,n))
				numOfY=len(range(0,ncol,n))
				##Creating arrays and reshaping needed read data into them
				x=np.zeros(numOfX*numOfY)
				y=np.zeros(numOfX*numOfY)
				altitudeResized=np.zeros(numOfX*numOfY)
				index=0
				for j in range(0,nrow,n):
					for i in range(0,ncol,n):
					   altitudeResized[index]=altitude[j][i] 
					   index+=1
				del altitude
				for j in range(0,numOfX):
					for i in range(0,numOfY):
						x[j*numOfY+i]=n*i*cellsize
				for j in range(0,numOfX):
					for i in range(0,numOfY):
						y[j*numOfY+i]=n*j*cellsize
						
				triangulationUp=np.zeros(((numOfY-1)*(numOfX-1),3),dtype=int)
				triangulationLo=np.zeros(((numOfY-1)*(numOfX-1),3),dtype=int)
				
				##=======Creating Triangulation for plot or txt file if specified=======##
				#4 points of the grid determine a square divided into 2 triangles:
				#	*---------------------------*
				#	|**                         |
				#	|  **                       |
				#	|    *                      |
				#	|     **                    |
				#	|       **                  |
				#	|         *         trUp    |
				#	|          **               |
				#	|            **             |
				#	|              *            |
				#	|               **          |
				#	|     trLo        *         |
				#	|                  **       |
				#	|                    **     |
				#	*---------------------------*
				if self.dlg.rbTXT.isChecked() or self.dlg.checkBox.isChecked():
					for j in range(0,numOfX-1):
							for i in range(0,numOfY-1):
								trUp=[j*numOfY+i,(j+1)*numOfY+i+1,j*numOfY+i+1]
								trLo=[j*numOfY+i,(j+1)*numOfY+i,(j+1)*numOfY+i+1]
								triangulationUp[i+(j*(numOfY-1))]=trUp
								triangulationLo[i+(j*(numOfY-1))]=trLo
				
				##=======Writing TXT file=======##
				if self.dlg.rbTXT.isChecked():
					with open(filename,'w') as myFile:
						##POINTS	
						for i in range(0,len(x)):
							s="{0} {1:.2f} {2:.2f} {3:.2f}\n".format(i, x[i], y[i], altitudeResized[i])
							myFile.write(s)
						##TRIANGLES
						for i in range(0,np.shape(triangulationUp)[0]):
							s="{0} {1} {2} \n{3} {4} {5}\n".format(triangulationUp[i][0],triangulationUp[i][1],triangulationUp[i][2],triangulationLo[i][0],triangulationLo[i][1],triangulationLo[i][2])
							myFile.write(s)

				##=======Writing STL file (Itasca)=======##
				if self.dlg.rbSTLASCII.isChecked() or self.dlg.rbSTLbinary.isChecked():
					data = np.zeros(2*(numOfX-1)*(numOfY-1), dtype=mesh.Mesh.dtype)
					index=0
					for j in range(0,numOfX-1):
						for i in range(0,numOfY-1):
							#Upper triangle of the cell (trUp)
							data['vectors'][index]=np.array([[x[j*numOfY+i],y[j*numOfY+i],altitudeResized[j*numOfY+i]],
															 [x[(j+1)*numOfY+i+1],y[(j+1)*numOfY+i+1],altitudeResized[(j+1)*numOfY+i+1]],
															 [x[j*numOfY+i+1],y[j*numOfY+i+1],altitudeResized[j*numOfY+i+1]]])
							#Lower triangle of the cell tr(Lo)
							data['vectors'][(numOfY-1)*(numOfX-1)+index]=np.array([[x[j*numOfY+i],y[j*numOfY+i],altitudeResized[j*numOfY+i]],
																				   [x[(j+1)*numOfY+i],y[(j+1)*numOfY+i],altitudeResized[(j+1)*numOfY+i]],
																				   [x[(j+1)*numOfY+i+1],y[(j+1)*numOfY+i+1],altitudeResized[(j+1)*numOfY+i+1]]])
							index+=1
													
					your_mesh = mesh.Mesh(data, remove_empty_areas=False)
					your_mesh.normals
					##!!!!!mode=1 forces to ASCII mode=2 BINARY mode = 0 AUTOMATIC!!!!!##
					if self.dlg.rbSTLASCII.isChecked():
						userChooses=1
					elif self.dlg.rbSTLbinary.isChecked():
						userChooses=2
					your_mesh.save(filename,mode=userChooses)

				##=======Plotting with matplotlib if specified=======##
				if self.dlg.checkBox.isChecked():
					tri=np.vstack((triangulationUp, triangulationLo))
					triang = mtri.Triangulation(x, y, triangles=tri)
					fig = plt.figure()
					ax = fig.gca(projection='3d')
					ax.plot_trisurf(triang, altitudeResized, cmap=cm.Spectral, linewidth=0.05)
					ax.view_init(elev=20, azim=45)
					#TG
					#elev=10 azim=115
					#ROASCHIA
					#elev=20, azim=45
					plt.show()
 def setUp(self):
     """Runs before each test."""
     self.dialog = SurafaceTriangulationDialog(None)