【问题标题】:Drawing on a canvas a big pixels在画布上绘制一个大像素
【发布时间】:2011-12-10 22:26:15
【问题描述】:

我正在编写一个允许用户在触摸屏显示器上绘图的应用程序。我目前正在使用下面的方法,效果很好。这种方法正在生成“高分辨率图像”,因为几乎每个像素都绘制了一条线(例如 100、100 -> 102、103)。

这是我的问题。我希望用户绘制一张“低分辨率图片”(大像素板),您可以在其中有意看到 50×50 的像素(例如 100、100 -> 150、150)。有人知道如何做到这一点吗?我正在为 Windows Phone 使用 Silverlight。我正在考虑构建一个 50×50 像素的大网格,但可能控件太多。

void FingerMove(object sender, MouseEventArgs e)
{
    if (this.IsDrawing)
    {
        this.DestinationPoint = e.GetPosition(paint);
        Line line = new Line
        {
            Stroke = this.Color,
            X1 = this.DestinationPoint.X,
            Y1 = this.DestinationPoint.Y,
            X2 = this.OriginPoint.X,
            Y2 = this.OriginPoint.Y,
            StrokeStartLineCap = PenLineCap.Round,
            StrokeEndLineCap = PenLineCap.Round,
            StrokeThickness = 15,
            Opacity = 1,
        };

        Debug.WriteLine(string.Join(",", line.X1, line.Y1, line.X2, line.Y2));

        paint.Children.Add(line);
    }

    this.OriginPoint = this.DestinationPoint;
}

【问题讨论】:

  • 在渲染到屏幕之前,绘制到一个后台缓冲区(屏幕外位图),然后缩放到另一个尺寸 x 和 y 太小的 50 倍,然后放大到最终在屏幕上绘制,所有这些都没有插值。
  • 您是说要查看块状线,还是符合网格的线?
  • @GeorgeDuckett:是的,这就是我想要的。
  • @Martin,哪一个,您想要像素化图像,还是要绘制平滑线条,“对齐网格”?
  • 不要画线,而是画 50x50 的矩形。将用户位置除以 50,然后乘以 50(整数除法/乘法)以使其对齐网格。

标签: c# .net silverlight windows-phone-7 drawing


【解决方案1】:

@Amr 有正确的想法。我会给你这段代码,但需要注意的是我根本没有测试过它。我从here中取了线段相交算法。

首先,您需要设置一个矩形列表并将它们添加到作为您的“像素”的画布中:

    private List<Rectangle> _rects = new List<Rectangle>();

    private void GenerateRects()
    {
        int width = 300; // or whatever dimensions...
        int height = 300;
        int gridSize = 50;

        for (int x = 0; x < width; x += gridSize)
        {
            for (int y = 0; y < height; y += gridSize)
            {
                var rect = new Rectangle
                {
                    Opacity = 0,
                    Width = Math.Min(gridSize, width - x),
                    Height = Math.Min(gridSize, height - y),
                };

                Canvas.SetLeft(rect, x);
                Canvas.SetTop(rect, y);

                _rects.Add(rect);
                this.paint.Children.Add(rect);
            }
        }
    }

我们需要这些辅助方法:

    class LineSegment
    {
        public double X1 { get; set; }
        public double X2 { get; set; }
        public double Y1 { get; set; }
        public double Y2 { get; set; }
    }

    private static bool SegmentsIntersect(LineSegment A, LineSegment B)
    {
        double x1 = A.X1, x2 = A.X2, x3 = B.X1, x4 = B.X2;
        double y1 = A.Y1, y2 = A.Y2, y3 = B.Y1, y4 = B.Y2;

        double denominator = (y4 - y3) * (x2 - x1) - (x4 - x3) * (y2 - y1);

        if (denominator == 0)
            return false;

        double ua = ((x4 - x3) * (y1 - y3) - (y4 - y3) * (x1 - x3)) / denominator;
        double ub = ((x2 - x1) * (y1 - y3) - (y2 - y1) * (x1 - x3)) / denominator;

        return (ua > 0 && ua < 1 && ub > 0 && ub < 1);
    }

    private static bool RectIntersectsLine(Rect A, LineSegment B)
    {
        return (SegmentsIntersect(B, new LineSegment { X1 = A.X, Y1 = A.Y, X2 = A.X, Y2 = A.Y + A.Height }) ||
            SegmentsIntersect(B, new LineSegment { X1 = A.X, Y1 = A.Y + A.Height, X2 = A.X + A.Width, Y2 = A.Y + A.Height }) ||
            SegmentsIntersect(B, new LineSegment { X1 = A.X + A.Width, Y1 = A.Y + A.Height, X2 = A.X + A.Width, Y2 = A.Y }) ||
            SegmentsIntersect(B, new LineSegment { X1 = A.X + A.Width, Y1 = A.Y, X2 = A.X, Y2 = A.Y }) ||
            RectContainsPoint(A, new Point(B.X1, B.Y1)) ||
            RectContainsPoint(A, new Point(B.X2, B.Y2)));
    }

    private static bool RectContainsPoint(Rect A, Point B)
    {
        return (B.X > A.X && B.X < A.X + A.Width && B.Y > A.Y && B.Y < A.Y + A.Height);
    }

然后,在 FingerMove 函数中,我们循环遍历每个 Rectangle 以查看它是否相交。如果是,我们改变它的颜色:

    void FingerMove(object sender, MouseEventArgs e)
    {
        if (this.IsDrawing)
        {
            this.DestinationPoint = e.GetPosition(paint);
            LineSegment line = new LineSegment
            {
                X1 = this.DestinationPoint.X,
                Y1 = this.DestinationPoint.Y,
                X2 = this.OriginPoint.X,
                Y2 = this.OriginPoint.Y
            };

            foreach (var rect in _rects)
            {
                var x = Canvas.GetLeft(rect);
                var y = Canvas.GetTop(rect);

                if (RectIntersectsLine(new Rect(x, y, rect.Width, rect.Height) , line))
                {
                    rect.Opacity = 1;
                    rect.Fill = Color;
                }
            }
        }

        this.OriginPoint = this.DestinationPoint;
    }

【讨论】:

    【解决方案2】:

    如果您只是想让线条更粗,只需尝试 StrokeThickness 的可能值,直到获得所需的效果。

    如果您想通过填充屏幕的大面积(50x50)矩形来手动绘制线条,您可以执行以下操作:

    1. 将屏幕划分为 50x50 的矩形
    2. 检查哪些矩形与用户绘制的线相交
    3. 仅绘制步骤 2 中的矩形

    这将为您提供所需的“对齐网格”线。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-07-08
      • 2016-10-22
      • 2011-05-20
      • 1970-01-01
      • 2012-01-14
      • 1970-01-01
      • 2021-05-03
      • 2014-01-16
      相关资源
      最近更新 更多