识别图元(Queue)

博客给出一段C++代码实现图元标记功能。代码先初始化围墙和偏移量,利用队列扫描所有像素,当遇到新图元时进行标记,并寻找其余图元,通过检查相邻像素并标记,将未探索像素入队,体现了数据结构和算法的应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

void Label()
{
 //初始化围墙
 for(int i=0;i<=m+1;i++)
 {
  pixel[0][i]=pixel[m+1][i]=0;
  pixel[i][0]=pixel[i][m+1]=0;
 }

 // 初始化offset
 Position offset[4];
 offset[0].row=0; offset[0].col=1; // 右
 offset[1].row=1; offset[1].col=0; //下
 offset[2].row=0; offset[2].col=-1; //左
 offset[3].row=-1; offset[3].col=0; //上

 int NumofNbrs=4;
 LinkedQueue<Position> Q;
 int id=1;
 Position here, nbr;

 //扫描所有象素
 for(int r=1; r<=m; r++)
  for(int c=1;c<=m; c++)
  {
   if(pixel[r][c]==1)// 新图元
   {
    pixel[r][c]==++id;
    here.row=r;
    here.col=c;
   }

   // 寻找其余图元
   do  
   {
    for(int i=0; i<NumofNbrs; i++)
    {
     //检查当前象素的所有相邻象素
     nbr.row=here.row+offset[i].row;
     nbr.col=here.row+offset[i].col;
     if(pixel[nbr.row][nbr.col]==1)
     {
      pixel[nbr.row][nbr.col]=id;
      Q.Add(nbr);
     }
    }
    // 还有未探索的象素吗?
    if(Q.IsEmpty())
     break;
    Q.Delete(here);
   }while(1);
  }
}

