views:

295

answers:

5

I have 2 (VisualBasic.PowerPacks)LineShapes on my form:

alt text

When I click on one of them, a specific context menu appears. The lines can be moved by the user. A context Menu is associated with a line. However, if the user clicks in the intersection point(if exists) I need to display an other menu, that will select one of intersection lines to perform an action.

Now, I wonder how to detect that 2 (or more) lines are intersected in the click point, because an other context-menu should appear in this case.

What I tried to do:

    private void shapeContainer1_MouseDown(object sender, MouseEventArgs e)
    {
        // right click only
        if (e.Button == MouseButtons.Right)
        {
            LineShape target = 
                (shapeContainer1.GetChildAtPoint(e.Location) as LineShape);

            if (target != null)
            {
                Console.WriteLine(new Point(target.X1, target.Y1));
            }

        }
    }

I suppose I have only LineShapes in the container. This told, the ShapeContainer will not raise a MouseDown event if any LineShape will be under the mouse.

But this code gives me only the mostTop line, but I want a list of others too.

A: 

serhio, thats simple Maths...

Work out the intersection points of your lines (probably do this when they are added and store result), then see if the mouse is close enough to warrent displaying the context menu so you don't need pixel perfect clicking.

Ian
Ahh, but he needs segment/segment intersection, not line intersection... That's (slightly) trickier.
Reed Copsey
My intersection points moves. User can move the lines. I need a method that will check a point when a line will be clicked, because the line is a Control(Component)
serhio
+3  A: 

In your coordinate network, you have two lines with y1 = ax + c1 and y2 = bx + c2. Find the intersection point where x1=x2 and y1=y2
y = ax + c1, y = bx + c2
ax + c1 = bx + c2
x = (c2 - c1)/(a - b)
Then check that the intersection point is not beyond the line borders and calculate proximity +- pixel or two.

alemjerus
Yeah. This is the theory. In practice this seems to be a little more complicated. When I click on the line, the line itself responds to be Clicked(eevnt). So, now, if I associated a context menu to the line, this context menu will however appear.
serhio
+2  A: 

You'll need to just compute the intersection of two line segments. This is fairly simple.

A full, working algorithm is described here. It works off line segments defined by two points, so should be easy to adapt to your situation.

Reed Copsey
May be this is simple. But the lines are not only 2, but a lot of, lines can be moved, and if I click on a lineShape object, it receives the eventClick like a normal control. So, this control should verify first if other "brothers" are not located at the same clicked point.
serhio
Computing these is fast - you could always maintain a list of intersection points, and when you "move" a line segment, recompute your intersection points for that line segment. Frankly, it's fast enough that (unless you have hundreds or thousands of lines) you could probably compute it on demand...
Reed Copsey
A: 

Apart from the line intersection algorithm (as shown by several people on this page), you need to decouple the context menu from the lines. In pseudo code you'll need something like:

onLine1Click:
if intersection then handle intersection
else handle line1 click

onLine2Click:
if intersection then handle intersection
else handle line2 click

This handling can be showing the context menu. I believe this if/then/else is required to resolve your remaining issue.

Adriaan
A: 
    /// obtains a list of shapes from a click point
    private List<LineShape> GetLinesFromAPoint(Point p) 
    {
        List<LineShape> result = new List<LineShape>();
        Point pt = shapeContainer1.PointToScreen(p);

        foreach (Shape item in shapeContainer1.Shapes)
        {
            LineShape line = (item as LineShape);
            if (line != null && line.HitTest(pt.X, pt.Y))
            {
                result.Add(line);                    
            }
        }
        return result;
    }

    private void shapeContainer1_MouseDown(object sender, MouseEventArgs e)
    {
        // right click only
        if (e.Button == MouseButtons.Right)
        {
            List<LineShape> shapesList = GetLinesFromAPoint(e.Location);
            Console.WriteLine(DateTime.Now);
            Console.WriteLine("At this point {0} there are {1} lines.", 
                e.Location, shapesList.Count);
        }
    }
serhio