#!/usr/bin/env python

#  Copyright 2019 Maurice https://github.com/easyw/

# some source tips @
# https://github.com/bpkempke/kicad-scripts
# https://github.com/MitjaNemec/Kicad_action_plugins
# https://github.com/jsreynaud/kicad-action-scripts

# GNU GENERAL PUBLIC LICENSE
#                        Version 3, 29 June 2007
# 
#  Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
#  Everyone is permitted to copy and distribute verbatim copies
#  of this license document, but changing it is not allowed.
#
#  This program is free software; you can redistribute it and/or modify
#  it under the terms of the GNU General Public License as published by
#  the Free Software Foundation.
#
#  This program is distributed in the hope that it will be useful,
#  but WITHOUT ANY WARRANTY; without even the implied warranty of
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#  GNU General Public License for more details.
#
#  You should have received a copy of the GNU General Public License
#  along with this program; if not, write to the Free Software
#  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
#  MA 02110-1301, USA.

# import round_trk; reload(round_trk)

## todo:
# 1) insert check drc for rounding & fencing
# 2) add radius as text to rounded curve
# 3) add selected track lenght

import sys
import os
from pcbnew import *
import wx
import pcbnew
import math
import cmath

#from .RoundTrackDlg import RoundTrackDlg
from . import RoundTrackDlg


ToUnits=pcbnew.ToMM #ToMils
FromUnits=pcbnew.FromMM #Mils

debug = False #True
debug2 = False
show_points = False
show_points2 = False

global delete_before_connect
delete_before_connect = False

# N_SEGMENTS = 32 #4#32
# distI = FromMM(10)

# import pcbnew; print (pcbnew.PLUGIN_DIRECTORIES_SEARCH)

# Python plugin stuff

class RoundTrack_Dlg(RoundTrackDlg.RoundTrackDlg):
    # from https://github.com/MitjaNemec/Kicad_action_plugins
    # hack for new wxFormBuilder generating code incompatible with old wxPython
    # noinspection PyMethodOverriding
    def SetSizeHints(self, sz1, sz2):
        if wx.__version__ < '4.0':
            self.SetSizeHintsSz(sz1, sz2)
        else:
            super(RoundTrack_Dlg, self).SetSizeHints(sz1, sz2)

    def onDeleteClick(self, event):
        return self.EndModal(wx.ID_DELETE)

    def onConnectClick(self, event):
        return self.EndModal(wx.ID_REVERT)

    def __init__(self,  parent):
        global delete_before_connect
        import wx
        RoundTrackDlg.RoundTrackDlg.__init__(self, parent)
        #self.GetSizer().Fit(self)
        self.SetMinSize(self.GetSize())
        self.m_buttonDelete.Bind(wx.EVT_BUTTON, self.onDeleteClick)
        self.m_buttonReconnect.Bind(wx.EVT_BUTTON, self.onConnectClick)
        if wx.__version__ < '4.0':
            self.m_buttonReconnect.SetToolTipString( u"Select two converging Tracks to re-connect them\nor Select tracks including one round corner to be straighten" )
            self.m_buttonRound.SetToolTipString( u"Select two connected Tracks to round the corner\nThen choose distance from intersection and the number of segments" )
        else:
            self.m_buttonReconnect.SetToolTip( u"Select two converging Tracks to re-connect them\nor Select tracks including one round corner to be straighten" )
            self.m_buttonRound.SetToolTip( u"Select two connected Tracks to round the corner\nThen choose distance from intersection and the number of segments" )
        if self.m_checkBoxDelete.IsChecked():
            delete_before_connect = True
            
