Соединение двух элементов холста WPF линией, без использования якорей?


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

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

Есть идеи?

1 2

1 ответ:

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

В основном я нахожу ограничивающую рамку элемента в координатах холста по:

    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, который предоставляет мне геометрию или путь, который я могу тест против.