示例#1
0
		internal override bool sameNode(Link otherLink)
		{
			ChartObject obj = otherLink.getNode();

			if(obj == null)
				return false;
			else
				return (obj == table);
		}
示例#2
0
		internal bool objsIntersect(Link link)
		{
			return Node.nodesIntersect(this.getNode(), link.getNode());
		}
示例#3
0
		internal abstract bool sameNode(Link otherLink);
示例#4
0
		internal override bool sameNode(Link otherLink)
		{
			ChartObject obj = otherLink.getNode();

			return (obj != null && obj == host);
		}
示例#5
0
		internal override bool sameNode(Link otherLink)
		{
			return false;
		}
示例#6
0
		internal override void restoreState(ItemState state)
		{
			base.restoreState(state);

			ArrowState astate = (ArrowState)state;
			style = astate.style;
			segmentCount = astate.segmentCount;
			points = astate.points.Clone();
			reflexive = astate.reflexive;
			cascadeStartHorizontal = astate.cascadeStartHorizontal;

			if (orgnLink != astate.orgnLink)
			{
				orgnLink.removeArrowFromObj();
				orgnLink = astate.orgnLink;
				orgnLink.addArrowToObj();
			}
			orgnAnchor = astate.orgnAnchor;

			if (destLink != astate.destLink)
			{
				destLink.removeArrowFromObj();
				destLink = astate.destLink;
				destLink.addArrowToObj();
			}
			destAnchor = astate.destAnchor;

			updateFromPoints(false);

			if (subordinateGroup != null)
				subordinateGroup.onRestoreState();

			orgnLink.RelativePosition = astate.orgnPoint;
			destLink.RelativePosition = astate.destPoint;

			resetCrossings();
			updateText();
		}
示例#7
0
		private void setEndPoints(Link orgnLink, Link destLink, PointF end)
		{
			reflexive = destLink.sameNode(orgnLink);

			// align the end points of the arrow to the outlines of the connected nodes
			if (orgnLink.calcIntrs())
				ptOrg = points[0] = orgnLink.getInitialPt();
			if (destLink.calcIntrs())
				ptEnd = destLink.getInitialPt();
			else
				ptEnd = end;

			if (!orgnLink.objsIntersect(destLink) && !reflexive)
			{
				if (orgnLink.calcIntrs())
					ptOrg = points[0] = orgnLink.getIntersection(ptOrg, ptEnd);
				if (destLink.calcIntrs())
					ptEnd = destLink.getIntersection(ptEnd, ptOrg);
			}
			else
			{
				// if the arrow will be routed, choose the closest points on the
				// horizontal line intersections with the node outlines. These points
				// should not be contained within a node
				if (autoRoute && !dynamic && orgnAnchor == -1 && destAnchor == -1)
				{
					chooseRouteOutlinePoints(orgnLink, destLink, ref ptOrg, ref ptEnd);
					points[0] = ptOrg;
				}
			}
		}
示例#8
0
		private void putEndPointsAtNodeBorders(bool routing, Link orgnLink, Link destLink)
		{
			PointF ptOrg = orgnLink.getInitialPt();
			PointF ptDest = destLink.getInitialPt();

			if (!orgnLink.objsIntersect(destLink))
			{
				// if destination and source do not intersect, use the points
				// where the line connecting their centers crosses their outlines
				if (style == ArrowStyle.Cascading)
					updateEndPtsPrp();
				ptOrg = orgnLink.getIntersection(ptOrg,
					routing ? ptDest : points[1]);
				ptDest = destLink.getIntersection(ptDest,
					routing ? ptOrg : points[points.Count - 2]);
			}
			else
			{
				// if the arrow will be rerouted, choose the closest points on the
				// horizontal line intersections with the node outlines. These points
				// should not be contained within a node
				if (routing)
					chooseRouteOutlinePoints(orgnLink, destLink, ref ptOrg, ref ptDest);
			}

			// snap to nearest anchors
			ptOrg = orgnLink.getNode().getAnchor(
				ptOrg, this, false, ref orgnAnchor);
			ptDest = destLink.getNode().getAnchor(
				ptDest, this, true, ref destAnchor);

			if (style != ArrowStyle.Cascading)
				retain(ptOrg.X - points[0].X, ptOrg.Y - points[0].Y, true);
			points[0] = ptOrg;
			if (style != ArrowStyle.Cascading)
				retain(ptDest.X - points[points.Count - 1].X, ptDest.Y - points[points.Count - 1].Y, false);
			points[points.Count - 1] = ptDest;

			if (style == ArrowStyle.Cascading)
				updateEndPtsPrp();
		}
