internal static bool Intersects(Ray ray, solids.Face face, out Vector3 result) { var edges = face.Outer.Edges; var a = edges[0].Vertex.Point; var b = edges[1].Vertex.Point; var c = edges[2].Vertex.Point; var plane = new Plane(a, b, c); if (ray.Intersects(plane, out Vector3 intersection)) { var boundaryPolygon = face.Outer.ToPolygon(); var transformToPolygon = new Transform(plane.Origin, plane.Normal); var transformFromPolygon = new Transform(transformToPolygon); transformFromPolygon.Invert(); var transformedPolygon = transformFromPolygon.OfPolygon(boundaryPolygon); var transformedIntersection = transformFromPolygon.OfVector(intersection); if (transformedPolygon.Contains(transformedIntersection) || transformedPolygon.Touches(transformedIntersection)) { result = intersection; return(true); } } result = default(Vector3); return(false); }
/// <summary> /// Construct a solid by sweeping a face in a direction. /// </summary> /// <param name="perimeter">The perimeter of the face to sweep.</param> /// <param name="holes">The holes of the face to sweep.</param> /// <param name="direction">The direction in which to sweep.</param> /// <param name="distance">The distance to sweep.</param> /// <param name="bothSides">Should the sweep start offset by direction distance/2? </param> /// <param name="rotation">An optional rotation in degrees of the perimeter around the direction vector.</param> /// <returns>A solid.</returns> public static Solid SweepFace(Polygon perimeter, IList <Polygon> holes, Vector3 direction, double distance, bool bothSides = false, double rotation = 0.0) { // We do a difference of the polygons // to get the clipped shape. This will fail in interesting // ways if the clip creates two islands. // if(holes != null) // { // var newPerimeter = perimeter.Difference(holes); // perimeter = newPerimeter[0]; // holes = newPerimeter.Skip(1).Take(newPerimeter.Count - 1).ToArray(); // } var solid = new Solid(); Face fStart = null; if (bothSides) { var t = new Transform(direction.Negate() * (distance / 2), rotation); if (holes != null) { fStart = solid.AddFace(perimeter, holes, transform: t, reverse: true); } else { fStart = solid.AddFace(perimeter, transform: t, reverse: true); } } else { if (holes != null) { fStart = solid.AddFace(perimeter, holes, reverse: true); } else { fStart = solid.AddFace(perimeter, reverse: true); } } var fEndOuter = solid.SweepLoop(fStart.Outer, direction, distance); if (holes != null) { var fEndInner = new Loop[holes.Count]; for (var i = 0; i < holes.Count; i++) { fEndInner[i] = solid.SweepLoop(fStart.Inner[i], direction, distance); } solid.AddFace(fEndOuter, fEndInner); } else { solid.AddFace(fEndOuter); } return(solid); }
/// <summary> /// Construct a solid by sweeping a face along a curve. /// </summary> /// <param name="perimeter">The perimeter of the face to sweep.</param> /// <param name="holes">The holes of the face to sweep.</param> /// <param name="curve">The curve along which to sweep.</param> /// <param name="startSetback">The setback distance of the sweep from the start of the curve.</param> /// <param name="endSetback">The setback distance of the sweep from the end of the curve.</param> /// <returns>A solid.</returns> public static Solid SweepFaceAlongCurve(Polygon perimeter, IList <Polygon> holes, ICurve curve, double startSetback = 0, double endSetback = 0) { var solid = new Solid(); var l = curve.Length(); // The start and end setbacks can't be more than // the length of the beam together. if ((startSetback + endSetback) >= l) { startSetback = 0; endSetback = 0; } // Calculate the setback parameter as a percentage // of the curve length. This will not work for curves // without non-uniform parameterization. var ssb = startSetback / l; var esb = endSetback / l; var transforms = curve.Frames(ssb, esb); if (curve is Polygon) { for (var i = 0; i < transforms.Length; i++) { var next = i == transforms.Length - 1 ? transforms[0] : transforms[i + 1]; solid.SweepPolygonBetweenPlanes(perimeter, transforms[i], next); } } else if (curve is Bezier) { var startCap = solid.AddFace(perimeter, transform: transforms[0]); for (var i = 0; i < transforms.Length - 1; i++) { var next = transforms[i + 1]; solid.SweepPolygonBetweenPlanes(perimeter, transforms[i], next); } var endCap = solid.AddFace(perimeter, transform: transforms[transforms.Length - 1], reverse: true); } else { // Add start cap. Face cap = null; Edge[][] openEdges; if (holes != null) { cap = solid.AddFace(perimeter, holes, transform: transforms[0]); openEdges = new Edge[1 + holes.Count][]; } else { cap = solid.AddFace(perimeter, transform: transforms[0]); openEdges = new Edge[1][]; } // last outer edge var openEdge = cap.Outer.GetLinkedEdges(); openEdge = solid.SweepEdges(transforms, openEdge); openEdges[0] = openEdge; if (holes != null) { for (var i = 0; i < cap.Inner.Length; i++) { openEdge = cap.Inner[i].GetLinkedEdges(); // last inner edge for one hole openEdge = solid.SweepEdges(transforms, openEdge); openEdges[i + 1] = openEdge; } } solid.Cap(openEdges, true); } return(solid); }