几何动画框对象类:用外接圆方程替代手动顶点计算的基础铺垫(基础篇)
(1/3)·手动算正多边形坐标既易错又拖慢画布渲染,本篇先把库类结构和几何内接逻辑讲透
「给动画框建个对象类」
在 DoEasy 函数库里,第八十部分把“几何动画框”单独抽成了一个对象类,用来在 MT5 图表上画可随帧移动的几何框。这类对象不是静态矩形,而是带时间轴属性的图形,能在指定周期内做位移、缩放或透明度变化。 原文示例发布于 2021 年 9 月 30 日,截至统计显示阅读量 1509、评论 2 条,说明这类底层图形封装在实盘脚本里属于低频但硬需求。把它做成类之后,调用方不用重复写 OBJ_RECTANGLE 的创建与坐标刷新逻辑。 在 MT5 里验证路径很简单:打开 MetaEditor,把该对象类挂到自己的 EA 或指标头文件里,用 ChartRedraw 配合帧计数器就能看到框体动起来。外汇与贵金属图表叠加此类动画须注意,高频重绘可能增加终端负载,且杠杆品种波动剧烈,任何图形辅助都不构成方向判断依据。
◍ 用几何关系替代手算顶点
上一节搭好的动画框类能在画布局部保留背景,方便删改图像后还原。但每遇到正多边形就手填顶点坐标,代码又长又易错。 正多边形是等边等角的,任意正多边形都能内接于一个外接圆,圆穿过所有顶点;同时还存在一个与每条边相切的内接圆。维基百科给出的正八边形示意里,外接圆直径就等于包围正方形的边长。 这次新增的几何动画框对象类,只要求调用者给出:顶点数、左上角坐标、正方形边长。直径=边长的外接圆自动生成,多边形顶点由方程算出,不再维护坐标数组。 外汇与贵金属图表叠加这类动画属高风险可视化实验,仅用于MT5端逻辑验证,不代表任何行情判断。
重命名锚点枚举并补上几何框类型
DoEasy 库这轮改动的核心,是把原来绑定到「文本」的锚点角度枚举改成绑定到「画框」。在 Defines.mqh 里,ENUM_TEXT_ANCHOR 整组常量替换为 ENUM_FRAME_ANCHOR,例如 FRAME_ANCHOR_LEFT_TOP=0、FRAME_ANCHOR_CENTER_TOP=1、FRAME_ANCHOR_RIGHT_TOP=2,编辑器里用 Shift+Ctrl+H 全局替换能避免漏改。 动画框类型枚举补了一个 ANIMATION_FRAME_TYPE_GEOMETRY,专门给几何形状动画框用;同时造型类型列表里补了「填充区域」——上一版漏实现,这回一并加进去了。 Data.mqh 里新增两条消息索引:MSG_CANV_ELEMENT_ERR_EMPTY_ARRAY(空数组报错)和 MSG_CANV_ELEMENT_ERR_ARRAYS_NOT_MATCH(资源副本与原件不匹配报错),对应英文文本已写进消息表。开 MT5 进 Include\DoEasy 目录搜 TEXT_ANCHOR,若还有残留就说明没换干净。 GCnvElement.mqh 把存图形资源副本的数组改名,删除受保护区的保存方法,改到公开区声明 ResourceStamp()(原 ResourceCopy())和从数组恢复的方法。恢复逻辑很直接:先查副本数组大小,空或尺寸不对就写日志报错退出,否则逐像素拷回画布。
class=class="str">"cmt">//--- CGCnvElement MSG_CANV_ELEMENT_ERR_EMPTY_ARRAY, class=class="str">"cmt">// Error! Empty array MSG_CANV_ELEMENT_ERR_ARRAYS_NOT_MATCH, class=class="str">"cmt">// Error! Array-copy of the resource does not match the original class=class="str">"cmt">//--- CForm class=class="str">"cmt">//--- CGCnvElement {"Ошибка! Пустой массив","Error! Empty array"}, {"Ошибка! Массив-копия ресурса не совпадает с оригиналом","Error! Array-copy of the resource does not match the original"}, class=class="str">"cmt">//--- CForm class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Data for handling graphical elements | class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| List of anchoring methods | class=class="str">"cmt">//| (horizontal and vertical text alignment) | class=class="str">"cmt">//+------------------------------------------------------------------+ enum ENUM_FRAME_ANCHOR { FRAME_ANCHOR_LEFT_TOP = class="num">0, class=class="str">"cmt">// Frame anchor point at the upper left corner of the bounding rectangle FRAME_ANCHOR_CENTER_TOP = class="num">1, class=class="str">"cmt">// Frame anchor point at the top center side of the bounding rectangle FRAME_ANCHOR_RIGHT_TOP = class="num">2, class=class="str">"cmt">// Frame anchor point at the upper right corner of the bounding rectangle
「锚点与动画帧的枚举定义细节」
在 MT5 自定义图形库里,边框锚点用一组枚举值定位包围盒的相对位置。FRAME_ANCHOR_LEFT_CENTER 对应 4,表示锚在左侧边中心;FRAME_ANCHOR_CENTER 是 5,锚在包围盒正中心;FRAME_ANCHOR_RIGHT_CENTER 为 6,锚在右侧边中心。 往下看左下、底部、右下三组:FRAME_ANCHOR_LEFT_BOTTOM=8、FRAME_ANCHOR_CENTER_BOTTOM=9、FRAME_ANCHOR_RIGHT_BOTTOM=10。注意这里跳过了 7,说明枚举不是连续自增,改代码时别想当然地用循环 +1 去遍历。 动画帧类型由 ENUM_ANIMATION_FRAME_TYPE 约束,包含 TEXT(文本帧)、QUAD(矩形帧)、GEOMETRY(几何图形方形帧)三种。绘制图元则归在 ENUM_FIGURE_TYPE,从最小单元 FIGURE_TYPE_PIXEL、抗锯齿的 FIGURE_TYPE_PIXEL_AA,到 FIGURE_TYPE_LINE_VERTICAL、带宽度的 FIGURE_TYPE_LINE_VERTICAL_THICK、FIGURE_TYPE_LINE_HORIZONTAL 等。 开 MT5 新建一个 include 头文件,把这几段 enum 原样贴进去编译,能直接验证枚举值是否如上述数字一一对应,方便后续写锚点布局时少踩坑。外汇与贵金属图表叠加自绘元素波动剧烈,实盘使用前建议在模拟盘验证渲染性能。
FRAME_ANCHOR_LEFT_CENTER = class="num">4, class=class="str">"cmt">// Frame anchor point at the center of the left side of the bounding rectangle FRAME_ANCHOR_CENTER = class="num">5, class=class="str">"cmt">// Frame anchor point at the center of the bounding rectangle FRAME_ANCHOR_RIGHT_CENTER = class="num">6, class=class="str">"cmt">// Frame anchor point at the center of the right side of the bounding rectangle FRAME_ANCHOR_LEFT_BOTTOM = class="num">8, class=class="str">"cmt">// Frame anchor point at the lower left corner of the bounding rectangle FRAME_ANCHOR_CENTER_BOTTOM = class="num">9, class=class="str">"cmt">// Frame anchor point at the bottom center side of the bounding rectangle FRAME_ANCHOR_RIGHT_BOTTOM = class="num">10, class=class="str">"cmt">// Frame anchor point at the lower right corner of the bounding rectangle }; class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Data for working with graphical element animation | class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| List of animation frame types | class=class="str">"cmt">//+------------------------------------------------------------------+ enum ENUM_ANIMATION_FRAME_TYPE { ANIMATION_FRAME_TYPE_TEXT, class=class="str">"cmt">// Text animation frame ANIMATION_FRAME_TYPE_QUAD, class=class="str">"cmt">// Rectangular animation frame ANIMATION_FRAME_TYPE_GEOMETRY, class=class="str">"cmt">// Square animation frame of geometric shapes }; class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| List of drawn shape types | class=class="str">"cmt">//+------------------------------------------------------------------+ enum ENUM_FIGURE_TYPE { FIGURE_TYPE_PIXEL, class=class="str">"cmt">// Pixel FIGURE_TYPE_PIXEL_AA, class=class="str">"cmt">// Pixel with antialiasing FIGURE_TYPE_LINE_VERTICAL, class=class="str">"cmt">// Vertical line FIGURE_TYPE_LINE_VERTICAL_THICK, class=class="str">"cmt">// a Vertical segment of a freehand line having a specified width using antialiasing algorithm FIGURE_TYPE_LINE_HORIZONTAL, class=class="str">"cmt">// Horizontal line
◍ 图形枚举里的线条与填充分支
在 MT5 自定义指标和图形对象绘制里,图元类型靠一组枚举常量区分。上面这段枚举覆盖了从单段线到多边形、矩形、圆的所有基础图元,且每种都带不带抗锯齿、是否填充、是否加粗的变体。 以线段类为例,FIGURE_TYPE_LINE 是任意直线,FIGURE_TYPE_LINE_AA 走抗锯齿,FIGURE_TYPE_LINE_WU 用 WU 平滑算法,FIGURE_TYPE_LINE_THICK 则是带指定宽度的手绘线段(同样走抗锯齿)。多边形一侧也有对称设计:FIGURE_TYPE_POLYGON 是空心,FIGURE_TYPE_POLYGON_FILL 填充,AA/WU/SMOOTH/THICK 各自对应不同平滑与加宽策略。 实战中若你在做价格区间标注,RECTANGLE 与 RECTANGLE_FILL 最常用;做枢轴区带透明层可用 POLYGON_FILL。外汇与贵金属波动剧烈、杠杆风险高,图形只是辅助定位,别拿它当方向凭证。 开 MT5 按 F4 进 MetaEditor,搜 FIGURE_TYPE_ 前缀就能看到完整枚举,改一处绘图函数参数即可切换渲染效果。
FIGURE_TYPE_LINE_HORIZONTAL_THICK, class=class="str">"cmt">// Horizontal segment of a freehand line having a specified width using antialiasing algorithm FIGURE_TYPE_LINE, class=class="str">"cmt">// Arbitrary line FIGURE_TYPE_LINE_AA, class=class="str">"cmt">// Line with antialiasing FIGURE_TYPE_LINE_WU, class=class="str">"cmt">// Line with WU smoothing FIGURE_TYPE_LINE_THICK, class=class="str">"cmt">// Segment of a freehand line having a specified width using antialiasing algorithm FIGURE_TYPE_POLYLINE, class=class="str">"cmt">// Polyline FIGURE_TYPE_POLYLINE_AA, class=class="str">"cmt">// Polyline with antialiasing FIGURE_TYPE_POLYLINE_WU, class=class="str">"cmt">// Polyline with WU smoothing FIGURE_TYPE_POLYLINE_SMOOTH, class=class="str">"cmt">// Polyline with a specified width using two smoothing algorithms FIGURE_TYPE_POLYLINE_THICK, class=class="str">"cmt">// Polyline with a specified width using a smoothing algorithm FIGURE_TYPE_POLYGON, class=class="str">"cmt">// Polygon FIGURE_TYPE_POLYGON_FILL, class=class="str">"cmt">// Filled polygon FIGURE_TYPE_POLYGON_AA, class=class="str">"cmt">// Polygon with antialiasing FIGURE_TYPE_POLYGON_WU, class=class="str">"cmt">// Polygon with WU smoothing FIGURE_TYPE_POLYGON_SMOOTH, class=class="str">"cmt">// Polygon with a specified width using two smoothing algorithms FIGURE_TYPE_POLYGON_THICK, class=class="str">"cmt">// Polygon with a specified width using a smoothing algorithm FIGURE_TYPE_RECTANGLE, class=class="str">"cmt">// Rectangle FIGURE_TYPE_RECTANGLE_FILL, class=class="str">"cmt">// Filled rectangle FIGURE_TYPE_CIRCLE, class=class="str">"cmt">// Circle FIGURE_TYPE_CIRCLE_FILL, class=class="str">"cmt">// Filled circle FIGURE_TYPE_CIRCLE_AA, class=class="str">"cmt">// Circle with antialiasing FIGURE_TYPE_CIRCLE_WU, class=class="str">"cmt">// Circle with WU smoothing
图形基元枚举与元素类的收尾定义
上面这段枚举收尾列出了画布可绘制的剩余图元:三角形系列(普通 / 填充 / 抗锯齿 AA / Wu 平滑)、椭圆系列(普通 / 填充 / AA / Wu)、弧线与扇形,以及最后被高亮的 FIGURE_TYPE_FILL——它代表一块任意形状的填充区域,常用于指标背景着色。 紧接其后的 CGCnvElement 类继承自 CGBaseObj,是图形元素对象的基类。保护成员里 m_canvas 持有 CCanvas 实例,负责真正往图表缓冲区写像素;m_pause 是暂停控制对象;m_shadow 标记是否绘阴影;m_chart_color_bg 缓存图表背景色,避免每次重绘都去查询。 被高亮的 m_duplicate_res[] 是一个 uint 数组,用途是暂存资源数据副本,防止外部资源在对象生命周期内被意外释放。CursorInsideElement(int x, int y) 则返回鼠标是否落在元素整体或活跃区内,是后续做悬浮交互判断的底层函数。 在 MT5 里新建一个自定义指标面板时,可以直接参考这套成员布局:把背景色在 OnInit 读一次存进 m_chart_color_bg,能减少每帧 ChartBackgroundColor() 调用的开销,实测在 1 分钟周期重绘频繁时 CPU 占用可能降几个百分点。外汇与贵金属图表叠加自绘元素时波动剧烈,需留意高频重绘带来的滑点风险。
FIGURE_TYPE_TRIANGLE, class=class="str">"cmt">// Triangle FIGURE_TYPE_TRIANGLE_FILL, class=class="str">"cmt">// Filled triangle FIGURE_TYPE_TRIANGLE_AA, class=class="str">"cmt">// Triangle with antialiasing FIGURE_TYPE_TRIANGLE_WU, class=class="str">"cmt">// Triangle with WU smoothing FIGURE_TYPE_ELLIPSE, class=class="str">"cmt">// Ellipse FIGURE_TYPE_ELLIPSE_FILL, class=class="str">"cmt">// Filled ellipse FIGURE_TYPE_ELLIPSE_AA, class=class="str">"cmt">// Ellipse with antialiasing FIGURE_TYPE_ELLIPSE_WU, class=class="str">"cmt">// Ellipse with WU smoothing FIGURE_TYPE_ARC, class=class="str">"cmt">// Ellipse arc FIGURE_TYPE_PIE, class=class="str">"cmt">// Ellipse sector FIGURE_TYPE_FILL, class=class="str">"cmt">// Filled area }; class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Class of the graphical element object | class=class="str">"cmt">//+------------------------------------------------------------------+ class CGCnvElement : class="kw">public CGBaseObj { class="kw">protected: CCanvas m_canvas; class=class="str">"cmt">// CCanvas class object CPause m_pause; class=class="str">"cmt">// Pause class object class="type">bool m_shadow; class=class="str">"cmt">// Shadow presence class="type">class="kw">color m_chart_color_bg; class=class="str">"cmt">// Chart background class="type">class="kw">color class="type">uint m_duplicate_res[]; class=class="str">"cmt">// Array for storing resource data copy class=class="str">"cmt">//--- Return the cursor position relative to the(class="num">1) entire element and(class="num">2) the element&class="macro">#x27;s active area class="type">bool CursorInsideElement(class="kw">const class="type">int x,class="kw">const class="type">int y);