#
class Tracks_Rounder(pcbnew.ActionPlugin):

    def defaults(self):
        self.name = "Rounder for Tracks\nversion 2.1"
        self.category = "Modify PCB"
        self.description = "Rounder for selected Traces on the PCB"
        self.icon_file_name = os.path.join(os.path.dirname(__file__), "./round_track.png")
        self.show_toolbar_button = True

    def Warn(self, message, caption='Warning!'):
        dlg = wx.MessageDialog(
            None, message, caption, wx.OK | wx.ICON_WARNING)
        dlg.ShowModal()
        dlg.Destroy()

    def CheckDistanceInput(self, value, data):
        val = None
        try:
            val = float(value.replace(',','.'))
            if val <= 0:
                raise Exception("Invalid")
        except:
            self.Warn(
                "Invalid parameter for %s: Must be a positive number" % data)
            val = None
        return val

    def CheckSegmentsInput(self, value, data):
        val = None
        try:
            val = int(value)
            if (val < 2) or (val >32):
                raise Exception("Invalid")
        except:
            self.Warn(
                "Invalid parameter for %s: Must be bigger than 2" % data)
            val = None
        return val

    def Run(self):
        global delete_before_connect
        #self.pcb = GetBoard()
        # net_name = "GND"
        pcb = pcbnew.GetBoard()
        
        #from https://github.com/MitjaNemec/Kicad_action_plugins
        #hack wxFormBuilder py2/py3
        _pcbnew_frame = [x for x in wx.GetTopLevelWindows() if x.GetTitle().lower().startswith('pcbnew')][0]
        #aParameters = RoundTrackDlg(None)
        aParameters = RoundTrack_Dlg(_pcbnew_frame)
        if hasattr (pcb, 'm_Uuid'):
            aParameters.m_buttonDelete.Disable()
            aParameters.m_checkBoxDelete.Disable()
        #aParameters = RoundTrack_DlgEx(_pcbnew_frame)
        aParameters.Show()
        #end hack
        aParameters.m_distanceMM.SetValue("5")
        aParameters.m_segments.SetValue("16")
        aParameters.m_bitmap1.SetBitmap(wx.Bitmap( os.path.join(os.path.dirname(os.path.realpath(__file__)), "round_track_help.png") ) )
        modal_result = aParameters.ShowModal()
        segments = self.CheckSegmentsInput(
            aParameters.m_segments.GetValue(), "number of segments")
        distI = FromMM(self.CheckDistanceInput(aParameters.m_distanceMM.GetValue(), "distance from intersection"))
        if aParameters.m_checkBoxDelete.IsChecked():
            delete_before_connect = True
        else:
            delete_before_connect = False
        if segments is not None and distI is not None:
            if modal_result == wx.ID_OK:
                Round_Selection(pcb, distI, segments)
            elif modal_result == wx.ID_DELETE:
                Delete_Segments(pcb)
                #wx.LogMessage('Round Segments on Track Net Deleted')
            elif modal_result == wx.ID_REVERT:
                wxLogDebug('Connecting Tracks',debug)
                Connect_Segments(pcb)
            else:
                None  # Cancel
        else:
            None  # Invalid input
        aParameters.Destroy()
        
        #Round_Selection(pcb)
#


def wxLogDebug(msg,show):
    """printing messages only if show is omitted or True"""
    if show:
        wx.LogMessage(msg)
# 
def distance (p1,p2):
    return math.hypot(p1.y-p2.y,p1.x-p2.x)
#
#gets the angle of a track
def getTrackAngle(t1,center):
	#use atan2 so the correct quadrant is returned
    if t1.GetStart().x == center.x and t1.GetStart().y == center.y:
        wxLogDebug("Start = Center",debug)
        return math.atan2((t1.GetEnd().y - t1.GetStart().y), (t1.GetEnd().x - t1.GetStart().x))
    else:
        wxLogDebug("End = Center",debug)
        return math.atan2((t1.GetStart().y - t1.GetEnd().y), (t1.GetStart().x - t1.GetEnd().x));
#
#track length
def GetTrackLength(t1):
	return t1.GetLength()
#
def create_Track(pcb,p1,p2,lyr=None,w=None,Nn=None,Ts=None):
    #draw segment to test
    #new_line = pcbnew.DRAWSEGMENT(pcb)
    new_line = pcbnew.TRACK(pcb)
    new_line.SetStart(p1)
    new_line.SetEnd(p2)
    if w is None:
        new_line.SetWidth(FromUnits(1.5)) #FromUnits(int(mask_width)))
    else:
        new_line.SetWidth(FromUnits(w))
    if lyr is None:
        lyr = F_SilkS
    if Nn is not None:
        new_line.SetNet(Nn)
        #new_line.SetNetname(Nn)
    new_line.SetLayer(lyr) #pcbnew.F_SilkS) #pcb.GetLayerID(mask_layer))
    if Ts is not None:
        tsc = 0
        Nname = new_line.GetNetname()
        for c in Nname:
            tsc = tsc + ord(c)
        if hasattr(new_line, 'SetTimeStamp'):
            new_line.SetTimeStamp(tsc)  # adding a unique number (this netname) as timestamp to mark this segment as generated by this script on this netname
    pcb.Add(new_line)
    return new_line
