using FeMM.Grasshopper.Helpers;
using Grasshopper.Kernel;
using Grasshopper.Kernel.Types;
using Rhino;
using Rhino.Geometry;
using Rhino.Geometry.Intersect;
using System;
using System.Collections.Generic;
using System.Linq;

namespace FeMM.Grasshopper.Components.Patterning
{
    public class MeshDivideComponent : GH_Component
    {
        /// <summary>
        /// Initializes a new instance of the MeshDivideComponent class.
        /// </summary>
        public MeshDivideComponent()
          : base("Mesh Divide", "MD", "Divide a mesh generating geodesics curve", CategoryNameConstants.CATEGORY_FEMM, CategoryNameConstants.SUBCATEGORY_PATTERNING)
        {
        }

        /// <summary>
        /// Registers all the input parameters for this component.
        /// </summary>
        protected override void RegisterInputParams(GH_InputParamManager pManager)
        {
            pManager.AddMeshParameter("Mesh", "M", "The mesh to divide", GH_ParamAccess.item);
            pManager.AddIntegerParameter("Number", "N", "The number of parts to divide", GH_ParamAccess.item);
            pManager.AddNumberParameter("Rotation", "D", "The rotation angle in degrees", GH_ParamAccess.item, 0);
            pManager.AddNumberParameter("Resolution", "R", "The resolution for generating the geodesics lines", GH_ParamAccess.item, 0);
            pManager.AddIntegerParameter("Iterations", "I", "The number of iteration for the geodesic calculation", GH_ParamAccess.item, 1000);
        }

        /// <summary>
        /// Registers all the output parameters for this component.
        /// </summary>
        protected override void RegisterOutputParams(GH_OutputParamManager pManager)
        {
            pManager.AddCurveParameter("Geodesics", "G", "The resulting geodesics curves", GH_ParamAccess.list);
        }

        /// <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)
        {
            GH_Mesh mesh = null;
            int numb = 0;
            double ang = 0;
            double res = 0;
            int steps = 0;

            if (!DA.GetData(0, ref mesh))
                return;
            if (!DA.GetData(1, ref numb))
                return;
            DA.GetData(2, ref ang);
            DA.GetData(3, ref res);
            if (!DA.GetData(4, ref steps))
                return;

            ang = RhinoMath.ToRadians(ang);

            // Find the rotated reference vectors
            BoundingBox bb = mesh.Value.GetBoundingBox(true);
            var rect = new Polyline
            {
                bb.Min,
                { bb.Max.X, bb.Min.Y, 0 },
                { bb.Max.X, bb.Max.Y, 0 },
                { bb.Min.X, bb.Max.Y, 0 },
                bb.Min
            };
            Transform xform = Transform.Rotation(ang, bb.Min);
            rect.Transform(xform);
            Point3d o = rect.BoundingBox.Min;
            var v_x = new Vector3d(rect.BoundingBox.Max.X - rect.BoundingBox.Min.X, 0, 0);
            var v_y = new Vector3d(0, rect.BoundingBox.Max.Y - rect.BoundingBox.Min.Y, 0);

            xform = Transform.Rotation(-ang, bb.Min);
            o.Transform(xform);
            v_x.Transform(xform);
            v_y.Transform(xform);

            if (res == 0)
                res = v_x.Length / 10.0;
            double stepsize = 0.5;

            var curves = new List<Curve>();
            Vector3d v = v_x;
            v.Unitize();
            double step = v_x.Length / numb;
            Brep b = Brep.CreateFromMesh(mesh.Value, true);

            for (int i = 1; i < numb; i++)
            {
                Point3d p1 = o + v * (step * i);
                Point3d p2 = p1 + v_y;

                var plane = new Plane(p1, v_y, Vector3d.ZAxis);
                Polyline[] pls = Intersection.MeshPlane(mesh.Value, plane);
                foreach (Polyline pl in pls)
                {
                    var line = new Line(pl.First(), pl.Last);
                    Common.Geometry.MeshGeodesic mg =
                        new(mesh.Value, pl.First(), pl.Last, res, stepsize, steps);
                    curves.Add(MeshGeodesicComponent.ProjectPolylineToMesh(mg.Polyline, mesh.Value));
                }
            }

            DA.SetDataList(0, curves);
        }

        public override GH_Exposure Exposure => GH_Exposure.secondary;

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

        /// <summary>
        /// Gets the unique ID for this component. Do not change this ID after release.
        /// </summary>
        public override Guid ComponentGuid => new("065060c5-cde9-489f-a9d4-348447b3be1f");
    }
}
303 files24 directories