protected GraphSetting graphSetting; // 绘图参数配置对象 /// <summary> /// 构造函数 /// </summary> /// <param name="line">缩放控制点所属的插槽容器</param> /// <param name="location">缩放控制点的位置</param> /// <param name="size">缩放控制点的大小</param> public ResizeControler(SlotContainer slotContainer, Point location, Size size) : base(location) { this.slotContainer = slotContainer; this.location = location; this.elementSize = size; }
/// <summary> /// 初始化图结点 /// </summary> /// <param name="graphElement">结点对象</param> /// <param name="id">结点ID</param> /// <param name="name">结点名称</param> private void InitSlotContainer(SlotContainer slotContainer, int id, string name) { slotContainer.ID = id; slotContainer.Name = name; slotContainer.Init(); graphManager.SlotContainerList.Add(slotContainer); description = "创建图元 " + slotContainer.Name; dataManager.AddDataElement(slotContainer); graphManager.SelectGraphElement(slotContainer, false); graphManager.ReconstructCanvasGraphElementList(); }
/// <summary> /// 添加插槽容器到区域 /// </summary> /// <param name="slotContainer">插槽容器</param> public void Add(SlotContainer slotContainer) { if (!slotContainers.Contains(slotContainer)) { slotContainers.Add(slotContainer); } }
/// <summary> /// 检查插槽容器是否与连接线相交 /// </summary> /// <param name="slotContainer">插槽容器</param> /// <param name="pointList">连接线的连接点坐标</param> /// <returns>是否相交</returns> private bool CheckSlotContainerIntersect6(SlotContainer slotContainer, List<Point> pointList) { bool intersect = false; Rectangle rectangle = slotContainer.TextRectangle; if (LineIntersect(rectangle, pointList[1], pointList[2]) || LineIntersect(rectangle, pointList[2], pointList[3]) || LineIntersect(rectangle, pointList[3], pointList[4])) { intersect = true; } else { if (slotContainer == inSlotContainer) { if (pointList[0].Y > pointList[1].Y) { intersect = true; } } else if (slotContainer == outSlotContainer) { if (pointList[4].Y > pointList[5].Y) { intersect = true; } } else { if (LineIntersect(rectangle, pointList[0], pointList[1]) || LineIntersect(rectangle, pointList[4], pointList[5])) { intersect = true; } } } return intersect; }
/// <summary> /// 检查连接线是否与插槽容器相交 /// </summary> /// <param name="slotContainer">插槽容器</param> /// <param name="headPoint">头结点</param> /// <param name="tailPoint">尾结点</param> /// <returns>是否相交</returns> private bool LineIntersect(SlotContainer slotContainer, Point headPoint, Point tailPoint) { if (slotContainer != inSlotContainer && slotContainer != outSlotContainer) { Rectangle rectangle = slotContainer.TextRectangle; int x1 = headPoint.X; int y1 = headPoint.Y; int x2 = tailPoint.X; int y2 = tailPoint.Y; int x, y; int topY = y1; int bottomY = y2; if (y1 > y2) { topY = y2; bottomY = y1; } int leftX = x1; int rightX = x2; if (x1 > x2) { leftX = x2; rightX = x1; } if (x1 == x2) // 垂直线 { if (x1 >= rectangle.Left && x1 <= rectangle.Right && topY <= rectangle.Top && bottomY >= rectangle.Bottom) { return true; } } else if (y1 == y2) // 水平线 { if (y1 >= rectangle.Top && y1 <= rectangle.Bottom && leftX < rectangle.Left && rightX >= rectangle.Right) { return true; } } else { // 检查上边 x = (x2 - x1) * (rectangle.Top - y1) / (y2 - y1) + x1; if (x > rectangle.Left && x < rectangle.Right && topY < rectangle.Top && bottomY > rectangle.Top) { return true; } // 检查下边 x = (x2 - x1) * (rectangle.Bottom - y1) / (y2 - y1) + x1; if (x > rectangle.Left && x < rectangle.Right && topY < rectangle.Bottom && bottomY > rectangle.Bottom) { return true; } // 检查左边 y = (y2 - y1) * (rectangle.Left - x1) / (x2 - x1) + y1; if (y > rectangle.Top && y < rectangle.Bottom && leftX < rectangle.Left && rightX > rectangle.Left) { return true; } // 检查右边 y = (y2 - y1) * (rectangle.Right - x1) / (x2 - x1) + y1; if (y > rectangle.Top && y < rectangle.Bottom && leftX < rectangle.Right && rightX > rectangle.Right) { return true; } } } return false; }
/// <summary> /// 自动连接图元 /// </summary> /// <param name="previousContainer">连出的插槽容器</param> /// <param name="currentContainer">连入的插槽容器</param> private void ConnectGraphElement(SlotContainer previousContainer, SlotContainer currentContainer) { SlotGraphElement outSlot = previousContainer.GetOutSlot(); SlotGraphElement inSlot = currentContainer.GetInSlot(); if(outSlot != null && inSlot != null) // 可能有些结点不能分配出新插槽 { FlowChartCreateAndConnectLineCommand cmd = new FlowChartCreateAndConnectLineCommand(this, "创建并连接图元"); InitFirstCommand(cmd); if (cmd.Execute(new object[] { outSlot, inSlot })) // 命令执行成功 { AdjustCommandList(cmd); ConnectorContainer line = selectedGraphElement as ConnectorContainer; regionManager.AddToRegion(line); // 调整图元所在区域 // 自动调整连接线 AdjustLine(line, currentContainer); if (previousContainer is ConditionGraphElement) // 编辑条件结点连出的连接线 { FlowChartEditCommand editCommand = new FlowChartEditCommand(this, "编辑图元"); if (editCommand.Execute(line)) { AdjustCommandList(editCommand); } } } } autoConnect = false; }
/// <summary> /// 调整连接线 /// </summary> /// <param name="slotContainer">插槽容器</param> private void AdjustLine(SlotContainer slotContainer) { List<ConnectorContainer> lineList = regionManager.GetConnectorContainerList(slotContainer.InvalidRectangle); foreach (ConnectorContainer line in lineList) { if (line.LineIntersect(slotContainer)) { AdjustLine(line, slotContainer); } } }
/// <summary> /// 创建调整网格线 /// </summary> /// <param name="slotContaienr">当前插槽容器</param> private void CreateAdjustLine(SlotContainer slotContainer, Direction direction, bool autoAdjust) { canvas.CurrentGuideLine.ClearGuideLineList(); Rectangle rectangle = Rectangle.Empty; rectangle.Location = canvas.ClientRectangle.Location - (Size)canvas.AutoScrollPosition; rectangle.Size = canvas.ClientSize; List<SlotContainer> list = regionManager.GetSlotContainerList(rectangle); int leftX = -1; int rightX = -1; int topY = -1; int bottomY = -1; canvas.PaintCanvas = false; foreach(SlotContainer s in list) { if (s != slotContainer) { // 插槽调整线 if (s.TextRectangle.Left < slotContainer.TextRectangle.Right && s.TextRectangle.Right > slotContainer.TextRectangle.Left) { if (s.TextRectangle.Bottom < slotContainer.TextRectangle.Top) { foreach (SlotGraphElement slot1 in s.GetOutSlotList()) { foreach (SlotGraphElement slot2 in slotContainer.GetInSlotList()) { if (slot1.Location.X == slot2.Location.X) { canvas.CurrentGuideLine.AddGuideLine(new Point[] { slot1.Location, slot2.Location }); } } } } if (s.TextRectangle.Top > slotContainer.TextRectangle.Bottom) { foreach (SlotGraphElement slot1 in s.GetInSlotList()) { foreach (SlotGraphElement slot2 in slotContainer.GetOutSlotList()) { if (slot1.Location.X == slot2.Location.X) { canvas.CurrentGuideLine.AddGuideLine(new Point[] { slot1.Location, slot2.Location }); } } } } } // 显示边框调整线 switch (direction) { case Direction.Left: { if (slotContainer.TextRectangle.Left - s.TextRectangle.Left >= 0 && slotContainer.TextRectangle.Left - s.TextRectangle.Left < moveAdjustWidth) { canvas.CurrentGuideLine.AddGuideLine(new Point[]{ new Point(s.TextRectangle.Left, canvas.VisibleRectangle.Top), new Point(s.TextRectangle.Left, canvas.VisibleRectangle.Bottom)}); if (s.TextRectangle.Left < leftX || leftX == -1) { leftX = s.TextRectangle.Left; } } break; } case Direction.Right: { if (s.TextRectangle.Right - slotContainer.TextRectangle.Right >= 0 && s.TextRectangle.Right - slotContainer.TextRectangle.Right < moveAdjustWidth) { canvas.CurrentGuideLine.AddGuideLine(new Point[]{ new Point(s.TextRectangle.Right, canvas.VisibleRectangle.Top), new Point(s.TextRectangle.Right, canvas.VisibleRectangle.Bottom)}); if (s.TextRectangle.Right > rightX || rightX == -1) { rightX = s.TextRectangle.Right; } } break; } case Direction.Up: { if (slotContainer.TextRectangle.Top - s.TextRectangle.Top >= 0 && slotContainer.TextRectangle.Top - s.TextRectangle.Top < moveAdjustWidth) { canvas.CurrentGuideLine.AddGuideLine(new Point[]{ new Point(canvas.VisibleRectangle.Left, s.TextRectangle.Top), new Point(canvas.VisibleRectangle.Right, s.TextRectangle.Top)}); if (s.TextRectangle.Top < topY || topY == -1) { topY = s.TextRectangle.Top; } } break; } case Direction.Down: { if (s.TextRectangle.Bottom - slotContainer.TextRectangle.Bottom >= 0 && s.TextRectangle.Bottom - slotContainer.TextRectangle.Bottom < moveAdjustWidth) { canvas.CurrentGuideLine.AddGuideLine(new Point[]{ new Point(canvas.VisibleRectangle.Left, s.TextRectangle.Bottom), new Point(canvas.VisibleRectangle.Right, s.TextRectangle.Bottom)}); if (s.TextRectangle.Bottom > bottomY || bottomY == -1) { bottomY = s.TextRectangle.Bottom; } } break; } } } } if (autoAdjust) // 自动调整位置 { bool requireAdjust = false; Size moveSize = Size.Empty; int lagPosition = -1; switch (direction) { case Direction.Left: { if (leftX != -1) { moveSize.Width = leftX - slotContainer.TextRectangle.Left; lagPosition = leftX; if (moveSize.Width < moveLagOffset) { requireAdjust = true; } } break; } case Direction.Right: { if (rightX != -1) { moveSize.Width = rightX - slotContainer.TextRectangle.Right; lagPosition = rightX; if (moveSize.Width < moveLagOffset) { requireAdjust = true; } } break; } case Direction.Up: { if (topY != -1) { moveSize.Height = topY - slotContainer.TextRectangle.Top; lagPosition = topY; if (moveSize.Height < moveLagOffset) { requireAdjust = true; } } break; } case Direction.Down: { if (bottomY != -1) { moveSize.Height = bottomY - slotContainer.TextRectangle.Bottom; lagPosition = bottomY; if (moveSize.Height < moveLagOffset) { requireAdjust = true; } } break; } default: { break; } } if (requireAdjust) { slotContainer.Move(moveSize); if (LagMove(direction, lagPosition)) // 移动延迟 { Cursor.Position += moveSize; } } } canvas.PaintCanvas = true; }
/// <summary> /// 检查区域中是否包含当前插槽容器 /// </summary> /// <param name="slotContainer">当前插槽容器</param> /// <returns>区域是否包含当前插槽容器</returns> public bool Contains(SlotContainer slotContainer) { bool result = slotContainers.Contains(slotContainer); return result; }
/// <summary> /// 删除区域中的插槽容器 /// </summary> /// <param name="slotContainer">当前插槽容器</param> public void Remove(SlotContainer slotContainer) { slotContainers.Remove(slotContainer); }
/// <summary> /// 更新插槽容器所在的区域 /// </summary> /// <param name="slotContainer">当前插槽容器</param> private void ChangeRegion(SlotContainer slotContainer) { bool added = false; // 是否已经添加到区域中 foreach (RegionData regionData in regionDataList) { if (regionData.Contains(slotContainer) && !regionData.IsInRegion(slotContainer.InvalidRectangle)) { regionData.Remove(slotContainer); } if (!regionData.Contains(slotContainer) && regionData.IsInRegion(slotContainer.InvalidRectangle)) { regionData.Add(slotContainer); added = true; } } if (!added) { backupRegionData.Add(slotContainer); } // 更新相关连接线所在的区域 foreach (ConnectorContainer line in slotContainer.GetConnectedLine()) { ChangeRegion(line); } }
/// <summary> /// 将插槽容器从区域中删除 /// </summary> /// <param name="slotContainer">当前插槽容器</param> private void DeleteFromRegion(SlotContainer slotContainer) { foreach (RegionData regionData in regionDataList) { regionData.Remove(slotContainer); } backupRegionData.Remove(slotContainer); // 更新网格数据 ClearSlotContainerGrid(slotContainer); }
/// <summary> /// 将插槽容器加入区域中 /// </summary> /// <param name="slotContainer">当前插槽容器</param> private void AddToRegion(SlotContainer slotContainer) { bool added = false; foreach (RegionData regionData in regionDataList) { if (regionData.IsInRegion(slotContainer.InvalidRectangle)) { regionData.Add(slotContainer); added = true; } } if (!added) { backupRegionData.Add(slotContainer); } // 更新网格数据 UpdateSlotContainerGrid(slotContainer); }
/// <summary> /// 获取插槽容器覆盖网格点的集合 /// </summary> /// <param name="slotContainer">插槽容器</param> /// <param name="gridWidth">网格宽度</param> /// <returns>插槽容器覆盖网格点的集合</returns> private List<Point> GetGridPointList(SlotContainer slotContainer, int gridWidth) { List<Point> list = new List<Point>(); Rectangle rectangle = slotContainer.TextRectangle; int leftX = (int)Math.Ceiling((float)rectangle.Left / gridWidth) * gridWidth; int rightX = (int)Math.Floor((float)rectangle.Right / gridWidth) * gridWidth; int topY = (int)Math.Ceiling((float)rectangle.Top / gridWidth) * gridWidth; int bottomY = (int)Math.Floor((float)rectangle.Bottom / gridWidth) * gridWidth; Point point = Point.Empty; for (int i = leftX; i <= rightX; i += gridWidth) { for (int j = topY; j <= bottomY; j += gridWidth) { point.X = i; point.Y = j; list.Add(point); } } return list; }
/// <summary> /// 清除插槽容器对应的网格 /// </summary> /// <param name="slotContainer">插槽容器</param> private void ClearSlotContainerGrid(SlotContainer slotContainer) { Rectangle rectangle = slotContainer.InvalidRectangle; List<Point> gridPointList = GetGridPointList(slotContainer, gridWidth); foreach (Point point in gridPointList) { int gridX = (int)(point.X / gridWidth); int gridY = (int)(point.Y / gridWidth); if (gridX >= 0 && gridX < gridBoardWidth && point.Y >= 0 && point.Y < gridBoardHeight) { canvasGridBoard[gridX, gridY] = false; } } }
/// <summary> /// 检查插槽容器的所有连出的线是否有效 /// </summary> /// <param name="slotContainer">插槽容器</param> private void CheckLineValid(DataManager dataManager, SlotContainer slotContainer) { int invalidLineCount = 0; List<ConnectorContainer> list = new List<ConnectorContainer>(); foreach (SlotGraphElement slot in slotContainer.GetOutSlotList()) { if (slot.Binded) { object data = dataManager.GetData(slot.BindingConnector.Line); if (data == null) { list.Add(slot.BindingConnector.Line); invalidLineCount++; } else { slot.BindingConnector.Line.Invalid = false; } } } if (invalidLineCount == 1) // 无效连接线数等于1 { foreach (ConnectorContainer line in list) { line.Invalid = false; line.Text = "else"; line.ShowText = true; line.AdjustText(); } } else if (invalidLineCount > 1) // 无效连接线数大于1 { foreach (ConnectorContainer line in list) { line.Invalid = true; line.Text = "×"; line.ShowText = true; line.AdjustText(); } } else { foreach (ConnectorContainer line in list) { line.Invalid = false; line.ShowText = false; } } }
/// <summary> /// 获取连入的所有插槽容器的链表 /// </summary> /// <param name="slotContainer">当前插槽容器</param> /// <returns>连入的所有插槽容器的链表</returns> public List<SlotContainer> GetAllPreviousSlotContainers(SlotContainer slotContainer) { List<SlotContainer> list = new List<SlotContainer>(); GetAllPreviousSlotContainers(slotContainer, list); return list; }
/// <summary> /// 获取连入的所有插槽容器的链表(辅助函数) /// </summary> /// <param name="slotContainer">当前插槽容器</param> /// <param name="list">当前搜索的所有插槽容器的练表</param> public void GetAllPreviousSlotContainers(SlotContainer slotContainer, List<SlotContainer> list) { if(!list.Contains(slotContainer)) // 避免出现死循环 { list.Add(slotContainer); foreach(SlotGraphElement slot in slotContainer.GetInSlotList()) { if(slot.Binded && slot.BindingConnector.Line.InSlotContainer != null) { GetAllPreviousSlotContainers(slot.BindingConnector.Line.InSlotContainer, list); } } } }
/// <summary> /// 标记插槽容器相关的连接线 /// </summary> /// <param name="slotContainer">当前插槽容器</param> /// <param name="mark">是否标记</param> private void MarkRelavateLines(SlotContainer slotContainer, bool mark) { foreach (ConnectorContainer line in slotContainer.GetConnectedLine()) { line.Marked = mark; } }
/// <summary> /// 获取连出的插槽容器链表 /// </summary> /// <param name="slotContainer">当前插槽容器</param> /// <returns>连出的插槽容器链表</returns> public List<SlotContainer> GetNextSlotContainers(SlotContainer slotContainer) { List<SlotContainer> list = new List<SlotContainer>(); foreach(SlotGraphElement slot in slotContainer.GetOutSlotList()) { if(slot.Binded && slot.BindingConnector.Line.OutSlotContainer != null && !list.Contains(slot.BindingConnector.Line.OutSlotContainer)) { list.Add(slot.BindingConnector.Line.OutSlotContainer); } } return list; }
/// <summary> /// 检查是否图元被选中 /// </summary> /// <param name="p">鼠标当前所在点</param> public void CheckGraphElementSelected(Point point) { Point p = AdjustMouseLocation(point); RecordLastSelectedPoint(p); selectedGraphElement = null; ConnectorContainer newLine = null; // 自动新建的连接线 bool selected = false; // 是否已经有图元被选中 GraphElement graphElement = null; // 当前图元 if (lastSelectedGraphElement != null) // 将上一个被选中的图元置为非选中状态 { if (!selectedGraphElementList.Contains(lastSelectedGraphElement)) // 在多选状态需要检查上一个被选中的图元是否在多选容器中 { lastSelectedGraphElement.Selected = false; } } if (lastResizingGraphElement != null) // 将上一个缩放的插槽容器置为非缩放状态 { lastResizingGraphElement.Resizing = false; } // 检查游标是否被选中 if (canvas.CurrentRodman.IsInRegion(p)) { InitMoveGraphElementList(); graphElement = canvas.CurrentRodman; selected = true; } // 索引检查是否有连接线控制点容器被选中 foreach (ConnectorContainer connectorContainer in regionManager.GetConnectorContainerList(p)) { if (selected) // 已经有图元被选中时自动跳出循环 { break; } // 先遍历检查是否有连接线控制点被选中 ConnectorGraphElement connector = connectorContainer.GetConnectorInRegion(p); if (connector != null) { graphElement = connector; selected = true; break; } if (connectorContainer.IsInRegion(p)) // 连接线被选中 { graphElement = connectorContainer; selected = true; break; } } foreach (SlotContainer slotContainer in regionManager.GetSlotContainerList(p)) // 索引检查是否有插槽容器被选中 { if (selected) // 如果有图元被选中的话则自动跳出循环 { break; } // 检查是否有缩放控制点被选中 ResizeControler resizeControler = slotContainer.GetResizeControlerInRegion(p); if (resizeControler != null) { graphElement = resizeControler; selected = true; slotContainer.Resizing = true; lastResizingGraphElement = slotContainer; ChangeMouseCursur(resizeControler.CurrentDirection); // 改变鼠标指针形状 break; } // 检查是否有按钮被选中 BaseButton baseButton = slotContainer.GetButtonInRegion(p); if (baseButton != null) { if (baseButton is ConnectButton) // 是连接按钮 { SlotGraphElement slot = (baseButton as ConnectButton).BindingSlot; if (!slot.Binded && slot.IsOutSlot) // 插槽没有绑定连接线控制点,则新建连接线并绑定到当前插槽上 { FlowChartCreateLineCommand cmd = new FlowChartCreateLineCommand(this, "创建图元"); InitFirstCommand(cmd); if (cmd.Execute(new object[] { slot, p })) { AdjustCommandList(cmd); newLine = selectedGraphElement as ConnectorContainer; ConnectorGraphElement connector = newLine.GetConnectorList()[1]; graphElement = connector; selected = true; } break; } } else if (baseButton is AddButton) // 是添加按钮 { SlotGraphElement slot = slotContainer.AddOutSlot(); graphElement = slotContainer; selected = true; break; } } // 检查是否有注释图元被选中 if (slotContainer.RemarkNode != null) { if (slotContainer.RemarkNode.IsInRegion(p)) { graphElement = slotContainer.RemarkNode; selected = true; break; } } if (slotContainer.IsInRegion(p)) { SlotGraphElement slot = slotContainer.GetSlotInRegion(p); if (slot != null) { graphElement = slot; selected = true; break; } slotContainer.Resizing = true; lastResizingGraphElement = slotContainer; graphElement = slotContainer; selected = true; break; } } if (selected) // 已经有图元被选中 { SelectGraphElement(graphElement, p); userOperation = UserOperation.SingleSelect; if (selectedGraphElementList.Contains(selectedGraphElement)) // 进行多图元操作 { if (controlMode) // 在control模式下需要反选图元 { selectedGraphElementList.Remove(selectedGraphElement); selectedGraphElement.Selected = false; selectedGraphElement = null; lastSelectedGraphElement = null; userOperation = UserOperation.None; if (selectedGraphElementList.Count == 0) { canvas.CurrentMultiSelectMark.Visible = false; } else { CreateMultiSelectRegion(); } } else { userOperation = UserOperation.MultiSelect; } } else { if (controlMode) // 在control模式下需要加入图元 { selectedGraphElementList.Add(selectedGraphElement); CreateMultiSelectRegion(); userOperation = UserOperation.MultiSelect; } else { if (graphElement is Rodman) { userOperation = UserOperation.MoveRodman; CreateMultiMoveRegion(); } // 清空多选图元链表 ClearSelectedGraphElementList(); } } } else // 没有图元被选中 { userOperation = UserOperation.RegionSelect; // 显示背景属性 documentManager.ShowObjectProperty(background); multiSelectStartPoint = p; // 清空多选图元链表 ClearSelectedGraphElementList(); } RefreshCanvas(); }
/// <summary> /// 获取插槽容器对应的事件结点的数据 /// </summary> /// <param name="slotContainer">当前插槽容器</param> /// <returns>事件结点的数据</returns> public object GetEventData(SlotContainer slotContainer) { object data = null; List<DataElement> eventList = GetEventList(slotContainer); if(eventList.Count > 0) { data = eventList[0].Data; } return data; }
/// <summary> /// 调整连接线 /// </summary> /// <param name="line">当前连接线</param> /// <param name="slotContainer">相关的插槽容器</param> private void AdjustLine(ConnectorContainer line , SlotContainer slotContainer) { Rectangle adjustRectangle = line.GetAdjustRectangle(background.CanvasSize, background.GridSize.Width); List<SlotContainer> totalSlotContainerList = regionManager.GetSlotContainerList(adjustRectangle); List<ConnectorContainer> totalLineList = regionManager.GetConnectorContainerList(adjustRectangle); line.AdjustLine(slotContainer, totalSlotContainerList, totalLineList, background.GridSize.Width, background.BaseSize, regionManager.CanvasGridBoard); line.AdjustRectangle(); }
/// <summary> /// 获取插槽容器对应的事件结点数据链表 /// </summary> /// <param name="slotContainer">当前插槽容器</param> /// <returns>插槽容器对应的事件结点数据链表</returns> public List<DataElement> GetEventList(SlotContainer slotContainer) { List<DataElement> list = new List<DataElement>(); List<SlotContainer> slotContainerList = GetAllPreviousSlotContainers(slotContainer); foreach(SlotContainer s in slotContainerList) { if(s is EventGraphElement) { DataElement dataElement = graphTable[s] as DataElement; if(dataElement != null) { list.Add(dataElement); } } } return list; }
private SlotContainer slotContainer; // 添加按钮对应的插槽 public AddButton(SlotContainer slotContainer, Point location, Size elementSize) :base(location, elementSize) { this.slotContainer = slotContainer; }
/// <summary> /// 检查是否连接有事件结点 /// </summary> /// <param name="slotContainer">当前插槽容器</param> /// <returns>是否连接有事件结点</returns> public bool IsConnectEventNode(SlotContainer slotContainer) { bool result = false; if (slotContainer.RequireEvent) // 需要入口事件 { if (GetEventList(slotContainer).Count > 0) { result = true; } } else { result = true; } return result; }
/// <summary> /// 检查矩形是否与当前连接线相交 /// </summary> /// <param name="slotContainer">插槽容器</param> /// <return>是否相交</return> public bool LineIntersect(SlotContainer slotContainer) { if (slotContainer != inSlotContainer && slotContainer != outSlotContainer) { Rectangle rectangle = slotContainer.TextRectangle; if(connectorList.Count == 6) { if (LineIntersect(rectangle, connectorList[0].Location, connectorList[1].Location)) { return true; } if (LineIntersect(rectangle, connectorList[1].Location, connectorList[2].Location)) { return true; } if (LineIntersect(rectangle, connectorList[2].Location, connectorList[3].Location)) { return true; } if (LineIntersect(rectangle, connectorList[3].Location, connectorList[4].Location)) { return true; } if (LineIntersect(rectangle, connectorList[4].Location, connectorList[5].Location)) { return true; } } else { int x1 = connectorList[0].Location.X; int y1 = connectorList[0].Location.Y; int x2 = connectorList[1].Location.X; int y2 = connectorList[1].Location.Y; int x, y; int topY = y1; int bottomY = y2; if (y1 > y2) { topY = y2; bottomY = y1; } int leftX = x1; int rightX = x2; if (x1 > x2) { leftX = x2; rightX = x1; } if(x1 == x2) // 垂直线 { if (x1 >= rectangle.Left && x1 <= rectangle.Right && topY <= rectangle.Top && bottomY >= rectangle.Bottom) { return true; } } else if (y1 == y2) // 水平线 { if (y1 >= rectangle.Top && y1 <= rectangle.Bottom && leftX < rectangle.Left && rightX >= rectangle.Right) { return true; } } else { // 检查上边 x = (x2 - x1) * (rectangle.Top - y1) / (y2 - y1) + x1; if (x > rectangle.Left && x < rectangle.Right && topY < rectangle.Top && bottomY > rectangle.Top) { return true; } // 检查下边 x = (x2 - x1) * (rectangle.Bottom - y1) / (y2 - y1) + x1; if (x > rectangle.Left && x < rectangle.Right && topY < rectangle.Bottom && bottomY > rectangle.Bottom) { return true; } // 检查左边 y = (y2 - y1) * (rectangle.Left - x1) / (x2 - x1) + y1; if (y > rectangle.Top && y < rectangle.Bottom && leftX < rectangle.Left && rightX > rectangle.Left) { return true; } // 检查右边 y = (y2 - y1) * (rectangle.Right - x1) / (x2 - x1) + y1; if (y > rectangle.Top && y < rectangle.Bottom && leftX < rectangle.Right && rightX > rectangle.Right) { return true; } } } } return false; }
/// <summary> /// 复制数据 /// </summary> /// <param name="srcSlotContainer">源插槽容器</param> /// <param name="destSlotContainer">目标插槽容器</param> protected virtual void CopyData(SlotContainer srcSlotContainer, SlotContainer destSlotContainer) { destSlotContainer.Name = srcSlotContainer.Name; destSlotContainer.Remark = srcSlotContainer.Remark; destSlotContainer.Text = srcSlotContainer.Text; destSlotContainer.DisplayText = srcSlotContainer.DisplayText; destSlotContainer.TooltipText = srcSlotContainer.TooltipText; destSlotContainer.ShowText = srcSlotContainer.ShowText; // 初始化绘图参数 destSlotContainer.Init(); destSlotContainer.InSlotCount = srcSlotContainer.InSlotCount; destSlotContainer.OutSlotCount = srcSlotContainer.OutSlotCount; destSlotContainer.AdjustText(); destSlotContainer.AdjustResizeControlerList(); destSlotContainer.AdjustButtonList(); }
/// <summary> /// 调整连接线 /// </summary> /// <param name="currentSlotContainer">当前移动的插槽容器</param> /// <param name="slotContainerList">插槽容器链表</param> /// <param name="connectorContainerList">连接线链表</param> /// <param name="gridWidth">网格的边长</param> /// <param name="canvasSize">绘图板的大小</param> /// <param name="gridBoard">网格数据绘图板</param> public virtual void AdjustLine(SlotContainer currentSlotContainer, List<SlotContainer> slotContainerList, List<ConnectorContainer> connectorContainerList, int gridWidth, Size canvasSize, bool[,] gridBoard) { if (inSlotContainer != null && outSlotContainer != null) // 连接线两端均已连接图元 { int headX = headConnector.Location.X; int headY = headConnector.Location.Y; int tailX = tailConnector.Location.X; int tailY = tailConnector.Location.Y; ConnectorGraphElement connector1 = null; ConnectorGraphElement connector2 = null; ConnectorGraphElement connector3 = null; ConnectorGraphElement connector4 = null; ConnectorGraphElement connector5 = null; ConnectorGraphElement connector6 = null; if (CheckRequireAdjust(slotContainerList, canvasSize)) // 需要寻路避让 { // 先尝试用寻路算法 bool findLine = false; Rectangle regionRectangle = Rectangle.Empty; List<SlotContainer> nodeList; List<ConnectorContainer> lineList; // 备用线路,允许连接线重合 bool findBackup = false; Point[] backupPoints = new Point[4]; backupPoints[0] = Point.Empty; backupPoints[1] = Point.Empty; backupPoints[2] = Point.Empty; backupPoints[3] = Point.Empty; List<Point> pointList = new List<Point>(); List<Point[]> validPoints = new List<Point[]>(); // 有效点的集合 bool preCheck = false; // 是否开启预检查 bool valid = true; // 记住上一次被阻隔的图元 SlotContainer lastBlockSlotContainer = null; ConnectorContainer lastBlockLine = null; // 初始化数据 int leftX; int rightX; int topY; int bottomY; if (inSlotContainer.Location.X < outSlotContainer.Location.X) { leftX = inSlotContainer.Location.X; } else { leftX = outSlotContainer.Location.X; } if (inSlotContainer.TextRectangle.Right > outSlotContainer.TextRectangle.Right) { rightX = inSlotContainer.TextRectangle.Right; } else { rightX = outSlotContainer.TextRectangle.Right; } if (inSlotContainer.Location.Y < outSlotContainer.Location.Y) { topY = inSlotContainer.Location.Y; } else { topY = outSlotContainer.Location.Y; } if (inSlotContainer.TextRectangle.Bottom > outSlotContainer.TextRectangle.Bottom) { bottomY = inSlotContainer.TextRectangle.Bottom; } else { bottomY = outSlotContainer.TextRectangle.Bottom; } // 先尝试连接控制点数量点为4的情况 if (head.Y > tail.Y) { bool requireRestore = false; // 是否需要保存当前连接控制点坐标 Point[] restorePointArray = new Point[6]; // 保存当前连接线控制点坐标的数组 if (connectorCount == 6) { requireRestore = true; restorePointArray[0] = connectorList[0].Location; restorePointArray[1] = connectorList[1].Location; restorePointArray[2] = connectorList[2].Location; restorePointArray[3] = connectorList[3].Location; restorePointArray[4] = connectorList[4].Location; restorePointArray[5] = connectorList[5].Location; } ConnectorCount = 4; connector1 = connectorList[0]; connector2 = connectorList[1]; connector3 = connectorList[2]; connector4 = connectorList[3]; // 筛选需要避让的结点和连接线 regionRectangle.Location = new Point(leftX, topY); regionRectangle.Size = new Size(rightX - leftX, bottomY - topY); nodeList = GetSlotContainerInRegion(regionRectangle, slotContainerList); lineList = GetLineInRegion(regionRectangle, connectorContainerList); // 预检查一次 if (currentSlotContainer == inSlotContainer) { connector1Location.X = connector1.Location.X; connector1Location.Y = connector1.Location.Y; connector2Location.X = connector1.Location.X; connector2Location.Y = connector2.Location.Y; connector3Location.X = connector4.Location.X; connector3Location.Y = connector2.Location.Y; connector4Location.X = connector4.Location.X; connector4Location.Y = connector4.Location.Y; preCheck = true; } else if (currentSlotContainer == outSlotContainer) { connector1Location.X = connector1.Location.X; connector1Location.Y = connector1.Location.Y; connector2Location.X = connector1.Location.X; connector2Location.Y = connector3.Location.Y; connector3Location.X = connector4.Location.X; connector3Location.Y = connector3.Location.Y; connector4Location.X = connector4.Location.X; connector4Location.Y = connector4.Location.Y; preCheck = true; } // 校正连接线的形状 if (connector2Location.X != connector1Location.X) { connector2Location.X = connector1Location.X; } if (connector3Location.Y != connector2Location.Y) { connector3Location.Y = connector2Location.Y; } if (connector3Location.X != connector4Location.X) { connector3Location.Y = connector5Location.X; } if (preCheck) { if (!CheckPointInGrid(connector2Location, connector3Location, gridBoard, gridWidth)) { List<Point> checkPointList = new List<Point>(); checkPointList.Add(connector1Location); checkPointList.Add(connector2Location); checkPointList.Add(connector3Location); checkPointList.Add(connector4Location); foreach (SlotContainer slotContainer in nodeList) { if (CheckSlotContainerIntersect4(slotContainer, checkPointList)) { valid = false; lastBlockSlotContainer = slotContainer; break; } } } } else { valid = false; } if (valid) // 预检查选择的线路成功,直接调整连接线 { validPoints.Add(new Point[] { connector2Location, connector3Location }); findLine = true; } else { int tempY1 = (int)Math.Ceiling((float)inSlotContainer.TextRectangle.Bottom / gridWidth) * gridWidth; int tempY2 = (int)Math.Floor((float)outSlotContainer.TextRectangle.Top / gridWidth) * gridWidth; for (int i = tempY1; i < tempY2; i += gridWidth) { valid = true; connector2Location.X = connector1Location.X; connector2Location.Y = i; connector3Location.X = connector4Location.X; connector3Location.Y = i; List<Point> checkPointList = new List<Point>(); checkPointList.Add(connector1Location); checkPointList.Add(connector2Location); checkPointList.Add(connector3Location); checkPointList.Add(connector4Location); if (CheckPointInGrid(connector2Location, connector3Location, gridBoard, gridWidth)) { valid = false; continue; } if (lastBlockSlotContainer != null) { if (CheckSlotContainerIntersect4(lastBlockSlotContainer, checkPointList)) { valid = false; continue; } } foreach (SlotContainer slotContainer in nodeList) { if (CheckSlotContainerIntersect4(slotContainer, checkPointList)) { valid = false; lastBlockSlotContainer = slotContainer; break; } } if (valid) { // 记录备用线路 if (!findBackup) { findBackup = true; backupPoints[0].X = connector1Location.X; backupPoints[0].Y = i; backupPoints[1].X = connector4Location.Y; backupPoints[1].Y = i; } pointList.Clear(); pointList.Add(connector1Location); pointList.Add(connector2Location); pointList.Add(connector3Location); pointList.Add(connector4Location); if (lastBlockLine != null) { List<ConnectorGraphElement> blockList = lastBlockLine.GetConnectorList(); switch (blockList.Count) { case 4: { if (PointInLine(blockList[1].Location, pointList) || PointInLine(blockList[2].Location, pointList)) { valid = false; continue; } break; } case 6: { if (PointInLine(blockList[1].Location, pointList) || PointInLine(blockList[2].Location, pointList) || (PointInLine(blockList[3].Location, pointList) || (PointInLine(blockList[4].Location, pointList)))) { valid = false; continue; } break; } } } } if (valid) { validPoints.Add(new Point[] { connector2Location, connector3Location }); findLine = true; } } } if (!findLine) { if (requireRestore) // 恢复连接线控制点坐标 { ConnectorCount = 6; connectorList[0].Location = restorePointArray[0]; connectorList[1].Location = restorePointArray[1]; connectorList[2].Location = restorePointArray[2]; connectorList[3].Location = restorePointArray[3]; connectorList[4].Location = restorePointArray[4]; connectorList[5].Location = restorePointArray[5]; } } } if (!findLine) // 再尝试连接线控制点数量为6的情况 { // 初始化数据 valid = true; preCheck = false; findBackup = false; pointList.Clear(); validPoints.Clear(); int leftLineX = (int)Math.Floor(((float)leftX - 10 * gridWidth) / gridWidth) * gridWidth; if (leftLineX < 0) { leftLineX = gridWidth; } int rightLineX = (int)Math.Ceiling(((float)rightX + 10 * gridWidth) / gridWidth) * gridWidth; if (rightLineX > canvasSize.Width) { rightLineX = canvasSize.Width; } int topLineY = (int)Math.Floor(((float)topY - 10 * gridWidth) / gridWidth) * gridWidth; if (topLineY < 0) { topLineY = gridWidth; } int bottomLineY = (int)Math.Ceiling(((float)bottomY + 10 * gridWidth) / gridWidth) * gridWidth; if (bottomLineY > canvasSize.Height) { bottomLineY = canvasSize.Height; } // 筛选需要避让的结点和连接线 regionRectangle.Location = new Point(leftLineX, topLineY); regionRectangle.Size = new Size(rightLineX - leftLineX, bottomLineY - topLineY); nodeList = GetSlotContainerInRegion(regionRectangle, slotContainerList); lineList = GetLineInRegion(regionRectangle, connectorContainerList); List<int> verticalLineList = new List<int>(); List<int> horizontalLineList = new List<int>(); for (int i = leftLineX; i < rightLineX; i += gridWidth) { verticalLineList.Add(i); } for (int i = topLineY; i < bottomLineY; i += gridWidth) { horizontalLineList.Add(i); } ConnectorCount = 6; connector1 = connectorList[0]; connector2 = connectorList[1]; connector3 = connectorList[2]; connector4 = connectorList[3]; connector5 = connectorList[4]; connector6 = connectorList[5]; // 开始遍历查找符合条件的路径 connector1Location = connector1.Location; connector6Location = connector6.Location; // 预检查一次 if (currentSlotContainer == inSlotContainer) { connector2Location.X = connector1.Location.X; connector2Location.Y = connector2.Location.Y; connector3Location.X = connector3.Location.X; connector3Location.Y = connector3.Location.Y; connector4Location.X = connector4.Location.X; connector4Location.Y = connector4.Location.Y; connector5Location.X = connector5.Location.X; connector5Location.Y = connector5.Location.Y; preCheck = true; } else if (currentSlotContainer == outSlotContainer) { connector2Location.X = connector1.Location.X; connector2Location.Y = connector2.Location.Y; connector3Location.X = connector3.Location.X; connector3Location.Y = connector3.Location.Y; connector4Location.X = connector4.Location.X; connector4Location.Y = connector4.Location.Y; connector5Location.X = connector6.Location.X; connector5Location.Y = connector5.Location.Y; preCheck = true; } // 校正连接线的形状 if (connector2Location.X != connector1Location.X) { connector2Location.X = connector1Location.X; } if (connector5Location.X != connector6Location.X) { connector5Location.X = connector6Location.X; } if (connector3Location.Y != connector2Location.Y) { connector3Location.Y = connector2Location.Y; } if (connector4Location.Y != connector5Location.Y) { connector4Location.Y = connector5Location.Y; } if (preCheck) { if (!CheckPointInGrid(connector2Location, connector3Location, connector4Location, connector5Location, gridBoard, gridWidth)) { List<Point> checkPointList = new List<Point>(); checkPointList.Add(connector1Location); checkPointList.Add(connector2Location); checkPointList.Add(connector3Location); checkPointList.Add(connector4Location); checkPointList.Add(connector5Location); checkPointList.Add(connector6Location); foreach (SlotContainer slotContainer in nodeList) { if (CheckSlotContainerIntersect6(slotContainer, checkPointList)) { valid = false; lastBlockSlotContainer = slotContainer; break; } } } } else { valid = false; } if (valid) // 预检查选择的线路成功,直接调整连接线 { validPoints.Add(new Point[] { connector2Location, connector3Location, connector4Location, connector5Location }); findLine = true; } else { for (int i = 0; i < verticalLineList.Count; i++) { for (int j = 0; j < horizontalLineList.Count; j++) { for (int k = 0; k < horizontalLineList.Count; k++) { valid = true; connector2Location.X = connector1Location.X; connector2Location.Y = horizontalLineList[k]; connector3Location.X = verticalLineList[i]; connector3Location.Y = horizontalLineList[k]; connector4Location.X = verticalLineList[i]; connector4Location.Y = horizontalLineList[j]; connector5Location.X = connector6Location.X; connector5Location.Y = horizontalLineList[j]; List<Point> checkPointList = new List<Point>(); checkPointList.Add(connector1Location); checkPointList.Add(connector2Location); checkPointList.Add(connector3Location); checkPointList.Add(connector4Location); checkPointList.Add(connector5Location); checkPointList.Add(connector6Location); if (CheckPointInGrid(connector2Location, connector3Location, connector4Location, connector5Location, gridBoard, gridWidth)) { valid = false; } if (lastBlockSlotContainer != null) { if (CheckSlotContainerIntersect6(lastBlockSlotContainer, checkPointList)) { valid = false; continue; } } foreach (SlotContainer slotContainer in nodeList) { if (CheckSlotContainerIntersect6(slotContainer, checkPointList)) { valid = false; lastBlockSlotContainer = slotContainer; break; } } if (valid) { // 记录备用线路 if (!findBackup) { findBackup = true; backupPoints[0].X = connector1.Location.X; backupPoints[0].Y = horizontalLineList[k]; backupPoints[1].X = verticalLineList[i]; backupPoints[1].Y = horizontalLineList[k]; backupPoints[2].X = verticalLineList[i]; backupPoints[2].Y = horizontalLineList[j]; backupPoints[3].X = connector6.Location.X; backupPoints[3].Y = horizontalLineList[j]; } pointList.Clear(); pointList.Add(connector1Location); pointList.Add(connector2Location); pointList.Add(connector3Location); pointList.Add(connector4Location); pointList.Add(connector5Location); pointList.Add(connector6Location); if (lastBlockLine != null) { List<ConnectorGraphElement> blockList = lastBlockLine.GetConnectorList(); if (PointInLine(blockList[1].Location, pointList) || PointInLine(blockList[2].Location, pointList) || (PointInLine(blockList[3].Location, pointList) || (PointInLine(blockList[4].Location, pointList)))) { valid = false; continue; } } foreach (ConnectorContainer line in lineList) { if (line != this && line.ConnectorCount == 6) { List<ConnectorGraphElement> list = line.GetConnectorList(); if (PointInLine(list[1].Location, pointList) || PointInLine(list[2].Location, pointList) || (PointInLine(list[3].Location, pointList) || (PointInLine(list[4].Location, pointList)))) { valid = false; lastBlockLine = line; break; } } } } if (valid) { validPoints.Add(new Point[] { connector2Location, connector3Location, connector4Location, connector5Location }); findLine = true; } } } } } } if (findLine) // 找到符合条件的路径 { // 优选最佳线路 int index = 0; int score = -1; Point[] points; int tempLength1; int tempLength2; int tempLength3; int tempLength4; int tempLength5; switch (connectorCount) { case 4: { for (int i = 0; i < validPoints.Count; i++) { points = validPoints[i]; tempLength1 = points[0].Y - connector1Location.Y; tempLength2 = Math.Abs(points[0].X - points[1].X); tempLength3 = connector4Location.Y - points[1].Y; if (tempLength1 < gridWidth || tempLength2 < gridWidth || tempLength3 < gridWidth ) { continue; } else { int currentScore = (Math.Abs(connector1Location.X - points[1].X) + Math.Abs(connector4Location.X - points[1].X)) * 10 + tempLength1 + tempLength3; if (currentScore < score || score == -1) { score = currentScore; index = i; } } } points = validPoints[index]; connector2.Location = points[0]; connector3.Location = points[1]; break; } case 6: { for (int i = 0; i < validPoints.Count; i++) { points = validPoints[i]; tempLength1 = points[0].Y - connector1Location.Y; tempLength2 = Math.Abs(points[0].X - points[1].X); tempLength3 = Math.Abs(points[1].Y - points[2].Y); tempLength4 = Math.Abs(points[2].X - points[3].X); tempLength5 = connector6Location.Y - points[3].Y; if (tempLength1 < gridWidth || tempLength2 < gridWidth || tempLength3 < gridWidth || tempLength4 < gridWidth || tempLength5 < gridWidth ) { continue; } else { int currentScore = (Math.Abs(connector1Location.X - points[1].X) + Math.Abs(connector6Location.X - points[1].X)) * 10 + tempLength1 + tempLength5; if (currentScore < score || score == -1) { score = currentScore; index = i; } } } points = validPoints[index]; connector2.Location = points[0]; connector3.Location = points[1]; connector4.Location = points[2]; connector5.Location = points[3]; break; } } } else // 寻路算法失效之后的处理 { if (findBackup) // 启用备用线路 { switch (connectorCount) { case 4: { connector2.Location = backupPoints[0]; connector3.Location = backupPoints[1]; break; } case 6: { connector2.Location = backupPoints[0]; connector3.Location = backupPoints[1]; connector4.Location = backupPoints[2]; connector5.Location = backupPoints[3]; break; } } } else { if (headY > tailY) // 头结点在尾结点之下 { ConnectorCount = 2; } else // 头结点在尾结点之上 { switch(connectorCount) { case 4: { int middleY = (int)((connector1.Location.Y + connector4.Location.Y) / 2); connector2.Location = new Point(connector1Location.X + 50, middleY); connector3.Location = new Point(connector4Location.X - 50, middleY); break; } case 6: { int middleX = (int)((connector1.Location.X + connector6.Location.X) / 2); connector2.Location = connector1Location + new Size(0, 50); connector5.Location = connector6Location + new Size(0, -50); connector3.Location = new Point(middleX, connector2Location.Y); connector4.Location = new Point(middleX, connector5Location.Y); break; } } } } } } } }
protected GraphSetting graphSetting; // 绘图参数配置对象 /// <summary> /// 构造函数 /// </summary> /// <param name="slotContainner">插槽所属容器</param> /// <param name="location">插槽的位置</param> /// <param name="size">插槽的大小</param> /// <param name="id">插槽的id</param> public SlotGraphElement(SlotContainer slotContainer, Point location, Size size) : base(location) { this.slotContainer = slotContainer; this.elementSize = size; }