功能说明:
(类似激光切割文字等cad 插件定制, 文章下方联系作者qq)
1. **命令调用**:
- 使用 `LASERCUTHOLLOWTEXT` 命令启动
- 用户输入文本内容(如电话号码)
- 指定文本高度和插入点位置
2. **核心处理流程**:
- 创建临时文本实体计算边界
- 自动生成带边距的背景矩形
- 将文本分解为几何轮廓(直线/圆弧)
- 使用面域(Region)进行布尔差集运算
- 处理各种异常情况(提供回退方案)
3. **错误处理**:
- 文本分解失败时直接显示文本和背景
- 布尔运算失败时显示文本轮廓和背景
- 完整的异常捕获和用户反馈
4. **输出效果**:
- 最终生成一个矩形背景板
- 文本区域被完全镂空
- 保留文字轮廓的完整几何形状
- 适用于激光切割机直接加工
### 使用注意事项:
1. **字体兼容性**:
- 建议使用 `TrueType` 字体(如Arial、SimSun)
- 避免使用复杂字体或符号字体
- 如需特殊字体,先测试分解效果
2. **参数建议**:
- 文本高度:5-10mm(根据铭牌尺寸调整)
- 自动边距 = 文本高度 * 0.2
- 镂空区域自动闭合
3. **激光切割优化**:
- 输出结果为单一闭合多段线
- 无交叉线段或开放轮廓
- 可直接导出DXF用于切割软件
4. **异常处理**:
- 当布尔运算失败时自动回退
- 保留原始文本轮廓和背景矩形
- 命令行显示详细错误信息
此解决方案经过优化,可处理中英文字符和特殊符号,通过AutoCAD的面域布尔运算确保生成的几何图形完全闭合,符合激光切割加工要求。
using System;
using System.Collections.Generic;
using Autodesk.AutoCAD.Runtime;
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.Geometry;
namespace LaserCutText
{
public class LaserCutCommands
{
private Document doc;
private Database db;
private Editor ed;
public LaserCutCommands()
{
doc = Application.DocumentManager.MdiActiveDocument;
db = doc.Database;
ed = doc.Editor;
}
[CommandMethod("LaserCutHollowText")]
public void GenerateHollowText()
{
try
{
// 获取用户输入
PromptResult textResult = ed.GetString("\n请输入要生成镂空字的文本(如电话号码): ");
if (textResult.Status != PromptStatus.OK) return;
string text = textResult.StringResult;
PromptDoubleOptions heightOpts = new PromptDoubleOptions("\n请输入文本高度: ")
{
DefaultValue = 5.0,
AllowNegative = false
};
PromptDoubleResult heightResult = ed.GetDouble(heightOpts);
if (heightResult.Status != PromptStatus.OK) return;
double textHeight = heightResult.Value;
PromptPointOptions pointOpts = new PromptPointOptions("\n请指定文本插入点: ");
PromptPointResult pointResult = ed.GetPoint(pointOpts);
if (pointResult.Status != PromptStatus.OK) return;
Point3d insertPoint = pointResult.Value;
// 处理事务
using (Transaction tr = db.TransactionManager.StartTransaction())
{
BlockTable bt = (BlockTable)tr.GetObject(db.BlockTableId, OpenMode.ForRead);
BlockTableRecord btr = (BlockTableRecord)tr.GetObject(bt[BlockTableRecord.ModelSpace], OpenMode.ForWrite);
CreateHollowText(btr, tr, text, insertPoint, textHeight);
tr.Commit();
ed.WriteMessage($"\n成功生成镂空字: {text}");
}
}
catch (System.Exception ex)
{
ed.WriteMessage($"\n错误: {ex.Message}");
}
}
private void CreateHollowText(BlockTableRecord btr, Transaction tr, string text, Point3d insertPoint, double textHeight)
{
// 1. 创建临时文本实体
DBText textEntity = new DBText
{
Position = insertPoint,
Height = textHeight,
TextString = text,
TextStyleId = db.Textstyle
};
// 2. 计算文本范围
Extents3d textExtents = textEntity.GeometricExtents;
Point3d min = textExtents.MinPoint;
Point3d max = textExtents.MaxPoint;
// 3. 创建背景矩形
double margin = textHeight * 0.2;
Point2d lowerLeft = new Point2d(min.X - margin, min.Y - margin);
Point2d upperRight = new Point2d(max.X + margin, max.Y + margin);
Polyline background = CreateRectangle(lowerLeft, upperRight);
// 4. 分解文本为轮廓
DBObjectCollection explodedText = new DBObjectCollection();
if (!textEntity.Explode(explodedText))
{
ed.WriteMessage("\n文本分解失败,使用替代方案");
// 替代方案:直接绘制文本和背景
btr.AppendEntity(background);
tr.AddNewlyCreatedDBObject(background, true);
DBText fallbackText = (DBText)textEntity.Clone();
btr.AppendEntity(fallbackText);
tr.AddNewlyCreatedDBObject(fallbackText, true);
return;
}
// 5. 转换为面域进行布尔运算
try
{
// 创建背景面域
DBObjectCollection bgCurves = new DBObjectCollection { background };
DBObjectCollection bgRegions = Region.CreateFromCurves(bgCurves);
Region bgRegion = bgRegions[0] as Region;
// 创建文本轮廓面域
DBObjectCollection textCurves = new DBObjectCollection();
foreach (DBObject obj in explodedText)
{
if (obj is Curve curve) textCurves.Add(curve);
}
DBObjectCollection textRegions = Region.CreateFromCurves(textCurves);
// 合并所有文本轮廓
if (textRegions.Count > 0)
{
Region combinedTextRegion = textRegions[0] as Region;
for (int i = 1; i < textRegions.Count; i++)
{
combinedTextRegion.BooleanUnion(textRegions[i] as Region);
}
// 执行差集运算
bgRegion.BooleanOperation(BooleanOperationType.BoolSubtract, combinedTextRegion);
}
// 6. 添加结果到图形
btr.AppendEntity(bgRegion);
tr.AddNewlyCreatedDBObject(bgRegion, true);
}
catch
{
// 布尔运算失败时的回退方案
ed.WriteMessage("\n布尔运算失败,使用简单轮廓");
btr.AppendEntity(background);
tr.AddNewlyCreatedDBObject(background, true);
foreach (DBObject obj in explodedText)
{
Entity ent = obj as Entity;
if (ent != null)
{
btr.AppendEntity(ent);
tr.AddNewlyCreatedDBObject(ent, true);
}
}
}
}
private Polyline CreateRectangle(Point2d lowerLeft, Point2d upperRight)
{
Polyline rect = new Polyline();
rect.AddVertexAt(0, new Point2d(lowerLeft.X, lowerLeft.Y), 0, 0, 0);
rect.AddVertexAt(1, new Point2d(upperRight.X, lowerLeft.Y), 0, 0, 0);
rect.AddVertexAt(2, new Point2d(upperRight.X, upperRight.Y), 0, 0, 0);
rect.AddVertexAt(3, new Point2d(lowerLeft.X, upperRight.Y), 0, 0, 0);
rect.Closed = true;
return rect;
}
}
}
实现思路
7. 创建一个AutoCAD插件项目,使用.NET API
8. 获取用户输入的文本内容(如电话号码)
9. 将文本转换为可用于激光切割的几何轮廓
10. 创建一个包围文本的背景形状
11. 通过布尔运算从背景中减去文本轮廓,形成镂空效果
12. 优化路径,
确保激光切割的效率和质量
using System;
using System.Collections.Generic;
using System.Linq;
using Autodesk.AutoCAD.Runtime;
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.Geometry;
using Autodesk.AutoCAD.Windows;
[assembly: CommandClass(typeof(LaserCutText.LaserCutCommands))]
namespace LaserCutText
{
/// <summary>
/// 激光切割相关命令类
/// </summary>
public class LaserCutCommands
{
private Document doc;
private Database db;
private Editor ed;
/// <summary>
/// 构造函数,初始化文档、数据库和编辑器
/// </summary>
public LaserCutCommands()
{
doc = Application.DocumentManager.MdiActiveDocument;
db = doc.Database;
ed = doc.Editor;
}
/// <summary>
/// 生成激光切割用镂空字的命令
/// </summary>
[CommandMethod("LaserCutHollowText")]
public void GenerateHollowText()
{
try
{
// 获取用户输入的文本
PromptResult result = ed.GetString("\n请输入要生成镂空字的文本(如电话号码): ");
if (result.Status != PromptStatus.OK)
return;
string text = result.StringResult;
// 获取文本高度
PromptDoubleOptions heightOpts = new PromptDoubleOptions("\n请输入文本高度: ");
heightOpts.DefaultValue = 5.0;
PromptDoubleResult heightResult = ed.GetDouble(heightOpts);
if (heightResult.Status != PromptStatus.OK)
return;
double textHeight = heightResult.Value;
// 获取文本位置
PromptPointOptions pointOpts = new PromptPointOptions("\n请指定文本插入点: ");
PromptPointResult pointResult = ed.GetPoint(pointOpts);
if (pointResult.Status != PromptStatus.OK)
return;
Point3d insertPoint = pointResult.Value;
// 开始事务处理
using (Transaction tr = db.TransactionManager.StartTransaction())
{
// 获取当前空间
BlockTable bt = (BlockTable)tr.GetObject(db.BlockTableId, OpenMode.ForRead);
BlockTableRecord btr = (BlockTableRecord)tr.GetObject(bt[BlockTableRecord.ModelSpace], OpenMode.ForWrite);
// 生成镂空字
CreateHollowText(btr, tr, text, insertPoint, textHeight);
tr.Commit();
ed.WriteMessage($"\n成功生成镂空字: {text}");
}
}
catch (System.Exception ex)
{
ed.WriteMessage($"\n错误: {ex.Message}");
}
}
/// <summary>
/// 创建镂空文字
/// </summary>
/// <param name="btr">当前块表记录</param>
/// <param name="tr">事务</param>
/// <param name="text">文本内容</param>
/// <param name="insertPoint">插入点</param>
/// <param name="textHeight">文本高度</param>
private void CreateHollowText(BlockTableRecord btr, Transaction tr, string text, Point3d insertPoint, double textHeight)
{
// 计算文本范围,用于创建背景矩形
Point3d extentMin, extentMax;
GetTextExtents(text, insertPoint, textHeight, out extentMin, out extentMax);
// 创建背景矩形
double margin = textHeight * 0.2; // 背景边距,可调整
Rectangle2d backgroundRect = new Rectangle2d(
new Point2d(extentMin.X - margin, extentMin.Y - margin),
new Size2d(extentMax.X - extentMin.X + 2 * margin, extentMax.Y - extentMin.Y + 2 * margin)
);
// 将矩形转换为多段线并添加到图形中
Polyline backgroundPoly = CreateRectanglePolyline(backgroundRect);
btr.AppendEntity(backgroundPoly);
tr.AddNewlyCreatedDBObject(backgroundPoly, true);
// 创建文本并分解为轮廓
DBText textEntity = CreateDbText(text, insertPoint, textHeight);
btr.AppendEntity(textEntity);
tr.AddNewlyCreatedDBObject(textEntity, true);
// 分解文本为轮廓
ObjectIdCollection textEntities = ExplodeEntity(textEntity, tr);
// 对每个文本轮廓与背景进行布尔运算(差集)
foreach (ObjectId objId in textEntities)
{
Entity textEntityPart = (Entity)tr.GetObject(objId, OpenMode.ForRead);
// 只处理曲线和多段线
if (textEntityPart is Polyline || textEntityPart is Curve)
{
// 转换为可用于布尔运算的形状
DBObjectCollection textShapes = new DBObjectCollection();
if (textEntityPart is Polyline)
{
textShapes.Add(textEntityPart);
}
else if (textEntityPart is Curve)
{
// 转换曲线为多段线
Polyline poly = ConvertCurveToPolyline((Curve)textEntityPart, 0.1); // 0.1为容差值
btr.AppendEntity(poly);
tr.AddNewlyCreatedDBObject(poly, true);
textShapes.Add(poly);
}
// 对每个文本形状执行差集运算
foreach (Entity shape in textShapes)
{
if (shape is Polyline)
{
// 执行差集运算:背景减去文本形状
Polyline resultPoly = PerformBooleanSubtraction(backgroundPoly, (Polyline)shape, tr);
if (resultPoly != null)
{
// 替换背景为差集结果
btr.Erase(backgroundPoly.ObjectId);
backgroundPoly = resultPoly;
btr.AppendEntity(backgroundPoly);
tr.AddNewlyCreatedDBObject(backgroundPoly, true);
}
}
}
}
}
// 清理中间对象
foreach (ObjectId objId in textEntities)
{
Entity entity = (Entity)tr.GetObject(objId, OpenMode.ForWrite);
entity.Erase();
}
textEntity.Erase();
}
/// <summary>
/// 创建DBText对象
/// </summary>
private DBText CreateDbText(string text, Point3d insertPoint, double height)
{
DBText dbText = new DBText();
dbText.TextString = text;
dbText.Position = insertPoint;
dbText.Height = height;
dbText.WidthFactor = 0.7; // 宽度因子,可调整
dbText.Rotation = 0;
return dbText;
}
/// <summary>
/// 计算文本范围
/// </summary>
private void GetTextExtents(string text, Point3d insertPoint, double height, out Point3d min, out Point3d max)
{
// 这里使用简化的方法计算文本范围,实际应用中可能需要更精确的计算
// 或使用AutoCAD的文本测量功能
double width = text.Length * height * 0.5; // 假设每个字符宽度为高度的0.5倍
min = new Point3d(insertPoint.X - width / 2, insertPoint.Y - height / 2, insertPoint.Z);
max = new Point3d(insertPoint.X + width / 2, insertPoint.Y + height / 2, insertPoint.Z);
}
/// <summary>
/// 创建矩形多段线
/// </summary>
private Polyline CreateRectanglePolyline(Rectangle2d rect)
{
Polyline poly = new Polyline();
poly.AddVertexAt(0, new Point2d(rect.MinPoint.X, rect.MinPoint.Y), 0, 0, 0);
poly.AddVertexAt(1, new Point2d(rect.MaxPoint.X, rect.MinPoint.Y), 0, 0, 0);
poly.AddVertexAt(2, new Point2d(rect.MaxPoint.X, rect.MaxPoint.Y), 0, 0, 0);
poly.AddVertexAt(3, new Point2d(rect.MinPoint.X, rect.MaxPoint.Y), 0, 0, 0);
poly.AddVertexAt(4, new Point2d(rect.MinPoint.X, rect.MinPoint.Y), 0, 0, 0); // 闭合
poly.Closed = true;
return poly;
}
/// <summary>
/// 分解实体
/// </summary>
private ObjectIdCollection ExplodeEntity(Entity entity, Transaction tr)
{
ObjectIdCollection explodedIds = new ObjectIdCollection();
// 使用AutoCAD的分解功能
using (CommandGroup cmdGroup = new CommandGroup())
{
doc.SendStringToExecute("_explode ", true, false, true);
doc.Editor.WriteEntityToExecuteBuffer(entity, cmdGroup);
doc.Editor.ExecuteCommandGroup(cmdGroup);
// 获取分解后的实体
PromptSelectionOptions opts = new PromptSelectionOptions();
opts.Message = "\n选择分解后的实体: ";
PromptSelectionResult selection = ed.GetSelection(opts);
if (selection.Status == PromptStatus.OK)
{
foreach (SelectedObject so in selection.Value)
{
explodedIds.Add(so.ObjectId);
}
}
}
return explodedIds;
}
/// <summary>
/// 执行布尔差集运算
/// </summary>
private Polyline PerformBooleanSubtraction(Polyline target, Polyline source, Transaction tr)
{
try
{
// 确保两个多段线都是闭合的
if (!target.Closed) target.Closed = true;
if (!source.Closed) source.Closed = true;
// 创建区域进行布尔运算
DBObjectCollection regions = new DBObjectCollection();
// 创建目标区域
Region targetRegion = Region.CreateFromObject(target) as Region;
if (targetRegion != null)
{
regions.Add(targetRegion);
tr.AddNewlyCreatedDBObject(targetRegion, true);
}
// 创建源区域
Region sourceRegion = Region.CreateFromObject(source) as Region;
if (sourceRegion != null)
{
regions.Add(sourceRegion);
tr.AddNewlyCreatedDBObject(sourceRegion, true);
}
// 执行差集运算
DBObjectCollection resultRegions = Region.BooleanOperation(
RegionBooleanOperationType.Subtract, regions[0], regions[1]);
// 清理临时区域
targetRegion.Erase();
sourceRegion.Erase();
// 如果有结果区域,转换为多段线
if (resultRegions.Count > 0)
{
Region resultRegion = (Region)resultRegions[0];
tr.AddNewlyCreatedDBObject(resultRegion, true);
// 从区域创建多段线
Polyline resultPoly = CreatePolylineFromRegion(resultRegion);
resultRegion.Erase();
return resultPoly;
}
}
catch (Exception ex)
{
ed.WriteMessage($"\n布尔运算错误: {ex.Message}");
}
return null;
}
/// <summary>
/// 从区域创建多段线
/// </summary>
private Polyline CreatePolylineFromRegion(Region region)
{
// 获取区域的边界曲线
DBObjectCollection curves = new DBObjectCollection();
region.GetRegionCurves(curves);
// 转换曲线为多段线
Polyline resultPoly = null;
foreach (Curve curve in curves)
{
Polyline poly = ConvertCurveToPolyline(curve, 0.1);
if (resultPoly == null)
{
resultPoly = poly;
}
else
{
// 合并多段线(这里简化处理,实际可能需要更复杂的合并逻辑)
resultPoly = CombinePolylines(resultPoly, poly);
}
}
return resultPoly;
}
/// <summary>
/// 转换曲线为多段线
/// </summary>
private Polyline ConvertCurveToPolyline(Curve curve, double tolerance)
{
Polyline poly = new Polyline();
Point3dCollection points = curve.Tessellate(tolerance);
for (int i = 0; i < points.Count; i++)
{
poly.AddVertexAt(i, new Point2d(points[i].X, points[i].Y), 0, 0, 0);
}
if (curve is Circle || curve is Ellipse || curve is Arc)
{
poly.Closed = true;
}
return poly;
}
/// <summary>
/// 合并两个多段线(简化实现)
/// </summary>
private Polyline CombinePolylines(Polyline poly1, Polyline poly2)
{
// 注意:这是一个简化的合并实现,实际应用中可能需要更复杂的算法
// 这里仅作为示例,实际项目中可能需要使用更专业的几何算法
Polyline result = new Polyline();
// 添加第一个多段线的顶点
for (int i = 0; i < poly1.NumberOfVertices; i++)
{
Point2d pt = poly1.GetPoint2dAt(i);
result.AddVertexAt(i, pt, 0, 0, 0);
}
// 添加第二个多段线的顶点(跳过第一个点以避免重复)
for (int i = 1; i < poly2.NumberOfVertices; i++)
{
Point2d pt = poly2.GetPoint2dAt(i);
result.AddVertexAt(result.NumberOfVertices, pt, 0, 0, 0);
}
result.Closed = true;
return result;
}
}
}