using FeMM.Common.Helpers;
using FeMM.Common.Models;
using FeMM.Grasshopper.Helpers;
using GH_IO.Serialization;
using Grasshopper.Kernel;
using Grasshopper.Kernel.Parameters;
using Grasshopper.Kernel.Types;
using Rhino.Geometry;
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Runtime.Versioning;
using System.Text;
using Rh = Rhino;
namespace FeMM.Grasshopper.Components.Tools
{
#if NETCOREAPP
[SupportedOSPlatform("windows")]
#endif
public class SurfaceMeshComponent : GH_Component
{
protected List<string> _output;
protected List<string> _errors;
protected List<string> _warnings;
protected bool _justCompleted;
private bool _run;
private bool _isRunning; // true if the st7Mesh in running in background
private List<Mesh> _meshes;
public SurfaceMeshComponent()
: base("Surface mesh", "SM", "Create a mesh with Straus7 AutoMesh", CategoryNameConstants.CATEGORY_FEMM, CategoryNameConstants.SUBCATEGORY_TOOLS)
{
_output = [];
_errors = [];
_warnings = [];
_meshes = null;
_run = false;
}
public override void CreateAttributes()
{
var attr = new ComponentAttributes.ComponentOneButtonAttributes(this, "Run");
attr.ButtonPressed += () =>
{
_run = true;
ExpireSolution(true);
};
m_attributes = attr;
}
protected override void RegisterInputParams(GH_InputParamManager pManager)
{
pManager.AddSurfaceParameter("Surfaces", "Ss", "The surface to mesh", GH_ParamAccess.list);
pManager.AddIntegerParameter("Units", "U", "The measure units", GH_ParamAccess.item, 2);
int i = 0;
foreach (ModelModel.ModelUnits name in Enum.GetValues(typeof(ModelModel.ModelUnits)))
((Param_Integer)pManager[pManager.ParamCount - 1]).AddNamedValue(name.GetDescription(), i++);
pManager.AddIntegerParameter("CleanGeometryToleranceType", "TT", "Clean geometry tolerance type", GH_ParamAccess.item, 0);
((Param_Integer)pManager[pManager.ParamCount - 1]).AddNamedValue("Relative", 0);
((Param_Integer)pManager[pManager.ParamCount - 1]).AddNamedValue("Absolute", 1);
pManager.AddNumberParameter("CleanGeometryEdgeMergeAngle", "EMA", "Clean geometry merging angle for adjacent edges", GH_ParamAccess.item, 160);
pManager.AddNumberParameter("CleanGeometryFeatureLength", "FL", "Clean geometry feature length", GH_ParamAccess.item, 0.0005);
pManager.AddIntegerParameter("MeshMode", "MM", "Meshing mode, either Auto or Custom", GH_ParamAccess.item, 0);
((Param_Integer)pManager[pManager.ParamCount - 1]).AddNamedValue("Auto", 0);
((Param_Integer)pManager[pManager.ParamCount - 1]).AddNamedValue("Custom", 1);
pManager.AddIntegerParameter("SizeMode", "SM", "Mesh size option, either Percentage or Absolute", GH_ParamAccess.item, 1);
((Param_Integer)pManager[pManager.ParamCount - 1]).AddNamedValue("Percentage", 0);
((Param_Integer)pManager[pManager.ParamCount - 1]).AddNamedValue("Absolute", 1);
pManager.AddIntegerParameter("Target Element", "TE", "Number of nodes in target element; one of 3, 4, 6 or 8", GH_ParamAccess.item, 4);
((Param_Integer)pManager[pManager.ParamCount - 1]).AddNamedValue("3", 3);
((Param_Integer)pManager[pManager.ParamCount - 1]).AddNamedValue("4", 4);
((Param_Integer)pManager[pManager.ParamCount - 1]).AddNamedValue("6", 6);
((Param_Integer)pManager[pManager.ParamCount - 1]).AddNamedValue("8", 8);
pManager.AddBooleanParameter("ApplyTransitioning", "T", "Apply edge transitioning when placing boundary nodes", GH_ParamAccess.item, true);
pManager.AddNumberParameter("MeshSize", "MS", "Mesh size, scaled based on SizeMode", GH_ParamAccess.item);
pManager.AddNumberParameter("LengthRatio", "LR", "Maximum allowable ratio between the largest and smallest edge on each face", GH_ParamAccess.item, 0.1);
pManager.AddNumberParameter("MaximumIncrease", "MI", "Rate of increase in edge length between neighbouring elements, in the range 0 to 1", GH_ParamAccess.item, 0.40);
pManager.AddIntegerParameter("CleanMeshToleranceType", "TT", "Clean mesh tolerance type", GH_ParamAccess.item, 0);
((Param_Integer)pManager[pManager.ParamCount - 1]).AddNamedValue("Relative", 0);
((Param_Integer)pManager[pManager.ParamCount - 1]).AddNamedValue("Absolute", 1);
pManager.AddNumberParameter("CleanMeshTolerance", "CMT", "Zip tolerance", GH_ParamAccess.item, 0.0001);
pManager.AddBooleanParameter("Always Run", "AR", "Always run", GH_ParamAccess.item, false);
}
protected override void RegisterOutputParams(GH_OutputParamManager pManager)
{
pManager.AddMeshParameter("Meshes", "Ms", "Mesh of surfaces", GH_ParamAccess.list);
pManager.AddTextParameter("Output", "O", "Test", GH_ParamAccess.item);
}
protected override void SolveInstance(IGH_DataAccess DA)
{
var surfaces = new List<GH_Surface>();
int units = 0;
int meshMode = 0;
int sizeMode = 0;
bool transitioning = true;
int tolType = 0;
double mergeAngle = 0;
double featLen = 0;
int targetElement = 0;
double meshSize = 0;
double lenRatio = 0;
double maxIncr = 0;
int meshTolType = 0;
double meshCleanTol = 0;
bool alwaysRun = false;
var offsets = new List<double>();
int count = 0;
if (!DA.GetDataList(count++, surfaces))
return;
if (!DA.GetData(count++, ref units))
return;
if (!DA.GetData(count++, ref tolType))
return;
if (!DA.GetData(count++, ref mergeAngle))
return;
if (!DA.GetData(count++, ref featLen))
return;
if (!DA.GetData(count++, ref meshMode))
return;
if (!DA.GetData(count++, ref sizeMode))
return;
if (!DA.GetData(count++, ref targetElement))
return;
if (!DA.GetData(count++, ref transitioning))
return;
if (!DA.GetData(count++, ref meshSize))
return;
if (!DA.GetData(count++, ref lenRatio) && meshMode == 1)
return;
if (!DA.GetData(count++, ref maxIncr) && meshMode == 1)
return;
if (!DA.GetData(count++, ref meshTolType))
return;
if (!DA.GetData(count++, ref meshCleanTol))
return;
if (!DA.GetData(count++, ref alwaysRun))
return;
_meshes = [];
Message = "";
if (_run || alwaysRun)
{
_warnings = [];
_errors = [];
try
{
Message = "Running. Wait...";
var layerIds = new List<int>();
var objectIds = new List<Guid>();
//at each surface one layer, to reconstruct the mesh topology after
for (int i = 0; i < surfaces.Count; i++)
{
int layerId = Rh.RhinoDoc.ActiveDoc.Layers.Add($"tmp_{i}_{Guid.NewGuid()}", System.Drawing.Color.Black);
if (layerId < 0)
throw new NotSupportedException("Layer already present");
layerIds.Add(layerId);
Guid objectId = Rh.RhinoDoc.ActiveDoc.Objects.AddBrep(surfaces[i].Value);
Rh.DocObjects.RhinoObject rhinoObject = Rh.RhinoDoc.ActiveDoc.Objects.FindId(objectId);
rhinoObject.Attributes.LayerIndex = layerId;
rhinoObject.CommitChanges();
rhinoObject.Select(true);
objectIds.Add(objectId);
}
string unitOpt = "";
unitOpt = (ModelModel.ModelUnits)units switch
{
ModelModel.ModelUnits.Nmm => "_i",// mm
ModelModel.ModelUnits.SI or ModelModel.ModelUnits.kNm => "_e",// m
_ => throw new NotSupportedException("Unknown units system"),
};
string igesFile = Path.Combine(Path.GetTempPath(), Path.GetFileNameWithoutExtension(Path.GetTempFileName()) + ".igs");
// string igesFile = Path.Combine(Path.GetTempPath(), Path.GetFileNameWithoutExtension(Path.GetTempFileName()) + ".stp");
if (Rh.RhinoApp.RunScript($"! -_Export {igesFile} _S {unitOpt} _Enter _Enter", true))
{
_output.Add($"Temporary file {igesFile} created succesfully");
}
else
{
throw new IOException($"Failed to export geometry file: {igesFile}{Environment.NewLine}");
}
var worker = new BackgroundWorker();
var parameters = new Hashtable
{
{ "surfCount", surfaces.Count },
{ "units", units },
{ "iges_file", igesFile },
{ "tol_type", tolType },
{ "merge_angle", mergeAngle },
{ "feat_len", featLen },
{ "target_element", targetElement},
{ "mesh_mode", meshMode },
{ "size_mode", sizeMode },
{ "transitioning", transitioning },
{ "mesh_size", meshSize },
{ "len_ratio", lenRatio },
{ "max_incr", maxIncr },
{ "mesh_tol_type", meshTolType },
{ "mesh_tol", meshCleanTol }
};
PerformSt7Mesh(parameters);
// Delete the temporary objects
foreach (Guid id in objectIds)
Rh.RhinoDoc.ActiveDoc.Objects.Delete(id, true);
foreach (int layer_idx in layerIds)
Rh.RhinoDoc.ActiveDoc.Layers.Delete(layer_idx, true);
_run = false;
}
catch (Exception ex)
{
_errors.Add(ex.Message);
_isRunning = false;
}
}
if (_warnings.Count != 0)
AddRuntimeMessage(GH_RuntimeMessageLevel.Warning, string.Join(Environment.NewLine, [.. _warnings]));
if (_errors.Count != 0)
AddRuntimeMessage(GH_RuntimeMessageLevel.Error, string.Join(Environment.NewLine, [.. _errors]));
DA.SetDataList(0, _meshes);
DA.SetData(1, string.Join(Environment.NewLine, [.. _output]));
}
/// <summary>
/// The main calculation function.
/// </summary>
private void PerformSt7Mesh(Hashtable parameters)
{
int surfCount = Convert.ToInt32(parameters["surfCount"]);
ModelModel.ModelUnits units = (ModelModel.ModelUnits)Convert.ToInt32(parameters["units"]);
int tolType = Convert.ToInt32(parameters["tol_type"]);
double mergeAngle = Convert.ToDouble(parameters["merge_angle"]);
double featLen = Convert.ToDouble(parameters["feat_len"]);
int meshMode = Convert.ToInt32(parameters["mesh_mode"]);
int sizeMode = Convert.ToInt32(parameters["size_mode"]);
int targetElement = Convert.ToInt32(parameters["target_element"]);
bool transitioning = Convert.ToBoolean(parameters["transitioning"]);
double meshSize = Convert.ToDouble(parameters["mesh_size"]);
double lenRatio = Convert.ToDouble(parameters["len_ratio"]);
double maxIncr = Convert.ToDouble(parameters["max_incr"]);
string igesFile = parameters["iges_file"].ToString();
int meshTolType = Convert.ToInt32(parameters["mesh_tol_type"]);
double meshTol = Convert.ToDouble(parameters["mesh_tol"]);
int modelId = 1;
try
{
St7API.St7.St7Init();
// Create a new model
if (St7API.St7.St7NewFile(modelId, Path.Combine(Path.GetTempPath(), Path.GetFileNameWithoutExtension(Path.GetTempFileName()) + ".st7"), Path.GetTempPath()) != 0)
throw new Exception("Failed to create new model");
// Set the measure units
int[] st7Units = new int[St7API.St7.kLastUnit];
switch (units)
{
case ModelModel.ModelUnits.Nmm:
st7Units[St7API.St7.ipLENGTHU] = St7API.St7.luMILLIMETRE;
break;
case ModelModel.ModelUnits.SI:
case ModelModel.ModelUnits.kNm:
st7Units[St7API.St7.ipLENGTHU] = St7API.St7.luMETRE;
break;
default:
throw new NotSupportedException("Unknown units");
}
//Other units not important here, setted always as:
st7Units[St7API.St7.ipFORCEU] = St7API.St7.fuNEWTON;
st7Units[St7API.St7.ipSTRESSU] = St7API.St7.suPASCAL;
st7Units[St7API.St7.ipMASSU] = St7API.St7.muKILOGRAM;
st7Units[St7API.St7.ipTEMPERU] = St7API.St7.tuKELVIN;
st7Units[St7API.St7.ipENERGYU] = St7API.St7.euJOULE;
if (St7API.St7.St7SetUnits(modelId, st7Units) != 0)
{
St7API.St7.St7CloseFile(modelId);
throw new Exception("Failed to set the units");
}
// Import the file IGES
int[] importIgsInts = new int[6];
importIgsInts[St7API.St7.ipGeomImportProperty] = 1;
importIgsInts[St7API.St7.ipGeomImportCurvesToBeams] = St7API.St7.btFalse;
importIgsInts[St7API.St7.ipGeomImportGroupsAs] = St7API.St7.ggAssemblies;
importIgsInts[St7API.St7.ipGeomImportColourAsProperty] = St7API.St7.btTrue;
importIgsInts[St7API.St7.ipGeomImportMatchExistingProperty] = St7API.St7.btTrue;
switch (units)
{
case ModelModel.ModelUnits.Nmm:
case ModelModel.ModelUnits.SI:
importIgsInts[St7API.St7.ipGeomImportLengthUnit] = St7API.St7.luGeomMillimetre;
break;
case ModelModel.ModelUnits.kNm:
importIgsInts[St7API.St7.ipGeomImportLengthUnit] = St7API.St7.luGeomMetre;
break;
default:
throw new NotSupportedException("Unknown units");
}
double[] importIgsDoubles = new double[1];
importIgsDoubles[St7API.St7.ipGeomImportTol] = 0.000001;
if (St7API.St7.St7ImportIGES(modelId, igesFile, importIgsInts, importIgsDoubles, St7API.St7.ieQuietRun) != 0)
// if (St7API.St7.St7ImportSTEP(modelId, igesFile, importIgsInts, importIgsDoubles, St7API.St7.ieProgressRun) != 0)
{
St7API.St7.St7CloseFile(modelId);
if (!string.IsNullOrEmpty(igesFile) && File.Exists(igesFile))
{
File.Delete(igesFile);
_output.Add($"Temporary file {igesFile} deleted succesfully.");
}
throw new Exception("Failed to import the IGES file");
}
// Clean Geometry
int[] cleanGeomInts = new int[5];
cleanGeomInts[St7API.St7.ipGeometryFeatureType] = tolType == 0 ? St7API.St7.ztRelative : St7API.St7.ztAbsolute;
cleanGeomInts[St7API.St7.ipGeometryActOnWholeModel] = St7API.St7.btTrue;
cleanGeomInts[St7API.St7.ipGeometryFreeEdgesOnly] = St7API.St7.btFalse;
cleanGeomInts[St7API.St7.ipGeometryDuplicateFaces] = St7API.St7.dfLeaveAll;
double[] cleanGeomDoubles = new double[3];
cleanGeomDoubles[St7API.St7.ipGeometryFeatureLength] = featLen;
cleanGeomDoubles[St7API.St7.ipGeometryEdgeMergeAngle] = mergeAngle;
if (St7API.St7.St7SetCleanGeometryOptions(modelId, cleanGeomInts, cleanGeomDoubles) != 0)
{
St7API.St7.St7CloseFile(modelId);
if (!string.IsNullOrEmpty(igesFile) && File.Exists(igesFile))
{
File.Delete(igesFile);
_output.Add($"Temporary file {igesFile} deleted succesfully.");
}
throw new Exception("Failed to set the clean geometry data");
}
int changes = 0;
if (St7API.St7.St7CleanGeometry(modelId, ref changes, St7API.St7.ieQuietRun) != 0)
{
St7API.St7.St7CloseFile(modelId);
if (!string.IsNullOrEmpty(igesFile) && File.Exists(igesFile))
{
File.Delete(igesFile);
_output.Add($"Temporary file {igesFile} deleted succesfully.");
}
throw new Exception("Failed to clean geometry");
}
changes = 0;
if (St7API.St7.St7CleanGeometry(modelId, ref changes, St7API.St7.ieQuietRun) != 0)
{
St7API.St7.St7CloseFile(modelId);
if (!string.IsNullOrEmpty(igesFile) && File.Exists(igesFile))
{
File.Delete(igesFile);
_output.Add($"Temporary file {igesFile} deleted succesfully.");
}
throw new Exception("Failed to clean geometry");
}
// Generate mesh
int[] meshInts = new int[10];
if (meshMode == 0)
meshInts[St7API.St7.ipSurfaceMeshMode] = St7API.St7.mmAuto;
else
meshInts[St7API.St7.ipSurfaceMeshMode] = St7API.St7.mmCustom;
if (sizeMode == 0)
meshInts[St7API.St7.ipSurfaceMeshSizeMode] = St7API.St7.smPercentage;
else
meshInts[St7API.St7.ipSurfaceMeshSizeMode] = St7API.St7.smAbsolute;
meshInts[St7API.St7.ipSurfaceMeshTargetNodes] = targetElement;
meshInts[St7API.St7.ipSurfaceMeshTargetPropertyID] = -1;
meshInts[St7API.St7.ipSurfaceMeshAutoCreateProperties] = St7API.St7.btTrue;
meshInts[St7API.St7.ipSurfaceMeshMinEdgesPerCircle] = 12;
meshInts[St7API.St7.ipSurfaceMeshApplyTransitioning] = transitioning ? St7API.St7.btTrue : St7API.St7.btFalse;
meshInts[St7API.St7.ipSurfaceMeshAllowUserStop] = St7API.St7.btFalse;
double[] meshDoublesp = new double[4];
meshDoublesp[St7API.St7.ipSurfaceMeshSize] = meshSize;
meshDoublesp[St7API.St7.ipSurfaceMeshLengthRatio] = lenRatio;
meshDoublesp[St7API.St7.ipSurfaceMeshMaximumIncrease] = maxIncr;
meshDoublesp[St7API.St7.ipSurfaceMeshOnEdgesLongerThan] = 0;
if (St7API.St7.St7SurfaceMesh(modelId, meshInts, meshDoublesp, St7API.St7.ieQuietRun) != 0)
{
St7API.St7.St7CloseFile(modelId);
if (!string.IsNullOrEmpty(igesFile) && File.Exists(igesFile))
{
File.Delete(igesFile);
_output.Add($"Temporary file {igesFile} deleted succesfully.");
}
throw new Exception("Failed to mesh");
}
// Clean mesh
int[] cleanMeshInts = new int[20];
cleanMeshInts[St7API.St7.ipMeshToleranceType] = meshTolType == 0 ? St7API.St7.ztRelative : St7API.St7.ztAbsolute;
cleanMeshInts[St7API.St7.ipActOnWholeModel] = St7API.St7.btTrue;
cleanMeshInts[St7API.St7.ipZipNodes] = St7API.St7.btTrue;
cleanMeshInts[St7API.St7.ipRemoveDuplicateElements] = St7API.St7.btTrue;
cleanMeshInts[St7API.St7.ipFixElementConnectivity] = St7API.St7.btTrue;
cleanMeshInts[St7API.St7.ipDeleteFreeNodes] = St7API.St7.btTrue;
cleanMeshInts[St7API.St7.ipDoBeams] = St7API.St7.btTrue;
cleanMeshInts[St7API.St7.ipDoPlates] = St7API.St7.btTrue;
cleanMeshInts[St7API.St7.ipDoBricks] = St7API.St7.btTrue;
cleanMeshInts[St7API.St7.ipDoLinks] = St7API.St7.btTrue;
cleanMeshInts[St7API.St7.ipZeroLengthLinks] = St7API.St7.btTrue;
cleanMeshInts[St7API.St7.ipZeroLengthBeams] = St7API.St7.btFalse;
cleanMeshInts[St7API.St7.ipNodeAttributeKeep] = St7API.St7.naHigher;
cleanMeshInts[St7API.St7.ipNodeCoordinates] = St7API.St7.ncAverage;
cleanMeshInts[St7API.St7.ipAllowDifferentProps] = St7API.St7.btFalse;
var cleanMeshDoubles = new double[] { meshTol }
;
if (St7API.St7.St7SetCleanMeshOptions(modelId, cleanMeshInts, cleanMeshDoubles) != 0)
{
St7API.St7.St7CloseFile(modelId);
if (!string.IsNullOrEmpty(igesFile) && File.Exists(igesFile))
{
File.Delete(igesFile);
_output.Add($"Temporary file {igesFile} deleted succesfully.");
}
throw new Exception("Filed to set the clean mesh data");
}
if (St7API.St7.St7CleanMesh(modelId) != 0)
{
St7API.St7.St7CloseFile(modelId);
if (!string.IsNullOrEmpty(igesFile) && File.Exists(igesFile))
{
File.Delete(igesFile);
_output.Add($"Temporary file {igesFile} deleted succesfully.");
}
throw new Exception("Failed to clean mesh");
}
// Totals nodes and plates
int numNodes = 0;
int numPlates = 0;
if (St7API.St7.St7GetTotal(modelId, St7API.St7.tyNODE, ref numNodes) != 0 || St7API.St7.St7GetTotal(modelId, St7API.St7.tyPLATE, ref numPlates) != 0)
{
St7API.St7.St7CloseFile(modelId);
if (!string.IsNullOrEmpty(igesFile) && File.Exists(igesFile))
{
File.Delete(igesFile);
_output.Add($"Temporary file {igesFile} deleted succesfully.");
}
throw new Exception("Failed to retrieve the total of generated elements");
}
// Read nodes
var nodes = new Dictionary<int, Point3d>();
for (int n = 1; n <= numNodes; n++)
{
double[] pos = [0, 0, 0];
if (St7API.St7.St7GetNodeXYZ(modelId, n, pos) != 0)
{
St7API.St7.St7CloseFile(modelId);
if (!string.IsNullOrEmpty(igesFile) && File.Exists(igesFile))
{
File.Delete(igesFile);
_output.Add($"Temporary file {igesFile} deleted succesfully.");
}
throw new Exception($"Unable to read node: {n}");
}
nodes.Add(n, new Point3d(pos[0], pos[1], pos[2]));
}
// Read plates
var surfaceFaceNodeId = new List<List<int[]>>(); // indice facce per ogni surface
var groupIdListPosition = new Dictionary<int, int>();
int surfCounter = 0;
for (int p = 1; p <= numPlates; p++)
{
int surfId = -1;
int groupId = 0;
var groupName = new StringBuilder(St7API.St7.kMaxStrLen);
if (St7API.St7.St7GetEntityGroup(modelId, St7API.St7.tyPLATE, p, ref groupId) != 0)
{
St7API.St7.St7CloseFile(modelId);
if (!string.IsNullOrEmpty(igesFile) && File.Exists(igesFile))
{
File.Delete(igesFile);
_output.Add($"Temporary file {igesFile} deleted succesfully.");
}
throw new Exception($"Unable to read group of plate: {p}");
}
if (St7API.St7.St7GetGroupIDName(modelId, groupId, groupName, St7API.St7.kMaxStrLen) != 0)
{
St7API.St7.St7CloseFile(modelId);
if (!string.IsNullOrEmpty(igesFile) && File.Exists(igesFile))
{
File.Delete(igesFile);
_output.Add($"Temporary file {igesFile} deleted succesfully.");
}
throw new Exception($"Unable to get group name of group: {groupId}");
}
if (!groupIdListPosition.ContainsKey(groupId))
{
groupIdListPosition.Add(groupId, surfCounter);
surfaceFaceNodeId.Add([]);
surfCounter++;
}
surfId = groupIdListPosition[groupId];
int[] connection = new int[St7API.St7.kMaxElementNode];
if (St7API.St7.St7GetElementConnection(modelId, St7API.St7.tyPLATE, p, connection) == 0)
{
if (connection[0] == 3 || connection[0] == 4)
surfaceFaceNodeId[surfId].Add([.. connection.Take(connection[0] + 1).Skip(1)]);
}
else
{
St7API.St7.St7CloseFile(modelId);
if (!string.IsNullOrEmpty(igesFile) && File.Exists(igesFile))
{
File.Delete(igesFile);
_output.Add($"Temporary file {igesFile} deleted succesfully.");
}
throw new Exception($"Unable to read plate: {p}");
}
}
//Creating meshes
_meshes = [];
for (int i = 0; i < surfaceFaceNodeId.Count; i++)
{
var mesh = new Mesh();
var verticesMap = new List<int>();
if (surfaceFaceNodeId[i] != null)
{
if (surfaceFaceNodeId[i].Count > 0)
{
for (int j = 0; j < surfaceFaceNodeId[i].Count; j++)
{
int[] face = surfaceFaceNodeId[i][j];
var faceNodes = new List<int>();
for (int k = 0; k < face.Length; k++)
{
int nodeId = face[k];
int vertexId = verticesMap.IndexOf(nodeId);
if (vertexId < 0)
{
mesh.Vertices.Add(nodes[nodeId]);
vertexId = mesh.Vertices.Count - 1;
verticesMap.Add(nodeId);
}
faceNodes.Add(vertexId);
}
if (faceNodes.Count == 3)
{
mesh.Faces.AddFace(faceNodes[0], faceNodes[1], faceNodes[2]);
}
else if (faceNodes.Count == 4)
{
mesh.Faces.AddFace(faceNodes[0], faceNodes[1], faceNodes[2], faceNodes[3]);
}
else
{
throw new NotSupportedException("Plate is not a tri or quad");
}
}
mesh.Compact();
mesh.RebuildNormals();
mesh.UnifyNormals();
mesh.Normals.ComputeNormals();
}
}
else
{
_warnings.Add($"Surface {i} has not been meshed successful");
_output.Add($"Surface {i} has not been meshed successful");
}
_meshes.Add(mesh);
}
St7API.St7.St7SaveFile(modelId);
if (St7API.St7.St7CloseFile(modelId) != 0)
throw new Exception("Failed to close st7 file");
St7API.St7.St7Release();
_output.Add($"Mesh generated succesfully.");
_output.Add($"Total amount of nodes = {numNodes}");
_output.Add($"Total amount of plates = {numPlates}");
Message = "Completed";
_justCompleted = true;
_isRunning = false;
}
catch (Exception ex)
{
_errors.Add(ex.Message);
if (modelId >= 0)
St7API.St7.St7CloseFile(modelId);
if (!string.IsNullOrEmpty(igesFile) && File.Exists(igesFile))
{
File.Delete(igesFile);
_output.Add($"Temporary file {igesFile} deleted succesfully.");
}
}
finally
{
}
if (!string.IsNullOrEmpty(igesFile) && File.Exists(igesFile))
{
File.Delete(igesFile);
_output.Add($"Temporary file {igesFile} deleted succesfully.");
}
}
public override bool Read(GH_IReader reader)
{
if (base.Read(reader))
{
if (reader.GetBoolean("hasMeshes"))
{
_meshes = [];
for (int i = 0; i < reader.GetInt32("count"); i++)
{
var data = new GH_Mesh();
data.Read(reader.FindChunk(i.ToString()));
_meshes.Add(data.Value);
}
}
return true;
}
return false;
}
public override bool Write(GH_IWriter writer)
{
if (base.Write(writer))
{
bool b = _meshes != null && _meshes.Count > 0;
writer.SetBoolean("hasMeshes", b);
if (b)
{
writer.SetInt32("count", _meshes.Count);
for (int i = 0; i < _meshes.Count; i++)
{
new GH_Mesh(_meshes[i]).Write(writer.CreateChunk(i.ToString()));
}
}
return true;
}
return false;
}
public override void ExpireSolution(bool recompute)
{
base.ExpireSolution(recompute);
_errors.Clear();
_warnings.Clear();
_output.Clear();
}
protected override System.Drawing.Bitmap Icon => Properties.Resources.SurfaceMeshIcon;
public override Guid ComponentGuid => new("071BF3ED-B38F-4BFC-AE79-062AE6381BD9");
}
}