public static List <string> Generate(Document doc, Floor floor, RebarInfoFloor rif, ElementId areaTypeId)
        {
            Debug.WriteLine("RebarWorkerFloor is started");
            List <string> messages = new List <string>();
            MyRebarType   mrt      = new MyRebarType(doc, rif.rebarTypeName);

            if (mrt.isValid == false)
            {
                messages.Add("Не удалось получить тип стержня " + rif.rebarTypeName);
            }
            double interval        = rif.interval;
            double topCoverUser    = rif.topCover;
            double bottomCoverUser = rif.bottomCover;

            RebarCoverType coverTop    = doc.GetElement(floor.get_Parameter(BuiltInParameter.CLEAR_COVER_TOP).AsElementId()) as RebarCoverType;
            RebarCoverType coverBottom = doc.GetElement(floor.get_Parameter(BuiltInParameter.CLEAR_COVER_BOTTOM).AsElementId()) as RebarCoverType;

            if (coverTop == null)
            {
                Debug.WriteLine("Top cover is null");
                coverTop = coverBottom;
            }
            if (coverBottom == null)
            {
                Debug.WriteLine("Bottom cover is null");
                coverBottom = coverTop;
            }

            Debug.WriteLine("Rebar cover types id, top: " + coverTop.Id.IntegerValue + ", bottom: " + coverBottom.Id.IntegerValue);

#if R2017 || R2018 || R2019 || R2020 || R2021
            double diam = mrt.bartype.BarDiameter;
#else
            double diam = mrt.bartype.BarNominalDiameter;
#endif

            double topCoverDir1 = topCoverUser - coverTop.CoverDistance;
            double topCoverDir2 = topCoverDir1 + diam;
            if (rif.turnTopBars)
            {
                topCoverDir1 += diam;
                topCoverDir2 -= diam;
            }

            double bottomCoverDir1 = bottomCoverUser - coverBottom.CoverDistance;
            double bottomCoverDir2 = bottomCoverDir1 + diam;
            if (rif.turnBottomBars)
            {
                bottomCoverDir1 += diam;
                bottomCoverDir2 -= diam;
            }


            List <Curve> curves = SupportGeometry.GetFloorOuterBoundary(floor);
            Debug.WriteLine("Boundary curves count: " + curves.Count);

            XYZ direction = new XYZ(1, 0, 0);

            if (rif.useDirection)
            {
                double    angle           = floor.SpanDirectionAngle;
                Transform rotateTransform = Transform.CreateRotationAtPoint(new XYZ(0, 0, 1), angle, new XYZ(0, 0, 0));
                Line      horizontal      = Line.CreateBound(new XYZ(0, 0, 0), new XYZ(1, 0, 0));
                Curve     rotatedCurve    = horizontal.CreateTransformed(rotateTransform);
                direction = rotatedCurve.GetEndPoint(1);
            }
            Debug.WriteLine("Direction: " + direction.ToString());

            AreaReinforcement arTopX = AreaReinforcement
                                       .Create(doc, floor, curves, direction, areaTypeId, mrt.bartype.Id, ElementId.InvalidElementId);
            arTopX.get_Parameter(BuiltInParameter.REBAR_SYSTEM_ACTIVE_TOP_DIR_1_GENERIC).Set(1);
            arTopX.get_Parameter(BuiltInParameter.REBAR_SYSTEM_ACTIVE_TOP_DIR_2_GENERIC).Set(0);
            arTopX.get_Parameter(BuiltInParameter.REBAR_SYSTEM_ACTIVE_BOTTOM_DIR_1_GENERIC).Set(0);
            arTopX.get_Parameter(BuiltInParameter.REBAR_SYSTEM_ACTIVE_BOTTOM_DIR_2_GENERIC).Set(0);
            arTopX.get_Parameter(BuiltInParameter.REBAR_SYSTEM_SPACING_TOP_DIR_1_GENERIC).Set(interval);
            arTopX.get_Parameter(BuiltInParameter.REBAR_SYSTEM_ADDL_TOP_OFFSET).Set(topCoverDir1);
            arTopX.get_Parameter(BuiltInParameter.NUMBER_PARTITION_PARAM).Set("верх X фон");
            Debug.WriteLine("Top X is created");

            AreaReinforcement arTopY = AreaReinforcement
                                       .Create(doc, floor, curves, direction, areaTypeId, mrt.bartype.Id, ElementId.InvalidElementId);
            arTopY.get_Parameter(BuiltInParameter.REBAR_SYSTEM_ACTIVE_TOP_DIR_1_GENERIC).Set(0);
            arTopY.get_Parameter(BuiltInParameter.REBAR_SYSTEM_ACTIVE_TOP_DIR_2_GENERIC).Set(1);
            arTopY.get_Parameter(BuiltInParameter.REBAR_SYSTEM_ACTIVE_BOTTOM_DIR_1_GENERIC).Set(0);
            arTopY.get_Parameter(BuiltInParameter.REBAR_SYSTEM_ACTIVE_BOTTOM_DIR_2_GENERIC).Set(0);
            arTopY.get_Parameter(BuiltInParameter.REBAR_SYSTEM_SPACING_TOP_DIR_2_GENERIC).Set(interval);
            arTopY.get_Parameter(BuiltInParameter.REBAR_SYSTEM_ADDL_TOP_OFFSET).Set(topCoverDir2);
            arTopY.get_Parameter(BuiltInParameter.NUMBER_PARTITION_PARAM).Set("верх Y фон");
            Debug.WriteLine("Top Y is created");

            AreaReinforcement arBottomX = AreaReinforcement
                                          .Create(doc, floor, curves, direction, areaTypeId, mrt.bartype.Id, ElementId.InvalidElementId);
            arBottomX.get_Parameter(BuiltInParameter.REBAR_SYSTEM_ACTIVE_TOP_DIR_1_GENERIC).Set(0);
            arBottomX.get_Parameter(BuiltInParameter.REBAR_SYSTEM_ACTIVE_TOP_DIR_2_GENERIC).Set(0);
            arBottomX.get_Parameter(BuiltInParameter.REBAR_SYSTEM_ACTIVE_BOTTOM_DIR_1_GENERIC).Set(1);
            arBottomX.get_Parameter(BuiltInParameter.REBAR_SYSTEM_ACTIVE_BOTTOM_DIR_2_GENERIC).Set(0);
            arBottomX.get_Parameter(BuiltInParameter.REBAR_SYSTEM_SPACING_BOTTOM_DIR_1_GENERIC).Set(interval);
            arBottomX.get_Parameter(BuiltInParameter.REBAR_SYSTEM_ADDL_BOTTOM_OFFSET).Set(bottomCoverDir1);
            arBottomX.get_Parameter(BuiltInParameter.NUMBER_PARTITION_PARAM).Set("низ X фон");
            Debug.WriteLine("Bottom X is created");

            AreaReinforcement arBottomY = AreaReinforcement
                                          .Create(doc, floor, curves, direction, areaTypeId, mrt.bartype.Id, ElementId.InvalidElementId);
            arBottomY.get_Parameter(BuiltInParameter.REBAR_SYSTEM_ACTIVE_TOP_DIR_1_GENERIC).Set(0);
            arBottomY.get_Parameter(BuiltInParameter.REBAR_SYSTEM_ACTIVE_TOP_DIR_2_GENERIC).Set(0);
            arBottomY.get_Parameter(BuiltInParameter.REBAR_SYSTEM_ACTIVE_BOTTOM_DIR_1_GENERIC).Set(0);
            arBottomY.get_Parameter(BuiltInParameter.REBAR_SYSTEM_ACTIVE_BOTTOM_DIR_2_GENERIC).Set(1);
            arBottomY.get_Parameter(BuiltInParameter.REBAR_SYSTEM_SPACING_BOTTOM_DIR_2_GENERIC).Set(interval);
            arBottomY.get_Parameter(BuiltInParameter.REBAR_SYSTEM_ADDL_BOTTOM_OFFSET).Set(bottomCoverDir2);
            arBottomY.get_Parameter(BuiltInParameter.NUMBER_PARTITION_PARAM).Set("низ Y фон");
            Debug.WriteLine("Bottom Y is created");

            return(messages);
        }
        public static List <string> GenerateRebar(Document doc, Wall wall, RebarInfoWall wri, RebarCoverType zeroCover, ElementId areaTypeId)
        {
            Debug.WriteLine("Start reinforcement for wall: " + wall.Id.IntegerValue.ToString());
            List <string> messages = new List <string>();

            double      lengthRound      = 5 / 304.8;
            ProjectInfo pi               = doc.ProjectInformation;
            Parameter   roundLengthParam = pi.LookupParameter("Арм.ОкруглениеДлины");

            if (roundLengthParam != null && roundLengthParam.HasValue)
            {
                lengthRound = roundLengthParam.AsDouble();
            }

            wall.get_Parameter(BuiltInParameter.CLEAR_COVER_OTHER).Set(zeroCover.Id);
            Debug.WriteLine("Set zero rebar cover for other faces");

            Solid       sol       = SupportGeometry.GetSolidFromElement(wall);
            List <Face> vertFaces = SupportGeometry.GetVerticalFaces(sol);
            Face        mainFace  = SupportGeometry.GetLargeFace(vertFaces);
            PlanarFace  pface     = mainFace as PlanarFace;

            Debug.WriteLine("Vertical planar face was found");

            List <Curve> wallOutlineDraft = SupportGeometry.GetFaceOuterBoundary(pface);

            Debug.WriteLine("Outline draft curves found: " + wallOutlineDraft.Count.ToString());

            //удаляю совпадающие линии
            List <Curve> wallOutline = SupportGeometry.CleanLoop(wallOutlineDraft);

            Debug.WriteLine("Outline clean curves found: " + wallOutline.Count.ToString());


            //определяю отступы для защитных слоев
            RebarCoverType coverFront = doc.GetElement(wall.get_Parameter(BuiltInParameter.CLEAR_COVER_EXTERIOR).AsElementId()) as RebarCoverType;
            RebarCoverType coverBack  = doc.GetElement(wall.get_Parameter(BuiltInParameter.CLEAR_COVER_INTERIOR).AsElementId()) as RebarCoverType;

            if (coverFront == null)
            {
                coverFront = coverBack;
            }
            if (coverBack == null)
            {
                coverBack = coverFront;
            }

            double userDefineCover = wri.rebarCover;


            MyRebarType verticalRebarType = new MyRebarType(doc, wri.verticalRebarTypeName);

            if (verticalRebarType.isValid == false)
            {
                messages.Add("Не удалось получить тип стержня " + wri.verticalRebarTypeName);
                Debug.WriteLine("Unable to get vertical rebartype: " + wri.verticalRebarTypeName);
            }
            MyRebarType horizontalRebarType = new MyRebarType(doc, wri.horizontalRebarTypeName);

            if (horizontalRebarType.isValid == false)
            {
                messages.Add("Не удалось получить тип стержня " + wri.horizontalRebarTypeName);
                Debug.WriteLine("Unable to get horizontal rebartype: " + wri.horizontalRebarTypeName);
            }

#if R2017 || R2018 || R2019 || R2020 || R2021
            double vertDiam  = verticalRebarType.bartype.BarDiameter;
            double horizDiam = horizontalRebarType.bartype.BarDiameter;
#else
            double vertDiam  = verticalRebarType.bartype.BarNominalDiameter;
            double horizDiam = horizontalRebarType.bartype.BarNominalDiameter;
#endif

            double offsetVerticalExterior   = userDefineCover - coverFront.CoverDistance - 0.5 * vertDiam;
            double offsetVerticalInterior   = userDefineCover - coverBack.CoverDistance - 0.5 * vertDiam;
            double offsetHorizontalExterior = offsetVerticalExterior - horizDiam;
            double offsetHorizontalInterior = offsetVerticalInterior - horizDiam;


            if (wri.generateVertical)
            {
                Debug.WriteLine("Start creating vertical rebar");
                Parameter paramFloorThickinessParam = wall.LookupParameter("Рзм.ТолщинаПерекрытия");

                if (wri.autoVerticalFreeLength)
                {
                    Debug.WriteLine("Try to auto-calculate vertical free length");
                    if (paramFloorThickinessParam != null && paramFloorThickinessParam.HasValue)
                    {
                        double floorThickness = paramFloorThickinessParam.AsDouble();
                        double freeLength     = ConcreteUtils.getRebarFreeLength(verticalRebarType.bartype, wall, lengthRound);
                        wri.verticalFreeLength = floorThickness + freeLength;
                        Debug.WriteLine("Vertical free length = " + wri.verticalFreeLength);
                    }
                    else
                    {
                        Debug.WriteLine("Unable to auto-calculate vertical free length");
                        throw new Exception("Не задан параметр Рзм.ТолщинаПерекрытия в элементе " + wall.Id.IntegerValue.ToString());
                    }
                }


                List <Curve> curvesVertical = SupportGeometry.MoveLine(wallOutline, wri.verticalFreeLength, SupportGeometry.LineSide.Top);
                Debug.WriteLine("Curves for vertical loop: " + curvesVertical.Count.ToString());

                if (wri.useUnification)
                {
                    Debug.WriteLine("Try to unificate vertical length");
                    double verticalZoneHeight = SupportGeometry.GetZoneHeigth(curvesVertical);
                    double unificateLength    = wri.getNearestLength(verticalZoneHeight);
                    double moveToUnificate    = unificateLength - verticalZoneHeight;
                    if (moveToUnificate > 0.005)
                    {
                        List <Curve> curvesVerticalUnificate = SupportGeometry.MoveLine(curvesVertical, moveToUnificate, SupportGeometry.LineSide.Top);
                        curvesVertical = curvesVerticalUnificate;
                    }
                }


                /*LocationCurve wallLocCurve = wall.Location as LocationCurve;
                 * Line wallCurve = wallLocCurve.Curve as Line;
                 * if (wallCurve == null) throw new Exception("Curved wall!");*/

                double sideOffset = wri.backOffset - 0.5 * vertDiam;

                curvesVertical = SupportGeometry.MoveLine(curvesVertical, sideOffset, SupportGeometry.LineSide.Left);
                curvesVertical = SupportGeometry.MoveLine(curvesVertical, sideOffset, SupportGeometry.LineSide.Right);

                CurveUtils.SortCurvesContiguous(doc.Application.Create, curvesVertical, true);
                Debug.WriteLine("Contiguous curves sort");

                if (wri.verticalOffset < 0.0001)
                {
                    Debug.WriteLine("Generate vertical rebar area without offset");
                    AreaReinforcement arVertical = Generate(doc, wall, curvesVertical, false, true, true, offsetVerticalInterior, offsetVerticalExterior, wri.verticalRebarInterval, areaTypeId, verticalRebarType.bartype, wri.verticalSectionText);
                }
                else
                {
                    Debug.WriteLine("Generate vertical rebar area with offset");
                    AreaReinforcement arVertical1 = Generate(doc, wall, curvesVertical, false, true, false, offsetVerticalInterior, offsetVerticalExterior, wri.verticalRebarInterval, areaTypeId, verticalRebarType.bartype, wri.verticalSectionText);

                    List <Curve> curves2 = SupportGeometry.MoveLine(curvesVertical, wri.verticalOffset, SupportGeometry.LineSide.Top);
                    curves2 = SupportGeometry.MoveLine(curves2, wri.verticalOffset, SupportGeometry.LineSide.Bottom);
                    AreaReinforcement arVertical2 = Generate(doc, wall, curves2, false, false, true, offsetVerticalInterior, offsetVerticalExterior, wri.verticalRebarInterval, areaTypeId, verticalRebarType.bartype, wri.verticalSectionText);
                }
            }

            if (wri.generateHorizontal)
            {
                Debug.WriteLine("Start creating horizontal rebar");
                //определяю контур
                double       horizontalTopOffset    = 0.5 * horizDiam - wri.topOffset;
                double       horizintalBottomOffset = wri.bottomOffset - 0.5 * horizDiam;
                List <Curve> curvesHorizontal       = SupportGeometry.MoveLine(wallOutline, horizontalTopOffset, SupportGeometry.LineSide.Top);
                curvesHorizontal = SupportGeometry.MoveLine(curvesHorizontal, horizintalBottomOffset, SupportGeometry.LineSide.Bottom);

                double sideOffset = wri.horizontalFreeLength * -1;
                curvesHorizontal = SupportGeometry.MoveLine(curvesHorizontal, sideOffset, SupportGeometry.LineSide.Left);
                curvesHorizontal = SupportGeometry.MoveLine(curvesHorizontal, sideOffset, SupportGeometry.LineSide.Right);

                List <AreaRebarInfo> curvesBase = new List <AreaRebarInfo>();


                if (wri.horizontalAddInterval)
                {
                    Debug.WriteLine("Create with additional offset");

                    double horizRebarInterval = wri.horizontalRebarInterval;

                    if (wri.horizontalAdditionalStepSpace)
                    {
                        horizRebarInterval = horizRebarInterval / 2;
                    }

                    double heigth              = SupportGeometry.GetZoneHeigth(curvesHorizontal);
                    double heigthByAxis        = heigth - horizDiam;
                    double countCheckAsDouble1 = heigthByAxis / horizRebarInterval;
                    double countCheckAsDouble2 = Math.Round(countCheckAsDouble1, 2);
                    double countCheckAsDouble3 = Math.Truncate(countCheckAsDouble2);
                    int    countCheck          = (int)countCheckAsDouble3;
                    double addIntervalByAxis   = heigthByAxis - countCheck * horizRebarInterval;
                    if (addIntervalByAxis < horizDiam) //доборный шаг не требуется
                    {
                        Debug.WriteLine("Additional offset not needed");
                        curvesBase.Add(new AreaRebarInfo(curvesHorizontal, horizRebarInterval));
                    }
                    else
                    {
                        Debug.WriteLine("Additional offset = " + (addIntervalByAxis * 304.8).ToString("F3"));
                        int count = countCheck - 1;

                        if (addIntervalByAxis < 50 / 304.8) //доборный шаг менее 50мм - увеличиваю отступ сверху
                        {
                            count--;
                        }

                        double       heigthClean = count * horizRebarInterval;
                        double       offsetMain  = heigth - heigthClean - horizDiam;
                        List <Curve> profileMain = SupportGeometry.MoveLine(curvesHorizontal, -offsetMain, SupportGeometry.LineSide.Top);

                        if (wri.horizontalAdditionalStepSpace)
                        {
                            if (wri.horizontalAddStepHeightBottom > 0)
                            {
                                List <List <Curve> > profilesAddBottom = SupportGeometry.CopyTopOrBottomLines(curvesHorizontal, wri.horizontalAddStepHeightBottom, false);
                                foreach (var prof in profilesAddBottom)
                                {
                                    curvesBase.Add(new AreaRebarInfo(prof, horizRebarInterval));
                                }

                                profileMain = SupportGeometry.MoveLine(profileMain, wri.horizontalAddStepHeightBottom, SupportGeometry.LineSide.Bottom);
                            }
                            else if (wri.horizontalAddStepHeightTop > 0)
                            {
                                List <List <Curve> > profilesAddTop = SupportGeometry.CopyTopOrBottomLines(curvesHorizontal, wri.horizontalAddStepHeightTop, true);
                                foreach (var prof in profilesAddTop)
                                {
                                    curvesBase.Add(new AreaRebarInfo(prof, horizRebarInterval));
                                }

                                profileMain = SupportGeometry.MoveLine(profileMain, -wri.horizontalAddStepHeightTop, SupportGeometry.LineSide.Top);
                            }
                            curvesBase.Add(new AreaRebarInfo(profileMain, horizRebarInterval * 2));
                        }
                        else
                        {
                            curvesBase.Add(new AreaRebarInfo(profileMain, horizRebarInterval));
                        }

                        double heigthAdd = heigth - heigthClean - horizRebarInterval;

                        List <List <Curve> > profilesAdd = SupportGeometry.CopyTopOrBottomLines(curvesHorizontal, heigthAdd, true);
                        foreach (var prof in profilesAdd)
                        {
                            curvesBase.Add(new AreaRebarInfo(prof, horizRebarInterval));
                        }
                    }
                }
                else
                {
                    Debug.WriteLine("Create only one zone for horizontal rebars");
                    curvesBase.Add(new AreaRebarInfo(curvesHorizontal, wri.horizontalRebarInterval));
                }


                Debug.WriteLine("Loops for horizontal rebar: " + curvesBase.Count.ToString());

                foreach (var profileInfo in curvesBase)
                {
                    double            interval = profileInfo.interval;
                    List <Curve>      curves   = profileInfo.curves;
                    AreaReinforcement ar       = Generate(doc, wall, curves, true, true, true, offsetHorizontalInterior, offsetHorizontalExterior, interval, areaTypeId, horizontalRebarType.bartype, wri.horizontalSectionText);
                }
            }
            return(messages);
        }