/// <summary> /// Reconstructs the path. /// </summary> /// <param name="toPoint">To point.</param> /// <param name="reachedPoints">The reached points.</param> /// <returns>GraphPoint[].</returns> private static GraphPoint[] reconstructPath(GraphPoint toPoint, Dictionary <GraphPoint, GraphPoint> reachedPoints) { GraphPoint currentPoint; if (!reachedPoints.TryGetValue(toPoint, out currentPoint)) { //path hasn't been found in current graph return(null); } var path = new List <GraphPoint>(); path.Add(toPoint); //trace path back from reached table while (currentPoint != null) { path.Add(currentPoint); currentPoint = reachedPoints[currentPoint]; } path.Reverse(); return(path.ToArray()); }
/// <summary> /// Get contact points defined for given item /// <remarks>Note that because of simple getting contact points we store them as first four</remarks>. /// </summary> /// <param name="item">Item which points are generated.</param> /// <returns>Generated points.</returns> private IEnumerable <GraphPoint> generatePoints(DiagramItem item) { var span = SceneNavigator.GetSpan(item, item.GlobalPosition); var topLeft = new GraphPoint(span.TopLeft, TopLeftCorner, item); var topRight = new GraphPoint(span.TopRight, TopRightCorner, item); var bottomLeft = new GraphPoint(span.BottomLeft, BottomLeftCorner, item); var bottomRight = new GraphPoint(span.BottomRight, BottomRightCorner, item); topLeft.SetEdgeStatus(topRight); topLeft.SetEdgeStatus(bottomLeft); bottomRight.SetEdgeStatus(topRight); bottomRight.SetEdgeStatus(bottomLeft); var points = new List <GraphPoint>(); points.Add(topLeft); points.Add(topRight); points.Add(bottomLeft); points.Add(bottomRight); generateConnectorPoints(item.TopConnectorDrawings, ConnectorAlign.Top, item, points); generateConnectorPoints(item.LeftConnectorDrawings, ConnectorAlign.Left, item, points); generateConnectorPoints(item.BottomConnectorDrawings, ConnectorAlign.Bottom, item, points); generateConnectorPoints(item.RightConnectorDrawings, ConnectorAlign.Right, item, points); return(points); }
/// <summary> /// Try to add edge between given points if possible. /// </summary> /// <param name="fromCandidate">Point where edge should start.</param> /// <param name="toCandidate">Point where edge should end.</param> /// <param name="target">Target that is not considered to be an obstacle.</param> /// <param name="obstacle">Obstacle if any is present between from and to candidate, <c>null</c> otherwise.</param> /// <returns><c>true</c> if edge can be added, <c>false</c> otherwise.</returns> private bool tryAddEdge(GraphPoint fromCandidate, GraphPoint toCandidate, DiagramItem target, out DiagramItem obstacle) { obstacle = null; if ( !fromCandidate.IsInAngle(toCandidate) || !toCandidate.IsInAngle(fromCandidate) ) { //edge is not possible between given points return(false); } if (fromCandidate.HasEdgeStatus(toCandidate)) { //edge already exists or has been forbidden earlier return(false); } obstacle = _navigator.GetFirstObstacle(fromCandidate.Position, toCandidate.Position); var isEdgeValid = obstacle == null || obstacle == target; fromCandidate.SetEdgeStatus(toCandidate, isEdgeValid); return(isEdgeValid); }
/// <summary> /// Square part of distance from current point to given point /// </summary> /// <param name="other">Other point which distance is determined</param> /// <returns>Square part of distance</returns> internal double DistanceTo(GraphPoint other) { var oPosition = other.Position; var xDiff = Position.X - oPosition.X; var yDiff = Position.Y - oPosition.Y; return(Math.Sqrt(xDiff * xDiff + yDiff * yDiff)); }
/// <summary> /// Try to enqueue point that is candidate of from points /// if it hasn't already been enqueued. /// </summary> /// <param name="fromCandidate">Candidate point.</param> private void tryEnqueue(GraphPoint fromCandidate) { if (!_processed.Add(fromCandidate)) { //point is already processed return; } _fromCandidates.Enqueue(fromCandidate); }
/// <summary> /// Enqueue edge between from candidate and given obstacle. /// </summary> /// <param name="fromCandidate">Candidate from which edge is enqueued.</param> /// <param name="obstacle">Obstacle which will be connected.</param> private void enqueueWithObstacleEdges(GraphPoint fromCandidate, DiagramItem obstacle) { if (obstacle == null) { //there is no obstacle which edges can be enqueued return; } var contactPoints = getContactPoints(obstacle); foreach (var contactPoint in contactPoints) { DiagramItem contactObstacle; if (tryAddEdge(fromCandidate, contactPoint, obstacle, out contactObstacle)) { tryEnqueue(contactPoint); } else { enqueueWithObstacleEdges(fromCandidate, contactObstacle); } } }
/// <summary> /// Gets the input slots. /// </summary> /// <param name="connectorIndex">Index of the connector.</param> /// <param name="connectorsCount">The connectors count.</param> /// <param name="connector">The connector.</param> /// <param name="item">The item.</param> /// <param name="contactPoints">The contact points.</param> /// <returns>GraphPoint[].</returns> /// <exception cref="System.NotSupportedException">Connector align + connectorAlign</exception> private GraphPoint[] getInputSlots(int connectorIndex, int connectorsCount, ConnectorDrawing connector, DiagramItem item, List <GraphPoint> contactPoints) { var connectorAlign = connector.Align; var span = _navigator.GetSpan(item); //find positions of slots for inputs according to connector align Point slot1End, slot1Start; Point slot2End; ViewAngle slot1View; ViewAngle slot2View; GraphPoint slot1Contact; GraphPoint slot2Contact; //slots has to be parallel with same length switch (connectorAlign) { case ConnectorAlign.Top: slot1Contact = contactPoints[2]; slot2Contact = contactPoints[3]; slot1View = TopLeftCorner; slot2View = TopRightCorner; slot1End = span.TopLeft; slot2End = span.TopRight; slot1Start = new Point(slot1End.X, slot1End.Y + item.TopConnectors.DesiredSize.Height); break; case ConnectorAlign.Bottom: slot1Contact = contactPoints[0]; slot2Contact = contactPoints[1]; slot1View = BottomLeftCorner; slot2View = BottomRightCorner; slot1End = span.BottomLeft; slot2End = span.BottomRight; slot1Start = new Point(slot1End.X, slot1End.Y - item.BottomConnectors.DesiredSize.Height); break; case ConnectorAlign.Left: slot1Contact = contactPoints[1]; slot2Contact = contactPoints[3]; slot1View = TopLeftCorner; slot2View = BottomLeftCorner; slot1End = span.TopLeft; slot2End = span.BottomLeft; slot1Start = new Point(slot1End.X + item.LeftConnectors.DesiredSize.Width, slot1End.Y); break; case ConnectorAlign.Right: slot1Contact = contactPoints[0]; slot2Contact = contactPoints[2]; slot1View = TopRightCorner; slot2View = BottomRightCorner; slot1End = span.TopRight; slot2End = span.BottomRight; slot1Start = new Point(slot1End.X - item.RightConnectors.DesiredSize.Width, slot1End.Y); break; default: throw new NotSupportedException("Connector align " + connectorAlign); } var slotVector = (slot1Start - slot1End) / (connectorsCount + 2); var slot1 = new GraphPoint(slot1End + slotVector * connectorIndex, slot1View, item); var slot2 = new GraphPoint(slot2End + slotVector * (connectorsCount - connectorIndex), slot2View, item); slot1.SetEdgeStatus(slot1Contact); slot2.SetEdgeStatus(slot2Contact); return(new[] { slot1, slot2 }); }
/// <summary> /// Set status for edge to given point /// </summary> /// <param name="point">Point which edge status will be set</param> /// <param name="status">Status that will be set</param> internal void SetEdgeStatus(GraphPoint point, bool status = true) { _edges[point] = status; point._edges[this] = status; }
/// <summary> /// Determine that edge status for given point is already available /// </summary> /// <param name="point">Point which defines tested edge</param> /// <returns><c>true</c> if edge status is available, <c>false</c> otherwise</returns> internal bool HasEdgeStatus(GraphPoint point) { return(_edges.ContainsKey(point)); }
/// <summary> /// Determine that current point has given point in view angle /// </summary> /// <param name="point">Point which presence in view angle is tested</param> /// <returns><c>true</c> if point is view angle, <c>false</c> otherwise</returns> internal bool IsInAngle(GraphPoint point) { return(View.IsInAngle(Position, point.Position)); }