C++调用gnuplot的技术需求:Windows终端后台运行、splot下鼠标点击坐标获取及交互控制实现
C++调用gnuplot的技术需求:Windows终端后台运行、splot下鼠标点击坐标获取及交互控制实现
嗨,刚好我之前做过类似的C++和gnuplot交互的项目,碰到过一模一样的鼠标坐标问题,给你一步步拆解解决方法:
首先说你最头疼的splot下鼠标坐标超出0-1的问题——这完全是因为你混淆了2D plot和3D splot的坐标逻辑!gnuplot帮助里的那个归一化公式是给2D绘图用的,针对的是数据坐标系的范围,但splot模式下,MOUSE_X和MOUSE_Y直接返回的是窗口像素坐标,和数据坐标系半毛钱关系都没有,所以用GPVAL_X_MIN之类的变量肯定会算出奇怪的结果。
一、正确获取splot下的归一化屏幕坐标
解决方法很简单,用gnuplot提供的终端像素尺寸变量GPVAL_TERM_XMAX(窗口宽度,像素)和GPVAL_TERM_YMAX(窗口高度,像素)来归一化:
# 以窗口左上角为原点的归一化坐标(范围0-1) norm_screen_x = MOUSE_X / GPVAL_TERM_XMAX norm_screen_y = MOUSE_Y / GPVAL_TERM_YMAX # 如果习惯以窗口左下角为原点,就把Y轴反转一下 norm_screen_y_bottom = (GPVAL_TERM_YMAX - MOUSE_Y) / GPVAL_TERM_YMAX
你可以在gnuplot里直接测试:点击窗口的四个角落,输出这几个变量,应该能得到0或者1的结果,这样就对了。
二、实现点击交互控制C++程序
你现在是用单向管道给gnuplot喂数据,要实现反向控制,得想办法让gnuplot把点击事件传给C++,这里给你两个实用方案:
方案1:临时文件中转(简单易上手)
这个方案不用改太多代码,适合快速验证:
- 在给gnuplot的初始化命令里加上鼠标绑定:
set mouse on # 绑定左键点击,把坐标和窗口尺寸写入临时文件 bind mouse1 "set print 'click_temp.txt'; print MOUSE_X, MOUSE_Y, GPVAL_TERM_XMAX, GPVAL_TERM_YMAX; set print"
- 你的C++程序在每次绘图间隔(比如1秒)的时候,去检查这个临时文件:
- 看看文件的修改时间有没有更新,避免重复处理同一点击
- 读取文件里的四个数值,用刚才的公式算出归一化坐标
- 预设几个按钮区域,比如右上角10%的区域是“停止”按钮,判断坐标是否在这个区域里,如果是就触发C++里的停止逻辑
- 处理完后可以清空文件,或者把文件重命名标记为已处理
方案2:命名管道双向通信(更高效)
如果觉得临时文件太麻烦,可以用Windows的命名管道实现双向通信,这样gnuplot能直接把点击事件发给C++:
- C++端用
CreateNamedPipe创建一个命名管道(具体参数可以查MSDN,设置成字节流模式就行) - gnuplot里的鼠标绑定改成输出到命名管道,注意路径里的反斜杠要转义:
bind mouse1 "set print '\\\\.\\pipe\\gnuplot_click_pipe'; print MOUSE_X, MOUSE_Y, GPVAL_TERM_XMAX, GPVAL_TERM_YMAX; set print"
- C++端监听管道的输入,一旦有数据就读取、处理坐标逻辑就行
三、Windows终端后台运行的小技巧
如果不想让C++的控制台窗口一直挡着,或者想让gnuplot窗口独立显示:
- 如果你用的是控制台程序,在C++代码开头加上
ShowWindow(GetConsoleWindow(), SW_HIDE);,就能把控制台窗口隐藏,只留gnuplot的绘图窗口 - 调用gnuplot的时候,用
CreateProcess函数代替system,设置dwCreationFlags为CREATE_NO_WINDOW,这样gnuplot不会额外弹控制台窗口
备注:内容来源于stack exchange,提问作者Martin_from_K
相关产品推荐
相关产品推荐

