/// <summary> /// /// </summary> /// <param name="gfx"></param> /// <param name="container"></param> private void DrawBackgroundInternal(Graphics gfx, Container container) { Brush brush = ToSolidBrush(container.Background); var rect = Rect2.Create(0, 0, container.Width, container.Height); gfx.FillRectangle( brush, _scaleToPage(rect.X), _scaleToPage(rect.Y), _scaleToPage(rect.Width), _scaleToPage(rect.Height)); brush.Dispose(); }
/// <summary> /// /// </summary> /// <param name="container"></param> /// <param name="rect"></param> /// <param name="treshold"></param> /// <returns></returns> public static ImmutableHashSet <BaseShape> HitTest(Container container, Rect2 rect, double treshold) { var builder = ImmutableHashSet.CreateBuilder <BaseShape>(); var selection = new Vector2[] { new Vector2(rect.X, rect.Y), new Vector2(rect.X + rect.Width, rect.Y), new Vector2(rect.X + rect.Width, rect.Y + rect.Height), new Vector2(rect.X, rect.Y + rect.Height) }; HitTest(container.CurrentLayer.Shapes.Reverse(), rect, selection, builder, treshold, 0, 0); return(builder.ToImmutableHashSet()); }
/// <summary> /// /// </summary> /// <param name="shapes"></param> /// <param name="rect"></param> /// <param name="selection"></param> /// <param name="builder"></param> /// <param name="treshold"></param> /// <param name="dx"></param> /// <param name="dy"></param> /// <returns></returns> private static bool HitTest( IEnumerable <BaseShape> shapes, Rect2 rect, Vector2[] selection, ImmutableHashSet <BaseShape> .Builder builder, double treshold, double dx, double dy) { foreach (var shape in shapes) { var result = HitTest(shape, rect, selection, builder, treshold, dx, dy); if (result == true) { return(true); } } return(false); }
/// <summary> /// /// </summary> /// <param name="p1"></param> /// <param name="p2"></param> /// <param name="p3"></param> /// <param name="p4"></param> /// <param name="dx"></param> /// <param name="dy"></param> /// <returns></returns> public static GdiArc FromXArc(XPoint p1, XPoint p2, XPoint p3, XPoint p4, double dx, double dy) { double x1 = p1.X + dx; double y1 = p1.Y + dy; double x2 = p2.X + dx; double y2 = p2.Y + dy; double x3 = p3.X + dx; double y3 = p3.Y + dy; double x4 = p4.X + dx; double y4 = p4.Y + dy; var rect = Rect2.Create(x1, y1, x2, y2, dx, dy); double cx = rect.X + rect.Width / 2.0; double cy = rect.Y + rect.Height / 2.0; double radiusX = cx - rect.X; double radiusY = cy - rect.Y; double startAngle = Math.Atan2(y3 - cy, x3 - cx); double endAngle = Math.Atan2(y4 - cy, x4 - cx); double sweepAngle = (endAngle - startAngle) * 180.0 / Math.PI; if (sweepAngle < 0) { sweepAngle += 360; } startAngle *= 180.0 / Math.PI; endAngle *= 180.0 / Math.PI; return(new GdiArc { X = rect.X, Y = rect.Y, Width = rect.Width, Height = rect.Height, RadiusX = radiusX, RadiusY = radiusY, StartAngle = startAngle, EndAngle = endAngle, SweepAngle = sweepAngle }); }
/// <summary> /// /// </summary> /// <param name="gfx"></param> /// <param name="stroke"></param> /// <param name="rect"></param> /// <param name="offsetX"></param> /// <param name="offsetY"></param> /// <param name="cellWidth"></param> /// <param name="cellHeight"></param> /// <param name="isStroked"></param> private void DrawGridInternal( Graphics gfx, Pen stroke, ref Rect2 rect, double offsetX, double offsetY, double cellWidth, double cellHeight, bool isStroked) { double ox = rect.X; double oy = rect.Y; double sx = ox + offsetX; double sy = oy + offsetY; double ex = ox + rect.Width; double ey = oy + rect.Height; for (double x = sx; x < ex; x += cellWidth) { var p0 = new PointF( _scaleToPage(x), _scaleToPage(oy)); var p1 = new PointF( _scaleToPage(x), _scaleToPage(ey)); DrawLineInternal(gfx, stroke, isStroked, ref p0, ref p1); } for (double y = sy; y < ey; y += cellHeight) { var p0 = new PointF( _scaleToPage(ox), _scaleToPage(y)); var p1 = new PointF( _scaleToPage(ex), _scaleToPage(y)); DrawLineInternal(gfx, stroke, isStroked, ref p0, ref p1); } }
/// <summary> /// /// </summary> /// <param name="rectangle"></param> /// <param name="dx"></param> /// <param name="dy"></param> /// <returns></returns> public static Rect2 GetRectangleBounds(XRectangle rectangle, double dx, double dy) { return(Rect2.Create(rectangle.TopLeft, rectangle.BottomRight, dx, dy)); }
/// <summary> /// /// </summary> /// <param name="rect"></param> /// <param name="p1"></param> /// <param name="p2"></param> /// <param name="onlySegment"></param> /// <returns></returns> public static IList <Point2> FindEllipseSegmentIntersections( Rect2 rect, Point2 p1, Point2 p2, bool onlySegment) { if ((rect.Width == 0) || (rect.Height == 0) || ((p1.X == p2.X) && (p1.Y == p2.Y))) { return new Point2[] { } } ; if (rect.Width < 0) { rect.X = rect.Right; rect.Width = -rect.Width; } if (rect.Height < 0) { rect.Y = rect.Bottom; rect.Height = -rect.Height; } double cx = rect.Left + rect.Width / 2.0; double cy = rect.Top + rect.Height / 2.0; rect.X -= cx; rect.Y -= cy; p1.X -= cx; p1.Y -= cy; p2.X -= cx; p2.Y -= cy; double a = rect.Width / 2.0; double b = rect.Height / 2.0; double A = (p2.X - p1.X) * (p2.X - p1.X) / a / a + (p2.Y - p1.Y) * (p2.Y - p1.Y) / b / b; double B = 2 * p1.X * (p2.X - p1.X) / a / a + 2 * p1.Y * (p2.Y - p1.Y) / b / b; double C = p1.X * p1.X / a / a + p1.Y * p1.Y / b / b - 1; var solutions = new List <double>(); double discriminant = B * B - 4 * A * C; if (discriminant == 0) { solutions.Add(-B / 2 / A); } else if (discriminant > 0) { solutions.Add((-B + Math.Sqrt(discriminant)) / 2 / A); solutions.Add((-B - Math.Sqrt(discriminant)) / 2 / A); } var points = new List <Point2>(); foreach (var t in solutions) { if (!onlySegment || ((t >= 0f) && (t <= 1f))) { double x = p1.X + (p2.X - p1.X) * t + cx; double y = p1.Y + (p2.Y - p1.Y) * t + cy; points.Add(Point2.Create(x, y)); } } return(points); }
/// <summary> /// /// </summary> /// <param name="gfx"></param> /// <param name="brush"></param> /// <param name="pen"></param> /// <param name="isStroked"></param> /// <param name="isFilled"></param> /// <param name="rect"></param> private static void DrawRectangleInternal( Graphics gfx, Brush brush, Pen pen, bool isStroked, bool isFilled, ref Rect2 rect) { if (isFilled) { gfx.FillRectangle( brush, (float)rect.X, (float)rect.Y, (float)rect.Width, (float)rect.Height); } if (isStroked) { gfx.DrawRectangle( pen, (float)rect.X, (float)rect.Y, (float)rect.Width, (float)rect.Height); } }
private static void DrawEllipseInternal( CanvasDrawingSession ds, Color brush, Color pen, CanvasStrokeStyle ss, bool isStroked, bool isFilled, ref Rect2 rect, double strokeWidth) { double radiusX = rect.Width / 2.0; double radiusY = rect.Height / 2.0; double x = rect.X + radiusX; double y = rect.Y + radiusY; if (isFilled) { ds.FillEllipse( (float)x, (float)y, (float)radiusX, (float)radiusY, brush); } if (isStroked) { ds.DrawEllipse( (float)x, (float)y, (float)radiusX, (float)radiusY, pen, (float)strokeWidth, ss); } }
private void DrawGridInternal( CanvasDrawingSession ds, Color stroke, CanvasStrokeStyle ss, ref Rect2 rect, double offsetX, double offsetY, double cellWidth, double cellHeight, bool isStroked, double strokeWidth) { double ox = rect.X; double oy = rect.Y; double sx = ox + offsetX; double sy = oy + offsetY; double ex = ox + rect.Width; double ey = oy + rect.Height; for (double x = sx; x < ex; x += cellWidth) { var p0 = new N.Vector2((float)x, (float)oy); var p1 = new N.Vector2((float)x, (float)ey); DrawLineInternal(ds, stroke, ss, isStroked, ref p0, ref p1, strokeWidth); } for (double y = sy; y < ey; y += cellHeight) { var p0 = new N.Vector2((float)ox, (float)y); var p1 = new N.Vector2((float)ex, (float)y); DrawLineInternal(ds, stroke, ss, isStroked, ref p0, ref p1, strokeWidth); } }
/// <summary> /// Check if line intersects with rectangle using Liang-Barsky line clipping algorithm. /// </summary> /// <param name="rect"></param> /// <param name="p0"></param> /// <param name="p1"></param> /// <returns>True if line intersects with rectangle.</returns> public static bool LineIntersectsWithRect(Rect2 rect, Point2 p0, Point2 p1) { double left = rect.Left; double right = rect.Right; double bottom = rect.Bottom; double top = rect.Top; double x0 = p0.X; double y0 = p0.Y; double x1 = p1.X; double y1 = p1.Y; double t0 = 0.0; double t1 = 1.0; double dx = x1 - x0; double dy = y1 - y0; double p = 0.0, q = 0.0, r; for (int edge = 0; edge < 4; edge++) { if (edge == 0) { p = -dx; q = -(left - x0); } if (edge == 1) { p = dx; q = (right - x0); } if (edge == 2) { p = dy; q = (bottom - y0); } if (edge == 3) { p = -dy; q = -(top - y0); } r = q / p; if (p == 0.0 && q < 0.0) { return false; } if (p < 0.0) { if (r > t1) { return false; } else if (r > t0) { t0 = r; } } else if (p > 0.0) { if (r < t0) { return false; } else if (r < t1) { t1 = r; } } } // to calulate clipped line position // x0clip = x0 + t0 * dx; // y0clip = y0 + t0 * dy; // x1clip = x0 + t1 * dx; // y1clip = y0 + t1 * dy; return true; }
/// <summary> /// /// </summary> /// <param name="shape"></param> /// <param name="rect"></param> /// <param name="selection"></param> /// <param name="builder"></param> /// <param name="treshold"></param> /// <param name="dx"></param> /// <param name="dy"></param> /// <returns></returns> private static bool HitTest( BaseShape shape, Rect2 rect, Vector2[] selection, ImmutableHashSet <BaseShape> .Builder builder, double treshold, double dx, double dy) { if (shape is XPoint) { if (GetPointBounds(shape as XPoint, treshold, dx, dy).IntersectsWith(rect)) { if (builder != null) { builder.Add(shape); } else { return(true); } } return(false); } else if (shape is XLine) { var line = shape as XLine; if (GetPointBounds(line.Start, treshold, dx, dy).IntersectsWith(rect) || GetPointBounds(line.End, treshold, dx, dy).IntersectsWith(rect) || MathHelpers.LineIntersectsWithRect(rect, new Point2(line.Start.X, line.Start.Y), new Point2(line.End.X, line.End.Y))) { if (builder != null) { builder.Add(line); return(false); } else { return(true); } } return(false); } else if (shape is XEllipse) { if (GetEllipseBounds(shape as XEllipse, dx, dy).IntersectsWith(rect)) { if (builder != null) { builder.Add(shape); return(false); } else { return(true); } } return(false); } else if (shape is XRectangle) { if (GetRectangleBounds(shape as XRectangle, dx, dy).IntersectsWith(rect)) { if (builder != null) { builder.Add(shape); return(false); } else { return(true); } } return(false); } else if (shape is XArc) { if (GetArcBounds(shape as XArc, dx, dy).IntersectsWith(rect)) { if (builder != null) { builder.Add(shape); return(false); } else { return(true); } } return(false); } else if (shape is XBezier) { if (ConvexHullBounds.Overlap(selection, ConvexHullBounds.GetVertices(shape as XBezier, dx, dy))) { if (builder != null) { builder.Add(shape); return(false); } else { return(true); } } return(false); } else if (shape is XQBezier) { if (ConvexHullBounds.Overlap(selection, ConvexHullBounds.GetVertices(shape as XQBezier, dx, dy))) { if (builder != null) { builder.Add(shape); return(false); } else { return(true); } } return(false); } else if (shape is XText) { if (GetTextBounds(shape as XText, dx, dy).IntersectsWith(rect)) { if (builder != null) { builder.Add(shape); return(false); } else { return(true); } } return(false); } else if (shape is XImage) { if (GetImageBounds(shape as XImage, dx, dy).IntersectsWith(rect)) { if (builder != null) { builder.Add(shape); return(false); } else { return(true); } } return(false); } else if (shape is XPath) { if ((shape as XPath).Geometry != null) { var points = (shape as XPath).GetAllPoints(); if (ConvexHullBounds.Overlap(selection, ConvexHullBounds.GetVertices(points, dx, dy))) { if (builder != null) { builder.Add(shape); return(false); } else { return(true); } } } return(false); } else if (shape is XGroup) { if (HitTest((shape as XGroup).Shapes.Reverse(), rect, selection, null, treshold, dx, dy) == true) { if (builder != null) { builder.Add(shape); return(false); } else { return(true); } } return(false); } return(false); }
/// <summary> /// /// </summary> /// <param name="dc"></param> /// <param name="brush"></param> /// <param name="pen"></param> /// <param name="isStroked"></param> /// <param name="isFilled"></param> /// <param name="rect"></param> private static void DrawRectangleInternal( IDrawingContext dc, Brush brush, Pen pen, bool isStroked, bool isFilled, ref Rect2 rect) { if (!isStroked && !isFilled) return; var r = new Rect(rect.X, rect.Y, rect.Width, rect.Height); if (isFilled) { dc.FillRectangle(brush, r); } if (isStroked) { dc.DrawRectangle(pen, r); } }
/// <summary> /// /// </summary> /// <param name="dc"></param> /// <param name="line"></param> /// <param name="dx"></param> /// <param name="dy"></param> /// <param name="db"></param> /// <param name="r"></param> public void Draw(object dc, XLine line, double dx, double dy, ImmutableArray<ShapeProperty> db, Record r) { var _dc = dc as IDrawingContext; Brush fillLine = ToSolidBrush(line.Style.Fill); Pen strokeLine = ToPen(line.Style, _scaleToPage); Brush fillStartArrow = ToSolidBrush(line.Style.StartArrowStyle.Fill); Pen strokeStartArrow = ToPen(line.Style.StartArrowStyle, _scaleToPage); Brush fillEndArrow = ToSolidBrush(line.Style.EndArrowStyle.Fill); Pen strokeEndArrow = ToPen(line.Style.EndArrowStyle, _scaleToPage); double _x1 = line.Start.X + dx; double _y1 = line.Start.Y + dy; double _x2 = line.End.X + dx; double _y2 = line.End.Y + dy; XLine.SetMaxLength(line, ref _x1, ref _y1, ref _x2, ref _y2); float x1 = _scaleToPage(_x1); float y1 = _scaleToPage(_y1); float x2 = _scaleToPage(_x2); float y2 = _scaleToPage(_y2); var sas = line.Style.StartArrowStyle; var eas = line.Style.EndArrowStyle; double a1 = Math.Atan2(y1 - y2, x1 - x2); double a2 = Math.Atan2(y2 - y1, x2 - x1); var t1 = MatrixHelper.Rotation(a1, new Vector(x1, y1)); var t2 = MatrixHelper.Rotation(a2, new Vector(x2, y2)); Point pt1 = default(Point); Point pt2 = default(Point); double radiusX1 = sas.RadiusX; double radiusY1 = sas.RadiusY; double sizeX1 = 2.0 * radiusX1; double sizeY1 = 2.0 * radiusY1; switch (sas.ArrowType) { default: case ArrowType.None: { pt1 = new Point(x1, y1); } break; case ArrowType.Rectangle: { pt1 = MatrixHelper.TransformPoint(t1, new Point(x1 - (float)sizeX1, y1)); var rect = new Rect2(x1 - sizeX1, y1 - radiusY1, sizeX1, sizeY1); var d = _dc.PushTransform(t1); DrawRectangleInternal(_dc, fillStartArrow, strokeStartArrow, sas.IsStroked, sas.IsFilled, ref rect); d.Dispose(); } break; case ArrowType.Ellipse: { pt1 = MatrixHelper.TransformPoint(t1, new Point(x1 - (float)sizeX1, y1)); var d = _dc.PushTransform(t1); var rect = new Rect2(x1 - sizeX1, y1 - radiusY1, sizeX1, sizeY1); DrawEllipseInternal(_dc, fillStartArrow, strokeStartArrow, sas.IsStroked, sas.IsFilled, ref rect); d.Dispose(); } break; case ArrowType.Arrow: { var pts = new Point[] { new Point(x1, y1), new Point(x1 - (float)sizeX1, y1 + (float)sizeY1), new Point(x1, y1), new Point(x1 - (float)sizeX1, y1 - (float)sizeY1), new Point(x1, y1) }; pt1 = MatrixHelper.TransformPoint(t1, pts[0]); var p11 = MatrixHelper.TransformPoint(t1, pts[1]); var p21 = MatrixHelper.TransformPoint(t1, pts[2]); var p12 = MatrixHelper.TransformPoint(t1, pts[3]); var p22 = MatrixHelper.TransformPoint(t1, pts[4]); DrawLineInternal(_dc, strokeStartArrow, sas.IsStroked, ref p11, ref p21); DrawLineInternal(_dc, strokeStartArrow, sas.IsStroked, ref p12, ref p22); } break; } double radiusX2 = eas.RadiusX; double radiusY2 = eas.RadiusY; double sizeX2 = 2.0 * radiusX2; double sizeY2 = 2.0 * radiusY2; switch (eas.ArrowType) { default: case ArrowType.None: { pt2 = new Point(x2, y2); } break; case ArrowType.Rectangle: { pt2 = MatrixHelper.TransformPoint(t2, new Point(x2 - (float)sizeX2, y2)); var rect = new Rect2(x2 - sizeX2, y2 - radiusY2, sizeX2, sizeY2); var d = _dc.PushTransform(t2); DrawRectangleInternal(_dc, fillEndArrow, strokeEndArrow, eas.IsStroked, eas.IsFilled, ref rect); d.Dispose(); } break; case ArrowType.Ellipse: { pt2 = MatrixHelper.TransformPoint(t2, new Point(x2 - (float)sizeX2, y2)); var d = _dc.PushTransform(t2); var rect = new Rect2(x2 - sizeX2, y2 - radiusY2, sizeX2, sizeY2); DrawEllipseInternal(_dc, fillEndArrow, strokeEndArrow, eas.IsStroked, eas.IsFilled, ref rect); d.Dispose(); } break; case ArrowType.Arrow: { var pts = new Point[] { new Point(x2, y2), new Point(x2 - (float)sizeX2, y2 + (float)sizeY2), new Point(x2, y2), new Point(x2 - (float)sizeX2, y2 - (float)sizeY2), new Point(x2, y2) }; pt2 = MatrixHelper.TransformPoint(t2, pts[0]); var p11 = MatrixHelper.TransformPoint(t2, pts[1]); var p21 = MatrixHelper.TransformPoint(t2, pts[2]); var p12 = MatrixHelper.TransformPoint(t2, pts[3]); var p22 = MatrixHelper.TransformPoint(t2, pts[4]); DrawLineInternal(_dc, strokeEndArrow, eas.IsStroked, ref p11, ref p21); DrawLineInternal(_dc, strokeEndArrow, eas.IsStroked, ref p12, ref p22); } break; } _dc.DrawLine(strokeLine, pt1, pt2); // TODO: fillLine.Dispose(); // TODO: strokeLine.Dispose(); // TODO: fillStartArrow.Dispose(); // TODO: strokeStartArrow.Dispose(); // TODO: fillEndArrow.Dispose(); // TODO: strokeEndArrow.Dispose(); }
/// <summary> /// /// </summary> /// <param name="tl"></param> /// <param name="br"></param> /// <param name="dx"></param> /// <param name="dy"></param> /// <returns></returns> private static Rect2 CreateRect(XPoint tl, XPoint br, double dx, double dy) { return(Rect2.Create(tl, br, dx, dy)); }
/// <summary> /// /// </summary> /// <param name="text"></param> /// <param name="dx"></param> /// <param name="dy"></param> /// <returns></returns> public static Rect2 GetTextBounds(XText text, double dx, double dy) { return(Rect2.Create(text.TopLeft, text.BottomRight, dx, dy)); }
/// <summary> /// /// </summary> /// <param name="ellipse"></param> /// <param name="dx"></param> /// <param name="dy"></param> /// <returns></returns> public static Rect2 GetEllipseBounds(XEllipse ellipse, double dx, double dy) { return(Rect2.Create(ellipse.TopLeft, ellipse.BottomRight, dx, dy)); }
/// <summary> /// /// </summary> /// <param name="dc"></param> /// <param name="brush"></param> /// <param name="pen"></param> /// <param name="isStroked"></param> /// <param name="isFilled"></param> /// <param name="rect"></param> private static void DrawEllipseInternal( IDrawingContext dc, Brush brush, Pen pen, bool isStroked, bool isFilled, ref Rect2 rect) { if (!isFilled && !isStroked) return; var r = new Rect(rect.X, rect.Y, rect.Width, rect.Height); var g = new EllipseGeometry(r); dc.DrawGeometry( isFilled ? brush : null, isStroked ? pen : null, g); // TODO: g.Dispose(); }
/// <summary> /// /// </summary> /// <param name="gfx"></param> /// <param name="line"></param> /// <param name="dx"></param> /// <param name="dy"></param> /// <param name="db"></param> /// <param name="r"></param> public void Draw(object gfx, XLine line, double dx, double dy, ImmutableArray <ShapeProperty> db, Record r) { var _gfx = gfx as Graphics; Brush fillLine = ToSolidBrush(line.Style.Fill); Pen strokeLine = ToPen(line.Style, _scaleToPage); Brush fillStartArrow = ToSolidBrush(line.Style.StartArrowStyle.Fill); Pen strokeStartArrow = ToPen(line.Style.StartArrowStyle, _scaleToPage); Brush fillEndArrow = ToSolidBrush(line.Style.EndArrowStyle.Fill); Pen strokeEndArrow = ToPen(line.Style.EndArrowStyle, _scaleToPage); double _x1 = line.Start.X + dx; double _y1 = line.Start.Y + dy; double _x2 = line.End.X + dx; double _y2 = line.End.Y + dy; XLine.SetMaxLength(line, ref _x1, ref _y1, ref _x2, ref _y2); float x1 = _scaleToPage(_x1); float y1 = _scaleToPage(_y1); float x2 = _scaleToPage(_x2); float y2 = _scaleToPage(_y2); var sas = line.Style.StartArrowStyle; var eas = line.Style.EndArrowStyle; float a1 = (float)(Math.Atan2(y1 - y2, x1 - x2) * 180.0 / Math.PI); float a2 = (float)(Math.Atan2(y2 - y1, x2 - x1) * 180.0 / Math.PI); var t1 = new Matrix(); var c1 = new PointF(x1, y1); t1.RotateAt(a1, c1); var t2 = new Matrix(); var c2 = new PointF(x2, y2); t2.RotateAt(a2, c2); PointF pt1; PointF pt2; double radiusX1 = sas.RadiusX; double radiusY1 = sas.RadiusY; double sizeX1 = 2.0 * radiusX1; double sizeY1 = 2.0 * radiusY1; switch (sas.ArrowType) { default: case ArrowType.None: { pt1 = new PointF(x1, y1); } break; case ArrowType.Rectangle: { var pts = new PointF[] { new PointF(x1 - (float)sizeX1, y1) }; t1.TransformPoints(pts); pt1 = pts[0]; var rect = new Rect2(x1 - sizeX1, y1 - radiusY1, sizeX1, sizeY1); var gs = _gfx.Save(); _gfx.MultiplyTransform(t1); DrawRectangleInternal(_gfx, fillStartArrow, strokeStartArrow, sas.IsStroked, sas.IsFilled, ref rect); _gfx.Restore(gs); } break; case ArrowType.Ellipse: { var pts = new PointF[] { new PointF(x1 - (float)sizeX1, y1) }; t1.TransformPoints(pts); pt1 = pts[0]; var gs = _gfx.Save(); _gfx.MultiplyTransform(t1); var rect = new Rect2(x1 - sizeX1, y1 - radiusY1, sizeX1, sizeY1); DrawEllipseInternal(_gfx, fillStartArrow, strokeStartArrow, sas.IsStroked, sas.IsFilled, ref rect); _gfx.Restore(gs); } break; case ArrowType.Arrow: { var pts = new PointF[] { new PointF(x1, y1), new PointF(x1 - (float)sizeX1, y1 + (float)sizeY1), new PointF(x1, y1), new PointF(x1 - (float)sizeX1, y1 - (float)sizeY1), new PointF(x1, y1) }; t1.TransformPoints(pts); pt1 = pts[0]; var p11 = pts[1]; var p21 = pts[2]; var p12 = pts[3]; var p22 = pts[4]; DrawLineInternal(_gfx, strokeStartArrow, sas.IsStroked, ref p11, ref p21); DrawLineInternal(_gfx, strokeStartArrow, sas.IsStroked, ref p12, ref p22); } break; } double radiusX2 = eas.RadiusX; double radiusY2 = eas.RadiusY; double sizeX2 = 2.0 * radiusX2; double sizeY2 = 2.0 * radiusY2; switch (eas.ArrowType) { default: case ArrowType.None: { pt2 = new PointF(x2, y2); } break; case ArrowType.Rectangle: { var pts = new PointF[] { new PointF(x2 - (float)sizeX2, y2) }; t2.TransformPoints(pts); pt2 = pts[0]; var rect = new Rect2(x2 - sizeX2, y2 - radiusY2, sizeX2, sizeY2); var gs = _gfx.Save(); _gfx.MultiplyTransform(t2); DrawRectangleInternal(_gfx, fillEndArrow, strokeEndArrow, eas.IsStroked, eas.IsFilled, ref rect); _gfx.Restore(gs); } break; case ArrowType.Ellipse: { var pts = new PointF[] { new PointF(x2 - (float)sizeX2, y2) }; t2.TransformPoints(pts); pt2 = pts[0]; var gs = _gfx.Save(); _gfx.MultiplyTransform(t2); var rect = new Rect2(x2 - sizeX2, y2 - radiusY2, sizeX2, sizeY2); DrawEllipseInternal(_gfx, fillEndArrow, strokeEndArrow, eas.IsStroked, eas.IsFilled, ref rect); _gfx.Restore(gs); } break; case ArrowType.Arrow: { var pts = new PointF[] { new PointF(x2, y2), new PointF(x2 - (float)sizeX2, y2 + (float)sizeY2), new PointF(x2, y2), new PointF(x2 - (float)sizeX2, y2 - (float)sizeY2), new PointF(x2, y2) }; t2.TransformPoints(pts); pt2 = pts[0]; var p11 = pts[1]; var p21 = pts[2]; var p12 = pts[3]; var p22 = pts[4]; DrawLineInternal(_gfx, strokeEndArrow, eas.IsStroked, ref p11, ref p21); DrawLineInternal(_gfx, strokeEndArrow, eas.IsStroked, ref p12, ref p22); } break; } _gfx.DrawLine(strokeLine, pt1, pt2); fillLine.Dispose(); strokeLine.Dispose(); fillStartArrow.Dispose(); strokeStartArrow.Dispose(); fillEndArrow.Dispose(); strokeEndArrow.Dispose(); }
/// <summary> /// /// </summary> /// <param name="style"></param> /// <param name="rect"></param> /// <param name="size"></param> /// <returns></returns> private Point GetTextOrigin(ShapeStyle style, ref Rect2 rect, ref Size size) { double ox, oy; switch (style.TextStyle.TextHAlignment) { case TextHAlignment.Left: ox = rect.X; break; case TextHAlignment.Right: ox = rect.Right - size.Width; break; case TextHAlignment.Center: default: ox = (rect.Left + rect.Width / 2.0) - (size.Width / 2.0); break; } switch (style.TextStyle.TextVAlignment) { case TextVAlignment.Top: oy = rect.Y; break; case TextVAlignment.Bottom: oy = rect.Bottom - size.Height; break; case TextVAlignment.Center: default: oy = (rect.Bottom - rect.Height / 2f) - (size.Height / 2f); break; } return new Point(ox, oy); }
/// <summary> /// /// </summary> /// <param name="rect"></param> /// <returns></returns> public bool IntersectsWith(Rect2 rect) { return (rect.Left <= Right) && (rect.Right >= Left) && (rect.Top <= Bottom) && (rect.Bottom >= Top); }
/// <summary> /// /// </summary> /// <param name="rect"></param> /// <param name="p1"></param> /// <param name="p2"></param> /// <param name="onlySegment"></param> /// <returns></returns> public static IList<Point2> FindEllipseSegmentIntersections( Rect2 rect, Point2 p1, Point2 p2, bool onlySegment) { if ((rect.Width == 0) || (rect.Height == 0) || ((p1.X == p2.X) && (p1.Y == p2.Y))) return new Point2[] { }; if (rect.Width < 0) { rect.X = rect.Right; rect.Width = -rect.Width; } if (rect.Height < 0) { rect.Y = rect.Bottom; rect.Height = -rect.Height; } double cx = rect.Left + rect.Width / 2.0; double cy = rect.Top + rect.Height / 2.0; rect.X -= cx; rect.Y -= cy; p1.X -= cx; p1.Y -= cy; p2.X -= cx; p2.Y -= cy; double a = rect.Width / 2.0; double b = rect.Height / 2.0; double A = (p2.X - p1.X) * (p2.X - p1.X) / a / a + (p2.Y - p1.Y) * (p2.Y - p1.Y) / b / b; double B = 2 * p1.X * (p2.X - p1.X) / a / a + 2 * p1.Y * (p2.Y - p1.Y) / b / b; double C = p1.X * p1.X / a / a + p1.Y * p1.Y / b / b - 1; var solutions = new List<double>(); double discriminant = B * B - 4 * A * C; if (discriminant == 0) { solutions.Add(-B / 2 / A); } else if (discriminant > 0) { solutions.Add((-B + Math.Sqrt(discriminant)) / 2 / A); solutions.Add((-B - Math.Sqrt(discriminant)) / 2 / A); } var points = new List<Point2>(); foreach (var t in solutions) { if (!onlySegment || ((t >= 0f) && (t <= 1f))) { double x = p1.X + (p2.X - p1.X) * t + cx; double y = p1.Y + (p2.Y - p1.Y) * t + cy; points.Add(Point2.Create(x, y)); } } return points; }
/// <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 }); }
public void Draw(object ds, XLine line, double dx, double dy, ImmutableArray<ShapeProperty> db, Record r) { // TODO: Finish draw line implementation. var _ds = ds as CanvasDrawingSession; double thicknessLine = line.Style.Thickness / _state.Zoom; double thicknessStartArrow = line.Style.StartArrowStyle.Thickness / _state.Zoom; double thicknessEndArrow = line.Style.EndArrowStyle.Thickness / _state.Zoom; var fillLine = ToColor(line.Style.Fill); var strokeLine = ToColor(line.Style.Stroke); var fillStartArrow = ToColor(line.Style.StartArrowStyle.Fill); var strokeStartArrow = ToColor(line.Style.StartArrowStyle.Stroke); var fillEndArrow = ToColor(line.Style.EndArrowStyle.Fill); var strokeEndArrow = ToColor(line.Style.EndArrowStyle.Stroke); var ssLine = CreateStrokeStyle(line.Style); var ssStartArrow = CreateStrokeStyle(line.Style.StartArrowStyle); var ssEndArrow = CreateStrokeStyle(line.Style.EndArrowStyle); double _x1 = line.Start.X + dx; double _y1 = line.Start.Y + dy; double _x2 = line.End.X + dx; double _y2 = line.End.Y + dy; XLine.SetMaxLength(line, ref _x1, ref _y1, ref _x2, ref _y2); float x1 = (float)_x1; float y1 = (float)_y1; float x2 = (float)_x2; float y2 = (float)_y2; var sas = line.Style.StartArrowStyle; var eas = line.Style.EndArrowStyle; float a1 = (float)Math.Atan2(y1 - y2, x1 - x2); float a2 = (float)Math.Atan2(y2 - y1, x2 - x1); var t1 = N.Matrix3x2.CreateRotation(a1, new N.Vector2(x1, y1)); var t2 = N.Matrix3x2.CreateRotation(a2, new N.Vector2(x2, y2)); N.Vector2 pt1; N.Vector2 pt2; double radiusX1 = sas.RadiusX; double radiusY1 = sas.RadiusY; double sizeX1 = 2.0 * radiusX1; double sizeY1 = 2.0 * radiusY1; switch (sas.ArrowType) { default: case ArrowType.None: { pt1 = new N.Vector2(x1, y1); } break; case ArrowType.Rectangle: { pt1 = N.Vector2.Transform(new N.Vector2(x1 - (float)sizeX1, y1), t1); var rect = new Rect2(x1 - sizeX1, y1 - radiusY1, sizeX1, sizeY1); var old = _ds.Transform; _ds.Transform = t1; DrawRectangleInternal(_ds, fillStartArrow, strokeStartArrow, ssStartArrow, sas.IsStroked, sas.IsFilled, ref rect, thicknessStartArrow); _ds.Transform = old; } break; case ArrowType.Ellipse: { pt1 = N.Vector2.Transform(new N.Vector2(x1 - (float)sizeX1, y1), t1); var old = _ds.Transform; _ds.Transform = t1; var rect = new Rect2(x1 - sizeX1, y1 - radiusY1, sizeX1, sizeY1); DrawEllipseInternal(_ds, fillStartArrow, strokeStartArrow, ssStartArrow, sas.IsStroked, sas.IsFilled, ref rect, thicknessStartArrow); _ds.Transform = old; } break; case ArrowType.Arrow: { pt1 = N.Vector2.Transform(new N.Vector2(x1, y1), t1); var p11 = N.Vector2.Transform(new N.Vector2(x1 - (float)sizeX1, y1 + (float)sizeY1), t1); var p21 = N.Vector2.Transform(new N.Vector2(x1, y1), t1); var p12 = N.Vector2.Transform(new N.Vector2(x1 - (float)sizeX1, y1 - (float)sizeY1), t1); var p22 = N.Vector2.Transform(new N.Vector2(x1, y1), t1); DrawLineInternal(_ds, strokeStartArrow, ssStartArrow, sas.IsStroked, ref p11, ref p21, thicknessStartArrow); DrawLineInternal(_ds, strokeStartArrow, ssStartArrow, sas.IsStroked, ref p12, ref p22, thicknessStartArrow); } break; } double radiusX2 = eas.RadiusX; double radiusY2 = eas.RadiusY; double sizeX2 = 2.0 * radiusX2; double sizeY2 = 2.0 * radiusY2; switch (eas.ArrowType) { default: case ArrowType.None: { pt2 = new N.Vector2(x2, y2); } break; case ArrowType.Rectangle: { pt2 = N.Vector2.Transform(new N.Vector2(x2 - (float)sizeX2, y2), t2); var rect = new Rect2(x2 - sizeX2, y2 - radiusY2, sizeX2, sizeY2); var old = _ds.Transform; _ds.Transform = t1; DrawRectangleInternal(_ds, fillEndArrow, strokeEndArrow, ssEndArrow, eas.IsStroked, eas.IsFilled, ref rect, thicknessEndArrow); _ds.Transform = old; } break; case ArrowType.Ellipse: { pt2 = N.Vector2.Transform(new N.Vector2(x2 - (float)sizeX2, y2), t2); var old = _ds.Transform; _ds.Transform = t1; var rect = new Rect2(x2 - sizeX2, y2 - radiusY2, sizeX2, sizeY2); DrawEllipseInternal(_ds, fillEndArrow, strokeEndArrow, ssEndArrow, eas.IsStroked, eas.IsFilled, ref rect, thicknessEndArrow); _ds.Transform = old; } break; case ArrowType.Arrow: { pt2 = N.Vector2.Transform(new N.Vector2(x2, y2), t2); var p11 = N.Vector2.Transform(new N.Vector2(x2 - (float)sizeX2, y2 + (float)sizeY2), t2); var p21 = N.Vector2.Transform(new N.Vector2(x2, y2), t2); var p12 = N.Vector2.Transform(new N.Vector2(x2 - (float)sizeX2, y2 - (float)sizeY2), t2); var p22 = N.Vector2.Transform(new N.Vector2(x2, y2), t2); DrawLineInternal(_ds, strokeEndArrow, ssEndArrow, eas.IsStroked, ref p11, ref p21, thicknessEndArrow); DrawLineInternal(_ds, strokeEndArrow, ssEndArrow, eas.IsStroked, ref p12, ref p22, thicknessEndArrow); } break; } DrawLineInternal(_ds, strokeLine, ssLine, line.IsStroked, ref pt1, ref pt2, thicknessLine); ssEndArrow.Dispose(); ssStartArrow.Dispose(); ssLine.Dispose(); }
/// <summary> /// /// </summary> /// <param name="container"></param> /// <param name="rect"></param> /// <param name="treshold"></param> /// <returns></returns> public static ImmutableHashSet<BaseShape> HitTest(Container container, Rect2 rect, double treshold) { var builder = ImmutableHashSet.CreateBuilder<BaseShape>(); var selection = new Vector2[] { new Vector2(rect.X, rect.Y), new Vector2(rect.X + rect.Width, rect.Y), new Vector2(rect.X + rect.Width, rect.Y + rect.Height), new Vector2(rect.X, rect.Y + rect.Height) }; HitTest(container.CurrentLayer.Shapes.Reverse(), rect, selection, builder, treshold, 0, 0); return builder.ToImmutableHashSet(); }
private static void DrawRectangleInternal( CanvasDrawingSession ds, Color brush, Color pen, CanvasStrokeStyle ss, bool isStroked, bool isFilled, ref Rect2 rect, double strokeWidth) { if (isFilled) { ds.FillRectangle( (float)rect.X, (float)rect.Y, (float)rect.Width, (float)rect.Height, brush); } if (isStroked) { ds.DrawRectangle( (float)rect.X, (float)rect.Y, (float)rect.Width, (float)rect.Height, pen, (float)strokeWidth, ss); } }
/// <summary> /// /// </summary> /// <param name="shape"></param> /// <param name="rect"></param> /// <param name="selection"></param> /// <param name="builder"></param> /// <param name="treshold"></param> /// <param name="dx"></param> /// <param name="dy"></param> /// <returns></returns> private static bool HitTest( BaseShape shape, Rect2 rect, Vector2[] selection, ImmutableHashSet<BaseShape>.Builder builder, double treshold, double dx, double dy) { if (shape is XPoint) { if (GetPointBounds(shape as XPoint, treshold, dx, dy).IntersectsWith(rect)) { if (builder != null) { builder.Add(shape); } else { return true; } } return false; } else if (shape is XLine) { var line = shape as XLine; if (GetPointBounds(line.Start, treshold, dx, dy).IntersectsWith(rect) || GetPointBounds(line.End, treshold, dx, dy).IntersectsWith(rect) || MathHelpers.LineIntersectsWithRect(rect, new Point2(line.Start.X, line.Start.Y), new Point2(line.End.X, line.End.Y))) { if (builder != null) { builder.Add(line); return false; } else { return true; } } return false; } else if (shape is XEllipse) { if (GetEllipseBounds(shape as XEllipse, dx, dy).IntersectsWith(rect)) { if (builder != null) { builder.Add(shape); return false; } else { return true; } } return false; } else if (shape is XRectangle) { if (GetRectangleBounds(shape as XRectangle, dx, dy).IntersectsWith(rect)) { if (builder != null) { builder.Add(shape); return false; } else { return true; } } return false; } else if (shape is XArc) { if (GetArcBounds(shape as XArc, dx, dy).IntersectsWith(rect)) { if (builder != null) { builder.Add(shape); return false; } else { return true; } } return false; } else if (shape is XBezier) { if (ConvexHullBounds.Overlap(selection, ConvexHullBounds.GetVertices(shape as XBezier, dx, dy))) { if (builder != null) { builder.Add(shape); return false; } else { return true; } } return false; } else if (shape is XQBezier) { if (ConvexHullBounds.Overlap(selection, ConvexHullBounds.GetVertices(shape as XQBezier, dx, dy))) { if (builder != null) { builder.Add(shape); return false; } else { return true; } } return false; } else if (shape is XText) { if (GetTextBounds(shape as XText, dx, dy).IntersectsWith(rect)) { if (builder != null) { builder.Add(shape); return false; } else { return true; } } return false; } else if (shape is XImage) { if (GetImageBounds(shape as XImage, dx, dy).IntersectsWith(rect)) { if (builder != null) { builder.Add(shape); return false; } else { return true; } } return false; } else if (shape is XPath) { if ((shape as XPath).Geometry != null) { var points = (shape as XPath).GetAllPoints(); if (ConvexHullBounds.Overlap(selection, ConvexHullBounds.GetVertices(points, dx, dy))) { if (builder != null) { builder.Add(shape); return false; } else { return true; } } } return false; } else if (shape is XGroup) { if (HitTest((shape as XGroup).Shapes.Reverse(), rect, selection, null, treshold, dx, dy) == true) { if (builder != null) { builder.Add(shape); return false; } else { return true; } } return false; } return false; }
/// <summary> /// Check if line intersects with rectangle using Liang-Barsky line clipping algorithm. /// </summary> /// <param name="rect"></param> /// <param name="p0"></param> /// <param name="p1"></param> /// <returns>True if line intersects with rectangle.</returns> public static bool LineIntersectsWithRect(Rect2 rect, Point2 p0, Point2 p1) { double left = rect.Left; double right = rect.Right; double bottom = rect.Bottom; double top = rect.Top; double x0 = p0.X; double y0 = p0.Y; double x1 = p1.X; double y1 = p1.Y; double t0 = 0.0; double t1 = 1.0; double dx = x1 - x0; double dy = y1 - y0; double p = 0.0, q = 0.0, r; for (int edge = 0; edge < 4; edge++) { if (edge == 0) { p = -dx; q = -(left - x0); } if (edge == 1) { p = dx; q = (right - x0); } if (edge == 2) { p = dy; q = (bottom - y0); } if (edge == 3) { p = -dy; q = -(top - y0); } r = q / p; if (p == 0.0 && q < 0.0) { return(false); } if (p < 0.0) { if (r > t1) { return(false); } else if (r > t0) { t0 = r; } } else if (p > 0.0) { if (r < t0) { return(false); } else if (r < t1) { t1 = r; } } } // to calulate clipped line position // x0clip = x0 + t0 * dx; // y0clip = y0 + t0 * dy; // x1clip = x0 + t1 * dx; // y1clip = y0 + t1 * dy; return(true); }
/// <summary> /// /// </summary> /// <param name="shapes"></param> /// <param name="rect"></param> /// <param name="selection"></param> /// <param name="builder"></param> /// <param name="treshold"></param> /// <param name="dx"></param> /// <param name="dy"></param> /// <returns></returns> private static bool HitTest( IEnumerable<BaseShape> shapes, Rect2 rect, Vector2[] selection, ImmutableHashSet<BaseShape>.Builder builder, double treshold, double dx, double dy) { foreach (var shape in shapes) { var result = HitTest(shape, rect, selection, builder, treshold, dx, dy); if (result == true) { return true; } } return false; }
/// <summary> /// /// </summary> /// <param name="gfx"></param> /// <param name="line"></param> /// <param name="dx"></param> /// <param name="dy"></param> /// <param name="db"></param> /// <param name="r"></param> public void Draw(object gfx, XLine line, double dx, double dy, ImmutableArray<ShapeProperty> db, Record r) { var _gfx = gfx as Graphics; Brush fillLine = ToSolidBrush(line.Style.Fill); Pen strokeLine = ToPen(line.Style, _scaleToPage); Brush fillStartArrow = ToSolidBrush(line.Style.StartArrowStyle.Fill); Pen strokeStartArrow = ToPen(line.Style.StartArrowStyle, _scaleToPage); Brush fillEndArrow = ToSolidBrush(line.Style.EndArrowStyle.Fill); Pen strokeEndArrow = ToPen(line.Style.EndArrowStyle, _scaleToPage); double _x1 = line.Start.X + dx; double _y1 = line.Start.Y + dy; double _x2 = line.End.X + dx; double _y2 = line.End.Y + dy; XLine.SetMaxLength(line, ref _x1, ref _y1, ref _x2, ref _y2); float x1 = _scaleToPage(_x1); float y1 = _scaleToPage(_y1); float x2 = _scaleToPage(_x2); float y2 = _scaleToPage(_y2); var sas = line.Style.StartArrowStyle; var eas = line.Style.EndArrowStyle; float a1 = (float)(Math.Atan2(y1 - y2, x1 - x2) * 180.0 / Math.PI); float a2 = (float)(Math.Atan2(y2 - y1, x2 - x1) * 180.0 / Math.PI); var t1 = new Matrix(); var c1 = new PointF(x1, y1); t1.RotateAt(a1, c1); var t2 = new Matrix(); var c2 = new PointF(x2, y2); t2.RotateAt(a2, c2); PointF pt1; PointF pt2; double radiusX1 = sas.RadiusX; double radiusY1 = sas.RadiusY; double sizeX1 = 2.0 * radiusX1; double sizeY1 = 2.0 * radiusY1; switch (sas.ArrowType) { default: case ArrowType.None: { pt1 = new PointF(x1, y1); } break; case ArrowType.Rectangle: { var pts = new PointF[] { new PointF(x1 - (float)sizeX1, y1) }; t1.TransformPoints(pts); pt1 = pts[0]; var rect = new Rect2(x1 - sizeX1, y1 - radiusY1, sizeX1, sizeY1); var gs = _gfx.Save(); _gfx.MultiplyTransform(t1); DrawRectangleInternal(_gfx, fillStartArrow, strokeStartArrow, sas.IsStroked, sas.IsFilled, ref rect); _gfx.Restore(gs); } break; case ArrowType.Ellipse: { var pts = new PointF[] { new PointF(x1 - (float)sizeX1, y1) }; t1.TransformPoints(pts); pt1 = pts[0]; var gs = _gfx.Save(); _gfx.MultiplyTransform(t1); var rect = new Rect2(x1 - sizeX1, y1 - radiusY1, sizeX1, sizeY1); DrawEllipseInternal(_gfx, fillStartArrow, strokeStartArrow, sas.IsStroked, sas.IsFilled, ref rect); _gfx.Restore(gs); } break; case ArrowType.Arrow: { var pts = new PointF[] { new PointF(x1, y1), new PointF(x1 - (float)sizeX1, y1 + (float)sizeY1), new PointF(x1, y1), new PointF(x1 - (float)sizeX1, y1 - (float)sizeY1), new PointF(x1, y1) }; t1.TransformPoints(pts); pt1 = pts[0]; var p11 = pts[1]; var p21 = pts[2]; var p12 = pts[3]; var p22 = pts[4]; DrawLineInternal(_gfx, strokeStartArrow, sas.IsStroked, ref p11, ref p21); DrawLineInternal(_gfx, strokeStartArrow, sas.IsStroked, ref p12, ref p22); } break; } double radiusX2 = eas.RadiusX; double radiusY2 = eas.RadiusY; double sizeX2 = 2.0 * radiusX2; double sizeY2 = 2.0 * radiusY2; switch (eas.ArrowType) { default: case ArrowType.None: { pt2 = new PointF(x2, y2); } break; case ArrowType.Rectangle: { var pts = new PointF[] { new PointF(x2 - (float)sizeX2, y2) }; t2.TransformPoints(pts); pt2 = pts[0]; var rect = new Rect2(x2 - sizeX2, y2 - radiusY2, sizeX2, sizeY2); var gs = _gfx.Save(); _gfx.MultiplyTransform(t2); DrawRectangleInternal(_gfx, fillEndArrow, strokeEndArrow, eas.IsStroked, eas.IsFilled, ref rect); _gfx.Restore(gs); } break; case ArrowType.Ellipse: { var pts = new PointF[] { new PointF(x2 - (float)sizeX2, y2) }; t2.TransformPoints(pts); pt2 = pts[0]; var gs = _gfx.Save(); _gfx.MultiplyTransform(t2); var rect = new Rect2(x2 - sizeX2, y2 - radiusY2, sizeX2, sizeY2); DrawEllipseInternal(_gfx, fillEndArrow, strokeEndArrow, eas.IsStroked, eas.IsFilled, ref rect); _gfx.Restore(gs); } break; case ArrowType.Arrow: { var pts = new PointF[] { new PointF(x2, y2), new PointF(x2 - (float)sizeX2, y2 + (float)sizeY2), new PointF(x2, y2), new PointF(x2 - (float)sizeX2, y2 - (float)sizeY2), new PointF(x2, y2) }; t2.TransformPoints(pts); pt2 = pts[0]; var p11 = pts[1]; var p21 = pts[2]; var p12 = pts[3]; var p22 = pts[4]; DrawLineInternal(_gfx, strokeEndArrow, eas.IsStroked, ref p11, ref p21); DrawLineInternal(_gfx, strokeEndArrow, eas.IsStroked, ref p12, ref p22); } break; } _gfx.DrawLine(strokeLine, pt1, pt2); fillLine.Dispose(); strokeLine.Dispose(); fillStartArrow.Dispose(); strokeStartArrow.Dispose(); fillEndArrow.Dispose(); strokeEndArrow.Dispose(); }
/// <summary> /// /// </summary> /// <param name="tl"></param> /// <param name="br"></param> /// <param name="dx"></param> /// <param name="dy"></param> /// <returns></returns> public static Rect2 Create( XPoint tl, XPoint br, double dx = 0.0, double dy = 0.0) { return(Rect2.Create(tl.X, tl.Y, br.X, br.Y, dx, dy)); }
/// <summary> /// /// </summary> /// <param name="image"></param> /// <param name="dx"></param> /// <param name="dy"></param> /// <returns></returns> public static Rect2 GetImageBounds(XImage image, double dx, double dy) { return(Rect2.Create(image.TopLeft, image.BottomRight, dx, dy)); }