GDI+问题,对象怎么沿着指定的线移动?

yulitian 2005-07-03 02:09:30
弱弱地问一下

我现在从某些特殊的设备获取到某些对象的坐标,实时刷新。
在窗体中控制对象沿着由起点坐标到终点坐标连成的线条移动。

我写了这样的代码,其中速度参数是float型(以下是伪代码)

对象.Left += (终点.X-起点.X) / 速度参数
对象.Top += 终点.Y-起点.Y) / 速度参数

然后画线
起点到对象画红线,对象到终点画蓝线
可是,这两条线,并不能连成直线,而有了一个偏角.应该是做除法运算的时候造成的.大家有好的办法解决吗?

或者换一种方式,直接让对象在线条上的坐标中移动,这样可行吗?
...全文
200 11 打赏 收藏 转发到动态 举报
写回复
用AI写文章
11 条回复
切换为时间正序
请发表友善的回复…
发表回复
俞庆平 2005-07-04
  • 打赏
  • 举报
回复
对象.Left += (终点.X-起点.X) / 速度参数
对象.Top += 终点.Y-起点.Y) / 速度参数
肯定是不正确的。举个例子:
因为是斜线,所以长度并不是终点.Y-起点.Y简单就能解决的。
正解是:注意,里面有些算法没有时间帮你整理了。
using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Drawing.Drawing2D;
using System.Threading;
using System.Windows.Forms;
using System.Data;

namespace GDIPlus
{
/// <summary>
/// Form1 的摘要说明。
/// </summary>
public class Form1 : System.Windows.Forms.Form
{
private System.ComponentModel.IContainer components;

public Form1()
{
//
// Windows 窗体设计器支持所必需的
//
InitializeComponent();
Init();
this.timer1.Enabled = true;
//
// TODO: 在 InitializeComponent 调用后添加任何构造函数代码
//
}

/// <summary>
/// 清理所有正在使用的资源。
/// </summary>
protected override void Dispose( bool disposing )
{
if( disposing )
{
if (components != null)
{
components.Dispose();
}
}
base.Dispose( disposing );
}

#region Windows 窗体设计器生成的代码
/// <summary>
/// 设计器支持所需的方法 - 不要使用代码编辑器修改
/// 此方法的内容。
/// </summary>
private void InitializeComponent()
{
this.components = new System.ComponentModel.Container();
this.timer1 = new System.Windows.Forms.Timer(this.components);
//
// timer1
//
this.timer1.Enabled = false;
this.timer1.Tick += new System.EventHandler(this.timer1_Tick);
//
// Form1
//
this.AutoScaleBaseSize = new System.Drawing.Size(6, 14);
this.ClientSize = new System.Drawing.Size(576, 357);
this.Name = "Form1";
this.Text = "Form1";
this.Paint += new System.Windows.Forms.PaintEventHandler(this.Form1_Paint);

}
#endregion

/// <summary>
/// 应用程序的主入口点。
/// </summary>
[STAThread]
static void Main()
{
Application.Run(new Form1());
}

private System.Windows.Forms.Timer timer1;
MovingObject 对象;
Point 终点;
Point 起点;
double 斜率;
double 斜角;
double 速度;
double X速度;
double Y速度;
int 符号位;
bool 正向方向;//运行方向;true表示起点到终点,false表示终点到起点。

private void Init()
{
终点 = new Point(10,10);
起点 = new Point(300,300);
对象 = new MovingObject();
对象.CurrentPoint = 起点;
正向方向 = true;
ResetStatus();
}
private void ResetStatus()
{
速度 = 10.0f;
//每0.1秒移动1个像素的距离(注意不是X,和Y都移动一个像素)
if(终点.Y != 起点.Y)
{
斜率 = ((double)(终点.X-起点.X))/(终点.Y-起点.Y);
斜角 = Math.Atan(斜率);
符号位 = 斜率>0?1:-1;
//因为坐标系的关系,图像显示出来的斜率与计算的斜率并不一样。

X速度 = 速度*Math.Cos(斜角);//X方向的速度
Y速度 = 速度*Math.Sin(斜角);//Y方向的速度
}
else
{
Y速度 = 速度;
X速度 = 0.0f;
符号位 = 1;
}
}
private void Form1_Paint(object sender, System.Windows.Forms.PaintEventArgs e)
{
e.Graphics.DrawLine(Pens.Black,起点,终点);
}

private void timer1_Tick(object sender, System.EventArgs e)
{
Graphics g = this.CreateGraphics();
try
{
this.Invalidate(对象.OldRect);
this.Update();
对象.CurrentPoint = GetNewPoint();
g.FillEllipse(Brushes.Red,对象.Left,对象.Top,10,10);
}
finally
{
g.Dispose();
}
}

private PointF GetNewPoint()
{
PointF f = new PointF();
if(正向方向)//起点到终点
{
if(起点.X > 终点.X)
{
f.X = (float)(对象.Left-X速度*符号位);
}
else
{
f.X = (float)(对象.Left+X速度*符号位);
}
if(起点.Y > 终点.Y)
{
f.Y = (float)(对象.Top-Y速度*符号位);
}
else
{
f.Y = (float)(对象.Top+Y速度*符号位);
}
}
else
{
if(起点.X < 终点.X)
{
f.X = (float)(对象.Left-X速度*符号位);
}
else
{
f.X = (float)(对象.Left+X速度*符号位);
}
if(起点.Y < 终点.Y)
{
f.Y = (float)(对象.Top-Y速度*符号位);
}
else
{
f.Y = (float)(对象.Top+Y速度*符号位);
}
}


if(this.正向方向)
{
if(this.斜率 > 0)
{
if(对象.Top*符号位 < this.终点.Y*符号位) 正向方向 = !正向方向;
}
else
{
if(对象.Top*符号位 > this.终点.Y*符号位) 正向方向 = !正向方向;
}
}
else
{
if(this.斜率 > 0)
{
if(对象.Top*符号位 > this.起点.Y*符号位) 正向方向 = !正向方向;
}
else
{
if(对象.Top*符号位 < this.终点.Y*符号位) 正向方向 = !正向方向;
}

}
return f;
}
}

public class MovingObject
{
private PointF startPoint;
private PointF oldPoint;

public Rectangle OldRect
{
get
{
if(oldPoint == PointF.Empty) return new Rectangle(1,1,1,1);
Rectangle rect = new Rectangle((int)oldPoint.X,(int)oldPoint.Y,1,1);
rect.Inflate(10,10);
return rect;
}
}
public float Left
{
get
{
return (float)(startPoint.X);
}
}
public float Top
{
get
{
return (float)(startPoint.Y);
}
}
public PointF CurrentPoint
{
set
{
oldPoint = startPoint;
startPoint = value;
}
}
}
}
yulitian 2005-07-04
  • 打赏
  • 举报