Ref:<<数据结构,算法与应用>>P204~206

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.Linq; using System.Text.RegularExpressions; public class CADUtilities { // 常量定义 - 使用固定重叠阈值 private const double OverlapThreshold = 10.0; // 毫米 // ================== 梁信息类 ================== private class BeamInfo { public ObjectId Id { get; set; } public Extents3d Extents { get; set; } public Vector3d Direction { get; set; } public Point3d Center { get; set; } public bool IsHorizontal { get; set; } } // ================== CLN - 清理无用实体命令 ================== [CommandMethod("CLN")] public void CleanUpDrawing() { Document doc = Application.DocumentManager.MdiActiveDocument; if (doc == null) return; Database db = doc.Database; Editor ed = doc.Editor; using (Transaction tr = db.TransactionManager.StartTransaction()) { try { BlockTableRecord btr = (BlockTableRecord)tr.GetObject( db.CurrentSpaceId, OpenMode.ForWrite); int deletedCount = 0; var idsToDelete = new List<ObjectId>(); // 第一遍:收集需要删除的实体 foreach (ObjectId id in btr) { DBText text = tr.GetObject(id, OpenMode.ForRead) as DBText; if (text != null) { string textStr = text.TextString; // 保护轴号和标高文本 if (IsAxisNumber(textStr) || textStr.Contains("标高")) continue; // 删除空文本和无效梁标注 if (string.IsNullOrWhiteSpace(textStr) || (!IsBeamDimension(textStr) && !IsBeamLabel(textStr))) { idsToDelete.Add(id); } continue; } // 检查零长度线 Line line = tr.GetObject(id, OpenMode.ForRead) as Line; if (line != null && line.Length < 0.001) { idsToDelete.Add(id); } } // 第二遍:执行删除 foreach (ObjectId id in idsToDelete) { Entity ent = (Entity)tr.GetObject(id, OpenMode.ForWrite); ent.Erase(); deletedCount++; } tr.Commit(); ed.WriteMessage($"\n清理完成,删除 {deletedCount} 个无用实体"); } catch (System.Exception ex) { ed.WriteMessage($"\n错误: {ex.Message}"); tr.Abort(); } } } // ================== DEL - 图层删除命令 ================== [CommandMethod("DEL")] public void DeleteByLayer() { Document doc = Application.DocumentManager.MdiActiveDocument; if (doc == null) return; Database db = doc.Database; Editor ed = doc.Editor; // 用户选择参考对象 PromptEntityOptions opt = new PromptEntityOptions("\n选择图层参考对象:"); PromptEntityResult res = ed.GetEntity(opt); if (res.Status != PromptStatus.OK) return; using (Transaction tr = db.TransactionManager.StartTransaction()) { try { // 获取目标图层 Entity refEnt = tr.GetObject(res.ObjectId, OpenMode.ForRead) as Entity; if (refEnt == null) return; string targetLayer = refEnt.Layer; // 收集当前空间所有实体 BlockTableRecord btr = (BlockTableRecord)tr.GetObject( db.CurrentSpaceId, OpenMode.ForWrite); List<ObjectId> toDelete = new List<ObjectId>(); foreach (ObjectId id in btr) { Entity ent = tr.GetObject(id, OpenMode.ForRead) as Entity; if (ent != null && ent.Layer == targetLayer) { toDelete.Add(id); } } // 执行删除 if (toDelete.Count > 0) { foreach (ObjectId id in toDelete) { Entity ent = (Entity)tr.GetObject(id, OpenMode.ForWrite); ent.Erase(); } tr.Commit(); ed.WriteMessage($"\n已删除图层 '{targetLayer}' 中的 {toDelete.Count} 个对象"); } else { ed.WriteMessage($"\n图层 '{targetLayer}' 中未找到可删除对象"); } } catch (System.Exception ex) { ed.WriteMessage($"\n错误: {ex.Message}"); tr.Abort(); } } } // ================== BLD - 梁原位标注引线修复命令 ================== [CommandMethod("BLD")] public void BeamAnnotationLeaderFix() { Document doc = Application.DocumentManager.MdiActiveDocument; if (doc == null) return; Database db = doc.Database; Editor ed = doc.Editor; // 获取距离阈值 double distanceThreshold = GetDistanceThresholdFromEditor(); if (distanceThreshold < 0) // 用户取消 { ed.WriteMessage("\n操作已取消"); return; } // 定义梁图层关键词 string[] beamLayers = { "梁", "BEAM", "B-", "STRUCTURE" }; // 扫描梁实体和标注文本 List<BeamInfo> beamInfos = new List<BeamInfo>(); List<DBText> dimensionTexts = new List<DBText>(); using (Transaction tr = db.TransactionManager.StartTransaction()) { try { BlockTableRecord btr = (BlockTableRecord)tr.GetObject( db.CurrentSpaceId, OpenMode.ForRead); foreach (ObjectId id in btr) { Entity ent = tr.GetObject(id, OpenMode.ForRead) as Entity; if (ent == null) continue; string layer = ent.Layer?.ToUpper() ?? ""; // 识别梁实体 if (beamLayers.Any(l => layer.Contains(l)) && IsBeamEntity(ent)) { Extents3d extents = ent.GeometricExtents; Vector3d dir = GetBeamDirection(ent); bool isHorizontal = Math.Abs(dir.X) > Math.Abs(dir.Y); beamInfos.Add(new BeamInfo { Id = id, Extents = extents, Direction = dir, Center = new Point3d( (extents.MinPoint.X + extents.MaxPoint.X) / 2, (extents.MinPoint.Y + extents.MaxPoint.Y) / 2, 0), IsHorizontal = isHorizontal }); } // 只收集纯尺寸标注文本 if (ent is DBText text && IsPureBeamDimension(text.TextString)) { dimensionTexts.Add(text); } } tr.Commit(); ed.WriteMessage($"\n找到 {beamInfos.Count} 个梁实体和 {dimensionTexts.Count} 个尺寸标注"); ed.WriteMessage($"\n使用距离阈值: {distanceThreshold} mm"); ed.WriteMessage($"\n使用固定重叠检测阈值: {OverlapThreshold} mm"); } catch (System.Exception ex) { ed.WriteMessage($"\n扫描错误: {ex.Message}"); tr.Abort(); return; } } // 开始修复引线 int leaderCount = 0; int skippedDistanceCount = 0; int skippedOverlapCount = 0; List<Line> createdLeaders = new List<Line>(); // 存储已创建的引线 using (Transaction tr = db.TransactionManager.StartTransaction()) { try { BlockTableRecord btr = (BlockTableRecord)tr.GetObject( db.CurrentSpaceId, OpenMode.ForWrite); foreach (DBText text in dimensionTexts) { Point3d textPos = text.Position; // 查找最近的梁 BeamInfo targetBeam = FindTargetBeam(textPos, beamInfos); if (targetBeam == null) continue; // 获取梁上的锚点 Point3d beamPoint = GetBeamAnchorPoint(textPos, targetBeam); // 计算距离 double distance = textPos.DistanceTo(beamPoint); // 检查距离是否小于等于阈值 if (distance <= distanceThreshold) { skippedDistanceCount++; continue; } // 创建引线对象 Line leader = new Line(textPos, beamPoint); // 检查重叠 if (CheckLeaderOverlap(leader, createdLeaders)) { skippedOverlapCount++; continue; // 存在重叠,跳过创建 } // 配置并添加引线 ConfigureLeader(leader); btr.AppendEntity(leader); tr.AddNewlyCreatedDBObject(leader, true); createdLeaders.Add(leader); // 添加到已创建列表 leaderCount++; } tr.Commit(); ed.WriteMessage($"\n成功创建 {leaderCount} 条梁尺寸标注引线"); ed.WriteMessage($"\n跳过 {skippedDistanceCount} 条距离≤{distanceThreshold}mm的标注"); ed.WriteMessage($"\n跳过 {skippedOverlapCount} 条存在重叠的标注"); } catch (System.Exception ex) { ed.WriteMessage($"\n引线创建错误: {ex.Message}"); tr.Abort(); } } } // ================== 辅助方法实现 ================== // 识别轴号文本 private bool IsAxisNumber(string text) { if (string.IsNullOrWhiteSpace(text)) return false; return Regex.IsMatch(text, @"^[A-Za-z]?[\d]+[A-Za-z]?$") || Regex.IsMatch(text, @"^[A-Za-z]-?\d+$") || Regex.IsMatch(text, @"^\d+[A-Za-z]?$"); } // 识别梁尺寸标注 private bool IsBeamDimension(string text) { if (string.IsNullOrWhiteSpace(text)) return false; return Regex.IsMatch(text, @"\d{2,4}[×xX]\d{2,4}"); } // 识别梁编号标注 private bool IsBeamLabel(string text) { if (string.IsNullOrWhiteSpace(text)) return false; return text.Contains("L") || text.Contains("B") || text.Contains("KL") || text.Contains("XL"); } // 识别纯梁尺寸标注 private bool IsPureBeamDimension(string text) { if (string.IsNullOrWhiteSpace(text)) return false; return Regex.IsMatch(text, @"^\d{2,4}[×xX]\d{2,4}$"); } // 识别梁实体 private bool IsBeamEntity(Entity ent) { if (ent == null) return false; return ent is Line || ent is Polyline; } // 获取梁方向向量 private Vector3d GetBeamDirection(Entity beam) { if (beam is Line line) return line.EndPoint - line.StartPoint; if (beam is Polyline pline && pline.NumberOfVertices >= 2) return pline.GetPoint3dAt(1) - pline.GetPoint3dAt(0); return new Vector3d(1, 0, 0); } // 查找目标梁方法 private BeamInfo FindTargetBeam(Point3d textPos, List<BeamInfo> beams) { if (beams == null || beams.Count == 0) return null; BeamInfo bestBeam = null; double minDistance = double.MaxValue; foreach (BeamInfo beam in beams) { // 水平梁:只考虑上方梁 if (beam.IsHorizontal) { if (beam.Extents.MinPoint.Y > textPos.Y) { double distY = beam.Extents.MinPoint.Y - textPos.Y; double distX = Math.Abs(textPos.X - beam.Center.X); double distance = distY + distX * 0.1; if (distance < minDistance) { minDistance = distance; bestBeam = beam; } } } // 垂直梁:只考虑左侧梁 else { if (beam.Extents.MaxPoint.X < textPos.X) { double distX = textPos.X - beam.Extents.MaxPoint.X; double distY = Math.Abs(textPos.Y - beam.Center.Y); double distance = distX + distY * 0.1; if (distance < minDistance) { minDistance = distance; bestBeam = beam; } } } } return bestBeam; } // ================== 命令行输入距离阈值 ================== private double GetDistanceThresholdFromEditor() { Document doc = Application.DocumentManager.MdiActiveDocument; if (doc == null) return 2000; // 默认值 Editor ed = doc.Editor; // 创建输入提示 PromptDoubleOptions pdo = new PromptDoubleOptions( "\n请输入原位标注的梁位置距梁边线最小距离,默认值为 <2000mm>: 根据需要输入"); // 设置提示选项 pdo.AllowNegative = false; // 不允许负数 pdo.AllowZero = false; // 不允许零值 pdo.DefaultValue = 2000; // 默认值 pdo.UseDefaultValue = true; // 允许使用默认值 // 获取用户输入 PromptDoubleResult pdr = ed.GetDouble(pdo); // 处理结果 if (pdr.Status == PromptStatus.OK) { return pdr.Value; } return -1; // 表示取消 } // 获取梁上的锚点(引线连接点) private Point3d GetBeamAnchorPoint(Point3d textPos, BeamInfo beam) { if (beam.IsHorizontal) { return new Point3d(textPos.X, beam.Extents.MinPoint.Y, 0); } else { return new Point3d(beam.Extents.MaxPoint.X, textPos.Y, 0); } } // 检查引线是否与现有引线重叠 private bool CheckLeaderOverlap(Line newLeader, List<Line> existingLeaders) { // 创建新引线的边界框(带缓冲) Extents3d newExtents = GetExtendedExtents(newLeader, OverlapThreshold); foreach (Line existingLeader in existingLeaders) { // 快速边界框检查 if (!ExtentsOverlap(newExtents, existingLeader.GeometricExtents)) continue; // 精确距离检查 double distance = GetLineDistance(newLeader, existingLeader); if (distance <= OverlapThreshold) { return true; // 存在重叠 } } return false; // 没有重叠 } // 检查两个边界框是否重叠 private bool ExtentsOverlap(Extents3d ext1, Extents3d ext2) { return ext1.MinPoint.X <= ext2.MaxPoint.X && ext1.MaxPoint.X >= ext2.MinPoint.X && ext1.MinPoint.Y <= ext2.MaxPoint.Y && ext1.MaxPoint.Y >= ext2.MinPoint.Y; } // 计算两条线之间的最小距离 private double GetLineDistance(Line line1, Line line2) { // 计算线1上点到线2的最短距离 double minDistance = double.MaxValue; // 检查线1的两个端点到线2的距离 minDistance = Math.Min(minDistance, GetPointToLineDistance(line1.StartPoint, line2)); minDistance = Math.Min(minDistance, GetPointToLineDistance(line1.EndPoint, line2)); // 检查线2的两个端点到线1的距离 minDistance = Math.Min(minDistance, GetPointToLineDistance(line2.StartPoint, line1)); minDistance = Math.Min(minDistance, GetPointToLineDistance(line2.EndPoint, line1)); return minDistance; } // 计算点到线的最短距离 private double GetPointToLineDistance(Point3d point, Line line) { // 获取线的起点和终点 Point3d start = line.StartPoint; Point3d end = line.EndPoint; // 计算向量 Vector3d lineVec = end - start; Vector3d pointVec = point - start; // 计算投影长度 double lineLength = lineVec.Length; double dotProduct = pointVec.DotProduct(lineVec); double projection = dotProduct / (lineLength * lineLength); // 限制投影在0-1之间 projection = Math.Max(0, Math.Min(1, projection)); // 计算最近点 Point3d closestPoint = start + lineVec * projection; // 返回距离 return point.DistanceTo(closestPoint); } // 获取扩展后的边界框(用于快速碰撞检测) private Extents3d GetExtendedExtents(Line line, double buffer) { Point3d min = new Point3d( Math.Min(line.StartPoint.X, line.EndPoint.X) - buffer, Math.Min(line.StartPoint.Y, line.EndPoint.Y) - buffer, 0); Point3d max = new Point3d( Math.Max(line.StartPoint.X, line.EndPoint.X) + buffer, Math.Max(line.StartPoint.Y, line.EndPoint.Y) + buffer, 0); return new Extents3d(min, max); } // 配置引线属性 private void ConfigureLeader(Entity leader) { leader.Layer = "标注"; leader.ColorIndex = 2; // 黄色 leader.Linetype = "Continuous"; leader.LineWeight = LineWeight.LineWeight013; } } 在“CLN”前面添加一个新功能框选所有图过滤填充、轴号、大样图、以及带有”ScaffoldPole“、“杆”图块不分解其余图块暴力分解,新功能命令改为缩写命令 将新增一起三个功能重新编写完整代码
最新发布
07-08
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值