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;
}
}
namespace BeamSectionPlugin
{
public class BeamSectionExtractor
{
[CommandMethod("ExtractBeamSections", "EB", "EBS", CommandFlags.Modal)]
public void ExtractBeamSections()
{
Document doc = Application.DocumentManager.MdiActiveDocument;
Database db = doc.Database;
Editor ed = doc.Editor;
try
{
// 提示用户选择对象
ed.WriteMessage("\n请框选包含梁截面尺寸的文本对象...");
// 设置选择选项
PromptSelectionOptions opts = new PromptSelectionOptions();
opts.MessageForAdding = "\n选择包含梁尺寸的文本: ";
// 获取用户选择
PromptSelectionResult selResult = ed.GetSelection(opts);
if (selResult.Status != PromptStatus.OK) return;
// 存储截面尺寸统计
Dictionary<string, int> sizeCounts = new Dictionary<string, int>();
Regex sizePattern = new Regex(@"(\d{1,4})\s*[xX×]\s*(\d{1,4})");
using (Transaction tr = db.TransactionManager.StartTransaction())
{
// 遍历选中对象
foreach (SelectedObject selObj in selResult.Value)
{
Entity ent = tr.GetObject(selObj.ObjectId, OpenMode.ForRead) as Entity;
if (ent is DBText text)
{
ProcessText(text.TextString, sizePattern, sizeCounts);
}
else if (ent is MText mtext)
{
ProcessText(mtext.Contents, sizePattern, sizeCounts);
}
// 可扩展支持属性文字等
}
// 生成统计表
if (sizeCounts.Count > 0)
{
ed.WriteMessage($"\n找到 {sizeCounts.Count} 种梁截面尺寸,正在生成统计表...");
CreateStatisticsTable(ed, db, tr, sizeCounts);
ed.WriteMessage("\n统计表生成完成!");
}
else
{
ed.WriteMessage("\n未找到梁截面尺寸!");
}
tr.Commit();
}
}
catch (Autodesk.AutoCAD.Runtime.Exception acex)
{
ed.WriteMessage($"\nAutoCAD错误: {acex.Message}");
}
catch (System.Exception ex)
{
ed.WriteMessage($"\n系统错误: {ex.Message}");
}
}
private void ProcessText(string text, Regex pattern, Dictionary<string, int> sizeCounts)
{
MatchCollection matches = pattern.Matches(text);
foreach (Match match in matches)
{
if (match.Success && match.Groups.Count >= 3)
{
// 统一尺寸格式为"宽×高"
string width = match.Groups[1].Value;
string height = match.Groups[2].Value;
string size = $"{width}×{height}";
if (sizeCounts.ContainsKey(size))
{
sizeCounts[size]++;
}
else
{
sizeCounts.Add(size, 1);
}
}
}
}
private void CreateStatisticsTable(Editor ed, Database db, Transaction tr, Dictionary<string, int> sizeCounts)
{
// 计算线荷载并排序
var sortedSizes = sizeCounts.Select(kv => new
{
Size = kv.Key,
Count = kv.Value,
Area = CalculateArea(kv.Key),
LineLoad = CalculateLineLoad(kv.Key)
}).OrderBy(item => item.LineLoad).ToList();
// 创建表格
Table table = new Table();
table.SetDatabaseDefaults();
// 设置表格尺寸
int numRows = sortedSizes.Count + 2; // 表头 + 数据行 + 备注行
int numCols = 5;
table.SetSize(numRows, numCols);
// 设置列宽(根据内容调整)
table.Columns[0].Width = 2000; // 序号列
table.Columns[1].Width = 3500; // 尺寸列
table.Columns[2].Width = 2000; // 数量列
table.Columns[3].Width = 3000; // 面积列
table.Columns[4].Width = 3500; // 荷载列
// 设置表格样式 - 修复拼写错误
table.TextStyleId = db.Textstyle; // 正确的属性名是 TextStyleId
table.TableStyle = db.Tablestyle;
// 设置行高
for (int i = 0; i < numRows; i++)
{
table.Rows[i].Height = 1.5; // 行高1.5
}
// 设置表头
SetCellStyle(table, 0, 0, "序号", true, CellAlignment.MiddleCenter);
SetCellStyle(table, 0, 1, "梁截面尺寸(mm)", true, CellAlignment.MiddleCenter);
SetCellStyle(table, 0, 2, "出现数量", true, CellAlignment.MiddleCenter);
SetCellStyle(table, 0, 3, "截面面积(㎡)", true, CellAlignment.MiddleCenter);
SetCellStyle(table, 0, 4, "梁线荷载(kN/m)", true, CellAlignment.MiddleCenter);
// 填充数据行
for (int i = 0; i < sortedSizes.Count; i++)
{
int row = i + 1;
var item = sortedSizes[i];
SetCellStyle(table, row, 0, (row).ToString(), false, CellAlignment.MiddleCenter);
SetCellStyle(table, row, 1, item.Size, false, CellAlignment.MiddleCenter);
SetCellStyle(table, row, 2, item.Count.ToString(), false, CellAlignment.MiddleCenter);
SetCellStyle(table, row, 3, item.Area.ToString("0.0000"), false, CellAlignment.MiddleRight);
SetCellStyle(table, row, 4, item.LineLoad.ToString("0.00"), false, CellAlignment.MiddleRight);
}
// 添加备注行
int lastRow = numRows - 1;
table.MergeCells(CellRange.Create(table, lastRow, 0, lastRow, numCols - 1));
SetCellStyle(table, lastRow, 0, "备注:表中线荷载值仅做参考值,混凝土容重按25kN/m³计算",
false, CellAlignment.MiddleCenter);
// 设置表格位置(屏幕中央)
ViewTableRecord view = ed.GetCurrentView();
Point3d position = new Point3d(
(view.Width / 2) + view.CenterPoint.X - 5000,
(view.Height / 2) + view.CenterPoint.Y - 3000,
0
);
table.Position = position;
// 设置表格比例
table.ScaleFactors = new Scale3d(1.2); // 放大1.2倍
// 添加到模型空间
BlockTable bt = tr.GetObject(db.BlockTableId, OpenMode.ForRead) as BlockTable;
BlockTableRecord btr = tr.GetObject(bt[BlockTableRecord.ModelSpace], OpenMode.ForWrite) as BlockTableRecord;
btr.AppendEntity(table);
tr.AddNewlyCreatedDBObject(table, true);
}
private double CalculateArea(string size)
{
string[] dims = size.Split('×');
if (dims.Length == 2 &&
double.TryParse(dims[0], out double width) &&
double.TryParse(dims[1], out double height))
{
return (width / 1000) * (height / 1000); // 转换为平方米
}
return 0;
}
private double CalculateLineLoad(string size)
{
double area = CalculateArea(size);
// 假设混凝土容重25kN/m³
return area * 25;
}
// 辅助方法:设置单元格样式
private void SetCellStyle(Table table, int row, int col, string content,
bool isHeader, CellAlignment alignment)
{
Cell cell = table.Cells[row, col];
cell.TextString = content;
// 设置字体高度
cell.TextHeight = isHeader ? 0.8 : 0.6;
// 设置对齐方式
cell.Alignment = alignment;
// 设置表头样式
if (isHeader)
{
// 设置背景色(浅灰色)
cell.BackgroundColor = Autodesk.AutoCAD.Colors.Color.FromRgb(230, 230, 230);
cell.TextHeight = 0.7; // 稍微减小字体大小
}
}
}
}
CS1061“Tale”未包含”TextStyleld”的定义,并且找不到可接受第一个“Table”类型参数的可访问扩展方法"TextStyleld”(是否缺少using指令或程序集引用?)
重写完整一套代码