using FeMM.Common.Helpers;
using FeMM.Common.Models;
using FeMM.Grasshopper.DataTypes.FeMM;
using FeMM.Grasshopper.Helpers;
using Grasshopper.Kernel;
using Grasshopper.Kernel.Parameters;
using Maffeis.Utilities.Units;
using Rhino.Geometry;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Versioning;

namespace FeMM.Grasshopper.Components.Checks
{
#if NETCOREAPP
    [SupportedOSPlatform("windows")]
#endif
    public class RCFrameAsComponent : GH_Component
    {

        /// <summary>
        /// Initializes a new instance of the BeamComponent class.
        /// </summary>
        public RCFrameAsComponent()
          : base("RC frames As", "RCFAs", "Calculate the reinforcement area of RC frames", CategoryNameConstants.CATEGORY_CHECKS, CategoryNameConstants.SUBCATEGORY_MECHECK)
        {
        }

        /// <summary>
        /// Registers all the input parameters for this component.
        /// </summary>
        protected override void RegisterInputParams(GH_InputParamManager pManager)
        {
            int n;
            pManager.AddGenericParameter("Frames", "Fs", "The frames containing results", GH_ParamAccess.list);
            pManager.AddNumberParameter("Top beam cover", "TBC", "Top cover of beams", GH_ParamAccess.item);
            pManager.AddNumberParameter("Bottom beam cover", "BBC", "Bottom cover of beams", GH_ParamAccess.item);
            pManager.AddNumberParameter("Pillar cover", "PC", "Cover of pillars", GH_ParamAccess.item);
            pManager.AddNumberParameter(char.ConvertFromUtf32(0x3B3) + "s", char.ConvertFromUtf32(0x3B3) + "s", "Partial safety factor of rebar", GH_ParamAccess.item, 1.15);
            pManager.AddNumberParameter("fyk", "fyk", "Caratheristic yield resistance of rebar", GH_ParamAccess.item);
            n = pManager.AddIntegerParameter("Length unit", "LU", "Units of the length", GH_ParamAccess.item);
            Param_Integer length_param = (Param_Integer)pManager[n];
            foreach (SteelFrameChecksComponent.LengthUnits value in Enum.GetValues(typeof(SteelFrameChecksComponent.LengthUnits)))
                length_param.AddNamedValue(value.GetDescription(), (int)value);
            n = pManager.AddIntegerParameter("Force unit", "FU", "Units of the forces", GH_ParamAccess.item);
            Param_Integer force_param = (Param_Integer)pManager[n];
            foreach (SteelFrameChecksComponent.ForceUnits value in Enum.GetValues(typeof(SteelFrameChecksComponent.ForceUnits)))
                force_param.AddNamedValue(value.GetDescription(), (int)value);
        }

        /// <summary>
        /// Registers all the output parameters for this component.
        /// </summary>
        protected override void RegisterOutputParams(GH_OutputParamManager pManager)
        {
            pManager.AddGenericParameter("RC Beams", "Bs", "Beams", GH_ParamAccess.list);
            pManager.AddNumberParameter("Beam ascissas", "BAs", "Ascissas of beams", GH_ParamAccess.tree);
            pManager.AddNumberParameter("Beam top As", "BTAs", "Beams required top reinforcement area", GH_ParamAccess.tree);
            pManager.AddNumberParameter("Beam bottom As", "BBAs", "Beams required bottom reinforcement area", GH_ParamAccess.tree);
            pManager.AddNumberParameter("Beam shear As", "BSAs", "Beams required shear reinforcement area", GH_ParamAccess.tree);

            pManager.AddGenericParameter("RC Pillars", "Ps", "Pillars", GH_ParamAccess.list);
            pManager.AddNumberParameter("Pillar ascissas", "PAs", "Ascissas of pillars", GH_ParamAccess.tree);
            pManager.AddNumberParameter("Pillar As", "PAs", "Pillar required longitudinal reinforcement area", GH_ParamAccess.tree);
            pManager.AddNumberParameter("Pillar shear As", "PSAs", "Pillars required shear reinforcement area", GH_ParamAccess.tree);
        }

