private A.Point GetTextOrigin(ShapeStyle style, ref Rect2 rect, ref A.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 A.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="point"></param> /// <param name="rect"></param> /// <param name="selected"></param> /// <param name="threshold"></param> /// <param name="dx"></param> /// <param name="dy"></param> /// <returns></returns> public static bool HitTestPoint(XPoint point, Rect2 rect, ISet<BaseShape> selected, double threshold, double dx, double dy) { if (ShapeBounds.GetPointBounds(point, threshold, dx, dy).IntersectsWith(rect)) { if (selected != null) { selected.Add(point); } else { return true; } } return false; }
/// <summary> /// /// </summary> /// <param name="ellipse"></param> /// <param name="rect"></param> /// <param name="selected"></param> /// <param name="dx"></param> /// <param name="dy"></param> /// <returns></returns> public static bool HitTestEllipse(XEllipse ellipse, Rect2 rect, ISet<BaseShape> selected, double dx, double dy) { if (ShapeBounds.GetEllipseBounds(ellipse, dx, dy).IntersectsWith(rect)) { if (selected != null) { selected.Add(ellipse); return false; } else { return true; } } return false; }
/// <summary> /// /// </summary> /// <param name="line"></param> /// <param name="rect"></param> /// <param name="selected"></param> /// <param name="threshold"></param> /// <param name="dx"></param> /// <param name="dy"></param> /// <returns></returns> public static bool HitTestLine(XLine line, Rect2 rect, ISet<BaseShape> selected, double threshold, double dx, double dy) { if (ShapeBounds.GetPointBounds(line.Start, threshold, dx, dy).IntersectsWith(rect) || ShapeBounds.GetPointBounds(line.End, threshold, dx, dy).IntersectsWith(rect) || MathHelpers.LineIntersectsWithRect(rect, new Point2(line.Start.X, line.Start.Y), new Point2(line.End.X, line.End.Y))) { if (selected != null) { selected.Add(line); return false; } else { return true; } } return false; }
private void DrawGridInternal(AM.DrawingContext dc, AM.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 A.Point( _scaleToPage(x), _scaleToPage(oy)); var p1 = new A.Point( _scaleToPage(x), _scaleToPage(ey)); DrawLineInternal(dc, stroke, isStroked, ref p0, ref p1); } for (double y = sy; y < ey; y += cellHeight) { var p0 = new A.Point( _scaleToPage(ox), _scaleToPage(y)); var p1 = new A.Point( _scaleToPage(ex), _scaleToPage(y)); DrawLineInternal(dc, stroke, isStroked, ref p0, ref p1); } }
private static void DrawEllipseInternal(AM.DrawingContext dc, AM.IBrush brush, AM.Pen pen, bool isStroked, bool isFilled, ref Rect2 rect) { if (!isFilled && !isStroked) return; var r = new A.Rect(rect.X, rect.Y, rect.Width, rect.Height); var g = new AM.EllipseGeometry(r); dc.DrawGeometry( isFilled ? brush : null, isStroked ? pen : null, g); }
private static void DrawRectangleInternal(AM.DrawingContext dc, AM.IBrush brush, AM.Pen pen, bool isStroked, bool isFilled, ref Rect2 rect) { if (!isStroked && !isFilled) return; var r = new A.Rect(rect.X, rect.Y, rect.Width, rect.Height); if (isFilled) { dc.FillRectangle(brush, r); } if (isStroked) { dc.DrawRectangle(pen, r); } }
private static A.Point DrawLineArrowInternal(AM.DrawingContext dc, AM.Pen pen, AM.IBrush brush, float x, float y, double angle, ArrowStyle style) { A.Point pt = default(A.Point); var rt = APAZ.MatrixHelper.Rotation(angle, new A.Vector(x, y)); double rx = style.RadiusX; double ry = style.RadiusY; double sx = 2.0 * rx; double sy = 2.0 * ry; switch (style.ArrowType) { default: case ArrowType.None: { pt = new A.Point(x, y); } break; case ArrowType.Rectangle: { pt = APAZ.MatrixHelper.TransformPoint(rt, new A.Point(x - (float)sx, y)); var rect = new Rect2(x - sx, y - ry, sx, sy); using (var d = dc.PushPreTransform(rt)) { DrawRectangleInternal(dc, brush, pen, style.IsStroked, style.IsFilled, ref rect); } } break; case ArrowType.Ellipse: { pt = APAZ.MatrixHelper.TransformPoint(rt, new A.Point(x - (float)sx, y)); using (var d = dc.PushPreTransform(rt)) { var rect = new Rect2(x - sx, y - ry, sx, sy); DrawEllipseInternal(dc, brush, pen, style.IsStroked, style.IsFilled, ref rect); } } break; case ArrowType.Arrow: { var pts = new A.Point[] { new A.Point(x, y), new A.Point(x - (float)sx, y + (float)sy), new A.Point(x, y), new A.Point(x - (float)sx, y - (float)sy), new A.Point(x, y) }; pt = APAZ.MatrixHelper.TransformPoint(rt, pts[0]); var p11 = APAZ.MatrixHelper.TransformPoint(rt, pts[1]); var p21 = APAZ.MatrixHelper.TransformPoint(rt, pts[2]); var p12 = APAZ.MatrixHelper.TransformPoint(rt, pts[3]); var p22 = APAZ.MatrixHelper.TransformPoint(rt, pts[4]); DrawLineInternal(dc, pen, style.IsStroked, ref p11, ref p21); DrawLineInternal(dc, pen, style.IsStroked, ref p12, ref p22); } break; } return pt; }
/// <summary> /// Calculate ellipse line segment intersection points. /// </summary> /// <param name="rect"></param> /// <param name="p1">The line segment start point.</param> /// <param name="p2">The line segment end point.</param> /// <param name="onlySegment">Include only line segment solutions.</param> /// <returns>The ellipse line segment intersection point list.</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 + Sqrt(discriminant)) / 2 / A); solutions.Add((-B - 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> /// Check if line intersects with rectangle using Liang-Barsky line clipping algorithm. /// </summary> /// <param name="rect">The rectangle shape.</param> /// <param name="p0">The line start point.</param> /// <param name="p1">The line end point.</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; } } } // Calculate clipped line position. // x0clip = x0 + t0 * dx; // y0clip = y0 + t0 * dy; // x1clip = x0 + t1 * dx; // y1clip = y0 + t1 * dy; return(true); }
private static void DrawEllipseInternal(Graphics gfx, Brush brush, Pen pen, bool isStroked, bool isFilled, ref Rect2 rect) { if (isFilled) { gfx.FillEllipse( brush, (float)rect.X, (float)rect.Y, (float)rect.Width, (float)rect.Height); } if (isStroked) { gfx.DrawEllipse( pen, (float)rect.X, (float)rect.Y, (float)rect.Width, (float)rect.Height); } }
private static PointF DrawLineArrowInternal(Graphics gfx, Pen pen, Brush brush, float x, float y, float angle, ArrowStyle style) { PointF pt; var rt = new Matrix(); rt.RotateAt(angle, new PointF(x, y)); double rx = style.RadiusX; double ry = style.RadiusY; double sx = 2.0 * rx; double sy = 2.0 * ry; switch (style.ArrowType) { default: case ArrowType.None: { pt = new PointF(x, y); } break; case ArrowType.Rectangle: { var pts = new PointF[] { new PointF(x - (float)sx, y) }; rt.TransformPoints(pts); pt = pts[0]; var rect = new Rect2(x - sx, y - ry, sx, sy); var gs = gfx.Save(); gfx.MultiplyTransform(rt); DrawRectangleInternal(gfx, brush, pen, style.IsStroked, style.IsFilled, ref rect); gfx.Restore(gs); } break; case ArrowType.Ellipse: { var pts = new PointF[] { new PointF(x - (float)sx, y) }; rt.TransformPoints(pts); pt = pts[0]; var gs = gfx.Save(); gfx.MultiplyTransform(rt); var rect = new Rect2(x - sx, y - ry, sx, sy); DrawEllipseInternal(gfx, brush, pen, style.IsStroked, style.IsFilled, ref rect); gfx.Restore(gs); } break; case ArrowType.Arrow: { var pts = new PointF[] { new PointF(x, y), new PointF(x - (float)sx, y + (float)sy), new PointF(x, y), new PointF(x - (float)sx, y - (float)sy), new PointF(x, y) }; rt.TransformPoints(pts); pt = pts[0]; var p11 = pts[1]; var p21 = pts[2]; var p12 = pts[3]; var p22 = pts[4]; DrawLineInternal(gfx, pen, style.IsStroked, ref p11, ref p21); DrawLineInternal(gfx, pen, style.IsStroked, ref p12, ref p22); } break; } return pt; }
/// <summary> /// /// </summary> /// <param name="arc"></param> /// <param name="rect"></param> /// <param name="selected"></param> /// <param name="dx"></param> /// <param name="dy"></param> /// <returns></returns> public static bool HitTestArc(XArc arc, Rect2 rect, ISet<BaseShape> selected, double dx, double dy) { if (ShapeBounds.GetArcBounds(arc, dx, dy).IntersectsWith(rect)) { if (selected != null) { selected.Add(arc); return false; } else { return true; } } return false; }
/// <summary> /// /// </summary> /// <param name="text"></param> /// <param name="rect"></param> /// <param name="selected"></param> /// <param name="dx"></param> /// <param name="dy"></param> /// <returns></returns> public static bool HitTestText(XText text, Rect2 rect, ISet<BaseShape> selected, double dx, double dy) { if (ShapeBounds.GetTextBounds(text, dx, dy).IntersectsWith(rect)) { if (selected != null) { selected.Add(text); return false; } else { return true; } } return false; }
/// <summary> /// Hit test rectangle if intersects with any of the shape bounds. /// </summary> /// <param name="shapes"></param> /// <param name="rect"></param> /// <param name="threshold"></param> /// <returns></returns> public static ImmutableHashSet<BaseShape> HitTest(IEnumerable<BaseShape> shapes, Rect2 rect, double threshold) { var selected = 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(shapes.Reverse(), rect, selection, selected, threshold, 0, 0); return selected.ToImmutableHashSet(); }
/// <summary> /// Hit test rectangle if intersects with any of the shape bounds. /// </summary> /// <param name="shapes"></param> /// <param name="rect"></param> /// <param name="selection"></param> /// <param name="selected"></param> /// <param name="threshold"></param> /// <param name="dx"></param> /// <param name="dy"></param> /// <returns></returns> public static bool HitTest(IEnumerable<BaseShape> shapes, Rect2 rect, Vector2[] selection, ISet<BaseShape> selected, double threshold, double dx, double dy) { foreach (var shape in shapes) { var result = HitTest(shape, rect, selection, selected, threshold, dx, dy); if (result == true) { return true; } } return false; }
/// <summary> /// Hit test rectangle if intersects with any of the shape bounds. /// </summary> /// <param name="shape"></param> /// <param name="rect"></param> /// <param name="selection"></param> /// <param name="selected"></param> /// <param name="threshold"></param> /// <param name="dx"></param> /// <param name="dy"></param> /// <returns></returns> public static bool HitTest(BaseShape shape, Rect2 rect, Vector2[] selection, ISet<BaseShape> selected, double threshold, double dx, double dy) { if (shape is XPoint) { return HitTestPoint(shape as XPoint, rect, selected, threshold, dx, dy); } else if (shape is XLine) { return HitTestLine(shape as XLine, rect, selected, threshold, dx, dy); } else if (shape is XEllipse) { return HitTestEllipse(shape as XEllipse, rect, selected, dx, dy); } else if (shape is XRectangle) { return HitTestRectangle(shape as XRectangle, rect, selected, dx, dy); } else if (shape is XArc) { return HitTestArc(shape as XArc, rect, selected, dx, dy); } else if (shape is XCubicBezier) { return HitTestCubicBezier(shape as XCubicBezier, selection, selected, dx, dy); } else if (shape is XQuadraticBezier) { return HitTestQadraticBezier(shape as XQuadraticBezier, selection, selected, dx, dy); } else if (shape is XText) { return HitTestText(shape as XText, rect, selected, dx, dy); } else if (shape is XImage) { return HitTestImage(shape as XImage, rect, selected, dx, dy); } else if (shape is XPath) { return HitTestPath(shape as XPath, selection, selected, dx, dy); } else if (shape is XGroup) { return HitTestGroup(shape as XGroup, rect, selection, selected, threshold, dx, dy); } return false; }
/// <summary> /// /// </summary> /// <param name="group"></param> /// <param name="rect"></param> /// <param name="selection"></param> /// <param name="selected"></param> /// <param name="threshold"></param> /// <param name="dx"></param> /// <param name="dy"></param> /// <returns></returns> public static bool HitTestGroup(XGroup group, Rect2 rect, Vector2[] selection, ISet<BaseShape> selected, double threshold, double dx, double dy) { if (HitTest(group.Shapes.Reverse(), rect, selection, null, threshold, dx, dy) == true) { if (selected != null) { selected.Add(group); return false; } else { return true; } } return false; }
/// <summary> /// /// </summary> /// <param name="image"></param> /// <param name="rect"></param> /// <param name="selected"></param> /// <param name="dx"></param> /// <param name="dy"></param> /// <returns></returns> public static bool HitTestImage(XImage image, Rect2 rect, ISet<BaseShape> selected, double dx, double dy) { if (ShapeBounds.GetImageBounds(image, dx, dy).IntersectsWith(rect)) { if (selected != null) { selected.Add(image); return false; } else { return true; } } return false; }
private void DrawBackgroundInternal(SKCanvas canvas, ArgbColor color, Rect2 rect) { using (SKPaint brush = ToSKPaintBrush(color)) { SKRect srect = SKRect.Create( _scaleToPage(rect.X), _scaleToPage(rect.Y), _scaleToPage(rect.Width), _scaleToPage(rect.Height)); canvas.DrawRect(srect, brush); } }
/// <summary> /// Creates a new <see cref="Rect2"/> instance. /// </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)); }