让用户在C#中绘制多边形、移动它们并向它们添加点

发布于:2024-12-18 ⋅ 阅读:(127) ⋅ 点赞:(0)

 

此示例添加了向多边形添加新点的功能。如果将鼠标移到多边形的边缘上,程序会将其光标更改为“添加点”光标(带有加号的小框)。如果您单击,程序会在该位置向多边形添加一个新点。

添加新点需要进行三个主要更改:检测鼠标何时位于多边形的边缘上、显示“添加点”光标以及添加新点。

在设计时,我添加了一个包含“添加点”光标的资源,该资源是位图图像。程序启动时,它使用以下代码使用该图像创建“添加点”光标。

程序使用MouseDownMouseMoveMouseUp事件处理程序让用户绘制多边形并与之交互。您可以编写三个复杂的事件处理程序来处理每种情况。例如,MouseMove事件处理程序将根据用户是否处于以下状态采取不同的操作:

  • 绘制新多边形
  • 移动多边形
  • 移动多边形的顶点
// Each polygon is represented by a List.
private List<List<Point>> Polygons = new List<List<Point>>();
// Points for the new polygon.
private List<Point> NewPolygon = null;

// The current mouse position while drawing a new polygon.
private Point NewPoint;
// Start or continue drawing a new polygon.
private void picCanvas_MouseDown(object sender, MouseEventArgs e)
{
    // See if we are already drawing a polygon.
    if (NewPolygon != null)
    {
        // We are already drawing a polygon.
        // If it's the right mouse button, finish this polygon.
        if (e.Button == MouseButtons.Right)
        {
            // Finish this polygon.
            if (NewPolygon.Count > 2) Polygons.Add(NewPolygon);
            NewPolygon = null;
        }
        else
        {
            // Add a point to this polygon.
            if (NewPolygon[NewPolygon.Count - 1] != e.Location)
            {
                NewPolygon.Add(e.Location);
            }
        }
    }
    else
    {
        // Start a new polygon.
        NewPolygon = new List<Point>();
        NewPoint = e.Location;
        NewPolygon.Add(e.Location);
    }

    // Redraw.
    picCanvas.Invalidate();
}

// Move the next point in the new polygon.
private void picCanvas_MouseMove(object sender, MouseEventArgs e)
{
    if (NewPolygon == null) return;
    NewPoint = e.Location;
    picCanvas.Invalidate();
}
// Redraw old polygons in blue. Draw the new polygon in green.
// Draw the final segment dashed.
private void picCanvas_Paint(object sender, PaintEventArgs e)
{
    e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
    e.Graphics.Clear(picCanvas.BackColor);

    // Draw the old polygons.
    foreach (List<Point> polygon in Polygons)
    {
        e.Graphics.FillPolygon(Brushes.White, polygon.ToArray());
        e.Graphics.DrawPolygon(Pens.Blue, polygon.ToArray());
    }

    // Draw the new polygon.
    if (NewPolygon != null)
    {
        // Draw the new polygon.
        if (NewPolygon.Count > 1)
        {
            e.Graphics.DrawLines(Pens.Green, NewPolygon.ToArray());
        }

        // Draw the newest edge.
        if (NewPolygon.Count > 0)
        {
            using (Pen dashed_pen = new Pen(Color.Green))
            {
                dashed_pen.DashPattern = new float[] { 3, 3 };
                e.Graphics.DrawLine(dashed_pen, 
                    NewPolygon[NewPolygon.Count - 1],
                    NewPoint);
            }
        }
    }
}

允许用户绘制和移动多边形并将其捕捉到网格中。

此方法获取Point的 X 和 Y 坐标,将其四舍五入为最接近GridGap的倍数,并返回具有四舍五入坐标的 新Point 。

// The grid spacing.
private const int GridGap = 8;

// Snap to the nearest grid point.
private Point SnapToGrid(Point point)
{
    int x = GridGap * (int)Math.Round((float)point.X / GridGap);
    int y = GridGap * (int)Math.Round((float)point.Y / GridGap);
    return new Point(x, y);
}

程序在处理点时都会调用SnapToGrid方法。例如,以下代码显示了在鼠标移动且没有进行绘制或移动操作时执行的 MouseDown事件处理程序。

// See if we're over a polygon or corner point.
private void picCanvas_MouseMove_NotDrawing(
    object sender, MouseEventArgs e)
{
    Cursor new_cursor = Cursors.Cross;

    // See what we're over.
    Point mouse_pt = SnapToGrid(e.Location);
    List<Point> hit_polygon;
    int hit_point, hit_point2;
    Point closest_point;

    if (MouseIsOverCornerPoint(mouse_pt,
        out hit_polygon, out hit_point))
    {
        new_cursor = Cursors.Arrow;
    }
    else if (MouseIsOverEdge(mouse_pt, out hit_polygon,
        out hit_point, out hit_point2, out closest_point))
    {
        new_cursor = AddPointCursor;
    }
    else if (MouseIsOverPolygon(mouse_pt, out hit_polygon))
    {
        new_cursor = Cursors.Hand;
    }

    // Set the new cursor.
    if (picCanvas.Cursor != new_cursor)
    {
        picCanvas.Cursor = new_cursor;
    }
}

首先,此代码将鼠标的当前位置传递给SnapToGrid方法。然后,它使用MouseIdOverCornerPointMouseIsOverEdgeMouseIsOverPolygon方法来查看鼠标是否位于多边形的一部分上。然后,它显示相应的光标:如果鼠标位于多边形的角上,则显示箭头;如果鼠标位于边上,则显示“添加点”光标;如果鼠标位于多边形的主体上,则显示手形光标

该示例的其他方法类似地将鼠标位置与网格位置对齐。例如,当您在多边形上按下鼠标时,程序会存储鼠标位置(未对齐到网格)与多边形原点之间的偏移量。然后,当您移动鼠标拖动多边形时,将执行以下代码。

// Move the selected polygon.
private void picCanvas_MouseMove_MovingPolygon(
    object sender, MouseEventArgs e)
{
    // See how far the first point will move.
    int new_x1 = e.X + OffsetX;
    int new_y1 = e.Y + OffsetY;

    int dx = new_x1 - MovingPolygon[0].X;
    int dy = new_y1 - MovingPolygon[0].Y;

    // Snap the movement to a multiple of the grid distance.
    dx = GridGap * (int)(Math.Round((float)dx / GridGap));
    dy = GridGap * (int)(Math.Round((float)dy / GridGap));

    if (dx == 0 && dy == 0) return;

    // Move the polygon.
    for (int i = 0; i < MovingPolygon.Count; i++)
    {
        MovingPolygon[i] = new Point(
            MovingPolygon[i].X + dx,
            MovingPolygon[i].Y + dy);
    }

    // Redraw.
    picCanvas.Invalidate();
}

此代码计算多边形应移动的 距离dxdy 。然后,它将这些值四舍五入为最接近的GridGap倍数,并将多边形的点移动四舍五入后的距离。最后,它使 PictureBox 无效,在新位置重新绘制多边形。


网站公告

今日签到

点亮在社区的每一天
去签到