如何在IMAGE图像中绘制可以指向任意方向的箭头呢?

shally5 2005-03-09 11:44:38
如何在IMAGE图像中绘制可以指向任意方向的箭头呢?
...全文
453 12 打赏 收藏 转发到动态 举报
写回复
用AI写文章
12 条回复
切换为时间正序
请发表友善的回复…
发表回复
JetKingLau 2005-03-10
  • 打赏
  • 举报
回复
参数中,dd 为风向,ff 为风力。
JetKingLau 2005-03-10
  • 打赏
  • 举报
回复

/
|/
|/
|
|


\_\_\_\_____


以下是在气象画风向风速的代码,结果类似上面,修改一下应该就可以了。

BTW:在气象中,北风为 0 度,东风为 90 度,南风为 180 度,西风为 270 度。


//---------------------------------------------------------------------------
void __fastcall Meteorology_PlotWind(TCanvas *Canvas,int x,int y,float dd, float ff)//风向风力填图
{
Meteorology_PlotWind(Canvas,x,y,dd,ff,24,8,4);
}
//---------------------------------------------------------------------------
void __fastcall Meteorology_PlotWind(TCanvas *Canvas,int x,int y,float dd, float ff,
int WindLen, int WindLine, int WindInterval )//风向风力填图
{
if( dd == 9999 || dd == 0 || ff == 9999 || ff == 0 ) return;
Canvas->Pen->Style = psSolid;
int i, j;
// int WindLen = 32; //风杆长度
// int WindLine = 10; //风标长度
// int WindInterval = 5; //风标间隔

float xPw, yPw, xPw1, yPw1;
float xD, yD, xP, yP;
xD = (dd >= 0 && dd <= 180 ) ? 1 : -1;
yD = (dd >= 90 && dd <= 270 ) ? 1 : -1;
xP = (dd >= 120 && dd <= 300 ) ? -1 : 1;
yP = (dd >= 30 && dd < 210 ) ? 1 : -1;
if( dd < 9999 && dd >= 0 )
{
dd = 90-dd;
while (dd > 360 ){
dd = (int)dd % 360;}
Canvas->MoveTo( x, y );
xPw = x + xD * WindLen * fabs(cos(PI*dd/180));
yPw = y + yD * WindLen * fabs(sin(PI*dd/180));
Canvas->LineTo( xPw, yPw );//画风杆
div_t iDiv;
iDiv = div( ff+1, 20 );
for( i=0;i<iDiv.quot;i++ )
{//风力大于20m/s则画三角符号
xPw = x + xD * (WindLen-i*WindInterval) * fabs(cos(PI*dd/180));
yPw = y + yD * (WindLen-i*WindInterval) * fabs(sin(PI*dd/180));
xPw1 = x + xD * (WindLen-(i+1)*WindInterval) * fabs(cos(PI*dd/180));
yPw1 = y + yD * (WindLen-(i+1)*WindInterval) * fabs(sin(PI*dd/180));
xPw1 = xPw1 + xP *WindLine*1.2*fabs(cos(PI*(60-dd)/180));
yPw1 = yPw1 + yP *WindLine*1.2*fabs(sin(PI*(60-dd)/180));
Canvas->MoveTo(xPw,yPw );
Canvas->LineTo(xPw1,yPw1 );
xPw = x + xD * (WindLen-(i+1)*WindInterval) * fabs(cos(PI*dd/180));
yPw = y + yD * (WindLen-(i+1)*WindInterval) * fabs(sin(PI*dd/180));
Canvas->LineTo(xPw,yPw );
}
j = iDiv.quot;
if( j > 0 ) j=j+1;
if( iDiv.rem != 0 ) iDiv.rem = iDiv.rem - 1;
iDiv = div( iDiv.rem, 4 );
for( i=0;i<iDiv.quot;i++ )
{
xPw = x + xD * (WindLen-(i+j)*WindInterval) * fabs(cos(PI*dd/180));
yPw = y + yD * (WindLen-(i+j)*WindInterval) * fabs(sin(PI*dd/180));
xPw1 = xPw + xP *WindLine*1.2*fabs(cos(PI*(60-dd)/180));
yPw1 = yPw + yP *WindLine*1.2*fabs(sin(PI*(60-dd)/180));
Canvas->MoveTo(xPw,yPw );
Canvas->LineTo(xPw1,yPw1 );
}
if( iDiv.rem >=3 )
{
xPw = x + xD * (WindLen-(i+j)*WindInterval) * fabs(cos(PI*dd/180));
yPw = y + yD * (WindLen-(i+j)*WindInterval) * fabs(sin(PI*dd/180));
xPw1 = xPw + xP *WindLine*1.2*fabs(cos(PI*(60-dd)/180));
yPw1 = yPw + yP *WindLine*1.2*fabs(sin(PI*(60-dd)/180));
Canvas->MoveTo(xPw,yPw );
Canvas->LineTo(xPw1,yPw1 );
}
if( j == 0 && iDiv.quot == 0 ) j = 1;
if( iDiv.rem >0 && iDiv.rem <=2 )
{
xPw = x + xD * (WindLen-(i+j)*WindInterval) * fabs(cos(PI*dd/180));
yPw = y + yD * (WindLen-(i+j)*WindInterval) * fabs(sin(PI*dd/180));
xPw1 = xPw + xP *WindLine/2*1.2*fabs(cos(PI*(60-dd)/180));
yPw1 = yPw + yP *WindLine/2*1.2*fabs(sin(PI*(60-dd)/180));
Canvas->MoveTo(xPw,yPw );
Canvas->LineTo(xPw1,yPw1 );
}
}
return;
}
//---------------------------------------------------------------------------
JetKingLau 2005-03-10
  • 打赏
  • 举报