#
def create_Draw(pcb,p1,p2,lyr=None,w=None):
    #draw segment to test
    new_line = pcbnew.DRAWSEGMENT(pcb)
    #new_line = pcbnew.TRACK(pcb)
    new_line.SetStart(p1)
    new_line.SetEnd(p2)
    if w is None:
        new_line.SetWidth(FromUnits(1.5)) #FromUnits(int(mask_width)))
    else:
        new_line.SetWidth(FromUnits(w))
    if lyr is None:
        lyr = F_SilkS
    new_line.SetLayer(lyr) #pcbnew.F_SilkS) #pcb.GetLayerID(mask_layer))
    pcb.Add(new_line)
    return new_line
#
def create_Text(pcb, txt, p, w, lyr):
    mytxt = pcbnew.TEXTE_PCB(pcb)
    mytxt.SetText(txt)
    mytxt.SetLayer(lyr)
    mytxt.SetPosition(p)
    mytxt.SetHorizJustify(pcbnew.GR_TEXT_HJUSTIFY_CENTER)
    mytxt.SetTextSize(pcbnew.wxSize(w,w))
    if hasattr(mytext, 'SetThickness'):
        mytxt.SetThickness(int(w/4))
    else:
        mytxt.SetTextThickness(int(w/4))
    pcb.Add(mytxt)
#

def getAngleRadians(p1,p2):
    #return math.degrees(math.atan2((p1.y-p2.y),(p1.x-p2.x)))
    return (math.atan2((p1.y-p2.y),(p1.x-p2.x)))
#

def rotatePoint(r,sa,da,c):
    # sa, da in radians
    x = c.x - math.cos(sa+da) * r
    y = c.y - math.sin(sa+da) * r
    return wxPoint(x,y)

def create_round_segments(pcb,sp,a1,ep,a2,cntr,rad,layer,width,Nn,N_SEGMENTS):
    start_point = sp
    end_point = ep
    pos = sp
    next_pos = ep
    a1 = getAngleRadians(cntr,sp)
    a2 = getAngleRadians(cntr,ep)
    wxLogDebug('a1:'+str(math.degrees(a1))+' a2:'+str(math.degrees(a2))+' a2-a1:'+str(math.degrees(a2-a1)),debug)
    if (a2-a1) > 0 and abs(a2-a1) > math.radians(180):
        deltaA = -(math.radians(360)-(a2-a1))/N_SEGMENTS
        wxLogDebug('deltaA reviewed:'+str(math.degrees(deltaA)),debug)
    elif (a2-a1) < 0 and abs(a2-a1) > math.radians(180):
        deltaA = (math.radians(360)-abs(a2-a1))/N_SEGMENTS
        wxLogDebug('deltaA reviewed2:'+str(math.degrees(deltaA)),debug)
    else:
        deltaA = (a2-a1)/N_SEGMENTS
    delta=deltaA
    wxLogDebug('delta:'+str(math.degrees(deltaA))+' radius:'+str(ToMM(rad)),debug)
    points = []
    #import round_trk; import importlib; importlib.reload(round_trk)
    for ii in range (N_SEGMENTS+1): #+1):
        points.append(pos)
        #t = create_Track(pos,pos)
        prv_pos = pos
        #pos = pos + fraction_delta
        #posPolar = cmath.polar(pos)
        #(rad) * cmath.exp(math.radians(deltaA)*1j) #cmath.rect(r, phi) : Return the complex number x with polar coordinates r and phi.
        #pos = wxPoint(posPolar.real+sp.x,posPolar.imag+sp.y)
        pos = rotatePoint(rad,a1,delta,cntr)
        delta=delta+deltaA
        wxLogDebug("pos:"+str(ToUnits(prv_pos.x))+":"+str(ToUnits(prv_pos.y))+";"+str(ToUnits(pos.x))+":"+str(ToUnits(pos.y)),debug)
    for i, p in enumerate(points):
        #if i < len (points)-1:
        if i < len (points)-2:
            t = create_Track(pcb,p,points[i+1],layer,width,Nn,True) #adding ts code to segments
    t = create_Track(pcb,points[-2],ep,layer,width,Nn,True) #avoiding rounding on last segment
    return points[-1]