        /// <summary>
        /// This is the method that actually does the work.
        /// </summary>
        /// <param name="DA">The DA object is used to retrieve from inputs and store in outputs.</param>
        protected override void SolveInstance(IGH_DataAccess DA)
        {
            var frames = new List<GH_Beam>();
            double topBeamCover = 0;
            double bottomBeamCover = 0;
            double pillarCover = 0;
            double gammaS = 0;
            double fyk = 0;
            int lengthValue = -1;
            int forceValue = -1;
            if (!DA.GetDataList(0, frames))
                return;
            if (!DA.GetData(1, ref topBeamCover))
                return;
            if (!DA.GetData(2, ref bottomBeamCover))
                return;
            if (!DA.GetData(3, ref pillarCover))
                return;
            if (!DA.GetData(4, ref gammaS))
                return;
            if (!DA.GetData(5, ref fyk))
                return;
            if (!DA.GetData(6, ref lengthValue))
                return;
            if (!DA.GetData(7, ref forceValue))
                return;

            SteelFrameChecksComponent.LengthUnits lengthUnits;
            SteelFrameChecksComponent.ForceUnits forceUnits;
            lengthUnits = (SteelFrameChecksComponent.LengthUnits)lengthValue;
            forceUnits = (SteelFrameChecksComponent.ForceUnits)forceValue;

            UnitsConvert.ForceUnits utilsForceCode;
            UnitsConvert.LengthUnits utilsLengthCode;
            switch (forceUnits)
            {
                case SteelFrameChecksComponent.ForceUnits.N:
                    utilsForceCode = UnitsConvert.ForceUnits.N;
                    break;
                case SteelFrameChecksComponent.ForceUnits.daN:
                    utilsForceCode = UnitsConvert.ForceUnits.daN;
                    break;
                case SteelFrameChecksComponent.ForceUnits.kN:
                    utilsForceCode = UnitsConvert.ForceUnits.kN;
                    break;
                default:
                    throw new NotSupportedException();
            }

            switch (lengthUnits)
            {
                case SteelFrameChecksComponent.LengthUnits.mm:
                    utilsLengthCode = UnitsConvert.LengthUnits.mm;
                    break;
                case SteelFrameChecksComponent.LengthUnits.cm:
                    utilsLengthCode = UnitsConvert.LengthUnits.cm;
                    break;
                case SteelFrameChecksComponent.LengthUnits.m:
                    utilsLengthCode = UnitsConvert.LengthUnits.m;
                    break;
                default:
                    throw new NotSupportedException();
            }

            List<GH_Beam> beams, rcBeams;
            List<GH_Beam> pillars, rcPillars;
            var beamTopAs = new Dictionary<BeamModel, List<double>>();
            var beamBottomAs = new Dictionary<BeamModel, List<double>>();
            var beamShearAs = new Dictionary<BeamModel, List<double>>();
            var pillarLongAs = new Dictionary<BeamModel, List<double>>();
            var pillarShearAs = new Dictionary<BeamModel, List<double>>();
            double fyd, fykMPa;
            Dictionary<BeamModel, List<double>> beamsAscissas, pillarAscissas, rcBeamsAscissas, rcPillarAscissas;

            GetBeamPillars(frames, out beams, out pillars, out beamsAscissas, out pillarAscissas);

            rcBeamsAscissas = [];
            rcPillarAscissas = [];

            fyd = fyk / gammaS;
            //fykMPa = fyk;
            fykMPa = UnitsConvert.ConvertToDefaultUnits(fyk, utilsForceCode, 1, utilsLengthCode, -2);

            //switch (lengthCode)
            //{
            //    case SteelFrameChecksComponent.LengthUnits.cm:
            //        fykMPa /= 100;
            //        break;
            //    case SteelFrameChecksComponent.LengthUnits.m:
            //        fykMPa /= 1000000;
            //        break;
            //    case SteelFrameChecksComponent.LengthUnits.mm:
            //        break;
            //    default:
            //        throw new NotSupportedException();
            //}
            //switch (forceCode)
            //{
            //    case SteelFrameChecksComponent.ForceUnits.daN:
            //        fykMPa *= 10;
            //        break;
            //    case SteelFrameChecksComponent.ForceUnits.kN:
            //        fykMPa *= 1000;
            //        break;
            //    case SteelFrameChecksComponent.ForceUnits.N:
            //        break;
            //    default:
            //        throw new NotSupportedException();
            //}

            //Beams
            rcBeams = [];
            foreach (GH_Beam beam in beams)
            {
                if (beam.Value.BeamProperty.Material.Kind == MaterialModel.MaterialKind.Concrete ||
                    beam.Value.BeamProperty.Material.Kind == MaterialModel.MaterialKind.Precast)
                {
                    List<double> bufferTopAs, bufferBottomAs, bufferShearAs;
                    double fckMPa, fck;
                    double fctmMPa, fctm;
                    double vertDimension, horDimension;
                    double minAs, minShearAs;

                    rcBeams.Add(beam);
                    rcBeamsAscissas.Add(beam.Value, beamsAscissas[beam.Value]);
                    bufferTopAs = [];
                    bufferBottomAs = [];
                    bufferShearAs = [];
                    fckMPa = beam.Value.BeamProperty.Material.SpecificCompressiveStrength;
                    fck = UnitsConvert.ConvertFromDefaultUnits(beam.Value.BeamProperty.Material.SpecificCompressiveStrength,
                                                                  utilsForceCode, 1, utilsLengthCode, -2);
                    //switch (lengthCode)
                    //{
                    //    case SteelFrameChecksComponent.LengthUnits.cm:
                    //        fckMPa /= 100;
                    //        break;
                    //    case SteelFrameChecksComponent.LengthUnits.m:
                    //        fckMPa /= 1000000;
                    //        break;
                    //    case SteelFrameChecksComponent.LengthUnits.mm:
                    //        break;
                    //    default:
                    //        throw new NotSupportedException();
                    //}
                    //switch (forceCode)
                    //{
                    //    case SteelFrameChecksComponent.ForceUnits.daN:
                    //        fckMPa *= 10;
                    //        break;
                    //    case SteelFrameChecksComponent.ForceUnits.kN:
                    //        fckMPa *= 1000;
                    //        break;
                    //    case SteelFrameChecksComponent.ForceUnits.N:
                    //        break;
                    //    default:
                    //        throw new NotSupportedException();
                    //}

                    if (fckMPa <= 50)
                    {
                        fctmMPa = 0.3 * Math.Pow(fckMPa, 2d / 3d);
                    }
                    else
                    {
                        fctmMPa = 2.12 * Math.Log(1d + (fckMPa + 8) / 10d);
                    }

                    fctm = fctmMPa;//N su mm2
                    switch (lengthUnits)
                    {
                        case SteelFrameChecksComponent.LengthUnits.cm:
                            fctm *= 100;
                            break;
                        case SteelFrameChecksComponent.LengthUnits.m:
                            fctm *= 1000000;
                            break;
                        case SteelFrameChecksComponent.LengthUnits.mm:
                            break;
                        default:
                            throw new NotSupportedException();
                    }
                    switch (forceUnits)
                    {
                        case SteelFrameChecksComponent.ForceUnits.daN:
                            fctm /= 10;
                            break;
                        case SteelFrameChecksComponent.ForceUnits.kN:
                            fctm /= 1000;
                            break;
                        case SteelFrameChecksComponent.ForceUnits.N:
                            break;
                        default:
                            throw new NotSupportedException();
                    }

                    if (beam.Value.AngleDeg == 90)
                    {
                        switch (beam.Value.BeamProperty.SectionType)
                        {
                            case SectionModel.SectionTypes.SolidRectangle:
                                {
                                    vertDimension = beam.Value.BeamProperty.D;
                                    horDimension = beam.Value.BeamProperty.B;
                                    break;
                                }
                            default:
                                throw new NotImplementedException();
                        }
                    }
                    else if (beam.Value.AngleDeg == 0)
                    {
                        switch (beam.Value.BeamProperty.SectionType)
                        {
                            case SectionModel.SectionTypes.SolidRectangle:
                                {
                                    vertDimension = beam.Value.BeamProperty.B;
                                    horDimension = beam.Value.BeamProperty.D;
                                    break;
                                }
                            default:
                                throw new NotImplementedException();
                        }
                    }
                    else
                    {
                        throw new NotSupportedException();
                    }

                    minAs = 0.26 * fctm / fyk * vertDimension * horDimension;
                    minShearAs = 0.08 * Math.Sqrt(fckMPa) / fykMPa * horDimension;

                    if (!beamTopAs.TryGetValue(beam.Value, out bufferTopAs))
                    {
                        bufferTopAs = [];
                        for (int ascCount = 0; ascCount < beamsAscissas[beam.Value].Count; ascCount++)
                        {
                            bufferTopAs.Add(minAs);
                        }
                        beamTopAs.Add(beam.Value, bufferTopAs);
                    }
                    if (!beamBottomAs.TryGetValue(beam.Value, out bufferBottomAs))
                    {
                        bufferBottomAs = [];
                        for (int ascCount = 0; ascCount < beamsAscissas[beam.Value].Count; ascCount++)
                        {
                            bufferBottomAs.Add(minAs);
                        }
                        beamBottomAs.Add(beam.Value, bufferBottomAs);
                    }
                    if (!beamShearAs.TryGetValue(beam.Value, out bufferShearAs))
                    {
                        bufferShearAs = [];
                        for (int ascCount = 0; ascCount < beamsAscissas[beam.Value].Count; ascCount++)
                        {
                            bufferShearAs.Add(minShearAs);
                        }
                        beamShearAs.Add(beam.Value, bufferShearAs);
                    }

                    BeamForceResultModel[] results = [.. beam.Value.Results.
                        Where(r => r.GetType() == typeof(BeamForceResultModel)).Cast<BeamForceResultModel>()];
                    foreach (BeamForceResultModel result in results)
                    {
                        double n, m11, m22, v11, v22;
                        double m, v;
                        double d;
                        double traction;
                        int index;

                        n = result.AxialForce;
                        //moment.X=m2,moment.Y=m3 con segni SAP
                        //shear.X=v2,shear.Y=v3 con segni SAP
                        //per segni SAP vedi manuale SAP

                        //per ora per me m>0 e v>0 se e'>0 il momento vettore
                        //TODO da rivedere tutto!!!!
                        m11 = result.BendingMoment.Y;
                        m22 = result.BendingMoment.X;
                        v11 = result.ShearForce.Y;
                        v22 = -result.ShearForce.X;

                        if (beam.Value.AngleDeg == 90)
                        {
                            //The vertical plane is the plane 2
                            m = m11;
                            v = v22;
                        }
                        else if (beam.Value.AngleDeg == 0)
                        {
                            //The vertical plane is the plane 1
                            m = m22;
                            v = v11;
                        }
                        else
                        {
                            throw new NotSupportedException();
                        }

                        if (m > 0)
                        {
                            //Bottom tensile
                            d = vertDimension - bottomBeamCover;
                        }
                        else
                        {
                            //Top tensile
                            d = vertDimension - topBeamCover;
                        }

                        traction = Math.Abs(m / (0.9 * d) + 0.5 * n);
                        index = beamsAscissas[beam.Value].IndexOf(result.Station);
                        if (index < 0)
                        {
                            throw new NotSupportedException();
                        }
                        if (traction > 0)
                        {
                            double aS;

                            aS = traction / fyd;
                            if (m > 0)
                            {
                                //Bottom tensile
                                bufferBottomAs[index] = Math.Max(bufferBottomAs[index], aS);
                            }
                            else
                            {
                                //Top tensile
                                bufferTopAs[index] = Math.Max(bufferTopAs[index], aS);
                            }
                        }

                        //ShearReinforcements
                        bufferShearAs[index] = Math.Max(bufferShearAs[index], Math.Abs(v) / (0.9 * d * fyd));
                    }
                }
            }

            //Pillars
            rcPillars = [];
            foreach (GH_Beam pillar in pillars)
            {
                if (pillar.Value.BeamProperty.Material.Kind == MaterialModel.MaterialKind.Concrete ||
                    pillar.Value.BeamProperty.Material.Kind == MaterialModel.MaterialKind.Precast)
                {
                    List<double> bufferLongAs, bufferShearAs;
                    double dimension11, dimension22, d11, d22;
                    double aCls;

                    bufferLongAs = [];
                    bufferShearAs = [];
                    rcPillars.Add(pillar);
                    rcPillarAscissas.Add(pillar.Value, pillarAscissas[pillar.Value]);

                    switch (pillar.Value.BeamProperty.SectionType)
                    {
                        case SectionModel.SectionTypes.SolidRectangle:
                            {
                                dimension11 = pillar.Value.BeamProperty.B;
                                dimension22 = pillar.Value.BeamProperty.D;
                                d11 = dimension11 - pillarCover;
                                d22 = dimension22 - pillarCover;
                                break;
                            }
                        default:
                            throw new NotImplementedException();
                    }

                    aCls = dimension11 * dimension22;

                    if (!pillarLongAs.TryGetValue(pillar.Value, out bufferLongAs))
                    {
                        bufferLongAs = [];
                        for (int ascCount = 0; ascCount < pillarAscissas[pillar.Value].Count; ascCount++)
                        {
                            bufferLongAs.Add(0);
                        }
                        pillarLongAs.Add(pillar.Value, bufferLongAs);
                    }
                    if (!pillarShearAs.TryGetValue(pillar.Value, out bufferShearAs))
                    {
                        bufferShearAs = [];
                        for (int ascCount = 0; ascCount < pillarAscissas[pillar.Value].Count; ascCount++)
                        {
                            bufferShearAs.Add(0);
                        }
                        pillarShearAs.Add(pillar.Value, bufferShearAs);
                    }
                    BeamForceResultModel[] results = [.. pillar.Value.Results.
                        Where(r => r.GetType() == typeof(BeamForceResultModel)).Cast<BeamForceResultModel>()];
                    foreach (BeamForceResultModel result in results)
                    {
                        double m1;
                        double m2;
                        double n;
                        double v1;
                        double v2;
                        double minAs;
                        double n11, n22;
                        double as11, as22;
                        double aS;
                        double shearAs11, shearAs22;
                        int index;

                        //Longitudinal reinforcements
                        //See beams for sign convetions
                        m1 = result.BendingMoment.Y;
                        m2 = result.BendingMoment.X;
                        n = result.AxialForce;
                        v1 = result.ShearForce.Y;
                        v2 = -result.ShearForce.X;

                        minAs = Math.Max(0.1 * Math.Abs(n) / fyd, 0.002 * aCls);
                        n11 = Math.Abs(m1 / (0.9 * d22)) + 0.5 * n;
                        n22 = Math.Abs(m2 / (0.9 * d11)) + 0.5 * n;
                        as11 = Math.Max(0, n11 / fyd);
                        as22 = Math.Max(0, n22 / fyd);
                        aS = 2 * as11 + 2 * as22;

                        index = pillarAscissas[pillar.Value].IndexOf(result.Station);
                        if (index < 0)
                        {
                            throw new NotSupportedException();
                        }

                        bufferLongAs[index] = Math.Max(bufferLongAs[index], Math.Max(aS, minAs));

                        //ShearReinforcements
                        shearAs11 = Math.Abs(v1) / (0.9 * d11 * fyd);
                        shearAs22 = Math.Abs(v2) / (0.9 * d22 * fyd);

                        bufferShearAs[index] = Math.Max(bufferShearAs[index], Math.Max(shearAs11, shearAs22));
                    }
                }
            }

            DA.SetDataList(0, rcBeams);
            DA.SetDataTree(1, SteelFrameChecksComponent.GetStructure(rcBeamsAscissas));
            DA.SetDataTree(2, SteelFrameChecksComponent.GetStructure(beamTopAs));
            DA.SetDataTree(3, SteelFrameChecksComponent.GetStructure(beamBottomAs));
            DA.SetDataTree(4, SteelFrameChecksComponent.GetStructure(beamShearAs));

            DA.SetDataList(5, rcPillars);
            DA.SetDataTree(6, SteelFrameChecksComponent.GetStructure(rcPillarAscissas));
            DA.SetDataTree(7, SteelFrameChecksComponent.GetStructure(pillarLongAs));
            DA.SetDataTree(8, SteelFrameChecksComponent.GetStructure(pillarShearAs));
        }

