/// <summary> /// 构造直线,为两平面的交线 /// </summary> public Line(Face face1, Face face2) { Vector3Double normalFace1 = face1.PlaneNormal; Vector3Double normalFace2 = face2.PlaneNormal; Direction = Vector3Double.Cross(normalFace1, normalFace2); if (!(Direction.magnitude < EqualityTolerance)) // 两平面不平行 { //getting a line point, zero is set to a coordinate whose direction // 获取线上一点,方向坐标设为零点 //component isn't zero (line intersecting its origin plan) // 成员不为零(线与第一个平面相交) var d1 = -Vector3Double.Dot(normalFace1, face1.v1.Position); var d2 = -Vector3Double.Dot(normalFace2, face2.v1.Position); if (Math.Abs(Direction.x) > EqualityTolerance) { startPoint = new Vector3Double { x = 0, y = (d2 * normalFace1.z - d1 * normalFace2.z) / Direction.x, z = (d1 * normalFace2.y - d2 * normalFace1.y) / Direction.x }; } else if (Math.Abs(Direction.y) > EqualityTolerance) { startPoint = new Vector3Double { x = (d1 * normalFace2.z - d2 * normalFace1.z) / Direction.y, y = 0, z = (d2 * normalFace1.x - d1 * normalFace2.x) / Direction.y }; } else { startPoint = new Vector3Double { x = (d2 * normalFace1.y - d1 * normalFace2.y) / Direction.z, y = (d1 * normalFace2.x - d2 * normalFace1.x) / Direction.z, z = 0 }; } } else { startPoint = default; } Direction.Normalize(); }
/// <summary> /// Compute the point resulting from the intersection with a plane /// </summary> /// <param name="normal">the plane normal</param> /// <param name="planePoint">a plane point.</param> /// <returns>intersection point.If they don't intersect, return null</returns> public Vector3Double ComputePlaneIntersection(Plane plane) { var distanceToStartFromOrigin = Vector3Double.Dot(plane.planeNormal, startPoint); var distanceFromPlane = distanceToStartFromOrigin - plane.distanceToPlaneFromOrigin; var denominator = Vector3Double.Dot(plane.planeNormal, Direction); if (Math.Abs(denominator) < EqualityTolerance) // 射线与平面垂直 { return(Math.Abs(distanceFromPlane) < EqualityTolerance ? startPoint : Vector3Double.PositiveInfinity); } else // 射线被平面拦截 { return(StartPoint + (Direction * -distanceFromPlane / denominator)); } }
/// <summary> /// 为表面分类,基于光线追踪技术 /// </summary> /// <param name="obj">计算面状态的 3D 物件</param> public void RayTraceClassify(Object3D obj) { Line ray = new Line(PlaneNormal, Center); // 射线从面的几何中心发出,方向为法线方向 Face closet = default; bool foundCloset = false; double closestDistance; bool success; do { success = true; closestDistance = double.MaxValue; for (int faceIndex = 0; faceIndex < obj.GetNumFaces(); faceIndex++) { Face face = obj.GetFace(faceIndex); var intersectionPoint = ray.ComputePlaneIntersection(face.Plane); // 对三角面所在的平面采样 if (intersectionPoint.x < float.PositiveInfinity) // 射线被平面拦截 { var distance = ray.ComputePointToPointDistance(intersectionPoint); var dot = Vector3Double.Dot(face.PlaneNormal, ray.Direction); bool parallel = Math.Abs(dot) < epsilon; // 射线与平面平行 //if ray lies in plane... if (Math.Abs(distance) < epsilon) // 交点是射线起点 { if (parallel) { // 略微抖动光线方向以免采样到另一平面 ray.PerturbDirection(); success = false; break; } else if (face.ContainsPoint(intersectionPoint)) { // 面重合 closet = face; foundCloset = true; closestDistance = 0; break; } } else if (!parallel && distance > epsilon) // 射线产生交点 { if (distance < closestDistance && face.ContainsPoint(intersectionPoint)) { closestDistance = distance; closet = face; // 当前的面时最近的平面 foundCloset = true; } } } } } while (!success); if (!foundCloset) { Status = Status.OUTSIDE; } // 没有找到面,自己是外部面 else // 由离自己最近的面,检查方向 { var dot = Vector3Double.Dot(closet.PlaneNormal, ray.Direction); if (Math.Abs(closestDistance) < epsilon) // 距离为零,这个面和自己重合 { if (dot > epsilon) { Status = Status.SAME; } else if (dot < -epsilon) { Status = Status.OPPOSITE; } } else if (dot > epsilon) { Status = Status.INSIDE; } // 不重合,同向,在参数物件内部 else if (dot < -epsilon) { Status = Status.OUTSIDE; } // 不重合,反向,在参数物件外部 } }
/// <summary> /// 计算从线到另一点的距离 /// </summary> /// <param name="otherPoint">the point to compute the distance from the line point. The point is supposed to be on the same line.</param> /// <returns>如果射线起点到另一点的向量与射线方向相反,会得到负数的值</returns> public double ComputePointToPointDistance(Vector3Double otherPoint) { var distance = (otherPoint - startPoint).magnitude; return((Vector3Double.Dot((otherPoint - startPoint).normalized, Direction) < 0) ? -distance : distance); }