使用PointBase代替Point

This commit is contained in:
艾竹
2023-01-08 09:22:37 +08:00
parent 8fc69bc96d
commit 5d7717cc2b
65 changed files with 4317 additions and 403 deletions

View File

@@ -4,12 +4,17 @@ using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Media;
using AIStudio.Wpf.DiagramDesigner.Geometry;
namespace AIStudio.Wpf.DiagramDesigner
{
public abstract class ConnectorInfoBase : BindableBase
{
public virtual PointBase Position
{
get;
}
public ConnectorInfoBase(ConnectorOrientation orientation)
{
this.Orientation = orientation;
@@ -23,7 +28,10 @@ namespace AIStudio.Wpf.DiagramDesigner
private ConnectorOrientation _orientation;
public ConnectorOrientation Orientation
{
get { return _orientation; }
get
{
return _orientation;
}
set
{
SetProperty(ref _orientation, value);
@@ -33,15 +41,27 @@ namespace AIStudio.Wpf.DiagramDesigner
private double connectorWidth = 8;
public double ConnectorWidth
{
get { return connectorWidth; }
set { connectorWidth = value; }
get
{
return connectorWidth;
}
set
{
connectorWidth = value;
}
}
private double connectorHeight = 8;
public double ConnectorHeight
{
get { return connectorHeight; }
set { connectorHeight = value; }
get
{
return connectorHeight;
}
set
{
connectorHeight = value;
}
}
private IColorViewModel _colorViewModel;
@@ -68,6 +88,6 @@ namespace AIStudio.Wpf.DiagramDesigner
{
SetProperty(ref _connectorValue, value);
}
}
}
}
}

View File

@@ -4,14 +4,13 @@ using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Media;
using AIStudio.Wpf.DiagramDesigner.Geometry;
namespace AIStudio.Wpf.DiagramDesigner
{
public class PointInfoBase : BindableBase
public class ConnectorPoint : BindableBase
{
public static PointInfoBase Zero { get; } = new PointInfoBase(0, 0);
public PointInfoBase()
public ConnectorPoint()
{
ColorViewModel = new ColorViewModel()
{
@@ -20,18 +19,21 @@ namespace AIStudio.Wpf.DiagramDesigner
};
}
public PointInfoBase(Point point) : this()
public ConnectorPoint(PointBase point) : this()
{
X = point.X;
Y = point.Y;
}
public PointInfoBase(double x, double y) : this()
public ConnectorPoint(double x, double y) : this()
{
X = x;
Y = y;
}
/// <summary>
/// 中间X
/// </summary>
private double _x;
public double X
{
@@ -48,6 +50,9 @@ namespace AIStudio.Wpf.DiagramDesigner
}
}
/// <summary>
/// 中间Y
/// </summary>
private double _y;
public double Y
{
@@ -64,6 +69,9 @@ namespace AIStudio.Wpf.DiagramDesigner
}
}
/// <summary>
/// 边界Left
/// </summary>
public double Left
{
get
@@ -72,6 +80,9 @@ namespace AIStudio.Wpf.DiagramDesigner
}
}
/// <summary>
/// 边界Top
/// </summary>
public double Top
{
get
@@ -80,6 +91,15 @@ namespace AIStudio.Wpf.DiagramDesigner
}
}
public PointBase Position
{
get
{
return new PointBase(Left, Top);
}
}
public PointBase MiddlePosition => new PointBase(Left + ConnectorWidth / 2, Top + ConnectorHeight / 2);
private double connectorWidth = 8;
public double ConnectorWidth
{
@@ -105,53 +125,32 @@ namespace AIStudio.Wpf.DiagramDesigner
{
SetProperty(ref _colorViewModel, value);
}
}
public static ConnectorPoint operator -(ConnectorPoint a, ConnectorPoint b)
{
return new ConnectorPoint(a.X - b.X, a.Y - b.Y);
}
public static ConnectorPoint operator +(ConnectorPoint a, ConnectorPoint b)
{
return new ConnectorPoint(a.X + b.X, a.Y + b.Y);
}
public double Dot(PointInfoBase other) => X * other.X + Y * other.Y;
public PointInfoBase Lerp(PointInfoBase other, double t)
=> new PointInfoBase(X * (1.0 - t) + other.X * t, Y * (1.0 - t) + other.Y * t);
// Maybe just make Points mutable?
public PointInfoBase Add(double value) => new PointInfoBase(X + value, Y + value);
public PointInfoBase Add(double x, double y) => new PointInfoBase(X + x, Y + y);
public PointInfoBase Substract(double value) => new PointInfoBase(X - value, Y - value);
public PointInfoBase Substract(double x, double y) => new PointInfoBase(X - x, Y - y);
public double DistanceTo(PointInfoBase other)
=> Math.Sqrt(Math.Pow(X - other.X, 2) + Math.Pow(Y - other.Y, 2));
public void Deconstruct(out double x, out double y)
public static implicit operator ConnectorPoint(PointBase point)
{
x = X;
y = Y;
}
public static PointInfoBase operator -(PointInfoBase a, PointInfoBase b)
{
return new Point(a.X - b.X, a.Y - b.Y);
}
public static PointInfoBase operator +(PointInfoBase a, PointInfoBase b)
{
return new Point(a.X + b.X, a.Y + b.Y);
return new ConnectorPoint(point);
}
public static implicit operator PointInfoBase(Point point)
public static implicit operator PointBase(ConnectorPoint pointInfoBase)
{
return new PointInfoBase(point);
return new PointBase(pointInfoBase.X, pointInfoBase.Y);
}
public static implicit operator Point(PointInfoBase pointInfoBase)
public static List<ConnectorPoint> ToList(List<PointBase> lst)
{
return new Point(pointInfoBase.X, pointInfoBase.Y);
return lst.Select(p => (ConnectorPoint)p).ToList();
}
public static List<PointInfoBase> ToList(List<Point> lst)
{
return lst.Select(p => (PointInfoBase)p).ToList();
}
public override string ToString() => $"PointInfoBase(x={X}, y={Y})";
public override string ToString() => $"ConnectorPoint(x={X}, y={Y})";
}
}