#

def create_round_points(pcb,sp,a1,ep,a2,cntr,rad,N_SEGMENTS):
    #TODO: Put some error checking in here...
    #Re-order the two converging tracks if we're selecting the startpoint
    start_point = sp
    end_point = ep
    pos = sp
    next_pos = ep
    wxLogDebug('sp:'+str(ToMM(sp))+';ep:'+str(ToMM(ep))+';cntr:'+str(ToMM(cntr)),debug)
    a1 = getAngleRadians(cntr,sp)
    a2 = getAngleRadians(cntr,ep)
    wxLogDebug('sp:'+str(ToMM(sp))+';ep:'+str(ToMM(ep))+';cntr:'+str(ToMM(cntr)),debug)
    wxLogDebug('a1:'+str(math.degrees(a1))+' a2:'+str(math.degrees(a2))+' a2-a1:'+str(math.degrees(a2-a1)),debug)
    #if a1 < 0:
    #    a1 = math.radians(180) -a1
    #if a2 < 0:
    #    a2 = math.radians(180) -a2
    if (a2-a1) > 0 and abs(a2-a1) > math.radians(180):
        deltaA = -(math.radians(360)-(a2-a1))/N_SEGMENTS
        wxLogDebug('deltaA reviewed:'+str(math.degrees(deltaA)),debug)
    elif (a2-a1) < 0 and abs(a2-a1) > math.radians(180):
        deltaA = (math.radians(360)-abs(a2-a1))/N_SEGMENTS
        wxLogDebug('deltaA reviewed2:'+str(math.degrees(deltaA)),debug)
    else:
        deltaA = (a2-a1)/N_SEGMENTS
    delta=deltaA
    wxLogDebug('delta:'+str(math.degrees(deltaA))+' radius:'+str(ToMM(rad)),debug)
    points = []
    #import round_trk; import importlib; importlib.reload(round_trk)
    for ii in range (N_SEGMENTS+1):
        points.append(pos)
        #t = create_Track(pos,pos)
        prv_pos = pos
        #pos = pos + fraction_delta
        #posPolar = cmath.polar(pos)
        #(rad) * cmath.exp(math.radians(deltaA)*1j) #cmath.rect(r, phi) : Return the complex number x with polar coordinates r and phi.
        #pos = wxPoint(posPolar.real+sp.x,posPolar.imag+sp.y)
        pos = rotatePoint(rad,a1,delta,cntr)
        delta=delta+deltaA
        wxLogDebug("pos:"+str(ToUnits(prv_pos.x))+":"+str(ToUnits(prv_pos.y))+";"+str(ToUnits(pos.x))+":"+str(ToUnits(pos.y)),debug)
    for i, p in enumerate(points):
        if i < len (points):
            t = create_Draw(pcb,p,p,B_CrtYd,0.5+i*0.05)
#
def not_eq(a,b):
    if abs(a-b) >= 1: #1nm
        return True
    else:
        return False
#

def getCircleCenterRadius(sp,ep,ip):
    #center
    # NB add always set float even if values are pcb internal Units!!!
    x1 = float(sp.x); y1 = float(sp.y)
    x2 = float(ep.x); y2 = float(ep.y)
    xi = float(ip.x); yi = float(ip.y)
    # mg formula
    cxN = (y2-y1)*(yi-y1)*(yi-y2)-(xi-x1)*x1*(yi-y2)+(xi-x2)*x2*(yi-y1)
    cxD = -x2*yi-xi*y1+x2*y1+xi*y2+x1*yi-x1*y2
    if cxD != 0:
        Cx = cxN/cxD
    else:
        #stop
        Cx= FromMM(100)
    wxLogDebug(str(ToMM(y1))+':'+str(ToMM(yi))+':'+str(ToMM(y2)),debug)
    wxLogDebug(str(ToMM(x1))+':'+str(ToMM(xi))+':'+str(ToMM(x2)),debug)
    if not_eq(yi,y1):
        Cy = y1 - (xi-x1)/(yi-y1)*(Cx-x1)
    elif yi==y1 and (yi!=y2):
        Cx = x1
        Cy = y2 - (xi-x2)/(yi-y2)*(Cx-x2)
    elif yi==y2 and (yi!=y1):
        Cx = x2
        Cy = y1 - (xi-x1)/(yi-y1)*(Cx-x1)
    else:
        Cy = FromMM(100)
    # import round_trk; reload(round_trk)
    # import round_trk; import importlib; importlib.reload(round_trk)
    
    radius = math.hypot(Cx-sp.x,Cy-sp.y)
    return wxPoint(Cx,Cy), radius
