using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.Geometry;
using Autodesk.AutoCAD.Runtime;
using Autodesk.AutoCAD.GraphicsInterface;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
using System.Reflection;
// 修复Polyline命名歧义
using DbPolyline = Autodesk.AutoCAD.DatabaseServices.Polyline;
[assembly: CommandClass(typeof(MyCadCommands.CadPlugin))]
namespace MyCadCommands
{
/// <summary>
/// 多段线扩展方法类
/// </summary>
public static class PolylineExtensions
{
public static bool ContainsPoint(this DbPolyline pl, Point3d point, double tolerance)
{
for (int i = 0; i < pl.NumberOfVertices; i++)
{
if (pl.GetPoint3dAt(i).DistanceTo(point) < tolerance)
return true;
}
return false;
}
/// <summary>
/// 预缓存多段线的线段信息
/// </summary>
public static List<(Point3d Start, Point3d End)> GetSegments(this DbPolyline pl)
{
var segments = new List<(Point3d, Point3d)>();
int vertCount = pl.NumberOfVertices;
for (int i = 0; i < vertCount; i++)
{
int nextIdx = (i + 1) % vertCount;
segments.Add((pl.GetPoint3dAt(i), pl.GetPoint3dAt(nextIdx)));
}
return segments;
}
/// <summary>
/// 获取向量的垂直向量
/// </summary>
public static Vector3d GetPerpendicularVector(this Vector3d vector)
{
return new Vector3d(-vector.Y, vector.X, vector.Z);
}
}
/// <summary>
/// 横杆信息类
/// </summary>
public class BarInfo
{
public ObjectId Id { get; set; }
public Point3d Position { get; set; }
public double Rotation { get; set; }
public double Length { get; set; }
public string Layer { get; set; }
public Point3d OriginalStartPoint { get; set; }
public Point3d OriginalEndPoint { get; set; }
}
/// <summary>
/// AutoCAD插件主类
/// </summary>
public class CadPlugin
{
// 图层名称常量
private const string PoleLayer = "盘扣-立杆";
private const string BarLayer = "盘扣-横杆";
private const string DiagonalBarLayer = "盘扣-斜杆";
private const string AxisLayer = "盘扣轴网";
private const string DebugLayer = "Debug";
// 脚手架绘制常量
private const double DEFAULT_OFFSET_DISTANCE = 250;
private const double DEFAULT_SCAFFOLD_WIDTH = 900;
private const double DEFAULT_MAX_SPACING = 1800;
private const double OVERLAP_TOLERANCE = 10;
private const double RECT_SIDE_LENGTH = 900;
private const double OUTLINE_TOLERANCE = 50;
private const double ToleranceValue = 0.001;
// 嵌入式图块映射表
private static readonly Dictionary<string, string> EmbeddedBlockMap = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
{
// 钢踏板图块
{"900", "ScaffoldPole钢踏板900mm"},
{"1200", "ScaffoldPole钢踏板1200mm"},
{"1500", "ScaffoldPole钢踏板1500mm"},
{"1800", "ScaffoldPole钢踏板1800mm"},
{"single", "ScaffoldPole单片钢踏板"},
// 其他可用图块(根据您提供的列表)
{"90度阳角型钢", "90度阳角型钢"},
{"ScaffoldPole90度阳角型钢", "ScaffoldPole90度阳角型钢"},
{"ScaffoldPole90度阳角配件", "ScaffoldPole90度阳角配件"},
{"ScaffoldPole三角架", "ScaffoldPole三角架"},
{"ScaffoldPole传统连墙件", "ScaffoldPole传统连墙件"},
{"ScaffoldPole卸料平台立面布置大样图", "ScaffoldPole卸料平台立面布置大样图"},
{"ScaffoldPole卸料钢平台大样图", "ScaffoldPole卸料钢平台大样图"},
{"ScaffoldPole双槽钢拖梁", "ScaffoldPole双槽钢拖梁"},
{"ScaffoldPole双槽钢拖梁1350mm", "ScaffoldPole双槽钢拖梁1350mm"},
{"ScaffoldPole双槽钢拖梁1650mm", "ScaffoldPole双槽钢拖梁1650mm"},
{"ScaffoldPole右45度角型钢", "ScaffoldPole右45度角型钢"},
{"ScaffoldPole固定桩", "ScaffoldPole固定桩"},
{"ScaffoldPole外架临时支撑大样图", "ScaffoldPole外架临时支撑大样图"},
{"ScaffoldPole外架剖面大样图", "ScaffoldPole外架剖面大样图"},
{"ScaffoldPole外架斜拉杆1200mm", "ScaffoldPole外架斜拉杆1200mm"},
{"ScaffoldPole外架斜拉杆1500mm", "ScaffoldPole外架斜拉杆1500mm"},
{"ScaffoldPole外架斜拉杆1800mm", "ScaffoldPole外架斜拉杆1800mm"},
{"ScaffoldPole外架斜拉杆600mm", "ScaffoldPole外架斜拉杆600mm"},
{"ScaffoldPole外架斜拉杆900mm", "ScaffoldPole外架斜拉杆900mm"},
{"ScaffoldPole工字钢与联梁加固节点图", "ScaffoldPole工字钢与联梁加固节点图"},
{"ScaffoldPole工字钢连梁", "ScaffoldPole工字钢连梁"},
{"ScaffoldPole左45度角型钢", "ScaffoldPole左45度角型钢"},
{"ScaffoldPole底托", "ScaffoldPole底托"},
{"ScaffoldPole底托1", "ScaffoldPole底托1"},
{"ScaffoldPole底托螺母", "ScaffoldPole底托螺母"},
{"ScaffoldPole悬挑型钢", "ScaffoldPole悬挑型钢"},
{"ScaffoldPole悬挑架用材和拉杆大样图", "ScaffoldPole悬挑架用材和拉杆大样图"},
{"ScaffoldPole扣件", "ScaffoldPole扣件"},
{"ScaffoldPole扣件2", "ScaffoldPole扣件2"},
{"ScaffoldPole扣件900mm", "ScaffoldPole扣件900mm"},
{"ScaffoldPole新型连墙件", "ScaffoldPole新型连墙件"},
{"ScaffoldPole方钢", "ScaffoldPole方钢"},
{"ScaffoldPole方钢1000mm", "ScaffoldPole方钢1000mm"},
{"ScaffoldPole施工电梯平面大样图", "ScaffoldPole施工电梯平面大样图"},
{"ScaffoldPole施工电梯立面大样图", "ScaffoldPole施工电梯立面大样图"},
{"ScaffoldPole横杆1200mm", "ScaffoldPole横杆1200mm"},
{"ScaffoldPole横杆1500mm", "ScaffoldPole横杆1500mm"},
{"ScaffoldPole横杆1800mm", "ScaffoldPole横杆1800mm"},
{"ScaffoldPole横杆300mm", "ScaffoldPole横杆300mm"},
{"ScaffoldPole横杆600mm", "ScaffoldPole横杆600mm"},
{"ScaffoldPole横杆900mm", "ScaffoldPole横杆900mm"},
{"ScaffoldPole水平斜拉杆1200mm", "ScaffoldPole水平斜拉杆1200mm"},
{"ScaffoldPole水平斜拉杆1500mm", "ScaffoldPole水平斜拉杆1500mm"},
{"ScaffoldPole水平斜拉杆1800mm", "ScaffoldPole水平斜拉杆1800mm"},
{"ScaffoldPole水平斜拉杆600mm", "ScaffoldPole水平斜拉杆600mm"},
{"ScaffoldPole水平斜拉杆900mm", "ScaffoldPole水平斜拉杆900mm"},
{"ScaffoldPole爬梯样板", "ScaffoldPole爬梯样板"},
{"ScaffoldPole立杆", "ScaffoldPole立杆"},
{"ScaffoldPole立杆1000mm", "ScaffoldPole立杆1000mm"},
{"ScaffoldPole立杆1500mm", "ScaffoldPole立杆1500mm"},
{"ScaffoldPole立杆2000mm", "ScaffoldPole立杆2000mm"},
{"ScaffoldPole立杆200mm", "ScaffoldPole立杆200mm"},
{"ScaffoldPole立杆2500mm", "ScaffoldPole立杆2500mm"},
{"ScaffoldPole立杆350mm", "ScaffoldPole立杆350mm"},
{"ScaffoldPole立杆500mm", "ScaffoldPole立杆500mm"},
{"ScaffoldPole立横杆1200mm", "ScaffoldPole立横杆1200mm"},
{"ScaffoldPole立横杆1500mm", "ScaffoldPole立横杆1500mm"},
{"ScaffoldPole立横杆1800mm", "ScaffoldPole立横杆1800mm"},
{"ScaffoldPole立横杆300mm", "ScaffoldPole立横杆300mm"},
{"ScaffoldPole立横杆600mm", "ScaffoldPole立横杆600mm"},
{"ScaffoldPole立横杆900mm", "ScaffoldPole立横杆900mm"},
{"ScaffoldPole竖向斜拉杆1200mm", "ScaffoldPole竖向斜拉杆1200mm"},
{"ScaffoldPole竖向斜拉杆1500mm", "ScaffoldPole竖向斜拉杆1500mm"},
{"ScaffoldPole竖向斜拉杆1800mm", "ScaffoldPole竖向斜拉杆1800mm"},
{"ScaffoldPole竖向斜拉杆600mm", "ScaffoldPole竖向斜拉杆600mm"},
{"ScaffoldPole竖向斜拉杆900mm", "ScaffoldPole竖向斜拉杆900mm"},
{"ScaffoldPole钢踏板1200mm", "ScaffoldPole钢踏板1200mm"},
{"ScaffoldPole钢踏板1500mm", "ScaffoldPole钢踏板1500mm"},
{"ScaffoldPole钢踏板1800mm", "ScaffoldPole钢踏板1800mm"},
{"ScaffoldPole钢踏板900mm", "ScaffoldPole钢踏板900mm"},
{"ScaffoldPole阳角斜拉大样图", "ScaffoldPole阳角斜拉大样图"},
{"ScaffoldPole顶托", "ScaffoldPole顶托"},
{"ScaffoldPole顶托1", "ScaffoldPole顶托1"},
{"ScaffoldPole顶托2", "ScaffoldPole顶托2"},
{"ScaffoldPole顶托剖面", "ScaffoldPole顶托剖面"},
{"ScaffoldPole顶托螺母", "ScaffoldPole顶托螺母"},
{"右45度角型钢", "右45度角型钢"},
{"左45度角型钢", "左45度角型钢"}
};
// 块目录
private static readonly string BlockDirectory = Path.Combine(
Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location),
"ScaffoldBlocks");
private Editor _ed;
private List<Entity> _entitiesToAdd;
#region DS命令 - 脚手架绘制
[CommandMethod("DS", CommandFlags.Modal)]
public void DrawScaffold()
{
Document doc = Application.DocumentManager.MdiActiveDocument;
Database db = doc.Database;
_ed = doc.Editor;
_entitiesToAdd = new List<Entity>();
int lineCount = 0, rectCount = 0;
object oldSaveTime = Application.GetSystemVariable("SAVETIME");
try
{
Application.SetSystemVariable("SAVETIME", 0);
_ed.WriteMessage("\n=== 脚手架布置参数输入 ===\n");
double offsetDistance = GetInputWithDefault("①请输入离楼层外沿距离(mm)", DEFAULT_OFFSET_DISTANCE);
double scaffoldWidth = GetInputWithDefault("②请输入外架宽(mm)", DEFAULT_SCAFFOLD_WIDTH);
double maxSpacing = GetInputWithDefault("③请输入立杆最大纵距(mm)", DEFAULT_MAX_SPACING);
if (offsetDistance < 0 || scaffoldWidth < 0 || maxSpacing < 0)
{
_ed.WriteMessage("\n❌ 输入参数不能为负数!");
return;
}
_ed.WriteMessage("\n=== 选择边界线 ===\n");
PromptSelectionOptions pso = new PromptSelectionOptions
{
MessageForAdding = "\n请选择边界线(直线、多段线): ",
RejectObjectsFromNonCurrentSpace = true,
RejectObjectsOnLockedLayers = true
};
TypedValue[] filterList = new TypedValue[]
{
new TypedValue((int)DxfCode.Start, "LINE,POLYLINE,LWPOLYLINE")
};
PromptSelectionResult psr = _ed.GetSelection(pso, new SelectionFilter(filterList));
if (psr.Status == PromptStatus.Cancel)
{
_ed.WriteMessage("\n用户取消操作!");
return;
}
if (psr.Status != PromptStatus.OK || psr.Value.Count == 0)
{
_ed.WriteMessage("\n未选中有效边界线!");
return;
}
using (Transaction tr = db.TransactionManager.StartTransaction())
{
BlockTable bt = (BlockTable)tr.GetObject(db.BlockTableId, OpenMode.ForRead);
BlockTableRecord modelSpace = (BlockTableRecord)tr.GetObject(bt[BlockTableRecord.ModelSpace], OpenMode.ForWrite);
CreateLayers(db);
bool hasBlockRef = psr.Value.Cast<SelectedObject>()
.Any(so => so != null && so.ObjectId.IsValid
&& tr.GetObject(so.ObjectId, OpenMode.ForRead) as BlockReference != null);
if (hasBlockRef)
{
_ed.WriteMessage("\n检测到选择了块引用,请直接选择边界线而不是块!");
tr.Abort();
return;
}
DbPolyline outline = CreateOutlineFromSelectedLines(tr, psr.Value);
if (outline == null)
{
tr.Abort();
return;
}
DbPolyline originalOutline = (DbPolyline)outline.Clone();
originalOutline.SetDatabaseDefaults(db);
originalOutline.Layer = AxisLayer;
originalOutline.ColorIndex = 5;
originalOutline.Closed = true;
_entitiesToAdd.Add(originalOutline);
bool isClockwise = IsClockwise(outline);
double outerOffset = offsetDistance + scaffoldWidth;
double innerOffsetVal = isClockwise ? -offsetDistance : offsetDistance;
double outerOffsetVal = isClockwise ? -outerOffset : outerOffset;
DBObjectCollection innerCurves = outline.GetOffsetCurves(innerOffsetVal);
DBObjectCollection outerCurves = outline.GetOffsetCurves(outerOffsetVal);
if (innerCurves.Count == 0 || outerCurves.Count == 0)
{
innerOffsetVal = -innerOffsetVal;
outerOffsetVal = -outerOffsetVal;
innerCurves = outline.GetOffsetCurves(innerOffsetVal);
outerCurves = outline.GetOffsetCurves(outerOffsetVal);
if (innerCurves.Count == 0 || outerCurves.Count == 0)
{
_ed.WriteMessage("\n轮廓偏移失败!");
tr.Abort();
return;
}
}
DbPolyline innerPl = ConvertToDbPolyline(innerCurves[0], db);
DbPolyline outerPl = ConvertToDbPolyline(outerCurves[0], db);
if (innerPl == null || outerPl == null)
{
_ed.WriteMessage("\n偏移曲线转换失败!");
tr.Abort();
return;
}
SetPolylineProperties(innerPl, db, AxisLayer, 1);
SetPolylineProperties(outerPl, db, AxisLayer, 3);
_entitiesToAdd.Add(innerPl);
_entitiesToAdd.Add(outerPl);
var originalSegments = originalOutline.GetSegments();
if (innerPl.NumberOfVertices >= 3)
{
for (int i = 0; i < innerPl.NumberOfVertices; i++)
{
Point3d innerPt = innerPl.GetPoint3dAt(i);
int nextInnerIdx = (i + 1) % innerPl.NumberOfVertices;
Vector3d tangentDir = (innerPl.GetPoint3dAt(nextInnerIdx) - innerPt).GetNormal();
Vector3d normalDir = GetSegmentNormal(innerPl, i);
bool isOverlap = IsPointOnSegments(innerPt, originalSegments, OVERLAP_TOLERANCE);
if (isOverlap)
{
DrawRectangle(innerPt, normalDir, tangentDir, db);
rectCount++;
}
else
{
DrawLine(innerPt, innerPt + normalDir * scaffoldWidth, db);
lineCount++;
}
}
}
else
{
_ed.WriteMessage("\n内轮廓顶点不足,无法绘制角点分隔线!");
}
if (innerPl.NumberOfVertices >= 2)
{
for (int i = 0; i < innerPl.NumberOfVertices; i++)
{
int nextIdx = (i + 1) % innerPl.NumberOfVertices;
Point3d start = innerPl.GetPoint3dAt(i);
Point3d end = innerPl.GetPoint3dAt(nextIdx);
double length = start.DistanceTo(end);
Vector3d dir = (end - start).GetNormal();
Vector3d normal = GetSegmentNormal(innerPl, i);
if (length < maxSpacing + 100)
{
continue;
}
double currentOffset = 0;
double remainingLength = length;
bool startOverlap = IsPointOnSegments(start, originalSegments, OVERLAP_TOLERANCE);
if (!startOverlap)
{
DrawLine(start, start + normal * scaffoldWidth, db);
lineCount++;
}
else
{
DrawRectangle(start, normal, dir, db);
rectCount++;
}
while (remainingLength > 0)
{
double nextSpacing = GetNextSpacing(remainingLength, maxSpacing);
if (nextSpacing == 0) break;
currentOffset += nextSpacing;
remainingLength = length - currentOffset;
if (currentOffset > length) break;
Point3d innerPoint = start + dir * currentOffset;
bool midOverlap = IsPointOnSegments(innerPoint, originalSegments, OVERLAP_TOLERANCE);
if (!midOverlap)
{
DrawLine(innerPoint, innerPoint + normal * scaffoldWidth, db);
lineCount++;
}
else
{
DrawRectangle(innerPoint, normal, dir, db);
rectCount++;
}
}
bool endOverlap = IsPointOnSegments(end, originalSegments, OVERLAP_TOLERANCE);
if (!endOverlap)
{
DrawLine(end, end + normal * scaffoldWidth, db);
lineCount++;
}
else
{
DrawRectangle(end, normal, dir, db);
rectCount++;
}
}
}
else
{
_ed.WriteMessage("\n内轮廓线段不足,无法绘制立杆分隔线!");
}
foreach (var entity in _entitiesToAdd)
{
if (entity != null)
{
modelSpace.AppendEntity(entity);
tr.AddNewlyCreatedDBObject(entity, true);
}
}
tr.Commit();
_ed.WriteMessage($"\n✅ 脚手架布置成功!");
_ed.WriteMessage($"\n📋 参数:外沿距离{offsetDistance:F0}mm | 外架宽{scaffoldWidth:F0}mm | 立杆纵距{maxSpacing:F0}mm");
_ed.WriteMessage($"\n📌 生成:原始轮廓(蓝) | 内轮廓(红) | 外轮廓(绿) | 直线分隔线({lineCount}条) | 矩形分隔线({rectCount}个)");
}
}
catch (Exception ex)
{
_ed.WriteMessage($"\n❌ 脚手架绘制错误:{ex.Message}\n堆栈:{ex.StackTrace}");
}
finally
{
if (oldSaveTime != null)
{
Application.SetSystemVariable("SAVETIME", oldSaveTime);
}
_entitiesToAdd?.Clear();
}
}
#endregion
#region GP命令 - 钢踏板布置
[CommandMethod("GP", CommandFlags.Modal)]
public void ArrangeSteelPedal()
{
Document doc = Application.DocumentManager.MdiActiveDocument;
Database db = doc.Database;
_ed = doc.Editor;
try
{
_ed.WriteMessage("\n=== 钢踏板布置 ===\n");
_ed.WriteMessage("\n请选择内轮廓线(第一道轮廓线): ");
PromptEntityOptions peoInner = new PromptEntityOptions("\n请选择内轮廓线(第一道轮廓线): ");
peoInner.SetRejectMessage("\n请选择多段线!");
peoInner.AddAllowedClass(typeof(DbPolyline), true);
PromptEntityResult perInner = _ed.GetEntity(peoInner);
if (perInner.Status == PromptStatus.Cancel)
{
_ed.WriteMessage("\n用户取消操作!");
return;
}
_ed.WriteMessage("\n请选择外轮廓线(第二道轮廓线): ");
PromptEntityOptions peoOuter = new PromptEntityOptions("\n请选择外轮廓线(第二道轮廓线): ");
peoOuter.SetRejectMessage("\n请选择多段线!");
peoOuter.AddAllowedClass(typeof(DbPolyline), true);
PromptEntityResult perOuter = _ed.GetEntity(peoOuter);
if (perOuter.Status == PromptStatus.Cancel)
{
_ed.WriteMessage("\n用户取消操作!");
return;
}
_ed.WriteMessage("\n请框选所有横杆图块: ");
PromptSelectionOptions pso = new PromptSelectionOptions
{
MessageForAdding = "\n选择所有横杆图块: ",
RejectObjectsFromNonCurrentSpace = true,
RejectObjectsOnLockedLayers = true
};
TypedValue[] filterList = new TypedValue[]
{
new TypedValue((int)DxfCode.Start, "INSERT")
};
PromptSelectionResult psr = _ed.GetSelection(pso, new SelectionFilter(filterList));
if (psr.Status == PromptStatus.Cancel)
{
_ed.WriteMessage("\n用户取消操作!");
return;
}
if (psr.Status != PromptStatus.OK || psr.Value.Count == 0)
{
_ed.WriteMessage("\n未选中有效横杆图块!");
return;
}
string scaffoldBlocksPath = Path.Combine(BlockDirectory);
if (!Directory.Exists(scaffoldBlocksPath))
{
_ed.WriteMessage($"\n❌ 找不到图块目录: {scaffoldBlocksPath}");
return;
}
Dictionary<string, string> pedalBlockPaths = new Dictionary<string, string>
{
{"900", Path.Combine(scaffoldBlocksPath, "ScaffoldPole钢踏板900mm.dwg")},
{"1200", Path.Combine(scaffoldBlocksPath, "ScaffoldPole钢踏板1200mm.dwg")},
{"1500", Path.Combine(scaffoldBlocksPath, "ScaffoldPole钢踏板1500mm.dwg")},
{"1800", Path.Combine(scaffoldBlocksPath, "ScaffoldPole钢踏板1800mm.dwg")},
{"single", Path.Combine(scaffoldBlocksPath, "ScaffoldPole单片钢踏板.dwg")}
};
foreach (var blockPath in pedalBlockPaths)
{
if (!File.Exists(blockPath.Value))
{
_ed.WriteMessage($"\n❌ 找不到钢踏板图块文件: {blockPath.Value}");
return;
}
}
_ed.WriteMessage($"\n✅ 所有钢踏板图块文件都存在");
using (Transaction tr = db.TransactionManager.StartTransaction())
{
BlockTable bt = (BlockTable)tr.GetObject(db.BlockTableId, OpenMode.ForRead);
BlockTableRecord modelSpace = (BlockTableRecord)tr.GetObject(bt[BlockTableRecord.ModelSpace], OpenMode.ForWrite);
DbPolyline innerPl = tr.GetObject(perInner.ObjectId, OpenMode.ForRead) as DbPolyline;
DbPolyline outerPl = tr.GetObject(perOuter.ObjectId, OpenMode.ForRead) as DbPolyline;
if (innerPl == null || outerPl == null)
{
_ed.WriteMessage("\n❌ 选择的轮廓线无效!");
return;
}
int processedCount = 0;
int pedalCount = 0;
int skippedCount = 0;
foreach (SelectedObject so in psr.Value)
{
if (so == null || !so.ObjectId.IsValid) continue;
BlockReference blockRef = tr.GetObject(so.ObjectId, OpenMode.ForRead) as BlockReference;
if (blockRef == null) continue;
BlockTableRecord btr = (BlockTableRecord)tr.GetObject(blockRef.BlockTableRecord, OpenMode.ForRead);
string blockName = btr.Name;
double beamLength = ParseBeamLength(blockName);
if (beamLength <= 0) continue;
Point3d blockPosition = blockRef.Position;
double distanceToInner = GetDistanceToPolyline(blockPosition, innerPl);
double distanceToOuter = GetDistanceToPolyline(blockPosition, outerPl);
if (distanceToOuter > OUTLINE_TOLERANCE)
{
skippedCount++;
continue;
}
string pedalBlockName = GetPedalBlockName(beamLength);
if (string.IsNullOrEmpty(pedalBlockName)) continue;
if (!bt.Has(pedalBlockName))
{
using (Database sourceDb = new Database(false, true))
{
try
{
sourceDb.ReadDwgFile(pedalBlockPaths[pedalBlockName], FileShare.Read, true, "");
ObjectId mappingId = db.Insert(pedalBlockName, sourceDb, true);
if (!mappingId.IsValid)
{
_ed.WriteMessage($"\n❌ 导入钢踏板图块失败: {pedalBlockName}");
continue;
}
}
catch (Exception ex)
{
_ed.WriteMessage($"\n❌ 读取图块文件失败: {pedalBlockPaths[pedalBlockName]}, 错误: {ex.Message}");
continue;
}
}
}
int pedalQuantity = CalculatePedalQuantity(beamLength, pedalBlockName);
if (pedalQuantity <= 0) continue;
if (PlacePedals(tr, modelSpace, blockRef, pedalBlockName, pedalQuantity, beamLength))
{
processedCount++;
pedalCount += pedalQuantity;
}
}
tr.Commit();
_ed.WriteMessage($"\n✅ 钢踏板布置完成!处理了 {processedCount} 根第二道轮廓线上的横杆,共布置 {pedalCount} 块钢踏板");
if (skippedCount > 0)
{
_ed.WriteMessage($"\n⚠️ 跳过了 {skippedCount} 根第一道轮廓线及分隔线上的横杆");
}
}
}
catch (Exception ex)
{
_ed.WriteMessage($"\n❌ 钢踏板布置错误:{ex.Message}\n堆栈:{ex.StackTrace}");
}
}
private double GetDistanceToPolyline(Point3d point, DbPolyline pl)
{
double minDistance = double.MaxValue;
for (int i = 0; i < pl.NumberOfVertices; i++)
{
int nextIdx = (i + 1) % pl.NumberOfVertices;
Point3d start = pl.GetPoint3dAt(i);
Point3d end = pl.GetPoint3dAt(nextIdx);
double distance = PointToLineDistance(point, start, end);
if (distance < minDistance)
{
minDistance = distance;
}
}
return minDistance;
}
private double ParseBeamLength(string blockName)
{
if (blockName.Contains("横杆"))
{
if (blockName.Contains("1800mm")) return 1800;
if (blockName.Contains("1500mm")) return 1500;
if (blockName.Contains("1200mm")) return 1200;
if (blockName.Contains("900mm")) return 900;
if (blockName.Contains("600mm")) return 600;
if (blockName.Contains("300mm")) return 300;
}
return 0;
}
private string GetPedalBlockName(double beamLength)
{
switch (beamLength)
{
case 1800: return "1800";
case 1500: return "1500";
case 1200: return "1200";
case 900: return "900";
case 600:
case 300:
default: return "single";
}
}
private int CalculatePedalQuantity(double beamLength, string pedalBlockName)
{
if (pedalBlockName == "single")
{
return (int)Math.Ceiling(beamLength / 240.0);
}
return 1;
}
private bool PlacePedals(Transaction tr, BlockTableRecord modelSpace, BlockReference beamRef,
string pedalBlockName, int quantity, double beamLength)
{
try
{
BlockTable bt = (BlockTable)tr.GetObject(beamRef.Database.BlockTableId, OpenMode.ForRead);
if (!bt.Has(pedalBlockName)) return false;
ObjectId pedalBlockId = bt[pedalBlockName];
Point3d insertionPoint = beamRef.Position;
double rotation = beamRef.Rotation;
Vector3d direction = new Vector3d(Math.Cos(rotation), Math.Sin(rotation), 0);
Vector3d perpendicular = direction.GetPerpendicularVector();
double singlePedalWidth = 240.0;
if (pedalBlockName != "single")
{
singlePedalWidth = beamLength;
}
double totalWidth = quantity * singlePedalWidth;
double startOffset = -singlePedalWidth;
for (int i = 0; i < quantity; i++)
{
double offset = startOffset + i * singlePedalWidth + singlePedalWidth / 2.0;
Point3d pedalPosition = insertionPoint + direction * offset;
BlockReference pedalRef = new BlockReference(pedalPosition, pedalBlockId);
pedalRef.Rotation = rotation;
pedalRef.Layer = "盘扣-钢踏板";
pedalRef.ColorIndex = 6;
modelSpace.AppendEntity(pedalRef);
tr.AddNewlyCreatedDBObject(pedalRef, true);
}
return true;
}
catch (Exception ex)
{
_ed.WriteMessage($"\n❌ 布置钢踏板失败: {ex.Message}");
return false;
}
}
#endregion
#region 辅助方法
private double GetInputWithDefault(string prompt, double defaultValue)
{
PromptDoubleOptions pdo = new PromptDoubleOptions($"\n{prompt} [默认: {defaultValue}]: ");
pdo.DefaultValue = defaultValue;
pdo.AllowNone = true;
PromptDoubleResult pdr = _ed.GetDouble(pdo);
if (pdr.Status == PromptStatus.Cancel) return -1;
if (pdr.Status == PromptStatus.None) return defaultValue;
return pdr.Value;
}
private double GetNextSpacing(double remainingLength, double maxSpacing)
{
if (remainingLength >= maxSpacing) return maxSpacing;
if (remainingLength >= 1500) return 1500;
if (remainingLength >= 1200) return 1200;
if (remainingLength >= 900) return 900;
if (remainingLength >= 600) return 600;
if (remainingLength >= 300) return 300;
return 0;
}
private bool IsPointOnSegments(Point3d point, List<(Point3d Start, Point3d End)> segments, double tolerance)
{
foreach (var (start, end) in segments)
{
double dist = PointToLineDistance(point, start, end);
if (dist < tolerance)
return true;
}
return false;
}
private void DrawLine(Point3d start, Point3d end, Database db)
{
Line line = new Line(start, end);
line.SetDatabaseDefaults(db);
line.Layer = AxisLayer;
line.ColorIndex = 4;
_entitiesToAdd.Add(line);
}
private void DrawRectangle(Point3d startPoint, Vector3d normalDir, Vector3d tangentDir, Database db)
{
Vector3d normal = normalDir.GetNormal();
Vector3d tangent = tangentDir.GetNormal();
Point3d p0 = startPoint;
Point3d p1 = p0 + normal * RECT_SIDE_LENGTH;
Point3d p3 = p0 + tangent * RECT_SIDE_LENGTH;
Point3d p2 = p1 + tangent * RECT_SIDE_LENGTH;
DbPolyline rectPoly = new DbPolyline();
rectPoly.SetDatabaseDefaults(db);
rectPoly.Layer = AxisLayer;
rectPoly.ColorIndex = 4;
rectPoly.Closed = true;
rectPoly.AddVertexAt(0, new Point2d(p0.X, p0.Y), 0, 0, 0);
rectPoly.AddVertexAt(1, new Point2d(p1.X, p1.Y), 0, 0, 0);
rectPoly.AddVertexAt(2, new Point2d(p2.X, p2.Y), 0, 0, 0);
rectPoly.AddVertexAt(3, new Point2d(p3.X, p3.Y), 0, 0, 0);
_entitiesToAdd.Add(rectPoly);
}
private void SetPolylineProperties(DbPolyline pl, Database db, string layer, int colorIndex)
{
pl.SetDatabaseDefaults(db);
pl.Closed = true;
pl.Layer = layer;
pl.ColorIndex = colorIndex;
}
private DbPolyline CreateOutlineFromSelectedLines(Transaction tr, SelectionSet ss)
{
try
{
List<Line> selectedLines = new List<Line>();
List<DbPolyline> selectedPolylines = new List<DbPolyline>();
foreach (SelectedObject so in ss)
{
if (so == null || !so.ObjectId.IsValid) continue;
Entity ent = tr.GetObject(so.ObjectId, OpenMode.ForRead) as Entity;
if (ent is Line line) selectedLines.Add(line);
else if (ent is DbPolyline pl) selectedPolylines.Add(pl);
}
if (selectedPolylines.Count > 0)
{
if (selectedPolylines.Count == 1 && selectedPolylines[0].Closed)
return selectedPolylines[0].Clone() as DbPolyline;
return JoinPolylines(selectedPolylines);
}
if (selectedLines.Count < 2)
{
_ed.WriteMessage("\n至少需要选择两条线段才能形成闭合轮廓!");
return null;
}
List<Point3d> intersectionPoints = new List<Point3d>();
for (int i = 0; i < selectedLines.Count; i++)
{
for (int j = i + 1; j < selectedLines.Count; j++)
{
Point3dCollection intersectPoints = new Point3dCollection();
selectedLines[i].IntersectWith(selectedLines[j], Intersect.OnBothOperands, intersectPoints, IntPtr.Zero, IntPtr.Zero);
foreach (Point3d pt in intersectPoints) intersectionPoints.Add(pt);
}
}
if (intersectionPoints.Count < 2)
{
_ed.WriteMessage("\n选择的线段没有足够的交点形成闭合轮廓!");
return null;
}
return CreatePolylineFromIntersections(selectedLines, intersectionPoints);
}
catch (Exception ex)
{
_ed.WriteMessage($"\n轮廓生成错误:{ex.Message}");
return null;
}
}
private DbPolyline CreatePolylineFromIntersections(List<Line> lines, List<Point3d> intersections)
{
try
{
List<Point3d> boundaryPoints = new List<Point3d>(intersections);
Point3dComparer comparer = new Point3dComparer(0.001);
foreach (Line line in lines)
{
if (!boundaryPoints.Contains(line.StartPoint, comparer)) boundaryPoints.Add(line.StartPoint);
if (!boundaryPoints.Contains(line.EndPoint, comparer)) boundaryPoints.Add(line.EndPoint);
}
List<Point3d> convexHull = ComputeConvexHull(boundaryPoints);
DbPolyline polyline = new DbPolyline();
for (int i = 0; i < convexHull.Count; i++)
{
polyline.AddVertexAt(i, new Point2d(convexHull[i].X, convexHull[i].Y), 0, 0, 0);
}
polyline.Closed = true;
return polyline;
}
catch (Exception ex)
{
_ed.WriteMessage($"\n创建轮廓错误:{ex.Message}");
return null;
}
}
private List<Point3d> ComputeConvexHull(List<Point3d> points)
{
if (points.Count < 3) return points;
Point3d startPoint = points[0];
foreach (Point3d p in points)
{
if (p.X < startPoint.X || (Math.Abs(p.X - startPoint.X) < 0.001 && p.Y < startPoint.Y))
{
startPoint = p;
}
}
List<Point3d> sortedPoints = new List<Point3d>(points);
sortedPoints.Sort((a, b) =>
{
if (a == startPoint) return -1;
if (b == startPoint) return 1;
double cross = CrossProduct(startPoint, a, b);
if (Math.Abs(cross) < 0.001)
return startPoint.DistanceTo(a).CompareTo(startPoint.DistanceTo(b));
return cross > 0 ? -1 : 1;
});
List<Point3d> hull = new List<Point3d> { startPoint };
if (sortedPoints.Count > 1) hull.Add(sortedPoints[1]);
for (int i = 2; i < sortedPoints.Count; i++)
{
while (hull.Count >= 2 && CrossProduct(hull[hull.Count - 2], hull[hull.Count - 1], sortedPoints[i]) <= 0)
{
hull.RemoveAt(hull.Count - 1);
}
hull.Add(sortedPoints[i]);
}
return hull;
}
private double CrossProduct(Point3d o, Point3d a, Point3d b)
{
return (a.X - o.X) * (b.Y - o.Y) - (a.Y - o.Y) * (b.X - o.X);
}
private DbPolyline JoinPolylines(List<DbPolyline> polylines)
{
return polylines[0].Clone() as DbPolyline;
}
private DbPolyline ConvertToDbPolyline(DBObject obj, Database db)
{
if (obj is DbPolyline pl)
{
pl.SetDatabaseDefaults(db);
return pl;
}
if (obj is Line line)
{
DbPolyline newPl = new DbPolyline();
newPl.SetDatabaseDefaults(db);
newPl.AddVertexAt(0, new Point2d(line.StartPoint.X, line.StartPoint.Y), 0, 0, 0);
newPl.AddVertexAt(1, new Point2d(line.EndPoint.X, line.EndPoint.Y), 0, 0, 0);
newPl.Closed = false;
return newPl;
}
if (obj is Arc arc)
{
DbPolyline newPl = new DbPolyline();
newPl.SetDatabaseDefaults(db);
double startAng = arc.StartAngle;
double endAng = arc.EndAngle;
double centralAng = endAng - startAng;
if (centralAng < 0) centralAng += 2 * Math.PI;
if (IsArcClockWise(arc)) centralAng = -centralAng;
double bulge = Math.Tan(centralAng / 4);
newPl.AddVertexAt(0, new Point2d(arc.StartPoint.X, arc.StartPoint.Y), bulge, 0, 0);
newPl.AddVertexAt(1, new Point2d(arc.EndPoint.X, arc.EndPoint.Y), 0, 0, 0);
newPl.Closed = false;
return newPl;
}
return null;
}
private bool IsArcClockWise(Arc arc)
{
Point3d center = arc.Center;
Point3d start = arc.StartPoint;
Point3d end = arc.EndPoint;
Vector2d vec1 = new Vector2d(start.X - center.X, start.Y - center.Y);
Vector2d vec2 = new Vector2d(end.X - center.X, end.Y - center.Y);
double crossProduct = vec1.X * vec2.Y - vec1.Y * vec2.X;
return crossProduct < 0;
}
private bool IsClockwise(DbPolyline pl)
{
if (pl == null || pl.NumberOfVertices < 3) return false;
double area = 0;
int vertCount = pl.NumberOfVertices;
for (int i = 0; i < vertCount; i++)
{
Point2d p1 = pl.GetPoint2dAt(i);
Point2d p2 = pl.GetPoint2dAt((i + 1) % vertCount);
area += p1.X * p2.Y - p2.X * p1.Y;
}
return area < 0;
}
private Vector3d GetSegmentNormal(DbPolyline pl, int segmentIndex)
{
if (pl == null || segmentIndex < 0 || segmentIndex >= pl.NumberOfVertices)
return Vector3d.ZAxis;
int nextIdx = (segmentIndex + 1) % pl.NumberOfVertices;
Point3d start = pl.GetPoint3dAt(segmentIndex);
Point3d end = pl.GetPoint3dAt(nextIdx);
Vector3d dir = (end - start).GetNormal();
Vector3d normal = new Vector3d(-dir.Y, dir.X, 0).GetNormal();
Point3d midPoint = start + (end - start) * 0.5;
Point3d testPoint = midPoint + normal * 10;
if (IsPointInsidePolyline(pl, testPoint))
normal = -normal;
return normal;
}
private bool IsPointInsidePolyline(DbPolyline pl, Point3d point)
{
if (pl == null || !pl.Closed) return false;
int crossings = 0;
int vertexCount = pl.NumberOfVertices;
for (int i = 0; i < vertexCount; i++)
{
int j = (i + 1) % vertexCount;
Point3d vi = pl.GetPoint3dAt(i);
Point3d vj = pl.GetPoint3dAt(j);
if (((vi.Y <= point.Y) && (vj.Y > point.Y)) || ((vj.Y <= point.Y) && (vi.Y > point.Y)))
{
double vt = (point.Y - vi.Y) / (vj.Y - vi.Y);
if (point.X < vi.X + vt * (vj.X - vi.X))
crossings++;
}
}
return (crossings % 2) != 0;
}
private double PointToLineDistance(Point3d point, Point3d lineStart, Point3d lineEnd)
{
Vector3d lineVec = lineEnd - lineStart;
Vector3d pointVec = point - lineStart;
double lineLength = lineVec.Length;
if (lineLength < 1e-10) return pointVec.Length;
Vector3d normalizedLineVec = lineVec / lineLength;
double projLength = pointVec.X * normalizedLineVec.X + pointVec.Y * normalizedLineVec.Y + pointVec.Z * normalizedLineVec.Z;
if (projLength < 0) return pointVec.Length;
if (projLength > lineLength) return (point - lineEnd).Length;
Point3d projPoint = lineStart + normalizedLineVec * projLength;
return point.DistanceTo(projPoint);
}
private void CreateLayers(Database db)
{
using (Transaction tr = db.TransactionManager.StartTransaction())
{
CreateLayerIfNotExists(tr, db, PoleLayer, 7);
CreateLayerIfNotExists(tr, db, BarLayer, 1);
CreateLayerIfNotExists(tr, db, DiagonalBarLayer, 4);
CreateLayerIfNotExists(tr, db, AxisLayer, 3);
CreateLayerIfNotExists(tr, db, DebugLayer, 2);
CreateLayerIfNotExists(tr, db, "盘扣-钢踏板", 6);
tr.Commit();
}
}
private void CreateLayerIfNotExists(Transaction tr, Database db, string layerName, int colorIndex = 7)
{
if (string.IsNullOrEmpty(layerName)) return;
LayerTable lt = (LayerTable)tr.GetObject(db.LayerTableId, OpenMode.ForRead);
if (!lt.Has(layerName))
{
lt.UpgradeOpen();
LayerTableRecord ltr = new LayerTableRecord
{
Name = layerName,
Color = Autodesk.AutoCAD.Colors.Color.FromColorIndex(Autodesk.AutoCAD.Colors.ColorMethod.ByAci, (short)colorIndex)
};
lt.Add(ltr);
tr.AddNewlyCreatedDBObject(ltr, true);
lt.DowngradeOpen();
_ed.WriteMessage($"\n创建图层:{layerName}");
}
}
#endregion
}
/// <summary>
/// Point3d比较器(含容差)
/// </summary>
public class Point3dComparer : IEqualityComparer<Point3d>
{
private double _tolerance;
public Point3dComparer(double tolerance)
{
_tolerance = tolerance;
}
public bool Equals(Point3d x, Point3d y)
{
return x.DistanceTo(y) < _tolerance;
}
public int GetHashCode(Point3d obj)
{
return obj.X.GetHashCode() ^ obj.Y.GetHashCode() ^ obj.Z.GetHashCode();
}
}
}
命令: GP
=== 钢踏板布置 ===
请选择内轮廓线(第一道轮廓线):
请选择内轮廓线(第一道轮廓线):
请选择外轮廓线(第二道轮廓线):
请选择外轮廓线(第二道轮廓线):
请框选所有横杆图块:
选择所有横杆图块: 指定对角点: 找到 1267 个
选择所有横杆图块:
❌ 找不到钢踏板图块文件: C:\ProgramData\Autodesk\ApplicationPlugins\Zhongli Mojia Software.bundle\Zhongli Mojia Software\net48\ScaffoldBlocks\ScaffoldPole钢踏板900mm.dwg
图块路径改成: // 嵌入式图块映射表
1.90度阳角型钢
2.ScaffoldPole90度阳角型钢
3.ScaffoldPole90度阳角配件
4.ScaffoldPole三角架
5.ScaffoldPole传统连墙件
6.ScaffoldPole单片钢踏板
7.ScaffoldPole卸料平台立面布置大样图
8.ScaffoldPole卸料钢平台大样图
9.ScaffoldPole双槽钢拖梁
10.ScaffoldPole双槽钢拖梁1350mm
11.ScaffoldPole双槽钢拖梁1650mm
12.ScaffoldPole右45度角型钢
13.ScaffoldPole固定桩
14.ScaffoldPole外架临时支撑大样图
15.ScaffoldPole外架剖面大样图
16.ScaffoldPole外架斜拉杆1200mm
17.ScaffoldPole外架斜拉杆1500mm
18.ScaffoldPole外架斜拉杆1800mm
19.ScaffoldPole外架斜拉杆600mm
20.ScaffoldPole外架斜拉杆900mm
21.ScaffoldPole工字钢与联梁加固节点图
22.ScaffoldPole工字钢连梁
23.ScaffoldPole左45度角型钢
24.ScaffoldPole底托
25.ScaffoldPole底托1
26.ScaffoldPole底托螺母
27.ScaffoldPole悬挑型钢
28.ScaffoldPole悬挑架用材和拉杆大样图
29.ScaffoldPole扣件
30.ScaffoldPole扣件2
31.ScaffoldPole扣件900mm
32.ScaffoldPole新型连墙件
33.ScaffoldPole方钢
34.ScaffoldPole方钢1000mm
35.ScaffoldPole施工电梯平面大样图
36.ScaffoldPole施工电梯立面大样图
37.ScaffoldPole横杆1200mm
38.ScaffoldPole横杆1500mm
39.ScaffoldPole横杆1800mm
40.ScaffoldPole横杆300mm
41.ScaffoldPole横杆600mm
42.ScaffoldPole横杆900mm
43.ScaffoldPole水平斜拉杆1200mm
44.ScaffoldPole水平斜拉杆1500mm
45.ScaffoldPole水平斜拉杆1800mm
46.ScaffoldPole水平斜拉杆600mm
47.ScaffoldPole水平斜拉杆900mm
48.ScaffoldPole爬梯样板
49.ScaffoldPole立杆
50.ScaffoldPole立杆1000mm
51.ScaffoldPole立杆1500mm
52.ScaffoldPole立杆2000mm
53.ScaffoldPole立杆200mm
54.ScaffoldPole立杆2500mm
55.ScaffoldPole立杆350mm
56.ScaffoldPole立杆500mm
57.ScaffoldPole立横杆1200mm
58.ScaffoldPole立横杆1500mm
59.ScaffoldPole立横杆1800mm
60.ScaffoldPole立横杆300mm
61.ScaffoldPole立横杆600mm
62.ScaffoldPole立横杆900mm
63.ScaffoldPole竖向斜拉杆1200mm
64.ScaffoldPole竖向斜拉杆1500mm
65.ScaffoldPole竖向斜拉杆1800mm
66.ScaffoldPole竖向斜拉杆600mm
67.ScaffoldPole竖向斜拉杆900mm
68.ScaffoldPole钢踏板1200mm
69.ScaffoldPole钢踏板1500mm
70.ScaffoldPole钢踏板1800mm
71.ScaffoldPole钢踏板900mm
72.ScaffoldPole阳角斜拉大样图
73.ScaffoldPole顶托
74.ScaffoldPole顶托1
75.ScaffoldPole顶托2
76.ScaffoldPole顶托剖面
77.ScaffoldPole顶托螺母
78.右45度角型钢
79.左45度角型钢
最新发布