【pyclipper+增材CAM】轮廓偏置

在增材打印CAM中,我们需要在切片得到的每层轮廓中规划生成打印路径。传统的三轴3D打印的常见填充方式有:轮廓平行填充方向平行填充。其中轮廓平行填充主要是通过轮廓偏置实现的。

pyclipper安装使用

Python下安装pyclipper库,命令行输入pip指令:

1
pip install pyclipper

通过 import pyclipper 导入使用。

pyclipper基础

pyclipper是Python环境下的Clipper库,主要用于平面闭合多边形或非闭合多线段的裁剪(clipping)和偏置(offsetting)。

重要术语:

  • 裁剪(Clipping): 指二维平面图形之间的四个布尔操作:交集(intersection)、并(union)、差(difference )和异或(exclusive-or))中的任何一个。

  • 路径(Path): 是一个有序的顶点集合,它定义一个单一的几何轮廓(contour),要么是一条线(一个开放的路径),要么是一个多边形(一个闭合的轮廓)。

  • 直线(Line): 或者多线段(polyline) 是一个包含两个或多个顶点的开放路径。

  • 多边形(Polygon): 通常是指一个二维的区域,其边界是一个外部不相交的闭合轮廓。

  • 轮廓(Contour): 同路径(path)。

  • 孔(Hole): 是一个多边形中不属于多边形的封闭区域。一个“孔多边形”是一个封闭的路径。

  • 多边形填充规则(Polygon Filling Rule): 填充规则,定义了平面封闭区域中的内部区域(即需要填充的区域)和外部的区域(即“孔”,不需要填充的区域)。

需要掌握的Clipper基础:

代码实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
import math
import vtk
from pyclipper import *

def numeric_scaling(digits: 'int > 0' = 7, *, pos: list):
def decorate(func):
def scaled(*_args):
__args = list(_args)
f = math.pow(10, digits) # 数值精度,默认为7位小数
for p in pos:
if isinstance(_args[p], int) or isinstance(_args[p], float):
__args[p] *= f
elif isinstance(_args[p], list):
__args[p] = [[tuple(map(lambda x: x * f, pt)) for pt in path] for path in _args[p]]
else:
pass
_result = func(*tuple(__args)) # _result is list of paths
_result = [[tuple(map(lambda x: x / f, pt)) for pt in path] for path in _result]
return _result

return scaled

return decorate


@numeric_scaling(digits = 7, pos = [0, 1])
def offset(polys, delta, jt = JT_SQUARE): # 偏置函数,输人多边形:[[[pt1_x,pt2_y],...,[ptN_x,ptN_y]],[...],...]
pco = PyclipperOffset()
pco.AddPaths(polys, jt, ET_CLOSEDPOLYGON)
sln = pco.Execute(delta) # 偏置距离delta
return sln # 返回偏置曲线

# 轮廓平行路径填充
def genCpPath_clipper(boundaries, interval, shellThk): # 输人:轮廓、偏置距离、填充带宽
offsetPolyses = [] # 偏置曲线列表
delta = interval / 2 # 首次偏置距离
polys = offset(boundaries, -delta, JT_SQUARE)
offsetPolyses.append(polys) # 偏置曲线存放在offsetPolys中
while math.fabs(delta) < shellThk: # 循环直至偏置距离大于填充带宽
delta += interval
polys = offset(boundaries, -delta, JT_SQUARE)
if polys is None or len(polys) == 0:
break # 已到偏置区域中心,则退出
offsetPolyses.append(polys)
return offsetPolyses

按理来讲装饰器定义和调用应该分开来,这里为了方便所以写在一个文件中。

测试结果

偏置轮廓填充结果如下图所示,其中黑色为切片得到的轮廓,红色为偏置填充的路径。

image-20221219150924658

第24层偏置填充结果:

image-20221219151007271

第27层偏置填充结果:

image-20221219151126533