使用缩放网格移动点(列表中的点)
Moving points with scaling grid (points in list)
我正在为我的学校作业做一些例子。
现在我卡在了一点。我会尽量包含尽可能少的代码,但我不确定你们都需要什么..
(抱歉在我的母语中加入了名字和评论)
这是我需要做的:
我得到了我的 "painting program" ,您可以在其中通过单击添加点,然后相互绘制线条。我编写了一个网格,当您选中一个复选框时,它会在 rastr(grid)list 中寻找最接近的可能点,然后将其坐标应用于您尝试用鼠标绘制的点。
您还可以按轨迹栏值缩放该网格。
现在我的问题来了:我需要在缩放网格时移动我绘制的点。我不知道,因为我不能简单地为 grid.X = p.X + trackbarValue 中的每个点做。 (出现错误)
这是我的网格和绘画代码:
List<Point> rastr = new List<Point>(); //rastr means grid
List<Point> body = new List<Point>(); //painting poits
private void panel1_Paint(object sender, PaintEventArgs e)
{
Graphics kp = e.Graphics;
foreach (Point p in body)
{
kp.FillEllipse(st, p.X-s/2, p.Y-s/2, s, s);
}
//double buffer nezapomenout
if (body.Count>1)
{
kp.DrawLines(pero, body.ToArray());//to array prevedeni na pole
}
for (int x = 0; x < panel1.Width; x += trackBarGrid.Value)
for (int y = 0; y < panel1.Height; y += trackBarGrid.Value)
{
if (showGrid == true)
{
kp.FillEllipse(grid, x-2, y-2, 4, 4);
}
Point gridpoint = new Point(x,y);
rastr.Add(gridpoint);
}
}
这里是在网格中寻找最近的一个然后应用坐标:
private void panel1_MouseClick(object sender, MouseEventArgs e)
{
if (useGrid == true)
{
//rozjedu cykly abych nasel nejblizsi bod (porovnavat jednotlivy koordinace)
foreach (Point p in rastr)
{
if (e.Location.X - p.X < trackBarGrid.Value / 2) //kdyz odecteme pozici bodu v listu rastr.x od pozice x kliknuti nesmi byt vetsi nez polovina delky odsazeni rastrovych bodu
if (e.Location.Y - p.Y < trackBarGrid.Value / 2) // to same jen s pozici Y
{
Point zapsat = new Point(p.X, p.Y);
body.Add(zapsat); //od tyhle pozice najit nejblizsi point v gridu
break;//bod jsme uspesne nasli. Nyni musime cyklus uzavrit aby se nezacli pridavat body ktere nechceme
}
}
panel1.Refresh();
}
else {
body.Add(e.Location);
panel1.Refresh();
}
}
还有我的轨迹栏事件:
private void trackBarGrid_Scroll(object sender, EventArgs e)
{
rastr.Clear();
panel1.Refresh();
}
我在这方面的尝试很糟糕
private void trackBarGrid_Scroll(object sender, EventArgs e)
{
foreach (Point p in rastr)
{
p.X += TrackBarValue;
p.Y += TrackBarValue;
}
panel1.Refresh();
}
最后一点,我不需要保留那幅 "freehand" 画。我可以只使用那个网格。
这是一些照片..
我以某种方式设法将这些点从列表中取出,然后编辑它们并将它们放回原处。所以正如你所说,我只需要找出那些比例因子。它已经在移动但没有与网格对应。我说我对我的英语感到抱歉,所以你看我不可能再更正它了 :D 抱歉......我出去了你没有帮助我;((只是笑了一下那个专业档案笔记)
有些人 post 这里的问题甚至比这个更糟糕 :D 无论如何,thx 又有点自己解决了。
只是那个倍增的东西:)
private void trackBarGrid_Scroll(object sender, EventArgs e)
{
if (trackBarGrid.Value > trackbarval)
{
for (int i = 0; i < body.Count; i++)
{
Point point = body[i];
point.X += trackBarGrid.Value - trackbarval;
point.Y += trackBarGrid.Value - trackbarval;
body[i] = point;
}
}
else if (trackBarGrid.Value < trackbarval)
{
for (int i = 0; i < body.Count; i++)
{
Point point = body[i];
point.X -= trackbarval- trackBarGrid.Value;
point.Y -= trackbarval- trackBarGrid.Value ;
body[i] = point;
}
}
rastr.Clear();
panel1.Refresh();
trackbarval = trackBarGrid.Value;
}
您可以选择两种缩放图形的方式。一个非常简单,另一个有点复杂。
这是最简单的:
只需将此添加到 Paint
事件的顶部:
float scale = trackBar1.Value / 100f;
if (scale == 0) scale = 1;
e.Graphics.ScaleTransform(scale, scale);
这看起来有点复杂,但是当 Paint
事件最初被调用时,TrackBar
将没有值。
Graphics
对象本身现在已缩放,您绘制的所有内容 都将被缩放。
那真的很简单。
您可能遇到的一个可能问题是所有内容,包括 Pen
的宽度都会按比例放大或缩小。
你的问题想用更复杂的方式,所以让我们也这样做吧..:[=42=]
首先我们创建一个函数,根据 TrackBar
的 Value
缩放一个点。这是:
PointF scaledPoint(PointF pt, float scale, bool unscale)
{
if (unscale) return new PointF(pt.X / scale, pt.Y / scale);
else return new PointF( pt.X * scale, (pt.Y * scale));
}
有两点值得注意:
该函数实际上适用于 PointF
而不是 Point
。这非常重要,因为缩放不能丢失 精度!从 5 下降到 33% 然后再次备份不会回到 5 而是 3..!
有一个额外的参数可以移除点的缩放比例。我们暂时不需要它;但是你会的,一旦你想在缩放打开时从 MouseClick
捕捉到一个点!
现在让我们用它来缩放我们的点列表。
我们可以直接做,可能是这样的:
for (int p = 0; p < body.Count; p++)
body[p] = scaledPoint(body[p], scale, false);
虽然这会起作用,但有一个 讨厌的 问题:当我们移动 TrackBar
时,它将 reapetedly 应用 增长 比例因子。这意味着图形会越来越大越来越快..不好。
相反,我们使用原始点值创建第二个 List<PointF> bodyO
,需要保持..
这意味着我们向 bodyO
添加点,但使用 body
绘制并将 bodyO
缩放到 body..:[=42=]
void scalePoints(float scale)
{
for (int p = 0; p < body.Count; p++)
body[p] = scaledPoint(body0[p], scale, false);
}
我们在您的代码中几乎调用了:
private void trackBar1_Scroll(object sender, EventArgs e)
{
scalePoints(trackBar1.Value / 100f);
panel1.Refresh();
}
让我们看看这在 Paint
事件中是如何工作的:
private void panel1_Paint(object sender, PaintEventArgs e)
{
float scale = trackBar1.Value / 100f;
if (scale == 0) scale = 1;
bool showGrid = true; // inserted for testing
// these graphics work with the scaled points:
foreach (PointF pt in body) e.Graphics.FillEllipse(Brushes.Red,
pt.X - 2, pt.Y - 2, scale * 4, scale * 4);
if (body.Count > 1) e.Graphics.DrawLines(Pens.Black, body.ToArray());
// here we don't use points but calculate the coordinates, so we need to scale
for (int x = 0; x < panel1.Width; x += trackBar2.Value)
for (int y = 0; y < panel1.Height; y += trackBar2.Value)
{
if (showGrid == true)
{
e.Graphics.FillEllipse(Brushes.Gray,
scale * (x - 2), scale * (y - 2), scale * 4, scale * 4);
}
// Point gridpoint = new Point(x, y); // not sure what you do here..?
// rastr.Add(gridpoint); // maybe add the point scaled?
}
}
请注意,我也缩放了点的大小。顺便说一句,要使两个版本看起来完全相同,您还必须缩放 Pen
:
using (Pen pen = new Pen(somecolor, penWidth * scale))
最后是在鼠标点击中添加新点的方法:
private void panel1_MouseClick(object sender, MouseEventArgs e)
{
body0.Add(scaledPoint(e.Location, trackBar1.Value / 100f, true));
body.Add(e.Location);
panel1.Invalidate();
}
我们将其添加到原始列表 bodyO
中,按原样反转当前缩放比例,即将当前 'pixel size' 添加到缩放列表中..
顺便说一句:如果没有DoubleBuffering
,很多网格点需要一些时间;这会产生一些闪烁。所以要么使用 Panel
子类 和 DoubleBuffering
:
class DrawPanel : Panel
{
public DrawPanel()
{ DoubleBuffered = true; }
}
或者选择 Picturebox
(推荐)!
我正在为我的学校作业做一些例子。
现在我卡在了一点。我会尽量包含尽可能少的代码,但我不确定你们都需要什么..
(抱歉在我的母语中加入了名字和评论)
这是我需要做的: 我得到了我的 "painting program" ,您可以在其中通过单击添加点,然后相互绘制线条。我编写了一个网格,当您选中一个复选框时,它会在 rastr(grid)list 中寻找最接近的可能点,然后将其坐标应用于您尝试用鼠标绘制的点。
您还可以按轨迹栏值缩放该网格。
现在我的问题来了:我需要在缩放网格时移动我绘制的点。我不知道,因为我不能简单地为 grid.X = p.X + trackbarValue 中的每个点做。 (出现错误)
这是我的网格和绘画代码:
List<Point> rastr = new List<Point>(); //rastr means grid
List<Point> body = new List<Point>(); //painting poits
private void panel1_Paint(object sender, PaintEventArgs e)
{
Graphics kp = e.Graphics;
foreach (Point p in body)
{
kp.FillEllipse(st, p.X-s/2, p.Y-s/2, s, s);
}
//double buffer nezapomenout
if (body.Count>1)
{
kp.DrawLines(pero, body.ToArray());//to array prevedeni na pole
}
for (int x = 0; x < panel1.Width; x += trackBarGrid.Value)
for (int y = 0; y < panel1.Height; y += trackBarGrid.Value)
{
if (showGrid == true)
{
kp.FillEllipse(grid, x-2, y-2, 4, 4);
}
Point gridpoint = new Point(x,y);
rastr.Add(gridpoint);
}
}
这里是在网格中寻找最近的一个然后应用坐标:
private void panel1_MouseClick(object sender, MouseEventArgs e)
{
if (useGrid == true)
{
//rozjedu cykly abych nasel nejblizsi bod (porovnavat jednotlivy koordinace)
foreach (Point p in rastr)
{
if (e.Location.X - p.X < trackBarGrid.Value / 2) //kdyz odecteme pozici bodu v listu rastr.x od pozice x kliknuti nesmi byt vetsi nez polovina delky odsazeni rastrovych bodu
if (e.Location.Y - p.Y < trackBarGrid.Value / 2) // to same jen s pozici Y
{
Point zapsat = new Point(p.X, p.Y);
body.Add(zapsat); //od tyhle pozice najit nejblizsi point v gridu
break;//bod jsme uspesne nasli. Nyni musime cyklus uzavrit aby se nezacli pridavat body ktere nechceme
}
}
panel1.Refresh();
}
else {
body.Add(e.Location);
panel1.Refresh();
}
}
还有我的轨迹栏事件:
private void trackBarGrid_Scroll(object sender, EventArgs e)
{
rastr.Clear();
panel1.Refresh();
}
我在这方面的尝试很糟糕
private void trackBarGrid_Scroll(object sender, EventArgs e)
{
foreach (Point p in rastr)
{
p.X += TrackBarValue;
p.Y += TrackBarValue;
}
panel1.Refresh();
}
最后一点,我不需要保留那幅 "freehand" 画。我可以只使用那个网格。
这是一些照片..
我以某种方式设法将这些点从列表中取出,然后编辑它们并将它们放回原处。所以正如你所说,我只需要找出那些比例因子。它已经在移动但没有与网格对应。我说我对我的英语感到抱歉,所以你看我不可能再更正它了 :D 抱歉......我出去了你没有帮助我;((只是笑了一下那个专业档案笔记) 有些人 post 这里的问题甚至比这个更糟糕 :D 无论如何,thx 又有点自己解决了。 只是那个倍增的东西:)
private void trackBarGrid_Scroll(object sender, EventArgs e)
{
if (trackBarGrid.Value > trackbarval)
{
for (int i = 0; i < body.Count; i++)
{
Point point = body[i];
point.X += trackBarGrid.Value - trackbarval;
point.Y += trackBarGrid.Value - trackbarval;
body[i] = point;
}
}
else if (trackBarGrid.Value < trackbarval)
{
for (int i = 0; i < body.Count; i++)
{
Point point = body[i];
point.X -= trackbarval- trackBarGrid.Value;
point.Y -= trackbarval- trackBarGrid.Value ;
body[i] = point;
}
}
rastr.Clear();
panel1.Refresh();
trackbarval = trackBarGrid.Value;
}
您可以选择两种缩放图形的方式。一个非常简单,另一个有点复杂。
这是最简单的:
只需将此添加到 Paint
事件的顶部:
float scale = trackBar1.Value / 100f;
if (scale == 0) scale = 1;
e.Graphics.ScaleTransform(scale, scale);
这看起来有点复杂,但是当 Paint
事件最初被调用时,TrackBar
将没有值。
Graphics
对象本身现在已缩放,您绘制的所有内容 都将被缩放。
那真的很简单。
您可能遇到的一个可能问题是所有内容,包括 Pen
的宽度都会按比例放大或缩小。
你的问题想用更复杂的方式,所以让我们也这样做吧..:[=42=]
首先我们创建一个函数,根据 TrackBar
的 Value
缩放一个点。这是:
PointF scaledPoint(PointF pt, float scale, bool unscale)
{
if (unscale) return new PointF(pt.X / scale, pt.Y / scale);
else return new PointF( pt.X * scale, (pt.Y * scale));
}
有两点值得注意:
该函数实际上适用于
PointF
而不是Point
。这非常重要,因为缩放不能丢失 精度!从 5 下降到 33% 然后再次备份不会回到 5 而是 3..!有一个额外的参数可以移除点的缩放比例。我们暂时不需要它;但是你会的,一旦你想在缩放打开时从
MouseClick
捕捉到一个点!
现在让我们用它来缩放我们的点列表。
我们可以直接做,可能是这样的:
for (int p = 0; p < body.Count; p++)
body[p] = scaledPoint(body[p], scale, false);
虽然这会起作用,但有一个 讨厌的 问题:当我们移动 TrackBar
时,它将 reapetedly 应用 增长 比例因子。这意味着图形会越来越大越来越快..不好。
相反,我们使用原始点值创建第二个 List<PointF> bodyO
,需要保持..
这意味着我们向 bodyO
添加点,但使用 body
绘制并将 bodyO
缩放到 body..:[=42=]
void scalePoints(float scale)
{
for (int p = 0; p < body.Count; p++)
body[p] = scaledPoint(body0[p], scale, false);
}
我们在您的代码中几乎调用了:
private void trackBar1_Scroll(object sender, EventArgs e)
{
scalePoints(trackBar1.Value / 100f);
panel1.Refresh();
}
让我们看看这在 Paint
事件中是如何工作的:
private void panel1_Paint(object sender, PaintEventArgs e)
{
float scale = trackBar1.Value / 100f;
if (scale == 0) scale = 1;
bool showGrid = true; // inserted for testing
// these graphics work with the scaled points:
foreach (PointF pt in body) e.Graphics.FillEllipse(Brushes.Red,
pt.X - 2, pt.Y - 2, scale * 4, scale * 4);
if (body.Count > 1) e.Graphics.DrawLines(Pens.Black, body.ToArray());
// here we don't use points but calculate the coordinates, so we need to scale
for (int x = 0; x < panel1.Width; x += trackBar2.Value)
for (int y = 0; y < panel1.Height; y += trackBar2.Value)
{
if (showGrid == true)
{
e.Graphics.FillEllipse(Brushes.Gray,
scale * (x - 2), scale * (y - 2), scale * 4, scale * 4);
}
// Point gridpoint = new Point(x, y); // not sure what you do here..?
// rastr.Add(gridpoint); // maybe add the point scaled?
}
}
请注意,我也缩放了点的大小。顺便说一句,要使两个版本看起来完全相同,您还必须缩放 Pen
:
using (Pen pen = new Pen(somecolor, penWidth * scale))
最后是在鼠标点击中添加新点的方法:
private void panel1_MouseClick(object sender, MouseEventArgs e)
{
body0.Add(scaledPoint(e.Location, trackBar1.Value / 100f, true));
body.Add(e.Location);
panel1.Invalidate();
}
我们将其添加到原始列表 bodyO
中,按原样反转当前缩放比例,即将当前 'pixel size' 添加到缩放列表中..
顺便说一句:如果没有DoubleBuffering
,很多网格点需要一些时间;这会产生一些闪烁。所以要么使用 Panel
子类 和 DoubleBuffering
:
class DrawPanel : Panel
{
public DrawPanel()
{ DoubleBuffered = true; }
}
或者选择 Picturebox
(推荐)!