怎样在检测单击在线段上。

zhwx 2000-04-01 05:02:00
我编一个图像处理程序,不知怎样在检测用户Mouse单击在线段上。
圆、矩形,多边形都可用PtInRegion检测。线段该如何?
线宽会改变。

...全文
341 13 打赏 收藏 转发到动态 举报
写回复
用AI写文章
13 条回复
切换为时间正序
请发表友善的回复…
发表回复
Un1 2000-04-07
  • 打赏
  • 举报
回复
给你一个程序片段研究研究:

Private Function IsNotInEither(typObject As typDraw, X As Single, Y As Single) As Boolean
Dim sngA As Single, sngB As Single, Ratio As Single, Ratio1 As Single
Dim sngX1 As Single, sngY1 As Single, sngX2 As Single, sngY2 As Single
Dim lngR As Single
Dim blnIsNotInEither As Boolean

With typObject
sngX1 = .X1 * sngMulripleEnlarge
sngY1 = .Y1 * sngMulripleEnlarge
Select Case .Shape
Case conTLine '当对象为线时
sngX2 = .X2 * sngMulripleEnlarge
sngY2 = .Y2 * sngMulripleEnlarge
If sngX2 = sngX1 Then '判断是否为垂直线
Ratio = .BorderWidth * conBorder * sngMulripleEnlarge + conLineWidth
If (Y >= sngY1 - Ratio And Y <= sngY2 + Ratio And X > sngX1 - Ratio And X < sngX1 + Ratio) Or _
(Y >= sngY2 - Ratio And Y <= sngY1 + Ratio And X > sngX1 - Ratio And X < sngX1 + Ratio) Then blnIsNotInEither = True
Else
sngA = (sngY1 - sngY2) / (sngX1 - sngX2)
sngB = sngY1 - sngA * sngX1
Ratio1 = Y - sngA * X
Ratio = .BorderWidth * conBorder * sngMulripleEnlarge + conLineWidth
Ratio = Ratio * Sqr(1 + sngA * sngA)
If Ratio1 < sngB + Ratio And Ratio1 > sngB - Ratio Then
Ratio = .BorderWidth * conBorder + conLineWidth
If ((Y >= sngY1 - Ratio And Y <= sngY2 + Ratio) Or (Y >= sngY2 - Ratio And Y <= sngY1 + Ratio)) _
And ((X > sngX1 - Ratio And X < sngX2 + Ratio) Or (X > sngX2 - Ratio And X < sngX1 + Ratio)) Then blnIsNotInEither = True
End If
End If
Case conTRectangle '当对象为矩形时
RiverHill 2000-04-06
  • 打赏
  • 举报
回复
由于GIS的信息海量,关于判断点是否在某个对象内,我们做程序时只能让CPU始终一直不停的Doing this Test,在我们的做法大致是这样的:
失量化的关键数据且比较小的全部读入内存,其他稍微较大的放在数据库中,当前屏幕逻辑坐标范围始终能计算出来,在相关的数据中皆有与屏幕对应的键值,这句话的意思说白了,将失量化图形划分为十几个区或几十个区,简化搜索范围。这样能提高效率!

RiverHill 2000-04-04
  • 打赏
  • 举报
回复
我在今天下午晚些时候,询问一些这方面的专家,你说的话有道理,我表示赞同。
关于用DC的path,我目前还未用到,相信过一段时间,随着工程进展,你提到的那些问题,我都得接触到。目前,我的GIS工程还正在缓步前进...
zhwx 2000-04-04
  • 打赏
  • 举报
回复
这样虽然可以,检测到,但不是很精确,当要用Mouse拖动
这个对象时,效果不是很好。圆、矩形就可以得到精确的区域
对象,从而可以很平滑地移动。
当绘图区对象很多时,计算量大。
如果是曲线,计算量就更大了。这样移动对象速度就很慢。
而VB不是很合适做浮点运算。所以我认为
如果能应用到Path就省事多了,可惜这方面资料很少。

我是做夭量绘图程序,绘图区可能会有很多的对象。

RiverHill 2000-04-04
  • 打赏
  • 举报
回复
你在图上画的线段,包括所有的其它图形,都必须有它自己的数据结构,不是随便拿几个变量颧常量数据,在屏幕上画一下就可以的.
例如,做GIS,就须要有几十类来管理各种图形的数据结构.

现成提供几个函数.以供检测范围.
//计算点(x1,y1)与点(x2,y2)间的距离
float CDraw::CalDisp(long x1, long y1, long x2, long y2)
{
return (float)sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2));
}

