/// <summary> /// Automaticaly update edge label position /// </summary> public virtual void UpdatePosition() { if (double.IsNaN(DesiredSize.Width) || DesiredSize.Width == 0) { return; } if (EdgeControl == null) { return; } if (EdgeControl.Source == null || EdgeControl.Target == null) { Debug.WriteLine("EdgeLabelControl_LayoutUpdated() -> Got empty edgecontrol!"); return; } //if hidden if (Visibility != Visibility.Visible) { return; } if (EdgeControl.IsSelfLooped) { var idesiredSize = DesiredSize; var pt = EdgeControl.Source.GetCenterPosition(); SetSelfLoopedSize(pt, idesiredSize); Arrange(LastKnownRectSize); return; } var p1 = EdgeControl.SourceConnectionPoint.GetValueOrDefault(); var p2 = EdgeControl.TargetConnectionPoint.GetValueOrDefault(); double edgeLength = 0; var routingInfo = EdgeControl.Edge as IRoutingInfo; if (routingInfo != null) { var routePoints = routingInfo.RoutingPoints == null ? null : routingInfo.RoutingPoints.ToWindows(); if (routePoints == null || routePoints.Length == 0) { // the edge is a single segment (p1,p2) edgeLength = GetLabelDistance(MathHelper.GetDistanceBetweenPoints(p1, p2)); } else { // the edge has one or more segments // compute the total length of all the segments edgeLength = 0; var rplen = routePoints.Length; for (var i = 0; i <= rplen; ++i) { if (i == 0) { edgeLength += MathHelper.GetDistanceBetweenPoints(p1, routePoints[0]); } else if (i == rplen) { edgeLength += MathHelper.GetDistanceBetweenPoints(routePoints[rplen - 1], p2); } else { edgeLength += MathHelper.GetDistanceBetweenPoints(routePoints[i - 1], routePoints[i]); } } // find the line segment where the half distance is located edgeLength = GetLabelDistance(edgeLength); var newp1 = p1; var newp2 = p2; for (var i = 0; i <= rplen; ++i) { double lengthOfSegment; if (i == 0) { lengthOfSegment = MathHelper.GetDistanceBetweenPoints(newp1 = p1, newp2 = routePoints[0]); } else if (i == rplen) { lengthOfSegment = MathHelper.GetDistanceBetweenPoints(newp1 = routePoints[rplen - 1], newp2 = p2); } else { lengthOfSegment = MathHelper.GetDistanceBetweenPoints(newp1 = routePoints[i - 1], newp2 = routePoints[i]); } if (lengthOfSegment >= edgeLength) { break; } edgeLength -= lengthOfSegment; } // redefine our edge points p1 = newp1; p2 = newp2; } } // The label control should be laid out on a rectangle, in the middle of the edge var angleBetweenPoints = MathHelper.GetAngleBetweenPoints(p1, p2); var desiredSize = DesiredSize; bool flipAxis = p1.X > p2.X; // Flip axis if source is "after" target // Calculate the center point of the edge var centerPoint = new Point(p1.X + edgeLength * Math.Cos(angleBetweenPoints), p1.Y - edgeLength * Math.Sin(angleBetweenPoints)); if (EdgeControl.AlignLabelsToEdges) { // If we're aligning labels to the edges make sure add the label vertical offset var yEdgeOffset = EdgeControl.LabelVerticalOffset; if (FlipOnRotation && flipAxis && !EdgeControl.IsParallel) // If we've flipped axis, move the offset to the other side of the edge { yEdgeOffset = -yEdgeOffset; } // Adjust offset for rotation. Remember, the offset is perpendicular from the edge tangent. // Slap on 90 degrees to the angle between the points, to get the direction of the offset. centerPoint.Y -= yEdgeOffset * Math.Sin(angleBetweenPoints + Math.PI / 2); centerPoint.X += yEdgeOffset * Math.Cos(angleBetweenPoints + Math.PI / 2); // Angle is in degrees Angle = -angleBetweenPoints * 180 / Math.PI; if (flipAxis) { Angle += 180; // Reorient the label so that it's always "pointing north" } } UpdateFinalPosition(centerPoint, desiredSize); Arrange(LastKnownRectSize); }
/// <summary> /// Create and apply edge path using calculated ER parameters stored in edge /// </summary> /// <param name="useCurrentCoords">Use current vertices coordinates or final coorfinates (for.ex if move animation is active final coords will be its destination)</param> /// <param name="externalRoutingPoints">Provided custom routing points will be used instead of stored ones.</param> /// <param name="updateLabel">Should edge label be updated in this pass</param> public virtual void PrepareEdgePath(bool useCurrentCoords = false, Measure.Point[] externalRoutingPoints = null, bool updateLabel = true) { //do not calculate invisible edges if ((Visibility != Visibility.Visible && !IsHiddenEdgesUpdated) && Source == null || Target == null || ManualDrawing || !IsTemplateLoaded) { return; } #region Get the inputs //get the size of the source var sourceSize = new Size { Width = Source.ActualWidth, Height = Source.ActualHeight }; if (CustomHelper.IsInDesignMode(this)) { sourceSize = new Size(80, 20); } //get the position center of the source var sourcePos = new Point { X = (useCurrentCoords ? GraphAreaBase.GetX(Source) : GraphAreaBase.GetFinalX(Source)) + sourceSize.Width * .5, Y = (useCurrentCoords ? GraphAreaBase.GetY(Source) : GraphAreaBase.GetFinalY(Source)) + sourceSize.Height * .5 }; //get the size of the target var targetSize = new Size { Width = Target.ActualWidth, Height = Target.ActualHeight }; if (CustomHelper.IsInDesignMode(this)) { targetSize = new Size(80, 20); } //get the position center of the target var targetPos = new Point { X = (useCurrentCoords ? GraphAreaBase.GetX(Target) : GraphAreaBase.GetFinalX(Target)) + targetSize.Width * .5, Y = (useCurrentCoords ? GraphAreaBase.GetY(Target) : GraphAreaBase.GetFinalY(Target)) + targetSize.Height * .5 }; var routedEdge = Edge as IRoutingInfo; if (routedEdge == null) { throw new GX_InvalidDataException("Edge must implement IRoutingInfo interface"); } //get the route informations var routeInformation = externalRoutingPoints ?? routedEdge.RoutingPoints; // Get the TopLeft position of the Source Vertex. var sourcePos1 = new Point { X = (useCurrentCoords ? GraphAreaBase.GetX(Source) : GraphAreaBase.GetFinalX(Source)), Y = (useCurrentCoords ? GraphAreaBase.GetY(Source) : GraphAreaBase.GetFinalY(Source)) }; // Get the TopLeft position of the Target Vertex. var targetPos1 = new Point { X = (useCurrentCoords ? GraphAreaBase.GetX(Target) : GraphAreaBase.GetFinalX(Target)), Y = (useCurrentCoords ? GraphAreaBase.GetY(Target) : GraphAreaBase.GetFinalY(Target)) }; var hasEpSource = EdgePointerForSource != null; var hasEpTarget = EdgePointerForTarget != null; #endregion //if self looped edge if (IsSelfLooped) { PrepareSelfLoopedEdge(sourcePos1); return; } //check if we have some edge route data var hasRouteInfo = routeInformation != null && routeInformation.Length > 1; //calculate source and target edge attach points if (RootArea != null && !hasRouteInfo && RootArea.EnableParallelEdges && ParallelEdgeOffset != 0) { sourcePos = GetParallelOffset(Source, Target, ParallelEdgeOffset); targetPos = GetParallelOffset(Target, Source, -ParallelEdgeOffset); } /* Rectangular shapes implementation by bleibold */ var gEdge = Edge as IGraphXCommonEdge; Point p1; Point p2; //calculate edge source (p1) and target (p2) endpoints based on different settings if (gEdge?.SourceConnectionPointId != null) { var sourceCp = Source.GetConnectionPointById(gEdge.SourceConnectionPointId.Value, true); if (sourceCp == null) { throw new GX_ObjectNotFoundException(string.Format("Can't find source vertex VCP by edge source connection point Id({1}) : {0}", Source, gEdge.SourceConnectionPointId)); } if (sourceCp.Shape == VertexShape.None) { p1 = sourceCp.RectangularSize.Center(); } else { var targetCpPos = gEdge.TargetConnectionPointId.HasValue ? Target.GetConnectionPointById(gEdge.TargetConnectionPointId.Value, true).RectangularSize.Center() : (hasRouteInfo ? routeInformation[1].ToWindows() : (targetPos)); p1 = GeometryHelper.GetEdgeEndpoint(sourceCp.RectangularSize.Center(), sourceCp.RectangularSize, targetCpPos, sourceCp.Shape); } } else { p1 = GeometryHelper.GetEdgeEndpoint(sourcePos, new SysRect(sourcePos1, sourceSize), (hasRouteInfo ? routeInformation[1].ToWindows() : (targetPos)), Source.VertexShape); } if (gEdge?.TargetConnectionPointId != null) { var targetCp = Target.GetConnectionPointById(gEdge.TargetConnectionPointId.Value, true); if (targetCp == null) { throw new GX_ObjectNotFoundException(string.Format("Can't find target vertex VCP by edge target connection point Id({1}) : {0}", Target, gEdge.TargetConnectionPointId)); } if (targetCp.Shape == VertexShape.None) { p2 = targetCp.RectangularSize.Center(); } else { var sourceCpPos = gEdge.SourceConnectionPointId.HasValue ? Source.GetConnectionPointById(gEdge.SourceConnectionPointId.Value, true).RectangularSize.Center() : hasRouteInfo ? routeInformation[routeInformation.Length - 2].ToWindows() : (sourcePos); p2 = GeometryHelper.GetEdgeEndpoint(targetCp.RectangularSize.Center(), targetCp.RectangularSize, sourceCpPos, targetCp.Shape); } } else { p2 = GeometryHelper.GetEdgeEndpoint(targetPos, new SysRect(targetPos1, targetSize), hasRouteInfo ? routeInformation[routeInformation.Length - 2].ToWindows() : (sourcePos), Target.VertexShape); } SourceConnectionPoint = p1; TargetConnectionPoint = p2; Linegeometry = new PathGeometry(); PathFigure lineFigure; //if we have route and route consist of 2 or more points if (RootArea != null && hasRouteInfo) { //replace start and end points with accurate ones var routePoints = routeInformation.ToWindows().ToList(); routePoints.Remove(routePoints.First()); routePoints.Remove(routePoints.Last()); routePoints.Insert(0, p1); routePoints.Add(p2); if (externalRoutingPoints == null && routedEdge.RoutingPoints != null) { routedEdge.RoutingPoints = routePoints.ToArray().ToGraphX(); } if (RootArea.EdgeCurvingEnabled) { var oPolyLineSegment = GeometryHelper.GetCurveThroughPoints(routePoints.ToArray(), 0.5, RootArea.EdgeCurvingTolerance); if (hasEpTarget) { UpdateTargetEpData(oPolyLineSegment.Points[oPolyLineSegment.Points.Count - 1], oPolyLineSegment.Points[oPolyLineSegment.Points.Count - 2]); oPolyLineSegment.Points.RemoveAt(oPolyLineSegment.Points.Count - 1); } if (hasEpSource) { UpdateSourceEpData(oPolyLineSegment.Points.First(), oPolyLineSegment.Points[1]); oPolyLineSegment.Points.RemoveAt(0); } lineFigure = GeometryHelper.GetPathFigureFromPathSegments(routePoints[0], true, true, oPolyLineSegment); #if WPF //freeze and create resulting geometry GeometryHelper.TryFreeze(oPolyLineSegment); #endif } else { if (hasEpSource) { routePoints[0] = routePoints[0].Subtract(UpdateSourceEpData(routePoints.First(), routePoints[1])); } if (hasEpTarget) { routePoints[routePoints.Count - 1] = routePoints[routePoints.Count - 1].Subtract(UpdateTargetEpData(p2, routePoints[routePoints.Count - 2])); } // Reverse the path if specified. if (gEdge.ReversePath) { routePoints.Reverse(); } var pcol = new PointCollection(); routePoints.ForEach(a => pcol.Add(a)); lineFigure = new PathFigure { StartPoint = p1, Segments = new PathSegmentCollection { new PolyLineSegment { Points = pcol } }, IsClosed = false }; } } else // no route defined { bool allowUpdateEpDataToUnsuppress = true; //check for hide only if prop is not 0 if (HideEdgePointerByEdgeLength != 0d) { if (MathHelper.GetDistanceBetweenPoints(p1, p2) <= HideEdgePointerByEdgeLength) { EdgePointerForSource?.Suppress(); EdgePointerForTarget?.Suppress(); allowUpdateEpDataToUnsuppress = false; } else { EdgePointerForSource?.UnSuppress(); EdgePointerForTarget?.UnSuppress(); } } if (hasEpSource) { p1 = p1.Subtract(UpdateSourceEpData(p1, p2, allowUpdateEpDataToUnsuppress)); } if (hasEpTarget) { p2 = p2.Subtract(UpdateTargetEpData(p2, p1, allowUpdateEpDataToUnsuppress)); } lineFigure = new PathFigure { StartPoint = gEdge.ReversePath ? p2 : p1, Segments = new PathSegmentCollection { new LineSegment() { Point = gEdge.ReversePath ? p1 : p2 } }, IsClosed = false }; } ((PathGeometry)Linegeometry).Figures.Add(lineFigure); #if WPF GeometryHelper.TryFreeze(lineFigure); GeometryHelper.TryFreeze(Linegeometry); #endif if (ShowLabel && EdgeLabelControl != null && _updateLabelPosition && updateLabel) { EdgeLabelControl.UpdatePosition(); } }