using CaeGlobals; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows; namespace CaeMesh { [Serializable] public class LinearTriangleElement : FeElement2D { // Variables private static readonly int vtkCellTypeInt = (int)vtkCellType.VTK_TRIANGLE; private static readonly double a = 1.0 / 3.0; private static readonly double b = 1.0 / 2.0; // Properties // Constructors public LinearTriangleElement(int id, int[] nodeIds) : base(id, nodeIds) { } public LinearTriangleElement(int id, int partId, int[] nodeIds) : base(id, partId, nodeIds) { } // Methods public override int[] GetVtkNodeIds() { // return a copy -> ToArray return NodeIds.ToArray(); } public override int[] GetGmshNodeIds() { // return a copy -> ToArray return NodeIds.ToArray(); } public override int GetVtkCellType() { return vtkCellTypeInt; } public override FeFaceName GetFaceNameFromSortedNodeIds(int[] nodeIds) { throw new NotImplementedException(); } public override int[] GetNodeIdsFromFaceName(FeFaceName faceName) { // NEG S1 = 1-3-2 . 0-2-1 // POS S2 = 1-2-3 . 0-1-2 // S3 = 1-2 . 0-1 // S4 = 2-3 . 1-2 // S5 = 3-1 . 2-0 switch (faceName) { case FeFaceName.S1: return new int[] { NodeIds[0], NodeIds[2], NodeIds[1] }; case FeFaceName.S2: return new int[] { NodeIds[0], NodeIds[1], NodeIds[2] }; case FeFaceName.S3: return new int[] { NodeIds[0], NodeIds[1] }; case FeFaceName.S4: return new int[] { NodeIds[1], NodeIds[2] }; case FeFaceName.S5: return new int[] { NodeIds[2], NodeIds[0] }; default: throw new NotSupportedException(); } } public override int[] GetVtkCellFromFaceName(FeFaceName faceName) { // NEG S1 = 1-3-2 . 0-2-1 // POS S2 = 1-2-3 . 0-1-2 // S3 = 1-2 . 0-1 // S4 = 2-3 . 1-2 // S5 = 3-1 . 2-0 switch (faceName) { case FeFaceName.S1: return new int[] { NodeIds[0], NodeIds[2], NodeIds[1] }; case FeFaceName.S2: return new int[] { NodeIds[0], NodeIds[1], NodeIds[2] }; case FeFaceName.S3: return new int[] { NodeIds[0], NodeIds[1] }; case FeFaceName.S4: return new int[] { NodeIds[1], NodeIds[2] }; case FeFaceName.S5: return new int[] { NodeIds[2], NodeIds[0] }; default: throw new NotSupportedException(); } } public override int[][] GetAllVtkCells() { int[][] cells = new int[5][]; // cells[0] = new int[] { NodeIds[0], NodeIds[2], NodeIds[1] }; cells[1] = new int[] { NodeIds[0], NodeIds[1], NodeIds[2] }; cells[2] = new int[] { NodeIds[0], NodeIds[1] }; cells[3] = new int[] { NodeIds[1], NodeIds[2] }; cells[4] = new int[] { NodeIds[2], NodeIds[0] }; // return cells; } public override Dictionary GetFaceNamesAndAreasFromNodeSet(HashSet nodeSet, Dictionary nodes, bool edgeFaces) { int significantNodes = 3; bool[] faceNodeIds = new bool[significantNodes]; // int count = 0; for (int i = 0; i < significantNodes; i++) { if (nodeSet.Contains(NodeIds[i])) { faceNodeIds[i] = true; count++; } // If two or more nodes were missed: break if (i + 1 - count >= 2) break; } // Dictionary faces = new Dictionary(); // if (edgeFaces) { if (count >= 2) { // S3 = 1-2 . 0-1 // S4 = 2-3 . 1-2 // S5 = 3-1 . 2-0 if (faceNodeIds[0] && faceNodeIds[1]) faces.Add(FeFaceName.S3, GetArea(FeFaceName.S3, nodes)); if (faceNodeIds[1] && faceNodeIds[2]) faces.Add(FeFaceName.S4, GetArea(FeFaceName.S4, nodes)); if (faceNodeIds[2] && faceNodeIds[0]) faces.Add(FeFaceName.S5, GetArea(FeFaceName.S5, nodes)); } } else if (count == 3) { // POS S2 = 1-2-3 . 0-1-2 if (faceNodeIds[0] && faceNodeIds[1] && faceNodeIds[2]) faces.Add(FeFaceName.S2, GetArea(FeFaceName.S2, nodes)); } // return faces; } public override double[] GetEquivalentForcesFromFaceName(FeFaceName faceName) { if (faceName == FeFaceName.S1 || faceName == FeFaceName.S2) return new double[] { a, a, a }; else if (faceName == FeFaceName.S3 || faceName == FeFaceName.S4 || faceName == FeFaceName.S5) return new double[] { b, b }; else throw new NotSupportedException(); } public override double[] GetEquivalentForcesFromFaceName(FeFaceName faceName, double[] nodalValues) { if (faceName == FeFaceName.S1 || faceName == FeFaceName.S2) return GetEquivalentForces(typeof(LinearTriangleElement), nodalValues); else if (faceName == FeFaceName.S3 || faceName == FeFaceName.S4 || faceName == FeFaceName.S5) return GetEquivalentForces(typeof(LinearBeamElement), nodalValues); else throw new NotSupportedException(); } public override double GetArea(FeFaceName faceName, Dictionary nodes) { int[] cell = GetVtkCellFromFaceName(faceName); if (cell.Length == 3) return GeometryTools.TriangleArea(nodes[cell[0]], nodes[cell[1]], nodes[cell[2]]); else if (cell.Length == 2) return GeometryTools.BeamLength(nodes[cell[0]], nodes[cell[1]]); else throw new NotSupportedException(); } public override double[] GetFaceCG(FeFaceName faceName, Dictionary nodes, out double area) { int[] cell = GetVtkCellFromFaceName(faceName); if (cell.Length == 3) return GeometryTools.TriangleCG(nodes[cell[0]], nodes[cell[1]], nodes[cell[2]], out area); else if (cell.Length == 2) return GeometryTools.BeamCG(nodes[cell[0]], nodes[cell[1]], out area); else throw new NotSupportedException(); } public override double[] GetCG(Dictionary nodes, out double area) { return GeometryTools.TriangleCG(nodes[NodeIds[0]], nodes[NodeIds[1]], nodes[NodeIds[2]], out area); } public override FeElement DeepCopy() { return new LinearTriangleElement(Id, PartId, NodeIds.ToArray()); } // public double GetMinAngleDeg(Dictionary nodes) { Vec3D n1 = new Vec3D(nodes[NodeIds[0]].Coor); Vec3D n2 = new Vec3D(nodes[NodeIds[1]].Coor); Vec3D n3 = new Vec3D(nodes[NodeIds[2]].Coor); // Calculate the angle between each pair of points double angle1 = Vec3D.GetAngleAtP2Deg(n3, n1, n2); double angle2 = Vec3D.GetAngleAtP2Deg(n1, n2, n3); double angle3 = Vec3D.GetAngleAtP2Deg(n2, n3, n1); // Find the smallest angle double minAngle = Math.Min(Math.Min(angle1, angle2), angle3); // return minAngle; } // public void FlipNormal() { int tmp = NodeIds[1]; NodeIds[1] = NodeIds[2]; NodeIds[2] = tmp; } } }