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;
using System.Reflection;
namespace ScaffoldPlugin
{
public class ScaffoldGenerator
{
// 图块尺寸映射
private static readonly Dictionary<string, int> BlockSizes = new Dictionary<string, int>(StringComparer.OrdinalIgnoreCase)
{
// 立杆
{"ScaffoldPole立杆200mm", 200},
{"ScaffoldPole立杆350mm", 350},
{"ScaffoldPole立杆500mm", 500},
{"ScaffoldPole立杆1000mm", 1000},
{"ScaffoldPole立杆1500mm", 1500},
{"ScaffoldPole立杆2000mm", 2000},
{"ScaffoldPole立杆2500mm", 2500},
// 横杆
{"ScaffoldPole立横杆300mm", 300},
{"ScaffoldPole立横杆600mm", 600},
{"ScaffoldPole立横杆900mm", 900},
{"ScaffoldPole立横杆1200mm", 1200},
{"ScaffoldPole立横杆1500mm", 1500},
{"ScaffoldPole立横杆1800mm", 1800},
// 附件
{"ScaffoldPole顶托", 0},
{"ScaffoldPole顶托螺母", 0},
{"ScaffoldPole连接盘", 0},
// 竖向斜拉杆
{"ScaffoldPolexie竖向斜拉杆600mm", 600},
{"ScaffoldPolexie竖向斜拉杆900mm", 900},
{"ScaffoldPolexie竖向斜拉杆1500mm", 1500},
{"ScaffoldPolexie竖向斜拉杆1800mm", 1800},
// 水平斜拉杆
{"ScaffoldPolehengxie水平斜拉杆", 0}
};
// 斜拉杆尺寸到图块名称的映射
private static readonly Dictionary<int, string> XieBarBlockMap = new Dictionary<int, string>
{
{600, "ScaffoldPolexie竖向斜拉杆600mm"},
{900, "ScaffoldPolexie竖向斜拉杆900mm"},
{1500, "ScaffoldPolexie竖向斜拉杆1500mm"},
{1800, "ScaffoldPolexie竖向斜拉杆1800mm"}
};
// 顶部横杆偏移映射(根据立杆尺寸)
private static readonly Dictionary<int, double> TopBarOffsets = new Dictionary<int, double>
{
{200, 105}, // 200mm立杆在105mm处布置横杆
{350, 125}, // 350mm立杆在125mm处布置横杆
{500, 250}, // 500mm立杆在250mm处布置横杆
{1000, 750}, // 1000mm立杆在750mm处布置横杆
{1500, 1250}, // 1500mm立杆在1250mm处布置横杆
{2000, 1750}, // 2000mm立杆在1750mm处布置横杆
{2500, 2250} // 2500mm立杆在2250mm处布置横杆
};
// 常量定义
private const double FirstBarHeight = 250.0;
private const double HorizontalBarSpacing = 1500.0;
private const double StandardDiskOffset = 250.0;
private const double Tolerance = 5.0;
private const double NutOffset = 75.0;
private const double MinTopGap = 200.0;
private const double MaxTopGap = 400.0;
private const double RelaxedTolerance = 50.0;
private const double MaxBarDistance = 1800.0;
private const double MaxDiskSearchDistance = 500.0;
private const double HeightDifferenceThreshold = 50.0;
private const double TopControlLineTolerance = 10.0;
private const double DimensionOffset = 600.0;
private const double XieBarSpacing = 1.0;
private const double MinXieBarSpacing = 1500.0; // 斜拉杆最小步距
private Editor _ed;
private string _blocksFolderPath;
private Curve _topControlLine;
private bool _isAscending;
private readonly Dictionary<double, List<double>> _diskPositions = new Dictionary<double, List<double>>();
private readonly Dictionary<double, double> _adjusterPositions = new Dictionary<double, double>();
private readonly Dictionary<double, int> _lastPoleSizes = new Dictionary<double, int>();
private readonly Dictionary<double, double> _poleBasePositions = new Dictionary<double, double>();
private readonly Dictionary<double, double> _topDiskPositions = new Dictionary<double, double>();
private readonly HashSet<Tuple<double, double>> _placedHorizontalBars = new HashSet<Tuple<double, double>>();
private readonly List<Tuple<double, double, double>> _horizontalXieBarPositions = new List<Tuple<double, double, double>>();
// 记录所有插入的斜拉杆图块ID
private readonly List<ObjectId> _insertedXieBars = new List<ObjectId>();
[CommandMethod("GS", CommandFlags.Modal)]
public void GenerateScaffold()
{
Document doc = Application.DocumentManager.MdiActiveDocument;
Database db = doc.Database;
_ed = doc.Editor;
try
{
_ed.WriteMessage("\n脚手架生成开始...");
_blocksFolderPath = GetBlocksFolderPath();
if (string.IsNullOrEmpty(_blocksFolderPath))
{
_ed.WriteMessage("\n错误:无法获取图块文件夹路径");
return;
}
LoadAllBlockDefinitions(db);
var blockRefs = SelectBlocks();
if (blockRefs == null || blockRefs.Count == 0)
{
_ed.WriteMessage("\n未选择任何脚手架图块");
return;
}
_ed.WriteMessage($"\n已选择 {blockRefs.Count} 个脚手架图块");
_ed.WriteMessage("\n选择底标高水平控制线");
var baseLine = SelectControlLine();
if (baseLine == null)
{
_ed.WriteMessage("\n未选择底标高水平控制线");
return;
}
double baseElev = GetLineElevation(baseLine);
_ed.WriteMessage($"\n底标高: {baseElev}");
_ed.WriteMessage("\n选择顶部控制线");
_topControlLine = SelectControlLine();
if (_topControlLine == null)
{
_ed.WriteMessage("\n未选择顶部控制线");
return;
}
double topElev = GetLineElevation(_topControlLine);
_ed.WriteMessage($"\n顶标高: {topElev}");
using (Transaction tr = db.TransactionManager.StartTransaction())
{
BlockTable bt = (BlockTable)tr.GetObject(db.BlockTableId, OpenMode.ForRead);
BlockTableRecord btr = (BlockTableRecord)tr.GetObject(db.CurrentSpaceId, OpenMode.ForWrite);
// 重置所有数据结构
ResetDataStructures();
// 收集水平斜拉杆位置
CollectHorizontalXieBarPositions(blockRefs);
// 布置立杆
LayoutVerticalPoles(tr, bt, btr, blockRefs, baseElev);
// 布置横杆
LayoutHorizontalBars(tr, bt, btr, blockRefs, baseElev);
// 布置斜拉杆
LayoutXieBars(tr, bt, btr, baseElev);
// 删除超出控制线的斜拉杆
RemoveOverTopXieBars(tr, btr);
// 添加尺寸标注
AddDimensions(tr, btr, db, baseElev);
tr.Commit();
}
_ed.WriteMessage("\n脚手架生成完成!");
}
catch (Autodesk.AutoCAD.Runtime.Exception acadEx)
{
if (acadEx.ErrorStatus != ErrorStatus.UserBreak)
{
_ed.WriteMessage($"\nAutoCAD错误: {acadEx.Message}");
_ed.WriteMessage($"\n堆栈跟踪: {acadEx.StackTrace}");
}
}
catch (System.Exception sysEx)
{
_ed.WriteMessage($"\n系统错误: {sysEx.Message}");
_ed.WriteMessage($"\n堆栈跟踪: {sysEx.StackTrace}");
}
}
// 重置数据结构
private void ResetDataStructures()
{
_diskPositions.Clear();
_adjusterPositions.Clear();
_lastPoleSizes.Clear();
_poleBasePositions.Clear();
_topDiskPositions.Clear();
_placedHorizontalBars.Clear();
_horizontalXieBarPositions.Clear();
_insertedXieBars.Clear();
}
private void CollectHorizontalXieBarPositions(List<BlockReference> blocks)
{
try
{
// 收集所有水平斜拉杆位置
var xieBarBlocks = blocks
.Where(b => b.Name.Contains("hengxie") || b.Name.Contains("水平斜拉杆"))
.ToList();
foreach (var block in xieBarBlocks)
{
// 获取块的几何范围
Extents3d extents = block.GeometricExtents;
// 计算起点和终点
double startX = extents.MinPoint.X;
double endX = extents.MaxPoint.X;
double height = block.Position.Y;
_horizontalXieBarPositions.Add(new Tuple<double, double, double>(startX, endX, height));
}
_ed.WriteMessage($"\n找到 {xieBarBlocks.Count} 个水平斜拉杆位置");
}
catch (System.Exception ex)
{
_ed.WriteMessage($"\n收集水平斜拉杆位置错误: {ex.Message}");
}
}
private void LayoutXieBars(Transaction tr, BlockTable bt, BlockTableRecord btr, double baseElev)
{
try
{
_ed.WriteMessage("\n开始布置竖向斜拉杆...");
int xieBarCount = 0;
int skippedCount = 0;
// 获取所有立杆位置(按X排序)
var polePositions = _poleBasePositions.Keys.OrderBy(x => x).ToList();
if (polePositions.Count < 2)
{
_ed.WriteMessage("\n立杆数量不足,无法布置斜拉杆");
return;
}
// 计算最大高度(考虑安全距离)
double maxHeight = _isAscending ?
_topDiskPositions.Values.Max() - MinTopGap :
_topDiskPositions.Values.Min() + MinTopGap;
// 遍历每个水平斜拉杆位置
foreach (var xieBarPos in _horizontalXieBarPositions)
{
double startX = xieBarPos.Item1;
double endX = xieBarPos.Item2;
double barHeight = xieBarPos.Item3;
_ed.WriteMessage($"\n处理水平斜拉杆: {startX:F0} - {endX:F0} 高度 {barHeight:F0}");
// 找到最近的立杆位置
double? leftPole = FindNearestPole(startX, polePositions);
double? rightPole = FindNearestPole(endX, polePositions);
if (!leftPole.HasValue || !rightPole.HasValue)
{
_ed.WriteMessage($"\n 找不到对应的立杆位置");
continue;
}
// 获取左右立杆之间的所有立杆
var polesInRange = polePositions
.Where(x => x >= leftPole.Value && x <= rightPole.Value)
.OrderBy(x => x)
.ToList();
if (polesInRange.Count < 2)
{
_ed.WriteMessage($"\n 跨间内立杆不足");
continue;
}
// 计算步距高度列表(从水平斜拉杆高度开始向上布置)
var stepHeights = new List<double>();
double currentHeight = barHeight;
double stepDirection = _isAscending ? 1 : -1;
// 计算最大步数(避免超出最大高度)
while ((_isAscending && currentHeight <= maxHeight) ||
(!_isAscending && currentHeight >= maxHeight))
{
// 添加当前高度
stepHeights.Add(currentHeight);
// 计算下一高度
currentHeight += HorizontalBarSpacing * stepDirection;
// 检查是否超出范围(使用安全高度)
if ((_isAscending && currentHeight > maxHeight) ||
(!_isAscending && currentHeight < maxHeight))
{
break;
}
}
_ed.WriteMessage($"\n 计算得到 {stepHeights.Count} 个布置高度");
// 遍历每个跨间(相邻立杆之间)
for (int i = 0; i < polesInRange.Count - 1; i++)
{
double leftX = polesInRange[i];
double rightX = polesInRange[i + 1];
double distance = Math.Abs(rightX - leftX);
// 跳过过远或过近的跨间
if (distance < 300 || distance > MaxBarDistance)
{
_ed.WriteMessage($"\n 跳过跨间 {i} (距离 {distance} 不在范围内)");
continue;
}
// 在每个步距高度上布置斜拉杆
foreach (double height in stepHeights)
{
// === 新增:检查步距是否满足最小要求 ===
double controlY = GetElevationAtX((leftX + rightX) / 2.0);
double topGap = _isAscending ?
(controlY - height) :
(height - controlY);
if (topGap < MinXieBarSpacing)
{
_ed.WriteMessage($"\n 跳过步距不足的斜拉杆: {height:F0} (到顶部距离={topGap:F0}<{MinXieBarSpacing})");
skippedCount++;
continue;
}
// 获取左右立杆上最接近的连接盘高度
double? leftDisk = GetNearestDiskHeight(leftX, height, 100.0); // 使用更大的容差
double? rightDisk = GetNearestDiskHeight(rightX, height, 100.0);
if (!leftDisk.HasValue || !rightDisk.HasValue)
{
_ed.WriteMessage($"\n 在高度 {height:F0} 找不到连接盘");
skippedCount++;
continue;
}
// 计算实际安装高度(取平均值)
double actualHeight = (leftDisk.Value + rightDisk.Value) / 2.0;
// 增强高度验证
if (Math.Abs(actualHeight) < 1.0 ||
double.IsNaN(actualHeight) ||
double.IsInfinity(actualHeight))
{
_ed.WriteMessage($"\n 无效高度: {actualHeight:F0} (左={leftDisk.Value}, 右={rightDisk.Value})");
skippedCount++;
continue;
}
// 使用中点位置的控制线高度进行安全距离检查
double midX = (leftX + rightX) / 2.0;
controlY = GetElevationAtX(midX);
// 检查是否超出顶部控制线
bool isOverTop = _isAscending ?
(actualHeight > controlY - MinTopGap) :
(actualHeight < controlY + MinTopGap);
if (isOverTop)
{
_ed.WriteMessage($"\n 超出顶控制线: {actualHeight:F0} vs {controlY - MinTopGap:F0} - 已跳过");
skippedCount++;
continue;
}
// 计算实际需要的斜拉杆长度
double actualDistance = Math.Sqrt(
Math.Pow(rightX - leftX, 2) +
Math.Pow(0, 2) // 高度相同,所以高度差为0
);
// 选择最佳斜拉杆尺寸
int bestSize = GetBestXieBarSize(actualDistance);
if (bestSize <= 0)
{
_ed.WriteMessage($"\n 找不到合适的斜拉杆尺寸: {actualDistance}");
skippedCount++;
continue;
}
// 获取图块名称
if (!XieBarBlockMap.TryGetValue(bestSize, out string blockName) ||
!bt.Has(blockName))
{
_ed.WriteMessage($"\n 找不到图块: {bestSize}mm");
skippedCount++;
continue;
}
// 计算中点
double midY = actualHeight;
// 计算旋转角度(水平方向)
double dx = rightX - leftX;
double dy = 0; // 同一高度,高度差为0
double angle = Math.Atan2(dy, dx); // 结果为0,水平方向
// 八字形布置:基于跨间位置决定方向
bool isPositiveSlope = (Math.Floor(midX / 3000) % 2 == 0); // 每3米交替方向
// 创建镜像矩阵
Matrix3d mirrorMatrix = isPositiveSlope ?
Matrix3d.Identity :
Matrix3d.Mirroring(new Line3d(
new Point3d(midX, midY, 0),
new Point3d(midX, midY + 1, 0)
));
// 插入斜拉杆
InsertXieBarBlock(tr, btr, bt, blockName, midX, midY, angle, mirrorMatrix);
xieBarCount++;
_ed.WriteMessage($"\n 在高度 {actualHeight:F0} 处布置斜拉杆");
}
}
}
_ed.WriteMessage($"\n共布置 {xieBarCount} 根竖向斜拉杆");
_ed.WriteMessage($"\n跳过 {skippedCount} 个无效位置");
}
catch (System.Exception ex)
{
_ed.WriteMessage($"\n布置斜拉杆错误: {ex.Message}");
}
}
// 删除超出控制线的斜拉杆
private void RemoveOverTopXieBars(Transaction tr, BlockTableRecord btr)
{
try
{
int removedCount = 0;
var barsToRemove = new List<ObjectId>();
// 检查所有插入的斜拉杆
foreach (ObjectId id in _insertedXieBars)
{
if (!id.IsValid || id.IsErased) continue;
BlockReference bref = tr.GetObject(id, OpenMode.ForRead) as BlockReference;
if (bref == null) continue;
Point3d position = bref.Position;
double controlY = GetElevationAtX(position.X);
// 检查是否超出控制线(考虑安全距离)
bool isOverTop = _isAscending ?
(position.Y > controlY - MinTopGap + Tolerance) :
(position.Y < controlY + MinTopGap - Tolerance);
if (isOverTop)
{
barsToRemove.Add(id);
removedCount++;
}
}
// 删除超出控制线的斜拉杆
foreach (ObjectId id in barsToRemove)
{
BlockReference bref = tr.GetObject(id, OpenMode.ForWrite) as BlockReference;
if (bref != null)
{
bref.Erase();
}
}
_ed.WriteMessage($"\n删除 {removedCount} 根超出顶部的斜拉杆");
}
catch (System.Exception ex) // 明确指定 System.Exception
{
_ed.WriteMessage($"\n删除斜拉杆错误: {ex.Message}");
}
}
// 改进的斜拉杆尺寸选择方法
private int GetBestXieBarSize(double distance)
{
if (distance <= 0) return 0;
// 精确匹配优先(容差±5%)
int[] validSizes = { 600, 900, 1500, 1800 };
var exactMatch = validSizes
.Where(s => Math.Abs(s - distance) <= distance * 0.05)
.OrderBy(s => Math.Abs(s - distance))
.FirstOrDefault();
if (exactMatch > 0) return exactMatch;
// 宽松匹配(容差±15%)
return validSizes
.Where(s => Math.Abs(s - distance) <= distance * 0.15)
.OrderBy(s => Math.Abs(s - distance))
.FirstOrDefault();
}
// 增强的高度获取方法
private double GetElevationAtX(double x)
{
if (_topControlLine == null) return 0;
try
{
// 增加对多段线的精确处理
if (_topControlLine is Polyline pline)
{
for (int i = 0; i < pline.NumberOfVertices - 1; i++)
{
Point3d start = pline.GetPoint3dAt(i);
Point3d end = pline.GetPoint3dAt(i + 1);
if (x >= Math.Min(start.X, end.X) &&
x <= Math.Max(start.X, end.X))
{
double t = (x - start.X) / (end.X - start.X);
return start.Y + t * (end.Y - start.Y);
}
}
return pline.GetPoint3dAt(0).Y;
}
// 直线处理
if (_topControlLine is Line line)
{
Vector3d direction = line.EndPoint - line.StartPoint;
if (Math.Abs(direction.X) < 0.001) return line.StartPoint.Y;
double t = (x - line.StartPoint.X) / direction.X;
return line.StartPoint.Y + t * direction.Y;
}
return 0;
}
catch
{
return 0;
}
}
private string GetBlocksFolderPath()
{
try
{
string assemblyPath = Assembly.GetExecutingAssembly().Location;
string pluginDir = Path.GetDirectoryName(assemblyPath);
return Path.Combine(pluginDir, "ScaffoldBlocks");
}
catch (System.Exception ex)
{
_ed.WriteMessage($"\n获取图块路径错误: {ex.Message}");
return null;
}
}
private void LoadAllBlockDefinitions(Database db)
{
if (string.IsNullOrEmpty(_blocksFolderPath)) return;
try
{
string[] blockFiles = Directory.GetFiles(_blocksFolderPath, "*.dwg");
if (blockFiles.Length == 0)
{
_ed.WriteMessage("\n未找到任何图块文件");
return;
}
using (Transaction tr = db.TransactionManager.StartTransaction())
{
BlockTable bt = (BlockTable)tr.GetObject(db.BlockTableId, OpenMode.ForRead);
foreach (string filePath in blockFiles)
{
string fileName = Path.GetFileNameWithoutExtension(filePath);
if (!BlockSizes.ContainsKey(fileName)) continue;
if (bt.Has(fileName)) continue;
using (Database sourceDb = new Database(false, true))
{
try
{
sourceDb.ReadDwgFile(filePath, FileShare.Read, true, null);
ObjectId blockId = db.Insert(fileName, sourceDb, true);
_ed.WriteMessage($"\n已加载图块: {fileName}");
}
catch (System.Exception ex)
{
_ed.WriteMessage($"\n加载图块 {fileName} 失败: {ex.Message}");
}
}
}
tr.Commit();
}
}
catch (System.Exception ex)
{
_ed.WriteMessage($"\n加载图块定义错误: {ex.Message}");
}
}
private Curve SelectControlLine()
{
try
{
var opts = new PromptEntityOptions("\n选择控制线: ")
{
AllowNone = false,
AllowObjectOnLockedLayer = true
};
opts.SetRejectMessage("\n必须选择直线或多段线");
opts.AddAllowedClass(typeof(Line), true);
opts.AddAllowedClass(typeof(Polyline), true);
PromptEntityResult result = _ed.GetEntity(opts);
if (result.Status != PromptStatus.OK) return null;
using (Transaction tr = _ed.Document.TransactionManager.StartTransaction())
{
Curve curve = tr.GetObject(result.ObjectId, OpenMode.ForRead) as Curve;
tr.Commit();
return curve;
}
}
catch (System.Exception ex)
{
_ed.WriteMessage($"\n选择控制线错误: {ex.Message}");
return null;
}
}
private double GetLineElevation(Curve curve)
{
if (curve == null) return 0;
try
{
if (curve is Line line) return line.StartPoint.Y;
if (curve is Polyline pline) return pline.GetPoint3dAt(0).Y;
return 0;
}
catch (System.Exception ex)
{
_ed.WriteMessage($"\n获取控制线高程错误: {ex.Message}");
return 0;
}
}
private List<BlockReference> SelectBlocks()
{
try
{
var filter = new SelectionFilter(new[]
{
new TypedValue(0, "INSERT"),
new TypedValue(2, "ScaffoldPole*")
});
var selOptions = new PromptSelectionOptions
{
MessageForAdding = "\n框选脚手架图块: ",
AllowDuplicates = false
};
PromptSelectionResult selResult = _ed.GetSelection(selOptions, filter);
if (selResult.Status != PromptStatus.OK) return null;
var references = new List<BlockReference>();
using (var resBuf = selResult.Value)
{
Database db = _ed.Document.Database;
using (Transaction tr = db.TransactionManager.StartTransaction())
{
foreach (ObjectId objId in resBuf.GetObjectIds())
{
var bref = tr.GetObject(objId, OpenMode.ForRead) as BlockReference;
if (bref != null) references.Add(bref);
}
tr.Commit();
}
}
return references;
}
catch (System.Exception ex)
{
_ed.WriteMessage($"\n选择图块错误: {ex.Message}");
return null;
}
}
private void LayoutVerticalPoles(
Transaction tr, BlockTable bt, BlockTableRecord btr,
List<BlockReference> blocks, double baseElev)
{
try
{
_ed.WriteMessage("\n开始布置立杆...");
var polePositions = blocks
.Where(b => b.Name.Contains("立杆") && !b.Name.Contains("横杆"))
.Select(b => b.Position.X)
.Distinct()
.OrderBy(x => x)
.ToList();
if (polePositions.Count == 0)
{
_ed.WriteMessage("\n未找到立杆位置");
return;
}
double minY = polePositions.Min(x => GetElevationAtX(x));
double maxY = polePositions.Max(x => GetElevationAtX(x));
_isAscending = maxY > minY;
int[] standardSizes = { 2500, 2000, 1500, 1000, 500, 350, 200 };
foreach (var xPos in polePositions)
{
_poleBasePositions[xPos] = baseElev;
double topElev = GetElevationAtX(xPos);
double totalHeight = Math.Abs(topElev - baseElev);
double currentY = baseElev;
List<int> usedSizes = new List<int>();
double remaining = totalHeight;
while (remaining > MinTopGap + 350)
{
double maxUsableSize = remaining - MinTopGap;
int bestSize = standardSizes
.Where(s => s <= maxUsableSize)
.OrderByDescending(s => s)
.FirstOrDefault();
if (bestSize <= 0) break;
usedSizes.Add(bestSize);
remaining -= bestSize;
currentY += _isAscending ? bestSize : -bestSize;
}
int lastPoleSize = 0;
double gap = 0;
double minGap = MinTopGap;
double maxGap = MaxTopGap;
var validLastSizes = standardSizes
.Where(s => s <= remaining - minGap && s >= remaining - maxGap)
.OrderByDescending(s => s)
.ToList();
if (validLastSizes.Any())
{
lastPoleSize = validLastSizes.First();
gap = remaining - lastPoleSize;
}
else
{
lastPoleSize = standardSizes
.OrderBy(s => Math.Abs((remaining - s) - 300))
.First();
gap = remaining - lastPoleSize;
if (gap < minGap && usedSizes.Count > 0)
{
int lastStandard = usedSizes.Last();
usedSizes.RemoveAt(usedSizes.Count - 1);
remaining += lastStandard;
currentY += _isAscending ? -lastStandard : lastStandard;
lastPoleSize = standardSizes
.Where(s => s <= remaining - minGap)
.OrderByDescending(s => s)
.First();
gap = remaining - lastPoleSize;
}
}
usedSizes.Add(lastPoleSize);
gap = remaining - lastPoleSize;
_lastPoleSizes[xPos] = lastPoleSize;
currentY = baseElev;
foreach (int size in usedSizes)
{
string blockName = $"ScaffoldPole立杆{size}mm";
if (bt.Has(blockName))
{
InsertBlock(tr, btr, bt, blockName, xPos, currentY);
RecordDiskPositions(xPos, currentY, size);
currentY += _isAscending ? size : -size;
}
else
{
_ed.WriteMessage($"\n找不到图块: {blockName}");
}
}
if (bt.Has("ScaffoldPole顶托"))
{
double topPosition = topElev;
InsertBlock(tr, btr, bt, "ScaffoldPole顶托", xPos, topPosition);
_adjusterPositions[xPos] = topPosition;
// 添加顶部横杆位置计算
if (TopBarOffsets.TryGetValue(lastPoleSize, out double topBarOffset))
{
double topBarY = _isAscending ?
topPosition - topBarOffset :
topPosition + topBarOffset;
// 记录顶部横杆位置
if (!_diskPositions.ContainsKey(xPos))
_diskPositions[xPos] = new List<double>();
if (!_diskPositions[xPos].Contains(topBarY))
_diskPositions[xPos].Add(topBarY);
_ed.WriteMessage($"\n记录顶部横杆位置: X={xPos}, 高度={topBarY:F1}");
}
double nutPosition = _isAscending ?
(currentY + NutOffset) :
(currentY - NutOffset);
if (bt.Has("ScaffoldPole顶托螺母"))
{
InsertBlock(tr, btr, bt, "ScaffoldPole顶托螺母", xPos, nutPosition);
}
}
}
_ed.WriteMessage($"\n布置了 {polePositions.Count} 根立杆");
}
catch (System.Exception ex)
{
_ed.WriteMessage($"\n布置立杆错误: {ex.Message}");
}
}
private void RecordDiskPositions(double x, double startY, int poleSize)
{
try
{
if (!_diskPositions.ContainsKey(x))
_diskPositions[x] = new List<double>();
double actualTopY = GetElevationAtX(x);
double direction = _isAscending ? 1 : -1;
// 添加第一个连接盘位置(250mm处)
double firstDiskY = startY + FirstBarHeight * direction;
if (!_diskPositions[x].Contains(firstDiskY))
_diskPositions[x].Add(firstDiskY);
int stepCount = 1;
while (true)
{
double diskHeight = FirstBarHeight + stepCount * HorizontalBarSpacing;
double diskY = startY + diskHeight * direction;
// 检查是否超过顶部控制线
if ((_isAscending && diskY > actualTopY - MinTopGap) ||
(!_isAscending && diskY < actualTopY + MinTopGap))
{
break;
}
if (!_diskPositions[x].Contains(diskY))
_diskPositions[x].Add(diskY);
stepCount++;
}
// 添加顶部控制线位置
if (!_diskPositions[x].Contains(actualTopY))
_diskPositions[x].Add(actualTopY);
_topDiskPositions[x] = actualTopY;
// 调试日志
_ed.WriteMessage($"\n立杆位置: X={x}, 底部={startY}, 顶部={actualTopY}");
_ed.WriteMessage($"\n连接盘位置: {string.Join(", ", _diskPositions[x])}");
}
catch (System.Exception ex)
{
_ed.WriteMessage($"\n记录连接盘位置错误: {ex.Message}");
}
}
private void LayoutHorizontalBars(
Transaction tr, BlockTable bt, BlockTableRecord btr,
List<BlockReference> blocks, double baseElev)
{
try
{
_ed.WriteMessage("\n开始布置横杆...");
var poleXPositions = _poleBasePositions.Keys
.OrderBy(x => x)
.ToList();
if (poleXPositions.Count < 2)
{
_ed.WriteMessage("\n立杆不足,无法布置横杆");
return;
}
// 布置常规横杆(从底部250mm开始,步距1500mm)
PlaceRegularHorizontalBars(tr, bt, btr, poleXPositions, baseElev);
// 布置顶部横杆(根据立杆尺寸的特殊位置)
PlaceTopBarsOnDisks(tr, bt, btr, poleXPositions);
_ed.WriteMessage($"\n布置了 {_placedHorizontalBars.Count} 根横杆");
}
catch (System.Exception ex)
{
_ed.WriteMessage($"\n布置横杆错误: {ex.Message}");
}
}
private void PlaceRegularHorizontalBars(
Transaction tr, BlockTable bt, BlockTableRecord btr,
List<double> poleXPositions, double baseElev)
{
try
{
_ed.WriteMessage("\n开始布置常规横杆...");
int regularBarCount = 0;
// 计算所有可能的横杆高度
List<double> barHeights = CalculateBarHeights(poleXPositions, baseElev);
_ed.WriteMessage($"\n计算得到 {barHeights.Count} 个横杆高度");
// 按高度布置横杆
foreach (double originalHeight in barHeights)
{
double currentHeight = originalHeight; // 创建可修改的副本
for (int i = 0; i < poleXPositions.Count - 1; i++)
{
double x1 = poleXPositions[i];
double x2 = poleXPositions[i + 1];
double distance = Math.Abs(x2 - x1);
// 跳过距离过大的立杆对
if (distance > MaxBarDistance) continue;
// === 关键修改1:检查两侧是否有连接盘 ===
bool hasDisk1 = HasDiskAtHeight(x1, currentHeight, Tolerance);
bool hasDisk2 = HasDiskAtHeight(x2, currentHeight, Tolerance);
if (!hasDisk1 || !hasDisk2)
{
_ed.WriteMessage($"\n跳过无连接盘的横杆: X1={x1}, X2={x2}, 高度={currentHeight:F0}");
continue;
}
double actualHeight = currentHeight; // 实际安装高度
bool heightAdjusted = false; // 标记高度是否被调整
// 检查是否已布置过相同位置的横杆
double midX = (x1 + x2) / 2.0;
if (_placedHorizontalBars.Any(p =>
Math.Abs(p.Item1 - midX) < Tolerance &&
Math.Abs(p.Item2 - actualHeight) < Tolerance))
{
continue;
}
// 选择最佳横杆尺寸
int bestSize = GetBestBarSize(distance);
if (bestSize <= 0) continue;
string blockName = $"ScaffoldPole立横杆{bestSize}mm";
if (!bt.Has(blockName)) continue;
// 插入横杆
InsertBlock(tr, btr, bt, blockName, midX, actualHeight);
regularBarCount++;
// 记录已布置的横杆位置
_placedHorizontalBars.Add(new Tuple<double, double>(midX, actualHeight));
if (heightAdjusted)
{
_ed.WriteMessage($"\n在调整高度 {actualHeight:F0} 处布置横杆 (原计划高度: {currentHeight:F0})");
}
}
}
_ed.WriteMessage($"\n布置了 {regularBarCount} 根常规横杆");
}
catch (System.Exception ex)
{
_ed.WriteMessage($"\n布置常规横杆错误: {ex.Message}");
}
}
private void PlaceTopBarsOnDisks(
Transaction tr, BlockTable bt, BlockTableRecord btr,
List<double> poleXPositions)
{
try
{
_ed.WriteMessage("\n开始布置顶部横杆...");
int topBarCount = 0;
for (int i = 0; i < poleXPositions.Count - 1; i++)
{
double x1 = poleXPositions[i];
double x2 = poleXPositions[i + 1];
double distance = Math.Abs(x2 - x1);
if (distance > MaxBarDistance) continue;
// === 新增:获取顶部立杆尺寸 ===
if (!_lastPoleSizes.TryGetValue(x1, out int lastSize1) ||
!_lastPoleSizes.TryGetValue(x2, out int lastSize2))
{
continue;
}
// === 根据立杆尺寸计算顶部横杆位置 ===
double topBarY1 = GetTopBarHeight(x1, lastSize1);
double topBarY2 = GetTopBarHeight(x2, lastSize2);
// 检查高度差是否在允许范围内
double heightDiff = Math.Abs(topBarY1 - topBarY2);
if (heightDiff > HeightDifferenceThreshold) continue;
double barHeight = (topBarY1 + topBarY2) / 2.0;
// === 关键修改:检查两侧必须有连接盘 ===
bool hasLeftDisk = HasDiskAtHeight(x1, barHeight, Tolerance);
bool hasRightDisk = HasDiskAtHeight(x2, barHeight, Tolerance);
if (!hasLeftDisk || !hasRightDisk)
{
_ed.WriteMessage($"\n跳过无连接盘的顶部横杆: X1={x1}, X2={x2}, 高度={barHeight:F1}");
continue;
}
// 检查是否已布置
double midX = (x1 + x2) / 2.0;
if (_placedHorizontalBars.Any(p =>
Math.Abs(p.Item1 - midX) < Tolerance &&
Math.Abs(p.Item2 - barHeight) < Tolerance))
{
continue;
}
// 使用"立横杆"图块名称
int bestSize = GetBestBarSize(distance);
if (bestSize <= 0) continue;
string blockName = $"ScaffoldPole立横杆{bestSize}mm";
if (!bt.Has(blockName)) continue;
InsertBlock(tr, btr, bt, blockName, midX, barHeight);
topBarCount++;
// 记录已布置的横杆位置
_placedHorizontalBars.Add(new Tuple<double, double>(midX, barHeight));
_ed.WriteMessage($"\n在高度 {barHeight:F1} 布置顶部横杆 (尺寸={bestSize}mm)");
}
_ed.WriteMessage($"\n布置了 {topBarCount} 根顶部横杆");
}
catch (System.Exception ex)
{
_ed.WriteMessage($"\n布置顶部横杆错误: {ex.Message}");
}
}
// === 新增:根据立杆尺寸获取顶部横杆高度 ===
private double GetTopBarHeight(double x, int poleSize)
{
if (!_adjusterPositions.TryGetValue(x, out double topPos))
return 0;
// 根据立杆尺寸应用不同的偏移量
double offset = poleSize switch
{
200 => 105,
350 => 125,
500 => 250,
1000 => 750,
1500 => 1250,
2000 => 1750,
2500 => 2250,
_ => 0
};
return _isAscending ?
topPos - offset :
topPos + offset;
}
private List<double> CalculateBarHeights(List<double> polePositions, double baseElev)
{
var barHeights = new List<double>();
try
{
double firstBarHeight = _isAscending ?
baseElev + FirstBarHeight :
baseElev - FirstBarHeight;
barHeights.Add(firstBarHeight);
double maxHeight = _isAscending ?
_topDiskPositions.Values.Max() :
_topDiskPositions.Values.Min();
double step = _isAscending ? HorizontalBarSpacing : -HorizontalBarSpacing;
int stepCount = 1;
while (true)
{
double currentHeight = _isAscending ?
firstBarHeight + (stepCount * HorizontalBarSpacing) :
firstBarHeight - (stepCount * HorizontalBarSpacing);
if (_isAscending && currentHeight > maxHeight + Tolerance) break;
if (!_isAscending && currentHeight < maxHeight - Tolerance) break;
double topGap = _isAscending ?
(maxHeight - currentHeight) :
(currentHeight - maxHeight);
if (topGap < MinTopGap) break;
barHeights.Add(currentHeight);
stepCount++;
}
}
catch (System.Exception ex)
{
_ed.WriteMessage($"\n计算横杆高度错误: {ex.Message}");
}
return barHeights;
}
private void AddDimensions(Transaction tr, BlockTableRecord btr, Database db, double baseElev)
{
try
{
DimensionPoleSpacing(tr, btr, db, baseElev);
DimensionBarSpacing(tr, btr, db, baseElev);
AddDimensionLeaders(tr, btr, db, baseElev);
}
catch (System.Exception ex)
{
_ed.WriteMessage($"\n添加尺寸标注错误: {ex.Message}");
}
}
private void DimensionPoleSpacing(Transaction tr, BlockTableRecord btr, Database db, double baseElev)
{
if (_poleBasePositions.Count < 2) return;
var positions = _poleBasePositions.Keys.OrderBy(x => x).ToList();
double dimensionY = baseElev - DimensionOffset;
for (int i = 0; i < positions.Count - 1; i++)
{
double x1 = positions[i];
double x2 = positions[i + 1];
double distance = Math.Abs(x2 - x1);
using (AlignedDimension dim = new AlignedDimension())
{
dim.XLine1Point = new Point3d(x1, dimensionY, 0);
dim.XLine2Point = new Point3d(x2, dimensionY, 0);
dim.DimLinePoint = new Point3d((x1 + x2) / 2, dimensionY - 50, 0);
dim.DimensionStyle = db.Dimstyle;
btr.AppendEntity(dim);
tr.AddNewlyCreatedDBObject(dim, true);
}
}
}
private void DimensionBarSpacing(Transaction tr, BlockTableRecord btr, Database db, double baseElev)
{
if (_poleBasePositions.Count == 0) return;
double firstPoleX = _poleBasePositions.Keys.OrderBy(x => x).First();
double dimensionX = firstPoleX - DimensionOffset;
List<double> barHeights = CalculateBarHeightsForDimension(baseElev);
barHeights.Sort();
for (int i = 0; i < barHeights.Count - 1; i++)
{
double y1 = barHeights[i];
double y2 = barHeights[i + 1];
using (AlignedDimension dim = new AlignedDimension())
{
dim.XLine1Point = new Point3d(dimensionX, y1, 0);
dim.XLine2Point = new Point3d(dimensionX, y2, 0);
dim.DimLinePoint = new Point3d(dimensionX - 50, (y1 + y2) / 2, 0);
dim.DimensionStyle = db.Dimstyle;
btr.AppendEntity(dim);
tr.AddNewlyCreatedDBObject(dim, true);
}
}
}
private void AddDimensionLeaders(Transaction tr, BlockTableRecord btr, Database db, double baseElev)
{
try
{
if (_poleBasePositions.Count > 0)
{
var polePositions = _poleBasePositions.Keys.OrderBy(x => x).ToList();
double firstPoleX = polePositions.First();
double dimensionX = firstPoleX - DimensionOffset;
var barHeights = CalculateBarHeightsForDimension(baseElev);
foreach (double height in barHeights)
{
using (Leader leader = new Leader())
{
leader.AppendVertex(new Point3d(firstPoleX, height, 0));
leader.AppendVertex(new Point3d(dimensionX, height, 0));
leader.DimensionStyle = db.Dimstyle;
btr.AppendEntity(leader);
tr.AddNewlyCreatedDBObject(leader, true);
}
}
}
}
catch (System.Exception ex)
{
_ed.WriteMessage($"\n添加标注引线错误: {ex.Message}");
}
}
private List<double> CalculateBarHeightsForDimension(double baseElev)
{
var barHeights = new List<double>();
try
{
double firstBarHeight = _isAscending ?
baseElev + FirstBarHeight :
baseElev - FirstBarHeight;
barHeights.Add(firstBarHeight);
double maxHeight = _isAscending ?
_topDiskPositions.Values.Max() :
_topDiskPositions.Values.Min();
double step = _isAscending ? HorizontalBarSpacing : -HorizontalBarSpacing;
int stepCount = 1;
while (true)
{
double currentHeight = _isAscending ?
firstBarHeight + (stepCount * HorizontalBarSpacing) :
firstBarHeight - (stepCount * HorizontalBarSpacing);
if (_isAscending && currentHeight > maxHeight + Tolerance) break;
if (!_isAscending && currentHeight < maxHeight - Tolerance) break;
double topGap = _isAscending ?
(maxHeight - currentHeight) :
(currentHeight - maxHeight);
if (topGap < MinTopGap) break;
barHeights.Add(currentHeight);
stepCount++;
}
}
catch (System.Exception ex)
{
_ed.WriteMessage($"\n计算标注高度错误: {ex.Message}");
}
return barHeights;
}
private bool HasDiskAtHeight(double x, double height, double tolerance)
{
if (!_diskPositions.TryGetValue(x, out List<double> heights))
return false;
return heights.Any(h => Math.Abs(h - height) <= tolerance);
}
private double? FindNearestDiskBelow(double x, double height, double maxDistance)
{
if (!_diskPositions.TryGetValue(x, out List<double> heights))
return null;
var belowHeights = heights
.Where(h => (_isAscending && h <= height) || (!_isAscending && h >= height))
.ToList();
if (!belowHeights.Any()) return null;
var closest = belowHeights
.OrderBy(h => Math.Abs(h - height))
.First();
if (Math.Abs(closest - height) <= maxDistance)
return closest;
return null;
}
private int GetBestBarSize(double distance)
{
if (distance <= 0) return 0;
int[] validSizes = { 300, 600, 900, 1200, 1500, 1800 };
return validSizes
.Where(s => s >= distance * 0.8 && s <= distance * 1.2)
.OrderBy(s => Math.Abs(s - distance))
.FirstOrDefault();
}
private bool IsOnTopControlLine(double x, double y)
{
if (_topControlLine == null) return false;
try
{
double controlY = GetElevationAtX(x);
return Math.Abs(controlY - y) <= TopControlLineTolerance;
}
catch (System.Exception ex)
{
_ed.WriteMessage($"\n检查控制线位置错误: {ex.Message}");
return false;
}
}
private double? FindNearestPole(double x, List<double> polePositions)
{
if (polePositions == null || polePositions.Count == 0)
return null;
// 找到最近的立杆位置
return polePositions
.OrderBy(p => Math.Abs(p - x))
.FirstOrDefault();
}
private void InsertBlock(Transaction tr, BlockTableRecord btr, BlockTable bt,
string blockName, double x, double y, double rotation = 0)
{
if (!bt.Has(blockName))
{
_ed.WriteMessage($"\n图块不存在: {blockName}");
return;
}
try
{
// 特殊部件(顶托和螺母)不进行高度验证
if (!blockName.Contains("顶托") && !blockName.Contains("螺母"))
{
double controlY = GetElevationAtX(x);
bool isValid = _isAscending ?
(y <= controlY - MinTopGap) :
(y >= controlY + MinTopGap);
if (!isValid)
{
_ed.WriteMessage($"\n跳过无效位置: {blockName} @ ({x}, {y})");
return;
}
}
BlockReference bref = new BlockReference(new Point3d(x, y, 0), bt[blockName]);
bref.Rotation = rotation;
btr.AppendEntity(bref);
tr.AddNewlyCreatedDBObject(bref, true);
// 调试日志
if (blockName.Contains("顶托"))
_ed.WriteMessage($"\n插入顶托: ({x}, {y})");
}
catch (System.Exception ex)
{
_ed.WriteMessage($"\n插入图块 {blockName} 错误: {ex.Message}");
}
}
// 插入斜拉杆块(应用镜像变换)
private void InsertXieBarBlock(
Transaction tr, BlockTableRecord btr, BlockTable bt,
string blockName, double x, double y, double rotation, Matrix3d mirrorMatrix)
{
try
{
if (!bt.Has(blockName))
{
_ed.WriteMessage($"\n图块不存在: {blockName}");
return;
}
BlockReference bref = new BlockReference(new Point3d(x, y, 0), bt[blockName]);
bref.Rotation = rotation;
// 应用镜像变换
bref.TransformBy(mirrorMatrix);
btr.AppendEntity(bref);
tr.AddNewlyCreatedDBObject(bref, true);
// 记录插入的斜拉杆
_insertedXieBars.Add(bref.ObjectId);
}
catch (System.Exception ex)
{
_ed.WriteMessage($"\n插入斜拉杆图块 {blockName} 错误: {ex.Message}");
}
}
// 获取最近的连接盘高度
private double? GetNearestDiskHeight(double x, double targetHeight, double tolerance)
{
try
{
if (!_diskPositions.TryGetValue(x, out List<double> heights) || heights.Count == 0)
{
_ed.WriteMessage($"\n警告:立杆{x}未记录连接盘位置");
return null;
}
// 查找最接近的高度
double? closestHeight = null;
double minDiff = double.MaxValue;
foreach (double h in heights)
{
double diff = Math.Abs(h - targetHeight);
if (diff < minDiff)
{
minDiff = diff;
closestHeight = h;
}
}
if (minDiff > tolerance)
{
_ed.WriteMessage($"\n警告:立杆{x}在高度{targetHeight}附近未找到连接盘,最小差距={minDiff}");
return null;
}
return closestHeight;
}
catch (System.Exception ex)
{
_ed.WriteMessage($"\n获取连接盘高度错误: {ex.Message}");
return null;
}
}
}
}
CS8370功能”递归模式”在C#7.3中不可用。请使用8.0或更高的语言版本。
CS8370功能”递归模式”在C#7.3中不可用。请使用8.0或更高的语言版本。
最新发布