mirror of
https://github.com/deepmodeling/Uni-Lab-OS
synced 2026-05-23 14:49:55 +00:00
Replace scipy differential_evolution with custom DE loop for per-device crossover, circular θ wrapping, and configurable mutation strategy (currenttobest1bin default, best1bin as turbo mode). Key improvements: - Graduate ALL hard constraints during DE (proportional penalty instead of flat inf), giving DE smooth gradient for reachability, min_spacing, etc. Binary inf preserved for final pass/fail reporting. - 2-axis sweep-and-prune AABB broad phase for collision pair pruning - Multi-seed injection from multiple seeder presets + Gaussian variants - snap_theta_safe: collision-check after angle snapping, revert on violation - Weight normalization (100 distance / 60 angle / 5× hard multiplier) - Constraint priority field (critical/high/normal/low → weight multiplier) with LLM intent interpreter setting priority per constraint type - Final success field now checks user hard constraints in binary mode - arm_slider added to mock checker reach table (1.07m) Tests: 202 passed, 24 new tests added (optimizer 7, constraints 6, broad_phase 11) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
98 lines
2.6 KiB
Python
98 lines
2.6 KiB
Python
"""数据模型定义:Device, Lab, Placement, Constraint 及 API 请求/响应。"""
|
||
|
||
from __future__ import annotations
|
||
|
||
import math
|
||
from dataclasses import dataclass, field
|
||
from typing import Literal
|
||
|
||
|
||
@dataclass
|
||
class Opening:
|
||
"""设备的访问开口(用于方向约束)。"""
|
||
|
||
# 设备局部坐标系中的方向单位向量,如 (0, -1) = 正前方
|
||
direction: tuple[float, float] = (0.0, -1.0)
|
||
label: str = ""
|
||
|
||
|
||
@dataclass
|
||
class Device:
|
||
"""设备描述。"""
|
||
|
||
id: str
|
||
name: str
|
||
# 碰撞包围盒 (width along X, depth along Y),单位:米
|
||
bbox: tuple[float, float] = (0.6, 0.4)
|
||
device_type: Literal["static", "articulation", "rigid"] = "static"
|
||
# 以下为可选扩展字段(向后兼容)
|
||
height: float = 0.4
|
||
origin_offset: tuple[float, float] = (0.0, 0.0)
|
||
openings: list[Opening] = field(default_factory=list)
|
||
source: Literal["registry", "assets", "manual"] = "manual"
|
||
model_path: str = ""
|
||
model_type: str = ""
|
||
thumbnail_url: str = ""
|
||
|
||
|
||
@dataclass
|
||
class Obstacle:
|
||
"""实验室内固定障碍物(矩形)。"""
|
||
|
||
x: float
|
||
y: float
|
||
width: float
|
||
depth: float
|
||
|
||
|
||
@dataclass
|
||
class Lab:
|
||
"""实验室平面图。"""
|
||
|
||
width: float # X 方向,单位:米
|
||
depth: float # Y 方向,单位:米
|
||
obstacles: list[Obstacle] = field(default_factory=list)
|
||
|
||
|
||
@dataclass
|
||
class Placement:
|
||
"""单个设备的布局位姿。"""
|
||
|
||
device_id: str
|
||
x: float
|
||
y: float
|
||
theta: float # 旋转角,弧度
|
||
uuid: str = "" # 前端分配的唯一标识,透传不生成
|
||
|
||
def rotated_bbox(self, device: Device) -> tuple[float, float]:
|
||
"""返回旋转后的 AABB 尺寸 (half_w, half_h)。"""
|
||
w, d = device.bbox
|
||
cos_t = abs(math.cos(self.theta))
|
||
sin_t = abs(math.sin(self.theta))
|
||
half_w = (w * cos_t + d * sin_t) / 2
|
||
half_h = (w * sin_t + d * cos_t) / 2
|
||
return half_w, half_h
|
||
|
||
|
||
@dataclass
|
||
class Constraint:
|
||
"""约束规则。"""
|
||
|
||
type: Literal["hard", "soft"]
|
||
rule_name: str
|
||
# 规则参数,含义因 rule_name 而异
|
||
params: dict = field(default_factory=dict)
|
||
# 仅 soft 约束使用
|
||
weight: float = 1.0
|
||
# 优先级等级,影响有效权重的乘数
|
||
priority: str | None = None # "critical" | "high" | "normal" | "low"
|
||
|
||
|
||
@dataclass
|
||
class Intent:
|
||
"""LLM 可生成的语义化意图,由 interpreter 翻译为 Constraint 列表。"""
|
||
|
||
intent: str # 意图类型,如 "reachable_by", "close_together"
|
||
params: dict = field(default_factory=dict)
|
||
description: str = "" # 可选的自然语言描述(用于审计/调试)
|