//作用:计算点(xx,yy)到线段(x1,y1)(x2,y2)的距离,返回计算的距离值

//函数PointRgn作用:判断一个点是否在任意多边形区域内
//参数:Numble-边界点数,x,y是点的坐标,多边形顶点的坐标在结构数组PointList中
//返回:1-点在多边形区域0-不在
float CDraw::PointLine(long xx, long yy, long x1, long y1, long x2, long y2)
{
float a, b, c, ang1, ang2, ang;
//计算三条边的距离
a=CalDisp(x1, y1, xx, yy); if(a == 0.0) return 0.0;
b=CalDisp(x2, y2, xx, yy); if(b == 0.0) return 0.0;
c=CalDisp(x1, y1, x2, y2);

//如果(x1,y1)和(x2,y2)是一个点直接返回距离
if(c==0.0) return a;
if(a<b) //如果(xx,yy)的点(x1,y1)这条边较短
{
if(y1==y2)
{
if(x1<x2)
ang1=0;
else
ang1=(float)pi;
}
else
{
ang1=(float)acos((x2-x1)/c);
if(y1>y2)ang1=(float)pi*2-ang1; //直线(x1,y1)-(x2,y2)的弧度
}
ang2=(float)acos((xx-x1)/a);
if(y1>yy)ang2=(float)pi*2-ang2; //直线(x1,y1)-(xx,yy)的弧度
ang=ang2-ang1;
if(ang<0)ang=-ang;
if(ang>pi) ang=(float)pi*2-ang; //交角的大小
if(ang>pi/2) return a; //如果为钝角,直接返回距离
else
return (a*(float)sin(ang)); //否则返回计算得到的距离
}
else //如果(xx,yy)的点(x2,y2)这条边较短
{
if(y1==y2)
{
if(x1<x2)
ang1=(float)pi;
else
ang1=0;
}
else
{
ang1=(float)acos((x1-x2)/c); //直线(x2,y2)-(x1,y1)的斜率的弧度
if(y2>y1)ang1=(float)pi*2-ang1;
}
ang2=(float)acos((xx-x2)/b); //直线(x2,x1)-(xx,yy)的斜率的弧度
if(y2>yy)ang2=(float)pi*2-ang2;
ang=ang2-ang1;
if(ang<0) ang=-ang;
if(ang>pi) ang=(float)pi*2-ang; //交角的大小 ?
if(ang>pi/2) return b; //如果为钝角,直接返回距离
else
return(b*(float)sin(ang)); //否则返回计算得到的距离
}
}
RiverHill 2000-04-04
  • 打赏
  • 举报
回复
其实,不管用什么语言实现,其基本思想是一样。
如果做绘图程序的话,你得自己操作失量图形数据。在检测范围时加上线段的宽度,就可以了。

举例:
1、线段有两个顶点,其坐标为point1(0, 0); point2(50, 100);
2、那么当前鼠标点的坐标(须经设置到逻辑转换)为pointX(x, y);
3、现在就可以求鼠标点坐标到线段间距离,检测是再加上线段的宽度。
就可以判断出来了。

我现在在做GIS,全部都是失量.
RiverHill 2000-04-04
  • 打赏
  • 举报
回复
顺便问一句,你做这些东东是做会么用的。是做绘图程序,还是做GIS,还是自己抽空学习一下?
RiverHill 2000-04-04
  • 打赏
  • 举报
回复
顺便问一句,你做这些东东是做什么用的。是做绘图程序,还是做GIS,还是自己抽空学习一下?
zhwx 2000-04-03
  • 打赏
  • 举报
回复
我不懂C,看不大懂,我觉得
这样太烦了。再说如果线宽不一样时怎么办?

我有想法:

BeginPath hdc
MovetoEx hdc,x,y
Lineto hdc,x2,y2
EndPath
r=PathToRegion(hdc)

路径转化务区域,再用PtInRegion,这样就非常简单了。对
任意复杂的折线,贝赛尔线也能检测到。

但我PathToRegion(hdc)虽然返回r<>0,
但还是无法检测到。
书上说路径中用的绘图函数全部用逻辑坐标,但我试过
,好象没起作用。问题可能也就出在这里。
RiverHill 2000-04-01
  • 打赏
  • 举报