回复
先顶顶,做个标记,明天再看看。
constantine 2005-03-10
  • 打赏
  • 举报
回复
路过
jishiping 2005-03-10
  • 打赏
  • 举报
回复
其实这个和BCB还是VC无关,纯粹是数学计算的问题。你看BCB编程的书也好,看VCBCB编程的书也好,没有哪个书会给你讲这个东西的。
jishiping 2005-03-10
  • 打赏
  • 举报
回复
其实很简单的啊,我来说说原理,代码就不写了。运用一下向量的旋转,一下子就计算出来了。
对于点(x0,y0)指向(x1,y1)的箭头线,以(x1,y1)为原点,先计算出(x1,y1)指向(x0,y0)的单位
向量,箭头线与直线的角度为d,那么就是将这个向量旋转角度d和-d,向量旋转的公式为:
(a+b*i)*(cos(d)+i*sin(d)) = a*cos(d)-b*sin(d) + i*(a*sin(d)+b*cos(d))
因为上面的向量以(x1,y1)为原点的单位向量,所以还需要乘以一个长度(箭头线的长度),然
后加上偏移就可以了。也就是画的箭头线的顶点的坐标为x=x1+L*(a*cos(d)-b*sin(d)), y=
y1+L*(a*sin(d)+b*cos(d))。另一个顶点的坐标,将上面的sin(d)换成 -sin(d) 就可以了。
上面公式中的a为(x0-x1)/L0, b为(y0-y1)/L0,L0是(x0,y0)与(x1,y1)的长度,L是箭头线的长
度(自己设定)。
jishiping 2005-03-10
  • 打赏
  • 举报
回复
严格一点的话,最好判断一下p0!=p1,否则的话,如果p0==p1,上面的L0为0,就会出错。
jishiping 2005-03-10
  • 打赏
  • 举报
回复
上面已经给出原理,公式也有了,代码还是写一下吧,很简单的:

#define PI 3.14159265

void DrawLineArrow(TCanvas* Canvas, TPoint p0, TPoint p1)
{
//对于点(x0,y0)指向(x1,y1)的箭头线,以(x1,y1)为原点,先计算出(x1,y1)
//指向(x0,y0)的单位向量,箭头线与直线的角度为d,那么就是将这个向量
//旋转角度d和-d,向量旋转的公式为:
//(a+b*i)*(cos(d)+i*sin(d)) = a*cos(d)-b*sin(d) + i*(a*sin(d)+b*cos(d))
//因为上面的向量以(x1,y1)为原点的单位向量,所以还需要乘以一个长度(
//箭头线的长度),然后加上偏移就可以了。也就是画的箭头线的顶点的坐标为
//x=x1+L*(a*cos(d)-b*sin(d)), y=y1+L*(a*sin(d)+b*cos(d))。
//另一个顶点的坐标,将上面的sin(d)换成 -sin(d) 就可以了。
//上面公式中的a为(x0-x1)/L0, b为(y0-y1)/L0,L0是(x0,y0)与(x1,y1)的长度,
//L是箭头线的长度(自己设定)。
float a, b, L0, L, d, x, y;

Canvas->MoveTo(p0.x, p0.y);
Canvas->LineTo(p1.x, p1.y); //画p0 到 p1 的直线

L0 = sqrt(pow(p0.x-p1.x,2)+pow(p0.y-p1.y,2)); //直线的长度
a = (p0.x-p1.x)/L0; b = (p0.y-p1.y)/L0; //单位向量的两个分量
L = 10.0; //箭头线长度,这儿我写成固定的,你可以自己修改或者计算
d = 30.0/180.0*PI; //箭头线与直线的角度30度,你可以自己调整
for(int n=0; n<2; n++) {
x = p1.x+L*(a*cos(d)-b*sin(n==0?d:-d));
y = p1.y+L*(a*sin(n==0?d:-d)+b*cos(d));
Canvas->MoveTo(p1.x, p1.y);
Canvas->LineTo(x, y); //画箭头线
}
}
h98458 2005-03-10
  • 打赏
  • 举报
回复
学习...
JetKingLau 2005-03-10
  • 打赏
  • 举报
回复
呵呵,偶很久以前写的代码,可读性还不是一般滴差!

脸红ing……
JetKingLau 2005-03-10
  • 打赏
  • 举报
回复
呵呵,偶很久以前写的代码,可读性还不是一般滴差!

脸红ing……
shally5 2005-03-10
  • 打赏
  • 举报
回复
JetKingLau(时差):也是搞气象的吗?

13,825

社区成员

发帖
与我相关
我的任务
社区描述
C++ Builder相关内容讨论区
社区管理员
  • 基础类社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

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