#!/usr/bin/env python

"""
Distances from markers to segmented lines from imageJ
(c) Olivier Friard 2012

"""

from __future__ import division

prog_name = 'distances'
__version__ = '2'

#import PyQt5
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *

import sys
from math import *
import xml.etree.ElementTree as ET



def parse_xml(infile):

    max_type = -1
    markers = []
    tree = ET.parse(infile)
    root = tree.getroot()

    for contour in root.getiterator('Marker_Type'):
        type_ = contour.findtext('Type')

        #print 'type:', type_
        
        for point in contour.getiterator('Marker'):
            #print point.get('MarkerX')
            mx = point.findtext('MarkerX')
            my = point.findtext('MarkerY')
            markers.append( (int(type_), (int(mx), int(my))) )
            max_type = max( max_type, int(type_) )

    return markers, max_type


def DistancePointLine(P, M1, M2):
    """
    return distance from a point to a segment
    """

    EPS = 0
    EPSEPS = EPS * EPS

    def SqLineMagnitude(x1, y1, x2, y2):
        return (x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1)

    px, py = P
    x1, y1 = M1
    x2, y2 = M2

    result = 0

    SqLineMag = SqLineMagnitude(x1, y1, x2, y2)
    if SqLineMag < EPSEPS:
        return - 1.0

    u = ((px - x1) * (x2 - x1) + (py - y1) * (y2 - y1)) / SqLineMag

    if (u < EPS) or (u > 1):
        ###  Closest point does not fall within the line segment,
        ###  take the shorter distance to an endpoint
        d1 = SqLineMagnitude(px, py, x1, y1)
        d2 = SqLineMagnitude(px, py, x2, y2)
        if d1 <= d2:
            result = d1
            ix, iy = x1, y1
        else:
            result = d2
            ix, iy = x2, y2

    else:

        ###  Intersecting point is on the line, use the formula
        ix = x1 + u * (x2 - x1)
        iy = y1 + u * (y2 - y1)
        result = SqLineMagnitude(px, py, ix, iy)


    return sqrt(result), (ix, iy)