回复
我现在正在做这种程序,其实这种并不难。不过,我是用VC++做的。
只是你给的分太低了,现在,我把详细设计告诉你。
具体思路:
1、从CObject派生出一个CDraw类来,CDraw类中具有的特征:
class CDraw:public CObject //基本图形类,用来存储图形的颜色、线型、层等信息
{
protected:
CDraw(){} //构造函数
short m_ColorPen; //笔色
short m_ColorBrush; //填充刷颜色
short m_LineWide; //线宽(像素)
short m_LineType; //线型(像素)
short m_Layer; //所处层
BOOL b_Delete; //是否处于删除状态
// DECLARE_SERIAL(CDraw); //串形化
public:
CDraw(short ColorPen,short ColorBrush,short LineWide,
short LineType,short Layer,BOOL Delete)
//构造函数
{
m_ColorPen=ColorPen;
m_ColorBrush=ColorBrush;
m_LineWide=LineWide;
m_LineType=LineType;
m_Layer=Layer;
b_Delete=Delete;
}
//计算点到直线的距离的函数
float PointLine(float xx,float yy,float x1,float y1,float x2,float y2);
//判断点是否在一个多边形区域中的函数
BOOL PointRgn(float x,float y,int Numble,PointStruct *PointList,float blc);
BOOL IsDelete(); //判断一个图形元素是否删除的函数
float CalDisp(float x1,float y1,float x2,float y2);//计算两点间的距离的函数
void Delete(BOOL Is); //删除或恢复删除图形元素的函数
//从一个文件中存储或读出图形坐标数据的函数
virtual void Save(CFile* file,BOOL Yn);
virtual void Serialize(CArchive& ar); //文档串形化函数
void toChar(char *p_Char);
char *toData(char *p_Char);
virtual void Draw(CDC *pDC,int m_DrawMode,int m_DrawMode1,short BackColor)=0;
}
;
2、从CDraw类中派出生直线类
class CLine:public CDraw //直线类
{
protected:
float m_X1,m_X2,m_Y1,m_Y2; //直线的起点和终点
DECLARE_SERIAL(CLine); //声明串形化

public:
CLine(){} //不带任何参数的构造函数
//以下是有初始化参数的构造函数
CLine(short ColorPen,short ColorBrush,
short LineWide,short LineType,short Layer,
BOOL Delete,float X1,float Y1,float X2,float Y2)
:CDraw(ColorPen,ColorBrush,LineWide,LineType,Layer,Delete)
{
m_X1=X1;
m_Y1=Y1;
m_X2=X2;
m_Y2=Y2;
}
//直线的绘制函数
virtual void Draw(CDC *pDC,int m_DrawMode,int m_DrawMode1,short BackColor);
//得到边界矩形的函数
void GetRect(float *minX,float *minY,float *maxX,float *maxY);
BOOL IsPoint(float x,float y,float jl); //判断是否被点选中的函数
virtual void Serialize(CArchive& ar); //串形化函数
//从剪裁板中读出或写入剪裁板的函数
void Save(CFile* file,BOOL Yn);
void toChar(char *p_Char);
char *toData(char *p_Char);
void Move(float x_Move,float y_Move);
};

3、从CDraw类中派生出连续直线或区域类
class CPline:public CDraw //连续直线或多边形区域类
{
protected:
int m_Numble; //连续直线或多边形区域的顶点数
BOOL b_Fill; //是否为连续直线
PointStruct* m_PointList; //存储顶点的数组指针
DECLARE_SERIAL(CPline); //声明串形化
;
public:
CPline() //不带任何参数的构造函数
{ m_Numble=0;}
CPline(short ColorPen,short ColorBrush,
short LineWide,short LineType,short Layer,
BOOL Delete,int Numble,PointStruct* PointList,BOOL Fill)
:CDraw(ColorPen,ColorBrush,LineWide,LineType,Layer,Delete)
{
m_Numble=Numble;
b_Fill=Fill;
m_PointList=new PointStruct[Numble]; //分配空间
if(Numble>0)
{
for(int i=0;i<Numble;i++)
m_PointList[i]=PointList[i];
}
}
~CPline() //析够函数
{
if(m_Numble>0)
delete m_PointList;
}
virtual void Draw(CDC *pDC,int m_DrawMode,int m_DrawMode1,short BackColor);
void GetRect(float *minX,float *minY,float *maxX,float *maxY);
BOOL IsPoint(float x,float y,float jl,float blc);
BOOL IsPLine();
void Save(CFile* file,BOOL Yn);
virtual void Serialize(CArchive& ar);
void toChar(char *p_Char);
char *toData(char *p_Char);
int GetNumb();
void Move(float x_Move,float y_Move);
};