示例#9
0
		private void chooseRouteOutlinePoints(Link orgnLink, Link destLink,
			ref PointF ptOrg, ref PointF ptDest)
		{
			RoutingOptions rop = flowChart.RoutingOptions;
			Node origin = orgnLink.getNode();
			Node destination = destLink.getNode();
			bool reflexive = orgnLink.sameNode(destLink);

			// how many points to consider ?
			int srcCount = rop.StartOrientation == Orientation.Auto ? 4 : 2;
			int dstCount = rop.EndOrientation == Orientation.Auto ? 4 : 2;
			PointF[] srcPoints = new PointF[srcCount];
			PointF[] dstPoints = new PointF[dstCount];

			// determine the coordinates of the points to be checked ...
			int srcIdx = 0, dstIdx = 0;

			// source points
			if (rop.StartOrientation != Orientation.Vertical)
			{
				srcPoints[srcIdx++] = orgnLink.getIntersection(ptOrg,
					new PointF(ptOrg.X - 2*origin.BoundingRect.Width, ptOrg.Y));
				srcPoints[srcIdx++] = orgnLink.getIntersection(ptOrg,
					new PointF(ptOrg.X + 2*origin.BoundingRect.Width, ptOrg.Y));
			}
			if (rop.StartOrientation != Orientation.Horizontal)
			{
				srcPoints[srcIdx++] = orgnLink.getIntersection(ptOrg,
					new PointF(ptOrg.X, ptOrg.Y - 2*origin.BoundingRect.Height));
				srcPoints[srcIdx++] = orgnLink.getIntersection(ptOrg,
					new PointF(ptOrg.X, ptOrg.Y + 2*origin.BoundingRect.Height));
			}

			// destination points
			if (rop.EndOrientation != Orientation.Vertical)
			{
				dstPoints[dstIdx++] = dstPoints[1] = destLink.getIntersection(ptDest,
					new PointF(ptDest.X - 2*destination.BoundingRect.Width, ptDest.Y));
				dstPoints[dstIdx++] = destLink.getIntersection(ptDest,
					new PointF(ptDest.X + 2*destination.BoundingRect.Width, ptDest.Y));
			}
			if (rop.EndOrientation != Orientation.Horizontal)
			{
				dstPoints[dstIdx++] = destLink.getIntersection(ptDest,
					new PointF(ptDest.X, ptDest.Y - 2*destination.BoundingRect.Height));
				dstPoints[dstIdx++] = destLink.getIntersection(ptDest,
					new PointF(ptDest.X, ptDest.Y + 2*destination.BoundingRect.Height));
			}

			// check which of these points are closest
			ptOrg = srcPoints[0];
			ptDest = dstPoints[0];
			float minDist = Single.MaxValue;
			for (int sidx = 0; sidx < srcCount; ++sidx)
			{
				if (!reflexive && destination.containsPoint(srcPoints[sidx]))
					continue;

				for (int didx = 0; didx < dstCount; ++didx)
				{
					if (!reflexive && origin.containsPoint(dstPoints[didx]))
						continue;

					float dist = Utilities.Distance(
						srcPoints[sidx], dstPoints[didx]);

					if (dist < 2 * rop.GridSize)
						continue;

					// we prefer these to be on the same side
					if (sidx != didx) dist *= 3;

					if (dist < minDist)
					{
						minDist = dist;
						ptOrg = srcPoints[sidx];
						ptDest = dstPoints[didx];
					}
				}
			}
		}
示例#10
0
		internal void setOrgAndDest(Link orgLink, Link trgLink)
		{
			orgnLink = orgLink;
			destLink = trgLink;

			// place the end points of the arrow at their respective object edge
			points[0] = orgnLink.getInitialPt();
			points[points.Count-1] = destLink.getInitialPt();
			if (!orgnLink.objsIntersect(destLink))
			{
				points[0] = orgnLink.getIntersection(points[0], points[points.Count-1]);
				points[points.Count-1] = destLink.getIntersection(points[points.Count-1], points[0]);
			}

			points[0] = orgnLink.getAnchor(points[0], this, false, ref orgnAnchor);
			points[points.Count-1] = destLink.getAnchor(points[points.Count-1], this, true, ref destAnchor);

			// set reflexive arrow position & form
			reflexive = orgnLink.sameNode(destLink);
			if (reflexive)
			{
				setReflexive();
			}
			else
			{
				// compute the arrow points
				updatePoints(points[points.Count-1]);
				if (dynamic)
					updatePosFromOrgAndDest(true);
			}

			rectFromPoints();

			// relative position to nodes
			orgnLink.saveEndRelative();
			destLink.saveEndRelative();

			doRoute();
		}
