Line Segment Intersections

本文档详细介绍了直线和平面相交的数学原理与计算方法,适用于计算机图形学及几何算法的学习者。通过实例解析了如何确定一条直线是否与一个平面相交以及如何找到交点。

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

From: https://people.scs.carleton.ca/~michiel/lecturenotes/ALGGEOM/horverintersect.pdf

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; namespace OptimizedMergePlugin { public class Commands { [CommandMethod("MG", CommandFlags.Modal)] public void MergeLines() { Document doc = Application.DocumentManager.MdiActiveDocument; Database db = doc.Database; Editor ed = doc.Editor; try { // 获取选择集 PromptSelectionResult selResult = ed.GetSelection(); if (selResult.Status != PromptStatus.OK) return; using (Transaction tr = db.TransactionManager.StartTransaction()) { // 按图层分组并收集所有线段 var layerGroups = new Dictionary<string, List<LineSegment>>(); CollectLineSegments(selResult, tr, layerGroups, ed); // 处理每个图层 BlockTableRecord btr = (BlockTableRecord)tr.GetObject( db.CurrentSpaceId, OpenMode.ForWrite); int totalLayers = layerGroups.Count; int currentLayer = 0; foreach (var kvp in layerGroups) { currentLayer++; ed.WriteMessage($"\n处理图层: {kvp.Key} ({currentLayer}/{totalLayers})"); // 使用空间索引加速处理 var spatialIndex = BuildSpatialIndex(kvp.Value); // 打断重叠线段 List<LineSegment> brokenSegments = BreakSegmentsWithIndex(kvp.Value, spatialIndex, ed); // 合并共线线段 List<Line> mergedLines = MergeSegments(brokenSegments); // 添加新实体 foreach (Line newLine in mergedLines) { newLine.Layer = kvp.Key; btr.AppendEntity(newLine); tr.AddNewlyCreatedDBObject(newLine, true); } } tr.Commit(); } ed.WriteMessage("\n线段合并完成!"); } catch (System.Exception ex) { ed.WriteMessage($"\n错误: {ex.Message}"); } } // 公开的线段表示类 public class LineSegment { public Point3d Start { get; set; } public Point3d End { get; set; } public ObjectId OriginalId { get; set; } = ObjectId.Null; public LineSegment(Point3d start, Point3d end) { Start = start; End = end; } public Extents3d Extents => new Extents3d(Start, End); } // 收集所有线段 private void CollectLineSegments(PromptSelectionResult selResult, Transaction tr, Dictionary<string, List<LineSegment>> layerGroups, Editor ed) { int totalObjects = selResult.Value.Count; int processed = 0; foreach (SelectedObject selObj in selResult.Value) { processed++; // 每处理100个对象显示一次进度 if (processed % 100 == 0) ed.WriteMessage($"\n已处理: {processed}/{totalObjects}"); Entity ent = tr.GetObject(selObj.ObjectId, OpenMode.ForRead) as Entity; if (ent == null) continue; string layer = ent.Layer; if (!layerGroups.ContainsKey(layer)) layerGroups.Add(layer, new List<LineSegment>()); // 处理直线 if (ent is Line line) { layerGroups[layer].Add(new LineSegment(line.StartPoint, line.EndPoint) { OriginalId = line.ObjectId }); } // 处理多段线 else if (ent is Polyline pline) { for (int i = 0; i < pline.NumberOfVertices - 1; i++) { layerGroups[layer].Add(new LineSegment( pline.GetPoint3dAt(i), pline.GetPoint3dAt(i + 1) )); } } } } // 构建空间索引 private SpatialIndex BuildSpatialIndex(List<LineSegment> segments) { SpatialIndex index = new SpatialIndex(); foreach (LineSegment seg in segments) { index.Add(seg.Extents, seg); } return index; } // 使用空间索引打断线段 private List<LineSegment> BreakSegmentsWithIndex(List<LineSegment> segments, SpatialIndex index, Editor ed) { List<LineSegment> result = new List<LineSegment>(); HashSet<LineSegment> processed = new HashSet<LineSegment>(); int totalSegments = segments.Count; int processedCount = 0; foreach (LineSegment seg in segments) { processedCount++; // 每处理100个线段显示一次进度 if (processedCount % 100 == 0) ed.WriteMessage($"\n打断线段: {processedCount}/{totalSegments}"); if (processed.Contains(seg)) continue; List<LineSegment> currentSegments = new List<LineSegment> { seg }; bool modified; do { modified = false; List<LineSegment> nextSegments = new List<LineSegment>(); foreach (LineSegment current in currentSegments) { // 使用空间索引查找可能相交的线段 var candidates = index.Search(current.Extents) .Where(s => !processed.Contains(s) && s != current) .ToList(); bool broken = false; foreach (var candidate in candidates) { if (TryBreakSegment(current, candidate, out List<LineSegment> newSegments)) { // 将打断后的线段加入待处理列表 nextSegments.AddRange(newSegments); processed.Add(candidate); broken = true; break; } } if (!broken) { nextSegments.Add(current); } else { modified = true; } } currentSegments = nextSegments; } while (modified); result.AddRange(currentSegments); processed.Add(seg); } return result; } // 尝试打断两条线段 private bool TryBreakSegment(LineSegment seg1, LineSegment seg2, out List<LineSegment> result) { result = new List<LineSegment>(); Line line1 = new Line(seg1.Start, seg1.End); Line line2 = new Line(seg2.Start, seg2.End); Point3dCollection intersections = new Point3dCollection(); // 修复:使用 IntPtr.Zero 代替容差指针参数 line1.IntersectWith(line2, Intersect.OnBothOperands, intersections, IntPtr.Zero, IntPtr.Zero); // 关键修改在这里 if (intersections.Count == 0) return false; // 处理交点 List<Point3d> splitPoints = new List<Point3d>(); foreach (Point3d pt in intersections) { splitPoints.Add(pt); } // 按距离起点排序 splitPoints.Sort((a, b) => seg1.Start.DistanceTo(a).CompareTo(seg1.Start.DistanceTo(b))); // 分割第一条线段 Point3d lastPoint = seg1.Start; foreach (Point3d splitPoint in splitPoints) { result.Add(new LineSegment(lastPoint, splitPoint)); lastPoint = splitPoint; } result.Add(new LineSegment(lastPoint, seg1.End)); return true; } // 合并线段 private List<Line> MergeSegments(List<LineSegment> segments) { // 按起点排序 List<LineSegment> sortedSegments = segments .OrderBy(s => s.Start.X) .ThenBy(s => s.Start.Y) .ThenBy(s => s.Start.Z) .ToList(); List<Line> result = new List<Line>(); LineSegment current = null; foreach (LineSegment seg in sortedSegments) { if (current == null) { current = seg; continue; } // 检查是否共线且连接 if (AreSegmentsConnectable(current, seg)) { // 扩展当前线段 current = new LineSegment( PointMin(current.Start, seg.Start), PointMax(current.End, seg.End) ); } else { // 添加完成合并的线段 result.Add(new Line(current.Start, current.End)); current = seg; } } if (current != null) { result.Add(new Line(current.Start, current.End)); } return result; } // 检查线段是否可连接 private bool AreSegmentsConnectable(LineSegment seg1, LineSegment seg2) { Vector3d dir1 = seg1.End - seg1.Start; Vector3d dir2 = seg2.End - seg2.Start; // 使用全局容差检查方向是否平行 bool isColinear = dir1.IsParallelTo(dir2, Tolerance.Global); // 使用全局容差检查端点连接 bool isConnected = seg1.End.IsEqualTo(seg2.Start, Tolerance.Global) || seg1.Start.IsEqualTo(seg2.End, Tolerance.Global) || seg1.End.IsEqualTo(seg2.End, Tolerance.Global) || seg1.Start.IsEqualTo(seg2.Start, Tolerance.Global); return isColinear && isConnected; } // 辅助方法:获取最小点 private Point3d PointMin(Point3d a, Point3d b) { return new Point3d( Math.Min(a.X, b.X), Math.Min(a.Y, b.Y), Math.Min(a.Z, b.Z)); } // 辅助方法:获取最大点 private Point3d PointMax(Point3d a, Point3d b) { return new Point3d( Math.Max(a.X, b.X), Math.Max(a.Y, b.Y), Math.Max(a.Z, b.Z)); } } // 空间索引实现(公开类) public class SpatialIndex { private List<Tuple<Extents3d, Commands.LineSegment>> _items = new List<Tuple<Extents3d, Commands.LineSegment>>(); public void Add(Extents3d extents, Commands.LineSegment segment) { _items.Add(new Tuple<Extents3d, Commands.LineSegment>(extents, segment)); } public IEnumerable<Commands.LineSegment> Search(Extents3d searchExtents) { // 简单实现:检查边界框重叠 return _items .Where(item => item.Item1.MinPoint.X <= searchExtents.MaxPoint.X && item.Item1.MaxPoint.X >= searchExtents.MinPoint.X && item.Item1.MinPoint.Y <= searchExtents.MaxPoint.Y && item.Item1.MaxPoint.Y >= searchExtents.MinPoint.Y) .Select(item => item.Item2); } } } 还是删除不掉重叠线
最新发布
07-09
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值