DoEasy 函数库中的图形(第八十部分):几何动画框对象类·进阶篇
◍ 画布元素基类的属性读写接口
在 MT5 自定义图形界面里,所有画布元素都从一个基类 CGCnvElement 派生。它把整数、双精度、字符串三类属性分别塞进三个数组,用枚举值当索引,避免每加一个属性就改一次类结构。 下面这段声明给出了光标命中检测、资源拷贝,以及对象与结构体互转的虚函数入口。ResourceCopy 负责把图形资源(如图标 bmp/png)读进数组,供后续绘制调用。 [CODE] bool CursorInsideActiveArea(const int x,const int y); //--- Create (1) the object structure and (2) the object from the structure virtual bool ObjectToStruct(void); virtual void StructToObject(void); //--- Save the graphical resource to the array bool ResourceCopy(const string source); [/CODE] 公开的 SetProperty 有三个重载:整数属性直接按枚举下标写入 m_long_prop;双精度和字符串则先经过 IndexProp 做偏移映射再存。这意味着双精度属性在数组里的位置不一定和枚举值一一对应,调试时别直接猜下标。 [CODE] void SetProperty(ENUM_CANV_ELEMENT_PROP_INTEGER property,long value) { this.m_long_prop[property]=value; } void SetProperty(ENUM_CANV_ELEMENT_PROP_DOUBLE property,double value){ this.m_double_prop[this.IndexProp(property)]=value; } void SetProperty(ENUM_CANV_ELEMENT_PROP_STRING property,string value){ this.m_string_prop[this.IndexProp(property)]=value; } [/CODE] GetProperty 的 const 重载对称地往外取数。SupportProperty 默认实现里,双精度返回 false——即基类默认不宣称支持任何双精度属性,派生类需要自己重写来开启。 [CODE] long GetProperty(ENUM_CANV_ELEMENT_PROP_INTEGER property) const { return this.m_long_prop[property]; } double GetProperty(ENUM_CANV_ELEMENT_PROP_DOUBLE property) const { return this.m_double_prop[this.IndexProp(property)]; } string GetProperty(ENUM_CANV_ELEMENT_PROP_STRING property) const { return this.m_string_prop[this.IndexProp(property)]; } virtual bool SupportProperty(ENUM_CANV_ELEMENT_PROP_INTEGER property) { return true; } virtual bool SupportProperty(ENUM_CANV_ELEMENT_PROP_DOUBLE property) { return false; } virtual bool SupportProperty(ENUM_CANV_ELEMENT_PROP_STRING property) { return true; } CGCnvElement *GetObject(void) { return &this; } [/CODE] 开 MT5 新建一个继承 CGCnvElement 的测试类,重写 SupportProperty 双精度版返回 true,再断点看 IndexProp 的实际偏移,能确认你那套属性枚举有没有排错位。外汇与贵金属图表上做这类自定义控件,需注意跨周期重载时资源数组可能被清空,属于高风险调试场景。
class="type">bool CursorInsideActiveArea(class="kw">const class="type">int x,class="kw">const class="type">int y); class=class="str">"cmt">//--- Create(class="num">1) the object structure and(class="num">2) the object from the structure class="kw">virtual class="type">bool ObjectToStruct(class="type">void); class="kw">virtual class="type">void StructToObject(class="type">void); class=class="str">"cmt">//--- Save the graphical resource to the array class="type">bool ResourceCopy(class="kw">const class="type">class="kw">string source); class="kw">private: class="kw">public: class=class="str">"cmt">//--- Set object&class="macro">#x27;s(class="num">1) integer, (class="num">2) real and(class="num">3) class="type">class="kw">string properties class="type">void SetProperty(ENUM_CANV_ELEMENT_PROP_INTEGER class="kw">property,class="type">long value) { this.m_long_prop[class="kw">property]=value; } class="type">void SetProperty(ENUM_CANV_ELEMENT_PROP_DOUBLE class="kw">property,class="type">class="kw">double value){ this.m_double_prop[this.IndexProp(class="kw">property)]=value; } class="type">void SetProperty(ENUM_CANV_ELEMENT_PROP_STRING class="kw">property,class="type">class="kw">string value){ this.m_string_prop[this.IndexProp(class="kw">property)]=value; } class=class="str">"cmt">//--- Return object’s(class="num">1) integer, (class="num">2) real and(class="num">3) class="type">class="kw">string class="kw">property from the properties array class="type">long GetProperty(ENUM_CANV_ELEMENT_PROP_INTEGER class="kw">property) class="kw">const { class="kw">return this.m_long_prop[class="kw">property]; } class="type">class="kw">double GetProperty(ENUM_CANV_ELEMENT_PROP_DOUBLE class="kw">property) class="kw">const { class="kw">return this.m_double_prop[this.IndexProp(class="kw">property)]; } class="type">class="kw">string GetProperty(ENUM_CANV_ELEMENT_PROP_STRING class="kw">property) class="kw">const { class="kw">return this.m_string_prop[this.IndexProp(class="kw">property)]; } class=class="str">"cmt">//--- Return the flag of the object supporting this class="kw">property class="kw">virtual class="type">bool SupportProperty(ENUM_CANV_ELEMENT_PROP_INTEGER class="kw">property) { class="kw">return true; } class="kw">virtual class="type">bool SupportProperty(ENUM_CANV_ELEMENT_PROP_DOUBLE class="kw">property) { class="kw">return class="kw">false; } class="kw">virtual class="type">bool SupportProperty(ENUM_CANV_ELEMENT_PROP_STRING class="kw">property) { class="kw">return true; } class=class="str">"cmt">//--- Return itself CGCnvElement *GetObject(class="type">void) { class="kw">return &this; } class=class="str">"cmt">//--- Compare CGCnvElement objects with each other by all possible properties(for sorting the lists by a specified object class="kw">property)
「图形容器类的方法接口拆解」
在 MT5 里做自定义图形面板,常会碰到一个封装好的图形元素类(如 CGCnvElement)。它对外暴露的方法决定了你能怎样比较、持久化和重绘这些元素。 比较与判等由 Compare 和 IsEqual 承担:前者按所有属性对比两个对象,便于在容器里检索相同项;后者直接接收同类型指针做相等判断。若你在 EA 里维护一组画布按钮,用 IsEqual 可以快速跳过重复创建。 持久化走两套:Save/Load 对接文件句柄,把对象写盘或读回;ResourceStamp 则是把图形资源存进数组、再从数组还原,适合把图标打进 ex5 资源避免外部依赖。Reset 负责清空状态。 真正建元素看 Create:入参覆盖 chart_id、子窗口号、名字、x/y 坐标、宽高、颜色、透明度以及是否立即重绘。注意 opacity 是 uchar,0 为全透、255 为不透,调低能做出悬浮半透明面板。 GetCanvasObj 直接返回内部 CCanvas 指针,意味着你能绕过封装去调底层绘图。SetFrequency 通过 m_pause.SetWaitingMSC(value) 控制画布刷新间隔——比如设 100 毫秒可能让动画更顺,设 500 可能降 CPU 占用。外汇与贵金属图表叠加这类图形属高风险操作,参数不当可能卡顿甚至误导下单。
class="kw">virtual class="type">int Compare(class="kw">const CObject *node,class="kw">const class="type">int mode=class="num">0) class="kw">const; class=class="str">"cmt">//--- Compare CGCnvElement objects with each other by all properties(to search equal objects) class="type">bool IsEqual(CGCnvElement* compared_obj) class="kw">const; class=class="str">"cmt">//--- (class="num">1) Save the object to file and(class="num">2) upload the object from the file class="kw">virtual class="type">bool Save(class="kw">const class="type">int file_handle); class="kw">virtual class="type">bool Load(class="kw">const class="type">int file_handle); class=class="str">"cmt">//--- (class="num">1) Save the graphical resource to the array and(class="num">2) restore the resource from the array class="type">bool ResourceStamp(class="kw">const class="type">class="kw">string source); class="kw">virtual class="type">bool Reset(class="type">void); class=class="str">"cmt">//--- Create the element class="type">bool Create(class="kw">const class="type">long chart_id, class="kw">const class="type">int wnd_num, class="kw">const class="type">class="kw">string name, class="kw">const class="type">int x, class="kw">const class="type">int y, class="kw">const class="type">int w, class="kw">const class="type">int h, class="kw">const class="type">class="kw">color colour, class="kw">const class="type">uchar opacity, class="kw">const class="type">bool redraw=class="kw">false); class=class="str">"cmt">//--- Return the pointer to a canvas object CCanvas *GetCanvasObj(class="type">void) { class="kw">return &this.m_canvas; } class=class="str">"cmt">//--- Set the canvas update frequency class="type">void SetFrequency(class="kw">const class="type">class="kw">ulong value) { this.m_pause.SetWaitingMSC(value); }
画布对象的资源存取与色彩微调
在封装画布元素时,把图形资源存成数组再还原,是避免重绘抖动的常用手段。下面这段接口里,CanvasUpdate 直接转发到底层画布更新,DuplicateResArraySize 用 ArraySize 返回副本数组长度,调用方可据此判断是否已经做过快照。 Move 负责按像素偏移画布坐标,ImageCopy 把指定 source 的图像写入 uint 数组;两者都返回 bool,调用失败时能立即被外层逻辑捕获。 色彩处理给了 ARGB(uint)与 COLOR(color)两套重载:ChangeColorLightness 按 change_value 调整明度,ChangeColorSaturation 调饱和度。change_value 传 0.1 表示倾向提亮或增饱和约 10%,负值则反向,具体观感要在 MT5 里跑一遍才准。外汇与贵金属图表叠加此类自定义层存在刷新耗时风险,参数激进时可能拖累终端响应。 protected 区的 ResourceStamp 调用 ImageCopy(DFUN, m_duplicate_res) 完成快照;Reset 先取数组大小,若为 0 则写日志 MSG_CANV_ELEMENT_ERR_EMPTY_ARRAY 并返回 false。另一道校验是画布宽高乘积必须等于数组大小,否则报 MSG_CANV_ELEMENT_ERR_ARRAYS_NOT_MATCH 且返回 false——这能拦掉大部分分辨率不匹配导致的花屏。
class="type">void CanvasUpdate(class="kw">const class="type">bool redraw=class="kw">false) { this.m_canvas.Update(redraw); } class=class="str">"cmt">//--- Return the size of the graphical resource copy array class="type">uint DuplicateResArraySize(class="type">void) { class="kw">return ::ArraySize(this.m_duplicate_res); } class=class="str">"cmt">//--- Update the coordinates(shift the canvas) class="type">bool Move(class="kw">const class="type">int x,class="kw">const class="type">int y,class="kw">const class="type">bool redraw=class="kw">false); class=class="str">"cmt">//--- Save an image to the array class="type">bool ImageCopy(class="kw">const class="type">class="kw">string source,class="type">uint &array[]); class=class="str">"cmt">//--- Change the lightness of(class="num">1) ARGB and(class="num">2) COLOR by a specified amount class="type">uint ChangeColorLightness(class="kw">const class="type">uint clr,class="kw">const class="type">class="kw">double change_value); class="type">class="kw">color ChangeColorLightness(class="kw">const class="type">class="kw">color colour,class="kw">const class="type">class="kw">double change_value); class=class="str">"cmt">//--- Change the saturation of(class="num">1) ARGB and(class="num">2) COLOR by a specified amount class="type">uint ChangeColorSaturation(class="kw">const class="type">uint clr,class="kw">const class="type">class="kw">double change_value); class="type">class="kw">color ChangeColorSaturation(class="kw">const class="type">class="kw">color colour,class="kw">const class="type">class="kw">double change_value); class="kw">protected: class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Save the graphical resource to the array | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">bool CGCnvElement::ResourceStamp(class="kw">const class="type">class="kw">string source) { class="kw">return this.ImageCopy(DFUN,this.m_duplicate_res); } class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Restore the graphical resource from the array | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">bool CGCnvElement::Reset(class="type">void) { class=class="str">"cmt">//--- Get the size of the graphical resource copy array class="type">int size=::ArraySize(this.m_duplicate_res); class=class="str">"cmt">//--- If the array is empty, inform of that and class="kw">return &class="macro">#x27;class="kw">false&class="macro">#x27; if(size==class="num">0) { CMessage::ToLog(DFUN,MSG_CANV_ELEMENT_ERR_EMPTY_ARRAY); class="kw">return class="kw">false; } class=class="str">"cmt">//--- If the size of the graphical resource copy array does not match the size of the graphical resource, class=class="str">"cmt">//--- inform of that in the journal and class="kw">return &class="macro">#x27;class="kw">false&class="macro">#x27; if(this.m_canvas.Width()*this.m_canvas.Height()!=size) { CMessage::ToLog(DFUN,MSG_CANV_ELEMENT_ERR_ARRAYS_NOT_MATCH); class="kw">return class="kw">false; }
◍ 像素回写与高斯模糊的半径边界
把缓存数组重新铺回画布,本质就是按宽高两层循环把每个像素归位。下面这段逻辑先置数组下标 n=0,再对画布高度、宽度做嵌套遍历,每次用 PixelSet(x,y,m_duplicate_res[n]) 写回并自增 n,最后以 Update(false) 刷新。 int n=0; for(int y=0;y<this.m_canvas.Height();y++) { for(int x=0;x<this.m_canvas.Width();x++) { this.m_canvas.PixelSet(x,y,this.m_duplicate_res[n]); n++; } } this.m_canvas.Update(false); return true; 高斯模糊入口 GaussianBlur(radius) 里有个硬约束:节点数 n_nodes = radius*2+1,若 radius 大于等于宽或高的一半,函数直接返回 false 并提示资源过小。这意味着在 100×100 的副本上,模糊半径最多只能给到 49,否则整轮计算被跳过。 bool CShadowObj::GaussianBlur(const uint radius) { int n_nodes=(int)radius*2+1; if(!CGCnvElement::ResourceStamp(DFUN)) return false;
| if((int)radius>=this.Width()/2 | (int)radius>=this.Height()/2) |
|---|
{ ::Print(DFUN,CMessage::Text(MSG_SHADOW_OBJ_IMG_SMALL_BLUR_LARGE)); return false; } int size=::ArraySize(this.m_duplicate_res); uchar a_h_data[],r_h_data[],g_h_data[],b_h_data[]; uchar a_v_data[],r_v_data[],g_v_data[],b_v_data[]; if(::ArrayResize(a_h_data,size)==-1) { CMessage::ToLog(DFUN,MSG_LIB_SYS_FAILED_ARRAY_RESIZE); ::Print(DFUN_ERR_LINE,": \"a_h_data\""); return false; } if(::ArrayResize(r_h_data,size)==-1) { CMessage::ToLog(DFUN,MSG_LIB_SYS_FAILED_ARRAY_RESIZE); ::Print(DFUN_ERR_LINE,": \"r_h_data\""); return false; } if(::ArrayResize(g_h_data,size)==-1) { CMessage::ToLog(DFUN,MSG_LIB_SYS_FAILED_ARRAY_RESIZE); ::Print(DFUN_ERR_LINE,": \"g_h_data\""); return false; } 之后把副本资源按 size 拆成 A/R/G/B 四个分量,并分别建横向、纵向两套缓冲数组。ArrayResize 任一失败就写日志并返回 false,所以开 MT5 跑自定义阴影对象时,若控制台冒出 "a_h_data" 类报错,优先查资源尺寸而非算法本身。外汇与贵金属图表叠加此类图形层存在渲染占用风险,参数宜从小半径试起。
class="type">int n=class="num">0; for(class="type">int y=class="num">0;y<this.m_canvas.Height();y++) { for(class="type">int x=class="num">0;x<this.m_canvas.Width();x++) { this.m_canvas.PixelSet(x,y,this.m_duplicate_res[n]); n++; } } this.m_canvas.Update(class="kw">false); class="kw">return true; class="type">bool CShadowObj::GaussianBlur(class="kw">const class="type">uint radius) { class="type">int n_nodes=(class="type">int)radius*class="num">2+class="num">1; if(!CGCnvElement::ResourceStamp(DFUN)) class="kw">return class="kw">false; if((class="type">int)radius>=this.Width()/class="num">2 || (class="type">int)radius>=this.Height()/class="num">2) { ::Print(DFUN,CMessage::Text(MSG_SHADOW_OBJ_IMG_SMALL_BLUR_LARGE)); class="kw">return class="kw">false; } class="type">int size=::ArraySize(this.m_duplicate_res); class="type">uchar a_h_data[],r_h_data[],g_h_data[],b_h_data[]; class="type">uchar a_v_data[],r_v_data[],g_v_data[],b_v_data[]; if(::ArrayResize(a_h_data,size)==-class="num">1) { CMessage::ToLog(DFUN,MSG_LIB_SYS_FAILED_ARRAY_RESIZE); ::Print(DFUN_ERR_LINE,": \"a_h_data\""); class="kw">return class="kw">false; } if(::ArrayResize(r_h_data,size)==-class="num">1) { CMessage::ToLog(DFUN,MSG_LIB_SYS_FAILED_ARRAY_RESIZE); ::Print(DFUN_ERR_LINE,": \"r_h_data\""); class="kw">return class="kw">false; } if(::ArrayResize(g_h_data,size)==-class="num">1) { CMessage::ToLog(DFUN,MSG_LIB_SYS_FAILED_ARRAY_RESIZE); ::Print(DFUN_ERR_LINE,": \"g_h_data\""); class="kw">return class="kw">false; }
「图像水平模糊前的数组兜底与权重准备」
这段逻辑出现在自定义图像类的模糊方法里,核心是先给六个颜色分量数组(a/r/g/b 各分水平 h 与垂直 v)按 size 扩容,任一 ArrayResize 返回 -1 就写日志并 return false,避免后续越界。 size 通常等于图像宽高乘积,例如 512×512 的图会尝试分配 262144 个 double 元素;MT5 里 ArrayResize 失败多发生在内存紧张或 size 计算错误时,此时 Print 会带出具体数组名方便定位。 兜底之后声明 weights[] 并调用 GetQuadratureWeights(1,n_nodes,weights) 取模糊权重,失败直接退出;随后用 for 循环把 m_duplicate_res 里每个像素的 ARGB 拆进 a_h_data/r_h_data/g_h_data/b_h_data,为沿 X 轴卷积做准备。 水平模糊主循环从 Y=0 扫到 Height(),X 从 radius 到 Width()-radius,用 XY=Y*Width()+X 算线性下标,四个临时累加变量 a_temp/r_temp/g_temp/b_temp 置零,coef 计数归零,下一步才按权重乘加。
class="kw">return class="kw">false; } if(ArrayResize(b_h_data,size)==-class="num">1) { CMessage::ToLog(DFUN,MSG_LIB_SYS_FAILED_ARRAY_RESIZE); ::Print(DFUN_ERR_LINE,": \"b_h_data\""); class="kw">return class="kw">false; } if(::ArrayResize(a_v_data,size)==-class="num">1) { CMessage::ToLog(DFUN,MSG_LIB_SYS_FAILED_ARRAY_RESIZE); ::Print(DFUN_ERR_LINE,": \"a_v_data\""); class="kw">return class="kw">false; } if(::ArrayResize(r_v_data,size)==-class="num">1) { CMessage::ToLog(DFUN,MSG_LIB_SYS_FAILED_ARRAY_RESIZE); ::Print(DFUN_ERR_LINE,": \"r_v_data\""); class="kw">return class="kw">false; } if(::ArrayResize(g_v_data,size)==-class="num">1) { CMessage::ToLog(DFUN,MSG_LIB_SYS_FAILED_ARRAY_RESIZE); ::Print(DFUN_ERR_LINE,": \"g_v_data\""); class="kw">return class="kw">false; } if(::ArrayResize(b_v_data,size)==-class="num">1) { CMessage::ToLog(DFUN,MSG_LIB_SYS_FAILED_ARRAY_RESIZE); ::Print(DFUN_ERR_LINE,": \"b_v_data\""); class="kw">return class="kw">false; } class=class="str">"cmt">//--- Declare the array for storing blur weight ratios and, class=class="str">"cmt">//--- if failed to get the array of weight ratios, class="kw">return &class="macro">#x27;class="kw">false&class="macro">#x27; class="type">class="kw">double weights[]; if(!this.GetQuadratureWeights(class="num">1,n_nodes,weights)) class="kw">return class="kw">false; class=class="str">"cmt">//--- Set components of each image pixel to the class="type">class="kw">color component arrays for(class="type">int i=class="num">0;i<size;i++) { a_h_data[i]=GETRGBA(this.m_duplicate_res[i]); r_h_data[i]=GETRGBR(this.m_duplicate_res[i]); g_h_data[i]=GETRGBG(this.m_duplicate_res[i]); b_h_data[i]=GETRGBB(this.m_duplicate_res[i]); } class=class="str">"cmt">//--- Blur the image horizontally(along the X axis) class="type">uint XY; class=class="str">"cmt">// Pixel coordinate in the array class="type">class="kw">double a_temp=class="num">0.0,r_temp=class="num">0.0,g_temp=class="num">0.0,b_temp=class="num">0.0; class="type">int coef=class="num">0; class="type">int j=(class="type">int)radius; class=class="str">"cmt">//--- Loop by the image width for(class="type">int Y=class="num">0;Y<this.Height();Y++) { class=class="str">"cmt">//--- Loop by the image height for(class="type">uint X=radius;X<this.Width()-radius;X++) { XY=Y*this.Width()+X; a_temp=class="num">0.0; r_temp=class="num">0.0; g_temp=class="num">0.0; b_temp=class="num">0.0; coef=class="num">0; class=class="str">"cmt">//--- Multiply each class="type">class="kw">color component by the weight ratio corresponding to the current image pixel
纵向模糊与边缘伪影的像素回填
横向模糊跑完之后,图像还要再沿 Y 轴来一遍高斯模糊,否则只顺一个方向抹匀,视觉上仍是条状残影。代码里用 dxdy = i * (int)this.Width() 把行偏移换算成一维数组下标,再拿 weights[coef] 逐行加权累加 a/r/g/b 四个分量,逻辑和横向那一轮完全对称。 边界处理是这套算法的落点:左右两侧在横向阶段已经用相邻像素拷贝填过,上下两端则在纵向循环里靠 radius 跳过。Y 从 radius 跑到 Height()-radius,意味着上下各 radius 行不参与加权,直接留待后续回填,否则数组越界会把图表资源搞崩。 回填动作虽短但必须做——不补的话 MT5 自定义指标面板的四边会出现半透明拖影,在 4K 屏上尤其明显。把纵向模糊后的 a_h_data、r_h_data 等数组按 (Y+1)*Width()-radius-1 这类锚点复制进残留行,伪影即消失。外汇与贵金属图表叠加此类绘制时波动剧烈,高杠杆下误读图形风险不小,验证前先开模拟盘跑一遍。
for(class="type">int i=-class="num">1*j;i<j+class="num">1;i=i+class="num">1) { a_temp+=a_h_data[XY+i]*weights[coef]; r_temp+=r_h_data[XY+i]*weights[coef]; g_temp+=g_h_data[XY+i]*weights[coef]; b_temp+=b_h_data[XY+i]*weights[coef]; coef++; } class=class="str">"cmt">//--- Save each rounded class="type">class="kw">color component calculated according to the ratios to the component arrays a_h_data[XY]=(class="type">uchar)::round(a_temp); r_h_data[XY]=(class="type">uchar)::round(r_temp); g_h_data[XY]=(class="type">uchar)::round(g_temp); b_h_data[XY]=(class="type">uchar)::round(b_temp); } class=class="str">"cmt">//--- Remove blur artifacts to the left by copying adjacent pixels for(class="type">uint x=class="num">0;x<radius;x++) { XY=Y*this.Width()+x; a_h_data[XY]=a_h_data[Y*this.Width()+radius]; r_h_data[XY]=r_h_data[Y*this.Width()+radius]; g_h_data[XY]=g_h_data[Y*this.Width()+radius]; b_h_data[XY]=b_h_data[Y*this.Width()+radius]; } class=class="str">"cmt">//--- Remove blur artifacts to the right by copying adjacent pixels for(class="type">int x=class="type">int(this.Width()-radius);x<this.Width();x++) { XY=Y*this.Width()+x; a_h_data[XY]=a_h_data[(Y+class="num">1)*this.Width()-radius-class="num">1]; r_h_data[XY]=r_h_data[(Y+class="num">1)*this.Width()-radius-class="num">1]; g_h_data[XY]=g_h_data[(Y+class="num">1)*this.Width()-radius-class="num">1]; b_h_data[XY]=b_h_data[(Y+class="num">1)*this.Width()-radius-class="num">1]; } } class=class="str">"cmt">//--- Blur vertically(along the Y axis) the image already blurred horizontally class="type">int dxdy=class="num">0; class=class="str">"cmt">//--- Loop by the image height for(class="type">int X=class="num">0;X<this.Width();X++) { class=class="str">"cmt">//--- Loop by the image width for(class="type">uint Y=radius;Y<this.Height()-radius;Y++) { XY=Y*this.Width()+X; a_temp=class="num">0.0; r_temp=class="num">0.0; g_temp=class="num">0.0; b_temp=class="num">0.0; coef=class="num">0; class=class="str">"cmt">//--- Multiply each class="type">class="kw">color component by the weight ratio corresponding to the current image pixel for(class="type">int i=-class="num">1*j;i<j+class="num">1;i=i+class="num">1) { dxdy=i*(class="type">int)this.Width(); a_temp+=a_h_data[XY+dxdy]*weights[coef]; r_temp+=r_h_data[XY+dxdy]*weights[coef];