from __future__ import annotations import math import vtk from PySide6.QtCore import Qt from .records import OperationRecord INFO_GROUPS: list[tuple[str, list[str]]] = [ ( "身份", [ "kind", "name", "path", "file", "part_id", "solid_id", "selection_title", "selection_display_id", "selection_topological_face_id", "logical_face_id", "face_region_logical_id", "topological_face_id", "face_id", "edge_id", "parent_id", "depth", "feature_mode", "feature_type", "feature_source_face_id", ], ), ( "拓扑", [ "parts", "solids", "faces", "edges", "vertices", "boundary_edges", "same_domain_face_ids", "same_domain_face_count", "same_domain_v_range", "same_domain_range_source", "same_domain_note", "orientation", "surface", "curve", "adjacent_face_ids", "adjacent_face_count", "first_level_fact_model", "first_level_fact_status", "first_level_fact_relation_depth", "first_level_fact_relation_boundary", "first_level_fact_scope", "first_level_fact_source_model", "first_level_fact_subject_role", "first_level_fact_subject_edge_ids", "first_level_fact_subject_edge_count", "first_level_fact_subject_face_ids", "first_level_fact_subject_face_count", "first_level_fact_boundary_edge_ids", "first_level_fact_boundary_edge_count", "first_level_fact_boundary_vertex_points", "first_level_fact_boundary_vertex_count", "first_level_fact_adjacent_edge_ids", "first_level_fact_adjacent_edge_count", "first_level_fact_adjacent_face_ids", "first_level_fact_adjacent_face_count", "first_level_fact_included_edge_ids", "first_level_fact_included_edge_count", "first_level_fact_included_face_ids", "first_level_fact_included_face_count", "first_level_fact_role_groups", "first_level_fact_ignored_relation_depths", "first_level_fact_ignored_relation_note", "first_level_fact_summary", "selected_edge_ids", "selected_edge_count", "first_level_vertex_points", "first_level_vertex_count", "first_level_adjacent_edge_ids", "first_level_adjacent_edge_count", "first_level_edge_ids", "first_level_edge_count", "first_level_adjacent_face_boundary_edge_ids", "first_level_adjacent_face_boundary_edge_count", ], ), ( "测量", [ "volume", "surface_area", "area", "length", "edge_length", "current_length", "target_length", "delta_length", "length_change_ratio", "edge_length_anchor_mode", "edge_length_anchor_label", "affine_initial_scale", "affine_scale", "affine_scale_correction", "affine_predicted_edge_length", "affine_scale_refine_iterations", "planar_edge_scale_sample_count", "planar_edge_scale_plane_deviation", "circular_edge_current_radius", "circular_edge_target_radius", "circular_edge_length_scale", "cylinder_resize_current_diameter", "cylinder_resize_target_diameter", "cylinder_resize_delta_diameter", "cylinder_resize_delta_ratio", "radius", "diameter", "target_radius", "radius_to_length_ratio", "target_distance", "distance_to_length_ratio", "translation_distance", "rotation_angle_degrees", "current_diameter", "target_diameter", "delta_diameter", "diameter_delta_ratio", "target_to_height_ratio", "major_radius", "minor_radius", "reference_radius", "semi_angle", "angular_span", "height_estimate", "same_domain_height_estimate", "hole_depth_estimate", "slot_chord_width_estimate", "slot_arc_length_estimate", "slot_sagitta_depth_estimate", "existing_fillet_radius_estimate", "existing_fillet_angular_span", "existing_fillet_arc_length_estimate", "current_depth", "target_depth", "delta_depth", "depth_delta_ratio", "is_full_cylinder", "bbox_diagonal", ], ), ( "位置", [ "pick_position", "center", "center_of_mass", "surface_center", "area_center", "length_center", "bbox_min", "bbox_max", "bbox_size", "start_point", "end_point", "translation_vector", "rotation_center", "end_face_id", "end_face_label", "end_face_plane_distance", "push_pull_distance", ], ), ( "方向 / 轴线", [ "normal", "oriented_normal", "plane_origin", "axis_point", "axis", "direction", "line_origin", "rotation_axis", "end_face_outward_direction", "desired_movement_vector", "push_pull_outward_direction", "push_pull_inward_direction", "push_pull_plus_side", "push_pull_minus_side", "push_pull_confidence", "push_pull_note", "push_pull_status", "push_pull_risk", "push_pull_message", "push_pull_scope_face_ids", "push_pull_scope_face_count", "push_pull_scope_area", "push_pull_scope_note", "shell_region_kind", "shell_region_status", "shell_confidence", "shell_source_face_ids", "shell_opposite_face_id", "shell_thickness_estimate", "shell_current_thickness", "shell_target_thickness", "shell_delta_thickness", "shell_delta_ratio", "shell_signed_thickness", "shell_overlap_ratio_estimate", "shell_opposite_normal_dot", "shell_desired_movement_vector", "shell_movement_alignment", "shell_note", "shell_region_note", ], ), ( "参数", [ "u_range", "v_range", "first_parameter", "last_parameter", "param_height", ], ), ( "特征判断", [ "recognition_summary", "recognition_candidate", "recognition_confidence", "recognition_risk", "recognition_score", "recognition_decision", "recognition_evidence", "recognition_evidence_keys", "recognition_ready_actions", "recognition_limited_actions", "recognition_blockers", "recognition_limitations", "feature_guess", "confidence", "material_vote_summary", "material_sample_count", "material_toward_axis", "material_away_axis", "cylinder_end_type", "start_end_state", "end_end_state", "start_end_open", "end_end_open", "open_end_count", "closed_end_count", "end_sample_offset", "end_sample_note", "note", "feature_face_ids", "feature_side_face_ids", "feature_end_face_ids", "feature_bottom_face_ids", "feature_opening_face_ids", "feature_start_end_face_ids", "feature_end_end_face_ids", "feature_highlight_face_ids", "feature_adjacent_face_ids", "feature_boundary_edge_ids", "feature_bottom_confidence", "feature_bottom_detection", "feature_bottom_note", "feature_slot_face_ids", "feature_slot_boundary_face_ids", "slot_kind", "slot_status", "slot_angular_span", "slot_open_angle", "slot_chord_width_estimate", "slot_arc_length_estimate", "slot_sagitta_depth_estimate", "slot_note", "feature_existing_fillet_face_ids", "feature_existing_fillet_support_face_ids", "existing_fillet_kind", "existing_fillet_status", "existing_fillet_note", "feature_edit_actions", "resize_status", "resize_strategy", "resize_mode", "resize_risk", "resize_warnings", "resize_blockers", "resize_note", "circular_edge_cylinder_face_id", "circular_edge_cylinder_mode", "circular_edge_cylinder_mode_label", "cylinder_resize_face_id", "cylinder_resize_operation", "cylinder_resize_status", "cylinder_resize_risk", "cylinder_resize_feature_guess", "cylinder_resize_confidence", "cylinder_resize_same_domain_face_ids", "cylinder_resize_same_domain_face_count", "boss_resize_status", "boss_resize_risk", "boss_resize_warnings", "boss_resize_blockers", "boss_resize_note", "suppress_status", "suppress_risk", "suppress_warnings", "suppress_blockers", "suppress_note", "depth_status", "depth_mode", "depth_risk", "depth_warnings", "depth_blockers", "depth_note", "cutter_strategy", "cutter_height", "cutter_margin", "cutter_start_margin", "cutter_end_margin", "cutter_radius", "cutter_start_parameter", "cutter_end_parameter", "cutter_axis_direction", "cutter_start_point", "cutter_bottom_protection", "cutter_protected_bottom_face_ids", "cutter_opening_face_ids", "cutter_bottom_note", "cutter_note", "fill_strategy", "fill_height", "fill_radius", "fill_radius_overlap", "fill_start_point", "fill_note", "boss_tool_strategy", "boss_tool_note", "boss_tool_height", "boss_tool_radius", "boss_tool_old_radius", "boss_tool_outer_radius", "boss_tool_inner_radius", "boss_tool_axial_margin", "boss_tool_radial_overlap", "boss_tool_start_parameter", "boss_tool_end_parameter", "boss_tool_axis_point", "boss_tool_axis_direction", "boss_tool_start_point", "depth_tool_strategy", "depth_tool_role", "depth_tool_note", "depth_tool_height", "depth_tool_radius", "depth_tool_radius_overlap", "depth_tool_start_parameter", "depth_tool_end_parameter", "depth_open_parameter", "depth_bottom_parameter", "depth_nominal_bottom_parameter", "depth_bottom_parameter_source", "depth_current_depth", "depth_current_depth_source", "depth_target_bottom_parameter", "depth_axis_direction", "depth_open_point", "depth_current_bottom_point", "depth_target_bottom_point", "depth_tool_start_point", "fillet_status", "fillet_risk", "fillet_warnings", "fillet_blockers", "fillet_note", "chamfer_status", "chamfer_risk", "chamfer_warnings", "chamfer_blockers", "chamfer_note", "translate_status", "translate_risk", "translate_warnings", "translate_blockers", "translate_note", "part_solid_count", "rotate_status", "rotate_risk", "rotate_warnings", "rotate_blockers", "rotate_note", ], ), ] INFO_LABELS = { "kind": "类型", "name": "名称", "path": "层级路径", "file": "文件", "part_id": "零件 ID", "solid_id": "Solid ID", "selection_title": "当前选中对象", "selection_display_id": "逻辑选择 ID", "selection_topological_face_id": "当前拓扑 Face ID", "logical_face_id": "逻辑 Face ID", "face_region_logical_id": "面区域逻辑 ID", "topological_face_id": "拓扑 Face ID", "face_id": "当前拓扑 Face ID", "face_region_ids": "面区域 Face", "face_region_count": "面区域 Face 数", "edge_id": "Edge ID", "parent_id": "父级 ID", "depth": "层级深度", "feature_mode": "特征模式说明", "cad_modeling_form": "建模形式", "cad_recommended_operation": "推荐操作", "feature_type": "特征类型", "feature_source_face_id": "特征来源 Face", "recognition_summary": "识别摘要", "recognition_candidate": "识别候选", "recognition_confidence": "识别置信度", "recognition_risk": "识别风险", "recognition_score": "识别评分", "recognition_decision": "识别结论", "recognition_evidence": "识别依据", "recognition_evidence_keys": "识别依据项", "recognition_ready_actions": "当前可改", "recognition_limited_actions": "当前受限修改", "recognition_blockers": "识别限制", "recognition_limitations": "受限能力", "parts": "零件数", "solids": "Solid 数", "faces": "Face 数", "edges": "Edge 数", "vertices": "Vertex 数", "boundary_edges": "边界边数", "same_domain_face_ids": "同域区域 Face", "same_domain_face_count": "同域区域 Face 数", "same_domain_v_range": "同域区域 V 范围", "same_domain_height_estimate": "同域区域估算高度", "same_domain_range_source": "同域范围来源", "same_domain_note": "同域区域说明", "orientation": "拓扑方向", "surface": "曲面类型", "curve": "曲线类型", "adjacent_face_ids": "相邻 Face", "adjacent_face_count": "相邻 Face 数", "first_level_fact_model": "一级事实模型", "first_level_fact_status": "一级事实状态", "first_level_fact_relation_depth": "一级事实深度", "first_level_fact_relation_boundary": "一级事实边界", "first_level_fact_scope": "一级事实范围", "first_level_fact_source_model": "一级事实来源", "first_level_fact_subject_role": "一级事实主体", "first_level_fact_subject_edge_ids": "一级主体 Edge", "first_level_fact_subject_edge_count": "一级主体 Edge 数", "first_level_fact_subject_face_ids": "一级主体 Face", "first_level_fact_subject_face_count": "一级主体 Face 数", "first_level_fact_boundary_edge_ids": "一级边界 Edge", "first_level_fact_boundary_edge_count": "一级边界 Edge 数", "first_level_fact_boundary_vertex_points": "一级边界 Vertex", "first_level_fact_boundary_vertex_count": "一级边界 Vertex 数", "first_level_fact_adjacent_edge_ids": "一级相邻 Edge", "first_level_fact_adjacent_edge_count": "一级相邻 Edge 数", "first_level_fact_adjacent_face_ids": "一级相邻 Face", "first_level_fact_adjacent_face_count": "一级相邻 Face 数", "first_level_fact_included_edge_ids": "一级范围 Edge", "first_level_fact_included_edge_count": "一级范围 Edge 数", "first_level_fact_included_face_ids": "一级范围 Face", "first_level_fact_included_face_count": "一级范围 Face 数", "first_level_fact_role_groups": "一级角色分组", "first_level_fact_ignored_relation_depths": "暂不传播层级", "first_level_fact_ignored_relation_note": "暂不传播说明", "first_level_fact_summary": "一级事实摘要", "selected_edge_ids": "当前 Edge", "selected_edge_count": "当前 Edge 数", "first_level_vertex_points": "一级端点 Vertex", "first_level_vertex_count": "一级端点 Vertex 数", "first_level_adjacent_edge_ids": "一级相邻 Edge", "first_level_adjacent_edge_count": "一级相邻 Edge 数", "first_level_edge_ids": "一级范围 Edge", "first_level_edge_count": "一级范围 Edge 数", "first_level_adjacent_face_boundary_edge_ids": "相邻 Face 的边界 Edge", "first_level_adjacent_face_boundary_edge_count": "相邻 Face 的边界 Edge 数", "volume": "体积", "surface_area": "表面积", "area": "面积", "length": "长度", "edge_length": "Edge长度", "current_length": "当前Edge长度", "target_length": "目标Edge长度", "delta_length": "Edge长度变化量", "length_change_ratio": "Edge长度变化比例", "edge_length_anchor_mode": "Edge长度基准模式", "edge_length_anchor_label": "Edge长度基准", "local_edge_deform_target_kind": "局部边形变目标", "local_edge_deform_anchor": "局部边形变基准", "local_edge_deform_face_count": "局部边形变重建面数", "local_edge_deform_start_move": "局部边形变起点移动", "local_edge_deform_end_move": "局部边形变终点移动", "local_edge_deform_moved_endpoint_count": "局部边形变移动端点数", "local_edge_deform_risk": "局部边形变风险", "local_edge_deform_note": "局部边形变说明", "circular_edge_current_radius": "圆边当前半径", "circular_edge_target_radius": "圆边目标半径", "circular_edge_length_scale": "圆边长度比例", "circular_edge_cylinder_face_id": "圆边相邻圆柱 Face", "circular_edge_cylinder_mode": "圆边圆柱模式", "circular_edge_cylinder_mode_label": "圆边编辑模式", "cylinder_resize_face_id": "圆柱编辑 Face", "cylinder_resize_operation": "圆柱编辑操作", "cylinder_resize_current_diameter": "圆柱当前直径", "cylinder_resize_target_diameter": "圆柱目标直径", "cylinder_resize_delta_diameter": "圆柱直径变化量", "cylinder_resize_delta_ratio": "圆柱直径变化比例", "cylinder_resize_status": "圆柱编辑状态", "cylinder_resize_risk": "圆柱编辑风险", "cylinder_resize_feature_guess": "圆柱面候选判断", "cylinder_resize_confidence": "圆柱判断置信度", "cylinder_resize_same_domain_face_ids": "圆柱同域 Face", "cylinder_resize_same_domain_face_count": "圆柱同域 Face 数", "affine_scale": "几何缩放比例", "affine_initial_scale": "几何缩放初始比例", "affine_scale_correction": "几何缩放校正比例", "affine_predicted_edge_length": "几何缩放预估Edge长度", "affine_scale_refine_iterations": "几何缩放校正次数", "affine_scale_refine_note": "几何缩放校正说明", "affine_transform_kind": "几何缩放类型", "affine_transform_label": "几何缩放类型", "affine_transform_note": "几何缩放说明", "affine_transform_warning": "几何缩放警告", "affine_transform_risk": "几何缩放风险", "affine_axis_point": "几何缩放基准点", "affine_axis_direction": "几何缩放轴线方向", "affine_axis_source": "几何缩放轴线来源", "affine_anchor_source": "几何缩放基准来源", "affine_target_kind": "几何缩放目标", "planar_edge_scale_sample_count": "平面曲线采样点数", "planar_edge_scale_plane_deviation": "平面曲线采样偏差", "radius": "半径", "diameter": "直径", "target_radius": "目标圆角半径", "radius_to_length_ratio": "半径/边长比例", "target_distance": "目标倒角距离", "distance_to_length_ratio": "倒角距离/边长比例", "translation_distance": "平移距离", "rotation_angle_degrees": "旋转角度", "current_diameter": "当前直径", "target_diameter": "目标直径", "delta_diameter": "直径变化量", "diameter_delta_ratio": "直径变化比例", "target_to_height_ratio": "目标直径/估算高度", "major_radius": "主半径", "minor_radius": "小半径", "ellipse_edge_major_radius": "椭圆Edge主半径", "ellipse_edge_minor_radius": "椭圆Edge小半径", "reference_radius": "参考半径", "semi_angle": "圆锥半角", "angular_span": "角度跨度", "height_estimate": "估算高度", "hole_depth_estimate": "孔/槽深度估算", "current_depth": "当前深度", "target_depth": "目标深度", "delta_depth": "深度变化量", "depth_delta_ratio": "深度变化比例", "manual_bottom_face_id": "手动底面 Face", "manual_bottom_face_used": "使用手动底面", "manual_bottom_face_note": "手动底面说明", "depth_open_direction_source": "孔深方向来源", "is_full_cylinder": "接近完整圆柱", "bbox_diagonal": "包围盒对角线", "pick_position": "拾取点", "center": "中心", "center_of_mass": "重心", "surface_center": "表面积中心", "area_center": "面积中心", "local_face_width": "U向尺寸", "local_face_height": "V向尺寸", "local_face_width_direction": "U向方向", "local_face_height_direction": "V向方向", "local_face_size_center": "U/V 尺寸中心", "face_size_axis": "U/V 尺寸方向", "face_size_label": "U/V 尺寸名称", "current_face_width": "当前 U向尺寸", "target_face_width": "目标 U向尺寸", "current_face_height": "当前 V向尺寸", "target_face_height": "目标 V向尺寸", "current_face_size": "当前 U/V 尺寸", "target_face_size": "目标 U/V 尺寸", "face_size_delta": "U/V 尺寸变化量", "face_size_delta_ratio": "U/V 尺寸变化比例", "face_size_scale": "U/V 尺寸缩放比例", "face_size_center": "U/V 尺寸缩放中心", "face_size_axis_direction": "U/V 尺寸缩放方向", "owning_face_size_rebuild_mode": "所属对象尺寸重建模式", "length_center": "长度中心", "bbox_min": "包围盒最小点", "bbox_max": "包围盒最大点", "bbox_size": "包围盒尺寸", "start_point": "起点", "end_point": "终点", "translation_vector": "平移向量", "rotation_center": "旋转中心", "end_face_id": "端面 Face", "end_face_label": "端面位置", "end_face_plane_distance": "端面匹配距离", "push_pull_distance": "拉伸/切除距离", "normal": "几何法向", "oriented_normal": "拓扑修正法向", "plane_origin": "平面原点", "axis_point": "轴线点", "axis": "轴方向", "direction": "方向", "line_origin": "直线原点", "rotation_axis": "旋转轴", "end_face_outward_direction": "端面向外方向", "desired_movement_vector": "目标移动向量", "push_pull_outward_direction": "拉伸向外方向", "push_pull_inward_direction": "切除向内方向", "push_pull_plus_side": "原始法向侧", "push_pull_minus_side": "反向法向侧", "push_pull_confidence": "拉伸/切除方向置信度", "push_pull_note": "拉伸/切除方向说明", "push_pull_status": "拉伸/切除状态", "push_pull_risk": "拉伸/切除风险", "push_pull_message": "拉伸/切除说明", "push_pull_scope_face_ids": "拉伸/切除共面区域 Face", "push_pull_scope_face_count": "拉伸/切除共面区域 Face 数", "push_pull_scope_area": "拉伸/切除共面区域面积", "push_pull_scope_note": "拉伸/切除共面区域说明", "shell_region_kind": "壳体候选类型", "shell_region_status": "壳体识别状态", "shell_confidence": "壳体置信度", "shell_thickness": "壳体厚度", "shell_source_face_ids": "壳体源平面 Face", "shell_opposite_face_id": "相对平面 Face", "shell_thickness_estimate": "壳体厚度估算", "shell_current_thickness": "当前壳体厚度", "shell_target_thickness": "目标壳体厚度", "shell_delta_thickness": "壳体厚度变化量", "shell_delta_ratio": "壳体厚度变化比例", "shell_signed_thickness": "有符号壳体厚度", "shell_overlap_ratio_estimate": "相对平面重叠率估算", "shell_opposite_normal_dot": "相对平面法向点积", "shell_desired_movement_vector": "壳体目标移动向量", "shell_movement_alignment": "壳体移动方向匹配度", "shell_note": "壳体识别说明", "shell_region_note": "壳体识别说明", "u_range": "U 参数范围", "v_range": "V 参数范围", "first_parameter": "起始参数", "last_parameter": "结束参数", "param_height": "参数高度", "feature_guess": "候选判断", "confidence": "置信度", "material_vote_summary": "材料投票", "material_sample_count": "采样数量", "material_toward_axis": "轴侧材料", "material_away_axis": "外侧材料", "cylinder_end_type": "端部类型", "start_end_state": "起点端状态", "end_end_state": "终点端状态", "start_end_open": "起点端开口", "end_end_open": "终点端开口", "open_end_count": "开口端数量", "closed_end_count": "封闭端数量", "end_sample_offset": "端部采样偏移", "end_sample_note": "端部采样说明", "end_sample_range_source": "端部采样范围来源", "end_sample_scope_face_ids": "端部采样同域 Face", "end_sample_scope_face_count": "端部采样同域 Face 数", "note": "备注", "feature_face_ids": "特征 Face", "feature_side_face_ids": "特征侧壁 Face", "feature_end_face_ids": "特征端面 Face", "feature_bottom_face_ids": "疑似底面 Face", "feature_opening_face_ids": "开口端相邻 Face", "feature_start_end_face_ids": "起点端 Face", "feature_end_end_face_ids": "终点端 Face", "feature_highlight_face_ids": "特征高亮 Face", "feature_adjacent_face_ids": "相邻 Face", "feature_boundary_edge_ids": "特征边界 Edge", "feature_bottom_confidence": "底面判断置信度", "feature_bottom_detection": "底面识别来源", "feature_bottom_note": "底面判断说明", "feature_slot_face_ids": "槽圆柱 Face", "feature_slot_boundary_face_ids": "槽边界相邻 Face", "slot_kind": "槽类型", "slot_status": "槽识别状态", "slot_angular_span": "槽圆弧角度", "slot_open_angle": "槽开口角度", "slot_chord_width_estimate": "槽宽估算", "slot_arc_length_estimate": "槽圆弧长度估算", "slot_sagitta_depth_estimate": "槽深估算", "slot_note": "槽识别说明", "feature_existing_fillet_face_ids": "已有圆角 Face", "feature_existing_fillet_support_face_ids": "已有圆角支撑 Face", "existing_fillet_kind": "已有圆角类型", "existing_fillet_status": "已有圆角识别状态", "existing_fillet_radius_estimate": "已有圆角半径估算", "feature_reference_radius": "特征参考半径", "feature_reference_diameter": "特征参考直径", "feature_cone_small_radius": "锥孔小端半径", "feature_cone_small_diameter": "锥孔小端直径", "feature_cone_large_radius": "锥孔大端半径", "feature_cone_large_diameter": "锥孔大端直径", "feature_cone_height": "锥孔高度", "feature_cone_boundary_half_angle_degrees": "锥孔半角", "feature_sphere_radius": "球面半径", "feature_sphere_diameter": "球面直径", "feature_torus_major_radius": "环面主半径", "feature_torus_minor_radius": "环面小半径", "current_major_radius": "当前主半径", "target_major_radius": "目标主半径", "current_minor_radius": "当前小半径", "target_minor_radius": "目标小半径", "torus_radius_mode": "环面半径模式", "current_area": "当前面积", "target_area": "目标面积", "area_delta": "面积变化量", "area_delta_ratio": "面积变化比例", "area_center": "面积中心", "current_reference_radius": "当前参考半径", "target_reference_radius": "目标参考半径", "current_reference_diameter": "当前参考直径", "target_reference_diameter": "目标参考直径", "delta_reference_radius": "参考半径变化量", "reference_radius_delta_ratio": "参考半径变化比例", "existing_fillet_angular_span": "已有圆角圆弧角度", "existing_fillet_arc_length_estimate": "已有圆角圆弧长度估算", "existing_fillet_note": "已有圆角识别说明", "feature_edit_actions": "当前可用操作", "freeform_face_status": "自由曲面状态", "freeform_face_risk": "自由曲面风险", "freeform_face_blockers": "自由曲面限制", "resize_status": "切削状态", "resize_strategy": "执行策略", "edit_strategy_label": "执行策略说明", "edit_semantics": "建模意图", "resize_mode": "调整模式", "resize_risk": "切削风险", "resize_warnings": "切削警告", "resize_blockers": "切削阻止原因", "resize_note": "切削说明", "boss_resize_status": "凸台调整状态", "boss_resize_risk": "凸台调整风险", "boss_resize_warnings": "凸台调整警告", "boss_resize_blockers": "凸台调整阻止原因", "boss_resize_note": "凸台调整说明", "suppress_status": "封堵状态", "suppress_risk": "封堵风险", "suppress_warnings": "封堵警告", "suppress_blockers": "封堵阻止原因", "suppress_note": "封堵说明", "depth_status": "孔深状态", "depth_mode": "孔深调整模式", "depth_risk": "孔深风险", "depth_warnings": "孔深警告", "depth_blockers": "孔深阻止原因", "depth_note": "孔深说明", "cutter_strategy": "Cutter 策略", "cutter_scope_face_ids": "Cutter 同域 Face", "cutter_scope_face_count": "Cutter 同域 Face 数", "cutter_range_source": "Cutter 范围来源", "cutter_height": "Cutter 高度", "cutter_margin": "Cutter 余量", "cutter_start_margin": "Cutter 起点余量", "cutter_end_margin": "Cutter 终点余量", "cutter_radius": "Cutter 半径", "cutter_start_parameter": "Cutter 起始参数", "cutter_end_parameter": "Cutter 结束参数", "cutter_axis_direction": "Cutter 轴方向", "cutter_start_point": "Cutter 起点", "cutter_bottom_protection": "Cutter 底面保护", "cutter_protected_bottom_face_ids": "Cutter 保护底面 Face", "cutter_opening_face_ids": "Cutter 开口端 Face", "cutter_bottom_note": "Cutter 底面保护说明", "cutter_note": "Cutter 说明", "fill_strategy": "补料策略", "fill_scope_face_ids": "补料同域 Face", "fill_scope_face_count": "补料同域 Face 数", "fill_range_source": "补料范围来源", "fill_height": "补料高度", "fill_radius": "补料半径", "fill_radius_overlap": "补料重叠量", "fill_start_point": "补料起点", "fill_note": "补料说明", "boss_tool_strategy": "凸台工具策略", "boss_tool_scope_face_ids": "凸台工具同域 Face", "boss_tool_scope_face_count": "凸台工具同域 Face 数", "boss_tool_range_source": "凸台工具范围来源", "boss_tool_note": "凸台工具说明", "boss_tool_height": "凸台工具高度", "boss_tool_radius": "凸台目标半径", "boss_tool_old_radius": "凸台原半径", "boss_tool_outer_radius": "凸台移除包络半径", "boss_tool_inner_radius": "凸台重建目标半径", "boss_tool_axial_margin": "凸台工具轴向余量", "boss_tool_radial_overlap": "凸台工具径向重叠", "boss_tool_start_parameter": "凸台工具起始参数", "boss_tool_end_parameter": "凸台工具结束参数", "boss_tool_axis_point": "凸台工具轴线点", "boss_tool_axis_direction": "凸台工具轴线方向", "boss_tool_start_point": "凸台工具起点", "boss_tool_exact_start_point": "凸台精确重建起点", "boss_tool_exact_height": "凸台精确重建高度", "depth_tool_strategy": "孔深工具策略", "depth_tool_role": "孔深工具类型", "depth_tool_note": "孔深工具说明", "depth_tool_height": "孔深工具高度", "depth_tool_radius": "孔深工具半径", "depth_tool_radius_overlap": "孔深工具半径重叠", "depth_scope_face_ids": "孔深同域 Face", "depth_scope_face_count": "孔深同域 Face 数", "depth_range_source": "孔深范围来源", "depth_tool_start_parameter": "孔深工具起始参数", "depth_tool_end_parameter": "孔深工具结束参数", "depth_open_parameter": "孔开口参数", "depth_bottom_parameter": "当前底面参数", "depth_nominal_bottom_parameter": "圆柱参数底面", "depth_bottom_parameter_source": "底面参数来源", "depth_current_depth": "当前几何深度", "depth_current_depth_source": "当前深度来源", "depth_target_bottom_parameter": "目标底面参数", "depth_axis_direction": "孔深方向", "depth_open_point": "孔开口点", "depth_current_bottom_point": "当前底面点", "depth_target_bottom_point": "目标底面点", "depth_tool_start_point": "孔深工具起点", "fillet_status": "圆角状态", "fillet_risk": "圆角风险", "fillet_warnings": "圆角警告", "fillet_blockers": "圆角阻止原因", "fillet_note": "圆角说明", "chamfer_status": "倒角状态", "chamfer_risk": "倒角风险", "chamfer_warnings": "倒角警告", "chamfer_blockers": "倒角阻止原因", "chamfer_note": "倒角说明", "translate_status": "平移状态", "translate_risk": "平移风险", "translate_warnings": "平移警告", "translate_blockers": "平移阻止原因", "translate_note": "平移说明", "part_solid_count": "零件内 Solid 数", "rotate_status": "旋转状态", "rotate_risk": "旋转风险", "rotate_warnings": "旋转警告", "rotate_blockers": "旋转阻止原因", "rotate_note": "旋转说明", "scope": "作用范围", "repair_strategy": "修复策略", } PART_TREE_KIND_ROLE = Qt.UserRole PART_TREE_ID_ROLE = Qt.UserRole + 1 PART_TREE_PART_ID_ROLE = Qt.UserRole + 2 EDITABLE_TARGET_ID_ROLE = Qt.UserRole EDITABLE_ACTION_ROLE = Qt.UserRole + 1 EDITABLE_TARGET_KIND_ROLE = Qt.UserRole + 2 SELECTION_MODE_LABELS = { "Part": "零件", "Solid": "Solid", "Face": "Face", "Edge": "Edge", "Feature": "特征", } SELECTION_MODE_VALUES = {label: mode for mode, label in SELECTION_MODE_LABELS.items()} SURFACE_VALUE_LABELS = { "plane": "平面", "cylinder": "圆柱面", "cone": "圆锥面 / 拔模面", "sphere": "球面", "torus": "环面", "bezier surface": "Bezier 曲面", "b-spline surface": "B-spline 曲面", "surface of revolution": "旋转曲面", "surface of extrusion": "拉伸曲面", "offset surface": "偏移曲面", "other surface": "其它曲面", } CURVE_VALUE_LABELS = { "line": "直线", "circle": "圆 / 圆弧", "ellipse": "椭圆 / 椭圆弧", "hyperbola": "双曲线", "parabola": "抛物线", "bezier curve": "Bezier 曲线", "b-spline curve": "B-spline 曲线", "other curve": "其它曲线", } def _selection_mode_label(mode: object) -> str: mode_text = str(mode or "") return SELECTION_MODE_LABELS.get(mode_text, mode_text or "Face") def _selection_mode_value(mode_or_label: object) -> str: mode_text = str(mode_or_label or "") return SELECTION_MODE_VALUES.get(mode_text, mode_text or "Face") def _format_float(value: float) -> str: return f"{value:.6g}" def _info_to_text(info: dict[str, object]) -> str: return "\n".join(f"{INFO_LABELS.get(key, key)}: {_format_info_value(key, value)}" for key, value in info.items()) def _part_tree_kind_label(kind: str) -> str: return { "assembly": "装配", "part": "零件", "solid": "实体", }.get(kind, kind or "对象") def _enable_overlay_depth_offset(mapper) -> None: """Draw coplanar overlays in front of the base model to avoid highlight flicker.""" if hasattr(mapper, "SetResolveCoincidentTopologyToPolygonOffset"): mapper.SetResolveCoincidentTopologyToPolygonOffset() if hasattr(mapper, "SetRelativeCoincidentTopologyPolygonOffsetParameters"): mapper.SetRelativeCoincidentTopologyPolygonOffsetParameters(-6.0, -6.0) if hasattr(mapper, "SetRelativeCoincidentTopologyLineOffsetParameters"): mapper.SetRelativeCoincidentTopologyLineOffsetParameters(-8.0, -8.0) if hasattr(mapper, "SetRelativeCoincidentTopologyPointOffsetParameter"): mapper.SetRelativeCoincidentTopologyPointOffsetParameter(-8.0) def _smooth_surface_polydata(polydata): normals = vtk.vtkPolyDataNormals() # build_face_polydata owns a separate point set for each B-Rep Face. # Keep those boundary points separate: averaging a side-wall normal into a # planar cap creates the dark triangular gradients seen in the UI. normals.SetInputData(polydata) normals.ComputePointNormalsOn() normals.ComputeCellNormalsOff() normals.ConsistencyOn() normals.SplittingOff() if hasattr(normals, "NonManifoldTraversalOff"): normals.NonManifoldTraversalOff() normals.Update() smoothed = vtk.vtkPolyData() smoothed.ShallowCopy(normals.GetOutput()) return smoothed def _format_percent(value: object) -> str: if value is None or value == "": return "" try: return f"{float(value) * 100.0:.6g}%" except (TypeError, ValueError): return str(value) def _edit_quality_warnings(before_part_stats, after_part_stats) -> list[str]: if before_part_stats is None or after_part_stats is None: return [] warnings: list[str] = [] if after_part_stats.solids == 0: warnings.append("目标零件编辑后没有检测到Solid,导出前请确认模型是否有效。") elif before_part_stats.solids > 0 and after_part_stats.solids != before_part_stats.solids: warnings.append( "目标零件Solid数发生变化:" f"{before_part_stats.solids} -> {after_part_stats.solids}。" "如果这是一次局部拉伸/切除/孔径修改,请重点检查导出后是否仍是一体实体。" ) return warnings def _export_quality_text(info: dict[str, object]) -> str: warnings = str(info.get("quality_warnings", "")) lines = [ "导出质量检查:", f" 对象: {info.get('quality_label', '')}", f" 状态: {info.get('quality_status', '')}", f" B-Rep 有效: {_format_value(info.get('brep_valid', ''))}", f" solids: {_format_value(info.get('solids', ''))}", f" faces: {_format_value(info.get('faces', ''))}", f" edges: {_format_value(info.get('edges', ''))}", f" vertices: {_format_value(info.get('vertices', ''))}", f" volume: {_format_value(info.get('volume', ''))}", f" bbox_diagonal: {_format_value(info.get('bbox_diagonal', ''))}", ] if warnings: lines.extend([" 警告:", f" {warnings}"]) else: lines.append(" 警告: 无") return "\n".join(lines) def _format_value(value: object) -> str: if isinstance(value, float): return _format_float(value) if isinstance(value, (tuple, list)): parts: list[str] = [] for item in value: try: parts.append(_format_float(float(item))) except (TypeError, ValueError): parts.append(str(item)) return "(" + ", ".join(parts) + ")" return str(value) def _format_info_value(key: object, value: object) -> str: key_text = str(key or "") if key_text == "surface": value_text = str(value or "") return SURFACE_VALUE_LABELS.get(value_text, value_text) if key_text == "curve": value_text = str(value or "") return CURVE_VALUE_LABELS.get(value_text, value_text) return _format_value(value) def _int_values(value: object) -> list[int]: if value is None or value == "": return [] if isinstance(value, int): return [value] if isinstance(value, (list, tuple, set)): result: list[int] = [] for item in value: try: result.append(int(item)) except (TypeError, ValueError): continue return result return [] def _int_tuple_or_none(values) -> tuple[int, ...] | None: if values is None: return None if isinstance(values, int): return (values,) return tuple(sorted({int(value) for value in values})) def _float_or_none(value: object) -> float | None: if value is None or value == "": return None try: return float(value) except (TypeError, ValueError): return None def _merge_polydata_bounds(*polydatas) -> tuple[float, float, float, float, float, float] | None: merged: list[float] | None = None for polydata in polydatas: if polydata is None or polydata.GetNumberOfPoints() <= 0: continue bounds = polydata.GetBounds() if bounds is None or bounds[0] > bounds[1] or bounds[2] > bounds[3] or bounds[4] > bounds[5]: continue values = [float(item) for item in bounds] if merged is None: merged = values else: merged[0] = min(merged[0], values[0]) merged[1] = max(merged[1], values[1]) merged[2] = min(merged[2], values[2]) merged[3] = max(merged[3], values[3]) merged[4] = min(merged[4], values[4]) merged[5] = max(merged[5], values[5]) return tuple(merged) if merged is not None else None def _format_after_delta(before: dict[str, object], after: dict[str, object], key: str) -> str: before_value = before.get(key) after_value = after.get(key) if isinstance(before_value, (int, float)) and isinstance(after_value, (int, float)): return f"{_format_value(float(after_value))} ({_signed_float_delta(float(after_value) - float(before_value))})" if isinstance(before_value, tuple) and isinstance(after_value, tuple) and len(before_value) == len(after_value): try: deltas = tuple(float(after_item) - float(before_item) for before_item, after_item in zip(before_value, after_value)) except (TypeError, ValueError): return _format_value(after_value) return f"{_format_value(after_value)} (delta={_format_value(deltas)})" return _format_value(after_value if after_value is not None else "") def _vector_tuple(values) -> tuple[float, float, float]: return (float(values[0]), float(values[1]), float(values[2])) def _signed_delta(value: int) -> str: if value > 0: return f"+{value}" return str(value) def _signed_float_delta(value: float) -> str: if value > 0: return f"+{_format_float(value)}" return _format_float(value) __all__ = [name for name in globals() if not name.startswith("__")]