using SAP2000v1;
using FeMM.Common.Models;
using Rhino.Geometry;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Versioning;

namespace FeMM.Grasshopper.Components.SAPExtra
{
#if NETCOREAPP
    [SupportedOSPlatform("windows")]
#endif
    internal class ExtraSapHelper
    {
        #region Label

        public static string GetNodeLabel(NodeModel node)
        {
            string userName = GetElementName(node);
            if (userName == "")
            {
                return node.NodeId;
            }
            else
            {
                return userName;
            }
        }

        public static string GetBeamLabel(BeamModel beam)
        {
            string userName = GetElementName(beam);
            if (userName == "")
            {
                return beam.BeamId;
            }
            else
            {
                return userName;
            }
        }

        public static string GetPlateLabel(PlateModel plate)
        {
            string userName = GetElementName(plate);
            if (userName == "")
            {
                return plate.PlateId;
            }
            else
            {
                return userName;
            }
        }

        private static string GetElementName(ElementModel el)
        {
            ElementIdAttributeModel attr = (ElementIdAttributeModel)el.Attributes.FirstOrDefault(a => a is ElementIdAttributeModel);
            if (attr == null)
            {
                return "";
            }
            else
            {
                return attr.Value;
            }
        }

        #endregion

        private static void CreateFrameProp(BeamPropertyModel property, string propName, cSapModel sapModel, Dictionary<string, string> materials_map, double multiplierX,
            double multiplierY, ref int ret, ref List<string> errors, ref List<string> warnings)
        {
            switch (property.SectionType)
            {
                case SectionModel.SectionTypes.SolidCircle:
                    if (Math.Abs(multiplierX - multiplierY) > 0.001)
                    {
                        errors.Add($"Unable to apply a different taper coefficient to property {propName}");
                    }
                    ret = sapModel.PropFrame.SetCircle(propName, materials_map[property.Material.Name], property.D * multiplierX);
                    break;

                case SectionModel.SectionTypes.HollowCircle:
                    if (Math.Abs(multiplierX - multiplierY) > 0.001)
                    {
                        errors.Add($"Unable to apply a different taper coefficient to property {propName}");
                    }
                    ret = sapModel.PropFrame.SetPipe(propName, materials_map[property.Material.Name], property.D * multiplierX, property.T);
                    break;

                case SectionModel.SectionTypes.SolidRectangle:
                    ret = sapModel.PropFrame.SetRectangle(propName, materials_map[property.Material.Name], property.D * multiplierY, property.B * multiplierX);
                    break;

                case SectionModel.SectionTypes.HollowRectangle:
                    ret = sapModel.PropFrame.SetTube(propName, materials_map[property.Material.Name],
                        property.D * multiplierY, property.B * multiplierX, property.T1, property.T2);
                    break;

                case SectionModel.SectionTypes.I:
                    ret = sapModel.PropFrame.SetISection(propName, materials_map[property.Material.Name],
                        property.D * multiplierY, property.B2 * multiplierX, property.T2, property.T3,
                        property.B1 * multiplierX, property.T1);
                    break;

                case SectionModel.SectionTypes.T:
                    ret = sapModel.PropFrame.SetTee(propName, materials_map[property.Material.Name],
                        property.D * multiplierY, property.B * multiplierX, property.T1, property.T2);
                    break;

                case SectionModel.SectionTypes.C:
                case SectionModel.SectionTypes.Omega:
                    if (property.Mirror == SectionModel.MirrorTypes.None)
                        ret = sapModel.PropFrame.SetChannel(propName, materials_map[property.Material.Name],
                            property.D * multiplierY, property.B * multiplierX, property.T1, property.T2);
                    else
                        ret = sapModel.PropFrame.SetDblChannel(propName, materials_map[property.Material.Name],
                            property.D * multiplierY, 2 * property.B * multiplierX, property.T1, property.T2, property.MirrorGapA);
                    if (property.L > 0 || property.T3 > 0)
                        warnings.Add($"Warning: section {propName} not fully supported");
                    break;

                case SectionModel.SectionTypes.Angle:
                    if (property.Mirror == SectionModel.MirrorTypes.None)
                        ret = sapModel.PropFrame.SetAngle(propName, materials_map[property.Material.Name],
                            property.D * multiplierY, property.B * multiplierX, property.T1, property.T2);
                    else
                        ret = sapModel.PropFrame.SetDblAngle(propName, materials_map[property.Material.Name],
                            property.D * multiplierY, 2 * property.B * multiplierX, property.T1, property.T2, property.MirrorGapA);
                    break;

                case SectionModel.SectionTypes.Z:
                    ret = 1;
                    break;

                case SectionModel.SectionTypes.Generic:
                    double t2, t3 = t2 = Math.Sqrt(property.SectionArea);

                    if (Math.Abs(multiplierX - 1) > 0.001 || Math.Abs(multiplierY - 1) > 0.001)
                        warnings.Add("Unable to taper a generic section");

                    ret = sapModel.PropFrame.SetGeneral(propName, materials_map[property.Material.Name],
                        t3, t2, property.SectionArea, property.ShearA1, property.ShearA2, property.J,
                        property.I11, property.I22, property.W11, property.W22, 0, 0,
                           Math.Sqrt(property.I11 / property.SectionArea),
                           Math.Sqrt(property.I22 / property.SectionArea));

                    break;

                // SECTION DESIGNER
                case SectionModel.SectionTypes.GenericShapes:
                    int design_type = 0; // 0 : NOCheck; 1 = Design as general steel section; 2 = Design as a concrete column (check the reinforcing); Design as a concrete column; design the reinforcing

                    string material = materials_map[property.Material.Name];
                    eMatType type_material = eMatType.NoDesign;
                    int uninterest_int = 0;
                    string uninterest_string = string.Empty;
                    ret = sapModel.PropMaterial.GetMaterial(material, ref type_material, ref uninterest_int, ref uninterest_string, ref uninterest_string);

                    if (type_material == eMatType.Steel)
                    {
                        design_type = 1;
                    }
                    else if (type_material == eMatType.Concrete)
                    {
                        design_type = 2;
                    }

                    ret = sapModel.PropFrame.SetSDSection(propName, material, design_type);
                    if (ret != 0)
                    {
                        string error = string.Format($"Error {ret} creating SD propery {propName}");
                        errors.Add(error);
                        throw new Exception(error);
                    }


                    Maffeis.Geometry.Shape2d[] shapes = property.GenericShapes.ToShapes2d();
                    for (int j = 0; j < shapes.Length; j++)
                    {
                        Maffeis.Geometry.Shape2d shape = shapes[j];
                        double[] xs = new double[shape.Fill.Count];
                        double[] ys = new double[shape.Fill.Count];

                        for (int i = 0; i < xs.Length; i++)
                        {
                            xs[i] = shape.Fill[i].X * multiplierX;
                            ys[i] = shape.Fill[i].Y * multiplierY;
                        }

                        double[] radius = new double[xs.Length];

                        string shapeName = string.Empty;
                        ret = sapModel.PropFrame.SDShape.SetPolygon(propName, ref shapeName, material, string.Empty, xs.Length, ref xs, ref ys, ref radius);

                        if (ret != 0)
                        {
                            string error = string.Format($"Error {ret} creating SD property {propName} shapes");
                            errors.Add(error);
                            throw new Exception(error);
                        }
                    }


                    break;
            }
            if (ret != 0)
            {
                string error = string.Format($"Error {ret} creating frame property {propName}");
                errors.Add(error);
                throw new Exception(error);
            }
        }

