using FeMM.Common.Models;
using FeMM.Grasshopper.DataTypes.FeMM;
using FeMM.Grasshopper.Helpers;
using Grasshopper.Kernel;
using Rhino.Geometry;
using System;
using System.Collections.Generic;

namespace FeMM.Grasshopper.Components.Sections
{
    public class BeamSectionBrepComponent : GH_Component
    {
        /// <summary>
        /// Initializes a new instance of the BeamSectionCComponent class.
        /// </summary>
        public BeamSectionBrepComponent()
          : base("Brep Section", "BS", "Defines a section composed by brep faces", CategoryNameConstants.CATEGORY_FEMM, CategoryNameConstants.SUBCATEGORY_SECTIONS)
        {
        }

        /// <summary>
        /// Registers all the input parameters for this component.
        /// </summary>
        protected override void RegisterInputParams(GH_InputParamManager pManager)
        {
            pManager.AddBrepParameter("Breps", "Bs", "Breps with only one face coplanar", GH_ParamAccess.list);
        }

        /// <summary>
        /// Registers all the output parameters for this component.
        /// </summary>
        protected override void RegisterOutputParams(GH_OutputParamManager pManager)
        {
            pManager.AddGenericParameter("Section", "S", "The brep section", GH_ParamAccess.item);
        }

        /// <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)
        {
            List<Brep> breps = [];
            if (!DA.GetDataList(0, breps)) return;

            //Test that all brep faces are coplanar
            Vector3d normal = Vector3d.Unset;

            List<Maffeis.Geometry.Shape2d> shapesList = [];
            for (int j = 0; j < breps.Count; j++)
            {
                Brep b = breps[j];
                foreach (BrepFace bf in b.Faces)
                {
                    if (!bf.IsPlanar())
                    {
                        AddRuntimeMessage(GH_RuntimeMessageLevel.Error, "Brep faces must be planar");
                        return;
                    }
                    if (normal == Vector3d.Unset)
                    {
                        normal = bf.NormalAt(0, 0);
                        normal.Unitize();
                    }
                    else
                    {
                        Vector3d faceNorm = bf.NormalAt(0, 0);
                        faceNorm.Unitize();
                        if (Math.Abs(faceNorm * normal) < 0.999)
                        {
                            AddRuntimeMessage(GH_RuntimeMessageLevel.Error, "Brep faces must be coplanar");
                        }
                    }
                }

                Transform tr = Transform.PlaneToPlane(new Plane(Point3d.Origin, normal), Plane.WorldXY);

                foreach (BrepFace bf in b.Faces)
                {
                    if (!bf.OuterLoop.To3dCurve().TryGetPolyline(out Polyline pl))
                    {
                        AddRuntimeMessage(GH_RuntimeMessageLevel.Error, "Brep loops must be polylines");
                        return;
                    }
                    int lastIndex = pl.IsClosed ? pl.Count - 1 : pl.Count;
                    Maffeis.Geometry.Polygon2d fill = [];
                    for (int i = 0; i < lastIndex; i++)
                    {
                        var local = new Point3d(pl[i]);
                        local.Transform(tr);
                        fill.Add(local.X, local.Y);
                    }
                    List<Maffeis.Geometry.Polygon2d> holes = null;
                    foreach (BrepLoop bl in bf.Loops)
                    {
                        if (bl != bf.OuterLoop)
                        {
                            //is an hole
                            Maffeis.Geometry.Polygon2d hole;
                            if (!bl.To3dCurve().TryGetPolyline(out pl))
                            {
                                AddRuntimeMessage(GH_RuntimeMessageLevel.Error, "Brep loops must be polylines");
                                return;
                            }
                            lastIndex = pl.IsClosed ? pl.Count - 1 : pl.Count;
                            hole = [];
                            for (int i = 0; i < lastIndex; i++)
                            {
                                var local = new Point3d(pl[i]);
                                local.Transform(tr);
                                hole.Add(local.X, local.Y);
                            }
                            holes ??= [];
                            holes.Add(hole);
                        }
                    }
                    shapesList.Add(new Maffeis.Geometry.Shape2d(fill, holes?.ToArray()));
                }
            }

            if (shapesList.Count > 0)
            {
                var sectionModel = new SectionModel()
                {
                    SectionType = SectionModel.SectionTypes.GenericShapes,
                    GenericShapes = new Common.Geometry.Shapes(shapesList)
                };

                sectionModel.CalculateSection();

                var section = new GH_BeamSection(sectionModel);

                DA.SetData(0, section);
            }
        }

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

        /// <summary>
        /// Gets the unique ID for this component. Do not change this ID after release.
        /// </summary>
        public override Guid ComponentGuid => new("348FB5B1-671C-4FD5-B409-8C241761DBF1");
    }
}
303 files24 directories