using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.IO; using CaeMesh; using System.Xml.Linq; using System.Runtime.InteropServices; using CaeResults; using CaeGlobals; namespace FileInOut.Input { static public class MmgFileReader { private static string[] _spaceSplitter = new string[] { " " }; public static FeMesh Read(string fileName, ElementsToImport elementsToImport, MeshRepresentation meshRepresentation, bool convertToSecondOrder = false, int firstNodeId = 1, int firstElementId = 1, Dictionary existingNodes = null, Dictionary existingMidNodes = null, double epsilon = 1E-6, Dictionary> partNameNewSurfIdOldSurfId = null, Dictionary> partNameNewEdgeIdOldEdgeId = null) { if (File.Exists(fileName)) { Dictionary nodes = new Dictionary(); Dictionary elements = new Dictionary(); HashSet surfaceNodeIds; HashSet edgeNodeIds; Dictionary> surfaceIdElementIds = null; Dictionary> surfaceIdNodeIds = new Dictionary>(); Dictionary> edgeIdElementIds = null; Dictionary> edgeIdNodeIds = new Dictionary>(); Dictionary> edgeIdNodeIdCount = null; Dictionary oldNodeIdNewNodeId = null; // int nodeId = firstNodeId; int elementId = firstElementId; int maxPartId = 1; string[] lines = CaeGlobals.Tools.ReadAllLines(fileName); // Read for (int i = 0; i < lines.Length; i++) { if (lines[i].ToUpper().StartsWith("VERTICES")) { ReadVertices(lines, ref i, ref nodeId, existingNodes, epsilon, ref nodes, out oldNodeIdNewNodeId); } else if (lines[i].ToUpper().StartsWith("EDGES")) { ReadEdges(lines, ref i, ref elementId, oldNodeIdNewNodeId, ref elements, out edgeIdNodeIdCount, out edgeIdElementIds); //edgeIdNodeIdCount = new Dictionary>(); //edgeIdElementIds = new Dictionary>(); } else if (lines[i].ToUpper().StartsWith("TRIANGLES")) { ReadTriangles(lines, ref i, ref elementId, ref maxPartId, oldNodeIdNewNodeId, ref elements, out surfaceIdElementIds); } } // Count number of edges in an edge node Dictionary nodeIdEdgeCount = new Dictionary(); foreach (var edgeEntry in edgeIdNodeIdCount) { foreach (var nodeEntry in edgeEntry.Value) { if (nodeIdEdgeCount.ContainsKey(nodeEntry.Key)) nodeIdEdgeCount[nodeEntry.Key]++; else nodeIdEdgeCount.Add(nodeEntry.Key, 1); } } // Get vertices HashSet vertexNodeIds = new HashSet(); foreach (var entry in nodeIdEdgeCount) { if (entry.Value > 1) vertexNodeIds.Add(entry.Key); } // if (convertToSecondOrder) FeMesh.LinearToParabolic(ref nodes, ref elements, firstNodeId, existingMidNodes); // Surface node ids foreach (var entry in surfaceIdElementIds) { surfaceNodeIds = new HashSet(); foreach (var elementIdEntry in entry.Value) surfaceNodeIds.UnionWith(elements[elementIdEntry].NodeIds); surfaceIdNodeIds.Add(entry.Key, surfaceNodeIds); } // Edge node ids foreach (var entry in edgeIdElementIds) { edgeNodeIds = new HashSet(); foreach (var elementIdEntry in entry.Value) edgeNodeIds.UnionWith(elements[elementIdEntry].NodeIds); edgeIdNodeIds.Add(entry.Key, edgeNodeIds); } // FeMesh mesh = new FeMesh(nodes, elements, meshRepresentation, null, null, false, ImportOptions.DetectEdges); // mesh.ConvertLineFeElementsToEdges(vertexNodeIds); // Collect surfaceIdNodeIds for each part var allPartsSurfaceIdNodeIds = new Dictionary>>(); Dictionary> partSurfaceIdNodeIds; HashSet intersect; foreach (var partEntry in mesh.Parts) { partSurfaceIdNodeIds = new Dictionary>(); if (partEntry.Value.PartType != PartType.Wire) { foreach (var surfaceEntry in surfaceIdNodeIds) { intersect = new HashSet(surfaceEntry.Value.Intersect(partEntry.Value.NodeLabels)); partSurfaceIdNodeIds.Add(surfaceEntry.Key, intersect); } } allPartsSurfaceIdNodeIds.Add(partEntry.Key, partSurfaceIdNodeIds); } // Renumber surfaces mesh.RenumberVisualizationSurfaces(allPartsSurfaceIdNodeIds, null, partNameNewSurfIdOldSurfId); // Collect edgeIdNodeIds for each part var allPartsEdgeIdNodeIds = new Dictionary>>(); Dictionary> partEdgeIdNodeIds; foreach (var partEntry in mesh.Parts) { partEdgeIdNodeIds = new Dictionary>(); if (partEntry.Value.PartType != PartType.Wire) { foreach (var edgeEntry in edgeIdNodeIds) { intersect = new HashSet(edgeEntry.Value.Intersect(partEntry.Value.NodeLabels)); partEdgeIdNodeIds.Add(edgeEntry.Key, intersect); } } allPartsEdgeIdNodeIds.Add(partEntry.Key, partEdgeIdNodeIds); } // Renumber edges mesh.RenumberVisualizationEdges(allPartsEdgeIdNodeIds, partNameNewEdgeIdOldEdgeId); // if (elementsToImport != ElementsToImport.All) { if (!elementsToImport.HasFlag(ElementsToImport.Beam)) mesh.RemoveElementsByType(); if (!elementsToImport.HasFlag(ElementsToImport.Shell)) mesh.RemoveElementsByType(); if (!elementsToImport.HasFlag(ElementsToImport.Solid)) mesh.RemoveElementsByType(); } // return mesh; } // return null; } public static FeMesh Read3D(string fileName, ElementsToImport elementsToImport, MeshRepresentation meshRepresentation, bool convertToSecondOrder = false, double epsilon = 1E-6) { if (File.Exists(fileName)) { Dictionary nodes = new Dictionary(); Dictionary elements = new Dictionary(); Dictionary oldNodeIdNewNodeId = null; // int nodeId = 1; int elementId = 1; int maxParId = 1; string[] lines = Tools.ReadAllLines(fileName); // Read for (int i = 0; i < lines.Length; i++) { if (lines[i].ToUpper().StartsWith("VERTICES")) { ReadVertices(lines, ref i, ref nodeId, null, epsilon, ref nodes, out oldNodeIdNewNodeId); } else if (lines[i].ToUpper().StartsWith("EDGES")) { ReadEdges(lines, ref i, ref elementId, oldNodeIdNewNodeId, ref elements, out _, out _); } else if (lines[i].ToUpper().StartsWith("TRIANGLES")) { ReadTriangles(lines, ref i, ref elementId, ref maxParId, oldNodeIdNewNodeId, ref elements, out _); } else if (lines[i].ToUpper().StartsWith("TETRAHEDRA")) { ReadTetrahedrons(lines, ref i, ref elementId, ref maxParId, oldNodeIdNewNodeId, ref elements, out _); } } // Get edges between faces GetEdgesFromMaterialBoundaries(ref elementId, ref elements); // Count number of edges in an edge node Dictionary nodeIdEdgeCount = new Dictionary(); foreach (var entry in elements) { if (entry.Value is LinearBeamElement lbe) { if (nodeIdEdgeCount.ContainsKey(lbe.NodeIds[0])) nodeIdEdgeCount[lbe.NodeIds[0]]++; else nodeIdEdgeCount.Add(lbe.NodeIds[0], 1); if (nodeIdEdgeCount.ContainsKey(lbe.NodeIds[1])) nodeIdEdgeCount[lbe.NodeIds[1]]++; else nodeIdEdgeCount.Add(lbe.NodeIds[1], 1); } } // Get vertices HashSet vertexNodeIds = new HashSet(); foreach (var entry in nodeIdEdgeCount) { if (entry.Value > 2) vertexNodeIds.Add(entry.Key); } // if (convertToSecondOrder) FeMesh.LinearToParabolic(ref nodes, ref elements); // FeMesh mesh = new FeMesh(nodes, elements, meshRepresentation, null, null, false, ImportOptions.DetectEdges); // mesh.ConvertLineFeElementsToEdges(vertexNodeIds); // if (elementsToImport != ElementsToImport.All) { if (!elementsToImport.HasFlag(ElementsToImport.Beam)) mesh.RemoveElementsByType(); if (!elementsToImport.HasFlag(ElementsToImport.Shell)) mesh.RemoveElementsByType(); if (!elementsToImport.HasFlag(ElementsToImport.Solid)) mesh.RemoveElementsByType(); } // return mesh; } // return null; } private static void ReadVertices(string[] lines, ref int currentLine, ref int nodeId, Dictionary existingNodes, double epsilon, ref Dictionary nodes, out Dictionary oldNodeIdNewNodeId) { int numOfNodes; int possibleNodeId; string[] tmp; FeNode node; // oldNodeIdNewNodeId = new Dictionary(); currentLine++; // if (currentLine < lines.Length) { numOfNodes = int.Parse(lines[currentLine]); currentLine++; for (int j = 0; j < numOfNodes && currentLine + j < lines.Length; j++) { tmp = lines[currentLine + j].Split(_spaceSplitter, StringSplitOptions.RemoveEmptyEntries); if (tmp.Length >= 3) { node = new FeNode(); node.Id = nodeId++; node.X = double.Parse(tmp[0]); node.Y = double.Parse(tmp[1]); node.Z = double.Parse(tmp[2]); possibleNodeId = int.Parse(tmp[3]); // If the node id is not equal to 0 check if the node exists by coordinates if (existingNodes != null && possibleNodeId != 0) node.Id = GetExistingNodeId(node, possibleNodeId, existingNodes, epsilon); nodes.Add(node.Id, node); // oldNodeIdNewNodeId.Add(j + 1, node.Id); } } } } private static void ReadEdges(string[] lines, ref int currentLine, ref int elementId, Dictionary oldNodeIdNewNodeId, ref Dictionary elements, out Dictionary> edgeIdNodeIdCount, out Dictionary> edgeIdElementIds) { int numOfEdges; int edgeId; string[] tmp; LinearBeamElement beam; Dictionary nodeIdCount; HashSet edgeElementIds; // edgeIdNodeIdCount = new Dictionary>(); edgeIdElementIds = new Dictionary>(); currentLine++; // if (currentLine < lines.Length) { numOfEdges = int.Parse(lines[currentLine]); currentLine++; for (int j = 0; j < numOfEdges && currentLine + j < lines.Length; j++) { tmp = lines[currentLine + j].Split(_spaceSplitter, StringSplitOptions.RemoveEmptyEntries); if (tmp.Length >= 3) { edgeId = int.Parse(tmp[2]); // if (edgeId > 0) { edgeId--; // if (!edgeIdNodeIdCount.TryGetValue(edgeId, out nodeIdCount)) { nodeIdCount = new Dictionary(); edgeIdNodeIdCount.Add(edgeId, nodeIdCount); } // beam = new LinearBeamElement(elementId++, new int[2]); beam.NodeIds[0] = oldNodeIdNewNodeId[int.Parse(tmp[0])]; beam.NodeIds[1] = oldNodeIdNewNodeId[int.Parse(tmp[1])]; // If node already on the edge remove it if (!nodeIdCount.Remove(beam.NodeIds[0])) nodeIdCount.Add(beam.NodeIds[0], true); if (!nodeIdCount.Remove(beam.NodeIds[1])) nodeIdCount.Add(beam.NodeIds[1], true); // elements.Add(beam.Id, beam); // if (edgeIdElementIds.TryGetValue(edgeId, out edgeElementIds)) edgeElementIds.Add(beam.Id); else edgeIdElementIds.Add(edgeId, new HashSet { beam.Id }); } //else if (System.Diagnostics.Debugger.IsAttached) throw new NotSupportedException(); } else if (System.Diagnostics.Debugger.IsAttached) throw new NotSupportedException(); } } } private static void ReadTriangles(string[] lines, ref int currentLine, ref int elementId, ref int maxPartId, Dictionary oldNodeIdNewNodeId, ref Dictionary elements, out Dictionary> surfaceIdElementIds) { int numOfElements; int surfaceId; int newMaxPartId = 0; string[] tmp; HashSet surfaceElementIds; LinearTriangleElement triangle; // surfaceIdElementIds = new Dictionary>(); currentLine++; // if (currentLine < lines.Length) { numOfElements = int.Parse(lines[currentLine]); currentLine++; for (int j = 0; j < numOfElements && currentLine + j < lines.Length; j++) { tmp = lines[currentLine + j].Split(_spaceSplitter, StringSplitOptions.RemoveEmptyEntries); if (tmp.Length >= 4) { triangle = new LinearTriangleElement(elementId++, new int[3]); triangle.NodeIds[0] = oldNodeIdNewNodeId[int.Parse(tmp[0])]; triangle.NodeIds[1] = oldNodeIdNewNodeId[int.Parse(tmp[1])]; triangle.NodeIds[2] = oldNodeIdNewNodeId[int.Parse(tmp[2])]; surfaceId = int.Parse(tmp[3]) - 1; // triangle.PartId = surfaceId + 1 + maxPartId + 1; if (triangle.PartId > newMaxPartId) newMaxPartId = triangle.PartId; // // elements.Add(triangle.Id, triangle); // if (surfaceIdElementIds.TryGetValue(surfaceId, out surfaceElementIds)) surfaceElementIds.Add(triangle.Id); else surfaceIdElementIds.Add(surfaceId, new HashSet { triangle.Id }); } } } // maxPartId = newMaxPartId; } private static void ReadTetrahedrons(string[] lines, ref int currentLine, ref int elementId, ref int maxPartId, Dictionary oldNodeIdNewNodeId, ref Dictionary elements, out Dictionary> partIdElementIds) { int numOfElements; int newMaxPartId = 0; string[] tmp; LinearTetraElement tetra; HashSet surfaceElementIds; // partIdElementIds = new Dictionary>(); currentLine++; // if (currentLine < lines.Length) { numOfElements = int.Parse(lines[currentLine]); currentLine++; for (int j = 0; j < numOfElements && currentLine + j < lines.Length; j++) { tmp = lines[currentLine + j].Split(_spaceSplitter, StringSplitOptions.RemoveEmptyEntries); if (tmp.Length >= 5) { tetra = new LinearTetraElement(elementId++, new int[4]); tetra.NodeIds[0] = oldNodeIdNewNodeId[int.Parse(tmp[0])]; tetra.NodeIds[1] = oldNodeIdNewNodeId[int.Parse(tmp[1])]; tetra.NodeIds[2] = oldNodeIdNewNodeId[int.Parse(tmp[2])]; tetra.NodeIds[3] = oldNodeIdNewNodeId[int.Parse(tmp[3])]; tetra.PartId = int.Parse(tmp[4]) + maxPartId + 1; if (tetra.PartId > newMaxPartId) newMaxPartId = tetra.PartId; // elements.Add(tetra.Id, tetra); // if (partIdElementIds.TryGetValue(tetra.PartId, out surfaceElementIds)) surfaceElementIds.Add(tetra.Id); else partIdElementIds.Add(tetra.PartId, new HashSet { tetra.Id }); } } } // maxPartId = newMaxPartId; } // private static void GetEdgesFromMaterialBoundaries(ref int elementId, ref Dictionary elements) { int id1; int id2; int[] key; List surfaceIds; CompareIntArray comparer = new CompareIntArray(); HashSet existingEdges = new HashSet(comparer); Dictionary> edgeSurfaceId = new Dictionary>(comparer); // foreach (var entry in elements) { if (entry.Value is LinearBeamElement existingBeam) { id1 = existingBeam.NodeIds[0]; id2 = existingBeam.NodeIds[1]; if (id1 > id2) (id1, id2) = (id2, id1); // sort key = new int[] { id1, id2 }; existingEdges.Add(key); } else if (entry.Value is LinearTriangleElement triangle) { for (int i = 0; i < 3; i++) { id1 = triangle.NodeIds[i % 3]; id2 = triangle.NodeIds[(i + 1) % 3]; if (id1 > id2) (id1, id2) = (id2, id1); // sort key = new int[] { id1, id2 }; // if (edgeSurfaceId.TryGetValue(key, out surfaceIds)) surfaceIds.Add(triangle.PartId); else edgeSurfaceId.Add(key, new List { triangle.PartId }); } } } HashSet uniqueSurfaceIds; LinearBeamElement beam; foreach (var entry in edgeSurfaceId) { if (!existingEdges.Contains(entry.Key)) { uniqueSurfaceIds = new HashSet(entry.Value); // Free edge if (entry.Value.Count == 1) { beam = new LinearBeamElement(elementId++, entry.Key); elements.Add(beam.Id, beam); } // Internal surface edge else if (entry.Value.Count == 2 && uniqueSurfaceIds.Count == 1) { } // Edge else if (entry.Value.Count > 2 || uniqueSurfaceIds.Count > 1) { beam = new LinearBeamElement(elementId++, entry.Key); elements.Add(beam.Id, beam); } } } } private static int GetExistingNodeId(FeNode node, int possibleId, Dictionary existingNodes, double epsilon) { FeNode node2; // Check if the node ids represent the same coordinates if (existingNodes.TryGetValue(possibleId, out node2)) { if (Math.Abs(node.X - node2.X) < epsilon) { if (Math.Abs(node.Y - node2.Y) < epsilon) { if (Math.Abs(node.Z - node2.Z) < epsilon) { return node2.Id; } } } } // Search for the same coordinates foreach (var entry in existingNodes) { if (Math.Abs(node.X - entry.Value.X) < epsilon) { if (Math.Abs(node.Y - entry.Value.Y) < epsilon) { if (Math.Abs(node.Z - entry.Value.Z) < epsilon) { return entry.Key; } } } } // return node.Id; } } }