mirror of
https://gitee.com/akwkevin/aistudio.-wpf.-diagram
synced 2026-04-12 12:16:37 +08:00
画线优化基本完成
This commit is contained in:
@@ -25,7 +25,7 @@ namespace AIStudio.Wpf.Flowchart
|
||||
{
|
||||
FlowchartService.InitData(DiagramViewModel.Items.OfType<FlowNode>().ToList(), DiagramViewModel.Items.OfType<ConnectorViewModel>().ToList(), DiagramViewModel);
|
||||
}
|
||||
_service.DrawModeViewModel.LineDrawMode = DrawMode.BoundaryConnectingLine;
|
||||
_service.DrawModeViewModel.LineDrawMode = DrawMode.ConnectingLineSmooth;
|
||||
}
|
||||
|
||||
protected override void InitDiagramViewModel()
|
||||
@@ -36,7 +36,7 @@ namespace AIStudio.Wpf.Flowchart
|
||||
DiagramViewModel.GridCellSize = new Size(100, 100);
|
||||
DiagramViewModel.CellHorizontalAlignment = CellHorizontalAlignment.Center;
|
||||
DiagramViewModel.CellVerticalAlignment = CellVerticalAlignment.Center;
|
||||
_service.DrawModeViewModel.LineDrawMode = DrawMode.BoundaryConnectingLine;
|
||||
_service.DrawModeViewModel.LineDrawMode = DrawMode.ConnectingLineSmooth;
|
||||
}
|
||||
|
||||
protected override void Init()
|
||||
|
||||
@@ -17,7 +17,7 @@ namespace AIStudio.Wpf.Logical
|
||||
}
|
||||
public LogicalViewModel(string filename, DiagramDocument diagramDocument) : base(filename, diagramDocument)
|
||||
{
|
||||
_service.DrawModeViewModel.LineDrawMode = DrawMode.CornerConnectingLine;
|
||||
_service.DrawModeViewModel.LineDrawMode = DrawMode.ConnectingLineSmooth;
|
||||
}
|
||||
|
||||
protected override void InitDiagramViewModel()
|
||||
@@ -31,7 +31,7 @@ namespace AIStudio.Wpf.Logical
|
||||
DiagramViewModel.CellVerticalAlignment = CellVerticalAlignment.None;
|
||||
|
||||
DiagramViewModel.Items.CollectionChanged += Items_CollectionChanged;
|
||||
_service.DrawModeViewModel.LineDrawMode = DrawMode.CornerConnectingLine;
|
||||
_service.DrawModeViewModel.LineDrawMode = DrawMode.ConnectingLineSmooth;
|
||||
}
|
||||
|
||||
protected override void Init()
|
||||
|
||||
@@ -32,7 +32,7 @@ namespace AIStudio.Wpf.Flowchart
|
||||
readDataTimer.Interval = 1000;
|
||||
readDataTimer.AutoReset = false;
|
||||
readDataTimer.Start();
|
||||
_service.DrawModeViewModel.LineDrawMode = DrawMode.BoundaryConnectingLine;
|
||||
_service.DrawModeViewModel.LineDrawMode = DrawMode.ConnectingLineBoundary;
|
||||
}
|
||||
|
||||
protected override void InitDiagramViewModel()
|
||||
@@ -43,7 +43,7 @@ namespace AIStudio.Wpf.Flowchart
|
||||
DiagramViewModel.GridCellSize = new Size(100, 60);
|
||||
DiagramViewModel.CellHorizontalAlignment = CellHorizontalAlignment.Center;
|
||||
DiagramViewModel.CellVerticalAlignment = CellVerticalAlignment.Center;
|
||||
_service.DrawModeViewModel.LineDrawMode = DrawMode.BoundaryConnectingLine;
|
||||
_service.DrawModeViewModel.LineDrawMode = DrawMode.ConnectingLineBoundary;
|
||||
}
|
||||
|
||||
private System.Timers.Timer readDataTimer = new System.Timers.Timer();
|
||||
|
||||
@@ -802,10 +802,10 @@
|
||||
</Fluent:ToggleButton>
|
||||
|
||||
<Fluent:SplitButton Header="连接线" GroupName="DrawMode" IsCheckable="True" IsChecked="{Binding LineDrawModeSelected}" Icon="{iconPacks:Material Kind=VectorPolyline}" Width="50" VerticalAlignment="Top">
|
||||
<Fluent:MenuItem Header="曲线连接线" Size="Middle" IsCheckable="True" IsChecked="{Binding LineDrawMode,Converter={dd:ConverterValueMapToBool Parameter='SmoothConnectingLine'}, ConverterParameter='SmoothConnectingLine'}" Icon="{iconPacks:Material Kind=VectorRadius}"/>
|
||||
<Fluent:MenuItem Header="直线连接线" Size="Middle" IsCheckable="True" IsChecked="{Binding LineDrawMode,Converter={dd:ConverterValueMapToBool Parameter='StraightConnectingLine'}, ConverterParameter='StraightConnectingLine'}" Icon="{iconPacks:Material Kind=VectorLine}"/>
|
||||
<Fluent:MenuItem Header="折线连接线" Size="Middle" IsCheckable="True" IsChecked="{Binding LineDrawMode,Converter={dd:ConverterValueMapToBool Parameter='CornerConnectingLine'}, ConverterParameter='CornerConnectingLine'}" Icon="{iconPacks:Material Kind=VectorPolyline}"/>
|
||||
<Fluent:MenuItem Header="边界连接线" Size="Middle" IsCheckable="True" IsChecked="{Binding LineDrawMode,Converter={dd:ConverterValueMapToBool Parameter='BoundaryConnectingLine'}, ConverterParameter='BoundaryConnectingLine'}" Icon="{iconPacks:Material Kind=VectorPolylineEdit}"/>
|
||||
<Fluent:MenuItem Header="曲线连接线" Size="Middle" IsCheckable="True" IsChecked="{Binding LineDrawMode,Converter={dd:ConverterValueMapToBool Parameter='ConnectingLineSmooth'}, ConverterParameter='ConnectingLineSmooth'}" Icon="{iconPacks:Material Kind=VectorRadius}"/>
|
||||
<Fluent:MenuItem Header="直线连接线" Size="Middle" IsCheckable="True" IsChecked="{Binding LineDrawMode,Converter={dd:ConverterValueMapToBool Parameter='ConnectingLineStraight'}, ConverterParameter='ConnectingLineStraight'}" Icon="{iconPacks:Material Kind=VectorLine}"/>
|
||||
<Fluent:MenuItem Header="折线连接线" Size="Middle" IsCheckable="True" IsChecked="{Binding LineDrawMode,Converter={dd:ConverterValueMapToBool Parameter='ConnectingLineCorner'}, ConverterParameter='ConnectingLineCorner'}" Icon="{iconPacks:Material Kind=VectorPolyline}"/>
|
||||
<Fluent:MenuItem Header="边界连接线" Size="Middle" IsCheckable="True" IsChecked="{Binding LineDrawMode,Converter={dd:ConverterValueMapToBool Parameter='ConnectingLineBoundary'}, ConverterParameter='ConnectingLineBoundary'}" Icon="{iconPacks:Material Kind=VectorPolylineEdit}"/>
|
||||
<Fluent:SplitButton.Style>
|
||||
<Style TargetType="{x:Type Fluent:SplitButton}" BasedOn="{StaticResource RibbonSplitButtonStyle}">
|
||||
<Setter Property="LargeIcon">
|
||||
@@ -814,28 +814,28 @@
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding LineDrawMode}" Value="SmoothConnectingLine">
|
||||
<DataTrigger Binding="{Binding LineDrawMode}" Value="ConnectingLineSmooth">
|
||||
<Setter Property="LargeIcon">
|
||||
<Setter.Value>
|
||||
<iconPacks:PackIconMaterial Kind="VectorRadius" VerticalAlignment="Center" HorizontalAlignment="Center"/>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</DataTrigger>
|
||||
<DataTrigger Binding="{Binding LineDrawMode}" Value="StraightConnectingLine">
|
||||
<DataTrigger Binding="{Binding LineDrawMode}" Value="ConnectingLineStraight">
|
||||
<Setter Property="LargeIcon">
|
||||
<Setter.Value>
|
||||
<iconPacks:PackIconMaterial Kind="VectorLine" VerticalAlignment="Center" HorizontalAlignment="Center"/>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</DataTrigger>
|
||||
<DataTrigger Binding="{Binding LineDrawMode}" Value="CornerConnectingLine">
|
||||
<DataTrigger Binding="{Binding LineDrawMode}" Value="ConnectingLineCorner">
|
||||
<Setter Property="LargeIcon">
|
||||
<Setter.Value>
|
||||
<iconPacks:PackIconMaterial Kind="VectorPolyline" VerticalAlignment="Center" HorizontalAlignment="Center"/>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</DataTrigger>
|
||||
<DataTrigger Binding="{Binding LineDrawMode}" Value="BoundaryConnectingLine">
|
||||
<DataTrigger Binding="{Binding LineDrawMode}" Value="ConnectingLineBoundary">
|
||||
<Setter Property="LargeIcon">
|
||||
<Setter.Value>
|
||||
<iconPacks:PackIconMaterial Kind="VectorPolylineEdit" VerticalAlignment="Center" HorizontalAlignment="Center"/>
|
||||
@@ -852,9 +852,9 @@
|
||||
</Fluent:SplitButton.ToolTip>
|
||||
</Fluent:SplitButton>
|
||||
|
||||
<Fluent:SplitButton Header="连接方式" GroupName="RouterMode" IsCheckable="False" IsChecked="{Binding LineRouterModeSelected}" Icon="{iconPacks:FontAwesome Kind=WindowMinimizeRegular}" Width="50" VerticalAlignment="Top">
|
||||
<Fluent:MenuItem Header="普通" Size="Middle" IsCheckable="True" IsChecked="{Binding LineRouterMode,Converter={dd:ConverterValueMapToBool Parameter='Normal'}, ConverterParameter='Normal'}" Icon="{iconPacks:FontAwesome Kind=WindowMinimizeRegular}"/>
|
||||
<Fluent:MenuItem Header="正交" Size="Middle" IsCheckable="True" IsChecked="{Binding LineRouterMode,Converter={dd:ConverterValueMapToBool Parameter='Orthogonal'}, ConverterParameter='Orthogonal'}" Icon="{iconPacks:FontAwesome Kind=BorderStyleSolid}"/>
|
||||
<!--<Fluent:SplitButton Header="连接方式" GroupName="RouterMode" IsCheckable="False" IsChecked="{Binding LineRouterModeSelected}" Icon="{iconPacks:FontAwesome Kind=WindowMinimizeRegular}" Width="50" VerticalAlignment="Top">
|
||||
<Fluent:MenuItem Header="普通" Size="Middle" IsCheckable="True" IsChecked="{Binding LineRouterMode,Converter={dd:ConverterValueMapToBool Parameter='RouterNormal'}, ConverterParameter='RouterNormal'}" Icon="{iconPacks:FontAwesome Kind=WindowMinimizeRegular}"/>
|
||||
<Fluent:MenuItem Header="正交" Size="Middle" IsCheckable="True" IsChecked="{Binding LineRouterMode,Converter={dd:ConverterValueMapToBool Parameter='RouterOrthogonal'}, ConverterParameter='RouterOrthogonal'}" Icon="{iconPacks:FontAwesome Kind=BorderStyleSolid}"/>
|
||||
<Fluent:SplitButton.Style>
|
||||
<Style TargetType="{x:Type Fluent:SplitButton}" BasedOn="{StaticResource RibbonSplitButtonStyle}">
|
||||
<Setter Property="LargeIcon">
|
||||
@@ -863,14 +863,14 @@
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding LineRouterMode}" Value="Normal">
|
||||
<DataTrigger Binding="{Binding LineRouterMode}" Value="RouterNormal">
|
||||
<Setter Property="LargeIcon">
|
||||
<Setter.Value>
|
||||
<iconPacks:PackIconFontAwesome Kind="WindowMinimizeRegular" VerticalAlignment="Center" HorizontalAlignment="Center"/>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</DataTrigger>
|
||||
<DataTrigger Binding="{Binding LineRouterMode}" Value="Orthogonal">
|
||||
<DataTrigger Binding="{Binding LineRouterMode}" Value="RouterOrthogonal">
|
||||
<Setter Property="LargeIcon">
|
||||
<Setter.Value>
|
||||
<iconPacks:PackIconFontAwesome Kind="BorderStyleSolid" VerticalAlignment="Center" HorizontalAlignment="Center"/>
|
||||
@@ -885,7 +885,7 @@
|
||||
Text="连接线的连接方式"
|
||||
Width="190" />
|
||||
</Fluent:SplitButton.ToolTip>
|
||||
</Fluent:SplitButton>
|
||||
</Fluent:SplitButton>-->
|
||||
|
||||
<Fluent:SplitButton Header="形状" GroupName="DrawMode" IsCheckable="True" IsChecked="{Binding ShapeDrawModeSelected}" Width="50" VerticalAlignment="Top">
|
||||
<Fluent:MenuItem Header="矩形工具" Size="Middle" IsCheckable="True" IsChecked="{Binding ShapeDrawMode,Converter={dd:ConverterValueMapToBool Parameter='Rectangle'}, ConverterParameter='Rectangle'}" Icon="{iconPacks:Material Kind=RectangleOutline}" />
|
||||
|
||||
@@ -75,7 +75,7 @@ namespace AIStudio.Wpf.DiagramDesigner.Test.ViewModels
|
||||
DiagramViewModel.CellVerticalAlignment = CellVerticalAlignment.Center;
|
||||
DiagramViewModel.PageSizeType = PageSizeType.Custom;
|
||||
DiagramViewModel.PageSize = new Size(double.NaN, double.NaN);
|
||||
DiagramViewModel.DrawModeViewModel = new DrawModeViewModel() { LineDrawMode = DrawMode.BoundaryConnectingLine };
|
||||
DiagramViewModel.DrawModeViewModel = new DrawModeViewModel() { LineDrawMode = DrawMode.ConnectingLineBoundary };
|
||||
|
||||
DiagramViewModel.PropertyChanged += DiagramViewModel_PropertyChanged;
|
||||
}
|
||||
|
||||
@@ -284,7 +284,7 @@ namespace AIStudio.Wpf.DiagramDesigner
|
||||
}
|
||||
e.Handled = true;
|
||||
|
||||
if (_service.DrawModeViewModel.GetDrawMode() == DrawMode.SmoothConnectingLine)
|
||||
if (_service.DrawModeViewModel.GetDrawMode() == DrawMode.ConnectingLineSmooth)
|
||||
{
|
||||
if (connectorsHit.Count == 0)
|
||||
{
|
||||
@@ -378,7 +378,7 @@ namespace AIStudio.Wpf.DiagramDesigner
|
||||
sinkDataItem.DataItem.Parent.Items[indexOfLastTempConnection]);
|
||||
sinkDataItem.DataItem.Parent.AddItemCommand.Execute(new ConnectorViewModel(_viewModel, sourceDataItem, sinkDataItem, DrawMode, RouterMode));
|
||||
}
|
||||
else if (_service.DrawModeViewModel.GetDrawMode() == DrawMode.SmoothConnectingLine && connectorsHit.Count() == 1)
|
||||
else if (_service.DrawModeViewModel.GetDrawMode() == DrawMode.DirectLine && connectorsHit.Count() == 1)
|
||||
{
|
||||
LinkPointDesignerItemViewModel pointItemView = new LinkPointDesignerItemViewModel(e.GetPosition(this));
|
||||
FullyCreatedConnectorInfo sinkDataItem = pointItemView.TopConnector;
|
||||
|
||||
@@ -13,10 +13,10 @@ namespace AIStudio.Wpf.DiagramDesigner
|
||||
Polyline = 4,
|
||||
Polygon = 5,
|
||||
DirectLine = 6,
|
||||
SmoothConnectingLine = 10,
|
||||
StraightConnectingLine = 11,
|
||||
CornerConnectingLine = 12,
|
||||
BoundaryConnectingLine = 13,
|
||||
ConnectingLineSmooth = 10,
|
||||
ConnectingLineStraight = 11,
|
||||
ConnectingLineCorner = 12,
|
||||
ConnectingLineBoundary = 13,
|
||||
Text = 20,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ namespace AIStudio.Wpf.DiagramDesigner
|
||||
{
|
||||
public enum RouterMode
|
||||
{
|
||||
Normal,
|
||||
Orthogonal
|
||||
RouterNormal,
|
||||
RouterOrthogonal
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,179 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using AIStudio.Wpf.DiagramDesigner.Geometrys;
|
||||
|
||||
namespace AIStudio.Wpf.DiagramDesigner
|
||||
{
|
||||
public class BoundaryPathFinder : IPathFinder
|
||||
{
|
||||
public List<ConnectorPoint> UpdateConnectionPoints(IDiagramViewModel diagramViewModel, PointBase sourceA, PointBase sourceB, FullyCreatedConnectorInfo sourceConnectorInfo, ConnectorInfoBase sinkConnectorInfo)
|
||||
{
|
||||
List<ConnectorPoint> connectionPoints;
|
||||
var isFullConnection = sinkConnectorInfo is FullyCreatedConnectorInfo;
|
||||
|
||||
var points = new List<PointBase>()
|
||||
{
|
||||
sourceA,
|
||||
sourceB
|
||||
};
|
||||
|
||||
ConnectorInfo sourceInfo = ConnectorInfo(sourceConnectorInfo.Orientation,
|
||||
points[0].X,
|
||||
points[0].Y,
|
||||
sourceConnectorInfo.DataItem.ItemWidth,
|
||||
sourceConnectorInfo.DataItem.ItemHeight,
|
||||
points[0]);
|
||||
|
||||
|
||||
//StartPoint = points[0];
|
||||
if (isFullConnection)
|
||||
{
|
||||
|
||||
ConnectorInfo sinkInfo = ConnectorInfo(sinkConnectorInfo.Orientation,
|
||||
points[1].X,
|
||||
points[1].Y,
|
||||
((FullyCreatedConnectorInfo)sinkConnectorInfo).DataItem.ItemWidth,
|
||||
((FullyCreatedConnectorInfo)sinkConnectorInfo).DataItem.ItemHeight,
|
||||
points[1]);
|
||||
|
||||
connectionPoints = ConnectorPoint.ToList(GetConnectionLine(diagramViewModel, sourceInfo, sinkInfo, false, sourceConnectorInfo.IsInnerPoint));
|
||||
//EndPoint = ConnectionPoints.Last();
|
||||
}
|
||||
else
|
||||
{
|
||||
connectionPoints = ConnectorPoint.ToList(GetConnectionLine(diagramViewModel, sourceInfo, points[1], sourceConnectorInfo.Orientation, false, sourceConnectorInfo.IsInnerPoint));
|
||||
//EndPoint = new PointBase();
|
||||
}
|
||||
|
||||
return connectionPoints;
|
||||
}
|
||||
|
||||
public ConnectorInfo ConnectorInfo(ConnectorOrientation orientation, double left, double top, double width, double height, PointBase position)
|
||||
{
|
||||
return new ConnectorInfo()
|
||||
{
|
||||
Orientation = orientation,
|
||||
DesignerItemSize = new SizeBase(width, height),
|
||||
DesignerItemLeft = left,
|
||||
DesignerItemTop = top,
|
||||
Position = position
|
||||
};
|
||||
}
|
||||
|
||||
public List<PointBase> GetConnectionLine(IDiagramViewModel diagramViewModel, ConnectorInfo source, ConnectorInfo sink, bool showLastLine, bool sourceInnerPoint = false)
|
||||
{
|
||||
var points = new List<PointBase>();
|
||||
var ends = new List<PointBase> { source.Position, sink.Position };
|
||||
|
||||
points.Add(ends[0]);
|
||||
points.AddRange(GetMiddlePoints(source, sink, diagramViewModel.GridCellSize, diagramViewModel.GridMargin, true));
|
||||
points.Add(ends[1]);
|
||||
var res = points.ToArray();
|
||||
DoShift(res);
|
||||
return res.ToList();
|
||||
}
|
||||
|
||||
public List<PointBase> GetConnectionLine(IDiagramViewModel diagramViewModel, ConnectorInfo source, PointBase sinkPoint, ConnectorOrientation preferredOrientation, bool showLastLine, bool isInnerPoint = false)
|
||||
{
|
||||
var points = new List<PointBase>();
|
||||
var ends = new List<PointBase> { source.Position, sinkPoint };
|
||||
|
||||
points.Add(ends[0]);
|
||||
points.AddRange(GetMiddlePoints(source, new ConnectorInfo() { Orientation = ConnectorOrientation.Top, Position = sinkPoint }, diagramViewModel.GridCellSize, diagramViewModel.GridMargin, false));
|
||||
points.Add(ends[1]);
|
||||
var res = points.ToArray();
|
||||
DoShift(res);
|
||||
return res.ToList();
|
||||
}
|
||||
|
||||
private IEnumerable<PointBase> GetMiddlePoints(ConnectorInfo source, ConnectorInfo sink, SizeBase gridCellSize, double gridMargin, bool isFullConnection)
|
||||
{
|
||||
var points = new List<PointBase>();
|
||||
if (isFullConnection)
|
||||
{
|
||||
var p0 = GetFirstSegment(source.Orientation, source.Position, gridCellSize, gridMargin);
|
||||
var p1 = GetFirstSegment(sink.Orientation, sink.Position, gridCellSize, gridMargin);
|
||||
|
||||
if (p0 == p1)
|
||||
return points;
|
||||
|
||||
|
||||
var p2 = new PointBase(GetNearestCross(p0.X, p1.X), GetNearestCross(p0.Y, p1.Y));
|
||||
var p3 = new PointBase(GetNearestCross(p1.X, p0.X), GetNearestCross(p1.Y, p0.Y));
|
||||
if (p2 == p3)
|
||||
{
|
||||
points.Add(p0);
|
||||
points.Add(p2);
|
||||
points.Add(p1);
|
||||
}
|
||||
else
|
||||
{
|
||||
points.Add(p0);
|
||||
points.Add(p2);
|
||||
if (!(Math.Abs(p2.X - p3.X) < 0.0001) && !(Math.Abs(p2.Y - p3.Y) < 0.0001))
|
||||
points.Add(new PointBase(p2.X, p3.Y));
|
||||
points.Add(p3);
|
||||
points.Add(p1);
|
||||
}
|
||||
DoScale(points, gridCellSize, gridMargin);
|
||||
}
|
||||
return points;
|
||||
}
|
||||
|
||||
private PointBase GetFirstSegment(ConnectorOrientation orientation, PointBase point, SizeBase cellSize, double margin)
|
||||
{
|
||||
double x = (int)((point.X - margin) / cellSize.Width) + 0.5;
|
||||
double y = (int)((point.Y - margin) / cellSize.Height) + 0.5;
|
||||
if (orientation == ConnectorOrientation.Top)
|
||||
return new PointBase(x, y - 0.5);
|
||||
else if (orientation == ConnectorOrientation.Bottom)
|
||||
return new PointBase(x, y + 0.5);
|
||||
else if (orientation == ConnectorOrientation.Left)
|
||||
return new PointBase(x - 0.5, y);
|
||||
else
|
||||
return new PointBase(x + 0.5, y);
|
||||
}
|
||||
|
||||
public static double GetNearestCross(double a, double b)
|
||||
{
|
||||
if (Math.Abs(a - b) < 0.0001 && (int)a == a)
|
||||
return a;
|
||||
else if (a < b)
|
||||
return Math.Ceiling(a);
|
||||
else
|
||||
return Math.Floor(a);
|
||||
}
|
||||
|
||||
public static PointBase SegmentMiddlePoint(PointBase p1, PointBase p2)
|
||||
{
|
||||
return new PointBase((p1.X + p2.X) / 2, (p1.Y + p2.Y) / 2);
|
||||
}
|
||||
|
||||
|
||||
private void DoScale(List<PointBase> points, SizeBase cellSize, double margin)
|
||||
{
|
||||
for (int i = 0; i < points.Count; i++)
|
||||
{
|
||||
points[i] = new PointBase(points[i].X * cellSize.Width + margin,
|
||||
points[i].Y * cellSize.Height + margin);
|
||||
}
|
||||
}
|
||||
|
||||
private void DoShift(PointBase[] points)
|
||||
{
|
||||
double left = new PointBase[] { points.FirstOrDefault(), points.LastOrDefault() }.Min(p => p.X);
|
||||
double top = new PointBase[] { points.FirstOrDefault(), points.LastOrDefault() }.Min(p => p.Y);
|
||||
|
||||
for (int i = 0; i < points.Length; i++)
|
||||
{
|
||||
points[i].X = points[i].X - left;
|
||||
points[i].Y = points[i].Y - top;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using AIStudio.Wpf.DiagramDesigner.Geometrys;
|
||||
|
||||
namespace AIStudio.Wpf.DiagramDesigner
|
||||
{
|
||||
public interface IPathFinder
|
||||
{
|
||||
List<ConnectorPoint> UpdateConnectionPoints(IDiagramViewModel diagramViewModel, PointBase sourceA, PointBase sourceB, FullyCreatedConnectorInfo sourceConnectorInfo, ConnectorInfoBase sinkConnectorInfo);
|
||||
List<PointBase> GetConnectionLine(IDiagramViewModel diagramViewModel, ConnectorInfo source, ConnectorInfo sink, bool showLastLine, bool sourceInnerPoint = false);
|
||||
List<PointBase> GetConnectionLine(IDiagramViewModel diagramViewModel, ConnectorInfo source, PointBase sinkPoint, ConnectorOrientation preferredOrientation, bool showLastLine, bool isInnerPoint = false);
|
||||
}
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using AIStudio.Wpf.DiagramDesigner.Geometrys;
|
||||
|
||||
namespace AIStudio.Wpf.DiagramDesigner
|
||||
{
|
||||
public class StraightLinePathFinder : IPathFinder
|
||||
{
|
||||
public List<ConnectorPoint> UpdateConnectionPoints(IDiagramViewModel diagramViewModel, PointBase sourceA, PointBase sourceB, FullyCreatedConnectorInfo sourceConnectorInfo, ConnectorInfoBase sinkConnectorInfo)
|
||||
{
|
||||
var area = new RectangleBase(sourceA, sourceB);
|
||||
var connectionPoints = ConnectorPoint.ToList(new List<PointBase>()
|
||||
{
|
||||
|
||||
new PointBase(sourceA.X < sourceB.X ? 0d : area.Width, sourceA.Y < sourceB.Y ? 0d : area.Height ),
|
||||
new PointBase(sourceA.X > sourceB.X ? 0d : area.Width, sourceA.Y > sourceB.Y ? 0d : area.Height)
|
||||
});
|
||||
|
||||
return connectionPoints;
|
||||
}
|
||||
|
||||
public List<PointBase> GetConnectionLine(IDiagramViewModel diagramViewModel, ConnectorInfo source, ConnectorInfo sink, bool showLastLine, bool sourceInnerPoint = false)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public List<PointBase> GetConnectionLine(IDiagramViewModel diagramViewModel, ConnectorInfo source, PointBase sinkPoint, ConnectorOrientation preferredOrientation, bool showLastLine, bool isInnerPoint = false)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using AIStudio.Wpf.DiagramDesigner.Geometrys;
|
||||
|
||||
namespace AIStudio.Wpf.DiagramDesigner
|
||||
{
|
||||
public class ConnectingLineBoundary : IPathGenerator
|
||||
{
|
||||
public PathGeneratorResult Get(IDiagramViewModel _, ConnectorViewModel link, PointBase[] route, PointBase source, PointBase target)
|
||||
{
|
||||
return PathGenerators.Boundary(_, link, route, source, target);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using AIStudio.Wpf.DiagramDesigner.Geometrys;
|
||||
|
||||
namespace AIStudio.Wpf.DiagramDesigner
|
||||
{
|
||||
public class ConnectingLineCorner : IPathGenerator
|
||||
{
|
||||
public PathGeneratorResult Get(IDiagramViewModel _, ConnectorViewModel link, PointBase[] route, PointBase source, PointBase target)
|
||||
{
|
||||
return PathGenerators.Corner(_, link, route, source, target);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5,7 +5,7 @@ using AIStudio.Wpf.DiagramDesigner.Geometrys;
|
||||
|
||||
namespace AIStudio.Wpf.DiagramDesigner
|
||||
{
|
||||
public class SmoothPathGenerator : IPathGenerator
|
||||
public class ConnectingLineSmooth : IPathGenerator
|
||||
{
|
||||
public PathGeneratorResult Get(IDiagramViewModel _, ConnectorViewModel link, PointBase[] route, PointBase source, PointBase target)
|
||||
{
|
||||
@@ -5,7 +5,7 @@ using AIStudio.Wpf.DiagramDesigner.Geometrys;
|
||||
|
||||
namespace AIStudio.Wpf.DiagramDesigner
|
||||
{
|
||||
public class StraightPathGenerator : IPathGenerator
|
||||
public class ConnectingLineStraight : IPathGenerator
|
||||
{
|
||||
public PathGeneratorResult Get(IDiagramViewModel _, ConnectorViewModel link, PointBase[] route, PointBase source, PointBase target)
|
||||
{
|
||||
@@ -0,0 +1,111 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using AIStudio.Wpf.DiagramDesigner.Geometrys;
|
||||
|
||||
namespace AIStudio.Wpf.DiagramDesigner
|
||||
{
|
||||
public static partial class PathGenerators
|
||||
{
|
||||
public static PathGeneratorResult Boundary(IDiagramViewModel _, ConnectorViewModel link, PointBase[] route, PointBase source, PointBase target)
|
||||
{
|
||||
route = ConcatRouteAndSourceAndTarget(route, source, target);
|
||||
|
||||
if (route.Length > 2)
|
||||
return CurveThroughPoints(route, link);
|
||||
|
||||
route = GetRouteWithMiddlePoints(_, link, route);
|
||||
double? sourceAngle = null;
|
||||
double? targetAngle = null;
|
||||
|
||||
sourceAngle = SourceMarkerAdjustement(route, link.ColorViewModel.LeftArrowPathStyle == ArrowPathStyle.None ? 0d : (double)link.ColorViewModel.LeftArrowSizeStyle);
|
||||
targetAngle = TargetMarkerAdjustement(route, link.ColorViewModel.RightArrowPathStyle == ArrowPathStyle.None ? 0d : (double)link.ColorViewModel.RightArrowPathStyle);
|
||||
|
||||
DoShift(route, link);
|
||||
|
||||
var paths = new string[route.Length - 1];
|
||||
for (var i = 0; i < route.Length - 1; i++)
|
||||
{
|
||||
paths[i] = FormattableString.Invariant($"M {route[i].X} {route[i].Y} L {route[i + 1].X} {route[i + 1].Y}");
|
||||
}
|
||||
|
||||
return new PathGeneratorResult(paths, sourceAngle, route[0], targetAngle, route[route.Length - 1]);
|
||||
}
|
||||
|
||||
private static PointBase[] GetRouteWithMiddlePoints(IDiagramViewModel _, ConnectorViewModel link, PointBase[] route)
|
||||
{
|
||||
var middle = GetMiddlePoints(
|
||||
link.SourceConnectorInfo.Location.Position,
|
||||
link.SourceConnectorInfo.Orientation,
|
||||
link.SinkConnectorInfo.Location.Position,
|
||||
link.IsFullConnection ? link.SinkConnectorInfoFully.Orientation : (link.SinkConnectorInfo.Location.Position.Y >= link.SourceConnectorInfo.Location.Position.Y ? ConnectorOrientation.Top : ConnectorOrientation.Bottom),
|
||||
_.GridCellSize,
|
||||
_.GridMargin);
|
||||
|
||||
middle.Insert(0, route[0]);
|
||||
middle.Add(route[1]);
|
||||
|
||||
return middle.ToArray();
|
||||
}
|
||||
|
||||
private static List<PointBase> GetMiddlePoints(PointBase source, ConnectorOrientation sourceOrientation, PointBase sink, ConnectorOrientation sinkOrientation, SizeBase gridCellSize, double gridMargin)
|
||||
{
|
||||
var points = new List<PointBase>();
|
||||
|
||||
var p0 = GetFirstSegment(source, sourceOrientation, gridCellSize, gridMargin);
|
||||
var p1 = GetFirstSegment(sink, sinkOrientation, gridCellSize, gridMargin);
|
||||
|
||||
if (p0 == p1)
|
||||
return points;
|
||||
|
||||
var p2 = new PointBase(GetNearestCross(p0.X, p1.X, gridCellSize.Width, gridMargin), GetNearestCross(p0.Y, p1.Y, gridCellSize.Height, gridMargin));
|
||||
var p3 = new PointBase(GetNearestCross(p1.X, p0.X, gridCellSize.Width, gridMargin), GetNearestCross(p1.Y, p0.Y, gridCellSize.Height, gridMargin));
|
||||
if (p2 == p3)
|
||||
{
|
||||
points.Add(p0);
|
||||
points.Add(p2);
|
||||
points.Add(p1);
|
||||
}
|
||||
else
|
||||
{
|
||||
points.Add(p0);
|
||||
points.Add(p2);
|
||||
if (!(Math.Abs(p2.X - p3.X) < 0.0001) && !(Math.Abs(p2.Y - p3.Y) < 0.0001))
|
||||
points.Add(new PointBase(p2.X, p3.Y));
|
||||
points.Add(p3);
|
||||
points.Add(p1);
|
||||
}
|
||||
|
||||
return points;
|
||||
}
|
||||
|
||||
private static PointBase GetFirstSegment(PointBase point, ConnectorOrientation orientation, SizeBase cellSize, double margin)
|
||||
{
|
||||
double x = ((int)((point.X - margin) / cellSize.Width) + 0.5) * cellSize.Width + margin;
|
||||
double y = ((int)((point.Y - margin) / cellSize.Height) + 0.5) * cellSize.Height + margin;
|
||||
if (orientation == ConnectorOrientation.Top)
|
||||
return new PointBase(x, y - 0.5 * cellSize.Height);
|
||||
else if (orientation == ConnectorOrientation.Bottom)
|
||||
return new PointBase(x, y + 0.5 * cellSize.Height);
|
||||
else if (orientation == ConnectorOrientation.Left)
|
||||
return new PointBase(x - 0.5 * cellSize.Width, y);
|
||||
else
|
||||
return new PointBase(x + 0.5 * cellSize.Width, y);
|
||||
}
|
||||
|
||||
public static double GetNearestCross(double a, double b, double cellSize, double margin)
|
||||
{
|
||||
if (Math.Abs(a - b) < 0.0001 && (int)((a - margin)/ cellSize) == ((a - margin) / cellSize))
|
||||
return a;
|
||||
else if (a < b)
|
||||
return Math.Ceiling((a - margin) / cellSize) * cellSize + margin;
|
||||
else
|
||||
return Math.Floor((a - margin) / cellSize) * cellSize + margin;
|
||||
}
|
||||
|
||||
public static PointBase SegmentMiddlePoint(PointBase p1, PointBase p2)
|
||||
{
|
||||
return new PointBase((p1.X + p2.X) / 2, (p1.Y + p2.Y) / 2);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,85 +1,59 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Windows.Controls;
|
||||
using System.Text;
|
||||
using AIStudio.Wpf.DiagramDesigner.Geometrys;
|
||||
|
||||
namespace AIStudio.Wpf.DiagramDesigner
|
||||
{
|
||||
// Note: I couldn't find a useful open source library that does
|
||||
// orthogonal routing so started to write something on my own.
|
||||
// Categorize this as a quick and dirty short term solution.
|
||||
// I will keep on searching.
|
||||
|
||||
// Helper class to provide an orthogonal connection path
|
||||
public class OrthogonalPathFinder : IPathFinder
|
||||
public static partial class PathGenerators
|
||||
{
|
||||
public static PathGeneratorResult Corner(IDiagramViewModel _, ConnectorViewModel link, PointBase[] route, PointBase source, PointBase target)
|
||||
{
|
||||
route = ConcatRouteAndSourceAndTarget(route, source, target);
|
||||
|
||||
if (route.Length > 2)
|
||||
return CurveThroughPoints(route, link);
|
||||
|
||||
if (link.IsFullConnection)
|
||||
route = GetRouteWithFullConnectionLine(_, link, route);
|
||||
else
|
||||
route = GetRouteWithPartConnectionLine(_, link, route);
|
||||
double? sourceAngle = null;
|
||||
double? targetAngle = null;
|
||||
|
||||
sourceAngle = SourceMarkerAdjustement(route, link.ColorViewModel.LeftArrowPathStyle == ArrowPathStyle.None ? 0d : (double)link.ColorViewModel.LeftArrowSizeStyle);
|
||||
targetAngle = TargetMarkerAdjustement(route, link.ColorViewModel.RightArrowPathStyle == ArrowPathStyle.None ? 0d : (double)link.ColorViewModel.RightArrowPathStyle);
|
||||
|
||||
DoShift(route, link);
|
||||
|
||||
var paths = new string[route.Length - 1];
|
||||
for (var i = 0; i < route.Length - 1; i++)
|
||||
{
|
||||
paths[i] = FormattableString.Invariant($"M {route[i].X} {route[i].Y} L {route[i + 1].X} {route[i + 1].Y}");
|
||||
}
|
||||
|
||||
return new PathGeneratorResult(paths, sourceAngle, route[0], targetAngle, route[route.Length - 1]);
|
||||
}
|
||||
|
||||
private const int const_margin = 20;
|
||||
|
||||
public List<ConnectorPoint> UpdateConnectionPoints(IDiagramViewModel diagramViewModel, PointBase sourceA, PointBase sourceB, FullyCreatedConnectorInfo sourceConnectorInfo, ConnectorInfoBase sinkConnectorInfo)
|
||||
private static PointBase[] GetRouteWithFullConnectionLine(IDiagramViewModel _, ConnectorViewModel link, PointBase[] route)
|
||||
{
|
||||
List<ConnectorPoint> connectionPoints;
|
||||
var isFullConnection = sinkConnectorInfo is FullyCreatedConnectorInfo;
|
||||
var area = new RectangleBase(sourceA, sourceB);
|
||||
var sourceInnerPoint = link.SourceConnectorInfo.IsInnerPoint;
|
||||
PointBase sourcePoint = link.SourceConnectorInfo.Location.MiddlePosition;
|
||||
PointBase sinkPoint = link.SinkConnectorInfo.Location.MiddlePosition;
|
||||
ConnectorOrientation sourceOrientation = link.SourceConnectorInfo.Orientation;
|
||||
ConnectorOrientation sinkOrientation = link.SinkConnectorInfoFully.Orientation;
|
||||
|
||||
var points = new List<PointBase>()
|
||||
{
|
||||
new PointBase(sourceA.X < sourceB.X ? 0d : area.Width, sourceA.Y < sourceB.Y ? 0d : area.Height ),
|
||||
new PointBase(sourceA.X > sourceB.X ? 0d : area.Width, sourceA.Y > sourceB.Y ? 0d : area.Height)
|
||||
};
|
||||
|
||||
ConnectorInfo sourceInfo = ConnectorInfo(sourceConnectorInfo.Orientation,
|
||||
points[0].X,
|
||||
points[0].Y,
|
||||
sourceConnectorInfo.DataItem.ItemWidth,
|
||||
sourceConnectorInfo.DataItem.ItemHeight,
|
||||
points[0]);
|
||||
|
||||
//StartPoint = points[0];
|
||||
if (isFullConnection)
|
||||
{
|
||||
|
||||
ConnectorInfo sinkInfo = ConnectorInfo(sinkConnectorInfo.Orientation,
|
||||
points[1].X,
|
||||
points[1].Y,
|
||||
((FullyCreatedConnectorInfo)sinkConnectorInfo).DataItem.ItemWidth,
|
||||
((FullyCreatedConnectorInfo)sinkConnectorInfo).DataItem.ItemHeight,
|
||||
points[1]);
|
||||
|
||||
connectionPoints = ConnectorPoint.ToList(GetConnectionLine(diagramViewModel, sourceInfo, sinkInfo, false, sourceConnectorInfo.IsInnerPoint));
|
||||
//EndPoint = ConnectionPoints.Last();
|
||||
}
|
||||
else
|
||||
{
|
||||
connectionPoints = ConnectorPoint.ToList(GetConnectionLine(diagramViewModel, sourceInfo, points[1], sourceConnectorInfo.Orientation, false, sourceConnectorInfo.IsInnerPoint));
|
||||
//EndPoint = new PointBase();
|
||||
}
|
||||
|
||||
return connectionPoints;
|
||||
}
|
||||
|
||||
public ConnectorInfo ConnectorInfo(ConnectorOrientation orientation, double left, double top, double width, double height, PointBase position)
|
||||
{
|
||||
return new ConnectorInfo()
|
||||
{
|
||||
Orientation = orientation,
|
||||
DesignerItemSize = new SizeBase(width, height),
|
||||
DesignerItemLeft = left,
|
||||
DesignerItemTop = top,
|
||||
Position = position
|
||||
};
|
||||
}
|
||||
|
||||
public List<PointBase> GetConnectionLine(IDiagramViewModel diagramViewModel, ConnectorInfo source, ConnectorInfo sink, bool showLastLine, bool sourceInnerPoint = false)
|
||||
{
|
||||
List<PointBase> linePoints = new List<PointBase>();
|
||||
int margin1 = sourceInnerPoint ? 0 : const_margin;
|
||||
int margin2 = const_margin;
|
||||
|
||||
RectangleBase rectSource = GetRectWithMargin(source, margin1);
|
||||
RectangleBase rectSink = GetRectWithMargin(sink, margin2);
|
||||
RectangleBase rectSource = GetRectWithMargin(sourcePoint, margin1);
|
||||
RectangleBase rectSink = GetRectWithMargin(sinkPoint, margin2);
|
||||
|
||||
PointBase startPoint = GetOffsetPoint(source, rectSource, sourceInnerPoint);
|
||||
PointBase endPoint = GetOffsetPoint(sink, rectSink);
|
||||
PointBase startPoint = GetOffsetPoint(sourcePoint, sourceOrientation, rectSource, sourceInnerPoint);
|
||||
PointBase endPoint = GetOffsetPoint(sinkPoint, sinkOrientation, rectSink);
|
||||
|
||||
linePoints.Add(startPoint);
|
||||
PointBase currentPoint = startPoint;
|
||||
@@ -97,7 +71,7 @@ namespace AIStudio.Wpf.DiagramDesigner
|
||||
break;
|
||||
}
|
||||
|
||||
PointBase neighbour = GetNearestVisibleNeighborSink(currentPoint, endPoint, sink, rectSource, rectSink);
|
||||
PointBase neighbour = GetNearestVisibleNeighborSink(currentPoint, endPoint, sinkOrientation, rectSource, rectSink);
|
||||
if (!double.IsNaN(neighbour.X))
|
||||
{
|
||||
linePoints.Add(neighbour);
|
||||
@@ -109,7 +83,7 @@ namespace AIStudio.Wpf.DiagramDesigner
|
||||
if (currentPoint == startPoint)
|
||||
{
|
||||
bool flag;
|
||||
PointBase n = GetNearestNeighborSource(source, endPoint, rectSource, rectSink, out flag, sourceInnerPoint);
|
||||
PointBase n = GetNearestNeighborSource(sourceOrientation, endPoint, rectSource, rectSink, out flag, sourceInnerPoint);
|
||||
if (linePoints.Contains(n))
|
||||
{
|
||||
break;
|
||||
@@ -120,7 +94,7 @@ namespace AIStudio.Wpf.DiagramDesigner
|
||||
if (!IsRectVisible(currentPoint, rectSink, new RectangleBase[] { rectSource }))
|
||||
{
|
||||
PointBase n1, n2;
|
||||
GetOppositeCorners(source.Orientation, rectSource, out n1, out n2, sourceInnerPoint);
|
||||
GetOppositeCorners(sourceOrientation, rectSource, out n1, out n2, sourceInnerPoint);
|
||||
if (flag)
|
||||
{
|
||||
linePoints.Add(n1);
|
||||
@@ -154,8 +128,8 @@ namespace AIStudio.Wpf.DiagramDesigner
|
||||
{
|
||||
PointBase n1, n2; // neighbour corner
|
||||
PointBase s1, s2; // opposite corner
|
||||
GetNeighborCorners(sink.Orientation, rectSink, out s1, out s2);
|
||||
GetOppositeCorners(sink.Orientation, rectSink, out n1, out n2);
|
||||
GetNeighborCorners(sinkOrientation, rectSink, out s1, out s2);
|
||||
GetOppositeCorners(sinkOrientation, rectSink, out n1, out n2);
|
||||
|
||||
bool n1Visible = IsPointVisible(currentPoint, n1, new RectangleBase[] { rectSource, rectSink });
|
||||
bool n2Visible = IsPointVisible(currentPoint, n2, new RectangleBase[] { rectSource, rectSink });
|
||||
@@ -260,20 +234,27 @@ namespace AIStudio.Wpf.DiagramDesigner
|
||||
linePoints.Add(endPoint);
|
||||
}
|
||||
|
||||
linePoints = OptimizeLinePoints(linePoints, new RectangleBase[] { rectSource, rectSink }, source.Orientation, sink.Orientation);
|
||||
linePoints = OptimizeLinePoints(linePoints, new RectangleBase[] { rectSource, rectSink }, sourceOrientation, sinkOrientation);
|
||||
|
||||
CheckPathEnd(source, sink, showLastLine, linePoints, sourceInnerPoint);
|
||||
linePoints.Insert(0, sourcePoint);
|
||||
linePoints.Add(sinkPoint);
|
||||
|
||||
return linePoints;
|
||||
return linePoints.ToArray();
|
||||
}
|
||||
|
||||
public List<PointBase> GetConnectionLine(IDiagramViewModel diagramViewModel, ConnectorInfo source, PointBase sinkPoint, ConnectorOrientation preferredOrientation, bool showLastLine, bool isInnerPoint = false)
|
||||
private static PointBase[] GetRouteWithPartConnectionLine(IDiagramViewModel diagramViewModel, ConnectorViewModel link, PointBase[] route)
|
||||
{
|
||||
List<PointBase> linePoints = new List<PointBase>();
|
||||
int margin = isInnerPoint ? 0 : const_margin;
|
||||
var sourceInnerPoint = link.SourceConnectorInfo.IsInnerPoint;
|
||||
PointBase sourcePoint = link.SourceConnectorInfo.Location.MiddlePosition;
|
||||
PointBase sinkPoint = link.SinkConnectorInfo.Location.MiddlePosition;
|
||||
ConnectorOrientation sourceOrientation = link.SourceConnectorInfo.Orientation;
|
||||
ConnectorOrientation preferredOrientation = link.SourceConnectorInfo.Orientation;
|
||||
|
||||
RectangleBase rectSource = GetRectWithMargin(source, margin);
|
||||
PointBase startPoint = GetOffsetPoint(source, rectSource, isInnerPoint);
|
||||
List<PointBase> linePoints = new List<PointBase>();
|
||||
int margin = sourceInnerPoint ? 0 : const_margin;
|
||||
|
||||
RectangleBase rectSource = GetRectWithMargin(sourcePoint, margin);
|
||||
PointBase startPoint = GetOffsetPoint(sourcePoint, sourceOrientation, rectSource, sourceInnerPoint);
|
||||
PointBase endPoint = sinkPoint;
|
||||
|
||||
linePoints.Add(startPoint);
|
||||
@@ -290,7 +271,7 @@ namespace AIStudio.Wpf.DiagramDesigner
|
||||
}
|
||||
|
||||
bool sideFlag;
|
||||
PointBase n = GetNearestNeighborSource(source, endPoint, rectSource, out sideFlag, isInnerPoint);
|
||||
PointBase n = GetNearestNeighborSource(sourceOrientation, endPoint, rectSource, out sideFlag, sourceInnerPoint);
|
||||
linePoints.Add(n);
|
||||
currentPoint = n;
|
||||
|
||||
@@ -302,7 +283,7 @@ namespace AIStudio.Wpf.DiagramDesigner
|
||||
else
|
||||
{
|
||||
PointBase n1, n2;
|
||||
GetOppositeCorners(source.Orientation, rectSource, out n1, out n2, isInnerPoint);
|
||||
GetOppositeCorners(sourceOrientation, rectSource, out n1, out n2, sourceInnerPoint);
|
||||
if (sideFlag)
|
||||
linePoints.Add(n1);
|
||||
else
|
||||
@@ -319,16 +300,13 @@ namespace AIStudio.Wpf.DiagramDesigner
|
||||
}
|
||||
|
||||
if (preferredOrientation != ConnectorOrientation.None)
|
||||
linePoints = OptimizeLinePoints(linePoints, new RectangleBase[] { rectSource }, source.Orientation, preferredOrientation);
|
||||
linePoints = OptimizeLinePoints(linePoints, new RectangleBase[] { rectSource }, sourceOrientation, preferredOrientation);
|
||||
else
|
||||
linePoints = OptimizeLinePoints(linePoints, new RectangleBase[] { rectSource }, source.Orientation, GetOpositeOrientation(source.Orientation));
|
||||
linePoints = OptimizeLinePoints(linePoints, new RectangleBase[] { rectSource }, sourceOrientation, GetOpositeOrientation(sourceOrientation));
|
||||
|
||||
linePoints.Insert(0, sourcePoint);
|
||||
|
||||
if (!showLastLine)
|
||||
{
|
||||
linePoints.Insert(0, source.Position);
|
||||
}
|
||||
|
||||
return linePoints;
|
||||
return linePoints.ToArray();
|
||||
}
|
||||
|
||||
private static List<PointBase> OptimizeLinePoints(List<PointBase> linePoints, RectangleBase[] rectangles, ConnectorOrientation sourceOrientation, ConnectorOrientation sinkOrientation)
|
||||
@@ -434,31 +412,10 @@ namespace AIStudio.Wpf.DiagramDesigner
|
||||
throw new Exception("Failed to retrieve orientation");
|
||||
}
|
||||
|
||||
private static Orientation GetOrientation(ConnectorOrientation sourceOrientation, bool isInnerPoint)
|
||||
{
|
||||
if (isInnerPoint)
|
||||
{
|
||||
return Orientation.Vertical;
|
||||
}
|
||||
switch (sourceOrientation)
|
||||
{
|
||||
case ConnectorOrientation.Left:
|
||||
return Orientation.Horizontal;
|
||||
case ConnectorOrientation.Top:
|
||||
return Orientation.Vertical;
|
||||
case ConnectorOrientation.Right:
|
||||
return Orientation.Horizontal;
|
||||
case ConnectorOrientation.Bottom:
|
||||
return Orientation.Vertical;
|
||||
default:
|
||||
throw new Exception("Unknown ConnectorOrientation");
|
||||
}
|
||||
}
|
||||
|
||||
private static PointBase GetNearestNeighborSource(ConnectorInfo source, PointBase endPoint, RectangleBase rectSource, RectangleBase rectSink, out bool flag, bool isInnerPoint)
|
||||
private static PointBase GetNearestNeighborSource(ConnectorOrientation orientation, PointBase endPoint, RectangleBase rectSource, RectangleBase rectSink, out bool flag, bool isInnerPoint)
|
||||
{
|
||||
PointBase n1, n2; // neighbors
|
||||
GetNeighborCorners(source.Orientation, rectSource, out n1, out n2, isInnerPoint);
|
||||
GetNeighborCorners(orientation, rectSource, out n1, out n2, isInnerPoint);
|
||||
|
||||
if (rectSink.Contains(n1))
|
||||
{
|
||||
@@ -484,10 +441,10 @@ namespace AIStudio.Wpf.DiagramDesigner
|
||||
}
|
||||
}
|
||||
|
||||
private static PointBase GetNearestNeighborSource(ConnectorInfo source, PointBase endPoint, RectangleBase rectSource, out bool flag, bool isInnerPoint)
|
||||
private static PointBase GetNearestNeighborSource(ConnectorOrientation orientation, PointBase endPoint, RectangleBase rectSource, out bool flag, bool isInnerPoint)
|
||||
{
|
||||
PointBase n1, n2; // neighbors
|
||||
GetNeighborCorners(source.Orientation, rectSource, out n1, out n2, isInnerPoint);
|
||||
GetNeighborCorners(orientation, rectSource, out n1, out n2, isInnerPoint);
|
||||
|
||||
if ((Distance(n1, endPoint) <= Distance(n2, endPoint)))
|
||||
{
|
||||
@@ -501,10 +458,10 @@ namespace AIStudio.Wpf.DiagramDesigner
|
||||
}
|
||||
}
|
||||
|
||||
private static PointBase GetNearestVisibleNeighborSink(PointBase currentPoint, PointBase endPoint, ConnectorInfo sink, RectangleBase rectSource, RectangleBase rectSink)
|
||||
private static PointBase GetNearestVisibleNeighborSink(PointBase currentPoint, PointBase endPoint, ConnectorOrientation orientation, RectangleBase rectSource, RectangleBase rectSink)
|
||||
{
|
||||
PointBase s1, s2; // neighbors on sink side
|
||||
GetNeighborCorners(sink.Orientation, rectSink, out s1, out s2);
|
||||
GetNeighborCorners(orientation, rectSink, out s1, out s2);
|
||||
|
||||
bool flag1 = IsPointVisible(currentPoint, s1, new RectangleBase[] { rectSource, rectSink });
|
||||
bool flag2 = IsPointVisible(currentPoint, s2, new RectangleBase[] { rectSource, rectSink });
|
||||
@@ -633,40 +590,36 @@ namespace AIStudio.Wpf.DiagramDesigner
|
||||
return PointBase.Subtract(p1, p2).Length;
|
||||
}
|
||||
|
||||
private static RectangleBase GetRectWithMargin(ConnectorInfo connectorThumb, double margin)
|
||||
private static RectangleBase GetRectWithMargin(PointBase point, double margin)
|
||||
{
|
||||
RectangleBase rect = new RectangleBase(connectorThumb.DesignerItemLeft,
|
||||
connectorThumb.DesignerItemTop,
|
||||
0,
|
||||
0);
|
||||
|
||||
RectangleBase rect = new RectangleBase(point.X, point.Y, 0, 0);
|
||||
rect.Inflate(margin, margin);
|
||||
|
||||
return rect;
|
||||
}
|
||||
|
||||
private static PointBase GetOffsetPoint(ConnectorInfo connector, RectangleBase rect, bool isInnerPoint = false)
|
||||
private static PointBase GetOffsetPoint(PointBase point, ConnectorOrientation orientation, RectangleBase rect, bool isInnerPoint = false)
|
||||
{
|
||||
PointBase offsetPoint = new PointBase();
|
||||
if (isInnerPoint)
|
||||
{
|
||||
offsetPoint = new PointBase(connector.Position.X, connector.Position.Y);
|
||||
offsetPoint = new PointBase(point.X, point.Y);
|
||||
return offsetPoint;
|
||||
}
|
||||
|
||||
switch (connector.Orientation)
|
||||
switch (orientation)
|
||||
{
|
||||
case ConnectorOrientation.Left:
|
||||
offsetPoint = new PointBase(rect.Left, connector.Position.Y);
|
||||
offsetPoint = new PointBase(rect.Left, point.Y);
|
||||
break;
|
||||
case ConnectorOrientation.Top:
|
||||
offsetPoint = new PointBase(connector.Position.X, rect.Top);
|
||||
offsetPoint = new PointBase(point.X, rect.Top);
|
||||
break;
|
||||
case ConnectorOrientation.Right:
|
||||
offsetPoint = new PointBase(rect.Right, connector.Position.Y);
|
||||
offsetPoint = new PointBase(rect.Right, point.Y);
|
||||
break;
|
||||
case ConnectorOrientation.Bottom:
|
||||
offsetPoint = new PointBase(connector.Position.X, rect.Bottom);
|
||||
offsetPoint = new PointBase(point.X, rect.Bottom);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@@ -675,62 +628,6 @@ namespace AIStudio.Wpf.DiagramDesigner
|
||||
return offsetPoint;
|
||||
}
|
||||
|
||||
private static void CheckPathEnd(ConnectorInfo source, ConnectorInfo sink, bool showLastLine, List<PointBase> linePoints, bool sourceInnerPoint)
|
||||
{
|
||||
if (showLastLine)
|
||||
{
|
||||
PointBase startPoint = new PointBase(0, 0);
|
||||
PointBase endPoint = new PointBase(0, 0);
|
||||
double marginPath = 15;
|
||||
switch (source.Orientation)
|
||||
{
|
||||
case ConnectorOrientation.Left:
|
||||
startPoint = new PointBase(source.Position.X - marginPath, source.Position.Y);
|
||||
break;
|
||||
case ConnectorOrientation.Top:
|
||||
startPoint = new PointBase(source.Position.X, source.Position.Y - marginPath);
|
||||
break;
|
||||
case ConnectorOrientation.Right:
|
||||
startPoint = new PointBase(source.Position.X + marginPath, source.Position.Y);
|
||||
break;
|
||||
case ConnectorOrientation.Bottom:
|
||||
startPoint = new PointBase(source.Position.X, source.Position.Y + marginPath);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (sourceInnerPoint)
|
||||
{
|
||||
startPoint = new PointBase(source.Position.X, source.Position.Y);
|
||||
}
|
||||
|
||||
switch (sink.Orientation)
|
||||
{
|
||||
case ConnectorOrientation.Left:
|
||||
endPoint = new PointBase(sink.Position.X - marginPath, sink.Position.Y);
|
||||
break;
|
||||
case ConnectorOrientation.Top:
|
||||
endPoint = new PointBase(sink.Position.X, sink.Position.Y - marginPath);
|
||||
break;
|
||||
case ConnectorOrientation.Right:
|
||||
endPoint = new PointBase(sink.Position.X + marginPath, sink.Position.Y);
|
||||
break;
|
||||
case ConnectorOrientation.Bottom:
|
||||
endPoint = new PointBase(sink.Position.X, sink.Position.Y + marginPath);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
linePoints.Insert(0, startPoint);
|
||||
linePoints.Add(endPoint);
|
||||
}
|
||||
else
|
||||
{
|
||||
linePoints.Insert(0, source.Position);
|
||||
linePoints.Add(sink.Position);
|
||||
}
|
||||
}
|
||||
|
||||
private static ConnectorOrientation GetOpositeOrientation(ConnectorOrientation connectorOrientation)
|
||||
{
|
||||
switch (connectorOrientation)
|
||||
@@ -19,8 +19,8 @@ namespace AIStudio.Wpf.DiagramDesigner
|
||||
double? sourceAngle = null;
|
||||
double? targetAngle = null;
|
||||
|
||||
sourceAngle = SourceMarkerAdjustement(route, (double)link.ColorViewModel.LeftArrowSizeStyle);
|
||||
targetAngle = TargetMarkerAdjustement(route, (double)link.ColorViewModel.RightArrowPathStyle);
|
||||
sourceAngle = SourceMarkerAdjustement(route, link.ColorViewModel.LeftArrowPathStyle == ArrowPathStyle.None ? 0d : (double)link.ColorViewModel.LeftArrowSizeStyle);
|
||||
targetAngle = TargetMarkerAdjustement(route, link.ColorViewModel.RightArrowPathStyle == ArrowPathStyle.None ? 0d : (double)link.ColorViewModel.RightArrowPathStyle);
|
||||
|
||||
DoShift(route, link);
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ using AIStudio.Wpf.DiagramDesigner.Geometrys;
|
||||
|
||||
namespace AIStudio.Wpf.DiagramDesigner
|
||||
{
|
||||
public class NormalRouter : IRouter
|
||||
public class RouterNormal : IRouter
|
||||
{
|
||||
public PointBase[] Get(IDiagramViewModel _, ConnectorViewModel link)
|
||||
{
|
||||
@@ -5,7 +5,7 @@ using AIStudio.Wpf.DiagramDesigner.Geometrys;
|
||||
|
||||
namespace AIStudio.Wpf.DiagramDesigner
|
||||
{
|
||||
public class OrthogonalRouter : IRouter
|
||||
public class RouterOrthogonal : IRouter
|
||||
{
|
||||
public PointBase[] Get(IDiagramViewModel _, ConnectorViewModel link)
|
||||
{
|
||||
@@ -118,7 +118,7 @@ namespace AIStudio.Wpf.DiagramDesigner
|
||||
}
|
||||
}
|
||||
|
||||
private DrawMode _lineDrawMode = DrawMode.CornerConnectingLine;
|
||||
private DrawMode _lineDrawMode = DrawMode.ConnectingLineSmooth;
|
||||
public DrawMode LineDrawMode
|
||||
{
|
||||
get
|
||||
@@ -132,7 +132,7 @@ namespace AIStudio.Wpf.DiagramDesigner
|
||||
}
|
||||
}
|
||||
|
||||
private RouterMode _lineRouterMode = RouterMode.Normal;
|
||||
private RouterMode _lineRouterMode = RouterMode.RouterNormal;
|
||||
public RouterMode LineRouterMode
|
||||
{
|
||||
get
|
||||
|
||||
@@ -14,7 +14,7 @@ namespace AIStudio.Wpf.DiagramDesigner
|
||||
public ConnectorViewModel(IDiagramViewModel parent, FullyCreatedConnectorInfo sourceConnectorInfo, ConnectorInfoBase sinkConnectorInfo, DrawMode drawMode, RouterMode routerMode)
|
||||
{
|
||||
Parent = parent;
|
||||
PathMode = drawMode.ToString().Replace("ConnectingLine","");
|
||||
PathMode = drawMode.ToString();
|
||||
RouterMode = routerMode.ToString();
|
||||
Init(sourceConnectorInfo, sinkConnectorInfo);
|
||||
}
|
||||
@@ -26,9 +26,9 @@ namespace AIStudio.Wpf.DiagramDesigner
|
||||
Init(sourceConnectorInfo, sinkConnectorInfo);
|
||||
}
|
||||
|
||||
public ConnectorViewModel(FullyCreatedConnectorInfo sourceConnectorInfo, ConnectorInfoBase sinkConnectorInfo, DrawMode drawMode, RouterMode routerMode) :this(null, sourceConnectorInfo, sinkConnectorInfo, drawMode, routerMode)
|
||||
public ConnectorViewModel(FullyCreatedConnectorInfo sourceConnectorInfo, ConnectorInfoBase sinkConnectorInfo, DrawMode drawMode, RouterMode routerMode) : this(null, sourceConnectorInfo, sinkConnectorInfo, drawMode, routerMode)
|
||||
{
|
||||
|
||||
|
||||
}
|
||||
|
||||
private void Init(FullyCreatedConnectorInfo sourceConnectorInfo, ConnectorInfoBase sinkConnectorInfo)
|
||||
@@ -36,10 +36,10 @@ namespace AIStudio.Wpf.DiagramDesigner
|
||||
this.Parent = sourceConnectorInfo.DataItem.Parent;
|
||||
|
||||
var routetype = GlobalType.AllTypes.Where(p => typeof(IRouter).IsAssignableFrom(p)).FirstOrDefault(p => p.Name == RouterMode);
|
||||
Router = routetype != null ? (System.Activator.CreateInstance(routetype) as IRouter) : new NormalRouter();
|
||||
Router = routetype != null ? (System.Activator.CreateInstance(routetype) as IRouter) : new RouterNormal();
|
||||
|
||||
var pathGeneratortype = GlobalType.AllTypes.Where(p => typeof(IPathGenerator).IsAssignableFrom(p)).FirstOrDefault(p => p.Name == PathMode);
|
||||
PathGenerator = pathGeneratortype != null ? (System.Activator.CreateInstance(pathGeneratortype) as IPathGenerator) : new SmoothPathGenerator();
|
||||
PathGenerator = pathGeneratortype != null ? (System.Activator.CreateInstance(pathGeneratortype) as IPathGenerator) : new ConnectingLineSmooth();
|
||||
|
||||
this.SourceConnectorInfo = sourceConnectorInfo;
|
||||
this.SinkConnectorInfo = sinkConnectorInfo;
|
||||
@@ -72,7 +72,7 @@ namespace AIStudio.Wpf.DiagramDesigner
|
||||
public override Type ToXmlType()
|
||||
{
|
||||
return typeof(ConnectionItem);
|
||||
}
|
||||
}
|
||||
|
||||
private PointBase _sourceA;
|
||||
public PointBase SourceA
|
||||
@@ -249,7 +249,7 @@ namespace AIStudio.Wpf.DiagramDesigner
|
||||
{
|
||||
SourceB = _sinkConnectorInfo.Location;
|
||||
if (_sinkConnectorInfo is FullyCreatedConnectorInfo)
|
||||
{
|
||||
{
|
||||
(((FullyCreatedConnectorInfo)_sinkConnectorInfo).DataItem as INotifyPropertyChanged).PropertyChanged += new WeakINPCEventHandler(ConnectorViewModel_PropertyChanged).Handler;
|
||||
}
|
||||
}
|
||||
@@ -297,18 +297,19 @@ namespace AIStudio.Wpf.DiagramDesigner
|
||||
|
||||
private void UpdateConnectionPoints()
|
||||
{
|
||||
//ConnectionPoints = PathFinder.UpdateConnectionPoints(Parent, SourceA, SourceB, SourceConnectorInfo, SinkConnectorInfo);
|
||||
//StartPoint = ConnectionPoints.First();
|
||||
//EndPoint = ConnectionPoints.Last();
|
||||
if (SourceConnectorInfo == null || SinkConnectorInfo == null)
|
||||
return;
|
||||
|
||||
var route = Router.Get(Parent, this);
|
||||
|
||||
|
||||
(var source, var target) = FindConnectionPoints(route);
|
||||
if (source == null || target == null)
|
||||
return;
|
||||
|
||||
PathGeneratorResult = PathGenerator.Get(Parent, this, route, source.Value, target.Value);
|
||||
}
|
||||
StartPoint = PathGeneratorResult.SourceMarkerPosition ?? new PointBase();
|
||||
EndPoint = PathGeneratorResult.TargetMarkerPosition ?? new PointBase();
|
||||
}
|
||||
|
||||
private void ConnectorViewModel_PropertyChanged(object sender, PropertyChangedEventArgs e)
|
||||
{
|
||||
@@ -338,7 +339,7 @@ namespace AIStudio.Wpf.DiagramDesigner
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public SimpleCommand DeleteConnectionCommand
|
||||
{
|
||||
@@ -369,14 +370,14 @@ namespace AIStudio.Wpf.DiagramDesigner
|
||||
TextDesignerItemViewModel textitem = new TextDesignerItemViewModel();
|
||||
textitem.ItemWidth = Double.NaN;
|
||||
textitem.ItemHeight = double.NaN;
|
||||
if (diagramVM.DiagramType == DiagramType.FlowChart)
|
||||
{
|
||||
var mid = (int)(ConnectionPoints.Count / 2);
|
||||
var p = BoundaryPathFinder.SegmentMiddlePoint(ConnectionPoints[mid - 1], ConnectionPoints[mid]);
|
||||
textitem.Left = this.Area.Left + p.X + 2;
|
||||
textitem.Top = this.Area.Top + p.Y - 15;
|
||||
}
|
||||
else
|
||||
//if (this.PathMode == DrawMode.ConnectingLineBoundary.ToString())
|
||||
//{
|
||||
// var mid = (int)(ConnectionPoints.Count / 2);
|
||||
// var p = PathGenerators.SegmentMiddlePoint(ConnectionPoints[mid - 1], ConnectionPoints[mid]);
|
||||
// textitem.Left = this.Area.Left + p.X + 2;
|
||||
// textitem.Top = this.Area.Top + p.Y - 15;
|
||||
//}
|
||||
//else
|
||||
{
|
||||
textitem.Left = this.Area.Left + this.Area.Width / 2 - 16;
|
||||
textitem.Top = this.Area.Top + this.Area.Height / 2 - 5;
|
||||
|
||||
@@ -225,7 +225,7 @@ namespace AIStudio.Wpf.Flowchart.Models
|
||||
{
|
||||
FullyCreatedConnectorInfo sourceConnectorInfo = sourceNode.Connectors.FirstOrDefault(p => p.Orientation.ToString() == diagramLink.SourcePortAlignment);
|
||||
FullyCreatedConnectorInfo sinkConnectorInfo = targetNode.Connectors.FirstOrDefault(p => p.Orientation.ToString() == diagramLink.TargetPortAlignment);
|
||||
ConnectorViewModel linkModel = new ConnectorViewModel(diagram, sourceConnectorInfo, sinkConnectorInfo, diagram.DrawModeViewModel?.LineDrawMode ?? DrawMode.SmoothConnectingLine, diagram.DrawModeViewModel?.LineRouterMode ?? RouterMode.Normal);
|
||||
ConnectorViewModel linkModel = new ConnectorViewModel(diagram, sourceConnectorInfo, sinkConnectorInfo, diagram.DrawModeViewModel?.LineDrawMode ?? DrawMode.ConnectingLineSmooth, diagram.DrawModeViewModel?.LineRouterMode ?? RouterMode.RouterNormal);
|
||||
linkModel.Id = new Guid(diagramLink.Id);
|
||||
linkModel.ColorViewModel.LineColor.Color = SerializeHelper.DeserializeColor(diagramLink.Color);
|
||||
linkModel.ColorViewModel.LineWidth = diagramLink.Width;
|
||||
|
||||
Reference in New Issue
Block a user