//接着派生出
class CCircle:public CDraw //圆及圆形区域类
{
protected:
float m_CircleX,m_CircleY,m_CircleR; //圆心及半径
BOOL b_Fill; //是否填充 1-圆形区域 0-普通圆
DECLARE_SERIAL(CCircle);
public:
CCircle() //不带任何参数的构造函数
{}
CCircle(short ColorPen,short ColorBrush,
short LineWide,short LineType,short Layer,
BOOL Delete,float CircleX,float CircleY,float CircleR,BOOL Fill)
:CDraw(ColorPen,ColorBrush,LineWide,LineType,Layer,Delete)
{
m_CircleX=CircleX;
m_CircleY=CircleY;
m_CircleR=CircleR;
b_Fill=Fill;
}
virtual void Draw(CDC *pDC,int m_DrawMode,int m_DrawMode1,short BackColor);
void GetRect(float *minX,float *minY,float *maxX,float *maxY);
virtual IsPoint(float x,float y,float jl);
BOOL IsCircle();
virtual void Save(CFile* file,BOOL Yn);
virtual void Serialize(CArchive& ar);
void toChar(char *p_Char);
char *toData(char *p_Char);
void Move(float x_Move,float y_Move);
};

class CArc:public CCircle //圆弧类
{
protected:
float m_Angle1,m_Angle2; //圆弧的起点和终点角度
DECLARE_SERIAL(CArc);
public:
CArc() //不带任何参数的构造函数
{}
CArc(short ColorPen,short ColorBrush,short LineWide
,short LineType,short Layer,BOOL Delete,float CircleX
,float CircleY,float CircleR,BOOL Fill,float Angle1,float Angle2)
:CCircle(ColorPen,ColorBrush,LineWide,LineType,Layer,Delete,CircleX,
CircleY,CircleR,Fill)
{
m_Angle1=Angle1;
m_Angle2=Angle2;
}
virtual void Draw(CDC *pDC,int m_DrawMode,int m_DrawMode1,short BackColor);
void Init(short ColorPen,short ColorBrush,short LineWide,short LineType,short Layer,BOOL Delete,float CircleX,float CircleY,float CircleR,BOOL Fill,float Angle1,float Angle2);
void GetRect(float *minX,float *minY,float *maxX,float *maxY);
virtual BOOL IsPoint(float x,float y,float jl);
void Save(CFile* file,BOOL Yn);
virtual void Serialize(CArchive& ar);
void toChar(char *p_Char);
char *toData(char *p_Char);
};

class CText:public CDraw //标注文本类
{
protected:
float m_StartX; //文本起点横坐标
float m_StartY; //起点纵坐标
float m_Angle1; //标注角度
float m_Angle2; //字体旋转角度
float m_TextHeight; //字体高度
float m_TextWide; //字体宽度
float m_OffWide; //间隔宽度
unsigned char m_TextFont; //字体
CString c_Text; //标注的文本信息
int m_TextLong; //标注信息的长度
DECLARE_SERIAL(CText);
public:
CText() //不带任何参数的构造函数
{}
CText(short ColorPen,short ColorBrush,short LineWide
,short LineType,short Layer,BOOL Delete,float StartX,
float StartY,float Angle1,float Angle2,float TextHeight,float TextWide,
float OffWide,unsigned char TextFont,CString Text)
:CDraw(ColorPen,ColorBrush,LineWide,LineType,Layer,Delete)
{
m_StartX=StartX;
m_StartY=StartY;
m_Angle1=Angle1;
m_Angle2=Angle2;
m_TextHeight=TextHeight;
m_TextWide=TextWide;
m_OffWide=OffWide;
m_TextLong=Text.GetLength(); //计算字符的长度
c_Text=Text;
}
virtual void Draw(CDC *pDC,int m_DrawMode,int m_DrawMode1,short BackColor);
void Init(short ColorPen,short ColorBrush,short LineWide,short LineType,short Layer,float StartX,float StartY,float Angle1,float Angle2,float TextHeight,float TextWide,float OffWide,unsigned char TextFont,CString Text);
void GetRect(float *minX,float *minY,float *maxX,float *maxY);
BOOL IsPoint(float x,float y,float jl,float blc);
void Save(CFile* file,BOOL Yn);
virtual void Serialize(CArchive& ar);
void toChar(char *p_Char);
char *toData(char *p_Char);
int GetLong();
void Move(float x_Move,float y_Move);
};


2、实现类函数:
BOOL IsRectCross(float minx,float miny,float maxx,float maxy);

//检查矩形是否与屏幕矩形相交
BOOL IsRectCross(float minx,float miny,float maxx,float maxy)
{
if(minx>xMaxScreen and and maxx<xMinScreen and and miny>yMaxScreen and and maxy<yMinScreen) //两个矩形区域不相交
return 0; //如不相交函数返回0
else
return 1; //如果相交就返回1
}