View File

@@ -0,0 +1,494 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
//using System.Windows;
using System.Windows.Media;
using AIStudio.Wpf.DiagramDesigner.Geometry;
using AIStudio.Wpf.DiagramDesigner.Helpers;
namespace AIStudio.Wpf.DiagramDesigner
{
public class ConnectorViewModel : SelectableDesignerItemViewModelBase
{
public ConnectorViewModel(IDiagramViewModel parent, FullyCreatedConnectorInfo sourceConnectorInfo, FullyCreatedConnectorInfo sinkConnectorInfo,
SelectableDesignerItemBase designer, DrawMode vectorLineDrawMode) : base(parent, designer)
{
VectorLineDrawMode = vectorLineDrawMode;
Init(sourceConnectorInfo, sinkConnectorInfo);
}
public ConnectorViewModel(IDiagramViewModel parent, FullyCreatedConnectorInfo sourceConnectorInfo, ConnectorInfoBase sinkConnectorInfo, DrawMode vectorLineDrawMode)
{
Parent = parent;
VectorLineDrawMode = vectorLineDrawMode;
Init(sourceConnectorInfo, sinkConnectorInfo);
}
public ConnectorViewModel( FullyCreatedConnectorInfo sourceConnectorInfo, ConnectorInfoBase sinkConnectorInfo, DrawMode vectorLineDrawMode):this(null, sourceConnectorInfo, sinkConnectorInfo, vectorLineDrawMode)
{
}
public override SelectableDesignerItemBase ToXmlObject()
{
if (IsFullConnection)
{
ConnectionItem connection = new ConnectionItem(
SourceConnectorInfo.DataItem.Id,
SourceConnectorInfo.Orientation,
SourceConnectorInfo.DataItem.GetType(),
GetXRatioFromConnector(SourceConnectorInfo),
GetYRatioFromConnector(SourceConnectorInfo),
SourceConnectorInfo.IsInnerPoint,
SinkConnectorInfoFully.DataItem.Id,
SinkConnectorInfoFully.Orientation,
SinkConnectorInfoFully.DataItem.GetType(),
GetXRatioFromConnector(SinkConnectorInfoFully),
GetYRatioFromConnector(SinkConnectorInfoFully),
SinkConnectorInfoFully.IsInnerPoint,
this);
return connection;
}
else
{
return null;
}
}
public override Type ToXmlType()
{
return typeof(ConnectionItem);
}
public IPathFinder PathFinder
{
get; set;
}
private PointBase _sourceA;
public PointBase SourceA
{
get
{
return _sourceA;
}
set
{
if (SetProperty(ref _sourceA, value))
{
UpdateArea();
}
}
}
private PointBase _sourceB;
public PointBase SourceB
{
get
{
return _sourceB;
}
set
{
if (SetProperty(ref _sourceB, value))
{
UpdateArea();
}
}
}
private List<ConnectorPoint> _connectionPoints;
public List<ConnectorPoint> ConnectionPoints
{
get
{
return _connectionPoints;
}
private set
{
if (_connectionPoints != null)
{
_connectionPoints.ForEach(p => p.PropertyChanged -= new WeakINPCEventHandler(ConnectionPoint_PropertyChanged).Handler);
}
SetProperty(ref _connectionPoints, value);
if (_connectionPoints != null)
{
_connectionPoints.ForEach(p => p.PropertyChanged += new WeakINPCEventHandler(ConnectionPoint_PropertyChanged).Handler);
}
}
}
private PointBase _startPoint;
public PointBase StartPoint
{
get
{
return _startPoint;
}
private set
{
SetProperty(ref _startPoint, value);
}
}
private PointBase _endPoint;
public PointBase EndPoint
{
get
{
return _endPoint;
}
private set
{
SetProperty(ref _endPoint, value);
}
}
private RectangleBase _area;
public RectangleBase Area
{
get
{
return _area;
}
private set
{
RectangleBase oldarea = _area;
if (SetProperty(ref _area, value))
{
UpdateConnectionPoints();
OutTextItemLocation(oldarea, value);
}
}
}
public DrawMode VectorLineDrawMode
{
get; set;
}
//待完善这两处
public List<LinkVertexModel> Vertices { get; } = new List<LinkVertexModel>();
public List<LinkLabelModel> Labels { get; set; } = new List<LinkLabelModel>();
public virtual Dictionary<string, string> PropertiesSetting
{
get
{
return new Dictionary<string, string>()
{
{ "Text","文本" },
};
}
}
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
};
}
private FullyCreatedConnectorInfo _sourceConnectorInfo;
public FullyCreatedConnectorInfo SourceConnectorInfo
{
get
{
return _sourceConnectorInfo;
}
set
{
if (SetProperty(ref _sourceConnectorInfo, value))
{
SourceA = PointHelper.GetPointForConnector(_sourceConnectorInfo);
(_sourceConnectorInfo.DataItem as INotifyPropertyChanged).PropertyChanged += new WeakINPCEventHandler(ConnectorViewModel_PropertyChanged).Handler;
}
}
}
private ConnectorInfoBase _sinkConnectorInfo;
public ConnectorInfoBase SinkConnectorInfo
{
get
{
return _sinkConnectorInfo;
}
set
{
if (SetProperty(ref _sinkConnectorInfo, value))
{
if (_sinkConnectorInfo is FullyCreatedConnectorInfo)
{
SourceB = PointHelper.GetPointForConnector((FullyCreatedConnectorInfo)_sinkConnectorInfo);
(((FullyCreatedConnectorInfo)_sinkConnectorInfo).DataItem as INotifyPropertyChanged).PropertyChanged += new WeakINPCEventHandler(ConnectorViewModel_PropertyChanged).Handler;
}
else
{
SourceB = SinkConnectorInfoPart.Position;
}
}
}
}
public FullyCreatedConnectorInfo SinkConnectorInfoFully
{
get
{
return SinkConnectorInfo as FullyCreatedConnectorInfo;
}
}
public PartCreatedConnectionInfo SinkConnectorInfoPart
{
get
{
return SinkConnectorInfo as PartCreatedConnectionInfo;
}
}
public ConnectorPoint OnGoingPosition
{
get
{
return SinkConnectorInfoPart?.Position;
}
}
public bool IsFullConnection
{
get
{
return SinkConnectorInfoFully != null;
}
}
public bool IsPortless => SourceConnectorInfo?.DataItem?.Connectors?.Count() == 0;
public double GetXRatioFromConnector(FullyCreatedConnectorInfo info)
{
if (info.IsInnerPoint)
{
return info.XRatio;
}
else
{
switch (info.Orientation)
{
case ConnectorOrientation.Top:
return 0.5;
case ConnectorOrientation.Left:
return 0;
case ConnectorOrientation.Bottom:
return 0.5;
case ConnectorOrientation.Right:
return 1;
default: return info.XRatio;
}
}
}
public double GetYRatioFromConnector(FullyCreatedConnectorInfo info)
{
if (info.IsInnerPoint)
{
return info.YRatio;
}
else
{
switch (info.Orientation)
{
case ConnectorOrientation.Top:
return 0;
case ConnectorOrientation.Left:
return 0.5;
case ConnectorOrientation.Bottom:
return 1;
case ConnectorOrientation.Right:
return 0.5;
default: return info.YRatio;
}
}
}
private void UpdateArea()
{
Area = new RectangleBase(SourceA, SourceB);
}
private void UpdateConnectionPoints()
{
ConnectionPoints = PathFinder.UpdateConnectionPoints(Parent, SourceA, SourceB, SourceConnectorInfo, SinkConnectorInfo);
StartPoint = ConnectionPoints.First();
EndPoint = ConnectionPoints.Last();
//var router = Routers.Normal(Parent, this);
//var pathGenerator = PathGenerators.Smooth(Parent, this, router, SourceA, SourceB);
}
private void ConnectorViewModel_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
switch (e.PropertyName)
{
case "ItemHeight":
case "ItemWidth":
case "Left":
case "Top":
SourceA = PointHelper.GetPointForConnector(this.SourceConnectorInfo);
if (IsFullConnection)
{
SourceB = PointHelper.GetPointForConnector(this.SinkConnectorInfoFully);
}
break;
}
}
private void ConnectionPoint_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
switch (e.PropertyName)
{
case "Left":
case "Top":
RaisePropertyChanged(nameof(ConnectionPoints));
break;
}
}
private void Init(FullyCreatedConnectorInfo sourceConnectorInfo, ConnectorInfoBase sinkConnectorInfo)
{
this.Parent = sourceConnectorInfo.DataItem.Parent;
if (VectorLineDrawMode == DrawMode.ConnectingLine)
{
PathFinder = new StraightLinePathFinder();
}
else if (VectorLineDrawMode == DrawMode.BoundaryConnectingLine)
{
PathFinder = new BoundaryPathFinder();
}
else
{
PathFinder = new OrthogonalPathFinder();
}
this.SourceConnectorInfo = sourceConnectorInfo;
this.SinkConnectorInfo = sinkConnectorInfo;
DeleteConnectionCommand = new SimpleCommand(DeleteConnection);
if (Parent != null && Parent.ColorViewModel != null)
{
this.ColorViewModel = CopyHelper.Mapper(Parent.ColorViewModel);
}
if (sinkConnectorInfo is FullyCreatedConnectorInfo sink && sink.DataItem.ShowArrow == false)
{
this.ColorViewModel.RightArrowPathStyle = ArrowPathStyle.None;
}
}
public SimpleCommand DeleteConnectionCommand
{
get; set;
}
private void DeleteConnection(object args)
{
if (this.Parent is IDiagramViewModel)
{
var diagramVM = this.Parent as IDiagramViewModel;
diagramVM.RemoveItemCommand.Execute(this);
}
}
protected override void ExecuteEditCommand(object param)
{
if (this.OutTextItem != null) return;
AddText("");
}
public void AddText(string text)
{
if (this.Parent is IDiagramViewModel)
{
var diagramVM = this.Parent as IDiagramViewModel;
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
{
textitem.Left = this.Area.Left + this.Area.Width / 2 - 16;
textitem.Top = this.Area.Top + this.Area.Height / 2 - 5;
}
textitem.Watermark = null;
textitem.ZIndex = diagramVM.Items.Count;
textitem.ParentId = this.Id;
textitem.ParentItem = this;
textitem.ColorViewModel.FillColor = new ColorObject() { Color = Colors.White };
textitem.Text = text;
diagramVM.DirectAddItemCommand.Execute(textitem);
this.OutTextItem = textitem;
}
}
public void OutTextItemLocation(RectangleBase oldArea, RectangleBase newArea)
{
if (this.OutTextItem is TextDesignerItemViewModel text)
{
var oldpoint = new PointBase(oldArea.Left + oldArea.Width / 2, oldArea.Top + oldArea.Height / 2);
var newpoint = new PointBase(newArea.Left + newArea.Width / 2, newArea.Top + newArea.Height / 2);
text.Left = text.Left + newpoint.X - oldpoint.X;
text.Top = text.Top + newpoint.Y - oldpoint.Y;
}
}
//private (PointInfoBase source, PointInfoBase target) FindConnectionPoints(PointInfoBase[] route)
//{
// if (IsPortless) // Portless
// {
// if (SourceConnectorInfo.DataItem == null || (IsFullConnection && SinkConnectorInfoFully.DataItem == null))
// return (null, null);
// var sourceCenter = SourceConnectorInfo.DataItem.GetBounds().Center;
// var targetCenter = SinkConnectorInfoFully?.DataItem?.GetBounds().Center ?? SinkConnectorInfoFully.Position;
// var firstPt = route.Length > 0 ? route[0] : targetCenter;
// var secondPt = route.Length > 0 ? route[0] : sourceCenter;
// var sourceLine = new Line(firstPt, sourceCenter);
// var targetLine = new Line(secondPt, targetCenter);
// var sourceIntersections = Link.SourceNode.GetShape().GetIntersectionsWithLine(sourceLine);
// var targetIntersections = Link.TargetNode.GetShape().GetIntersectionsWithLine(targetLine);
// var sourceIntersection = GetClosestPointTo(sourceIntersections, firstPt);
// var targetIntersection = GetClosestPointTo(targetIntersections, secondPt);
// return (sourceIntersection ?? sourceCenter, targetIntersection ?? targetCenter);
// }
// else
// {
// if (!Link.SourcePort.Initialized || Link.TargetPort?.Initialized == false)
// return (null, null);
// var source = GetPortPositionBasedOnAlignment(Link.SourcePort, Link.SourceMarker);
// var target = GetPortPositionBasedOnAlignment(Link.TargetPort, Link.TargetMarker);
// return (source, target ?? Link.OnGoingPosition);
// }
//}
}
}

