from shapely.geometry import Polygon
import triangle
from shapely.ops import unary_union
from stl import mesh
import numpy as np
from collections import defaultdict
from 三維投影線段尋找 import get_adjusted_clusters,get_clusters,get_intersect_lines
import networkx as nx
if __name__ == "__main__":dxf_file_path = 'a.dxf'clusters=get_clusters(dxf_file_path)adjusted_clusters,yz中間面線段集,xy上下面線段集,xz左右面線段集 =get_adjusted_clusters(clusters)intersect_lines=get_intersect_lines(xz左右面線段集,yz中間面線段集,xy上下面線段集)intersect_lines1,intersect_lines2,intersect_lines3 = intersect_lines
# 定義一個函數來消除坐標差異
def align_coordinates(lines, step):aligned_lines = []for line in lines:# 四舍五入坐標到最近的step的倍數aligned_line = ((np.round(line[0][0] / step) * step, np.round(line[0][1] / step) * step, np.round(line[0][2] / step) * step),(np.round(line[1][0] / step) * step, np.round(line[1][1] / step) * step, np.round(line[1][2] / step) * step),)aligned_lines.append(aligned_line)return aligned_lines# 使用函數消除坐標差異,這里以0.2為步長
aligned_intersectlines1 = align_coordinates(intersect_lines1, 0.2)
aligned_intersectlines2 = align_coordinates(intersect_lines2, 0.2)
aligned_intersectlines3 = align_coordinates(intersect_lines3, 0.2)
lines_grouped_by_y = defaultdict(list)
lines_grouped_by_x = defaultdict(list)
lines_grouped_by_z = defaultdict(list)
for line in aligned_intersectlines1:y = line[0][1] # 假設y值是線段第一個點的y坐標lines_grouped_by_y[y].append(line)
for line in aligned_intersectlines2:z = line[0][2] # 假設y值是線段第一個點的y坐標lines_grouped_by_z[z].append(line)
for line in aligned_intersectlines3:x = line[0][0] # 假設y值是線段第一個點的y坐標lines_grouped_by_x[x].append(line)
print(f"y找到了{len(lines_grouped_by_y )}個面")
print(f"z找到了{len(lines_grouped_by_z )}個面")
print(f"x找到了{len(lines_grouped_by_x )}個面")def get_2d_polygon(d,nodes):if d==0:polygon = Polygon([(y,z) for x,y, z in nodes])elif d==1:polygon = Polygon([(x,z) for x,y, z in nodes])else:polygon = Polygon([(x,y) for x,y, z in nodes])return polygon
def get_3dvertices_array(d,t, vertices):if d==0:vertices_array = np.array([(t, y, z) for y, z in vertices])elif d==1:vertices_array = np.array([(x, t, z) for x, z in vertices])else :vertices_array = np.array([(x, y, t) for x, y in vertices])return vertices_arraydef polygon_to_mesh(d,t,polygon):vertices = list(polygon.exterior.coords)[:-1]# 創建外環邊界的線段列表segments = [[i, i+1] for i in range(0,len(vertices)-1 )]segments.append([len(vertices) - 1, 0]) tridict = {'vertices': vertices,'segments': segments, # 注意:segments 應該是一個列表的列表 }tri = triangle.triangulate(tridict, 'p')triangles = tri['triangles']vertices=tri['vertices']# print(" triangles", triangles)# print(" vertices2", vertices)faces_array = np.array(triangles) # STL 文件中的索引是從1開始的vertices_array=get_3dvertices_array(d,t,vertices)# 創建 mesh 對象triangle_mesh = mesh.Mesh(np.zeros(faces_array.shape[0], dtype=mesh.Mesh.dtype))for i, fa in enumerate(faces_array):for j in range(3):triangle_mesh.vectors[i][j] = vertices_array[fa[j], :]return triangle_mesh
def merge_meshes(meshes_to_merge):# 合并所有網格的頂點combined_data = []for m in meshes_to_merge:combined_data.append(m.data)combined_mesh = mesh.Mesh(np.concatenate(combined_data))return combined_mesh
def get_closed_subgraphs_in_open_faces(d,lines_grouped_by):meshes_to_merge=[]for t, items in lines_grouped_by.items():polygons=[]G = nx.Graph()G.add_edges_from(items)outer_ring=Noneinner_rings=[]if not nx.is_connected(G):closed_subgraphs_in_current_faces = []# 對于不閉合的面,找到所有的連通分量for component in nx.connected_components(G):# 創建一個子圖,只包含當前連通分量中的節點和邊subgraph = G.subgraph(component)# 檢查子圖是否閉合(形成一個環)if nx.is_eulerian(subgraph):print(f"當前面閉合圖形數{len(closed_subgraphs_in_current_faces)}")eulerian_circuit = list(nx.eulerian_circuit(subgraph))# 提取頂點列表subgraph_nodes = [edge[0] for edge in eulerian_circuit]subgraph_polygon = get_2d_polygon(d, subgraph_nodes )# 檢查是否有環在另一個環內部for other_polygon in closed_subgraphs_in_current_faces:if subgraph_polygon.within( other_polygon):# 如果內環在外環內,則可以在這里處理(例如,進行三角剖分切割)#用shaply對內外環形成的圖形內部做三角剖分切割print("這是一個內環")outer_ring= other_polygoninner_rings.append(subgraph_polygon)breakelif other_polygon.within(subgraph_polygon):print("這是一個外環")outer_ring=subgraph_polygoninner_rings.append( other_polygon)breakelse:print("分開環")closed_subgraphs_in_current_faces.append(subgraph_polygon ) if outer_ring:inner_rings_union = unary_union(inner_rings)poly=outer_ring.difference(inner_rings_union)# print("poly",poly)# 提取多邊形的頂點和邊界vertices = list(poly.exterior.coords)[:-1]# 創建外環邊界的線段列表segments = [[i, i+1] for i in range(0,len(vertices)-1 )]segments.append([len(vertices) - 1, 0]) # 連接最后一個和第一個外環頂點# 提取所有內環的頂點,并添加到 vertices 列表中for interior_ring in poly.interiors:vertices.extend(list(interior_ring.coords)[:-1]) # 內環頂點,去掉最后一個重復點# 創建內環邊界的線段列表for interior_ring in poly.interiors:start_index = len(vertices) - len(interior_ring.coords)+1for i in range(len(interior_ring.coords) - 2):segments.append([start_index + i, start_index + i + 1])segments.append([start_index + len(interior_ring.coords) - 2, start_index]) # 連接最后一個和第一個內環頂點holes = []for interior_ring in poly.interiors:# 可以使用內環的幾何中心點作為洞的位置holes.append(list(interior_ring.centroid.coords)[0])# 創建一個三角形庫的輸入字典tridict = {'vertices': vertices,'segments': segments, # 注意:segments 應該是一個列表的列表'holes': holes # 如果沒有內環,則不需要這一項}# print( 'vertices', vertices)# print( 'segments', segments)# print( 'holes', holes)# 使用 triangle 進行三角劃分tri = triangle.triangulate(tridict, 'p')# 假設 tri['triangles'] 包含了三角劃分的結果triangles = tri['triangles']vertices=tri['vertices']# print(" triangles", triangles)# print(" vertices2", vertices)# 創建一個 numpy 數組來保存頂點和三角形信息#draw_3d_p(vertices_array)faces_array = np.array(triangles) # STL 文件中的索引是從1開始的vertices_array=get_3dvertices_array(d,t,vertices)# 創建 mesh 對象triangle_mesh = mesh.Mesh(np.zeros(faces_array.shape[0], dtype=mesh.Mesh.dtype))for i, fa in enumerate(faces_array):for j in range(3):triangle_mesh.vectors[i][j] = vertices_array[fa[j], :]meshes_to_merge.append(triangle_mesh)else :polygons.extend(closed_subgraphs_in_current_faces) else: eulerian_circuit = list(nx.eulerian_circuit(G))subgraph_nodes = [edge[0] for edge in eulerian_circuit]eulerian_polygon = get_2d_polygon(d, subgraph_nodes )polygons.append(eulerian_polygon)for polygon in polygons:triangle_mesh=polygon_to_mesh(d,t,polygon)meshes_to_merge.append(triangle_mesh)#我這里也要生成triangle_mesh然后合并起來一起導出return meshes_to_merge
meshes_to_merge0=get_closed_subgraphs_in_open_faces(0,lines_grouped_by_x)
meshes_to_merge1=get_closed_subgraphs_in_open_faces(1,lines_grouped_by_y)
meshes_to_merge2=get_closed_subgraphs_in_open_faces(2,lines_grouped_by_z)meshes_to_merge = []# 將其他列表的內容添加到這個列表中
meshes_to_merge.extend(meshes_to_merge0)
meshes_to_merge.extend(meshes_to_merge1)
meshes_to_merge.extend(meshes_to_merge2)# 現在meshes_to_merge包含了所有網格,可以用來合并
mesh_merged = merge_meshes(meshes_to_merge)mesh_merged.save('merged_output_mesh.stl')
一跑就通,別的ai做得到嗎
readdxf: 三視圖,工程圖轉模型