| import glob
|
| import ray
|
| import numpy as np
|
| import argparse
|
|
|
| from OCC.Core.BRepAdaptor import BRepAdaptor_Surface
|
| from OCC.Core.BRepGProp import brepgprop
|
| from OCC.Core.BRepLProp import BRepLProp_SLProps
|
| from OCC.Core.GProp import GProp_GProps
|
| from lightning_fabric import seed_everything
|
|
|
| from eval.eval_condition import *
|
|
|
| import networkx as nx
|
| from OCC.Core.STEPControl import STEPControl_Reader
|
| from OCC.Core.TopExp import TopExp_Explorer
|
| from OCC.Core.TopAbs import TopAbs_VERTEX, TopAbs_EDGE
|
| from OCC.Core.BRep import BRep_Tool
|
| from OCC.Core.gp import gp_Pnt
|
|
|
|
|
| def remove_outliers_zscore(data, threshold=3, max_value=50):
|
| if len(data) == 0 or sum(data) == 0:
|
| return data
|
| mean = np.mean(data)
|
| std_dev = np.std(data)
|
| return [x for x in data if abs((x - mean) / (std_dev + 1e-8)) <= threshold and x < max_value]
|
|
|
|
|
| def extract_edges_and_vertices(shape):
|
| explorer_edges = TopExp_Explorer(shape, TopAbs_EDGE)
|
| explorer_vertices = TopExp_Explorer(shape, TopAbs_VERTEX)
|
|
|
| vertex_map = {}
|
| edges = []
|
|
|
| while explorer_edges.More():
|
| edge = explorer_edges.Current()
|
|
|
| vertices_on_edge = []
|
| vertex_explorer = TopExp_Explorer(edge, TopAbs_VERTEX)
|
| while vertex_explorer.More():
|
| vertex = vertex_explorer.Current()
|
| point = BRep_Tool.Pnt(vertex)
|
| coord = (round(point.X(), 6), round(point.Y(), 6), round(point.Z(), 6))
|
|
|
| if coord not in vertex_map:
|
| vertex_map[coord] = len(vertex_map)
|
|
|
| vertices_on_edge.append(vertex_map[coord])
|
| vertex_explorer.Next()
|
|
|
| if len(vertices_on_edge) == 2:
|
| edges.append(tuple(vertices_on_edge))
|
|
|
| explorer_edges.Next()
|
|
|
| return vertex_map, edges
|
|
|
|
|
| def create_nx_graph(vertex_map, edges):
|
| graph = nx.Graph()
|
|
|
| for coord, node_id in vertex_map.items():
|
| graph.add_node(node_id, coord=coord)
|
|
|
| for edge in edges:
|
| graph.add_edge(edge[0], edge[1])
|
|
|
| return graph
|
|
|
|
|
| def calculate_cyclomatic_complexity(graph):
|
| num_nodes = graph.number_of_nodes()
|
| num_edges = graph.number_of_edges()
|
| if graph.is_directed():
|
| num_components = nx.number_strongly_connected_components(graph)
|
| else:
|
| num_components = nx.number_connected_components(graph)
|
|
|
| cyclomatic_complexity = num_edges - num_nodes + 2 * num_components
|
| return cyclomatic_complexity
|
|
|
|
|
| def eval_complexity_one(step_file_path):
|
| isvalid, shape = check_step_valid_soild(step_file_path, return_shape=True)
|
| if not isvalid:
|
| return None
|
|
|
| vertex_map, edges = extract_edges_and_vertices(shape)
|
| graph = create_nx_graph(vertex_map, edges)
|
| cyclomatic_complexity = calculate_cyclomatic_complexity(graph)
|
|
|
| face_list = get_primitives(shape, TopAbs_FACE)
|
| num_face = len(face_list)
|
| num_edge = len(vertex_map.keys())
|
| num_vertex = len(edges)
|
|
|
| sample_point_curvature = []
|
| num_samples = 256
|
| for face in face_list:
|
| surf_adaptor = BRepAdaptor_Surface(face)
|
| u_min, u_max, v_min, v_max = (surf_adaptor.FirstUParameter(), surf_adaptor.LastUParameter(), surf_adaptor.FirstVParameter(),
|
| surf_adaptor.LastVParameter())
|
|
|
| u_samples = np.linspace(u_min, u_max, int(np.sqrt(num_samples)))
|
| v_samples = np.linspace(v_min, v_max, int(np.sqrt(num_samples)))
|
|
|
| face_sample_point_curvature = []
|
| for u in u_samples:
|
| for v in v_samples:
|
| props = BRepLProp_SLProps(surf_adaptor, u, v, 2, 1e-8)
|
| if props.IsCurvatureDefined():
|
| mean_curvature = props.MeanCurvature()
|
| face_sample_point_curvature.append(abs(mean_curvature))
|
| face_sample_point_curvature = remove_outliers_zscore(face_sample_point_curvature)
|
| if len(face_sample_point_curvature) == 0:
|
| continue
|
| sample_point_curvature.append(np.median(face_sample_point_curvature))
|
|
|
| mean_curvature = np.mean(sample_point_curvature) if len(sample_point_curvature) > 0 else np.nan
|
|
|
| if num_face == 0 or mean_curvature == np.nan:
|
| return None
|
|
|
| return {
|
| 'num_face' : int(num_face),
|
| 'num_edge' : int(num_edge),
|
| 'num_vertex' : int(num_vertex),
|
| 'cyclomatic_complexity': cyclomatic_complexity,
|
| 'mean_curvature' : mean_curvature,
|
| }
|
|
|
|
|
| eval_complexity_one_remote = ray.remote(eval_complexity_one)
|
|
|
| if __name__ == '__main__':
|
| parser = argparse.ArgumentParser(description='Evaluate Brep Complexity')
|
| parser.add_argument('--eval_root', type=str)
|
| parser.add_argument('--only_valid', action='store_true')
|
| args = parser.parse_args()
|
|
|
|
|
| seed_everything(0)
|
| ray.init(ignore_reinit_error=True, local_mode=False)
|
|
|
| all_folders = os.listdir(args.eval_root)
|
| is_valid_list = []
|
| futures = []
|
| for folder in tqdm(all_folders):
|
| step_path_list = glob.glob(os.path.join(args.eval_root, folder, '*.step'))
|
| if len(step_path_list) == 0:
|
| is_valid_list.append(False)
|
| futures.append(None)
|
| continue
|
| is_valid_list.append(check_step_valid_soild(step_path_list[0], return_shape=False))
|
| futures.append(eval_complexity_one_remote.remote(step_path_list[0]))
|
|
|
| assert len(is_valid_list) == len(futures) == len(all_folders)
|
| all_result = {}
|
| for i, future in enumerate(tqdm(futures)):
|
| if future is None:
|
| continue
|
| result = ray.get(future)
|
| if args.only_valid and not is_valid_list[i]:
|
| continue
|
| all_result[all_folders[i]] = result
|
|
|
| num_face_list = []
|
| num_edge_list = []
|
| num_vertex_list = []
|
| cyclomatic_complexity_list = []
|
| mean_curvature_list = []
|
| exception_folder = []
|
|
|
| for folder, result in tqdm(all_result.items()):
|
| if result is None:
|
| continue
|
| result = dict(result)
|
| num_face_list.append(result['num_face'])
|
| num_edge_list.append(result['num_edge'])
|
| num_vertex_list.append(result['num_vertex'])
|
| cyclomatic_complexity_list.append(result['cyclomatic_complexity'])
|
| mean_curvature_list.append(result['mean_curvature'])
|
| exception_folder.append(folder)
|
|
|
| print(f'Num Face: {np.mean(num_face_list)}')
|
| print(f'Num Edge: {np.mean(num_edge_list)}')
|
| print(f'Num Vertex: {np.mean(num_vertex_list)}')
|
| print(f'Cyclomatic Complexity: {np.mean(cyclomatic_complexity_list)}')
|
| print(f'Mean Curvature: {np.mean(mean_curvature_list)}')
|
| print(f"{np.mean(num_face_list)} {np.mean(num_edge_list)} {np.mean(num_vertex_list)} "
|
| f"{np.mean(cyclomatic_complexity_list)} {np.mean(mean_curvature_list)}")
|
| ray.shutdown()
|
|
|