Files
aistudio-wpf-diagram/AIStudio.Wpf.DiagramDesigner/ViewModels/BaseViewModel/DiagramViewModelHelper.cs
2023-06-19 15:47:39 +08:00

492 lines
21 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using AIStudio.Wpf.DiagramDesigner.Geometrys;
namespace AIStudio.Wpf.DiagramDesigner
{
public static class DiagramViewModelHelper
{
public static DesignerItemViewModelBase GetConnectorDataItem(IEnumerable<SelectableDesignerItemViewModelBase> items, Guid conectorDataItemId, Type connectorDataItemType)
{
DesignerItemViewModelBase dataItem = items.OfType<DesignerItemViewModelBase>().Single(x => x.Id == conectorDataItemId);
return dataItem;
}
public static RectangleBase GetBoundingRectangle(IEnumerable<DesignerItemViewModelBase> items)
{
double x1 = Double.MaxValue;
double y1 = Double.MaxValue;
double x2 = Double.MinValue;
double y2 = Double.MinValue;
foreach (DesignerItemViewModelBase item in items)
{
x1 = Math.Min(item.Left, x1);
y1 = Math.Min(item.Top, y1);
x2 = Math.Max(item.Left + item.GetItemWidth(), x2);
y2 = Math.Max(item.Top + item.GetItemHeight(), y2);
}
return new RectangleBase(new PointBase(x1, y1), new PointBase(x2, y2));
}
public static RectangleBase GetBoundingRectangle(DesignerItemViewModelBase item)
{
return GetBoundingRectangle(new DesignerItemViewModelBase[] { item });
}
#region
public static FullyCreatedConnectorInfo FindNearPortToAttachTo(this IDiagramViewModel diagramViewModel, ConnectionViewModel partialConnection, ConnectorVertexType connectorVertexType)
{
if (partialConnection == null)
return null;
diagramViewModel.ClearNearPort();
foreach (var port in diagramViewModel.Items.OfType<DesignerItemViewModelBase>().ToList().SelectMany(n => n.Connectors))
{
if (connectorVertexType == ConnectorVertexType.Start)
{
if (partialConnection.SourceConnectorInfo.Position.DistanceTo(port.Position) < diagramViewModel.DiagramOption.SnappingOption.SnappingRadius)
{
if (partialConnection.SinkConnectorInfo?.CanAttachTo(port) == true)
{
port.DataItem.ShowConnectors = true;
port.BeAttachTo = true;
return port;
}
else
{
port.DataItem.ShowConnectors = true;
port.DisableAttachTo = true;
return null;
}
}
}
else if (connectorVertexType == ConnectorVertexType.End)
{
if (partialConnection.SinkConnectorInfo.Position.DistanceTo(port.Position) < diagramViewModel.DiagramOption.SnappingOption.SnappingRadius)
{
if (partialConnection.SourceConnectorInfo?.CanAttachTo(port) == true)
{
port.DataItem.ShowConnectors = true;
port.BeAttachTo = true;
return port;
}
else
{
port.DataItem.ShowConnectors = true;
port.DisableAttachTo = true;
return null;
}
}
}
}
return null;
}
public static FullyCreatedConnectorInfo FindNearPortToAttachTo(this IDiagramViewModel diagramViewModel, ConnectionViewModel partialConnection)
{
if (partialConnection == null)
return null;
diagramViewModel.ClearNearPort();
foreach (var port in diagramViewModel.Items.OfType<DesignerItemViewModelBase>().ToList().SelectMany(n => n.Connectors))
{
if (partialConnection.OnGoingPosition.DistanceTo(port.Position) < diagramViewModel.DiagramOption.SnappingOption.SnappingRadius)
{
port.DataItem.ShowConnectors = true;
if (partialConnection.SourceConnectorInfo?.CanAttachTo(port) == true)
{
port.BeAttachTo = true;
return port;
}
else
{
port.DisableAttachTo = true;
return null;
}
}
}
return null;
}
/// <summary>
/// type=0最近且没有依附=1
/// </summary>
/// <param name="blockDesignerItemViewModel"></param>
/// <param name="type"></param>
/// <returns></returns>
public static Tuple<FullyCreatedConnectorInfo, FullyCreatedConnectorInfo> FindNearPortToAttachTo(this IDiagramViewModel diagramViewModel, BlockDesignerItemViewModel blockDesignerItemViewModel, bool isExist)
{
if (blockDesignerItemViewModel == null)
return new Tuple<FullyCreatedConnectorInfo, FullyCreatedConnectorInfo>(null, null);
List<BlockDesignerItemViewModel> items;
if (isExist == false)
{
items = diagramViewModel.Items.OfType<BlockDesignerItemViewModel>().
Where(p => p != blockDesignerItemViewModel && p != blockDesignerItemViewModel.Parent && p != blockDesignerItemViewModel.Next)
.ToList();
}
else
{
items = diagramViewModel.Items.OfType<BlockDesignerItemViewModel>().
Where(p => p != blockDesignerItemViewModel)
.ToList();
}
FullyCreatedConnectorInfo parent = null;
FullyCreatedConnectorInfo next = null;
foreach (var port in items.SelectMany(n => n.Connectors))
{
foreach (var port2 in blockDesignerItemViewModel.Connectors)
{
//parent
if (parent == null)
{
if ((port.Orientation == ConnectorOrientation.Right && port2.Orientation == ConnectorOrientation.Left)
|| (port.Orientation == ConnectorOrientation.Bottom && port2.Orientation == ConnectorOrientation.Top))
{
if (port.Position.DistanceTo(port2.Position) < diagramViewModel.DiagramOption.SnappingOption.SnappingRadius)
{
port.DataItem.ShowConnectors = true;
if (port2.CanAttachTo(port) == true)
{
port.BeAttachTo = true;
parent = port;
continue;
}
else
{
port.DisableAttachTo = true;
}
}
}
}
//next
if (next == null)
{
if ((port.Orientation == ConnectorOrientation.Left && port2.Orientation == ConnectorOrientation.Right)
|| (port.Orientation == ConnectorOrientation.Top && port2.Orientation == ConnectorOrientation.Bottom))
{
if (port.Position.DistanceTo(port2.Position) < diagramViewModel.DiagramOption.SnappingOption.SnappingRadius)
{
port.DataItem.ShowConnectors = true;
if (port2.CanAttachTo(port) == true)
{
port.BeAttachTo = true;
next = port;
continue;
}
else
{
port.DisableAttachTo = true;
}
}
}
}
}
}
return new Tuple<FullyCreatedConnectorInfo, FullyCreatedConnectorInfo>(parent, next);
}
public static BlockItemsContainerInfo FindNearContainerToAttachTo(this IDiagramViewModel diagramViewModel, BlockDesignerItemViewModel blockDesignerItemViewModel)
{
if (blockDesignerItemViewModel == null)
return null;
List<BlockDesignerItemViewModel> items;
items = diagramViewModel.Items.OfType<BlockDesignerItemViewModel>().
Where(p => p != blockDesignerItemViewModel)
.ToList();
foreach (var port in items.SelectMany(n => n.Containers))
{
if (port.GetBounds().IntersectsWith(blockDesignerItemViewModel.GetBounds())) //如果两个位置相交
{
var innerport = port.GetAllContainers(port.Children, false).Where(p => p.GetBounds().IntersectsWith(blockDesignerItemViewModel.GetBounds())).OrderByDescending(p => p.ContainerLevel).FirstOrDefault();
if (innerport != null)
{
innerport.DataItem.ShowConnectors = true;
if (innerport.CanAttachTo(blockDesignerItemViewModel) == true)
{
innerport.BeAttachTo = true;
}
else
{
innerport.DisableAttachTo = true;
}
return innerport;
}
else
{
port.DataItem.ShowConnectors = true;
if (port.CanAttachTo(blockDesignerItemViewModel) == true)
{
port.BeAttachTo = true;
}
else
{
port.DisableAttachTo = true;
}
return port;
}
}
}
return null;
}
/// <summary>
/// type=0最近且没有依附=1
/// </summary>
/// <param name="blockDesignerItemViewModel"></param>
/// <param name="type"></param>
/// <returns></returns>
public static Tuple<FullyCreatedConnectorInfo, FullyCreatedConnectorInfo> FindNearPortToAttachTo(this IDiagramViewModel diagramViewModel, BlockDesignerItemTempLink blockDesignerItemTempLink, bool isExist)
{
if (blockDesignerItemTempLink == null || blockDesignerItemTempLink.Items == null || blockDesignerItemTempLink.Items.Count == 0)
return new Tuple<FullyCreatedConnectorInfo, FullyCreatedConnectorInfo>(null, null);
List<BlockDesignerItemViewModel> items;
if (isExist == false)
{
items = diagramViewModel.Items.OfType<BlockDesignerItemViewModel>().Where(p => !blockDesignerItemTempLink.Items.Contains(p)).ToList();
}
else
{
items = diagramViewModel.Items.OfType<BlockDesignerItemViewModel>().Where(p => !blockDesignerItemTempLink.Items.Contains(p)).ToList();
}
FullyCreatedConnectorInfo parent = null;
FullyCreatedConnectorInfo next = null;
foreach (var port in items.SelectMany(n => n.Connectors).OfType<BlockConnectorInfo>())
{
//已经被连接的不允许在顶部吸附了
if ((port.Orientation == ConnectorOrientation.Top || port.Orientation == ConnectorOrientation.Left) && port.DataItem.Prev != null)
{
continue;
}
foreach (var port2 in blockDesignerItemTempLink.Connectors)
{
//parent
if (parent == null)
{
if ((port.Orientation == ConnectorOrientation.Right && port2.Orientation == ConnectorOrientation.Left)
|| (port.Orientation == ConnectorOrientation.Bottom && port2.Orientation == ConnectorOrientation.Top))
{
if (port.Position.DistanceTo(port2.Position) < diagramViewModel.DiagramOption.SnappingOption.SnappingRadius)
{
port.DataItem.ShowConnectors = true;
if (port2.CanAttachTo(port) == true)
{
port.BeAttachTo = true;
parent = port;
continue;
}
else
{
port.DisableAttachTo = true;
}
}
}
}
//next
if (next == null)
{
if ((port.Orientation == ConnectorOrientation.Left && port2.Orientation == ConnectorOrientation.Right)
|| (port.Orientation == ConnectorOrientation.Top && port2.Orientation == ConnectorOrientation.Bottom))
{
if (port.Position.DistanceTo(port2.Position) < diagramViewModel.DiagramOption.SnappingOption.SnappingRadius)
{
port.DataItem.ShowConnectors = true;
if (port2.CanAttachTo(port) == true)
{
port.BeAttachTo = true;
next = port;
continue;
}
else
{
port.DisableAttachTo = true;
}
}
}
}
}
}
return new Tuple<FullyCreatedConnectorInfo, FullyCreatedConnectorInfo>(parent, next);
}
public static BlockItemsContainerInfo FindNearContainerToAttachTo(this IDiagramViewModel diagramViewModel, BlockDesignerItemTempLink blockDesignerItemTempLink)
{
if (blockDesignerItemTempLink == null || blockDesignerItemTempLink.Items == null || blockDesignerItemTempLink.Items.Count == 0)
return null;
List<BlockDesignerItemViewModel> items;
items = diagramViewModel.Items.OfType<BlockDesignerItemViewModel>().Where(p => !blockDesignerItemTempLink.Items.Contains(p)).ToList();
foreach (var port in items.SelectMany(n => n.Containers))
{
if (port.GetBounds().IntersectsWith(blockDesignerItemTempLink.GetBounds())) //如果两个位置相交
{
var innerport = port.GetAllContainers(port.Children, false).Where(p => p.GetBounds().IntersectsWith(blockDesignerItemTempLink.GetBounds())).OrderByDescending(p => p.ContainerLevel).FirstOrDefault();
if (innerport != null)
{
innerport.DataItem.ShowConnectors = true;
if (innerport.CanAttachTo(blockDesignerItemTempLink.Items.FirstOrDefault()) == true)
{
innerport.BeAttachTo = true;
return innerport;
}
//else
//{
// innerport.DisableAttachTo = true;
// return null;
//}
}
else
{
port.DataItem.ShowConnectors = true;
if (port.CanAttachTo(blockDesignerItemTempLink.Items.FirstOrDefault()) == true)
{
port.BeAttachTo = true;
return port;
}
//else
//{
// port.DisableAttachTo = true;
// return null;
//}
}
}
}
return null;
}
public static void ClearNearPort(this IDiagramViewModel diagramViewModel)
{
diagramViewModel.Items.OfType<DesignerItemViewModelBase>().ToList().SelectMany(n => n.Connectors).Where(p => p.BeAttachTo == true || p.DisableAttachTo == true).ToList()
.ForEach(p => {
p.DisableAttachTo = false;
p.BeAttachTo = false;
});
}
public static void ClearNearContain(this IDiagramViewModel diagramViewModel)
{
diagramViewModel.Items.OfType<BlockDesignerItemViewModel>().ToList().SelectMany(n => n.GetAllContainers()).Where(p => p.BeAttachTo == true || p.DisableAttachTo == true).ToList()
.ForEach(p => {
p.DisableAttachTo = false;
p.BeAttachTo = false;
});
}
#endregion
#region Block拖拽预览-
public static void PreviewNearBlock(this IDiagramViewModel diagramViewModel, List<BlockDesignerItemViewModel> blocks)
{
if (blocks.Any())
{
diagramViewModel.ClearNearPort();
diagramViewModel.ClearNearContain();
var links = BlockDesignerItemTempLink.Build(blocks);
foreach (BlockDesignerItemTempLink item in links)
{
var container = diagramViewModel.FindNearContainerToAttachTo(item);
if (container != null)
{
continue;
}
diagramViewModel.FindNearPortToAttachTo(item, false);
}
}
}
public static void FinishNearBlock(this IDiagramViewModel diagramViewModel, List<BlockDesignerItemViewModel> blocks)
{
if (blocks.Any())
{
diagramViewModel.ClearNearPort();
diagramViewModel.ClearNearContain();
var links = BlockDesignerItemTempLink.Build(blocks);
foreach (BlockDesignerItemTempLink item in links)
{
var container = diagramViewModel.FindNearContainerToAttachTo(item);
if (container != null)
{
container.DataItem.AddChild(item.Items.FirstOrDefault(), container);//待完善
container.BeAttachTo = false;
container.DisableAttachTo = false;
continue;
}
var portTuple = diagramViewModel.FindNearPortToAttachTo(item, true);
var portParent = portTuple.Item1;
var portNext = portTuple.Item2;
if (portParent != null)
{
(portParent.DataItem as BlockDesignerItemViewModel).AddNext(item.Items.FirstOrDefault());
portParent.BeAttachTo = false;
portParent.DisableAttachTo = false;
}
else
{
if (item.Items.FirstOrDefault().Parent != null)
{
(item.Items.FirstOrDefault().Parent as BlockDesignerItemViewModel).RemoveNext();
}
}
if (portNext != null)
{
item.Items.LastOrDefault().AddNext(portNext.DataItem as BlockDesignerItemViewModel);
portNext.BeAttachTo = false;
portNext.DisableAttachTo = false;
}
else
{
if (item.Items.LastOrDefault().Next != null)
{
item.Items.LastOrDefault().RemoveNext();
}
}
}
}
}
#endregion
}
}