你提供的数据是 **Genesis 中 `surface` 类型图形的原始描述格式(`#OB`, `#OS`, `#OC`, `#OE`)**,我们需要从中解析出几何路径,并区分:
- `#OS x y`:直线段到点 `(x, y)`
- `#OC x_end y_end cx cy Y`:圆弧,终点为 `(x_end, y_end)`,圆心为 `(cx, cy)`,方向由上下文判断(Y 表示圆弧)
---
### ✅ 目标
修改原有代码逻辑,支持处理包含 **直线 + 圆弧混合路径** 的 `surface` 特征,实现:
1. 遇到 `#OS` → 画直线
2. 遇到 `#OC ... Y` → 解析圆弧并调用 `arc_to_polyline` 分段绘制
---
## ✅ 改进后的完整类(含 surface 处理)
```python
class DrawSurfacePolyline:
def __init__(self):
self.JOB = os.environ.get('JOB', None)
self.STEP = os.environ.get('STEP', None)
INCAM_DEBUG = os.getenv('INCAM_DEBUG', None)
if INCAM_DEBUG == 'yes':
self.incam = Gateway()
self.JOB = self.incam.job_name
self.STEP = self.incam.step_name
self.pid = self.incam.pid
else:
self.incam = InCAM()
self.pid = os.getpid()
self.ico = ICO(incam=self.incam)
self.icNet = ICNET(incam=self.incam)
# 输出层
self.output_layer = "_surf_as_poly"
if not self.ico.IsLayerExist(self.JOB, self.STEP, self.output_layer):
self.ico.CreateLayer(job=self.JOB, step=self.STEP, layer=self.output_layer, layer_type="conductor")
def arc_to_polyline(self, xs, ys, xe, ye, xc, yc, direction='ccw', angle_step=5):
"""
根据起点、终点、圆心生成折线拟合圆弧
注意:direction 需要根据 Genesis 规则推断(通常从移动趋势判断)
"""
radius = math.hypot(xs - xc, ys - yc)
start_angle = math.atan2(ys - yc, xs - xc)
end_angle = math.atan2(ye - yc, xe - xc)
# 推测方向(基于角度差最小原则不成立时需结合实际)
diff = (end_angle - start_angle) % (2 * math.pi)
if diff < math.pi: # 小于180°可能是 ccw
direction = 'ccw'
else:
direction = 'cw'
if direction == 'cw':
if end_angle > start_angle:
end_angle -= 2 * math.pi
else: # ccw
if end_angle < start_angle:
end_angle += 2 * math.pi
total_angle = abs(end_angle - start_angle)
num_segments = max(1, int(total_angle / math.radians(angle_step)))
step_angle = total_angle / num_segments
points = []
for i in range(num_segments + 1):
t = i / num_segments
angle = start_angle + t * (end_angle - start_angle)
x = xc + radius * math.cos(angle)
y = yc + radius * math.sin(angle)
points.append((round(x, 4), round(y, 4)))
return points
def parse_surface_commands(self, orig_lines):
"""
解析 surface 的 orig 字段命令流
返回路径点列表,每项为 {'type': 'line', 'p1':(x1,y1), 'p2':(x2,y2)} 或
{'type': 'arc', 'start':(sx,sy), 'end':(ex,ey), 'center':(cx,cy)}
"""
path = []
current_point = None
prev_point = None
for line in orig_lines:
line = line.strip()
if not line or line.startswith('#S') or line.startswith('#OE'):
continue
parts = line.split()
if line.startswith('#OB'): # 起始点
coords = list(map(float, parts[1:3]))
current_point = tuple(coords)
prev_point = current_point
elif line.startswith('#OS'): # 直线段
coords = list(map(float, parts[1:3]))
next_point = tuple(coords)
if prev_point:
path.append({
'type': 'line',
'p1': prev_point,
'p2': next_point
})
prev_point = next_point
elif '#OC' in line and line.endswith('Y'): # 圆弧
data = parts[1:]
# 格式: x_end y_end cx cy Y
xe, ye, cx, cy = map(float, data[:4])
xs, ys = prev_point # 弧的起点是上一个位置
path.append({
'type': 'arc',
'start': (xs, ys),
'end': (xe, ye),
'center': (cx, cy)
})
prev_point = (xe, ye)
return path
def draw_path(self, path, angle_step=5):
"""根据解析后的路径进行绘制"""
for seg in path:
if seg['type'] == 'line':
p1, p2 = seg['p1'], seg['p2']
self.ico.AddLine(xs=p1[0], ys=p1[1], xe=p2[0], ye=p2[1])
elif seg['type'] == 'arc':
xs, ys = seg['start']
xe, ye = seg['end']
xc, yc = seg['center']
# 判断方向(近似)
dx1, dy1 = xs - xc, ys - yc
dx2, dy2 = xe - yc, ye - yc
cross_z = (dx1 * dy2 - dy1 * dx2)
direction = 'cw' if cross_z > 0 else 'ccw'
# 调用已有函数生成多段线
points = self.arc_to_polyline(
xs=xs, ys=ys,
xe=xe, ye=ye,
xc=xc, yc=yc,
direction=direction,
angle_step=angle_step
)
# 绘制所有子线段
for i in range(len(points) - 1):
p1, p2 = points[i], points[i + 1]
self.ico.AddLine(xs=p1[0], ys=p1[1], xe=p2[0], ye=p2[1])
def get_surface_features(self):
"""获取所有 surface 类型特征"""
job = self.JOB
step_list = self.ico.GetStepList()
layer_list = self.ico.GetLayerList()
surfaces = []
for step in step_list:
for layer in layer_list:
features = self.ico.GetFeaturesPro(job, step, layer)
for f in features:
if f.get('type') == 'surface':
surfaces.append({
'step': step,
'layer': layer,
'feature': f
})
return surfaces
def process_surfaces(self, angle_step=5):
"""主处理流程"""
surf_list = self.get_surface_features()
processed_count = 0
for item in surf_list:
step = item['step']
layer = item['layer']
feature = item['feature']
# 设置当前绘图上下文
self.ico.SetCurJob(self.JOB)
self.ico.SetCurStep(step)
self.ico.SetCurLayer(self.output_layer)
# 解析原始命令
orig_lines = feature.get('orig', [])
if not orig_lines:
continue
path = self.parse_surface_commands(orig_lines)
self.draw_path(path, angle_step=angle_step)
processed_count += 1
print(f"✅ 共处理 {processed_count} 个 surface,已转换为折线并绘制至层 '{self.output_layer}'")
```
---
### ✅ 使用方式
```python
if __name__ == '__main__':
try:
drawer = DrawSurfacePolyline()
drawer.process_surfaces(angle_step=3) # 每3度分割一次圆弧
print("🎉 所有 surface 已成功拟合为折线!")
except Exception as e:
print(f"❌ 错误: {str(e)}")
import traceback
traceback.print_exc()
```
---
### 🔍 示例输入分析
#### 示例 1:纯矩形 surface(只有 `#OS`)
```python
'#OB 8.0449075 24.973565 I'
'#OS 8.0449075 29.786695'
'#OS 16.6308125 29.786695'
'#OS 16.6308125 24.973565'
'#OS 8.0449075 24.973565'
'#OE'
```
→ 被解析为 4 条直线,直接用 `AddLine` 绘制。
#### 示例 2:含圆弧 surface(`#OC ... Y`)
```python
'#OC 5.319965 31.098685 4.35734 27.7812225 Y'
```
→ 上一点是 `(5.319965, 24.46376)` → 弧起点
→ 当前终点 `(5.319965, 31.098685)`,圆心 `(4.35734, 27.7812225)`
→ 自动计算方向并生成多段折线
---
### ✅ 优势与改进点总结
| 功能 | 是否支持 |
|------|----------|
| 解析 `#OB`, `#OS`, `#OC Y` 命令 | ✅ |
| 区分直线与圆弧 | ✅ |
| 圆弧自动方向判断 | ✅(通过叉积估算) |
| 折线精度可调(angle_step) | ✅ |
| 输出到独立 layer | ✅ |
| 支持跨象限圆弧 | ✅(使用 atan2) |
---
###