protected override RectangleF CalculateBounds() { if (!m_BaseLineFixed) { RectangleF total = new RectangleF(Vertices[0], SizeF.Empty); Geometry.Extend(ref total, Vertices[1]); return(total); } else { // base would use text - but we need to include the corners for the highlighter EnsureTextFormatted(); float height = 0; if (m_Fragments != null && m_Fragments.Count > 0) { height = m_Fragments[m_Fragments.Count - 1].Bounds.Bottom - m_Fragments[0].Bounds.Top; } RectangleF rct = new RectangleF(); Geometry.Extend(ref rct, Vertices[0]); Geometry.Extend(ref rct, Vertices[1]); if (height > 0) { SizeF sz = Vertices[0].VectorTo(Vertices[1]).Perpendicular(1); // down vector sz = sz.ChangeLength(height); Geometry.Extend(ref rct, Vertices[0] + sz); Geometry.Extend(ref rct, Vertices[1] + sz); } return(rct); } }
public override VerbResult OtherVerb(EditableView.ClickPosition position, SAW.Functions.Codes code) { switch (code) { case SAW.Functions.Codes.Increment: case SAW.Functions.Codes.Decrement: int delta = code == SAW.Functions.Codes.Increment ? 1 : -1; float step = position.ScalarSnapStep(0); if (step <= 0) { step = delta * Globals.Root.CurrentConfig.ReadSingle(Config.Radius_Step, 1); } else { step *= delta; } SizeF vector = Vertices[0].VectorTo(Vertices[1]); float length = vector.Length(); if (length + step < 5 || length < Geometry.NEGLIGIBLESMALL) { return(VerbResult.Rejected); } Vertices[1] = Vertices[0] + vector.ChangeLength(length + step); m_Bounds = RectangleF.Empty; return(VerbResult.Continuing); default: return(VerbResult.Rejected); } }
protected internal override void DoGrabMove(GrabMovement move) { switch (move.GrabType) { case GrabTypes.SingleVertex: if (move.ShapeIndex != 1) { Debug.Fail("Isosceles.DoGrabMove(SingleVertex): index must be 1"); return; } if (move.Current.Snapped.ApproxEqual(Vertices[0])) { return; } int direction = base.TurnDirection(); // maintain the same winding direction, and transverse length (i.e. from baseline to third point) float transverseSize = Geometry.DistancePointToLine(Vertices[0], Vertices[1], Vertices[2]); Vertices[1] = move.Current.Snapped; SizeF transverseVector = BaseVector().Perpendicular(direction); transverseVector = transverseVector.ChangeLength(transverseSize); // the correct, new vector from the midpoint of the baseline Vertices[2] = PointF.Add(Geometry.MidPoint(Vertices[0], Vertices[1]), transverseVector); m_Bounds = CalculateBounds(); break; case GrabTypes.Radius: // this moves the last point if (move.ShapeIndex != 2) { Debug.Fail("Isosceles.DoGrabMove(Radius): index must be 1"); return; } PointF original = Vertices[2]; SizeF baseVector = BaseVector().MultiplyBy(0.5f); // actually half the base vector Vertices[2] = Geometry.PerpendicularPoint(Vertices[0], Vertices[0] + baseVector, move.Current.Exact); if (VerticesFormLine(0)) { Vertices[2] = original; // cannot store this } m_Bounds = CalculateBounds(); break; default: base.DoGrabMove(move); break; } DiscardPath(); }
public override bool Tidy(SnapModes mode, Page page) { int direction = base.TurnDirection(); bool changed = base.TidyVertices(mode, page, 2); if (changed) { // just need to check that the vertices do not form a single line if (Geometry.PointApproxOnLine(Vertices[0], Vertices[1], Vertices[2])) { // move the point again to get it off the line if (direction == 0) { direction = 1; // just in case it was already a single line } SizeF vector = Vertices[0].VectorTo(Vertices[1]).Perpendicular(direction); Vertices[2] = Vertices[2] + vector.ChangeLength(page.Paper.UnitStep); // UnitStep always returns a valid value } } return(changed); }
private void ProcessExitVector(List <PointF> points, int index, float primaryAngle) { // index is 0 or 1; specifying which end we are looking at Shape shape = m_Links[index].Shape; // the shape that this end is connected to if (shape == null) { return; // just stops at this point, no processing needed if not attached to a shape } SizeF exitVector = shape.SocketExitVector(ResolveIndefiniteSocket(index)); float exitAngle = Geometry.NormaliseAngle(exitVector.VectorAngle()); float difference = Math.Abs(Geometry.AngleBetween(exitAngle, Geometry.NormaliseAngle(primaryAngle))); if (difference < EXITANGLETOLERANCE || difference > Geometry.ANGLE360 - EXITANGLETOLERANCE) { // the line exits in roughly the right direction, we don't need to add an exit stage } else { exitVector = exitVector.ChangeLength(EXITSTAGELENGTH); PointF exitPoint = points[0] + exitVector; // need to see if this has cleared the shape boundary RectangleF bounds = shape.Bounds; if (bounds.Contains(exitPoint)) { // find where the exit vector crosses the boundary //initially set the exit point a long distance away to test for the intersections. I think we need to test each of the four edges of the bounding rectangle separately exitPoint = points[0] + exitVector.ChangeLength(1000); // top: PointF intersection = Intersection.Line_LineIntersection(points[0], exitPoint, new PointF(bounds.Left, bounds.Top), new PointF(bounds.Right, bounds.Top)); // right: if (intersection.IsEmpty) { intersection = Intersection.Line_LineIntersection(points[0], exitPoint, new PointF(bounds.Right, bounds.Top), new PointF(bounds.Right, bounds.Bottom)); } // bottom: if (intersection.IsEmpty) { intersection = Intersection.Line_LineIntersection(points[0], exitPoint, new PointF(bounds.Left, bounds.Bottom), new PointF(bounds.Right, bounds.Bottom)); } // left: if (intersection.IsEmpty) { intersection = Intersection.Line_LineIntersection(points[0], exitPoint, new PointF(bounds.Left, bounds.Top), new PointF(bounds.Left, bounds.Bottom)); } if (intersection.IsEmpty) { // huh Debug.Fail("Failed to find where exit vector leaves the bounding rectangle"); // leave szExit with the default length } else { float length = Geometry.DistanceBetween(intersection, points[0]); exitVector = exitVector.ChangeLength(length + EXITSTAGELENGTH / 2); // second term gets us a bit outside the rectangle } exitPoint = points[0] + exitVector; } points.Add(exitPoint); } }