using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using CaeGlobals; namespace CaeMesh { public class ContactGraph { // Variables private Graph _graph; // Constructors public ContactGraph() { _graph = new Graph(); } // Methods public void AddMasterSlaveItems(IEnumerable masterSlaveItems, FeMesh mesh) { HashSet mergedItemIds; List> itemIdsList = new List>(); List> itemIdsListToRemove = new List>(); // Collect item ids foreach (var masterSlaveItem in masterSlaveItems) { // Master side mergedItemIds = new HashSet(masterSlaveItem.MasterGeometryIds); // Find intersecting foreach (var node in itemIdsList) { if (node.Intersect(mergedItemIds).Count() > 0) { mergedItemIds.UnionWith(node); itemIdsListToRemove.Add(node); } } // Remove merged foreach (var node in itemIdsListToRemove) itemIdsList.Remove(node); // Add new/merged item itemIdsList.Add(mergedItemIds); // Slave side itemIdsListToRemove.Clear(); mergedItemIds = new HashSet(masterSlaveItem.SlaveGeometryIds); // Find intersecting foreach (var node in itemIdsList) { if (node.Intersect(mergedItemIds).Count() > 0) { mergedItemIds.UnionWith(node); itemIdsListToRemove.Add(node); } } // Remove merged foreach (var node in itemIdsListToRemove) itemIdsList.Remove(node); // Add new/merged item itemIdsList.Add(mergedItemIds); } // Add items to graph int id; string name; List allNames = new List(); double size; NodeData nodeData; foreach (var itemIds in itemIdsList) { id = _graph.Nodes.Count() + 1; name = GetNameFromItemIds(itemIds, allNames, mesh); size = GetSizeFromItemIds(itemIds, mesh); nodeData = new NodeData(id, name, itemIds, size); // _graph.AddNode(new Node(nodeData)); allNames.Add(name); } // Add edges to graph Node masterNode; Node slaveNode; foreach (var masterSlaveItem in masterSlaveItems) { masterNode = null; slaveNode = null; foreach (Node node in _graph.Nodes) { // Find the nodes if (masterNode == null && node.Value.ItemIds.Intersect(masterSlaveItem.MasterGeometryIds).Count() > 0) masterNode = node; // Use if - master and slave ids can belong to the same graph node if (slaveNode == null && node.Value.ItemIds.Intersect(masterSlaveItem.SlaveGeometryIds).Count() > 0) slaveNode = node; if (masterNode != null && slaveNode != null) break; } // _graph.AddUndirectedEdge(masterNode, slaveNode); } } // public List GetMasterSlaveItems(bool checkUnresolved) { List> connectedSubgraphList = _graph.GetConnectedSubgraphs(); List masterSlaveItems = new List(); // foreach (var connectedGraph in connectedSubgraphList) { if (connectedGraph.IsGraphWithoutCycles()) { masterSlaveItems.AddRange(GetMasterSlaveItemsFromGraphWithoutCycles(connectedGraph)); } else if (connectedGraph.IsGraphWithOneCycle()) { masterSlaveItems.AddRange(GetMasterSlaveItemsFromGraphWithOneCycle(connectedGraph)); } else { masterSlaveItems.AddRange(GetMasterSlaveItemsFromGraphWithMultipleCycles(connectedGraph, checkUnresolved)); } } return masterSlaveItems; } // public static string GetNameFromItemIds(HashSet itemIds, List allNames, FeMesh mesh) { string name; HashSet partIds = new HashSet(); foreach (var itemId in itemIds) { partIds.Add(FeMesh.GetPartIdFromGeometryId(itemId)); } if (partIds.Count == 1) name = mesh.GetPartNamesFromPartIds(partIds.ToArray())[0]; else name = allNames.GetNextNumberedKey("Merged"); // return name; } public static double GetSizeFromItemIds(HashSet itemIds, FeMesh mesh) { double size = 0; foreach (var itemId in itemIds) size += GetSize(itemId, mesh); return size; } private static double GetSize(int geometryId, FeMesh mesh) { int[] itemTypePartIds = FeMesh.GetItemTypePartIdsFromGeometryId(geometryId); GeometryType geomType = (GeometryType)itemTypePartIds[1]; VisualizationData vis = mesh.GetPartFromId(itemTypePartIds[2]).Visualization; // Face if (geomType.IsSurface()) { int faceId = itemTypePartIds[0]; return vis.FaceAreas[faceId] * 1E6; } // Edge else if (geomType.IsEdge()) { int edgeId = itemTypePartIds[0]; return vis.EdgeLengths[edgeId]; } // Vertex else return 0; } // private static List GetMasterSlaveItemsFromGraphWithoutCycles(Graph graph) { Graph reducedGraph; return GetMasterSlaveItemsFromGraphWithoutCycles(graph, out reducedGraph); } private static List GetMasterSlaveItemsFromGraphWithoutCycles(Graph graph, out Graph reducedGraph) { Node neighbour; List> singleConnectedNodes = new List>(); List masterSlaveItems = new List(); reducedGraph = new Graph(graph); // do { singleConnectedNodes.Clear(); // foreach (Node node in reducedGraph.Nodes) { if (node.Neighbours.Count() == 1) { neighbour = node.Neighbours[0]; masterSlaveItems.Add(new MasterSlaveItem(node.Value.Name, neighbour.Value.Name, node.Value.ItemIds, neighbour.Value.ItemIds)); // singleConnectedNodes.Add(node); // break; // this makes master slave parts more organized for the user } } // foreach (var node in singleConnectedNodes) { reducedGraph.Remove(node); } } while (singleConnectedNodes.Count > 0); // return masterSlaveItems; } private static List GetMasterSlaveItemsFromGraphWithOneCycle(Graph graph) { Graph reducedGraph; List masterSlaveItems = GetMasterSlaveItemsFromGraphWithoutCycles(graph, out reducedGraph); // Node currentNode; Node parentNode; Queue> queue = new Queue>(); Queue> parentQueue = new Queue>(); HashSet> visitedNodes = new HashSet>(); // queue.Enqueue(reducedGraph.Nodes.First()); parentQueue.Enqueue(reducedGraph.Nodes.First()); // while (queue.Count() > 0) { currentNode = queue.Dequeue(); parentNode = parentQueue.Dequeue(); // Check for cycles if (visitedNodes.Add(currentNode)) { // Add all neighbours to the queue foreach (var neighbour in currentNode.Neighbours) { if (neighbour != parentNode) { masterSlaveItems.Add(new MasterSlaveItem(currentNode.Value.Name, neighbour.Value.Name, currentNode.Value.ItemIds, neighbour.Value.ItemIds)); // queue.Enqueue(neighbour); parentQueue.Enqueue(currentNode); break; // add only the first neighbour and continue } } } } // return masterSlaveItems; } private static List GetMasterSlaveItemsFromGraphWithMultipleCycles(Graph graph, bool checkUnresolved) { string prefix = ""; HashSet ids = new HashSet(); List masterSlaveItems = new List(); // Create an unresolved master slave item that is shown to the user as a single surface if (checkUnresolved) { MasterSlaveItem masterSlaveItem; foreach (var node in graph.Nodes) ids.UnionWith(node.Value.ItemIds); masterSlaveItem = new MasterSlaveItem("Unresolved", "", ids, null); masterSlaveItem.Unresolved = true; masterSlaveItems.Add(masterSlaveItem); // prefix = "Unresolved_"; } // Create master slave items Graph reducedGraph; masterSlaveItems.AddRange(GetMasterSlaveItemsFromGraphWithoutCycles(graph, out reducedGraph)); // foreach (var node in reducedGraph.Nodes) { foreach (var neighbour in node.Neighbours) { masterSlaveItems.Add(new MasterSlaveItem(prefix + node.Value.Name, neighbour.Value.Name, node.Value.ItemIds, neighbour.Value.ItemIds)); reducedGraph.RemoveDirectedEdge(neighbour, node); } node.Neighbours.Clear(); } // return masterSlaveItems; } } }