Рисование на холсте большими пикселями - PullRequest
0 голосов
/ 19 октября 2011

Я пишу приложение, которое позволяет пользователю рисовать на сенсорном экране.В настоящее время я использую метод ниже, и он работает очень хорошо.Этот метод создает «изображение с высоким разрешением», поскольку почти для каждого пикселя рисуется линия (например, 100, 100 -> 102, 103).

Вот мой вопрос.Я бы хотел, чтобы пользователь нарисовал «картинку с низким разрешением» (большую доску пикселей), где вы можете преднамеренно видеть пиксели 50 × 50 (например, 100, 100 -> 150, 150).У кого-нибудь есть идея, как этого добиться?Я использую Silverlight для Windows Phone.Я думал о создании большой сетки размером 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;
}

Ответы [ 2 ]

1 голос
/ 19 октября 2011

@ У Амра правильная идея. Я дам вам этот код с оговоркой, которую я вообще не проверял. Я взял алгоритм пересечения отрезков от здесь .

Во-первых, вам нужно настроить список прямоугольников и добавить их на холст, которые являются вашими "пикселями":

    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 мы перебираем каждый прямоугольник, чтобы увидеть, пересекается ли он. Если это так, мы меняем его цвет:

    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;
    }
0 голосов
/ 19 октября 2011

Если вы просто хотите сделать линию более толстой, просто поэкспериментируйте с возможными значениями StrokeThickness, пока не получите желаемый эффект.

Если вы хотите нарисовать линию вручную, заполнив большие области экрана, скажите(50x50) прямоугольников можно выполнить следующим образом:

  1. разделить экран на прямоугольники 50x50
  2. проверить, какие прямоугольники пересекаются линией, нарисованной пользователем
  3. Нарисуйте прямоугольники только с шага 2

Это даст вам желаемую линию «привязки к сетке».

...