/***************************************************/ 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); }
/// <summary> /// Determines if curve loop is counterclockwise. /// </summary> /// <param name="curveLoop"> /// The curveLoop. /// </param> /// <param name="normal"> /// The normal. /// </param> /// <returns> /// Returns true only if the loop is counterclockwise, false otherwise. /// </returns> public static bool IsIFCLoopCCW(CurveLoop curveLoop, XYZ normal) { if (curveLoop == null) throw new Exception("CurveLoop is null."); // If loop is not suitable for ccw evaluation an exception is thrown return curveLoop.IsCounterclockwise(normal); }
/// <summary> /// 1 过滤器筛选元素 2 通过区域锁定元素 3 使用clipper进行裁剪 /// </summary> public void RegionCalcution(Document doc, CurveArray controlRegionBaseWall) { #region 获取目标region内的元素 ElementCategoryFilter detailGroupFilter = new ElementCategoryFilter(BuiltInCategory.OST_IOSDetailGroups); //ElementCategoryFilter modelGroupFilter = new ElementCategoryFilter(BuiltInCategory.OST_IOSModelGroups); ElementCategoryFilter detailComponentsFilter = new ElementCategoryFilter(BuiltInCategory.OST_DetailComponents); ElementCategoryFilter linesFilter = new ElementCategoryFilter(BuiltInCategory.OST_Lines); ElementCategoryFilter genericModel = new ElementCategoryFilter(BuiltInCategory.OST_GenericModel); LogicalOrFilter logicalOrFilter = new LogicalOrFilter(new List <ElementFilter>() { detailGroupFilter, detailComponentsFilter, linesFilter, genericModel }); List <Element> allTarEles = (new FilteredElementCollector(doc, doc.ActiveView.Id)).WherePasses(logicalOrFilter).WhereElementIsNotElementType().ToElements().ToList(); List <Element> selEles = _Methods.GetTarlElesByRegion(doc, controlRegionBaseWall, allTarEles); #endregion #region 筛选 地库_地库外墙线圈中的目标元素 障碍物 主次道路中线 处理地库_地库外墙线退距 默认800mm #region 基于各属性进行目标元素抓取 CurveArray roadCurves = new CurveArray(); CurveArray mainRoadCurves = RegionConditionGrab(doc, selEles, out roadCurves); #endregion CurveLoop baseWallLoop = new CurveLoop(); bool isLoop = _Methods.IsCurveLoop(controlRegionBaseWall, out baseWallLoop); CurveArrArray baseWallCurveArrArray = new CurveArrArray(); XYZ normal = new XYZ(0, 0, 1); double offsetDistance = 0; bool isCounterclockwise = baseWallLoop.IsCounterclockwise(normal);//curveloop内外偏移的依据 if (isCounterclockwise) { offsetDistance = -CMD.basementWall_offset_distance; } else if (!isCounterclockwise) { offsetDistance = CMD.basementWall_offset_distance; } CurveLoop curveLoop = CurveLoop.CreateViaOffset(baseWallLoop, offsetDistance, normal); CurveArray _controlRegion = _Methods.CurveLoopToCurveArray(curveLoop); baseWallCurveArrArray.Append(_controlRegion); #endregion #region clipper最后图形处理 得到各个可停车区域region Paths basementWallPath = clipper_methods.Paths_xyzToPaths(_Methods.GetUniqueXYZFromCurves(baseWallCurveArrArray)); Paths roadRegion = HandleMainRoadSpace(mainRoadCurves, roadCurves, CMD.Wd_main, CMD.Wd); Paths canPlacedRegion = clipper_methods.RegionCropctDifference(basementWallPath, roadRegion);//得到可停车区域 this.parkingRegionsPoints = clipper_methods.PathsToPaths_xyz(canPlacedRegion); List <List <Line> > listLines = _Methods.GetListClosedtLineFromListPoints(this.parkingRegionsPoints); this.parkingCurveArrArray = _Methods.ListLinesToCurveArrArray(listLines); #endregion }
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); }
/// <returns>true if the curve loop is clockwise, false otherwise.</returns> private static bool SafeIsCurveLoopClockwise(CurveLoop curveLoop, XYZ dir) { if (curveLoop == null) return false; if (curveLoop.IsOpen()) return false; if ((curveLoop.Count() == 1) && !(curveLoop.First().IsBound)) return false; return !curveLoop.IsCounterclockwise(dir); }
/// <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); }