活动介绍
file-type

3DMAX测量与标注插件:提高3D建模精准度与效率

下载需积分: 7 | 98KB | 更新于2025-04-08 | 98 浏览量 | 26 下载量 举报 1 收藏
download 立即下载
标题中提到的“3DMAX长度测量、标注插件”是指一款可以集成在3D Studio Max(通常称为3DS Max或3DMAX)软件内的插件,它的主要功能是帮助用户在3D场景中测量对象的长度或者距离,并对测量结果进行标注,从而提高工作效率,确保测量数据的准确性。3DMAX是一款广泛应用于游戏设计、电影制作、建筑可视化等领域中的3D建模、动画和渲染软件。该插件的出现是为了弥补原软件在测量功能上的不足,尤其对精确度要求很高的工作场景中,这样的插件显得尤为重要。 从描述中,我们可以了解到该插件非常实用,通过使用它可以显著节省工作时间,同时保证数据的准确性。插件的安装过程也相对简单,用户只需要将插件脚本直接拖动到3DMAX的主窗口即可完成安装。这种安装方式通常意味着插件是用3DMAX支持的脚本语言编写的,比如MaxScript或者是支持的插件格式,比如.mse文件。 在【标签】中,我们可以看到一系列相关关键词,包括“3dmax插件”、“3dsmax”、“3dmax测量距离”和“3dmax标注插件”,这些都是与3DMAX软件相关联的功能标签。这些标签表明该插件是专门针对3DMAX用户开发的,目的是为了提高3D建模和渲染的效率和准确性。通过搜索这些标签,用户可以快速定位到这个插件的相关信息,从而下载使用。 【压缩包子文件的文件名称列表】中的“测量距离.mse”可能是一个编译后的3DMAX插件文件,用户可以将该文件拖拽到3DMAX软件中进行安装。而“安装使用.txt”很可能是一个文本文件,包含关于如何安装和使用该插件的详细指南,这对于初次接触该插件的用户来说是非常有帮助的。最后,“测量距离.png”可能是一个说明插件如何使用或者插件界面的图片文件,用于直观展示插件的功能和效果,便于用户理解和学习。 在技术层面上,了解该插件如何具体测量距离和进行标注的操作是很重要的。通常,插件可能包括以下功能: 1. 点对点测量:用户可以选择场景中的两个点,插件会计算并显示这两点之间的直线距离。 2. 面对面测量:对于三维物体表面的两点,插件能够计算它们之间在曲面上的实际距离。 3. 角度测量:除了长度测量,插件还可以测量两个平面或者两条线之间的夹角。 4. 标注:用户可以将测量结果直接标注在3D场景中,方便记录和展示。 5. 数据输出:测量结果可以输出到文件或者直接复制粘贴,方便进一步分析或报告制作。 考虑到3DMAX是3D设计师、动画师和视觉效果师的常用工具,这样的插件能够为这些专业人员提供更加精确和便捷的测量手段,提高工作效率,减少因手动测量而导致的错误。安装使用此类插件前,确保系统的兼容性,并且定期对插件进行更新,以保持最佳的性能和最新的功能支持。

相关推荐

filetype

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) { _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; // 检查两侧是否有连接盘 (使用50mm容差) bool hasDisk1 = HasDiskAtHeight(x1, currentHeight, 50.0); bool hasDisk2 = HasDiskAtHeight(x2, currentHeight, 50.0); 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; } // 获取顶托位置 if (!_adjusterPositions.TryGetValue(x1, out double topPos1) || !_adjusterPositions.TryGetValue(x2, out double topPos2)) { continue; } // 根据立杆尺寸计算顶部横杆位置 double topBarY1 = _isAscending ? topPos1 - TopBarOffsets[lastSize1] : topPos1 + TopBarOffsets[lastSize1]; double topBarY2 = _isAscending ? topPos2 - TopBarOffsets[lastSize2] : topPos2 + TopBarOffsets[lastSize2]; // 检查高度差是否在允许范围内 double heightDiff = Math.Abs(topBarY1 - topBarY2); if (heightDiff > HeightDifferenceThreshold) continue; double barHeight = (topBarY1 + topBarY2) / 2.0; // 确保顶部横杆位置在连接盘上 double? diskHeight1 = GetNearestDiskHeight(x1, barHeight, 50.0); double? diskHeight2 = GetNearestDiskHeight(x2, barHeight, 50.0); if (!diskHeight1.HasValue || !diskHeight2.HasValue) { _ed.WriteMessage($"\n跳过无连接盘的顶部横杆: X1={x1}, X2={x2}, 高度={barHeight:F1}"); continue; } // 使用实际连接盘位置的平均值 barHeight = (diskHeight1.Value + diskHeight2.Value) / 2.0; // 检查是否已布置 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 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; } } } } 1500mm竖向斜拉杆布置成了1200mm竖向斜拉杆,需要布置1200mm竖向斜拉杆位置未布置

沐风老师
  • 粉丝: 1w+
上传资源 快速赚钱