x
This commit is contained in:
@@ -68,18 +68,28 @@ class GeometryVerificationService:
|
|||||||
# 构建命令 - 使用 FreeCAD 命令行模式
|
# 构建命令 - 使用 FreeCAD 命令行模式
|
||||||
cmd = None
|
cmd = None
|
||||||
|
|
||||||
# 尝试1: freecad.cmd (snap 安装的命令行模式)
|
# 尝试多种 FreeCAD 命令名称
|
||||||
for cmd_name in ['freecad.cmd', '/snap/bin/freecad.cmd', 'freecad-cmd']:
|
# PPA 版本通常使用 freecad 或 freecadcmd
|
||||||
|
# snap 版本使用 freecad.cmd
|
||||||
|
for cmd_name in ['freecadcmd', 'freecad-cmd', 'freecad', '/usr/bin/freecad', '/usr/bin/freecadcmd', '/snap/bin/freecad.cmd']:
|
||||||
try:
|
try:
|
||||||
result = subprocess.run(['which', cmd_name], capture_output=True, text=True)
|
result = subprocess.run(['which', cmd_name], capture_output=True, text=True)
|
||||||
if result.returncode == 0 and result.stdout.strip():
|
if result.returncode == 0 and result.stdout.strip():
|
||||||
# 使用绝对路径
|
# 使用绝对路径
|
||||||
cmd = [cmd_name, str(self.verification_script), str(Path(stp_path_str).absolute())]
|
cmd = [cmd_name, str(self.verification_script), str(Path(stp_path_str).absolute())]
|
||||||
logger.debug(f"找到 FreeCAD 命令: {cmd_name}")
|
logger.info(f"找到 FreeCAD 命令: {cmd_name}")
|
||||||
break
|
break
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
# 如果 which 找不到,尝试直接检查常见路径
|
||||||
|
if not cmd:
|
||||||
|
for cmd_path in ['/usr/bin/freecad', '/usr/bin/freecadcmd', '/usr/local/bin/freecad', '/snap/bin/freecad.cmd']:
|
||||||
|
if Path(cmd_path).exists():
|
||||||
|
cmd = [cmd_path, str(self.verification_script), str(Path(stp_path_str).absolute())]
|
||||||
|
logger.info(f"找到 FreeCAD 命令路径: {cmd_path}")
|
||||||
|
break
|
||||||
|
|
||||||
# 尝试2: freecad with offscreen
|
# 尝试2: freecad with offscreen
|
||||||
if not cmd:
|
if not cmd:
|
||||||
try:
|
try:
|
||||||
@@ -147,6 +157,11 @@ class GeometryVerificationService:
|
|||||||
if stderr_text:
|
if stderr_text:
|
||||||
logger.warning(f"验证脚本 stderr: {stderr_text[:500]}")
|
logger.warning(f"验证脚本 stderr: {stderr_text[:500]}")
|
||||||
|
|
||||||
|
# 检查是否有 FreeCAD 权限错误
|
||||||
|
if 'Cannot read STEP file' in stderr_text or 'Cannot read STEP file' in stdout_text:
|
||||||
|
logger.warning("FreeCAD 无法读取文件(可能是 snap 沙盒限制),使用 PythonOCC 验证")
|
||||||
|
return self._verify_with_pythonocc_only(stp_path_str)
|
||||||
|
|
||||||
if process.returncode == 0:
|
if process.returncode == 0:
|
||||||
# 尝试读取生成的报告文件(在 STP 文件目录下)
|
# 尝试读取生成的报告文件(在 STP 文件目录下)
|
||||||
report_path = stp_dir / (stp_abs_path.stem + "_verification_report.json")
|
report_path = stp_dir / (stp_abs_path.stem + "_verification_report.json")
|
||||||
@@ -241,6 +256,106 @@ class GeometryVerificationService:
|
|||||||
|
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
def _verify_with_pythonocc_only(self, stp_path: str) -> Dict[str, Any]:
|
||||||
|
"""
|
||||||
|
仅使用 PythonOCC 验证(当 FreeCAD 不可用时)
|
||||||
|
|
||||||
|
Args:
|
||||||
|
stp_path: STP 文件路径
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
验证结果
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
from OCC.Core.STEPControl import STEPControl_Reader
|
||||||
|
from OCC.Core.IFSelect import IFSelect_RetDone
|
||||||
|
from OCC.Core.GProp import GProp_GProps
|
||||||
|
from OCC.Core.BRepGProp import brepgprop_VolumeProperties, brepgprop_SurfaceProperties
|
||||||
|
from OCC.Core.Bnd import Bnd_Box
|
||||||
|
from OCC.Core.BRepBndLib import brepbndlib_Add
|
||||||
|
from OCC.Core.TopExp import TopExp_Explorer
|
||||||
|
from OCC.Core.TopAbs import TopAbs_FACE, TopAbs_EDGE, TopAbs_VERTEX, TopAbs_SOLID
|
||||||
|
|
||||||
|
logger.info(f"使用 PythonOCC 进行验证: {stp_path}")
|
||||||
|
|
||||||
|
# 读取 STP 文件
|
||||||
|
reader = STEPControl_Reader()
|
||||||
|
status = reader.ReadFile(stp_path)
|
||||||
|
|
||||||
|
if status != IFSelect_RetDone:
|
||||||
|
return {
|
||||||
|
"status": "error",
|
||||||
|
"error": "无法读取 STP 文件",
|
||||||
|
"timestamp": datetime.now().isoformat()
|
||||||
|
}
|
||||||
|
|
||||||
|
reader.TransferRoots()
|
||||||
|
shape = reader.OneShape()
|
||||||
|
|
||||||
|
# 计算体积
|
||||||
|
vol_props = GProp_GProps()
|
||||||
|
brepgprop_VolumeProperties(shape, vol_props)
|
||||||
|
volume_mm3 = vol_props.Mass()
|
||||||
|
com = vol_props.CentreOfMass()
|
||||||
|
|
||||||
|
# 计算表面积
|
||||||
|
surf_props = GProp_GProps()
|
||||||
|
brepgprop_SurfaceProperties(shape, surf_props)
|
||||||
|
surface_area_mm2 = surf_props.Mass()
|
||||||
|
|
||||||
|
# 计算边界框
|
||||||
|
bbox = Bnd_Box()
|
||||||
|
brepbndlib_Add(shape, bbox)
|
||||||
|
xmin, ymin, zmin, xmax, ymax, zmax = bbox.Get()
|
||||||
|
|
||||||
|
# 拓扑统计
|
||||||
|
def count_topology(shape, top_type):
|
||||||
|
explorer = TopExp_Explorer(shape, top_type)
|
||||||
|
count = 0
|
||||||
|
while explorer.More():
|
||||||
|
count += 1
|
||||||
|
explorer.Next()
|
||||||
|
return count
|
||||||
|
|
||||||
|
return {
|
||||||
|
"status": "skipped",
|
||||||
|
"reason": "FreeCAD 无法访问文件(snap 沙盒限制),仅使用 PythonOCC 验证",
|
||||||
|
"timestamp": datetime.now().isoformat(),
|
||||||
|
"pythonocc": {
|
||||||
|
"volume_mm3": float(volume_mm3),
|
||||||
|
"volume_cm3": float(volume_mm3 / 1000),
|
||||||
|
"surface_area_mm2": float(surface_area_mm2),
|
||||||
|
"surface_area_cm2": float(surface_area_mm2 / 100),
|
||||||
|
"bounding_box": {
|
||||||
|
"x_min": float(xmin),
|
||||||
|
"x_max": float(xmax),
|
||||||
|
"y_min": float(ymin),
|
||||||
|
"y_max": float(ymax),
|
||||||
|
"z_min": float(zmin),
|
||||||
|
"z_max": float(zmax),
|
||||||
|
"x_length": float(xmax - xmin),
|
||||||
|
"y_length": float(ymax - ymin),
|
||||||
|
"z_length": float(zmax - zmin),
|
||||||
|
"center": [float((xmin + xmax) / 2), float((ymin + ymax) / 2), float((zmin + zmax) / 2)]
|
||||||
|
},
|
||||||
|
"center_of_mass": [float(com.X()), float(com.Y()), float(com.Z())],
|
||||||
|
"topology": {
|
||||||
|
"faces": count_topology(shape, TopAbs_FACE),
|
||||||
|
"edges": count_topology(shape, TopAbs_EDGE),
|
||||||
|
"vertices": count_topology(shape, TopAbs_VERTEX),
|
||||||
|
"solids": count_topology(shape, TopAbs_SOLID)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"PythonOCC 验证失败: {e}")
|
||||||
|
return {
|
||||||
|
"status": "error",
|
||||||
|
"error": str(e),
|
||||||
|
"timestamp": datetime.now().isoformat()
|
||||||
|
}
|
||||||
|
|
||||||
def verify_with_pythonocc(self, shape) -> Dict[str, Any]:
|
def verify_with_pythonocc(self, shape) -> Dict[str, Any]:
|
||||||
"""
|
"""
|
||||||
使用 PythonOCC 验证几何数据(同步方法,用于内部验证)
|
使用 PythonOCC 验证几何数据(同步方法,用于内部验证)
|
||||||
|
|||||||
Reference in New Issue
Block a user