Соединить два элемента холста WPF линией, без использования якорей? - PullRequest
2 голосов
/ 15 ноября 2009

У меня есть холст для построения диаграмм, и я хочу соединить узлы на диаграмме направленными линиями (стрелки заканчиваются). Я попробовал подход якоря, где линии только прикрепляются в определенных точках на узлах, но это не сработало для меня, это было похоже на дерьмо

Мне просто нужна линия от центра каждого объекта к другому, и остановка линии на краю узлов, чтобы конец стрелки отображался правильно. Но найти край элемента canvas для проверки пересечений оказалось трудным.

Есть идеи?

1 Ответ

4 голосов
/ 15 ноября 2009

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

Обычно я нахожу ограничивающую рамку элемента в координатах Canvas по:

    private static Rect GetBounds(FrameworkElement element, UIElement visual)
    {
        return new Rect(
            element.TranslatePoint(new Point(0, 0), visual),
            element.TranslatePoint(new Point(element.ActualWidth, element.ActualHeight), visual));
    }

Затем я нахожу пересечение линии от центра к центру напротив каждой из четырех сторон ограничительной рамки и использую эту точку пересечения для соединения двух элементов в форме линии.

Я нашел код пересечения у сторонних ниндзя: http://thirdpartyninjas.com/blog/2008/10/07/line-segment-intersection/

private void ProcessIntersection()
    {
        float ua = (point4.X - point3.X) * (point1.Y - point3.Y) - (point4.Y - point3.Y) * (point1.X - point3.X);
        float ub = (point2.X - point1.X) * (point1.Y - point3.Y) - (point2.Y - point1.Y) * (point1.X - point3.X);
        float denominator = (point4.Y - point3.Y) * (point2.X - point1.X) - (point4.X - point3.X) * (point2.Y - point1.Y);

        intersection = coincident = false;

        if (Math.Abs(denominator) <= 0.00001f)
        {
            if (Math.Abs(ua) <= 0.00001f && Math.Abs(ub) <= 0.00001f)
            {
                intersection = coincident = true;
                intersectionPoint = (point1 + point2) / 2;
            }
        }
        else
        {
            ua /= denominator;
            ub /= denominator;

            if (ua >= 0 && ua <= 1 && ub >= 0 && ub <= 1)
            {
                intersection = true;
                intersectionPoint.X = point1.X + ua * (point2.X - point1.X);
                intersectionPoint.Y = point1.Y + ua * (point2.Y - point1.Y);
            }
        }
    }

И вуаля! Теперь линии нарисованы так, как будто они идут от центра каждого узла к другому, но останавливаются приблизительно на краю узла, поэтому конец стрелки виден.

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

...