using CaeGlobals; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Collections.Concurrent; using System.Windows.Forms.VisualStyles; namespace CaeMesh { [Serializable] public class VisualizationData { // vertex // edge - parabolic edge [0, 1, 2] is visually discretized like 0----2----1 // face - cells limited by edges // surface - can be arbitrary combination of cells // Variables protected int[][] _cells; protected int[] _cellIds; protected int[][] _cellIdsByFace; // could be hashSet<> but serialization could be bad protected double[] _faceAreas; protected GeomFaceType[] _faceTypes; protected int[][] _faceEdgeIds; protected int[][][] _cellIdCellIdEdgeNodeIds; protected int[][] _cellNeighboursOverCellEdge; protected int[][] _edgeCells; protected int[][] _edgeCellIdsByEdge; protected double[] _edgeLengths; protected GeomCurveType[] _edgeTypes; protected int[] _vertexNodeIds; // [NonSerialized] private Dictionary _cellNeighboursOverCell; // this are solid cell neighbours to extract surface // Properties /// /// Cells /// [0...num. of cells][0...num. of nodes] -> global node id /// public int[][] Cells { get { return _cells; } set { _cells = value; } } /// /// CellIds /// [0...num. of cells] -> global element id /// public int[] CellIds { get { return _cellIds; } set { _cellIds = value; } } /// /// FaceCount /// Return number of faces /// public int FaceCount { get { return _cellIdsByFace != null ? _cellIdsByFace.Length : 0; } } /// /// CellIdsByFace /// [0...num. of faces][0...num. of face cells] -> local cell id /// public int[][] CellIdsByFace { get { return _cellIdsByFace; } set { _cellIdsByFace = value; if (_cellIdsByFace != null) { // sort ids for binary search for (int i = 0; i < _cellIdsByFace.Length; i++) Array.Sort(_cellIdsByFace[i]); } } } /// /// FaceAreas /// [0...num. of faces] /// public double[] FaceAreas { get { return _faceAreas; } set { _faceAreas = value; } } /// /// FaceTypes /// [0...num. of faces] /// public GeomFaceType[] FaceTypes { get { return _faceTypes; } set { _faceTypes = value; } } /// /// EdgeCount /// Return number of edges /// public int EdgeCount { get { return _edgeCellIdsByEdge.Length; } } /// /// FaceEdgeIds /// [0...num. of faces][0...num. of edges] -> local edge id /// public int[][] FaceEdgeIds { get { return _faceEdgeIds; } set { _faceEdgeIds = value; } } /// /// CellIdCellIdEdgeNodeIds /// [0...num. of cells][0...num. of neigh.] -> edge node ids /// public int[][][] CellIdCellIdEdgeNodeIds { get { return _cellIdCellIdEdgeNodeIds; } set { _cellIdCellIdEdgeNodeIds = value; } } /// /// CellNeighboursOverEdge /// [0...num. of cells][0...num. of neigh.] -> local cell id /// public int[][] CellNeighboursOverCellEdge { get { return _cellNeighboursOverCellEdge; } set { _cellNeighboursOverCellEdge = value; } } /// /// EdgeCells /// [0...num. of edge cells][0...num. of nodes] -> global node id /// public int[][] EdgeCells { get { return _edgeCells; } set { _edgeCells = value; } } /// /// EdgeCellIdsByEdge /// [0...num. of edges][0...num. of edge cells] -> local edge cell id /// public int[][] EdgeCellIdsByEdge { get { return _edgeCellIdsByEdge; } set { _edgeCellIdsByEdge = value; } } /// /// EdgeLengths /// [0...num. of edges] /// public double[] EdgeLengths { get { return _edgeLengths; } set { _edgeLengths = value; } } /// /// EdgeTypes /// [0...num. of edges] /// public GeomCurveType[] EdgeTypes { get { return _edgeTypes; } set { _edgeTypes = value; } } /// /// VertexNodeIds /// [0...num. of vertices] -> global node id (a vertice is a node where more than two edge cells meet) /// public int[] VertexNodeIds { get { return _vertexNodeIds; } set { _vertexNodeIds = value; } } // Constructors public VisualizationData() { _cells = null; _cellIds = null; _cellIdsByFace = null; _faceAreas = null; _faceTypes = null; _faceEdgeIds = null; _cellNeighboursOverCellEdge = null; _edgeCells = null; _edgeCellIdsByEdge = null; _edgeLengths = null; _edgeTypes = null; _vertexNodeIds = null; ResetCellNeighboursOverCell(); } public VisualizationData(VisualizationData visualization) : this() { if (visualization.Cells != null) { _cells = new int[visualization.Cells.Length][]; for (int i = 0; i < _cells.Length; i++) _cells[i] = visualization.Cells[i].ToArray(); } _cellIds = visualization.CellIds != null ? visualization.CellIds.ToArray() : null; // if (visualization.CellIdsByFace != null) { _cellIdsByFace = new int[visualization.CellIdsByFace.Length][]; for (int i = 0; i < _cellIdsByFace.Length; i++) _cellIdsByFace[i] = visualization.CellIdsByFace[i].ToArray(); } // _faceAreas = visualization.FaceAreas != null ? visualization.FaceAreas.ToArray() : null; // Bug fix - visualization.FaceTypes can become an array of integers that cannot be directly copied using ToArray // Probable reason is a PrePoMax crash and model rebuild if (visualization.FaceTypes != null && visualization.FaceTypes.Length > 0) { _faceTypes = new GeomFaceType[visualization.FaceTypes.Length]; for (int i = 0; i < _faceTypes.Length; i++) _faceTypes[i] = visualization.FaceTypes[i]; } else _faceTypes = null; // if (visualization.FaceEdgeIds != null) { _faceEdgeIds = new int[visualization.FaceEdgeIds.Length][]; for (int i = 0; i < _faceEdgeIds.Length; i++) _faceEdgeIds[i] = visualization.FaceEdgeIds[i].ToArray(); } // if (visualization.CellIdCellIdEdgeNodeIds != null) { _cellIdCellIdEdgeNodeIds = new int[visualization.CellIdCellIdEdgeNodeIds.Length][][]; for (int i = 0; i < _cellIdCellIdEdgeNodeIds.Length; i++) { if (visualization.CellIdCellIdEdgeNodeIds[i] != null) { _cellIdCellIdEdgeNodeIds[i] = new int[visualization.CellIdCellIdEdgeNodeIds[i].Length][]; for (int j = 0; j < _cellIdCellIdEdgeNodeIds[i].Length; j++) { _cellIdCellIdEdgeNodeIds[i][j] = visualization.CellIdCellIdEdgeNodeIds[i][j].ToArray(); } } } } // if (visualization.CellNeighboursOverCellEdge != null) { _cellNeighboursOverCellEdge = new int[visualization.CellNeighboursOverCellEdge.Length][]; for (int i = 0; i < _cellNeighboursOverCellEdge.Length; i++) { if (visualization.CellNeighboursOverCellEdge[i] != null) _cellNeighboursOverCellEdge[i] = visualization.CellNeighboursOverCellEdge[i].ToArray(); } } // if (visualization.EdgeCells != null) { _edgeCells = new int[visualization.EdgeCells.Length][]; for (int i = 0; i < _edgeCells.Length; i++) _edgeCells[i] = visualization.EdgeCells[i].ToArray(); } // if (visualization.EdgeCellIdsByEdge != null) { _edgeCellIdsByEdge = new int[visualization.EdgeCellIdsByEdge.Length][]; for (int i = 0; i < _edgeCellIdsByEdge.Length; i++) _edgeCellIdsByEdge[i] = visualization.EdgeCellIdsByEdge[i].ToArray(); } // _edgeLengths = visualization.EdgeLengths != null ? visualization.EdgeLengths.ToArray() : null; // // Bug fix - visualization.EdgeTypes can become an array of integers that cannot be directly copied using ToArray // Probable reason is a PrePoMax crash and model rebuild if (visualization.EdgeTypes != null && visualization.EdgeTypes.Length > 0) { _edgeTypes = new GeomCurveType[visualization.EdgeTypes.Length]; for (int i = 0; i < _edgeTypes.Length; i++) _edgeTypes[i] = visualization.EdgeTypes[i]; } else _edgeTypes = null; // _vertexNodeIds = visualization.VertexNodeIds != null ? visualization.VertexNodeIds.ToArray() : null; // Reference exchange - for speed and memory - might be a problem _cellNeighboursOverCell = visualization._cellNeighboursOverCell != null ? visualization._cellNeighboursOverCell : null; } // Static methods public static void WriteToBinaryStream(VisualizationData visualizationData, System.IO.BinaryWriter bw) { if (visualizationData == null) { bw.Write(-1); } else { bw.Write(1); // must be here // ReadWrite.WriteToBinaryStream(visualizationData._cells, bw); ReadWrite.WriteToBinaryStream(visualizationData._cellIds, bw); ReadWrite.WriteToBinaryStream(visualizationData._cellIdsByFace, bw); ReadWrite.WriteToBinaryStream(visualizationData._faceAreas, bw); WriteToBinaryStream((int[])(object)visualizationData._faceTypes, bw); ReadWrite.WriteToBinaryStream(visualizationData._faceEdgeIds, bw); ReadWrite.WriteToBinaryStream(visualizationData._cellNeighboursOverCellEdge, bw); ReadWrite.WriteToBinaryStream(visualizationData._edgeCells, bw); ReadWrite.WriteToBinaryStream(visualizationData._edgeCellIdsByEdge, bw); ReadWrite.WriteToBinaryStream(visualizationData._edgeLengths, bw); WriteToBinaryStream((int[])(object)visualizationData._edgeTypes, bw); ReadWrite.WriteToBinaryStream(visualizationData._vertexNodeIds, bw); } } public static void ReadFromBinaryStream(out VisualizationData visualizationData, System.IO.BinaryReader br, int version) { int exists = br.ReadInt32(); if (exists <= -1) visualizationData = null; else { int[] types; visualizationData = new VisualizationData(); ReadWrite.ReadFromBinaryStream(out visualizationData._cells, br); ReadWrite.ReadFromBinaryStream(out visualizationData._cellIds, br); ReadWrite.ReadFromBinaryStream(out visualizationData._cellIdsByFace, br); ReadWrite.ReadFromBinaryStream(out visualizationData._faceAreas, br); ReadFromBinaryStream(out types, br); visualizationData._faceTypes = (GeomFaceType[])(object)types; ReadWrite.ReadFromBinaryStream(out visualizationData._faceEdgeIds, br); ReadWrite.ReadFromBinaryStream(out visualizationData._cellNeighboursOverCellEdge, br); ReadWrite.ReadFromBinaryStream(out visualizationData._edgeCells, br); ReadWrite.ReadFromBinaryStream(out visualizationData._edgeCellIdsByEdge, br); ReadWrite.ReadFromBinaryStream(out visualizationData._edgeLengths, br); if (version > 1_004_001) { ReadFromBinaryStream(out types, br); visualizationData._edgeTypes = (GeomCurveType[])(object)types; } ReadWrite.ReadFromBinaryStream(out visualizationData._vertexNodeIds, br); } } private static void WriteToBinaryStream(int[] data, System.IO.BinaryWriter bw) { if (data == null) { bw.Write(-1); } else { bw.Write(data.Length); for (int i = 0; i < data.Length; i++) bw.Write(data[i]); } } private static void ReadFromBinaryStream(out int[] data, System.IO.BinaryReader br) { int numOfEntries = br.ReadInt32(); if (numOfEntries <= -1) data = null; else { data = new int[numOfEntries]; for (int i = 0; i < data.Length; i++) data[i] = br.ReadInt32(); } } // Methods public void ResetCellNeighboursOverCell() { _cellNeighboursOverCell = null; } // public void ExtractVisualizationCellsFromElements3D(Dictionary elements, int[] elementIds) { if (_cellNeighboursOverCell == null) ExtractCellNeighboursOverCell(elements, elementIds); // List visualizationCells = new List(); List visualizationCellsIds = new List(); // Extract free faces foreach (var entry in _cellNeighboursOverCell) { if (entry.Value.Id2 == -1) { visualizationCells.Add(entry.Value.Cell1); visualizationCellsIds.Add(entry.Value.Id1); } } // Save _cells = visualizationCells.ToArray(); _cellIds = visualizationCellsIds.ToArray(); } public void ExtractVisualizationCellsFromElements2D(Dictionary elements, int[] elementIds) { int count; int[][] visualizationCells = new int[elementIds.Length][]; int[] visualizationCellsIds = new int[elementIds.Length]; // count = 0; foreach (var id in elementIds) { visualizationCellsIds[count] = id; visualizationCells[count++] = elements[id].GetVtkNodeIds(); } // Save _cells = visualizationCells.ToArray(); _cellIds = visualizationCellsIds.ToArray(); } private void ExtractCellNeighboursOverCell(Dictionary elements, int[] elementIds) { int[] key; CompareIntArray comparer = new CompareIntArray(); CellNeighbour cellNeighbour; _cellNeighboursOverCell = new Dictionary(elementIds.Length, comparer); // Parallelizing this loop does not bring any speedup foreach (var id in elementIds) { foreach (int[] cell in ((FeElement3D)elements[id]).GetAllVtkCells()) { key = cell.ToArray(); Array.Sort(key); // if (_cellNeighboursOverCell.TryGetValue(key, out cellNeighbour)) cellNeighbour.Id2 = id; else _cellNeighboursOverCell.Add(key, new CellNeighbour(id, -1, cell)); } } } // public void RenumberNodes(Dictionary newIds) { // Cells int id; if (_cells != null) { for (int i = 0; i < _cells.Length; i++) { for (int j = 0; j < _cells[i].Length; j++) { if (newIds.TryGetValue(_cells[i][j], out id)) _cells[i][j] = id; } } } // Edge cells if (_edgeCells != null) { for (int i = 0; i < _edgeCells.Length; i++) { for (int j = 0; j < _edgeCells[i].Length; j++) { if (newIds.TryGetValue(_edgeCells[i][j], out id)) _edgeCells[i][j] = id; } } } // Vertex ids if (_vertexNodeIds != null) { for (int i = 0; i < _vertexNodeIds.Length; i++) { if (newIds.TryGetValue(_vertexNodeIds[i], out id)) _vertexNodeIds[i] = id; } } // Cell neighbours over cell bool error = false; int[] cellIds = new int[4]; if (_cellNeighboursOverCell != null) { int[] renumberedKey; int[] renumberedCell; CellNeighbour cellNeighbour; CellNeighbour existingCellNeighbour; CompareIntArray comparer = new CompareIntArray(); Dictionary renumberedNeighbours = new Dictionary(_cellNeighboursOverCell.Count, comparer); // foreach (var entry in _cellNeighboursOverCell) { renumberedCell = entry.Value.Cell1.ToArray(); // not all nodes are renumbered - make a copy // for (int i = 0; i < renumberedCell.Length; i++) { if (newIds.TryGetValue(entry.Value.Cell1[i], out id)) renumberedCell[i] = id; } // renumberedKey = renumberedCell.ToArray(); Array.Sort(renumberedKey); // cellNeighbour = entry.Value; cellNeighbour.Cell1 = renumberedCell; // if (renumberedNeighbours.TryGetValue(renumberedKey, out existingCellNeighbour)) { cellIds[0] = cellNeighbour.Id1; cellIds[1] = cellNeighbour.Id2; cellIds[2] = existingCellNeighbour.Id1; cellIds[3] = existingCellNeighbour.Id2; Array.Sort(cellIds); // The same cell if (cellIds[0] == cellIds[1] && cellIds[2] == cellIds[3]) error = true; // Two outer cells connected together else if (cellIds[0] == -1 && cellIds[1] == -1 && cellIds[2] != -1 && cellIds[3] != -1) { existingCellNeighbour.Id1 = cellIds[2]; existingCellNeighbour.Id2 = cellIds[3]; } // The rest else error = true; } else renumberedNeighbours.Add(renumberedKey, cellNeighbour); } _cellNeighboursOverCell = renumberedNeighbours; } // if (System.Diagnostics.Debugger.IsAttached && error) MessageBoxes.ShowError("VisualizationData:RenumberNodes: This should not happen!"); } public void RenumberElements(Dictionary newIds) { int id; if (_cellIds != null) { for (int i = 0; i < _cellIds.Length; i++) { if (newIds.TryGetValue(_cellIds[i], out id)) _cellIds[i] = id; } } // Cell neighbours over cell if (_cellNeighboursOverCell != null) { foreach (var entry in _cellNeighboursOverCell) { if (entry.Value.Id1 != -1 && newIds.TryGetValue(entry.Value.Id1, out id)) entry.Value.Id1 = id; if (entry.Value.Id2 != -1 && newIds.TryGetValue(entry.Value.Id2, out id)) entry.Value.Id2 = id; } } } public void RenumberSurfaces(int[] orderedSurfaceIds) { // Surface cells int[][] newCellIdsByFace = new int[_cellIdsByFace.Length][]; for (int i = 0; i < orderedSurfaceIds.Length; i++) { newCellIdsByFace[i] = _cellIdsByFace[orderedSurfaceIds[i]]; } _cellIdsByFace = newCellIdsByFace; // Areas double[] newFaceAreas = new double[_faceAreas.Length]; for (int i = 0; i < orderedSurfaceIds.Length; i++) { newFaceAreas[i] = _faceAreas[orderedSurfaceIds[i]]; } _faceAreas = newFaceAreas; // Types if (_faceTypes != null) { GeomFaceType[] newFaceTypes = new GeomFaceType[_faceTypes.Length]; for (int i = 0; i < orderedSurfaceIds.Length; i++) { newFaceTypes[i] = _faceTypes[orderedSurfaceIds[i]]; } _faceTypes = newFaceTypes; } // Edges int[][] newFaceEdgeIds = new int[_faceEdgeIds.Length][]; for (int i = 0; i < orderedSurfaceIds.Length; i++) { newFaceEdgeIds[i] = _faceEdgeIds[orderedSurfaceIds[i]]; } _faceEdgeIds = newFaceEdgeIds; } public void RenumberEdges(int[] orderedEdgeIds) { // Inverse map int[] map = new int[orderedEdgeIds.Length]; for (int i = 0; i < orderedEdgeIds.Length; i++) { map[orderedEdgeIds[i]] = i; } // Surface edges if (_faceEdgeIds != null) { int[][] newFaceEdgeIds = new int[_faceEdgeIds.Length][]; for (int i = 0; i < _faceEdgeIds.Length; i++) { newFaceEdgeIds[i] = new int[_faceEdgeIds[i].Length]; for (int j = 0; j < _faceEdgeIds[i].Length; j++) { newFaceEdgeIds[i][j] = map[_faceEdgeIds[i][j]]; } } _faceEdgeIds = newFaceEdgeIds; } // Edge cells int[][] newEdgeCellIdsByEdge = new int[_edgeCellIdsByEdge.Length][]; for (int i = 0; i < orderedEdgeIds.Length; i++) { newEdgeCellIdsByEdge[i] = _edgeCellIdsByEdge[orderedEdgeIds[i]]; } _edgeCellIdsByEdge = newEdgeCellIdsByEdge; // Lengths double[] newEdgeLengths = new double[_edgeLengths.Length]; for (int i = 0; i < orderedEdgeIds.Length; i++) { newEdgeLengths[i] = _edgeLengths[orderedEdgeIds[i]]; } _edgeLengths = newEdgeLengths; // Types if (_edgeTypes != null) { GeomCurveType[] newEdgeTypes = new GeomCurveType[_edgeTypes.Length]; for (int i = 0; i < orderedEdgeIds.Length; i++) { newEdgeTypes[i] = _edgeTypes[orderedEdgeIds[i]]; } _edgeTypes = newEdgeTypes; } } public HashSet GetNodeIdsForEdgeId(int edgeId) { HashSet edgeNodeIds = new HashSet(); // if (_edgeCellIdsByEdge != null) { for (int i = 0; i < _edgeCellIdsByEdge[edgeId].Length; i++) { edgeNodeIds.UnionWith(_edgeCells[_edgeCellIdsByEdge[edgeId][i]]); } } return edgeNodeIds; } public Dictionary> GetEdgeIdNodeIds() { HashSet edgeNodeIds; Dictionary> edgeIdNodeIds = new Dictionary>(); // if (_edgeCellIdsByEdge != null) { for (int i = 0; i < _edgeCellIdsByEdge.Length; i++) { edgeNodeIds = new HashSet(); for (int j = 0; j < _edgeCellIdsByEdge[i].Length; j++) { edgeNodeIds.UnionWith(_edgeCells[_edgeCellIdsByEdge[i][j]]); } edgeIdNodeIds.Add(i, edgeNodeIds); } } return edgeIdNodeIds; } public HashSet GetNodeIdsForAllEdges() { HashSet edgeNodeIds = new HashSet(); // if (_edgeCellIdsByEdge != null) { for (int i = 0; i < _edgeCellIdsByEdge.Length; i++) { for (int j = 0; j < _edgeCellIdsByEdge[i].Length; j++) { edgeNodeIds.UnionWith(_edgeCells[_edgeCellIdsByEdge[i][j]]); } } } return edgeNodeIds; } public int[] GetOrderedNodeIdsForEdgeId(int edgeId) { int[] edgeNodeIds; List allEdgeNodeIds = new List(); for (int i = 0; i < _edgeCellIdsByEdge[edgeId].Length; i++) { edgeNodeIds = _edgeCells[_edgeCellIdsByEdge[edgeId][i]]; // if (i == 0) allEdgeNodeIds.Add(edgeNodeIds[0]); // add the first node only once if (edgeNodeIds.Length == 3) allEdgeNodeIds.Add(edgeNodeIds[2]); allEdgeNodeIds.Add(edgeNodeIds[1]); } // return allEdgeNodeIds.ToArray(); } // public HashSet GetNodeIds() { HashSet nodeIds = new HashSet(); for (int i = 0; i < _cells.Length; i++) nodeIds.UnionWith(_cells[i]); return nodeIds; } public Dictionary> GetVertexIdEdgeCells() { HashSet vertexNodeIds = new HashSet(_vertexNodeIds); List edgeCells; Dictionary> vertexIdEdgeCells = new Dictionary>(); // List ids = new List(); int[] edgeCellNodeIds; foreach (var edgeCell in _edgeCells) { ids.Clear(); if (vertexNodeIds.Contains(edgeCell[0])) ids.Add(0); if (vertexNodeIds.Contains(edgeCell[1])) ids.Add(1); // foreach (var id in ids) { edgeCellNodeIds = new int[] { edgeCell[id], edgeCell[(id + 1) % 2] }; if (vertexIdEdgeCells.TryGetValue(edgeCell[id], out edgeCells)) edgeCells.Add(edgeCellNodeIds); else vertexIdEdgeCells.Add(edgeCell[id], new List { edgeCellNodeIds }); } } // return vertexIdEdgeCells; } public Dictionary> GetVertexIdEdgeIds() { HashSet edgeIds; Dictionary> edgeIdNodeIds = GetEdgeIdNodeIds(); Dictionary> vertexIdEdgeIds = new Dictionary>(); // foreach (int vertexId in _vertexNodeIds) { foreach (var entry in edgeIdNodeIds) { if (entry.Value.Contains(vertexId)) { if (vertexIdEdgeIds.TryGetValue(vertexId, out edgeIds)) edgeIds.Add(entry.Key); else vertexIdEdgeIds.Add(vertexId, new HashSet { entry.Key }); } } } // return vertexIdEdgeIds; } public HashSet GetNodeIdsForSurfaceId(int surfaceId) { HashSet surfaceNodeIds = new HashSet(); for (int i = 0; i < _cellIdsByFace[surfaceId].Length; i++) { surfaceNodeIds.UnionWith(_cells[_cellIdsByFace[surfaceId][i]]); } return surfaceNodeIds; } public Dictionary> GetSurfaceIdNodeIds() { HashSet surfaceNodeIds; Dictionary> surfaceIdNodeIds = new Dictionary>(); for (int i = 0; i < _cellIdsByFace.Length; i++) { surfaceNodeIds = new HashSet(); for (int j = 0; j < _cellIdsByFace[i].Length; j++) { surfaceNodeIds.UnionWith(_cells[_cellIdsByFace[i][j]]); } surfaceIdNodeIds.Add(i, surfaceNodeIds); } return surfaceIdNodeIds; } public Dictionary> GetSurfaceIdElementIds() { HashSet surfaceElementIds; Dictionary> surfaceIdElementIds = new Dictionary>(); for (int i = 0; i < _cellIdsByFace.Length; i++) { surfaceElementIds = new HashSet(); for (int j = 0; j < _cellIdsByFace[i].Length; j++) { surfaceElementIds.Add(_cellIds[_cellIdsByFace[i][j]]); } surfaceIdElementIds.Add(i, surfaceElementIds); } return surfaceIdElementIds; } public Dictionary> GetSurfaceIdSurfaceNeighbourIds() { Dictionary> surfaceIdSurfaceNeighbourIds = new Dictionary>(); HashSet surfaceNeighbourIds; for (int i = 0; i < _faceEdgeIds.Length; i++) { for (int j = 0; j < _faceEdgeIds.Length; j++) { if (i == j) continue; // if (_faceEdgeIds[i].Intersect(_faceEdgeIds[j]).Count() > 0) { if (surfaceIdSurfaceNeighbourIds.TryGetValue(i, out surfaceNeighbourIds)) surfaceNeighbourIds.Add(j); else surfaceIdSurfaceNeighbourIds.Add(i, new HashSet() { j }); } } } return surfaceIdSurfaceNeighbourIds; } public Dictionary> GetElementIdSurfaceIds() { int elementId; HashSet elementSurfaceIds; Dictionary> elementIdSurfaceIds = new Dictionary>(); for (int i = 0; i < _cellIdsByFace.Length; i++) { for (int j = 0; j < _cellIdsByFace[i].Length; j++) { elementId = _cellIds[_cellIdsByFace[i][j]]; // if (elementIdSurfaceIds.TryGetValue(elementId, out elementSurfaceIds)) elementSurfaceIds.Add(i); else elementIdSurfaceIds.Add(elementId, new HashSet() { i }); } } return elementIdSurfaceIds; } public HashSet GetVertexIdsForNodeIds(int[] nodeIds) { HashSet nodeIdsHash = new HashSet(nodeIds); HashSet vertexNodeIds = new HashSet(); for (int i = 0; i < _vertexNodeIds.Length; i++) { if (nodeIdsHash.Contains(_vertexNodeIds[i])) vertexNodeIds.Add(i + 1); } return vertexNodeIds; } public int[] GetVertexNodeIdsForEdgeId(int edgeId) { HashSet edgeNodeIds = new HashSet(GetNodeIdsForEdgeId(edgeId)); edgeNodeIds.IntersectWith(_vertexNodeIds); // Return start/end ids if (edgeNodeIds.Count == 1) return new int[] { edgeNodeIds.First(), edgeNodeIds.First() }; else return edgeNodeIds.ToArray(); } public HashSet GetVertexNodeIdsForEdgeIds(int[] edgeIds) { HashSet edgeNodeIds = new HashSet(); foreach (int edgeId in edgeIds) edgeNodeIds.UnionWith(GetNodeIdsForEdgeId(edgeId)); return edgeNodeIds.Intersect(_vertexNodeIds).ToHashSet(); } public int[] GetVertexNodeIdsForSurfaceId(int surfaceId) { HashSet surfaceNodeIds = new HashSet(GetNodeIdsForSurfaceId(surfaceId)); return surfaceNodeIds.Intersect(_vertexNodeIds).ToArray(); } public HashSet GetVertexNodeIdsForSurfaceIds(int[] surfaceIds) { HashSet surfaceNodeIds = new HashSet(); foreach (int surfaceId in surfaceIds) surfaceNodeIds.UnionWith(GetNodeIdsForSurfaceId(surfaceId)); return surfaceNodeIds.Intersect(_vertexNodeIds).ToHashSet(); } public HashSet GetEdgeIdsForSurfaceIds(int[] surfaceIds) { HashSet surfaceEdgeIds = new HashSet(); foreach (int surfaceId in surfaceIds) surfaceEdgeIds.UnionWith(_faceEdgeIds[surfaceId]); return surfaceEdgeIds; } public bool AreSurfacesConnected(int[] surfaceIds, Dictionary> surfaceIdSurfaceNeighbourIds = null) { if (surfaceIds.Length == 1) return true; // HashSet selectedSurfaceNeighboursIds = new HashSet(); if (surfaceIdSurfaceNeighbourIds == null) surfaceIdSurfaceNeighbourIds = GetSurfaceIdSurfaceNeighbourIds(); // HashSet surfaceNeighbours; foreach (var surfaceId in surfaceIds) { if (surfaceIdSurfaceNeighbourIds.TryGetValue(surfaceId, out surfaceNeighbours)) selectedSurfaceNeighboursIds.UnionWith(surfaceNeighbours); else return false; } // If surfaces are connected all of them are also their neighbours return selectedSurfaceNeighboursIds.Intersect(surfaceIds).Count() == surfaceIds.Count(); } public HashSet GetEdgeNodeIds() { HashSet nodeIds = new HashSet(); foreach (var edgeCell in _edgeCells) nodeIds.UnionWith(edgeCell); return nodeIds; } // Free edges and nodes public HashSet GetFreeEdgeIds() { int[] count; Dictionary edgeIdCount = new Dictionary(); // foreach (var faceEdgeIds in _faceEdgeIds) { foreach (var edgeId in faceEdgeIds) { if (edgeIdCount.TryGetValue(edgeId, out count)) count[0]++; else edgeIdCount[edgeId] = new int[] { 1 }; } } // HashSet freeEdgeIds = new HashSet(); foreach (var entry in edgeIdCount) { if (entry.Value[0] == 1) freeEdgeIds.Add(entry.Key); } // return freeEdgeIds; } public HashSet GetFreeEdgeNodeIds() { HashSet freeEdgeIds = GetFreeEdgeIds(); HashSet freeNodeIds = new HashSet(); foreach (var edgeId in freeEdgeIds) { foreach (var edgeCellId in _edgeCellIdsByEdge[edgeId]) { freeNodeIds.UnionWith(_edgeCells[edgeCellId]); } } return freeNodeIds; } public int GetEdgeCellBaseCellIdSlow(int edgeCellId) { bool found; int[] nodeIds = _edgeCells[edgeCellId]; // for (int i = 0; i < _cellNeighboursOverCellEdge.Length; i++) { for (int j = 0; j < _cellNeighboursOverCellEdge[i].Length; j++) { if (_cellNeighboursOverCellEdge[i][j] == -1) { found = true; for (int k = 0; k < nodeIds.Length; k++) { if (!_cells[i].Contains(nodeIds[k])) { found = false; break; } } if (found) return i; else break; } } } return -1; } public int[] GetAllEdgeCellBaseCellIds() { bool found; int cellId; int[] nodeIds; int[] baseCellIds = new int[_edgeCells.Length]; // Set initial value to -1 for (int i = 0; i < baseCellIds.Length; i++) baseCellIds[i] = -1; // for (int k = 0; k < _edgeCells.Length; k++) { nodeIds = _edgeCells[k]; // For cells for (int i = 0; i < _cellNeighboursOverCellEdge.Length; i++) { // For cell neighbours for (int j = 0; j < _cellNeighboursOverCellEdge[i].Length; j++) { if (_cellNeighboursOverCellEdge[i][j] == -1) { found = true; for (int l = 0; l < nodeIds.Length; l++) { if (!_cells[i].Contains(nodeIds[l])) { found = false; break; } } if (found) baseCellIds[k] = i; // break; } } // Check if edge cell is shared with another cell or is it really an free edge cell if (baseCellIds[k] > -1) { for (int j = 0; j < _cellNeighboursOverCellEdge[i].Length; j++) { if (_cellNeighboursOverCellEdge[i][j] > -1) { found = true; cellId = _cellNeighboursOverCellEdge[i][j]; for (int l = 0; l < nodeIds.Length; l++) { if (!_cells[cellId].Contains(nodeIds[l])) { found = false; break; } } if (found) { baseCellIds[k] = -1; // it is not a free edge break; } } } } // if (baseCellIds[k] > -1) break; } } return baseCellIds; } // public Dictionary GetCellEdgeData(Func GetVisualizationEdgeCells) { int[][] cells = _cells; CompareIntArray comparer = new CompareIntArray(); Dictionary allEdges = new Dictionary(comparer); // int[] key; CellEdgeData data; int[][] cellEdges; // System.Diagnostics.Stopwatch watch = new System.Diagnostics.Stopwatch(); watch.Start(); // Get all edges for (int i = 0; i < cells.Length; i++) { cellEdges = GetVisualizationEdgeCells(cells[i], ElementFaceType.Face); // foreach (var cellEdge in cellEdges) { key = cellEdge.ToArray(); Array.Sort(key); // if (key[0] == key[1] || (key.Length == 3 && key[1] == key[2])) { //manifoldGeometry continue; } // if (allEdges.TryGetValue(key, out data)) data.CellIds.Add(i); else allEdges.Add(key, new CellEdgeData() { NodeIds = cellEdge, CellIds = new List() { i } }); } } watch.Stop(); // return allEdges; } public Dictionary GetCellEdgeData1(Func GetVisualizationEdgeCells) { int[][] cells = _cells; CompareIntArray comparer = new CompareIntArray(); ConcurrentDictionary allEdges = new ConcurrentDictionary(comparer); // System.Diagnostics.Stopwatch watch = new System.Diagnostics.Stopwatch(); watch.Start(); // Get all edges Parallel.For(0, cells.Length, i => { int[][] cellEdges = GetVisualizationEdgeCells(cells[i], ElementFaceType.Face); int[] key; CellEdgeData data; // foreach (var cellEdge in cellEdges) { key = cellEdge.ToArray(); Array.Sort(key); // if (key[0] == key[1] || (key.Length == 3 && key[1] == key[2])) { //manifoldGeometry continue; } // if (allEdges.TryGetValue(key, out data)) data.CellIds.Add(i); else allEdges.TryAdd(key, new CellEdgeData() { NodeIds = cellEdge, CellIds = new List() { i } }); } } ); // Copy dictionary Dictionary edges = new Dictionary(comparer); foreach (var entry in allEdges) edges.Add(entry.Key, entry.Value); // watch.Stop(); // return edges; } public Dictionary GetCellEdgeData3(Func GetVisualizationEdgeCells) { CellEdgeData[][] cellEdgeData = new CellEdgeData[_cells.Length][]; // System.Diagnostics.Stopwatch watch = new System.Diagnostics.Stopwatch(); watch.Start(); // Get all edges Parallel.For(0, _cells.Length, i => { int[][] cellEdges = GetVisualizationEdgeCells(_cells[i], ElementFaceType.Face); int[] key; cellEdgeData[i] = new CellEdgeData[cellEdges.Length]; // for (int j = 0; j < cellEdges.Length; j++) { key = cellEdges[j].ToArray(); Array.Sort(key); // if (key[0] == key[1] || (key.Length == 3 && key[1] == key[2])) { // manifoldGeometry continue; } // cellEdgeData[i][j] = new CellEdgeData() // 8 % time { Key = key, NodeIds = cellEdges[j], CellIds = new List() { i } // 18 % time }; } } ); // CellEdgeData data; CompareIntArray comparer = new CompareIntArray(); Dictionary allEdges = new Dictionary(comparer); for (int i = 0; i < cellEdgeData.Length; i++) { for (int j = 0; j < cellEdgeData[i].Length; j++) { if (cellEdgeData[i][j] != null) // check for manifold geometry { if (allEdges.TryGetValue(cellEdgeData[i][j].Key, out data)) data.CellIds.Add(i); else allEdges.Add(cellEdgeData[i][j].Key, cellEdgeData[i][j]); } } } watch.Stop(); // return allEdges; } public int[] GetFreeEdgeCellIds(Func GetVisualizationEdgeCells) { Dictionary allEdges = GetCellEdgeData3(GetVisualizationEdgeCells); // int[] key; int edgeCellId = 0; CompareIntArray comparer = new CompareIntArray(); Dictionary edgeCellEdgeCellId = new Dictionary(comparer); foreach (var edgeCell in _edgeCells) { key = edgeCell.ToArray(); Array.Sort(key); edgeCellEdgeCellId.Add(key, edgeCellId++); } // int freeEdgeCellId; List freeEdgeCellIds = new List(); foreach (var entry in allEdges) { // Free edges if (entry.Value.CellIds.Count == 1) { if (edgeCellEdgeCellId.TryGetValue(entry.Key, out freeEdgeCellId)) freeEdgeCellIds.Add(freeEdgeCellId); else freeEdgeCellId = freeEdgeCellId; } } // return freeEdgeCellIds.ToArray(); } public int[] GetFreeVertexNodeIds(int[] freeEdgeCellIds) { HashSet freeEdgeNodeIds = new HashSet(); foreach (var edgeCellId in freeEdgeCellIds) freeEdgeNodeIds.UnionWith(_edgeCells[edgeCellId]); List freeVertexNodeIds = new List(); foreach (var nodeId in _vertexNodeIds) { if (freeEdgeNodeIds.Contains(nodeId)) freeVertexNodeIds.Add(nodeId); } return freeVertexNodeIds.ToArray(); } // public VisualizationData DeepCopy() { return new VisualizationData(this); } // Topology public void CheckForErrorElementsInShellCADPart(out int[] errorEdgeCellIds, out int[] errorNodeIds) { // Shell parts int edgeId; int[] edgeCell; int[] edgeNodeIds; List vertexEdgeIds; List errorEdgeCellIdsList = new List(); List errorNodeIdsList = new List(); HashSet errorEdgeIds = new HashSet(); HashSet vertexNodeIds = new HashSet(_vertexNodeIds); // Build a map of all edges connected to a vertex Dictionary>[] faceVertexEdgeIds = new Dictionary>[_faceEdgeIds.Length]; // For each surface for (int i = 0; i < _faceEdgeIds.Length; i++) { faceVertexEdgeIds[i] = new Dictionary>(); // For each surface edge for (int j = 0; j < _faceEdgeIds[i].Length; j++) { edgeId = _faceEdgeIds[i][j]; //IsEdgeAClosedLoop(edgeId, out edgeNodeIds); //if (edgeNodeIds != null && edgeId == 9) // errorNodeIdsList = new List(edgeNodeIds); // Skip edges that form a single edge loop if (IsEdgeAClosedLoop(edgeId, out edgeNodeIds)) continue; // For each edge cell for (int k = 0; k < _edgeCellIdsByEdge[edgeId].Length; k++) { edgeCell = _edgeCells[_edgeCellIdsByEdge[edgeId][k]]; // For each node in edge cell for (int l = 0; l < edgeCell.Length; l++) { if (vertexNodeIds.Contains(edgeCell[l])) // is this node a vertex { if (faceVertexEdgeIds[i].TryGetValue(edgeCell[l], out vertexEdgeIds)) vertexEdgeIds.Add(edgeId); else faceVertexEdgeIds[i].Add(edgeCell[l], new List() { edgeId }); } } } } } // From the map extract all end/start vertices and their open edge loops GeomFaceType faceType; // For each face Dictionary> face_i_VertexEdgeIds; for (int i = 0; i < faceVertexEdgeIds.Length; i++) { face_i_VertexEdgeIds = faceVertexEdgeIds[i]; // if (_faceTypes != null) faceType = _faceTypes[i]; else faceType = GeomFaceType.Unknown; // RemoveEdgeLoops(face_i_VertexEdgeIds); // foreach (var entry in face_i_VertexEdgeIds) { // Cylinder and toruses have a single edge along their axis which creates 3 edge vertices if (entry.Value.Count % 2 == 1 && (faceType == GeomFaceType.Cylinder || faceType == GeomFaceType.Torus)) continue; else { foreach (var remainingEdgeId in entry.Value) errorEdgeIds.Add(remainingEdgeId); } } } // Collect error edge cell ids foreach (var errorEdgeId in errorEdgeIds) errorEdgeCellIdsList.AddRange(_edgeCellIdsByEdge[errorEdgeId]); // Save if (errorEdgeCellIdsList.Count > 0) errorEdgeCellIds = errorEdgeCellIdsList.ToArray(); else errorEdgeCellIds = null; // if (errorNodeIdsList.Count > 0) errorNodeIds = errorNodeIdsList.ToArray(); else errorNodeIds = null; } public HashSet[] GetFreeEdgeLoops(int[] surfaceIds) { int edgeId; int surfaceId; Dictionary allEdgeIdCount = new Dictionary(); for (int i = 0; i < surfaceIds.Length; i++) { surfaceId = surfaceIds[i]; for (int j = 0; j < _faceEdgeIds[surfaceId].Length; j++) { edgeId = _faceEdgeIds[surfaceId][j]; // if (allEdgeIdCount.ContainsKey(edgeId)) allEdgeIdCount[edgeId]++; else allEdgeIdCount[edgeId] = 1; } } HashSet outerEdgeIds = new HashSet(); foreach (var entry in allEdgeIdCount) { if (entry.Value == 1) outerEdgeIds.Add(entry.Key); } // Dictionary> vertexIdEdgeIds = GetVertexIdEdgeIds(); // Split edges into connected groups Node node; Graph connections = new Graph(); Dictionary> outerEdgeIdNode = new Dictionary>(); // foreach (var outerEdgeId in outerEdgeIds) { node = new Node(outerEdgeId); connections.AddNode(node); outerEdgeIdNode.Add(outerEdgeId, node); } int[] edgeIds; foreach (var entry in vertexIdEdgeIds) { edgeIds = entry.Value.ToArray(); for (int i = 0; i < edgeIds.Length - 1; i++) { for (int j = i + 1; j < edgeIds.Length; j++) { if (outerEdgeIds.Contains(edgeIds[i]) && outerEdgeIds.Contains(edgeIds[j])) connections.AddUndirectedEdge(outerEdgeIdNode[edgeIds[i]], outerEdgeIdNode[edgeIds[j]]); } } } List> loops = connections.GetConnectedSubgraphs(); // int count = 0; HashSet[] loopEdgeIds = new HashSet[loops.Count]; foreach (var loop in loops) { loopEdgeIds[count++] = new HashSet(loop.GetValues()); } // return loopEdgeIds; } public bool IsSurfaceACylinderLike(int surfaceId, out int directionEdgeId) { directionEdgeId = -1; if (_faceEdgeIds[surfaceId].Length == 3) { HashSet closedLoopEdgeIds = new HashSet(); HashSet directionEdgeIds = new HashSet(); for (int i = 0; i < _faceEdgeIds[surfaceId].Length; i++) { if (IsEdgeAClosedLoop(_faceEdgeIds[surfaceId][i], out _)) closedLoopEdgeIds.Add(_faceEdgeIds[surfaceId][i]); else directionEdgeIds.Add(_faceEdgeIds[surfaceId][i]); } if (closedLoopEdgeIds.Count == 2 && directionEdgeIds.Count == 1) { directionEdgeId = directionEdgeIds.First(); return true; } } return false; } public bool IsEdgeAClosedLoop(int edgeId, out int[] edgeNodeIds) { edgeNodeIds = null; int[] edgeCellIds = _edgeCellIdsByEdge[edgeId]; if (edgeCellIds.Length > 0) { int count = 0; int[] edgeCell; HashSet allNodeIds = new HashSet(); // for (int i = 0; i < edgeCellIds.Length; i++) { edgeCell = _edgeCells[edgeCellIds[i]]; // Add only first and second node id count += 2; allNodeIds.Add(edgeCell[0]); allNodeIds.Add(edgeCell[1]); } // edgeNodeIds = allNodeIds.ToArray(); // if (allNodeIds.Count == 2) return false; else return allNodeIds.Count() * 2 == count; } else return false; } private void RemoveEdgeLoops(Dictionary> vertexIdEdgeIds) { List edgeLoop; List verticesToRemove = new List(); // while (true) { edgeLoop = GetEdgeLoop(vertexIdEdgeIds); if (edgeLoop.Count > 0) { verticesToRemove.Clear(); // foreach (var entry in vertexIdEdgeIds) { foreach (var edgeId in edgeLoop) { entry.Value.Remove(edgeId); if (entry.Value.Count == 0) verticesToRemove.Add(entry.Key); } } // foreach (var vertexId in verticesToRemove) vertexIdEdgeIds.Remove(vertexId); } else break; } return; } private List GetEdgeLoop(Dictionary> vertexIdEdgeIds) { List loopEdgeIds = new List(); List loopVertexIds = new List(); // int[] vertexIds; Dictionary edgeIdVertexIds = new Dictionary(); foreach (var entry in vertexIdEdgeIds) { foreach (var edgeId in entry.Value) { if (edgeIdVertexIds.TryGetValue(edgeId, out vertexIds)) vertexIds[1] = entry.Key; else edgeIdVertexIds.Add(edgeId, new int[] { entry.Key, 0 }); } } // First vertex must not be an end point foreach (var entry in vertexIdEdgeIds) { if (entry.Value.Count % 2 == 0) { loopEdgeIds.Clear(); loopVertexIds.Clear(); AddNextEdgeToLoop(entry.Key, vertexIdEdgeIds, edgeIdVertexIds, loopVertexIds, loopEdgeIds); if (loopEdgeIds.Count > 0) return loopEdgeIds; } } // return loopEdgeIds; } private bool AddNextEdgeToLoop(int vertexId, Dictionary> vertexIdEdgeIds, Dictionary edgeIdVertexIds, List loopVertexIds, List loopEdgeIds) { // Check if there is a loop of vertices before there is a loop of edges loopVertexIds.Add(vertexId); // bool closed = false; int newVertexId; int[] vertexIds; List edgeIds = vertexIdEdgeIds[vertexId]; // foreach (var edgeId in edgeIds) { if (loopEdgeIds.Count > 1 && loopEdgeIds[0] == edgeId && loopVertexIds.Count > 1 && loopVertexIds[0] == vertexId) return true; else { if (loopEdgeIds.Count == 0 || !loopEdgeIds.Contains(edgeId)) { // Add loopEdgeIds.Add(edgeId); // vertexIds = edgeIdVertexIds[edgeId]; if (vertexId == vertexIds[0]) newVertexId = vertexIds[1]; else newVertexId = vertexIds[0]; // closed = AddNextEdgeToLoop(newVertexId, vertexIdEdgeIds, edgeIdVertexIds, loopVertexIds, loopEdgeIds); // Finish if (closed) return true; // Remove else loopEdgeIds.Remove(edgeId); } } } // loopVertexIds.Remove(vertexId); return false; } public bool IsNonManifold() { int[] edgeCount = new int[EdgeCount]; for (int i = 0; i < _faceEdgeIds.Length; i++) { for (int j = 0; j < _faceEdgeIds[i].Length; j++) { edgeCount[_faceEdgeIds[i][j]]++; if (edgeCount[_faceEdgeIds[i][j]] > 2) return true; } } return false; } // Flip normals public void FlipTriangleNormals() { int tmp; foreach (var cell in _cells) { if (cell.Length == 3) { tmp = cell[1]; cell[1] = cell[2]; cell[2] = tmp; } } } // Compute nodal average public AvgData GetAvgData() { int nodeId; int elementId; int[] cell; AvgData avgData = new AvgData(); AvgNodalData avgNode; AvgNodalElementData avgElement; // for (int i = 0; i < _cells.Length; i++) { cell = _cells[i]; elementId = _cellIds[i]; // for (int j = 0; j < cell.Length; j++) { nodeId = cell[j]; // if (avgData.Nodes.TryGetValue(nodeId, out avgNode)) { if (avgNode.Elements.TryGetValue(elementId, out avgElement)) { } else { avgElement = new AvgNodalElementData(); // avgNode.Elements.Add(elementId, avgElement); } } else { avgElement = new AvgNodalElementData(); // avgNode = new AvgNodalData(); avgNode.Elements.Add(elementId, avgElement); // avgData.Nodes.Add(nodeId, avgNode); } } } // return avgData; } // public double GetEqualEdgeLengthOrNegative(HashSet edgeIds) { if (edgeIds.Count < 1) return -1; else { double l; double min = double.MaxValue; double max = -double.MaxValue; // foreach (var edgeId in edgeIds) { l = _edgeLengths[edgeId]; if (l < min) min = l; if (l > max) max = l; // if (min <= 0 || max <= 0) return -1; // edge lengths must be positive if (max - min > 1E-3 * max) return -1; } return (min + max) / 2; } } public double GetMaxEdgeCurvature(int edgeId, Dictionary nodes) { double curvature = 0; int[] nodeIds = GetOrderedNodeIdsForEdgeId(edgeId); // if (nodeIds.Length <= 2) return 0; else { Vec3D[] v = new Vec3D[nodeIds.Length]; v[0] = new Vec3D(nodes[nodeIds[0]].Coor); v[1] = new Vec3D(nodes[nodeIds[1]].Coor); // double r; double tmpCurvature; for (int i = 0; i < nodeIds.Length - 2; i++) { v[i + 2] = new Vec3D(nodes[nodeIds[i + 2]].Coor); // Vec3D.GetCircleR(v[i], v[i + 1], v[i + 2], out r); if (r > 0) tmpCurvature = 1 / r; else tmpCurvature = 0; // if (tmpCurvature > curvature) curvature = tmpCurvature; } return curvature; } } public bool IsEdgeRadiusConstant(HashSet edgeIds, Dictionary nodes) { if (edgeIds.Count < 1) return false; else { double r; foreach (var edgeId in edgeIds) { r = GetConstantEdgeRadiusOrNegative(edgeId, nodes); if (r < 0) return false; } return true; } } public double GetConstantEdgeRadiusOrNegative(int edgeId, Dictionary nodes) { int[] nodeIds = GetOrderedNodeIdsForEdgeId(edgeId); // if (nodeIds.Length <= 2) return -1; else { Vec3D[] v = new Vec3D[nodeIds.Length]; v[0] = new Vec3D(nodes[nodeIds[0]].Coor); v[1] = new Vec3D(nodes[nodeIds[1]].Coor); // double r; double min = double.MaxValue; double max = -double.MaxValue; // for (int i = 0; i < nodeIds.Length - 2; i++) { v[i + 2] = new Vec3D(nodes[nodeIds[i + 2]].Coor); // Vec3D.GetCircleR(v[i], v[i + 1], v[i + 2], out r); if (r < min) min = r; if (r > max) max = r; // if (min <= 0 || max <= 0) return -1; // edge radius must be positive if (max - min > 1E-3 * max) return -1; } // return (min + max) / 2; } } public void GetArcEdgeDataForEdgeIds(HashSet edgeIds, HashSet startNodeIds, Dictionary nodes, out double r, out double arcAngleDeg, out double[] axisCenter, out double[] axisDirection) { r = -1; arcAngleDeg = -1; axisCenter = null; axisDirection = null; // HashSet arcAnglesDeg = new HashSet(); HashSet radii = new HashSet(); BoundingBox bbDirection = new BoundingBox(); BoundingBox bbCenter = new BoundingBox(); // if (edgeIds.Count < 1) return; else { int numLines = 0; foreach (var edgeId in edgeIds) { GetArcEdgeDataForEdgeId(edgeId, startNodeIds, nodes, out r, out arcAngleDeg, out axisCenter, out axisDirection); if (double.IsInfinity(r)) numLines++; else { radii.Add(r); arcAnglesDeg.Add(arcAngleDeg); bbCenter.IncludeCoor(axisCenter); bbDirection.IncludeCoor(axisDirection); } } // bool equal = true; double min = double.MaxValue; double max = -double.MaxValue; // foreach (var angle in arcAnglesDeg) { if (angle < min) min = angle; if (angle > max) max = angle; // if (min <= 0 || max <= 0) equal = false; // angles must be positive if (max - min > 1E-3 * max) equal = false; // if (!equal) break; } // if (equal && bbDirection.GetDiagonal() < 0.0017) // approximately 0.1° difference { double[] sortedR = radii.ToArray(); Array.Sort(sortedR); r = (sortedR[0] + sortedR[sortedR.Length - 1]) / 2; arcAngleDeg = (min + max) / 2; axisCenter = bbCenter.GetCenter(); axisDirection = bbDirection.GetCenter(); } else { if (numLines == edgeIds.Count) r = double.PositiveInfinity; else r = -1; // arcAngleDeg = -1; axisCenter = null; axisDirection = null; } } } public void GetArcEdgeDataForEdgeId(int edgeId, HashSet startNodeIds, Dictionary nodes, out double r, out double arcAngleDeg, out double[] axisCenter, out double[] axisDirection) { r = -1; arcAngleDeg = -1; axisCenter = null; axisDirection = null; int[] nodeIds = GetOrderedNodeIdsForEdgeId(edgeId); // if (nodeIds.Length == 2) { r = double.PositiveInfinity; } else if (nodeIds.Length < 3) { } else { if (!startNodeIds.Contains(nodeIds[0])) Array.Reverse(nodeIds); // if (!startNodeIds.Contains(nodeIds[0])) return; else { Vec3D v1 = new Vec3D(nodes[nodeIds[0]].Coor); Vec3D v2 = new Vec3D(nodes[nodeIds[(nodeIds.Length + 1) / 2]].Coor); Vec3D v3 = new Vec3D(nodes[nodeIds[nodeIds.Length - 1]].Coor); Vec3D center, direction; Vec3D.GetCircle(v1, v2, v3, out r, out arcAngleDeg, out center, out direction); axisCenter = center.Coor; axisDirection = direction.Coor; } } } // Sweep mesh // Section cut public void ApplySectionView(Dictionary elements, int[] elementIds, HashSet frontNodes, HashSet backNodes) { HashSet visibleNodes; SectionCutCells(elements, frontNodes, backNodes, out visibleNodes); SectionCutEdgeCells(visibleNodes); //_cells = new int[0][]; //_cellIds = new int[0]; //_cellIdsByFace = new int[0][]; CreateSectionPlaneCellsAndEdges(elements, elementIds, frontNodes, backNodes); } public void RemoveSectionView() { } private HashSet SectionCutCells(Dictionary elements, HashSet frontNodes, HashSet backNodes, out HashSet visibleNodes) { // Split visualization cells FeElement element; bool insert; int[] cellMap = new int[_cells.Length]; List splitCells = new List(); List splitCellIds = new List(); visibleNodes = new HashSet(); for (int i = 0; i < _cells.Length; i++) { element = elements[CellIds[i]]; insert = true; for (int j = 0; j < element.NodeIds.Length; j++) { if (frontNodes.Contains(element.NodeIds[j])) { insert = false; break; } } if (insert) { cellMap[i] = splitCells.Count; splitCells.Add(_cells[i]); splitCellIds.Add(_cellIds[i]); visibleNodes.UnionWith(_cells[i]); } else { cellMap[i] = -1; } } // Renumber cell ids by face int cellId; List cellIds = new List(); for (int i = 0; i < _cellIdsByFace.Length; i++) { cellIds.Clear(); for (int j = 0; j < _cellIdsByFace[i].Length; j++) { cellId = cellMap[_cellIdsByFace[i][j]]; if (cellId != -1) cellIds.Add(cellId); } _cellIdsByFace[i] = cellIds.ToArray(); } // Save _cells = splitCells.ToArray(); _cellIds = splitCellIds.ToArray(); return visibleNodes; } private void SectionCutEdgeCells(HashSet visibleNodes) { // Split visualization edges bool insert; int[] cellMap = new int[_edgeCells.Length]; List splitEdgeCells = new List(); for (int i = 0; i < _edgeCells.Length; i++) { insert = true; for (int j = 0; j < _edgeCells[i].Length; j++) { if (!visibleNodes.Contains(_edgeCells[i][j])) { insert = false; break; } } if (insert) { cellMap[i] = splitEdgeCells.Count; splitEdgeCells.Add(_edgeCells[i]); } else { cellMap[i] = -1; } } // Renumber edge cell ids by edge int cellId; List cellIds = new List(); for (int i = 0; i < _edgeCellIdsByEdge.Length; i++) { cellIds.Clear(); for (int j = 0; j < _edgeCellIdsByEdge[i].Length; j++) { cellId = cellMap[_edgeCellIdsByEdge[i][j]]; if (cellId != -1) cellIds.Add(cellId); } _edgeCellIdsByEdge[i] = cellIds.ToArray(); } _edgeCells = splitEdgeCells.ToArray(); } private void CreateSectionPlaneCellsAndEdges(Dictionary elements, int[] elementIds, HashSet frontNodes, HashSet backNodes) { List sectionPlaneCells; List sectionPlaneCellIds; GetSectionElementsAndIds(elements, elementIds, frontNodes, backNodes, out sectionPlaneCells, out sectionPlaneCellIds); AddSectionPlaneCellsAndIds(sectionPlaneCells, sectionPlaneCellIds); AddSectionPlaneEdgeCellsAndIds(sectionPlaneCells); } private void GetSectionElementsAndIds(Dictionary elements, int[] elementIds, HashSet frontNodes, HashSet backNodes, out List sectionPlaneCells, out List sectionPlaneCellIds) { // Check if cell neighbours exists if (_cellNeighboursOverCell == null) ExtractCellNeighboursOverCell(elements, elementIds); // Get vtk cells on the plane int countFront; int countBack; bool insert; int id; int[] cell; int[] sorted; int[] sorted2; int[][] vtkCells; int[][] vtkCells2; CellNeighbour cellNeighbour; sectionPlaneCells = new List(); sectionPlaneCellIds = new List(); CompareIntArray comparer = new CompareIntArray(); for (int i = 0; i < elementIds.Length; i++) { if (elements[elementIds[i]] is FeElement3D element) { countFront = 0; countBack = 0; for (int j = 0; j < element.NodeIds.Length; j++) { if (frontNodes.Contains(element.NodeIds[j])) countFront++; else if (backNodes.Contains(element.NodeIds[j])) countBack++; if (countFront > 0 && countBack > 0) { // The element is on the plane vtkCells = element.GetAllVtkCells(); for (int k = 0; k < vtkCells.Length; k++) { insert = true; for (int l = 0; l < vtkCells[k].Length; l++) { if (frontNodes.Contains(vtkCells[k][l])) { insert = false; break; } } if (insert) { cell = null; sorted = vtkCells[k].ToArray(); Array.Sort(sorted); cellNeighbour =_cellNeighboursOverCell[sorted]; // Add only cells with elements on the other side if (cellNeighbour.Id2 != -1) { // Looking for the other element of the vtkCell where cell orientation is positive if (cellNeighbour.Id1 == element.Id) { id = cellNeighbour.Id2; // Find the appropriate element cell element = elements[id] as FeElement3D; vtkCells2 = element.GetAllVtkCells(); for (int m = 0; m < vtkCells2.Length; m++) { sorted2 = vtkCells2[m].ToArray(); Array.Sort(sorted2); if (comparer.Equals(sorted, sorted2)) { cell = vtkCells2[m]; break; } } } else { id = cellNeighbour.Id1; cell = cellNeighbour.Cell1; } if (cell == null) throw new Exception("The vtk cell was not found."); // The vtk cell is in front of the plane sectionPlaneCells.Add(cell); sectionPlaneCellIds.Add(id); } } } break; } } } } } private void AddSectionPlaneCellsAndIds(List sectionPlaneCells, List sectionPlaneCellIds) { // Add section face to visualization List splitCells = new List(_cells); List splitCellIds = new List(_cellIds); int firstOnPlaneCellLocalId = splitCells.Count; splitCells.AddRange(sectionPlaneCells); splitCellIds.AddRange(sectionPlaneCellIds); // Cell ids by face int[][] cellIdsByFace = new int[_cellIdsByFace.Length + 1][]; for (int i = 0; i < _cellIdsByFace.Length; i++) cellIdsByFace[i] = _cellIdsByFace[i]; cellIdsByFace[_cellIdsByFace.Length] = new int[sectionPlaneCells.Count]; for (int i = 0; i < sectionPlaneCells.Count; i++) cellIdsByFace[_cellIdsByFace.Length][i] = firstOnPlaneCellLocalId + i; // Save _cells = splitCells.ToArray(); _cellIds = splitCellIds.ToArray(); _cellIdsByFace = cellIdsByFace.ToArray(); } private void AddSectionPlaneEdgeCellsAndIds(List sectionPlaneCells) { // Add section edge to visualization int[] sorted; int[][] cellEdges; CompareIntArray comparer = new CompareIntArray(); Dictionary allEdgeCells = new Dictionary(comparer); foreach (int[] cell in sectionPlaneCells) { cellEdges = FeMesh.GetVisualizationEdgeCells(cell, ElementFaceType.Face); for (int i = 0; i < cellEdges.Length; i++) { sorted = cellEdges[i].ToArray(); Array.Sort(sorted); if (!allEdgeCells.Remove(sorted)) allEdgeCells.Add(sorted, cellEdges[i]); } } List splitEdgeCells = new List(_edgeCells); int firstOnPlaneEdgeCellLocalId = splitEdgeCells.Count; splitEdgeCells.AddRange(allEdgeCells.Values); // Edge cell ids by edge int[][] edgeCellIdsByEdge = new int[_edgeCellIdsByEdge.Length + 1][]; for (int i = 0; i < _edgeCellIdsByEdge.Length; i++) edgeCellIdsByEdge[i] = _edgeCellIdsByEdge[i]; edgeCellIdsByEdge[_edgeCellIdsByEdge.Length] = new int[allEdgeCells.Count]; for (int i = 0; i < allEdgeCells.Count; i++) edgeCellIdsByEdge[_edgeCellIdsByEdge.Length][i] = firstOnPlaneEdgeCellLocalId + i; // Face edge ids List faceEdgeIds = new List(_faceEdgeIds); faceEdgeIds.Add(new int[] { edgeCellIdsByEdge.Length - 1 }); // Save _edgeCells = splitEdgeCells.ToArray(); _edgeCellIdsByEdge = edgeCellIdsByEdge.ToArray(); _faceEdgeIds = faceEdgeIds.ToArray(); } } }