// We are going to try a few passes to add a curve to the CurveLoop, based on the fact that we can't always trust that the // orientation of the given curve loop is correct. So we will: // 1. Try to add the curve, according to the orientation we believe is correct. // 2. Try to add the curve, reversing the orientation. // 3. Reverse the curve loop, and try steps 1-2 again. private void AddCurveToLoop(CurveLoop curveLoop, Curve curve, bool initialReverse, bool allowFlip) { try { AddCurveToLoopInternal(curveLoop, curve, initialReverse, false); } catch (Exception ex) { if (ex.Message.Contains("not contiguous")) { // One last attempt to solve the problem - flip the curve loop, try again. if (allowFlip) { curveLoop.Flip(); AddCurveToLoop(curveLoop, curve, initialReverse, false); } else { throw ex; } } else { throw ex; } } }
/// <summary> /// Reverses curve loop. /// </summary> /// <param name="curveloop"> /// The curveloop. /// </param> /// <returns> /// The reversed curve loop. /// </returns> public static CurveLoop ReverseOrientation(CurveLoop curveloop) { CurveLoop copyOfCurveLoop = CurveLoop.CreateViaCopy(curveloop); copyOfCurveLoop.Flip(); return(copyOfCurveLoop); }
/***************************************************/ private static void AddLoop(this BRepBuilder brep, BRepBuilderGeometryId face, XYZ normal, ICurve curve, bool external) { CurveLoop cl = new CurveLoop(); foreach (ICurve sp in curve.ISubParts()) { foreach (Curve cc in sp.IToRevitCurves()) { cl.Append(cc); } } if (external != cl.IsCounterclockwise(normal)) { cl.Flip(); } BRepBuilderGeometryId loop = brep.AddLoop(face); foreach (Curve cc in cl) { BRepBuilderGeometryId edge = brep.AddEdge(BRepBuilderEdgeGeometry.Create(cc)); brep.AddCoEdge(loop, edge, false); } brep.FinishLoop(loop); }
private CurveArray ConvertLoopToArray(CurveLoop loop) { CurveArray a = new CurveArray(); if (loop.IsCounterclockwise(XYZ.BasisZ)) { loop.Flip(); } foreach (Curve c in loop) { a.Append(c); } return(a); }
// We are going to try a few passes to add a curve to the CurveLoop, based on the fact that we can't always trust that the // orientation of the given curve loop is correct. So we will: // 1. Try to add the curve, according to the orientation we believe is correct. // 2. Try to add the curve, reversing the orientation. // 3. Reverse the curve loop, and try steps 1-2 again. private void AddCurveToLoop(CurveLoop curveLoop, Curve curve, bool initialReverse, bool allowFlip) { try { AddCurveToLoopInternal(curveLoop, curve, initialReverse, false); } catch (Exception ex) { if (ex.Message.Contains("not contiguous")) { // One last attempt to solve the problem - flip the curve loop, try again. if (allowFlip) { curveLoop.Flip(); AddCurveToLoop(curveLoop, curve, initialReverse, false); } else throw ex; } else throw ex; } }
/// <summary> /// Attempts to create a clipping, recess, or opening from a collection of faces. /// </summary> /// <param name="exporterIFC">The exporter.</param> /// <param name="cuttingElement">The cutting element. This will help determine whether to use a clipping or opening in boundary cases.</param> /// <param name="extrusionBasePlane">The plane of the extrusion base.</param> /// <param name="extrusionDirection">The extrusion direction.</param> /// <param name="faces">The collection of faces.</param> /// <param name="range">The valid range of the extrusion.</param> /// <param name="origBodyRepHnd">The original body representation.</param> /// <returns>The new body representation. If the clipping completely clips the extrusion, this will be null. Otherwise, this /// will be the clipped representation if a clipping was done, or the original representation if not.</returns> public static IFCAnyHandle ProcessFaceCollection(ExporterIFC exporterIFC, Element cuttingElement, Plane extrusionBasePlane, XYZ extrusionDirection, ICollection <Face> faces, IFCRange range, IFCAnyHandle origBodyRepHnd) { if (IFCAnyHandleUtil.IsNullOrHasNoValue(origBodyRepHnd)) { return(null); } bool polygonalOnly = ExporterCacheManager.ExportOptionsCache.ExportAs2x2; IList <CurveLoop> outerCurveLoops = new List <CurveLoop>(); IList <Plane> outerCurveLoopPlanes = new List <Plane>(); IList <bool> boundaryIsPolygonal = new List <bool>(); bool allPlanes = true; UV faceOriginUV = new UV(0, 0); foreach (Face face in faces) { FaceBoundaryType faceBoundaryType; CurveLoop curveLoop = GetOuterFaceBoundary(face, null, polygonalOnly, out faceBoundaryType); outerCurveLoops.Add(curveLoop); boundaryIsPolygonal.Add(faceBoundaryType == FaceBoundaryType.Polygonal); if (face is PlanarFace) { PlanarFace planarFace = face as PlanarFace; XYZ faceOrigin = planarFace.Origin; XYZ faceNormal = planarFace.ComputeNormal(faceOriginUV); Plane plane = new Plane(faceNormal, faceOrigin); outerCurveLoopPlanes.Add(plane); if (!curveLoop.IsCounterclockwise(faceNormal)) { curveLoop.Flip(); } } else { outerCurveLoopPlanes.Add(null); allPlanes = false; } } if (allPlanes) { int numFaces = faces.Count; // Special case: one face is a clip plane. if (numFaces == 1) { return(ProcessClippingFace(exporterIFC, outerCurveLoops[0], outerCurveLoopPlanes[0], extrusionBasePlane, extrusionDirection, range, false, origBodyRepHnd)); } KeyValuePair <bool, bool> clipsExtrusionEnds = CollectionClipsExtrusionEnds(outerCurveLoops, extrusionDirection, range); if (clipsExtrusionEnds.Key == true || clipsExtrusionEnds.Value == true) { // Don't clip for a door, window or opening. if (CreateOpeningForCategory(cuttingElement)) { throw new Exception("Unhandled opening."); } ICollection <int> facesToSkip = new HashSet <int>(); bool clipStart = (clipsExtrusionEnds.Key == true); bool clipBoth = (clipsExtrusionEnds.Key == true && clipsExtrusionEnds.Value == true); if (!clipBoth) { for (int ii = 0; ii < numFaces; ii++) { double slant = outerCurveLoopPlanes[ii].Normal.DotProduct(extrusionDirection); if (!MathUtil.IsAlmostZero(slant)) { if (clipStart && (slant > 0.0)) { throw new Exception("Unhandled clip plane direction."); } if (!clipStart && (slant < 0.0)) { throw new Exception("Unhandled clip plane direction."); } } else { facesToSkip.Add(ii); } } } else { // If we are clipping both the start and end of the extrusion, we have to make sure all of the clipping // planes have the same a non-negative dot product relative to one another. int clipOrientation = 0; for (int ii = 0; ii < numFaces; ii++) { double slant = outerCurveLoopPlanes[ii].Normal.DotProduct(extrusionDirection); if (!MathUtil.IsAlmostZero(slant)) { if (slant > 0.0) { if (clipOrientation < 0) { throw new Exception("Unhandled clipping orientations."); } clipOrientation = 1; } else { if (clipOrientation > 0) { throw new Exception("Unhandled clipping orientations."); } clipOrientation = -1; } } else { facesToSkip.Add(ii); } } } IFCAnyHandle newBodyRepHnd = origBodyRepHnd; for (int ii = 0; ii < numFaces; ii++) { if (facesToSkip.Contains(ii)) { continue; } newBodyRepHnd = ProcessClippingFace(exporterIFC, outerCurveLoops[ii], outerCurveLoopPlanes[ii], extrusionBasePlane, extrusionDirection, range, true, newBodyRepHnd); if (newBodyRepHnd == null) { return(null); } } return(newBodyRepHnd); } } bool unhandledCases = true; if (unhandledCases) { throw new Exception("Unhandled opening or clipping."); } // We will attempt to "sew" the faces, and see what we have left over. Depending on what we have, we have an opening, recess, or clipping. IList <Edge> boundaryEdges = new List <Edge>(); foreach (Face face in faces) { EdgeArrayArray faceBoundaries = face.EdgeLoops; // We only know how to deal with the outer loop; we'll throw if we have multiple boundaries. if (faceBoundaries.Size != 1) { throw new Exception("Can't process faces with inner boundaries."); } EdgeArray faceBoundary = faceBoundaries.get_Item(0); foreach (Edge edge in faceBoundary) { if (edge.get_Face(0) == null || edge.get_Face(1) == null) { boundaryEdges.Add(edge); } } } return(origBodyRepHnd); }