View File

@@ -7,6 +7,7 @@ using System.Windows;
using System.Linq;
using System.Reactive.Linq;
using AIStudio.Wpf.DiagramDesigner.Models;
using AIStudio.Wpf.DiagramDesigner.Geometry;
namespace AIStudio.Wpf.DiagramDesigner
{
@@ -85,6 +86,10 @@ namespace AIStudio.Wpf.DiagramDesigner
get { return (connectors != null && connectors.Count >= 4) ? connectors[3] : null; }
}
public ShapeDefiner ShapeDefiner
{
get;
}
private string _icon;
[CanDo]
@@ -133,16 +138,16 @@ namespace AIStudio.Wpf.DiagramDesigner
}
[CanDo]
public Point ItemWidthHeight
public SizeBase Size
{
get
{
return new Point(ItemWidth, ItemHeight);
return new SizeBase(ItemWidth, ItemHeight);
}
set
{
ItemWidth = value.X;
ItemHeight = value.Y;
ItemWidth = value.Width;
ItemHeight = value.Height;
}
}
@@ -211,14 +216,22 @@ namespace AIStudio.Wpf.DiagramDesigner
{
SetProperty(ref _top, value);
}
}
}
[CanDo]
public Point TopLeft
public PointBase Position
{
get
{
return new Point(Left, Top);
return new PointBase(Left, Top);
}
}
[CanDo]
public PointBase TopLeft
{
get
{
return new PointBase(Left, Top);
}
set
{
@@ -386,17 +399,37 @@ namespace AIStudio.Wpf.DiagramDesigner
public void RaiseTopLeft()
{
this.RaisePropertyChanged(nameof(TopLeft), new Point(GetOldValue<double>(nameof(Left)), GetOldValue<double>(nameof(Top))), TopLeft);
this.RaisePropertyChanged(nameof(TopLeft), new PointBase(GetOldValue<double>(nameof(Left)), GetOldValue<double>(nameof(Top))), TopLeft);
}
public void RaiseItemWidthHeight()
{
this.RaisePropertyChanged(nameof(ItemWidthHeight), new Point(GetOldValue<double>(nameof(ItemWidth)), GetOldValue<double>(nameof(ItemHeight))), ItemWidthHeight);
this.RaisePropertyChanged(nameof(Size), new SizeBase(GetOldValue<double>(nameof(ItemWidth)), GetOldValue<double>(nameof(ItemHeight))), Size);
}
public void RaiseAngle()
{
this.RaisePropertyChanged(nameof(Angle), GetOldValue<double>(nameof(Angle)), Angle);
}
public RectangleBase GetBounds(bool includePorts = false)
{
if (!includePorts)
return new RectangleBase(Left, Top, ItemWidth, ItemHeight);
var leftPort = LeftConnector;
var topPort = TopConnector;
var rightPort = RightConnector;
var bottomPort = BottomConnector;
var left = leftPort == null ? Left: Math.Min(Left, leftPort.Position.X);
var top = topPort == null ? Top : Math.Min(Left, topPort.Position.Y);
var right = rightPort == null ? Left + ItemWidth :
Math.Max(rightPort.Position.X + rightPort.ConnectorWidth, Left + ItemWidth);
var bottom = bottomPort == null ? Top + ItemHeight :
Math.Max(bottomPort.Position.Y + bottomPort.ConnectorHeight, Top + ItemHeight);
return new RectangleBase(left, top, right, bottom);
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,158 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using AIStudio.Wpf.DiagramDesigner.Geometry;
namespace AIStudio.Wpf.DiagramDesigner
{
public class FullyCreatedConnectorInfo : ConnectorInfoBase
{
public override PointBase Position
{
get
{
return PointHelper.GetPointForConnector(this);
}
}
private List<CinchMenuItem> menuOptions;
public FullyCreatedConnectorInfo(DesignerItemViewModelBase dataItem, ConnectorOrientation orientation, bool isInnerPoint = false, ValueTypePoint valueTypePoint = 0)
: base(orientation)
{
this.DataItem = dataItem;
this.IsInnerPoint = isInnerPoint;
this.ValueTypePoint = valueTypePoint;
menuOptions = new List<CinchMenuItem>();
MenuItemCommand = new SimpleCommand(ExecuteMenuItemCommand);
DeleteCommand = new SimpleCommand(ExecuteDeleteCommand);
if (IsInnerPoint == true)
{
BuildMenuOptions();
}
}
public void ExecuteMenuItemCommand(object arg)
{
Orientation = (ConnectorOrientation)arg;
}
public void ExecuteDeleteCommand(object arg)
{
DataItem.RemoveConnector(this);
}
private void BuildMenuOptions()
{
menuOptions.Clear();
var orientation = new CinchMenuItem("方向");
var top = new CinchMenuItem("上");
top.Command = MenuItemCommand;
top.CommandParameter = ConnectorOrientation.Top;
var bottom = new CinchMenuItem("下");
bottom.Command = MenuItemCommand;
bottom.CommandParameter = ConnectorOrientation.Bottom;
var left = new CinchMenuItem("左");
left.Command = MenuItemCommand;
left.CommandParameter = ConnectorOrientation.Left;
var right = new CinchMenuItem("右");
right.Command = MenuItemCommand;
right.CommandParameter = ConnectorOrientation.Right;
orientation.Children.Add(top);
orientation.Children.Add(bottom);
orientation.Children.Add(left);
orientation.Children.Add(right);
var delete = new CinchMenuItem("删除");
delete.Command = DeleteCommand;
menuOptions.Add(orientation);
menuOptions.Add(delete);
}
public DesignerItemViewModelBase DataItem
{
get; private set;
}
private bool _showConnectors = false;
public bool ShowConnectors
{
get
{
return _showConnectors;
}
set
{
SetProperty(ref _showConnectors, value);
}
}
private double _xRatio;
public double XRatio
{
get
{
return _xRatio;
}
set
{
SetProperty(ref _xRatio, value);
}
}
private double _yRatio;
public double YRatio
{
get
{
return _yRatio;
}
set
{
SetProperty(ref _yRatio, value);
}
}
public bool IsInnerPoint
{
get; set;
}
public ValueTypePoint _valueTypePoint;
public ValueTypePoint ValueTypePoint
{
get
{
return _valueTypePoint;
}
set
{
SetProperty(ref _valueTypePoint, value);
}
}
public SimpleCommand DeleteCommand
{
get; private set;
}
public SimpleCommand MenuItemCommand
{
get; private set;
}
public IEnumerable<CinchMenuItem> MenuOptions
{
get
{
return menuOptions;
}
}
}
}

View File

@@ -0,0 +1,32 @@
namespace AIStudio.Wpf.DiagramDesigner
{
public class LinkLabelModel : ConnectorPoint
{
public LinkLabelModel(ConnectorViewModel parent, string id, string content, double? distance = null, ConnectorPoint offset = null)
{
Parent = parent;
Content = content;
Distance = distance;
Offset = offset;
}
public LinkLabelModel(ConnectorViewModel parent, string content, double? distance = null, ConnectorPoint offset = null)
{
Parent = parent;
Content = content;
Distance = distance;
Offset = offset;
}
public ConnectorViewModel Parent { get; }
public string Content { get; set; }
/// <summary>
/// 3 types of values are possible:
/// <para>- A number between 0 and 1: Position relative to the link's length</para>
/// <para>- A positive number, greater than 1: Position away from the start</para>
/// <para>- A negative number, less than 0: Position away from the end</para>
/// </summary>
public double? Distance { get; set; }
public ConnectorPoint Offset { get; set; }
}
}

View File

@@ -0,0 +1,20 @@
using AIStudio.Wpf.DiagramDesigner.Geometry;
namespace AIStudio.Wpf.DiagramDesigner
{
public class LinkVertexModel : ConnectorPoint
{
public LinkVertexModel(ConnectorViewModel parent, PointBase? position = null)
{
Parent = parent;
X = position?.X ?? 0;
Y = position?.Y ?? 0;
}
public ConnectorViewModel Parent
{
get;
}
}
}

View File

@@ -1,299 +0,0 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Media;
namespace AIStudio.Wpf.DiagramDesigner
{
public class LogicalGateItemViewModelBase : DesignerItemViewModelBase
{
public SimpleCommand AddInputCommand { get; private set; }
public SimpleCommand AddOutputCommand { get; private set; }
public LogicalGateItemViewModelBase(LogicalType logicalType) : base()
{
this.LogicalType = logicalType;
if (this.LogicalType == LogicalType.Input)
{
ClearConnectors();
ExecuteAddOutput(null);
}
else if (this.LogicalType == LogicalType.Output)
{
ClearConnectors();
ExecuteAddInput(null);
}
else if (this.LogicalType == LogicalType.Constant)
{
ClearConnectors();
ExecuteAddOutput(null);
}
else if (this.LogicalType == LogicalType.Time)
{
ClearConnectors();
ExecuteAddOutput(null);
}
else if (this.LogicalType == LogicalType.None)
{
ClearConnectors();
ExecuteAddOutput(null);
}
else if (this.LogicalType == LogicalType.NOT)
{
ClearConnectors();
ExecuteAddInput(null);
ExecuteAddOutput(null);
}
else if (this.LogicalType == LogicalType.SEL)
{
ClearConnectors();
ExecuteAddInput(null, 0);
ExecuteAddInput(null, 1);
ExecuteAddInput(null, 2);
ExecuteAddOutput(null, 0);
}
else if (this.LogicalType >= LogicalType.ABS && this.LogicalType <= LogicalType.EXPT)
{
ClearConnectors();
ExecuteAddInput(null);
ExecuteAddOutput(null);
}
else
{
ClearConnectors();
ExecuteAddInput(null);
ExecuteAddInput(null);
ExecuteAddOutput(null);
}
BuildMenuOptions();
}
public LogicalGateItemViewModelBase(IDiagramViewModel parent, LogicalGateDesignerItemBase designer) : base(parent, designer)
{
BuildMenuOptions();
}
public LogicalGateItemViewModelBase(IDiagramViewModel parent, string json) : base(parent, json)
{
BuildMenuOptions();
}
public override SelectableDesignerItemBase ToXmlObject()
{
return new LogicalGateDesignerItemBase(this);
}
public override Type ToXmlType()
{
return typeof(LogicalGateDesignerItemBase);
}
protected override void Init()
{
ShowRotate = false;
ShowArrow = false;
AddInputCommand = new SimpleCommand(para => ExecuteAddInput(para));
AddOutputCommand = new SimpleCommand(para => ExecuteAddOutput(para));
base.Init();
}
private void BuildMenuOptions()
{
bool enAddInput = false;
bool enAddOutput = false;
if (LogicalType >= LogicalType.ADD && LogicalType <= LogicalType.AVE)
{
enAddInput = true;
enAddOutput = false;
}
else
{
enAddInput = false;
enAddOutput = false;
}
menuOptions = new ObservableCollection<CinchMenuItem>();
if (enAddInput == true)
{
CinchMenuItem menuItem = new CinchMenuItem();
menuItem.Text = "添加输入";
menuItem.Command = AddInputCommand;
menuItem.CommandParameter = menuItem;
menuOptions.Add(menuItem);
}
if (enAddOutput == true)
{
CinchMenuItem menuItem = new CinchMenuItem();
menuItem.Text = "添加输出";
menuItem.Command = AddOutputCommand;
menuItem.CommandParameter = menuItem;
menuOptions.Add(menuItem);
}
}
protected override void LoadDesignerItemViewModel(IDiagramViewModel parent, SelectableDesignerItemBase designerbase)
{
base.LoadDesignerItemViewModel(parent, designerbase);
LogicalGateDesignerItemBase designer = designerbase as LogicalGateDesignerItemBase;
this.LogicalType = designer.LogicalType;
this.OrderNumber = designer.OrderNumber;
this.Value = designer.Value;
this.IsEnabled = designer.IsEnabled;
ClearConnectors();
Input.Clear();
Output.Clear();
foreach (var connector in designer.Connectors)
{
FullyCreatedConnectorInfo fullyCreatedConnectorInfo = new FullyCreatedConnectorInfo(this, connector.Orientation, true);
fullyCreatedConnectorInfo.XRatio = connector.XRatio;
fullyCreatedConnectorInfo.YRatio = connector.YRatio;
fullyCreatedConnectorInfo.ConnectorWidth = connector.ConnectorWidth;
fullyCreatedConnectorInfo.ConnectorHeight = connector.ConnectorHeight;
fullyCreatedConnectorInfo.Orientation = connector.Orientation;
fullyCreatedConnectorInfo.IsInnerPoint = connector.IsInnerPoint;
fullyCreatedConnectorInfo.ValueTypePoint = connector.ValueTypePoint;
fullyCreatedConnectorInfo.ConnectorValue = connector.ConnectorValue;
if (fullyCreatedConnectorInfo.Orientation == ConnectorOrientation.Left)
{
Input.Add(Input.Count, fullyCreatedConnectorInfo);
}
else if (fullyCreatedConnectorInfo.Orientation == ConnectorOrientation.Right)
{
Output.Add(Output.Count, fullyCreatedConnectorInfo);
}
AddConnector(fullyCreatedConnectorInfo);
}
}
private int _orderNumber;
public int OrderNumber
{
get
{
return _orderNumber;
}
set
{
SetProperty(ref _orderNumber, value);
}
}
private bool _isEnabled;
public bool IsEnabled
{
get
{
return _isEnabled;
}
set
{
SetProperty(ref _isEnabled, value);
}
}
private double _value;
public double Value
{
get
{
return _value;
}
set
{
SetProperty(ref _value, value);
}
}
public LogicalType LogicalType { get; set; }
public Dictionary<int, FullyCreatedConnectorInfo> Input { get; set; } = new Dictionary<int, FullyCreatedConnectorInfo>();
public Dictionary<int, FullyCreatedConnectorInfo> Output { get; set; } = new Dictionary<int, FullyCreatedConnectorInfo>();
public virtual void ExecuteAddInput(object parameter, int index = 0)
{
if (Input.Values.Count >= 2)
{
this.ItemHeight = this.ItemHeight * (Input.Values.Count + 1) / Input.Values.Count;
}
FullyCreatedConnectorInfo connector = new FullyCreatedConnectorInfo(this, ConnectorOrientation.Left, true, ValueTypeInput.Count > index ? ValueTypeInput[index] : ValueTypeInput[0]);
connector.XRatio = 0;
Input.Add(Input.Count, connector);
for (int i = 0; i < Input.Values.Count; i++)
{
Input[i].YRatio = (i + 1.0) / (Input.Values.Count + 1.0);
}
AddConnector(connector);
}
public virtual void ExecuteAddOutput(object parameter, int index = 0)
{
FullyCreatedConnectorInfo connector = new FullyCreatedConnectorInfo(this, ConnectorOrientation.Right, true, ValueTypeOutput.Count > index ? ValueTypeOutput[index] : ValueTypeInput[0]);
connector.XRatio = 1;
Output.Add(Output.Count, connector);
for (int i = 0; i < Output.Values.Count; i++)
{
Output[i].YRatio = (i + 1.0) / (Output.Values.Count + 1.0);
}
AddConnector(connector);
}
public List<ValueTypePoint> ValueTypeInput
{
get
{
if (LogicalType == LogicalType.NOT)
{
return new List<ValueTypePoint>() { ValueTypePoint.Bool };
}
else if (LogicalType == LogicalType.AND || LogicalType == LogicalType.OR || LogicalType == LogicalType.XOR
|| LogicalType == LogicalType.SHL || LogicalType == LogicalType.SHR || LogicalType == LogicalType.ROL || LogicalType == LogicalType.ROR)
{
return new List<ValueTypePoint>() { ValueTypePoint.Int };
}
else if (LogicalType == LogicalType.SEL)
{
return new List<ValueTypePoint>() { ValueTypePoint.Bool, ValueTypePoint.Real, ValueTypePoint.Real };
}
else
{
return new List<ValueTypePoint>() { ValueTypePoint.Real };
}
}
}
public List<ValueTypePoint> ValueTypeOutput
{
get
{
if (LogicalType == LogicalType.GT || LogicalType == LogicalType.LT || LogicalType == LogicalType.GE || LogicalType == LogicalType.LE || LogicalType == LogicalType.EQ || LogicalType == LogicalType.NE
|| LogicalType == LogicalType.NOT)
{
return new List<ValueTypePoint>() { ValueTypePoint.Bool };
}
else if (LogicalType == LogicalType.AND || LogicalType == LogicalType.OR || LogicalType == LogicalType.XOR
|| LogicalType == LogicalType.SHL || LogicalType == LogicalType.SHR || LogicalType == LogicalType.ROL || LogicalType == LogicalType.ROR)
{
return new List<ValueTypePoint>() { ValueTypePoint.Int };
}
else
{
return new List<ValueTypePoint>() { ValueTypePoint.Real };
}
}
}
}
}

View File

@@ -0,0 +1,26 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using AIStudio.Wpf.DiagramDesigner.Geometry;
namespace AIStudio.Wpf.DiagramDesigner
{
public class PartCreatedConnectionInfo : ConnectorInfoBase
{
private PointBase position;
public override PointBase Position
{
get
{
return position;
}
}
public PartCreatedConnectionInfo(double X, double Y) : base(ConnectorOrientation.None)
{
this.position = new PointBase(X, Y);
}
}
}