/// <summary> /// Construct a Revit FilledRegion element by Curves /// </summary> /// <param name="view">View to place filled region on</param> /// <param name="boundary">Boundary curves</param> /// <param name="regionType">Region Type</param> /// <returns></returns> public static FilledRegion ByCurves(Revit.Elements.Views.View view, IEnumerable <Autodesk.DesignScript.Geometry.Curve> boundary, FilledRegionType regionType) { Autodesk.Revit.DB.FilledRegionType type = regionType.InternalRevitElement; CurveLoop loop = new CurveLoop(); foreach (Autodesk.DesignScript.Geometry.Curve curve in boundary) { loop.Append(curve.ToRevitType()); } if (loop.IsOpen()) { throw new Exception(Properties.Resources.CurveLoopNotClosed); } Autodesk.Revit.DB.View revitView = (Autodesk.Revit.DB.View)view.InternalElement; if (!view.IsAnnotationView()) { throw new Exception(Properties.Resources.ViewDoesNotSupportAnnotations); } return(new FilledRegion(revitView, type.Id, new List <CurveLoop>() { loop })); }
public Polycurve CurveLoopToSpeckle(CurveLoop loop, string units = null) { var polycurve = new Polycurve(); polycurve.units = units ?? ModelUnits; polycurve.closed = !loop.IsOpen(); polycurve.length = units == Units.None ? loop.GetExactLength() : ScaleToSpeckle(loop.GetExactLength()); polycurve.segments.AddRange(loop.Select(x => CurveToSpeckle(x))); return(polycurve); }
public Polycurve CurveLoopToSpeckle(CurveLoop loop) { var polycurve = new Polycurve(); polycurve.units = ModelUnits; polycurve.closed = !loop.IsOpen(); polycurve.length = ScaleToSpeckle(loop.GetExactLength()); polycurve.segments.AddRange(loop.Select(x => CurveToSpeckle(x))); return(polycurve); }
public void GetAreaProfile() { try { SpatialElementBoundaryOptions opt = new SpatialElementBoundaryOptions(); opt.StoreFreeBoundaryFaces = true; opt.SpatialElementBoundaryLocation = SpatialElementBoundaryLocation.Center; IList <IList <BoundarySegment> > boundaryListList = m_area.GetBoundarySegments(opt); List <CurveLoop> profiles = new List <CurveLoop>(); foreach (IList <BoundarySegment> boundaryList in boundaryListList) { List <Curve> curveList = new List <Curve>(); foreach (BoundarySegment segment in boundaryList) { #if RELEASE2015 curveList.Add(segment.Curve); #else curveList.Add(segment.GetCurve()); #endif } CurveLoop curveLoop = CurveLoop.Create(curveList); if (!curveLoop.IsOpen()) { areaProfile.Add(curveLoop); } } if (areaProfile.Count > 0) { CalculateCenterPoint(); } } catch (Exception ex) { string message = ex.Message; } }
/// <summary> /// Get the curve from the Axis representation of the given IfcProduct, transformed to the current local coordinate system. /// </summary> /// <param name="creator">The IfcProduct that may or may not contain a valid axis curve.</param> /// <param name="lcs">The local coordinate system.</param> /// <returns>The axis curve, if found, and valid.</returns> /// <remarks>In this case, we only allow bounded lines and arcs to be valid axis curves, as per IFC2x3 convention. /// The Curve may be contained as either a single Curve in the IFCCurve representation item, or it could be an /// open CurveLoop with one item.</remarks> private Curve GetAxisCurve(IFCProduct creator, Transform lcs) { // We need an axis curve to clip the extrusion profiles; if we can't get one, fail IFCProductRepresentation productRepresentation = creator.ProductRepresentation; if (productRepresentation == null) { return(null); } IList <IFCRepresentation> representations = productRepresentation.Representations; if (representations == null) { return(null); } foreach (IFCRepresentation representation in representations) { // Go through the list of representations for this product, to find the Axis representation. if (representation == null || representation.Identifier != IFCRepresentationIdentifier.Axis) { continue; } IList <IFCRepresentationItem> items = representation.RepresentationItems; if (items == null) { continue; } // Go through the list of representation items in the Axis representation, to look for the IfcCurve. foreach (IFCRepresentationItem item in items) { if (item is IFCCurve) { // We will accept either a bounded Curve of type Line or Arc, // or an open CurveLoop with one curve that satisfies the same condition. IFCCurve ifcCurve = item as IFCCurve; Curve axisCurve = ifcCurve.Curve; if (axisCurve == null) { CurveLoop axisCurveLoop = ifcCurve.CurveLoop; if (axisCurveLoop != null && axisCurveLoop.IsOpen() && axisCurveLoop.Count() == 1) { axisCurve = axisCurveLoop.First(); if (!(axisCurve is Line || axisCurve is Arc)) { axisCurve = null; } } } if (axisCurve != null) { return(axisCurve.CreateTransformed(lcs)); } } } } return(null); }
/// <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> /// Determines if a curveloop can be exported as an I-Shape profile. /// </summary> /// <param name="exporterIFC">The exporter.</param> /// <param name="profileName">The name of the profile.</param> /// <param name="curveLoop">The curve loop.</param> /// <param name="origPlane">The plane of the loop.</param> /// <param name="projDir">The projection direction.</param> /// <returns>The IfcIShapeProfileDef, or null if not possible.</returns> /// <remarks>This routine works with I-shaped curveloops projected onto origPlane, in either orientation; /// it does not work with H-shaped curveloops.</remarks> private static IFCAnyHandle CreateIShapeProfileDefIfPossible(ExporterIFC exporterIFC, string profileName, CurveLoop curveLoop, Plane origPlane, XYZ projDir) { IFCFile file = exporterIFC.GetFile(); if (curveLoop.IsOpen()) return null; if (curveLoop.Count() != 12 && curveLoop.Count() != 16) return null; // All curves must be lines, except for 4 optional fillets; get direction vectors and start points. XYZ xDir = origPlane.XVec; XYZ yDir = origPlane.YVec; // The list of vertices, in order. startVertex below is the upper-right hand vertex, in UV-space. IList<UV> vertices = new List<UV>(); // The directions in UV of the line segments. directions[ii] is the direction of the line segment starting with vertex[ii]. IList<UV> directions = new List<UV>(); // The lengths in UV of the line segments. lengths[ii] is the length of the line segment starting with vertex[ii]. IList<double> lengths = new List<double>(); // turnsCCW[ii] is true if directions[ii+1] is clockwise relative to directions[ii] in UV-space. IList<bool> turnsCCW = new List<bool>(); IList<Arc> fillets = new List<Arc>(); IList<int> filletPositions = new List<int>(); int idx = 0; int startVertex = -1; int startFillet = -1; UV upperRight = null; double lowerBoundU = 1e+30; double upperBoundU = -1e+30; foreach (Curve curve in curveLoop) { if (!(curve is Line)) { if (!(curve is Arc)) return null; fillets.Add(curve as Arc); filletPositions.Add(idx); // share the index of the next line segment. continue; } Line line = curve as Line; XYZ point = line.GetEndPoint(0); UV pointProjUV = GeometryUtil.ProjectPointToPlane(origPlane, projDir, point); if (pointProjUV == null) return null; pointProjUV = UnitUtil.ScaleLength(pointProjUV); if ((upperRight == null) || ((pointProjUV.U > upperRight.U - MathUtil.Eps()) && (pointProjUV.V > upperRight.V - MathUtil.Eps()))) { upperRight = pointProjUV; startVertex = idx; startFillet = filletPositions.Count; } if (pointProjUV.U < lowerBoundU) lowerBoundU = pointProjUV.U; if (pointProjUV.U > upperBoundU) upperBoundU = pointProjUV.U; vertices.Add(pointProjUV); XYZ direction3d = line.Direction; UV direction = new UV(direction3d.DotProduct(xDir), direction3d.DotProduct(yDir)); lengths.Add(UnitUtil.ScaleLength(line.Length)); bool zeroU = MathUtil.IsAlmostZero(direction.U); bool zeroV = MathUtil.IsAlmostZero(direction.V); if (zeroU && zeroV) return null; // Accept only non-rotated I-Shapes. if (!zeroU && !zeroV) return null; direction.Normalize(); if (idx > 0) { if (!MathUtil.IsAlmostZero(directions[idx - 1].DotProduct(direction))) return null; turnsCCW.Add(directions[idx - 1].CrossProduct(direction) > 0); } directions.Add(direction); idx++; } if (directions.Count != 12) return null; if (!MathUtil.IsAlmostZero(directions[11].DotProduct(directions[0]))) return null; turnsCCW.Add(directions[11].CrossProduct(directions[0]) > 0); bool firstTurnIsCCW = turnsCCW[startVertex]; // Check proper turning of lines. // The orientation of the turns should be such that 8 match the original orientation, and 4 go in the opposite direction. // The opposite ones are: // For I-Shape: // if the first turn is clockwise (i.e., in -Y direction): 1,2,7,8. // if the first turn is counterclockwise (i.e., in the -X direction): 2,3,8,9. // For H-Shape: // if the first turn is clockwise (i.e., in -Y direction): 2,3,8,9. // if the first turn is counterclockwise (i.e., in the -X direction): 1,2,7,8. int iShapeCCWOffset = firstTurnIsCCW ? 1 : 0; int hShapeCWOffset = firstTurnIsCCW ? 0 : 1; bool isIShape = true; bool isHShape = false; for (int ii = 0; ii < 12 && isIShape; ii++) { int currOffset = 12 + (startVertex - iShapeCCWOffset); int currIdx = (ii + currOffset) % 12; if (currIdx == 1 || currIdx == 2 || currIdx == 7 || currIdx == 8) { if (firstTurnIsCCW == turnsCCW[ii]) isIShape = false; } else { if (firstTurnIsCCW == !turnsCCW[ii]) isIShape = false; } } if (!isIShape) { // Check if it is orientated like an H - if neither I nor H, fail. isHShape = true; for (int ii = 0; ii < 12 && isHShape; ii++) { int currOffset = 12 + (startVertex - hShapeCWOffset); int currIdx = (ii + currOffset) % 12; if (currIdx == 1 || currIdx == 2 || currIdx == 7 || currIdx == 8) { if (firstTurnIsCCW == turnsCCW[ii]) return null; } else { if (firstTurnIsCCW == !turnsCCW[ii]) return null; } } } // Check that the lengths of parallel and symmetric line segments are equal. double overallWidth = 0.0; double overallDepth = 0.0; double flangeThickness = 0.0; double webThickness = 0.0; // I-Shape: // CCW pairs:(0,6), (1,5), (1,7), (1,11), (2,4), (2,8), (2,10), (3, 9) // CW pairs: (11,5), (0,4), (0,6), (0,10), (1,3), (1,7), (1,9), (2, 8) // H-Shape is reversed. int cwPairOffset = (firstTurnIsCCW == isIShape) ? 0 : 11; overallWidth = lengths[(startVertex + cwPairOffset) % 12]; flangeThickness = lengths[(startVertex + 1 + cwPairOffset) % 12]; if (isIShape) { if (firstTurnIsCCW) { overallDepth = vertices[startVertex].V - vertices[(startVertex + 7) % 12].V; webThickness = vertices[(startVertex + 9) % 12].U - vertices[(startVertex + 3) % 12].U; } else { overallDepth = vertices[startVertex].V - vertices[(startVertex + 5) % 12].V; webThickness = vertices[(startVertex + 2) % 12].U - vertices[(startVertex + 8) % 12].U; } } else { if (!firstTurnIsCCW) { overallDepth = vertices[startVertex].U - vertices[(startVertex + 7) % 12].U; webThickness = vertices[(startVertex + 9) % 12].V - vertices[(startVertex + 3) % 12].V; } else { overallDepth = vertices[startVertex].U - vertices[(startVertex + 5) % 12].U; webThickness = vertices[(startVertex + 2) % 12].V - vertices[(startVertex + 8) % 12].V; } } if (!MathUtil.IsAlmostEqual(overallWidth, lengths[(startVertex + 6 + cwPairOffset) % 12])) return null; if (!MathUtil.IsAlmostEqual(flangeThickness, lengths[(startVertex + 5 + cwPairOffset) % 12]) || !MathUtil.IsAlmostEqual(flangeThickness, lengths[(startVertex + 7 + cwPairOffset) % 12]) || !MathUtil.IsAlmostEqual(flangeThickness, lengths[(startVertex + 11 + cwPairOffset) % 12])) return null; double innerTopLeftLength = lengths[(startVertex + 2 + cwPairOffset) % 12]; if (!MathUtil.IsAlmostEqual(innerTopLeftLength, lengths[(startVertex + 4 + cwPairOffset) % 12]) || !MathUtil.IsAlmostEqual(innerTopLeftLength, lengths[(startVertex + 8 + cwPairOffset) % 12]) || !MathUtil.IsAlmostEqual(innerTopLeftLength, lengths[(startVertex + 10 + cwPairOffset) % 12])) return null; double iShaftLength = lengths[(startVertex + 3 + cwPairOffset) % 12]; if (!MathUtil.IsAlmostEqual(iShaftLength, lengths[(startVertex + 9 + cwPairOffset) % 12])) return null; // Check fillet validity. int numFillets = fillets.Count(); double? filletRadius = null; if (numFillets != 0) { if (numFillets != 4) return null; // startFillet can have any value from 0 to 4; if it is 4, need to reset it to 0. // The fillet positions relative to the upper right hand corner are: // For I-Shape: // if the first turn is clockwise (i.e., in -Y direction): 2,3,8,9. // if the first turn is counterclockwise (i.e., in the -X direction): 3,4,9,10. // For H-Shape: // if the first turn is clockwise (i.e., in -Y direction): 3,4,9,10. // if the first turn is counterclockwise (i.e., in the -X direction): 2,3,8,9. int filletOffset = (isIShape == firstTurnIsCCW) ? 1 : 0; if (filletPositions[startFillet % 4] != ((2 + filletOffset + startVertex) % 12) || filletPositions[(startFillet + 1) % 4] != ((3 + filletOffset + startVertex) % 12) || filletPositions[(startFillet + 2) % 4] != ((8 + filletOffset + startVertex) % 12) || filletPositions[(startFillet + 3) % 4] != ((9 + filletOffset + startVertex) % 12)) return null; double tmpFilletRadius = fillets[0].Radius; for (int ii = 1; ii < 4; ii++) { if (!MathUtil.IsAlmostEqual(tmpFilletRadius, fillets[ii].Radius)) return null; } if (!MathUtil.IsAlmostZero(tmpFilletRadius)) filletRadius = UnitUtil.ScaleLength(tmpFilletRadius); } XYZ planeNorm = origPlane.Normal; for (int ii = 0; ii < numFillets; ii++) { bool filletIsCCW = (fillets[ii].Normal.DotProduct(planeNorm) > MathUtil.Eps()); if (filletIsCCW == firstTurnIsCCW) return null; } if (MathUtil.IsAlmostZero(overallWidth) || MathUtil.IsAlmostZero(overallDepth) || MathUtil.IsAlmostZero(flangeThickness) || MathUtil.IsAlmostZero(webThickness)) return null; // We have an I-Shape Profile! IList<double> newCtr = new List<double>(); newCtr.Add((vertices[0].U + vertices[6].U) / 2); newCtr.Add((vertices[0].V + vertices[6].V) / 2); IFCAnyHandle location = IFCInstanceExporter.CreateCartesianPoint(file, newCtr); IList<double> refDir = new List<double>(); if (isIShape) { refDir.Add(1.0); refDir.Add(0.0); } else { refDir.Add(0.0); refDir.Add(1.0); } IFCAnyHandle refDirectionOpt = ExporterUtil.CreateDirection(file, refDir); IFCAnyHandle positionHnd = IFCInstanceExporter.CreateAxis2Placement2D(file, location, null, refDirectionOpt); return IFCInstanceExporter.CreateIShapeProfileDef(file, IFCProfileType.Area, profileName, positionHnd, overallWidth, overallDepth, webThickness, flangeThickness, filletRadius); }
private static IFCAnyHandle CreateCircleProfileDefIfPossible(ExporterIFC exporterIFC, string profileName, CurveLoop curveLoop, Plane origPlane, XYZ projDir) { IFCFile file = exporterIFC.GetFile(); if (curveLoop.IsOpen()) return null; XYZ origPlaneNorm = origPlane.Normal; Plane curveLoopPlane = null; try { curveLoopPlane = curveLoop.GetPlane(); } catch { return null; } XYZ curveLoopPlaneNorm = curveLoopPlane.Normal; if (!MathUtil.IsAlmostEqual(Math.Abs(origPlaneNorm.DotProduct(curveLoopPlaneNorm)), 1.0)) return null; IList<Arc> arcs = new List<Arc>(); foreach (Curve curve in curveLoop) { if (!(curve is Arc)) return null; arcs.Add(curve as Arc); } int numArcs = arcs.Count; if (numArcs == 0) return null; double radius = arcs[0].Radius; XYZ ctr = arcs[0].Center; for (int ii = 1; ii < numArcs; ii++) { XYZ newCenter = arcs[ii].Center; if (!newCenter.IsAlmostEqualTo(ctr)) return null; } double scale = exporterIFC.LinearScale; radius *= scale; XYZ xDir = origPlane.XVec; XYZ yDir = origPlane.YVec; XYZ orig = origPlane.Origin; ctr -= orig; IList<double> newCtr = new List<double>(); newCtr.Add(xDir.DotProduct(ctr) * scale); newCtr.Add(yDir.DotProduct(ctr) * scale); IFCAnyHandle location = IFCInstanceExporter.CreateCartesianPoint(file, newCtr); IList<double> refDir = new List<double>(); refDir.Add(1.0); refDir.Add(0.0); IFCAnyHandle refDirectionOpt = ExporterUtil.CreateDirection(file, refDir); IFCAnyHandle defPosition = IFCInstanceExporter.CreateAxis2Placement2D(file, location, null, refDirectionOpt); return IFCInstanceExporter.CreateCircleProfileDef(file, IFCProfileType.Area, profileName, defPosition, radius); }
/// <summary> /// 获取一组连续封闭的模型线 /// </summary> /// <returns></returns> /// <remarks></remarks> private CurveLoop GetLoopedCurve(out List <ModelCurve> modelCurves) { Document Doc = this._uiDoc.Document; // IList <Reference> boundaries = Selector.SelectGeneralElements <ModelCurve>(_uiDoc, out modelCurves, "选择一组模型线"); // if (boundaries == null || !boundaries.Any()) { return(null); } CurveLoop cvLoop = new CurveLoop(); try { if (boundaries.Count == 1) // 要么是封闭的圆或圆弧,要么就不封闭 { Curve c = ((ModelCurve)Doc.GetElement(boundaries[0])).GeometryCurve; if ((c is Arc || c is Ellipse) && !c.IsBound) { cvLoop.Append(c); } else { throw new InvalidOperationException("选择的一条圆弧线或者椭圆线并不封闭。"); } } else { // 对于选择了多条曲线的情况 IList <Curve> cs = CurvesFormator.GetContiguousCurvesFromCurves(Doc, boundaries); if (cs != null) { foreach (Curve c in cs) { cvLoop.Append(c); } } else { throw new InvalidOperationException("所选择的曲线不连续。"); } if (cvLoop.IsOpen()) { throw new InvalidOperationException("所选择的曲线不能形成封闭的曲线。"); } else if (!cvLoop.HasPlane()) { throw new InvalidOperationException("所选择的曲线不在同一个平面上。"); } else { return(cvLoop); } } } catch (Exception ex) { DialogResult res = MessageBox.Show( ex.Message + " 点击是以重新选择,点击否以退出绘制。" + "\r\n" + "当前选择的曲线条数为:" + Convert.ToString(boundaries.Count) + "条。" + "\r\n" + ex.StackTrace, "Warnning", MessageBoxButtons.YesNo); if (res == DialogResult.Yes) { cvLoop = GetLoopedCurve(out modelCurves); } else { cvLoop = new CurveLoop(); return(cvLoop); } } return(cvLoop); }
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; } }