示例#11
0
		private void routeGetEndPoints(ref PointF startPoint, ref PointF endPoint,
			ref int oNearest, ref int dNearest, Link orgnLink, Link destLink, bool nowCreating)
		{
			if (flowChart.RoutingOptions.Anchoring == Anchoring.Ignore)
			{
				float gridSize = flowChart.RoutingOptions.GridSize;

				// find the intersection of the nodes outlines with the four rays
				// that go outwards from the start/end points
				PointF[] opts = new PointF[4];
				PointF ptoCenter = startPoint;
				RectangleF or = orgnLink.getNodeRect(true);
				Utilities.getProjections(startPoint, or, opts);

				PointF[] dpts = new PointF[4];
				PointF ptdCenter = endPoint;
				RectangleF dr = destLink.getNodeRect(true);
				Utilities.getProjections(endPoint, dr, dpts);

				// get the intersection point nearest to the origin and destination centers.
		
				int oLen = opts.Length;
				if (flowChart.RoutingOptions.StartOrientation == Orientation.Horizontal)
				{
					oNearest = 2;
				}
				else if (flowChart.RoutingOptions.StartOrientation == Orientation.Vertical)
				{
					oLen = 2;
				}

				for (int i = oNearest + 1; i < oLen; i++)
				{
					if (Math.Abs(opts[i].X - ptoCenter.X) + Math.Abs(opts[i].Y - ptoCenter.Y) <
						Math.Abs(opts[oNearest].X - ptoCenter.X) + Math.Abs(opts[oNearest].Y - ptoCenter.Y))
						oNearest = i;
				}

				int dLen = dpts.Length;
				if (flowChart.RoutingOptions.EndOrientation == Orientation.Horizontal)
				{
					dNearest = 2;
				}
				else if (flowChart.RoutingOptions.EndOrientation == Orientation.Vertical)
				{
					dLen = 2;
				}

				for (int i = dNearest + 1; i < dLen; i++)
				{
					if (Math.Abs(dpts[i].X - ptdCenter.X) + Math.Abs(dpts[i].Y - ptdCenter.Y) <
						Math.Abs(dpts[dNearest].X - ptdCenter.X) + Math.Abs(dpts[dNearest].Y - ptdCenter.Y))
						dNearest = i;
				}

				startPoint = opts[oNearest];
				endPoint = dpts[dNearest];

				// Offset the starting and ending point a little bit
				float[,] pull = new float[4, 2] { { 0, -1 }, { 0, 1 }, { 1, 0 }, { -1, 0 } };
				startPoint.X += pull[oNearest, 0] * gridSize;
				startPoint.Y += pull[oNearest, 1] * gridSize;
				endPoint.X += pull[dNearest, 0] * gridSize;
				endPoint.Y += pull[dNearest, 1] * gridSize;
			}
			else
			{
				oNearest = -1;
				dNearest = -1;

				if (nowCreating ||
					flowChart.RoutingOptions.Anchoring == Anchoring.Reassign)
				{
					putEndPointsAtNodeBorders(true, orgnLink, destLink);
					startPoint = points[0];
					endPoint = points[points.Count - 1];
				}
			}
		}
