I have to represent graphically an oriented graph like in the image below.
alt text http://img694.imageshack.us/img694/1605/graf.gif
i have a C# form, when i click with the mouse on it i have to draw a node. If i click somewhere on the form where is not already a node drawn it means i cliked with the intetion of drawing a node, if it is a node there i must select it and memorize it. On the next mouse click if i touch a place where there is not already a node drawn it means like before that i want to draw a new node, if it is a node where i clicked i need to draw the line from the first memorized node to th开发者_如何学Goe selected one and add road cost details.
i know how to draw the circles that represent the nodes of the graph when i click on the form. i'm using the following code:
namespace RepGraficaAUnuiGraf
{
public partial class Form1 : Form
{
Graphics graphDrawingArea;
Bitmap bmpDrawingArea;
Graphics graph;
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
bmpDrawingArea = new Bitmap(Width, Height);
graphDrawingArea = Graphics.FromImage(bmpDrawingArea);
graph = Graphics.FromHwnd(this.Handle);
}
private void Form1_Click(object sender, EventArgs e)
{
DrawCentralCircle(((MouseEventArgs)e).X, ((MouseEventArgs)e).Y, 15);
graph.DrawImage(bmpDrawingArea, 0, 0);
}
void DrawCentralCircle(int CenterX, int CenterY, int Radius)
{
int start = CenterX - Radius;
int end = CenterY - Radius;
int diam = Radius * 2;
bmpDrawingArea = new Bitmap(Width, Height);
graphDrawingArea = Graphics.FromImage(bmpDrawingArea);
graphDrawingArea.DrawEllipse(new Pen(Color.Blue), start, end, diam, diam);
graphDrawingArea.DrawString("1", new Font("Tahoma", 13), Brushes.Black, new PointF(CenterX - 8, CenterY - 10));
}
}
}
My question is how can i find out if at the coordinates (x,y) on my form i drew a node and which one is it? I thought of representing the nodes as buttons, having a tag or something similar as the node number(which in drawing should be 1 for Santa Barbara, 2 for Barstow etc.)
Expanding upon the answer from Anders Abel:
- keep a list storing information about each node including
- center point
- radius
- other relevant information ...
When you click determine whether one of the nodes was hit
- iterate through all of the nodes
- find the distance from the click point to the center of the node using the Pythagorean Theorem
- if the distance is less than the radius then select the node
- if a node was not selected then add a new node at the clicked location
One way would be to create a UserControl that represents (and draws) your circles, and also handles when a user clicks it. You could then let each circle object determine whether or not it has been clicked rather than using X and Y coordinates to try to figure out where a user clicked and whether or not they clicked a circle.
I'm afraid you're missing the basic intended pattern for Windows UIs. Throw out your code above and do this:
Create a data structure in memory that represents the "document" (everything you need to keep track of about the graph, its nodes and edges).
On mouse click, you don't draw. You just modify your "document" data structure (as suggested above). Plus you call Invalidate() which will cause a redraw later.
Override OnPaint(). That's where you do all your drawing, drawing your visual representation of the data structure you've stored.
A simple approach is to put all circles into a list when you draw them. In your mouse click handler you can go through the list and check for each of the circles whether the mouse is within the circle.
This approach won't however scale in the long run. If you have a lot of circles you probably want to look into spatial search algorithms.
You can also make a list of nodes and check if the distance between the center of the node to the clicked point is <= radius.
private void Form1_MouseClick(object sender, MouseEventArgs e)
{
int x1 = node.Center.X, y1 = node.Center.Y, x2, y2;
Point local = this.PointToClient(Cursor.Position);
bool clicked = false;
x2 = local.X;
y2 = local.Y;
float distance = Convert.ToSingle(Math.Sqrt((x1 - x2) ^ 2 + (y1 - y2) ^ 2));
if(distance <= radius) clicked = true;
}
精彩评论