#
def deleteSelectedTracks(pcb):
    tracks = pcb.GetTracks()
    tracks_cp = list(tracks)
    l = len (tracks_cp)
    for i in range(l):
        if type(tracks_cp[i]) is TRACK and tracks_cp[i].IsSelected(): #item.GetNetname() == net_name:
            pcb.RemoveNative(tracks_cp[i])
    #for item in pcb.GetTracks():
    #    if type(item) is TRACK and item.IsSelected(): #item.GetNetname() == net_name:
    #        pcb.RemoveNative(item)
    #        #pcb.Delete(item)
#
def deleteListTracks(pcb,tracks):
    tracksToDel_cp = list(tracks)
    l = len (tracksToDel_cp)
    for i in range(l):
        if type(tracksToDel_cp[i]) is TRACK: #item.GetNetname() == net_name:
            pcb.RemoveNative(tracksToDel_cp[i])
    #for item in tracks:
    #    if type(item) is TRACK: #item.GetNetname() == net_name:
    #        pcb.RemoveNative(item)
    #        #pcb.Delete(item)
#
def selectListTracks(pcb,tracks):
    for item in tracks:
        if type(item) is TRACK:
            item.SetSelected()
#

def getSelTracksLength(pcb):
    ln = 0.
    for item in pcb.GetTracks():
        if type(item) is pcbnew.TRACK and item.IsSelected():
            ln+=(item.GetLength())
    return(ln)
    #print(pcbnew.ToMM(ln))
#
##    def HitTest(self, *args): for Tracks and Vias

