From ae68ee97ab61c53932105fb225dcd42151258a2e Mon Sep 17 00:00:00 2001
From: juru <juru@dtu.dk>
Date: Wed, 13 Oct 2021 12:57:54 +0200
Subject: [PATCH] First commit heuristics

---
 edwin/__init__.py               |   6 +-
 edwin/c_mst.py                  | 451 ++++++++++++++++++++++++++++++++
 edwin/c_mst_cables.py           | 109 ++++++++
 edwin/collection_system.py      |  46 ++++
 edwin/intersection_checker.py   |  30 +++
 edwin/two_lines_intersecting.py | 179 +++++++++++++
 6 files changed, 818 insertions(+), 3 deletions(-)
 create mode 100644 edwin/c_mst.py
 create mode 100644 edwin/c_mst_cables.py
 create mode 100644 edwin/collection_system.py
 create mode 100644 edwin/intersection_checker.py
 create mode 100644 edwin/two_lines_intersecting.py

diff --git a/edwin/__init__.py b/edwin/__init__.py
index d0f8dbd..2198dce 100644
--- a/edwin/__init__.py
+++ b/edwin/__init__.py
@@ -1,3 +1,3 @@
-# 'filled_by_setup.py'
-__version__ = '4fbf778c0f6c9c019f2bb08835d3e6596a380f1'
-__release__ = '4fbf778c0f6c9c019f2bb08835d3e6596a380f1'
+# 'filled_by_setup.py'
+__version__ = 'c6c857252e379ba76e90ff3f5bf58f9efe828ee'
+__release__ = 'c6c857252e379ba76e90ff3f5bf58f9efe828ee'
diff --git a/edwin/c_mst.py b/edwin/c_mst.py
new file mode 100644
index 0000000..eb47528
--- /dev/null
+++ b/edwin/c_mst.py
@@ -0,0 +1,451 @@
+# -*- coding: utf-8 -*-
+"""
+Created on Thu May 28 08:12:54 2020
+
+@author: juru
+"""
+import numpy as np
+from intersection_checker import intersection_checker
+import matplotlib.pyplot as plt
+
+def capacitated_spanning_tree(X=[],Y=[],option=3,UL=100,Inters_const=True,max_it=20000):
+    """
+    Calculate a minimum spanning tree distance for a layout.
+    Capacitated minimum spanning tree heuristics algorithm for Topfarm.
+
+    Parameters
+    ----------
+    *X, Y: list([n_wt_oss]) or array type as well
+            X,Y positions of the wind turbines and oss
+    *option: Heuristic type. option=1 is Prim. option=2 is Kruskal. option=3 is Esau-Williams
+    *max_it: Maximm number of iterations for the heuristics
+    *UL: Upper limit for the max number of wind turbines connectable by the biggest available cable
+    *Inters_const=Bool. True is cable crossings are not allowed. False if they are allowed.
+    
+    :return: T: Array. First column is first node, second column is second noce, third column is the distance between nodes
+                       The OSS is always the node number 1. The WTs go from 2 to number of WTs plus one
+             feasible: Bool. True is solution is feasible. False if not.
+
+    """  
+#%%  Initializing arrays, lists, variables (until line 46 .m file)  
+    n_wt_oss=len(X)  #Defining number of wind turbines with OSS
+    half=int(n_wt_oss*(n_wt_oss-1)/2)  
+    edges_tot=np.zeros((2*half,5)) #Defining the matrix with Edges information
+    cont_edges=0
+    for i in range(n_wt_oss):
+        for j in range(i+1,n_wt_oss):
+            edges_tot[cont_edges,0]=i+1 #First element is first node (Element =1 is the OSS. and from 2 to Nwt the WTs)
+            edges_tot[cont_edges,1]=j+1 #Second element is second node
+            edges_tot[cont_edges,2]=np.sqrt((X[j]-X[i])**2+(Y[j]-Y[i])**2) #Third element is the length of the edge
+            cont_edges+=1
+    CP=[x for x in range(n_wt_oss)] #Initializing component position list for each node. A component goes from 0 until n_wt_oss-1. Fixed length.
+    address_nodes=[-1 for x in range(n_wt_oss)] #Initializing address list for each node. It indicates the root node for each node in the tree and in subtrees from OSS. Fixed length.
+    address_nodes[0]=0
+    address_nodes=np.array(address_nodes,dtype=int)
+    C=[[x+1] for x in range(n_wt_oss)] #Initializing component list (nodes belonging to each comonent). A component goes from 0 until n_wt_oss-1, and its length decreases until 1 (component 0). Variable length.
+    S=[1 for x in range(n_wt_oss)] #Initializing size of components list (how many nodes are in each component). A component goes from 0 until n_wt_oss-1, and its length decreases until 1 (component 0 with n_wt_oss-1 elements). Variable length.
+    go,it,node1,node2,weight = True,0,0,0,np.zeros((n_wt_oss,1)) #Initializing variables for iterations 
+    if option == 1: #Initializing weight of nodes. Each index represents a node, such as Node=Index+1
+       weight[0],weight[1:n_wt_oss]=0,-10**50
+    elif option == 2:
+       weight
+    elif option == 3:
+       weight[0],weight[1:n_wt_oss]=0,edges_tot[0:n_wt_oss-1,2].reshape(n_wt_oss-1,1)           
+    else:
+        raise Exception('option should be either 1, 2 or 3 The value of x was: {}'.format(option))
+    for i in range(2*half):#Forming the big matrix with all edges and corresponding trade-off values (fixed size).
+        if i<=half-1:
+           edges_tot[i,3]=weight[edges_tot[i,0].astype(int)-1,0]
+           edges_tot[i,4] = edges_tot[i,2]-edges_tot[i,3]
+        else:
+           edges_tot[i,0]=edges_tot[i-half,1]
+           edges_tot[i,1]=edges_tot[i-half,0]
+           edges_tot[i,2]=edges_tot[i-half,2]
+           edges_tot[i,3]=weight[edges_tot[i,0].astype(int)-1,0]
+           edges_tot[i,4] = edges_tot[i,2]-edges_tot[i,3]
+    mst_edges=np.zeros(2*half, dtype=bool) #Array containing the activation variables of selected edges
+    feasible=False
+#%%  Main (until line 609 .m file)
+    while go:
+        flag1,flag2,flag3,flag4=True,True,True,True
+        it+=1
+        value_potential_edge,pos_potential_edge=np.min(edges_tot[:,4]),np.argmin(edges_tot[:,4])
+        if (value_potential_edge>10**49) or (it==max_it): #Condition to stop if a C-MST cannot be found
+            #print(it)
+            #print(value_potential_edge)
+            break
+        node1,node2=edges_tot[pos_potential_edge,0].astype(int),edges_tot[pos_potential_edge,1].astype(int)
+        if (CP[node1-1]==CP[node2-1]) and (flag1) and (flag2) and (flag3) and (flag4): #Condition for avoiding the creation of loops
+            flag1=False  #Boolean for loops creation
+            if pos_potential_edge<=half-1: #Eliminiating edges which connect the same component
+                edges_tot[pos_potential_edge,4] = edges_tot[pos_potential_edge,2] + 10**50
+                edges_tot[pos_potential_edge+half,4] = edges_tot[pos_potential_edge+half,2] + 10**50
+            else:
+                edges_tot[pos_potential_edge,4] = edges_tot[pos_potential_edge,2] + 10**50
+                edges_tot[pos_potential_edge-half,4] = edges_tot[pos_potential_edge-half,2] + 10**50
+    #%%  Next code is when the potential edge is connected directly to the OSS (node==1) and it does not create loops             
+        if ((node1 == 1) or (node2 == 1)) and (flag1 ==True) and (flag2 ==True) and (flag3 ==True) and (flag4 ==True): #Evaluation of the number of nodes in a subtree rooted at 1
+           flag2=False
+           if node1==1: #If the selected edge has a node 1 the OSS
+               if (S[CP[node2-1]] > UL): #Evaluation of the capacity constraint: If true, proceeding to eliminate edges 
+                   if pos_potential_edge<=half-1: 
+                       edges_tot[pos_potential_edge,4] = edges_tot[pos_potential_edge,2] + 10**50
+                       edges_tot[pos_potential_edge+half,4] = edges_tot[pos_potential_edge+half,2] + 10**50
+                   else:
+                       edges_tot[pos_potential_edge,4] = edges_tot[pos_potential_edge,2] + 10**50
+                       edges_tot[pos_potential_edge-half,4] = edges_tot[pos_potential_edge-half,2] + 10**50
+               else:   #If capacity constraint not violated, then evaluate no-crossing cables constraint
+                    if (not(intersection_checker(pos_potential_edge,edges_tot,mst_edges,X,Y,Inters_const))): #If no cables crossing, add the edge to the tree
+                       mst_edges[pos_potential_edge]=True #Add it to the tree. line 88 .m file
+                       #Update node address
+                       address_nodes[node2-1]=1
+                       C_sliced_n2=C[CP[node2-1]]
+                       for j in range(len(C_sliced_n2)): #This could be replaced without for loop as address_nodes is now an array (before was a list)
+                           if C_sliced_n2[j]==node2:
+                               pass
+                           else:
+                               address_nodes[C_sliced_n2[j]-1]=node2
+                       #Update weights and cost functions
+                       if option == 1: 
+                           weight[node2-1]=0
+                           edges_tot[np.where(edges_tot[:,0]==node2)[0],3]=weight[node2-1]
+                           edges_tot[np.where(edges_tot[:,0]==node2)[0],4]=edges_tot[np.where(edges_tot[:,0]==node2)[0],2]-\
+                                                                          edges_tot[np.where(edges_tot[:,0]==node2)[0],3]
+                       elif option == 2:
+                           pass
+                       elif option == 3:
+                           C_sliced_n1=C[CP[node1-1]]
+                           for j in range(len(C_sliced_n1)):
+                               weight[C_sliced_n1[j]-1]=weight[node2-1]
+                               edges_tot[np.where(edges_tot[:,0]==C_sliced_n1[j])[0],3]=weight[node2-1]
+                               edges_tot[np.where(edges_tot[:,0]==C_sliced_n1[j])[0],4]=edges_tot[np.where(edges_tot[:,0]==C_sliced_n1[j])[0],2]-\
+                                                                                       edges_tot[np.where(edges_tot[:,0]==C_sliced_n1[j])[0],3]                              
+                       else:
+                           raise Exception('option should be either 1, 2 or 3 The value of x was: {}'.format(option)) #Weight and cost function updated. line 126 .m file                     
+                       #Eliminating selected edge from edges potential list
+                       if pos_potential_edge<=half-1: 
+                           edges_tot[pos_potential_edge,4] = edges_tot[pos_potential_edge,2] + 10**50
+                           edges_tot[pos_potential_edge+half,4] = edges_tot[pos_potential_edge+half,2] + 10**50
+                       else:
+                           edges_tot[pos_potential_edge,4] = edges_tot[pos_potential_edge,2] + 10**50
+                           edges_tot[pos_potential_edge-half,4] = edges_tot[pos_potential_edge-half,2] + 10**50
+                       #Updating auxiliary matrix CP, C, S
+                       u,v=min(node1,node2),max(node1,node2)
+                       C_sliced_u,C_sliced_v=C[CP[u-1]],C[CP[v-1]]
+                       S[CP[u-1]] = len(C_sliced_u) + len(C_sliced_v) #Updating size of components
+                       C[CP[u-1]]+=C[CP[v-1]] #Merging two lists due to component's merge 
+                       old_pos = CP[v-1]
+                       for j in range(len(C_sliced_v)): #Updating components position for each merged node
+                           CP[C_sliced_v[j]-1]=CP[u-1]
+                       for j in range(len(CP)):
+                           if CP[j]>old_pos:
+                               CP[j]-=1
+                       del C[old_pos] #Deleting old component
+                       del S[old_pos] #Deleting old component size (line 167 .m file)
+                    else: #If a cable crossing is detected
+                        if pos_potential_edge<=half-1: 
+                           edges_tot[pos_potential_edge,4] = edges_tot[pos_potential_edge,2] + 10**50
+                           edges_tot[pos_potential_edge+half,4] = edges_tot[pos_potential_edge+half,2] + 10**50
+                        else:
+                           edges_tot[pos_potential_edge,4] = edges_tot[pos_potential_edge,2] + 10**50
+                           edges_tot[pos_potential_edge-half,4] = edges_tot[pos_potential_edge-half,2] + 10**50
+           if node2==1: #If the selected edge has a node 2 the OSS
+              if (S[CP[node1-1]] > UL): #Evaluation of the capacity constraint: If true, proceeding to eliminate edges 
+                   if pos_potential_edge<=half-1: 
+                       edges_tot[pos_potential_edge,4] = edges_tot[pos_potential_edge,2] + 10**50
+                       edges_tot[pos_potential_edge+half,4] = edges_tot[pos_potential_edge+half,2] + 10**50
+                   else:
+                       edges_tot[pos_potential_edge,4] = edges_tot[pos_potential_edge,2] + 10**50
+                       edges_tot[pos_potential_edge-half,4] = edges_tot[pos_potential_edge-half,2] + 10**50
+              else:
+                    if (not(intersection_checker(pos_potential_edge,edges_tot,mst_edges,X,Y,Inters_const))): #If no cables crossing, add the edge to the tree
+                       mst_edges[pos_potential_edge]=True #Add it to the tree. line 190 .m file
+                       #Update node address
+                       address_nodes[node1-1]=1
+                       C_sliced_n1=C[CP[node1-1]]
+                       for j in range(len(C_sliced_n1)):
+                           if C_sliced_n1[j]==node1:
+                               pass
+                           else:
+                               address_nodes[C_sliced_n1[j]-1]=node1 
+                       #Update weights and cost functions
+                       if option == 1: 
+                           weight[node2-1]=0
+                           edges_tot[np.where(edges_tot[:,0]==node2)[0],3]=weight[node2-1]
+                           edges_tot[np.where(edges_tot[:,0]==node2)[0],4]=edges_tot[np.where(edges_tot[:,0]==node2)[0],2]-\
+                                                                          edges_tot[np.where(edges_tot[:,0]==node2)[0],3]
+                       elif option == 2:
+                           pass
+                       elif option == 3:
+                           #C_sliced_n1=C[CP[node1-1]]
+                           for j in range(len(C_sliced_n1)):
+                               weight[C_sliced_n1[j]-1]=weight[node2-1]
+                               edges_tot[np.where(edges_tot[:,0]==C_sliced_n1[j])[0],3]=weight[node2-1]
+                               edges_tot[np.where(edges_tot[:,0]==C_sliced_n1[j])[0],4]=edges_tot[np.where(edges_tot[:,0]==C_sliced_n1[j])[0],2]-\
+                                                                                       edges_tot[np.where(edges_tot[:,0]==C_sliced_n1[j])[0],3]                              
+                       else:
+                           raise Exception('option should be either 1, 2 or 3 The value of x was: {}'.format(option)) #Weight and cost function updated. line 226 .m file 
+                       #Eliminating selected edge from edges potential list
+                       if pos_potential_edge<=half-1: 
+                           edges_tot[pos_potential_edge,4] = edges_tot[pos_potential_edge,2] + 10**50
+                           edges_tot[pos_potential_edge+half,4] = edges_tot[pos_potential_edge+half,2] + 10**50
+                       else:
+                           edges_tot[pos_potential_edge,4] = edges_tot[pos_potential_edge,2] + 10**50
+                           edges_tot[pos_potential_edge-half,4] = edges_tot[pos_potential_edge-half,2] + 10**50 #line 234 .m file
+                       #Updating auxiliary matrix CP, C, S
+                       u,v=min(node1,node2),max(node1,node2)
+                       C_sliced_u,C_sliced_v=C[CP[u-1]],C[CP[v-1]]
+                       S[CP[u-1]] = len(C_sliced_u) + len(C_sliced_v) #Updating size of components
+                       C[CP[u-1]]+=C[CP[v-1]] #Merging two lists due to component's merge 
+                       old_pos = CP[v-1]
+                       for j in range(len(C_sliced_v)): #Updating components position for each merged node
+                           CP[C_sliced_v[j]-1]=CP[u-1]
+                       for j in range(len(CP)):
+                           if CP[j]>old_pos:
+                               CP[j]-=1
+                       del C[old_pos] #Deleting old component
+                       del S[old_pos] #Deleting old component size (line 267 .m file)
+                    else: #If a cable crossing is detected
+                        if pos_potential_edge<=half-1: 
+                           edges_tot[pos_potential_edge,4] = edges_tot[pos_potential_edge,2] + 10**50
+                           edges_tot[pos_potential_edge+half,4] = edges_tot[pos_potential_edge+half,2] + 10**50
+                        else:
+                           edges_tot[pos_potential_edge,4] = edges_tot[pos_potential_edge,2] + 10**50
+                           edges_tot[pos_potential_edge-half,4] = edges_tot[pos_potential_edge-half,2] + 10**50
+    #%%  Next code is when the potential edge is not connected directly to the OSS (node==1) and it does not create loops. Two cases: One of the components has as element node=1 or none of them.
+        if (flag1 ==True) and (flag2 ==True) and (flag3 ==True) and (flag4 ==True): 
+           if (1 in C[CP[node1-1]]) or (1 in C[CP[node2-1]]): #One of the components has an element '1' (OSS)
+               flag3 ==False #line 284 .m file
+               if (1 in C[CP[node1-1]]): #The component of node1 includes the root 1
+                  if address_nodes[node1-1]==1: #The node 1 is connected directly to the OSS (element '1')
+                     tot_nodes=np.where(address_nodes==node1)[0].size+S[CP[node2-1]]+1
+                  else: #The node 1 is not connected directly to the OSS (element '1')
+                     tot_nodes=np.where(address_nodes==address_nodes[node1-1])[0].size+S[CP[node2-1]]+1
+                  if tot_nodes>UL: ##Evaluation of the capacity constraint: If true, proceeding to eliminate edges 
+                     if pos_potential_edge<=half-1: 
+                        edges_tot[pos_potential_edge,4] = edges_tot[pos_potential_edge,2] + 10**50
+                        edges_tot[pos_potential_edge+half,4] = edges_tot[pos_potential_edge+half,2] + 10**50
+                     else:
+                        edges_tot[pos_potential_edge,4] = edges_tot[pos_potential_edge,2] + 10**50
+                        edges_tot[pos_potential_edge-half,4] = edges_tot[pos_potential_edge-half,2] + 10**50
+                  else:#No violation of capacity constraint
+                      if (not(intersection_checker(pos_potential_edge,edges_tot,mst_edges,X,Y,Inters_const))): #If no cables crossing, add the edge to the tree
+                          mst_edges[pos_potential_edge]=True #Add it to the tree. line 301 .m file
+                          #Update node address
+                          if address_nodes[node1-1]==1:
+                             C_sliced_n2=C[CP[node2-1]]
+                             for j in range(len(C_sliced_n2)):
+                                address_nodes[C_sliced_n2[j]-1]=node1
+                          else:
+                             C_sliced_n2=C[CP[node2-1]]
+                             for j in range(len(C_sliced_n2)):
+                                address_nodes[C_sliced_n2[j]-1]=address_nodes[node1-1] #line 318 .m file
+                          #Update weights and cost functions
+                          if option == 1: 
+                             weight[node2-1]=0
+                             edges_tot[np.where(edges_tot[:,0]==node2)[0],3]=weight[node2-1]
+                             edges_tot[np.where(edges_tot[:,0]==node2)[0],4]=edges_tot[np.where(edges_tot[:,0]==node2)[0],2]-\
+                                                                          edges_tot[np.where(edges_tot[:,0]==node2)[0],3]
+                          elif option == 2:
+                              pass
+                          elif option == 3:
+                              C_sliced_n1=C[CP[node1-1]]
+                              for j in range(len(C_sliced_n1)):
+                                  weight[C_sliced_n1[j]-1]=weight[node2-1]
+                                  edges_tot[np.where(edges_tot[:,0]==C_sliced_n1[j])[0],3]=weight[node2-1]
+                                  edges_tot[np.where(edges_tot[:,0]==C_sliced_n1[j])[0],4]=edges_tot[np.where(edges_tot[:,0]==C_sliced_n1[j])[0],2]-\
+                                                                                       edges_tot[np.where(edges_tot[:,0]==C_sliced_n1[j])[0],3]                              
+                          else:
+                              raise Exception('option should be either 1, 2 or 3 The value of x was: {}'.format(option)) #Weight and cost function updated. line 344 .m file
+                          #Eliminating selected edge from edges potential list
+                          if pos_potential_edge<=half-1: 
+                             edges_tot[pos_potential_edge,4] = edges_tot[pos_potential_edge,2] + 10**50
+                             edges_tot[pos_potential_edge+half,4] = edges_tot[pos_potential_edge+half,2] + 10**50
+                          else:
+                             edges_tot[pos_potential_edge,4] = edges_tot[pos_potential_edge,2] + 10**50
+                             edges_tot[pos_potential_edge-half,4] = edges_tot[pos_potential_edge-half,2] + 10**50 #line 352 .m file
+                          #Updating auxiliary matrix CP, C, S
+                          u,v=min(node1,node2),max(node1,node2)
+                          C_sliced_u,C_sliced_v=C[CP[u-1]],C[CP[v-1]]
+                          S[CP[u-1]] = len(C_sliced_u) + len(C_sliced_v) #Updating size of components
+                          C[CP[u-1]]+=C[CP[v-1]] #Merging two lists due to component's merge 
+                          old_pos = CP[v-1]
+                          for j in range(len(C_sliced_v)): #Updating components position for each merged node
+                              CP[C_sliced_v[j]-1]=CP[u-1]
+                          for j in range(len(CP)):
+                              if CP[j]>old_pos:
+                                 CP[j]-=1
+                          del C[old_pos] #Deleting old component
+                          del S[old_pos] #Deleting old component size (line 385 .m file)
+                      else:#If a cable crossing is detected
+                          if pos_potential_edge<=half-1: 
+                              edges_tot[pos_potential_edge,4] = edges_tot[pos_potential_edge,2] + 10**50
+                              edges_tot[pos_potential_edge+half,4] = edges_tot[pos_potential_edge+half,2] + 10**50
+                          else:
+                              edges_tot[pos_potential_edge,4] = edges_tot[pos_potential_edge,2] + 10**50
+                              edges_tot[pos_potential_edge-half,4] = edges_tot[pos_potential_edge-half,2] + 10**50  #(line 396 .m file)
+               else: #The component of node2 includes the root 1
+                  if address_nodes[node2-1]==1: #The node 2 is connected directly to the OSS (element '1')
+                     tot_nodes=np.where(address_nodes==node2)[0].size+S[CP[node1-1]]+1
+                  else: #The node 2 is not connected directly to the OSS (element '1')
+                     tot_nodes=np.where(address_nodes==address_nodes[node2-1])[0].size+S[CP[node1-1]]+1
+                  if tot_nodes>UL: ##Evaluation of the capacity constraint: If true, proceeding to eliminate edges 
+                     if pos_potential_edge<=half-1: 
+                        edges_tot[pos_potential_edge,4] = edges_tot[pos_potential_edge,2] + 10**50
+                        edges_tot[pos_potential_edge+half,4] = edges_tot[pos_potential_edge+half,2] + 10**50
+                     else:
+                        edges_tot[pos_potential_edge,4] = edges_tot[pos_potential_edge,2] + 10**50
+                        edges_tot[pos_potential_edge-half,4] = edges_tot[pos_potential_edge-half,2] + 10**50
+                  else: #No violation of capacity constraint
+                      if (not(intersection_checker(pos_potential_edge,edges_tot,mst_edges,X,Y,Inters_const))): #If no cables crossing, add the edge to the tree
+                          mst_edges[pos_potential_edge]=True #Add it to the tree. line 413 .m file
+                          #Update node address
+                          if address_nodes[node2-1]==1:
+                             C_sliced_n1=C[CP[node1-1]]
+                             for j in range(len(C_sliced_n1)):
+                                address_nodes[C_sliced_n1[j]-1]=node2
+                          else:
+                             C_sliced_n1=C[CP[node1-1]]
+                             for j in range(len(C_sliced_n1)):
+                                address_nodes[C_sliced_n1[j]-1]=address_nodes[node2-1] #line 430 .m file
+                          #Update weights and cost functions
+                          if option == 1: 
+                             weight[node2-1]=0
+                             edges_tot[np.where(edges_tot[:,0]==node2)[0],3]=weight[node2-1]
+                             edges_tot[np.where(edges_tot[:,0]==node2)[0],4]=edges_tot[np.where(edges_tot[:,0]==node2)[0],2]-\
+                                                                          edges_tot[np.where(edges_tot[:,0]==node2)[0],3]
+                          elif option == 2:
+                              pass
+                          elif option == 3:
+                              C_sliced_n1=C[CP[node1-1]]
+                              for j in range(len(C_sliced_n1)):
+                                  weight[C_sliced_n1[j]-1]=weight[node2-1]
+                                  edges_tot[np.where(edges_tot[:,0]==C_sliced_n1[j])[0],3]=weight[node2-1]
+                                  edges_tot[np.where(edges_tot[:,0]==C_sliced_n1[j])[0],4]=edges_tot[np.where(edges_tot[:,0]==C_sliced_n1[j])[0],2]-\
+                                                                                       edges_tot[np.where(edges_tot[:,0]==C_sliced_n1[j])[0],3]                              
+                          else:
+                              raise Exception('option should be either 1, 2 or 3 The value of x was: {}'.format(option)) #Weight and cost function updated. line 456 .m file
+                          #Eliminating selected edge from edges potential list
+                          if pos_potential_edge<=half-1: 
+                             edges_tot[pos_potential_edge,4] = edges_tot[pos_potential_edge,2] + 10**50
+                             edges_tot[pos_potential_edge+half,4] = edges_tot[pos_potential_edge+half,2] + 10**50
+                          else:
+                             edges_tot[pos_potential_edge,4] = edges_tot[pos_potential_edge,2] + 10**50
+                             edges_tot[pos_potential_edge-half,4] = edges_tot[pos_potential_edge-half,2] + 10**50 #line 464 .m file
+                          #Updating auxiliary matrix CP, C, S
+                          u,v=min(node1,node2),max(node1,node2)
+                          C_sliced_u,C_sliced_v=C[CP[u-1]],C[CP[v-1]]
+                          S[CP[u-1]] = len(C_sliced_u) + len(C_sliced_v) #Updating size of components
+                          C[CP[u-1]]+=C[CP[v-1]] #Merging two lists due to component's merge 
+                          old_pos = CP[v-1]
+                          for j in range(len(C_sliced_v)): #Updating components position for each merged node
+                              CP[C_sliced_v[j]-1]=CP[u-1]
+                          for j in range(len(CP)):
+                              if CP[j]>old_pos:
+                                 CP[j]-=1
+                          del C[old_pos] #Deleting old component
+                          del S[old_pos] #Deleting old component size (line 497 .m file)
+                      else: #If a cable crossing is detected
+                          if pos_potential_edge<=half-1: 
+                              edges_tot[pos_potential_edge,4] = edges_tot[pos_potential_edge,2] + 10**50
+                              edges_tot[pos_potential_edge+half,4] = edges_tot[pos_potential_edge+half,2] + 10**50
+                          else:
+                              edges_tot[pos_potential_edge,4] = edges_tot[pos_potential_edge,2] + 10**50
+                              edges_tot[pos_potential_edge-half,4] = edges_tot[pos_potential_edge-half,2] + 10**50  #(line 507 .m file)
+           else:  # Node of the components has as element '1' (OSS)
+               flag4=False
+               if (S[CP[node1-1]]+S[CP[node2-1]]> UL): #Evaluation of the capacity constraint: If true, proceeding to eliminate edges 
+                  if pos_potential_edge<=half-1: 
+                     edges_tot[pos_potential_edge,4] = edges_tot[pos_potential_edge,2] + 10**50
+                     edges_tot[pos_potential_edge+half,4] = edges_tot[pos_potential_edge+half,2] + 10**50
+                  else:
+                     edges_tot[pos_potential_edge,4] = edges_tot[pos_potential_edge,2] + 10**50
+                     edges_tot[pos_potential_edge-half,4] = edges_tot[pos_potential_edge-half,2] + 10**50
+               else: #If no violation of the capacity constraint
+                    if (not(intersection_checker(pos_potential_edge,edges_tot,mst_edges,X,Y,Inters_const))): #If no cables crossing, add the edge to the tree
+                       mst_edges[pos_potential_edge]=True #Add it to the tree. line 522 .m file
+                       #Update weights and cost functions
+                       if option == 1: 
+                           weight[node2-1]=0
+                           edges_tot[np.where(edges_tot[:,0]==node2)[0],3]=weight[node2-1]
+                           edges_tot[np.where(edges_tot[:,0]==node2)[0],4]=edges_tot[np.where(edges_tot[:,0]==node2)[0],2]-\
+                                                                          edges_tot[np.where(edges_tot[:,0]==node2)[0],3]
+                       elif option == 2:
+                           pass
+                       elif option == 3:
+                           C_sliced_n1=C[CP[node1-1]]
+                           for j in range(len(C_sliced_n1)):
+                               weight[C_sliced_n1[j]-1]=weight[node2-1]
+                               edges_tot[np.where(edges_tot[:,0]==C_sliced_n1[j])[0],3]=weight[node2-1]
+                               edges_tot[np.where(edges_tot[:,0]==C_sliced_n1[j])[0],4]=edges_tot[np.where(edges_tot[:,0]==C_sliced_n1[j])[0],2]-\
+                                                                                       edges_tot[np.where(edges_tot[:,0]==C_sliced_n1[j])[0],3]                              
+                       else:
+                           raise Exception('option should be either 1, 2 or 3 The value of x was: {}'.format(option)) #Weight and cost function updated. line 548 .m file                     
+                       #Eliminating selected edge from edges potential list
+                       if pos_potential_edge<=half-1: 
+                           edges_tot[pos_potential_edge,4] = edges_tot[pos_potential_edge,2] + 10**50
+                           edges_tot[pos_potential_edge+half,4] = edges_tot[pos_potential_edge+half,2] + 10**50
+                       else:
+                           edges_tot[pos_potential_edge,4] = edges_tot[pos_potential_edge,2] + 10**50
+                           edges_tot[pos_potential_edge-half,4] = edges_tot[pos_potential_edge-half,2] + 10**50
+                       #Updating auxiliary matrix CP, C, S
+                       u,v=min(node1,node2),max(node1,node2)
+                       C_sliced_u,C_sliced_v=C[CP[u-1]],C[CP[v-1]]
+                       S[CP[u-1]] = len(C_sliced_u) + len(C_sliced_v) #Updating size of components
+                       C[CP[u-1]]+=C[CP[v-1]] #Merging two lists due to component's merge 
+                       old_pos = CP[v-1]
+                       for j in range(len(C_sliced_v)): #Updating components position for each merged node
+                           CP[C_sliced_v[j]-1]=CP[u-1]
+                       for j in range(len(CP)):
+                           if CP[j]>old_pos:
+                               CP[j]-=1
+                       del C[old_pos] #Deleting old component
+                       del S[old_pos] #Deleting old component size (line 590 .m file)
+                    else: #If a cable crossing is detected
+                        if pos_potential_edge<=half-1: 
+                           edges_tot[pos_potential_edge,4] = edges_tot[pos_potential_edge,2] + 10**50
+                           edges_tot[pos_potential_edge+half,4] = edges_tot[pos_potential_edge+half,2] + 10**50
+                        else:
+                           edges_tot[pos_potential_edge,4] = edges_tot[pos_potential_edge,2] + 10**50
+                           edges_tot[pos_potential_edge-half,4] = edges_tot[pos_potential_edge-half,2] + 10**50
+        if len(C)==1:
+           go=False #(line 606 .m file)
+           feasible=True
+    T=np.zeros((len(np.where(mst_edges==True)[0]),3))
+    T[:,0]=edges_tot[np.where(mst_edges==True)[0],0]
+    T[:,1]=edges_tot[np.where(mst_edges==True)[0],1]
+    T[:,2]=edges_tot[np.where(mst_edges==True)[0],2]    
+#%%  Running the function          
+    return T,feasible         
+if __name__ == "__main__": 
+    #First X,Y are for artifitial wind farm Diagonal 10 (10 WTs + 1 OSS)         
+    X=[10000,8285.86867841725,9097.62726321941,8736.91009361509,9548.66867841725,10360.4272632194,9187.95150881294,9999.71009361510,10811.4686784173,10450.7515088129,11262.5100936151]
+    Y=[10000,9426,8278,10574,9426,8278,11722,10574,9426,11722,10574]
+    #Next X,Y are for real-world wind farm Ormonde (30 WTs + 1 OSS)
+    #X=[473095,471790,471394,470998,470602,470207,469811,472523,469415,472132,471742,471351,470960,470569,470179,469788,472866,472480,472094,471708,471322,470937,470551,473594,473213,472833,472452,472071,471691,471310,470929]
+    #Y=[5992345,5991544,5991899,5992252,5992607,5992960,5993315,5991874,5993668,5992236,5992598,5992960,5993322,5993684,5994047,5994409,5992565,5992935,5993306,5993675,5994045,5994416,5994786,5992885,5993264,5993643,5994021,5994400,5994779,5995156,5995535]
+    #Next X, Y are for real-world wind farm DanTysk (80 WTs + 1 OSS)
+    #X=[387100,383400,383400,383900,383200,383200,383200,383200,383200,383200,383200,383200,383300,384200,384200,384100,384000,383800,383700,383600,383500,383400,383600,384600,385400,386000,386100,386200,386300,386500,386600,386700,386800,386900,387000,387100,387200,383900,387400,387500,387600,387800,387900,388000,387600,386800,385900,385000,384100,384500,384800,385000,385100,385200,385400,385500,385700,385800,385900,385900,385500,385500,386000,386200,386200,384500,386200,386700,386700,386700,384300,384400,384500,384600,384300,384700,384700,384700,385500,384300,384300]
+    #Y=[6109500,6103800,6104700,6105500,6106700,6107800,6108600,6109500,6110500,6111500,6112400,6113400,6114000,6114200,6115100,6115900,6116700,6118400,6119200,6120000,6120800,6121800,6122400,6122000,6121700,6121000,6120000,6119100,6118100,6117200,6116200,6115300,6114300,6113400,6112400,6111500,6110700,6117600,6108900,6108100,6107400,6106300,6105200,6104400,6103600,6103600,6103500,6103400,6103400,6104400,6120400,6119500,6118400,6117400,6116500,6115500,6114600,6113500,6112500,6111500,6105400,6104200,6110400,6109400,6108400,6121300,6107500,6106400,6105300,6104400,6113300,6112500,6111600,6110800,6110100,6109200,6108400,6107600,6106500,6106600,6105000]
+    X=np.array(X)
+    Y=np.array(Y)    
+    option=3
+    UL=15
+    Inters_const=True
+    T,feasible=capacitated_spanning_tree(X,Y,option,UL,Inters_const)
+
+    print("The total length of the solution is {value:.2f} m".format(value = sum(T[:,2])))
+    print("Feasibility: {feasible1}".format(feasible1=feasible))
+    plt.figure()
+    plt.plot(X[1:], Y[1:], 'r+',markersize=10, label='Turbines')
+    plt.plot(X[0], Y[0], 'ro',markersize=10, label='OSS')
+    for i in range(len(X)):
+        plt.text(X[i]+50, Y[i]+50,str(i+1))
+    n1xs = X[T[:,0].astype(int)-1].ravel().T
+    n2xs = X[T[:,1].astype(int)-1].ravel().T
+    n1ys = Y[T[:,0].astype(int)-1].ravel().T
+    n2ys = Y[T[:,1].astype(int)-1].ravel().T
+    xs = np.vstack([n1xs,n2xs])
+    ys = np.vstack([n1ys,n2ys])
+    plt.plot(xs,ys,'b')
+    plt.legend()
\ No newline at end of file
diff --git a/edwin/c_mst_cables.py b/edwin/c_mst_cables.py
new file mode 100644
index 0000000..da43f91
--- /dev/null
+++ b/edwin/c_mst_cables.py
@@ -0,0 +1,109 @@
+# -*- coding: utf-8 -*-
+"""
+Created on Thu Jun  4 08:07:37 2020
+
+@author: juru
+"""
+
+import numpy as np
+import networkx as nx
+import matplotlib.pyplot as plt
+from c_mst import capacitated_spanning_tree
+import time
+
+def cmst_cables(X=[],Y=[],T=[],Cables=[],plot=True):
+    """
+    Assigns cables to the obtained C-MST in previous stage
+
+    Parameters
+    ----------
+    *X, Y: Arrays([n_wt_oss]) 
+            X,Y positions of the wind turbines and oss
+    *T: Obtained tree in previous stage
+    *Cables: Array([cables available, 3]). Each row is a cable available. Column number one is cross-section, column number 2 number of WTs
+                                           and column number 3 is the price/km of the cable
+    
+    :return: Td: Array. Each row is a connection. First column is node 1, second column node 2, third column length (m), fourd column is
+                        cable type (index of the Cables array), and last column is the cost of the edge
+
+    """   
+    G = nx.Graph() 
+    G.add_nodes_from([x+1 for x in range(len(T[:,1])+1)])
+    G.add_edges_from([tuple(T[edge,0:2]) for edge in range(len(T[:,1]))]) 
+    T_d=np.array([x for x in nx.dfs_edges(G, source=1)]).astype(int)
+    accumulator=np.zeros(T_d.shape[0])
+    for j in range(len(T[:,1])):
+        k = j + 2
+        continue_ite = 1
+        look_up = k
+        while continue_ite:
+              accumulator += (T_d[:,1]==look_up).astype(int)
+              if (T_d[:,1]==look_up).astype(int).sum() > 1:
+                 Exception('Error')
+              if T_d[(T_d[:,1]==look_up)][0,0] == 1:
+                 continue_ite = 0
+              else:
+                  look_up=T_d[(T_d[:,1]==look_up)][0,0]
+    T_d=np.append(T_d,np.zeros((accumulator.shape[0],3)),axis=1)
+    for k in range(T_d.shape[0]):
+        aux1=np.argwhere((T[:,0]==T_d[k,0]) & (T[:,1]==T_d[k,1]))
+        aux2=np.argwhere((T[:,1]==T_d[k,0]) & (T[:,0]==T_d[k,1]))
+        if aux2.size==0:
+           T_d[k,2]=T[aux1,2]
+        if aux1.size==0:
+           T_d[k,2]=T[aux2,2]
+        if (aux2.size==0) and (aux1.size==0):
+            Exception('Error')
+        for k in range(accumulator.shape[0]):
+            for l in range(Cables.shape[0]):
+                if accumulator[k]<=Cables[l,1]:
+                   break  
+            T_d[k,3]=l
+        for k in range(T_d.shape[0]):
+            T_d[k,4]=(T_d[k,2]/1000)*Cables[T_d.astype(int)[k,3],2]
+    if plot:
+        plt.figure()
+        plt.plot(X[1:], Y[1:], 'r+',markersize=10, label='Turbines')
+        plt.plot(X[0], Y[0], 'ro',markersize=10, label='OSS')
+        for i in range(len(X)):
+            plt.text(X[i]+50, Y[i]+50,str(i+1))
+        colors = ['b','g','r','c','m','y','k','bg','gr','rc','cm']
+        for i in range(Cables.shape[0]):
+            index = T_d[:,3]==i
+            if index.any():
+               n1xs = X[T_d[index,0].astype(int)-1].ravel().T
+               n2xs = X[T_d[index,1].astype(int)-1].ravel().T
+               n1ys = Y[T_d[index,0].astype(int)-1].ravel().T
+               n2ys = Y[T_d[index,1].astype(int)-1].ravel().T
+               xs = np.vstack([n1xs,n2xs])
+               ys = np.vstack([n1ys,n2ys])
+               plt.plot(xs,ys,'{}'.format(colors[i]))
+               plt.plot([],[],'{}'.format(colors[i]),label='Cable: {} mm2'.format(Cables[i,0]))
+        plt.legend()
+    return T_d
+if __name__ == "__main__":
+  t = time.time()
+  X=[387100,383400,383400,383900,383200,383200,383200,383200,383200,383200,383200,383200,383300,384200,384200,384100,384000,383800,383700,383600,383500,383400,383600,384600,385400,386000,386100,386200,386300,386500,386600,386700,386800,386900,387000,387100,387200,383900,387400,387500,387600,387800,387900,388000,387600,386800,385900,385000,384100,384500,384800,385000,385100,385200,385400,385500,385700,385800,385900,385900,385500,385500,386000,386200,386200,384500,386200,386700,386700,386700,384300,384400,384500,384600,384300,384700,384700,384700,385500,384300,384300]
+  Y=[6109500,6103800,6104700,6105500,6106700,6107800,6108600,6109500,6110500,6111500,6112400,6113400,6114000,6114200,6115100,6115900,6116700,6118400,6119200,6120000,6120800,6121800,6122400,6122000,6121700,6121000,6120000,6119100,6118100,6117200,6116200,6115300,6114300,6113400,6112400,6111500,6110700,6117600,6108900,6108100,6107400,6106300,6105200,6104400,6103600,6103600,6103500,6103400,6103400,6104400,6120400,6119500,6118400,6117400,6116500,6115500,6114600,6113500,6112500,6111500,6105400,6104200,6110400,6109400,6108400,6121300,6107500,6106400,6105300,6104400,6113300,6112500,6111600,6110800,6110100,6109200,6108400,6107600,6106500,6106600,6105000]  
+  X=np.array(X)
+  Y=np.array(Y)
+  
+  option=3
+  UL=11
+  Inters_const=False
+  Cables=np.array([[500,3,100000],[800,5,150000],[1000,10,250000]])
+  
+  T,feasible=capacitated_spanning_tree(X,Y,option,UL,Inters_const)
+
+  print("The total length of the solution is {value:.2f} m".format(value = sum(T[:,2])))
+  print("Feasibility: {feasible1}".format(feasible1=feasible)) 
+  
+  if feasible:
+      T_cables=cmst_cables(X,Y,T,Cables)
+      print("The total cost of the system is {value:.2f} Euros".format(value = T_cables[:,-1].sum()))
+  elapsed = time.time() - t
+  print("The total time is {timep: .2f} s".format(timep=elapsed))
+  
+
+  
+  
diff --git a/edwin/collection_system.py b/edwin/collection_system.py
new file mode 100644
index 0000000..8d3ca70
--- /dev/null
+++ b/edwin/collection_system.py
@@ -0,0 +1,46 @@
+# -*- coding: utf-8 -*-
+"""
+Created on Mon Jun 22 10:59:47 2020
+
+@author: juru
+"""
+import numpy as np
+from c_mst import capacitated_spanning_tree
+from c_mst_cables import cmst_cables
+
+def collection_system(X=[],Y=[],option=3,Inters_const=True,max_it=20000,Cables=[],plot=False):
+    UL=max(Cables[:,1])
+    T,feasible=capacitated_spanning_tree(X,Y,option,UL,Inters_const)
+    T_cables_cost=((T[:,-1].sum())/1000)*Cables[-1,2]
+    T_cables=np.concatenate((T,np.full((T.shape[0],2),Cables.shape[1]-1)), axis=1)
+    if feasible:
+       T_cables=cmst_cables(X,Y,T,Cables,plot)
+       T_cables_cost=T_cables[:,-1].sum()
+    return T_cables,T_cables_cost
+
+if __name__ == "__main__":
+  #X=[387100,383400,383400,383900,383200,383200,383200,383200,383200,383200,383200,383200,383300,384200,384200,384100,384000,383800,383700,383600,383500,383400,383600,384600,385400,386000,386100,386200,386300,386500,386600,386700,386800,386900,387000,387100,387200,383900,387400,387500,387600,387800,387900,388000,387600,386800,385900,385000,384100,384500,384800,385000,385100,385200,385400,385500,385700,385800,385900,385900,385500,385500,386000,386200,386200,384500,386200,386700,386700,386700,384300,384400,384500,384600,384300,384700,384700,384700,385500,384300,384300]
+  #Y=[6109500,6103800,6104700,6105500,6106700,6107800,6108600,6109500,6110500,6111500,6112400,6113400,6114000,6114200,6115100,6115900,6116700,6118400,6119200,6120000,6120800,6121800,6122400,6122000,6121700,6121000,6120000,6119100,6118100,6117200,6116200,6115300,6114300,6113400,6112400,6111500,6110700,6117600,6108900,6108100,6107400,6106300,6105200,6104400,6103600,6103600,6103500,6103400,6103400,6104400,6120400,6119500,6118400,6117400,6116500,6115500,6114600,6113500,6112500,6111500,6105400,6104200,6110400,6109400,6108400,6121300,6107500,6106400,6105300,6104400,6113300,6112500,6111600,6110800,6110100,6109200,6108400,6107600,6106500,6106600,6105000]  
+  #X=np.array(X)
+  #Y=np.array(Y)
+  X=np.array([    0.        ,  2000.        ,  4000.        ,  6000.        ,
+         8000.        ,   498.65600569,  2498.65600569,  4498.65600569,
+         6498.65600569,  8498.65600569,   997.31201137,  2997.31201137,
+         4997.31201137, 11336.25662483,  8997.31201137,  1495.96801706,
+         3495.96801706,  5495.96801706, 10011.39514341, 11426.89538545,
+         1994.62402275,  3994.62402275,  5994.62402275,  7994.62402275,
+        10588.90471566])
+  Y=np.array([   0.        ,    0.        ,    0.        ,    0.        ,
+           0.        , 2000.        , 2000.        , 2000.        ,
+        2000.        , 2000.        , 4000.        , 4000.        ,
+        4000.        , 6877.42528387, 4000.        , 6000.        ,
+        6000.        , 6000.        , 3179.76530545, 5953.63051694,
+        8000.        , 8000.        , 8000.        , 8000.        ,
+        4734.32972738])
+  
+  option=3
+  #UL=5
+  Inters_const=True
+  Cables=np.array([[500,3,100000],[800,5,150000],[1000,10,250000]])
+  
+  T,amount=collection_system(X,Y,option,Inters_const,Cables=Cables,plot=True)
\ No newline at end of file
diff --git a/edwin/intersection_checker.py b/edwin/intersection_checker.py
new file mode 100644
index 0000000..b4fba78
--- /dev/null
+++ b/edwin/intersection_checker.py
@@ -0,0 +1,30 @@
+# -*- coding: utf-8 -*-
+"""
+Created on Fri May 29 10:08:54 2020
+
+@author: juru
+"""
+
+import numpy as np
+from two_lines_intersecting import two_lines_intersecting
+
+def intersection_checker(pos_potential_edge,edges_tot,mst_edges,X,Y,Inters_const): 
+    current_edges=np.where(mst_edges==True)[0]
+    current_edges_size=current_edges.size
+    intersection=False
+    if Inters_const:
+        if current_edges_size==0:
+            pass
+        else:
+            for i in range(current_edges_size):
+                line1=np.array([[X[edges_tot[pos_potential_edge,0].astype(int)-1],Y[edges_tot[pos_potential_edge,0].astype(int)-1]],\
+                                [X[edges_tot[pos_potential_edge,1].astype(int)-1],Y[edges_tot[pos_potential_edge,1].astype(int)-1]]])
+                line2=np.array([[X[edges_tot[current_edges[i],0].astype(int)-1],Y[edges_tot[current_edges[i],0].astype(int)-1]],\
+                                [X[edges_tot[current_edges[i],1].astype(int)-1],Y[edges_tot[current_edges[i],1].astype(int)-1]]])
+                if two_lines_intersecting(line1,line2):
+                    intersection=True
+                    break
+    return intersection
+
+#if __name__ == '__main__':
+    #cross=intersection_checker(pos_potential_edge,edges_tot,mst_edges,X,Y)
diff --git a/edwin/two_lines_intersecting.py b/edwin/two_lines_intersecting.py
new file mode 100644
index 0000000..ee58954
--- /dev/null
+++ b/edwin/two_lines_intersecting.py
@@ -0,0 +1,179 @@
+# -*- coding: utf-8 -*-
+"""
+Created on Tue Feb 11 13:33:46 2020
+
+@author: juru
+"""
+
+import numpy as np
+import matplotlib.pylab as plt
+
+def two_lines_intersecting(line1,line2):
+    """
+    """
+    intersect = False
+    if (((line1[0][0] == line1[1][0]) and (line1[0][1] == line1[1][1])) or ((line2[0][0] == line2[1][0]) and (line2[0][1] == line2[1][1]))):
+        intersect = False
+    else:
+        x1 = [line1[0][0],line1[1][0]]
+        y1 = [line1[0][1],line1[1][1]]
+        #plt.figure()
+        #plt.plot(x1, y1, label = "line 1")  
+        x2 = [line2[0][0],line2[1][0]]
+        y2 = [line2[0][1],line2[1][1]]
+        #plt.plot(x2, y2, label = "line 2")   
+    
+        if (line1[1,0] - line1[0,0])!=0:
+            m1=(line1[1,1] - line1[0,1])/(line1[1,0] - line1[0,0])
+        else:
+            if (line1[1,1] - line1[0,1])>0:
+                m1=float('inf')
+            else:
+                m1=float('-inf')
+        if (line2[1,0] - line2[0,0])!=0:
+            m2=(line2[1,1] - line2[0,1])/(line2[1,0] - line2[0,0])
+        else:
+            if (line2[1,1] - line2[0,1])>0:
+                m2=float('inf')
+            else:
+                m2=float('-inf')                        
+        #m1 = np.true_divide((line1[1,1] - line1[0,1]), (line1[1,0] - line1[0,0]))
+        #m2 = np.true_divide((line2[1,1] - line2[0,1]), (line2[1,0] - line2[0,0]))
+        b1 = line1[0,1] - m1*line1[0,0]
+        b2 = line2[0,1] - m2*line2[0,0]
+        check_val=False
+        if (((m1 != np.inf)and(m1 != -np.inf)) and ((m2 != np.inf)and(m2 != -np.inf))):
+            check_val=True
+            if (m1-m2)!=0:
+                xintersect=(b2-b1)/(m1-m2)
+            else:
+                if (b2-b1)>0:
+                    xintersect=float('inf')
+                else:
+                    xintersect=float('-inf')                         
+        #xintersect = np.true_divide((b2-b1), (m1-m2))
+        #yintersect = m1*xintersect + b1
+        
+        if ((np.abs(m1-m2)>1e-6) and (check_val==True)):
+            isPointInsidex1 = (
+                ((xintersect - line1[0,0]) > 1e-6 and (xintersect - line1[1,0]) < -1e-6 ) or 
+                ((xintersect - line1[1,0]) > 1e-6 and (xintersect - line1[0,0]) < -1e-6))
+        
+            isPointInsidex2 = (
+                ((xintersect - line2[0,0]) > 1e-6 and (xintersect - line2[1,0]) < -1e-6 ) or
+                ((xintersect - line2[1,0]) > 1e-6 and (xintersect - line2[0,0]) < -1e-6))
+        
+            inside = isPointInsidex1 and isPointInsidex2
+            intersect = inside
+            #NEW TWO LINES 20-09-2021
+            if (line1[0,0]==line2[0,0] and line1[0,1]==line2[0,1]) or (line1[0,0]==line2[1,0] and line1[0,1]==line2[1,1]) or (line1[1,0]==line2[0,0] and line1[1,1]==line2[0,1]) or (line1[1,0]==line2[1,0] and line1[1,1]==line2[1,1]):
+               intersect=False
+    
+               
+        if (np.abs(m1-m2)<1e-6) :
+            if (np.abs(b1-b2)>1e-6) :
+                intersect = False
+                
+            if (np.abs(b1-b2)<1e-6) :
+                isPointInside12 = (((line1[0,0] - line2[0,0]) > 1e-6 and
+                    (line1[0,0] - line2[1,0]) < -1e-6 ) or
+                    ((line1[0,0] - line2[1,0]) > 1e-6 and
+                    (line1[0,0] - line2[0,0]) < -1e-6))
+                
+                isPointInside22 = (((line1[1,0] - line2[0,0]) > 1e-6 and
+                    (line1[1,0] - line2[1,0]) < -1e-6 ) or
+                    ((line1[1,0]- line2[1,0]) > 1e-6 and
+                    (line1[1,0] - line2[0,0]) < -1e-6))
+                inside = isPointInside12 or isPointInside22
+                intersect = inside
+                
+        
+        if (((m1 == np.inf) or (m1 == -np.inf)) or ((m2 == np.inf) or (m2 == -np.inf))):
+            if (((m1 != np.inf)and(m1 != -np.inf)) or ((m2 != np.inf)and(m2 != -np.inf))):
+                if ((m1 != 0) and (m2 != 0)):
+                    line3 = np.zeros((2,2))
+                    line4 = np.zeros((2,2))
+                    line3[0,0] = line1[0,1]
+                    line3[0,1] = line1[0,0] 
+                    line3[1,0] = line1[1,1] 
+                    line3[1,1] = line1[1,0] 
+                    line4[0,0] = line2[0,1] 
+                    line4[0,1] = line2[0,0] 
+                    line4[1,0] = line2[1,1]
+                    line4[1,1] = line2[1,0]
+                    m3 = (line3[1,1] - line3[0,1])/(line3[1,0] - line3[0,0])
+                    m4 = (line4[1,1] - line4[0,1])/(line4[1,0] - line4[0,0])
+                    b3 = line3[0,1] - m3*line3[0,0]
+                    b4 = line4[0,1] - m4*line4[0,0]
+                    xintersect2 = (b4-b3)/(m3-m4)
+                    #yintersect2 = m3*xintersect2 + b3
+                    isPointInsidex6 = (
+                    ((xintersect2 - line3[0,0]) > 1e-6 and (xintersect2 - line3[1,0]) < -1e-6 ) or 
+                    ((xintersect2 - line3[1,0]) > 1e-6 and (xintersect2 - line3[0,0]) < -1e-6))
+                    isPointInsidex7 = (
+                    ((xintersect2 - line4[0,0]) > 1e-6 and (xintersect2 - line4[1,0]) < -1e-6 ) or 
+                    ((xintersect2 - line4[1,0]) > 1e-6 and (xintersect2 - line4[0,0]) < -1e-6))
+        
+                    inside = isPointInsidex6 and isPointInsidex7
+                
+                    intersect = inside
+                    
+                    #NEW TWO LINES 20-09-2021
+                    if (line1[0,0]==line2[0,0] and line1[0,1]==line2[0,1]) or (line1[0,0]==line2[1,0] and line1[0,1]==line2[1,1]) or (line1[1,0]==line2[0,0] and line1[1,1]==line2[0,1]) or (line1[1,0]==line2[1,0] and line1[1,1]==line2[1,1]):
+                        intersect=False
+                    
+                else:
+                    if (m1==0):
+                        y1=line1[0,1]
+                        x1min=np.min((line1[0,0],line1[1,0]))
+                        x1max=np.max((line1[0,0],line1[1,0]))
+                        x2=line2[0,0]
+                        y2min=np.min((line2[0,1],line2[1,1]))
+                        y2max=np.max((line2[0,1],line2[1,1]))
+                        if ((y1>y2min)and(y1<y2max)and(x2>x1min)and(x2<x1max)):                      
+                            intersect = True
+                            
+                        else:
+                            intersect = False
+                            
+                    if (m2==0):
+                       y2=line2[0,1]
+                       x2min=np.min((line2[0,0],line2[1,0]))
+                       x2max=np.max((line2[0,0],line2[1,0]))
+                       x1=line1[0,0]
+                       y1min=np.min((line1[0,1],line1[1,1]))
+                       y1max=np.max((line1[0,1],line1[1,1]))
+                       if ((y2>y1min)and(y2<y1max)and(x1>x2min)and(x1<x2max))   :  
+                           intersect = True
+                           
+                       else:
+                           intersect = False
+                           
+            if (((m1 == np.inf)or(m1 == -np.inf)) and ((m2 == np.inf)or(m2 == -np.inf))):
+                if (line1[0,0] == line2[0,0]) : 
+                    insidet= (((line1[0,1] - line2[0,1]) > 1e-6  and (line1[0,1] - line2[1,1]) < -1e-6) or 
+                    ((line1[0,1] - line2[1,1]) > 1e-6  and (line1[0,1] - line2[0,1]) < -1e-6))
+                    insidep=(((line1[1,1] - line2[0,1]) > 1e-6  and (line1[1,1] - line2[1,1]) < -1e-6) or 
+                    ((line1[1,1] - line2[1,1]) > 1e-6  and (line1[1,1] - line2[0,1]) < -1e-6))
+                    inside = insidet or insidep
+                    intersect = inside
+                    
+                if (line1[0,0] != line2[0,0]):
+                    intersect = False
+                    
+    return intersect
+
+
+if __name__ == '__main__':
+    line1=np.array([[1,2],[3,4]]) # The first column represents to x-values of the line segment line[0,0] y line[1,0]. The second column represents the y-values of
+                                    #the line segment
+    line2=np.array([[1,4],[3,2]])
+    
+    line1 = np.random.rand(4).reshape((2,2))*10-5
+    line2 = np.random.rand(4).reshape((2,2))*10-5
+    
+#    line1=np.array([[1,2],[7,2]]) 
+#    line2=np.array([[5,3],[5,1]])
+    
+    intersect = two_lines_intersecting(line1,line2)
+    print(intersect)
\ No newline at end of file
-- 
GitLab