public bool IntersectsAnyPU(MathCore.LineSegment segment, params AbstractProcessUnit[] exclusionList) { foreach (UIElement uie in Children) { ProcessUnitControl puc = uie as ProcessUnitControl; if (null == puc) { // Not a process unit control continue; } if (null != exclusionList) { bool goNext = false; foreach (AbstractProcessUnit excludeMe in exclusionList) { // See if we want to exclude this one if (object.ReferenceEquals(puc.ProcessUnit, excludeMe)) { goNext = true; break; } } if (goNext) { continue; } } // Build a rectangle for the control Point pt = new Point( (double)puc.GetValue(Canvas.LeftProperty), (double)puc.GetValue(Canvas.TopProperty)); MathCore.Rectangle r; if (double.IsNaN(puc.Width) || double.IsNaN(puc.Height) || 0.0 == puc.Width || 0.0 == puc.Height) { // Silverlight UI stuff can be funky so we have a condition to use // hard coded dimensions as opposed to getting them from the control r = MathCore.Rectangle.CreateFromCanvasRect(pt, 40.0, 40.0); } else { r = MathCore.Rectangle.CreateFromCanvasRect(pt, puc.Width, puc.Height); } if (r.GetIntersections(segment).Length > 0) { return(true); } } return(false); }
public double GetShortestDistanceFromLines(MathCore.Vector location) { if (0 == m_lines.Count) { // If there are no lines we'll say it's very far away return(double.MaxValue); } double d = double.MaxValue; foreach (Line line in m_lines) { MathCore.LineSegment ls = new MathCore.LineSegment( line.X1, line.Y1, line.X2, line.Y2); double tempD = ls.GetDistance(location); if (tempD < d) { d = tempD; } } return(d); }
/// <summary> /// Computes line segments for the stream lines that should be rendered. The first point (A) /// in the first segment will be the source location and the last point (B) in the last /// segment will be the destination location. The number of lines in the array can be any /// value greater than 1. /// </summary> private MathCore.LineSegment[] ComputeLineSegments(out MathCore.Vector midpoint, out MathCore.Vector sourceIconLocation) { MathCore.Vector s = (null == m_stream.Source) ? m_stream.SourceLocation : m_stream.Source.Location; MathCore.Vector d = (null == m_stream.Destination) ? m_stream.DestinationLocation : m_stream.Destination.Location; // Set the default source icon location. Will get changed below if need be sourceIconLocation = s; // Start with the simplest case of 1 straight line MathCore.LineSegment simplest = new MathCore.LineSegment( m_stream.SourceLocation, m_stream.DestinationLocation); // If it doesn't intersect any other process units then we'll use it if (!m_canvas.IntersectsAnyPU(simplest, m_stream.Source, m_stream.Destination)) { midpoint = (s + d) / 2.0; m_lastMidPoint = midpoint; if (null != m_stream.Source) { sourceIconLocation = s + (MathCore.Vector.Normalize(d - s) * 30.0); } return(new MathCore.LineSegment[] { simplest }); } // If that doesn't work, try two lines that make a 90 degree angle MathCore.Vector corner = new MathCore.Vector(s.X, d.Y); MathCore.LineSegment a = new MathCore.LineSegment(s, corner); MathCore.LineSegment b = new MathCore.LineSegment(corner, d); if (!m_canvas.IntersectsAnyPU(a, m_stream.Source, m_stream.Destination) && !m_canvas.IntersectsAnyPU(b, m_stream.Source, m_stream.Destination)) { // These lines will work midpoint = corner; m_lastMidPoint = midpoint; if (null != m_stream.Source) { sourceIconLocation = s + (MathCore.Vector.Normalize(a.Direction) * 30.0); } return(new MathCore.LineSegment[] { a, b }); } // Try the other variant corner = new MathCore.Vector(d.X, s.Y); a = new MathCore.LineSegment(s, corner); b = new MathCore.LineSegment(corner, d); if (!m_canvas.IntersectsAnyPU(a, m_stream.Source, m_stream.Destination) && !m_canvas.IntersectsAnyPU(b, m_stream.Source, m_stream.Destination)) { // These lines will work midpoint = corner; m_lastMidPoint = midpoint; if (null != m_stream.Source) { sourceIconLocation = s + (MathCore.Vector.Normalize(a.Direction) * 30.0); } return(new MathCore.LineSegment[] { a, b }); } // If we still don't have it then try a 3-line box double dx = Math.Abs(s.X - d.X); double dy = Math.Abs(s.Y - d.Y); if (dy > dx) { double xPos = Math.Min(s.X, d.X - 35.0); corner = new MathCore.Vector(xPos, s.Y); MathCore.Vector corner2 = new MathCore.Vector(xPos, d.Y); a = new MathCore.LineSegment(s, corner); b = new MathCore.LineSegment(corner, corner2); MathCore.LineSegment c = new MathCore.LineSegment(corner2, d); if (!m_canvas.IntersectsAnyPU(a, m_stream.Source, m_stream.Destination) && !m_canvas.IntersectsAnyPU(b, m_stream.Source, m_stream.Destination) && !m_canvas.IntersectsAnyPU(c, m_stream.Source, m_stream.Destination)) { // These lines will work midpoint = (corner + corner2) / 2.0; m_lastMidPoint = midpoint; if (null != m_stream.Source) { sourceIconLocation = s + (MathCore.Vector.Normalize(a.Direction) * 30.0); } return(new MathCore.LineSegment[] { a, b, c }); } } else { double yPos = Math.Min(s.Y, d.Y) - 35.0; corner = new MathCore.Vector(s.X, yPos); MathCore.Vector corner2 = new MathCore.Vector(d.X, yPos); a = new MathCore.LineSegment(s, corner); b = new MathCore.LineSegment(corner, corner2); MathCore.LineSegment c = new MathCore.LineSegment(corner2, d); if (!m_canvas.IntersectsAnyPU(a, m_stream.Source, m_stream.Destination) && !m_canvas.IntersectsAnyPU(b, m_stream.Source, m_stream.Destination) && !m_canvas.IntersectsAnyPU(c, m_stream.Source, m_stream.Destination)) { // These lines will work midpoint = (corner + corner2) / 2.0; m_lastMidPoint = midpoint; if (null != m_stream.Source) { sourceIconLocation = s + (MathCore.Vector.Normalize(a.Direction) * 30.0); } return(new MathCore.LineSegment[] { a, b, c }); } } // Out of options if we come here, so use the straight line midpoint = (s + d) / 2.0; m_lastMidPoint = midpoint; if (null != m_stream.Source) { sourceIconLocation = s + (MathCore.Vector.Normalize(d - s) * 30.0); } return(new MathCore.LineSegment[] { simplest }); }
/// <summary> /// Recomputes location of all relevant controls within the stream (endpoint icons, /// stream lines, etc.) /// </summary> public virtual void UpdateStreamLocation() { // Error check: we shouldn't be here if the control has been removed from the canvas if (m_hasBeenRemoved) { throw new InvalidOperationException( "Stream control that was removed from the PFD is being notified to update its location."); } if (m_updatingLocation) { return; } m_updatingLocation = true; MathCore.Vector sPt = m_stream.SourceLocation; MathCore.Vector dPt = m_stream.DestinationLocation; MathCore.Vector lineMidpoint = (sPt + dPt) / 2.0; // Compute the line segments for our stream lines MathCore.Vector mid, sIconPt; MathCore.LineSegment[] lines = ComputeLineSegments(out mid, out sIconPt); // Get the list of UI lines to the right size while (m_lines.Count > lines.Length) { int index = m_lines.Count - 1; m_canvas.RemoveChild(m_lines[index]); m_lines.RemoveAt(index); } while (m_lines.Count < lines.Length) { Line line = new Line(); m_lines.Add(line); m_canvas.AddNewChild(line); // Make sure the line has a low z-index line.SetValue(Canvas.ZIndexProperty, -1); // Remember to set the line color Brush b = m_isSelected ? s_streamLineSelected : m_streamLineNotSelected; line.Fill = b; line.Stroke = b; } // Set the positions for (int i = 0; i < lines.Length; i++) { SetLineLocation(m_lines[i], lines[i].A, lines[i].B); } // Now do the table line if necessary if (null != m_table && !m_tableMinimized) { TableLine.X1 = mid.X; TableLine.Y1 = mid.Y; TableLine.X2 = m_table.Location.X; TableLine.Y2 = m_table.Location.Y; } // Check if we're minimized then we need to position the mini table if (m_tableMinimized) { m_miniTable.SetValue(Canvas.LeftProperty, mid.X); m_miniTable.SetValue(Canvas.TopProperty, mid.Y); } // Take care of the source drag icon if (null != m_stream.Source) { m_sourceDragIcon.Visibility = System.Windows.Visibility.Collapsed; // We need to show the square drag handle and position it if (null == m_square) { m_square = new System.Windows.Shapes.Rectangle() { Fill = m_streamLineNotSelected, Width = 10.0, Height = 10.0 }; m_canvas.AddNewChild(m_square); m_square.MouseLeftButtonDown += new MouseButtonEventHandler(SourceSquare_MouseLeftButtonDown); } m_square.Visibility = System.Windows.Visibility.Visible; m_square.SetValue(Canvas.LeftProperty, sIconPt.X - 5.0); m_square.SetValue(Canvas.TopProperty, sIconPt.Y - 5.0); } else { m_sourceDragIcon.Location = new Point( m_stream.SourceLocation.X, m_stream.SourceLocation.Y); m_sourceDragIcon.Visibility = System.Windows.Visibility.Visible; if (null != m_square) { m_square.Visibility = System.Windows.Visibility.Collapsed; } } // Take care of the destination drag icon as well if (null == m_stream.Destination) { m_dstDragIcon.Location = new Point(dPt.X, dPt.Y); m_dstDragIcon.Visibility = System.Windows.Visibility.Visible; } else { m_dstDragIcon.Visibility = System.Windows.Visibility.Collapsed; } // If we have a non-null destination, update the arrow if (null != m_stream.Destination) { // Where the last line segment intersects the destination process unit is where // the tip of the arrow is Point pt = new Point( m_stream.Destination.Location.X - 20.0, m_stream.Destination.Location.Y - 20.0); MathCore.Rectangle destRect = MathCore.Rectangle.CreateFromCanvasRect(pt, 40.0, 40.0); MathCore.Vector[] isects = destRect.GetIntersections(lines[lines.Length - 1]); MathCore.LineSegment lastLine = lines[lines.Length - 1]; if (0 == isects.Length) { // No clue what to do here } double minDist = double.MaxValue; foreach (MathCore.Vector isectPt in isects) { double tempDist = (isectPt - lastLine.A).Length; if (tempDist < minDist) { minDist = tempDist; } } MathCore.Vector dirNorm = MathCore.Vector.Normalize(lastLine.Direction); MathCore.Vector tip = lastLine.A + dirNorm * minDist; MathCore.Vector perp1 = MathCore.Vector.Normalize( MathCore.Vector.GetPerpendicular1(lastLine.Direction)); MathCore.Vector perp2 = MathCore.Vector.Normalize( MathCore.Vector.GetPerpendicular2(lastLine.Direction)); MathCore.Vector[] pts = new MathCore.Vector[] { tip, tip - (dirNorm * 10.0) + (perp1 * 10.0), tip - (dirNorm * 10.0) + (perp2 * 10.0) }; // Set the vertices for (int i = 0; i < 3; i++) { m_arrow.Points[i] = new Point(pts[i].X, pts[i].Y); } m_arrow.Visibility = System.Windows.Visibility.Visible; } // Lastly, tell the comment sticky notes to update foreach (StickyNoteControl sn in m_stickyNotes) { sn.UpdateLineToParent(); } m_updatingLocation = false; }