##-----------------------------------------------------------------------------------------------------
def Round_Selection(pcb,distI,segments):
    global delete_before_connect
    tracks = []
    #print ("TRACKS WHICH MATCH CRITERIA:")
    for item in pcb.GetTracks():
        if type(item) is TRACK and item.IsSelected(): #item.GetNetname() == net_name:
            tracks.append(item)
    wxLogDebug(str(len(tracks)),debug)
        
    if len (tracks) == 2:            
        #add all the possible intersections to a unique set, for iterating over later
        intersections = set();	
        for t1 in range(len(tracks)):
            for t2 in range(t1+1, len(tracks)):
                #check if these two tracks share an endpoint
                # reduce it to a 2-part tuple so there are not multiple objects of the same point in the set
                if(tracks[t1].IsPointOnEnds(tracks[t2].GetStart())): 
                    intersections.add((tracks[t2].GetStart().x, tracks[t2].GetStart().y))
                if(tracks[t1].IsPointOnEnds(tracks[t2].GetEnd())):
                    intersections.add((tracks[t2].GetEnd().x, tracks[t2].GetEnd().y))
        if len(intersections)==1:
            for ip in intersections:
                (x,y) = ip
                wxLogDebug("intersections: "+str(ToUnits(x))+":"+str(ToUnits(y)),debug)
                #wx.LogMessage(str(tracks[0].GetStart()))
                intersection = wxPoint(x,y)
                if tracks[0].GetStart() == pcbnew.wxPoint(x,y):
                    first_trk_extNode = tracks[0].GetEnd()
                    #wx.LogMessage("tracks[0] external node="+str(ToUnits(tracks[0].GetEnd().x))+";"+str(ToUnits(tracks[0].GetEnd().y)))
                else:
                    first_trk_extNode = tracks[0].GetStart()
                    #wx.LogMessage("tracks[0] external node="+str(ToUnits(tracks[0].GetStart().x))+";"+str(ToUnits(tracks[0].GetStart().y)))
                if tracks[1].GetStart() == pcbnew.wxPoint(x,y):
                    last_trk_extNode = tracks[1].GetEnd()
                    #wx.LogMessage("tracks[1] external node="+str(ToUnits(tracks[1].GetEnd().x))+";"+str(ToUnits(tracks[1].GetEnd().y)))
                else:
                    last_trk_extNode = tracks[1].GetStart()
                    #wx.LogMessage("tracks[1] external node="+str(ToUnits(tracks[1].GetStart().x))+";"+str(ToUnits(tracks[1].GetStart().y)))
                angle1 = math.degrees((getTrackAngle(tracks[0],intersection)))
                angle2 = math.degrees((getTrackAngle(tracks[1],intersection)))
                end_coord1 = (distI) * cmath.exp(math.radians(angle1)*1j) #cmath.rect(r, phi) : Return the complex number x with polar coordinates r and phi.
                end_coord2 = (distI) * cmath.exp(math.radians(angle2)*1j)
                startP = wxPoint(end_coord1.real+x,end_coord1.imag+y)
                endP = wxPoint(end_coord2.real+x,end_coord2.imag+y)
                layer = tracks[0].GetLayer()
                width = ToMM(tracks[0].GetWidth())
                Nname = tracks[0].GetNet() #.GetNetname()
                wxLogDebug("offset1 = "+str(ToUnits(startP)),debug) #+":"+str(ToUnits(endP)),debug)
                wxLogDebug("offset2 = "+str(ToUnits(endP)),debug) #end_coord2.real+x))+":"+str(ToUnits(end_coord2.imag+y)))
                center,radius = getCircleCenterRadius( startP,endP,intersection )
                #rad = math.hypot(center.x-startP.x,center.y-startP.y)
                wxLogDebug('radius'+str(ToMM(radius)),debug)
                wxLogDebug('center'+str(ToMM(center)),debug)
                # import round_trk; import importlib; importlib.reload(round_trk)
                lenT1 = GetTrackLength(tracks[0])
                dist1 = math.hypot(startP.y-intersection.y,startP.x-intersection.x)
                lenT2 = GetTrackLength(tracks[1])
                dist2 = math.hypot(endP.y-intersection.y,endP.x-intersection.x)
                wxLogDebug('Len T1 {0:.3f} mm, dist1 {1:.3f} mm, LenT2 {2:.3f} mm, dist2 {3:.3f} mm'.format(ToMM(lenT1),ToMM(dist1),ToMM(lenT2),ToMM(dist2)),debug)
                if show_points:
                    create_Draw(pcb,startP,startP,F_Mask,0.2)
                    create_Draw(pcb,intersection,intersection,Eco1_User,1.5)
                    create_Draw(pcb,endP,endP,B_Mask,0.2)
                    create_Draw(pcb,center,center,F_SilkS,2.)
                    create_round_points(pcb,startP,angle1,endP,angle2,center,radius,segments)
                    pcbnew.Refresh()
                    selectListTracks(pcb,tracks)
                if (lenT1 < dist1) or (lenT2 < dist2):
                    wxLogDebug('Segments too short compared to selected distance {0:.3f} mm'.format(ToMM(distI)),True)
                else:
                    #create_Track(pcb,first_trk_extNode,startP,layer,width,Nname) #B_Cu,0.2)
                    #if delete_before_connect:
                    deleteListTracks(pcb,tracks)
                    create_Track(pcb,startP,first_trk_extNode,layer,width,Nname) #B_Cu,0.2)
                    #create_Draw(pcb,startP,startP,F_Mask,1.5)
                    newEP = create_round_segments(pcb,startP,angle1,endP,angle2,center,radius,layer,width,Nname,segments) #B_Cu,0.2)
                    #wxLogDebug(str(newEP)+':'+str(endP),True)
                    #create_Draw(pcb,endP,endP,B_Mask,1.9)
                    create_Track(pcb,endP,last_trk_extNode,layer,width,Nname) # B_Cu,0.2)
                    #create_Track(pcb,last_trk_extNode,endP,layer,width,Nname) # B_Cu,0.2)
                    #deleteSelectedTracks(pcb)
                    #selectListTracks(pcb,tracks)
                    w3 = 3*float(width)
                    rad = float(ToMM(radius))
                    wxLogDebug(str(w3),debug)
                    msg = u'Corner Radius: {0:.3f} mm'.format(rad)
                    msg+= u'\nAngle between tracks: {0:.1f} deg'.format(angle1-angle2)
                    if rad < w3:
                        msg += u'\n\u2718 ALERT: Radius < 3 *(track width) !!!\n[{0:.3f}mm < 3*{1:.3f}mm]'.format(rad,width)
                    #else:
                    #    #msg = u'\n\u2714 Radius > 3 * (track width)'
                    #    msg = u'\u2714 Corner Radius: {0:.3f} mm'.format(rad)
                    wxLogDebug(msg,True)
                    pcbnew.Refresh()
    # import round_trk; reload(round_trk)
    # import round_trk; import importlib; importlib.reload(round_trk)
    else:
        wxLogDebug("you must select two tracks (only)",not debug)
