1

我必须以图形方式表示一个有向图,如下图所示。

替代文字 http://img694.imageshack.us/img694/1605/graf.gif

我有一个 C# 表单,当我用鼠标点击它时,我必须绘制一个节点。如果我单击表单上尚未绘制节点的某个位置,则意味着我单击了绘制节点的意图,如果它是一个节点,我必须选择它并记住它。在下一次鼠标点击时,如果我触摸一个尚未绘制节点的地方,这意味着我想绘制一个新节点,如果它是我点击的节点,我需要从第一个记忆的节点开始画线到选定的一个并添加道路成本详细信息。

当我点击表格时,我知道如何绘制代表图形节点的圆圈。我正在使用以下代码:

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

    }
}

我的问题是如何确定我是否在表单上的坐标 (x,y) 上绘制了一个节点,它是哪一个?我想将节点表示为按钮,具有标记或类似于节点号的东西(在图中,圣巴巴拉应该是 1,巴斯托应该是 2 等)

4

5 回答 5

4

一种方法是创建一个 UserControl 来表示(并绘制)您的圆圈,并在用户单击它时进行处理。然后,您可以让每个圆形对象确定它是否已被单击,而不是使用 X 和 Y 坐标来尝试确定用户单击的位置以及他们是否单击了一个圆圈。

于 2010-03-07T21:34:35.590 回答
4

扩展 Anders Abel 的答案:

  • 保留一个列表,存储有关每个节点的信息,包括
  • 中心点
  • 半径
  • 其他相关信息...

当您单击时确定是否命中了某个节点

  • 遍历所有节点
  • 使用勾股定理找到从点击点到节点中心的距离
  • 如果距离小于半径,则选择节点
  • 如果未选择节点,则在单击的位置添加一个新节点
于 2010-03-07T21:41:11.147 回答
2

恐怕您错过了 Windows UI 的基本预期模式。扔掉上面的代码并执行以下操作:

  1. 在内存中创建一个表示“文档”的数据结构(您需要跟踪有关图形、其节点和边的所有内容)。

  2. 在鼠标单击时,您不会绘制。您只需修改“文档”数据结构(如上所述)。另外,您调用 Invalidate() 将导致稍后重绘。

  3. 覆盖 OnPaint()。这就是您进行所有绘图的地方,绘制您存储的数据结构的可视化表示。

于 2010-03-08T06:12:17.780 回答
1

一个简单的方法是在绘制时将所有圆圈放入一个列表中。在鼠标单击处理程序中,您可以浏览列表并检查每个圆圈是否鼠标在圆圈内。

然而,从长远来看,这种方法不会扩大规模。如果你有很多圈子,你可能想研究空间搜索算法。

于 2010-03-07T21:02:22.470 回答
1

您还可以制作节点列表并检查节点中心到单击点之间的距离是否<=半径。

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;
}
于 2011-10-02T21:30:47.283 回答