示例#1
0
        /// <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
            }));
        }
示例#2
0
        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);
        }
示例#8
0
        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);
        }
示例#9
0
        /// <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;
            }
        }