//将实际坐标转换为逻辑坐标
void DPtoVP(float x,float y,int *X,int *Y)
{
p_View->DPtoVP(x,y,X,Y);
}

//将逻辑坐标转换为实际坐标
void VPtoDP(int x,int y,float *X,float *Y)
{
p_View->VPtoDP(x,y,X,Y);
}

//将实际距离转换成逻辑距离
int DLtoVL(float l)
{
return p_View->DLtoVL(l);
}

//将逻辑距离转变成实际距离
float VLtoDL(int l)
{
return p_View->VLtoDL(l);
}

第二、接下来:
需要在CDoc类中利用CTypeArrayPtr类将管理对象全部读入内存,

1、利用当前鼠标点坐标从设备坐标转换成逻辑坐标,在当前内存中的各种对象进行比较,比较函数我已经在上面写明了。

若你不好理解,可以给我发Email至RiverHill@263.net

另外,如果你有兴趣可参阅陈建春博士所著《Visual C++ 高级编程技术》一书 《电子工业出版社》出版。
major2 2000-04-01
  • 打赏
  • 举报
回复
在form_click事件里自己编程检验鼠标位置离开线段的距离
Chen_Lin 2000-04-01
  • 打赏
  • 举报
回复
自己编吧,反正我是自己编程实现的。
zdg 2000-04-01
  • 打赏
  • 举报
回复
需要自己写函数, 方法:
1)计算点到线段的垂直距离(中学课本上有公式)
2)判断距离<线宽???
开发背景随着时代的进步和科技的发展,计算机网络的发展日新月异,深刻的影响着我们的生活,受疫情的影响,为了方便教师和学生打印文件以及取文件,节约学生和老师等待时间,节约打印店的打印成本,提高打印店的打印效率,开发一款在线的打印系统是十分有必要的,校园在线打印预约系统把上传文件、选择打印店、打印支付、打印完成取文件以及管理功能集成一身,各管理人员分工合作、相互配合,及时完成打印任务。也方便打印店打印更方便更节约成本的打印文件以及节约学生的空闲时间。现阶段学校的打印文件模式都是传统的打印方式:学生需要跑到打印店拿QQ,微信,U盘给打印店的电脑上传文件,在等待别人打印完成后才能让打印店管理员打印文件,打印店管理员需要一个一个选择文件打印,在打印高峰期间,管理员打印文件忙不过来,不能给同学良好的打印服务,所以传统的打印文件方式不满足与当前社会的发展趋势。 开发目的利用现代计算机相关技术来进行在线打印预约,以减轻打印店工作人员的工作负担以及提高工作效率,减少学生打印等待时间。学生只需要上传需要打印的文件,然后选择打印店,选择支付以及去打印文件大概时间就可以,而打印店管理员只需要接收学生发的文件,以及打印,把打印的文件整理即可,可以根据学生取文件的时间自己编排打印文件的顺序,更好的利用时间,提高打印文件效率。 项目简介该项目是基于SpringBoot+SSM校园在线打印预约系统,包含两个角色:一个是用户模块,一个是打印店管理员模块。用户模块下面有个人中心模块,店铺选择模块,资料分享模块,资料分享模块,交易记录模块,使用帮助模块。在打印店管理员模块下有点单管理模块,店铺管理模块,价格管理模块。 项目运行截图下面从登录页面、用户界面和打印店管理页面三个部位来叙述全部系统。用户、商店和管理员都必须登录才可以浏览在线管理系统系统。管理员可以管理方法商店,但管理员可以是商店。用户登录输入校园在线打印预约系统的网址后,电脑浏览器将进到校园在线打印预约系统。会先进到系统的主页。用户可以先浏览系统首页,随后登录。用户注册如果登录者尚未注册,您需要注册一个帐户。单击右侧的注册按钮,将显示注册页面。用户需要填写用户名、电话号码、登录密码等信息。输入手机号码后,点击发送验证码,验证码就会发送到手机上。填写完毕后,点击注册按钮。添加后会跳转到登录页面。注册界面如图 短信验证码发送成功后,在线预约打印系统会弹出提示,此时用户的手机就会收到短信验证码。短信验证码发送成功界面如图进行账号注册。用户收到短信验证码如图 用户登录后的首页店铺详情个人中心      积分记录我的文件  文件共享管理员登录订单信息  订单详情店铺信息  价格设置 项目论文      

7,763

社区成员

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

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