class MainWindow(QMainWindow):

    def __init__(self, parent=None):

        super(MainWindow, self).__init__(parent)
        
        self.resize(800, 340)
        self.setWindowTitle("")
        self.centralwidget = QWidget()
        self.centralwidget.setObjectName("centralwidget")
        self.gridLayout_2 = QGridLayout(self.centralwidget)
        self.gridLayout_2.setObjectName("gridLayout_2")
        self.gridLayout = QGridLayout()
        self.gridLayout.setObjectName("gridLayout")
        self.label = QLabel(self.centralwidget)
        self.label.setObjectName("label")
        self.gridLayout.addWidget(self.label, 0, 0, 1, 1)
        self.leFilename1 = QLineEdit(self.centralwidget)
        self.leFilename1.setObjectName("leFilename1")
        self.gridLayout.addWidget(self.leFilename1, 0, 1, 1, 1)
        self.pbBrowse1 = QPushButton(self.centralwidget)
        self.pbBrowse1.setObjectName("pbBrowse1")
        self.gridLayout.addWidget(self.pbBrowse1, 0, 2, 1, 1)
        self.lbFileSQL = QLabel(self.centralwidget)
        self.lbFileSQL.setObjectName("lbFileSQL")
        self.gridLayout.addWidget(self.lbFileSQL, 1, 0, 1, 1)
        self.leFilename2 = QLineEdit(self.centralwidget)
        self.leFilename2.setObjectName("leFilename2")
        self.gridLayout.addWidget(self.leFilename2, 1, 1, 1, 1)
        self.pbBrowse2 = QPushButton(self.centralwidget)
        self.pbBrowse2.setObjectName("pbBrowse2")
        self.gridLayout.addWidget(self.pbBrowse2, 1, 2, 1, 1)
        self.lbFileSQL_2 = QLabel(self.centralwidget)
        self.lbFileSQL_2.setObjectName("lbFileSQL_2")
        self.gridLayout.addWidget(self.lbFileSQL_2, 2, 0, 1, 1)
        self.leResultsFilename = QLineEdit(self.centralwidget)
        self.leResultsFilename.setObjectName("leResultsFilename")
        self.gridLayout.addWidget(self.leResultsFilename, 2, 1, 1, 1)
        self.pbBrowseResults = QPushButton(self.centralwidget)
        self.pbBrowseResults.setObjectName("pbBrowseResults")
        self.gridLayout.addWidget(self.pbBrowseResults, 2, 2, 1, 1)
        self.pbOK = QPushButton(self.centralwidget)
        self.pbOK.setObjectName("pbOK")
        self.gridLayout.addWidget(self.pbOK, 3, 0, 1, 2)
        self.gridLayout_2.addLayout(self.gridLayout, 0, 0, 1, 1)
        self.setCentralWidget(self.centralwidget)
        self.menubar = QMenuBar(self)
        self.menubar.setGeometry(QRect(0, 0, 821, 29))
        self.menubar.setObjectName("menubar")
        self.menuHelp = QMenu(self.menubar)
        self.menuHelp.setObjectName("menuHelp")
        self.setMenuBar(self.menubar)
        self.statusbar = QStatusBar(self)
        self.statusbar.setObjectName("statusbar")
        self.setStatusBar(self.statusbar)
        self.actionAbout = QAction(self)
        self.actionAbout.setObjectName("actionAbout")
        self.menuHelp.addAction(self.actionAbout)
        self.menubar.addAction(self.menuHelp.menuAction())
        

        self.label.setText( "file with segmented line coordinates")
        self.pbBrowse1.setText("Browse")
        self.lbFileSQL.setText("file with markers (XML)")
        self.pbBrowse2.setText( "Browse")
        self.lbFileSQL_2.setText( "results file")
        self.pbBrowseResults.setText( "Browse")
        self.pbOK.setText( "Run")
        self.menuHelp.setTitle( "Help")
        self.actionAbout.setText( "About")

        
        self.connections()

    def connections(self):

        self.setWindowTitle(prog_name + ' v. %s' % (__version__))

        self.actionAbout.triggered.connect(self.actionAbout_activated)
        
        self.pbBrowse1.clicked.connect(self.pbBrowse1_clicked)
               
        self.pbBrowse2.clicked.connect(self.pbBrowse2_clicked)
        
        self.pbBrowseResults.clicked.connect(self.pbBrowseResults_clicked)

        self.pbOK.clicked.connect(self.pbOK_clicked)


    def actionAbout_activated(self):
        QMessageBox.about(self, prog_name, 'Copyright Olivier Friard<br>version %s - PySide: %s' % (__version__,PySide.__version__))

    def pbBrowse1_clicked(self):
        self.statusbar.showMessage('Open file', 5000)
        fd = QFileDialog(self)
        filename = fd.getOpenFileName(self, 'Open file', '', 'All files files (*)')[0]
        if filename:
            self.leFilename1.setText(filename)


    def pbBrowse2_clicked(self):
        self.statusbar.showMessage('Open file', 5000)
        fd = QFileDialog(self)
        filename = fd.getOpenFileName(self, 'Open file', '', 'All files (*)')[0]
        if filename:
            self.leFilename2.setText(filename)

    def pbBrowseResults_clicked(self):
        self.statusbar.showMessage('Select file for results', 5000)
        fd = QFileDialog(self)
        filename = fd.getSaveFileName(self, 'Save file', '', 'All files (*)')[0]
        if filename:
            self.leResultsFilename.setText(filename)


    def pbOK_clicked(self):

        ### check files
        if not self.leFilename1.text() or not self.leFilename2.text() or not self.leResultsFilename.text():
            QMessageBox.warning(self, prog_name, 'Please indicate all files')
            return

        self.statusbar.showMessage('Please wait...', 0)


        ### doing some analysis
        
        points_str = open(  self.leFilename1.text() ).readlines()

        line = []
        
        for point_str in points_str:
            x, y = point_str.strip().split('\t')
            line.append((int(x),int(y)))
            
        #print line
        
        markers, max_type = parse_xml(self.leFilename2.text())
        
        print(markers)
        print(max_type)
        
        #print 'Number of markers:', len(markers)
        
        
        results = {}
        
        for m in markers:    
        
            dmin = 1e6
            for i in range( len(line) - 1):
                
                x1 = line [i]
                x2 = line [i + 1]
            
                d, dummy = DistancePointLine(m[1], x1, x2)
        
                dmin = min(d, dmin)
        
        
            if m[0] in results:
                results[m[0]].append(dmin)
            else:
                results[m[0]] = [dmin]
                
        
        #print results
        
        out = ''
        
        for i in range(1, max_type +1):
            if i in results:
                out += str(i) + '\t'
        
        out += '\n'
        
        while True:
            
            not_empty = True
            for i in range(1, max_type + 1):
                #print 'i',i
                if i in results:
                    if results[i]:
                        #print 'results[i]', i, results[i]
                        d = results[i].pop(0)
                        #print 'results[i]', i, results[i]
                        out += str(d) + '\t'
            
                        if results[i]:
                            not_empty = False
                    else:
                        out +=  '\t'
               
            out += '\n'
        
        
            if not_empty:
                break
         
        print(out)

        
        
        
        
        
        
        
        f = open(self.leResultsFilename.text(),'w')
        f.write(out)
        f.close()
        

        self.statusbar.showMessage('Done', 5000)

if __name__ == "__main__":

    app = QApplication(sys.argv)
    mainWindow = MainWindow()
    mainWindow.show()
    mainWindow.raise_()
    sys.exit(app.exec_())

