/// <summary> /// /// </summary> /// <param name="arc"></param> /// <param name="dx"></param> /// <param name="dy"></param> /// <returns></returns> public static Rect2 GetArcBounds(XArc arc, double dx, double dy) { double x1 = arc.Point1.X + dx; double y1 = arc.Point1.Y + dy; double x2 = arc.Point2.X + dx; double y2 = arc.Point2.Y + dy; double x0 = (x1 + x2) / 2.0; double y0 = (y1 + y2) / 2.0; double r = Math.Sqrt((x1 - x0) * (x1 - x0) + (y1 - y0) * (y1 - y0)); double x = x0 - r; double y = y0 - r; double width = 2.0 * r; double height = 2.0 * r; return new Rect2(x, y, width, height); }
/// <summary> /// /// </summary> /// <param name="x"></param> /// <param name="y"></param> public override void LeftDown(double x, double y) { double sx = _editor.Project.Options.SnapToGrid ? Editor.Snap(x, _editor.Project.Options.SnapX) : x; double sy = _editor.Project.Options.SnapToGrid ? Editor.Snap(y, _editor.Project.Options.SnapY) : y; switch (_currentState) { case State.None: { _connectedP3 = false; _connectedP4 = false; _shape = XArc.Create( sx, sy, _editor.Project.CurrentStyleLibrary.CurrentStyle, _editor.Project.Options.PointShape, _editor.Project.Options.DefaultIsStroked, _editor.Project.Options.DefaultIsFilled); if (_editor.Project.Options.TryToConnect) { TryToConnectPoint1(_shape, sx, sy); } _editor.Project.CurrentContainer.WorkingLayer.Invalidate(); ToStateOne(); Move(_shape); _editor.Project.CurrentContainer.HelperLayer.Invalidate(); _currentState = State.One; _editor.CancelAvailable = true; } break; case State.One: { if (_shape != null) { _shape.Point2.X = sx; _shape.Point2.Y = sy; _shape.Point3.X = sx; _shape.Point3.Y = sy; if (_editor.Project.Options.TryToConnect) { TryToConnectPoint2(_shape, sx, sy); } _editor.Project.CurrentContainer.WorkingLayer.Invalidate(); ToStateTwo(); Move(_shape); _editor.Project.CurrentContainer.HelperLayer.Invalidate(); _currentState = State.Two; } } break; case State.Two: { if (_shape != null) { _shape.Point3.X = sx; _shape.Point3.Y = sy; _shape.Point4.X = sx; _shape.Point4.Y = sy; if (_editor.Project.Options.TryToConnect) { _connectedP3 = TryToConnectPoint3(_shape, sx, sy); } _editor.Project.CurrentContainer.WorkingLayer.Shapes = _editor.Project.CurrentContainer.WorkingLayer.Shapes.Add(_shape); _editor.Project.CurrentContainer.WorkingLayer.Invalidate(); ToStateThree(); Move(_shape); _editor.Project.CurrentContainer.HelperLayer.Invalidate(); _currentState = State.Three; } } break; case State.Three: { if (_shape != null) { _shape.Point4.X = sx; _shape.Point4.Y = sy; if (_editor.Project.Options.TryToConnect) { _connectedP4 = TryToConnectPoint4(_shape, sx, sy); } _editor.Project.CurrentContainer.WorkingLayer.Shapes = _editor.Project.CurrentContainer.WorkingLayer.Shapes.Remove(_shape); Remove(); Finalize(_shape); _editor.AddWithHistory(_shape); _currentState = State.None; _editor.CancelAvailable = false; } } break; } }
/// <summary> /// /// </summary> /// <param name="arc"></param> /// <param name="x"></param> /// <param name="y"></param> /// <returns></returns> public bool TryToConnectPoint4(XArc arc, double x, double y) { var result = ShapeBounds.HitTest(_editor.Project.CurrentContainer, new Vector2(x, y), _editor.Project.Options.HitTreshold); if (result != null && result is XPoint) { arc.Point4 = result as XPoint; return true; } return false; }
/// <summary> /// /// </summary> /// <param name="dc"></param> /// <param name="arc"></param> /// <param name="dx"></param> /// <param name="dy"></param> /// <param name="db"></param> /// <param name="r"></param> public void Draw(object dc, XArc arc, double dx, double dy, ImmutableArray<ShapeProperty> db, Record r) { var _dc = dc as DrawingContext; var style = arc.Style; if (style == null) return; double thickness = style.Thickness / _state.Zoom; double half = thickness / 2.0; Tuple<Brush, Pen> cache = null; Brush fill; Pen stroke; if (_enableStyleCache && _styleCache.TryGetValue(style, out cache)) { fill = cache.Item1; stroke = cache.Item2; } else { fill = CreateBrush(style.Fill); stroke = CreatePen(style, thickness); if (_enableStyleCache) _styleCache.Add(style, Tuple.Create(fill, stroke)); } var a = WpfArc.FromXArc(arc, dx, dy); PathGeometry pg = null; if (_enableArcCache && _arcCache.TryGetValue(arc, out pg)) { var pf = pg.Figures[0]; pf.StartPoint = new Point(a.Start.X, a.Start.Y); pf.IsFilled = arc.IsFilled; var segment = pf.Segments[0] as ArcSegment; segment.Point = new Point(a.End.X, a.End.Y); segment.Size = new Size(a.Radius.Width, a.Radius.Height); segment.IsLargeArc = a.IsLargeArc; segment.IsStroked = arc.IsStroked; } else { var pf = new PathFigure() { StartPoint = new Point(a.Start.X, a.Start.Y), IsFilled = arc.IsFilled }; var segment = new ArcSegment( new Point(a.End.X, a.End.Y), new Size(a.Radius.Width, a.Radius.Height), 0.0, a.IsLargeArc, SweepDirection.Clockwise, arc.IsStroked); //segment.Freeze(); pf.Segments.Add(segment); //pf.Freeze(); pg = new PathGeometry(); pg.Figures.Add(pf); //pg.Freeze(); if (_enableArcCache) _arcCache.Add(arc, pg); } DrawPathGeometryInternal(_dc, half, fill, stroke, arc.IsStroked, arc.IsFilled, pg); }
/// <summary> /// /// </summary> /// <param name="arc"></param> /// <param name="dx"></param> /// <param name="dy"></param> /// <returns></returns> public static GdiArc FromXArc(XArc arc, double dx, double dy) { return FromXArc(arc.Point1, arc.Point2, arc.Point3, arc.Point4, dx, dy); }
/// <summary> /// /// </summary> /// <param name="arc"></param> /// <param name="dx"></param> /// <param name="dy"></param> /// <returns></returns> public static WpfArc FromXArc(XArc arc, double dx, double dy) { var p1 = Point2.Create(arc.Point1.X + dx, arc.Point1.Y + dy); var p2 = Point2.Create(arc.Point2.X + dx, arc.Point2.Y + dy); var p3 = Point2.Create(arc.Point3.X + dx, arc.Point3.Y + dy); var p4 = Point2.Create(arc.Point4.X + dx, arc.Point4.Y + dy); var rect = Rect2.Create(p1, p2); var center = Point2.Create(rect.X + rect.Width / 2.0, rect.Y + rect.Height / 2.0); double offsetX = center.X - rect.X; double offsetY = center.Y - rect.Y; double minLenght = Math.Max(offsetX, offsetY); double length1 = center.Distance(p3); double p3x = p3.X + (p3.X - center.X) / length1 * minLenght; double p3y = p3.Y + (p3.Y - center.Y) / length1 * minLenght; double length2 = center.Distance(p4); double p4x = p4.X + (p4.X - center.X) / length2 * minLenght; double p4y = p4.Y + (p4.Y - center.Y) / length2 * minLenght; p3.X = p3x; p3.Y = p3y; p4.X = p4x; p4.Y = p4y; var p3i = MathHelpers.FindEllipseSegmentIntersections(rect, center, p3, true); var p4i = MathHelpers.FindEllipseSegmentIntersections(rect, center, p4, true); Point2 start; Point2 end; if (p3i.Count == 1) start = p3i.FirstOrDefault(); else start = Point2.Create(p3.X, p3.Y); if (p4i.Count == 1) end = p4i.FirstOrDefault(); else end = Point2.Create(p4.X, p4.Y); double angle = MathHelpers.AngleLineSegments(center, start, center, end); bool isLargeArc = angle > 180.0; double helperLenght = 60.0; double lengthStart = center.Distance(start); double p3hx = start.X + (start.X - center.X) / lengthStart * helperLenght; double p3hy = start.Y + (start.Y - center.Y) / lengthStart * helperLenght; double lengthEnd = center.Distance(end); double p4hx = end.X + (end.X - center.X) / lengthEnd * helperLenght; double p4hy = end.Y + (end.Y - center.Y) / lengthEnd * helperLenght; p3.X = p3hx; p3.Y = p3hy; p4.X = p4hx; p4.Y = p4hy; return new WpfArc() { P1 = p1, P2 = p2, P3 = p3, P4 = p4, Rect = rect, Center = center, Start = start, End = end, Radius = Size2.Create(offsetX, offsetY), IsLargeArc = isLargeArc, Angle = angle }; }
/// <summary> /// /// </summary> /// <param name="gfx"></param> /// <param name="arc"></param> /// <param name="dx"></param> /// <param name="dy"></param> /// <param name="db"></param> /// <param name="r"></param> public void Draw(object gfx, XArc arc, double dx, double dy, ImmutableArray<ShapeProperty> db, Record r) { var a = GdiArc.FromXArc(arc, dx, dy); if (a.Width <= 0.0 || a.Height <= 0.0) return; var _gfx = gfx as Graphics; Brush brush = ToSolidBrush(arc.Style.Fill); Pen pen = ToPen(arc.Style, _scaleToPage); if (arc.IsFilled) { var path = new GraphicsPath(); path.AddArc( _scaleToPage(a.X), _scaleToPage(a.Y), _scaleToPage(a.Width), _scaleToPage(a.Height), (float)a.StartAngle, (float)a.SweepAngle); _gfx.FillPath(brush, path); } if (arc.IsStroked) { _gfx.DrawArc( pen, _scaleToPage(a.X), _scaleToPage(a.Y), _scaleToPage(a.Width), _scaleToPage(a.Height), (float)a.StartAngle, (float)a.SweepAngle); } brush.Dispose(); pen.Dispose(); }