using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.Geometry;
using Autodesk.AutoCAD.Runtime;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
public class CADUtilities
{
// 常量定义 - 使用固定重叠阈值
private const double OverlapThreshold = 10.0; // 毫米
// ================== 梁信息类 ==================
private class BeamInfo
{
public ObjectId Id { get; set; }
public Extents3d Extents { get; set; }
public Vector3d Direction { get; set; }
public Point3d Center { get; set; }
public bool IsHorizontal { get; set; }
}
// ================== CLN - 清理无用实体命令 ==================
[CommandMethod("CLN")]
public void CleanUpDrawing()
{
Document doc = Application.DocumentManager.MdiActiveDocument;
if (doc == null) return;
Database db = doc.Database;
Editor ed = doc.Editor;
using (Transaction tr = db.TransactionManager.StartTransaction())
{
try
{
BlockTableRecord btr = (BlockTableRecord)tr.GetObject(
db.CurrentSpaceId, OpenMode.ForWrite);
int deletedCount = 0;
var idsToDelete = new List<ObjectId>();
// 第一遍:收集需要删除的实体
foreach (ObjectId id in btr)
{
DBText text = tr.GetObject(id, OpenMode.ForRead) as DBText;
if (text != null)
{
string textStr = text.TextString;
// 保护轴号和标高文本
if (IsAxisNumber(textStr) || textStr.Contains("标高"))
continue;
// 删除空文本和无效梁标注
if (string.IsNullOrWhiteSpace(textStr) ||
(!IsBeamDimension(textStr) && !IsBeamLabel(textStr)))
{
idsToDelete.Add(id);
}
continue;
}
// 检查零长度线
Line line = tr.GetObject(id, OpenMode.ForRead) as Line;
if (line != null && line.Length < 0.001)
{
idsToDelete.Add(id);
}
}
// 第二遍:执行删除
foreach (ObjectId id in idsToDelete)
{
Entity ent = (Entity)tr.GetObject(id, OpenMode.ForWrite);
ent.Erase();
deletedCount++;
}
tr.Commit();
ed.WriteMessage($"\n清理完成,删除 {deletedCount} 个无用实体");
}
catch (System.Exception ex)
{
ed.WriteMessage($"\n错误: {ex.Message}");
tr.Abort();
}
}
}
// ================== DEL - 图层删除命令 ==================
[CommandMethod("DEL")]
public void DeleteByLayer()
{
Document doc = Application.DocumentManager.MdiActiveDocument;
if (doc == null) return;
Database db = doc.Database;
Editor ed = doc.Editor;
// 用户选择参考对象
PromptEntityOptions opt = new PromptEntityOptions("\n选择图层参考对象:");
PromptEntityResult res = ed.GetEntity(opt);
if (res.Status != PromptStatus.OK) return;
using (Transaction tr = db.TransactionManager.StartTransaction())
{
try
{
// 获取目标图层
Entity refEnt = tr.GetObject(res.ObjectId, OpenMode.ForRead) as Entity;
if (refEnt == null) return;
string targetLayer = refEnt.Layer;
// 收集当前空间所有实体
BlockTableRecord btr = (BlockTableRecord)tr.GetObject(
db.CurrentSpaceId, OpenMode.ForWrite);
List<ObjectId> toDelete = new List<ObjectId>();
foreach (ObjectId id in btr)
{
Entity ent = tr.GetObject(id, OpenMode.ForRead) as Entity;
if (ent != null && ent.Layer == targetLayer)
{
toDelete.Add(id);
}
}
// 执行删除
if (toDelete.Count > 0)
{
foreach (ObjectId id in toDelete)
{
Entity ent = (Entity)tr.GetObject(id, OpenMode.ForWrite);
ent.Erase();
}
tr.Commit();
ed.WriteMessage($"\n已删除图层 '{targetLayer}' 中的 {toDelete.Count} 个对象");
}
else
{
ed.WriteMessage($"\n图层 '{targetLayer}' 中未找到可删除对象");
}
}
catch (System.Exception ex)
{
ed.WriteMessage($"\n错误: {ex.Message}");
tr.Abort();
}
}
}
// ================== BLD - 梁原位标注引线修复命令 ==================
[CommandMethod("BLD")]
public void BeamAnnotationLeaderFix()
{
Document doc = Application.DocumentManager.MdiActiveDocument;
if (doc == null) return;
Database db = doc.Database;
Editor ed = doc.Editor;
// 获取距离阈值
double distanceThreshold = GetDistanceThresholdFromEditor();
if (distanceThreshold < 0) // 用户取消
{
ed.WriteMessage("\n操作已取消");
return;
}
// 定义梁图层关键词
string[] beamLayers = { "梁", "BEAM", "B-", "STRUCTURE" };
// 扫描梁实体和标注文本
List<BeamInfo> beamInfos = new List<BeamInfo>();
List<DBText> dimensionTexts = new List<DBText>();
using (Transaction tr = db.TransactionManager.StartTransaction())
{
try
{
BlockTableRecord btr = (BlockTableRecord)tr.GetObject(
db.CurrentSpaceId, OpenMode.ForRead);
foreach (ObjectId id in btr)
{
Entity ent = tr.GetObject(id, OpenMode.ForRead) as Entity;
if (ent == null) continue;
string layer = ent.Layer?.ToUpper() ?? "";
// 识别梁实体
if (beamLayers.Any(l => layer.Contains(l)) && IsBeamEntity(ent))
{
Extents3d extents = ent.GeometricExtents;
Vector3d dir = GetBeamDirection(ent);
bool isHorizontal = Math.Abs(dir.X) > Math.Abs(dir.Y);
beamInfos.Add(new BeamInfo
{
Id = id,
Extents = extents,
Direction = dir,
Center = new Point3d(
(extents.MinPoint.X + extents.MaxPoint.X) / 2,
(extents.MinPoint.Y + extents.MaxPoint.Y) / 2,
0),
IsHorizontal = isHorizontal
});
}
// 只收集纯尺寸标注文本
if (ent is DBText text && IsPureBeamDimension(text.TextString))
{
dimensionTexts.Add(text);
}
}
tr.Commit();
ed.WriteMessage($"\n找到 {beamInfos.Count} 个梁实体和 {dimensionTexts.Count} 个尺寸标注");
ed.WriteMessage($"\n使用距离阈值: {distanceThreshold} mm");
ed.WriteMessage($"\n使用固定重叠检测阈值: {OverlapThreshold} mm");
}
catch (System.Exception ex)
{
ed.WriteMessage($"\n扫描错误: {ex.Message}");
tr.Abort();
return;
}
}
// 开始修复引线
int leaderCount = 0;
int skippedDistanceCount = 0;
int skippedOverlapCount = 0;
List<Line> createdLeaders = new List<Line>(); // 存储已创建的引线
using (Transaction tr = db.TransactionManager.StartTransaction())
{
try
{
BlockTableRecord btr = (BlockTableRecord)tr.GetObject(
db.CurrentSpaceId, OpenMode.ForWrite);
foreach (DBText text in dimensionTexts)
{
Point3d textPos = text.Position;
// 查找最近的梁
BeamInfo targetBeam = FindTargetBeam(textPos, beamInfos);
if (targetBeam == null) continue;
// 获取梁上的锚点
Point3d beamPoint = GetBeamAnchorPoint(textPos, targetBeam);
// 计算距离
double distance = textPos.DistanceTo(beamPoint);
// 检查距离是否小于等于阈值
if (distance <= distanceThreshold)
{
skippedDistanceCount++;
continue;
}
// 创建引线对象
Line leader = new Line(textPos, beamPoint);
// 检查重叠
if (CheckLeaderOverlap(leader, createdLeaders))
{
skippedOverlapCount++;
continue; // 存在重叠,跳过创建
}
// 配置并添加引线
ConfigureLeader(leader);
btr.AppendEntity(leader);
tr.AddNewlyCreatedDBObject(leader, true);
createdLeaders.Add(leader); // 添加到已创建列表
leaderCount++;
}
tr.Commit();
ed.WriteMessage($"\n成功创建 {leaderCount} 条梁尺寸标注引线");
ed.WriteMessage($"\n跳过 {skippedDistanceCount} 条距离≤{distanceThreshold}mm的标注");
ed.WriteMessage($"\n跳过 {skippedOverlapCount} 条存在重叠的标注");
}
catch (System.Exception ex)
{
ed.WriteMessage($"\n引线创建错误: {ex.Message}");
tr.Abort();
}
}
}
// ================== 辅助方法实现 ==================
// 识别轴号文本
private bool IsAxisNumber(string text)
{
if (string.IsNullOrWhiteSpace(text)) return false;
return Regex.IsMatch(text, @"^[A-Za-z]?[\d]+[A-Za-z]?$") ||
Regex.IsMatch(text, @"^[A-Za-z]-?\d+$") ||
Regex.IsMatch(text, @"^\d+[A-Za-z]?$");
}
// 识别梁尺寸标注
private bool IsBeamDimension(string text)
{
if (string.IsNullOrWhiteSpace(text)) return false;
return Regex.IsMatch(text, @"\d{2,4}[×xX]\d{2,4}");
}
// 识别梁编号标注
private bool IsBeamLabel(string text)
{
if (string.IsNullOrWhiteSpace(text)) return false;
return text.Contains("L") || text.Contains("B") ||
text.Contains("KL") || text.Contains("XL");
}
// 识别纯梁尺寸标注
private bool IsPureBeamDimension(string text)
{
if (string.IsNullOrWhiteSpace(text)) return false;
return Regex.IsMatch(text, @"^\d{2,4}[×xX]\d{2,4}$");
}
// 识别梁实体
private bool IsBeamEntity(Entity ent)
{
if (ent == null) return false;
return ent is Line || ent is Polyline;
}
// 获取梁方向向量
private Vector3d GetBeamDirection(Entity beam)
{
if (beam is Line line)
return line.EndPoint - line.StartPoint;
if (beam is Polyline pline && pline.NumberOfVertices >= 2)
return pline.GetPoint3dAt(1) - pline.GetPoint3dAt(0);
return new Vector3d(1, 0, 0);
}
// 查找目标梁方法
private BeamInfo FindTargetBeam(Point3d textPos, List<BeamInfo> beams)
{
if (beams == null || beams.Count == 0) return null;
BeamInfo bestBeam = null;
double minDistance = double.MaxValue;
foreach (BeamInfo beam in beams)
{
// 水平梁:只考虑上方梁
if (beam.IsHorizontal)
{
if (beam.Extents.MinPoint.Y > textPos.Y)
{
double distY = beam.Extents.MinPoint.Y - textPos.Y;
double distX = Math.Abs(textPos.X - beam.Center.X);
double distance = distY + distX * 0.1;
if (distance < minDistance)
{
minDistance = distance;
bestBeam = beam;
}
}
}
// 垂直梁:只考虑左侧梁
else
{
if (beam.Extents.MaxPoint.X < textPos.X)
{
double distX = textPos.X - beam.Extents.MaxPoint.X;
double distY = Math.Abs(textPos.Y - beam.Center.Y);
double distance = distX + distY * 0.1;
if (distance < minDistance)
{
minDistance = distance;
bestBeam = beam;
}
}
}
}
return bestBeam;
}
// ================== 命令行输入距离阈值 ==================
private double GetDistanceThresholdFromEditor()
{
Document doc = Application.DocumentManager.MdiActiveDocument;
if (doc == null) return 2000; // 默认值
Editor ed = doc.Editor;
// 创建输入提示
PromptDoubleOptions pdo = new PromptDoubleOptions(
"\n请输入原位标注的梁位置距梁边线最小距离,默认值为 <2000mm>: 根据需要输入");
// 设置提示选项
pdo.AllowNegative = false; // 不允许负数
pdo.AllowZero = false; // 不允许零值
pdo.DefaultValue = 2000; // 默认值
pdo.UseDefaultValue = true; // 允许使用默认值
// 获取用户输入
PromptDoubleResult pdr = ed.GetDouble(pdo);
// 处理结果
if (pdr.Status == PromptStatus.OK)
{
return pdr.Value;
}
return -1; // 表示取消
}
// 获取梁上的锚点(引线连接点)
private Point3d GetBeamAnchorPoint(Point3d textPos, BeamInfo beam)
{
if (beam.IsHorizontal)
{
return new Point3d(textPos.X, beam.Extents.MinPoint.Y, 0);
}
else
{
return new Point3d(beam.Extents.MaxPoint.X, textPos.Y, 0);
}
}
// 检查引线是否与现有引线重叠
private bool CheckLeaderOverlap(Line newLeader, List<Line> existingLeaders)
{
// 创建新引线的边界框(带缓冲)
Extents3d newExtents = GetExtendedExtents(newLeader, OverlapThreshold);
foreach (Line existingLeader in existingLeaders)
{
// 快速边界框检查
if (!ExtentsOverlap(newExtents, existingLeader.GeometricExtents))
continue;
// 精确距离检查
double distance = GetLineDistance(newLeader, existingLeader);
if (distance <= OverlapThreshold)
{
return true; // 存在重叠
}
}
return false; // 没有重叠
}
// 检查两个边界框是否重叠
private bool ExtentsOverlap(Extents3d ext1, Extents3d ext2)
{
return
ext1.MinPoint.X <= ext2.MaxPoint.X &&
ext1.MaxPoint.X >= ext2.MinPoint.X &&
ext1.MinPoint.Y <= ext2.MaxPoint.Y &&
ext1.MaxPoint.Y >= ext2.MinPoint.Y;
}
// 计算两条线之间的最小距离
private double GetLineDistance(Line line1, Line line2)
{
// 计算线1上点到线2的最短距离
double minDistance = double.MaxValue;
// 检查线1的两个端点到线2的距离
minDistance = Math.Min(minDistance, GetPointToLineDistance(line1.StartPoint, line2));
minDistance = Math.Min(minDistance, GetPointToLineDistance(line1.EndPoint, line2));
// 检查线2的两个端点到线1的距离
minDistance = Math.Min(minDistance, GetPointToLineDistance(line2.StartPoint, line1));
minDistance = Math.Min(minDistance, GetPointToLineDistance(line2.EndPoint, line1));
return minDistance;
}
// 计算点到线的最短距离
private double GetPointToLineDistance(Point3d point, Line line)
{
// 获取线的起点和终点
Point3d start = line.StartPoint;
Point3d end = line.EndPoint;
// 计算向量
Vector3d lineVec = end - start;
Vector3d pointVec = point - start;
// 计算投影长度
double lineLength = lineVec.Length;
double dotProduct = pointVec.DotProduct(lineVec);
double projection = dotProduct / (lineLength * lineLength);
// 限制投影在0-1之间
projection = Math.Max(0, Math.Min(1, projection));
// 计算最近点
Point3d closestPoint = start + lineVec * projection;
// 返回距离
return point.DistanceTo(closestPoint);
}
// 获取扩展后的边界框(用于快速碰撞检测)
private Extents3d GetExtendedExtents(Line line, double buffer)
{
Point3d min = new Point3d(
Math.Min(line.StartPoint.X, line.EndPoint.X) - buffer,
Math.Min(line.StartPoint.Y, line.EndPoint.Y) - buffer,
0);
Point3d max = new Point3d(
Math.Max(line.StartPoint.X, line.EndPoint.X) + buffer,
Math.Max(line.StartPoint.Y, line.EndPoint.Y) + buffer,
0);
return new Extents3d(min, max);
}
// 配置引线属性
private void ConfigureLeader(Entity leader)
{
leader.Layer = "标注";
leader.ColorIndex = 2; // 黄色
leader.Linetype = "Continuous";
leader.LineWeight = LineWeight.LineWeight013;
}
}
在“CLN”前面添加一个新功能框选所有图过滤填充、轴号、大样图、以及带有”ScaffoldPole“、“杆”图块不分解其余图块暴力分解,新功能命令改为缩写命令
将新增一起三个功能重新编写完整代码
最新发布