这是一个非常基本的示例,用于测量在 winforms 中绘制到图像上的分段线。
它使用PictureBox 显示图像,使用Label 显示当前结果,为了更好地衡量,我添加了两个Buttons 清除所有点并撤消/删除最后一个。
我收集到List<Point> 中的像素位置:
List<Point> points = new List<Point>();
两个编辑按钮相当简单:
private void btn_Clear_Click(object sender, EventArgs e)
{
points.Clear();
pictureBox1.Invalidate();
show_Length();
}
private void btn_Undo_Click(object sender, EventArgs e)
{
if (points.Any())points.Remove(points.Last());
pictureBox1.Invalidate();
show_Length();
}
注意我是如何触发Paint事件的
其余的代码也很简单;我调用一个函数来计算和显示所有段长度的总和。请注意,我至少需要 两个 点才能执行此操作或显示第一行..
private void pictureBox1_MouseDown(object sender, MouseEventArgs e)
{
points.Add(e.Location);
pictureBox1.Invalidate();
show_Length();
}
private void pictureBox1_Paint(object sender, PaintEventArgs e)
{
if (points.Count > 1) e.Graphics.DrawLines(Pens.Red, points.ToArray());
}
void show_Length()
{
lbl_len.Text = (pointsF.Count) + " point(s), no segments. " ;
if (!(points.Count > 1)) return;
double len = 0;
for (int i = 1; i < points.Count; i++)
{
len += Math.Sqrt((points[i-1].X - points[i].X) * (points[i-1].X - points[i].X)
+ (points[i-1].Y - points[i].Y) * (points[i-1].Y - points[i].Y));
}
lbl_len.Text = (points.Count-1) + " segments, " + (int) len + " pixels";
}
一些注意事项:
图像显示时没有任何缩放。 PictureBox 有一个 SizeMode 属性,使缩放显示变得简单。在这种情况下,我建议不要存储鼠标的直接像素位置,而是存储“未缩放”值,并使用“重新缩放”的值列表进行显示。通过这种方式,您可以放大和缩小,并且仍然可以将点固定在正确的位置。
为此,您应该使用List<PointF> 来保持精度。
缩放时,例如通过扩大PictureBox,可能在将其嵌套在Panel 中之后,确保将纵横比保持等于Image 的纵横比或执行full calculation 以包括剩余空间或顶部;在SizeMode.Normal 中,图像将始终与 TopLeft 齐平,但在其他模式下,它并不总是如此。
对于实际距离的计算,即物理距离只需除以实际 dpi 值。
让我们看看我们的行动:
更新:
为了有机会创造更接近的拟合度和更好的精度,我们显然需要放大图像。
以下是必要的更改:
我们添加一个“浮点”列表:
List<PointF> pointsF = new List<PointF>();
并用它来存储未缩放的鼠标位置在鼠标向下:
pointsF.Add( scaled( e.Location, false));
我们将所有其他出现的points 替换为pointsF。
Paint 事件总是计算缩放点到当前缩放级别:
if (pointsF.Count > 1)
{
points = pointsF.Select(x => Point.Round(scaled(x, true))).ToList();
e.Graphics.DrawLines(Pens.Red, points.ToArray());
}
进行缩放的函数如下所示:
PointF scaled(PointF p, bool scaled)
{
float z = scaled ? 1f * zoom : 1f / zoom;
return new PointF(p.X * z, p.Y * z);
}
它使用一个类级别变量float zoom = 1f;,该变量在轨迹栏的Scroll 事件中与图片框的Clientsize 一起设置:
private void trackBar1_Scroll(object sender, EventArgs e)
{
List<float> zooms = new List<float>()
{ 0.1f, 0.2f, 0.5f, 0.75f, 1f, 2, 3, 4, 6, 8, 10};
zoom = zooms[trackBar1.Value];
int w = (int)(pictureBox2.Image.Width * zoom);
int h = (int)(pictureBox2.Image.Height * zoom);
pictureBox2.ClientSize = new Size(w, h);
lbl_zoom.Text = "zoom: " + (zoom*100).ToString("0.0");
}
图片框嵌套在Panel 中,AutoScroll 开启。现在我们可以在添加片段的同时进行缩放和滚动: