using SAP2000v1;
using FeMM.Grasshopper.Helpers;
using Grasshopper.Kernel;
using Grasshopper.Kernel.Types;
using Rhino;
using Rhino.DocObjects;
using Rhino.Geometry;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Versioning;
namespace FeMM.Grasshopper.Components.F2R
{
#if NETCOREAPP
[SupportedOSPlatform("windows")]
#endif
public class SAPJoinBeamsComponent : GH_Component
{
private bool _run = false;
/// <summary>
/// Initializes a new instance of the MyComponent1 class.
/// </summary>
public SAPJoinBeamsComponent()
: base("Join F2R Beam", "JB", "Join the selected beams in SAP2000", CategoryNameConstants.CATEGORY_F2R, CategoryNameConstants.SUBCATEGORY_F2R_INTERACTIVESAP)
{
}
public override void CreateAttributes()
{
var buttonAttributes = new ComponentAttributes.ComponentOneButtonAttributes(this, "Join");
buttonAttributes.ButtonPressed += () =>
{
_run = true;
ExpireSolution(true);
};
m_attributes = buttonAttributes;
}
/// <summary>
/// Registers all the input parameters for this component.
/// </summary>
protected override void RegisterInputParams(GH_InputParamManager pManager)
{
pManager.AddTextParameter("Model Path", "MP", "Sap2000 model path to open. If empty it will open an empty file", GH_ParamAccess.item, "");
pManager[0].Optional = true;
pManager.AddBooleanParameter("Attach to Instance", "AI", "Attach to instance. If true, 'model path' will be ignored", GH_ParamAccess.item, false);
pManager[1].Optional = true;
pManager.AddGeometryParameter("Beams", "B", "F2R curve to split", GH_ParamAccess.list);
pManager.AddTextParameter("New names", "NN", "The new beams names", GH_ParamAccess.list);
pManager[3].Optional = true;
}
/// <summary>
/// Registers all the output parameters for this component.
/// </summary>
protected override void RegisterOutputParams(GH_OutputParamManager pManager)
{
}
/// <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)
{
string modelPath = "";
bool attachToInstance = false;
var elements = new List<IGH_GeometricGoo>();
var names = new List<string>();
//input
DA.GetData(0, ref modelPath);
DA.GetData(1, ref attachToInstance);
if (!DA.GetDataList(2, elements))
return;
DA.GetDataList(3, names);
if (_run)
{
if (!System.IO.File.Exists(modelPath) && !attachToInstance) // model path non valido, Se path modello non valido fa partire con stringa vuota (file vuoto)
{
modelPath = string.Empty;
AddRuntimeMessage(GH_RuntimeMessageLevel.Warning, "Sap model path not valid, opening an empty file");
_run = false;
}
if (elements.Count == 0)
{
AddRuntimeMessage(GH_RuntimeMessageLevel.Error, "No elements selected");
_run = false;
}
try
{
cSapModel sapModel = F2RModelHelper.GetSapModel(out cOAPI sapObject, modelPath, attachToInstance);
sapModel.SelectObj.ClearSelection();
RhinoDoc doc = RhinoDoc.ActiveDoc;
var nodeBeamsAssociation = new Dictionary<string, List<string>>();
var nodePosAss = new Dictionary<string, Point3d>();
var beamNodesAss = new Dictionary<string, (string, string)>();
int numbBeams = 0;
string[] beamNames = [];
sapModel.FrameObj.GetNameList(ref numbBeams, ref beamNames);
var elemToJoinId = new List<string>();
for (int i = 0; i < elements.Count; i++)
{
Guid guid = elements[i].ReferenceID;
if (guid != Guid.Empty)
{
RhinoObject rhinoObj = doc.Objects.FindId(guid);
if (rhinoObj != null)
{
string id = rhinoObj.Attributes.GetUserString("F2R_ID");
if (rhinoObj.GetType() == typeof(CurveObject))
{
elemToJoinId.Add(id);
string pt1 = string.Empty;
string pt2 = string.Empty;
sapModel.FrameObj.GetPoints(id, ref pt1, ref pt2);
beamNodesAss.Add(id, (pt1, pt2));
if (!nodeBeamsAssociation.ContainsKey(pt1))
nodeBeamsAssociation.Add(pt1, []);
if (!nodeBeamsAssociation.ContainsKey(pt2))
nodeBeamsAssociation.Add(pt2, []);
nodeBeamsAssociation[pt1].Add(id);
nodeBeamsAssociation[pt2].Add(id);
}
else
{
AddRuntimeMessage(GH_RuntimeMessageLevel.Warning, $"Element n° {i} with ID: {id} is not a curve");
}
}
else
{
AddRuntimeMessage(GH_RuntimeMessageLevel.Warning, $"Element n° {i} don't exist in Rhino");
}
}
else
{
AddRuntimeMessage(GH_RuntimeMessageLevel.Warning, $"Element {i} don't have a valid GUID");
}
}
foreach (string node in nodeBeamsAssociation.Keys)
{
double x = 0;
double y = 0;
double z = 0;
sapModel.PointObj.GetCoordCartesian(node, ref x, ref y, ref z);
var point3D = new Point3d(x, y, z);
nodePosAss.Add(node, point3D);
}
var beamNameClone = new List<string>();
for (int i = 0; i < elemToJoinId.Count; i++)
beamNameClone.Add(elemToJoinId[i]);
var newBeamsName = new Dictionary<string, string>();
var testedBeams = new HashSet<(string, string)>();
foreach (KeyValuePair<string, List<string>> kvp in nodeBeamsAssociation)
{
string node = kvp.Key;
List<string> beams = kvp.Value;
if (beams.Count > 1)
{
for (int i = 0; i < beams.Count; i++)
{
for (int j = 0; j < beams.Count; j++)
{
if (i != j)
{
try
{
string startBeamName = beams[j];
string beamToMergeName = beams[i];
if (newBeamsName.ContainsKey(beams[i]))
beamToMergeName = newBeamsName[beams[i]];
if (newBeamsName.ContainsKey(beams[j]))
startBeamName = newBeamsName[beams[j]];
if (!testedBeams.Contains((startBeamName, beamToMergeName)))
{
(string, string) nodeStartBeam = beamNodesAss[startBeamName];
(string, string) nodeEndBeam = beamNodesAss[beamToMergeName];
Vector3d dir1 = nodePosAss[nodeStartBeam.Item1] - nodePosAss[nodeStartBeam.Item2];
Vector3d dir2 = nodePosAss[nodeEndBeam.Item1] - nodePosAss[nodeEndBeam.Item2];
dir1.Unitize();
dir2.Unitize();
double dotProduct = dir1 * dir2;
if (Math.Abs(dotProduct - 1) > 1E-4 && Math.Abs(dotProduct + 1) > 1E-4)
{
testedBeams.Add((startBeamName, beamToMergeName));
testedBeams.Add((beamToMergeName, startBeamName));
continue;
}
if (sapModel.EditFrame.Join(startBeamName, beamToMergeName) == 0)
{
sapModel.FrameObj.GetNameList(ref numbBeams, ref beamNames);
beamNameClone.Remove(startBeamName);
beamNameClone.Remove(beamToMergeName);
if (beamNames.Contains(startBeamName))
{
beamNameClone.Add(startBeamName);
newBeamsName.Add(beamToMergeName, startBeamName);
}
else
{
beamNameClone.Add(beamToMergeName);
newBeamsName.Add(startBeamName, beamToMergeName);
}
beams.RemoveAt(j);
j--;
testedBeams.Add((startBeamName, beamToMergeName));
testedBeams.Add((beamToMergeName, startBeamName));
}
else
{
testedBeams.Add((startBeamName, beamToMergeName));
testedBeams.Add((beamToMergeName, startBeamName));
}
}
}
catch
{
continue;
}
}
}
}
}
//startBeam++;
}
if (names.Count > 0)
{
for (int j = 0; j < names.Count; j++)
{
//sapModel.FrameObj.ChangeName(newName[j], name);
}
}
if (attachToInstance)
sapModel.View.RefreshView();
if (!attachToInstance)
sapObject.ApplicationExit(true);
_run = false;
}
catch (Exception)
{
AddRuntimeMessage(GH_RuntimeMessageLevel.Error, "Generic error");
_run = false;
}
}
}
protected override System.Drawing.Bitmap Icon => Properties.Resources.F2RSplitBeamIcon;
public override Guid ComponentGuid => new("c39b54bf-8057-4d81-98ce-3f8140401ac9");
}
}