        public static double GetSapPlateAngleFromDefault(PlateModel plate)
        {
            //pag.186 SAP2000 Analysis Reference Manual 
            plate.GetLocalAxes(out Vector3d femmAxesX, out Vector3d femmAxesY, out Vector3d femmAxesZ);
            Vector3d sapDefaultAxesZ = femmAxesZ;
            bool horizontalSap = Math.Sin(Math.Acos(sapDefaultAxesZ.Z)) < 0.001;
            Vector3d sapDefaultAxesY;
            //Plane defined by sapAxesY-Z vertical
            if (horizontalSap)
            {
                sapDefaultAxesY = Vector3d.CrossProduct(sapDefaultAxesZ, Vector3d.XAxis);
                sapDefaultAxesY.Unitize();
                if (Vector3d.Multiply(sapDefaultAxesY, Vector3d.YAxis) < 0)
                {
                    sapDefaultAxesY.Reverse();
                }
            }
            else
            {
                Vector3d buffer = Vector3d.CrossProduct(sapDefaultAxesZ, Vector3d.ZAxis);
                buffer.Unitize();
                sapDefaultAxesY = Vector3d.CrossProduct(buffer, sapDefaultAxesZ);
                sapDefaultAxesY.Unitize();
                if (Vector3d.Multiply(sapDefaultAxesY, Vector3d.ZAxis) < 0)
                {
                    sapDefaultAxesY.Reverse();
                }
            }
            Vector3d sapDefaultAxesX = Vector3d.CrossProduct(sapDefaultAxesY, sapDefaultAxesZ);
            sapDefaultAxesX.Unitize();
            return Math.Atan2(Vector3d.Multiply(sapDefaultAxesY, femmAxesX), Vector3d.Multiply(sapDefaultAxesX, femmAxesX)) * 180 / Math.PI;
        }

