using FeMM.Grasshopper.Helpers;
using Grasshopper.Kernel;
using Grasshopper.Kernel.Types;
using Rhino.Geometry;
using System;
using System.Collections.Generic;
namespace FeMM.Grasshopper.Components.Patterning
{
public class SplitMeshOnCurvesComponent : GH_Component
{
/// <summary>
/// Initializes a new instance of the SplitMeshOnCurvesComponent class.
/// </summary>
public SplitMeshOnCurvesComponent()
: base("Split Mesh On Curves", "SM", "Splits a mesh on the given curves", 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", GH_ParamAccess.item);
pManager.AddCurveParameter("Geodesics", "G", "The geodesics lines for cutting the mesh", GH_ParamAccess.list);
pManager.AddNumberParameter("Extend", "E", "Extend the lines endings of the given amount", GH_ParamAccess.item, 10.0);
pManager.AddNumberParameter("Height", "H", "Height of the cutters used to make the cut", GH_ParamAccess.item, 100.0);
pManager.AddVectorParameter("Direction", "D", "Direction in wich to raise the cutter", GH_ParamAccess.item, Vector3d.ZAxis);
}
/// <summary>
/// Registers all the output parameters for this component.
/// </summary>
protected override void RegisterOutputParams(GH_OutputParamManager pManager)
{
pManager.AddMeshParameter("Panels", "P", "The resulting panels", GH_ParamAccess.list);
pManager.AddMeshParameter("Cutters", "C", "The cutters used to make the cut", 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;
var geodesics = new List<GH_Curve>();
double extend = 10.0;
double height = 100.0;
Vector3d direction = Vector3d.ZAxis;
if (!DA.GetData(0, ref mesh))
return;
if (!DA.GetDataList(1, geodesics))
return;
DA.GetData(2, ref extend);
DA.GetData(3, ref height);
DA.GetData(4, ref direction);
Curve[] geodesicCurves = new Curve[geodesics.Count];
Mesh[] panels;
Mesh[] cutters;
for (int i = 0; i < geodesics.Count; i++)
{
geodesicCurves[i] = geodesics[i].Value;
}
try
{
(panels, cutters) = CutMesh2(mesh.Value, [.. geodesicCurves], direction, extend, height);
}
catch (Exception e)
{
AddRuntimeMessage(GH_RuntimeMessageLevel.Error, e.Message);
panels = null;
cutters = null;
}
DA.SetDataList(0, panels);
DA.SetDataList(1, cutters);
}
public static (Mesh[], Mesh[]) CutMesh2(Mesh mesh, Curve[] geodesics, Vector3d dir, double extend = 10, double height = 100)
{
Vector3d up = Vector3d.Multiply(dir, height);
Vector3d down = Vector3d.Multiply(dir, -height);
Mesh bufferMesh = mesh.DuplicateMesh();
var cutters = new List<Mesh>();
var toMesh = new Vector3d(bufferMesh.GetBoundingBox(false).Center);
var toOrigin = toMesh;
toOrigin.Reverse();
bufferMesh.Translate(toOrigin);
for (int i = 0; i < geodesics.Length; ++i)
{
var curveA = geodesics[i].DuplicateCurve();
if (extend > 0)
{
curveA = curveA.Extend(CurveEnd.Both, extend, CurveExtensionStyle.Line);
}
curveA.Translate(toOrigin);
var curveB = curveA.DuplicateCurve();
curveA.Translate(up);
curveB.Translate(down);
var lofts = Brep.CreateFromLoft(new List<Curve>() { curveA, curveB }, Point3d.Unset, Point3d.Unset, LoftType.Straight, false);
for (int j = 0; j < lofts.Length; ++j)
{
cutters.AddRange(Mesh.CreateFromBrep(lofts[j], MeshingParameters.Minimal));
}
}
var meshes = bufferMesh.Split(cutters);
for (int i = 0; i < meshes.Length; ++i)
{
meshes[i].Translate(toMesh);
}
for (int i = 0; i < cutters.Count; ++i)
{
cutters[i].Translate(toMesh);
}
return (meshes, cutters.ToArray());
}
public override GH_Exposure Exposure => GH_Exposure.tertiary;
/// <summary>
/// Provides an Icon for the component.
/// </summary>
protected override System.Drawing.Bitmap Icon => Properties.Resources.SplitMeshOnCurvesIcon;
/// <summary>
/// Gets the unique ID for this component. Do not change this ID after release.
/// </summary>
public override Guid ComponentGuid => new("6413cd87-824b-484f-89b4-115f928f96fd");
}
}