Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
504 views
in Technique[技术] by (71.8m points)

join - Connecting two WPF canvas elements by a line, without using anchors?

I have a canvas for diagramming, and want to join nodes in the diagram by directed lines (arrow ends). I tried the anchor approach, where lines only attach at specific points on the nodes but that did not work for me, it looked like crap.

I simply want a line from the centre of each object to the other, and stop the line at the nodes' edge in order for the arrow end to show properly. But finding the edge of a canvas element to test intersections against has proven difficult.

Any ideas?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

I got a method working using the bounding box of the element. It is not perfect, since my elements are not perfectly rectangular, but it looks OK.

Basically I find the bounding box of the element in Canvas coordinates by:

    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));
    }

Then I find the intersection of the centre-to-centre line against each of the four sides of the bounding box, and use that intersection point to connect the two elements by a Line shape.

I found the intersection code at Third Party Ninjas: 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);
            }
        }
    }

And voilá! The lines are now drawn as if they go from the centre of each node to the other, but stops approximately at the node's edge so the arrow end is visible.

An improvement of this method would be to test against the actual edge of the node itself, such as for elliptical nodes, but I have yet to find a WPF method that provides me with a Geometry or Path that I can test against.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...