        public static bool NeedRotate180(BeamModel beam)
        {
            return NeedRotate180(beam.BeamProperty);
        }

        public static bool NeedRotate180(BeamPropertyModel bpm)
        {
            return bpm.SectionType == SectionModel.SectionTypes.Angle && bpm.Mirror != SectionModel.MirrorTypes.None;
        }

        /// <summary>
        /// Get the frame name from the given point
        /// </summary>
        /// <param name="sapModel">The model object</param>
        /// <param name="node_i">The node I coordinates</param>
        /// <param name="node_j">The node J coordinates</param>
        /// <param name="name">The name of the frame</param>
        /// <returns>True if exists</returns>
        private static bool GetNameFrameByPoints(cSapModel sapModel, Point3d node_i, Point3d node_j, ref string name)
        {
            int count = 0;
            string[] names = [];
            sapModel.FrameObj.GetNameList(ref count, ref names);
            for (int i = 0; i < count; i++)
            {
                string name_i = "", name_j = "";
                sapModel.FrameObj.GetPoints(names[i], ref name_i, ref name_j);
                double x_i = 0, y_i = 0, z_i = 0;
                sapModel.PointObj.GetCoordCartesian(name_i, ref x_i, ref y_i, ref z_i);
                var pt_i = new Point3d(x_i, y_i, z_i);
                double x_j = 0, y_j = 0, z_j = 0;
                sapModel.PointObj.GetCoordCartesian(name_j, ref x_j, ref y_j, ref z_j);
                var pt_j = new Point3d(x_j, y_j, z_j);
                if (node_i.Equals(pt_i) && node_j.Equals(pt_j))
                {
                    name = names[i];
                    return true;
                }
            }

            return false;
        }

        public static void ConvertStressesFromSAP2000(BeamModel beam, ref double m1, ref double m2, ref double t1, ref double t2)
        {
            ConvertStressesFromSAP2000(beam.BeamProperty, ref m1, ref m2, ref t1, ref t2);
        }

        public static void ConvertStressesFromSAP2000(BeamPropertyModel bpm, ref double m1, ref double m2, ref double t1, ref double t2)
        {
            double cosAlfaXTo1 = Math.Cos(bpm.AngleX1Rad);
            double senAlfaXTo1 = Math.Sin(bpm.AngleX1Rad);
            double mPrinc1, mPrinc2, vx, vy, vPrinc1, vPrinc2, mx, my;

            // Getting axes moment values, on local sdr x-y-z
            mx = -m2;
            my = -m1;
            mPrinc1 = mx * cosAlfaXTo1 + my * senAlfaXTo1;
            mPrinc2 = -mx * senAlfaXTo1 + my * cosAlfaXTo1;
            // Moving to straus conventions
            m1 = mPrinc2;
            m2 = -mPrinc1;
            // Shear
            vx = -t2;
            vy = t1;
            vPrinc1 = vx * cosAlfaXTo1 + vy * senAlfaXTo1;
            vPrinc2 = -vx * senAlfaXTo1 + vy * cosAlfaXTo1;
            t1 = -vPrinc1;
            t2 = -vPrinc2;
            if (NeedRotate180(bpm))
            {
                m1 *= -1;
                m2 *= -1;
                t1 *= -1;
                t2 *= -1;
            }
        }

