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.IO;
using System.Linq;
namespace ScaffoldPlugin
{
public class ScaffoldCommands
{
// 水平杆标准尺寸及对应图块名称
private static readonly Dictionary<double, string> PoleBlocks = new Dictionary<double, string>
{
{ 600, "ScaffoldPolexie水平杆600mm.dwg" },
{ 900, "ScaffoldPolexie水平杆900mm.dwg" },
{ 1200, "ScaffoldPolexie水平杆1200mm.dwg" },
{ 1500, "ScaffoldPolexie水平杆1500mm.dwg" },
{ 1800, "ScaffoldPolexie水平杆1800mm.dwg" }
};
// 存储已布置的水平杆位置(用于避免重复)
private static readonly HashSet<string> PlacedPoles = new HashSet<string>();
[CommandMethod("HPD", CommandFlags.Modal)]
public void HorizontalPoleDistribution()
{
Document doc = Application.DocumentManager.MdiActiveDocument;
Database db = doc.Database;
Editor ed = doc.Editor;
try
{
// 清除之前的布置记录
PlacedPoles.Clear();
// 选择布置模式
PromptIntegerOptions modeOpts = new PromptIntegerOptions("\n选择布置模式: [1隔一布一/2隔二布一/3隔三布一/4满布]")
{
AllowZero = false,
AllowNegative = false,
LowerLimit = 1,
UpperLimit = 4,
UseDefaultValue = true,
DefaultValue = 4
};
PromptIntegerResult modeRes = ed.GetInteger(modeOpts);
if (modeRes.Status != PromptStatus.OK) return;
int mode = modeRes.Value;
// 框选盘扣轴网
PromptSelectionOptions selOpts = new PromptSelectionOptions
{
MessageForAdding = "\n框选盘扣轴网: ",
AllowDuplicates = false
};
PromptSelectionResult selRes = ed.GetSelection(selOpts);
if (selRes.Status != PromptStatus.OK) return;
using (Transaction tr = db.TransactionManager.StartTransaction())
{
BlockTable bt = tr.GetObject(db.BlockTableId, OpenMode.ForRead) as BlockTable;
BlockTableRecord btr = tr.GetObject(bt[BlockTableRecord.ModelSpace], OpenMode.ForWrite) as BlockTableRecord;
// 收集所有网格线
List<Line> gridLines = new List<Line>();
foreach (SelectedObject selObj in selRes.Value)
{
Entity ent = tr.GetObject(selObj.ObjectId, OpenMode.ForRead) as Entity;
if (ent is Line line && IsGridLine(line))
gridLines.Add(line);
}
if (gridLines.Count == 0)
{
ed.WriteMessage("\n未找到有效的网格线");
return;
}
// 构建网格拓扑 - 完全重构
GridTopology grid = new GridTopology(gridLines, ed);
if (!grid.IsValid)
{
ed.WriteMessage("\n错误:无法构建有效网格拓扑");
return;
}
ed.WriteMessage($"\n构建网格拓扑成功:{grid.Rows}行 x {grid.Cols}列");
// 执行布置逻辑
int poleCount = 0;
switch (mode)
{
case 1: poleCount = PlacePolesMode1(grid, btr, tr, db, ed); break;
case 2: poleCount = PlacePolesMode2(grid, btr, tr, db, ed); break;
case 3: poleCount = PlacePolesMode3(grid, btr, tr, db, ed); break;
case 4: poleCount = PlacePolesMode4(grid, btr, tr, db, ed); break;
}
tr.Commit();
ed.WriteMessage($"\n成功布置{poleCount}根水平杆");
}
}
catch (System.Exception ex)
{
ed.WriteMessage($"\n错误: {ex.Message}\n{ex.StackTrace}");
}
}
[CommandMethod("FLP", CommandFlags.Modal)]
public void FlipHorizontalPoles()
{
Document doc = Application.DocumentManager.MdiActiveDocument;
Editor ed = doc.Editor;
try
{
// 选择要翻转的水平杆
PromptSelectionOptions opts = new PromptSelectionOptions
{
MessageForAdding = "\n选择要翻转的水平杆: "
};
PromptSelectionResult selRes = ed.GetSelection(opts);
if (selRes.Status != PromptStatus.OK) return;
int flipCount = 0;
using (Transaction tr = doc.TransactionManager.StartTransaction())
{
Database db = doc.Database;
BlockTable bt = tr.GetObject(db.BlockTableId, OpenMode.ForRead) as BlockTable;
foreach (SelectedObject selObj in selRes.Value)
{
BlockReference br = tr.GetObject(selObj.ObjectId, OpenMode.ForWrite) as BlockReference;
if (br != null && IsPoleBlock(br))
{
// 计算新旋转角度(旋转180度)
br.TransformBy(Matrix3d.Rotation(Math.PI, Vector3d.ZAxis, br.Position));
flipCount++;
}
}
tr.Commit();
}
ed.WriteMessage($"\n成功翻转{flipCount}根水平杆");
}
catch (System.Exception ex)
{
ed.WriteMessage($"\n错误: {ex.Message}");
}
}
// 判断是否为网格线 (带容差)
private bool IsGridLine(Line line, double angleTolerance = 0.01)
{
if (line == null) return false;
Vector3d vec = line.EndPoint - line.StartPoint;
if (vec.Length < 0.001) return false; // 忽略零长度线段
// 检查是否为水平或垂直线
double angleToX = vec.GetAngleTo(Vector3d.XAxis);
double angleToY = vec.GetAngleTo(Vector3d.YAxis);
return angleToX < angleTolerance || Math.Abs(angleToX - Math.PI) < angleTolerance ||
angleToY < angleTolerance || Math.Abs(angleToY - Math.PI) < angleTolerance;
}
// 判断是否为水平杆图块
private bool IsPoleBlock(BlockReference br)
{
return PoleBlocks.Values.Any(name =>
br.Name.Equals(name, StringComparison.OrdinalIgnoreCase));
}
// 生成唯一标识符用于检测重复
private string GetSegmentKey(LineSegment seg)
{
return $"{Math.Round(seg.StartPoint.X, 3)},{Math.Round(seg.StartPoint.Y, 3)}|" +
$"{Math.Round(seg.EndPoint.X, 3)},{Math.Round(seg.EndPoint.Y, 3)}";
}
// 模式1:隔一布一 (2x2单元)
private int PlacePolesMode1(GridTopology grid, BlockTableRecord btr, Transaction tr, Database db, Editor ed)
{
int count = 0;
for (int row = 0; row < grid.Rows; row += 2) // 每2行一个单元
{
for (int col = 0; col < grid.Cols; col += 2) // 每2列一个单元
{
// 布置当前单元的4条边
if (PlacePoleOnSegment(grid.GetHorizontalSegment(row, col), btr, tr, db, ed, grid)) count++; // 上边
if (PlacePoleOnSegment(grid.GetHorizontalSegment(row + 1, col), btr, tr, db, ed, grid)) count++; // 下边
if (PlacePoleOnSegment(grid.GetVerticalSegment(row, col), btr, tr, db, ed, grid)) count++; // 左边
if (PlacePoleOnSegment(grid.GetVerticalSegment(row, col + 1), btr, tr, db, ed, grid)) count++; // 右边
}
}
return count;
}
// 模式2:隔二布一 (3跨单元)
private int PlacePolesMode2(GridTopology grid, BlockTableRecord btr, Transaction tr, Database db, Editor ed)
{
int count = 0;
// 遍历所有行
for (int row = 0; row < grid.Rows; row++)
{
// 按3列一个单元循环
for (int col = 0; col < grid.Cols; col += 3)
{
// 第一个方格 (满布四边)
if (col < grid.Cols)
{
// 布置四边
if (PlacePoleOnSegment(grid.GetHorizontalSegment(row, col), btr, tr, db, ed, grid)) count++; // 上边
if (PlacePoleOnSegment(grid.GetHorizontalSegment(row + 1, col), btr, tr, db, ed, grid)) count++; // 下边
if (PlacePoleOnSegment(grid.GetVerticalSegment(row, col), btr, tr, db, ed, grid)) count++; // 左边
if (PlacePoleOnSegment(grid.GetVerticalSegment(row, col + 1), btr, tr, db, ed, grid)) count++; // 右边
}
// 第二个方格 (中间方格(第二、三跨),只布置上下水平杆)
int col2 = col + 2;
if (col2 < grid.Cols)
{
// 只布置水平方向左右边的水平杆
if (PlacePoleOnSegment(grid.GetVerticalSegment(row, col2), btr, tr, db, ed, grid)) count++; // 左边
if (PlacePoleOnSegment(grid.GetVerticalSegment(row, col2 + 1), btr, tr, db, ed, grid)) count++; // 右边
// 严禁布置垂直杆件上的水平杆(不布置左右边)
}
// 第四个方格 (在下一个单元的第一个位置)
int col4 = col + 3;
if (col4 < grid.Cols)
{
// 布置四边
if (PlacePoleOnSegment(grid.GetHorizontalSegment(row, col4), btr, tr, db, ed, grid)) count++; // 上边
if (PlacePoleOnSegment(grid.GetHorizontalSegment(row + 1, col4), btr, tr, db, ed, grid)) count++; // 下边
if (PlacePoleOnSegment(grid.GetVerticalSegment(row, col4), btr, tr, db, ed, grid)) count++; // 左边
if (PlacePoleOnSegment(grid.GetVerticalSegment(row, col4 + 1), btr, tr, db, ed, grid)) count++; // 右边
}
}
}
return count;
}
// 模式3:隔三布一 (4跨单元)
private int PlacePolesMode3(GridTopology grid, BlockTableRecord btr, Transaction tr, Database db, Editor ed)
{
int count = 0;
// 遍历所有行
for (int row = 0; row < grid.Rows; row++)
{
// 按4跨一个单元循环
for (int col = 0; col < grid.Cols; col += 4)
{
// 第一个方格 (满布四边)
if (col < grid.Cols)
{
// 布置四边
if (PlacePoleOnSegment(grid.GetHorizontalSegment(row, col), btr, tr, db, ed, grid)) count++; // 上边
if (PlacePoleOnSegment(grid.GetHorizontalSegment(row + 1, col), btr, tr, db, ed, grid)) count++; // 下边
if (PlacePoleOnSegment(grid.GetVerticalSegment(row, col), btr, tr, db, ed, grid)) count++; // 左边
if (PlacePoleOnSegment(grid.GetVerticalSegment(row, col + 1), btr, tr, db, ed, grid)) count++; // 右边
}
// 第五个方格 (在下一个单元的第一个位置)
int col5 = col + 4;
if (col5 < grid.Cols)
{
// 布置四边
if (PlacePoleOnSegment(grid.GetHorizontalSegment(row, col5), btr, tr, db, ed, grid)) count++; // 上边
if (PlacePoleOnSegment(grid.GetHorizontalSegment(row + 1, col5), btr, tr, db, ed, grid)) count++; // 下边
if (PlacePoleOnSegment(grid.GetVerticalSegment(row, col5), btr, tr, db, ed, grid)) count++; // 左边
if (PlacePoleOnSegment(grid.GetVerticalSegment(row, col5 + 1), btr, tr, db, ed, grid)) count++; // 右边
}
// 中间三个方格 (第二、三、四跨) - 只布置左右水平杆
for (int i = 1; i <= 3; i++)
{
int midCol = col + i;
if (midCol < grid.Cols)
{
// 只布置左右边水平杆
if (PlacePoleOnSegment(grid.GetVerticalSegment(row, col5), btr, tr, db, ed, grid)) count++; // 左边
if (PlacePoleOnSegment(grid.GetVerticalSegment(row, col5 + 1), btr, tr, db, ed, grid)) count++; // 右边
// 严禁布置垂直杆件上的水平杆(不布置上下边)
}
}
}
}
return count;
}
// 模式4:满布
private int PlacePolesMode4(GridTopology grid, BlockTableRecord btr, Transaction tr, Database db, Editor ed)
{
int count = 0;
// 所有水平线段
for (int row = 0; row <= grid.Rows; row++)
{
for (int col = 0; col < grid.Cols; col++)
{
var seg = grid.GetHorizontalSegment(row, col);
if (seg != null && PlacePoleOnSegment(seg, btr, tr, db, ed, grid))
count++;
}
}
// 所有垂直线段
for (int col = 0; col <= grid.Cols; col++)
{
for (int row = 0; row < grid.Rows; row++)
{
var seg = grid.GetVerticalSegment(row, col);
if (seg != null && PlacePoleOnSegment(seg, btr, tr, db, ed, grid))
count++;
}
}
return count;
}
// 在指定线段上布置水平杆(新增端点验证)
private bool PlacePoleOnSegment(LineSegment seg, BlockTableRecord btr, Transaction tr, Database db, Editor ed, GridTopology grid)
{
// 新增端点验证
if (seg == null || !grid.HasEndpoints(seg) || seg.Length < 301)
{
return false;
}
// 匹配最接近的标准尺寸
double closestSize = PoleBlocks.Keys
.OrderBy(size => Math.Abs(size - seg.Length))
.FirstOrDefault(size => Math.Abs(size - seg.Length) <= 50);
if (closestSize <= 0 || !PoleBlocks.TryGetValue(closestSize, out string blockName))
{
return false;
}
// 获取插件目录下的图块路径
string pluginPath = Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location);
string blockDir = Path.Combine(pluginPath, "ScaffoldBlocks");
string blockPath = Path.Combine(blockDir, blockName);
// 确保图块文件存在
if (!File.Exists(blockPath))
{
ed.WriteMessage($"\n图块文件不存在: {blockPath}");
return false;
}
BlockTable bt = tr.GetObject(db.BlockTableId, OpenMode.ForRead) as BlockTable;
// 如果图块未定义,从文件插入
if (!bt.Has(blockName))
{
using (Database sourceDb = new Database(false, true))
{
try
{
sourceDb.ReadDwgFile(blockPath, FileShare.Read, true, null);
ObjectId blockId = db.Insert(blockName, sourceDb, true);
}
catch (System.Exception ex)
{
ed.WriteMessage($"\n插入图块失败: {ex.Message}");
return false;
}
}
}
// 计算插入点和旋转角度
Point3d midPoint = seg.MidPoint;
double angle = seg.Direction.AngleOnPlane(new Plane());
// 插入图块
using (BlockReference br = new BlockReference(midPoint, bt[blockName]))
{
br.Rotation = angle;
btr.AppendEntity(br);
tr.AddNewlyCreatedDBObject(br, true);
return true;
}
}
}
// 完全重构的网格拓扑类
internal class GridTopology
{
public int Rows { get; private set; } // 网格行数 (单元行数)
public int Cols { get; private set; } // 网格列数 (单元列数)
public bool IsValid => Rows > 0 && Cols > 0;
// 存储原始网格线
private List<Line> HorizontalLines { get; } = new List<Line>();
private List<Line> VerticalLines { get; } = new List<Line>();
// 网格交点
public SortedSet<double> XCoords { get; } = new SortedSet<double>();
public SortedSet<double> YCoords { get; } = new SortedSet<double>();
// 容差
private const double Tolerance = 0.05; // 1mm容差
private readonly Editor _ed;
public GridTopology(List<Line> gridLines, Editor ed = null)
{
_ed = ed;
try
{
// 1. 分类所有网格线
foreach (Line line in gridLines)
{
Vector3d vec = line.EndPoint - line.StartPoint;
// 水平线 (Y变化很小)
if (Math.Abs(vec.Y) < Tolerance)
{
HorizontalLines.Add(line);
YCoords.Add(Math.Round(line.StartPoint.Y, 3));
}
// 垂直线 (X变化很小)
else if (Math.Abs(vec.X) < Tolerance)
{
VerticalLines.Add(line);
XCoords.Add(Math.Round(line.StartPoint.X, 3));
}
}
if (_ed != null)
{
_ed.WriteMessage($"\n水平线: {HorizontalLines.Count}条, 垂直线: {VerticalLines.Count}条");
}
// 2. 验证网格完整性
if (XCoords.Count < 2 || YCoords.Count < 2)
{
if (_ed != null) _ed.WriteMessage("\n错误:网格坐标不足,无法形成有效网格");
return;
}
// 3. 确定网格大小
Rows = YCoords.Count - 1;
Cols = XCoords.Count - 1;
if (_ed != null)
{
_ed.WriteMessage($"\nX坐标: {XCoords.Count}, Y坐标: {YCoords.Count}");
_ed.WriteMessage($"\n网格单元: {Rows}行 x {Cols}列");
}
}
catch (System.Exception ex)
{
if (_ed != null) _ed.WriteMessage($"\n网格拓扑错误: {ex.Message}");
Rows = 0;
Cols = 0;
}
}
// 检查线段是否在网格线上
public bool IsSegmentOnGrid(LineSegment seg)
{
if (seg == null) return false;
// 检查是否为水平线
if (Math.Abs(seg.StartPoint.Y - seg.EndPoint.Y) < Tolerance)
{
return HorizontalLines.Any(line =>
IsSameLine(seg, line, Tolerance));
}
// 检查是否为垂直线
else if (Math.Abs(seg.StartPoint.X - seg.EndPoint.X) < Tolerance)
{
return VerticalLines.Any(line =>
IsSameLine(seg, line, Tolerance));
}
return false;
}
// 检查两个线段是否相同
private bool IsSameLine(LineSegment seg, Line line, double tolerance)
{
// 检查起点匹配
bool startMatch = (line.StartPoint.DistanceTo(seg.StartPoint) < tolerance &&
line.EndPoint.DistanceTo(seg.EndPoint) < tolerance);
// 检查反向匹配
bool reverseMatch = (line.StartPoint.DistanceTo(seg.EndPoint) < tolerance &&
line.EndPoint.DistanceTo(seg.StartPoint) < tolerance);
return startMatch || reverseMatch;
}
public LineSegment GetHorizontalSegment(int row, int col)
{
if (row < 0 || row > Rows || col < 0 || col >= Cols)
return null;
double y = YCoords.ElementAt(row);
double x1 = XCoords.ElementAt(col);
double x2 = XCoords.ElementAt(col + 1);
// 查找匹配的水平线
foreach (var line in HorizontalLines)
{
if (Math.Abs(line.StartPoint.Y - y) > Tolerance &&
Math.Abs(line.EndPoint.Y - y) > Tolerance)
continue;
double minX = Math.Min(line.StartPoint.X, line.EndPoint.X);
double maxX = Math.Max(line.StartPoint.X, line.EndPoint.X);
if (Math.Abs(minX - x1) < Tolerance && Math.Abs(maxX - x2) < Tolerance)
{
return new LineSegment(line.StartPoint, line.EndPoint);
}
}
return null;
}
public LineSegment GetVerticalSegment(int row, int col)
{
if (row < 0 || row >= Rows || col < 0 || col > Cols)
return null;
double x = XCoords.ElementAt(col);
double y1 = YCoords.ElementAt(row);
double y2 = YCoords.ElementAt(row + 1);
// 查找匹配的垂直线
foreach (var line in VerticalLines)
{
if (Math.Abs(line.StartPoint.X - x) > Tolerance &&
Math.Abs(line.EndPoint.X - x) > Tolerance)
continue;
double minY = Math.Min(line.StartPoint.Y, line.EndPoint.Y);
double maxY = Math.Max(line.StartPoint.Y, line.EndPoint.Y);
if (Math.Abs(minY - y1) < Tolerance && Math.Abs(maxY - y2) < Tolerance)
{
return new LineSegment(line.StartPoint, line.EndPoint);
}
}
return null;
}
}
internal class LineSegment
{
public Point3d StartPoint { get; }
public Point3d EndPoint { get; }
public double Length => StartPoint.DistanceTo(EndPoint);
public Vector3d Direction => (EndPoint - StartPoint).GetNormal();
public Point3d MidPoint => new Point3d(
(StartPoint.X + EndPoint.X) / 2,
(StartPoint.Y + EndPoint.Y) / 2,
(StartPoint.Z + EndPoint.Z) / 2);
public LineSegment(Point3d start, Point3d end)
{
StartPoint = start;
EndPoint = end;
}
}
}
CS1061“GnidTopology"未包含”HasEndpoints”的定义,并且找不到可接受第一个“GridTopology"类型参数的可访问扩展方法“HasEndpoints"(是否缺少using 指令或程序集引用?)
最新发布