private (SKPoint edgeSource, SKPoint edgeTarget) AddEdgePath(List <SKPoint> edgePath, Kaemika.Edge <Vertex> edge) { SKPoint source = layoutInfo.vertexPositions[edge.Source]; SKPoint target = layoutInfo.vertexPositions[edge.Target]; SKSize sourceSize = layoutInfo.vertexSizes[edge.Source]; SKSize targetSize = layoutInfo.vertexSizes[edge.Target]; if (layoutInfo.edgeRoutes == null) { layoutInfo.edgeRoutes = new Dictionary <Kaemika.Edge <Vertex>, SKPoint[]>(); } SKPoint[] route = (layoutInfo.edgeRoutes.ContainsKey(edge)) ? layoutInfo.edgeRoutes[edge] : new SKPoint[] { }; SKPoint initialTarget = (route.Length == 0) ? target : route[0]; SKPoint firstSource = PointOnRectangle(source, initialTarget, sourceSize.Width / 2, sourceSize.Height / 2); edgePath.Add(firstSource); SKPoint lastSource = firstSource; foreach (var nextTarget in route) { edgePath.Add(nextTarget); lastSource = nextTarget; } SKPoint lastTarget = PointOnRectangle(target, lastSource, targetSize.Width / 2, targetSize.Height / 2); SKPoint firstTarget = (route.Length == 0) ? lastTarget : initialTarget; if (!(edge.Target is Vertex_Routing)) { edgePath.Add(lastTarget); } return(firstSource, firstTarget); }
private void DrawSplineEdge(SKCanvas canvas, Kaemika.Edge <Vertex> edge, float nodeHeight, float textSize, SKColor color, Swipe swipe) { if (edge.Source is Vertex_Routing) { return; // this edge it will be drawn as part of another edge } List <SKPoint> edgePath = new List <SKPoint>(); Kaemika.Edge <Vertex> routedEdge = edge; (SKPoint firstSource, SKPoint firstTarget) = AddEdgePath(edgePath, routedEdge); while (routedEdge.Target is Vertex_Routing) { routedEdge = (routedEdge.Target as Vertex_Routing).toEdge; AddEdgePath(edgePath, routedEdge); } edgePath.Insert(0, edgePath[0]); // duplicate first point for spline SKPoint ultimate = edgePath[edgePath.Count - 1]; SKPoint penultimate = edgePath[edgePath.Count - 2]; edgePath.Insert(edgePath.Count, ultimate); // duplicate last point for spline List <SKPoint> controlPoints = ControlPoints(edgePath); SKPath path = AddBeziers(new SKPath(), controlPoints.ToArray(), swipe); using (var paint = new SKPaint()) { paint.TextSize = 10.0f; paint.IsAntialias = true; paint.Color = color; paint.IsStroke = true; canvas.DrawPath(path, paint); SKPoint arrowHeadBase = ultimate; if (routedEdge.Directed != Directed.No) // draw arrowhead on last routedEdge segment, update arrowHeadBase { VectorStd lineVector = VectorStd.DifferenceVector(ultimate, penultimate); float lineLength = lineVector.Length; // calculate point at base of arrowhead float arrowWidth = nodeHeight / 6; float tPointOnLine = (float)(arrowWidth / (2 * (Math.Tan(120) / 2) * lineLength)); VectorStd arrowReverseVector = -tPointOnLine * lineVector; arrowHeadBase = ultimate + arrowReverseVector; SKPoint arrowHeadMid = ultimate + (0.5F * arrowReverseVector); VectorStd normalVector = new VectorStd(-lineVector.Y, lineVector.X); float tNormal = arrowWidth / (2 * lineLength); SKPoint leftPoint = arrowHeadBase + tNormal * normalVector; SKPoint rightPoint = arrowHeadBase + -tNormal * normalVector; if (routedEdge.Directed == Directed.Solid) { var arrowPath = new SKPath(); paint.IsStroke = false; arrowPath.MoveTo(swipe % leftPoint); arrowPath.LineTo(swipe % ultimate); arrowPath.LineTo(swipe % rightPoint); arrowPath.Close(); canvas.DrawPath(arrowPath, paint); } if (routedEdge.Directed == Directed.Pointy) { var arrowPath = new SKPath(); paint.IsStroke = true; arrowPath.MoveTo(swipe % leftPoint); arrowPath.LineTo(swipe % ultimate); arrowPath.LineTo(swipe % rightPoint); canvas.DrawPath(arrowPath, paint); } if (routedEdge.Directed == Directed.Ball) { var arrowPath = new SKPath(); paint.IsStroke = false; canvas.DrawCircle(swipe % arrowHeadMid, swipe % (arrowReverseVector.Length / 2), paint); } } // if (routedEdge.Directed == Directed.Solid) { paint.IsStroke = false; canvas.DrawCircle(path.LastPoint, 20, paint); } // if (routedEdge.Directed == Directed.Pointy) { paint.IsStroke = true; canvas.DrawCircle(path.LastPoint, 20, paint); } if (edge.Label != null) // draw label on first routedEdge segment { var saveTextSize = paint.TextSize; paint.TextSize = swipe % textSize / 3; SKPoint labelTarget = (firstTarget == ultimate) ? arrowHeadBase : firstTarget; GraphLayout.CanvasDrawTextCentered(canvas, edge.Label, swipe % new SKPoint((firstSource.X + labelTarget.X) / 2, (firstSource.Y + labelTarget.Y) / 2), paint, true); paint.TextSize = saveTextSize; } } }
private void DrawEdge(SKCanvas canvas, Kaemika.Edge <Vertex> edge, float nodeHeight, float textSize, SKColor color, Swipe swipe) { bool spline = false; bool arc = false; using (var paint = new SKPaint()) { paint.TextSize = 10.0f; paint.IsAntialias = true; paint.Color = color; SKPoint source = layoutInfo.vertexPositions[edge.Source]; SKPoint target = layoutInfo.vertexPositions[edge.Target]; SKSize sourceSize = layoutInfo.vertexSizes[edge.Source]; SKSize targetSize = layoutInfo.vertexSizes[edge.Target]; if (layoutInfo.edgeRoutes == null) { layoutInfo.edgeRoutes = new Dictionary <Kaemika.Edge <Vertex>, SKPoint[]>(); } SKPoint[] route = (layoutInfo.edgeRoutes.ContainsKey(edge)) ? layoutInfo.edgeRoutes[edge] : new SKPoint[] { }; var routePath = new SKPath(); paint.IsStroke = true; SKPoint initialTarget = (route.Length == 0) ? target : route[0]; SKPoint firstSource = PointOnRectangle(source, initialTarget, sourceSize.Width / 2, sourceSize.Height / 2); routePath.MoveTo(swipe % firstSource); SKPoint lastSource = firstSource; foreach (var nextTarget in route) { if (spline) { (SKPoint control, SKPoint nextControl) = SplineControls(lastSource, nextTarget, new SKSize(textSize, textSize)); routePath.CubicTo(swipe % control, swipe % nextControl, swipe % nextTarget); } else { routePath.LineTo(swipe % nextTarget); } lastSource = nextTarget; } SKPoint lastTarget = PointOnRectangle(target, lastSource, targetSize.Width / 2, targetSize.Height / 2); SKPoint firstTarget = (route.Length == 0) ? lastTarget : initialTarget; if (spline) { (SKPoint control, SKPoint nextControl) = SplineControls(lastSource, lastTarget, new SKSize(textSize, textSize)); routePath.CubicTo(swipe % control, swipe % nextControl, swipe % lastTarget); } else if (arc && route.Length == 0) { routePath.ArcTo(swipe % lastSource, swipe % lastTarget, swipe % textSize); // see Postscript arct } else { routePath.LineTo(swipe % lastTarget); } canvas.DrawPath(routePath, paint); SKPoint arrowHeadBase = lastTarget; //SKPoint nextSource = source; //foreach (var nextTarget in route) { // if (nextSource == source) nextSource = PointOnRectangle(source, nextTarget, sourceSize.Width / 2, sourceSize.Height / 2); // canvas.DrawLine(swipe % nextSource, swipe % nextTarget, paint); // nextSource = nextTarget; //} //SKPoint lastSource = (nextSource != source) ? nextSource : PointOnRectangle(source, target, sourceSize.Width / 2, sourceSize.Height / 2); //SKPoint lastTarget = PointOnRectangle(target, lastSource, targetSize.Width / 2, targetSize.Height / 2); //canvas.DrawLine(swipe % lastSource, swipe % lastTarget, paint); //SKPoint pointOnLine = lastTarget; if (edge.Directed != Directed.No) // draw arrowhead, update arrowHeadBase { VectorStd lineVector = VectorStd.DifferenceVector(lastTarget, lastSource); float lineLength = lineVector.Length; // calculate point at base of arrowhead float arrowWidth = nodeHeight / 6; float tPointOnLine = (float)(arrowWidth / (2 * (Math.Tan(120) / 2) * lineLength)); arrowHeadBase = lastTarget + (-tPointOnLine * lineVector); VectorStd normalVector = new VectorStd(-lineVector.Y, lineVector.X); float tNormal = arrowWidth / (2 * lineLength); SKPoint leftPoint = arrowHeadBase + tNormal * normalVector; SKPoint rightPoint = arrowHeadBase + -tNormal * normalVector; if (edge.Directed == Directed.Solid) { var arrowPath = new SKPath(); paint.IsStroke = false; arrowPath.MoveTo(swipe % leftPoint); arrowPath.LineTo(swipe % lastTarget); arrowPath.LineTo(swipe % rightPoint); arrowPath.Close(); canvas.DrawPath(arrowPath, paint); } if (edge.Directed == Directed.Pointy) { var arrowPath = new SKPath(); paint.IsStroke = true; arrowPath.MoveTo(swipe % leftPoint); arrowPath.LineTo(swipe % lastTarget); arrowPath.LineTo(swipe % rightPoint); canvas.DrawPath(arrowPath, paint); } } if (edge.Label != null) // draw label { var saveTextSize = paint.TextSize; paint.TextSize = swipe % textSize / 3; SKPoint labelTarget = (route.Length == 0) ? arrowHeadBase : firstTarget; GraphLayout.CanvasDrawTextCentered(canvas, edge.Label, swipe % new SKPoint((firstSource.X + labelTarget.X) / 2, (firstSource.Y + labelTarget.Y) / 2), paint, true); paint.TextSize = saveTextSize; //var path = new SKPath(); paint.IsStroke = false; //path.MoveTo(swipe % firstSource); //path.LineTo(swipe % ((route.Length == 0) ? arrowHeadBase : firstTarget)); //path.Close(); // so the text wraps back around the closed single-line path //paint.TextSize = swipe % textSize / 3; //canvas.DrawTextOnPath(edge.Label, path, new SKPoint(paint.TextSize/2, -paint.TextSize/2), paint); } } }