private ArrowCrossings getCrossings() { float crad = flowChart.CrossingRadius; RectangleF rcArrow = getBoundingRect(); PointCollection intersections = new PointCollection(0); ArrowCrossings ac = (ArrowCrossings)getData(Constants.ARROW_CROSSINGS); if (ac == null) { ac = new ArrowCrossings(segmentCount); setData(Constants.ARROW_CROSSINGS, ac); // z index where this arrow is or will be placed int z = ZIndex; if (!constructed) z = flowChart.Objects.Count; // get the arrows which should be checked for intersections ArrowCollection arrows; if (flowChart.ArrowCrossings == MindFusion.FlowChartX.ArrowCrossings.Arcs) arrows = flowChart.getArrowsFromZ(true, z); else arrows = flowChart.getArrowsFromZ(false, z); // check each segment for (int sgt = 0; sgt < segmentCount; ++sgt) { PointF pt1 = Points[sgt]; PointF pt2 = Points[sgt+1]; if (pt1 == pt2) continue; // find intersecting points with each arrow for (int i = 0; i < arrows.Count; ++i) { Arrow arrow = arrows[i]; if (!arrow.Visible || arrow.Style == ArrowStyle.Bezier) continue; // dont check segments if arrow bounding rects dont intersect at all RectangleF rcTest = arrow.getBoundingRect(); if (!rcTest.IntersectsWith(rcArrow)) continue; for (int test = 0; test < arrow.SegmentCount; ++test) { PointF testPt1 = arrow.Points[test]; PointF testPt2 = arrow.Points[test+1]; if (testPt1 == testPt2) continue; PointF intersection = new PointF(0, 0); if (Utilities.segmentIntersect(pt1, pt2, testPt1, testPt2, ref intersection)) { if (Utilities.Distance(pt1, intersection) > crad && Utilities.Distance(pt2, intersection) > crad) intersections.Add(intersection); } } } // sort by distance to the first point intersections.Sort(new CloserDistance(pt1)); // add radial intersections to the runtime intersection data CloserDistance closer = new CloserDistance(pt1); PointCollection rintr = ac.segmentCrossings[sgt] as PointCollection; rintr.Add(pt1); for (int ptc = 0; ptc < intersections.Count; ++ptc) { PointF ptRes1, ptRes2, pt = intersections[ptc]; ptRes1 = ptRes2 = pt; RectangleF rc = RectangleF.FromLTRB( pt.X - crad, pt.Y - crad, pt.X + crad, pt.Y + crad); Utilities.getEllipseIntr(rc, pt1, pt, ref ptRes1); Utilities.getEllipseIntr(rc, pt2, pt, ref ptRes2); if (closer.Compare(ptRes1, ptRes2) < 0) { rintr.Add(ptRes1); rintr.Add(ptRes2); } else { rintr.Add(ptRes2); rintr.Add(ptRes1); } } rintr.Add(pt2); // Check if there are intersection that overlap for (int i = 1; i < rintr.Count - 2; ) { PointF p1 = rintr[i]; PointF p2 = rintr[i + 1]; if (closer.Compare(p1, p2) > 0 || Utilities.Distance(p1, p2) < Constants.getMillimeter(flowChart.MeasureUnit) / 2) { // Remove these points rintr.RemoveAt(i); rintr.RemoveAt(i); } else { i++; } } intersections.Clear(); } // for (int sgt = 0; sgt < GetSegments(); ++sgt) } return ac; }
public void Read(System.Xml.XmlReader reader) { // Disable auto-routing for a while _diagram.DontRouteForAwhile = true; _diagram.ClearAll(); // Read while <Diagram> reached while (reader.Read()) if (reader.Name == "Diagram") break; if (reader.Name != "Diagram") throw new InvalidFormatException("Invalid FlowChart document"); // Check version _version = 1; if (reader.HasAttributes) _version = XmlConvert.ToInt32(reader.GetAttribute("Version")); // Read the brushes SortedList brushes = new SortedList(); Brush brush; int count; int i; int id = 0; string type; int d; ReadMandatory(reader, "Brushes", "Brushes element missing or invalid"); count = XmlConvert.ToInt32( reader.GetAttribute("Count")); for(i = 0; i < count; i++) { ReadMandatory(reader, "Brush", "Unrecognized brush token"); id = XmlConvert.ToInt32( reader.GetAttribute("Id")); type = reader.GetAttribute("Type"); brush = null; switch(type) { case "Solid": { d = reader.Depth; string name; while(true) { // Read element reader.Read(); if(reader.Depth == d) break; name = reader.Name; // Read the value reader.Read(); if(name == "Color") { Color c = XmlConvert.ToColor(reader.Value); brush = new FlowChartX.SolidBrush(c); } // Read the closing element reader.Read(); } } break; case "Gradient": { d = reader.Depth; float angle = 0; Blend blend = null; Color c1 = Color.Black, c2 = Color.White; ColorBlend cblend = null; while(true) { // Read element reader.Read(); if(reader.Depth == d) break; switch (reader.Name) { case "Angle": // Read the value reader.Read(); angle = XmlConvert.ToSingle(reader.Value); break; case "Blend": { // Read positions reader.Read(); float[] pos = ReadFloatArrayElement(reader); // Read factors reader.Read(); float[] fac = ReadFloatArrayElement(reader); if(pos.Length != fac.Length) throw new InvalidFormatException( "Factors and positions in a gradient brush " + "have different lengths"); blend = new Blend(); blend.Positions = pos; blend.Factors = fac; } break; case "Color1": // Read the value reader.Read(); c1 = XmlConvert.ToColor(reader.Value); break; case "Color2": // Read the value reader.Read(); c2 = XmlConvert.ToColor(reader.Value); break; case "ColorBlend": { // Read positions reader.Read(); float[] pos = ReadFloatArrayElement(reader); // Read colors reader.Read(); Color[] colors = ReadColorArrayElement(reader); cblend = new ColorBlend(); cblend.Positions = pos; cblend.Colors = colors; } break; } // Read the closing element reader.Read(); } brush = new FlowChartX.LinearGradientBrush(c1, c2); ((LinearGradientBrush)brush).Angle = angle; ((LinearGradientBrush)brush).Blend = blend; ((LinearGradientBrush)brush).InterpolationColor = cblend; } break; case "Texture": { d = reader.Depth; string name; WrapMode wm = WrapMode.Tile; Image img = null; while(true) { // Read element reader.Read(); if(reader.Depth == d) break; name = reader.Name; // Read the value reader.Read(); switch(name) { case "WrapMode": wm = (WrapMode)XmlConvert.ToEnum( typeof(WrapMode), reader.Value); break; case "Image": img = _version >= 4 ? XmlConvert.ToImageV4(reader.Value) : XmlConvert.ToImage(reader.Value); break; } // Read the closing element reader.Read(); if (img != null) brush = new FlowChartX.TextureBrush(img, wm); } } break; case "Hatch": { d = reader.Depth; string name; Color fore = Color.Black, back = Color.White; HatchStyle style = HatchStyle.ForwardDiagonal; while(true) { // Read element reader.Read(); if(reader.Depth == d) break; name = reader.Name; // Read the value reader.Read(); switch(name) { case "ForeColor": fore = XmlConvert.ToColor(reader.Value); break; case "BackColor": back = XmlConvert.ToColor(reader.Value); break; case "Style": style = (HatchStyle)XmlConvert.ToEnum( typeof(HatchStyle), reader.Value); break; } // Read the closing element reader.Read(); brush = new FlowChartX.HatchBrush( style, fore, back); } } break; } if(!brushes.Contains(id) && brush != null) brushes.Add(id, brush); } // Read the brushes closing element if(count > 0) reader.Read(); ReadMandatory(reader, "Environment", "Environment element missing or invalid"); // Read all appearance properties ReadMandatory(reader, "Appearance", "Appearance element missing or invalid"); if(!ReadProperties(reader, _diagram, reader.Depth + 1)) throw new InvalidFormatException("Unexpected " + "EOF in the Appearance section"); // Read all bahaviour properties ReadMandatory(reader, "Behaviour", "Behaviour element missing or invalid"); if(!ReadProperties(reader, _diagram, reader.Depth + 1)) throw new InvalidFormatException("Unexpected " + "EOF in the Behaviour section"); // Read all default properties ReadMandatory(reader, "Defaults", "Defaults element missing or invalid"); if(!ReadProperties(reader, _diagram, reader.Depth + 1)) throw new InvalidFormatException("Unexpected " + "EOF in the Defaults section"); // Read default brushes and pens ReadMandatory(reader, "DefaultsGDI", "DefaultsGDI element missing or invalid"); d = reader.Depth; while(true) { // Read starting tag reader.Read(); if(reader.Depth == d) break; switch (reader.Name) { case "BoxBrush": id = XmlConvert.ToInt32( reader.GetAttribute("Id")); _diagram.BoxBrush = (FlowChartX.Brush)brushes[id]; break; case "TableBrush": id = XmlConvert.ToInt32( reader.GetAttribute("Id")); _diagram.TableBrush = (FlowChartX.Brush)brushes[id]; break; /* case "TableCaptionBackBrush": id = XmlConvert.ToInt32( reader.GetAttribute("Id")); _diagram.TableCaptionBackBrush = (FlowChartX.Brush)brushes[id]; break; */ case "ArrowBrush": id = XmlConvert.ToInt32( reader.GetAttribute("Id")); _diagram.ArrowBrush = (FlowChartX.Brush)brushes[id]; break; case "BackBrush": id = XmlConvert.ToInt32( reader.GetAttribute("Id")); _diagram.BackBrush = (FlowChartX.Brush)brushes[id]; break; case "ExteriorBrush": id = XmlConvert.ToInt32( reader.GetAttribute("Id")); if (id == -1) _diagram.ExteriorBrush = null; else _diagram.ExteriorBrush = (FlowChartX.Brush)brushes[id]; break; case "BoxPen": _diagram.BoxPen.Brush = null; // force release _diagram.BoxPen = (FlowChartX.Pen) ReadPenElement(reader, brushes); break; case "TablePen": _diagram.TablePen.Brush = null; // force release _diagram.TablePen = (FlowChartX.Pen) ReadPenElement(reader, brushes); break; case "ArrowPen": _diagram.ArrowPen.Brush = null; // force release _diagram.ArrowPen = (FlowChartX.Pen) ReadPenElement(reader, brushes); break; } } // Read all grid properties ReadMandatory(reader, "Grid", "Grid element missing or invalid"); if(!ReadProperties(reader, _diagram, reader.Depth + 1)) throw new InvalidFormatException("Unexpected " + "EOF in the Grid section"); // Read all layout properties ReadMandatory(reader, "Layout", "Layout element missing or invalid"); if(!ReadProperties(reader, _diagram, reader.Depth + 1)) throw new InvalidFormatException("Unexpected " + "EOF in the Layout section"); // Read all miscellaneous properties ReadMandatory(reader, "Miscellaneous", "Miscellaneous element missing or invalid"); if(!ReadProperties(reader, _diagram, reader.Depth + 1)) throw new InvalidFormatException("Unexpected " + "EOF in the Miscellaneous section"); // Read the Environment closing element reader.Read(); // Proceed to diagram objects // Box b; ControlHost h; Arrow a; Table t; Group g; object from, to; PointCollection points = new PointCollection(0); int idFrom, idTo, idArrow; int rowFrom, rowTo; int row, col; SortedList objects = new SortedList(); SortedList zOrder = new SortedList(); SortedList controlZOrder = new SortedList(); int zIndex; id = 0; // Read boxes info ReadMandatory(reader, "Boxes", "Boxes element missing or invalid"); count = XmlConvert.ToInt32(reader.GetAttribute("Count")); int brushId = -1; FlowChartX.Pen pen = null; FlowChartX.Pen headPen = null; for(i = 0; i < count; i++) { // Read the starting element ReadMandatory(reader, "Box", "Unrecognized box token"); id = XmlConvert.ToInt32(reader.GetAttribute("Id")); zIndex = XmlConvert.ToInt32(reader.GetAttribute("ZIndex")); b = _diagram.CreateBox(0, 0, 1, 1); objects.Add(id, b); zOrder.Add(zIndex, b); // Read the shape string shape; reader.Read(); if(!reader.IsEmptyElement) { reader.Read(); shape = reader.Value; reader.Read(); } else { shape = "Rectangle"; } BoxStyle style = BoxStyle.Rectangle; switch(shape) { case "RoundRectangle": style = BoxStyle.RoundedRectangle; break; default: // Assume it is a complex shape style = BoxStyle.Shape; break; } b.Style = style; if(style == BoxStyle.Shape) b.Shape = ShapeTemplate.FromId(shape); // Read brush reader.Read(); if (reader.GetAttribute("Id") != null) brushId = XmlConvert.ToInt32(reader.GetAttribute("Id")); else brushId = -1; // Read the pen reader.Read(); pen = ReadPenElement(reader, brushes); if(!ReadProperties(reader, b, reader.Depth)) throw new InvalidFormatException( "Unexpected EOF while parsing box info. Box: " + i.ToString()); // Set brush and pen if(brushId != -1) b.Brush = (FlowChartX.Brush)brushes[brushId]; if(pen != null) b.Pen = pen; } // Read boxes closing element if(count > 0) reader.Read(); // Read control hosts if (_version >= 3) { string assemblyName; string typeName; ReadMandatory(reader, "ControlHosts", "ControlHosts element missing or invalid"); count = XmlConvert.ToInt32(reader.GetAttribute("Count")); for (i = 0; i < count; i++) { // Read the host element ReadMandatory(reader, "Host", "Host element missing or invalid"); id = XmlConvert.ToInt32(reader.GetAttribute("Id")); zIndex = XmlConvert.ToInt32(reader.GetAttribute("ZIndex")); assemblyName = reader.GetAttribute("ControlAssembly"); typeName = reader.GetAttribute("ControlType"); int controlZIndex = XmlConvert.ToInt32(reader.GetAttribute("ControlZIndex")); // Create the control host and add it to the diagram h = _diagram.CreateControlHost(0, 0, 1, 1); objects.Add(id, h); zOrder.Add(zIndex, h); controlZOrder.Add(controlZIndex, h.Control); // Read brush reader.Read(); if(reader.GetAttribute("Id") != null) brushId = XmlConvert.ToInt32(reader.GetAttribute("Id")); else brushId = -1; // Read the pen reader.Read(); pen = ReadPenElement(reader, brushes); if (typeName != "" && assemblyName != "") { System.Type controlType = Utilities.getLoadedType(typeName, assemblyName); if (controlType == null) throw new FileLoadException("Cannot load hosted control of type " + typeName); ConstructorInfo ctorInfo = controlType.GetConstructor(System.Type.EmptyTypes); // Instantiate h.Control = (System.Windows.Forms.Control)ctorInfo.Invoke(null); // Read control properties BinaryFormatter fmt = new BinaryFormatter(); fmt.Binder = new DeserializationHack(); ReadControlProperties(reader, h.Control, fmt); } else { h.Control = null; } // Read properties if (!ReadProperties(reader, h, reader.Depth)) throw new InvalidFormatException( "Unexpected EOF while parsing control host info. ControlHost: " + i.ToString()); // Set brush and pen if (brushId != -1) h.Brush = (FlowChartX.Brush)brushes[brushId]; if (pen != null) h.Pen = pen; } // Update the z-indices of the contained controls foreach (System.Windows.Forms.Control control in controlZOrder.Values) control.BringToFront(); // Read control hosts closing element if(count > 0) reader.Read(); } // Read tables info ReadMandatory(reader, "Tables", "Tables element missing or invalid"); count = XmlConvert.ToInt32(reader.GetAttribute("Count")); for(i = 0; i < count; i++) { // Read the table element ReadMandatory(reader, "Table", "Unrecognized table token"); id = XmlConvert.ToInt32(reader.GetAttribute("Id")); zIndex = XmlConvert.ToInt32(reader.GetAttribute("ZIndex")); t = _diagram.CreateTable(0, 0, 1, 1); objects.Add(id, t); zOrder.Add(zIndex, t); t.RowCount = XmlConvert.ToInt32(reader.GetAttribute("Rows")); t.ColumnCount = XmlConvert.ToInt32(reader.GetAttribute("Columns")); // Read cell data ReadMandatory(reader, "Data", "Data element missing or invalid"); d = reader.Depth; row = 0; col = 0; if(!reader.IsEmptyElement) { while(true) { reader.Read(); if(d == reader.Depth) break; // Read brush in V5 if (_version >= 5) { reader.Read(); int bid = -1; if (reader.GetAttribute("Id") != null) bid = XmlConvert.ToInt32(reader.GetAttribute("Id")); if (bid != -1) t[col, row].Brush = (FlowChartX.Brush)brushes[bid]; else t[col, row].Brush = null; ReadProperties(reader, t[col, row], reader.Depth); } else { ReadProperties(reader, t[col, row], reader.Depth + 1); } col++; if(col >= t.ColumnCount) { col = 0; row++; } } } // Read row data ReadMandatory(reader, "Rows", "Rows element missing or invalid"); d = reader.Depth; row = 0; if(!reader.IsEmptyElement) { while(true) { reader.Read(); if(d == reader.Depth) break; ReadProperties(reader, t.Rows[row], reader.Depth + 1); row++; } } // Read column data ReadMandatory(reader, "Columns", "Columns element missing or invalid"); d = reader.Depth; col = 0; if(!reader.IsEmptyElement) { while(true) { reader.Read(); if(d == reader.Depth) break; ReadProperties(reader, t.Columns[col], reader.Depth + 1); col++; } } // Read brush reader.Read(); if (reader.GetAttribute("Id") != null) brushId = XmlConvert.ToInt32(reader.GetAttribute("Id")); else brushId = -1; // Read the caption brush int captionBrushId = -1; if (_version >= 10) { reader.Read(); if (reader.GetAttribute("Id") != null) captionBrushId = XmlConvert.ToInt32(reader.GetAttribute("Id")); else captionBrushId = -1; } // Read the pen reader.Read(); pen = ReadPenElement(reader, brushes); // Read table properties if(!ReadProperties(reader, t, reader.Depth)) throw new InvalidFormatException( "Unexpected EOF while parsing table info. Table: " + i.ToString()); // Set brush and pen if (brushId != -1) t.Brush = (FlowChartX.Brush)brushes[brushId]; if (captionBrushId != -1) t.CaptionBackBrush = (FlowChartX.Brush)brushes[captionBrushId]; if (pen != null) t.Pen = pen; } // Read tables closing element if(count > 0) reader.Read(); if (_version >= 7) { ReadMandatory(reader, "Containers", "Containers element missing or invalid"); int ccount = XmlConvert.ToInt32(reader.GetAttribute("Count")); if (ccount > 0) { int cdepth = reader.Depth; while (true) { reader.Read(); if (reader.Depth == cdepth) break; } } } // Read arrows info ReadMandatory(reader, "Arrows", "Arrows element missing or invalid"); count = XmlConvert.ToInt32(reader.GetAttribute("Count")); for(i = 0; i < count; i++) { // Read the arrow element ReadMandatory(reader, "Arrow", "Unrecognized arrow token"); // Read the origin and destination indices idFrom = XmlConvert.ToInt32(reader.GetAttribute("From")); idTo = XmlConvert.ToInt32(reader.GetAttribute("To")); idArrow = XmlConvert.ToInt32(reader.GetAttribute("Id")); zIndex = XmlConvert.ToInt32(reader.GetAttribute("ZIndex")); try { rowFrom = XmlConvert.ToInt32(reader.GetAttribute("RowFrom")); } catch { rowFrom = -1; } try { rowTo = XmlConvert.ToInt32(reader.GetAttribute("RowTo")); } catch { rowTo = -1; } if (idTo == -1 || idFrom == -1) { if (idTo == -1 && idFrom != -1) { from = objects[idFrom]; Node nodeFrom = from as Node; // Temporarily turn allow arrows off bool allowIn = nodeFrom.AllowIncomingArrows; bool allowOut = nodeFrom.AllowOutgoingArrows; nodeFrom.AllowIncomingArrows = true; nodeFrom.AllowOutgoingArrows = true; a = _diagram.CreateArrow(nodeFrom, PointF.Empty); nodeFrom.AllowIncomingArrows = allowIn; nodeFrom.AllowOutgoingArrows = allowOut; } else if (idTo != -1 && idFrom == -1) { to = objects[idTo]; Node nodeTo = to as Node; // Temporarily turn allow arrows off bool allowIn = nodeTo.AllowIncomingArrows; bool allowOut = nodeTo.AllowOutgoingArrows; nodeTo.AllowIncomingArrows = true; nodeTo.AllowOutgoingArrows = true; a = _diagram.CreateArrow(PointF.Empty, (Node)to); nodeTo.AllowIncomingArrows = allowIn; nodeTo.AllowOutgoingArrows = allowOut; } else { a = _diagram.CreateArrow(PointF.Empty, PointF.Empty); } } else { from = objects[idFrom]; to = objects[idTo]; Node nodeFrom = from as Node; Node nodeTo = to as Node; // Temporarily turn allow arrows off bool fromAllowIn = nodeFrom.AllowIncomingArrows; bool fromAllowOut = nodeFrom.AllowOutgoingArrows; bool toAllowIn = nodeTo.AllowIncomingArrows; bool toAllowOut = nodeTo.AllowOutgoingArrows; nodeFrom.AllowIncomingArrows = true; nodeFrom.AllowOutgoingArrows = true; nodeTo.AllowIncomingArrows = true; nodeTo.AllowOutgoingArrows = true; if(rowFrom == -1 && rowTo == -1) { a = _diagram.CreateArrow((Node)from, (Node)to); } else if(rowFrom != -1 && rowTo == -1) { a = _diagram.CreateArrow((Table)from, rowFrom, (Node)to); } else if(rowFrom == -1 && rowTo != -1) { a = _diagram.CreateArrow((Node)from, (Table)to, rowTo); } else { a = _diagram.CreateArrow((Table)from, rowFrom, (Table)to, rowTo); } nodeFrom.AllowIncomingArrows = fromAllowIn; nodeFrom.AllowOutgoingArrows = fromAllowOut; nodeTo.AllowIncomingArrows = toAllowIn; nodeTo.AllowOutgoingArrows = toAllowOut; } // Read the control points ReadMandatory(reader, "Data", "Data element missing or invalid"); d = reader.Depth; float x, y; points.Clear(); while(true) { // Read the point reader.Read(); if(reader.Depth == d) break; x = XmlConvert.ToSingle(reader.GetAttribute("X")); y = XmlConvert.ToSingle(reader.GetAttribute("Y")); points.Add(new PointF(x, y)); } // Read brush reader.Read(); if(reader.GetAttribute("Id") != null) brushId = XmlConvert.ToInt32(reader.GetAttribute("Id")); else brushId = -1; // Read the pen reader.Read(); pen = ReadPenElement(reader, brushes); // Read head pen if (_version > 1) { reader.Read(); headPen = ReadPenElement(reader, brushes); } // Read the properties if(!ReadProperties(reader, a, reader.Depth)) throw new InvalidFormatException( "Unexpected EOF while parsing arrow info. Arrow: " + i.ToString()); // Set again segment count, because // if the arrow is routed, settings // segment count through SegmentCount property // won't have any effect if (a.Style == ArrowStyle.Bezier) a.InternalSegmentCount = (short)((points.Count - 1) / 3); else a.InternalSegmentCount = (short)(points.Count - 1); // Set the control points for(int p = 0; p < points.Count; p++) a.ControlPoints[p] = points[p]; a.UpdateFromPoints(); // Set brush and pen if(brushId != -1) a.Brush = (FlowChartX.Brush)brushes[brushId]; if(pen != null) a.Pen = pen; if (headPen != null) a.HeadPen = headPen; objects.Add(idArrow, a); zOrder.Add(zIndex, a); } // Read arrows closing element if(count > 0) reader.Read(); // Adjust z-order for(i = 0; i < zOrder.Count; i++) { ChartObject obj = (ChartObject)zOrder.GetByIndex(i); obj.ZIndex = (int)zOrder.GetKey(i); } // Read groups ReadMandatory(reader, "Groups", "Groups element missing or invalid"); count = XmlConvert.ToInt32(reader.GetAttribute("Count")); for(i = 0; i < count; i++) { // Read the group element ReadMandatory(reader, "Group", "Unrecognized group token"); // Read the main object reader.Read(); id = XmlConvert.ToInt32(reader.GetAttribute("Id")); g = _diagram.CreateGroup((ChartObject)objects[id]); // Read group's visibility reader.Read(); reader.Read(); g.Visible = XmlConvert.ToBoolean(reader.Value.ToLower()); reader.Read(); // Read AutoDeleteItems flag if (_version >= 7) { reader.Read(); reader.Read(); g.AutoDeleteItems = XmlConvert.ToBoolean(reader.Value.ToLower()); reader.Read(); } // Read Expandable flag if (_version >= 8) { reader.Read(); reader.Read(); g.Expandable = XmlConvert.ToBoolean(reader.Value.ToLower()); reader.Read(); } // Read FollowMasterRotation flag if (_version >= 9) { reader.Read(); reader.Read(); g.FollowMasterRotation = XmlConvert.ToBoolean(reader.Value.ToLower()); reader.Read(); } reader.Read(); // read Tag or Attachments if (reader.Name == "Tag") { if (_options.CustomTagSerialization) { if(DeserializeTag != null) { SerializeTagArgs args = new SerializeTagArgs(g, null, reader); DeserializeTag(this, args); } } else { // Read the value reader.Read(); if(DeserializeTag != null) { SerializeTagArgs args = new SerializeTagArgs(g); args.Representation = reader.Value; DeserializeTag(this, args); } } // Read the closing Tag element reader.Read(); // Read the Attachments reader.Read(); } // Process attachments int acount = XmlConvert.ToInt32(reader.GetAttribute("Count")); int ai; int adata; Node node; float al, at, ar, ab; AttachTo atype; for(ai = 0; ai < acount; ai++) { // Read attachment element reader.Read(); // Read data reader.Read(); reader.Read(); adata = XmlConvert.ToInt32(reader.Value); reader.Read(); // Read object reader.Read(); reader.Read(); node = (Node)objects[XmlConvert.ToInt32(reader.Value)]; reader.Read(); // Read percents reader.Read(); al = XmlConvert.ToSingle(reader.GetAttribute("Left")); at = XmlConvert.ToSingle(reader.GetAttribute("Top")); ar = XmlConvert.ToSingle(reader.GetAttribute("Right")); ab = XmlConvert.ToSingle(reader.GetAttribute("Bottom")); // Read type reader.Read(); reader.Read(); atype = (AttachTo)XmlConvert.ToEnum( typeof(AttachTo), reader.Value); reader.Read(); switch(atype) { case AttachTo.ArrowPoint: g.AttachToArrowPoint(node, adata); break; case AttachTo.ArrowSegment: g.AttachToArrowSegment(node, adata); break; case AttachTo.FixedCorner: g.AttachToCorner(node, adata); break; case AttachTo.Proportional: g.AttachProportional(node, al, at, ar, ab); break; case AttachTo.LongestHSegment: g.AttachToLongestHSegment(node); break; case AttachTo.SideMiddle: g.AttachToSideMiddle(node, adata); break; } // Read attachment closing element reader.Read(); } // Read attachments' closing element if(acount > 0) reader.Read(); // Read the group closing element reader.Read(); } // Read groups closing element reader.Read(); // Read diagram closing element reader.Read(); foreach (ChartObject obj in _diagram.Objects) obj.onLoad(); // Note: If exception is thrown this // flag will remain raised _diagram.DontRouteForAwhile = false; }
internal void doRoute(bool force, Link orgnLink, Link destLink, bool nowCreating) { if (!force) if (!autoRoute) return; if (flowChart.DontRouteForAwhile) return; int i; float gridSize = flowChart.RoutingOptions.GridSize; PointF startPoint = points[0]; PointF endPoint = points[points.Count - 1]; // get a rectangle bounding both the origin and the destination RectangleF bounds = orgnLink.getNodeRect(true); bounds = Utilities.unionRects(bounds, destLink.getNodeRect(true)); bounds = RectangleF.Union(bounds, Utilities.normalizeRect( RectangleF.FromLTRB(startPoint.X, startPoint.Y, endPoint.X, endPoint.Y))); if (bounds.Width < gridSize * 4) bounds.Inflate(gridSize * 4, 0); if (bounds.Height < gridSize * 4) bounds.Inflate(0, gridSize * 4); bounds.Inflate(bounds.Width, bounds.Height); int oNearest = 0, dNearest = 0; routeGetEndPoints(ref startPoint, ref endPoint, ref oNearest, ref dNearest, orgnLink, destLink, nowCreating); // Get the starting and ending square Point ptStart = new Point((int)((startPoint.X - bounds.X) / gridSize), (int)((startPoint.Y - bounds.Y) / gridSize)); Point ptEnd = new Point((int)((endPoint.X - bounds.X) / gridSize), (int)((endPoint.Y - bounds.Y) / gridSize)); if (ptStart.X == ptEnd.X && ptStart.Y == ptEnd.Y) return; // init the route grid int gridCols = (int)(bounds.Width / gridSize); int gridRows = (int)(bounds.Height / gridSize); RoutingGrid routingGrid = flowChart.RoutingGrid; routingGrid.allocate(gridCols, gridRows, bounds, this); byte[,] grid = routingGrid.getCostGrid(); PathNode[,] gridClosed = routingGrid.getClosedGrid(); PathNode[,] gridOpen = routingGrid.getOpenGrid(); bool hurry = (gridCols * gridRows > 90000) && flowChart.RoutingOptions.DontOptimizeLongRoutes; RouteHeuristics calcRouteHeuristics = hurry ? RoutingOptions.DistSquare : flowChart.RoutingOptions.RouteHeuristics; routeFixEndRegions(grid, ref ptStart, oNearest, ref ptEnd, dNearest, gridCols, gridRows); grid[ptStart.X, ptStart.Y] = 0; grid[ptEnd.X, ptEnd.Y] = 0; //---------- A* algorithm initialization ----------- SortedList open = new SortedList(); ArrayList closed = new ArrayList(); Stack stack = new Stack(); PathNode temp = new PathNode(ptStart.X, ptStart.Y); temp.G = 0; temp.H = calcRouteHeuristics(ptStart, ptEnd); temp.F = temp.G + temp.H; open.Add(temp, temp); gridOpen[temp.X, temp.Y] = temp; // setup A* cost function int adjcCost = flowChart.RoutingOptions.LengthCost; int turnCost = flowChart.RoutingOptions.TurnCost; PathNode best = null; bool found = false; int iterations = 0; for ( ; ; ) { iterations++; // Get the best node from the open list if (open.Count == 0) break; PathNode pstmp = open.GetByIndex(0) as PathNode; open.RemoveAt(0); gridOpen[pstmp.X, pstmp.Y] = null; closed.Add(pstmp); gridClosed[pstmp.X, pstmp.Y] = pstmp; if ((best = pstmp) == null) break; // If best == destination -> path found if (best.X == ptEnd.X && best.Y == ptEnd.Y) { found = true; break; } // Generate best's successors int x = best.X; int y = best.Y; int[,] off = new int[4, 2] { { 1, 0 }, { 0, 1 }, { -1, 0 }, { 0, -1 } }; for (i = 0; i < 4; i++) { byte localCost = grid[x + off[i, 0], y + off[i, 1]]; if (localCost == 255) continue; int g = best.G + adjcCost + localCost; bool straight = best.Parent == null || (best.Parent.Y == best.Y && off[i, 1] == 0) || (best.Parent.X == best.X && off[i, 0] == 0); if (best.Parent == null && oNearest >= 0 && ( oNearest < 2 && off[i, 1] == 0 || oNearest >= 2 && off[i, 1] == 1)) straight = false; if (!straight) g += turnCost; PathNode check = null; // if the successor is an open node, add it to the path check = gridOpen[x + off[i, 0], y + off[i, 1]]; if (check != null) { best.Children[best.ChildCount++] = check; // and update its cost if now it is reached via a better path if (g < check.G) { open.Remove(check); // keep sorted check.Parent = best; check.G = g; check.F = g + check.H; open.Add(check, check); // keep sorted } } else { // if the successor is a closed node, add it to the path check = gridClosed[x + off[i, 0], y + off[i, 1]]; if (check != null) { best.Children[best.ChildCount++] = check; // and update its cost if now it is reached via a better path if (g < check.G) { check.Parent = best; check.G = g; check.F = g + check.H; // and update its child items int gg = check.G; int cc = check.ChildCount; PathNode kid = null; for (int j = 0; j < cc; j++) { kid = check.Children[j]; int gi = adjcCost; straight = check.Parent == null || (check.Parent.Y == check.Y && check.Y == kid.Y) || (check.Parent.X == check.X && check.X == kid.X); if (!straight) gi += turnCost; if (g + gi < kid.G) { bool wasOpen = gridOpen[kid.X, kid.Y] != null; if (wasOpen) open.Remove(kid); // keep sorted kid.G = g + gi; kid.F = kid.G + kid.H; kid.Parent = check; stack.Push(kid); if (wasOpen) open.Add(kid, kid); } } PathNode parent; while (stack.Count > 0) { parent = stack.Pop() as PathNode; cc = parent.ChildCount; for (int j = 0; j < cc; j++) { kid = parent.Children[j]; int gi = adjcCost; straight = parent.Parent == null || (parent.Parent.Y == parent.Y && parent.Y == kid.Y) || (parent.Parent.X == parent.X && parent.X == kid.X); if (!straight) gi += turnCost; if (parent.G + gi < kid.G) { bool wasOpen = gridOpen[kid.X, kid.Y] != null; if (wasOpen) open.Remove(kid); // keep sorted kid.G = parent.G + gi; kid.F = kid.G + kid.H; kid.Parent = parent; stack.Push(kid); if (wasOpen) open.Add(kid, kid); } } } } } else { // haven't considered this grid square by now // create and initialize a path node for it Point current = new Point(x + off[i, 0], y + off[i, 1]); PathNode newNode = new PathNode(current.X, current.Y); newNode.Parent = best; newNode.G = g; newNode.H = calcRouteHeuristics(current, ptEnd); newNode.F = newNode.G + newNode.H; // add it to the list of open nodes to be evaluated later open.Add(newNode, newNode); gridOpen[newNode.X, newNode.Y] = newNode; // add to the path best.Children[best.ChildCount++] = newNode; } } } } if (found) { PtCollection current = new PtCollection(0); current.Add(new Point((int)((points[points.Count - 1].X - bounds.X) / gridSize), (int)((points[points.Count - 1].Y - bounds.Y) / gridSize))); while (best != null) { current.Add(new Point(best.X, best.Y)); best = best.Parent; } current.Add(new Point((int)((points[0].X - bounds.X) / gridSize), (int)((points[0].Y - bounds.Y) / gridSize))); // Remove all unneeded points Point pt1, pt2, pt3; for (i = 1; i < current.Count - 1;) { pt1 = current[i - 1]; pt2 = current[i]; pt3 = current[i + 1]; if (pt1.X == pt2.X && pt2.X == pt3.X) current.RemoveAt(i); else if(pt1.Y == pt2.Y && pt2.Y == pt3.Y) current.RemoveAt(i); else i++; } // Save the first and last points of the arrow PointF ptFirst = points[0]; PointF ptLast = points[points.Count - 1]; // no perp. arrows on a single line if (style == ArrowStyle.Cascading && current.Count == 2 && ptFirst.X != ptLast.X && ptFirst.Y != ptLast.Y) { Point orgPt = current[0]; Point trgPt = current[current.Count-1]; if (orgPt.X == trgPt.X || orgPt.Y == trgPt.Y) { Point insPt = new Point( (orgPt.X + trgPt.X) / 2, (orgPt.Y + trgPt.Y) / 2); current.Insert(1, insPt); current.Insert(1, insPt); } } // Re-segment the arrow points = new PointCollection(current.Count); points[0] = ptFirst; points[points.Count - 1] = ptLast; // Assign the points from the path i = current.Count - 1; i--; // Skip the first point while (i > 0) { Point pt = current[i]; PointF ptDoc = new PointF(0, 0); ptDoc.X = bounds.X + pt.X * gridSize + gridSize / 2; ptDoc.Y = bounds.Y + pt.Y * gridSize + gridSize / 2; if (i == 1) { // Align to the last point if (pt.Y == current[0].Y) ptDoc.Y = ptLast.Y; else ptDoc.X = ptLast.X; } if (i == current.Count - 2) { // Align to the first point if (pt.Y == current[current.Count - 1].Y) ptDoc.Y = ptFirst.Y; else ptDoc.X = ptFirst.X; if (style == ArrowStyle.Cascading) cascadeStartHorizontal = (ptDoc.X != ptFirst.X); } points[current.Count - i - 1] = ptDoc; i--; } PointF ptf, ptf1, ptf2, ptf3; // If the line is perpendicular make it at least 2 segments if(style == ArrowStyle.Cascading && points.Count == 2) { ptf1 = points[0]; ptf2 = points[points.Count - 1]; ptf = ptf1; if (cascadeStartHorizontal) ptf.X = ptf2.X; else ptf.Y = ptf2.Y; points.Insert(1, ptf); } // If the line is straight there might be more unneeded points if (style == ArrowStyle.Polyline) { i = 0; while(i < points.Count - 2) { ptf1 = points[i]; ptf2 = points[i + 2]; ChartObject obj = flowChart.objectIntersectedBy(ptf1, ptf2, orgnLink.getNode(), destLink.getNode()); if(obj == null) points.RemoveAt(i + 1); else i++; } } // If the line is bezier, smooth it a bit if (style == ArrowStyle.Bezier) { PointCollection newPoints = new PointCollection(0); newPoints.Add(points[0]); i = 0; while(i < points.Count - 2) { ptf1 = points[i]; ptf2 = points[i + 1]; newPoints.Add(ptf2); newPoints.Add(ptf2); if(i != points.Count - 3) { ptf3 = points[i + 2]; ptf = new PointF((ptf2.X + ptf3.X) / 2, (ptf2.Y + ptf3.Y) / 2); newPoints.Add(ptf); } else { newPoints.Add(points[i + 2]); } i += 1; } if (newPoints.Count == 1) { newPoints = new PointCollection(4); ptf1 = points[0]; ptf2 = points[points.Count - 1]; ptf = new PointF((ptf1.X + ptf2.X) / 2, (ptf1.Y + ptf2.Y) / 2); newPoints[0] = ptf1; newPoints[1] = ptf; newPoints[2] = ptf; newPoints[3] = ptf2; } points.Clear(); points = newPoints; } // Update SegmentCount property value if (style == ArrowStyle.Bezier) segmentCount = (short)((points.Count - 1) / 3); else segmentCount = (short)(points.Count - 1); } else { // No path found -> reset the arrow, leaving as little points as possible int ptsToLeave = 2; if (style == ArrowStyle.Cascading) ptsToLeave = 4; else if (style == ArrowStyle.Bezier) ptsToLeave = 4; if (style == ArrowStyle.Cascading) { cascadeOrientation = Orientation.Auto; segmentCount = 3; } else segmentCount = 1; while (points.Count > ptsToLeave) points.RemoveAt(1); if (style == ArrowStyle.Cascading && points.Count == 3) segmentCount = 2; updatePoints(points[points.Count - 1]); } updateArrowHeads(); if (subordinateGroup != null) { subordinateGroup.onSegmentsChanged(); subordinateGroup.updateObjects(new InteractionState(this, -1, Action.Modify)); } resetCrossings(); updateText(); flowChart.fireArrowRoutedEvent(this); }