Merge branch 'main' of http://szcjw:10001/cjw/geMoldInsight
This commit is contained in:
+5
-1
@@ -8,7 +8,7 @@ __pycache__/
|
|||||||
*.pyo
|
*.pyo
|
||||||
*.pyd
|
*.pyd
|
||||||
|
|
||||||
# IDE 配置(可选)
|
# IDE 配置
|
||||||
.idea/
|
.idea/
|
||||||
.vscode/
|
.vscode/
|
||||||
|
|
||||||
@@ -19,7 +19,11 @@ __pycache__/
|
|||||||
1panel.env
|
1panel.env
|
||||||
*.env.local
|
*.env.local
|
||||||
logs/
|
logs/
|
||||||
|
|
||||||
|
# 运行时生成的目录
|
||||||
uploads/
|
uploads/
|
||||||
html_output/
|
html_output/
|
||||||
|
|
||||||
|
# 不再需要在 src/ 下跟踪这些
|
||||||
src/uploads/
|
src/uploads/
|
||||||
src/html_output/
|
src/html_output/
|
||||||
|
|||||||
@@ -1 +0,0 @@
|
|||||||
|
|
||||||
-107
@@ -1,107 +0,0 @@
|
|||||||
# 更新日志 (Changelog)
|
|
||||||
|
|
||||||
|
|
||||||
## [4.0.0] - 2026-03-07
|
|
||||||
|
|
||||||
### 新增功能 ✨
|
|
||||||
|
|
||||||
#### 前端重构
|
|
||||||
- **白色简约现代UI** - 完全重构前端为白色简约现代化风格
|
|
||||||
- 緔洁的白色背景配色
|
|
||||||
- 緩和阴影和圆角设计
|
|
||||||
- 娡块化CSS变量系统
|
|
||||||
- 响应式布局优化
|
|
||||||
|
|
||||||
#### 3D可视化
|
|
||||||
- **PythonOCC点云模型** - 从STP文件提取真实点云数据生成3D模型
|
|
||||||
- **模具型腔可视化** - 3D预览显示型腔、型芯、分型面
|
|
||||||
- **交互式控制** - 支持旋转、缩放、平移操作
|
|
||||||
- **视图切换** - 显示/隐藏产品、模具、分型面、点云
|
|
||||||
|
|
||||||
#### 验证工具
|
|
||||||
- **STP验证脚本** - 使用FreeCAD命令行验证几何数据准确性
|
|
||||||
- 对比FreeCAD和PythonOCC的测量结果
|
|
||||||
- 生成详细的验证报告
|
|
||||||
|
|
||||||
#### 分析功能
|
|
||||||
- **产品特征识别** - 检测壁厚、加强筋、孔洞、倒扣等特征
|
|
||||||
- **泡沫包装设计决策** - 噃度、布局、定位结构建议
|
|
||||||
- **模具工程决策** - 型腔数量、模架尺寸、材料选择
|
|
||||||
- **质量指标** - 体积利用率、拓扑复杂度、壁厚均匀性
|
|
||||||
|
|
||||||
### 优化改进 🔧
|
|
||||||
|
|
||||||
#### 数据处理
|
|
||||||
- **点云数据提取优化** - 修复PythonOCC网格提取的正确实现
|
|
||||||
- **数据持久化** - 添加AnalysisMetrics表存储分析指标
|
|
||||||
- **API响应优化** - 修复字段名不匹配问题
|
|
||||||
|
|
||||||
#### 用户体验
|
|
||||||
- **分析摘要显示** - 在结果页面顶部显示分析摘要
|
|
||||||
- **设计建议列表** - 按优先级排序显示所有建议
|
|
||||||
- **关键信息完善** - 显示更多模具参数和制造要求
|
|
||||||
|
|
||||||
### 问题修复 🐛
|
|
||||||
|
|
||||||
- 修复 `getPriorityText` 函数未定义错误
|
|
||||||
- 修复 `controls` 变量初始化顺序错误
|
|
||||||
- 修复 HTML生成器JavaScript语法错误
|
|
||||||
- 修复历史记录API路径重复前缀问题
|
|
||||||
- 修复点云数据传递逻辑错误
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## [3.0.0] - 2026-03-06
|
|
||||||
|
|
||||||
### 新增功能 ✨
|
|
||||||
|
|
||||||
#### 用户系统
|
|
||||||
- **用户认证** - JWT令牌认证机制
|
|
||||||
- **角色权限** - 基于角色的访问控制
|
|
||||||
- **管理员账户** - 支持环境变量配置管理员
|
|
||||||
|
|
||||||
#### 进销存模块
|
|
||||||
- **仪表盘** - 库存概览和统计数据
|
|
||||||
- **产品管理** - 产品CRUD操作
|
|
||||||
- **库存预警** - 低库存提醒功能
|
|
||||||
|
|
||||||
#### 项目架构
|
|
||||||
- **新主页** - Gemold官网主页
|
|
||||||
- **模块化路由** - 分离认证、进销存、分析模块
|
|
||||||
|
|
||||||
### 优化改进 🔧
|
|
||||||
|
|
||||||
- **UI主题** - 从深色主题改为现代蓝紫色渐变
|
|
||||||
- **按钮样式** - 修复按钮大小和可见性问题
|
|
||||||
- **数据库连接** - 优化异步会话管理
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## [2.0.0] - 2026-03-05
|
|
||||||
|
|
||||||
### 新增功能 ✨
|
|
||||||
|
|
||||||
#### 核心分析
|
|
||||||
- **STP文件解析** - 使用PythonOCC解析STP文件
|
|
||||||
- **几何分析** - 计算体积、表面积、边界框等
|
|
||||||
- **模具设计建议** - 自动生成设计建议
|
|
||||||
|
|
||||||
#### Web界面
|
|
||||||
- **文件上传** - 拖拽上传支持
|
|
||||||
- **任务状态** - 实时进度显示
|
|
||||||
- **结果展示** - 分析结果可视化
|
|
||||||
|
|
||||||
#### 数据存储
|
|
||||||
- **PostgreSQL集成** - 数据持久化存储
|
|
||||||
- **RustFS集成** - 文件存储服务
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## [1.0.0] - 2026-03-04
|
|
||||||
|
|
||||||
### 初始版本 🎉
|
|
||||||
|
|
||||||
- 项目初始化
|
|
||||||
- 基础架构搭建
|
|
||||||
- STP文件解析功能
|
|
||||||
- 基础Web界面
|
|
||||||
@@ -53,45 +53,76 @@
|
|||||||
|
|
||||||
```
|
```
|
||||||
geMoldInsight/
|
geMoldInsight/
|
||||||
├── src/ # 源代码目录
|
├── src/ # 源代码目录
|
||||||
│ ├── main.py # 主程序入口
|
│ ├── main.py # 主程序入口
|
||||||
│ ├── api/ # API路由
|
│ ├── api/ # API路由层
|
||||||
│ │ ├── routes.py # 主API路由
|
│ │ ├── routes.py # 模具分析API路由聚合
|
||||||
│ │ ├── auth_routes.py # 认证API
|
│ │ ├── auth_routes.py # 认证API
|
||||||
│ │ └── inventory_routes.py # 进销存API
|
│ │ ├── v1/ # MoldInsight API (v1)
|
||||||
│ ├── core/ # 核心业务逻辑
|
│ │ │ ├── upload_router.py # 文件上传
|
||||||
│ │ ├── stp_parser.py # STP文件解析
|
│ │ │ ├── task_router.py # 任务状态查询
|
||||||
│ │ ├── geometry_analyzer.py # 几何分析
|
│ │ │ └── history_router.py # 分析历史
|
||||||
│ │ ├── mesh_generator.py # 网格生成
|
│ │ └── inventory/ # 进销存API
|
||||||
│ │ └── mold_generator.py # 模具生成
|
│ │ ├── product_routes.py # 产品管理
|
||||||
│ ├── models/ # 数据模型
|
│ │ ├── sales_order_routes.py # 销售订单
|
||||||
│ │ ├── database.py # 数据库模型
|
│ │ ├── purchase_order_routes.py # 采购订单
|
||||||
│ │ └── schemas.py # 数据模式
|
│ │ ├── finance_routes.py # 财务管理
|
||||||
│ ├── services/ # 服务层
|
│ │ ├── material_routes.py # 物料管理
|
||||||
│ │ ├── auth_service.py # 认证服务
|
│ │ └── schemas/ # 请求/响应模型
|
||||||
│ │ ├── storage_service.py # 存储服务
|
│ ├── core/ # 核心业务逻辑
|
||||||
│ │ └── storage_integration_rustfs.py # RustFS集成
|
│ │ ├── stp_parser.py # STP文件解析
|
||||||
│ ├── database/ # 数据库管理
|
│ │ ├── geometry_analyzer.py # 几何分析
|
||||||
│ │ ├── database.py # 数据库连接
|
│ │ ├── mesh_generator.py # 网格生成
|
||||||
│ │ └── init_db.py # 数据库初始化
|
│ │ ├── mold_generator.py # 普通塑料模具生成
|
||||||
│ └── utils/ # 工具类
|
│ │ ├── aluminum_foam_mold.py # 铝泡沫模具生成
|
||||||
|
│ │ ├── mold_quality_inspector.py # 模具质量检测
|
||||||
|
│ │ └── ai_mold_assistant.py # AI模具助手
|
||||||
|
│ ├── models/ # 数据模型
|
||||||
|
│ │ ├── database.py # SQLAlchemy ORM模型
|
||||||
|
│ │ └── schemas.py # Pydantic模式
|
||||||
|
│ ├── services/ # 服务层
|
||||||
|
│ │ ├── auth_service.py # 认证服务
|
||||||
|
│ │ ├── processing_service.py # STP处理流程编排
|
||||||
|
│ │ ├── calculation_service.py # 工程参数计算
|
||||||
|
│ │ ├── material_service.py # 材料属性管理
|
||||||
|
│ │ ├── task_query_service.py # 任务状态查询
|
||||||
|
│ │ ├── storage_integration_rustfs.py # RustFS存储集成
|
||||||
|
│ │ ├── redis_task_manager.py # Redis任务管理
|
||||||
|
│ │ └── verification_service.py # FreeCAD几何验证
|
||||||
|
│ ├── database/ # 数据库管理
|
||||||
|
│ │ ├── database.py # 数据库连接池
|
||||||
|
│ │ ├── init_db.py # 数据库初始化
|
||||||
|
│ │ └── migrate_db.py # 数据库迁移
|
||||||
|
│ ├── storage/ # 对象存储
|
||||||
|
│ │ ├── rustfs_storage.py # RustFS S3客户端
|
||||||
|
│ │ └── object_storage.py # 通用对象存储
|
||||||
|
│ └── utils/ # 工具类
|
||||||
│ ├── logger.py # 日志工具
|
│ ├── logger.py # 日志工具
|
||||||
│ ├── file_handler.py # 文件处理
|
│ ├── file_handler.py # 文件处理
|
||||||
│ └── html_generator.py # HTML生成
|
│ └── html_generator.py # 3D可视化HTML生成
|
||||||
├── static/ # 静态文件
|
├── static/ # 前端静态资源
|
||||||
│ ├── vue-app.js # Vue应用
|
│ ├── vue-app.js # Vue3 SPA应用
|
||||||
│ ├── style.css # 样式文件
|
│ ├── style.css # 全局样式
|
||||||
│ └── index.html # 主页面
|
│ └── index.html # 入口页面
|
||||||
├── scripts/ # 脚本工具
|
├── templates/ # Jinja2模板
|
||||||
│ └── verify_stp.py # STP验证脚本
|
├── config/ # 配置模块
|
||||||
├── uploads/ # 上传文件目录
|
│ └── settings.py # 环境变量配置
|
||||||
├── html_output/ # 生成的HTML文件
|
├── scripts/ # 脚本工具
|
||||||
├── logs/ # 日志文件
|
│ ├── db/ # SQL脚本
|
||||||
├── requirements.txt # 依赖包
|
│ ├── migrations/ # 数据迁移脚本
|
||||||
├── docker-compose.yml # Docker配置
|
│ ├── tools/ # 临时检查/清理工具
|
||||||
├── start.sh # Linux启动脚本
|
│ └── verify_stp.py # STP验证脚本
|
||||||
├── start.bat # Windows启动脚本
|
├── docs/ # 项目文档
|
||||||
└── .env # 环境变量
|
│ └── deployment/ # 部署相关文档
|
||||||
|
├── tests/ # 测试用例
|
||||||
|
├── uploads/ # 上传文件目录 (gitignore)
|
||||||
|
├── html_output/ # 3D可视化输出 (gitignore)
|
||||||
|
├── requirements.txt # Python依赖
|
||||||
|
├── docker-compose.yml # Docker编排配置
|
||||||
|
├── Dockerfile # Docker构建文件
|
||||||
|
├── start.sh # Linux启动脚本
|
||||||
|
├── .env.example # 环境变量模板
|
||||||
|
└── .env # 环境变量 (gitignore)
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|||||||
@@ -230,9 +230,12 @@ class AluminumFoamMoldGenerator(BaseMoldGenerator):
|
|||||||
"manufacturing_info": {
|
"manufacturing_info": {
|
||||||
"estimated_mold_size": self._calculate_mold_size(analysis),
|
"estimated_mold_size": self._calculate_mold_size(analysis),
|
||||||
"estimated_clamping_force": self._calculate_clamping_force(analysis),
|
"estimated_clamping_force": self._calculate_clamping_force(analysis),
|
||||||
|
"clamping_force_formula": "投影面积(cm²) × 0.3 (泡沫材料系数)",
|
||||||
"recommended_material": material_info.get("description", "Aluminum Foam Mold"),
|
"recommended_material": material_info.get("description", "Aluminum Foam Mold"),
|
||||||
"molding_temperature": material_info.get("molding_temp", 380),
|
"molding_temperature": material_info.get("molding_temp", 380),
|
||||||
"expansion_ratio": material_info.get("expansion_ratio", 2.5)
|
"expansion_ratio": material_info.get("expansion_ratio", 2.5),
|
||||||
|
"parting_direction": "Z",
|
||||||
|
"parting_description": "Z轴上下开模,分型面位于包围盒Z中心",
|
||||||
},
|
},
|
||||||
"quality_checks": {
|
"quality_checks": {
|
||||||
"undercut_regions": cavity_data.get("undercut_regions", []),
|
"undercut_regions": cavity_data.get("undercut_regions", []),
|
||||||
@@ -301,8 +304,13 @@ class AluminumFoamMoldGenerator(BaseMoldGenerator):
|
|||||||
|
|
||||||
def _detect_parting_surfaces(self, shape: Any, analysis: Dict) -> Dict[str, Any]:
|
def _detect_parting_surfaces(self, shape: Any, analysis: Dict) -> Dict[str, Any]:
|
||||||
"""
|
"""
|
||||||
检测分型面(支持多分型面)
|
检测分型面(泡沫模具专用)
|
||||||
|
|
||||||
|
规则:
|
||||||
|
1. 优先选择 Z 轴方向分型(上下开模)
|
||||||
|
2. 分型面位置选在产品的最大轮廓处,即包围盒的 Z 方向中心
|
||||||
"""
|
"""
|
||||||
|
<<<<<<< HEAD
|
||||||
primary_parting = self._detect_primary_parting(shape, analysis)
|
primary_parting = self._detect_primary_parting(shape, analysis)
|
||||||
parting_surface = primary_parting["surface"]
|
parting_surface = primary_parting["surface"]
|
||||||
parting_line = self.optimize_parting_line(primary_parting["line"])
|
parting_line = self.optimize_parting_line(primary_parting["line"])
|
||||||
@@ -328,15 +336,54 @@ class AluminumFoamMoldGenerator(BaseMoldGenerator):
|
|||||||
})
|
})
|
||||||
except Exception:
|
except Exception:
|
||||||
pass
|
pass
|
||||||
|
=======
|
||||||
|
# 1. 尝试 AI 模型
|
||||||
|
if self.ai_parting_detector is not None:
|
||||||
|
try:
|
||||||
|
ai_result = self.ai_parting_detector.detect(shape, analysis)
|
||||||
|
if ai_result:
|
||||||
|
return self._create_parting_surface_from_ai(ai_result, analysis)
|
||||||
|
except Exception as e:
|
||||||
|
logger.warning(f"AI 分型面检测失败: {e}")
|
||||||
|
|
||||||
|
# 2. 泡沫模具强制 Z 轴方向分型(上下开模)
|
||||||
|
bbox = analysis["bounding_box"]
|
||||||
|
center = bbox["center"]
|
||||||
|
primary_direction = [0, 0, 1] # Z 轴方向
|
||||||
|
|
||||||
|
# 分型面位于包围盒 Z 方向中心(最大轮廓处)
|
||||||
|
parting_z = center[2]
|
||||||
|
parting_plane = gp_Pln(gp_Pnt(center[0], center[1], parting_z), gp_Dir(0, 0, 1))
|
||||||
|
|
||||||
|
try:
|
||||||
|
parting_surface = BRepBuilderAPI_MakeFace(parting_plane).Face()
|
||||||
|
except Exception:
|
||||||
|
# 回退到默认平面
|
||||||
|
parting_plane = gp_Pln(gp_Pnt(0, 0, parting_z), gp_Dir(0, 0, 1))
|
||||||
|
parting_surface = BRepBuilderAPI_MakeFace(parting_plane).Face()
|
||||||
|
|
||||||
|
logger.info(f"泡沫模具 Z 轴分型面: Z={parting_z:.2f} mm (包围盒中心)")
|
||||||
|
|
||||||
|
# 3. 计算分型线
|
||||||
|
parting_line = self._calculate_parting_line(shape, parting_surface)
|
||||||
|
>>>>>>> 77c4885a4020b609f4964184661f42e936814c4f
|
||||||
|
|
||||||
return {
|
return {
|
||||||
"primary_surface": parting_surface,
|
"primary_surface": parting_surface,
|
||||||
"primary_line": parting_line,
|
"primary_line": parting_line,
|
||||||
"primary_direction": primary_direction,
|
"primary_direction": primary_direction,
|
||||||
|
<<<<<<< HEAD
|
||||||
"confidence": primary_parting["confidence"],
|
"confidence": primary_parting["confidence"],
|
||||||
"method": primary_parting["method"],
|
"method": primary_parting["method"],
|
||||||
"additional_surfaces": additional_surfaces,
|
"additional_surfaces": additional_surfaces,
|
||||||
"surface_count": 1 + len(additional_surfaces)
|
"surface_count": 1 + len(additional_surfaces)
|
||||||
|
=======
|
||||||
|
"confidence": 0.95, # Z 轴分型置信度高
|
||||||
|
"additional_surfaces": [],
|
||||||
|
"surface_count": 1,
|
||||||
|
"parting_direction": "Z",
|
||||||
|
"parting_position_z": parting_z,
|
||||||
|
>>>>>>> 77c4885a4020b609f4964184661f42e936814c4f
|
||||||
}
|
}
|
||||||
|
|
||||||
def _build_undercut_regions(self, undercut_analysis: Dict[str, Any]) -> List[Dict[str, Any]]:
|
def _build_undercut_regions(self, undercut_analysis: Dict[str, Any]) -> List[Dict[str, Any]]:
|
||||||
@@ -416,7 +463,120 @@ class AluminumFoamMoldGenerator(BaseMoldGenerator):
|
|||||||
|
|
||||||
except Exception:
|
except Exception:
|
||||||
return 50.0
|
return 50.0
|
||||||
|
<<<<<<< HEAD
|
||||||
|
|
||||||
|
=======
|
||||||
|
|
||||||
|
def _apply_shrinkage_compensation(self, shape: Any) -> Any:
|
||||||
|
"""应用收缩率补偿(铝泡沫版本)"""
|
||||||
|
# 铝泡沫收缩率通常较大
|
||||||
|
scale_factor = 1.0 + self.shrinkage_rate
|
||||||
|
|
||||||
|
trsf = gp_Trsf()
|
||||||
|
trsf.SetScale(gp_Pnt(0, 0, 0), scale_factor)
|
||||||
|
|
||||||
|
try:
|
||||||
|
scaled_shape = BRepBuilderAPI_Transform(shape, trsf, True).Shape()
|
||||||
|
logger.info(f"收缩率补偿应用: {self.shrinkage_rate*100:.2f}%")
|
||||||
|
return scaled_shape
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"收缩补偿失败: {e}")
|
||||||
|
return shape
|
||||||
|
|
||||||
|
def _apply_draft_angles(self, shape: Any, parting_surface: Any) -> Any:
|
||||||
|
"""应用拔模角(改进版)"""
|
||||||
|
# 获取分型面法向量作为拔模方向
|
||||||
|
try:
|
||||||
|
surface = BRepAdaptor_Surface(parting_surface)
|
||||||
|
draft_direction = surface.Plane().Position().Direction()
|
||||||
|
|
||||||
|
logger.info(f"应用拔模角: {self.draft_angle}°, 方向: ({draft_direction.X():.3f}, {draft_direction.Y():.3f}, {draft_direction.Z():.3f})")
|
||||||
|
|
||||||
|
# 注意:完整的拔模实现需要更复杂的 BRepOffsetAPI_DraftAngle
|
||||||
|
# 这里简化处理,返回原始形状
|
||||||
|
return shape
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
logger.warning(f"拔模角处理失败: {e}")
|
||||||
|
return shape
|
||||||
|
|
||||||
|
def _split_cavity_core(self, shape: Any, parting_surface: Any) -> Tuple[Any, Any]:
|
||||||
|
"""
|
||||||
|
按分型面将模具分为 A 板(定模/型腔侧)和 B 板(动模/型芯侧)
|
||||||
|
|
||||||
|
流程:
|
||||||
|
1. 创建模具块(包围产品的长方体)
|
||||||
|
2. 用分型面水平切出上半块和下半块
|
||||||
|
3. 从上半块减去产品 → A 板(含型腔负形)
|
||||||
|
4. 从下半块减去产品 → B 板(含型芯负形)
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
# 获取产品边界框
|
||||||
|
bbox = Bnd_Box()
|
||||||
|
brepbndlib_Add(shape, bbox)
|
||||||
|
xmin, ymin, zmin, xmax, ymax, zmax = bbox.Get()
|
||||||
|
|
||||||
|
# 获取分型面 Z 位置(包围盒 Z 中心)
|
||||||
|
parting_z = (zmin + zmax) / 2
|
||||||
|
|
||||||
|
# 模具块尺寸(比产品大一圈余量)
|
||||||
|
margin = 25
|
||||||
|
mold_xmin = xmin - margin
|
||||||
|
mold_ymin = ymin - margin
|
||||||
|
mold_zmin = zmin - margin
|
||||||
|
mold_xmax = xmax + margin
|
||||||
|
mold_ymax = ymax + margin
|
||||||
|
mold_zmax = zmax + margin
|
||||||
|
|
||||||
|
# Step 1: 创建整块模具
|
||||||
|
mold_block = BRepPrimAPI_MakeBox(
|
||||||
|
gp_Pnt(mold_xmin, mold_ymin, mold_zmin),
|
||||||
|
gp_Pnt(mold_xmax, mold_ymax, mold_zmax)
|
||||||
|
).Shape()
|
||||||
|
|
||||||
|
# Step 2: 用分型面切出上下半块
|
||||||
|
# 创建一个足够大的水平切割面(分型面 Z 位置)
|
||||||
|
cutting_plane = gp_Pln(gp_Pnt(0, 0, parting_z), gp_Dir(0, 0, 1))
|
||||||
|
cutting_face = BRepBuilderAPI_MakeFace(cutting_plane).Face()
|
||||||
|
|
||||||
|
# 创建上半空间和下半空间的实体
|
||||||
|
# 上半块: 从 parting_z 到 mold_zmax
|
||||||
|
upper_block = BRepPrimAPI_MakeBox(
|
||||||
|
gp_Pnt(mold_xmin, mold_ymin, parting_z),
|
||||||
|
gp_Pnt(mold_xmax, mold_ymax, mold_zmax)
|
||||||
|
).Shape()
|
||||||
|
|
||||||
|
# 下半块: 从 mold_zmin 到 parting_z
|
||||||
|
lower_block = BRepPrimAPI_MakeBox(
|
||||||
|
gp_Pnt(mold_xmin, mold_ymin, mold_zmin),
|
||||||
|
gp_Pnt(mold_xmax, mold_ymax, parting_z)
|
||||||
|
).Shape()
|
||||||
|
|
||||||
|
# Step 3: 从上半块减去产品 → A 板(定模)
|
||||||
|
a_plate_op = BRepAlgoAPI_Cut(upper_block, shape)
|
||||||
|
if a_plate_op.IsDone():
|
||||||
|
a_plate = a_plate_op.Shape()
|
||||||
|
logger.info(f"A板(定模)生成成功: Z={parting_z:.1f} ~ {mold_zmax:.1f}")
|
||||||
|
else:
|
||||||
|
logger.warning("A板布尔减法失败,使用上半块")
|
||||||
|
a_plate = upper_block
|
||||||
|
|
||||||
|
# Step 4: 从下半块减去产品 → B 板(动模)
|
||||||
|
b_plate_op = BRepAlgoAPI_Cut(lower_block, shape)
|
||||||
|
if b_plate_op.IsDone():
|
||||||
|
b_plate = b_plate_op.Shape()
|
||||||
|
logger.info(f"B板(动模)生成成功: Z={mold_zmin:.1f} ~ {parting_z:.1f}")
|
||||||
|
else:
|
||||||
|
logger.warning("B板布尔减法失败,使用下半块")
|
||||||
|
b_plate = lower_block
|
||||||
|
|
||||||
|
return a_plate, b_plate
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"分模失败: {e}")
|
||||||
|
return shape, shape
|
||||||
|
|
||||||
|
>>>>>>> 77c4885a4020b609f4964184661f42e936814c4f
|
||||||
def _generate_mold_block(self, cavity: Any, analysis: Dict) -> Any:
|
def _generate_mold_block(self, cavity: Any, analysis: Dict) -> Any:
|
||||||
"""生成完整的模具块(包含A/B板结构)"""
|
"""生成完整的模具块(包含A/B板结构)"""
|
||||||
try:
|
try:
|
||||||
@@ -496,6 +656,7 @@ class AluminumFoamMoldGenerator(BaseMoldGenerator):
|
|||||||
}
|
}
|
||||||
|
|
||||||
def _calculate_clamping_force(self, analysis: Dict) -> str:
|
def _calculate_clamping_force(self, analysis: Dict) -> str:
|
||||||
|
<<<<<<< HEAD
|
||||||
"""估算锁模力"""
|
"""估算锁模力"""
|
||||||
volume_cm3 = analysis.get("volume", 0) / 1000
|
volume_cm3 = analysis.get("volume", 0) / 1000
|
||||||
|
|
||||||
@@ -508,6 +669,32 @@ class AluminumFoamMoldGenerator(BaseMoldGenerator):
|
|||||||
else:
|
else:
|
||||||
return "200+ 吨"
|
return "200+ 吨"
|
||||||
|
|
||||||
|
=======
|
||||||
|
"""
|
||||||
|
估算锁模力(泡沫模具专用)
|
||||||
|
|
||||||
|
公式: 锁模力(吨) = 投影面积(cm²) × 0.3 (泡沫材料系数)
|
||||||
|
投影面积 = 长度 × 宽度 (Z轴开模)
|
||||||
|
"""
|
||||||
|
bbox = analysis.get("bounding_box", {})
|
||||||
|
dims = bbox.get("dimensions", [0, 0, 0])
|
||||||
|
|
||||||
|
# 投影面积 = 长度 × 宽度 (mm² → cm²)
|
||||||
|
projected_area_cm2 = (dims[0] * dims[1]) / 100 if len(dims) >= 2 else 0
|
||||||
|
|
||||||
|
# 锁模力(吨) = 投影面积(cm²) × 0.3
|
||||||
|
clamping_force_ton = int(projected_area_cm2 * 0.3)
|
||||||
|
clamping_force_ton = max(30, clamping_force_ton)
|
||||||
|
|
||||||
|
return f"{clamping_force_ton} 吨 (投影面积 {projected_area_cm2:.1f} cm² × 0.3)"
|
||||||
|
|
||||||
|
def _calculate_product_weight(self, analysis: Dict) -> str:
|
||||||
|
"""计算产品重量"""
|
||||||
|
volume_cm3 = analysis.get("volume", 0) / 1000
|
||||||
|
weight_g = volume_cm3 * self.material_density
|
||||||
|
return f"{weight_g:.2f} g"
|
||||||
|
|
||||||
|
>>>>>>> 77c4885a4020b609f4964184661f42e936814c4f
|
||||||
def _estimate_wall_thickness(self, analysis: Dict) -> str:
|
def _estimate_wall_thickness(self, analysis: Dict) -> str:
|
||||||
"""估算壁厚范围"""
|
"""估算壁厚范围"""
|
||||||
volume = analysis.get("volume", 0)
|
volume = analysis.get("volume", 0)
|
||||||
|
|||||||
@@ -237,6 +237,7 @@ class MoldCavityGenerator(BaseMoldGenerator):
|
|||||||
logger.info(f"转换得到 {len(regions)} 个兼容倒扣区域")
|
logger.info(f"转换得到 {len(regions)} 个兼容倒扣区域")
|
||||||
return regions
|
return regions
|
||||||
|
|
||||||
|
<<<<<<< HEAD
|
||||||
def _analyze_face_normals(self, shape: Any) -> gp_Dir:
|
def _analyze_face_normals(self, shape: Any) -> gp_Dir:
|
||||||
"""
|
"""
|
||||||
分析产品表面的法向量分布,找出最优分型方向
|
分析产品表面的法向量分布,找出最优分型方向
|
||||||
@@ -248,6 +249,87 @@ class MoldCavityGenerator(BaseMoldGenerator):
|
|||||||
"""
|
"""
|
||||||
face_normals = []
|
face_normals = []
|
||||||
explorer = TopExp_Explorer(shape, TopAbs_FACE)
|
explorer = TopExp_Explorer(shape, TopAbs_FACE)
|
||||||
|
=======
|
||||||
|
return scaled_shape
|
||||||
|
|
||||||
|
def _apply_draft_angles(self, shape: Any, parting_surface: Any) -> Any:
|
||||||
|
"""添加拔模角(简化实现)"""
|
||||||
|
# 实际实现需要复杂的拔模面处理
|
||||||
|
# 这里返回原始形状(假设已在CAD中处理)
|
||||||
|
logger.warning("拔模角处理为简化实现,建议在设计阶段处理")
|
||||||
|
return shape
|
||||||
|
|
||||||
|
def _split_cavity_core(self, shape: Any, parting_surface: Any) -> Tuple[Any, Any]:
|
||||||
|
"""
|
||||||
|
按分型面将模具分为 A 板(定模/型腔侧)和 B 板(动模/型芯侧)
|
||||||
|
|
||||||
|
流程:
|
||||||
|
1. 创建模具块(包围产品的长方体)
|
||||||
|
2. 用分型面 Z 位置切出上半块和下半块
|
||||||
|
3. 从上半块减去产品 → A 板(含型腔负形)
|
||||||
|
4. 从下半块减去产品 → B 板(含型芯负形)
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
from OCC.Core.BRepPrimAPI import BRepPrimAPI_MakeBox
|
||||||
|
from OCC.Core.BRepAlgoAPI import BRepAlgoAPI_Cut
|
||||||
|
from OCC.Core.TopExp import TopExp_Explorer
|
||||||
|
from OCC.Core.TopAbs import TopAbs_SOLID
|
||||||
|
|
||||||
|
# 获取产品边界框
|
||||||
|
from OCC.Core.Bnd import Bnd_Box
|
||||||
|
from OCC.Core.BRepBndLib import brepbndlib
|
||||||
|
bbox = Bnd_Box()
|
||||||
|
brepbndlib.Add(shape, bbox)
|
||||||
|
xmin, ymin, zmin, xmax, ymax, zmax = bbox.Get()
|
||||||
|
|
||||||
|
# 获取分型面 Z 位置(包围盒 Z 中心)
|
||||||
|
parting_z = (zmin + zmax) / 2
|
||||||
|
|
||||||
|
# 计算模具块尺寸(比产品大一定余量)
|
||||||
|
margin = 20 # mm
|
||||||
|
mold_xmin = xmin - margin
|
||||||
|
mold_ymin = ymin - margin
|
||||||
|
mold_zmin = zmin - margin
|
||||||
|
mold_xmax = xmax + margin
|
||||||
|
mold_ymax = ymax + margin
|
||||||
|
mold_zmax = zmax + margin
|
||||||
|
|
||||||
|
# 上半块: 从 parting_z 到 mold_zmax
|
||||||
|
upper_block = BRepPrimAPI_MakeBox(
|
||||||
|
gp_Pnt(mold_xmin, mold_ymin, parting_z),
|
||||||
|
gp_Pnt(mold_xmax, mold_ymax, mold_zmax)
|
||||||
|
).Shape()
|
||||||
|
|
||||||
|
# 下半块: 从 mold_zmin 到 parting_z
|
||||||
|
lower_block = BRepPrimAPI_MakeBox(
|
||||||
|
gp_Pnt(mold_xmin, mold_ymin, mold_zmin),
|
||||||
|
gp_Pnt(mold_xmax, mold_ymax, parting_z)
|
||||||
|
).Shape()
|
||||||
|
|
||||||
|
# A 板(定模)= 上半块 - 产品
|
||||||
|
a_plate_op = BRepAlgoAPI_Cut(upper_block, shape)
|
||||||
|
if a_plate_op.IsDone():
|
||||||
|
a_plate = a_plate_op.Shape()
|
||||||
|
logger.info(f"A板(定模)生成成功: Z={parting_z:.1f} ~ {mold_zmax:.1f}")
|
||||||
|
else:
|
||||||
|
logger.warning("A板布尔减法失败,使用上半块")
|
||||||
|
a_plate = upper_block
|
||||||
|
|
||||||
|
# B 板(动模)= 下半块 - 产品
|
||||||
|
b_plate_op = BRepAlgoAPI_Cut(lower_block, shape)
|
||||||
|
if b_plate_op.IsDone():
|
||||||
|
b_plate = b_plate_op.Shape()
|
||||||
|
logger.info(f"B板(动模)生成成功: Z={mold_zmin:.1f} ~ {parting_z:.1f}")
|
||||||
|
else:
|
||||||
|
logger.warning("B板布尔减法失败,使用下半块")
|
||||||
|
b_plate = lower_block
|
||||||
|
|
||||||
|
return a_plate, b_plate
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"分模失败: {e}")
|
||||||
|
return shape, shape
|
||||||
|
>>>>>>> 77c4885a4020b609f4964184661f42e936814c4f
|
||||||
|
|
||||||
while explorer.More():
|
while explorer.More():
|
||||||
face = TopoDS_Face(explorer.Current())
|
face = TopoDS_Face(explorer.Current())
|
||||||
|
|||||||
@@ -1,207 +0,0 @@
|
|||||||
|
|
||||||
<!DOCTYPE html>
|
|
||||||
<html lang="zh-CN">
|
|
||||||
<head>
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
||||||
<title>3D模具几何可视化 - fsa30scy_tc-01-0817.stp</title>
|
|
||||||
<script src="https://cdn.jsdelivr.net/npm/three@0.132.2/build/three.min.js"></script>
|
|
||||||
<script src="https://cdn.jsdelivr.net/npm/three@0.132.2/examples/js/controls/OrbitControls.js"></script>
|
|
||||||
<style>
|
|
||||||
body { margin: 0; overflow: hidden; font-family: Arial, sans-serif; }
|
|
||||||
#container { position: relative; width: 100vw; height: 100vh; }
|
|
||||||
#canvas { display: block; }
|
|
||||||
#info-panel {
|
|
||||||
position: absolute;
|
|
||||||
top: 10px;
|
|
||||||
left: 10px;
|
|
||||||
background: rgba(255, 255, 255, 0.9);
|
|
||||||
padding: 15px;
|
|
||||||
border-radius: 8px;
|
|
||||||
max-width: 300px;
|
|
||||||
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
|
|
||||||
}
|
|
||||||
#controls {
|
|
||||||
position: absolute;
|
|
||||||
bottom: 10px;
|
|
||||||
left: 10px;
|
|
||||||
background: rgba(255, 255, 255, 0.9);
|
|
||||||
padding: 10px;
|
|
||||||
border-radius: 8px;
|
|
||||||
}
|
|
||||||
.metric { margin: 5px 0; }
|
|
||||||
.metric-label { font-weight: bold; color: #333; }
|
|
||||||
.metric-value { color: #666; }
|
|
||||||
</style>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div id="container">
|
|
||||||
<canvas id="canvas"></canvas>
|
|
||||||
|
|
||||||
<div id="info-panel">
|
|
||||||
<h3>模具几何信息</h3>
|
|
||||||
<div class="metric">
|
|
||||||
<span class="metric-label">文件名:</span>
|
|
||||||
<span class="metric-value">fsa30scy_tc-01-0817.stp</span>
|
|
||||||
</div>
|
|
||||||
<div class="metric">
|
|
||||||
<span class="metric-label">体积:</span>
|
|
||||||
<span class="metric-value">1000000.00 mm³</span>
|
|
||||||
</div>
|
|
||||||
<div class="metric">
|
|
||||||
<span class="metric-label">表面积:</span>
|
|
||||||
<span class="metric-value">60000.00 mm²</span>
|
|
||||||
</div>
|
|
||||||
<div class="metric">
|
|
||||||
<span class="metric-label">边界框:</span>
|
|
||||||
<span class="metric-value">100.0 × 100.0 × 100.0 mm</span>
|
|
||||||
</div>
|
|
||||||
<div class="metric">
|
|
||||||
<span class="metric-label">面数:</span>
|
|
||||||
<span class="metric-value">6</span>
|
|
||||||
</div>
|
|
||||||
<div class="metric">
|
|
||||||
<span class="metric-label">边数:</span>
|
|
||||||
<span class="metric-value">12</span>
|
|
||||||
</div>
|
|
||||||
<div class="metric">
|
|
||||||
<span class="metric-label">顶点数:</span>
|
|
||||||
<span class="metric-value">8</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="controls">
|
|
||||||
<button onclick="resetView()">重置视图</button>
|
|
||||||
<button onclick="toggleWireframe()">切换线框</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
// 初始化Three.js场景
|
|
||||||
const scene = new THREE.Scene();
|
|
||||||
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
|
|
||||||
const renderer = new THREE.WebGLRenderer({ canvas: document.getElementById('canvas') });
|
|
||||||
|
|
||||||
renderer.setSize(window.innerWidth, window.innerHeight);
|
|
||||||
renderer.setClearColor(0xf0f0f0);
|
|
||||||
|
|
||||||
// 添加光源
|
|
||||||
const ambientLight = new THREE.AmbientLight(0x404040);
|
|
||||||
scene.add(ambientLight);
|
|
||||||
|
|
||||||
const directionalLight = new THREE.DirectionalLight(0xffffff, 1);
|
|
||||||
directionalLight.position.set(1, 1, 1);
|
|
||||||
scene.add(directionalLight);
|
|
||||||
|
|
||||||
// 添加坐标轴
|
|
||||||
const axesHelper = new THREE.AxesHelper(50);
|
|
||||||
scene.add(axesHelper);
|
|
||||||
|
|
||||||
// 创建几何体(模拟模具形状)
|
|
||||||
const geometryData = {
|
|
||||||
"bounding_box": {
|
|
||||||
"min": [
|
|
||||||
0.0,
|
|
||||||
0.0,
|
|
||||||
0.0
|
|
||||||
],
|
|
||||||
"max": [
|
|
||||||
100.0,
|
|
||||||
100.0,
|
|
||||||
100.0
|
|
||||||
],
|
|
||||||
"dimensions": [
|
|
||||||
100.0,
|
|
||||||
100.0,
|
|
||||||
100.0
|
|
||||||
],
|
|
||||||
"center": [
|
|
||||||
50.0,
|
|
||||||
50.0,
|
|
||||||
50.0
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"volume": 1000000.0,
|
|
||||||
"surface_area": 60000.0,
|
|
||||||
"topology": {
|
|
||||||
"faces": 6,
|
|
||||||
"edges": 12,
|
|
||||||
"vertices": 8
|
|
||||||
},
|
|
||||||
"center_of_mass": [
|
|
||||||
50.0,
|
|
||||||
50.0,
|
|
||||||
50.0
|
|
||||||
],
|
|
||||||
"inertia_properties": {},
|
|
||||||
"analysis_method": "simulated"
|
|
||||||
};
|
|
||||||
|
|
||||||
// 根据边界框创建模拟几何体
|
|
||||||
const bbox = geometryData.bounding_box;
|
|
||||||
if (bbox) {
|
|
||||||
const width = bbox.dimensions ? bbox.dimensions[0] : 100;
|
|
||||||
const height = bbox.dimensions ? bbox.dimensions[1] : 100;
|
|
||||||
const depth = bbox.dimensions ? bbox.dimensions[2] : 100;
|
|
||||||
|
|
||||||
// 创建基础几何体
|
|
||||||
const geometry = new THREE.BoxGeometry(width, height, depth);
|
|
||||||
const material = new THREE.MeshPhongMaterial({
|
|
||||||
color: 0x4CAF50,
|
|
||||||
transparent: true,
|
|
||||||
opacity: 0.8,
|
|
||||||
wireframe: false
|
|
||||||
});
|
|
||||||
|
|
||||||
const mesh = new THREE.Mesh(geometry, material);
|
|
||||||
scene.add(mesh);
|
|
||||||
|
|
||||||
// 添加线框
|
|
||||||
const wireframe = new THREE.WireframeGeometry(geometry);
|
|
||||||
const line = new THREE.LineSegments(wireframe);
|
|
||||||
line.material.depthTest = false;
|
|
||||||
line.material.opacity = 0.25;
|
|
||||||
line.material.transparent = true;
|
|
||||||
scene.add(line);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 设置相机位置
|
|
||||||
camera.position.set(200, 200, 200);
|
|
||||||
camera.lookAt(0, 0, 0);
|
|
||||||
|
|
||||||
// 添加轨道控制器
|
|
||||||
const controls = new THREE.OrbitControls(camera, renderer.domElement);
|
|
||||||
controls.enableDamping = true;
|
|
||||||
controls.dampingFactor = 0.25;
|
|
||||||
|
|
||||||
// 动画循环
|
|
||||||
function animate() {
|
|
||||||
requestAnimationFrame(animate);
|
|
||||||
controls.update();
|
|
||||||
renderer.render(scene, camera);
|
|
||||||
}
|
|
||||||
|
|
||||||
animate();
|
|
||||||
|
|
||||||
// 窗口大小调整
|
|
||||||
window.addEventListener('resize', () => {
|
|
||||||
camera.aspect = window.innerWidth / window.innerHeight;
|
|
||||||
camera.updateProjectionMatrix();
|
|
||||||
renderer.setSize(window.innerWidth, window.innerHeight);
|
|
||||||
});
|
|
||||||
|
|
||||||
// 控制函数
|
|
||||||
function resetView() {
|
|
||||||
controls.reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
function toggleWireframe() {
|
|
||||||
scene.traverse((child) => {
|
|
||||||
if (child.isMesh) {
|
|
||||||
child.material.wireframe = !child.material.wireframe;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
@@ -18,11 +18,27 @@ class CalculationService:
|
|||||||
return volume_cm3 * density
|
return volume_cm3 * density
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def calculate_projected_area(bbox_dims: List[float]) -> float:
|
def calculate_projected_area(bbox_dims: List[float], parting_direction: str = "Z") -> float:
|
||||||
"""计算投影面积(cm²),取 X、Y 方向"""
|
"""
|
||||||
if len(bbox_dims) >= 2:
|
计算投影面积(cm²)
|
||||||
|
|
||||||
|
Args:
|
||||||
|
bbox_dims: [长度, 宽度, 高度] (mm)
|
||||||
|
parting_direction: 开模方向,"Z" 表示上下开模(投影到XY平面),
|
||||||
|
"Y" 表示前后开模(投影到XZ平面),
|
||||||
|
"X" 表示左右开模(投影到YZ平面)
|
||||||
|
"""
|
||||||
|
if len(bbox_dims) < 3:
|
||||||
|
return 0.0
|
||||||
|
if parting_direction == "Z":
|
||||||
|
# Z轴开模 → 投影面积 = 长度 × 宽度
|
||||||
return (bbox_dims[0] * bbox_dims[1]) / 100
|
return (bbox_dims[0] * bbox_dims[1]) / 100
|
||||||
return 0.0
|
elif parting_direction == "Y":
|
||||||
|
return (bbox_dims[0] * bbox_dims[2]) / 100
|
||||||
|
elif parting_direction == "X":
|
||||||
|
return (bbox_dims[1] * bbox_dims[2]) / 100
|
||||||
|
# 默认 Z 轴
|
||||||
|
return (bbox_dims[0] * bbox_dims[1]) / 100
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def calculate_cavity_count(product_weight_g: float, projected_area_cm2: float) -> int:
|
def calculate_cavity_count(product_weight_g: float, projected_area_cm2: float) -> int:
|
||||||
@@ -55,14 +71,27 @@ class CalculationService:
|
|||||||
cavity_count: int,
|
cavity_count: int,
|
||||||
runner_ratio: float = 0.20,
|
runner_ratio: float = 0.20,
|
||||||
injection_pressure: float = 700,
|
injection_pressure: float = 700,
|
||||||
|
is_foam: bool = False,
|
||||||
) -> int:
|
) -> int:
|
||||||
"""
|
"""
|
||||||
计算所需夹紧力(吨)
|
计算所需夹紧力(吨)
|
||||||
runner_ratio: 流道系统占型腔投影面积比(0.15-0.25)
|
|
||||||
injection_pressure: 注塑压力 kg/cm²
|
塑料模具: 锁模力 = 投影面积 × 型腔数 × (1+流道比) × 注塑压力 / 1000
|
||||||
|
泡沫模具: 锁模力 = 投影面积(cm²) × 0.3 (泡沫材料系数)
|
||||||
|
|
||||||
|
Args:
|
||||||
|
projected_area_cm2: 投影面积 cm²
|
||||||
|
cavity_count: 型腔数
|
||||||
|
runner_ratio: 流道系统占型腔投影面积比(0.15-0.25)
|
||||||
|
injection_pressure: 注塑压力 kg/cm²
|
||||||
|
is_foam: 是否泡沫材料
|
||||||
"""
|
"""
|
||||||
total_projected_area = projected_area_cm2 * cavity_count * (1 + runner_ratio)
|
if is_foam:
|
||||||
clamping_force_ton = int(total_projected_area * injection_pressure / 1000)
|
# 泡沫模具: 锁模力(吨) = 投影面积(cm²) × 0.3
|
||||||
|
clamping_force_ton = int(projected_area_cm2 * 0.3)
|
||||||
|
else:
|
||||||
|
total_projected_area = projected_area_cm2 * cavity_count * (1 + runner_ratio)
|
||||||
|
clamping_force_ton = int(total_projected_area * injection_pressure / 1000)
|
||||||
return max(50, min(clamping_force_ton, 3000))
|
return max(50, min(clamping_force_ton, 3000))
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
@@ -165,13 +194,19 @@ class CalculationService:
|
|||||||
|
|
||||||
material_density = material["density"]
|
material_density = material["density"]
|
||||||
shrinkage_rate = material["shrinkage"]
|
shrinkage_rate = material["shrinkage"]
|
||||||
|
is_foam = material.get("is_foam", False)
|
||||||
|
|
||||||
|
# 泡沫模具优先 Z 轴开模(上下开模)
|
||||||
|
parting_direction = "Z"
|
||||||
|
|
||||||
# 各项计算
|
# 各项计算
|
||||||
volume_cm3 = volume_mm3 / 1000
|
volume_cm3 = volume_mm3 / 1000
|
||||||
product_weight_g = cls.calculate_product_weight(volume_mm3, material_density)
|
product_weight_g = cls.calculate_product_weight(volume_mm3, material_density)
|
||||||
projected_area_cm2 = cls.calculate_projected_area(bbox_dims)
|
projected_area_cm2 = cls.calculate_projected_area(bbox_dims, parting_direction)
|
||||||
cavity_count = cls.calculate_cavity_count(product_weight_g, projected_area_cm2)
|
cavity_count = cls.calculate_cavity_count(product_weight_g, projected_area_cm2)
|
||||||
clamping_force_ton = cls.calculate_clamping_force(projected_area_cm2, cavity_count)
|
clamping_force_ton = cls.calculate_clamping_force(
|
||||||
|
projected_area_cm2, cavity_count, is_foam=is_foam
|
||||||
|
)
|
||||||
wall = cls.calculate_wall_thickness(volume_mm3, surface_area_mm2)
|
wall = cls.calculate_wall_thickness(volume_mm3, surface_area_mm2)
|
||||||
complexity_score = cls.calculate_complexity(wall["avg_thickness_mm"])
|
complexity_score = cls.calculate_complexity(wall["avg_thickness_mm"])
|
||||||
mold_size = cls.calculate_mold_size(bbox_dims, cavity_count)
|
mold_size = cls.calculate_mold_size(bbox_dims, cavity_count)
|
||||||
@@ -187,6 +222,8 @@ class CalculationService:
|
|||||||
"shrinkage_rate": shrinkage_rate,
|
"shrinkage_rate": shrinkage_rate,
|
||||||
"draft_angle": 2.0,
|
"draft_angle": 2.0,
|
||||||
"selected_material": material["name"],
|
"selected_material": material["name"],
|
||||||
|
"is_foam": is_foam,
|
||||||
|
"parting_direction": parting_direction,
|
||||||
},
|
},
|
||||||
"product_analysis": {
|
"product_analysis": {
|
||||||
"volume": volume_mm3,
|
"volume": volume_mm3,
|
||||||
@@ -197,6 +234,10 @@ class CalculationService:
|
|||||||
"recommended_material": material["name"],
|
"recommended_material": material["name"],
|
||||||
"material_density": f"{material_density} g/cm³",
|
"material_density": f"{material_density} g/cm³",
|
||||||
"estimated_clamping_force": f"{clamping_force_ton} 吨",
|
"estimated_clamping_force": f"{clamping_force_ton} 吨",
|
||||||
|
"clamping_force_formula": (
|
||||||
|
"投影面积(cm²) × 0.3" if is_foam
|
||||||
|
else "投影面积 × 型腔数 × (1+流道比) × 注塑压力 / 1000"
|
||||||
|
),
|
||||||
"estimated_mold_size": {
|
"estimated_mold_size": {
|
||||||
"length": int(mold_size["length"]),
|
"length": int(mold_size["length"]),
|
||||||
"width": int(mold_size["width"]),
|
"width": int(mold_size["width"]),
|
||||||
@@ -208,6 +249,7 @@ class CalculationService:
|
|||||||
"parting_line_length": f"{parting_line_length:.2f} mm",
|
"parting_line_length": f"{parting_line_length:.2f} mm",
|
||||||
"estimated_cycle_time": f"{cycle_time} 秒",
|
"estimated_cycle_time": f"{cycle_time} 秒",
|
||||||
"injection_pressure": f"{injection_pressure} kg/cm²",
|
"injection_pressure": f"{injection_pressure} kg/cm²",
|
||||||
|
"parting_direction": parting_direction,
|
||||||
},
|
},
|
||||||
"mold_cavities": {
|
"mold_cavities": {
|
||||||
"cavity_count": cavity_count,
|
"cavity_count": cavity_count,
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
+108
-10
@@ -80,7 +80,7 @@ class HTMLGenerator:
|
|||||||
<strong style="color: #333;">制造要求</strong>
|
<strong style="color: #333;">制造要求</strong>
|
||||||
</div>
|
</div>
|
||||||
<div class="metric">
|
<div class="metric">
|
||||||
<span class="metric-label">型腔材料:</span>
|
<span class="metric-label">模仁材料:</span>
|
||||||
<span class="metric-value">{manufacturing_info.get("mold_material", "N/A")}</span>
|
<span class="metric-value">{manufacturing_info.get("mold_material", "N/A")}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="metric">
|
<div class="metric">
|
||||||
@@ -176,9 +176,10 @@ class HTMLGenerator:
|
|||||||
<button onclick="resetView()">重置视图</button>
|
<button onclick="resetView()">重置视图</button>
|
||||||
<button onclick="toggleWireframe()">切换线框</button>
|
<button onclick="toggleWireframe()">切换线框</button>
|
||||||
<button onclick="toggleProduct()">显示/隐藏产品</button>
|
<button onclick="toggleProduct()">显示/隐藏产品</button>
|
||||||
<button onclick="toggleMold()">显示/隐藏模具</button>
|
<button onclick="toggleMold()">显示/隐藏A/B板</button>
|
||||||
<button onclick="toggleParting()">显示/隐藏分型面</button>
|
<button onclick="toggleParting()">显示/隐藏分型面</button>
|
||||||
<button onclick="togglePointcloud()">显示/隐藏点云</button>
|
<button onclick="togglePointcloud()">显示/隐藏点云</button>
|
||||||
|
<button id="splitBtn" onclick="splitMold()" style="background:#FF5722;color:#fff;font-weight:bold;">分模拆分</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -277,7 +278,7 @@ class HTMLGenerator:
|
|||||||
scene.add(productMesh);
|
scene.add(productMesh);
|
||||||
}}
|
}}
|
||||||
|
|
||||||
// 创建型腔(上半模 - 蓝色)
|
// 创建A板/定模(蓝色,分型面以上)
|
||||||
// 尝试从后端数据获取实际几何,否则使用简化Box
|
// 尝试从后端数据获取实际几何,否则使用简化Box
|
||||||
if (cavityData && cavityData.mold_cavities && cavityData.mold_cavities.cavity && cavityData.mold_cavities.cavity.vertices) {{
|
if (cavityData && cavityData.mold_cavities && cavityData.mold_cavities.cavity && cavityData.mold_cavities.cavity.vertices) {{
|
||||||
const cavityVerts = cavityData.mold_cavities.cavity.vertices;
|
const cavityVerts = cavityData.mold_cavities.cavity.vertices;
|
||||||
@@ -323,7 +324,7 @@ class HTMLGenerator:
|
|||||||
createSimpleCavity(width, height, depth);
|
createSimpleCavity(width, height, depth);
|
||||||
}}
|
}}
|
||||||
|
|
||||||
// 创建型芯(下半模 - 橙色)
|
// 创建B板/动模(橙色,分型面以下)
|
||||||
if (cavityData && cavityData.mold_cavities && cavityData.mold_cavities.core && cavityData.mold_cavities.core.vertices) {{
|
if (cavityData && cavityData.mold_cavities && cavityData.mold_cavities.core && cavityData.mold_cavities.core.vertices) {{
|
||||||
const coreVerts = cavityData.mold_cavities.core.vertices;
|
const coreVerts = cavityData.mold_cavities.core.vertices;
|
||||||
const coreFaces = cavityData.mold_cavities.core.faces;
|
const coreFaces = cavityData.mold_cavities.core.faces;
|
||||||
@@ -388,9 +389,11 @@ class HTMLGenerator:
|
|||||||
}}
|
}}
|
||||||
}}
|
}}
|
||||||
|
|
||||||
// 创建简化型腔(备用)
|
// 创建简化型腔/A板(定模,分型面以上)— 备用
|
||||||
function createSimpleCavity(width, height, depth) {{
|
function createSimpleCavity(width, height, depth) {{
|
||||||
const cavityGeometry = new THREE.BoxGeometry(width * 1.2, height * 0.4, depth * 1.2);
|
// A板:分型面(Z中心)以上的上半模
|
||||||
|
const halfHeight = height / 2;
|
||||||
|
const cavityGeometry = new THREE.BoxGeometry(width * 1.2, depth * 1.2, halfHeight + 10);
|
||||||
const cavityMaterial = new THREE.MeshPhongMaterial({{
|
const cavityMaterial = new THREE.MeshPhongMaterial({{
|
||||||
color: 0x2196F3,
|
color: 0x2196F3,
|
||||||
transparent: true,
|
transparent: true,
|
||||||
@@ -399,7 +402,8 @@ class HTMLGenerator:
|
|||||||
}});
|
}});
|
||||||
|
|
||||||
cavityMesh = new THREE.Mesh(cavityGeometry, cavityMaterial);
|
cavityMesh = new THREE.Mesh(cavityGeometry, cavityMaterial);
|
||||||
cavityMesh.position.set(0, height * 0.7, 0);
|
// Z轴开模:A板放在分型面以上
|
||||||
|
cavityMesh.position.set(0, 0, halfHeight / 2 + 5);
|
||||||
scene.add(cavityMesh);
|
scene.add(cavityMesh);
|
||||||
|
|
||||||
const cavityWireframe = new THREE.WireframeGeometry(cavityGeometry);
|
const cavityWireframe = new THREE.WireframeGeometry(cavityGeometry);
|
||||||
@@ -411,9 +415,11 @@ class HTMLGenerator:
|
|||||||
cavityMesh.add(cavityLine);
|
cavityMesh.add(cavityLine);
|
||||||
}}
|
}}
|
||||||
|
|
||||||
// 创建简化型芯(备用)
|
// 创建简化型芯/B板(动模,分型面以下)— 备用
|
||||||
function createSimpleCore(width, height, depth) {{
|
function createSimpleCore(width, height, depth) {{
|
||||||
const coreGeometry = new THREE.BoxGeometry(width * 1.2, height * 0.4, depth * 1.2);
|
// B板:分型面(Z中心)以下的下半模
|
||||||
|
const halfHeight = height / 2;
|
||||||
|
const coreGeometry = new THREE.BoxGeometry(width * 1.2, depth * 1.2, halfHeight + 10);
|
||||||
const coreMaterial = new THREE.MeshPhongMaterial({{
|
const coreMaterial = new THREE.MeshPhongMaterial({{
|
||||||
color: 0xFF9800,
|
color: 0xFF9800,
|
||||||
transparent: true,
|
transparent: true,
|
||||||
@@ -422,7 +428,8 @@ class HTMLGenerator:
|
|||||||
}});
|
}});
|
||||||
|
|
||||||
coreMesh = new THREE.Mesh(coreGeometry, coreMaterial);
|
coreMesh = new THREE.Mesh(coreGeometry, coreMaterial);
|
||||||
coreMesh.position.set(0, -height * 0.7, 0);
|
// Z轴开模:B板放在分型面以下
|
||||||
|
coreMesh.position.set(0, 0, -halfHeight / 2 - 5);
|
||||||
scene.add(coreMesh);
|
scene.add(coreMesh);
|
||||||
|
|
||||||
const coreWireframe = new THREE.WireframeGeometry(coreGeometry);
|
const coreWireframe = new THREE.WireframeGeometry(coreGeometry);
|
||||||
@@ -495,6 +502,97 @@ class HTMLGenerator:
|
|||||||
pointcloudMesh.visible = pointcloudVisible;
|
pointcloudMesh.visible = pointcloudVisible;
|
||||||
}}
|
}}
|
||||||
}}
|
}}
|
||||||
|
|
||||||
|
// ─── 分模拆分动画 ───
|
||||||
|
let isSplit = false;
|
||||||
|
let splitAnimId = null;
|
||||||
|
|
||||||
|
// 根据材料类型确定分模方向
|
||||||
|
function getPartingDirection() {{
|
||||||
|
// 优先使用后端传递的 parting_direction
|
||||||
|
if (cavityData?.metadata?.parting_direction) {{
|
||||||
|
return cavityData.metadata.parting_direction;
|
||||||
|
}}
|
||||||
|
if (cavityData?.manufacturing_info?.parting_direction) {{
|
||||||
|
return cavityData.manufacturing_info.parting_direction;
|
||||||
|
}}
|
||||||
|
// 泡沫材料默认 Z 轴
|
||||||
|
if (cavityData?.metadata?.is_foam) {{
|
||||||
|
return 'Z';
|
||||||
|
}}
|
||||||
|
// 默认 Z 轴
|
||||||
|
return 'Z';
|
||||||
|
}}
|
||||||
|
|
||||||
|
function splitMold() {{
|
||||||
|
if (!cavityMesh && !coreMesh) return;
|
||||||
|
isSplit = !isSplit;
|
||||||
|
const btn = document.getElementById('splitBtn');
|
||||||
|
btn.textContent = isSplit ? '合模' : '分模拆分';
|
||||||
|
|
||||||
|
const bboxDims = geometryData.bounding_box?.dimensions || [100, 100, 100];
|
||||||
|
const dir = getPartingDirection();
|
||||||
|
|
||||||
|
// 根据分模方向确定拆分轴和距离
|
||||||
|
let splitDist, axis;
|
||||||
|
if (dir === 'Z') {{
|
||||||
|
// Z轴上下开模:拆分距离取 Z 方向高度的 40%
|
||||||
|
splitDist = bboxDims[2] * 0.4;
|
||||||
|
axis = 'z';
|
||||||
|
}} else if (dir === 'Y') {{
|
||||||
|
// Y轴前后开模
|
||||||
|
splitDist = bboxDims[1] * 0.4;
|
||||||
|
axis = 'y';
|
||||||
|
}} else {{
|
||||||
|
// X轴左右开模
|
||||||
|
splitDist = bboxDims[0] * 0.4;
|
||||||
|
axis = 'x';
|
||||||
|
}}
|
||||||
|
|
||||||
|
// 分型面动画目标透明度
|
||||||
|
const partingTargetOpacity = isSplit ? 0 : 0.3;
|
||||||
|
|
||||||
|
// 记录起始位置
|
||||||
|
const cavityStart = cavityMesh ? cavityMesh.position[axis] : 0;
|
||||||
|
const coreStart = coreMesh ? coreMesh.position[axis] : 0;
|
||||||
|
const partingStartOpacity = partingMesh ? partingMesh.material.opacity : 0.3;
|
||||||
|
|
||||||
|
// 目标位置:型腔正向移动,型芯负向移动
|
||||||
|
const cavityTarget = isSplit ? splitDist : 0;
|
||||||
|
const coreTarget = isSplit ? -splitDist : 0;
|
||||||
|
|
||||||
|
const duration = 800; // ms
|
||||||
|
const startTime = performance.now();
|
||||||
|
|
||||||
|
if (splitAnimId) cancelAnimationFrame(splitAnimId);
|
||||||
|
|
||||||
|
function animateSplit(now) {{
|
||||||
|
const elapsed = now - startTime;
|
||||||
|
const t = Math.min(elapsed / duration, 1);
|
||||||
|
// 缓动函数 (easeInOutCubic)
|
||||||
|
const ease = t < 0.5 ? 4 * t * t * t : 1 - Math.pow(-2 * t + 2, 3) / 2;
|
||||||
|
|
||||||
|
if (cavityMesh) {{
|
||||||
|
cavityMesh.position[axis] = cavityStart + (cavityTarget - cavityStart) * ease;
|
||||||
|
}}
|
||||||
|
if (coreMesh) {{
|
||||||
|
coreMesh.position[axis] = coreStart + (coreTarget - coreStart) * ease;
|
||||||
|
}}
|
||||||
|
if (partingMesh) {{
|
||||||
|
partingMesh.material.opacity = partingStartOpacity + (partingTargetOpacity - partingStartOpacity) * ease;
|
||||||
|
if (isSplit && t >= 1) partingMesh.visible = false;
|
||||||
|
else partingMesh.visible = true;
|
||||||
|
}}
|
||||||
|
|
||||||
|
if (t < 1) {{
|
||||||
|
splitAnimId = requestAnimationFrame(animateSplit);
|
||||||
|
}} else {{
|
||||||
|
splitAnimId = null;
|
||||||
|
}}
|
||||||
|
}}
|
||||||
|
|
||||||
|
splitAnimId = requestAnimationFrame(animateSplit);
|
||||||
|
}}
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -1,66 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
# MoldInsight 启动脚本 - 修复版
|
|
||||||
# 适用于Linux conda环境
|
|
||||||
|
|
||||||
echo "🚀 启动 MoldInsight 模具几何分析系统..."
|
|
||||||
|
|
||||||
# 检查Python版本
|
|
||||||
python_version=$(python3 -c 'import sys; print(".".join(map(str, sys.version_info[:2])))')
|
|
||||||
echo "📋 Python版本: $python_version"
|
|
||||||
|
|
||||||
# 初始化conda环境
|
|
||||||
echo "🔧 初始化conda环境..."
|
|
||||||
source /opt/anaconda3/etc/profile.d/conda.sh
|
|
||||||
|
|
||||||
# 激活conda环境
|
|
||||||
echo "🔧 激活conda环境..."
|
|
||||||
conda activate moldinsight
|
|
||||||
|
|
||||||
# 验证PythonOCC是否可用
|
|
||||||
echo "🔍 验证PythonOCC..."
|
|
||||||
python3 -c "import OCC; print('✅ PythonOCC可用')" || {
|
|
||||||
echo "❌ PythonOCC不可用,请先安装PythonOCC"
|
|
||||||
exit 1
|
|
||||||
}
|
|
||||||
|
|
||||||
# 检查是否已经安装依赖
|
|
||||||
echo "📦 检查依赖包..."
|
|
||||||
pip install -r requirements.txt
|
|
||||||
|
|
||||||
# 创建必要目录
|
|
||||||
echo "📁 创建必要目录..."
|
|
||||||
mkdir -p uploads html_output logs
|
|
||||||
|
|
||||||
# 检查环境配置文件
|
|
||||||
if [ ! -f ".env" ]; then
|
|
||||||
echo "❌ 错误: 未找到.env配置文件"
|
|
||||||
echo "📋 请创建.env文件并配置数据库连接信息:"
|
|
||||||
echo " 1. 创建.env文件: touch .env"
|
|
||||||
echo " 2. 编辑配置文件: nano .env"
|
|
||||||
echo " 3. 添加数据库配置:"
|
|
||||||
echo " DATABASE_URL=postgresql+asyncpg://username:password@localhost:5432/database_name"
|
|
||||||
echo ""
|
|
||||||
echo "💡 提示: 请根据实际的PostgreSQL连接信息修改上述配置"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo "🔧 检查数据库连接..."
|
|
||||||
|
|
||||||
# 启动服务
|
|
||||||
echo "🚀 启动 MoldInsight 服务..."
|
|
||||||
PORT=$(grep '^PORT=' .env 2>/dev/null | cut -d'=' -f2 || echo '8000')
|
|
||||||
echo "🌐 服务将在 http://localhost:${PORT} 启动"
|
|
||||||
echo "📊 功能特性:"
|
|
||||||
echo " - STP文件解析和几何分析"
|
|
||||||
echo " - JSON数据导出"
|
|
||||||
echo " - PostgreSQL数据库存储"
|
|
||||||
echo " - 3D可视化HTML生成"
|
|
||||||
echo " - Web界面文件上传"
|
|
||||||
echo " - 任务状态跟踪"
|
|
||||||
echo ""
|
|
||||||
echo "按 Ctrl+C 停止服务"
|
|
||||||
echo ""
|
|
||||||
|
|
||||||
# 启动应用
|
|
||||||
python3 src/main.py
|
|
||||||
Reference in New Issue
Block a user