        public static void ConvertStressesToSAP2000(BeamModel beam, ref double m1To3, ref double m2To2, ref double t1To3, ref double t2To2)
        {
            ConvertStressesToSAP2000(beam.BeamProperty, ref m1To3, ref m2To2, ref t1To3, ref t2To2);
        }

        public static void ConvertStressesToSAP2000(BeamPropertyModel bpm, ref double m1To3, ref double m2To2, ref double t1To3, ref double t2To2)
        {
            double cosAlfa1ToX = Math.Cos(-bpm.AngleX1Rad);
            double senAlfa1ToX = Math.Sin(-bpm.AngleX1Rad);
            double mPrinc1, mPrinc2, vx, vy, vPrinc1, vPrinc2, mx, my;

            // Getting axes moment values, on local sdr x-y-z
            mPrinc1 = -m2To2;
            mPrinc2 = m1To3;
            if (NeedRotate180(bpm))
            {
                mPrinc1 *= -1;
                mPrinc2 *= -1;
            }
            mx = mPrinc1 * cosAlfa1ToX + mPrinc2 * senAlfa1ToX;
            my = -mPrinc1 * senAlfa1ToX + mPrinc2 * cosAlfa1ToX;
            //Moving to sap conventions
            m1To3 = -mx;
            m2To2 = -my;

            // Shear
            vPrinc1 = -t1To3;
            vPrinc2 = -t2To2;
            if (NeedRotate180(bpm))
            {
                vPrinc1 *= -1;
                vPrinc2 *= -1;
            }
            vx = vPrinc1 * cosAlfa1ToX + vPrinc2 * senAlfa1ToX;
            vy = -vPrinc1 * senAlfa1ToX + vPrinc2 * cosAlfa1ToX;
            t1To3 = -vx;
            t2To2 = vy;
        }

        public static int ConvertDirectionToSap(int dir_straus, bool absolute = true)
        {
            int dir_sap = -1;
            if (dir_straus == 3)
            {
                dir_sap = 1;
            }
            else if (dir_straus == 2)
            {
                dir_sap = 2;
            }
            else if (dir_straus == 1)
            {
                dir_sap = -3;
            }
            else if (dir_straus == 6)
            {
                dir_sap = 4;
            }
            else if (dir_straus == 5)
            {
                dir_sap = 5;
            }
            else if (dir_straus == 4)
            {
                dir_sap = -6;
            }

            if (absolute == true)
            {
                return Math.Abs(dir_sap);
            }
            else
            {
                return dir_sap;
            }
        }

        public static int ConvertDirectionToStrauss(int dir_sap, bool absolute = true)
        {
            int dir_strauss = -1;
            if (dir_sap == 1)
            {
                dir_strauss = 3;
            }
            else if (dir_sap == 2)
            {
                dir_strauss = 2;
            }
            else if (dir_sap == 3)
            {
                dir_strauss = 1;
            }
            else if (dir_sap == 4)
            {
                dir_strauss = 6;
            }
            else if (dir_sap == 5)
            {
                dir_strauss = 5;
            }
            else if (dir_sap == 6)
            {
                dir_strauss = -4;
            }

            if (absolute == true)
            {
                return Math.Abs(dir_strauss);
            }
            else
            {
                return dir_strauss;
            }
        }

        public static bool InitializeModel(bool newIstance, string sapExe, string sapModel, out cOAPI mySapObject, out cSapModel mySapModel, out cHelper myHelper)
        {
            ExternalProgram.CSIComObjects.InizializeSAPModel(out mySapModel, out mySapObject, out myHelper, !newIstance, sapModel, eUnits.N_mm_C, true);
            return true;
        }
    }
}
303 files24 directories