/// <summary> /// Gets the relative location (to the to shape absolute location). /// </summary> /// <returns></returns> public PointD GetRelativeLocation() { PointD ret = new PointD(); ret.X = this.AbsoluteLocation.X - this.ToShape.AbsoluteLocation.X; ret.Y = this.AbsoluteLocation.Y - this.ToShape.AbsoluteLocation.Y; return ret; }
/// <summary> /// Sets the relative location (to the to shape absolute location). /// </summary> /// <returns></returns> public void SetRelativeLocation(PointD relativeLocation) { PointD p = new PointD( this.ToShape.AbsoluteLocation.X + relativeLocation.X, this.ToShape.AbsoluteLocation.Y + relativeLocation.Y); this.AbsoluteLocation = p; this.LinkShape.UpdateLinkPlacementTarget(); }
/// <summary> /// Constructor. /// </summary> /// <param name="info">The SerializationInfo to get the data from.</param> /// <param name="context">The destination (see System.Runtime.Serialization.StreamingContext) for this serialization.</param> protected DiagramModelMergeOptions(SerializationInfo info, StreamingContext context) { if (info == null) throw new System.ArgumentNullException("info"); this.LayoutInfoString = (string)info.GetValue("layoutInfo", typeof(string)); this.ElementId = (Guid)info.GetValue("elementId", typeof(Guid)); this.DomainClassId = (Guid)info.GetValue("domainClassId", typeof(Guid)); this.ShapeDomainClassId = (Guid)info.GetValue("shapeDomainClassId", typeof(Guid)); this.RelativeLocation = (PointD)info.GetValue("relativeLocation", typeof(PointD)); }
/// <summary> /// Layouts an edge between the given points. /// </summary> /// <param name="startPoint">Start point.</param> /// <param name="endPoint">End point.</param> /// <param name="rMode">Routing mode.</param> /// <returns>Edge point collection.</returns> public override EdgePointCollection LayoutEdge(PointD startPoint, PointD endPoint, RoutingMode rMode) { double middle = startPoint.X + (endPoint.X - startPoint.X) / 2.0; EdgePointCollection points = new EdgePointCollection(); points.Add(new EdgePoint(startPoint)); points.Add(new EdgePoint(middle, startPoint.Y)); points.Add(new EdgePoint(middle, endPoint.Y)); points.Add(new EdgePoint(endPoint)); return points; }
protected BaseDiagramItemElementViewModel(ViewModelStore viewModelStore, DiagramSurfaceViewModel diagram, NodeShape shapeElement) : base(viewModelStore, diagram, shapeElement) { this.itemLocation = shapeElement.Location; this.itemSize = shapeElement.Size; this.parentItem = null; this.nestedChildItems = new ObservableCollection<BaseDiagramItemElementViewModel>(); this.nestedChildItemsRO = new ReadOnlyObservableCollection<BaseDiagramItemElementViewModel>(nestedChildItems); this.relativeChildItems = new ObservableCollection<BaseDiagramItemElementViewModel>(); this.relativeChildItemsRO = new ReadOnlyObservableCollection<BaseDiagramItemElementViewModel>(relativeChildItems); Subscribe(); }
/// <summary> /// Update anchor points. Called after source or target was moved. /// </summary> protected virtual void UpdateAnchorPoints() { if (this.ShapeElement.EdgePoints.Count == 0) { this.fromAnchorPosition = PointD.Empty; this.toAnchorPosition = PointD.Empty; } else { this.fromAnchorPosition = new PointD(this.ShapeElement.EdgePoints[0].X, this.ShapeElement.EdgePoints[0].Y); this.toAnchorPosition = new PointD(this.ShapeElement.EdgePoints[this.ShapeElement.EdgePoints.Count - 1].X, this.ShapeElement.EdgePoints[this.ShapeElement.EdgePoints.Count - 1].Y); } UpdateEdgePoints(); try { Point pathStartPoint, pathTangentAtStartPoint; Point pathEndPoint, pathTangentAtEndPoint; Point pathMidPoint, pathTangentAtMidPoint; // the PathGeometry.GetPointAtFractionLength method gets the point and a tangent vector // on PathGeometry at the specified fraction of its length this.Geometry.GetPointAtFractionLength(0, out pathStartPoint, out pathTangentAtStartPoint); this.Geometry.GetPointAtFractionLength(1, out pathEndPoint, out pathTangentAtEndPoint); this.Geometry.GetPointAtFractionLength(0.5, out pathMidPoint, out pathTangentAtMidPoint); // get angle from tangent vector this.FromAnchorAngle = Math.Atan2(-pathTangentAtStartPoint.Y, -pathTangentAtStartPoint.X) * (180 / Math.PI); this.ToAnchorAngle = Math.Atan2(pathTangentAtEndPoint.Y, pathTangentAtEndPoint.X) * (180 / Math.PI); } catch { this.FromAnchorAngle = 0.0; this.ToAnchorAngle = 0.0; } }
/// <summary> /// Layouts the edge betweend the given points. This method is used to calculate a path that is displayed /// when any of the anchors is changed (via drag&drop). /// </summary> /// <param name="startPoint"></param> /// <param name="endPoint"></param> /// <param name="rMode">Routing mode. TODO: Not yet supported.</param> /// <returns></returns> public virtual EdgePointCollection CalcLayoutEdge(PointD startPoint, PointD endPoint, RoutingMode rMode) { EdgePointCollection points = new EdgePointCollection(); /*if (rMode == RoutingMode.Orthogonal) { try { // calculate points between start and end List<PointD> calcPoints = OrthogonalEdgeRouter.GetConnectionLineSimple(this, this.FromShape, startPoint, this.ToShape, endPoint, GetLinkPlacement(this.ToShape.AbsoluteBounds, endPoint)); foreach (PointD p in calcPoints) points.Add(new EdgePoint(p.X, p.Y)); } catch { points.Add(new EdgePoint(startPoint)); points.Add(new EdgePoint(endPoint)); } } else {*/ points.Add(new EdgePoint(startPoint)); points.Add(new EdgePoint(endPoint)); //} return points; }
/// <summary> /// Gets the link placement based on the shape dimensions as well as the proposed location. /// </summary> /// <param name="shapeDimensions">Dimensions of the shape, this link start/end is created at.</param> /// <param name="proposedLocation">Proposed location of the link start/end.</param> /// <returns>LinkPlacement.</returns> public static LinkPlacement GetLinkPlacement(RectangleD shapeDimensions, PointD proposedLocation) { PointD pointD1 = new PointD(proposedLocation.X + 3.5 - shapeDimensions.Left, proposedLocation.Y + 3.5 - shapeDimensions.Top); PointD pointD2 = new PointD(shapeDimensions.Width / 2.0, shapeDimensions.Height / 2.0); double d1 = System.Math.Atan2(pointD2.Y, pointD2.X); double d2 = System.Math.Atan2(pointD1.Y - pointD2.Y, pointD1.X - pointD2.X); if ((d2 <= d1) && (d2 >= -d1)) return LinkPlacement.Right; if ((d2 > d1) && (d2 < (Math.PI - d1))) return LinkPlacement.Bottom; if ((d2 > -(Math.PI - d1)) && (d2 < -d1)) return LinkPlacement.Top; if ((d2 >= (Math.PI - d1)) || (d2 <= -(Math.PI - d1))) return LinkPlacement.Left; throw new System.InvalidOperationException(); }
/// <summary> /// Calculates a path between two points. /// </summary> /// <param name="startPoint">Start point.</param> /// <param name="endPoint">End point.</param> /// <returns>Path specified by a points collection.</returns> public virtual List<PointD> CalculatePath(PointD startPoint, PointD endPoint) { // TODO List<PointD> calculatedPoints = new List<PointD>(); calculatedPoints.Add(startPoint); calculatedPoints.Add(endPoint); return calculatedPoints; }
/// <summary> /// Calculates an allowed position based on the given proposed position. The Idea behind this is /// to correct the proposed position if we are within an target elements border. /// </summary> /// <param name="targetShape">Target shape.</param> /// <param name="proposedPosition">Proposed position.</param> /// <returns>Corrected position.</returns> public virtual PointD CalculateAllowedPosition(NodeShape targetShape, PointD proposedPosition) { PointD position = proposedPosition; RectangleD absoluteBounds = targetShape.AbsoluteBounds; if (position.Y > absoluteBounds.Top - ConnectorHeight && position.Y < absoluteBounds.Top + ConnectorHeight) { position.Y = absoluteBounds.Top; } else if (position.Y > absoluteBounds.Bottom - ConnectorHeight && position.Y < absoluteBounds.Bottom + ConnectorHeight) { position.Y = absoluteBounds.Bottom; } if (position.X > absoluteBounds.Left - ConnectorWidth && position.X < absoluteBounds.Left + ConnectorWidth) { position.X = absoluteBounds.Left; } else if (position.X > absoluteBounds.Right - ConnectorWidth && position.X < absoluteBounds.Right + ConnectorWidth) { position.X = absoluteBounds.Right; } return position; }
/// <summary> /// Calculates a path geometry between the source and the target point. /// </summary> /// <param name="proposedSourcePoint">Source point (Absolute location).</param> /// <param name="targetShape">Target shape.</param> /// <param name="proposedTargetPoint">Target point (Absolute location).</param> /// <param name="fixedPoints">Fixed points.</param> /// <returns>Calculated path geometry.</returns> public virtual List<PointD> CalcPath(PointD proposedSourcePoint, NodeShape targetShape, PointD proposedTargetPoint, FixedGeometryPoints fixedPoints) { PointD sourcePoint = proposedSourcePoint; PointD targetPoint = proposedTargetPoint; if (fixedPoints != FixedGeometryPoints.SourceAndTarget && fixedPoints != FixedGeometryPoints.Source) { // calculate allowed source position // TODO } if (fixedPoints != FixedGeometryPoints.SourceAndTarget && fixedPoints != FixedGeometryPoints.Target) { // calculate allowed target position targetPoint = CalculateAllowedPosition(targetShape, proposedTargetPoint); } List<PointD> edgePoints = CalculatePath(sourcePoint, targetPoint); return edgePoints; }
/// <summary> /// Calculates a location based on the shape dimensions as well as the proposed location. /// </summary> /// <param name="placement">Link placement.</param> /// <param name="shapeDimensions">Dimensions of the shape, this link start/end is created at.</param> /// <param name="proposedLocation">Proposed location of the link start/end.</param> /// <returns>Calculated location.</returns> public static PointD CalculateLocation(LinkPlacement placement, RectangleD shapeDimensions, PointD proposedLocation) { double x = proposedLocation.X; double y = proposedLocation.Y; double itemWidth = 7; double itemHeight = 7; switch (placement) { case LinkPlacement.Left: x = shapeDimensions.Left - itemWidth; if (y <= (shapeDimensions.Top - itemHeight)) y = shapeDimensions.Top - itemHeight; else if (y > shapeDimensions.Bottom) y = shapeDimensions.Bottom; break; case LinkPlacement.Top: y = shapeDimensions.Top - itemHeight; if (x <= (shapeDimensions.Left - itemWidth)) x = shapeDimensions.Left - itemWidth; else if (x > shapeDimensions.Right) x = shapeDimensions.Right; break; case LinkPlacement.Right: x = shapeDimensions.Right + 3.4 * 2; if (y <= (shapeDimensions.Top - itemHeight)) y = shapeDimensions.Top - itemHeight; else if (y > shapeDimensions.Bottom) y = shapeDimensions.Bottom; break; case LinkPlacement.Bottom: y = shapeDimensions.Bottom + 3.4 * 2; if (x <= (shapeDimensions.Left - itemWidth)) x = shapeDimensions.Left - itemWidth; else if (x > shapeDimensions.Right) x = shapeDimensions.Right; break; } return new PointD(x, y); }
/// <summary> /// Layouts the edge betweend the given points. /// </summary> /// <param name="startPoint"></param> /// <param name="endPoint"></param> /// <returns></returns> private EdgePointCollection LayoutEdge(PointD startPoint, PointD endPoint) { return this.LayoutEdge(startPoint, endPoint, this.RoutingMode); }
private void UpdateLinkAnchorAndShape(DragItem item, PointD locationFrom, PointD locationTo) { if (item == null) return; if (this.EdgePointType == EdgePointVMType.Start) item.Thumb.Margin = new System.Windows.Thickness(locationFrom.X, locationFrom.Y, 0, 0); else if (this.EdgePointType == EdgePointVMType.End) item.Thumb.Margin = new System.Windows.Thickness(locationTo.X, locationTo.Y, 0, 0); else { //... } FixedGeometryPoints fixedPoints = FixedGeometryPoints.Source; if (this.EdgePointType == EdgePointVMType.End) fixedPoints = FixedGeometryPoints.Target; else if (this.EdgePointType == EdgePointVMType.Normal) fixedPoints = FixedGeometryPoints.None; item.Path.Data = selectedItemVM.CalcPathGeometry(locationFrom, locationTo, fixedPoints, selectedItemVM.RoutingMode); }
/// <summary> /// Constructs the SizeD from a given point. /// </summary> /// <param name="pt">PointD</param> public SizeD(PointD pt) { width = pt.X; height = pt.Y; }
/// <summary> /// Calculates a path geometry between the source and the target points. /// </summary> /// <param name="sourcePoint">Source point (Absolute location).</param> /// <param name="targetPoint">Target point (Absolute location).</param> /// <param name="fixedPoints">Fixed points.</param> /// <param name="routingMode">Routing mode.</param> /// <returns>Calculated path geometry.</returns> public virtual PathGeometry CalcPathGeometry(PointD sourcePoint, PointD targetPoint, FixedGeometryPoints fixedPoints, RoutingMode routingMode) { // fixedPoints: not required yet... EdgePointCollection col = this.ShapeElement.CalcLayoutEdge(sourcePoint, targetPoint, routingMode); PathGeometry geometry = new PathGeometry(); PathFigure figure = new PathFigure(); figure.StartPoint = new System.Windows.Point(col[0].X, col[0].Y); List<System.Windows.Point> points = new List<System.Windows.Point>(); for (int i = 1; i < col.Count; i++) { points.Add(new System.Windows.Point(col[i].X, col[i].Y)); } figure.Segments.Add(new PolyLineSegment(points, true)); geometry.Figures.Add(figure); return geometry; }
/// <summary> /// Set an anchor position based on a horizontal and verical changes proposed. /// </summary> /// <param name="horizontalChange">Horizontal change.</param> /// <param name="verticalChange">Vertical change.</param> /// <returns>Calculated position.</returns> public virtual void SetToAnchorPosition(double horizontalChange, double verticalChange) { PointD proposedPoint = new PointD(this.EndEdgePoint.X + horizontalChange, this.EndEdgePoint.Y + verticalChange); LinkPlacement placement = LinkShape.GetLinkPlacement(this.ShapeElement.ToShape.AbsoluteBounds, proposedPoint); PointD calculatedLocation = LinkShape.CalculateLocation(placement, this.ShapeElement.ToShape.AbsoluteBounds, proposedPoint); if( this.ShapeElement.EndPoint != calculatedLocation ) using (Transaction transaction = this.Store.TransactionManager.BeginTransaction("Move To Anchor")) { this.ShapeElement.LinkPlacementEnd = placement; this.ShapeElement.SetEndPoint(calculatedLocation); this.ShapeElement.Layout(FixedGeometryPoints.Target); transaction.Commit(); } }
/// <summary> /// Calculates an anchor position based on a horizontal and verical changes proposed. /// </summary> /// <param name="horizontalChange">Horizontal change.</param> /// <param name="verticalChange">Vertical change.</param> /// <returns>Calculated position.</returns> public virtual PointD CalcToAnchorPosition(double horizontalChange, double verticalChange) { PointD proposedPoint = new PointD(this.EndEdgePoint.X + horizontalChange, this.EndEdgePoint.Y + verticalChange); return LinkShape.CalculateLocation(this.ShapeElement.ToShape.AbsoluteBounds, proposedPoint); }
/// <summary> /// Sets a new start point. /// </summary> /// <param name="newStartPoint">New start point.</param> public void SetStartPoint(PointD newStartPoint) { if (this.SourceAnchor.AbsoluteLocation != newStartPoint) { if (!this.Store.InSerializationTransaction) this.SourceAnchor.DiscardLocationChange = true; this.SourceAnchor.AbsoluteLocation = newStartPoint; } }
/// <summary> /// Gets the item that is directly under the mouse. /// </summary> /// <param name="position">Position.</param> /// <returns>Item under the mouse or null.</returns> public object GetItemAtPosition(PointD position) { DiagramDesignerItem hitItem = null; DependencyObject hitObject = this.InputHitTest(position.ToPoint()) as DependencyObject; while (hitObject != null) { if (hitObject is DiagramDesignerItem) { hitItem = hitObject as DiagramDesignerItem; break; } hitObject = VisualTreeHelper.GetParent(hitObject); } if (hitItem != null) return hitItem.DataContext; else return null; }
/// <summary> /// Adds the specified size to the specified point. /// </summary> /// <param name="point">Point to add the size to.</param> /// <param name="size">Size to add.</param> /// <returns>Point with the added size.</returns> public static PointD Add(PointD point, SizeD size) { return new PointD(point.X + size.Width, point.Y + size.Height); }
/// <summary> /// Updates the clicked point value, which is always relative to the source of the click event. /// </summary> /// <param name="e"></param> protected override void OnPreviewMouseDown(MouseButtonEventArgs e) { base.OnPreviewMouseDown(e); Point point = e.GetPosition(e.MouseDevice.DirectlyOver); ClickedPoint = new PointD(point.X, point.Y); }
/// <summary> /// Layouts this link shape. /// </summary> /// <param name="startPoint">Start point.</param> /// <param name="endPoint">End point.</param> /// <param name="fixedPoints">Fixed points.</param> public virtual void Layout(PointD startPoint, PointD endPoint, FixedGeometryPoints fixedPoints) { if (this.IsDeleted || this.IsDeleting) return; IsLayoutInProgress = true; EdgePointCollection colNew = new EdgePointCollection(); colNew.AddRange(LayoutEdge(startPoint, endPoint)); this.EdgePoints = colNew; if (colNew.Count > 0) { if (this.SourceAnchor != null) if (this.StartPoint != this.EdgePoints[0].Point) { if (!this.Store.InSerializationTransaction) this.SourceAnchor.DiscardLocationChange = true; SetStartPoint(this.EdgePoints[0].Point); } if (this.TargetAnchor != null) if (this.EndPoint != this.EdgePoints[this.EdgePoints.Count - 1].Point) { if (!this.Store.InSerializationTransaction) this.TargetAnchor.DiscardLocationChange = true; SetEndPoint(this.EdgePoints[this.EdgePoints.Count - 1].Point); } } UpdateLinkPlacement(); IsLayoutInProgress = false; }
/// <summary> /// Sets the location of this item and propagates it to the hosted shape element if allowed. /// </summary> /// <param name="proposedLocation">Location to apply.</param> /// <remarks> /// This function needs to be called withing a modeling transaction. /// </remarks> public virtual void SetLocation(PointD proposedLocation) { if (this.ShapeElement.Location != proposedLocation) { this.ShapeElement.SetLocation(proposedLocation); } }
/// <summary> /// Calculates a location based on the shape dimensions as well as the proposed location. /// </summary> /// <param name="shapeDimensions">Dimensions of the shape, this link start/end is created at.</param> /// <param name="proposedLocation">Proposed location of the link start/end.</param> /// <returns>Calculated location.</returns> public static PointD CalculateLocation(RectangleD shapeDimensions, PointD proposedLocation) { LinkPlacement placement = GetLinkPlacement(shapeDimensions, proposedLocation); return CalculateLocation(placement, shapeDimensions, proposedLocation); }
private void AddLinkAnchorAndShape(PointD locationFrom, PointD locationTo) { DragItem dragItem = new DragItem(); Rectangle r = new Rectangle(); r.Stroke = new SolidColorBrush(Colors.Black); r.StrokeThickness = 1.0; r.Width = this.ActualWidth; r.Height = this.ActualHeight; if (this.EdgePointType == EdgePointVMType.Start) r.Margin = new System.Windows.Thickness(locationFrom.X, locationFrom.Y, 0, 0); else if (this.EdgePointType == EdgePointVMType.End) r.Margin = new System.Windows.Thickness(locationTo.X, locationTo.Y, 0, 0); else { //... } dragItem.Thumb = r; FixedGeometryPoints fixedPoints = FixedGeometryPoints.Source; if (this.EdgePointType == EdgePointVMType.End) fixedPoints = FixedGeometryPoints.Target; else if (this.EdgePointType == EdgePointVMType.Normal) fixedPoints = FixedGeometryPoints.None; Path path = new Path(); path.Data = selectedItemVM.CalcPathGeometry(locationFrom, locationTo, fixedPoints, selectedItemVM.RoutingMode); path.Stroke = new SolidColorBrush(Colors.Black); path.StrokeThickness = 1.0; dragItem.Path = path; dragCanvas.Children.Add(dragItem); }
/// <summary> /// Called whenever the location of the hosted shape changes. /// </summary> /// <param name="args"></param> protected virtual void OnLocationChanged(ElementPropertyChangedEventArgs args) { PointD oldLocation = this.itemLocation; PointD newLocation = (PointD)args.NewValue; if (this.Location != newLocation) { this.itemLocation = newLocation; if (oldLocation.X != this.itemLocation.X || oldLocation.Y != this.itemLocation.Y) { OnPropertyChanged("Location"); if (oldLocation.X != this.itemLocation.X) { OnPropertyChanged("Left"); } if (oldLocation.Y != this.itemLocation.Y) { OnPropertyChanged("Top"); } } } }
public static EdgePointCollection ConvertFromRelativeEdgePoints(EdgePointCollection col, PointD relativeTo) { EdgePointCollection retCol = new EdgePointCollection(); foreach (EdgePoint p in col) { PointD ret = new PointD(); ret.X = p.X + relativeTo.X; ret.Y = p.Y + relativeTo.Y; EdgePoint point = new EdgePoint(ret, p.PointType); retCol.Add(point); } return retCol; }
/// <summary> /// Calculates a path between the source and the target point. /// </summary> /// <param name="proposedSourcePoint">Source point (Absolute location).</param> /// <param name="proposedTargetPoint">Target point (Absolute location).</param> /// <param name="fixedPoints">Fixed points.</param> /// <returns>Calculated path geometry.</returns> public virtual List<PointD> CalcPath(PointD proposedSourcePoint, PointD proposedTargetPoint, FixedGeometryPoints fixedPoints) { PointD sourcePoint = proposedSourcePoint; PointD targetPoint = proposedTargetPoint; if (fixedPoints != FixedGeometryPoints.SourceAndTarget && fixedPoints != FixedGeometryPoints.Source) { // calculate allowed source position // TODO: not required yet } if (fixedPoints != FixedGeometryPoints.SourceAndTarget && fixedPoints != FixedGeometryPoints.Target) { // calculate allowed target position // TODO: not required yet } List<PointD> edgePoints = new List<PointD>(); edgePoints.Add(sourcePoint); edgePoints.Add(targetPoint); return edgePoints; }
/// <summary> /// Substracts the specified size from the specified point. /// </summary> /// <param name="point">Point to substract the size from.</param> /// <param name="size">Size to substract.</param> /// <returns>Returns the result of subtracting specified Size from the specified Point.</returns> public static PointD Subtract(PointD point, SizeD size) { return new PointD(point.X - size.Width, point.Y - size.Height); }