本文涉及知识点
拐点类型(JoinType)
白色原图;红色尖角(斜接),延长到交点。黄色,圆角,用圆弧过渡,就是通常说的倒圆角。绿色,方角(Square),下面解释。斜切,用直线线连接两个端点。


斜接
白色矩形各边偏移300后,形成白色四条线段。红线是斜接方式偏移矩形。

圆角
红色是圆角方式偏移矩形。

方角
红色是直角方式偏移矩形。先延长线段,再用直线段连接。


斜切
红色是以斜切方式偏移矩形。

miterLimit
斜接如果造成的尖锐的角,超过miterLimit的限制,则转成直角方式。当尖角长度超过 miterLimit × delta 时,转换规则。

首位端点类型
平头方头圆头


白线原图,青色线段平头,绿色折线方头,黄色半圆圆头。
多边形

连接
结果是带空洞的多边形。

代码
csharp
[CommandMethod("QSMInflatePaths")]
public void InflatePaths()
{
CPLineSelInfo selInfo = new CPLineSelInfo();
CSelEntity sel = new CSelEntity() { m_messageForAdd = "可以选择多个多义线,包括自交多边形。填充方式非零。" };
List<ObjectId> ids = sel.Sel(selInfo);
if (0 == ids.Count) { return; }
var edit = Application.DocumentManager.MdiActiveDocument.Editor;
PromptDoubleOptions pdo = new PromptDoubleOptions("请输入需要偏移的距离,非零实数") { DefaultValue = 10 };
var pdr = edit.GetDouble(pdo);
if (pdr.Status != PromptStatus.OK) { return; }
JoinType jt = JoinType.Miter;
{
PromptKeywordOptions pko = new PromptKeywordOptions(
"\n拐点类型JoinType。"
);
pko.Keywords.Add("Miter", "M", "尖角(斜接)(M)");
pko.Keywords.Add("Round", "R", "圆角(R)");
pko.Keywords.Add("Square", "S", "方角(S)");
pko.Keywords.Add("Bevel", "B", "斜切(B)");
pko.Keywords.Default = "Miter";
PromptResult pr = edit.GetKeywords(pko);
if (pr.Status == PromptStatus.Cancel) { return; }
if (pr.StringResult == "Round")
{
jt = JoinType.Round;
}
else if (pr.StringResult == "Square")
{
jt = JoinType.Square;
}
else if (pr.StringResult == "Bevel")
{
jt = JoinType.Bevel;
}
}
EndType et = EndType.Polygon;
{
PromptKeywordOptions pko = new PromptKeywordOptions("\n首尾端点类型EndType。");
pko.Keywords.Add("Polygon", "P", "多边形(M)");
pko.Keywords.Add("Butt", "B", "平头(B)");
pko.Keywords.Add("Square", "S", "方头(S)");
pko.Keywords.Add("Round", "R", "圆头(R)");
pko.Keywords.Add("Joined", "J", "连接(J)");
pko.Keywords.Default = "Polygon";
PromptResult pr = edit.GetKeywords(pko);
if (pr.Status == PromptStatus.Cancel) { return; }
if (pr.StringResult == "Joined")
{
et = EndType.Joined;
}
else if (pr.StringResult == "Butt")
{
et = EndType.Butt;
}
else if (pr.StringResult == "Square")
{
et = EndType.Square;
}
else if (pr.StringResult == "Round")
{
et = EndType.Round;
}
}
PathsD ps = new PathsD();
using (var tr = CadBase.GetDefaultDatabase().TransactionManager.StartTransaction())
{
foreach (var id in ids)
{
var pl = tr.GetObject(id, OpenMode.ForWrite) as Polyline;
if (null == pl) { continue; }
var path = pl.PolylineToPath();
ps.Add(path);
pl.SetEndWidth10();
}
tr.Commit();
}
ps = Clipper.Union(ps, FillRule.NonZero);//通过并集避免自相交
double miterLimit = 4;
var sol= Clipper.InflatePaths(ps, pdr.Value, jt, et);
var rect = Clipper.GetBounds(sol);
// sol = Clipper.TranslatePaths(sol, (long)(rect.Width * 1.2 + 0.5), 0);
ShowPaths(sol);
}
演示视频及工具下载
演示工具基于Cad,支持Cad2013及更高版本。
亲士库版本:2026.9.4
Cliper库版本:2.0.0.0
如果不会操作,请看视频:https://edu.csdn.net/course/detail/41418

扩展阅读
| 计算几何为骨,排样优化为魂 |
|---|
| 作品:亲士CAD工具箱 |
| 经典文章推荐:二维排样 |
| 万物皆数学 |
| 查阅鄙人的博文,请点击博文下载学院导航 |
| 活到老,学到老。明朝中后期,大约50%的进士能当上堂官(副部及更高);能当上堂官的举人只有十余人。 |
| 子墨子言之:事无终始,无务多业。也就是我们常说的专业的人做专业的事。 |
测试环境
操作系统:win7 开发环境: VS2019 C++17
或者 操作系统:win10 开发环境: VS2022 C++17
如无特殊说明,本算法用**C++**实现。
