/// <summary> /// 将一个directShape中的多个Solid进行合并 /// </summary> /// <param name="originalSolids"></param> /// <returns>理想情况下,返回的集合中应该只有一个Solid,但是由于Union操作不一定每次都能成功,所以此集合中还会有出现不成功时的那些Solid。</returns> private List <Solid> UnionSolid(IList <Solid> originalSolids) { List <Solid> solids = new List <Solid>(); double v1 = 0; foreach (Solid s in originalSolids) { // v1 += s.Volume; } Solid s1 = originalSolids[0]; solids.Add(s1); for (int i = 1; i < originalSolids.Count; i++) { Solid s2 = originalSolids[i]; try { // 将两个实体进行组合 BooleanOperationsUtils.ExecuteBooleanOperationModifyingOriginalSolid(s1, s2, BooleanOperationsType.Union); } catch (Exception ex) { // 说明实体组合不成功,此时应该将未组合进去的Solid记录下来 solids.Add(s2); } } return(solids); }
/// <summary> /// 判断当前创建出来的那个实体是否与其他单元相交,如果相交,则在原实体中剪除相交的部分,如果没有相交,则直接返回原实体集合(集合中的元素个数与原 originalSolids 集合中元素个数相同)。 /// </summary> /// <param name="directShape"></param> /// <param name="originalSolids"> directShape 所对应的实体,由于 ExecuteBooleanOperationModifyingOriginalSolid 函数中的 OriginalSolid /// 不能是直接从Revit的Element中得到的,所以要将前面通过轮廓拉伸出来的实体作为参数传入。</param> /// <param name="hasIntersect"></param>剪切后的实体的体积有可能不大于 0 啊 /// <returns> 返回的集合中的元素个数与原 originalSolids 集合中元素个数相同。剪切后的实体的体积有可能不大于 0 .</returns> private IList <Solid> ExcludeIntersect(DirectShape directShape, IList <Solid> originalSolids, out bool hasIntersect) { // 应用过滤器,在整个文档中搜索与指定Element相交的Element FilteredElementCollector collector = new FilteredElementCollector(directShape.Document); ElementIntersectsElementFilter elementFilter = new ElementIntersectsElementFilter(element: directShape, inverted: false); collector.WherePasses(elementFilter); // 排除面层本身 collector.Excluding(new ElementId[] { directShape.Id }); if (!collector.Any()) { // 说明没有相交的部分 hasIntersect = false; return(originalSolids); } hasIntersect = true; // 将与其相交的实体进行剪切操作 bool promptWhileError = false; foreach (Element interSectElem in collector) { var interSectSolids = GeoHelper.GetSolidsInModel(interSectElem, GeoHelper.SolidVolumnConstraint.Positive).Keys; // 与面层对象相交的 Element 中所有的实体 for (int i = 0; i < originalSolids.Count; i++) { Solid originalS = originalSolids[i]; foreach (Solid interSectS in interSectSolids) { try { // 在原实体中减去相交的部分 BooleanOperationsUtils.ExecuteBooleanOperationModifyingOriginalSolid(originalS, interSectS, BooleanOperationsType.Difference); } catch (Exception ex) { if (promptWhileError) { // 在剪切时如果不能剪切,则不剪切。 DialogResult res = MessageBox.Show("实体剪切时出现错误,可能的原因是面层与模型中的其他实体有细微交叉," + "以致剪切后的实体出现细小锯齿。\n\r (忽略此细微交叉对于面层算量并无明显影响)。" + " \n\r 点击“是”以忽略并继续,点击“否”不再提示。", "提示", MessageBoxButtons.YesNo, MessageBoxIcon.Hand, MessageBoxDefaultButton.Button2); promptWhileError = (res != DialogResult.No); } } } // 剪切后的实体的体积有可能不大于 0 啊 originalSolids[i] = originalS; // 将剪切完成后的 Solid 再赋值回集合中 } } return(originalSolids); }
public static bool TryCutSolid(Solid beingCutted, Solid cuts) { try { BooleanOperationsUtils.ExecuteBooleanOperationModifyingOriginalSolid (beingCutted, cuts, BooleanOperationsType.Difference); return(true); } catch (InternalException) { return(false); } }
/***************************************************/ private static List <ISurface> GetOpeningGeometry(Transaction t, Document doc, List <HostObject> hosts, List <ElementId> inserts, FamilyInstance familyInstance, RevitSettings settings = null) { List <List <Solid> > solidsWithOpening = new List <List <Solid> >(); foreach (HostObject h in hosts) { solidsWithOpening.Add(h.Solids(new Options()).Select(x => SolidUtils.Clone(x)).ToList()); } // Rollback and restart of the transaction is needed because otherwise the object, to which familyInstance is pointing can become invalidated. FailureHandlingOptions failureHandlingOptions = t.GetFailureHandlingOptions().SetClearAfterRollback(true); t.RollBack(failureHandlingOptions); t.Start(); List <ISurface> surfaces = new List <ISurface> (); List <CurveLoop> loops = new List <CurveLoop>(); try { doc.Delete(inserts); doc.Regenerate(); for (int i = 0; i < hosts.Count; i++) { HostObject h = hosts[i]; List <Autodesk.Revit.DB.Plane> planes = h.IPanelPlanes(); if (planes.Count == 0) { continue; } List <Solid> fullSolids = h.Solids(new Options()).SelectMany(x => SolidUtils.SplitVolumes(x)).ToList(); if (h is Wall) { fullSolids = fullSolids.Select(x => BooleanOperationsUtils.CutWithHalfSpace(x, planes[0])).ToList(); planes[0] = Autodesk.Revit.DB.Plane.CreateByNormalAndOrigin(-planes[0].Normal, planes[0].Origin); } foreach (Solid s in fullSolids) { foreach (Solid s2 in solidsWithOpening[i]) { BooleanOperationsUtils.ExecuteBooleanOperationModifyingOriginalSolid(s, s2, BooleanOperationsType.Difference); } foreach (Autodesk.Revit.DB.Face f in s.Faces) { PlanarFace pf = f as PlanarFace; if (pf == null) { continue; } if (planes.Any(x => Math.Abs(1 - pf.FaceNormal.DotProduct(x.Normal)) <= settings.DistanceTolerance && Math.Abs((pf.Origin - x.Origin).DotProduct(x.Normal)) <= settings.AngleTolerance)) { loops.AddRange(pf.GetEdgesAsCurveLoops()); } } } } } catch { loops = null; } t.RollBack(failureHandlingOptions); if (loops != null) { surfaces.AddRange(loops.Select(x => new PlanarSurface(x.FromRevit(), null))); } else if (surfaces.Count != 0) { BH.Engine.Reflection.Compute.RecordWarning(String.Format("Geometrical processing of a Revit element failed due to an internal Revit error. Converted opening might be missing one or more of its surfaces. Revit ElementId: {0}", familyInstance.Id)); } return(surfaces); }
/// <summary> /// Boolean difference geometric operation, modify the original solid as the result /// </summary> /// <param name="solid1">Operation solid 1 and operation result</param> /// <param name="solid2">Operation solid 2</param> public static void BooleanOperation_Difference(ref Solid solid1, Solid solid2) { BooleanOperationsUtils.ExecuteBooleanOperationModifyingOriginalSolid(solid1, solid2, BooleanOperationsType.Difference); }
/// <summary> /// Boolean union geometric operation, modify the original solid as the result /// </summary> /// <param name="solid1">Operation solid 1 and operation result</param> /// <param name="solid2">Operation solid 2</param> public static void BooleanOperation_Union(ref Solid solid1, Solid solid2) { BooleanOperationsUtils.ExecuteBooleanOperationModifyingOriginalSolid(solid1, solid2, BooleanOperationsType.Union); }
/// <summary> /// Boolean intersect geometric operation, modify the original solid as the result /// </summary> /// <param name="solid1">Operation solid 1 and operation result</param> /// <param name="solid2">Operation solid 2</param> public static void BooleanOperation_Intersect(ref Solid solid1, Solid solid2) { BooleanOperationsUtils.ExecuteBooleanOperationModifyingOriginalSolid(solid1, solid2, BooleanOperationsType.Intersect); }
/// <summary> /// Creates a negative block family from the geometry of the target element and boundaries. /// </summary> /// <remarks>This is the main implementation of the sample command.</remarks> /// <param name="targetElement">The target solid element.</param> /// <param name="boundaries">The selected curve element boundaries.</param> /// <param name="familyLoadOptions">The family load options when loading the new family.</param> /// <param name="familyTemplate">The family template.</param> public static FailureCondition CreateNegativeBlock(Element targetElement, IList <Reference> boundaries, IFamilyLoadOptions familyLoadOptions, String familyTemplate) { Document doc = targetElement.Document; Autodesk.Revit.ApplicationServices.Application app = doc.Application; // Get curve loop for boundary IList <Curve> curves = GetContiguousCurvesFromSelectedCurveElements(doc, boundaries); CurveLoop loop = null; try { loop = CurveLoop.Create(curves); } catch (Autodesk.Revit.Exceptions.ArgumentException) { // Curves are not contiguous return(FailureCondition.CurvesNotContigous); } List <CurveLoop> loops = new List <CurveLoop>(); loops.Add(loop); // Get elevation of loop double elevation = curves[0].GetEndPoint(0).Z; // Get height for extrusion BoundingBoxXYZ bbox = targetElement.get_BoundingBox(null); double height = bbox.Max.Z - elevation; if (height <= 1e-5) { return(FailureCondition.CurveLoopAboveTarget); } height += 1; // Create family Document familyDoc = app.NewFamilyDocument(familyTemplate); // Create block from boundaries Solid block = GeometryCreationUtilities.CreateExtrusionGeometry(loops, XYZ.BasisZ, height); // Subtract target element IList <Solid> fromElement = GetTargetSolids(targetElement); int solidCount = fromElement.Count; // Merge all found solids into single one Solid toSubtract = null; if (solidCount == 1) { toSubtract = fromElement[0]; } else if (solidCount > 1) { toSubtract = BooleanOperationsUtils.ExecuteBooleanOperation(fromElement[0], fromElement[1], BooleanOperationsType.Union); } if (solidCount > 2) { for (int i = 2; i < solidCount; i++) { toSubtract = BooleanOperationsUtils.ExecuteBooleanOperation(toSubtract, fromElement[i], BooleanOperationsType.Union); } } // Subtract merged solid from overall block try { BooleanOperationsUtils.ExecuteBooleanOperationModifyingOriginalSolid(block, toSubtract, BooleanOperationsType.Difference); } catch (Autodesk.Revit.Exceptions.InvalidOperationException) { return(FailureCondition.NoIntersection); } // Create freeform element using (Transaction t = new Transaction(familyDoc, "Add element")) { t.Start(); RevitFreeFormElement element = Autodesk.Revit.DB.FreeFormElement.Create(familyDoc, block); t.Commit(); } // Load family into document Family family = familyDoc.LoadFamily(doc, familyLoadOptions); familyDoc.Close(false); // Get symbol as first symbol of loaded family FilteredElementCollector collector = new FilteredElementCollector(doc); collector.WherePasses(new FamilySymbolFilter(family.Id)); FamilySymbol fs = collector.FirstElement() as FamilySymbol; // Place instance at location of original curves using (Transaction t2 = new Transaction(doc, "Place instance")) { t2.Start(); doc.Create.NewFamilyInstance(XYZ.Zero, fs, Autodesk.Revit.DB.Structure.StructuralType.NonStructural); t2.Commit(); } return(FailureCondition.Success); }