SerializeField 序列化域

本文详细介绍了Unity中SerializeField序列化属性的作用、使用场景及限制条件,包括如何强制序列化私有字段、序列化的类型范围、注意事项以及与.NET序列化功能的区别。同时提供了实例代码演示,帮助开发者更深入地理解和运用这一特性。
SerializeField 序列化域

  Inherits from Attribute

  Force  unity  to serialize a private field.

  强制Unity去序列化一个私有域。

  You will almost never need this. When Unity serializes your scripts, it will only serialize public fields. If in addition to that you also want Unity to serialize one of your private fields you can add the SerializeField attribute to the field.

  你几乎从来不需要它。当Unity序列化你的脚本的时候,它将紧紧序列化公有域。如果作为附加你也想要Unity去序列化你的一个私有域,你可以添加SerializeField(序列化域)属性给这个域。

  Unity will serialize all your script components, reload the new assemblies, and recreate your script components from the serialized verions. This serialization does not happen with .NET's serialization functionality, but with an internal Unity one.

  Unity将序列化所有你的脚本组件,重载新的集合,并且重新创建你的脚本组件从这个序列化版本。这个序列化不会发生通过.Net的序列化功能,而是用一个内部的Unity序列化功能。

  The serialization system used can do the following:

  这个序列化系统使用可以做以下事情:

  - CAN serialize public nonstatic fields (of serializable types)

  - 可以序列化公有的非静态域(序列化类型的)

  - CAN serialize nonpublic nonstatic fields marked with the [SerializeField] attribute.

  - 可以序列化非公有非静态域用[SerializeField]属性标记。

  - CANNOT serialize static fields.

  - 不可以序列化静态域。

  - CANNOT serialize properties.

  - 不可以序列化属性。

  Your field will only serialize if it is of a type that Unity can serialize:

  你的域将紧紧序列化如果他是Unity可以序列化的一种类型。

  Serializable types are:

  序列化的类型有:

  - All classed inheriting from UnityEngine.Object, for example Gameobject, Commponent, MonoBehaviour, Texture 2D , AnimationClip.. - All basic data types like int, string, float, bool. - Some built in types like Vector2, Vector3, Vector4, Quaternion, Matrix4x4, Color, Rect, Layermask.. - Arrays of a serializable type

  - 所有继承自UnityEngine.Object的类,例如GameObject,Component,MonoBehaviour,Texture2D,AnimationClip..- 所有基本类型像int,string,float,bool.- 一些内建类型像Vector2,Vector3,Vector4,Quaternion,Matrix4x4,Color,Rect,Layermask..- 一个序列化类型的Array(数组)

  - List of a serializable type (new in Unity2.6)

  - 一个序列化类型的列表(新的在Unity2.6)

  - Enums

  - 枚举。

  Headsup note: if you put one element in a list (or array) twice, when the list gets serialized, you'll get two copies of that element, instead of one copy being in the new list twice.

  特别注意:如果你放一个元素在一个列表(或者数组)两次,当列表被序列化的时候,你将得到两个这个元素的拷贝,而不是一个拷贝两次在新的列表。

  Hint: Unity won't serialize Dictionary, however you could store a Listf<> or keys and a List<> for values, and sew them up in a non serialized dictionary on Awake(). This doesn't solve the problem of when you want to modify the dictionary and have it “saved” back, but it is a handy trick in a lot of other cases.

  暗示:Unity不会序列化Dictionary(字典),然而你可以存储一个列表给键,一个列表给值,并且缝合他们在一个非序列化dictionary(字典)在Awake()。这不会解决当你想要修改dictionary(字典)和让它的“被保存”返回的 问题 ,但是它在很多其他的情况里是一个便利的窍门。

  For UnityScript users: Fields in c# is a script variable in UnityScript, and [SerializeField] becomes @SerializeField. [Serializable] on a class becomes @script Serializable in a UnityScript

  给UnityScript用户:C#中的域在UnityScript中是一个脚本变量,并且[SerializeField]变成@SerializeField。[Serializable] 在一个类上变成@script Serializable在一个UnityScript。

[AppleScript]  纯文本查看  复制代码
?
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
/ / Javascript example
 
/ / This field gets serialized because it is public.
 
/ / 这个域被序列化因为他是公开的。
 
var name = “John”;
 
/ / This field does not get serialized because it is private.
 
/ / 这个域没有被序列化因为它是私有的。
 
private var age = 40 ;
 
/ / This field gets serialized even though it is private
 
