遇到一个口头机遇的答辩准备9(接8-选种子)
之前选种子说完了自动计时器这里开始详细说选种子本身哦。初级的题目其实内容还是挺多的……【找合法的第一个种子】// 打开模型空间 var ms tr.GetObject(db.CurrentSpaceId, OpenMode.ForRead) as BlockTableRecord; // 遍历所有图元按句柄排序保证查找顺序稳定 foreach (ObjectId id in ms.CastObjectId().OrderBy(x x.Handle.ToString())) { …… }这里主要就是从模型空间里面按句柄顺序找图元这样才可以知道是第几个。可以把句柄理解成自增主键……【判断矩形】#region 标准矩形判断 /// summary /// 严格判断一条多段线是否为【标准矩形】 /// 校验规则 /// 1. 必须闭合 4个顶点 /// 2. 相邻边互相垂直点积0 /// 3. 对边长度相等 /// 4. 带浮点精度容错1e-6 /// /summary /// param namepl待判断的多段线/param /// returnstrue标准矩形false不是/returns public static bool IsStandardRectangle(Polyline pl) { // 浮点计算容错值解决CAD精度误差 const double tolerance 1e-6; // 基础校验空、未闭合、顶点数≠4 → 直接不是矩形 if (pl null || !pl.Closed || pl.NumberOfVertices ! 4) return false; // 获取矩形4个角点二维点 Point2d p0 pl.GetPoint2dAt(0); Point2d p1 pl.GetPoint2dAt(1); Point2d p2 pl.GetPoint2dAt(2); Point2d p3 pl.GetPoint2dAt(3); // 计算四条边的向量 Vector2d v0 p1 - p0; Vector2d v1 p2 - p1; Vector2d v2 p3 - p2; Vector2d v3 p0 - p3; // 校验1相邻边互相垂直点积绝对值≈0 if (Math.Abs(v0.DotProduct(v1)) tolerance) return false; if (Math.Abs(v1.DotProduct(v2)) tolerance) return false; if (Math.Abs(v2.DotProduct(v3)) tolerance) return false; if (Math.Abs(v3.DotProduct(v0)) tolerance) return false; // 校验2对边长度相等 if (Math.Abs(v0.Length - v2.Length) tolerance) return false; if (Math.Abs(v1.Length - v3.Length) tolerance) return false; // 全部满足 → 标准矩形 return true; } #endregion这里有几个重要的概念向量向量是同时包含[方向]和[大小长度/模]的几何量不关心具体位置向量终点-起点。举个栗子我有点A12点B34。这个时候A到B的向量就是3-14-222长度是√(2^22^2) √8≈2.828这个时候B到A的向量就是1-32-4-2-2长度是√(-2^2-2^2) √8≈2.828注意要是向量|A|他不是绝对值A他是向量A的长度的意思哦点积向量a(x1,y1), 向量b(x2,y2)点积 a ⋅ bx1x2y1y2 a · b |a| × |b| × cosθ举个栗子向量22和-2-2的点积等于2*-22*-2 -8cosθ-8/(√8*√8)-1180°通过点积判断角θ0(方向完全相同正负号完全相同→ 积点最大 → cosθ 1θ90 → 积点0 → cosθ 0→直角θ90°→ 积点0 → cosθ 0→锐角θ90°→ 积点0 → cosθ 0→钝角θ0(方向完全相反正负号完全相反→ 积点最小 → cosθ -1至于为什么用1e-6不是0那就是因为担心除法浮点溢出【判断是否在边界内】/// summary /// 几何计算点-in-多边形、重叠判断、曲线排序、面域转换 /// /summary public static class GeometryHelper { /// summary /// 判断种子是否完全在边界内部修复尖角漏裁 /// 规则 /// 1. 所有种子顶点都在边界内/线上原有逻辑保留 /// 2. 边界与种子无【非顶点】相交新增防止切穿内部 /// 3. 完全满足才是完整内部否则必须裁剪 /// /summary public static bool IsSeedFullyInside(Polyline boundary, Polyline seed) { // --------------- 原有正确逻辑种子顶点全在边界内 --------------- for (int i 0; i seed.NumberOfVertices; i) { if (!IsPointInPolyline(boundary, seed.GetPoint3dAt(i))) return false; } // --------------- 新增核心修复检查非顶点相交解决尖角漏裁--------------- using (Point3dCollection intersectPoints new Point3dCollection()) { // 获取种子和边界的所有交点 seed.IntersectWith(boundary, Intersect.OnBothOperands, intersectPoints, IntPtr.Zero, IntPtr.Zero); foreach (Point3d pt in intersectPoints) { // 判断交点 不是 种子的4个顶点 bool isSeedVertex false; for (int i 0; i seed.NumberOfVertices; i) { if (pt.DistanceTo(seed.GetPoint3dAt(i)) CommandData.Tolerance) { isSeedVertex true; break; } } // 发现【非顶点】交点 边界切穿矩形内部 → 必须裁剪 if (!isSeedVertex) { return false; } } } // 所有顶点在内部 仅顶点相交 → 真正的完整内部 return true; }一共做了2个判断一个判断点是不是在内部一个是判断有没有正好顶点相交的。这里主要讲下射线法原理判断点向右发射一条无限长的线这条线穿过多边形的边穿过奇数次点在内部穿过偶数次点在外部/// summary /// 射线法判断点是否在多边形内 /// /summary private static bool IsPointInPolyline(Polyline pline, Point3d point) { if (pline null) return false; // // 第一步快速判断点是否在多边形的边上 // using (Line ray new Line(point, point)) // 一条长度为0的线就是点自己 using (Point3dCollection intersectPoints new Point3dCollection()) { // 判断点是否在多边形上 pline.IntersectWith(ray, Intersect.OnBothOperands, intersectPoints, IntPtr.Zero, IntPtr.Zero); if (intersectPoints.Count 0) return true; // 在边上 → 直接算在内部 } // // 第二步构造一条【向右的长射线】 // Extents3d extents pline.GeometricExtents; // 多边形的包围盒 double length extents.MinPoint.DistanceTo(extents.MaxPoint) * 3; // 足够长的长度确保穿出多边形 // 射线终点点右边 非常远 的地方 Point3d endPoint new Point3d(point.X length, point.Y, 0); // // 第三步发射射线求交点数量 // using (Line ray new Line(point, endPoint)) // 向右的射线 using (Point3dCollection intersectPoints new Point3dCollection()) { // 射线 和 多边形 相交多少次 pline.IntersectWith(ray, Intersect.OnBothOperands, intersectPoints, IntPtr.Zero, IntPtr.Zero); // // 核心 // 奇数 → 在内部 // 偶数 → 在外部 // return intersectPoints.Count % 2 1; } }至于补充的检查非顶点相交解决尖角漏裁这是个射线的补丁因为实际可能点都在但是部分面不在所以只要穿过了的也要补上