void SubDivideSoffits_CreateFireRatedLayers(Document doc) { try { #region Get Soffits List <Element> Soffits = new FilteredElementCollector(doc).OfCategory(BuiltInCategory.OST_Floors).ToElements().Where(m => !(m is ElementType)).ToList(); #endregion //Subdivide foreach (Element Soffit in Soffits.Where(m => m.Name.ToLower().Contains("eave"))) { #region Get Soffit Geometry Options ops = new Options(); ops.DetailLevel = ViewDetailLevel.Fine; ops.IncludeNonVisibleObjects = true; GeometryElement Geo = Soffit.get_Geometry(ops); #endregion foreach (var item in Geo) { if (item is Solid) { #region Get one of the Main Faces, it doesn't really matter if it is top or bottom Solid GSol = item as Solid; List <Face> Fs = new List <Face>(); foreach (Face f in GSol.Faces) { Fs.Add(f); } Face F = Fs.Where(m => m.Area == Fs.Max(a => a.Area)).First(); #endregion #region Triangulate the Face with max detail Mesh M = F.Triangulate(1); #endregion #region Create Variables for: the curves that will define the new Soffits, List of Custom Triangle Class, List of Custom Pair of Triangle Class List <List <Curve> > LLC = new List <List <Curve> >(); List <Triangle> Triangles = new List <Triangle>(); List <TrianglePair> TPairs = new List <TrianglePair>(); #endregion #region Loop Through Triangles & Add Them to the list of My Triangle Class for (int i = 0; i < M.NumTriangles; i++) { List <Curve> LC = new List <Curve>(); #region Make List of Curves From Triangle MeshTriangle MT = M.get_Triangle(i); List <Curve> Curves = new List <Curve>(); Curve C = Line.CreateBound(MT.get_Vertex(0), MT.get_Vertex(1)) as Curve; Curves.Add(C); C = Line.CreateBound(MT.get_Vertex(1), MT.get_Vertex(2)) as Curve; Curves.Add(C); C = Line.CreateBound(MT.get_Vertex(2), MT.get_Vertex(0)) as Curve; Curves.Add(C); #endregion Triangle T = new Triangle(); T.Sides = new List <Curve>(); T.Sides = Curves; T.Vertices = new List <XYZ>(); T.Vertices.Add(MT.get_Vertex(0)); T.Vertices.Add(MT.get_Vertex(1)); T.Vertices.Add(MT.get_Vertex(2)); Triangles.Add(T); } #endregion #region Loop Through Triangles And Create Trapezoid Pairs To Catch The Segments, Getting Rid of The Shared sides bool GO = true; do { Triangle TKeeper1 = new Triangle(); Triangle TKeeper2 = new Triangle(); foreach (Triangle T in Triangles) { TKeeper1 = new Triangle(); foreach (Triangle T2 in Triangles) { TKeeper2 = new Triangle(); if (T != T2) { if (FindCurvesFacing(T, T2) != null) { if (FindCurvesFacing(T, T2)[0].Length == T.Sides.Min(c => c.Length) || FindCurvesFacing(T, T2)[1].Length == T2.Sides.Min(c => c.Length)) { continue; } Curve[] Cs = FindCurvesFacing(T, T2); T.Sides.Remove(Cs[0]); T2.Sides.Remove(Cs[1]); if (T.Sides.Count() == 2 && T2.Sides.Count() == 2) { TKeeper1 = T; TKeeper2 = T2; goto ADDANDGOROUND; } } } } } GO = false; ADDANDGOROUND: if (GO) { Triangles.Remove(TKeeper1); Triangles.Remove(TKeeper2); TrianglePair TP = new TrianglePair(); TP.T1 = TKeeper1; TP.T2 = TKeeper2; TPairs.Add(TP); } } while(GO); #endregion #region Create Curve Loops From Triangle Pairs foreach (TrianglePair TPair in TPairs) { List <Curve> Cs = new List <Curve>(); Cs.AddRange(TPair.T1.Sides); Cs.AddRange(TPair.T2.Sides); LLC.Add(Cs); } #endregion double Offset = Convert.ToDouble(Soffit.LookupParameter("Height Offset From Level").AsValueString()); FloorType FT = (Soffit as Floor).FloorType; Level Lvl = doc.GetElement((Soffit as Floor).LevelId) as Level; #region Delete Old Soffit If All Went Well using (Transaction T = new Transaction(doc, "Delete Soffit")) { T.Start(); doc.Delete(Soffit.Id); T.Commit(); } #endregion #region Sort The Lists of Curves and Create The New Segments foreach (List <Curve> LC in LLC) { List <Curve> LCSorted = new List <Curve>(); try { LCSorted = SortCurvesContiguous(LC, false); } #region Exception Details if Curves Could not be sorted catch (Exception EXC) { string exmsge = EXC.Message; } #endregion CurveArray CA = new CurveArray(); foreach (Curve C in LCSorted) { CA.Append(C); } using (Transaction T = new Transaction(doc, "Make Segment")) { T.Start(); Floor newFloor = doc.Create.NewFloor(CA, FT, Lvl, false); newFloor.LookupParameter("Height Offset From Level").SetValueString(Offset.ToString()); T.Commit(); } } #endregion } } } //refresh collection Soffits = new FilteredElementCollector(doc).OfCategory(BuiltInCategory.OST_Floors).ToElements().Where(m => !(m is ElementType)).ToList(); //test soffits for needing fire rating foreach (Element Soffit in Soffits.Where(m => m.Name.ToLower().Contains("eave"))) { #region Get Soffit Geometry Options ops = new Options(); ops.DetailLevel = ViewDetailLevel.Fine; ops.IncludeNonVisibleObjects = true; GeometryElement Geo = Soffit.get_Geometry(ops); #endregion foreach (var item in Geo) { if (item is Solid) { #region Find boundary Void Element List <Element> MaybeBoundary = new FilteredElementCollector(doc).OfCategory(BuiltInCategory.OST_Floors).ToElements().Where(m => !(m is ElementType)).ToList(); Element BoundryElement = MaybeBoundary.Where(m => !(m is FloorType) && m.Name == "Boundary").First(); #endregion #region Get Intersection of Boundary and eave PolygonAnalyser com = new PolygonAnalyser(); List <CurveArray> CArray = com.Execute(BoundryElement as Floor, Soffit as Floor); Level L = doc.GetElement(Soffit.LevelId) as Level; #endregion foreach (CurveArray CA in CArray) { #region Sort The Curves IList <Curve> CAL = new List <Curve>(); foreach (Curve C in CA) { CAL.Add(C); } List <Curve> Curves = SortCurvesContiguous(CAL, false); List <XYZ> NewCurveEnds = new List <XYZ>(); #endregion #region Close the loop if nesesary CurveLoop CL = new CurveLoop(); foreach (Curve curv in Curves) { CL.Append(curv); } if (CL.IsOpen()) { Curves.Add(Line.CreateBound(CL.First().GetEndPoint(0), CL.Last().GetEndPoint(1)) as Curve); } #endregion #region Recreate a Curve Array Curves = SortCurvesContiguous(Curves, false); CurveArray CA2 = new CurveArray(); int i = 0; foreach (Curve c in Curves) { CA2.Insert(c, i); i += 1; } #endregion #region Create The New Fire Rated Layer element FloorType ft = new FilteredElementCollector(doc).WhereElementIsElementType().OfCategory(BuiltInCategory.OST_Floors).ToElements().Where(m => m.Name == "Fire Rated Layer").First() as FloorType; Transaction T = new Transaction(doc, "Fire Rated Layer Creation"); try { T.Start(); Floor F = doc.Create.NewFloor(CA2, ft, L, false); string s = Soffit.LookupParameter("Height Offset From Level").AsValueString(); double si = Convert.ToDouble(s); si = si + (Convert.ToDouble(Soffit.LookupParameter("Thickness").AsValueString())); F.LookupParameter("Height Offset From Level").SetValueString(si.ToString()); T.Commit(); } catch (Exception EX) { T.RollBack(); string EXmsg = EX.Message; } #endregion } } } } } catch (Exception ex) { string mesg = ex.Message; } }