using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.Colors;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.Geometry;
using Autodesk.AutoCAD.Runtime;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text.RegularExpressions;
// 使用别名解决 Exception 冲突
using SysException = System.Exception;
using AecException = Autodesk.AutoCAD.Runtime.Exception;
namespace ScaffoldPlugin
{
public class ScaffoldCommands
{
#region 常量配置
// 杆件长度配置
private static readonly double[] BarLengths = { 300, 600, 900, 1200, 1500, 1800 };
// 斜拉杆长度配置
private static readonly double[] DiagonalBarLengths = { 600, 900, 1200, 1500, 1800 };
// 块目录路径
private static readonly string BlockDirectory = Path.Combine(
Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location),
"ScaffoldBlocks");
// 容差参数
private const double ToleranceValue = 0.1;
private const double SpacingTolerance = 150.0;
private const double MinAxisLength = 100.0;
private const double MinDistanceForBar = 50.0;
private const double MaxGapFactor = 1.2;
private const double SkipTolerance = 1.0;
// 块名称定义
private const string PoleBlockName = "ScaffoldPole立杆";
private const string BarPrefix = "ScaffoldPole横杆";
private const string DiagonalBarPrefix = "ScaffoldPolexie水平斜拉杆";
// 图层定义
private const string PoleLayer = "盘扣-立杆";
private const string BarLayer = "盘扣-横杆";
private const string DiagonalBarLayer = "盘扣-斜杆";
private const string AxisLayer = "盘扣轴网";
private const string DebugLayer = "盘扣-调试";
// 材料统计块名
private static readonly string[] TargetBlockNames = {
"ScaffoldPole横杆300mm",
"ScaffoldPole横杆600mm",
"ScaffoldPole横杆900mm",
"ScaffoldPole横杆1200mm",
"ScaffoldPole横杆1500mm",
"ScaffoldPole横杆1800mm",
"ScaffoldPolexie水平斜拉杆600mm",
"ScaffoldPolexie水平斜拉杆900mm",
"ScaffoldPolexie水平斜拉杆1200mm",
"ScaffoldPolexie水平斜拉杆1500mm",
"ScaffoldPolexie水平斜拉杆1800mm",
"ScaffoldPole立杆"
};
#endregion
#region BP命令 - 布置脚手架杆件
[CommandMethod("BuildPlatform", "BP", CommandFlags.Modal)]
public void BuildPlatform()
{
Document doc = Application.DocumentManager.MdiActiveDocument;
Database db = doc.Database;
Editor ed = doc.Editor;
try
{
// 用户确认对话框
if (!ConfirmWithUser(ed, "⚠️ 框选布置杆件数量建议不要超过40000个\n是否继续?"))
return;
// 检查块目录
if (!CheckBlockDirectory())
return;
// 创建必要图层
CreateLayers(db);
// 选择轴网线
var axisLines = GetAxisLines(ed);
if (axisLines.Count == 0)
return;
// 计算交点
List<Point3d> intersections = CalculateIntersections(axisLines);
ed.WriteMessage($"\n共找到 {intersections.Count} 个有效交点");
// 加载块定义
if (!LoadBlockDefinitions(db, ed))
return;
// 缓存现有实体
BuildExistingEntityCache(db);
// 布置立杆
int poleCount = PlacePoles(db, intersections, ed);
ed.WriteMessage($"\n已布置 {poleCount} 根立杆");
// 布置横杆
int barCount = PlaceBars(db, intersections, axisLines, ed);
ed.WriteMessage($"\n已布置 {barCount} 根横杆");
// 结果反馈
if (poleCount > 0 || barCount > 0)
{
Application.ShowAlertDialog($"成功布置 {poleCount}根立杆和{barCount}根横杆!");
}
else
{
ShowErrorDialog("脚手架布置失败,未布置任何构件!");
}
}
catch (AecException ex) // 使用别名处理AutoCAD异常
{
HandleException(ed, ex);
}
catch (SysException ex) // 使用别名处理.NET异常
{
HandleException(ed, ex);
}
}
#endregion
#region BD命令 - 布置斜拉杆
[CommandMethod("BuildDiagonal", "BD", CommandFlags.Modal)]
public void BuildDiagonal()
{
Document doc = Application.DocumentManager.MdiActiveDocument;
Database db = doc.Database;
Editor ed = doc.Editor;
try
{
// 创建斜杆图层
CreateLayerIfNotExists(db, DiagonalBarLayer, 4); // 青色
// 步骤1:选择布置模式
int mode = GetDiagonalMode(ed);
if (mode == 0) return;
// 步骤2:选择横杆图块
PromptSelectionOptions selOpts = new PromptSelectionOptions();
selOpts.MessageForAdding = "\n选择横杆图块: ";
PromptSelectionResult selResult = ed.GetSelection(selOpts);
if (selResult.Status != PromptStatus.OK) return;
// 加载斜拉杆块定义
if (!LoadDiagonalBlockDefinitions(db, ed))
return;
// 缓存现有实体
BuildExistingEntityCache(db);
using (Transaction tr = db.TransactionManager.StartTransaction())
{
// 收集所有横杆信息
var beams = CollectBeams(db, selResult, tr);
if (beams.Count == 0)
{
ed.WriteMessage("\n未找到有效的横杆图块");
return;
}
// 按模式布置斜拉杆
int diagonalCount = PlaceDiagonalBars(db, tr, beams, mode);
tr.Commit();
ed.WriteMessage($"\n成功布置 {diagonalCount} 根斜拉杆");
}
}
catch (AecException ex)
{
HandleException(ed, ex);
}
catch (SysException ex)
{
HandleException(ed, ex);
}
}
private int GetDiagonalMode(Editor ed)
{
PromptKeywordOptions pko = new PromptKeywordOptions("\n选择斜拉杆布置模式: ");
pko.Keywords.Add("1", "1", "1. 隔一布一");
pko.Keywords.Add("2", "2", "2. 隔二布一");
pko.Keywords.Add("3", "3", "3. 隔三布一");
pko.AllowNone = false;
pko.AppendKeywordsToMessage = true;
PromptResult pr = ed.GetKeywords(pko);
if (pr.Status != PromptStatus.OK) return 0;
return int.Parse(pr.StringResult);
}
private bool LoadDiagonalBlockDefinitions(Database db, Editor ed)
{
using (Transaction tr = db.TransactionManager.StartTransaction())
{
BlockTable bt = tr.GetObject(db.BlockTableId, OpenMode.ForRead) as BlockTable;
// 加载斜拉杆块
foreach (double len in DiagonalBarLengths)
{
string blockName = $"{DiagonalBarPrefix}{len}mm";
string blockPath = Path.Combine(BlockDirectory, $"{blockName}.dwg");
if (!File.Exists(blockPath))
{
ed.WriteMessage($"\n斜拉杆块文件未找到: {blockPath}");
continue;
}
if (!bt.Has(blockName))
{
LoadBlockFromFile(db, blockPath, blockName);
ed.WriteMessage($"\n已加载斜拉杆块: {blockName}");
}
}
tr.Commit();
return true;
}
}
private List<(BlockReference Block, double Length)> CollectBeams(Database db, PromptSelectionResult selResult, Transaction tr)
{
var beams = new List<(BlockReference, double)>();
BlockTable bt = (BlockTable)tr.GetObject(db.BlockTableId, OpenMode.ForRead);
foreach (ObjectId objId in selResult.Value.GetObjectIds())
{
if (objId.ObjectClass.Name != "AcDbBlockReference") continue;
BlockReference br = (BlockReference)tr.GetObject(objId, OpenMode.ForRead);
BlockTableRecord btr = (BlockTableRecord)tr.GetObject(br.BlockTableRecord, OpenMode.ForRead);
// 检查是否是横杆图块
string blockName = btr.Name.ToUpper();
if (blockName.Contains("HORIZONTAL") || blockName.Contains("BEAM") ||
blockName.Contains("横杆"))
{
double length = GetBeamLength(br);
if (length > 0) beams.Add((br, length));
}
}
return beams;
}
// 新增:获取横杆长度的方法
private double GetBeamLength(BlockReference br)
{
try
{
// 获取图块的几何范围
Extents3d ext = br.GeometricExtents;
// 计算包围盒的宽度(X方向)
double width = ext.MaxPoint.X - ext.MinPoint.X;
// 计算包围盒的高度(Y方向)
double height = ext.MaxPoint.Y - ext.MinPoint.Y;
// 横杆通常是沿一个方向延伸的,取最大值作为长度
return Math.Max(width, height);
}
catch
{
return 0;
}
}
private int PlaceDiagonalBars(Database db, Transaction tr, List<(BlockReference Block, double Length)> beams, int mode)
{
BlockTableRecord btr = (BlockTableRecord)tr.GetObject(db.CurrentSpaceId, OpenMode.ForWrite) as BlockTableRecord;
BlockTable bt = (BlockTable)tr.GetObject(db.BlockTableId, OpenMode.ForRead) as BlockTable;
// 按Y坐标分组并排序
var groups = beams
.GroupBy(b => Math.Round(b.Block.Position.Y, 2))
.OrderBy(g => g.Key)
.ToList();
if (groups.Count < 2)
{
Application.ShowAlertDialog("至少需要两排横杆才能布置斜拉杆!");
return 0;
}
int diagonalCount = 0;
int step = mode + 1; // 1=隔一布一(每2跨), 2=隔二布一(每3跨), 3=隔三布一(每4跨)
for (int i = 0; i < groups.Count - 1; i++)
{
var currentRow = groups[i].OrderBy(b => b.Block.Position.X).ToList();
var nextRow = groups[i + 1].OrderBy(b => b.Block.Position.X).ToList();
// 计算起始偏移量
int startOffset = i % step;
for (int j = startOffset; j < currentRow.Count - 1; j += step)
{
if (j >= nextRow.Count - 1) continue;
// 获取当前网格四个角点
Point3d topLeft = currentRow[j].Block.Position;
Point3d topRight = currentRow[j + 1].Block.Position;
Point3d bottomLeft = nextRow[j].Block.Position;
Point3d bottomRight = nextRow[j + 1].Block.Position;
// 计算对角线长度
Vector3d diagonal1 = bottomRight - topLeft;
double length1 = diagonal1.Length;
Vector3d diagonal2 = bottomLeft - topRight;
double length2 = diagonal2.Length;
// 选择较短的对角线
bool useDiagonal1 = length1 <= length2;
double requiredLength = useDiagonal1 ? length1 : length2;
Vector3d diagonal = useDiagonal1 ? diagonal1 : diagonal2;
Point3d startPoint = useDiagonal1 ? topLeft : topRight;
// 获取最接近的标准长度
string lengthKey = GetClosestDiagonalLength(requiredLength);
string blockName = $"{DiagonalBarPrefix}{lengthKey}mm";
if (!bt.Has(blockName))
{
Application.ShowAlertDialog($"斜拉杆块 {blockName} 未加载!");
continue;
}
ObjectId blockId = bt[blockName];
// 计算中点
Point3d midPoint = new Point3d(
(startPoint.X + (startPoint.X + diagonal.X) / 2),
(startPoint.Y + (startPoint.Y + diagonal.Y) / 2),
0);
// 计算旋转角度
double angle = diagonal.AngleOnPlane(new Plane(Point3d.Origin, Vector3d.ZAxis));
// 检查是否已存在相同位置的斜杆
if (IsCached(blockName, midPoint, angle)) continue;
// 创建斜杆图块引用
BlockReference br = new BlockReference(midPoint, blockId);
br.Layer = DiagonalBarLayer;
br.Rotation = angle;
// 添加到图形
btr.AppendEntity(br);
tr.AddNewlyCreatedDBObject(br, true);
diagonalCount++;
}
}
return diagonalCount;
}
private string GetClosestDiagonalLength(double actualLength)
{
double minDiff = double.MaxValue;
double closestLength = 600; // 默认值
foreach (double len in DiagonalBarLengths)
{
double diff = Math.Abs(len - actualLength);
if (diff < minDiff)
{
minDiff = diff;
closestLength = len;
}
}
return closestLength.ToString();
}
#endregion
#region BPS命令 - 材料统计
[CommandMethod("GenerateMaterialStats", "BPS", CommandFlags.Modal)]
public void GenerateMaterialStats()
{
Document doc = Application.DocumentManager.MdiActiveDocument;
Database db = doc.Database;
Editor ed = doc.Editor;
try
{
// 选择要统计的块参照
PromptSelectionResult res = ed.GetSelection(new SelectionFilter(new TypedValue[]
{
new TypedValue(0, "INSERT")
}));
if (res.Status != PromptStatus.OK)
{
ed.WriteMessage("\n未选择对象或操作取消");
return;
}
// 统计块数量
Dictionary<string, int> stats = CountBlocks(db, res.Value.GetObjectIds());
if (stats.Count == 0)
{
ed.WriteMessage("\n选定区域中没有可统计的杆件");
return;
}
// 构建表格数据
List<TableRowData> tableData = BuildTableData(stats);
// 插入统计表格
InsertStatTable(db, ed, tableData);
ed.WriteMessage("\n材料统计表已成功插入!");
}
catch (AecException ex)
{
HandleException(ed, ex);
}
catch (SysException ex)
{
HandleException(ed, ex);
}
}
#endregion
#region BP命令辅助方法
private bool ConfirmWithUser(Editor ed, string message)
{
PromptKeywordOptions options = new PromptKeywordOptions(message);
options.Keywords.Add("Y");
options.Keywords.Add("N");
options.AllowNone = false;
return ed.GetKeywords(options).StringResult == "Y";
}
private bool CheckBlockDirectory()
{
if (!Directory.Exists(BlockDirectory))
{
Directory.CreateDirectory(BlockDirectory);
ShowErrorDialog($"块目录已创建: {BlockDirectory}\n请添加块文件后重新运行命令");
return false;
}
return true;
}
private void CreateLayers(Database db)
{
CreateLayerIfNotExists(db, PoleLayer, 7); // 白色
CreateLayerIfNotExists(db, BarLayer, 1); // 红色
CreateLayerIfNotExists(db, DiagonalBarLayer, 4); // 青色
CreateLayerIfNotExists(db, AxisLayer, 3); // 绿色
CreateLayerIfNotExists(db, DebugLayer, 2); // 黄色
}
private List<Line> GetAxisLines(Editor ed)
{
var filter = new SelectionFilter(new[] {
new TypedValue(0, "LINE"),
new TypedValue(8, AxisLayer)
});
PromptSelectionResult selection = ed.GetSelection(
new PromptSelectionOptions
{
MessageForAdding = "\n选择盘扣轴网线: "
},
filter
);
if (selection.Status != PromptStatus.OK)
return new List<Line>();
List<Line> lines = new List<Line>();
using (Transaction tr = ed.Document.TransactionManager.StartTransaction())
{
foreach (ObjectId id in selection.Value.GetObjectIds())
{
Line line = tr.GetObject(id, OpenMode.ForRead) as Line;
if (line != null && line.Length > MinAxisLength)
{
lines.Add(line.Clone() as Line);
}
}
tr.Commit();
}
ed.WriteMessage($"\n已选择 {lines.Count} 条有效轴网线");
return lines;
}
private List<Point3d> CalculateIntersections(List<Line> lines)
{
var results = new HashSet<Point3d>(new Point3dComparer(ToleranceValue));
for (int i = 0; i < lines.Count; i++)
{
for (int j = i + 1; j < lines.Count; j++)
{
Point3dCollection pts = new Point3dCollection();
lines[i].IntersectWith(lines[j], Intersect.OnBothOperands, pts, IntPtr.Zero, IntPtr.Zero);
foreach (Point3d pt in pts)
{
if (IsPointOnLineSegment(pt, lines[i], ToleranceValue) &&
IsPointOnLineSegment(pt, lines[j], ToleranceValue))
{
results.Add(pt);
}
}
}
}
return results.ToList();
}
private bool IsPointOnLineSegment(Point3d pt, Line line, double tolerance)
{
Vector3d lineVec = line.EndPoint - line.StartPoint;
Vector3d startToPt = pt - line.StartPoint;
double dotProduct = lineVec.DotProduct(startToPt);
if (dotProduct < -tolerance || dotProduct > lineVec.LengthSqrd + tolerance)
return false;
double distSq = startToPt.LengthSqrd - (dotProduct * dotProduct) / lineVec.LengthSqrd;
return distSq <= tolerance * tolerance;
}
private bool LoadBlockDefinitions(Database db, Editor ed)
{
using (Transaction tr = db.TransactionManager.StartTransaction())
{
BlockTable bt = tr.GetObject(db.BlockTableId, OpenMode.ForRead) as BlockTable;
// 加载立杆块
string polePath = Path.Combine(BlockDirectory, $"{PoleBlockName}.dwg");
if (!File.Exists(polePath))
{
ShowErrorDialog($"立杆块文件未找到: {polePath}");
return false;
}
if (!bt.Has(PoleBlockName))
{
LoadBlockFromFile(db, polePath, PoleBlockName);
ed.WriteMessage($"\n已加载立杆块: {PoleBlockName}");
}
// 加载横杆块
foreach (double len in BarLengths)
{
string barName = $"{BarPrefix}{len}mm";
string barPath = Path.Combine(BlockDirectory, $"{barName}.dwg");
if (!bt.Has(barName) && File.Exists(barPath))
{
LoadBlockFromFile(db, barPath, barName);
ed.WriteMessage($"\n已加载横杆块: {barName}");
}
}
tr.Commit();
return true;
}
}
private void LoadBlockFromFile(Database db, string filePath, string blockName)
{
using (Database sourceDb = new Database(false, true))
{
sourceDb.ReadDwgFile(filePath, FileOpenMode.OpenForReadAndAllShare, false, null);
db.Insert(blockName, sourceDb, true);
}
}
private void BuildExistingEntityCache(Database db)
{
_existingEntitiesCache = new HashSet<(string, Point3d, double)>(new EntityKeyComparer());
using (Transaction tr = db.TransactionManager.StartTransaction())
{
BlockTableRecord btr = tr.GetObject(SymbolUtilityServices.GetBlockModelSpaceId(db), OpenMode.ForRead) as BlockTableRecord;
foreach (ObjectId id in btr)
{
BlockReference br = tr.GetObject(id, OpenMode.ForRead) as BlockReference;
if (br != null && (br.Name == PoleBlockName || br.Name.StartsWith(BarPrefix) || br.Name.StartsWith(DiagonalBarPrefix)))
{
_existingEntitiesCache.Add((br.Name, br.Position, br.Rotation));
}
}
}
}
private int PlacePoles(Database db, List<Point3d> points, Editor ed)
{
int count = 0;
using (Transaction tr = db.TransactionManager.StartTransaction())
{
BlockTable bt = tr.GetObject(db.BlockTableId, OpenMode.ForRead) as BlockTable;
BlockTableRecord btr = tr.GetObject(SymbolUtilityServices.GetBlockModelSpaceId(db), OpenMode.ForWrite) as BlockTableRecord;
if (!bt.Has(PoleBlockName))
{
ShowErrorDialog($"错误:立杆块 {PoleBlockName} 未加载!");
return 0;
}
ObjectId poleBlockId = bt[PoleBlockName];
foreach (Point3d pt in points)
{
if (double.IsNaN(pt.X) || double.IsNaN(pt.Y)) continue;
if (IsCached(PoleBlockName, pt, 0)) continue;
BlockReference br = new BlockReference(pt, poleBlockId);
br.Layer = PoleLayer;
btr.AppendEntity(br);
tr.AddNewlyCreatedDBObject(br, true);
count++;
}
tr.Commit();
}
return count;
}
private int PlaceBars(Database db, List<Point3d> points, List<Line> axisLines, Editor ed)
{
int count = 0;
using (Transaction tr = db.TransactionManager.StartTransaction())
{
BlockTable bt = tr.GetObject(db.BlockTableId, OpenMode.ForRead) as BlockTable;
BlockTableRecord btr = tr.GetObject(SymbolUtilityServices.GetBlockModelSpaceId(db), OpenMode.ForWrite) as BlockTableRecord;
foreach (Line axisLine in axisLines)
{
List<Point3d> linePoints = points.Where(p =>
IsPointOnLineSegment(p, axisLine, ToleranceValue)).ToList();
if (linePoints.Count < 2) continue;
linePoints = SortPointsByLineParam(axisLine, linePoints);
List<Segment> segments = GroupPointsIntoSegments(linePoints);
foreach (Segment segment in segments)
{
for (int i = 0; i < segment.Points.Count - 1; i++)
{
Point3d start = segment.Points[i];
Point3d end = segment.Points[i + 1];
double distance = start.DistanceTo(end);
if (distance < MinDistanceForBar) continue;
double bestLength = FindBestBarLength(distance);
if (bestLength < 0) continue;
string blockName = $"{BarPrefix}{bestLength}mm";
if (!bt.Has(blockName)) continue;
Point3d midPoint = new Point3d(
(start.X + end.X) / 2,
(start.Y + end.Y) / 2,
(start.Z + end.Z) / 2);
Vector3d direction = (end - start).GetNormal();
double angle = Math.Atan2(direction.Y, direction.X);
if (IsCached(blockName, midPoint, angle)) continue;
BlockReference br = new BlockReference(midPoint, bt[blockName]);
br.Layer = BarLayer;
br.Rotation = angle;
btr.AppendEntity(br);
tr.AddNewlyCreatedDBObject(br, true);
count++;
}
}
}
tr.Commit();
}
return count;
}
private double FindBestBarLength(double distance)
{
double bestLength = -1;
double minDiff = double.MaxValue;
foreach (double len in BarLengths)
{
double diff = Math.Abs(len - distance);
if (diff < minDiff && diff <= SpacingTolerance)
{
minDiff = diff;
bestLength = len;
}
}
return bestLength;
}
private List<Point3d> SortPointsByLineParam(Line line, List<Point3d> points)
{
Vector3d lineVec = line.EndPoint - line.StartPoint;
double lineLength = lineVec.Length;
return points
.Select(p => new {
Point = p,
Param = lineVec.DotProduct(p - line.StartPoint) / lineLength
})
.OrderBy(x => x.Param)
.Select(x => x.Point)
.ToList();
}
private List<Segment> GroupPointsIntoSegments(List<Point3d> points)
{
List<Segment> segments = new List<Segment>();
if (points.Count < 2) return segments;
double maxGap = BarLengths.Max() * MaxGapFactor;
Segment currentSegment = new Segment { Points = { points[0] } };
for (int i = 1; i < points.Count; i++)
{
double distance = points[i - 1].DistanceTo(points[i]);
if (distance > maxGap)
{
if (currentSegment.Points.Count > 1) segments.Add(currentSegment);
currentSegment = new Segment { Points = { points[i] } };
}
else
{
currentSegment.Points.Add(points[i]);
}
}
if (currentSegment.Points.Count > 1) segments.Add(currentSegment);
return segments;
}
private void CreateLayerIfNotExists(Database db, string layerName, short colorIndex)
{
using (Transaction tr = db.TransactionManager.StartTransaction())
{
LayerTable lt = tr.GetObject(db.LayerTableId, OpenMode.ForRead) as LayerTable;
if (lt.Has(layerName)) return;
lt.UpgradeOpen();
LayerTableRecord ltr = new LayerTableRecord
{
Name = layerName,
Color = Color.FromColorIndex(ColorMethod.ByAci, colorIndex)
};
lt.Add(ltr);
tr.AddNewlyCreatedDBObject(ltr, true);
tr.Commit();
}
}
private bool IsCached(string blockName, Point3d pos, double angle)
{
return _existingEntitiesCache?.Contains((blockName, pos, angle)) ?? false;
}
#endregion
#region BPS命令辅助方法
private Dictionary<string, int> CountBlocks(Database db, ObjectId[] ids)
{
var stats = new Dictionary<string, int>();
using (Transaction tr = db.TransactionManager.StartTransaction())
{
foreach (ObjectId id in ids)
{
BlockReference br = tr.GetObject(id, OpenMode.ForRead) as BlockReference;
if (br == null || !TargetBlockNames.Contains(br.Name)) continue;
stats[br.Name] = stats.TryGetValue(br.Name, out int count) ? count + 1 : 1;
}
tr.Commit();
}
return stats;
}
private List<TableRowData> BuildTableData(Dictionary<string, int> stats)
{
var tableData = new List<TableRowData>();
foreach (string blockName in TargetBlockNames)
{
string materialName = "其他";
if (blockName.Contains("横杆")) materialName = "横杆";
else if (blockName.Contains("斜拉杆")) materialName = "斜拉杆";
else if (blockName.Contains("立杆")) materialName = "立杆";
string length = Regex.Match(blockName, @"\d+").Value;
string quantity = stats.TryGetValue(blockName, out int count) ? count.ToString() : "0";
tableData.Add(new TableRowData
{
MaterialName = materialName,
Length = length,
Quantity = quantity
});
}
return tableData;
}
private void InsertStatTable(Database db, Editor ed, List<TableRowData> data)
{
using (Transaction tr = db.TransactionManager.StartTransaction())
{
BlockTableRecord btr = tr.GetObject(SymbolUtilityServices.GetBlockModelSpaceId(db), OpenMode.ForWrite) as BlockTableRecord;
// 获取表格插入点
PromptPointResult ppr = ed.GetPoint("\n请选择表格插入点: ");
if (ppr.Status != PromptStatus.OK) return;
Point3d insertPoint = ppr.Value;
// 创建表格对象
Table table = new Table();
table.Position = insertPoint;
table.SetSize(data.Count + 2, 4); // 标题行+表头行+数据行
table.SetRowHeight(3.0);
table.SetColumnWidth(0, 6.0);
table.SetColumnWidth(1, 18.0);
table.SetColumnWidth(2, 18.0);
table.SetColumnWidth(3, 18.0);
table.Layer = "0";
// 合并标题行单元格
table.MergeCells(CellRange.Create(table, 0, 0, 0, 3));
// 设置标题行
table.Cells[0, 0].TextString = "平面盘扣布置材料统计表";
table.Cells[0, 0].Alignment = CellAlignment.MiddleCenter;
table.Cells[0, 0].TextHeight = 3.0;
// 设置表头行
table.Cells[1, 0].TextString = "序号";
table.Cells[1, 1].TextString = "材料名称";
table.Cells[1, 2].TextString = "杆件长度(mm)";
table.Cells[1, 3].TextString = "合计数量/根";
// 设置表头样式
for (int col = 0; col < 4; col++)
{
table.Cells[1, col].Alignment = CellAlignment.MiddleCenter;
table.Cells[1, col].TextHeight = 2.5;
}
// 填充数据行
for (int i = 0; i < data.Count; i++)
{
int row = i + 2;
table.Cells[row, 0].TextString = (i + 1).ToString();
table.Cells[row, 1].TextString = data[i].MaterialName;
table.Cells[row, 2].TextString = data[i].Length;
table.Cells[row, 3].TextString = data[i].Quantity;
// 设置数据行样式
table.Cells[row, 0].Alignment = CellAlignment.MiddleCenter;
table.Cells[row, 1].Alignment = CellAlignment.MiddleLeft;
table.Cells[row, 2].Alignment = CellAlignment.MiddleLeft;
table.Cells[row, 3].Alignment = CellAlignment.MiddleLeft;
table.Cells[row, 0].TextHeight = 2.5;
}
btr.AppendEntity(table);
tr.AddNewlyCreatedDBObject(table, true);
tr.Commit();
}
}
#endregion
#region 通用辅助方法
private void ShowErrorDialog(string message)
{
Application.ShowAlertDialog(message);
}
private void HandleException(Editor ed, SysException ex)
{
string errorType = ".NET";
ed.WriteMessage($"\n{errorType}错误: {ex.Message}");
ShowErrorDialog($"发生{errorType}异常: {ex.Message}\n详细请查看命令行日志");
}
private void HandleException(Editor ed, AecException ex)
{
string errorType = "AutoCAD";
ed.WriteMessage($"\n{errorType}错误: {ex.Message} (状态: {ex.ErrorStatus})");
ShowErrorDialog($"发生{errorType}异常: {ex.Message}\n详细请查看命令行日志");
}
#endregion
#region 数据结构
private class TableRowData
{
public string MaterialName { get; set; }
public string Length { get; set; }
public string Quantity { get; set; }
}
private class Segment
{
public List<Point3d> Points { get; set; } = new List<Point3d>();
}
private class Point3dComparer : IEqualityComparer<Point3d>
{
private readonly double _tolerance;
public Point3dComparer(double tolerance) => _tolerance = tolerance;
public bool Equals(Point3d p1, Point3d p2) =>
p1.DistanceTo(p2) < _tolerance;
public int GetHashCode(Point3d p) =>
p.X.GetHashCode() ^ p.Y.GetHashCode() ^ p.Z.GetHashCode();
}
private class EntityKeyComparer : IEqualityComparer<(string, Point3d, double)>
{
public bool Equals((string, Point3d, double) x, (string, Point3d, double) y) =>
x.Item1 == y.Item1 &&
x.Item2.DistanceTo(y.Item2) < SkipTolerance &&
Math.Abs(x.Item3 - y.Item3) < 0.01;
public int GetHashCode((string, Point3d, double) obj) =>
obj.Item1.GetHashCode() ^ obj.Item2.GetHashCode() ^ obj.Item3.GetHashCode();
}
private HashSet<(string blockName, Point3d pos, double angle)> _existingEntitiesCache;
#endregion
}
}
布置的斜拉杆不显示