示例#12
0
		internal void doRoute(bool force, Link orgnLink, Link destLink, bool nowCreating)
		{
			if (!force)
				if (!autoRoute) return;

			if (flowChart.DontRouteForAwhile)
				return;

			int i;

			float gridSize = flowChart.RoutingOptions.GridSize;

			PointF startPoint = points[0];
			PointF endPoint = points[points.Count - 1];

			// get a rectangle bounding both the origin and the destination
			RectangleF bounds = orgnLink.getNodeRect(true);
			bounds = Utilities.unionRects(bounds, destLink.getNodeRect(true));
			bounds = RectangleF.Union(bounds, Utilities.normalizeRect(
				RectangleF.FromLTRB(startPoint.X, startPoint.Y, endPoint.X, endPoint.Y)));
			if (bounds.Width < gridSize * 4)
				bounds.Inflate(gridSize * 4, 0);
			if (bounds.Height < gridSize * 4)
				bounds.Inflate(0, gridSize * 4);
			bounds.Inflate(bounds.Width, bounds.Height);

			int oNearest = 0, dNearest = 0;
			routeGetEndPoints(ref startPoint, ref endPoint,
				ref oNearest, ref dNearest, orgnLink, destLink, nowCreating);

			// Get the starting and ending square
			Point ptStart = new Point((int)((startPoint.X - bounds.X) / gridSize),
				(int)((startPoint.Y - bounds.Y) / gridSize));
			Point ptEnd = new Point((int)((endPoint.X - bounds.X) / gridSize),
				(int)((endPoint.Y - bounds.Y) / gridSize));
			if (ptStart.X == ptEnd.X && ptStart.Y == ptEnd.Y)
				return;

			// init the route grid
			int gridCols = (int)(bounds.Width / gridSize);
			int gridRows = (int)(bounds.Height / gridSize);

			RoutingGrid routingGrid = flowChart.RoutingGrid;
			routingGrid.allocate(gridCols, gridRows, bounds, this);
			byte[,] grid = routingGrid.getCostGrid();
			PathNode[,] gridClosed = routingGrid.getClosedGrid();
			PathNode[,] gridOpen = routingGrid.getOpenGrid();

			bool hurry = (gridCols * gridRows > 90000) &&
				flowChart.RoutingOptions.DontOptimizeLongRoutes;
			RouteHeuristics calcRouteHeuristics = hurry ?
				RoutingOptions.DistSquare : flowChart.RoutingOptions.RouteHeuristics;

			routeFixEndRegions(grid, ref ptStart, oNearest, ref ptEnd, dNearest, gridCols, gridRows);
			grid[ptStart.X, ptStart.Y] = 0;
			grid[ptEnd.X, ptEnd.Y] = 0;

			//---------- A* algorithm initialization -----------
			SortedList open = new SortedList();
			ArrayList closed = new ArrayList();
			Stack stack = new Stack();

			PathNode temp = new PathNode(ptStart.X, ptStart.Y);
			temp.G = 0;
			temp.H = calcRouteHeuristics(ptStart, ptEnd);
			temp.F = temp.G + temp.H;
			open.Add(temp, temp);
			gridOpen[temp.X, temp.Y] = temp;

			// setup A* cost function
			int adjcCost = flowChart.RoutingOptions.LengthCost;
			int turnCost = flowChart.RoutingOptions.TurnCost;

			PathNode best = null;
			bool found = false;
			int iterations = 0;
			for ( ; ; )
			{
				iterations++;

				// Get the best node from the open list
				if (open.Count == 0) break;
				PathNode pstmp = open.GetByIndex(0) as PathNode;

				open.RemoveAt(0);
				gridOpen[pstmp.X, pstmp.Y] = null;

				closed.Add(pstmp);
				gridClosed[pstmp.X, pstmp.Y] = pstmp;

				if ((best = pstmp) == null) break;

				// If best == destination -> path found
				if (best.X == ptEnd.X && best.Y == ptEnd.Y)
				{
					found = true;
					break;
				}

				// Generate best's successors
				int x = best.X;
				int y = best.Y;

				int[,] off = new int[4, 2] { { 1, 0 }, { 0, 1 }, { -1, 0 }, { 0, -1 } };
				for (i = 0; i < 4; i++)
				{
					byte localCost = grid[x + off[i, 0], y + off[i, 1]];
					if (localCost == 255)
						continue;

					int g = best.G + adjcCost + localCost;
					bool straight = best.Parent == null ||
						(best.Parent.Y == best.Y && off[i, 1] == 0) ||
						(best.Parent.X == best.X && off[i, 0] == 0);
					if (best.Parent == null && oNearest >= 0 && (
						oNearest < 2 && off[i, 1] == 0 || oNearest >= 2 && off[i, 1] == 1))
						straight = false;
					if (!straight) g += turnCost;

					PathNode check = null;

					// if the successor is an open node, add it to the path
					check = gridOpen[x + off[i, 0], y + off[i, 1]];
					if (check != null)
					{
						best.Children[best.ChildCount++] = check;

						// and update its cost if now it is reached via a better path
						if (g < check.G)
						{
							open.Remove(check);		// keep sorted
							check.Parent = best;
							check.G = g;
							check.F = g + check.H;
							open.Add(check, check);	// keep sorted
						}
					}
					else
					{
						// if the successor is a closed node, add it to the path
						check = gridClosed[x + off[i, 0], y + off[i, 1]];
						if (check != null)
						{
							best.Children[best.ChildCount++] = check;

							// and update its cost if now it is reached via a better path
							if (g < check.G)
							{
								check.Parent = best;
								check.G = g;
								check.F = g + check.H;

								// and update its child items
								int gg = check.G;
								int cc = check.ChildCount;
								PathNode kid = null;
								for (int j = 0; j < cc; j++)
								{
									kid = check.Children[j];

									int gi = adjcCost;
									straight = check.Parent == null ||
										(check.Parent.Y == check.Y && check.Y == kid.Y) ||
										(check.Parent.X == check.X && check.X == kid.X);
									if (!straight) gi += turnCost;

									if (g + gi < kid.G)
									{
										bool wasOpen = gridOpen[kid.X, kid.Y] != null;
										if (wasOpen) open.Remove(kid);	// keep sorted

										kid.G = g + gi;
										kid.F = kid.G + kid.H;
										kid.Parent = check;
										stack.Push(kid);

										if (wasOpen) open.Add(kid, kid);
									}
								}
								PathNode parent;
								while (stack.Count > 0)
								{
									parent = stack.Pop() as PathNode;
									cc = parent.ChildCount;
									for (int j = 0; j < cc; j++)
									{
										kid = parent.Children[j];

										int gi = adjcCost;
										straight = parent.Parent == null ||
											(parent.Parent.Y == parent.Y && parent.Y == kid.Y) ||
											(parent.Parent.X == parent.X && parent.X == kid.X);
										if (!straight) gi += turnCost;

										if (parent.G + gi < kid.G)
										{
											bool wasOpen = gridOpen[kid.X, kid.Y] != null;
											if (wasOpen) open.Remove(kid);	// keep sorted

											kid.G = parent.G + gi;
											kid.F = kid.G + kid.H;
											kid.Parent = parent;
											stack.Push(kid);

											if (wasOpen) open.Add(kid, kid);
										}
									}
								}
							}
						}
						else
						{
							// haven't considered this grid square by now
							// create and initialize a path node for it 
							Point current = new Point(x + off[i, 0], y + off[i, 1]);
							PathNode newNode = new PathNode(current.X, current.Y);
							newNode.Parent = best;
							newNode.G = g;
							newNode.H = calcRouteHeuristics(current, ptEnd);
							newNode.F = newNode.G + newNode.H;

							// add it to the list of open nodes to be evaluated later
							open.Add(newNode, newNode);
							gridOpen[newNode.X, newNode.Y] = newNode;

							// add to the path
							best.Children[best.ChildCount++] = newNode;
						}
					}
				}
			}

			if (found)
			{
				PtCollection current = new PtCollection(0);

				current.Add(new Point((int)((points[points.Count - 1].X - bounds.X) / gridSize),
					(int)((points[points.Count - 1].Y - bounds.Y) / gridSize)));
				while (best != null)
				{
					current.Add(new Point(best.X, best.Y));
					best = best.Parent;
				}
				current.Add(new Point((int)((points[0].X - bounds.X) / gridSize),
					(int)((points[0].Y - bounds.Y) / gridSize)));

				// Remove all unneeded points
				Point pt1, pt2, pt3;
				for (i = 1; i < current.Count - 1;)
				{
					pt1 = current[i - 1];
					pt2 = current[i];
					pt3 = current[i + 1];

					if (pt1.X == pt2.X && pt2.X == pt3.X)
						current.RemoveAt(i);
					else if(pt1.Y == pt2.Y && pt2.Y == pt3.Y)
						current.RemoveAt(i);
					else
						i++;
				}

				// Save the first and last points of the arrow
				PointF ptFirst = points[0];
				PointF ptLast = points[points.Count - 1];

				// no perp. arrows on a single line
				if (style == ArrowStyle.Cascading && current.Count == 2 &&
					ptFirst.X != ptLast.X && ptFirst.Y != ptLast.Y)
				{
					Point orgPt = current[0];
					Point trgPt = current[current.Count-1];
					if (orgPt.X == trgPt.X || orgPt.Y == trgPt.Y)
					{
						Point insPt = new Point(
							(orgPt.X + trgPt.X) / 2, (orgPt.Y + trgPt.Y) / 2);
						current.Insert(1, insPt);
						current.Insert(1, insPt);
					}
				}

				// Re-segment the arrow
				points = new PointCollection(current.Count);
				points[0] = ptFirst;
				points[points.Count - 1] = ptLast;

				// Assign the points from the path
				i = current.Count - 1;
				i--; // Skip the first point
				while (i > 0)
				{
					Point pt = current[i];
					PointF ptDoc = new PointF(0, 0);
					ptDoc.X = bounds.X + pt.X * gridSize + gridSize / 2;
					ptDoc.Y = bounds.Y + pt.Y * gridSize + gridSize / 2;

					if (i == 1)
					{
						// Align to the last point
						if (pt.Y == current[0].Y)
							ptDoc.Y = ptLast.Y;
						else
							ptDoc.X = ptLast.X;
					}
					if (i == current.Count - 2)
					{
						// Align to the first point
						if (pt.Y == current[current.Count - 1].Y)
							ptDoc.Y = ptFirst.Y;
						else
							ptDoc.X = ptFirst.X;

						if (style == ArrowStyle.Cascading)
							cascadeStartHorizontal = (ptDoc.X != ptFirst.X);
					}

					points[current.Count - i - 1] = ptDoc;
					i--;
				}

				PointF ptf, ptf1, ptf2, ptf3;

				// If the line is perpendicular make it at least 2 segments
				if(style == ArrowStyle.Cascading && points.Count == 2)
				{
					ptf1 = points[0];
					ptf2 = points[points.Count - 1];
					ptf = ptf1;
					if (cascadeStartHorizontal)
						ptf.X = ptf2.X;
					else
						ptf.Y = ptf2.Y;
					points.Insert(1, ptf);
				}

				// If the line is straight there might be more unneeded points
				if (style == ArrowStyle.Polyline)
				{
					i = 0;
					while(i < points.Count - 2)
					{
						ptf1 = points[i];
						ptf2 = points[i + 2];

						ChartObject obj = flowChart.objectIntersectedBy(ptf1, ptf2,
							orgnLink.getNode(), destLink.getNode());
						if(obj == null)
							points.RemoveAt(i + 1);
						else
							i++;
					}
				}

				// If the line is bezier, smooth it a bit
				if (style == ArrowStyle.Bezier)
				{
					PointCollection newPoints = new PointCollection(0);
					newPoints.Add(points[0]);
					i = 0;
					while(i < points.Count - 2)
					{
						ptf1 = points[i];
						ptf2 = points[i + 1];

						newPoints.Add(ptf2);
						newPoints.Add(ptf2);
						if(i != points.Count - 3)
						{
							ptf3 = points[i + 2];
							ptf = new PointF((ptf2.X + ptf3.X) / 2, (ptf2.Y + ptf3.Y) / 2);
							newPoints.Add(ptf);
						}
						else
						{
							newPoints.Add(points[i + 2]);
						}
						i += 1;
					}

					if (newPoints.Count == 1)
					{
						newPoints = new PointCollection(4);

						ptf1 = points[0];
						ptf2 = points[points.Count - 1];
						ptf = new PointF((ptf1.X + ptf2.X) / 2, (ptf1.Y + ptf2.Y) / 2);
						newPoints[0] = ptf1;
						newPoints[1] = ptf;
						newPoints[2] = ptf;
						newPoints[3] = ptf2;
					}

					points.Clear();
					points = newPoints;
				}

				// Update SegmentCount property value
				if (style == ArrowStyle.Bezier)
					segmentCount = (short)((points.Count - 1) / 3);
				else
					segmentCount = (short)(points.Count - 1);
			}
			else
			{
				// No path found -> reset the arrow, leaving as little points as possible
				int ptsToLeave = 2;
				if (style == ArrowStyle.Cascading)
					ptsToLeave = 4;
				else if (style == ArrowStyle.Bezier)
					ptsToLeave = 4;

				if (style == ArrowStyle.Cascading)
				{
					cascadeOrientation = Orientation.Auto;
					segmentCount = 3;
				}
				else
					segmentCount = 1;

				while (points.Count > ptsToLeave)
					points.RemoveAt(1);

				if (style == ArrowStyle.Cascading && points.Count == 3)
					segmentCount = 2;

				updatePoints(points[points.Count - 1]);
			}

			updateArrowHeads();

			if (subordinateGroup != null)
			{
				subordinateGroup.onSegmentsChanged();
				subordinateGroup.updateObjects(new InteractionState(this, -1, Action.Modify));
			}

			resetCrossings();
			updateText();

			flowChart.fireArrowRoutedEvent(this);
		}