回复
楼上的方法.......
还是没有很好的解决哦,该死的坐标,始终都要用int的,只要有除法运算,就一定会有偏移,晕晕啊,打算放弃了。
fsdy2000 2005-07-04
  • 打赏
  • 举报
回复
终点和起点有了,可以算出这条线的斜率和长度。那么对象.top/对象.Left=斜率。可以先根据速度参数得到对象.Top或对象.Left,再根据斜率求出另一个值即可。
itoltgvi 2005-07-04
  • 打赏
  • 举报
回复
帮你顶
cdo 2005-07-04
  • 打赏
  • 举报
回复
up
yulitian 2005-07-04
  • 打赏
  • 举报
回复
速度参数,我也尝试过使用Int类型,但是效果相同。

对象.Left += (终点.X-起点.X) / 速度参数
对象.Top += (终点.Y-起点.Y) / 速度参数

其中对象.Left 和对象.Top 都是int型的,所以后面是用了除法的地方就会造成误差。每次差一点,线条就会偏移很多很多了。

大家还有好办法吗?
jimh 2005-07-04
  • 打赏
  • 举报
回复
你的速度参数有问题,是怎么样计算出来的?按公式,应该是一个比例吧,0-1之间的比例,计算有偏差是正常的,不过一般情况下就一个象素,应该没问题。
yulitian 2005-07-04
  • 打赏
  • 举报
回复
Up
Up
yulitian 2005-07-03
  • 打赏
  • 举报
回复
How to?
seonxp 2005-07-03
  • 打赏
  • 举报
回复
对象的左上角定点坐标在浮点数累加过程中会产生较大的误差,偏离理论直线坐标,所以会产生偏角。要实现你所需要的过程很简单,不用累加过程计算坐标,而是计算每次的实际坐标,或者使用图形学的画线算法求点坐标,都可以的。
yulitian 2005-07-03
  • 打赏
  • 举报
回复

110,538

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • Web++
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

试试用AI创作助手写篇文章吧