#
def Delete_Segments(pcb, track=None):
    global delete_before_connect
    tracks = []
    tracksToKeep = []
    if track is None:
        for item in pcb.GetTracks():
            if type(item) is TRACK and item.IsSelected():
                tracks.append(item)
        wxLogDebug('tracks selected: '+str(len(tracks)),debug2)
    else:
        tracks.append(track)
    if len (tracks) == 1 and delete_before_connect:            
        Netname = tracks[0].GetNetname()
        tsc = 0
        for c in Netname:
            tsc = tsc + ord(c)
        nseg = 0
        tracksToDel = []
        for track in pcb.GetTracks():
            if hasattr(track,'GetTimeStamp'):
                tsd = track.GetTimeStamp()
            else:
                tsd = track.m_Uuid.AsLegacyTimestamp()
            wxLogDebug('tracks ts: '+str(tsc)+';'+str(tsd),debug2)
            if tsd == tsc and tsd != 0:
                tracksToDel.append(track)
                #pcb.RemoveNative(track)
                nseg+=1
        if nseg > 0:
            tracksToDel_cp = list(tracksToDel)
            l = len (tracksToDel_cp)
            #for track in tracksToDel:
            for i in range(l):
                pcb.RemoveNative(tracksToDel_cp[i])
            wxLogDebug(u'\u2714 Round Segments on Track Net Deleted',True)
    else:
        Netname = tracks[0].GetNetname()
        tsc = 0
        for c in Netname:
            tsc = tsc + ord(c)
        nseg = 0
        tracksToDel = []
        for track in pcb.GetTracks():
            if type(track) is TRACK and track.IsSelected():
                if hasattr(track,'GetTimeStamp'):
                    tsd = track.GetTimeStamp()
                else:
                    tsd = track.m_Uuid.AsLegacyTimestamp()
                wxLogDebug('tracks ts: '+str(tsc)+';'+str(tsd),debug2)
                if tsd == tsc and tsd != 0:
                    tracksToDel.append(track)
                    #pcb.RemoveNative(track)
                    nseg+=1
                else:
                    tracksToKeep.append(track)
        if nseg > 0:
            tracksToDel_cp = list(tracksToDel)
            l = len (tracksToDel_cp)
            for i in range(l):
                pcb.RemoveNative(tracksToDel_cp[i])
            #for track in tracksToDel:
            #    pcb.RemoveNative(track)
            wxLogDebug(u'\u2714 Round Segments on Selected Track deleted',True)
        elif delete_before_connect:
            wxLogDebug(u'\u2718 you must select One track only',not debug)
        return tracksToKeep
