/// <summary> /// Recursively creates the cell state for the given cell if visible is true and /// the given cell is visible. If the cell is not visible but the state exists /// then it is removed using removeState. /// </summary> /// <param name="cell">Cell whose cell state should be created.</param> /// <param name="visible">Boolean indicating if the cell should be visible.</param> public Object ValidateCell(Object cell, Boolean visible) { if (cell != null) { visible = visible && graph.IsCellVisible(cell); mxCellState state = GetState(cell, visible); if (state != null && !visible) { RemoveState(cell); } else { mxIGraphModel model = graph.Model; int childCount = model.GetChildCount(cell); for (int i = 0; i < childCount; i++) { ValidateCell( model.GetChildAt(cell, i), visible && !graph.IsCellCollapsed(cell)); } } } return(cell); }
/// <summary> /// Returns all opposite vertices wrt terminal for the given edges, only$ /// returning sources and/or targets as specified. The result is returned as /// an array of mxCells. /// </summary> /// <param name="model">Model that contains the graph.</param> /// <param name="edges">Array of edges to be examined.</param> /// <param name="terminal">Cell that specifies the known end of the edges.</param> /// <param name="sources">Boolean that specifies if source terminals should /// be contained in the result. Default is true.</param> /// <param name="targets">Boolean that specifies if target terminals should /// be contained in the result. Default is true.</param> /// <returns>Returns the array of opposite terminals for the given edges.</returns> public static Object[] GetOpposites(mxIGraphModel model, Object[] edges, Object terminal, bool sources, bool targets) { List <Object> terminals = new List <Object>(); if (edges != null) { for (int i = 0; i < edges.Length; i++) { Object source = model.GetTerminal(edges[i], true); Object target = model.GetTerminal(edges[i], false); // Checks if the terminal is the source of // the edge and if the target should be // stored in the result if (source == terminal && target != null && target != terminal && targets) { terminals.Add(target); } // Checks if the terminal is the taget of // the edge and if the source should be // stored in the result else if (target == terminal && source != null && source != terminal && sources) { terminals.Add(source); } } } return(terminals.ToArray()); }
/// <summary> /// Returns the nearest ancestor terminal that is visible. The edge appears /// to be connected to this terminal on the display. /// </summary> /// <param name="edge">Cell whose visible terminal should be returned.</param> /// <param name="source">Boolean that specifies if the source or target terminal /// should be returned.</param> /// <returns>Returns the visible source or target terminal.</returns> public Object GetVisibleTerminal(Object edge, bool source) { mxIGraphModel model = graph.Model; Object result = model.GetTerminal(edge, source); Object best = result; while (result != null) { if (!graph.IsCellVisible(best) || graph.IsCellCollapsed(result)) { best = result; } result = model.GetParent(result); } // Checks if the result is not a layer if (model.GetParent(best) == model.Root) { best = null; } return(best); }
/// <summary> /// Sets the source and target of the given edge in a single atomic change. /// </summary> /// <param name="model">Model that contains the graph.</param> /// <param name="edge">Cell that specifies the edge.</param> /// <param name="source">Cell that specifies the new source terminal.</param> /// <param name="target">Cell that specifies the new target terminal.</param> public static void SetTerminals(mxIGraphModel model, Object edge, Object source, Object target) { model.BeginUpdate(); try { model.SetTerminal(edge, source, true); model.SetTerminal(edge, target, false); } finally { model.EndUpdate(); } }
/// <summary> /// Invoked when a child state was moved as a result of late evaluation /// of its position. This is invoked for relative edge children whose /// position can only be determined after the points of the parent edge /// are updated in validatePoints, and validates the bounds of all /// descendants of the child using validateBounds. /// </summary> /// <param name="parent">State that represents the parent.</param> /// <param name="child">State that represents the child.</param> public void childMoved(mxCellState parent, mxCellState child) { Object cell = child.Cell; // Children of relative edge children need to validate // their bounds after their parent state was updated if (!graph.IsCellCollapsed(cell)) { mxIGraphModel model = graph.Model; int childCount = model.GetChildCount(cell); for (int i = 0; i < childCount; i++) { ValidateBounds(child, model.GetChildAt(cell, i)); } } }
/// <summary> /// Returns the number of incoming or outgoing edges, ignoring the given /// edge. /// </summary> /// <param name="model">Graph model that contains the connection data.</param> /// <param name="cell">Cell whose edges should be counted.</param> /// <param name="outgoing">Boolean that specifies if the number of outgoing or /// incoming edges should be returned.</param> /// <param name="ignoredEdge">Object that represents an edge to be ignored.</param> /// <returns>Returns the number of incoming or outgoing edges.</returns> public static int GetDirectedEdgeCount(mxIGraphModel model, Object cell, bool outgoing, Object ignoredEdge) { int count = 0; int edgeCount = model.GetEdgeCount(cell); for (int i = 0; i < edgeCount; i++) { Object edge = model.GetEdgeAt(cell, i); if (edge != ignoredEdge && model.GetTerminal(edge, outgoing) == cell) { count++; } } return(count); }
/// <summary> /// Returns the children of the given cell that are vertices and/or edges /// depending on the arguments. /// </summary> /// <param name="model">Model that contains the hierarchical information.</param> /// <param name="parent">Cell whose child vertices or edges should be returned.</param> /// <param name="vertices">Boolean indicating if child vertices should be returned.</param> /// <param name="edges">Boolean indicating if child edges should be returned.</param> /// <returns>Returns the child vertices and/or edges of the given parent.</returns> public static Object[] getChildCells(mxIGraphModel model, Object parent, bool vertices, bool edges) { int childCount = model.GetChildCount(parent); List <Object> result = new List <Object>(childCount); for (int i = 0; i < childCount; i++) { Object child = model.GetChildAt(parent, i); if ((edges && model.IsEdge(child)) || (vertices && model.IsVertex(child))) { result.Add(child); } } return(result.ToArray()); }
/// <summary> /// Validates the cell state for the given cell. /// </summary> /// <param name="cell">Cell whose cell state should be validated.</param> /// <param name="recurse">Boolean indicating if the children of the cell should be /// validated.</param> /// <returns></returns> public mxCellState ValidateCellState(Object cell, Boolean recurse) { mxCellState state = null; if (cell != null) { state = GetState(cell); if (state != null) { mxIGraphModel model = graph.Model; if (state.Invalid) { state.Invalid = false; ValidateCellState(model.GetParent(cell), false); mxCellState source = ValidateCellState(GetVisibleTerminal(cell, true), false); mxCellState target = ValidateCellState(GetVisibleTerminal(cell, false), false); UpdateCellState(state, source, target); if (model.IsEdge(cell) || model.IsVertex(cell)) { UpdateLabelBounds(state); UpdateBoundingBox(state); } } if (recurse) { int childCount = model.GetChildCount(cell); for (int i = 0; i < childCount; i++) { ValidateCellState(model.GetChildAt(cell, i)); } } } } return(state); }
/// <summary> /// Returns all edges between the given source and target mxCells. If the /// optional boolean directed argument is false, then a matching edge is /// returned regardless of its direction. /// </summary> /// <param name="model">The graph model that contains the graph.</param> /// <param name="source">mxCell that defines the source terminal of the edge to be /// returned.</param> /// <param name="target">mxCell that defines the target terminal of the edge to be /// returned.</param> /// <param name="directed">Optional boolean that specifies if the direction of the /// edge should be taken into account. Default is true.</param> /// <returns></returns> public static Object[] GetEdgesBetween(mxIGraphModel model, Object source, Object target, bool directed) { int tmp1 = model.GetEdgeCount(source); int tmp2 = model.GetEdgeCount(target); // Assumes the source has less connected edges Object terminal = source; int edgeCount = tmp1; // Uses the smaller array of connected edges // for searching the edge if (tmp2 < tmp1) { edgeCount = tmp2; terminal = target; } List <Object> result = new List <Object>(); // Checks if the edge is connected to the correct // cell and returns the first match for (int i = 0; i < edgeCount; i++) { Object edge = model.GetEdgeAt(terminal, i); Object src = model.GetTerminal(edge, true); Object trg = model.GetTerminal(edge, false); bool isSource = src == source; if (isSource && trg == target || (!directed && model.GetTerminal(edge, !isSource) == target)) { result.Add(edge); } } return(result.ToArray()); }
/// <summary> /// Returns the bounding box of the shape and the label for the given /// cell state and its children if recurse is true. /// </summary> /// <param name="state">Cell state whose bounding box should be returned.</param> /// <param name="recurse">Boolean indicating if the children should be included.</param> public mxRectangle GetBoundingBox(mxCellState state, Boolean recurse) { mxRectangle bbox = null; if (state != null) { if (state.BoundingBox != null) { bbox = (mxRectangle)state.BoundingBox.Clone(); } if (recurse) { mxIGraphModel model = graph.Model; int childCount = model.GetChildCount(state.Cell); for (int i = 0; i < childCount; i++) { mxRectangle bounds = GetBoundingBox( GetState(model.GetChildAt(state.Cell, i)), true); if (bounds != null) { if (bbox == null) { bbox = bounds; } else { bbox.Add(bounds); } } } } } return(bbox); }
/// <summary> /// Removes and returns the mxCellState for the given cell. /// </summary> /// <param name="cell">mxCell for which the mxCellState should be removed.</param> /// <returns>Returns the mxCellState that has been removed.</returns> public mxCellState RemoveState(Object cell, Boolean recurse) { if (recurse) { mxIGraphModel model = graph.Model; int childCount = model.GetChildCount(cell); for (int i = 0; i < childCount; i++) { RemoveState(model.GetChildAt(cell, i), true); } } mxCellState state = null; if (states.ContainsKey(cell)) { state = states[cell]; states.Remove(cell); } return(state); }
/// <summary> /// Returns all distinct edges connected to this cell. If at least one of /// incoming or outgoing is true, then loops are ignored, otherwise if both /// are false, then all edges connected to the given cell are returned /// including loops. /// </summary> /// <param name="model">Model that contains the connection information</param> /// <param name="cell">Cell whose connections should be returned</param> /// <param name="incoming">Specifies if incoming edges should be returned</param> /// <param name="outgoing">Specifies if outgoing edges should be returned</param> /// <param name="includeLoops">Specifies if loops should be returned</param> /// <returns>Returns the array of connected edges for the given cell</returns> public static Object[] GetEdges(mxIGraphModel model, Object cell, bool incoming, bool outgoing, bool includeLoops) { int edgeCount = model.GetEdgeCount(cell); List <Object> result = new List <Object>(edgeCount); for (int i = 0; i < edgeCount; i++) { Object edge = model.GetEdgeAt(cell, i); Object source = model.GetTerminal(edge, true); Object target = model.GetTerminal(edge, false); if ((includeLoops && source == target) || ((source != target) && ((incoming && target == cell) || (outgoing && source == cell)))) { result.Add(edge); } } return(result.ToArray()); }
/// <summary> /// Returns the bounding box for an array of cells or null, if no cells are /// specified. /// </summary> public mxRectangle GetBounds(Object[] cells, bool boundingBox) { mxRectangle result = null; if (cells != null && cells.Length > 0) { mxIGraphModel model = graph.Model; for (int i = 0; i < cells.Length; i++) { if (model.IsVertex(cells[i]) || model.IsEdge(cells[i])) { mxCellState state = GetState(cells[i]); if (state != null) { mxRectangle tmp = (boundingBox) ? state.BoundingBox : state; if (tmp != null) { if (result == null) { result = new mxRectangle(tmp); } else { result.Add(tmp); } } } } } } return(result); }
/// <summary> /// Returns the outgoing edges of the given cell without loops. /// </summary> /// <param name="model">Graphmodel that contains the edges</param> /// <param name="cell">Cell whose outgoing edges should be returned</param> /// <returns>Returns the outgoing edges for the given cell</returns> public static Object[] GetOutgoingEdges(mxIGraphModel model, Object cell) { return(GetEdges(model, cell, false, true, false)); }
/// <summary> /// Returns the number of incoming or outgoing edges, ignoring the given /// edge. /// </summary> /// <param name="model">Graph model that contains the connection data.</param> /// <param name="cell">Cell whose edges should be counted.</param> /// <param name="outgoing">Boolean that specifies if the number of outgoing or /// incoming edges should be returned.</param> /// <param name="ignoredEdge">Object that represents an edge to be ignored.</param> /// <returns>Returns the number of incoming or outgoing edges.</returns> public static int GetDirectedEdgeCount(mxIGraphModel model, Object cell, bool outgoing, Object ignoredEdge) { int count = 0; int edgeCount = model.GetEdgeCount(cell); for (int i = 0; i < edgeCount; i++) { Object edge = model.GetEdgeAt(cell, i); if (edge != ignoredEdge && model.GetTerminal(edge, outgoing) == cell) { count++; } } return count; }
/// <summary> /// Returns all edges connected to this cell without loops. /// </summary> /// <param name="model">Model that contains the connection information</param> /// <param name="cell">Cell whose connections should be returned</param> /// <returns>Returns the array of connected edges for the given cell</returns> public static Object[] GetConnections(mxIGraphModel model, Object cell) { return(GetEdges(model, cell, true, true, false)); }
/// <summary> /// Constructs a new graph for the specified model. If no model is /// specified, then a new, empty graph model is used. /// </summary> public mxGraph(mxIGraphModel model) : this(model, null) { }
/// <summary> /// Returns the child vertices of the given parent. /// </summary> /// <param name="model">Model that contains the hierarchical information.</param> /// <param name="parent">Cell whose child vertices should be returned.</param> /// <returns>Returns the child vertices of the given parent.</returns> public static Object[] getChildVertices(mxIGraphModel model, Object parent) { return getChildCells(model, parent, true, false); }
/// <summary> /// Validates the points for the state of the given cell recursively if the /// cell is not collapsed and returns the bounding box of all visited states /// as a rectangle. /// </summary> public mxRectangle ValidatePoints(mxCellState parentState, Object cell) { mxIGraphModel model = graph.Model; mxCellState state = GetState(cell); mxRectangle bbox = null; if (state != null) { mxGeometry geo = graph.GetCellGeometry(cell); if (geo != null && model.IsEdge(cell)) { // Updates the points on the source terminal if its an edge mxCellState source = GetState(GetVisibleTerminal(cell, true)); if (source != null && model.IsEdge(source.Cell) && !model.IsAncestor(source, cell)) { mxCellState tmp = GetState(model.GetParent(source.Cell)); ValidatePoints(tmp, source.Cell); } // Updates the points on the target terminal if its an edge mxCellState target = GetState(GetVisibleTerminal(cell, false)); if (target != null && model.IsEdge(target.Cell) && !model.IsAncestor(target.Cell, cell)) { mxCellState tmp = GetState(model.GetParent(target.Cell)); ValidatePoints(tmp, target.Cell); } UpdateFixedTerminalPoints(state, source, target); UpdatePoints(state, geo.Points, source, target); UpdateFloatingTerminalPoints(state, source, target); UpdateEdgeBounds(state); state.AbsoluteOffset = GetPoint(state, geo); } else if (geo != null && geo.Relative && parentState != null && model.IsEdge(parentState.Cell)) { mxPoint origin = GetPoint(parentState, geo); if (origin != null) { state.X = origin.X; state.Y = origin.Y; origin.X = (origin.X / scale) - translate.X; origin.Y = (origin.Y / scale) - translate.Y; state.Origin = origin; childMoved(parentState, state); } } if (model.IsEdge(cell) || model.IsVertex(cell)) { UpdateLabelBounds(state); bbox = new mxRectangle(UpdateBoundingBox(state)); } } if (state != null && !graph.IsCellCollapsed(cell)) { int childCount = model.GetChildCount(cell); for (int i = 0; i < childCount; i++) { Object child = model.GetChildAt(cell, i); mxRectangle bounds = ValidatePoints(state, child); if (bounds != null) { if (bbox == null) { bbox = bounds; } else { bbox.Add(bounds); } } } } return(bbox); }
/// <summary> /// Returns all edges connected to this cell including loops. /// </summary> /// <param name="model">Model that contains the connection information</param> /// <param name="cell">Cell whose connections should be returned</param> /// <returns></returns> public static Object[] GetEdges(mxIGraphModel model, Object cell) { return GetEdges(model, cell, true, true, true); }
/// <summary> /// Updates the given cell state. /// </summary> /// <param name="state"></param> public void UpdateCellState(mxCellState state, mxCellState source, mxCellState target) { state.AbsoluteOffset.X = 0; state.AbsoluteOffset.Y = 0; state.Origin.X = 0; state.Origin.Y = 0; state.Length = 0; mxIGraphModel model = graph.Model; mxCellState pState = GetState(model.GetParent(state.Cell)); if (pState != null) { state.Origin.X += pState.Origin.X; state.Origin.Y += pState.Origin.Y; } mxPoint offset = graph.GetChildOffsetForCell(state.Cell); if (offset != null) { state.Origin.X += offset.X; state.Origin.Y += offset.Y; } mxGeometry geo = graph.GetCellGeometry(state.Cell); if (geo != null) { if (!model.IsEdge(state.Cell)) { mxPoint origin = state.Origin; offset = geo.Offset; if (offset == null) { offset = EMPTY_POINT; } if (geo.Relative && pState != null) { if (model.IsEdge(pState.Cell)) { mxPoint orig = GetPoint(pState, geo); if (orig != null) { origin.X += (orig.X / scale) - pState.Origin.X - translate.X; origin.Y += (orig.Y / scale) - pState.Origin.Y - translate.Y; } } else { origin.X += geo.X * pState.Width / scale + offset.X; origin.Y += geo.Y * pState.Height / scale + offset.Y; } } else { state.AbsoluteOffset = new mxPoint(scale * offset.X, scale * offset.Y); origin.X += geo.X; origin.Y += geo.Y; } } state.X = scale * (translate.X + state.Origin.X); state.Y = scale * (translate.Y + state.Origin.Y); state.Width = scale * geo.Width; state.Height = scale * geo.Height; if (model.IsVertex(state.Cell)) { UpdateVertexState(state, geo); } if (model.IsEdge(state.Cell)) { UpdateEdgeState(state, geo, source, target); } } }
/// <summary> /// Validates the bounds of the given parent's child using the given parent /// state as the origin for the child. The validation is carried out /// recursively for all non-collapsed descendants. /// </summary> /// <param name="parentState">Cell state for the given parent.</param> /// <param name="cell">Cell for which the bounds in the state should be updated.</param> public void ValidateBounds(mxCellState parentState, Object cell) { mxIGraphModel model = graph.Model; mxCellState state = GetState(cell, true); if (state != null) { if (!graph.IsCellVisible(cell)) { RemoveState(cell); } else if (parentState != null) { state.AbsoluteOffset.X = 0; state.AbsoluteOffset.Y = 0; state.Origin = new mxPoint(parentState.Origin.X, parentState.Origin.Y); mxGeometry geo = graph.GetCellGeometry(cell); if (geo != null) { if (!model.IsEdge(cell)) { mxPoint origin = state.Origin; mxPoint offset = geo.Offset; if (offset == null) { offset = EMPTY_POINT; } if (geo.Relative) { origin.X += geo.X * parentState.Width / Scale + offset.X; origin.Y += geo.Y * parentState.Height / Scale + offset.Y; } else { state.AbsoluteOffset = new mxPoint( scale * offset.X, scale * offset.Y); origin.X += geo.X; origin.Y += geo.Y; } } // Updates the cell state's bounds state.X = scale * (translate.X + state.Origin.X); state.Y = scale * (translate.Y + state.Origin.Y); state.Width = scale * geo.Width; state.Height = scale * geo.Height; if (model.IsVertex(cell)) { UpdateVertexLabelOffset(state); } } } // Applies child offset to origin mxPoint childOffset = graph.GetChildOffsetForCell(cell); if (childOffset != null) { state.Origin.X += childOffset.X; state.Origin.Y += childOffset.Y; } } // Recursively validates the child bounds if (state != null && !graph.IsCellCollapsed(cell)) { int childCount = model.GetChildCount(cell); for (int i = 0; i < childCount; i++) { ValidateBounds(state, model.GetChildAt(cell, i)); } } }
/// <summary> /// Returns all distinct edges connected to this cell. If at least one of /// incoming or outgoing is true, then loops are ignored, otherwise if both /// are false, then all edges connected to the given cell are returned /// including loops. /// </summary> /// <param name="model">Model that contains the connection information</param> /// <param name="cell">Cell whose connections should be returned</param> /// <param name="incoming">Specifies if incoming edges should be returned</param> /// <param name="outgoing">Specifies if outgoing edges should be returned</param> /// <param name="includeLoops">Specifies if loops should be returned</param> /// <returns>Returns the array of connected edges for the given cell</returns> public static Object[] GetEdges(mxIGraphModel model, Object cell, bool incoming, bool outgoing, bool includeLoops) { int edgeCount = model.GetEdgeCount(cell); List<Object> result = new List<Object>(edgeCount); for (int i = 0; i < edgeCount; i++) { Object edge = model.GetEdgeAt(cell, i); Object source = model.GetTerminal(edge, true); Object target = model.GetTerminal(edge, false); if ((includeLoops && source == target) || ((source != target) && ((incoming && target == cell) || (outgoing && source == cell)))) { result.Add(edge); } } return result.ToArray(); }
/// <summary> /// Returns all edges between the given source and target mxCells. If the /// optional boolean directed argument is false, then a matching edge is /// returned regardless of its direction. /// </summary> /// <param name="model"></param> /// <param name="source"></param> /// <param name="target"></param> /// <returns></returns> public static Object[] GetEdgesBetween(mxIGraphModel model, Object source, Object target) { return GetEdgesBetween(model, source, target, false); }
/// <summary> /// Returns all edges between the given source and target mxCells. If the /// optional boolean directed argument is false, then a matching edge is /// returned regardless of its direction. /// </summary> /// <param name="model">The graph model that contains the graph.</param> /// <param name="source">mxCell that defines the source terminal of the edge to be /// returned.</param> /// <param name="target">mxCell that defines the target terminal of the edge to be /// returned.</param> /// <param name="directed">Optional boolean that specifies if the direction of the /// edge should be taken into account. Default is true.</param> /// <returns></returns> public static Object[] GetEdgesBetween(mxIGraphModel model, Object source, Object target, bool directed) { int tmp1 = model.GetEdgeCount(source); int tmp2 = model.GetEdgeCount(target); // Assumes the source has less connected edges Object terminal = source; int edgeCount = tmp1; // Uses the smaller array of connected edges // for searching the edge if (tmp2 < tmp1) { edgeCount = tmp2; terminal = target; } List<Object> result = new List<Object>(); // Checks if the edge is connected to the correct // cell and returns the first match for (int i = 0; i < edgeCount; i++) { Object edge = model.GetEdgeAt(terminal, i); Object src = model.GetTerminal(edge, true); Object trg = model.GetTerminal(edge, false); bool isSource = src == source; if (isSource && trg == target || (!directed && model.GetTerminal(edge, !isSource) == target)) { result.Add(edge); } } return result.ToArray(); }
/// <summary> /// Returns all opposite vertices wrt terminal for the given edges, only$ /// returning sources and/or targets as specified. The result is returned as /// an array of mxCells. /// </summary> /// <param name="model">Model that contains the graph.</param> /// <param name="edges">Array of edges to be examined.</param> /// <param name="terminal">Cell that specifies the known end of the edges.</param> /// <param name="sources">Boolean that specifies if source terminals should /// be contained in the result. Default is true.</param> /// <param name="targets">Boolean that specifies if target terminals should /// be contained in the result. Default is true.</param> /// <returns>Returns the array of opposite terminals for the given edges.</returns> public static Object[] GetOpposites(mxIGraphModel model, Object[] edges, Object terminal, bool sources, bool targets) { List<Object> terminals = new List<Object>(); if (edges != null) { for (int i = 0; i < edges.Length; i++) { Object source = model.GetTerminal(edges[i], true); Object target = model.GetTerminal(edges[i], false); // Checks if the terminal is the source of // the edge and if the target should be // stored in the result if (source == terminal && target != null && target != terminal && targets) { terminals.Add(target); } // Checks if the terminal is the taget of // the edge and if the source should be // stored in the result else if (target == terminal && source != null && source != terminal && sources) { terminals.Add(source); } } } return terminals.ToArray(); }
/// <summary> /// Returns the number of incoming or outgoing edges. /// </summary> /// <param name="model">Graph model that contains the connection data.</param> /// <param name="cell">Cell whose edges should be counted.</param> /// <param name="outgoing">Boolean that specifies if the number of outgoing or /// incoming edges should be returned.</param> /// <returns>Returns the number of incoming or outgoing edges.</returns> public static int GetDirectedEdgeCount(mxIGraphModel model, Object cell, bool outgoing) { return GetDirectedEdgeCount(model, cell, outgoing, null); }
/// <summary> /// Executes the fast organic layout. /// </summary> /// <param name="parent"></param> public void execute(Object parent) { mxIGraphModel model = graph.Model; // Finds the relevant vertices for the layout int childCount = model.GetChildCount(parent); List <Object> tmp = new List <Object>(childCount); for (int i = 0; i < childCount; i++) { Object child = model.GetChildAt(parent, i); if (!IsCellIgnored(child)) { tmp.Add(child); } } vertexArray = tmp.ToArray(); int n = vertexArray.Length; dispX = new double[n]; dispY = new double[n]; cellLocation = new double[n][]; isMoveable = new bool[n]; neighbours = new int[n][]; radius = new double[n]; radiusSquared = new double[n]; minDistanceLimitSquared = minDistanceLimit * minDistanceLimit; if (forceConstant < 0.001) { forceConstant = 0.001; } forceConstantSquared = forceConstant * forceConstant; // Create a map of vertices first. This is required for the array of // arrays called neighbours which holds, for each vertex, a list of // ints which represents the neighbours cells to that vertex as // the indices into vertexArray for (int i = 0; i < vertexArray.Length; i++) { Object vertex = vertexArray[i]; cellLocation[i] = new double[2]; // Set up the mapping from array indices to cells indices[vertex] = i; mxGeometry bounds = model.GetGeometry(vertex); // Set the X,Y value of the internal version of the cell to // the center point of the vertex for better positioning double width = bounds.Width; double height = bounds.Height; // Randomize (0, 0) locations double x = bounds.X; double y = bounds.Y; cellLocation[i][0] = x + width / 2.0; cellLocation[i][1] = y + height / 2.0; radius[i] = Math.Min(width, height); radiusSquared[i] = radius[i] * radius[i]; } for (int i = 0; i < n; i++) { dispX[i] = 0; dispY[i] = 0; isMoveable[i] = graph.IsCellMovable(vertexArray[i]); // Get lists of neighbours to all vertices, translate the cells // obtained in indices into vertexArray and store as an array // against the orginial cell index Object[] edges = mxGraphModel.GetEdges(model, vertexArray[i]); Object[] cells = mxGraphModel.GetOpposites(model, edges, vertexArray[i], true, true); neighbours[i] = new int[cells.Length]; for (int j = 0; j < cells.Length; j++) { int?index = indices[cells[j]]; // Check the connected cell in part of the vertex list to be // acted on by this layout if (index != null) { neighbours[i][j] = (int)index; } // Else if index of the other cell doesn't correspond to // any cell listed to be acted upon in this layout. Set // the index to the value of this vertex (a dummy self-loop) // so the attraction force of the edge is not calculated else { neighbours[i][j] = i; } } } temperature = initialTemp; // If max number of iterations has not been set, guess it if (maxIterations == 0) { maxIterations = (int)(20 * Math.Sqrt(n)); } // Main iteration loop for (iteration = 0; iteration < maxIterations; iteration++) { if (!allowedToRun) { return; } // Calculate repulsive forces on all vertices calcRepulsion(); // Calculate attractive forces through edges calcAttraction(); calcPositions(); reduceTemperature(); } // Moved cell location back to top-left from center locations used in // algorithm model.BeginUpdate(); try { double?minx = null; double?miny = null; for (int i = 0; i < vertexArray.Length; i++) { Object vertex = vertexArray[i]; mxGeometry geo = model.GetGeometry(vertex); if (geo != null) { cellLocation[i][0] -= geo.Width / 2.0; cellLocation[i][1] -= geo.Height / 2.0; geo = geo.Clone(); geo.X = graph.Snap(cellLocation[i][0]); geo.Y = graph.Snap(cellLocation[i][1]); model.SetGeometry(vertex, geo); if (minx == null) { minx = geo.X; } else { minx = Math.Min((double)minx, geo.X); } if (miny == null) { miny = geo.Y; } else { miny = Math.Min((double)miny, geo.Y); } } } // Modifies the cloned geometries in-place. Not needed // to clone the geometries again as we're in the same // undoable change. if (minx != null || miny != null) { for (int i = 0; i < vertexArray.Length; i++) { Object vertex = vertexArray[i]; mxGeometry geo = model.GetGeometry(vertex); if (geo != null) { if (minx != null) { geo.X -= ((double)minx) - 1; } if (miny != null) { geo.Y -= ((double)miny) - 1; } } } } } finally { model.EndUpdate(); } }
/// <summary> /// Returns all edges between the given source and target mxCells. If the /// optional boolean directed argument is false, then a matching edge is /// returned regardless of its direction. /// </summary> /// <param name="model"></param> /// <param name="source"></param> /// <param name="target"></param> /// <returns></returns> public static Object[] GetEdgesBetween(mxIGraphModel model, Object source, Object target) { return(GetEdgesBetween(model, source, target, false)); }
/// <summary> /// Assigns the value for the given key in the styles of the given cells, or /// removes the key from the styles if the value is null. /// </summary> /// <param name="model">Model to execute the transaction in.</param> /// <param name="cells">Array of cells to be updated.</param> /// <param name="key">Key of the style to be changed.</param> /// <param name="value">New value for the given key.</param> public static void SetCellStyles(mxIGraphModel model, Object[] cells, String key, String value) { if (cells != null && cells.Length > 0) { model.BeginUpdate(); try { for (int i = 0; i < cells.Length; i++) { if (cells[i] != null) { String style = SetStyle( model.GetStyle(cells[i]), key, value); model.SetStyle(cells[i], style); } } } finally { model.EndUpdate(); } } }
/// <summary> /// Returns the children of the given cell that are vertices and/or edges /// depending on the arguments. /// </summary> /// <param name="model">Model that contains the hierarchical information.</param> /// <param name="parent">Cell whose child vertices or edges should be returned.</param> /// <param name="vertices">Boolean indicating if child vertices should be returned.</param> /// <param name="edges">Boolean indicating if child edges should be returned.</param> /// <returns>Returns the child vertices and/or edges of the given parent.</returns> public static Object[] getChildCells(mxIGraphModel model, Object parent, bool vertices, bool edges) { int childCount = model.GetChildCount(parent); List<Object> result = new List<Object>(childCount); for (int i = 0; i < childCount; i++) { Object child = model.GetChildAt(parent, i); if ((edges && model.IsEdge(child)) || (vertices && model.IsVertex(child))) { result.Add(child); } } return result.ToArray(); }
/// <summary> /// Constructs a new graph for the specified model. If no model is /// specified, then a new, empty graph model is used. /// </summary> public mxGraph(mxIGraphModel model, mxStylesheet stylesheet) { this.Model = (model != null) ? model : new mxGraphModel(); this.Stylesheet = (stylesheet != null) ? stylesheet : CreateStylesheet(); this.View = CreateGraphView(); }
/// <summary> /// Returns the child edges of the given parent. /// </summary> /// <param name="model">Model that contains the hierarchical information.</param> /// <param name="parent">Cell whose child edges should be returned.</param> /// <returns>Returns the child edges of the given parent.</returns> public static Object[] getChildEdges(mxIGraphModel model, Object parent) { return(getChildCells(model, parent, false, true)); }
/// <summary> /// Returns the outgoing edges of the given cell without loops. /// </summary> /// <param name="model">Graphmodel that contains the edges</param> /// <param name="cell">Cell whose outgoing edges should be returned</param> /// <returns>Returns the outgoing edges for the given cell</returns> public static Object[] GetOutgoingEdges(mxIGraphModel model, Object cell) { return GetEdges(model, cell, false, true, false); }
/// <summary> /// Returns the number of incoming or outgoing edges. /// </summary> /// <param name="model">Graph model that contains the connection data.</param> /// <param name="cell">Cell whose edges should be counted.</param> /// <param name="outgoing">Boolean that specifies if the number of outgoing or /// incoming edges should be returned.</param> /// <returns>Returns the number of incoming or outgoing edges.</returns> public static int GetDirectedEdgeCount(mxIGraphModel model, Object cell, bool outgoing) { return(GetDirectedEdgeCount(model, cell, outgoing, null)); }
public void execute(Object parent) { mxIGraphModel model = graph.Model; //.GetModel(); // Moves the vertices to build a circle. Makes sure the // radius is large enough for the vertices to not // overlap model.BeginUpdate(); try { // Gets all vertices inside the parent and finds // the maximum dimension of the largest vertex double max = 0; Double top = 0; Double left = 0; List <Object> vertices = new List <Object>(); int childCount = model.GetChildCount(parent); for (int i = 0; i < childCount; i++) { Object cell = model.GetChildAt(parent, i); if (!isVertexIgnored(cell)) { vertices.add(cell); mxRectangle bounds = getVertexBounds(cell); if (top == null) { top = bounds.getY(); } else { top = Math.Min(top, bounds.getY()); } if (left == null) { left = bounds.getX(); } else { left = Math.Min(left, bounds.getX()); } max = Math.Max(max, Math.Max(bounds.getWidth(), bounds .getHeight())); } else if (!isEdgeIgnored(cell)) { if (isResetEdges()) { graph.resetEdge(cell); } if (isDisableEdgeStyle()) { setEdgeStyleEnabled(cell, false); } } } int vertexCount = vertices.size(); double r = Math.Max(vertexCount * max / Math.PI, radius); // Moves the circle to the specified origin if (moveCircle) { left = x0; top = y0; } circle(vertices.ToArray(), r, left, top); } finally { model.EndUpdate(); } }