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}
};
// 斜拉杆尺寸到图块名称的映射
private static readonly Dictionary<int, string> XieBarBlockMap = new Dictionary<int, string>
{
{600, "ScaffoldPolexie竖向斜拉杆600mm"},
{900, "ScaffoldPolexie竖向斜拉杆900mm"},
{1500, "ScaffoldPolexie竖向斜拉杆1500mm"},
{1800, "ScaffoldPolexie竖向斜拉杆1800mm"}
};
// 常量定义
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 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>();
// 记录已布置的横杆位置 (x位置, 高度)
private readonly HashSet<Tuple<double, double>> _placedHorizontalBars = new HashSet<Tuple<double, double>>();
// 记录水平斜拉杆位置 (起点x, 终点x, 高度)
private readonly HashSet<Tuple<double, double, double>> _placedHorizontalXieBars = new HashSet<Tuple<double, double, double>>();
[CommandMethod("GS", CommandFlags.Modal)]
public void GenerateScaffold()
{
Document doc = Application.DocumentManager.MdiActiveDocument;
Database db = doc.Database;
_ed = doc.Editor;
try
{
_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选择底标高水平控制线");
var baseLine = SelectControlLine();
if (baseLine == null)
{
_ed.WriteMessage("\n未选择底标高水平控制线");
return;
}
_ed.WriteMessage("\n选择顶部控制线");
_topControlLine = SelectControlLine();
if (_topControlLine == null)
{
_ed.WriteMessage("\n未选择顶部控制线");
return;
}
double baseElev = GetLineElevation(baseLine);
using (Transaction tr = db.TransactionManager.StartTransaction())
{
BlockTable bt = (BlockTable)tr.GetObject(db.BlockTableId, OpenMode.ForRead);
BlockTableRecord btr = (BlockTableRecord)tr.GetObject(db.CurrentSpaceId, OpenMode.ForWrite);
_diskPositions.Clear();
_adjusterPositions.Clear();
_lastPoleSizes.Clear();
_poleBasePositions.Clear();
_topDiskPositions.Clear();
_placedHorizontalBars.Clear();
_placedHorizontalXieBars.Clear();
LayoutVerticalPoles(tr, bt, btr, blockRefs, baseElev);
LayoutHorizontalBars(tr, bt, btr, blockRefs, baseElev);
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}");
}
}
catch (System.Exception sysEx)
{
_ed.WriteMessage($"\n系统错误: {sysEx.Message}");
}
}
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
{
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;
double nutPosition = _isAscending ?
(currentY + NutOffset) :
(currentY - NutOffset);
if (bt.Has("ScaffoldPole顶托螺母"))
{
InsertBlock(tr, btr, bt, "ScaffoldPole顶托螺母", xPos, nutPosition);
}
}
}
}
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 actualHeight = Math.Abs(actualTopY - startY);
double direction = _isAscending ? 1 : -1;
double firstDiskY = startY + FirstBarHeight * direction;
if (!_diskPositions[x].Contains(firstDiskY))
_diskPositions[x].Add(firstDiskY);
int stepCount = 1;
while (true)
{
double diskHeight = FirstBarHeight + stepCount * HorizontalBarSpacing;
if (diskHeight > actualHeight - MinTopGap) break;
double diskY = startY + diskHeight * direction;
if (!_diskPositions[x].Contains(diskY))
_diskPositions[x].Add(diskY);
stepCount++;
}
if (!_diskPositions[x].Contains(actualTopY))
_diskPositions[x].Add(actualTopY);
_topDiskPositions[x] = actualTopY;
}
catch (System.Exception ex)
{
_ed.WriteMessage($"\n记录连接盘位置错误: {ex.Message}");
}
}
private void LayoutHorizontalBars(
Transaction tr,
BlockTable bt,
BlockTableRecord btr,
List<BlockReference> blocks,
double baseElev)
{
try
{
var poleXPositions = _poleBasePositions.Keys
.OrderBy(x => x)
.ToList();
if (poleXPositions.Count < 2) return;
List<double> barHeights = CalculateBarHeights(poleXPositions, baseElev);
// 先布置横杆
for (int i = 0; i < barHeights.Count; i++)
{
PlaceBarsAtHeight(tr, bt, btr, poleXPositions, barHeights[i], i + 1);
}
PlaceTopBarsOnDisks(tr, bt, btr, poleXPositions);
// 最后布置斜拉杆
LayoutXieBars(tr, bt, btr, poleXPositions, barHeights);
}
catch (System.Exception ex)
{
_ed.WriteMessage($"\n布置横杆错误: {ex.Message}");
}
}
private void LayoutXieBars(
Transaction tr,
BlockTable bt,
BlockTableRecord btr,
List<double> poleXPositions,
List<double> barHeights)
{
try
{
_ed.WriteMessage("\n开始布置竖向斜拉杆(八形布置)...");
int xieBarCount = 0;
// 按步距过滤高度(每层都布置)
for (int heightIndex = 0; heightIndex < barHeights.Count; heightIndex++)
{
double targetHeight = barHeights[heightIndex];
_ed.WriteMessage($"\n在高度 {targetHeight} 布置斜拉杆...");
// 遍历每个跨间(相邻立杆之间)
for (int i = 0; i < poleXPositions.Count - 1; i++)
{
double leftPole = poleXPositions[i];
double rightPole = poleXPositions[i + 1];
double distance = Math.Abs(rightPole - leftPole);
// 跳过过远或过近的跨间
if (distance < 300 || distance > MaxBarDistance)
{
_ed.WriteMessage($"\n 跳过跨间 {i}: 距离 {distance} 不在范围内");
continue;
}
// 获取实际连接盘位置(考虑地形)
double? diskY1 = GetNearestDiskHeight(leftPole, targetHeight, MaxDiskSearchDistance);
double? diskY2 = GetNearestDiskHeight(rightPole, targetHeight, MaxDiskSearchDistance);
if (!diskY1.HasValue || !diskY2.HasValue)
{
_ed.WriteMessage($"\n 跨间 {i}: 在位置 {leftPole} 或 {rightPole} 找不到连接盘");
continue;
}
double y1 = diskY1.Value;
double y2 = diskY2.Value;
// 跳过高度差过大的位置
if (Math.Abs(y1 - y2) > HeightDifferenceThreshold)
{
_ed.WriteMessage($"\n 跨间 {i}: 高度差过大: {Math.Abs(y1 - y2)} > {HeightDifferenceThreshold}");
continue;
}
// 计算实际需要的斜拉杆长度
double actualDistance = Math.Sqrt(
Math.Pow(rightPole - leftPole, 2) +
Math.Pow(y2 - y1, 2)
);
// 选择最佳斜拉杆尺寸
int bestSize = GetBestXieBarSize(actualDistance);
if (bestSize <= 0)
{
_ed.WriteMessage($"\n 跨间 {i}: 找不到合适的斜拉杆尺寸: {actualDistance}");
continue;
}
// 使用斜拉杆映射字典获取正确的图块名称
if (!XieBarBlockMap.TryGetValue(bestSize, out string blockName))
{
_ed.WriteMessage($"\n跨间 {i}: 找不到斜拉杆图块映射: {bestSize}mm");
continue;
}
if (!bt.Has(blockName))
{
_ed.WriteMessage($"\n跨间 {i}: 找不到图块: {blockName}");
continue;
}
// 计算中点
double midX = (leftPole + rightPole) / 2.0;
double midY = (y1 + y2) / 2.0;
// 严格检查是否超出顶部控制线
if (IsAboveTopControlLine(midX, midY) ||
IsAboveTopControlLine(leftPole, y1) ||
IsAboveTopControlLine(rightPole, y2))
{
_ed.WriteMessage($"\n 跨间 {i}: 跳过超出顶控制线的位置");
continue;
}
// 计算旋转角度(考虑地形坡度)
double dx = rightPole - leftPole;
double dy = y2 - y1;
double angle = Math.Atan2(dy, dx);
// ==================== 关键修改:八形布置 ====================
// 奇数跨间使用正斜方向(左上到右下)
// 偶数跨间使用反斜方向(左下到右上)
if (i % 2 == 1) // 偶数索引(从0开始)
{
// 反斜方向:旋转180度
angle += Math.PI;
}
// ==================== 修改结束 ====================
// 插入斜拉杆
InsertBlock(tr, btr, bt, blockName, midX, midY, angle);
_ed.WriteMessage($"\n 跨间 {i}: 布置斜拉杆: {blockName} 在 ({midX:F2},{midY:F2}) 角度: {angle:F2}");
xieBarCount++;
}
}
_ed.WriteMessage($"\n共布置 {xieBarCount} 根竖向斜拉杆");
}
catch (System.Exception ex)
{
_ed.WriteMessage($"\n布置斜拉杆错误: {ex.Message}");
}
}
// 查找左侧最近的立杆 (修复方法)
private double FindNearestPoleLeft(double x, List<double> polePositions)
{
// 获取所有在x左侧的立杆位置
var leftPoles = polePositions.Where(p => p <= x).ToList();
if (leftPoles.Count == 0)
return double.NaN;
// 返回最接近x的值(最大值)
return leftPoles.Max();
}
// 查找右侧最近的立杆 (修复方法)
private double FindNearestPoleRight(double x, List<double> polePositions)
{
// 获取所有在x右侧的立杆位置
var rightPoles = polePositions.Where(p => p >= x).ToList();
if (rightPoles.Count == 0)
return double.NaN;
// 返回最接近x的值(最小值)
return rightPoles.Min();
}
// 检查点是否在顶部控制线之上
private bool IsAboveTopControlLine(double x, double y)
{
if (_topControlLine == null) return false;
try
{
double controlY = GetElevationAtX(x);
// 使用严格检查
double tolerance = 0.01;
if (_isAscending)
{
return y > (controlY - tolerance);
}
else
{
return y < (controlY + tolerance);
}
}
catch
{
return false;
}
}
// 获取最近的连接盘高度
private double? GetNearestDiskHeight(double x, double targetHeight, double tolerance)
{
if (!_diskPositions.TryGetValue(x, out List<double> heights) || heights.Count == 0)
return null;
return heights
.OrderBy(h => Math.Abs(h - targetHeight))
.FirstOrDefault(h => Math.Abs(h - targetHeight) <= tolerance);
}
// 斜拉杆尺寸选择方法
private int GetBestXieBarSize(double distance)
{
if (distance <= 0) return 0;
int[] validSizes = { 600, 900, 1500, 1800 };
// 精确匹配(容差±10%)
return validSizes
.Where(s => Math.Abs(s - distance) <= distance * 0.1)
.OrderBy(s => Math.Abs(s - distance))
.FirstOrDefault();
}
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 PlaceBarsAtHeight(
Transaction tr, BlockTable bt, BlockTableRecord btr,
List<double> poleXPositions, double height, int stepNumber)
{
try
{
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;
// 使用"立横杆"图块名称
int bestSize = GetBestBarSize(distance);
if (bestSize <= 0) continue;
string blockName = $"ScaffoldPole立横杆{bestSize}mm";
if (!bt.Has(blockName)) continue;
double? altHeight1 = null;
double? altHeight2 = null;
double actualHeight = height;
bool hasDisk1 = HasDiskAtHeight(x1, height, RelaxedTolerance);
bool hasDisk2 = HasDiskAtHeight(x2, height, RelaxedTolerance);
if (!hasDisk1)
{
altHeight1 = FindNearestDiskBelow(x1, height, MaxDiskSearchDistance);
if (altHeight1.HasValue)
{
hasDisk1 = true;
actualHeight = altHeight1.Value;
}
}
if (!hasDisk2)
{
altHeight2 = FindNearestDiskBelow(x2, height, MaxDiskSearchDistance);
if (altHeight2.HasValue)
{
if (altHeight1.HasValue && Math.Abs(altHeight2.Value - actualHeight) > RelaxedTolerance)
{
continue;
}
hasDisk2 = true;
actualHeight = altHeight2.Value;
}
}
if (hasDisk1 && hasDisk2)
{
double midX = (x1 + x2) / 2;
if (IsOnTopControlLine(midX, actualHeight)) continue;
InsertBlock(tr, btr, bt, blockName, midX, actualHeight);
// 记录已布置的横杆位置
_placedHorizontalBars.Add(new Tuple<double, double>(midX, actualHeight));
}
}
}
catch (System.Exception ex)
{
_ed.WriteMessage($"\n在高度 {height} 布置横杆错误: {ex.Message}");
}
}
private void PlaceTopBarsOnDisks(
Transaction tr, BlockTable bt, BlockTableRecord btr,
List<double> poleXPositions)
{
try
{
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 (!_topDiskPositions.TryGetValue(x1, out double topDisk1) ||
!_topDiskPositions.TryGetValue(x2, out double topDisk2))
{
continue;
}
double heightDiff = Math.Abs(topDisk1 - topDisk2);
if (heightDiff > HeightDifferenceThreshold) continue;
double barHeight = (topDisk1 + topDisk2) / 2.0;
if (IsOnTopControlLine((x1 + x2) / 2.0, barHeight)) continue;
// 使用"立横杆"图块名称
int bestSize = GetBestBarSize(distance);
if (bestSize <= 0) continue;
string blockName = $"ScaffoldPole立横杆{bestSize}mm";
if (!bt.Has(blockName)) continue;
double midX = (x1 + x2) / 2.0;
InsertBlock(tr, btr, bt, blockName, midX, barHeight);
// 记录已布置的横杆位置
_placedHorizontalBars.Add(new Tuple<double, double>(midX, barHeight));
}
}
catch (System.Exception ex)
{
_ed.WriteMessage($"\n布置顶部横杆错误: {ex.Message}");
}
}
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 GetElevationAtX(double x)
{
if (_topControlLine == null) return 0;
try
{
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;
}
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 >= start.X && x <= end.X) || (x <= start.X && x >= end.X))
{
if (Math.Abs(end.X - start.X) < 0.001) return start.Y;
double t = (x - start.X) / (end.X - start.X);
return start.Y + t * (end.Y - start.Y);
}
}
return pline.GetPoint3dAt(0).Y;
}
}
catch (System.Exception ex)
{
_ed.WriteMessage($"\n获取控制线高程错误: {ex.Message}");
}
return 0;
}
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
{
BlockReference bref = new BlockReference(new Point3d(x, y, 0), bt[blockName]);
bref.Rotation = rotation;
btr.AppendEntity(bref);
tr.AddNewlyCreatedDBObject(bref, true);
}
catch (System.Exception ex)
{
_ed.WriteMessage($"\n插入图块 {blockName} 错误: {ex.Message}");
}
}
}
}
竖向斜拉杆依然布置错误,
框选的块中没有水平斜拉杆垂直位置也布置了竖向斜拉杆
布置的竖向斜拉杆超出顶部控制线未被删除
竖向斜拉杆未布置成八字形,应该第一列正斜布置时第二列应该将竖向斜拉杆翻转布置成反斜布置
最新发布