using FeMM.Common.Helpers;
using FeMM.Common.Models;
using FeMM.Grasshopper.DataTypes;
using FeMM.Grasshopper.DataTypes.FeMM;
using FeMM.Grasshopper.Helpers;
using Grasshopper.Kernel;
using Grasshopper.Kernel.Data;
using Grasshopper.Kernel.Parameters;
using Grasshopper.Kernel.Types;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.Linq;
namespace FeMM.Grasshopper.Components.MeCheck2
{
public abstract class PrintCheckImageMeCheckTaubComponentBase : GH_Component
{
protected bool _run;
protected Color[] ComboColors =
[
Color.Red,
Color.Green,
Color.Blue,
Color.Orange,
Color.Magenta,
Color.Yellow,
Color.Purple,
Color.Orchid,
Color.Aquamarine,
];
protected readonly List<string> _forceComponent =
[
"τ*b",
];
/// <summary>
/// Initializes a new instance of the MyComponent1 class.
/// </summary>
public PrintCheckImageMeCheckTaubComponentBase()
: base("Print MeCheck τb", "PI", "Create the check image of super element check", CategoryNameConstants.CATEGORY_CHECKS, CategoryNameConstants.SUBCATEGORY_MECHECK2)
{
}
public override void CreateAttributes()
{
var attr = new ComponentAttributes.ComponentOneButtonAttributes(this, "Run");
attr.ButtonPressed += () =>
{
_run = true;
ExpireSolution(true);
};
m_attributes = attr;
}
protected abstract void RegisterInputMarks(GH_InputParamManager pManager);
protected abstract void GetInputMarks(IGH_DataAccess DA, ref int nnn, ref bool showMarks, List<double> customMarks);
/// <summary>
/// Registers all the input parameters for this component.
/// </summary>
protected override void RegisterInputParams(GH_InputParamManager pManager)
{
pManager.AddGenericParameter("FeMM Model", "FM", "The FEM models (more than one for stages)", GH_ParamAccess.item);
pManager.AddGenericParameter("Super-Element Beam", "SE", "The Super-Element Beam", GH_ParamAccess.list);
pManager.AddGenericParameter("Results", "R", "The MeCheck Results", GH_ParamAccess.tree);
pManager.AddIntegerParameter("Result component", "FC", "The force component to print", GH_ParamAccess.item, 0);
Param_Integer param = (Param_Integer)pManager[pManager.ParamCount - 1];
for (int i = 0; i < _forceComponent.Count; i++)
param.AddNamedValue(_forceComponent[i], i);
pManager.AddTextParameter("Combinations", "C", "The list of the combinations to draw", GH_ParamAccess.list);
pManager[pManager.ParamCount - 1].Optional = true;
pManager.AddBooleanParameter("Show Min/Max Combo", "SMM", "If true, show the combinations that maximize and minimize the envelop", GH_ParamAccess.item, true);
pManager.AddGenericParameter("Additional Curves", "AC", "List of curves to add to the graph", GH_ParamAccess.list);
pManager[pManager.ParamCount - 1].Optional = true;
pManager.AddNumberParameter("Reference Values", "RV", "List of reference values to add to the graph", GH_ParamAccess.list);
pManager[pManager.ParamCount - 1].Optional = true;
pManager.AddTextParameter("File Path", "P", "The path of the file", GH_ParamAccess.item);
pManager.AddTextParameter("Graphic Title", "T", "The title of the graphic", GH_ParamAccess.item, "");
pManager.AddIntegerParameter("Significant digits", "SD", "Significant digits of ascissas", GH_ParamAccess.item, 2);
pManager.AddBooleanParameter("Keep Running", "KR", "Run", GH_ParamAccess.item, false);
RegisterInputMarks(pManager);
}
/// <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)
{
Message = "";
var model = new GH_Model();
var beams = new List<GH_CompositeBeam>();
var comboToDraw = new List<string>();
int resultComponent = 0;
bool showMinMax = true;
var additionalValue = new List<GraphicCreator.Curve>();
var referenceValues = new List<double>();
string savePath = "";
string title = "";
int significantDigits = 0;
bool keepRunning = false;
int nnn = 0;
if (!DA.GetData(nnn++, ref model))
return;
if (!DA.GetDataList(nnn++, beams))
return;
if (!DA.GetDataTree(nnn++, out GH_Structure<IGH_Goo> inputTree))
return;
if (!DA.GetData(nnn++, ref resultComponent))
return;
DA.GetDataList(nnn++, comboToDraw);
DA.GetData(nnn++, ref showMinMax);
DA.GetDataList(nnn++, additionalValue);
DA.GetDataList(nnn++, referenceValues);
DA.GetData(nnn++, ref savePath);
DA.GetData(nnn++, ref title);
DA.GetData(nnn++, ref significantDigits);
if (!DA.GetData(nnn++, ref keepRunning))
return;
bool showMarks = true;
var customMarks = new List<double>();
GetInputMarks(DA, ref nnn, ref showMarks, customMarks);
if (_run || keepRunning)
{
try
{
var n0List = new List<int>();
var n1List = new List<int>();
int n0 = 0;
int n1 = 0;
for (int i = 0; i < inputTree.Branches.Count; i++)
{
GH_Path path = inputTree.Paths[i];
var indices = path.Indices;
if (i == 0)
{
n0 = indices[0];
n1 = indices[1];
continue;
}
if (i == inputTree.Branches.Count - 1)
{
n1 = indices[1];
n1List.Add(n1 + 1);
}
if (indices[0] > n0)
{
n1List.Add(n1 + 1);
n0 = indices[0];
n1 = indices[1];
continue;
}
if (indices[1] > n1)
n1 = indices[1];
}
double[][][] results = new double[beams.Count][][];
for (int i = 0; i < beams.Count; i++)
{
results[i] = new double[n1List[i]][];
for (int j = 0; j < n1List[i]; j++)
{
List<IGH_Goo> row = (List<IGH_Goo>)inputTree.get_Branch(new GH_Path([i, j]));
results[i][j] = new double[row.Count];
for (int k = 0; k < row.Count; k++)
{
try
{
results[i][j][k] = ((GH_Goo<double>)row[k]).Value;
}
catch (Exception)
{
results[i][j][k] = 0;
}
}
}
}
var gc = new GraphicCreator(1500.0F, 900.0F, true)
{
Title = title,
CustomMarkPositions = customMarks
};
List<string> comboName = [.. model.Value.Combinations.Select(j => j.Name)];
double x = 0;
int absoluteMinIndex = 0;
int absoluteMaxIndex = 0;
double absoluteMinValue = 0;
double absoluteMaxValue = 0;
x = 0;
// Set the minimum/maximum values
for (int i = 0; i < beams.Count; i++)
{
var stationBuffer = new HashSet<double>();
for (int k = 0; k < beams[i].Value.Results.Count; k++)
{
BeamForceResultModel force = (BeamForceResultModel)beams[i].Value.Results[k];
double dist = Math.Round(force.NormalizedLength ? force.Station * beams[i].Value.Length : force.Station, 15);
stationBuffer.Add(dist);
}
double[] dists = [.. stationBuffer];
var v = new List<(double dist, double max, double min)>();
for (int n = 0; n < dists.Length; n++)
{
double[] fff = results[i][n];
double min = 0;
double max = 0;
switch (resultComponent)
{
case 0:
for (int j = 0; j < fff.Length; j++)
{
double combonentBuffer = fff[j];
GraphicCreator.MinMax(j, combonentBuffer, showMinMax, ref absoluteMaxValue, ref absoluteMinValue, ref absoluteMaxIndex, ref absoluteMinIndex, ref max, ref min);
}
break;
}
double mod = 0;
if (n == dists.Length - 1)
mod = -1;
v.Add((x + dists[n] - mod, max, min));
}
var sorted = v.OrderBy(a => a.dist).ToList();
for (int k = 0; k < sorted.Count; k++)
gc.AddMaximumValues(sorted[k].dist, sorted[k].min, sorted[k].max);
x += dists.Max();
gc.FrameLenths.Add(dists.Max());
}
if (referenceValues.Count > 0)
{
for (int i = 0; i < referenceValues.Count; i++)
{
gc.AddReferenceLine(referenceValues[i], Color.FromArgb(100, 100, 100));
gc.AddMaxValue(referenceValues[i]);
gc.AddMinValue(referenceValues[i]);
}
}
if (additionalValue.Count > 0)
{
for (int i = 0; i < additionalValue.Count; i++)
{
gc.AddCurve(additionalValue[i].Name, additionalValue[i].Color, additionalValue[i].Thickness);
for (int j = 0; j < additionalValue[i].Values.Count; j++)
gc.AddCurveValue(additionalValue[i].Name, additionalValue[i].Values[j][0], additionalValue[i].Values[j][1]);
}
}
if (showMinMax)
{
comboToDraw.Insert(0, comboName[absoluteMaxIndex]);
comboToDraw.Insert(1, comboName[absoluteMinIndex]);
}
for (int c = 0; c < comboToDraw.Count; c++)
{
int comboIndex = comboName.IndexOf(comboToDraw[c]);
Color color = ComboColors[c % ComboColors.Length];
gc.AddCurve(comboToDraw[c], color);
x = 0;
for (int i = 0; i < beams.Count; i++)
{
var stationBuffer = new HashSet<double>();
var cc = new List<(string combo, double delta, double value)>();
for (int k = 0; k < beams[i].Value.Results.Count; k++)
{
BeamForceResultModel force = (BeamForceResultModel)beams[i].Value.Results[k];
double dist = Math.Round(force.NormalizedLength ? force.Station * beams[i].Value.Length : force.Station, 15);
stationBuffer.Add(dist);
}
double[] dists = [.. stationBuffer];
for (int n = 0; n < dists.Length; n++)
{
double[] fff = results[i][n];
double vv = 0;
switch (resultComponent)
{
case 0:
vv = fff[comboIndex];
break;
}
double mod = 0;
if (n == dists.Length - 1)
mod = -1;
cc.Add((comboToDraw[c], x + dists[n] - mod, vv));
}
var sorted = cc.OrderBy(a => a.delta).ToList();
for (int k = 0; k < sorted.Count(); k++)
gc.AddCurveValue(sorted[k].combo, sorted[k].delta, sorted[k].value);
x += dists.Max();
}
}
switch (resultComponent)
{
case 0:
gc.YAxisTitle = "kN/m";
break;
}
gc.XAxisTitle = "m";
double _valuesScaleRatio = 1.0;
Bitmap _graphicImage = gc.Create(true, (float)_valuesScaleRatio, significantDigits, showMarks);
_graphicImage.Save(savePath, ImageFormat.Png);
_run = false;
}
catch (Exception e)
{
AddRuntimeMessage(GH_RuntimeMessageLevel.Error, $"Fail to create the image: {e}");
_run = false;
}
}
}
/// <summary>
/// Provides an Icon for the component.
/// </summary>
protected override Bitmap Icon => Properties.Resources.PrintCompositeSectionTaubIcon;
}
}