#
def Connect_Segments(pcb):
    tracks = []
    tracksToKeep = []
    for item in pcb.GetTracks():
        if type(item) is TRACK and item.IsSelected():
            tracks.append(item)
    wxLogDebug(str(len(tracks)),debug)
        
    if len (tracks) >= 2:
        pi_exists = True
        if len (tracks) > 2:
            tracksToKeep = Delete_Segments(pcb)
            if len (tracksToKeep) == 2:
                tracks[0] = tracksToKeep[0]
                tracks[1] = tracksToKeep[1]
            else:
                wxLogDebug(u'\u2718 wrong selection (error)\nselect Only one corner to be straighten',not debug)
        else:
            Delete_Segments(pcb,tracks[0])
        #getting points
        if tracks[0].GetStart().x < tracks[0].GetEnd().x:
            first_trk_startP = tracks[0].GetStart()
            first_trk_endP = tracks[0].GetEnd()
        else:
            first_trk_startP = tracks[0].GetEnd()
            first_trk_endP = tracks[0].GetStart()
        if tracks[1].GetStart().x < tracks[1].GetEnd().x:
            last_trk_startP = tracks[1].GetStart()
            last_trk_endP = tracks[1].GetEnd()
        else:
            last_trk_startP = tracks[1].GetEnd()
            last_trk_endP = tracks[1].GetStart()
        wxLogDebug('sp1:'+str(first_trk_startP)+';'+str(first_trk_endP),debug2)
        wxLogDebug('sp2:'+str(last_trk_startP)+';'+str(last_trk_endP),debug2)
        x1 = float(first_trk_startP.x); y1 = float(first_trk_startP.y)
        x3 = float(first_trk_endP.x); y3 = float(first_trk_endP.y)
        x2 = float(last_trk_startP.x); y2 = float(last_trk_startP.y)
        x4 = float(last_trk_endP.x); y4 =   float(last_trk_endP.y)
        if (x3!=x1) and (x4!=x2):
            N = y2-y1-x2*(y4-y2)/(x4-x2)+x1*(y3-y1)/(x3-x1)
            D = (y3-y1)/(x3-x1)-(y4-y2)/(x4-x2)
            xi = N/D
            yi = y1+(y3-y1)/(x3-x1)*(xi-x1)
        elif (x3==x1):
            xi = x1
            yi = y2+(y4-y2)/(x4-x2)*(x1-x2)
        elif (x4 == x2):
            xi = x2
            yi = y1 + (y3-y1)/(x3-x1)*(x2-x1)
        else:
            pi_exists = False
            wxLogDebug(u'\u2718 intersection point doesn\'t exist',not debug)
        if pi_exists:
            wxLogDebug('pi:'+str(wxPoint(xi,yi)),debug2) #xi)+';'+str(yi),debug1)
            wxLogDebug('sp1:('+str(ToMM(x1))+','+str(ToMM(y1))+')'+\
                    ';('+str(ToMM(x2))+','+str(ToMM(y2))+')',debug2)
            wxLogDebug('sp2:('+str(ToMM(x3))+','+str(ToMM(y3))+')'+\
                    ';('+str(ToMM(x4))+','+str(ToMM(y4))+')',debug2)
            wxLogDebug('pi:('+str(ToMM(xi))+','+str(ToMM(yi))+')',debug2)
            pi = wxPoint(xi,yi)
            if show_points2:
                #create_Text(pcb, txt, p, w)
                create_Text(pcb,'1',wxPoint(x1,y1),FromMM(1.0),pcbnew.F_SilkS)
                create_Text(pcb,'2',wxPoint(x2,y2),FromMM(1.0),pcbnew.F_SilkS)
                create_Text(pcb,'3',wxPoint(x3,y3),FromMM(1.0),pcbnew.F_SilkS)
                create_Text(pcb,'4',wxPoint(x4,y4),FromMM(1.0),pcbnew.F_SilkS)
                create_Text(pcb,'C',wxPoint(xi,yi),FromMM(2.0),pcbnew.B_SilkS)
            wxLogDebug('dp1,pi)'+str(distance(wxPoint(x1,y1),pi)),debug2)
            wxLogDebug('dp3,pi)'+str(distance(wxPoint(x3,y3),pi)),debug2)
            if distance(wxPoint(x1,y1),pi) > distance(wxPoint(x3,y3),pi):
                tracks[0].SetStart(wxPoint(x1,y1))
                tracks[0].SetEnd(pi)
            else:
                tracks[0].SetStart(wxPoint(x3,y3))
                tracks[0].SetEnd(pi)
            wxLogDebug('dp2,pi)'+str(distance(wxPoint(x2,y2),pi)),debug2)
            wxLogDebug('dp4,pi)'+str(distance(wxPoint(x4,y4),pi)),debug2)
            if distance(wxPoint(x2,y2),pi) > distance(wxPoint(x4,y4),pi):
                tracks[1].SetStart(wxPoint(x2,y2))
                tracks[1].SetEnd(pi)
            else:
                tracks[1].SetStart(wxPoint(x4,y4))
                tracks[1].SetEnd(pi)
            pcbnew.Refresh()
    else:
        wxLogDebug(u'\u2718 you must select two tracks only',not debug)
#