/// <summary> /// allocates larger grid arrays if necessary /// </summary> internal void allocate(int cols, int rows, RectangleF bounds, Arrow arrow) { int curCols = 0; int curRows = 0; if (costGrid != null) { curCols = costGrid.GetLength(0); curRows = costGrid.GetLength(1); } // allocate new arrays if needed if (costGrid == null || curCols < cols || curRows < rows) { int newCols = Math.Max(curCols, cols); int newRows = Math.Max(curRows, rows); costGrid = new byte[newCols, newRows]; closedGrid = new PathNode[newCols, newRows]; openGrid = new PathNode[newCols, newRows]; } //or reuse the existing ones else { Array.Clear(costGrid, 0, costGrid.Length); Array.Clear(closedGrid, 0, closedGrid.Length); Array.Clear(openGrid, 0, openGrid.Length); } // mark border lines as obstacles for (int c = 0; c < cols; c++) { costGrid[c, 0] = 255; costGrid[c, rows - 1] = 255; } for (int r = 1; r < rows - 1; r++) { costGrid[0, r] = 255; costGrid[cols - 1, r] = 255; } // mark node locations markObstacles(bounds, arrow, cols, rows); }
internal virtual PointF getAnchor(PointF pt, Arrow arrow, bool incm, ref int idx) { return getNode().getAnchor(pt, arrow, incm, ref idx); }
// invoked when an arrow is drawn from / to a table. // finds the anchor point nearest to arrow's end point. // tables need special handling to combine row's and table's anchor patterns internal override PointF getNearestAnchor(PointF pt, Arrow arrow, bool incoming, ref int anchorIdx) { PointF nearestPt = pt; anchorIdx = -1; // check if at that position, an arrow would link to a row lastAnchorForTable = false; int row = rowFromPt(pt); if(row == -1) { // it seems not, so use Table's anchor pattern, not Row's one PointF result = base.getNearestAnchor(pt, arrow, incoming, ref anchorIdx); lastAnchorForTable = true; lastFoundAnchor = result; return result; } // link to a row, get the relevant anchor pattern for this row AnchorPattern rowap = getRowAnchorPattern(row); bool foundAp = false; // get row extents RectangleF rowRect = getRowRect(row); float nearestDist = 100 * Math.Max(rowRect.Width, rowRect.Height); if (rowap != null) { // look for appropriate anchor points, in or out for (int i = 0; i < rowap.Points.Count; i++) { AnchorPoint ap = rowap.Points[i]; if (incoming && !ap.AllowIncoming) continue; if (!incoming && !ap.AllowOutgoing) continue; if (!flowChart.validateAnchor(arrow, !incoming, this, i)) continue; foundAp = true; // how close an anchor point is to the point passed as parameter RectangleF testRect = ap.Column == -1 ? rowRect : getSpannedCellRect(row, ap.Column); PointF pos = ap.getPos(testRect); float dx = pos.X - pt.X; float dy = pos.Y - pt.Y; float ptDist = (float)Math.Sqrt(dx*dx + dy*dy); if (ptDist < nearestDist) { // dis closer than the others nearestDist = ptDist; nearestPt = pos; anchorIdx = i; } } if (foundAp) return nearestPt; } // haven't found suitable anchor point for this row if (anchorPattern != null && linkStyle != TableLinkStyle.Rows) { PointF result = base.getNearestAnchor(pt, arrow, incoming, ref anchorIdx); lastAnchorForTable = true; lastFoundAnchor = result; return result; } if (!foundAp) { nearestDist = float.MaxValue; for (int r = 0; r < RowCount; ++r) { if (r == row) continue; rowap = getRowAnchorPattern(r); if (rowap == null) continue; // get row extents rowRect = getRowRect(r); // look for anchor points for (int i = 0; i < rowap.Points.Count; i++) { AnchorPoint ap = rowap.Points[i]; if (incoming && !ap.AllowIncoming) continue; if (!incoming && !ap.AllowOutgoing) continue; if (!flowChart.validateAnchor(arrow, !incoming, this, i)) continue; RectangleF testRect = ap.Column == -1 ? rowRect : getSpannedCellRect(r, ap.Column); PointF pos = ap.getPos(testRect); float dx = pos.X - pt.X; float dy = pos.Y - pt.Y; float ptDist = (float)Math.Sqrt(dx*dx + dy*dy); if (ptDist < nearestDist) { nearestDist = ptDist; nearestPt = pos; anchorIdx = i; } } } } return nearestPt; }
internal void addOutgoingArrow(int row, Arrow arrow) { if (rowsList == null || row >= rowsCount) return; ArrowCollection arrows = ((Row)rowsList[row]).OutgoingArrows; if (!arrows.Contains(arrow)) arrows.Add(arrow); }
internal override Link createLink(Arrow arrow, PointF pt, bool incoming) { return new TableLink(this, arrow, incoming, rowFromPt(pt)); }
public void Remove(Arrow a) { List.Remove(a); }
public void Add(Arrow a) { List.Add(a); }
internal void fireArrowRoutedEvent(Arrow arrow) { if (ArrowRouted != null) ArrowRouted(this, new ArrowEventArgs(arrow)); }
private ItemsAndGroups copySelection( FlowChart doc, bool unconnectedArrows, bool copyGroups) { if (doc.Selection.Objects.Count == 0) return null; // determine which items and groups to copy ChartObjectCollection items = new ChartObjectCollection(); GroupCollection groups = new GroupCollection(); Hashtable indexMap = new Hashtable(); for (int i = 0; i < doc.Selection.Objects.Count; ++i) { ChartObject item = doc.Selection.Objects[i]; // do not copy unconncted arrows if specified if (!unconnectedArrows && item is Arrow) { Arrow arrow = item as Arrow; if (!arrow.IsConnected) continue; } indexMap[item] = items.Count; items.Add(item); if (copyGroups && item.SubordinateGroup != null) groups.Add(item.SubordinateGroup); } // add subordinated group items foreach (Group group in groups) { foreach (ChartObject item in group.AttachedObjects) { if (!items.Contains(item)) { indexMap[item] = items.Count; items.Add(item); } } } // copy nodes for (int i = 0; i < items.Count; ++i) { ChartObject item = items[i]; if (item is Box) items[i] = new Box((Box)item); if (item is ControlHost) items[i] = new ControlHost((ControlHost)item); if (item is Table) items[i] = new Table((Table)item); } // copy arrows, linking them to node clones for (int i = 0; i < items.Count; ++i) { if (items[i] is Arrow) { Arrow arrow = items[i] as Arrow; int srcIndex = indexMap.Contains(arrow.Origin) ? (int)indexMap[arrow.Origin] : -1; int dstIndex = indexMap.Contains(arrow.Destination) ? (int)indexMap[arrow.Destination] : -1; items[i] = new Arrow(arrow, srcIndex == -1 ? Dummy : items[srcIndex] as Node, dstIndex == -1 ? Dummy : items[dstIndex] as Node); } } // copy groups for (int i = 0; i < groups.Count; ++i) { Group group = new Group(groups[i]); groups[i] = group; group.setMainObject(items[(int)indexMap[group.MainObject]]); foreach (Attachment atc in group.Attachments) { atc.node = items[(int)indexMap[atc.node]] as Node; atc.node.putInGroup(group); } group.updateObjCol(); } return new ItemsAndGroups(items, groups); }
internal void drawArrow(Graphics g, Arrow arrow, bool shadow, PointCollection points) { if (DrawArrow != null) DrawArrow(this, new ArrowDrawArgs(g, arrow, shadow, points)); }
/// <summary> /// Determines whether a link must be rerouted. /// </summary> internal bool rerouteArrow(Arrow arrow) { if ((routingOptions.TriggerRerouting & RerouteArrows.WhenModified) != 0) return true; if ((routingOptions.TriggerRerouting & RerouteArrows.WhenIntersectNode) != 0) { RectangleF arrowRect = arrow.BoundingRect; for (int j = 0; j < zOrder.Count; ++j) { if (zOrder[j] is Node) { Node node = zOrder[j] as Node; if (node == arrow.Origin || node == arrow.Destination) continue; RectangleF rect = node.getRotatedBounds(); if (arrowRect.IntersectsWith(rect)) { if (arrow.Intersects(node)) return true; } // if (arrowRect.IntersectsWith(rect)) } // if (zOrder[j] is Node) } // for (int j = 0; j < zOrder.Count; ++j) } return false; }
/// <summary> /// Creates a new Arrow instance and adds it to the flowchart. /// </summary> /// <param name="src">Specifies the origin point.</param> /// <param name="dest">Specifies the destination point.</param> /// <returns>A reference to the new arrow.</returns> public Arrow CreateArrow(PointF src, PointF dest) { // create the arrow instance and add it to the chart Arrow newArrow = new Arrow(this, src, dest); Add(newArrow, SelectAfterCreate); return newArrow; }
/// <summary> /// Creates a new Arrow instance and adds it to the flowchart. /// </summary> /// <param name="src">Specifies the origin point.</param> /// <param name="dest">Specifies the destination node.</param> /// <returns>A reference to the new arrow.</returns> public Arrow CreateArrow(PointF src, Node dest) { if (dest == null) return null; // create the arrow instance and add it to the chart Arrow newArrow = new Arrow(this, src, dest); Add(newArrow, SelectAfterCreate); return newArrow; }
/// <summary> /// Creates a new Arrow instance and adds it to the flowchart. /// </summary> /// <param name="srcTable">Specifies the origin table.</param> /// <param name="srcRow">Specifies the origin row.</param> /// <param name="dstNode">Specifies the destination node.</param> /// <returns>A reference to the new arrow.</returns> public Arrow CreateArrow(Table srcTable, int srcRow, Node dstNode) { if (srcTable == null || dstNode == null) return null; if (!srcTable.canHaveArrows(true) && srcRow != -1) return null; if (srcRow < -1 || srcRow >= srcTable.RowCount) return null; // create the arrow object and store it in the item array Arrow newArrow = new Arrow(this); newArrow.setOrgAndDest( srcTable.createLink(newArrow, false, srcRow), dstNode.createLink(newArrow, dstNode.getCenter(), true)); Add(newArrow, SelectAfterCreate); return newArrow; }
internal bool requestAttach(Arrow arrow, bool changingOrg, Node node) { if (ArrowAttaching != null) { PointF endPt = changingOrg ? arrow.Points[0] : arrow.Points[arrow.Points.Count - 1]; int id = 0; int row = -1; node.getAnchor(endPt, arrow, !changingOrg, ref id); // get the row if attaching to table Table table = node as Table; if (table != null) row = table.rowFromPt(endPt); AttachConfirmArgs args = new AttachConfirmArgs(arrow, node, changingOrg, id, row); ArrowAttaching(this, args); return args.Confirm; } return true; }
internal virtual void removeOutgoingArrow(Arrow arrow) { outgoingArrows.Remove(arrow); }
internal bool validateAnchor(Arrow arrow, bool outgoing, Node node, int pointIndex) { if (ValidateAnchorPoint != null) { AttachConfirmArgs args = new AttachConfirmArgs(arrow, node, outgoing, pointIndex, 0); ValidateAnchorPoint(this, args); return args.Confirm; } return true; }
/// <summary> /// mark obstacles and costs in the routing grid. /// </summary> private void markObstacles(RectangleF bounds, Arrow arrow, int cols, int rows) { RoutingOptions rop = flowChart.RoutingOptions; float gridSize = rop.GridSize; byte ccost = rop.CrossingCost; foreach (ChartObject obj in flowChart.Objects) { // if there is a crossing cost assigned, mark arrows in the route grid if (obj is Arrow && ccost > 0) { if (obj == arrow) continue; Arrow link = obj as Arrow; // at this time we handle only asPerpendicular links if (link.Style == ArrowStyle.Cascading) { PointF cp1 = link.ControlPoints[0]; Point gp1 = new Point( (int)((cp1.X - bounds.Left) / gridSize), (int)((cp1.Y - bounds.Top) / gridSize)); // iterate over all segments for (int i = 0; i < link.ControlPoints.Count - 1; ++i) { PointF cp2 = link.ControlPoints[i + 1]; Point gp2 = new Point( (int)((cp2.X - bounds.Left) / gridSize), (int)((cp2.Y - bounds.Top) / gridSize)); if (!gp1.Equals(gp2)) { if (gp1.X == gp2.X) { // vertical segment if (gp1.X >= 0 && gp1.X < cols) { int miny = Math.Min(gp1.Y, gp2.Y); miny = Math.Max(0, miny); int maxy = Math.Max(gp1.Y, gp2.Y); maxy = Math.Min(rows - 1, maxy); for (int y = miny; y <= maxy; ++y) if (costGrid[gp1.X, y] < ccost) costGrid[gp1.X, y] = ccost; } } else { // horizontal segment if (gp1.Y >= 0 && gp1.Y < rows) { int minx = Math.Min(gp1.X, gp2.X); minx = Math.Max(0, minx); int maxx = Math.Max(gp1.X, gp2.X); maxx = Math.Min(cols - 1, maxx); for (int x = minx; x <= maxx; ++x) if (costGrid[x, gp1.Y] < ccost) costGrid[x, gp1.Y] = ccost; } } } gp1 = gp2; } } continue; } if (!(obj is Node)) continue; Node node = obj as Node; if (!node.Obstacle) continue; if (node.MasterGroup != null && node.MasterGroup.MainObject == arrow) continue; RectangleF nodeRect = node.getRotatedBounds(); if (bounds.IntersectsWith(nodeRect)) { RectangleF intrRect = bounds; intrRect.Intersect(nodeRect); Point ptStart = new Point( (int)((intrRect.Left - bounds.Left) / gridSize), (int)((intrRect.Top - bounds.Top) / gridSize)); Point ptEnd = new Point( (int)((intrRect.Right - bounds.Left) / gridSize), (int)((intrRect.Bottom - bounds.Top) / gridSize)); if (ptStart.X < 0) ptStart.X = 0; if (ptStart.Y < 0) ptStart.Y = 0; if (ptEnd.X >= cols) ptEnd.X = cols - 1; if (ptEnd.Y >= rows) ptEnd.Y = rows - 1; // mark node interior as obstacle for (int c = ptStart.X; c <= ptEnd.X; ++c) for (int r = ptStart.Y; r <= ptEnd.Y; ++r) costGrid[c, r] = 255; // mark surrounding area with any cost assigned // going lineary down to the outside directions if (rop.NodeVicinityCost == 0) continue; for (int i = 1; i <= rop.NodeVicinitySize / gridSize; ++i) { byte cost = (byte)(rop.NodeVicinityCost / i); int minc = Math.Max(0, ptStart.X - i); int maxc = Math.Min(cols - 1, ptEnd.X + i); int minr = Math.Max(0, ptStart.Y - i); int maxr = Math.Min(rows - 1, ptEnd.Y + i); // top side int r = ptStart.Y - i; if (r >= 0) { for (int c = minc; c <= maxc; ++c) if (costGrid[c, r] < cost) costGrid[c, r] = cost; } // bottom side r = ptEnd.Y + i; if (r <= maxr) { for (int c = minc; c <= maxc; ++c) if (costGrid[c, r] < cost) costGrid[c, r] = cost; } // left side int cc = ptStart.X - i; if (cc >= 0) { for (r = minr; r <= maxr; ++r) if (costGrid[cc, r] < cost) costGrid[cc, r] = cost; } // right side cc = ptEnd.X + i; if (cc <= maxc) { for (r = minr; r <= maxr; ++r) if (costGrid[cc, r] < cost) costGrid[cc, r] = cost; } } } } }
internal virtual PointF getNearestAnchor(PointF pt, Arrow arrow, bool incoming, ref int anchorIdx) { anchorIdx = -1; if (anchorPattern == null) return pt; if (rotation() != 0) pt = Utilities.rotatePointAt(pt, getCenter(), -rotation()); PointF nearestPt = pt; RectangleF nodeRect = getBoundingRect(); float nearestDist = 2 * Math.Max(nodeRect.Width, nodeRect.Height); for (int i = 0; i < anchorPattern.Points.Count; i++) { AnchorPoint ap = anchorPattern.Points[i]; if (incoming && !ap.AllowIncoming) continue; if (!incoming && !ap.AllowOutgoing) continue; if (!flowChart.validateAnchor(arrow, !incoming, this, i)) continue; PointF pos = ap.getPos(nodeRect); float dx = pos.X - pt.X; float dy = pos.Y - pt.Y; float ptDist = (float)Math.Sqrt(dx*dx + dy*dy); if (ptDist < nearestDist) { nearestDist = ptDist; nearestPt = pos; anchorIdx = i; } } if (rotation() != 0) nearestPt = Utilities.rotatePointAt(nearestPt, getCenter(), rotation()); return nearestPt; }
public void Insert(int i, Arrow a) { List.Insert(i, a); }
internal abstract Link createLink(Arrow arrow, PointF pt, bool incoming);
public bool Contains(Arrow obj) { return List.Contains(obj); }
public void AttachTo(Arrow arrow, AttachToArrow attType, int index) { // that returns the active composite if somebody has already created one CompositeCmd composite = flowChart.UndoManager.StartComposite("_fcnet_"); Detach(); Group masterGroup = getSubordinateGroup(arrow); switch (attType) { case AttachToArrow.Point: masterGroup.AttachToArrowPoint(this, index); break; case AttachToArrow.Segment: masterGroup.AttachToArrowSegment(this, index); break; case AttachToArrow.LongestHSegment: masterGroup.AttachToLongestHSegment(this); break; } if (composite != null && composite.Title == "_fcnet_") { // this is our own composite cmd composite.Title = "Attach"; composite.Execute(); } }
internal Link createLink(Arrow arrow, bool incm, int row) { return new TableLink(this, arrow, incm, row); }
internal void addIncomingArrow(Arrow arrow) { if (!incomingArrows.Contains(arrow)) incomingArrows.Add(arrow); }
internal void removeOutgoingArrow(int row, Arrow arrow) { if (rowsList == null || row >= rowsCount) return; foreach(Arrow a in ((Row)rowsList[row]).OutgoingArrows) if(a == arrow) { ((Row)rowsList[row]).OutgoingArrows.Remove(a); return; } }
internal void addOutgoingArrow(Arrow arrow) { if (!outgoingArrows.Contains(arrow)) outgoingArrows.Add(arrow); }
internal PointF getNearestAnchor(int row, PointF pt, Arrow arrow, bool incoming, ref int anchorIdx) { lastAnchorForTable = false; PointF nearestPt = pt; anchorIdx = -1; if (row == -1) return base.getNearestAnchor(pt, arrow, incoming, ref anchorIdx); // link to a row, get the relevant anchor pattern for this row AnchorPattern rowap = getRowAnchorPattern(row); // get row extents RectangleF rowRect = getRowRect(row); float nearestDist = 100 * Math.Max(rowRect.Width, rowRect.Height); if (rowap != null) { // look for appropriate anchor points, in or out for (int i = 0; i < rowap.Points.Count; i++) { AnchorPoint ap = rowap.Points[i]; if (incoming && !ap.AllowIncoming) continue; if (!incoming && !ap.AllowOutgoing) continue; if (!flowChart.validateAnchor(arrow, !incoming, this, i)) continue; // how close an anchor point is to the point passed as parameter RectangleF testRect = ap.Column == -1 ? rowRect : getSpannedCellRect(row, ap.Column); PointF pos = ap.getPos(testRect); float dx = pos.X - pt.X; float dy = pos.Y - pt.Y; float ptDist = (float)Math.Sqrt(dx*dx + dy*dy); if (ptDist < nearestDist) { // dis closer than the others nearestDist = ptDist; nearestPt = pos; anchorIdx = i; } } } return nearestPt; }
internal virtual void removeIncomingArrow(Arrow arrow) { incomingArrows.Remove(arrow); }
/// <summary> /// Initializes a new instance of the Link class. /// </summary> /// <param name="arrow">The arrow whose connection to a node is managed by this Link.</param> /// <param name="incoming">Specifies which end of the arrow is represented by this Link.</param> public Link(Arrow arrow, bool incoming) { this.arrow = arrow; this.incoming = incoming; this.relativePosition = new PointF(0, 0); }
/// <summary> /// Converts Flowchart.NET arrow into SVG /// </summary> /// <param name="newArrow">Arrow reference</param> /// <returns>TRUE if successfull otherwise FALSE</returns> private bool CreateArrow(MindFusion.FlowChartX.Arrow newArrow) { bool bOk = false; string sPath = "", sPathPart = ""; int iCount = 0; try { if (newArrow.Origin != null) { if ((!newArrow.Origin.Visible) && (!InvisibleItems)) { return(true); } } if (newArrow.Destination != null) { if ((!newArrow.Destination.Visible) && (!InvisibleItems)) { return(true); } } if (newArrow.Style == ArrowStyle.Bezier) { sPath = String.Format("M{0},{1} C{2},{3} {4},{5} {6},{7} ", Unit2Pix(newArrow.ControlPoints[0].X), Unit2Pix(newArrow.ControlPoints[0].Y), Unit2Pix(newArrow.ControlPoints[1].X), Unit2Pix(newArrow.ControlPoints[1].Y), Unit2Pix(newArrow.ControlPoints[newArrow.ControlPoints.Count - 2].X), Unit2Pix(newArrow.ControlPoints[newArrow.ControlPoints.Count - 2].Y), Unit2Pix(newArrow.ControlPoints[newArrow.ControlPoints.Count - 1].X), Unit2Pix(newArrow.ControlPoints[newArrow.ControlPoints.Count - 1].Y)); } else { sPath = String.Format("M{0},{1} ", Unit2Pix(newArrow.ControlPoints[0].X), Unit2Pix(newArrow.ControlPoints[0].Y)); for (iCount = 1; iCount < newArrow.ControlPoints.Count; iCount++) { sPathPart = String.Format("L{0},{1} ", Unit2Pix(newArrow.ControlPoints[iCount].X), Unit2Pix(newArrow.ControlPoints[iCount].Y)); sPath += sPathPart; } } if (sPath == "") { return(false); } sPath = sPath.TrimEnd(); string sWidth = "1px"; if (newArrow.Pen.Width != 0) { String.Format("{0}px", Unit2Pix(newArrow.Pen.Width)); } sMan.AddPath(sPath, sWidth, newArrow.PenColor, Color.Transparent); sPath = ""; sPath = sMan.GetArrowHead(newArrow.HeadShape); XmlNode last_node = sMan.AddPath(sPath, sWidth, newArrow.PenColor, newArrow.PenColor); sPath = ""; sPath = sMan.GetArrowHead(newArrow.BaseShape); last_node = sMan.AddPath(sPath, sWidth, newArrow.PenColor, newArrow.PenColor); RectangleF rect = RectangleF.Empty; float angle = 0; rect = getTextRect(System.Drawing.Graphics.FromHwnd(SvgManager.GetActiveWindow()), newArrow.Style, newArrow.TextStyle, newArrow.ControlPoints, newArrow.TextColor, newArrow.SegmentCount, newArrow.Text, newArrow.Font, RectangleF.Empty, ref angle); if (!rect.Equals(RectangleF.Empty)) { StringFormat sf = new StringFormat(); sf.Alignment = StringAlignment.Center; XmlNode text_added = sMan.AddText(null, newArrow.Text, newArrow.Font, rect, newArrow.TextColor, sf, false, angle); } bOk = true; } catch (Exception ex) { Trace.WriteLine(String.Format("{0} error {1}\n", "CreateArrow", ex.Message)); bOk = false; } return(bOk); }