diff --git a/mip.py b/mip.py index 0a66005..26a661e 100644 --- a/mip.py +++ b/mip.py @@ -320,6 +320,21 @@ def design_with_mip( f"NOTICE: Clusters are relatively close ({min_cluster_distance:.2f} m)" ) + # Check for cable crossings + cable_crossings = check_cable_crossings(connections, turbines, substation) + if cable_crossings: + print( + f"WARNING: Found {len(cable_crossings)} cable crossing(s) in the solution" + ) + for i, (idx1, idx2, p1, p2, p3, p4) in enumerate(cable_crossings): + conn1 = connections[idx1] + conn2 = connections[idx2] + print( + f" Crossing {i + 1}: Connection {conn1[0]}-{conn1[1]} crosses {conn2[0]}-{conn2[1]}" + ) + else: + print("No cable crossings detected in the solution") + print( f"MIP optimization completed successfully, {len(connections)} connections generated" ) @@ -363,3 +378,63 @@ def check_cluster_distances(clusters, turbines, min_distance_threshold=1000): min_pair = (c1, c2) return min_distance + + +def check_cable_crossings(connections, turbines, substation): + """Check if there are cable crossings in the solution.""" + crossings = [] + + def line_intersection(p1, p2, p3, p4): + """Check if line segments (p1,p2) and (p3,p4) intersect.""" + x1, y1 = p1 + x2, y2 = p2 + x3, y3 = p3 + x4, y4 = p4 + + denom = (y4 - y3) * (x2 - x1) - (x4 - x3) * (y2 - y1) + + if abs(denom) < 1e-10: + return False + + ua = ((x4 - x3) * (y1 - y3) - (y4 - y3) * (x1 - x3)) / denom + ub = ((x2 - x1) * (y1 - y3) - (y2 - y1) * (x1 - x3)) / denom + + return 0 <= ua <= 1 and 0 <= ub <= 1 + + def get_turbine_coord(connection_part): + """Get coordinates from connection part (turbine_# or substation).""" + if connection_part == "substation": + # Ensure substation is returned as a proper tuple for unpacking + if isinstance(substation, (list, np.ndarray)): + return (substation[0], substation[1]) + else: + return (substation[0], substation[1]) + else: + turbine_idx = int(connection_part.split("_")[1]) + return ( + turbines.iloc[turbine_idx]["x"], + turbines.iloc[turbine_idx]["y"], + ) + + for i in range(len(connections)): + for j in range(i + 1, len(connections)): + conn1 = connections[i] + conn2 = connections[j] + + p1 = get_turbine_coord(conn1[0]) + p2 = get_turbine_coord(conn1[1]) + p3 = get_turbine_coord(conn2[0]) + p4 = get_turbine_coord(conn2[1]) + + if ( + np.array_equal(p1, p3) + or np.array_equal(p1, p4) + or np.array_equal(p2, p3) + or np.array_equal(p2, p4) + ): + continue + + if line_intersection(p1, p2, p3, p4): + crossings.append((i, j, p1, p2, p3, p4)) + + return crossings