        private static void GetBeamPillars(List<GH_Beam> frames,
                                           out List<GH_Beam> beams,
                                           out List<GH_Beam> pillars,
                                           out Dictionary<BeamModel, List<double>> beamsAscissas,
                                           out Dictionary<BeamModel, List<double>> pillarAscissas)
        {
            beams = [];
            pillars = [];
            beamsAscissas = [];
            pillarAscissas = [];
            foreach (GH_Beam frame in frames)
            {
                List<double> ascissas;
                Vector3d dir = frame.Value.PointTo - frame.Value.PointFrom;
                dir.Unitize();
                ascissas = [];
                BeamForceResultModel[] results = [.. frame.Value.Results.
                        Where(r => r.GetType() == typeof(BeamForceResultModel)).Cast<BeamForceResultModel>()];
                foreach (BeamForceResultModel result in results)
                {
                    if (!ascissas.Contains(result.Station))
                    {
                        ascissas.Add(result.Station);
                    }
                }
                if (Math.Abs(dir * Vector3d.ZAxis) > 0.8)
                {
                    //pillar, pseudo vertical
                    pillars.Add(frame);
                    pillarAscissas.Add(frame.Value, ascissas);
                }
                else
                {
                    //beam
                    beams.Add(frame);
                    beamsAscissas.Add(frame.Value, ascissas);
                }
            }
        }

        public override GH_Exposure Exposure => GH_Exposure.primary;

        /// <summary>
        /// Provides an Icon for the component.
        /// </summary>
        protected override System.Drawing.Bitmap Icon => Properties.Resources.RCFrameAsIcon;

        /// <summary>
        /// Gets the unique ID for this component. Do not change this ID after release.
        /// </summary>
        public override Guid ComponentGuid => new("E1DFC6FF-F680-4A6D-971C-33B7015322A9");
    }
}
303 files24 directories