/ / 这个域被序列化尽管他是私有的。
 
/ / because it has the SerializeField attribute applied.
 
/ / 因为它应用了SerializeField属性
 
@SerializeField
 
private var hasHealthPotion : boolean = true ;
 
function Update ( ) {
 
}
 
/ / C # example
 
using UnityEngine;
 
public class SomePerson : MonoBehaviour {
 
/ / This field gets serialized because it is public.
 
public string name = “John”;
 
/ / This field does not get serialized because it is private.
 
private int age = 40 ;
 
/ / This field gets serialized even though it is private
 
/ / because it has the SerializeField attribute applied.
 
[SerializeField]
 
private bool hasHealthPotion = true ;
 
void Update ( ) {
 
}
 
}

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; // 使用别名解决Exception冲突 using AcadException = Autodesk.AutoCAD.Runtime.Exception; using SysException = System.Exception; 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} // 连接盘高度 }; // 常量定义 private const double FirstBarHeight = 250.0; // 第一道横杆高度 private const double HorizontalBarSpacing = 1500.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 = 25.0; // 放大的容差用于连接盘检测 private const double MaxBarDistance = 2000.0; // 最大横杆跨度 private const double DiskHeightOffset = 125.0; // 连接盘在立杆上的高度偏移(标准值) private const double MaxDiskSearchDistance = 1000.0; // 最大向下搜索连接盘距离 private Editor _ed; private string _blocksFolderPath; private Curve _topControlLine; private bool _isAscending; // 立杆高度是否递增 // 存储所有连接盘位置 [X坐标 -> 连接盘Y坐标列表] private readonly Dictionary<double, List<double>> _diskPositions = new Dictionary<double, List<double>>(); // 存储顶部连接盘位置 [X坐标 -> 顶部连接盘Y坐标] private readonly Dictionary<double, double> _topDiskPositions = new Dictionary<double, double>(); // 存储顶托位置 [X坐标 -> 顶托Y坐标] private readonly Dictionary<double, double> _adjusterPositions = new Dictionary<double, double>(); // 存储最后一根立杆信息 [X坐标 -> 最后一根立杆尺寸] private readonly Dictionary<double, int> _lastPoleSizes = new Dictionary<double, int>(); // 存储立杆底部位置 [X坐标 -> 底部Y坐标] private readonly Dictionary<double, double> _poleBasePositions = new Dictionary<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) return; // 选择控制线 _ed.WriteMessage("\n选择底标高水平控制线"); var baseLine = SelectControlLine(); if (baseLine == null) return; _ed.WriteMessage("\n选择顶部控制线"); _topControlLine = SelectControlLine(); if (_topControlLine == null) 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(); _topDiskPositions.Clear(); _adjusterPositions.Clear(); _lastPoleSizes.Clear(); _poleBasePositions.Clear(); // 立杆布置 int poleCount = LayoutVerticalPoles(tr, bt, btr, blockRefs, baseElev); _ed.WriteMessage($"\n已布置 {poleCount} 根立杆。"); // 横杆布置 int barCount = LayoutHorizontalBars(tr, bt, btr, blockRefs, baseElev); _ed.WriteMessage($"\n已布置 {barCount} 根横杆。"); tr.Commit(); } _ed.WriteMessage("\n盘扣支模架生成完成!"); } catch (AcadException acadEx) // AutoCAD特有异常 { HandleAcadException(acadEx); } catch (SysException sysEx) // 系统异常 { _ed.WriteMessage($"\n系统错误: {sysEx.Message}"); } } // 处理AutoCAD特有异常 private void HandleAcadException(AcadException acadEx) { if (acadEx.ErrorStatus == ErrorStatus.UserBreak) { _ed.WriteMessage("\n操作已取消"); } else { _ed.WriteMessage($"\nAutoCAD错误: {acadEx.ErrorStatus} - {acadEx.Message}"); } } // 获取图块文件夹路径 private string GetBlocksFolderPath() { try { string assemblyPath = Assembly.GetExecutingAssembly().Location; string pluginDir = Path.GetDirectoryName(assemblyPath); return Path.Combine(pluginDir, "ScaffoldBlocks"); } catch { return null; } } // 加载所有图块定义 private void LoadAllBlockDefinitions(Database db) { if (string.IsNullOrEmpty(_blocksFolderPath)) return; try { string[] blockFiles = Directory.GetFiles(_blocksFolderPath, "*.dwg"); if (blockFiles.Length == 0) 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) || bt.Has(fileName)) continue; using (Database sourceDb = new Database(false, true)) { sourceDb.ReadDwgFile(filePath, FileShare.Read, true, null); db.Insert(fileName, sourceDb, true); } } tr.Commit(); } } catch (SysException 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 (AcadException acadEx) { HandleAcadException(acadEx); return null; } } // 获取直线/多段线的Y坐标 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 (SysException 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 (AcadException acadEx) { HandleAcadException(acadEx); return null; } } // 立杆布置 - 严格保证顶部间隙200-400mm private int LayoutVerticalPoles( Transaction tr, BlockTable bt, BlockTableRecord btr, List<BlockReference> blocks, double baseElev) { int poleCount = 0; 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) return 0; // 确定整体方向 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; // 1. 先配标准杆(保留顶部间隙空间) while (remaining > MinTopGap + 350) // 保留至少350mm+200mm间隙 { // 计算最大可用尺寸(考虑最小间隙200mm) 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; } // 2. 顶部配杆算法(关键:确保间隙在200-400mm) int lastPoleSize = 0; double gap = 0; // 计算理想顶部间隙(200-400mm) 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 { // 次选:最接近300mm间隙的杆 lastPoleSize = standardSizes .OrderBy(s => Math.Abs((remaining - s) - 300)) // 300是理想间隙 .First(); gap = remaining - lastPoleSize; // 确保间隙至少200mm if (gap < minGap) { // 减少一根标准杆来增加空间 if (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; } else { // 无法调整时使用350mm杆 lastPoleSize = 350; gap = remaining - lastPoleSize; } } } // 添加最后一根立杆 usedSizes.Add(lastPoleSize); gap = remaining - lastPoleSize; // 记录最后一根立杆尺寸 _lastPoleSizes[xPos] = lastPoleSize; // 3. 布置所有立杆 currentY = baseElev; // 重置当前高度 foreach (int size in usedSizes) { string blockName = $"ScaffoldPole立杆{size}mm"; if (bt.Has(blockName)) { InsertBlock(tr, btr, bt, blockName, xPos, currentY); poleCount++; // 记录连接盘位置(关键:包括顶部连接盘) RecordDiskPositions(xPos, currentY, size); currentY += _isAscending ? size : -size; } } // 4. 布置顶托和螺母 if (bt.Has("ScaffoldPole顶托")) { // 顶托顶部精确对齐控制线 double topPosition = topElev; InsertBlock(tr, btr, bt, "ScaffoldPole顶托", xPos, topPosition); _adjusterPositions[xPos] = topPosition; // 螺母位置(在最后一根立杆顶部上方75mm) double nutPosition = _isAscending ? (currentY + NutOffset) : (currentY - NutOffset); if (bt.Has("ScaffoldPole顶托螺母")) { InsertBlock(tr, btr, bt, "ScaffoldPole顶托螺母", xPos, nutPosition); } } // 5. 验证顶部间隙 if (gap < minGap || gap > maxGap) { _ed.WriteMessage($"\n警告: 位置 {xPos} 顶部间隙为 {gap:F1}mm (要求200-400mm)"); } } } catch (SysException ex) { _ed.WriteMessage($"\n布置立杆错误: {ex.Message}"); } return poleCount; } // 记录立杆上的连接盘位置(包括顶部连接盘) private void RecordDiskPositions(double x, double startY, int poleSize) { try { if (!_diskPositions.ContainsKey(x)) _diskPositions[x] = new List<double>(); double direction = _isAscending ? 1 : -1; double poleHeight = poleSize; // 1. 添加250mm处的连接盘 double firstDiskY = startY + FirstBarHeight * direction; if (!_diskPositions[x].Contains(firstDiskY)) _diskPositions[x].Add(firstDiskY); // 2. 添加1500mm步距连接盘 double currentHeight = firstDiskY; double step = HorizontalBarSpacing * direction; // 添加后续连接盘(1500mm步距) while (_isAscending ? (currentHeight + step <= startY + poleHeight * direction) : (currentHeight + step >= startY - poleHeight)) { currentHeight += step; if (!_diskPositions[x].Contains(currentHeight)) _diskPositions[x].Add(currentHeight); } // 3. 添加顶部连接盘(立杆顶部连接盘位置) double topDiskY = startY + poleHeight * direction; if (!_diskPositions[x].Contains(topDiskY)) _diskPositions[x].Add(topDiskY); // 4. 单独记录顶部连接盘位置(关键修改) _topDiskPositions[x] = topDiskY; } catch (SysException ex) { _ed.WriteMessage($"\n记录连接盘错误: {ex.Message}"); } } // 横杆布置 - 严格按连接盘布置 private int LayoutHorizontalBars( Transaction tr, BlockTable bt, BlockTableRecord btr, List<BlockReference> blocks, double baseElev) { int barCount = 0; try { // 获取所有立杆位置 var poleXPositions = _poleBasePositions.Keys .OrderBy(x => x) .ToList(); if (poleXPositions.Count < 2) return 0; // 计算横杆布置高度序列(250mm起始,1500mm步距) List<double> barHeights = CalculateBarHeights(poleXPositions, baseElev); // 为每个横杆高度布置横杆 foreach (var height in barHeights) { barCount += PlaceBarsAtHeight(tr, bt, btr, poleXPositions, height); } // 在顶部立杆圆盘处布置横杆(强制) barCount += PlaceTopDiskBars(tr, bt, btr, poleXPositions, barHeights); } catch (SysException ex) { _ed.WriteMessage($"\n布置横杆错误: {ex.Message}"); } return barCount; } // 计算横杆布置高度序列(250mm起始,1500mm步距) private List<double> CalculateBarHeights(List<double> polePositions, double baseElev) { var barHeights = new List<double>(); try { // 1. 添加第一道横杆(250mm高度) double firstBarHeight = baseElev + (_isAscending ? FirstBarHeight : -FirstBarHeight); barHeights.Add(firstBarHeight); // 2. 确定最高点(顶部立杆圆盘位置) double maxHeight = polePositions .Where(x => _topDiskPositions.ContainsKey(x)) .Max(x => _topDiskPositions[x]); // 3. 计算1500mm步距序列 double currentHeight = firstBarHeight; double step = _isAscending ? HorizontalBarSpacing : -HorizontalBarSpacing; // 添加中间横杆(直到接近顶部) while (_isAscending ? (currentHeight + step <= maxHeight - MinTopGap) : (currentHeight + step >= maxHeight + MinTopGap)) { currentHeight += step; barHeights.Add(currentHeight); } } catch (SysException ex) { _ed.WriteMessage($"\n计算横杆高度错误: {ex.Message}"); } return barHeights; } // 在指定高度布置横杆 - 支持向下寻找连接盘 private int PlaceBarsAtHeight( Transaction tr, BlockTable bt, BlockTableRecord btr, List<double> poleXPositions, double height) { int barCount = 0; 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; // 检查两端是否都有连接盘(使用放宽的容差) bool hasDisk1 = HasDiskAtHeight(x1, height, RelaxedTolerance); bool hasDisk2 = HasDiskAtHeight(x2, height, RelaxedTolerance); double actualHeight = height; bool adjustedHeight = false; // 如果某端缺少连接盘,尝试向下1000mm内寻找替代位置 if (!hasDisk1 || !hasDisk2) { // 尝试在左端向下寻找连接盘 if (!hasDisk1) { double? altHeight1 = FindNearestDiskBelow(x1, height, MaxDiskSearchDistance); if (altHeight1.HasValue) { hasDisk1 = true; actualHeight = altHeight1.Value; adjustedHeight = true; } } // 尝试在右端向下寻找连接盘 if (!hasDisk2) { double? altHeight2 = FindNearestDiskBelow(x2, height, MaxDiskSearchDistance); if (altHeight2.HasValue) { // 如果左端已调整,检查高度是否匹配 if (adjustedHeight && Math.Abs(altHeight2.Value - actualHeight) > RelaxedTolerance) { // 两端找到的高度不一致,跳过 _ed.WriteMessage($"\n警告: 位置 {x1}-{x2} 两端连接盘高度不匹配 ({altHeight1.Value:F1} vs {altHeight2.Value:F1})"); continue; } hasDisk2 = true; actualHeight = altHeight2.Value; adjustedHeight = true; } } } // 确保两端都有连接盘 if (hasDisk1 && hasDisk2) { double midX = (x1 + x2) / 2; InsertBlock(tr, btr, bt, blockName, midX, actualHeight); barCount++; if (adjustedHeight) { _ed.WriteMessage($"\n调整高度: 在 {x1}-{x2} 使用 {actualHeight:F1}mm 替代 {height:F1}mm"); } } else { _ed.WriteMessage($"\n警告: 位置 {x1}-{x2} 高度 {height} 缺少连接盘,跳过横杆布置"); } } } catch (SysException ex) { _ed.WriteMessage($"\n在高度 {height} 布置横杆错误: {ex.Message}"); } return barCount; } // 在顶部立杆圆盘处布置横杆(严格模式) private int PlaceTopDiskBars( Transaction tr, BlockTable bt, BlockTableRecord btr, List<double> poleXPositions, List<double> existingBarHeights) { int barCount = 0; try { // 1. 按高度分组顶部连接盘 var heightGroups = new Dictionary<double, List<double>>(); foreach (var x in poleXPositions) { if (!_topDiskPositions.TryGetValue(x, out double topY)) continue; // 对Y坐标分组(容差处理) double roundedY = Math.Round(topY / Tolerance) * Tolerance; if (!heightGroups.ContainsKey(roundedY)) heightGroups[roundedY] = new List<double>(); heightGroups[roundedY].Add(x); } // 2. 为每个高度组布置横杆 foreach (var group in heightGroups) { double height = group.Key; var xPositions = group.Value.OrderBy(x => x).ToList(); // 跳过已布置的高度(防重叠) if (existingBarHeights.Any(h => Math.Abs(h - height) <= Tolerance)) continue; // 仅当有2根以上立杆时才布置 if (xPositions.Count < 2) continue; // 3. 布置相邻立杆间的横杆 for (int i = 0; i < xPositions.Count - 1; i++) { double x1 = xPositions[i]; double x2 = xPositions[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 actualHeight = _topDiskPositions[x1]; // 使用实际高度 double midX = (x1 + x2) / 2; // 严格检查两端连接盘 bool hasDisk1 = HasDiskAtHeight(x1, actualHeight, Tolerance); bool hasDisk2 = HasDiskAtHeight(x2, actualHeight, Tolerance); if (hasDisk1 && hasDisk2) { InsertBlock(tr, btr, bt, blockName, midX, actualHeight); barCount++; existingBarHeights.Add(actualHeight); _ed.WriteMessage($"\n已布置顶部横杆: {x1}-{x2} @ {actualHeight:F1}mm"); } else { _ed.WriteMessage($"\n警告: 顶部位置 {x1}-{x2} 缺少连接盘,跳过横杆布置"); } } } } catch (SysException ex) { _ed.WriteMessage($"\n布置顶部横杆错误: {ex.Message}"); } return barCount; } // 检查指定位置是否有连接盘 private bool HasDiskAtHeight(double x, double height, double tolerance = Tolerance) { try { if (!_diskPositions.ContainsKey(x)) return false; return _diskPositions[x].Any(y => Math.Abs(y - height) <= tolerance); } catch { return false; } } // 向下寻找最近的连接盘位置 private double? FindNearestDiskBelow(double x, double startHeight, double maxSearchDistance) { try { if (!_diskPositions.ContainsKey(x) || !_diskPositions[x].Any()) return null; // 确定搜索方向(向基础方向) double searchDirection = _isAscending ? -1 : 1; double minDistance = double.MaxValue; double bestHeight = 0; bool found = false; // 获取该位置的所有连接盘 foreach (double diskHeight in _diskPositions[x]) { // 计算高度差 double heightDiff = Math.Abs(diskHeight - startHeight); double directionDiff = (diskHeight - startHeight) * searchDirection; // 只考虑向下方向(向基础方向) if (directionDiff > 0) continue; // 检查是否在搜索范围内 if (heightDiff <= maxSearchDistance && heightDiff < minDistance) { minDistance = heightDiff; bestHeight = diskHeight; found = true; } } return found ? bestHeight : (double?)null; } catch (SysException ex) { _ed.WriteMessage($"\n寻找连接盘错误: {ex.Message}"); 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) // 允许20%误差 .OrderBy(s => Math.Abs(s - distance)) .FirstOrDefault(); } // 获取指定X坐标在控制线上的Y值 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 (SysException ex) { _ed.WriteMessage($"\n计算标高错误: {ex.Message}"); } return 0; } // 插入图块 private void InsertBlock(Transaction tr, BlockTableRecord btr, BlockTable bt, string blockName, double x, double y) { if (!bt.Has(blockName)) return; try { BlockReference bref = new BlockReference(new Point3d(x, y, 0), bt[blockName]); btr.AppendEntity(bref); tr.AddNewlyCreatedDBObject(bref, true); } catch (SysException ex) { _ed.WriteMessage($"\n插入图块错误: {ex.Message}"); } } } } CS0103当前上下文中不存在名称altHeight1”
最新发布
07-10
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值