using FeMM.Common.Models;
using FeMM.Grasshopper.DataTypes.FeMM;
using FeMM.Grasshopper.Helpers;
using Grasshopper.Kernel;
using Grasshopper.Kernel.Special;
using Rhino.Geometry;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Versioning;
namespace FeMM.Grasshopper.Components.Results
{
#if NETCOREAPP
[SupportedOSPlatform("windows")]
#endif
public class DisplacementModelComponent : GH_Component
{
/// <summary>
/// Initializes a new instance of the DecomposeModelComponent class.
/// </summary>
public DisplacementModelComponent()
: base("Displacement Model", "DM", "Apply the displacements to a FEMM model", CategoryNameConstants.CATEGORY_FEMM, CategoryNameConstants.SUBCATEGORY_RESULTS)
{
}
/// <summary>
/// Registers all the input parameters for this component.
/// </summary>
protected override void RegisterInputParams(GH_InputParamManager pManager)
{
pManager.AddGenericParameter("Model", "M", "The FEM model", GH_ParamAccess.item);
int n = pManager.AddTextParameter("Analysis Results", "AR", "The analysis result cases or combination to returns", GH_ParamAccess.item);
pManager[n].Optional = true;
n = pManager.AddTextParameter("StepType", "ST", "The analysis result cases or combination to returns", GH_ParamAccess.item, "1");
pManager[n].Optional = true;
n = pManager.AddTextParameter("Step Num", "SN", "The analysis result cases or combination to returns", GH_ParamAccess.item, "");
pManager[n].Optional = true;
pManager.AddNumberParameter("Scale Factor", "SF", "The scale factor multiplier", GH_ParamAccess.item, 1);
}
/// <summary>
/// Registers all the output parameters for this component.
/// </summary>
protected override void RegisterOutputParams(GH_OutputParamManager pManager)
{
pManager.AddGenericParameter("Model", "M", "The displaced model", 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)
{
GH_Model model = null;
double multipl = 1;
if (!DA.GetData("Model", ref model))
return;
if (model.Value == null)
return;
CaseModel[] cases = [.. model.Value.Elements.SelectMany(e => e.Results).Select(l => l.LoadCase)];
double[] stepNums = [.. model.Value.Elements.SelectMany(e => e.Results).Select(l => l.StepNum)];
string[] stepTypes = [.. model.Value.Elements.SelectMany(e => e.Results).Select(l => l.StepType)];
// Connect the ValueList component on the analysis results input item
IGH_Param[] keys_analysisResultLists = [.. Params.Input[1].Sources.Where(s => s.GetType() == typeof(GH_ValueList))];
for (int i = 0; i < keys_analysisResultLists.Length; i++)
{
GH_ValueList vallist = (GH_ValueList)keys_analysisResultLists[i];
if (vallist.ListMode != GH_ValueListMode.CheckList)
vallist.ListMode = GH_ValueListMode.CheckList;
List<string> names = [.. cases.Select(lc => lc.Name).Distinct()];
ComponentsHelper.SetValueList(vallist, names);
vallist.NickName = "Results";
}
if (keys_analysisResultLists.Length > 1)
{
AddRuntimeMessage(GH_RuntimeMessageLevel.Error, "Only one case can be selected");
return;
}
IGH_Param[] keys_stepNumList = [.. Params.Input[2].Sources.Where(s => s.GetType() == typeof(GH_ValueList))];
for (int i = 0; i < keys_stepNumList.Length; i++)
{
GH_ValueList vallist = (GH_ValueList)keys_stepNumList[i];
if (vallist.ListMode != GH_ValueListMode.CheckList)
vallist.ListMode = GH_ValueListMode.CheckList;
List<string> names = [.. stepTypes.Select(lc => lc).Distinct()];
ComponentsHelper.SetValueList(vallist, names);
vallist.NickName = "Step Type";
}
if (keys_stepNumList.Length > 1)
{
AddRuntimeMessage(GH_RuntimeMessageLevel.Error, "Only one step type can be selected");
return;
}
IGH_Param[] keys_stepTypeList = [.. Params.Input[3].Sources.Where(s => s.GetType() == typeof(GH_ValueList))];
for (int i = 0; i < keys_stepTypeList.Length; i++)
{
GH_ValueList vallist = (GH_ValueList)keys_stepTypeList[i];
if (vallist.ListMode != GH_ValueListMode.CheckList)
vallist.ListMode = GH_ValueListMode.CheckList;
List<string> names = [.. stepNums.Select(lc => lc.ToString()).Distinct()];
ComponentsHelper.SetValueList(vallist, names);
vallist.NickName = "Step Num";
}
if (keys_stepTypeList.Length > 1)
{
AddRuntimeMessage(GH_RuntimeMessageLevel.Error, "Only one step num can be selected");
return;
}
string selectedCase = "";
string stepNum = "";
string stepType = "";
if (!DA.GetData(1, ref selectedCase))
return;
DA.GetData(2, ref stepType);
DA.GetData(3, ref stepNum);
DA.GetData(4, ref multipl);
ModelModel cloneModel = (ModelModel)model.Value.Clone();
var oldNewPointMap = new Dictionary<Point3d, Point3d>();
for (int i = 0; i < cloneModel.Nodes.Count; i++)
{
NodeModel node = cloneModel.Nodes[i];
NodeDisplResultModel displ = null;
List<NodeDisplResultModel> res = [.. node.Results.Where(k => k is NodeDisplResultModel).Where(j => j.LoadCase.Name == selectedCase).Select(j => (NodeDisplResultModel)j)];
if (res != null)
{
if (res.Count > 1)
{
if (!int.TryParse(stepNum, out int stp))
stp = 1;
List<NodeDisplResultModel> list = [.. res.Where(j => j.StepNum == stp)];
if (list.Count != 0)
{
if (list.Count > 1)
displ = list.Where(k => k.StepType == stepType).FirstOrDefault();
else
displ = list.FirstOrDefault();
}
else
{
displ = res.Where(j => j.StepType == stepType).FirstOrDefault();
}
}
else
displ = res.FirstOrDefault();
if (displ != null)
{
Point3d newPoint = node.Position + displ.Displacement * multipl;
oldNewPointMap.Add(node.Position, newPoint);
node.Position = newPoint;
}
}
}
for (int i = 0; i < cloneModel.Beams.Count; i++)
{
BeamModel beam = cloneModel.Beams[i];
beam.PointFrom = oldNewPointMap[beam.PointFrom];
beam.PointTo = oldNewPointMap[beam.PointTo];
}
for (int i = 0; i < cloneModel.Links.Count; i++)
{
LinkModel link = cloneModel.Links[i];
link.PointFrom = oldNewPointMap[link.PointFrom];
link.PointTo = oldNewPointMap[link.PointTo];
}
for (int i = 0; i < cloneModel.Plates.Count; i++)
{
PlateModel plate = cloneModel.Plates[i];
for (int j = 0; j < plate.Points.Count; j++)
plate.Points[j] = oldNewPointMap[plate.Points[j]];
}
var nodes = new List<GH_Node>();
var beams = new List<GH_Beam>();
var plates = new List<GH_Plate>();
var links = new List<GH_Link>();
try
{
for (int i = 0; i < model.Value.Nodes.Count; i++)
{
NodeModel node = model.Value.Nodes[i];
NodeModel newnode = cloneModel.Nodes[i];
nodes.Add(new GH_Node(newnode, model.Guids[node]));
}
for (int i = 0; i < model.Value.Beams.Count; i++)
{
BeamModel beam = model.Value.Beams[i];
BeamModel newbeam = cloneModel.Beams[i];
beams.Add(new GH_Beam(newbeam, model.Guids[beam]));
}
for (int i = 0; i < model.Value.Links.Count; i++)
{
var link = model.Value.Links[i];
var newLink = cloneModel.Links[i];
links.Add(new GH_Link(newLink, model.Guids[link]));
}
for (int i = 0; i < model.Value.Plates.Count; i++)
{
PlateModel plate = model.Value.Plates[i];
PlateModel newplate = cloneModel.Plates[i];
plates.Add(new GH_Plate(newplate, model.Guids[plate]));
}
}
catch (Exception e)
{
AddRuntimeMessage(GH_RuntimeMessageLevel.Error, e.Message);
}
DA.SetData(0, new GH_Model(model.Value.Units, nodes, beams, plates, links, [], []));
}
public override GH_Exposure Exposure => GH_Exposure.tertiary;
/// <summary>
/// Provides an Icon for the component.
/// </summary>
protected override System.Drawing.Bitmap Icon => Properties.Resources.DeformedModelIcon;
/// <summary>
/// Gets the unique ID for this component. Do not change this ID after release.
/// </summary>
public override Guid ComponentGuid => new("c934e5ca-e120-4b41-a757-2649fcbc7d52");
}
}