From caf91fe43d7fdc8ab50b39f871e30c89256586b5 Mon Sep 17 00:00:00 2001 From: lorinczandrea Date: Wed, 16 Oct 2024 06:01:42 +0200 Subject: [PATCH] :sparkles: #802 composite sections (squashed commit) commit 87e5320a586312d6fa48627681457d15b276ff5c Author: lorinczandrea Date: Wed Oct 16 05:59:43 2024 +0200 exclude non-working sections & error handling #802 commit 877d2d97bc02e835910e10eb55cbfead3ce8e8c4 Author: lorinczandrea Date: Thu Oct 3 21:54:47 2024 +0200 :construction: icons and override ToString() #802 commit ea20fb08979b39a6378ff718531e4452370182d8 Author: lorinczandrea Date: Wed Oct 2 13:54:34 2024 +0200 :construction: DeltaBeam and bug fix #802 commit 1c1cebd6cb520e159156d63ebb968ef7eb28f61d Author: lorinczandrea Date: Thu Sep 19 22:37:41 2024 +0300 :construction: bugfix in Model.cs & GH subcomponents #802 still testing commit b5f1ac8dadb921ec7849f92af412b5f568bdbf5a Author: lorinczandrea Date: Thu Sep 19 17:40:49 2024 +0300 :construction: CS implementation and GH components #802 --- FemDesign.Core/Bars/Bar.cs | 96 +- FemDesign.Core/Bars/BarPart.cs | 141 +- FemDesign.Core/Bars/BarType.cs | 6 + FemDesign.Core/Bars/Beam.cs | 6 +- FemDesign.Core/Bars/Column.cs | 4 + FemDesign.Core/Composites/ComplexComposite.cs | 98 ++ .../Composites/ComplexCompositePart.cs | 54 + .../Composites/CompositeParameterTypeEnum.cs | 79 ++ FemDesign.Core/Composites/CompositeSection.cs | 1203 +++++++++++++++++ .../Composites/CompositeSectionParameter.cs | 43 + .../Composites/CompositeSectionPart.cs | 149 ++ .../Composites/CompositeTypeEnum.cs | 37 + FemDesign.Core/Composites/Composites.cs | 20 + FemDesign.Core/FemDesign.Core.csproj | 8 + FemDesign.Core/Geometry/Contour.cs | 24 +- FemDesign.Core/Model/Model.cs | 138 +- FemDesign.Core/Sections/Section.cs | 6 +- FemDesign.Grasshopper/Bars/CompositeBar.cs | 145 ++ .../SectionDeconstruct _OBSOLETE2307.cs | 60 + .../Deconstruct/SectionDeconstruct.cs | 70 +- .../FemDesign.Grasshopper.csproj | 21 + .../Properties/Resources.Designer.cs | 90 ++ .../Properties/Resources.resx | 27 + .../Resources/icons/DeltaBeamProfile.png | Bin 0 -> 310 bytes .../icons/EffectiveCompositeSlab.png | Bin 0 -> 219 bytes .../icons/FilledCruciformProfile.png | Bin 0 -> 336 bytes .../Resources/icons/FilledIProfile.png | Bin 0 -> 195 bytes .../Resources/icons/FilledSteelTube.png | Bin 0 -> 598 bytes .../Resources/icons/HSQProfile.png | Bin 0 -> 164 bytes .../Resources/icons/RHSProfile.png | Bin 0 -> 303 bytes .../Resources/icons/SteelTubeWithIProfile.png | Bin 0 -> 674 bytes .../icons/SteelTubeWithSteelCore.png | Bin 0 -> 701 bytes .../Composite/CompositeSectionDefine.cs | 127 ++ .../Sections/Composite/DeltaBeamProfile.cs | 71 + .../Composite/EffectiveCompositeSlab.cs | 120 ++ .../Composite/FilledCruciformProfile.cs | 95 ++ .../Sections/Composite/FilledIProfile.cs | 97 ++ .../Sections/Composite/FilledSteelTube.cs | 74 + .../Sections/Composite/HSQProfile.cs | 113 ++ .../Sections/Composite/RHSProfile.cs | 70 + .../Composite/SteelTubeWithIProfile.cs | 103 ++ .../Composite/SteelTubeWithSteelCore.cs | 85 ++ .../Composites/CompositeBeamTest.cs | 186 +++ FemDesign.Tests/Composites/materials.struxml | 37 + FemDesign.Tests/Composites/sections.struxml | 902 ++++++++++++ FemDesign.Tests/FemDesign.Tests.csproj | 3 + 46 files changed, 4503 insertions(+), 105 deletions(-) create mode 100644 FemDesign.Core/Composites/ComplexComposite.cs create mode 100644 FemDesign.Core/Composites/ComplexCompositePart.cs create mode 100644 FemDesign.Core/Composites/CompositeParameterTypeEnum.cs create mode 100644 FemDesign.Core/Composites/CompositeSection.cs create mode 100644 FemDesign.Core/Composites/CompositeSectionParameter.cs create mode 100644 FemDesign.Core/Composites/CompositeSectionPart.cs create mode 100644 FemDesign.Core/Composites/CompositeTypeEnum.cs create mode 100644 FemDesign.Core/Composites/Composites.cs create mode 100644 FemDesign.Grasshopper/Bars/CompositeBar.cs create mode 100644 FemDesign.Grasshopper/Deconstruct/SectionDeconstruct _OBSOLETE2307.cs create mode 100644 FemDesign.Grasshopper/Resources/icons/DeltaBeamProfile.png create mode 100644 FemDesign.Grasshopper/Resources/icons/EffectiveCompositeSlab.png create mode 100644 FemDesign.Grasshopper/Resources/icons/FilledCruciformProfile.png create mode 100644 FemDesign.Grasshopper/Resources/icons/FilledIProfile.png create mode 100644 FemDesign.Grasshopper/Resources/icons/FilledSteelTube.png create mode 100644 FemDesign.Grasshopper/Resources/icons/HSQProfile.png create mode 100644 FemDesign.Grasshopper/Resources/icons/RHSProfile.png create mode 100644 FemDesign.Grasshopper/Resources/icons/SteelTubeWithIProfile.png create mode 100644 FemDesign.Grasshopper/Resources/icons/SteelTubeWithSteelCore.png create mode 100644 FemDesign.Grasshopper/Sections/Composite/CompositeSectionDefine.cs create mode 100644 FemDesign.Grasshopper/Sections/Composite/DeltaBeamProfile.cs create mode 100644 FemDesign.Grasshopper/Sections/Composite/EffectiveCompositeSlab.cs create mode 100644 FemDesign.Grasshopper/Sections/Composite/FilledCruciformProfile.cs create mode 100644 FemDesign.Grasshopper/Sections/Composite/FilledIProfile.cs create mode 100644 FemDesign.Grasshopper/Sections/Composite/FilledSteelTube.cs create mode 100644 FemDesign.Grasshopper/Sections/Composite/HSQProfile.cs create mode 100644 FemDesign.Grasshopper/Sections/Composite/RHSProfile.cs create mode 100644 FemDesign.Grasshopper/Sections/Composite/SteelTubeWithIProfile.cs create mode 100644 FemDesign.Grasshopper/Sections/Composite/SteelTubeWithSteelCore.cs create mode 100644 FemDesign.Tests/Composites/CompositeBeamTest.cs create mode 100644 FemDesign.Tests/Composites/materials.struxml create mode 100644 FemDesign.Tests/Composites/sections.struxml diff --git a/FemDesign.Core/Bars/Bar.cs b/FemDesign.Core/Bars/Bar.cs index 76f6ec389..557f58a22 100644 --- a/FemDesign.Core/Bars/Bar.cs +++ b/FemDesign.Core/Bars/Bar.cs @@ -173,9 +173,9 @@ protected Bar() /// /// /// - /// Section, same at start/end - /// Analytical eccentricity, same at start. Eccentricity set to 0,0 if null/end - /// Connectivity, same at start/end. Connectivity set to Rigid if null + /// Section, same at start/end. + /// Analytical eccentricity, same at start and end. If null, eccentricity set to 0. + /// Connectivity, same at start/end. Connectivity set to Rigid if null. /// Identifier public Bar(Geometry.Edge edge, Materials.Material material, Sections.Section section, BarType type, Eccentricity eccentricity = null, Connectivity connectivity = null, string identifier = "B") { @@ -197,12 +197,12 @@ public Bar(Geometry.Edge edge, Materials.Material material, Sections.Section sec /// /// /// - /// Section, same at start/end + /// Section, same at start/end. /// Vector to orient the cross section. If null, localY will be set as a cross product between Z-Axis and the local X Axis./end - /// Analytical eccentricity. Eccentricity set to 0,0 if null/end - /// Analytical eccentricity. Eccentricity set to 0,0 if null/end - /// Connectivity. Connectivity set to Rigid if null/end - /// Connectivity. Connectivity set to Rigid if null + /// Analytical eccentricity at start. If null, eccentricity set to 0. + /// Analytical eccentricity at end. If null, eccentricity set to 0. + /// Connectivity. Connectivity set to Rigid if null. + /// Connectivity. Connectivity set to Rigid if null. /// Identifier public Bar(FemDesign.Geometry.Point3d startPoint, FemDesign.Geometry.Point3d endPoint, Materials.Material material, Sections.Section section, BarType type, Geometry.Vector3d localY = null, Eccentricity startEccentricity = null, Eccentricity endEccentricity = null, Connectivity startConnectivity = null, Connectivity endConnectivity = null, string identifier = "B") { @@ -222,19 +222,17 @@ public Bar(FemDesign.Geometry.Point3d startPoint, FemDesign.Geometry.Point3d end this.BarPart = new BarPart(edge, this.Type, material, section, startEccentricity, endEccentricity, startConnectivity, endConnectivity, identifier); } - - /// /// Construct beam or column with uniform section and different start/end conditions /// /// /// /// - /// Section, same at start/end - /// Analytical start eccentricity - /// Analytical end eccentricity - /// Start connectivity - /// End connectivity + /// Section, same at start/end. + /// Analytical eccentricity at start. If null, eccentricity set to 0. + /// Analytical eccentricity at end. If null, eccentricity set to 0. + /// Start connectivity. + /// End connectivity. /// Identifier public Bar(Geometry.Edge edge, BarType type, Materials.Material material, Sections.Section section, Eccentricity startEccentricity = null, Eccentricity endEccentricity = null, Connectivity startConnectivity = null, Connectivity endConnectivity = null, string identifier = "B") { @@ -259,12 +257,12 @@ public Bar(Geometry.Edge edge, BarType type, Materials.Material material, Sectio /// /// /// - /// Start section - /// End section - /// Analytical start eccentricity - /// Analytical end eccentricity - /// Start connectivity - /// End connectivity + /// Start section. + /// End section. + /// Analytical eccentricity at start. If null, eccentricity set to 0. + /// Analytical eccentricity at end. If null, eccentricity set to 0. + /// Start connectivity. + /// End connectivity. /// Identifier public Bar(Geometry.Edge edge, BarType type, Materials.Material material, Sections.Section startSection, Sections.Section endSection, Eccentricity startEccentricity, Eccentricity endEccentricity, Connectivity startConnectivity, Connectivity endConnectivity, string identifier) { @@ -306,8 +304,8 @@ public Bar(Geometry.Edge edge, BarType type, Materials.Material material, Sectio /// List of sections, 2 or more items. /// List of parametric (0-1) section positions, 2 or more items. /// List of analytical eccentricities, 2 or more items. - /// Start connectivity - /// End connectivity + /// Start connectivity. + /// End connectivity. /// Identifier public Bar(Geometry.Edge edge, BarType type, Materials.Material material, Sections.Section[] sections, double[] positions, Eccentricity[] eccentricities, Connectivity startConnectivity, Connectivity endConnectivity, string identifier) { @@ -346,6 +344,53 @@ public Bar(Geometry.Edge edge, Materials.Material material, Sections.Section sec } + /// + /// Construct a composite beam or composite column with uniform section and uniform start/end conditions. + /// + /// + /// + /// + /// Analytical eccentricity, same at start/end. Eccentricity set to 0,0 if null. + /// Connectivity, same at start/end. Connectivity set to Rigid if null. + /// Identifier + public Bar(Geometry.Edge edge, BarType type, Composites.CompositeSection compositeSection, Eccentricity eccentricity = null, Connectivity connectivity = null, string identifier = "B") + { + if (type == BarType.Truss) { throw new System.Exception("Truss is not a valid type"); } + + this.EntityCreated(); + this.Type = type; + + if (eccentricity == null) { eccentricity = Eccentricity.Default; } + if (connectivity == null) { connectivity = Connectivity.Default; } + this.BarPart = new BarPart(edge, this.Type, compositeSection, eccentricity, connectivity, identifier); + } + + /// + /// Construct composite beam or composite column with uniform section and different start/end conditions. + /// + /// + /// + /// + /// Analytical start eccentricity + /// Analytical end eccentricity + /// Start connectivity + /// End connectivity + /// Identifier + public Bar(Geometry.Edge edge, BarType type, Composites.CompositeSection compositeSection, Eccentricity startEccentricity = null, Eccentricity endEccentricity = null, Connectivity startConnectivity = null, Connectivity endConnectivity = null, string identifier = "B") + { + if (type == BarType.Truss) { throw new System.Exception("Truss is not a valid type"); } + + this.EntityCreated(); + this.Type = type; + + if (startEccentricity == null) { startEccentricity = Eccentricity.Default; } + if (endEccentricity == null) { endEccentricity = Eccentricity.Default; } + if (startConnectivity == null) { startConnectivity = Connectivity.Default; } + if (endConnectivity == null) { endConnectivity = Connectivity.Default; } + + this.BarPart = new BarPart(edge, this.Type, compositeSection, startEccentricity, endEccentricity, startConnectivity, endConnectivity, identifier); + } + /// /// Construct a truss element. @@ -462,7 +507,10 @@ public override string ToString() { if (this.BarPart.HasComplexCompositeRef) { - return $"{this.Type} Start: {this.BarPart.Edge.Points.First()}, End: {this.BarPart.Edge.Points.Last()}, Length: {this.BarPart.Edge.Length} m, Sections: Composite section type, Material: Composite"; + var compositeSection = this.BarPart.ComplexCompositeObj.CompositeSections[0]; + List compositeMaterials = compositeSection.Materials.Select(m => m.Name).ToList(); + + return $"{this.Type} Start: {this.BarPart.Edge.Points.First()}, End: {this.BarPart.Edge.Points.Last()}, Length: {this.BarPart.Edge.Length} m, Section: Composite - {compositeSection.Type}, Materials: {string.Join(", ", compositeMaterials)}"; } if (this.BarPart.HasDeltaBeamComplexSectionRef) { diff --git a/FemDesign.Core/Bars/BarPart.cs b/FemDesign.Core/Bars/BarPart.cs index 8307a1adc..69930f84c 100644 --- a/FemDesign.Core/Bars/BarPart.cs +++ b/FemDesign.Core/Bars/BarPart.cs @@ -39,6 +39,7 @@ protected override int GetUniqueInstanceCount() throw new System.ArgumentException($"Incorrect type of bar: {this.Type}"); } } + /// /// Edge field /// @@ -213,29 +214,79 @@ public SectionType SectionType } [XmlAttribute("complex_composite")] - public string ComplexCompositeRef { get; set; } // guidtype + public System.Guid _complexCompositeRef; + + public bool ShouldSerialize_complexCompositeRef() + { + return this.HasComplexCompositeRef; + } + + [XmlIgnore] + public System.Guid ComplexCompositeRef + { + get + { + return this._complexCompositeRef; + } + set + { + this._complexCompositeRef = value; + } + } + + [XmlIgnore] + public bool HasComplexCompositeRef { get => this.ComplexCompositeRef != System.Guid.Empty; } [XmlIgnore] - public bool HasComplexCompositeRef { get => this.ComplexCompositeRef != null; } + public Composites.ComplexComposite _complexCompositeObj; [XmlIgnore] - public StruSoft.Interop.StruXml.Data.Complex_composite_type ComplexCompositeObj { get; set; } + public Composites.ComplexComposite ComplexCompositeObj + { + get + { + return this._complexCompositeObj; + } + set + { + this._complexCompositeObj = value; + this.ComplexCompositeRef = value.Guid; + + // Composite bars BarPart doesn't have ComplexMaterial and ComplexSection attributes + if (this.HasComplexSectionRef) + { + this.ComplexSectionObj = null; + this.ComplexSectionRef = null; + } + if (this.HasComplexMaterialRef) + { + this.ComplexMaterialObj = null; + this.ComplexMaterialRef = System.Guid.Empty; + } + } + } [XmlAttribute("complex_material")] - public string _complexMaterialRef; + public System.Guid _complexMaterialRef; + + public bool ShouldSerialize_complexMaterialRef() + { + return this.HasComplexMaterialRef; + } [XmlIgnore] public System.Guid ComplexMaterialRef { get { - return System.Guid.Parse(this._complexMaterialRef); + return this._complexMaterialRef; } set { - this._complexMaterialRef = value.ToString(); + this._complexMaterialRef = value; } } + [XmlIgnore] public bool HasComplexMaterialRef { get => this.ComplexMaterialRef != System.Guid.Empty; } @@ -262,10 +313,15 @@ public Materials.Material ComplexMaterialObj } } - [XmlIgnore] - private string _complexSectionRef; - [XmlAttribute("complex_section")] + public string _complexSectionRef; + + public bool ShouldSerialize_complexSectionRef() + { + return this.HasComplexSectionRef; + } + + [XmlIgnore] public string ComplexSectionRef { get @@ -313,7 +369,21 @@ public string ComplexSectionRef public bool HasDeltaBeamComplexSectionRef { get => !System.Guid.TryParse(this.ComplexSectionRef, out System.Guid result); } [XmlIgnore] - public Sections.ComplexSection ComplexSectionObj; + public Sections.ComplexSection _complexSectionObj; + + [XmlIgnore] + public Sections.ComplexSection ComplexSectionObj + { + get + { + return this._complexSectionObj; + } + set + { + this._complexSectionObj = value; + this._complexSectionRef = this._complexSectionObj.Guid.ToString(); + } + } [XmlIgnore] public Sections.Section TrussUniformSectionObj; @@ -369,9 +439,10 @@ public Connectivity[] Connectivity } } - [XmlIgnore] - public ModelEccentricity _eccentricityTypeField; [XmlElement("eccentricity", Order = 4)] + public ModelEccentricity _eccentricityTypeField; + + [XmlIgnore] public ModelEccentricity _eccentricityTypeProperty { get @@ -407,6 +478,7 @@ public ModelEccentricity _eccentricityTypeProperty this._eccentricityTypeField = value; } } + [XmlIgnore] public Eccentricity[] AnalyticalEccentricity { @@ -629,6 +701,51 @@ public BarPart(Geometry.Edge edge, BarType type, Materials.Material material, Se this.CheckMaterialAndSectionType(); } + /// + /// Construct a composite barpart with uniform section and uniform start/end conditions. + /// + public BarPart(Geometry.Edge edge, BarType type, Composites.CompositeSection compositeSection, Eccentricity eccentricity, Connectivity connectivity, string identifier) + { + if (type == BarType.Truss) + { + throw new System.ArgumentException($"Type: {type.ToString()}, is not of type {BarType.Beam.ToString()} or {BarType.Column.ToString()}"); + } + else + { + this.EntityCreated(); + this.Type = type; + this.Edge = edge; + this.ComplexCompositeObj = new Composites.ComplexComposite(compositeSection); + this.EccentricityCalc = true; + this._eccentricityTypeProperty = new ModelEccentricity(eccentricity, true); + this.Connectivity = new Connectivity[1] { connectivity }; + this.Identifier = identifier; + } + } + + /// + /// Construct a composite barpart with uniform section and different start/end conditions. + /// + public BarPart(Geometry.Edge edge, BarType type, Composites.CompositeSection compositeSection, Eccentricity startEccentricity, Eccentricity endEccentricity, Connectivity startConnectivity, Connectivity endConnectivity, string identifier) + { + if (type == BarType.Truss) + { + throw new System.ArgumentException($"Type: {type.ToString()}, is not of type {BarType.Beam.ToString()} or {BarType.Column.ToString()}"); + } + else + { + this.EntityCreated(); + this.Type = type; + this.Edge = edge; + this.ComplexCompositeObj = new Composites.ComplexComposite(compositeSection); + this.EccentricityCalc = true; + this._eccentricityTypeProperty = new ModelEccentricity(startEccentricity, endEccentricity, true); + this.Connectivity = new Connectivity[2] { startConnectivity, endConnectivity }; + this.Identifier = identifier; + } + } + + /// /// Orient this object's coordinate system to GCS /// diff --git a/FemDesign.Core/Bars/BarType.cs b/FemDesign.Core/Bars/BarType.cs index 0528dc364..2cfc599e2 100644 --- a/FemDesign.Core/Bars/BarType.cs +++ b/FemDesign.Core/Bars/BarType.cs @@ -1,4 +1,5 @@ // https://strusoft.com/ +using FemDesign.GenericClasses; using System.Collections.Generic; using System.Linq; using System.Xml.Serialization; @@ -11,10 +12,15 @@ namespace FemDesign.Bars [System.Serializable] public enum BarType { + [Parseable("beam", "Beam", "BEAM")] [XmlEnum("beam")] Beam, + + [Parseable("column", "Column", "COLUMN")] [XmlEnum("column")] Column, + + [Parseable("truss", "Truss", "TRUSS")] [XmlEnum("truss")] Truss }; diff --git a/FemDesign.Core/Bars/Beam.cs b/FemDesign.Core/Bars/Beam.cs index 700694244..6b1317833 100644 --- a/FemDesign.Core/Bars/Beam.cs +++ b/FemDesign.Core/Bars/Beam.cs @@ -29,5 +29,9 @@ public Beam(Geometry.Edge edge, Materials.Material material, Sections.Section st public Beam(Geometry.Edge edge, Materials.Material material, Sections.Section[] sections, Eccentricity[] eccentricities, Connectivity[] connectivities, string identifier) : base(edge, BarType.Beam, material, sections, eccentricities, connectivities, identifier) { } - } + + public Beam(Geometry.Edge edge, Composites.CompositeSection compositeSection, Eccentricity startEccentricity = null, Eccentricity endEccentricity = null, Connectivity startConnectivity = null, Connectivity endConnectivity = null, string identifier = "B") : base(edge, BarType.Beam, compositeSection, startEccentricity, endEccentricity, startConnectivity, endConnectivity, identifier) + { + } + } } diff --git a/FemDesign.Core/Bars/Column.cs b/FemDesign.Core/Bars/Column.cs index 169efc383..1e6abff95 100644 --- a/FemDesign.Core/Bars/Column.cs +++ b/FemDesign.Core/Bars/Column.cs @@ -29,5 +29,9 @@ public Column(Geometry.Edge edge, Materials.Material material, Sections.Section public Column(Geometry.Edge edge, Materials.Material material, Sections.Section[] sections, Eccentricity[] eccentricities, Connectivity[] connectivities, string identifier) : base(edge, BarType.Column, material, sections, eccentricities, connectivities, identifier) { } + + public Column(Geometry.Edge edge, Composites.CompositeSection compositeSection, Eccentricity startEccentricity = null, Eccentricity endEccentricity = null, Connectivity startConnectivity = null, Connectivity endConnectivity = null, string identifier = "B") : base(edge, BarType.Column, compositeSection, startEccentricity, endEccentricity, startConnectivity, endConnectivity, identifier) + { + } } } diff --git a/FemDesign.Core/Composites/ComplexComposite.cs b/FemDesign.Core/Composites/ComplexComposite.cs new file mode 100644 index 000000000..f81ae20ed --- /dev/null +++ b/FemDesign.Core/Composites/ComplexComposite.cs @@ -0,0 +1,98 @@ +// https://strusoft.com/ + +using System; +using System.Collections.Generic; +using System.Xml.Serialization; +using System.Linq; + +namespace FemDesign.Composites +{ + [System.Serializable] + public partial class ComplexComposite : EntityBase + { + [XmlElement("composite_section")] + public List Parts = new List(); + + [XmlIgnore] + public CompositeSection[] CompositeSections + { + get + { + return this.Parts.Select(s => s.CompositeSectionObj).ToArray(); + } + set + { + if (value.Length > 2) + { + throw new System.ArgumentException($"Length of input composite sections: {value.Length}, does not match number of allowed composite sections: 2." + + $" It is ambigious how the sections should be positioned. Create new complex composite section or match input CompositeSection's length."); + } + else if (this.Parts.Count == value.Length) + { + for (int idx = 0; idx < value.Length; idx++) + { + this.Parts[idx].CompositeSectionRef = value[idx].Guid; + this.Parts[idx].CompositeSectionObj = value[idx]; + } + } + else if (this.Parts.Count == 2 && value.Length == 1) + { + this.Parts[0].CompositeSectionRef = value[0].Guid; + this.Parts[0].CompositeSectionObj = value[0]; + + this.Parts[1].CompositeSectionRef = value[0].Guid; + this.Parts[1].CompositeSectionObj = value[0]; + } + } + } + + [XmlIgnore] + public double[] Positions + { + get + { + return this.Parts.Select(p => p.Pos).ToArray(); + } + } + + /// + /// Parameterless constructor for serialization. + /// + private ComplexComposite() + { + + } + + /// + /// Create complex composite from a composite section. Same cross-section at both ends of bar. + /// + /// Composite section + internal ComplexComposite(CompositeSection compositeSection) + { + this.EntityCreated(); + this.Parts.Add(new ComplexCompositePart(0, compositeSection)); + this.Parts.Add(new ComplexCompositePart(1, compositeSection)); + + } + + //public static void CheckComplexComposite(ComplexComposite complex) + //{ + // if (complex.Positions[0] != 0) + // { + // throw new System.Exception($"First position of complex section must be 0 but is: {complex.Parts[0].Pos}"); + // } + // else if (complex.Positions.Last() != 1) + // { + // throw new System.Exception($"Last position of complex section must be 1 but is: {complex.Parts[0].Pos}"); + // } + // else if (complex.Parts.Count > 2) + // { + // throw new System.Exception($"Length of Parts can be up to 2 but is: {complex.Parts.Count}"); + // } + // else if(complex.Parts.Where(p => p != complex.Parts[0]).Any()) + // { + // throw new System.Exception($"The same composite section must be used for each composite section part. Variable cross-sections for composite bars are not available in Fem-Design."); + // } + //} + } +} diff --git a/FemDesign.Core/Composites/ComplexCompositePart.cs b/FemDesign.Core/Composites/ComplexCompositePart.cs new file mode 100644 index 000000000..a380e97ae --- /dev/null +++ b/FemDesign.Core/Composites/ComplexCompositePart.cs @@ -0,0 +1,54 @@ +// https://strusoft.com/ + +using System; +using System.Xml.Serialization; + +namespace FemDesign.Composites +{ + [System.Serializable] + public partial class ComplexCompositePart + { + [XmlAttribute("guid")] + public Guid _compositeSectionRef { get; set; } + + [XmlIgnore] + public Guid CompositeSectionRef + { + get { return this._compositeSectionRef; } + set { this._compositeSectionRef = value; } + } + + [XmlIgnore] + public CompositeSection CompositeSectionObj { get; set; } + + [XmlAttribute("pos")] + public double _pos; + + [XmlIgnore] + public double Pos + { + get { return this._pos; } + set { this._pos = RestrictedDouble.NonNegMax_1(value); } + } + + /// + /// Parameterless constructor for serialization. + /// + private ComplexCompositePart() + { + + } + + /// + /// Constructor to create Composites. + /// + /// Position parameter (0-1). + /// Composite section at pos. + internal ComplexCompositePart(double pos, CompositeSection composite) + { + this.Pos = pos; + this.CompositeSectionObj = composite; + this.CompositeSectionRef = composite.Guid; + } + } +} diff --git a/FemDesign.Core/Composites/CompositeParameterTypeEnum.cs b/FemDesign.Core/Composites/CompositeParameterTypeEnum.cs new file mode 100644 index 000000000..474b18383 --- /dev/null +++ b/FemDesign.Core/Composites/CompositeParameterTypeEnum.cs @@ -0,0 +1,79 @@ +// https://strusoft.com/ + +using System.Xml.Serialization; + +namespace FemDesign.Composites +{ + [System.Serializable] + public enum CompositeSectionParameterType // number values must be expressed in mm + { + [XmlEnum("b")] + b, + + [XmlEnum("b_eff")] + bEff, + + [XmlEnum("bb")] + bb, + + [XmlEnum("bc")] + bc, + + [XmlEnum("bf")] + bf, + + [XmlEnum("bt")] + bt, + + [XmlEnum("cy")] + cy, + + [XmlEnum("cz")] + cz, + + [XmlEnum("d")] + d, + + [XmlEnum("d1")] + d1, + + [XmlEnum("d2")] + d2, + + [XmlEnum("fill_beam")] + FillBeam, + + [XmlEnum("h")] + h, + + [XmlEnum("hc")] + hc, + + [XmlEnum("name")] + Name, + + [XmlEnum("o1")] + o1, + + [XmlEnum("o2")] + o2, + + [XmlEnum("t")] + t, + + [XmlEnum("tf")] + tf, + + [XmlEnum("tfb")] + tfb, + + [XmlEnum("tft")] + tft, + + [XmlEnum("th")] + th, + + [XmlEnum("tw")] + tw, + } +} diff --git a/FemDesign.Core/Composites/CompositeSection.cs b/FemDesign.Core/Composites/CompositeSection.cs new file mode 100644 index 000000000..750f6f45f --- /dev/null +++ b/FemDesign.Core/Composites/CompositeSection.cs @@ -0,0 +1,1203 @@ +// https://strusoft.com/ + +using System; +using System.Xml.Serialization; +using System.Collections.Generic; +using System.Linq; + +using FemDesign.Sections; +using FemDesign.Materials; +using FemDesign.Geometry; +using System.Runtime.CompilerServices; +using System.ComponentModel; + +namespace FemDesign.Composites +{ + [System.Serializable] + public partial class CompositeSection : EntityBase + { + [XmlAttribute("type")] + public CompositeSectionType _type; + + [XmlIgnore] + public CompositeSectionType Type + { + get + { + return this._type; + } + set + { + this._type = value; + } + } + + [XmlElement("part", Order = 1)] + public List Parts { get; set; } + + [XmlIgnore] + public List Materials + { + get + { + List list = new List(); + foreach (var part in this.Parts) + { + list.Add(part.Material); + } + + return list; + } + } + + [XmlIgnore] + public List
Sections + { + get + { + List
list = new List
(); + foreach (var part in this.Parts) + { + list.Add(part.Section); + } + + return list; + } + } + + [XmlElement("property", Order = 2)] + public List ParameterList { get; set; } + + [XmlIgnore] + public Dictionary ParameterDictionary + { + get + { + return ParameterList.ToDictionary(p => p.Name, p => p.Value); + } + } + + /// + /// Parameterless constructor for serialization. + /// + private CompositeSection() + { + + } + + /// + /// Create a composite section with offset. Use this constructor for beam types. For column types offset must be 0. + /// + /// CompositeType enum member. + /// The list of materials corresponding to each composite section part. + /// The list of sections corresponding to each composite section part. + /// Offset of center of each section from center of steel section in Y direction. It must be expressed in meter. + /// Offset of center of each section from center of steel section in Z direction. It must be expressed in meter. + /// List of composite section parameters describing the composite section (e.g. name, geometry, etc.). Values of geometry parameters must be expressed in milimeters. + /// + internal CompositeSection(CompositeSectionType type, List materials, List
sections, double[] offsetY, double[] offsetZ, List parameters) + { + // check incoming data + if ((materials.Count != sections.Count) || (materials.Count != offsetY.Length) || (materials.Count != offsetZ.Length)) + { + throw new ArgumentException("Input variables of materials, sections, offsetY and offsetZ must have the same length."); + } + + this.EntityCreated(); + this.Type = type; + this.ParameterList = parameters; + this.Parts = new List(); + + for (int i = 0; i < materials.Count; i++) + { + this.Parts.Add(new CompositeSectionPart(materials[i], sections[i], offsetY[i], offsetZ[i])); + } + this.CheckCompositeSectionPartList(type, this.Parts); + } + + /// + /// Create a composite section without offset. Use this constructor for column types. + /// + /// CompositeType enum member. + /// The list of materials corresponding to each composite section part. + /// The list of sections corresponding to each composite section part. + /// List of composite section parameters describing the composite section (e.g. name, geometry, etc.). Values of geometry parameters must be expressed in milimeters. + /// + internal CompositeSection(CompositeSectionType type, List materials, List
sections, List parameters) + { + // check incoming data + if (materials.Count != sections.Count) + { + throw new ArgumentException("Input variables of materials and sections must have the same length."); + } + //if (IsOffsetNeeded(type)) + //{ + // throw new ArgumentException("Offset is required. For this type of composite section, the distance of concrete section part from the steel part must be defined."); + //} + + this.EntityCreated(); + this.Type = type; + this.ParameterList = parameters; + this.Parts = new List(); + + for (int i = 0; i < materials.Count; i++) + { + this.Parts.Add(new CompositeSectionPart(materials[i], sections[i])); + } + this.CheckCompositeSectionPartList(type, this.Parts); + } + + /// + /// Create an EffectiveCompositeSlab type CompositeSection object. + /// + /// Steel part material. + /// Concrete part material. + /// Steel section from database. Can be a KKR, VKR or I-profile section type. + /// Composite section name. + /// Slab thickness [mm]. + /// Concrete slab effective width [mm]. + /// Hunch thickness [mm]. + /// Hunch width at the top [mm]. + /// Hunch width at the bottom [mm]. + /// True if steel section is filled with concrete, false if not. + /// + [Description("Waiting for Budapest. GitHub: #802. Fogbugz case: 135669")] + internal static CompositeSection EffectiveCompositeSlab(string name, Material steel, Material concrete, Section steelProfile, double t, double bEff, double th, double bt, double bb, bool filled = false) + { + CheckMaterialFamily(new List { steel }, concrete); + + // check input data + CheckSteelSectionCompatibility(CompositeSectionType.EffectiveCompositeSlab, steelProfile); + + List materials = new List() { steel, concrete }; // !the sequence of steel and concrete materials must match the sequence of steel and concrete sections + List
sections = CreateEffectiveCompositeSlabSection(steelProfile, t, bEff, th, bt, bb, filled); + + List parameters = new List + { + new CompositeSectionParameter(CompositeSectionParameterType.Name, name), + new CompositeSectionParameter(CompositeSectionParameterType.t, t.ToString()), + new CompositeSectionParameter(CompositeSectionParameterType.bEff, bEff.ToString()), + new CompositeSectionParameter(CompositeSectionParameterType.th, th.ToString()), + new CompositeSectionParameter(CompositeSectionParameterType.bt, bt.ToString()), + new CompositeSectionParameter(CompositeSectionParameterType.bb, bb.ToString()), + new CompositeSectionParameter(CompositeSectionParameterType.FillBeam, filled.ToString()) + }; + + return new CompositeSection(CompositeSectionType.EffectiveCompositeSlab, materials, sections, parameters); + } + + /// + /// Create a parametric section for EffectiveCompositeSlab type CompositeSection object. + /// + /// Steel section from database. Can be a KKR, VKR or I-profile section type. + /// Slab thickness [mm]. + /// Concrete slab effective width [mm]. + /// Hunch thickness [mm]. + /// Hunch width at the top [mm]. + /// Hunch width at the bottom [mm]. + /// True if steel section is filled with concrete, false if not. + /// + internal static List CreateEffectiveCompositeSlabSection(Section steelProfile, double t, double bEff, double th, double bt, double bb, bool filled = false) + { + // round inputs + t = Math.Round(t, 2, MidpointRounding.AwayFromZero); + bEff = Math.Round(bEff, 2, MidpointRounding.AwayFromZero); + th = Math.Round(th, 2, MidpointRounding.AwayFromZero); + bt = Math.Round(bt, 2, MidpointRounding.AwayFromZero); + bb = Math.Round(bb, 2, MidpointRounding.AwayFromZero); + + // check inputs + string steelProfileFamiliy = steelProfile.TypeName; + var isRHS = steelProfileFamiliy == FemDesign.Sections.Family.VKR.ToString() || steelProfileFamiliy == FemDesign.Sections.Family.KKR.ToString() || steelProfile.RegionGroup.Regions?.Count > 1 || steelProfile.RegionGroup.Regions[0].Contours.Count > 1; + if (filled && isRHS) + throw new ArgumentException($" For {CompositeSectionType.EffectiveCompositeSlab} composite section types, the RHS profiles must be unfilled!"); + if (t <= 0 || bEff <= 0 || th < 0 || bt <= 0 || bb <= 0) + throw new ArgumentException(" Composite section parameters must be positive, non-zero numbers!"); + if (bt < bb) + throw new ArgumentException(" Hunch width at the top must be greater than or equal to the hunch width at the bottom!"); + if (bEff < bt) + throw new ArgumentException(" Concrete slab effective width top must be greater than or equal to the hunch width at the top!"); + + // conversion of geometric parameters from millimeters to meters + t /= 1000; + bEff /= 1000; + th /= 1000; + bt /= 1000; + bb /= 1000; + + // definition of corner points (order of points matters!) + List points = new List(); + //points.Add(new Point3d(-bEff / 2, heightI / 2 + t + th, 0)); + points.Add(new Point3d(-bEff / 2, 0, 0)); + points.Add(new Point3d(points[0].X, points[0].Y - t, 0)); + points.Add(new Point3d(points[1].X + (bEff - bt) / 2, points[1].Y, 0)); + points.Add(new Point3d(points[2].X + (bt - bb) / 2, points[2].Y - th, 0)); + points.Add(new Point3d(points[3].X + bb, points[3].Y, 0)); + points.Add(new Point3d(points[4].X + (bt - bb) / 2, points[4].Y + th, 0)); + points.Add(new Point3d(points[5].X + (bEff - bt) / 2, points[5].Y, 0)); + points.Add(new Point3d(points[6].X, points[6].Y + t, 0)); + var slabPoints = points.Take(points.Count).ToList(); + + // create contours + Contour steelContour = steelProfile.RegionGroup.Regions[0].Contours[0]; + List steelContours = new List { steelContour }; + + Contour slabContour = new Contour(slabPoints); + List slabContours = new List { slabContour }; + + // create region groups + RegionGroup steelRegion = new RegionGroup(new Region(steelContours)); + RegionGroup slabRegion = new RegionGroup(new Region(slabContours)); + if (filled) + { + Results.SectionProperties secProp = steelProfile.GetSectionProperties(Results.SectionalData.mm); + double heightI = secProp.Height; + double widthI = secProp.Width; + heightI /= 1000; + widthI /= 1000; + + points.Add(new Point3d(widthI / 2, heightI / 2, 0)); + points.Add(new Point3d(-widthI / 2, heightI / 2, 0)); + points.Add(new Point3d(-widthI / 2, -heightI / 2, 0)); + points.Add(new Point3d(widthI / 2, -heightI / 2, 0)); + var fillExtPoints = points.Skip(slabPoints.Count).Take(points.Count - slabPoints.Count).ToList(); + + List fillContours = new List { new Contour(fillExtPoints), steelContour }; + slabRegion = new RegionGroup(new List { new Region(slabContours), new Region(fillContours) }); + } + + // create sections + List
sections = new List
() + { + steelProfile, + new Section(slabRegion, "custom", MaterialTypeEnum.Concrete, "Concrete section", MaterialTypeEnum.Concrete.ToString(), "--") + }; + + return sections; + } + + /// + /// Create a FilledHSQProfile type CompositeSection object. + /// + /// Steel part material. + /// Concrete part material. + /// Composite section name. + /// Intermediate width of the bottom flange [mm]. + /// Top flange width [mm]. + /// Left overhang [mm]. + /// Right overhang [mm]. + /// Web hight [mm]. + /// Web thickness [mm]. + /// Bottom flange thickness [mm]. + /// Top flange thickness [mm]. + /// + public static CompositeSection FilledHSQProfile(string name, Material steel, Material concrete, double b, double bt, double o1, double o2, double h, double tw, double tfb, double tft) + { + CheckMaterialFamily(new List { steel }, concrete); + + List materials = new List() { steel, concrete }; // !the sequence of steel and concrete materials must match the sequence of steel and concrete sections + List
sections = CreateFilledHSQSection(b, bt, o1, o2, h, tw, tfb, tft); + + List parameters = new List + { + new CompositeSectionParameter(CompositeSectionParameterType.Name, name), + new CompositeSectionParameter(CompositeSectionParameterType.b, b.ToString()), + new CompositeSectionParameter(CompositeSectionParameterType.bt, bt.ToString()), + new CompositeSectionParameter(CompositeSectionParameterType.o1, o1.ToString()), + new CompositeSectionParameter(CompositeSectionParameterType.o2, o2.ToString()), + new CompositeSectionParameter(CompositeSectionParameterType.h, h.ToString()), + new CompositeSectionParameter(CompositeSectionParameterType.tw, tw.ToString()), + new CompositeSectionParameter(CompositeSectionParameterType.tfb, tfb.ToString()), + new CompositeSectionParameter(CompositeSectionParameterType.tft, tft.ToString()) + }; + + return new CompositeSection(CompositeSectionType.FilledHSQProfile, materials, sections, parameters); + } + + /// + /// Create a parametric section for FilledHSQProfile type CompositeSection object. + /// + /// Intermediate width of the bottom flange [mm]. + /// Top flange width [mm]. + /// Left overhang [mm]. + /// Right overhang [mm]. + /// Web hight [mm]. + /// Web thickness [mm]. + /// Bottom flange thickness [mm]. + /// Top flange thickness [mm]. + /// + internal static List CreateFilledHSQSection(double b, double bt, double o1, double o2, double h, double tw, double tfb, double tft) + { + // round inputs + b = Math.Round(b, 2, MidpointRounding.AwayFromZero); + bt = Math.Round(bt, 2, MidpointRounding.AwayFromZero); + o1 = Math.Round(o1, 2, MidpointRounding.AwayFromZero); + o2 = Math.Round(o2, 2, MidpointRounding.AwayFromZero); + h = Math.Round(h, 2, MidpointRounding.AwayFromZero); + tw = Math.Round(tw, 2, MidpointRounding.AwayFromZero); + tfb = Math.Round(tfb, 2, MidpointRounding.AwayFromZero); + tft = Math.Round(tft, 2, MidpointRounding.AwayFromZero); + + // check inputs + if (b <= 0 || bt <= 0 || o1 <= 0 || o2 <= 0 || h <= 0 || tw <= 0 || tfb <= 0 || tft <= 0) + throw new ArgumentException(" Composite section parameters must be positive, non-zero numbers!"); + if (bt < b) + throw new ArgumentException(" Top flange width must be greater than or equal to the bottom flange intermediate width!"); + if (tw >= b / 2) + throw new ArgumentException($" Web thickness must be smaller than b/2 = {b / 2}!"); + + // conversion of geometric parameters from millimeters to meters + b /= 1000; + bt /= 1000; + o1 /= 1000; + o2 /= 1000; + h /= 1000; + tw /= 1000; + tfb /= 1000; + tft /= 1000; + + // definition of corner points (order of points matters!) + List points = new List(); + points.Add(new Point3d(-b / 2 + tw, -h / 2, 0)); + points.Add(new Point3d(-points[0].X, points[0].Y, 0)); + points.Add(new Point3d(-points[0].X, -points[0].Y, 0)); + points.Add(new Point3d(points[0].X, -points[0].Y, 0)); + var intPoints = points.Take(4).ToList(); + + points.Add(new Point3d(-b / 2, h / 2, 0)); + points.Add(new Point3d(points[4].X, -points[4].Y, 0)); + points.Add(new Point3d(points[5].X - o1, points[5].Y, 0)); + points.Add(new Point3d(points[6].X, points[6].Y - tfb, 0)); + points.Add(new Point3d(b / 2 + o2, points[7].Y, 0)); + points.Add(new Point3d(points[8].X, points[5].Y, 0)); + points.Add(new Point3d(-points[5].X, points[5].Y, 0)); + points.Add(new Point3d(-points[4].X, points[4].Y, 0)); + if (b / 2 != bt / 2) + { + points.Add(new Point3d(bt / 2, points[4].Y, 0)); + } + points.Add(new Point3d(points[points.Count - 1].X, points[4].Y + tft, 0)); + points.Add(new Point3d(-points[points.Count - 1].X, points[points.Count - 1].Y, 0)); + if (b / 2 != bt / 2) + { + points.Add(new Point3d(points[points.Count - 1].X, points[4].Y, 0)); + } + var extPoints = points.Skip(4).Take(points.Count - 4).ToList(); + + // create contours + var intContour = new Contour(intPoints); + var extContour = new Contour(extPoints); + List contours = new List { extContour, intContour }; + + // define section data + List materialTypes = new List { MaterialTypeEnum.SteelWelded, MaterialTypeEnum.Concrete }; + List groupNames = new List { "Steel section", "Concrete section" }; + List typeNames = materialTypes.Select(x => x.ToString()).ToList(); + + string steelSizeName = $"{bt * 1000}x{tft * 1000}-{h * 1000}x{tw * 1000}-{(b + o1 + o2) * 1000}x{tfb * 1000}"; + string concreteSizeName = $"{(b - 2 * tw) * 1000}x{h * 1000}"; + List sizeNames = new List { steelSizeName, concreteSizeName }; + + + return SectionsFromContours(contours, materialTypes, groupNames, typeNames, sizeNames); + } + + /// + /// Create a FilledDeltaBeamProfile type CompositeSection object. + /// + /// Steel part material. + /// Concrete part material. + /// Delta beam cross-section from database. Can be a D or DR section type. + /// Composite section name. + /// + [Description("Waiting for Budapest. GitHub: #802. Fogbugz case: 135669")] + internal static CompositeSection FilledDeltaBeamProfile(string name, Material steel, Material concrete, Section deltaBeamProfile) + { + CheckMaterialFamily(new List { steel }, concrete); + + // check input data + CheckSteelSectionCompatibility(CompositeSectionType.FilledDeltaBeamProfile, deltaBeamProfile); + + List materials = new List() { steel, concrete }; // !the sequence of steel and concrete materials must match the sequence of steel and concrete sections + List
sections = CreateFilledDeltaBeamSection(deltaBeamProfile); // !CreateFilledDeltaBeamSection() method is not impemented yet + + List parameters = new List + { + new CompositeSectionParameter(CompositeSectionParameterType.Name, name) + }; + + return new CompositeSection(CompositeSectionType.FilledDeltaBeamProfile, materials, sections, parameters); + } + + /// + /// Create a parametric section for FilledDeltaBeamProfile type CompositeSection object. + /// + /// Steel section from database. Can be a D or DR section type. + /// + internal static List CreateFilledDeltaBeamSection(Section deltaBeamProfile) + { + // get contour points for concrete section part + List steelRegions = deltaBeamProfile.RegionGroup.Regions; + List intSideEdgs = GetDeltaBeamSideEdges(steelRegions, out double topPtsY); + List concretePts = GetDeltaBeamInteriorPoints(intSideEdgs, topPtsY); + + // create contours + List concreteContours = new List { new Contour(concretePts) }; + + // create region groups + RegionGroup conreteRegion = new RegionGroup(new Region(concreteContours)); + + // create sections + List
sections = new List
() + { + deltaBeamProfile, + new Section(conreteRegion, "custom", MaterialTypeEnum.Concrete, "Concrete section", MaterialTypeEnum.Concrete.ToString(), "--") + }; + + return sections; + } + + /// + /// Private method for CreateFilledDeltaBeamSection() + /// + /// + /// + /// + private static List GetDeltaBeamSideEdges(List deltaBeamSteelRegions, out double topPtsY) + { + if (deltaBeamSteelRegions?.Count != 4) + throw new ArgumentException("Invalid input section! The input section must be a Deltabeam profile and the number of regions must be 4!"); + + topPtsY = 0; + List sideEdges = new List(); + + foreach (var region in deltaBeamSteelRegions) + { + if (region.Contours?.Count != 1) + throw new ArgumentException("Invalid input section! Number of contours must be 1!"); + + var points = region.Contours[0].Points; + var topPts = points.Where(p => p.Y > 0).ToList(); + + if (topPts.Count == points.Count) + { + topPtsY = points.Select(p => p.Y).Min(); + } + else if (topPts.Count != points.Count && topPts.Count != 0) + { + var edges = region.Contours[0].Edges; + var interiorEdg = edges.OrderBy(e => ((Vector3d)e.GetIntermediatePoint(0.5)).Length()).First(); + + sideEdges.Add(interiorEdg); + } + } + + if (sideEdges?.Count == 0 || topPtsY == 0) + throw new Exception("Invalid section geometry! Deltabeam section origin must be (0,0,0)!"); + + return sideEdges; + } + + /// + /// Private method for CreateFilledDeltaBeamSection() + /// + /// + /// + private static List GetDeltaBeamInteriorPoints(List sideEdges, double topPtsY) + { + Point3d leftBottPt = null; + Point3d leftTopPt = null; + Point3d rightBottPt = null; + Point3d rightTopPt = null; + + foreach (var edg in sideEdges) + { + var pts = edg.Points.OrderBy(p => p.Y).ToList(); + Edge newEdg = new Edge(pts[0], pts[1]); + double h = Math.Abs(pts[0].Y) + Math.Abs(pts[1].Y); + double hi = Math.Abs(pts[0].Y) + topPtsY; + Point3d pi = newEdg.GetIntermediatePoint(hi / h); + if (pts[0].X < 0) + { + leftBottPt = pts[0]; + leftTopPt = pi; + } + else if (pts[0].X > 0) + { + rightBottPt = pts[0]; + rightTopPt = pi; + } + else + { + throw new ArgumentException("Invalid section geometry! Section origin must be (0,0,0)!"); + } + } + + return new List() { leftTopPt, leftBottPt, rightBottPt, rightTopPt }; + } + + /// + /// Create a FilledIProfile type CompositeSection object. + /// + /// Composite section name. + /// Steel part material. + /// Concrete part material. + /// Steel section from database. Must be an I-shaped section type. + /// Concrete cover in Y direction [mm]. + /// Concrete cover in Z direction [mm]. + /// + [Description("Waiting for Budapest. GitHub: #802. Fogbugz case: 135669")] + internal static CompositeSection FilledIProfile(string name, Material steel, Material concrete, Section steelIProfile, double cy, double cz) + { + CheckMaterialFamily(new List { steel }, concrete); + + // check input data + CheckSteelSectionCompatibility(CompositeSectionType.FilledIProfile, steelIProfile); + + List materials = new List() { steel, concrete }; // !the sequence of steel and concrete materials must match the sequence of steel and concrete sections + List
sections = CreateFilledISection(steelIProfile, cy, cz); + + List parameters = new List + { + new CompositeSectionParameter(CompositeSectionParameterType.Name, name), + new CompositeSectionParameter(CompositeSectionParameterType.cy, cy.ToString()), + new CompositeSectionParameter(CompositeSectionParameterType.cz, cz.ToString()) + }; + + return new CompositeSection(CompositeSectionType.FilledIProfile, materials, sections, parameters); + } + + /// + /// Create a parametric section for FilledIProfile type CompositeSection object. + /// + /// Steel section from database. Can be a KKR or VKR section type. + /// Concrete cover in Y direction [mm]. + /// Concrete cover in Z direction [mm]. + /// + internal static List CreateFilledISection(Section steelIProfile, double cy, double cz) + { + // round inputs + cy = Math.Round(cy, 2, MidpointRounding.AwayFromZero); + cz = Math.Round(cz, 2, MidpointRounding.AwayFromZero); + + // check inputs + if (cy < 0 || cz < 0) + throw new ArgumentException(" Composite section parameters must be positive numbers!"); + + // definition of corner points (order of points matters!) + Results.SectionProperties secProp = steelIProfile.GetSectionProperties(Results.SectionalData.mm); + double h = secProp.Height; + double w = secProp.Width; + + // conversion of geometric parameters from millimeters to meters + cy /= 1000; + cz /= 1000; + h /= 1000; + w /= 1000; + + List points = new List(); + points.Add(new Point3d(w / 2 + cy, h / 2 + cz, 0)); + points.Add(new Point3d(-points[0].X, points[0].Y, 0)); + points.Add(new Point3d(-points[0].X, -points[0].Y, 0)); + points.Add(new Point3d(points[0].X, -points[0].Y, 0)); + + // get contours + Contour extContour = new Contour(points); + Contour intContour = steelIProfile.RegionGroup.Regions[0].Contours[0]; + List contours = new List { extContour, intContour }; + + // define section data + MaterialTypeEnum matTypeIProfile = (MaterialTypeEnum)Enum.Parse(typeof(MaterialTypeEnum), steelIProfile.MaterialType); + List materialTypes = new List { MaterialTypeEnum.Concrete, matTypeIProfile }; + List groupNames = new List { "Concrete section", steelIProfile.GroupName }; // !the sequence of steel and concrete materials must match the sequence of steel and concrete sections + List typeNames = new List { MaterialTypeEnum.Concrete.ToString(), steelIProfile.TypeName }; + List sizeNames = new List { "--", steelIProfile.SizeName }; + + var sections = SectionsFromContours(contours, materialTypes, groupNames, typeNames, sizeNames); + sections.Reverse(); + + return sections; + } + + /// + /// Create a FilledCruciformProfile type CompositeSection object. + /// + /// Steel part material. + /// Concrete part material. + /// Composite section name. + /// Cross-section width [mm]. + /// Cross-section height [mm]. + /// Flange width [mm]. + /// Web thickness [mm]. + /// Flange thickness [mm]. + /// + public static CompositeSection FilledCruciformProfile(string name, Material steel, Material concrete, double bc, double hc, double bf, double tw, double tf) + { + CheckMaterialFamily(new List { steel }, concrete); + + List materials = new List() { steel, concrete }; // !the sequence of steel and concrete materials must match the sequence of steel and concrete sections + List
sections = CreateFilledCruciformSection(bc, hc, bf, tw, tf); + + List parameters = new List + { + new CompositeSectionParameter(CompositeSectionParameterType.Name, name), + new CompositeSectionParameter(CompositeSectionParameterType.bc, bc.ToString()), + new CompositeSectionParameter(CompositeSectionParameterType.hc, hc.ToString()), + new CompositeSectionParameter(CompositeSectionParameterType.bf, bf.ToString()), + new CompositeSectionParameter(CompositeSectionParameterType.tw, tw.ToString()), + new CompositeSectionParameter(CompositeSectionParameterType.tf, tf.ToString()) + }; + + return new CompositeSection(CompositeSectionType.FilledCruciformProfile, materials, sections, parameters); + } + + /// + /// Create a parametric section for FilledCruciformProfile type CompositeSection object. + /// + /// Cross-section width [mm]. + /// Cross-section height [mm]. + /// Flange width [mm]. + /// Web thickness [mm]. + /// Flange thickness [mm]. + /// + /// + internal static List CreateFilledCruciformSection(double bc, double hc, double bf, double tw, double tf) + { + // round inputs + bc = Math.Round(bc, 2, MidpointRounding.AwayFromZero); + hc = Math.Round(hc, 2, MidpointRounding.AwayFromZero); + bf = Math.Round(bf, 2, MidpointRounding.AwayFromZero); + tw = Math.Round(tw, 2, MidpointRounding.AwayFromZero); + tf = Math.Round(tf, 2, MidpointRounding.AwayFromZero); + + // check inputs + if (bc <= 0 || hc <= 0 || bf <= 0 || tw <= 0 || tf <= 0 ) + throw new ArgumentException(" Composite section parameters must be positive, non-zero numbers!"); + if (bf <= tw) + throw new ArgumentException(" Flange width must be greater than the thickness of the web!"); + if (bf >= (bc - 2 * tf) && bf >= (hc - 2 * tf)) + throw new ArgumentException(" Flange width must be smaller than the web hight/width!"); + if (tf >= ((bc - bf) / 2) || tf >= ((hc - bf) / 2)) + throw new ArgumentException(" Flange thickness is too big!"); + + // conversion of geometric parameters from millimeters to meters + bc /= 1000; + hc /= 1000; + bf /= 1000; + tw /= 1000; + tf /= 1000; + + // definition of corner points (order of points matters!) + // steel part corner points + List points = new List + { + new Point3d(-bf/2, hc/2, 0), + new Point3d(-bf/2, hc/2-tf, 0), + new Point3d(-tw/2, hc/2-tf, 0), + new Point3d(-tw/2, tw/2, 0), + new Point3d(-bc/2+tf, tw/2, 0), + new Point3d(-bc/2+tf, bf/2, 0), + new Point3d(-bc/2, bf/2, 0), + new Point3d(-bc/2, -bf/2, 0), + new Point3d(-bc/2+tf, -bf/2, 0), + new Point3d(-bc/2+tf, -tw/2, 0), + new Point3d(-tw/2, -tw/2, 0), + new Point3d(-tw/2, -hc/2+tf, 0), + new Point3d(-bf/2, -hc/2+tf, 0), + new Point3d(-bf/2, -hc/2, 0), + new Point3d(bf/2, -hc/2, 0), + new Point3d(bf/2, -hc/2+tf, 0), + new Point3d(tw/2, -hc/2+tf, 0), + new Point3d(tw/2, -tw/2, 0), + new Point3d(bc/2-tf, -tw/2, 0), + new Point3d(bc/2-tf, -bf/2, 0), + new Point3d(bc/2, -bf/2, 0), + new Point3d(bc/2, bf/2, 0), + new Point3d(bc/2-tf, bf/2, 0), + new Point3d(bc/2, tw/2, 0), + new Point3d(tw/2, tw/2, 0), + new Point3d(tw/2, hc/2-tf, 0), + new Point3d(bf/2, hc/2-tf, 0), + new Point3d(bf/2, hc/2, 0) + }; + + // concrete part corner points + List extPoints = new List(); + int d = points.Count / 4 - 1; + int i = 0; + while(i < points.Count) + { + extPoints.Add(points[i]); + i += d; + extPoints.Add(points[i]); + i++; + } + + // create contours + var extContour = new Contour(extPoints); + var intContour = new Contour(points); + List contours = new List { extContour, intContour }; + + // define section data + List materialTypes = new List { MaterialTypeEnum.Concrete, MaterialTypeEnum.SteelWelded }; + List groupNames = new List { "Concrete section", "Steel section" }; // !the sequence of steel and concrete materials must match the sequence of steel and concrete sections + List typeNames = materialTypes.Select(x => x.ToString()).ToList(); + + string concreteSizeName = $"{hc * 1000}-{bc * 1000}"; + string steelSizeName = $"{bf * 1000}x{tf * 1000}-{hc * 1000}x{tw * 1000}-{bc * 1000}x{tw * 1000}"; + List sizeNames = new List { concreteSizeName, steelSizeName }; + + var sections = SectionsFromContours(contours, materialTypes, groupNames, typeNames, sizeNames); + sections.Reverse(); + + return sections; + } + + /// + /// Create a FilledRHSProfile type CompositeSection object. + /// + /// Steel part material. + /// Concrete part material. + /// Steel section from database. Can be a KKR or VKR section type. + /// Composite section name. + /// + [Description("Waiting for Budapest. GitHub: #802. Fogbugz case: 135669")] + internal static CompositeSection FilledRHSProfile(string name, Material steel, Material concrete, Section steelRHSProfile) + { + CheckMaterialFamily(new List { steel }, concrete); + + // check input data + CheckSteelSectionCompatibility(CompositeSectionType.FilledRHSProfile, steelRHSProfile); + + List materials = new List() { steel, concrete }; // !the sequence of steel and concrete materials must match the sequence of steel and concrete sections + List
sections = CreateFilledRHSSection(steelRHSProfile); + + List parameters = new List + { + new CompositeSectionParameter(CompositeSectionParameterType.Name, name) + }; + + return new CompositeSection(CompositeSectionType.FilledRHSProfile, materials, sections, parameters); + } + + /// + /// Create a parametric section for FilledRHSProfile type CompositeSection object. + /// + /// Steel section from database. Can be a KKR or VKR section type. + /// + internal static List CreateFilledRHSSection(Section steelRHSProfile) + { + // get contours + var region = steelRHSProfile.RegionGroup.Regions[0]; + List contours = new List { region.Contours[0], region.Contours[1] }; + + // define section data + MaterialTypeEnum matTypeRHSProfile = (MaterialTypeEnum)Enum.Parse(typeof(MaterialTypeEnum), steelRHSProfile.MaterialType); + List materialTypes = new List { matTypeRHSProfile, MaterialTypeEnum.Concrete }; + List groupNames = new List { steelRHSProfile.GroupName, "Concrete section" }; // !the sequence of steel and concrete materials must match the sequence of steel and concrete sections + List typeNames = new List { steelRHSProfile.TypeName, MaterialTypeEnum.Concrete.ToString() }; + List sizeNames = new List { steelRHSProfile.SizeName, "--" }; + + return SectionsFromContours(contours, materialTypes, groupNames, typeNames, sizeNames); + } + + /// + /// Create a FilledSteelTube type CompositeSection object. + /// + /// Steel tube material. + /// Concrete part material. + /// Composite section name. + /// Steel tube exterior diameter [mm]. + /// Steel tube thickness [mm]. + /// + public static CompositeSection FilledSteelTube(string name, Material steel, Material concrete, double d, double t) + { + CheckMaterialFamily(new List { steel }, concrete); + + List materials = new List() { steel, concrete }; // !the sequence of steel and concrete materials must match the sequence of steel and concrete sections + List
sections = CreateFilledSteelTubeSection(d, t); + + List parameters = new List + { + new CompositeSectionParameter(CompositeSectionParameterType.Name, name), + new CompositeSectionParameter(CompositeSectionParameterType.d, d.ToString()), + new CompositeSectionParameter(CompositeSectionParameterType.t, t.ToString()) + }; + + return new CompositeSection(CompositeSectionType.FilledSteelTube, materials, sections, parameters); + } + + /// + /// Create a parametric section for FilledSteelTube type CompositeSection object. + /// + /// Steel tube exterior diameter [mm]. + /// Steel tube thickness [mm]. + /// + internal static List CreateFilledSteelTubeSection(double d, double t) + { + // round inputs + d = Math.Round(d, 2, MidpointRounding.AwayFromZero); + t = Math.Round(t, 2, MidpointRounding.AwayFromZero); + + // check inputs + if (d <= 0 || t <= 0) + throw new ArgumentException("Composite section parameters must be positive, non zero numbers!"); + if (d <= 2 * t) + throw new ArgumentException($"Diameter must be greater than 2t = {2*t}!"); + + // conversion of geometric parameters from millimeters to meters + d /= 1000; + t /= 1000; + + var center = new Point3d(0, 0, 0); + double extRadius = d / 2; + double intRadius = (d - 2 * t) / 2; + var plane = new Plane(center, Vector3d.UnitX, Vector3d.UnitY); + + var extCircle = new CircleEdge(extRadius, center, plane); + var intCircle = new CircleEdge(intRadius, center, plane); + + // create contours + var extContour = new Contour(new List() { extCircle }); + var intContour = new Contour(new List() { intCircle }); + List contours = new List { extContour, intContour }; + + // define section data + List materialTypes = new List { MaterialTypeEnum.SteelColdWorked, MaterialTypeEnum.Concrete }; + List groupNames = new List { "Steel section", "Concrete section" }; + List typeNames = materialTypes.Select(x => x.ToString()).ToList(); + + string steelSizeName = $"{d * 1000}-{t * 1000}"; + string concreteSizeName = $"{(d - 2 * t) * 1000}"; + List sizeNames = new List { steelSizeName, concreteSizeName }; + + + return SectionsFromContours(contours, materialTypes, groupNames, typeNames, sizeNames); + } + + /// + /// Create a FilledSteelTubeWithIProfile type CompositeSection object. + /// + /// Steel tube's material. + /// I-shaped section's material. + /// Concrete part material. + /// Steel section from database. Must be an I-shaped section type. + /// Composite section name. + /// Steel tube exterior diameter [mm]. + /// Steel tube thickness [mm]. + /// + [Description("Waiting for Budapest. GitHub: #802. Fogbugz case: 135669")] + internal static CompositeSection FilledSteelTubeWithIProfile(string name, Material steelTube, Material steelI, Material concrete, Section steelIProfile, double d, double t) + { + CheckMaterialFamily(new List { steelTube, steelI }, concrete); + + // check input data + CheckSteelSectionCompatibility(CompositeSectionType.FilledSteelTubeWithIProfile, steelIProfile); + + List materials = new List() { steelTube, steelI, concrete }; // !the sequence of steel and concrete materials must match the sequence of steel and concrete sections + List
sections = CreateFilledSteelTubeWithISection(steelIProfile, d, t); + + List parameters = new List + { + new CompositeSectionParameter(CompositeSectionParameterType.Name, name), + new CompositeSectionParameter(CompositeSectionParameterType.d, d.ToString()), + new CompositeSectionParameter(CompositeSectionParameterType.t, t.ToString()) + }; + + return new CompositeSection(CompositeSectionType.FilledSteelTubeWithIProfile, materials, sections, parameters); + } + + /// + /// Create a parametric section for FilledSteelTubeWithIProfile type CompositeSection object. + /// + /// Steel section from database. Must be an I-shaped section type. + /// Steel tube exterior diameter [mm]. + /// Steel tube thickness [mm]. + /// + /// + internal static List CreateFilledSteelTubeWithISection(Section steelIProfile, double d, double t) + { + Results.SectionProperties secProp = steelIProfile.GetSectionProperties(Results.SectionalData.mm); + double h = secProp.Height; + double w = secProp.Width; + double dI = Math.Sqrt(h * h + w * w); + + // round inputs + d = Math.Round(d, 2, MidpointRounding.AwayFromZero); + t = Math.Round(t, 2, MidpointRounding.AwayFromZero); + + // check inputs + if (d <= 0 || t <= 0) + throw new ArgumentException("Composite section parameters must be positive, non-zero numbers!"); + if (d <= 2 * t) + throw new ArgumentException($"Diameter must be greater than 2t = {2 * t}!"); + if (dI >= d - 2 * t) + throw new ArgumentException("Steel tube and 'I' profile partly overlap each other. Increase the tube diameter or select a smaller 'I' profile!"); + + // conversion of geometric parameters from millimeters to meters + d /= 1000; + t /= 1000; + + // definition of edges + var center = new Point3d(0, 0, 0); + double tubeExtRadius = d / 2; + double tubeIntRadius = (d - 2 * t) / 2; + var plane = new Plane(center, Vector3d.UnitX, Vector3d.UnitY); + + var tubeExtEdge = new CircleEdge(tubeExtRadius, center, plane); + var tubeIntEdge = new CircleEdge(tubeIntRadius, center, plane); + + // create contours + var tubeExtContour = new Contour(new List() { tubeExtEdge }); + var tubeIntContour = new Contour(new List() { tubeIntEdge }); + var contourIProfile = steelIProfile.RegionGroup.Regions[0].Contours[0]; + List contours = new List { tubeExtContour, tubeIntContour, contourIProfile }; + + // define section data + MaterialTypeEnum matTypeIProfile = (MaterialTypeEnum)Enum.Parse(typeof(MaterialTypeEnum), steelIProfile.MaterialType); + MaterialTypeEnum matTypeTube = MaterialTypeEnum.SteelWelded; + MaterialTypeEnum matTypeConcrete = MaterialTypeEnum.Concrete; + List materialTypes = new List { matTypeTube, matTypeConcrete, matTypeIProfile }; + List groupNames = new List { "Steel section", "Concrete section", steelIProfile.GroupName }; // !the sequence of steel and concrete materials must match the sequence of steel and concrete sections + List typeNames = new List { matTypeTube.ToString(), matTypeConcrete.ToString(), steelIProfile.TypeName }; + + string steelTubeSizeName = $"{d * 1000}-{t * 1000}"; + string concreteSizeName = $"{(d - 2 * t) * 1000}"; + List sizeNames = new List { steelTubeSizeName, concreteSizeName, steelIProfile.SizeName }; + + var sections = SectionsFromContours(contours, materialTypes, groupNames, typeNames, sizeNames); + sections.Reverse(1, 2); + + return sections; + } + + /// + /// Create a FilledSteelTubeWithSteelCore type CompositeSection object. + /// + /// Steel tube material. + /// Steel core material. + /// Concrete part material. + /// Composite section name. + /// Steel tube exterior diameter [mm]. + /// Steel core diameter [mm]. + /// Steel tube thickness [mm]. + /// + public static CompositeSection FilledSteelTubeWithSteelCore(string name, Material steelTube, Material steelCore, Material concrete, double d1, double d2, double t) + { + CheckMaterialFamily(new List { steelTube, steelCore }, concrete); + + List materials = new List() { steelTube, steelCore, concrete }; // !the sequence of steel and concrete materials must match the sequence of steel and concrete sections + List
sections = CreateFilledSteelTubeWithSteelCoreSection(d1, d2, t); + + List parameters = new List + { + new CompositeSectionParameter(CompositeSectionParameterType.Name, name), + new CompositeSectionParameter(CompositeSectionParameterType.d1, d1.ToString()), + new CompositeSectionParameter(CompositeSectionParameterType.d2, d2.ToString()), + new CompositeSectionParameter(CompositeSectionParameterType.t, t.ToString()) + }; + + return new CompositeSection(CompositeSectionType.FilledSteelTubeWithSteelCore, materials, sections, parameters); + } + + /// + /// Create a parametric section for FilledSteelTubeWithSteelCore type CompositeSection object. + /// + /// Steel tube exterior diameter [mm]. + /// Steel core diameter [mm]. + /// Steel tube thickness [mm]. + /// + /// + internal static List CreateFilledSteelTubeWithSteelCoreSection(double d1, double d2, double t) + { + // round inputs + d1 = Math.Round(d1, 2, MidpointRounding.AwayFromZero); + d2 = Math.Round(d2, 2, MidpointRounding.AwayFromZero); + t = Math.Round(t, 2, MidpointRounding.AwayFromZero); + + // check inputs + if (d1 <= 0 || d2 <= 0 || t <= 0) + throw new ArgumentException("Composite section parameters must be positive, non zero numbers!"); + if (d1 <= 2 * t) + throw new ArgumentException($"Diameter of steel tube must be greater than 2t = {2 * t}!"); + if (d2 >= (d1 - 2 * t)) + throw new ArgumentException($"Diameter of steel core must be smaller than d1 - 2t = {d1 - 2 * t}!"); + + // conversion of geometric parameters from millimeters to meters + d1 /= 1000; + d2 /= 1000; + t /= 1000; + + var center = new Point3d(0, 0, 0); + double tubeExtRadius = d1 / 2; + double tubeIntRadius = (d1 - 2 * t) / 2; + double coreRadius = d2 / 2; + var plane = new Plane(center, Vector3d.UnitX, Vector3d.UnitY); + + var tubeExtEdge = new CircleEdge(tubeExtRadius, center, plane); + var tubeIntEdge = new CircleEdge(tubeIntRadius, center, plane); + var coreEdge = new CircleEdge(coreRadius, center, plane); + + // create contours + var tubeExtContour = new Contour(new List() { tubeExtEdge }); + var tubeIntContour = new Contour(new List() { tubeIntEdge }); + var coreContour = new Contour(new List() { coreEdge }); + List contours = new List { tubeExtContour, tubeIntContour, coreContour }; + + // define section data + List materialTypes = new List { MaterialTypeEnum.SteelWelded, MaterialTypeEnum.Concrete, MaterialTypeEnum.SteelRolled }; + List groupNames = new List { "Steel section", "Concrete section", "Steel section" }; // !the sequence of steel and concrete materials must match the sequence of steel and concrete sections + List typeNames = materialTypes.Select(x => x.ToString()).ToList(); + + string steelTubeSizeName = $"{d1 * 1000}-{t * 1000}"; + string concreteSizeName = $"{(d1 - 2 * t) * 1000}"; + string steelCoreSizeName = $"{(d2) * 1000}"; + List sizeNames = new List { steelTubeSizeName, concreteSizeName, steelCoreSizeName }; + + var sections = SectionsFromContours(contours, materialTypes, groupNames, typeNames, sizeNames); + sections.Reverse(1, 2); + + return sections; + } + + public static void CheckSteelSectionCompatibility(CompositeSectionType type, Section steelSection) + { + // check section material + if (steelSection.MaterialFamily != "Steel") + throw new ArgumentException("Section group name must be Steel!"); + + // check steel section TypeName + string typeName = steelSection.TypeName; + List compatibleSectionTypes = GetCompatibleSteelSectionType(type).Select(f => f.ToString()).ToList(); + + if (!compatibleSectionTypes.Contains(typeName, StringComparer.OrdinalIgnoreCase)) + throw new ArgumentException($"Invalid steel section type. Compatible section types for {type}: {string.Join(", ", compatibleSectionTypes)}."); + } + + public static List GetCompatibleSteelSectionType(CompositeSectionType type) + { + switch (type) + { + case CompositeSectionType.EffectiveCompositeSlab: + return new List() + { + FemDesign.Sections.Family.HE_A, + FemDesign.Sections.Family.HE_B, + FemDesign.Sections.Family.HE_M, + FemDesign.Sections.Family.I, + FemDesign.Sections.Family.IPE, + FemDesign.Sections.Family.UKB, + FemDesign.Sections.Family.UKC, + FemDesign.Sections.Family.KKR, + FemDesign.Sections.Family.VKR + }; + case CompositeSectionType.FilledDeltaBeamProfile: + return new List() + { + FemDesign.Sections.Family.D, + FemDesign.Sections.Family.DR + }; + case CompositeSectionType.FilledIProfile: + return new List() + { + FemDesign.Sections.Family.HE_A, + FemDesign.Sections.Family.HE_B, + FemDesign.Sections.Family.HE_M, + FemDesign.Sections.Family.I, + FemDesign.Sections.Family.IPE, + FemDesign.Sections.Family.UKB, + FemDesign.Sections.Family.UKC + }; + case CompositeSectionType.FilledRHSProfile: + return new List() + { + FemDesign.Sections.Family.KKR, + FemDesign.Sections.Family.VKR + }; + case CompositeSectionType.FilledSteelTubeWithIProfile: + return new List() + { + FemDesign.Sections.Family.HE_A, + FemDesign.Sections.Family.HE_B, + FemDesign.Sections.Family.HE_M, + FemDesign.Sections.Family.I, + FemDesign.Sections.Family.IPE, + FemDesign.Sections.Family.UKB, + FemDesign.Sections.Family.UKC + }; + default: + throw new ArgumentException("For this CompositeSectionType you cannot specify a steel section from database."); + } + } + + internal static void CheckMaterialFamily(List steelMaterials, Material concrete) + { + foreach(var steel in steelMaterials) + { + if(steel.Family != FemDesign.Materials.Family.Steel) + throw new ArgumentException($"Each steel material input parameter must be FemDesign.Materials.Family.Steel, but one of them is: {steel.Family}"); + } + if (concrete.Family != FemDesign.Materials.Family.Concrete) + throw new ArgumentException($"Concrete material input parameter must be FemDesign.Materials.Family.Concrete, but it is: {concrete.Family}"); + } + + internal void CheckCompositeSectionPartList(CompositeSectionType type, List parts) + { + // Check list length. Occurance number is defined in the struxml schema + int listLength = parts.Count; + if (listLength < 2) + { + throw new ArgumentException($"Composite section must have at least 2 section parts, but it has {listLength}."); + } + else if (listLength > 8) + { + throw new ArgumentException($"Composite section may have up to 8 section parts, but it has {listLength}."); + } + + // Check materials + List materialTypes = parts.Select(p => p.Material.Family).ToList(); + int steelNum = materialTypes.Where(m => m == FemDesign.Materials.Family.Steel).Count(); + + if ((!materialTypes.Contains(FemDesign.Materials.Family.Concrete)) || (!materialTypes.Contains(FemDesign.Materials.Family.Steel))) + throw new ArgumentException("Check the material types! Composite section must contain at least one steel and one concrete section part."); + if (type == CompositeSectionType.FilledSteelTubeWithIProfile || type == CompositeSectionType.FilledSteelTubeWithSteelCore) + { + if (steelNum != 2) + throw new ArgumentException($"{type} must have 2 steel composite section parts, but it has {steelNum}."); + } + } + + internal static List SectionsFromContours(List contours, List materialTypes, List groupNames, List typeNames, List sizeNames) + { + // check input lists + if (contours.Count != materialTypes.Count || contours.Count != groupNames.Count || contours.Count != typeNames.Count || contours.Count != sizeNames.Count) + throw new ArgumentException("Length of input lists must be the same!"); + + List
sections = new List
(); + for(int i = 0; i < contours.Count; i++) + { + var region = new Region(); + if(i < contours.Count - 1) + { + region = new Region(new List { contours[i], contours[i + 1] }); + } + else + { + region = new Region(new List { contours[i] }); + } + + var regionGroup = new RegionGroup(region); + + sections.Add(new Section(regionGroup, "custom", materialTypes[i], groupNames[i], typeNames[i], sizeNames[i])); + } + + return sections; + } + + public override string ToString() + { + List parameters = ParameterDictionary.Select(d => d.Key + " = " + d.Value).ToList(); + return $"{Type}, Materials: {string.Join(", ", this.Materials.Select(m => m.Name).ToList())}, Parameters: {string.Join(", ", parameters)}"; + } + } +} \ No newline at end of file diff --git a/FemDesign.Core/Composites/CompositeSectionParameter.cs b/FemDesign.Core/Composites/CompositeSectionParameter.cs new file mode 100644 index 000000000..d70752ef1 --- /dev/null +++ b/FemDesign.Core/Composites/CompositeSectionParameter.cs @@ -0,0 +1,43 @@ +// https://strusoft.com/ + +using System; +using System.Xml.Serialization; +using System.Collections.Generic; +using System.Linq; + +namespace FemDesign.Composites +{ + [System.Serializable] + public partial class CompositeSectionParameter + { + [XmlAttribute("name")] + public CompositeSectionParameterType Name { get; set; } + + [XmlAttribute("value")] + public string Value { get; set; } + + + /// + /// Parameterless constructor for serialization + /// + private CompositeSectionParameter() + { + + } + + /// + /// Construct a new CompositeSectionParameter. + /// + /// Parameter name. + /// Parameter value. Number values must be expressed in milimeter. + internal CompositeSectionParameter(CompositeSectionParameterType paramName, string paramValue) + { + if ((paramName == CompositeSectionParameterType.Name) && (paramValue == null)) + throw new ArgumentException("Name parameter cannot be null."); + + this.Name = paramName; + this.Value = paramValue; + } + + } +} diff --git a/FemDesign.Core/Composites/CompositeSectionPart.cs b/FemDesign.Core/Composites/CompositeSectionPart.cs new file mode 100644 index 000000000..ac0563073 --- /dev/null +++ b/FemDesign.Core/Composites/CompositeSectionPart.cs @@ -0,0 +1,149 @@ +// https://strusoft.com/ + +using System; +using System.Xml.Serialization; +using System.Collections.Generic; +using System.Linq; + +namespace FemDesign.Composites +{ + [System.Serializable] + public partial class CompositeSectionPart + { + [XmlAttribute("material")] + public Guid _materialRef; + + [XmlIgnore] + public Guid MaterialRef + { + get + { + return this._materialRef; + } + set + { + this._materialRef = value; + } + } + + [XmlIgnore] + public Materials.Material _material; + + [XmlIgnore] + public Materials.Material Material + { + get + { + return this._material; + } + set + { + this._material = value; + this.MaterialRef = value.Guid; + } + } + + [XmlAttribute("section")] + public Guid _sectionRef; + + [XmlIgnore] + public Guid SectionRef + { + get { return this._sectionRef; } + set { this._sectionRef = value; } + } + + [XmlIgnore] + public Sections.Section _section; + + [XmlIgnore] + public Sections.Section Section + { + get + { + return this._section; + } + set + { + if (value.SizeName == null || value.SizeName == " ") + throw new ArgumentException("SizeName in Section object, must be a non-empty value."); + this._section = value; + this._sectionRef = value.Guid; + } + } + + [XmlAttribute("cog_offset_x")] + public double _offsetY; + + [XmlIgnore] + public double OffsetY + { + get { return _offsetY; } + set { _offsetY = value; } + } + + [XmlAttribute("cog_offset_y")] + public double _offsetZ; + + [XmlIgnore] + public double OffsetZ + { + get { return _offsetZ; } + set { _offsetZ = value; } + } + + /// + /// Parameterless constructor for serialization. + /// + private CompositeSectionPart() + { + + } + + /// + /// Construct a new composite section part with offset. This is for composite section types where the centre of the concrete and steel sections are not at the same point (e.g. beam composite types) + /// + /// Material of composite section part. Can be steel or concrete. + /// Section part. + /// Offset of concrete section's centre from steel section's center in Y direction. It must be expressed in meter. + /// Offset of concrete section's centre from steel section's center in Z direction. It must be expressed in meter. + internal CompositeSectionPart(Materials.Material material, Sections.Section section, double offsetY, double offsetZ) + { + CheckCompositeSectionPart(material, section); + + this.Material = material; + this.Section = section; + this.OffsetY = offsetY; + this.OffsetZ = offsetZ; + } + + /// + /// Construct a new composite section part without offset. This is for composite section types where the centre of the concrete and steel sections are at the same point (e.g. column composite types). + /// + /// Material of composite section part. Can be steel or concrete. + /// Section part. + /// + internal CompositeSectionPart(Materials.Material material, Sections.Section section) + { + CheckCompositeSectionPart(material, section); + + this.Material = material; + this.Section = section; + } + + internal void CheckCompositeSectionPart(Materials.Material material, Sections.Section section) + { + if ((material.Family == Materials.Family.Steel) || (material.Family == Materials.Family.Concrete)) + { + //pass + } + else + { + throw new ArgumentException("Material must be steel or concrete!"); + } + if (section.MaterialFamily != material.Family.ToString()) + throw new ArgumentException("Section material type doesn't match the specified material type"); + } + + } +} diff --git a/FemDesign.Core/Composites/CompositeTypeEnum.cs b/FemDesign.Core/Composites/CompositeTypeEnum.cs new file mode 100644 index 000000000..76f74bfbc --- /dev/null +++ b/FemDesign.Core/Composites/CompositeTypeEnum.cs @@ -0,0 +1,37 @@ +// https://strusoft.com/ + +using System.Xml.Serialization; + +namespace FemDesign.Composites +{ + [System.Serializable] + public enum CompositeSectionType + { + [XmlEnum("beam_a")] + EffectiveCompositeSlab, + + [XmlEnum("beam_b")] + FilledHSQProfile, + + [XmlEnum("beam_p")] + FilledDeltaBeamProfile, + + [XmlEnum("column_a")] + FilledIProfile, + + [XmlEnum("column_c")] + FilledCruciformProfile, + + [XmlEnum("column_d")] + FilledRHSProfile, + + [XmlEnum("column_e")] + FilledSteelTube, + + [XmlEnum("column_f")] + FilledSteelTubeWithIProfile, + + [XmlEnum("column_g")] + FilledSteelTubeWithSteelCore, + } +} diff --git a/FemDesign.Core/Composites/Composites.cs b/FemDesign.Core/Composites/Composites.cs new file mode 100644 index 000000000..f65657c74 --- /dev/null +++ b/FemDesign.Core/Composites/Composites.cs @@ -0,0 +1,20 @@ +// https://strusoft.com/ + +using System.Collections.Generic; +using System.Xml.Serialization; + +namespace FemDesign.Composites +{ + /// + /// composites + /// + [System.Serializable] + public partial class Composites + { + [XmlElement("composite_section", Order = 1)] + public List CompositeSection = new List(); + + [XmlElement("complex_composite", Order = 2)] + public List ComplexComposite = new List(); + } +} diff --git a/FemDesign.Core/FemDesign.Core.csproj b/FemDesign.Core/FemDesign.Core.csproj index d28cae616..a0e15a7ee 100644 --- a/FemDesign.Core/FemDesign.Core.csproj +++ b/FemDesign.Core/FemDesign.Core.csproj @@ -78,6 +78,14 @@ + + + + + + + + diff --git a/FemDesign.Core/Geometry/Contour.cs b/FemDesign.Core/Geometry/Contour.cs index 4ca62b8ac..d88ef9a5a 100644 --- a/FemDesign.Core/Geometry/Contour.cs +++ b/FemDesign.Core/Geometry/Contour.cs @@ -131,7 +131,6 @@ internal Contour() /// /// Construct Contour from Edges. - /// /// Edges should form a closed contour. /// public Contour(List edges) @@ -139,6 +138,29 @@ public Contour(List edges) this.Edges = edges; } + /// + /// Construct a closed contour from points. + /// + /// + public Contour(List points) + { + List edges = new List(); + + for (int i = 0; i < points.Count; i++) + { + if (i < points.Count - 1) + { + edges.Add(new Edge(points[i], points[i + 1])); + } + else + { + edges.Add(new Edge(points[i], points[0])); + } + } + + this.Edges = edges; + } + /// /// Reverse direction of edges in this contour /// diff --git a/FemDesign.Core/Model/Model.cs b/FemDesign.Core/Model/Model.cs index ae34e5975..b7f88565f 100644 --- a/FemDesign.Core/Model/Model.cs +++ b/FemDesign.Core/Model/Model.cs @@ -72,7 +72,7 @@ public partial class Model [XmlElement("reinforcing_materials", Order = 5)] public Materials.ReinforcingMaterials ReinforcingMaterials { get; set; } [XmlElement("composites", Order = 6)] - public StruSoft.Interop.StruXml.Data.DatabaseComposites Composites { get; set; } + public Composites.Composites Composites { get; set; } [XmlElement("point_connection_types", Order = 7)] public LibraryItems.PointConnectionTypes PointConnectionTypes { get; set; } [XmlElement("point_support_group_types", Order = 8)] @@ -195,6 +195,10 @@ private void Initialize(Country country) { this.Materials = new Materials.Materials(); } + if (this.Composites == null) + { + this.Composites = new Composites.Composites(); + } if (this.ReinforcingMaterials == null) { this.ReinforcingMaterials = new Materials.ReinforcingMaterials(); @@ -244,7 +248,7 @@ public static Model DeserializeFromFilePath(string filePath) // cast type Model model = (Model)obj; - if (model.Entities == null) model.Entities = new Entities(); + if (model.Entities == null) model.Entities = new Entities(); // prepare elements with library reference // Check if there are any elements of type to avoid null checks on each library type (sections, materials etc.) in each method below @@ -752,70 +756,84 @@ private bool ComplexSectionInModel(FemDesign.Sections.ComplexSection obj) /// /// Check if CompositeSection in Model. /// - private void AddCompositeSection(StruSoft.Interop.StruXml.Data.Complex_composite_type obj, bool overwrite) + private void AddCompositeSection(Composites.ComplexComposite obj, bool overwrite) { // in model? // obj.Composite_section.Unique(x => x.Guid); - var uniqueCompositeSection = obj.Composite_section.Where(x => x.Guid != null).GroupBy(x => x.Guid).Select(grp => grp.FirstOrDefault()); + var uniqueComplexCompositePart = obj.Parts.Where(x => x.CompositeSectionRef != null).GroupBy(x => x.CompositeSectionRef).Select(grp => grp.FirstOrDefault()); - foreach (var compositeSection in uniqueCompositeSection) + foreach (var complexCompositePart in uniqueComplexCompositePart) { // initialise variable as false bool inModel = false; - if (this.Composites.Composite_section != null) + if (this.Composites.CompositeSection != null) { - inModel = this.Composites.Composite_section.Any(x => x.Guid == compositeSection.Guid); + inModel = this.Composites.CompositeSection.Any(x => x.Guid == complexCompositePart.CompositeSectionRef); + + // check section name + var names = this.Composites.CompositeSection.Select(c => c.ParameterDictionary[FemDesign.Composites.CompositeSectionParameterType.Name]).ToList(); + var objName = complexCompositePart.CompositeSectionObj.ParameterDictionary[FemDesign.Composites.CompositeSectionParameterType.Name]; + if (names.Any(n => String.Equals(n, objName))) + throw new Exception("One or more composite sections have the same name. Different composite sections must have different names!"); } else { - this.Composites.Composite_section = new List(); + this.Composites.CompositeSection = new List(); } // in model, don't overwrite if (inModel && overwrite == false) { - throw new System.ArgumentException($"{compositeSection.GetType().FullName} with guid: {compositeSection.Guid} has already been added to model. Are you adding the same element twice?"); + //throw new System.ArgumentException($"{complexCompositePart.GetType().FullName} with guid: {complexCompositePart.CompositeSectionRef} has already been added to model. Are you adding the same element twice?"); } // in model, overwrite else if (inModel && overwrite == true) { - this.Composites.Composite_section.RemoveAll(x => x.Guid == compositeSection.Guid); + this.Composites.CompositeSection.RemoveAll(x => x.Guid == complexCompositePart.CompositeSectionRef); + this.Composites.CompositeSection.Add(complexCompositePart.CompositeSectionObj); + foreach (var part in complexCompositePart.CompositeSectionObj.Parts) + { + this.AddMaterial(part.Material, overwrite); + this.AddSection(part.Section, overwrite); + } } - // add complex composite - this.Composites.Composite_section.Add(compositeSection.CompositeSectionDataObj); - foreach (var part in compositeSection.CompositeSectionDataObj.Part) + // not in model + if (!inModel) + { - this.AddMaterial(part.MaterialObj, overwrite); - this.AddSection(part.SectionObj, overwrite); + this.Composites.CompositeSection.Add(complexCompositePart.CompositeSectionObj); + foreach (var part in complexCompositePart.CompositeSectionObj.Parts) + { + this.AddMaterial(part.Material, overwrite); + this.AddSection(part.Section, overwrite); + } } } } - - /// /// Add ComplexComposite to Model. - /// if ComplexComposite is present, also compositeSection will be created + /// if ComplexComposite is present, also CompositeSection will be created /// - private void AddComplexComposite(StruSoft.Interop.StruXml.Data.Complex_composite_type obj, bool overwrite) + private void AddComplexComposite(Composites.ComplexComposite obj, bool overwrite) { // in model? bool inModel = false; // if composites present if (this.Composites != null) { - inModel = this.Composites.Complex_composite.Any(x => x.Guid == obj.Guid); + inModel = this.Composites.ComplexComposite.Any(x => x.Guid == obj.Guid); } // if composites not present else { - this.Composites = new StruSoft.Interop.StruXml.Data.DatabaseComposites(); - this.Composites.Complex_composite = new List(); + this.Composites = new Composites.Composites(); + this.Composites.ComplexComposite = new List(); } // in model, don't overwrite @@ -827,17 +845,25 @@ private void AddComplexComposite(StruSoft.Interop.StruXml.Data.Complex_composite // in model, overwrite else if (inModel && overwrite == true) { - this.Composites.Complex_composite.RemoveAll(x => x.Guid == obj.Guid); + // remove objects with the same GUID + this.Composites.ComplexComposite.RemoveAll(x => x.Guid == obj.Guid); + // add complex composite + this.Composites.ComplexComposite.Add(obj); + // add composite section + this.AddCompositeSection(obj, overwrite); } - // add complex composite - this.Composites.Complex_composite.Add(obj); + // not in model + if (!inModel) + { + // add complex composite + this.Composites.ComplexComposite.Add(obj); - // add composite section - this.AddCompositeSection(obj, overwrite); + // add composite section + this.AddCompositeSection(obj, overwrite); + } } - /// /// Add Cover to Model. /// @@ -1390,7 +1416,7 @@ private bool ExcitationLoadInModel() return false; } - private void AddPeriodicExcitationForce(Loads.PeriodicLoad obj, bool overwrite) + private void AddPeriodicExcitationForceRecords(Loads.PeriodicLoad obj, bool overwrite) { // in model? bool inModel = this.PeriodicExcitationForceInModel(); @@ -3757,7 +3783,7 @@ public Model AddSupports(params T[] supports) where T : ISupportElement private void AddEntity(Loads.ExcitationForce obj, bool overwrite) => AddExcitationForce(obj, overwrite); private void AddEntity(Loads.PeriodicExcitation obj, bool overwrite) => AddPeriodicExcitationForce(obj, overwrite); - private void AddEntity(Loads.PeriodicLoad obj, bool overwrite) => AddPeriodicExcitationForce(obj, overwrite); + private void AddEntity(Loads.PeriodicLoad obj, bool overwrite) => AddPeriodicExcitationForceRecords(obj, overwrite); private void AddEntity(Loads.LoadCase obj, bool overwrite) => AddLoadCase(obj, overwrite); private void AddEntity(Loads.LoadCombination obj, bool overwrite) => AddLoadCombination(obj, overwrite); @@ -3777,15 +3803,34 @@ public Model AddSupports(params T[] supports) where T : ISupportElement internal void GetBars() { Dictionary complexSectionsMap = this.Sections.ComplexSection.ToDictionary(s => s.Guid, s => s.DeepClone()); - Dictionary materialMap = this.Materials.Material.ToDictionary(d => d.Guid, d => d.DeepClone()); Dictionary sectionsMap = this.Sections.Section.ToDictionary(s => s.Guid, s => s.DeepClone()); - Dictionary complexCompositeMap = new Dictionary(); - Dictionary compositeSectionMap = new Dictionary(); + Dictionary materialMap = this.Materials.Material.ToDictionary(d => d.Guid, d => d.DeepClone()); + Dictionary complexCompositeMap = new Dictionary(); + Dictionary compositeSectionMap = new Dictionary(); if (this.Composites != null) { - complexCompositeMap = this.Composites.Complex_composite.ToDictionary(s => Guid.Parse(s.Guid), s => s.DeepClone()); - compositeSectionMap = this.Composites.Composite_section.ToDictionary(s => Guid.Parse(s.Guid), s => s.DeepClone()); + // assign the material and section objects to the CompositeSectionPart + foreach (var compositeSection in this.Composites.CompositeSection) + { + foreach (var part in compositeSection.Parts) + { + part.Material = materialMap[part.MaterialRef]; + part.Section = sectionsMap[part.SectionRef]; + } + } + + compositeSectionMap = this.Composites.CompositeSection.ToDictionary(s => s.Guid, s => s.DeepClone()); + complexCompositeMap = this.Composites.ComplexComposite.ToDictionary(s => s.Guid, s => s.DeepClone()); + + // assign the CompositeSection object to the ComplexCompositePart + foreach (var complexComposite in this.Composites.ComplexComposite) + { + foreach (var part in complexComposite.Parts) + { + part.CompositeSectionObj = compositeSectionMap[part.CompositeSectionRef]; + } + } } foreach (Bars.Bar item in this.Entities.Bars) @@ -3872,29 +3917,18 @@ internal void GetBars() { try { - // assign the Complex Composite Object to the bar part - item.BarPart.ComplexCompositeObj = complexCompositeMap[new System.Guid(item.BarPart.ComplexCompositeRef)]; - - // iterate over the composite section inside the complex composite and assign the object from the database Composite - foreach (StruSoft.Interop.StruXml.Data.Composite_section_type compositeSection in item.BarPart.ComplexCompositeObj.Composite_section) - { - compositeSection.CompositeSectionDataObj = compositeSectionMap[Guid.Parse(compositeSection.Guid)]; - } + // assign the ComplexComposite Object to the bar part + item.BarPart.ComplexCompositeObj = complexCompositeMap[item.BarPart.ComplexCompositeRef]; - // assign the material object to the Composite_part_type - // it might be clever to move this method outside the loop and call it (add compositePart) - foreach (var compositeSection in item.BarPart.ComplexCompositeObj.Composite_section) + // iterate over the CompositeSection inside the ComplexComposite and assign the object from the Composites + foreach (Composites.ComplexCompositePart complexCompositePart in item.BarPart.ComplexCompositeObj.Parts) { - foreach (var compositePart in compositeSection.CompositeSectionDataObj.Part) - { - compositePart.MaterialObj = materialMap[Guid.Parse(compositePart.Material)]; - compositePart.SectionObj = sectionsMap[Guid.Parse(compositePart.Section)]; - } + complexCompositePart.CompositeSectionObj = compositeSectionMap[complexCompositePart.CompositeSectionRef]; } } catch (KeyNotFoundException) { - throw new ArgumentException("No matching complex composite or composite section"); + throw new ArgumentException("No matching complex composite or composite section."); } } else diff --git a/FemDesign.Core/Sections/Section.cs b/FemDesign.Core/Sections/Section.cs index 832e17717..bc9d3194b 100644 --- a/FemDesign.Core/Sections/Section.cs +++ b/FemDesign.Core/Sections/Section.cs @@ -217,13 +217,15 @@ public static Section SectionByName(this List sectio return sections[extr.Index]; } - public static List GetSectionProperties(this Section section, Results.SectionalData sectionUnits = Results.SectionalData.mm, string fdInstallationDir = null) + + public static Results.SectionProperties GetSectionProperties(this Section section, Results.SectionalData sectionUnits = Results.SectionalData.mm, string fdInstallationDir = null) { // Check input if (section == null) throw new ArgumentNullException("'section' input cannot be null!"); - return GetSectionProperties(new List
{ section }, sectionUnits, fdInstallationDir); + var secProp = GetSectionProperties(new List
{ section }, sectionUnits, fdInstallationDir); + return secProp[0]; } public static List GetSectionProperties(this List
sections, Results.SectionalData sectionUnits = Results.SectionalData.mm, string fdInstallationDir = null) diff --git a/FemDesign.Grasshopper/Bars/CompositeBar.cs b/FemDesign.Grasshopper/Bars/CompositeBar.cs new file mode 100644 index 000000000..b0604f4f7 --- /dev/null +++ b/FemDesign.Grasshopper/Bars/CompositeBar.cs @@ -0,0 +1,145 @@ +// https://strusoft.com/ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +using Grasshopper.Kernel; +using Rhino.Geometry; + +using FemDesign; + +using FemDesign.Grasshopper.Extension.ComponentExtension; +using Grasshopper.Kernel.Special; +using FemDesign.Bars; + +namespace FemDesign.Grasshopper +{ + public class CompositeBar : FEM_Design_API_Component + { + public CompositeBar() : base("Bars.CompositeBar", "CompositeBar", "Create a steel-concrete composite bar element.", CategoryName.Name(), SubCategoryName.Cat2a()) + { + + } + protected override void RegisterInputParams(GH_InputParamManager pManager) + { + pManager.AddCurveParameter("Curve", "Curve", "LineCurve or ArcCurve", GH_ParamAccess.item); + pManager.AddGenericParameter("BarType", "Type", "Connect 'ValueList' to get the options.\nBarType can be:\nBeam\nColumn\n\nDefault value is Beam.", GH_ParamAccess.item); + pManager[pManager.ParamCount - 1].Optional = true; + pManager.AddGenericParameter("CompositeSection", "Section", "Steel-concrete composite section.", GH_ParamAccess.item); + pManager.AddGenericParameter("Connectivity", "Connectivity", "Connectivity. If 1 item this item defines both start and end. If two items the first item defines the start and the last item defines the end.", GH_ParamAccess.list); + pManager[pManager.ParamCount - 1].Optional = true; + pManager.AddGenericParameter("Eccentricity", "Eccentricity", "Eccentricity.", GH_ParamAccess.list); + pManager[pManager.ParamCount - 1].Optional = true; + pManager.AddVectorParameter("LocalY", "LocalY", "Set local y-axis. Vector must be perpendicular to Curve mid-point local x-axis. This parameter overrides OrientLCS.", GH_ParamAccess.item); + pManager[pManager.ParamCount - 1].Optional = true; + pManager.AddBooleanParameter("OrientLCS", "OrientLCS", "Orient LCS to GCS? If true the LCS of this object will be oriented to the GCS trying to align local z to global z if possible or align local y to global y if possible (if object is vertical). If false local y-axis from Curve coordinate system at mid-point will be used.", GH_ParamAccess.item, true); + pManager[pManager.ParamCount - 1].Optional = true; + pManager.AddTextParameter("Identifier", "Identifier", "", GH_ParamAccess.item, "B"); + pManager[pManager.ParamCount - 1].Optional = true; + } + protected override void RegisterOutputParams(GH_OutputParamManager pManager) + { + pManager.AddGenericParameter("CompositeBar", "Bar", "Steel-concrete composite bar element.", GH_ParamAccess.item); + } + protected override void BeforeSolveInstance() + { + var valListNames = new List() { Bars.BarType.Beam.ToString(), Bars.BarType.Column.ToString() }; + ValueListUtils.UpdateValueLists(this, 1, valListNames, null, GH_ValueListMode.DropDown); + } + protected override void SolveInstance(IGH_DataAccess DA) + { + // get input + Curve curve = null; + if (!DA.GetData(0, ref curve)) { return; } + + string barType = Bars.BarType.Beam.ToString(); + DA.GetData(1, ref barType); + BarType _barType = FemDesign.GenericClasses.EnumParser.Parse(barType); + + Composites.CompositeSection section = null; + if (!DA.GetData(2, ref section)) { return; } + + List connectivity = new List(); + if (!DA.GetDataList(3, connectivity)) + { + var endConn = new List() { Bars.Connectivity.Rigid, Bars.Connectivity.Rigid }; + connectivity.AddRange(endConn); + } + + if (connectivity.Count == 1) + { + connectivity.Add(connectivity[0]); + } + else if (connectivity.Count != 2) + { + throw new ArgumentException("Connectivity list lenght must be equal to 1 or 2!"); + } + + List eccentricity = new List(); + if (!DA.GetDataList(4, eccentricity)) + { + var ecc = new List() { Bars.Eccentricity.Default, Bars.Eccentricity.Default }; + eccentricity.AddRange(ecc); + } + if (eccentricity.Count == 1) + { + eccentricity.Add(eccentricity[0]); + } + else if (eccentricity.Count != 2) + { + throw new ArgumentException("Eccentricity list lenght must be equal to 1 or 2!"); + } + + Vector3d v = Vector3d.Zero; + DA.GetData(5, ref v); + + bool orientLCS = true; + DA.GetData(6, ref orientLCS); + + string identifier = "B"; + DA.GetData(7, ref identifier); + + // check input data + if (curve == null || section == null || connectivity == null || eccentricity == null || identifier == null) + { + return; + } + if (_barType == Bars.BarType.Truss) + { + throw new ArgumentException($"BarType must be Beam or Column, but it is {barType}."); + } + + // create composite bar + Geometry.Edge line = curve.FromRhinoLineOrArc2(); + var bar = new Bars.Bar(line, _barType, section, eccentricity[0], eccentricity[1], connectivity[0], connectivity[1], identifier); + + // set local y-axis + if (!v.Equals(Vector3d.Zero)) + { + bar.BarPart.LocalY = v.FromRhino(); + } + // else orient coordinate system to GCS + else if (orientLCS) + { + bar.BarPart.OrientCoordinateSystemToGCS(); + } + + // get output + DA.SetData(0, bar); + v.IsPerpendicularTo(v); + } + protected override System.Drawing.Bitmap Icon + { + get + { + return FemDesign.Properties.Resources.BeamDefine; + } + } + public override Guid ComponentGuid + { + get { return new Guid("{4C301630-8109-4962-8933-0FFCCAE39501}"); } + } + public override GH_Exposure Exposure => GH_Exposure.primary; + } +} \ No newline at end of file diff --git a/FemDesign.Grasshopper/Deconstruct/SectionDeconstruct _OBSOLETE2307.cs b/FemDesign.Grasshopper/Deconstruct/SectionDeconstruct _OBSOLETE2307.cs new file mode 100644 index 000000000..9a7fcf826 --- /dev/null +++ b/FemDesign.Grasshopper/Deconstruct/SectionDeconstruct _OBSOLETE2307.cs @@ -0,0 +1,60 @@ +// https://strusoft.com/ +using System; +using Grasshopper.Kernel; + +namespace FemDesign.Grasshopper +{ + public class SectionDeconstruct_OBSOLETE2307: FEM_Design_API_Component + { + public SectionDeconstruct_OBSOLETE2307(): base("Section.Deconstruct", "Deconstruct", "Deconstruct a Section.", "FEM-Design", "Deconstruct") + { + + } + protected override void RegisterInputParams(GH_InputParamManager pManager) + { + pManager.AddGenericParameter("Section", "Section", "Section.", GH_ParamAccess.item); + } + protected override void RegisterOutputParams(GH_OutputParamManager pManager) + { + pManager.AddTextParameter("Guid", "Guid", "Guid.", GH_ParamAccess.item); + pManager.AddTextParameter("Name", "Name", "Name.", GH_ParamAccess.item); + pManager.AddBrepParameter("Surfaces", "Surfaces", "Surfaces.", GH_ParamAccess.list); + pManager.AddTextParameter("SectionType", "SectionType", "SectionType.", GH_ParamAccess.item); + pManager.AddTextParameter("MaterialType", "MaterialType", "MaterialType.", GH_ParamAccess.item); + pManager.AddTextParameter("GroupName", "GroupName", "GroupName.", GH_ParamAccess.item); + pManager.AddTextParameter("TypeName", "TypeName", "TypeName.", GH_ParamAccess.item); + pManager.AddTextParameter("SizeName", "SizeName", "SizeName.", GH_ParamAccess.item); + } + protected override void SolveInstance(IGH_DataAccess DA) + { + FemDesign.Sections.Section obj = null; + if (!DA.GetData(0, ref obj)) + { + return; + } + + DA.SetData(0, obj.Guid); + DA.SetData(1, obj.Name); + DA.SetDataList(2, obj.RegionGroup.ToRhino()); + DA.SetData(3, obj.Type); + DA.SetData(4, obj.MaterialType); + DA.SetData(5, obj.GroupName); + DA.SetData(6, obj.TypeName); + DA.SetData(7, obj.SizeName); + } + protected override System.Drawing.Bitmap Icon + { + get + { + return FemDesign.Properties.Resources.SectionDeconstruct; + } + } + public override Guid ComponentGuid + { + get { return new Guid("79ff17b1-387a-44e1-9596-981b8a96e847"); } + } + + public override GH_Exposure Exposure => GH_Exposure.hidden; + + } +} \ No newline at end of file diff --git a/FemDesign.Grasshopper/Deconstruct/SectionDeconstruct.cs b/FemDesign.Grasshopper/Deconstruct/SectionDeconstruct.cs index 5e8d452e2..149810399 100644 --- a/FemDesign.Grasshopper/Deconstruct/SectionDeconstruct.cs +++ b/FemDesign.Grasshopper/Deconstruct/SectionDeconstruct.cs @@ -1,6 +1,9 @@ // https://strusoft.com/ using System; +using System.Collections.Generic; +using System.Linq; using Grasshopper.Kernel; +using Grasshopper.Kernel.Types; namespace FemDesign.Grasshopper { @@ -20,28 +23,69 @@ protected override void RegisterOutputParams(GH_OutputParamManager pManager) pManager.AddTextParameter("Name", "Name", "Name.", GH_ParamAccess.item); pManager.AddBrepParameter("Surfaces", "Surfaces", "Surfaces.", GH_ParamAccess.list); pManager.AddTextParameter("SectionType", "SectionType", "SectionType.", GH_ParamAccess.item); - pManager.AddTextParameter("MaterialType", "MaterialType", "MaterialType.", GH_ParamAccess.item); + pManager.AddTextParameter("MaterialType", "MaterialType", "MaterialType.", GH_ParamAccess.list); pManager.AddTextParameter("GroupName", "GroupName", "GroupName.", GH_ParamAccess.item); pManager.AddTextParameter("TypeName", "TypeName", "TypeName.", GH_ParamAccess.item); pManager.AddTextParameter("SizeName", "SizeName", "SizeName.", GH_ParamAccess.item); } protected override void SolveInstance(IGH_DataAccess DA) { - FemDesign.Sections.Section obj = null; - if (!DA.GetData(0, ref obj)) + object _obj = null; + if (!DA.GetData(0, ref _obj)) { return; } - DA.SetData(0, obj.Guid); - DA.SetData(1, obj.Name); - DA.SetDataList(2, obj.RegionGroup.ToRhino()); - DA.SetData(3, obj.Type); - DA.SetData(4, obj.MaterialType); - DA.SetData(5, obj.GroupName); - DA.SetData(6, obj.TypeName); - DA.SetData(7, obj.SizeName); - } + if (_obj is GH_ObjectWrapper dataWrapper) + { + var objVal = dataWrapper.Value; + + if (objVal is Sections.Section) + { + Sections.Section obj = (Sections.Section)objVal; + DA.SetData(0, obj.Guid); + DA.SetData(1, obj.Name); + DA.SetDataList(2, obj.RegionGroup.ToRhino()); + DA.SetData(3, obj.Type); + DA.SetDataList(4, new List { obj.MaterialType }); + DA.SetData(5, obj.GroupName); + DA.SetData(6, obj.TypeName); + DA.SetData(7, obj.SizeName); + } + else if (objVal is Composites.CompositeSection) + { + Composites.CompositeSection obj = (Composites.CompositeSection)objVal; + DA.SetData(0, obj.Guid); + DA.SetData(1, obj.ParameterDictionary[Composites.CompositeSectionParameterType.Name]); + + List regions = new List(); + foreach (var item in obj.Sections) + { + var _region = item.RegionGroup.ToRhino(); + regions.AddRange(_region); + } + DA.SetDataList(2, regions); + + DA.SetData(3, obj.Type); + + List matType = obj.Materials.Select(m => m.Family.ToString()).ToList(); + DA.SetDataList(4, matType); + + DA.SetData(5, null); + DA.SetData(6, null); + DA.SetData(7, null); + } + else + { + throw new ArgumentException($"Section input parameter type must be Section or CompositeSection, but it is {_obj.GetType()}"); + } + } + else + { + return; + } + + } protected override System.Drawing.Bitmap Icon { get @@ -51,7 +95,7 @@ protected override System.Drawing.Bitmap Icon } public override Guid ComponentGuid { - get { return new Guid("79ff17b1-387a-44e1-9596-981b8a96e847"); } + get { return new Guid("{51E24345-C191-4FDA-BC7D-F99E15687405}"); } } public override GH_Exposure Exposure => GH_Exposure.tertiary; diff --git a/FemDesign.Grasshopper/FemDesign.Grasshopper.csproj b/FemDesign.Grasshopper/FemDesign.Grasshopper.csproj index c79a882a1..682b85bdf 100644 --- a/FemDesign.Grasshopper/FemDesign.Grasshopper.csproj +++ b/FemDesign.Grasshopper/FemDesign.Grasshopper.csproj @@ -69,6 +69,7 @@ Properties\GlobalAssemblyInfo.cs + @@ -133,6 +134,7 @@ + @@ -319,6 +321,16 @@ + + + + + + + + + + @@ -930,16 +942,22 @@ + + + + + + @@ -948,10 +966,13 @@ + + + diff --git a/FemDesign.Grasshopper/Properties/Resources.Designer.cs b/FemDesign.Grasshopper/Properties/Resources.Designer.cs index 779e11529..08d54725f 100644 --- a/FemDesign.Grasshopper/Properties/Resources.Designer.cs +++ b/FemDesign.Grasshopper/Properties/Resources.Designer.cs @@ -370,6 +370,16 @@ internal static System.Drawing.Bitmap Deconstruct_icon { } } + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap DeltaBeamProfile { + get { + object obj = ResourceManager.GetObject("DeltaBeamProfile", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + /// /// Looks up a localized resource of type System.Drawing.Bitmap. /// @@ -500,6 +510,16 @@ internal static System.Drawing.Bitmap EdgeConnectionRigid { } } + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap EffectiveCompositeSlab { + get { + object obj = ResourceManager.GetObject("EffectiveCompositeSlab", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + /// /// Looks up a localized resource of type System.Drawing.Bitmap. /// @@ -730,6 +750,36 @@ internal static System.Drawing.Bitmap FictShellDeconstruct { } } + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap FilledCruciformProfile { + get { + object obj = ResourceManager.GetObject("FilledCruciformProfile", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap FilledIProfile { + get { + object obj = ResourceManager.GetObject("FilledIProfile", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap FilledSteelTube { + get { + object obj = ResourceManager.GetObject("FilledSteelTube", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + /// /// Looks up a localized resource of type System.Drawing.Bitmap. /// @@ -870,6 +920,16 @@ internal static System.Drawing.Bitmap Help { } } + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap HSQProfile { + get { + object obj = ResourceManager.GetObject("HSQProfile", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + /// /// Looks up a localized resource of type System.Drawing.Bitmap. /// @@ -2080,6 +2140,16 @@ internal static System.Drawing.Bitmap ResultType { } } + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap RHSProfile { + get { + object obj = ResourceManager.GetObject("RHSProfile", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + /// /// Looks up a localized resource of type System.Drawing.Bitmap. /// @@ -2400,6 +2470,26 @@ internal static System.Drawing.Bitmap StagesDeconstruct { } } + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap SteelTubeWithIProfile { + get { + object obj = ResourceManager.GetObject("SteelTubeWithIProfile", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap SteelTubeWithSteelCore { + get { + object obj = ResourceManager.GetObject("SteelTubeWithSteelCore", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + /// /// Looks up a localized resource of type System.Drawing.Bitmap. /// diff --git a/FemDesign.Grasshopper/Properties/Resources.resx b/FemDesign.Grasshopper/Properties/Resources.resx index b3038895b..945cd5b64 100644 --- a/FemDesign.Grasshopper/Properties/Resources.resx +++ b/FemDesign.Grasshopper/Properties/Resources.resx @@ -7389,4 +7389,31 @@ ..\Resources\icons\PeriodicExcitationLoad.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + ..\Resources\icons\DeltaBeamProfile.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\icons\EffectiveCompositeSlab.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\icons\FilledCruciformProfile.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\icons\FilledIProfile.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\icons\FilledSteelTube.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\icons\HSQProfile.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\icons\RHSProfile.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\icons\SteelTubeWithIProfile.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\icons\SteelTubeWithSteelCore.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + \ No newline at end of file diff --git a/FemDesign.Grasshopper/Resources/icons/DeltaBeamProfile.png b/FemDesign.Grasshopper/Resources/icons/DeltaBeamProfile.png new file mode 100644 index 0000000000000000000000000000000000000000..9df662fd92a5d98bf38bc1a73af998beafeecfe1 GIT binary patch literal 310 zcmV-60m=S}P)Px#@JU2LR7gu>WS}u%q_O!7qZSYh;Smr-k=3*IGyMOL-KUHUR?Az{+3)Zfs2czw)KDwzl?$#}Dl!wldgOyp(r2p%<||?{0l!Vj^2uSXk4? zbB7Kc`tanWaNB|f3Trfl@{M9QCLOJ}w6vTvZBOOrwu9%-^RJg=`RthT)o0Gh^2%&0 z$G_|mQQZIl literal 0 HcmV?d00001 diff --git a/FemDesign.Grasshopper/Resources/icons/FilledCruciformProfile.png b/FemDesign.Grasshopper/Resources/icons/FilledCruciformProfile.png new file mode 100644 index 0000000000000000000000000000000000000000..25f1e597beb741a47d1d9ca49fd6e12f1dcb7095 GIT binary patch literal 336 zcmV-W0k8gvP)Px$3Q0skR7gu>WS}u%q_O!718c#IxeNZ^{lbOQlS({47&4RN@H!Hw7 z3-Yj&ZNa-QKNB00001KEU-?j3R#tY$;lLV$JvtSCKT2O*sCw#r>!N8Z6tZILretuh zQeNx1oniJ%1@DWzhnMwf$oE7sa5GN&bTC84KtM~YElfag_T-;CZ%P*Z@mVo>a;L8K tiE}5L?=vOEdURR+x^{BOj-H6E3{spql6DGHDu51Q@O1TaS?83{1OUF}N-zKb literal 0 HcmV?d00001 diff --git a/FemDesign.Grasshopper/Resources/icons/FilledSteelTube.png b/FemDesign.Grasshopper/Resources/icons/FilledSteelTube.png new file mode 100644 index 0000000000000000000000000000000000000000..e7d7faa7850ab3c51f2c6e468595052b81e02dec GIT binary patch literal 598 zcmV-c0;&CpP)Px%5J^NqR7gu>WS}u%q_O!718)I8KfjtAv4p;V-&HxGZ4JY?yRjP()JO$6SShkCPQ=RDJ&Ohhgi< zI}D%Rzqv7~CPR;bf#El@Vr&*LXEsc_sHCW*?P07yR3!apU|`sN{vpHthmUVhuF241 zU|{$IvjoEekD#~)BPZYbNC!=#42Ky6vSj7K8w?MwoSeR7dUqC93j_oN1R}~Oy^C|! zW#r?+9W1!Q>&wqS4D)wh{J)|zPZ$>QC_acx&YPfR?wB8FrAl`8*m&|T!-XTeC$649 zr2u3IiUs-YvmZJbYsslf@sn-Ay_cUEb{)I)Xi9CmJcb34rF~Dbg6*UQc{s?n;N#by z4AVCpd$FWFR}#a5!oC&%!|l`=csNK8f0&ED{`k$X?7$6%i6xQX&_RuZ(!R&p!FDnN z6#8Js#$(SHx8+JC&$DotTY8c`pJ@Gj|F?f?J) literal 0 HcmV?d00001 diff --git a/FemDesign.Grasshopper/Resources/icons/HSQProfile.png b/FemDesign.Grasshopper/Resources/icons/HSQProfile.png new file mode 100644 index 0000000000000000000000000000000000000000..8d9a0e797a6448e845518284edefa2622c227bf1 GIT binary patch literal 164 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM1|%Pp+x`GjjKx9jP7LeL$-D$|;yhg(Lp;2b zQx+H|EZO*zXR(+7Phyj!NT~5^d&S^sTbDdENq?Zruv6|y_bLu;p8hRsEsiyu|Ej>t zQfrWPFhihsnUcpnsVK?b8HakO9O_?D<8Z>E<`c*i+ga>_3>?cMB?GfPx#=}AOER7gu>WS}u%q_O!717|^aLPiCzibebH-+u^tl9iQ(;p5E{HLDlTXhm0y z(+3&ti~c(rC^BeD3otO^@#p{l3=B7)ePq~k?jFO;syGalIJKrU&;Ot1Wx&A2&Pvb+ zfB!QwOxkdYVQy{Ws0G+VYcz;PQxWzM7|m#~a2eRLDAm(|ft!PHVfW`hBg14;3%i`I zrTPx%TuDShR7gu>WS}u%q_O!718)I8KfjtAv4p;V-&HxGZ4JY?yRjP()JO$6SShkCPQ=RDJ&Ohhgi< zI}D%Rzqv7~CPR;bf#El@Vr&*LXEsc_sHCW*?P07yR3!apU|`sN{vpHthmUVhuF241 zU|{$IvjoEekD#~)BPZYbNC!=@;opD$VffDgG6FkbWME|AWM=`ZSb6XU!-Fd)r!Se_ zorTo`0RaJli1JDA;+%CE`M4m#GG)^lhEHFA!c7MmgzPF_E_Q}oe-p6$m!E$a=I^}t ze?@1WFf8Ixd=QzOH$ltXF+b2s6>i|?@4p!S|A+YC@4x>H%l2Jmh;q_qU}l17Wn^Sz z;N@h4tKWF?F2jW*yC<%mKcxUHkL>aM_Sp{|jJ4!crTB3M$($V*7*ae8aLV6%`I%wY zu}hDp)TYa0SP)s-_arOWPFj$MgKP^ve*MWXeZ#RAOWJcKF)S$TTk${KPMv{=19!3{ zp|IM)V)LoKF zQ&=WL)CVGbj5-RK^}&_Px%cS%G+R7gu>WS}u%q_O!718)I8KfjtAv4p;V-&HxGZ4JY?yRjP()JO$6SShkCPQ=RDJ&Ohhgi< zI}D%Rzqv7~CPR;bf#El@Vr&*LXEsc_sHCW*?P07yR3!apU|`sN{vpHthmUVhuF241 zU|{$IvjoEekD#~)BPZYbNC!=#42Ky6vSj7K8w?MwoSeR7dUqC93j_oN1R}~Oy^C|! zW#r>R4VFKD|1ms#^^xKAhi?ob{9FtQ;`|IO%uFaj_vPmwhWR@${$J6VCk%^t6dyz; z=S|Qucgzp8Qbp1D?(=ts<@>KOeE9kUF3!)*&Jf|C#UR4Rg`#%j$-4{}j_jVedj6CG zkOYba`R%hGIv8uosY>y~HGy0{bK7}_4_^?5!zB5**cmc?j8J@X@8xHPUB@mxno^rC zk6}S%Y2TBqU^{6+9uBw#_nv=XSbpFt&Qug;r^%oyEd-bU`1L2l^bN;eENRb`#IT^S zZ^i#`J9P#g4n+8$y7`P@_qqExEpX72XRy|mfy;mW@ta}Ufg21HOCrIcgBk~=eUGz) z?PLTf^udgc$DS{4%ay{gprC!uLwgfVIaNtY;@}g*?qgRTO|DJD5(l(SMU>_PP_eOK z7oL0o3NxDKWN1>LZCM1hg!t0*`)`J=r|yzen!?gFqCODeW7JW=tPif-f5q^a%=!RP j=FqT4qe^>#=9NAGf(KS8w+*-a00000NkvXXu0mjfm+et> literal 0 HcmV?d00001 diff --git a/FemDesign.Grasshopper/Sections/Composite/CompositeSectionDefine.cs b/FemDesign.Grasshopper/Sections/Composite/CompositeSectionDefine.cs new file mode 100644 index 000000000..34a50ba59 --- /dev/null +++ b/FemDesign.Grasshopper/Sections/Composite/CompositeSectionDefine.cs @@ -0,0 +1,127 @@ +using Grasshopper.Kernel; +using Grasshopper.Kernel.Parameters; +using Grasshopper.Kernel.Types; +using FemDesign.Grasshopper.Components.UIWidgets; +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Rhino.Geometry; +using FemDesign.Grasshopper; +using System.Windows.Forms; +using FemDesign.Grasshopper.Extension.ComponentExtension; +using FemDesign.Loads; +using Grasshopper.Kernel.Special; +using Eto.Drawing; + +namespace FemDesign.Grasshopper +{ + public class CompositeSectionDefine : GH_SwitcherComponent + { + private List _subcomponents = new List(); + public override string UnitMenuName => "Section"; + protected override string DefaultEvaluationUnit => _subcomponents[0].name(); + public override Guid ComponentGuid => new Guid("{A6B804EA-F254-4ABE-BEC5-FA69E92069AA}"); + public override GH_Exposure Exposure => GH_Exposure.tertiary; + protected override System.Drawing.Bitmap Icon => Properties.Resources.HSQProfile; + + public CompositeSectionDefine() + : base("Composite.Define", "Define", + "Define a new composite section.", + CategoryName.Name(), SubCategoryName.Cat4b()) + { + ((GH_Component)this).Hidden = true; + } + + protected override void RegisterInputParams(GH_InputParamManager pManager) + { + } + + protected override void RegisterOutputParams(GH_OutputParamManager pManager) + { + pManager.RegisterParam(new Param_GenericObject(), "CompositeSection", "Section", "Steel-concrete composite section."); + } + + protected override void RegisterEvaluationUnits(EvaluationUnitManager mngr) + { + //_subcomponents.Add(new EffectiveCompositeSlab()); + _subcomponents.Add(new HSQProfile()); + //_subcomponents.Add(new DeltaBeamProfile()); + //_subcomponents.Add(new FilledIProfile()); + _subcomponents.Add(new FilledCruciformProfile()); + //_subcomponents.Add(new RHSProfile()); + _subcomponents.Add(new FilledSteelTube()); + //_subcomponents.Add(new SteelTubeWithIProfile()); + _subcomponents.Add(new SteelTubeWithSteelCore()); + + foreach (SubComponent item in _subcomponents) + { + item.registerEvaluationUnits(mngr); + } + } + + protected override void OnComponentLoaded() + { + base.OnComponentLoaded(); + foreach (SubComponent item in _subcomponents) + { + item.OnComponentLoaded(); + } + } + + protected override void SolveInstance(IGH_DataAccess DA, EvaluationUnit unit) + { + if (unit == null) + { + return; + } + + foreach (SubComponent item in _subcomponents) + { + if (unit.Name.Equals(item.name())) + { + item.SolveInstance(DA, out var msg, out var level); + if (msg != "") + { + ((GH_ActiveObject)this).AddRuntimeMessage(level, msg); + } + return; + } + } + throw new Exception("Invalid sub-component"); + } + // Part of the code that allows to extend the menu with additional items + // Right click on the component to see the options + public override void AppendAdditionalMenuItems(ToolStripDropDown menu) + { + base.AppendAdditionalMenuItems(menu); + if (evalUnits.Units.Count > 0) + { + Menu_AppendSeparator(menu); + ToolStripMenuItem toolStripMenuItem = Menu_AppendItem(menu, "Section types"); + foreach (EvaluationUnit unit in evalUnits.Units) + { + Menu_AppendItem(toolStripMenuItem.DropDown, unit.Name, Menu_ActivateUnit, null, true, unit.Active).Tag = unit; + } + Menu_AppendSeparator(menu); + } + } + private void Menu_ActivateUnit(object sender, EventArgs e) + { + try + { + EvaluationUnit evaluationUnit = (EvaluationUnit)((ToolStripMenuItem)sender).Tag; + if (evaluationUnit != null) + { + SwitchUnit(evaluationUnit); + } + } + catch (Exception ex) + { + throw ex; + } + } + } +} \ No newline at end of file diff --git a/FemDesign.Grasshopper/Sections/Composite/DeltaBeamProfile.cs b/FemDesign.Grasshopper/Sections/Composite/DeltaBeamProfile.cs new file mode 100644 index 000000000..03ba1b375 --- /dev/null +++ b/FemDesign.Grasshopper/Sections/Composite/DeltaBeamProfile.cs @@ -0,0 +1,71 @@ +using System; +using System.Collections.Generic; +using Grasshopper.Kernel; +using Grasshopper.Kernel.Parameters; +using Grasshopper.Kernel.Types; +using FemDesign.Grasshopper.Components.UIWidgets; +using System.Linq; + +namespace FemDesign.Grasshopper +{ + public class DeltaBeamProfile : SubComponent + { + public System.Drawing.Bitmap Icon => Properties.Resources.DeltaBeamProfile; + public override string name() => "DeltaBeamProfile"; + public override string display_name() => "DeltaBeamProfile"; + + public override void registerEvaluationUnits(EvaluationUnitManager mngr) + { + EvaluationUnit evaluationUnit = new EvaluationUnit(name(), display_name(), "Create a composite section for Deltabeam sections. For more information, see FEM-Design GUI.", this.Icon); + mngr.RegisterUnit(evaluationUnit); + + evaluationUnit.RegisterInputParam(new Param_String(), "SectionName", "SectionName", "Composite section name.", GH_ParamAccess.item); + + evaluationUnit.RegisterInputParam(new Param_GenericObject(), "Steel", "Steel", "Steel material.", GH_ParamAccess.item); + + evaluationUnit.RegisterInputParam(new Param_GenericObject(), "Concrete", "Concrete", "Concrete material.", GH_ParamAccess.item); + + evaluationUnit.RegisterInputParam(new Param_GenericObject(), "DeltaBeamProfile", "DeltaBeamProfile", "Steel DeltaBeam profile. Can be 'D' or 'DR' section family types.", GH_ParamAccess.item); + } + + public override void SolveInstance(IGH_DataAccess DA, out string msg, out GH_RuntimeMessageLevel level) + { + msg = ""; + level = GH_RuntimeMessageLevel.Warning; + + // get input + string name = null; + if (!DA.GetData(0, ref name)) { return; } + + Materials.Material steel = new Materials.Material(); + if (!DA.GetData(1, ref steel)) { return; } + + Materials.Material concrete = new Materials.Material(); + if (!DA.GetData(2, ref concrete)) { return; } + + Sections.Section deltaProf = null; + if (!DA.GetData(3, ref deltaProf)) { return; } + + // check input data + if (steel.Family != Materials.Family.Steel) + { + throw new ArgumentException($"Steel input must be steel material but it is {steel.Family}"); + } + if (concrete.Family != Materials.Family.Concrete) + { + throw new ArgumentException($"Concrete input must be concrete material but it is {concrete.Family}"); + } + + // create composite section + Composites.CompositeSection compositeSection = Composites.CompositeSection.FilledDeltaBeamProfile(name, steel, concrete, deltaProf); + + // get output + DA.SetData(0, compositeSection); + } + + protected void setModelProps() + { + this.Parent_Component.ExpireSolution(true); + } + } +} \ No newline at end of file diff --git a/FemDesign.Grasshopper/Sections/Composite/EffectiveCompositeSlab.cs b/FemDesign.Grasshopper/Sections/Composite/EffectiveCompositeSlab.cs new file mode 100644 index 000000000..717d55538 --- /dev/null +++ b/FemDesign.Grasshopper/Sections/Composite/EffectiveCompositeSlab.cs @@ -0,0 +1,120 @@ +using System; +using Grasshopper.Kernel; +using Grasshopper.Kernel.Parameters; +using Grasshopper.Kernel.Types; +using FemDesign.Grasshopper.Components.UIWidgets; +using System.Threading.Tasks; + +namespace FemDesign.Grasshopper +{ + public class EffectiveCompositeSlab : SubComponent + { + public System.Drawing.Bitmap Icon => Properties.Resources.EffectiveCompositeSlab; + public override string name() => "EffectiveCompositeSlab"; + public override string display_name() => "EffectiveCompositeSlab"; + + public override void registerEvaluationUnits(EvaluationUnitManager mngr) + { + EvaluationUnit evaluationUnit = new EvaluationUnit(name(), display_name(), "Create a composite section for bars based on the effective width of a composite slab. For more information, see FEM-Design GUI.", this.Icon); + mngr.RegisterUnit(evaluationUnit); + + evaluationUnit.RegisterInputParam(new Param_String(), "SectionName", "SectionName", "Composite section name.", GH_ParamAccess.item); + + evaluationUnit.RegisterInputParam(new Param_GenericObject(), "Steel", "Steel", "Steel material.", GH_ParamAccess.item); + + evaluationUnit.RegisterInputParam(new Param_GenericObject(), "Concrete", "Concrete", "Concrete material.", GH_ParamAccess.item); + + evaluationUnit.RegisterInputParam(new Param_GenericObject(), "SteelProfile", "SteelProfile", "Steel profile.", GH_ParamAccess.item); + + evaluationUnit.RegisterInputParam(new Param_Number(), "t", "t", "Slab thickness [mm].", GH_ParamAccess.item, new GH_Number(150)); + evaluationUnit.Inputs[evaluationUnit.Inputs.Count - 1].Parameter.Optional = true; + + evaluationUnit.RegisterInputParam(new Param_Number(), "bEff", "bEff", "Concrete slab effective width [mm].", GH_ParamAccess.item, new GH_Number(800)); + evaluationUnit.Inputs[evaluationUnit.Inputs.Count - 1].Parameter.Optional = true; + + evaluationUnit.RegisterInputParam(new Param_Number(), "th", "th", "Hunch thickness [mm].", GH_ParamAccess.item, new GH_Number(60)); + evaluationUnit.Inputs[evaluationUnit.Inputs.Count - 1].Parameter.Optional = true; + + evaluationUnit.RegisterInputParam(new Param_Number(), "bt", "bt", "Hunch width at the top [mm].", GH_ParamAccess.item, new GH_Number(400)); + evaluationUnit.Inputs[evaluationUnit.Inputs.Count - 1].Parameter.Optional = true; + + evaluationUnit.RegisterInputParam(new Param_Number(), "bb", "bb", "Hunch width at the bottom [mm].", GH_ParamAccess.item, new GH_Number(200)); + evaluationUnit.Inputs[evaluationUnit.Inputs.Count - 1].Parameter.Optional = true; + + evaluationUnit.RegisterInputParam(new Param_Boolean(), "Filled", "Filled", "True if the steel section part is filled with concrete, false if not. The quality of the filling material is the same as the concrete of the slab.", GH_ParamAccess.item, new GH_Boolean(false)); + evaluationUnit.Inputs[evaluationUnit.Inputs.Count - 1].Parameter.Optional = true; + } + + public override void SolveInstance(IGH_DataAccess DA, out string msg, out GH_RuntimeMessageLevel level) + { + msg = ""; + level = GH_RuntimeMessageLevel.Warning; + + // get input + string name = null; + if (!DA.GetData(0, ref name)) { return; } + + Materials.Material steel = new Materials.Material(); + if (!DA.GetData(1, ref steel)) { return; } + + Materials.Material concrete = new Materials.Material(); + if (!DA.GetData(2, ref concrete)) { return; } + + Sections.Section steelProf = null; + if (!DA.GetData(3, ref steelProf)) { return; } + + double t = 150; + DA.GetData(4, ref t); + + double bEff = 800; + DA.GetData(5, ref bEff); + + double th = 60; + DA.GetData(6, ref th); + + double bt = 400; + DA.GetData(7, ref bt); + + double bb = 200; + DA.GetData(8, ref bb); + + bool filled = false; + DA.GetData(9, ref filled); + + // check input data + if (steel.Family != Materials.Family.Steel) + { + throw new ArgumentException($"Steel input must be steel material but it is {steel.Family}"); + } + if (concrete.Family != Materials.Family.Concrete) + { + throw new ArgumentException($"Concrete input must be concrete material but it is {concrete.Family}"); + } + + // create task to create composite section + Composites.CompositeSection compositeSection = null; + var task = Task.Run(() => + { + compositeSection = Composites.CompositeSection.EffectiveCompositeSlab(name, steel, concrete, steelProf, t, bEff, th, bt, bb, filled); + }); + + task.ConfigureAwait(false); + try + { + task.Wait(); + } + catch (Exception ex) + { + throw ex.InnerException; + } + + // get output + DA.SetData(0, compositeSection); + } + + protected void setModelProps() + { + this.Parent_Component.ExpireSolution(true); + } + } +} \ No newline at end of file diff --git a/FemDesign.Grasshopper/Sections/Composite/FilledCruciformProfile.cs b/FemDesign.Grasshopper/Sections/Composite/FilledCruciformProfile.cs new file mode 100644 index 000000000..3f2e9af5d --- /dev/null +++ b/FemDesign.Grasshopper/Sections/Composite/FilledCruciformProfile.cs @@ -0,0 +1,95 @@ +using System; +using Grasshopper.Kernel; +using Grasshopper.Kernel.Parameters; +using Grasshopper.Kernel.Types; +using FemDesign.Grasshopper.Components.UIWidgets; + + +namespace FemDesign.Grasshopper +{ + public class FilledCruciformProfile : SubComponent + { + public System.Drawing.Bitmap Icon => Properties.Resources.FilledCruciformProfile; + public override string name() => "FilledCruciformProfile"; + public override string display_name() => "FilledCruciformProfile"; + + public override void registerEvaluationUnits(EvaluationUnitManager mngr) + { + EvaluationUnit evaluationUnit = new EvaluationUnit(name(), display_name(), "Create a composite section for cruciform profiled cross-sections. For more information, see FEM-Design GUI.", this.Icon); + mngr.RegisterUnit(evaluationUnit); + + evaluationUnit.RegisterInputParam(new Param_String(), "SectionName", "SectionName", "Composite section name.", GH_ParamAccess.item); + + evaluationUnit.RegisterInputParam(new Param_GenericObject(), "Steel", "Steel", "Steel material.", GH_ParamAccess.item); + + evaluationUnit.RegisterInputParam(new Param_GenericObject(), "Concrete", "Concrete", "Concrete material.", GH_ParamAccess.item); + + evaluationUnit.RegisterInputParam(new Param_Number(), "bc", "bc", "Cross-section width [mm].", GH_ParamAccess.item, new GH_Number(600)); + evaluationUnit.Inputs[evaluationUnit.Inputs.Count - 1].Parameter.Optional = true; + + evaluationUnit.RegisterInputParam(new Param_Number(), "hc", "hc", "Cross-section height [mm].", GH_ParamAccess.item, new GH_Number(600)); + evaluationUnit.Inputs[evaluationUnit.Inputs.Count - 1].Parameter.Optional = true; + + evaluationUnit.RegisterInputParam(new Param_Number(), "bf", "bf", "Flange width [mm].", GH_ParamAccess.item, new GH_Number(250)); + evaluationUnit.Inputs[evaluationUnit.Inputs.Count - 1].Parameter.Optional = true; + + evaluationUnit.RegisterInputParam(new Param_Number(), "tw", "tw", "Web thickness [mm].", GH_ParamAccess.item, new GH_Number(15)); + evaluationUnit.Inputs[evaluationUnit.Inputs.Count - 1].Parameter.Optional = true; + + evaluationUnit.RegisterInputParam(new Param_Number(), "tf", "tf", "Flange thickness [mm].", GH_ParamAccess.item, new GH_Number(25)); + evaluationUnit.Inputs[evaluationUnit.Inputs.Count - 1].Parameter.Optional = true; + } + + public override void SolveInstance(IGH_DataAccess DA, out string msg, out GH_RuntimeMessageLevel level) + { + msg = ""; + level = GH_RuntimeMessageLevel.Warning; + + // get input + string name = null; + if (!DA.GetData(0, ref name)) { return; } + + Materials.Material steel = new Materials.Material(); + if (!DA.GetData(1, ref steel)) { return; } + + Materials.Material concrete = new Materials.Material(); + if (!DA.GetData(2, ref concrete)) { return; } + + double bc = 600; + DA.GetData(3, ref bc); + + double hc = 600; + DA.GetData(4, ref hc); + + double bf = 250; + DA.GetData(5, ref bf); + + double tw = 15; + DA.GetData(6, ref tw); + + double tf = 25; + DA.GetData(7, ref tf); + + // check input data + if (steel.Family != Materials.Family.Steel) + { + throw new ArgumentException($"Steel input must be steel material but it is {steel.Family}"); + } + if (concrete.Family != Materials.Family.Concrete) + { + throw new ArgumentException($"Concrete input must be concrete material but it is {concrete.Family}"); + } + + // create composite section + Composites.CompositeSection compositeSection = Composites.CompositeSection.FilledCruciformProfile(name, steel, concrete, bc, hc, bf, tw, tf); + + // get output + DA.SetData(0, compositeSection); + } + + protected void setModelProps() + { + this.Parent_Component.ExpireSolution(true); + } + } +} \ No newline at end of file diff --git a/FemDesign.Grasshopper/Sections/Composite/FilledIProfile.cs b/FemDesign.Grasshopper/Sections/Composite/FilledIProfile.cs new file mode 100644 index 000000000..54ac86fde --- /dev/null +++ b/FemDesign.Grasshopper/Sections/Composite/FilledIProfile.cs @@ -0,0 +1,97 @@ +using System; +using System.Threading.Tasks; +using Grasshopper.Kernel; +using Grasshopper.Kernel.Parameters; +using Grasshopper.Kernel.Types; +using FemDesign.Grasshopper.Components.UIWidgets; + + +namespace FemDesign.Grasshopper +{ + public class FilledIProfile : SubComponent + { + public System.Drawing.Bitmap Icon => Properties.Resources.FilledIProfile; + public override string name() => "FilledIProfile"; + public override string display_name() => "FilledIProfile"; + + public override void registerEvaluationUnits(EvaluationUnitManager mngr) + { + EvaluationUnit evaluationUnit = new EvaluationUnit(name(), display_name(), "Create a composite section for an 'I' profiled steel section with filled with concrete. For more information, see FEM-Design GUI.", this.Icon); + mngr.RegisterUnit(evaluationUnit); + + evaluationUnit.RegisterInputParam(new Param_String(), "SectionName", "SectionName", "Composite section name.", GH_ParamAccess.item); + + evaluationUnit.RegisterInputParam(new Param_GenericObject(), "Steel", "Steel", "Steel profile material.", GH_ParamAccess.item); + + evaluationUnit.RegisterInputParam(new Param_GenericObject(), "Concrete", "Concrete", "Concrete material.", GH_ParamAccess.item); + + evaluationUnit.RegisterInputParam(new Param_GenericObject(), "IProfile", "IProfile", "'I' profile steel section.", GH_ParamAccess.item); + + evaluationUnit.RegisterInputParam(new Param_Number(), "cy", "cy", "Concrete cover in Y direction [mm].", GH_ParamAccess.item, new GH_Number(80)); + evaluationUnit.Inputs[evaluationUnit.Inputs.Count - 1].Parameter.Optional = true; + + evaluationUnit.RegisterInputParam(new Param_Number(), "cz", "cz", "Concrete cover in Z direction [mm].", GH_ParamAccess.item, new GH_Number(80)); + evaluationUnit.Inputs[evaluationUnit.Inputs.Count - 1].Parameter.Optional = true; + } + + public override void SolveInstance(IGH_DataAccess DA, out string msg, out GH_RuntimeMessageLevel level) + { + msg = ""; + level = GH_RuntimeMessageLevel.Warning; + + // get input + string name = null; + if (!DA.GetData(0, ref name)) { return; } + + Materials.Material steel = new Materials.Material(); + if (!DA.GetData(1, ref steel)) { return; } + + Materials.Material concrete = new Materials.Material(); + if (!DA.GetData(2, ref concrete)) { return; } + + Sections.Section iProf = null; + if (!DA.GetData(3, ref iProf)) { return; } + + double cy = 80; + DA.GetData(4, ref cy); + + double cz = 80; + DA.GetData(5, ref cz); + + // check input data + if (steel.Family != Materials.Family.Steel) + { + throw new ArgumentException($"Steel input must be steel material but it is {steel.Family}"); + } + if (concrete.Family != Materials.Family.Concrete) + { + throw new ArgumentException($"Concrete input must be concrete material but it is {concrete.Family}"); + } + + // create task to create composite section + Composites.CompositeSection compositeSection = null; + var task = Task.Run(() => + { + compositeSection = Composites.CompositeSection.FilledIProfile(name, steel, concrete, iProf, cy, cz); + }); + + task.ConfigureAwait(false); + try + { + task.Wait(); + } + catch (Exception ex) + { + throw ex.InnerException; + } + + // get output + DA.SetData(0, compositeSection); + } + + protected void setModelProps() + { + this.Parent_Component.ExpireSolution(true); + } + } +} \ No newline at end of file diff --git a/FemDesign.Grasshopper/Sections/Composite/FilledSteelTube.cs b/FemDesign.Grasshopper/Sections/Composite/FilledSteelTube.cs new file mode 100644 index 000000000..d631487d6 --- /dev/null +++ b/FemDesign.Grasshopper/Sections/Composite/FilledSteelTube.cs @@ -0,0 +1,74 @@ +using System; +using Grasshopper.Kernel; +using Grasshopper.Kernel.Parameters; +using Grasshopper.Kernel.Types; +using FemDesign.Grasshopper.Components.UIWidgets; + + +namespace FemDesign.Grasshopper +{ + public class FilledSteelTube : SubComponent + { + public System.Drawing.Bitmap Icon => Properties.Resources.FilledSteelTube; + public override string name() => "FilledSteelTube"; + public override string display_name() => "FilledSteelTube"; + + public override void registerEvaluationUnits(EvaluationUnitManager mngr) + { + EvaluationUnit evaluationUnit = new EvaluationUnit(name(), display_name(), "Create a filled steel tube composite section. For more information, see FEM-Design GUI.", this.Icon); + mngr.RegisterUnit(evaluationUnit); + + evaluationUnit.RegisterInputParam(new Param_String(), "SectionName", "SectionName", "Composite section name.", GH_ParamAccess.item); + + evaluationUnit.RegisterInputParam(new Param_GenericObject(), "Steel", "Steel", "Steel material.", GH_ParamAccess.item); + + evaluationUnit.RegisterInputParam(new Param_GenericObject(), "Concrete", "Concrete", "Concrete material.", GH_ParamAccess.item); + + evaluationUnit.RegisterInputParam(new Param_Number(), "d", "d", "Diameter of steel tube [mm].", GH_ParamAccess.item, new GH_Number(400)); + evaluationUnit.Inputs[evaluationUnit.Inputs.Count - 1].Parameter.Optional = true; + + evaluationUnit.RegisterInputParam(new Param_Number(), "t", "t", "Thickness of tube [mm].", GH_ParamAccess.item, new GH_Number(15)); + evaluationUnit.Inputs[evaluationUnit.Inputs.Count - 1].Parameter.Optional = true; + + } + + public override void SolveInstance(IGH_DataAccess DA, out string msg, out GH_RuntimeMessageLevel level) + { + msg = ""; + level = GH_RuntimeMessageLevel.Warning; + + // get input + string name = null; + if (!DA.GetData(0, ref name)) { return; } + + Materials.Material steel = new Materials.Material(); + if (!DA.GetData(1, ref steel)) { return; } + + Materials.Material concrete = new Materials.Material(); + if (!DA.GetData(2, ref concrete)) { return; } + + double d = 400; + DA.GetData(3, ref d); + + double t = 15; + DA.GetData(4, ref t); + + // check input data + if (steel.Family != Materials.Family.Steel) + throw new ArgumentException($"Steel input must be steel material but it is {steel.Family}"); + if (concrete.Family != Materials.Family.Concrete) + throw new ArgumentException($"Concrete input must be concrete material but it is {concrete.Family}"); + + // create composite section + Composites.CompositeSection compositeSection = Composites.CompositeSection.FilledSteelTube(name, steel, concrete, d, t); + + // get output + DA.SetData(0, compositeSection); + } + + protected void setModelProps() + { + this.Parent_Component.ExpireSolution(true); + } + } +} \ No newline at end of file diff --git a/FemDesign.Grasshopper/Sections/Composite/HSQProfile.cs b/FemDesign.Grasshopper/Sections/Composite/HSQProfile.cs new file mode 100644 index 000000000..bf6e3e8ca --- /dev/null +++ b/FemDesign.Grasshopper/Sections/Composite/HSQProfile.cs @@ -0,0 +1,113 @@ +using System; +using Grasshopper.Kernel; +using Grasshopper.Kernel.Parameters; +using Grasshopper.Kernel.Types; +using FemDesign.Grasshopper.Components.UIWidgets; + + +namespace FemDesign.Grasshopper +{ + public class HSQProfile : SubComponent + { + public System.Drawing.Bitmap Icon => Properties.Resources.HSQProfile; + public override string name() => "HSQProfile"; + public override string display_name() => "HSQProfile"; + + public override void registerEvaluationUnits(EvaluationUnitManager mngr) + { + EvaluationUnit evaluationUnit = new EvaluationUnit(name(), display_name(), "Create a composite section for HSQ cross-sections. For more information, see FEM-Design GUI.", this.Icon); + mngr.RegisterUnit(evaluationUnit); + + evaluationUnit.RegisterInputParam(new Param_String(), "SectionName", "SectionName", "Composite section name.", GH_ParamAccess.item); + + evaluationUnit.RegisterInputParam(new Param_GenericObject(), "Steel", "Steel", "Steel material.", GH_ParamAccess.item); + + evaluationUnit.RegisterInputParam(new Param_GenericObject(), "Concrete", "Concrete", "Concrete material.", GH_ParamAccess.item); + + evaluationUnit.RegisterInputParam(new Param_Number(), "b", "b", "Intermediate width of the bottom flange [mm].", GH_ParamAccess.item, new GH_Number(200)); + evaluationUnit.Inputs[evaluationUnit.Inputs.Count - 1].Parameter.Optional = true; + + evaluationUnit.RegisterInputParam(new Param_Number(), "bt", "bt", "Top flange width [mm].", GH_ParamAccess.item, new GH_Number(240)); + evaluationUnit.Inputs[evaluationUnit.Inputs.Count - 1].Parameter.Optional = true; + + evaluationUnit.RegisterInputParam(new Param_Number(), "o1", "o1", "Left overhang [mm].", GH_ParamAccess.item, new GH_Number(150)); + evaluationUnit.Inputs[evaluationUnit.Inputs.Count - 1].Parameter.Optional = true; + + evaluationUnit.RegisterInputParam(new Param_Number(), "o2", "o2", "Right overhang [mm].", GH_ParamAccess.item, new GH_Number(150)); + evaluationUnit.Inputs[evaluationUnit.Inputs.Count - 1].Parameter.Optional = true; + + evaluationUnit.RegisterInputParam(new Param_Number(), "h", "h", "Web hight [mm].", GH_ParamAccess.item, new GH_Number(360)); + evaluationUnit.Inputs[evaluationUnit.Inputs.Count - 1].Parameter.Optional = true; + + evaluationUnit.RegisterInputParam(new Param_Number(), "tw", "tw", "Web thickness [mm].", GH_ParamAccess.item, new GH_Number(10)); + evaluationUnit.Inputs[evaluationUnit.Inputs.Count - 1].Parameter.Optional = true; + + evaluationUnit.RegisterInputParam(new Param_Number(), "tfb", "tfb", "Bottom flange thickness [mm].", GH_ParamAccess.item, new GH_Number(20)); + evaluationUnit.Inputs[evaluationUnit.Inputs.Count - 1].Parameter.Optional = true; + + evaluationUnit.RegisterInputParam(new Param_Number(), "tft", "tft", "Top flange thickness [mm].", GH_ParamAccess.item, new GH_Number(20)); + evaluationUnit.Inputs[evaluationUnit.Inputs.Count - 1].Parameter.Optional = true; + } + + public override void SolveInstance(IGH_DataAccess DA, out string msg, out GH_RuntimeMessageLevel level) + { + msg = ""; + level = GH_RuntimeMessageLevel.Warning; + + // get input + string name = null; + if (!DA.GetData(0, ref name)) { return; } + + Materials.Material steel = new Materials.Material(); + if (!DA.GetData(1, ref steel)) { return; } + + Materials.Material concrete = new Materials.Material(); + if (!DA.GetData(2, ref concrete)) { return; } + + double b = 200; + DA.GetData(3, ref b); + + double bt = 240; + DA.GetData(4, ref bt); + + double o1 = 150; + DA.GetData(5, ref o1); + + double o2 = 150; + DA.GetData(6, ref o2); + + double h = 360; + DA.GetData(7, ref h); + + double tw = 10; + DA.GetData(8, ref tw); + + double tfb = 20; + DA.GetData(9, ref tfb); + + double tft = 20; + DA.GetData(10, ref tft); + + // check input data + if (steel.Family != Materials.Family.Steel) + { + throw new ArgumentException($"Steel input must be steel material but it is {steel.Family}"); + } + if (concrete.Family != Materials.Family.Concrete) + { + throw new ArgumentException($"Concrete input must be concrete material but it is {concrete.Family}"); + } + + // create composite section + Composites.CompositeSection compositeSection = Composites.CompositeSection.FilledHSQProfile(name, steel, concrete, b, bt, o1, o2, h, tw, tfb, tft); + + // get output + DA.SetData(0, compositeSection); + } + + protected void setModelProps() + { + this.Parent_Component.ExpireSolution(true); + } + } +} \ No newline at end of file diff --git a/FemDesign.Grasshopper/Sections/Composite/RHSProfile.cs b/FemDesign.Grasshopper/Sections/Composite/RHSProfile.cs new file mode 100644 index 000000000..b76014197 --- /dev/null +++ b/FemDesign.Grasshopper/Sections/Composite/RHSProfile.cs @@ -0,0 +1,70 @@ +using System; +using Grasshopper.Kernel; +using Grasshopper.Kernel.Parameters; +using Grasshopper.Kernel.Types; +using FemDesign.Grasshopper.Components.UIWidgets; + + +namespace FemDesign.Grasshopper +{ + public class RHSProfile : SubComponent + { + public System.Drawing.Bitmap Icon => Properties.Resources.RHSProfile; + public override string name() => "RHSProfile"; + public override string display_name() => "RHSProfile"; + + public override void registerEvaluationUnits(EvaluationUnitManager mngr) + { + EvaluationUnit evaluationUnit = new EvaluationUnit(name(), display_name(), "Create a composite section for rectangular hollow sections. For more information, see FEM-Design GUI.", this.Icon); + mngr.RegisterUnit(evaluationUnit); + + evaluationUnit.RegisterInputParam(new Param_String(), "SectionName", "SectionName", "Composite section name.", GH_ParamAccess.item); + + evaluationUnit.RegisterInputParam(new Param_GenericObject(), "Steel", "Steel", "Steel material.", GH_ParamAccess.item); + + evaluationUnit.RegisterInputParam(new Param_GenericObject(), "Concrete", "Concrete", "Concrete material.", GH_ParamAccess.item); + + evaluationUnit.RegisterInputParam(new Param_GenericObject(), "RHSProfile", "RHSProfile", "Steel RHS profile.", GH_ParamAccess.item); + } + + public override void SolveInstance(IGH_DataAccess DA, out string msg, out GH_RuntimeMessageLevel level) + { + msg = ""; + level = GH_RuntimeMessageLevel.Warning; + + // get input + string name = null; + if (!DA.GetData(0, ref name)) { return; } + + Materials.Material steel = new Materials.Material(); + if (!DA.GetData(1, ref steel)) { return; } + + Materials.Material concrete = new Materials.Material(); + if (!DA.GetData(2, ref concrete)) { return; } + + Sections.Section rhsProf = null; + if (!DA.GetData(3, ref rhsProf)) { return; } + + // check input data + if (steel.Family != Materials.Family.Steel) + { + throw new ArgumentException($"Steel input must be steel material but it is {steel.Family}"); + } + if (concrete.Family != Materials.Family.Concrete) + { + throw new ArgumentException($"Concrete input must be concrete material but it is {concrete.Family}"); + } + + // create composite section + Composites.CompositeSection compositeSection = Composites.CompositeSection.FilledRHSProfile(name, steel, concrete, rhsProf); + + // get output + DA.SetData(0, compositeSection); + } + + protected void setModelProps() + { + this.Parent_Component.ExpireSolution(true); + } + } +} \ No newline at end of file diff --git a/FemDesign.Grasshopper/Sections/Composite/SteelTubeWithIProfile.cs b/FemDesign.Grasshopper/Sections/Composite/SteelTubeWithIProfile.cs new file mode 100644 index 000000000..66ccd078f --- /dev/null +++ b/FemDesign.Grasshopper/Sections/Composite/SteelTubeWithIProfile.cs @@ -0,0 +1,103 @@ +using System; +using System.Threading.Tasks; + +using Grasshopper.Kernel; +using Grasshopper.Kernel.Parameters; +using Grasshopper.Kernel.Types; + +using FemDesign.Grasshopper.Components.UIWidgets; +using FemDesign.Materials; + + +namespace FemDesign.Grasshopper +{ + public class SteelTubeWithIProfile : SubComponent + { + public System.Drawing.Bitmap Icon => Properties.Resources.SteelTubeWithIProfile; + public override string name() => "SteelTubeWithIProfile"; + public override string display_name() => "SteelTubeWithIProfile"; + + public override void registerEvaluationUnits(EvaluationUnitManager mngr) + { + EvaluationUnit evaluationUnit = new EvaluationUnit(name(), display_name(), "Create a filled steel tube composite section with I-profile. For more information, see FEM-Design GUI.", this.Icon); + mngr.RegisterUnit(evaluationUnit); + + evaluationUnit.RegisterInputParam(new Param_String(), "SectionName", "SectionName", "Composite section name.", GH_ParamAccess.item); + + evaluationUnit.RegisterInputParam(new Param_GenericObject(), "TubeMaterial", "TubeMaterial", "Steel tube material.", GH_ParamAccess.item); + + evaluationUnit.RegisterInputParam(new Param_GenericObject(), "IMateral", "IMateral", "I profile material.", GH_ParamAccess.item); + + evaluationUnit.RegisterInputParam(new Param_GenericObject(), "Concrete", "Concrete", "Concrete material.", GH_ParamAccess.item); + + evaluationUnit.RegisterInputParam(new Param_GenericObject(), "IProfile", "IProfile", "Steel section from database. Must be an I-shaped section type.", GH_ParamAccess.item); + + evaluationUnit.RegisterInputParam(new Param_Number(), "d", "d", "Diameter of steel tube [mm].", GH_ParamAccess.item, new GH_Number(600)); + evaluationUnit.Inputs[evaluationUnit.Inputs.Count - 1].Parameter.Optional = true; + + evaluationUnit.RegisterInputParam(new Param_Number(), "t", "t", "Thickness of tube [mm].", GH_ParamAccess.item, new GH_Number(15)); + evaluationUnit.Inputs[evaluationUnit.Inputs.Count - 1].Parameter.Optional = true; + + } + + public override void SolveInstance(IGH_DataAccess DA, out string msg, out GH_RuntimeMessageLevel level) + { + msg = ""; + level = GH_RuntimeMessageLevel.Warning; + + // get input + string name = null; + if (!DA.GetData(0, ref name)) { return; } + + Materials.Material steelTube = new Materials.Material(); + if (!DA.GetData(1, ref steelTube)) { return; } + + Materials.Material iMaterial = new Materials.Material(); + if (!DA.GetData(2, ref iMaterial)) { return; } + + Materials.Material concrete = new Materials.Material(); + if (!DA.GetData(3, ref concrete)) { return; } + + Sections.Section iProfile = null; + if(!DA.GetData(4, ref iProfile)) { return; } + + double d = 600; + DA.GetData(5, ref d); + + double t = 15; + DA.GetData(6, ref t); + + // check input data + if (steelTube.Family != Materials.Family.Steel || iMaterial.Family != Materials.Family.Steel) + throw new ArgumentException($"SteelTube and IMaterial inputs must be steel materials!"); + if (concrete.Family != Materials.Family.Concrete) + throw new ArgumentException($"Concrete input must be concrete material but it is {concrete.Family}"); + + // create task to create composite section + Composites.CompositeSection compositeSection = null; + var task = Task.Run(() => + { + compositeSection = Composites.CompositeSection.FilledSteelTubeWithIProfile(name, steelTube, iMaterial, concrete, iProfile, d, t); + }); + + task.ConfigureAwait(false); + try + { + task.Wait(); + } + catch (Exception ex) + { + throw ex.InnerException; + } + + + // get output + DA.SetData(0, compositeSection); + } + + protected void setModelProps() + { + this.Parent_Component.ExpireSolution(true); + } + } +} \ No newline at end of file diff --git a/FemDesign.Grasshopper/Sections/Composite/SteelTubeWithSteelCore.cs b/FemDesign.Grasshopper/Sections/Composite/SteelTubeWithSteelCore.cs new file mode 100644 index 000000000..97122969a --- /dev/null +++ b/FemDesign.Grasshopper/Sections/Composite/SteelTubeWithSteelCore.cs @@ -0,0 +1,85 @@ +using System; +using Grasshopper.Kernel; +using Grasshopper.Kernel.Parameters; +using Grasshopper.Kernel.Types; +using FemDesign.Grasshopper.Components.UIWidgets; + + +namespace FemDesign.Grasshopper +{ + public class SteelTubeWithSteelCore : SubComponent + { + public System.Drawing.Bitmap Icon => Properties.Resources.SteelTubeWithSteelCore; + public override string name() => "SteelTubeWithSteelCore"; + public override string display_name() => "SteelTubeWithSteelCore"; + + public override void registerEvaluationUnits(EvaluationUnitManager mngr) + { + EvaluationUnit evaluationUnit = new EvaluationUnit(name(), display_name(), "Create a filled steel tube composite section with a steel core. For more information, see FEM-Design GUI.", this.Icon); + mngr.RegisterUnit(evaluationUnit); + + evaluationUnit.RegisterInputParam(new Param_String(), "SectionName", "SectionName", "Composite section name.", GH_ParamAccess.item); + + evaluationUnit.RegisterInputParam(new Param_GenericObject(), "TubeMaterial", "TubeMaterial", "Steel tube material.", GH_ParamAccess.item); + + evaluationUnit.RegisterInputParam(new Param_GenericObject(), "CoreMaterial", "CoreMaterial", "Steel core material.", GH_ParamAccess.item); + + evaluationUnit.RegisterInputParam(new Param_GenericObject(), "Concrete", "Concrete", "Concrete material.", GH_ParamAccess.item); + + evaluationUnit.RegisterInputParam(new Param_Number(), "d1", "d1", "Steel tube exterior diameter [mm].", GH_ParamAccess.item, new GH_Number(300)); + evaluationUnit.Inputs[evaluationUnit.Inputs.Count - 1].Parameter.Optional = true; + + evaluationUnit.RegisterInputParam(new Param_Number(), "d2", "d2", "Steel core diameter [mm].", GH_ParamAccess.item, new GH_Number(160)); + evaluationUnit.Inputs[evaluationUnit.Inputs.Count - 1].Parameter.Optional = true; + + evaluationUnit.RegisterInputParam(new Param_Number(), "t", "t", "Thickness of tube [mm].", GH_ParamAccess.item, new GH_Number(8)); + evaluationUnit.Inputs[evaluationUnit.Inputs.Count - 1].Parameter.Optional = true; + + } + + public override void SolveInstance(IGH_DataAccess DA, out string msg, out GH_RuntimeMessageLevel level) + { + msg = ""; + level = GH_RuntimeMessageLevel.Warning; + + // get input + string name = null; + if (!DA.GetData(0, ref name)) { return; } + + Materials.Material steelTube = new Materials.Material(); + if (!DA.GetData(1, ref steelTube)) { return; } + + Materials.Material steelCore = new Materials.Material(); + if (!DA.GetData(2, ref steelCore)) { return; } + + Materials.Material concrete = new Materials.Material(); + if (!DA.GetData(3, ref concrete)) { return; } + + double d1 = 300; + DA.GetData(4, ref d1); + + double d2 = 160; + DA.GetData(5, ref d2); + + double t = 8; + DA.GetData(6, ref t); + + // check input data + if (steelTube.Family != Materials.Family.Steel || steelCore.Family != Materials.Family.Steel) + throw new ArgumentException($"SteelTube and SteelCore inputs must be steel material!"); + if (concrete.Family != Materials.Family.Concrete) + throw new ArgumentException($"Concrete input must be concrete material but it is {concrete.Family}"); + + // create composite section + Composites.CompositeSection compositeSection = Composites.CompositeSection.FilledSteelTubeWithSteelCore(name, steelTube, steelCore, concrete, d1, d2, t); + + // get output + DA.SetData(0, compositeSection); + } + + protected void setModelProps() + { + this.Parent_Component.ExpireSolution(true); + } + } +} \ No newline at end of file diff --git a/FemDesign.Tests/Composites/CompositeBeamTest.cs b/FemDesign.Tests/Composites/CompositeBeamTest.cs new file mode 100644 index 000000000..552aab747 --- /dev/null +++ b/FemDesign.Tests/Composites/CompositeBeamTest.cs @@ -0,0 +1,186 @@ +using Microsoft.VisualStudio.TestTools.UnitTesting; +using System; +using System.IO; +using System.Xml; +using System.Xml.Serialization; +using System.Collections.Generic; +using System.Linq; + +using FemDesign.Materials; +using FemDesign.Sections; +using FemDesign.Geometry; +using System.Collections; + +namespace FemDesign.Composites +{ + [TestClass] + public class CompositeBeamTest + { + [TestMethod] + public void CompositeBeamB() + { + // Geometry + Point3d firstPt = new Point3d(0, 0, 0); + Point3d secondPt = new Point3d(10, 0, 0); + Edge line = new Edge(firstPt, secondPt); + + + var materialsDB = Materials.MaterialDatabase.DeserializeStruxml(@"C:\Repository\femdesign-api\FemDesign.Tests\Composites\materials.struxml"); + var steel = materialsDB.MaterialByName("S 275"); + var concrete = materialsDB.MaterialByName("C25/30"); + + + // Create composite beam + CompositeSection compositeSection = CompositeSection.FilledHSQProfile(name: "beamB1", steel, concrete, b: 200, bt: 250, o1: 400, o2: 150, h: 360, tw: 10, tfb: 50, tft: 20); + Bars.Bar compositeBar = new Bars.Bar(line, Bars.BarType.Beam, compositeSection, null, null, "B"); + + + // Create output and input model + Model modelIn = new Model(Country.S); + Model modelOut = new Model(Country.S); + modelOut.AddElements(compositeBar); + + using (var femDesign = new FemDesignConnection( + fdInstallationDir: @"C:\Program Files\StruSoft\FEM-Design 22\", + outputDir: @"D:\Andi\API_Work\Github\802_CompositeSections\tests\CSharp\CompositeBeamB_out", + keepOpen: false)) + { + femDesign.Open(modelOut, false); + modelIn = femDesign.GetModel(); + } + + + // check Composite obj. + var compositesIn = modelIn.Composites; + Assert.IsNotNull(compositesIn); + + var compositeSectionsOut = modelOut.Composites.CompositeSection.OrderBy(c => c.Guid).ToList(); + var compositeSectionsIn = modelIn.Composites.CompositeSection.OrderBy(c => c.Guid).ToList(); + Assert.IsNotNull(compositeSectionsIn); + Assert.AreEqual(compositeSectionsIn.Count, compositeSectionsOut.Count); + for (int i = 0; i < compositeSectionsIn.Count; i++) + { + var partsIn = compositeSectionsIn[i].Parts; + var partsOut = compositeSectionsOut[i].Parts; + Assert.AreEqual(partsIn.Count, partsOut.Count); + + var partsMaterialIn = partsIn.Select(p => p.Material.Family).ToList(); + var partsMaterialOut = partsOut.Select(p => p.Material.Family).ToList(); + Assert.AreEqual(partsMaterialIn.Count, partsMaterialOut.Count); + for(int j = 0; j < partsMaterialIn.Count; j++) + { + Assert.AreEqual(partsMaterialIn[j], partsMaterialOut[j]); + } + + var paramsIn = compositeSectionsIn[i].ParameterList; + var paramsOut = compositeSectionsOut[i].ParameterList; + Assert.AreEqual(paramsIn.Count, paramsOut.Count); + for (int j = 0; j < paramsIn.Count; j++) + { + Assert.AreEqual(paramsIn[j].Value, paramsOut[j].Value); + } + } + + var complexCompositesOut = modelOut.Composites.ComplexComposite; + var complexCompositesIn = modelIn.Composites.ComplexComposite; + Assert.IsNotNull(complexCompositesIn); + Assert.AreEqual(complexCompositesOut.Count, complexCompositesIn.Count); + } + + public void CompositeColumnA() + { + // Load material and sections from .struxml files + var materialsDB = Materials.MaterialDatabase.DeserializeStruxml(@"C:\Repos\femdesign-api\FemDesign.Tests\bin\Debug\Composites\materials.struxml"); + var steel = materialsDB.MaterialByName("S 275"); + var concrete = materialsDB.MaterialByName("C25/30"); + var matList = new List() { steel, concrete }; + + var sectionsDB = Sections.SectionDatabase.DeserializeStruxml(@"C:\Repos\femdesign-api\FemDesign.Tests\bin\Debug\Composites\sections.struxml"); + var steelSection = sectionsDB.SectionByName("Steel sections, HE-B, 300"); + var concreteSection = sectionsDB.SectionByName("Unnamed, Concrete, 3"); + var secList = new List() { steelSection, concreteSection }; + + + // Create composite object + var composite = new Composites(); + + // Create composite section + string name = "TestColumnA1"; + double cy = 80; //mm + double cz = 80; //mm + CompositeSection compositeSection = CompositeSection.FilledIProfile(steel, concrete, steelSection, name, cy, cz); + + composite.CompositeSection = new List() { compositeSection }; + + //composite.CompositeSection[0].ParameterDictionary[CompositeParameterType.]; + //var sth = GetCompositeSectionParameters(compositeSection); + + + // Create complex composite + ComplexComposite complexComposite = new ComplexComposite(compositeSection); + composite.ComplexComposite = new List() { complexComposite }; + + + // Serialize struxml + string fileName = "CompositeSerialization"; + string filePath = @"D:\Andi\API_Work\0_Github\802_CompositeSections\tests\CSharp\" + fileName + ".struxml"; + this.SerializeComposite(filePath, composite); + + //Deserialize struxml + Composites inData = DeserializeComposite(filePath); + + // Compare data + Assert.AreEqual(composite, inData); + } + + + + public void SerializeComposite(string filePath, Composites composite) + { + // Check file extension + if (Path.GetExtension(filePath) != ".struxml") + { + throw new System.ArgumentException("File extension must be .struxml! Serialization failed."); + } + + // Serialize + XmlSerializer serializer = new XmlSerializer(typeof(Composites)); + using (TextWriter writer = new StreamWriter(filePath)) + { + serializer.Serialize(writer, composite); + writer.Close(); + } + } + public void SerializeSection(string filePath, ModelSections sections) + { + // Check file extension + if (Path.GetExtension(filePath) != ".struxml") + { + throw new System.ArgumentException("File extension must be .struxml! Serialization failed."); + } + + // Serialize + XmlSerializer serializer = new XmlSerializer(typeof(ModelSections)); + using (TextWriter writer = new StreamWriter(filePath)) + { + serializer.Serialize(writer, sections); + writer.Close(); + } + } + public static Composites DeserializeComposite(string filePath) + { + // Check file extension + if (Path.GetExtension(filePath) != ".struxml") + { + throw new System.ArgumentException("File extension must be .struxml! Serialization failed."); + } + + XmlSerializer deserializer = new XmlSerializer(typeof(Composites)); + TextReader reader = new StreamReader(filePath); + var obj = deserializer.Deserialize(reader); + Composites composite= (Composites)obj; + reader.Close(); + return composite; + } + } +} diff --git a/FemDesign.Tests/Composites/materials.struxml b/FemDesign.Tests/Composites/materials.struxml new file mode 100644 index 000000000..3b4c7941e --- /dev/null +++ b/FemDesign.Tests/Composites/materials.struxml @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/FemDesign.Tests/Composites/sections.struxml b/FemDesign.Tests/Composites/sections.struxml new file mode 100644 index 000000000..8758536a2 --- /dev/null +++ b/FemDesign.Tests/Composites/sections.struxml @@ -0,0 +1,902 @@ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + + + + + + + + + + + + + + + +
+
+ + + + + + + + + + + + + + + + + +
+ +
+ +
diff --git a/FemDesign.Tests/FemDesign.Tests.csproj b/FemDesign.Tests/FemDesign.Tests.csproj index 1ab78b7b8..cda97b50e 100644 --- a/FemDesign.Tests/FemDesign.Tests.csproj +++ b/FemDesign.Tests/FemDesign.Tests.csproj @@ -83,6 +83,7 @@ + @@ -179,6 +180,8 @@ PreserveNewest + + Always