public override Point[] ComputeSingle(TEdge edge) { CalculateMatrix(CancellationToken.None); //maybe shouldnt do this cause can be used from algo storage and already inited SetupPathFinder(); // ComputeER(edge, CancellationToken.None); return(EdgeRoutes.ContainsKey(edge) ? EdgeRoutes[edge] : null); }
public override void Compute() { if (VertexPositions == null || VertexPositions.Count < 3) { return; } foreach (var item in VertexPositions.Values) { _minPoint.X = Math.Min(item.X, _minPoint.X); _minPoint.Y = Math.Min(item.Y, _minPoint.Y); _maxPoint.X = Math.Max(item.X, _maxPoint.X); _maxPoint.Y = Math.Max(item.Y, _maxPoint.Y); } EdgeRoutes.Clear(); calculateMatrix(); setupPathFinder(); foreach (var item in _graph.Edges) { ComputeER(item); } }
public override void Compute(CancellationToken cancellationToken) { if (VertexPositions == null || VertexPositions.Count < 3) { return; } foreach (var item in VertexPositions.Values) { cancellationToken.ThrowIfCancellationRequested(); _minPoint.X = Math.Min(item.X, _minPoint.X); _minPoint.Y = Math.Min(item.Y, _minPoint.Y); _maxPoint.X = Math.Max(item.X, _maxPoint.X); _maxPoint.Y = Math.Max(item.Y, _maxPoint.Y); } EdgeRoutes.Clear(); CalculateMatrix(cancellationToken); SetupPathFinder(); foreach (var item in Graph.Edges) { ComputeER(item, cancellationToken); } }
private void ComputeER(TEdge item, CancellationToken cancellationToken) { var startPt = GetClosestPoint(_validPoints, VertexPositions[item.Source]); var endPt = GetClosestPoint(_validPoints, VertexPositions[item.Target]); var lst = _pathFinder.FindPath(startPt, endPt); if (lst == null) { return; } var ptlst = new List <Point>(); foreach (var pt in lst) { cancellationToken.ThrowIfCancellationRequested(); var mi = _resMatrix[pt.X, pt.Y]; ptlst.Add(mi.Point); } if (EdgeRoutes.ContainsKey(item)) { EdgeRoutes[item] = ptlst.ToArray(); } else { EdgeRoutes.Add(new KeyValuePair <TEdge, Point[]>(item, ptlst.ToArray())); } }
/// <summary> /// Bundles edges of the graph. /// </summary> /// /// <param name="graph"> /// Graph whose edges should be bundled /// </param> /// /// <param name="rectangle"> /// Rectangle in which the graph is laid out. /// Control points of bundled edges should not fall outside of this rectangle. /// </param> public void BundleAllEdges(TGraph graph) { EdgeRoutes.Clear(); //this.rectangle = rectangle; directed = true; // as we use bidirectional by default AddDataForAllEdges(graph.Edges); //Stopwatch sw = new Stopwatch(); //sw.Start(); FindCompatibleEdges(edgeGroupData); //sw.Stop(); DivideAllEdges(subdivisionPoints); //sw = new Stopwatch(); //sw.Start(); for (var i = 0; i < iterations; i++) { MoveControlPoints(edgeGroupData); } //prevents oscillating movements for (var i = 0; i < 5; i++) { cooldown *= 0.5f; MoveControlPoints(edgeGroupData); } //sw.Stop(); cooldown = 1f; if (straightening > 0) { StraightenEdgesInternally(edgeGroupData, straightening); } foreach (var e in graph.Edges) { if (!e.IsSelfLoop) { var key = new KeyPair(e.Source.ID, e.Target.ID); var list2 = edgeGroupData[key].controlPoints.ToList(); //Point p1 = GeometryHelper.GetEdgeEndpointOnRectangle(VertexPositions[e.Source], VertexSizes[e.Source], list2.First()); //Point p2 = GeometryHelper.GetEdgeEndpointOnRectangle(VertexPositions[e.Target], VertexSizes[e.Target], list2.Last()); //list2.Insert(0, p1); list2.Add(p2); list2.Insert(0, list2.First()); list2.Add(list2.Last()); EdgeRoutes.Add(e, list2.ToArray()); } } }
public override void Compute(CancellationToken cancellationToken) { EdgeRoutes.Clear(); foreach (var item in Graph.Edges) { EdgeRoutingTest(item, cancellationToken); } }
public override void Compute() { EdgeRoutes.Clear(); foreach (var item in _graph.Edges) { EdgeRoutingTest(item); } }
public override void Compute(CancellationToken cancellationToken) { EdgeRoutes.Clear(); foreach (var edge in Graph.Edges) { EdgeRoutes.Add(edge, ComputeSingle(edge)); } }
public override Point[] ComputeSingle(TEdge edge) { BundleEdges(_graph, new List <TEdge>() { edge }); return(EdgeRoutes.ContainsKey(edge) ? EdgeRoutes[edge] : null); }
/// <summary> /// Bundles specified edges. Shapes of all the other edges remain the same, /// so this method is faster than the one for bundling all edges, but also produces less optimal layout. /// </summary> /// /// <param name="graph"> /// Parent graph of the edge set /// </param> /// /// <param name="edges"> /// Edges that should be bundled /// </param> /// /// <param name="rectangle"> /// Rectangle in which the graph is laid out. /// Control points of bundled edges should not fall outside of this rectangle. /// </param> public void BundleEdges(TGraph graph, IEnumerable <TEdge> edges) { directed = true; AddAllExistingData(graph.Edges); AddEdgeDataForMovedEdges(edges); FindCompatibleEdges(movedEdgeGroupData); ResetMovedEdges(); for (var i = 0; i < iterations; i++) { MoveControlPoints(movedEdgeGroupData); } for (var i = 0; i < 5; i++) { cooldown *= 0.5f; MoveControlPoints(movedEdgeGroupData); } cooldown = 1f; if (straightening > 0) { StraightenEdgesInternally(movedEdgeGroupData, straightening); } foreach (var e in edges) { EdgeGroupData ed; var key = new KeyPair(e.Source.ID, e.Target.ID); movedEdgeGroupData.TryGetValue(key, out ed); if (ed != null) { var list2 = ed.controlPoints.ToList(); //Point p1 = GeometryHelper.GetEdgeEndpointOnRectangle(VertexPositions[e.Source], VertexSizes[e.Source], list2.First()); //Point p2 = GeometryHelper.GetEdgeEndpointOnRectangle(VertexPositions[e.Target], VertexSizes[e.Target], list2.Last()); //list2.Insert(0, p1); list2.Add(p2); if (list2.Count > 0) { list2.Insert(0, list2.First()); list2.Add(list2.Last()); } if (EdgeRoutes.ContainsKey(e)) { EdgeRoutes[e] = list2.ToArray(); } else { EdgeRoutes.Add(e, list2.ToArray()); } } //e.SetValue(ReservedMetadataKeys.PerEdgeIntermediateCurvePoints, ed.controlPoints); } }
/// <inheritdoc /> public override void Calculate() { var topLeft = new Point(double.PositiveInfinity, double.PositiveInfinity); var bottomRight = new Point(double.NegativeInfinity, double.NegativeInfinity); foreach (TVertex vertex in Graph.Vertices) { Point pos = Positions[vertex]; Size size = Sizes[vertex]; topLeft.X = Math.Min(pos.X - size.Width / 2.0, topLeft.X); topLeft.Y = Math.Min(pos.Y - size.Height / 2.0, topLeft.Y); bottomRight.X = Math.Max(pos.X + size.Width / 2.0, bottomRight.X); bottomRight.Y = Math.Max(pos.Y + size.Height / 2.0, bottomRight.Y); } foreach (TEdge edge in Graph.Edges) { if (!EdgeRoutes.TryGetValue(edge, out Point[] routePoints) ||
public override void Calculate() { Point topLeft = new Point(double.PositiveInfinity, double.PositiveInfinity); Point bottomRight = new Point(double.NegativeInfinity, double.NegativeInfinity); foreach (var v in Graph.Vertices) { Point p = Positions[v]; Size s = Sizes[v]; topLeft.X = Math.Min(p.X - s.Width / 2.0, topLeft.X); topLeft.Y = Math.Min(p.Y - s.Height / 2.0, topLeft.Y); bottomRight.X = Math.Max(p.X + s.Width / 2.0, bottomRight.X); bottomRight.Y = Math.Max(p.Y + s.Height / 2.0, bottomRight.Y); } foreach (var e in Graph.Edges) { Point[] routePoints = null; if (!EdgeRoutes.TryGetValue(e, out routePoints) || routePoints == null || routePoints.Length == 0) { continue; } for (int i = 0; i < routePoints.Length; i++) { Point p = routePoints[i]; topLeft.X = Math.Min(p.X, topLeft.X); topLeft.Y = Math.Min(p.Y, topLeft.Y); bottomRight.X = Math.Max(p.X, bottomRight.X); bottomRight.Y = Math.Max(p.Y, bottomRight.Y); } } Vector layoutAreaSize = bottomRight - topLeft; Area = layoutAreaSize.LengthSquared; Ratio = layoutAreaSize.X / layoutAreaSize.Y; }
public override void Compute(CancellationToken cancellationToken) { foreach (var edge in Graph.Edges) { var sourcePosition = VertexPositions[edge.Source]; var targetPosition = VertexPositions[edge.Target]; var sourceSize = VertexSizes[edge.Source]; var targetSize = VertexSizes[edge.Target]; if (sourcePosition.X != targetPosition.X) { EdgeRoutes.Add( edge, new[] { new Point(0, 0), new Point(targetPosition.X + targetSize.Width / 2, sourcePosition.Y + sourceSize.Height / 2), new Point(0, 0) }); } } }
private void EdgeRoutingTest(TEdge ctrl, CancellationToken cancellationToken) { //bad edge data check if (ctrl.Source.ID == -1 || ctrl.Target.ID == -1) { throw new GX_InvalidDataException("SimpleEdgeRouting() -> You must assign unique ID for each vertex to use SimpleER algo!"); } if (ctrl.Source.ID == ctrl.Target.ID || !VertexSizes.ContainsKey(ctrl.Source) || !VertexSizes.ContainsKey(ctrl.Target)) { return; } var ss = VertexSizes[ctrl.Source]; var es = VertexSizes[ctrl.Target]; var startPoint = new Point(ss.X + ss.Width * 0.5, ss.Y + ss.Height * 0.5); var endPoint = new Point(es.X + es.Width * 0.5, es.Y + es.Height * 0.5); if (startPoint == endPoint) { return; } var originalSizes = getSizesCollection(ctrl, endPoint); var checklist = new Dictionary <TVertex, KeyValuePair <TVertex, Rect> >(originalSizes); var leftSizes = new Dictionary <TVertex, KeyValuePair <TVertex, Rect> >(originalSizes); var tempList = new List <Point>(); tempList.Add(startPoint); bool haveIntersections = true; //while we have some intersections - proceed while (haveIntersections) { var curDrawback = drawback_distance; while (true) { cancellationToken.ThrowIfCancellationRequested(); var item = checklist.Keys.FirstOrDefault(); //set last route point as current start point startPoint = tempList.Last(); if (item == null) { //checked all vertices and no intersection was found - quit haveIntersections = false; break; } else { var r = originalSizes[item].Value; Point checkpoint; //check for intersection point. if none found - remove vertex from checklist if (GetIntersectionPoint(r, startPoint, endPoint, out checkpoint) == -1) { checklist.Remove(item); continue; } var mainVector = new Vector(endPoint.X - startPoint.X, endPoint.Y - startPoint.Y); double X = 0; double Y = 0; //calculate drawback X coordinate if (startPoint.X == checkpoint.X || Math.Abs(startPoint.X - checkpoint.X) < curDrawback) { X = startPoint.X; } else if (startPoint.X < checkpoint.X) { X = checkpoint.X - curDrawback; } else { X = checkpoint.X + curDrawback; } //calculate drawback Y coordinate if (startPoint.Y == checkpoint.Y || Math.Abs(startPoint.Y - checkpoint.Y) < curDrawback) { Y = startPoint.Y; } else if (startPoint.Y < checkpoint.Y) { Y = checkpoint.Y - curDrawback; } else { Y = checkpoint.Y + curDrawback; } //set drawback checkpoint checkpoint = new Point(X, Y); bool isStartPoint = checkpoint == startPoint; bool routeFound = false; bool viceversa = false; int counter = 1; var joint = new Point(); bool?blocked_direction = null; while (!routeFound) { cancellationToken.ThrowIfCancellationRequested(); //choose opposite vector side each cycle var signedDistance = viceversa ? side_distance : -side_distance; //get new point coordinate joint = new Point( checkpoint.X + signedDistance * counter * (mainVector.Y / mainVector.Length), checkpoint.Y - signedDistance * counter * (mainVector.X / mainVector.Length)); //now check if new point is in some other vertex var iresult = false; var forcedBreak = false; if (originalSizes.Any(sz => sz.Value.Value.Contains(joint))) { iresult = true; //block this side direction if (blocked_direction == null) { blocked_direction = viceversa; } else { //both sides blocked - need to drawback forcedBreak = true; } } if (forcedBreak) { break; } //get vector intersection if its ok if (!iresult) { iresult = IsIntersected(r, joint, endPoint); } //if no vector intersection - we've found it! if (!iresult) { routeFound = true; blocked_direction = null; } else { //still have an intersection with current vertex haveIntersections = true; //skip point search if too many attempts was made (bad logic hack) if (counter > 300) { break; } counter++; //switch vector search side if (blocked_direction == null || (blocked_direction == viceversa)) { viceversa = !viceversa; } } } //if blocked and this is not start point (nowhere to drawback) - then increase drawback distance if (blocked_direction != null && !isStartPoint) { //search has been blocked - need to drawback curDrawback += drawback_distance; } else { //add new route point if we found it // if(routeFound) tempList.Add(joint); leftSizes.Remove(item); } } //remove currently evaded obstacle vertex from the checklist checklist.Remove(item); } //assign possible left vertices as a new checklist if any intersections was found if (haveIntersections) { checklist = new Dictionary <TVertex, KeyValuePair <TVertex, Rect> >(leftSizes); } } //finally, add an end route point tempList.Add(endPoint); if (EdgeRoutes.ContainsKey(ctrl)) { EdgeRoutes[ctrl] = tempList.Count > 2 ? tempList.ToArray() : null; } else { EdgeRoutes.Add(ctrl, tempList.Count > 2 ? tempList.ToArray() : null); } }
public override Point[] ComputeSingle(TEdge edge) { EdgeRoutingTest(edge, CancellationToken.None); return(EdgeRoutes.ContainsKey(edge) ? EdgeRoutes[edge] : null); }
/// <inheritdoc /> public override void Calculate() { TEdge[] edges = Graph.Edges.ToArray(); var edgePoints = new List <Point> [edges.Length]; // Create the points of the edges for (int i = 0; i < edges.Length; ++i) { TEdge edge = edges[i]; List <Point> points = EdgeRoutes.TryGetValue(edge, out Point[] route) && route != null && route.Length > 0 ? new List <Point>(route.Length + 2) : new List <Point>(2); points.Add(Positions[edge.Source]); if (route != null && route.Length > 0) { points.AddRange(route); } points.Add(Positions[edge.Target]); edgePoints[i] = points; for (int j = 1; j < points.Count; ++j) { double length = (points[j] - points[j - 1]).Length; MinimumEdgeLength = Math.Min(MinimumEdgeLength, length); MaximumEdgeLength = Math.Max(MaximumEdgeLength, length); AverageEdgeLength += length; } } // Check the crosses for (int i = 0; i < edges.Length - 1; ++i) { for (int j = i + 1; j < edges.Length; ++j) { List <Point> edgePoints1 = edgePoints[i]; List <Point> edgePoints2 = edgePoints[j]; for (int ii = 0; ii < edgePoints1.Count - 1; ++ii) { Point pA = edgePoints1[ii]; Point pB = edgePoints1[ii + 1]; for (int jj = 0; jj < edgePoints2.Count - 1; ++jj) { Point pC = edgePoints2[jj]; Point pD = edgePoints2[jj + 1]; if (pB.Equals(pC) || pA.Equals(pC) || pA.Equals(pD) || pB.Equals(pD)) { continue; // Ignore if source and/or target are the same } // [AB] double xA = pA.X; double yA = pA.Y; double xB = pB.X; double yB = pB.Y; // [CD] double xC = pC.X; double yC = pC.Y; double xD = pD.X; double yD = pD.Y; // The edges crosses each other bool segmentCrossing = ((xC - xA) * (yB - yA) + (yC - yA) * (xA - xB) < 0) ^ ((xD - xA) * (yB - yA) + (yD - yA) * (xA - xB) < 0) && ((xA - xC) * (yD - yC) + (yA - yC) * (xC - xD) < 0) ^ ((xB - xC) * (yD - yC) + (yB - yC) * (xC - xD) < 0); if (segmentCrossing) { ++CrossCount; } } } } } }
public override void Calculate() { var edges = Graph.Edges.ToArray(); var edgePoints = new List <Point> [edges.Length]; int segmentCount = 0; //create the points of the edges for (int i = 0; i < edges.Length - 1; i++) { var edge = edges[i]; Point[] route = null; List <Point> points = null; if (EdgeRoutes.TryGetValue(edge, out route) && route != null && route.Length > 0) { points = new List <Point>(route.Length + 2); } else { points = new List <Point>(2); } points.Add(Positions[edge.Source]); if (route != null && route.Length > 0) { points.AddRange(route); } points.Add(Positions[edge.Target]); for (int j = 0; j < points.Count - 1; j++) { double length = (points[j] - points[j - 1]).Length; MinimumEdgeLength = Math.Min(MinimumEdgeLength, length); MaximumEdgeLength = Math.Max(MaximumEdgeLength, length); AverageEdgeLength += length; segmentCount += 1; } } //check the crosses for (int i = 0; i < edges.Length - 1; i++) { for (int j = i + 1; j < edges.Length; j++) { List <Point> edgePoints1 = edgePoints[i]; List <Point> edgePoints2 = edgePoints[j]; for (int ii = 0; ii < edgePoints1.Count - 1; ii++) { var p11 = edgePoints1[ii]; var p12 = edgePoints1[ii + 1]; if (p12.X < p11.X) { Point p = p12; p12 = p11; p11 = p; } for (int jj = 0; jj < edgePoints2.Count - 1; jj++) { var p21 = edgePoints2[jj]; var p22 = edgePoints2[jj + 1]; if (p22.X < p21.X) { Point p = p22; p22 = p21; p21 = p22; } p11.X = p21.X = Math.Max(p11.X, p21.X); p12.X = p22.X = Math.Min(p12.X, p22.X); if ((p11.Y - p21.Y) * (p12.Y - p22.Y) < 0) { //the edges crosses each other CrossCount += 1; Vector v1 = p11 - p12; Vector v2 = p21 - p22; double angle = Math.Acos(Math.Abs((v1.X * v2.X + v1.Y * v2.Y) / (v1.Length * v2.Length))); MinimumAngle = Math.Min(MinimumAngle, angle); MaximumAngle = Math.Max(MaximumAngle, angle); AverageAngle += angle; } } } } } AverageAngle /= segmentCount; AverageEdgeLength /= segmentCount; }