DoEasyライブラリのグラフィックス(第79部): 「アニメーションフレーム」オブジェクトクラスとその子孫オブジェクト
内容
概念
前回の記事では、描画された形状の下にある背景の一部を保存してから復元するためのクラスを作成しました。ここでは、この概念についての作業を再開し、それに基づいて、単一のアニメーションフレームの基本クラスとその子孫(テキストアニメーションフレームと長方形アニメーションフレームのクラス)を作成します。
基本クラスには単一のアニメーションフレームの共通のプロパティセットが含まれ、その子孫には、形状を描画するための固有のメソッドがあります。テキストアニメーションクラスはテキストの操作を可能にするためのものです。長方形アニメーションフレームは、単一のアニメーションフレームを作成し、そのようなCCanvasクラスメソッドに基づく描画メソッドを使用してさまざまな形状を描画するためのものです。
作成された各フォームオブジェクトはカスタムキャンバスに描画するための一連のメソッドを備えているため、フォーム上に新しい画像をすばやく作成して管理できます。各フォームで描画ツールを便利に使用できるように、フォーム上に作成されたすべてのテキストと形状の画像のリストを特徴とする共通クラスを作成します。後に新しいアニメーションメソッドを追加する際には、それらのリストも共通クラスに配置します。このような概念により、新しい画像を動的に作成して適切なリストに保存し、次に、フォームオブジェクトからそれらをすばやく取得して、その背景上に表示することができます。この場合、そのようなオブジェクトは、フォームの背景をその下に自動的に保存します。オブジェクトが削除、変更、または移動された場合、保存された背景が復元されます。
したがって、今回の記事では、前の記事で作成した描画フレームを少し修正し、基本アニメーションフレームオブジェクトのクラスを開発し、2つの子孫クラス(テキストアニメーションフレームと長方形アニメーションフレームクラス)を開発します。これらのフレームオブジェクトのリストを格納するためのクラスを作成し、フォームオブジェクトからそれらを操作する機能を提供しましょう。
ライブラリクラスの改善
まず、以前に作成したライブラリクラスを改善します。\MQL5\Include\DoEasy\Defines.mqhで、長方形アニメーションフレームクラスにアニメーションフレームのリストと描画された形状タイプのリストを追加します。
//+------------------------------------------------------------------+ //| Data for working with graphical element animation | //+------------------------------------------------------------------+ //+------------------------------------------------------------------+ //| List of animation frame types | //+------------------------------------------------------------------+ enum ENUM_ANIMATION_FRAME_TYPE { ANIMATION_FRAME_TYPE_TEXT, // Text animation frame ANIMATION_FRAME_TYPE_QUAD, // Rectangle animation frame }; //+------------------------------------------------------------------+ //| List of drawn shape types | //+------------------------------------------------------------------+ enum ENUM_FIGURE_TYPE { FIGURE_TYPE_PIXEL, // Pixel FIGURE_TYPE_PIXEL_AA, // Pixel with antialiasing FIGURE_TYPE_LINE_VERTICAL, // Vertical line FIGURE_TYPE_LINE_VERTICAL_THICK, // Vertical segment of a freehand line having a specified width using antialiasing algorithm FIGURE_TYPE_LINE_HORIZONTAL, // Horizontal line FIGURE_TYPE_LINE_HORIZONTAL_THICK, // Horizontal segment of a freehand line having a specified width using antialiasing algorithm FIGURE_TYPE_LINE, // Arbitrary line FIGURE_TYPE_LINE_AA, // Line with antialiasing FIGURE_TYPE_LINE_WU, // Line with WU smoothing FIGURE_TYPE_LINE_THICK, // Segment of a freehand line having a specified width using antialiasing algorithm FIGURE_TYPE_POLYLINE, // Polyline FIGURE_TYPE_POLYLINE_AA, // Polyline with antialiasing FIGURE_TYPE_POLYLINE_WU, // Polyline with WU smoothing FIGURE_TYPE_POLYLINE_SMOOTH, // Polyline with a specified width using two smoothing algorithms FIGURE_TYPE_POLYLINE_THICK, // Polyline with a specified width using a smoothing algorithm FIGURE_TYPE_POLYGON, // Polygon FIGURE_TYPE_POLYGON_FILL, // Filled polygon FIGURE_TYPE_POLYGON_AA, // Polygon with antialiasing FIGURE_TYPE_POLYGON_WU, // Polygon with WU smoothing FIGURE_TYPE_POLYGON_SMOOTH, // Polygon with a specified width using two smoothing algorithms FIGURE_TYPE_POLYGON_THICK, // Polygon with a specified width using a smoothing algorithm FIGURE_TYPE_RECTANGLE, // Rectangle FIGURE_TYPE_RECTANGLE_FILL, // Filled rectangle FIGURE_TYPE_CIRCLE, // Circle FIGURE_TYPE_CIRCLE_FILL, // Filled circle FIGURE_TYPE_CIRCLE_AA, // Circle with antialiasing FIGURE_TYPE_CIRCLE_WU, // Circle with WU smoothing FIGURE_TYPE_TRIANGLE, // Triangle FIGURE_TYPE_TRIANGLE_FILL, // Filled triangle FIGURE_TYPE_TRIANGLE_AA, // Triangle with antialiasing FIGURE_TYPE_TRIANGLE_WU, // Triangle with WU smoothing FIGURE_TYPE_ELLIPSE, // Ellipse FIGURE_TYPE_ELLIPSE_FILL, // Filled ellipse FIGURE_TYPE_ELLIPSE_AA, // Ellipse with antialiasing FIGURE_TYPE_ELLIPSE_WU, // Ellipse with WU smoothing FIGURE_TYPE_ARC, // Ellipse arc FIGURE_TYPE_PIE, // Ellipse sector }; //+------------------------------------------------------------------+
アニメーションフレームオブジェクトを識別するにはアニメーションフレームタイプ(テキスト、描画された形状、または次の記事で紹介するその他のアニメーションフレームタイプ)を使用します。描画される形状のタイプは、単一の長方形のアニメーションフレームに正確に描画されるものを示します。これらのタイプは、CCanvasクラスの既存の描画メソッド( クラスメソッドの表のデータアクセス、 プリミティブの描画、 塗りつぶされたプリミティブの描画、 アンチエイリアスを使用したプリミティブの描画セクション)に対応します。
\MQL5\Include\DoEasy\Data.mqhに、新しいメッセージインデックスを追加します。
//--- CForm MSG_FORM_OBJECT_TEXT_NO_SHADOW_OBJ_FIRST_CREATE_IT,// No shadow object. Create it using the CreateShadowObj() method MSG_FORM_OBJECT_ERR_FAILED_CREATE_SHADOW_OBJ, // Failed to create new shadow object MSG_FORM_OBJECT_ERR_FAILED_CREATE_PC_OBJ, // Failed to create new pixel copier object MSG_FORM_OBJECT_PC_OBJ_ALREADY_IN_LIST, // Pixel copier object with ID already present in the list MSG_FORM_OBJECT_PC_OBJ_NOT_EXIST_LIST, // No pixel copier object with ID in the list //--- CFrame MSG_FORM_OBJECT_ERR_FAILED_CREATE_FRAME, // Failed to create a new animation frame object MSG_FORM_OBJECT_FRAME_ALREADY_IN_LIST, // Animation frame object with ID already present in the list MSG_FORM_OBJECT_FRAME_NOT_EXIST_LIST, // Animation frame object with ID not present in the list //--- CShadowObj MSG_SHADOW_OBJ_IMG_SMALL_BLUR_LARGE, // Error! Image size too small or blur too extensive
また、新しく追加したインデックスに対応するメッセージテキストも追加します。
//--- CForm {"Отсутствует объект тени. Необходимо сначала его создать при помощи метода CreateShadowObj()","There is no shadow object. You must first create it using the CreateShadowObj () method"}, {"Не удалось создать новый объект для тени","Failed to create new object for shadow"}, {"Не удалось создать новый объект-копировщик пикселей","Failed to create new pixel copier object"}, {"В списке уже есть объект-копировщик пикселей с идентификатором ","There is already a pixel copier object in the list with ID "}, {"В списке нет объекта-копировщика пикселей с идентификатором ","No pixel copier object with ID "}, //--- CFrame {"Не удалось создать новый объект-кадр анимации","Failed to create new animation frame object"}, {"В списке уже есть объект-кадр анимации с идентификатором ","The list already contains an animation frame object with an ID "}, {"В списке нет объекта-кадра анимации с идентификатором ","No animation frame object with ID "}, //--- CShadowObj {"Ошибка! Размер изображения очень маленький или очень большое размытие","Error! Image size is very small or very large blur"},
ライブラリサービス関数ファイル(\MQL5\Include\DoEasy\Services\DELib.mqh)に、配列の最大値と最小値を返す関数を追加します。
//+------------------------------------------------------------------+ //| Return the maximum value in the array | //+------------------------------------------------------------------+ template<typename T> bool ArrayMaximumValue(const string source,const T &array[],T &max_value) { if(ArraySize(array)==0) { CMessage::ToLog(source,MSG_CANV_ELEMENT_ERR_EMPTY_ARRAY); return false; } max_value=0; int index=ArrayMaximum(array); if(index==WRONG_VALUE) return false; max_value=array[index]; return true; } //+------------------------------------------------------------------+ //| Return the minimum value in the array | //+------------------------------------------------------------------+ template<typename T> bool ArrayMinimumValue(const string source,const T &array[],T &min_value) { if(ArraySize(array)==0) { CMessage::ToLog(source,MSG_CANV_ELEMENT_ERR_EMPTY_ARRAY); return false; } min_value=0; int index=ArrayMinimum(array); if(index==WRONG_VALUE) return false; min_value=array[index]; return true; } //+------------------------------------------------------------------+
これらの関数は、リンクを介して渡された配列にある最大値または最小値を返します。関数からの戻り値は「無効な」値として配列セルに配置される可能性があるため、bool型です。たとえば、配列からデータを受信したときに-1が返される場合(多くの関数で行われるように)、そのような値は配列に設定されている値の1つにすることができます。有効な値(-1)が返された場合、プログラムはこれがエラーであると想定します。これは正しくありません。したがって、エラーが発生した場合はfalseを返し、配列で見つかった最大値または最小値はリンクを介して関数に渡された変数に設定されます。関数がtrueを返す場合、変数は目的の値を格納します。source変数は関数の呼び出し元メソッドの名前を受け取るため、エラーが発生した場合、関数の呼び出し元メソッドの名前とエラーメッセージを確認できます。
変数は、描画された形状タイプの説明を返す関数も受け取ります。
//+------------------------------------------------------------------+ //| Return the description of the drawn shape type | //+------------------------------------------------------------------+ string FigureTypeDescription(const ENUM_FIGURE_TYPE figure_type) { return(StringSubstr(EnumToString(figure_type),12)); } //+------------------------------------------------------------------+
ここでは、列挙形式で関数に渡されたタイプが文字列での説明に変換されます。12番目の記号の位置からの部分文字列は、不要なテキストをトリミングするためにタイプテキスト表現から取得されます。たとえば、FIGURE_TYPE_TRIANGLEの形状タイプは「FIGURE_TYPE_TRIANGLE」に変換され、このテキストから12番目の記号から始まる必要な部分文字列「FIGURE_TYPE_ TRIANGLE 」が取得され、結果として「TRIANGLE」文字列が返されます。
前回の記事では、背景の一部を配列にコピーするメソッドを作成するときに、コピーされた背景の長方形のサイズと座標をフォームに表示されるテキストサイズによって定義しました。ここでは画像も表示します。それらのサイズは、テキストサイズによって定義されなくなるため、背景部分のコピーされた長方形の座標とサイズを定義するメソッドを作成する必要があります。
グラフィック要素クラスの\MQL5\Include\DoEasy\Objects\Graph\GCnvElement.mqhファイルで、メソッドの名前を変更します。
//--- Return coordinate offsets relative to the text anchor point void TextGetShiftXY(const string text, // Text for calculating the size of its outlining rectangle const ENUM_TEXT_ANCHOR anchor,// Text anchor point, relative to which the offsets are calculated int &shift_x, // X coordinate of the rectangle upper left corner int &shift_y); // Y coordinate of the rectangle upper left corner
現在、このメソッドはGetShiftXYbyText()と呼ばれています。画像のコピーされた部分の座標とサイズをオブジェクトのアンカーポイントを基準にして指定されたサイズで返す新しいメソッドを宣言します。
//--- Return coordinate offsets relative to the text anchor point by text void GetShiftXYbyText(const string text, // Text for calculating the size of its outlining rectangle const ENUM_TEXT_ANCHOR anchor, // Text anchor point, relative to which the offsets are calculated int &shift_x, // X coordinate of the rectangle upper left corner int &shift_y); // Y coordinate of the rectangle upper left corner //--- Return coordinate offsets relative to the rectangle anchor point by size void GetShiftXYbySize(const int width, //Rectangle size by width const int height, //Rectangle size by height const ENUM_TEXT_ANCHOR anchor, // Rectangle anchor point, relative to which the offsets are calculated int &shift_x, // X coordinate of the rectangle upper left corner int &shift_y); // Y coordinate of the rectangle upper left corner
クラスの最後に実装します。
以下は、サイズごとに長方形のアンカーポイントを基準にした座標オフセットを返すメソッドです。
//+------------------------------------------------------------------+ //| Return coordinate offsets relative to the rectangle anchor point | //| by size | //+------------------------------------------------------------------+ void CGCnvElement::GetShiftXYbySize(const int width,const int height,const ENUM_TEXT_ANCHOR anchor,int &shift_x,int &shift_y) { switch(anchor) { case TEXT_ANCHOR_LEFT_TOP : shift_x=0; shift_y=0; break; case TEXT_ANCHOR_LEFT_CENTER : shift_x=0; shift_y=-height/2; break; case TEXT_ANCHOR_LEFT_BOTTOM : shift_x=0; shift_y=-height; break; case TEXT_ANCHOR_CENTER_TOP : shift_x=-width/2; shift_y=0; break; case TEXT_ANCHOR_CENTER : shift_x=-width/2; shift_y=-height/2; break; case TEXT_ANCHOR_CENTER_BOTTOM : shift_x=-width/2; shift_y=-height; break; case TEXT_ANCHOR_RIGHT_TOP : shift_x=-width; shift_y=0; break; case TEXT_ANCHOR_RIGHT_CENTER : shift_x=-width; shift_y=-height/2; break; case TEXT_ANCHOR_RIGHT_BOTTOM : shift_x=-width; shift_y=-height; break; default : shift_x=0; shift_y=0; break; } } //+------------------------------------------------------------------+
ここでは、コピーされた領域の幅と高さ、およびメソッドに渡されたアンカーポイントに応じて、アンカーポイントを基準にした座標オフセットを計算し、リンクを介してメソッドに渡された変数に書き込みます。
以下は、テキストアンカーポイントを基準にした座標オフセットを返すメソッドです。
//+------------------------------------------------------------------+ //| Return coordinate offsets relative to the text anchor point | //+------------------------------------------------------------------+ void CGCnvElement::GetShiftXYbyText(const string text,const ENUM_TEXT_ANCHOR anchor,int &shift_x,int &shift_y) { int tw=0,th=0; this.TextSize(text,tw,th); this.GetShiftXYbySize(tw,th,anchor,shift_x,shift_y); } //+------------------------------------------------------------------+
ここでは、まずメソッドに渡されるテキストのサイズを定義して、 保存されたフォームの背景画像領域の座標オフセットを定義するために上記のメソッドを呼び出します 。
前回の記事では、フォームの背景画像の一部をコピーしてその後配列から復元するためのクラスを開発しました。クラスは、フォームオブジェクトクラスファイルで設定されました。次に、フォームオブジェクトクラスファイルからクラスを削除して、新しく作成されたフレームオブジェクトクラスの新しいファイルに再配置します(クラスを別々のファイルに書き込んで保存する方がよいことがわかりました)。
単一のアニメーションフレームの基本クラスを作成しましょう。このクラスには、そのすべての子孫に共通のプロパティが含まれます。
「アニメーションフレーム」オブジェクトクラス
\MQL5\Include\DoEasy\Objects\Graph\で、新しいAnimations\フォルダーとCFrameクラスのFrame.mqhファイルを作成します。
クラスファイルにグラフィック要素オブジェクトクラスのファイルをインクルードします。
//+------------------------------------------------------------------+ //| Frame.mqh | //| Copyright 2021, MetaQuotes Ltd. | //| https://mql5.com/en/users/artmedia70 | //+------------------------------------------------------------------+ #property copyright "Copyright 2021, MetaQuotes Ltd." #property link "https://mql5.com/en/users/artmedia70" #property version "1.00" #property strict // Necessary for mql4 //+------------------------------------------------------------------+ //| Include files | //+------------------------------------------------------------------+ #include "..\GCnvElement.mqh" //+------------------------------------------------------------------+
次に、フォームオブジェクトクラスファイルから削除したピクセルコピーオブジェクトクラスを配置します(前の記事で検討しました)。
//+------------------------------------------------------------------+ //| Frame.mqh | //| Copyright 2021, MetaQuotes Ltd. | //| https://mql5.com/en/users/artmedia70 | //+------------------------------------------------------------------+ #property copyright "Copyright 2021, MetaQuotes Ltd." #property link "https://mql5.com/en/users/artmedia70" #property version "1.00" #property strict // Necessary for mql4 //+------------------------------------------------------------------+ //| Include files | //+------------------------------------------------------------------+ #include "..\GCnvElement.mqh" //+------------------------------------------------------------------+ //| Pixel copier class | //+------------------------------------------------------------------+ class CPixelCopier : public CObject { protected: CGCnvElement *m_element; // Pointer to the graphical element uint m_array[]; // Pixel array int m_id; // ID int m_x; // X coordinate of the upper left corner int m_y; // Y coordinate of the upper left corner int m_w; // Copied image width int m_h; // Copied image height int m_wr; // Calculated copied image width int m_hr; // Calculated copied image height public: //--- Compare CPixelCopier objects by a specified property (to sort the list by an object property) virtual int Compare(const CObject *node,const int mode=0) const { const CPixelCopier *obj_compared=node; return(mode==0 ? (this.ID()>obj_compared.ID() ? 1 : this.ID()<obj_compared.ID() ? -1 : 0) : WRONG_VALUE); } //--- Set the properties void SetElement(CGCnvElement *element) { this.m_element=element; } void SetID(const int id) { this.m_id=id; } void SetCoordX(const int value) { this.m_x=value; } void SetCoordY(const int value) { this.m_y=value; } void SetWidth(const int value) { this.m_w=value; } void SetHeight(const int value) { this.m_h=value; } //--- Get the properties int ID(void) const { return this.m_id; } int CoordX(void) const { return this.m_x; } int CoordY(void) const { return this.m_y; } int Width(void) const { return this.m_w; } int Height(void) const { return this.m_h; } int WidthReal(void) const { return this.m_wr; } int HeightReal(void) const { return this.m_hr; } //--- Copy the part or the entire image to the array bool CopyImgDataToArray(const uint x_coord,const uint y_coord,uint width,uint height); //--- Copy the part or the entire image from the array to the canvas bool CopyImgDataToCanvas(const int x_coord,const int y_coord); //--- Constructors CPixelCopier (void){;} CPixelCopier (const int id, const int x, const int y, const int w, const int h, CGCnvElement *element) : m_id(id), m_x(x),m_y(y),m_w(w),m_wr(w),m_h(h),m_hr(h) { this.m_element=element; } ~CPixelCopier (void){;} }; //+------------------------------------------------------------------+ //| Copy part or all of the image to the array | //+------------------------------------------------------------------+ bool CPixelCopier::CopyImgDataToArray(const uint x_coord,const uint y_coord,uint width,uint height) { //--- Assign coordinate values, passed to the method, to the variables int x1=(int)x_coord; int y1=(int)y_coord; //--- If X coordinates goes beyond the form on the right or Y coordinate goes beyond the form at the bottom, //--- there is nothing to copy, the copied area is outside the form. Return 'false' if(x1>this.m_element.Width()-1 || y1>this.m_element.Height()-1) return false; //--- Assign the width and height values of the copied area to the variables //--- If the passed width and height are equal to zero, assign the form width and height to them this.m_wr=int(width==0 ? this.m_element.Width() : width); this.m_hr=int(height==0 ? this.m_element.Height() : height); //--- If X and Y coordinates are equal to zero (the upper left corner of the form), as well as the width and height are equal to the form width and height, //--- the copied area is equal to the entire form area. Copy the entire form (returning it from the method) using the ImageCopy() method //if(x1==0 && y1==0 && this.m_wr==this.m_element.Width() && this.m_hr==this.m_element.Height()) // return this.m_element.ImageCopy(DFUN,this.m_array); //--- Calculate the right X coordinate and lower Y coordinate of the rectangle area int x2=int(x1+this.m_wr-1); int y2=int(y1+this.m_hr-1); //--- If the calculated X coordinate goes beyond the form, the right edge of the form will be used as the coordinate if(x2>=this.m_element.Width()-1) x2=this.m_element.Width()-1; //--- If the calculated Y coordinate goes beyond the form, the bottom edge of the form will be used as the coordinate if(y2>=this.m_element.Height()-1) y2=this.m_element.Height()-1; //--- Calculate the copied width and height this.m_wr=x2-x1+1; this.m_hr=y2-y1+1; //--- Define the necessary size of the array, which is to store all image pixels with calculated width and height int size=this.m_wr*this.m_hr; //--- If failed to set the array size, inform of that and return 'false' if(::ArrayResize(this.m_array,size)!=size) { CMessage::ToLog(DFUN,MSG_LIB_SYS_FAILED_ARRAY_RESIZE,true); return false; } //--- Set the index in the array for recording the image pixel int n=0; //--- In a loop by the calculated height of the copied area, starting from the specified Y coordinate for(int y=y1;y<y1+this.m_hr;y++) { //--- in a loop by the calculated width of the copied area, starting from the specified X coordinate for(int x=x1;x<x1+this.m_wr;x++) { //--- Copy the next image pixel to the array and increase the array index this.m_array[n]=this.m_element.GetCanvasObj().PixelGet(x,y); n++; } } //--- Successful - return 'true' return true; } //+------------------------------------------------------------------+ //| Copy the part or the entire image from the array to the canvas | //+------------------------------------------------------------------+ bool CPixelCopier::CopyImgDataToCanvas(const int x_coord,const int y_coord) { //--- If the array of saved pixels is empty, inform of that and return 'false' int size=::ArraySize(this.m_array); if(size==0) { CMessage::ToLog(DFUN,MSG_CANV_ELEMENT_ERR_EMPTY_ARRAY,true); return false; } //--- Set the index of the array for reading the image pixel int n=0; //--- In a loop by the previously calculated height of the copied area, starting from the specified Y coordinate for(int y=y_coord;y<y_coord+this.m_hr;y++) { //--- in a loop by the previously calculated width of the copied area, starting from the specified X coordinate for(int x=x_coord;x<x_coord+this.m_wr;x++) { //--- Restore the next image pixel from the array and increase the array index this.m_element.GetCanvasObj().PixelSet(x,y,this.m_array[n]); n++; } } return true; } //+------------------------------------------------------------------+
ここで(一時的に)変更されたのは、以前に保存したフォーム画像全体をコピーする必要があるコード文字列をコメントアウトしたという事実だけです。ここにエラーがあり、フォームオブジェクト配列からではなく、グラフィカルリソースから背景が直接コピーされました。グラフィカルリソースには、フォームの背景画像に適用されたすべての変更が含まれています。これを修正するには、元のフォーム画像のコピーを特徴とする別の配列にフォームの外観を保存する必要があります。すでにそのような配列がありますが、作成直後に元のフォームの外観を保存するためのメソッドを作成する必要があります。それまで、これらの文字列をコメントアウトしました。フォームの背景の一部ではなく全体のサイズの背景は、フォームの背景の一部を復元するループで復元されます(つまり、ある配列を別の配列にコピーするのではなく、フォームの背景要素を要素ごとに入力することによって) フォームの背景画像の一部の保存されたコピーを格納する配列)。
次に、ピクセルコピークラスの後に、アニメーションフレームオブジェクトクラスの本体を記述します。
//+------------------------------------------------------------------+ //| Single animation frame class | //+------------------------------------------------------------------+ class CFrame : public CPixelCopier { protected: ENUM_ANIMATION_FRAME_TYPE m_frame_figure_type; // Type of the figure drawn by the frame ENUM_TEXT_ANCHOR m_anchor_last; // Last frame anchor point double m_x_last; // X coordinate of the upper left corner of the last frame double m_y_last; // Y coordinate of the upper left corner of the last frame int m_shift_x_prev; // Offset of the X coordinate of the last frame upper left corner int m_shift_y_prev; // Offset of the Y coordinate of the last frame upper left corner public: //--- Return the last (1) anchor point, (2) X and (3) Y coordinate, //--- previous offset by (4) X and (5) Y, (6) type of the figure drawn by the frame ENUM_TEXT_ANCHOR LastAnchor(void) const { return this.m_anchor_last; } double LastX(void) const { return this.m_x_last; } double LastY(void) const { return this.m_y_last; } int LastShiftX(void) const { return this.m_shift_x_prev; } int LastShiftY(void) const { return this.m_shift_y_prev; } ENUM_ANIMATION_FRAME_TYPE FrameFigureType(void) const { return this.m_frame_figure_type; } //--- Default constructor CFrame(); protected: //--- Text frame constructor CFrame(const int id, const int x, const int y, const string text, CGCnvElement *element); //--- Rectangle frame constructor CFrame(const int id, const int x, const int y, const int w, const int h, CGCnvElement *element); }; //+------------------------------------------------------------------+
クラスはピクセルコピーオブジェクトクラスから派生しているため、実際には、ピクセルコピーオブジェクトクラスです。
クラスで宣言されたすべての変数とメソッドはコメントで説明されています。このクラスは他のアニメーションフレームクラスの基本であるため、子孫に共通するすべてのプロパティとメソッドをここで設定します。
画像を復元するときに画像の前に保存した部分の座標を定義できるように、最後の座標、オフセット、アンカーポイントを返す変数とメソッドが必要です。これらの座標は、その上に描画された画像によって消去された保存済みの背景を配置するために使用されます。
このクラスは3つのコンストラクタを備えています。
- デフォルトのpublicコンストラクタ
- protectedテキストフレームオブジェクトコンストラクタ
- protected長方形フレームオブジェクトコンストラクタ
protectedコンストラクタの実装について考えてみましょう。
以下は、長方形フレームのコンストラクタです。
//+------------------------------------------------------------------+ //| Constructor of rectangle frames | //+------------------------------------------------------------------+ CFrame::CFrame(const int id,const int x,const int y,const int w,const int h,CGCnvElement *element) : CPixelCopier(id,x,y,w,h,element) { this.m_frame_figure_type=ANIMATION_FRAME_TYPE_QUAD; this.m_anchor_last=TEXT_ANCHOR_LEFT_TOP; this.m_x_last=x; this.m_y_last=y; this.m_shift_x_prev=0; this.m_shift_y_prev=0; } //+------------------------------------------------------------------+
コンストラクタは、作成された長方形フレームオブジェクトのID、X座標とY座標、フレームの幅と高さ、および新しいオブジェクトが作成されたグラフィック要素オブジェクトへのポインタを受け取ります。クラスはピクセルコピーオブジェクトの子孫であるため、必要なすべてのパラメータをコンストラクタ初期化リストの基本クラスコンストラクタに渡します。これらのパラメータは、コンストラクタ引数に渡されるプロパティのすべてです。
デフォルトパラメータをクラス本体のすべてのクラスメンバー変数に設定します。
以下は、テキストフレームのコンストラクタです。
//+------------------------------------------------------------------+ //| The constructor of text frames | //+------------------------------------------------------------------+ CFrame::CFrame(const int id, const int x, const int y, const string text, CGCnvElement *element) { int w=0,h=0; this.m_element=element; this.m_element.GetCanvasObj().TextSize(text,w,h); this.m_anchor_last=this.m_element.TextAnchor(); this.m_frame_figure_type=ANIMATION_FRAME_TYPE_TEXT; this.m_x_last=x; this.m_y_last=y; this.m_shift_x_prev=0; this.m_shift_y_prev=0; CPixelCopier::SetID(id); CPixelCopier::SetCoordX(x); CPixelCopier::SetCoordY(y); CPixelCopier::SetWidth(w); CPixelCopier::SetHeight(h); } //+------------------------------------------------------------------+
コンストラクタは、作成されたテキストフレームオブジェクトのID、そのX座標とY座標、テキスト、および新しいオブジェクトが作成されたグラフィック要素オブジェクトへのポインタを受け取ります。
クラス本体で、最初にテキストサイズを定義し、次にクラスメンバー変数のデフォルト値を設定し、作成されたオブジェクトのID、その座標、およびテキストサイズを親ピクセルコピーオブジェクトに設定します。
アニメーションフレームオブジェクトクラスの子孫のオブジェクトのクラスを作成します。
テキストアニメーションフレームクラス
\MQL5\Include\DoEasy\Objects\Graph\Animations\で、CFrameTextクラスの新しいFrameText.mqhファイルを作成します。
アニメーションフレームクラスのファイルをファイルにインクルードする必要がありますが、クラス自体はその子孫である必要があります。
//+------------------------------------------------------------------+ //| FrameText.mqh | //| Copyright 2021, MetaQuotes Ltd. | //| https://mql5.com/en/users/artmedia70 | //+------------------------------------------------------------------+ #property copyright "Copyright 2021, MetaQuotes Ltd." #property link "https://mql5.com/en/users/artmedia70" #property version "1.00" #property strict // Necessary for mql4 //+------------------------------------------------------------------+ //| Include files | //+------------------------------------------------------------------+ #include "Frame.mqh" //+------------------------------------------------------------------+ //| Single text animation frame class | //+------------------------------------------------------------------+ class CFrameText : public CFrame { private: public: //--- Display the text on the background while saving and restoring the background bool TextOnBG(const string text,const int x,const int y,const ENUM_TEXT_ANCHOR anchor,const color clr,const uchar opacity,bool redraw=false); //--- Constructors CFrameText() {;} CFrameText(const int id,CGCnvElement *element) : CFrame(id,0,0,"",element) {} }; //+------------------------------------------------------------------+
ここには、フォームオブジェクトの背景にテキストを描画するための1つのpublicメソッドと 2つのコンストラクタ(デフォルトとパラメトリックコンストラクタ)があります。
パラメトリックコンストラクタは、作成されたテキストアニメーションフレームオブジェクトのIDと、オブジェクトが作成されたグラフィック要素へのポインタを受け取ります。初期化リストでは、親クラスはコンストラクタ引数で渡されたID、座標とテキストのデフォルト値、およびコンストラクタ引数で渡されたグラフィック要素へのポインタを受け取ります。
以下は、背景を保存および復元しながら背景にテキストを表示するメソッドです。
//+-------------------------------------------------------------------------------+ //| Display the text on the background, while saving and restoring the background | //+-------------------------------------------------------------------------------+ bool CFrameText::TextOnBG(const string text,const int x,const int y,const ENUM_TEXT_ANCHOR anchor,const color clr,const uchar opacity,bool redraw=false) { //--- Find out the width and height of the text outlining the rectangle (to be used as the size of the saved area) int w=0,h=0; this.m_element.TextSize(text,w,h); //--- Calculate coordinate offsets for the saved area depending on the text anchor point int shift_x=0,shift_y=0; this.m_element.GetShiftXYbySize(w,h,anchor,shift_x,shift_y); //--- If the pixel array is not empty, the background under the text has already been saved - //--- restore the previously saved background (by the previous coordinates and offsets) if(::ArraySize(this.m_array)>0) { if(!CPixelCopier::CopyImgDataToCanvas(int(this.m_x_last+this.m_shift_x_prev),int(this.m_y_last+this.m_shift_y_prev))) return false; } //--- If a background area with calculated coordinates and size under the future text is successfully saved if(!CPixelCopier::CopyImgDataToArray(x+shift_x,y+shift_y,w,h)) return false; //--- Draw the text and update the element this.m_element.Text(x,y,text,clr,opacity,anchor); this.m_element.Update(redraw); this.m_anchor_last=anchor; this.m_x_last=x; this.m_y_last=y; this.m_shift_x_prev=shift_x; this.m_shift_y_prev=shift_y; return true; } //+------------------------------------------------------------------+
メソッドのロジックについては、コードコメントで詳しく説明されています。前回の記事でテスト中にすでに検討した(テストEAのOnChartEvent()ハンドラで同様のロジックが設定されました)ため、ここではすべてが明確であると思います。フォームにテキストが描画された後、そのアンカーポイント、X座標とY座標、およびアンカーポイントを基準にしたオフセット値が、親クラスの変数に設定されて、テキストで上書きされたフォーム画像の背景を復元するために使用されます。
次に、アニメーションフレームオブジェクトの2番目の子孫クラスを作成しましょう。
長方形アニメーションフレームクラス
\MQL5\Include\DoEasy\Objects\Graph\Animations\で、CFrameQuadクラスの新しいFrameQuad.mqhファイルを作成します。
親クラスファイルとクラスファイルにインクルードします(およびクラスファイルから派生します)。
//+------------------------------------------------------------------+ //| FrameQuad.mqh | //| Copyright 2021, MetaQuotes Ltd. | //| https://mql5.com/en/users/artmedia70 | //+------------------------------------------------------------------+ #property copyright "Copyright 2021, MetaQuotes Ltd." #property link "https://mql5.com/en/users/artmedia70" #property version "1.00" #property strict // Necessary for mql4 //+------------------------------------------------------------------+ //| Include files | //+------------------------------------------------------------------+ #include "Frame.mqh" //+------------------------------------------------------------------+ //| Single sprite animation frame class | //+------------------------------------------------------------------+ class CFrameQuad : public CFrame { private: double m_quad_x; // X coordinate of the rectangle enclosing the shape double m_quad_y; // Y coordinate of the rectangle enclosing the shape uint m_quad_width; // Width of the rectangle enclosing the shape uint m_quad_height; // Height of the rectangle enclosing the shape public: //--- Constructors CFrameQuad() {;} CFrameQuad(const int id,CGCnvElement *element) : CFrame(id,0,0,0,0,element) { this.m_anchor_last=TEXT_ANCHOR_LEFT_TOP; } //+------------------------------------------------------------------+
クラスのprivateセクションで、描画された形状を囲む長方形の座標とサイズを格納するクラスメンバー変数を宣言します。これらは、描画された形状によって上書きされた、保存された背景パーツの画像領域の座標とサイズです。
パラメトリックコンストラクタは、作成されたオブジェクトのIDと、オブジェクトが作成されたグラフィック要素へのポインタを受け取ります。メソッド引数で渡されるID、デフォルトの座標とフレームサイズのパラメータ、およびグラフィック要素へのポインタは、コンストラクタ初期化リストの親クラスコンストラクタに渡されます。コンストラクタ本体で、描画した形状のアンカーポイントを「左上」に設定します。これは、コピーされた領域のオフセットを計算するために必要です。この値では、XおよびY座標オフセットのアンカーポイントはゼロに等しくなります。
CCanvasクラスには多数の描画メソッドがあるため、フォームオブジェクトの背景に形状を描画するためのすべての適切なメソッドはクラスのpublicセクションで宣言され、背景の復元が続きます。
public: //--- Constructors CFrameQuad() {;} CFrameQuad(const int id,CGCnvElement *element) : CFrame(id,0,0,0,0,element) { this.m_anchor_last=TEXT_ANCHOR_LEFT_TOP; } //+------------------------------------------------------------------+ //| Drawing primitives while saving and restoring the background | //+------------------------------------------------------------------+ //+------------------------------------------------------------------+ //| Methods of drawing primitives without smoothing | //+------------------------------------------------------------------+ //--- Set the color of the dot with the specified coordinates bool SetPixelOnBG(const int x,const int y,const color clr,const uchar opacity=255,const bool redraw=false); //--- Draw a segment of a vertical line bool DrawLineVerticalOnBG(const int x, // X coordinate of the segment const int y1, // Y coordinate of the segment first point const int y2, // Y coordinate of the segment second point const color clr, // Color const uchar opacity=255, // Opacity const bool redraw=false); // Chart redraw flag //--- Draw a segment of a horizontal line bool DrawLineHorizontalOnBG(const int x1, // X coordinate of the segment first point const int x2, // X coordinate of the segment second point const int y, // Segment Y coordinate const color clr, // Color const uchar opacity=255, // Opacity const bool redraw=false); // Chart redraw flag //--- Draw a segment of a freehand line bool DrawLineOnBG(const int x1, // X coordinate of the segment first point const int y1, // Y coordinate of the segment first point const int x2, // X coordinate of the segment second point const int y2, // Y coordinate of the segment second point const color clr, // Color const uchar opacity=255, // Opacity const bool redraw=false); // Chart redraw flag //--- Draw a polyline bool DrawPolylineOnBG(int &array_x[], // Array with the X coordinates of polyline points int &array_y[], // Array with the Y coordinates of polyline points const color clr, // Color const uchar opacity=255, // Opacity const bool redraw=false); // Chart redraw flag //--- Draw a polygon bool DrawPolygonOnBG(int &array_x[], // Array with the X coordinates of polygon points int &array_y[], // Array with the Y coordinates of polygon points const color clr, // Color const uchar opacity=255, // Opacity const bool redraw=false); // Chart redraw flag //--- Draw a rectangle using two points bool DrawRectangleOnBG(const int x1, // X coordinate of the first point defining the rectangle const int y1, // Y coordinate of the first point defining the rectangle const int x2, // X coordinate of the second point defining the rectangle const int y2, // Y coordinate of the second point defining the rectangle const color clr, // Color const uchar opacity=255, // Opacity const bool redraw=false); // Chart redraw flag //--- Draw a circle bool DrawCircleOnBG(const int x, // X coordinate of the circle center const int y, // Y coordinate of the circle center const int r, // Circle radius const color clr, // Color const uchar opacity=255, // Opacity const bool redraw=false); // Chart redraw flag //--- Draw a triangle bool DrawTriangleOnBG(const int x1, // X coordinate of the triangle first vertex const int y1, // Y coordinate of the triangle first vertex const int x2, // X coordinate of the triangle second vertex const int y2, // Y coordinate of the triangle second vertex const int x3, // X coordinate of the triangle third vertex const int y3, // Y coordinate of the triangle third vertex const color clr, // Color const uchar opacity=255, // Opacity const bool redraw=false); // Chart redraw flag //--- Draw an ellipse using two points bool DrawEllipseOnBG(const int x1, // X coordinate of the first point defining the ellipse const int y1, // Y coordinate of the first point defining the ellipse const int x2, // X coordinate of the second point defining the ellipse const int y2, // Y coordinate of the second point defining the ellipse const color clr, // Color const uchar opacity=255, // Opacity const bool redraw=false); // Chart redraw flag //--- Draw an arc of an ellipse inscribed in a rectangle with corners at (x1,y1) and (x2,y2). //--- The arc boundaries are clipped by lines from the center of the ellipse, which extend to two points with coordinates (x3,y3) and (x4,y4) bool DrawArcOnBG(const int x1, // X coordinate of the top left corner forming the rectangle const int y1, // Y coordinate of the top left corner forming the rectangle const int x2, // X coordinate of the bottom right corner forming the rectangle const int y2, // Y coordinate of the bottom right corner forming the rectangle const int x3, // X coordinate of the first point, to which a line from the rectangle center is drawn in order to obtain the arc boundary const int y3, // Y coordinate of the first point, to which a line from the rectangle center is drawn in order to obtain the arc boundary const int x4, // X coordinate of the second point, to which a line from the rectangle center is drawn in order to obtain the arc boundary const int y4, // Y coordinate of the second point, to which a line from the rectangle center is drawn in order to obtain the arc boundary const color clr, // Color const uchar opacity=255, // Opacity const bool redraw=false); // Chart redraw flag //--- Draw a filled sector of an ellipse inscribed in a rectangle with corners at (x1,y1) and (x2,y2). //--- The sector boundaries are clipped by lines from the center of the ellipse, which extend to two points with coordinates (x3,y3) and (x4,y4) bool DrawPieOnBG(const int x1, // X coordinate of the upper left corner of the rectangle const int y1, // Y coordinate of the upper left corner of the rectangle const int x2, // X coordinate of the bottom right corner of the rectangle const int y2, // Y coordinate of the bottom right corner of the rectangle const int x3, // X coordinate of the first point to find the arc boundaries const int y3, // Y coordinate of the first point to find the arc boundaries const int x4, // X coordinate of the second point to find the arc boundaries const int y4, // Y coordinate of the second point to find the arc boundaries const color clr, // Line color const color fill_clr, // Fill color const uchar opacity=255, // Opacity const bool redraw=false); // Chart redraw flag //+------------------------------------------------------------------+ //| Methods of drawing filled primitives without smoothing | //+------------------------------------------------------------------+ //--- Fill in the area bool FillOnBG(const int x, // X coordinate of the filling start point const int y, // Y coordinate of the filling start point const color clr, // Color const uchar opacity=255, // Opacity const uint threshould=0, // Threshold const bool redraw=false); // Chart redraw flag //--- Draw a filled rectangle bool DrawRectangleFillOnBG(const int x1, // X coordinate of the first point defining the rectangle const int y1, // Y coordinate of the first point defining the rectangle const int x2, // X coordinate of the second point defining the rectangle const int y2, // Y coordinate of the second point defining the rectangle const color clr, // Color const uchar opacity=255, // Opacity const bool redraw=false); // Chart redraw flag //--- Draw a filled circle bool DrawCircleFillOnBG(const int x, // X coordinate of the circle center const int y, // Y coordinate of the circle center const int r, // Circle radius const color clr, // Color const uchar opacity=255, // Opacity const bool redraw=false); // Chart redraw flag //--- Draw a filled triangle bool DrawTriangleFillOnBG(const int x1, // X coordinate of the triangle first vertex const int y1, // Y coordinate of the triangle first vertex const int x2, // X coordinate of the triangle second vertex const int y2, // Y coordinate of the triangle second vertex const int x3, // X coordinate of the triangle third vertex const int y3, // Y coordinate of the triangle third vertex const color clr, // Color const uchar opacity=255, // Opacity const bool redraw=false); // Chart redraw flag //--- Draw a filled polygon bool DrawPolygonFillOnBG(int &array_x[], // Array with the X coordinates of polygon points int &array_y[], // Array with the Y coordinates of polygon points const color clr, // Color const uchar opacity=255, // Opacity const bool redraw=false); // Chart redraw flag //--- Draw a filled ellipse inscribed in a rectangle with the specified coordinates bool DrawEllipseFillOnBG(const int x1, // X coordinate of the top left corner forming the rectangle const int y1, // Y coordinate of the top left corner forming the rectangle const int x2, // X coordinate of the bottom right corner forming the rectangle const int y2, // Y coordinate of the bottom right corner forming the rectangle const color clr, // Color const uchar opacity=255, // Opacity const bool redraw=false); // Chart redraw flag //+------------------------------------------------------------------+ //| Methods of drawing primitives using smoothing | //+------------------------------------------------------------------+ //--- Draw a point using AntiAliasing algorithm bool SetPixelAAOnBG(const double x, // Point X coordinate const double y, // Point Y coordinate const color clr, // Color const uchar opacity=255, // Opacity const bool redraw=false); // Chart redraw flag //--- Draw a segment of a freehand line using AntiAliasing algorithm bool DrawLineAAOnBG(const int x1, // X coordinate of the segment first point const int y1, // Y coordinate of the segment first point const int x2, // X coordinate of the segment second point const int y2, // Y coordinate of the segment second point const color clr, // Color const uchar opacity=255, // Opacity const bool redraw=false, // Chart redraw flag const uint style=UINT_MAX); // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value //--- Draw a segment of a freehand line using Wu algorithm bool DrawLineWuOnBG(const int x1, // X coordinate of the segment first point const int y1, // Y coordinate of the segment first point const int x2, // X coordinate of the segment second point const int y2, // Y coordinate of the segment second point const color clr, // Color const uchar opacity=255, // Opacity const bool redraw=false, // Chart redraw flag const uint style=UINT_MAX); // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value //--- Draws a segment of a freehand line having a specified width using smoothing algorithm with the preliminary filtration bool DrawLineThickOnBG(const int x1, // X coordinate of the segment first point const int y1, // Y coordinate of the segment first point const int x2, // X coordinate of the segment second point const int y2, // Y coordinate of the segment second point const int size, // Line width const color clr, // Color const uchar opacity=255, // Opacity const bool redraw=false, // Chart redraw flag const uint style=STYLE_SOLID, // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value ENUM_LINE_END end_style=LINE_END_ROUND); // Line style is one of the ENUM_LINE_END enumeration's values //--- Draw a vertical segment of a freehand line having a specified width using smoothing algorithm with the preliminary filtration bool DrawLineThickVerticalOnBG(const int x, // X coordinate of the segment const int y1, // Y coordinate of the segment first point const int y2, // Y coordinate of the segment second point const int size, // line width const color clr, // Color const uchar opacity=255, // Opacity const bool redraw=false, // Chart redraw flag const uint style=STYLE_SOLID, // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value const ENUM_LINE_END end_style=LINE_END_ROUND); // Line style is one of the ENUM_LINE_END enumeration's values //--- Draw a horizontal segment of a freehand line having a specified width using smoothing algorithm with the preliminary filtration bool DrawLineThickHorizontalOnBG(const int x1, // X coordinate of the segment first point const int x2, // X coordinate of the segment second point const int y, // Segment Y coordinate const int size, // line width const color clr, // Color const uchar opacity=255, // Opacity const bool redraw=false, // Chart redraw flag const uint style=STYLE_SOLID, // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value const ENUM_LINE_END end_style=LINE_END_ROUND); // Line style is one of the ENUM_LINE_END enumeration's values //--- Draws a polyline using AntiAliasing algorithm bool DrawPolylineAAOnBG(int &array_x[], // Array with the X coordinates of polyline points int &array_y[], // Array with the Y coordinates of polyline points const color clr, // Color const uchar opacity=255, // Opacity const bool redraw=false, // Chart redraw flag const uint style=UINT_MAX); // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value //--- Draws a polyline using Wu algorithm bool DrawPolylineWuOnBG(int &array_x[], // Array with the X coordinates of polyline points int &array_y[], // Array with the Y coordinates of polyline points const color clr, // Color const uchar opacity=255, // Opacity const bool redraw=false, // Chart redraw flag const uint style=UINT_MAX); // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value //--- Draw a polyline with a specified width consecutively using two antialiasing algorithms. //--- First, individual line segments are smoothed based on Bezier curves. //--- Then, the raster antialiasing algorithm is applied to the polyline built from these segments to improve the rendering quality bool DrawPolylineSmoothOnBG(const int &array_x[], // Array with the X coordinates of polyline points const int &array_y[], // Array with the Y coordinates of polyline points const int size, // Line width const color clr, // Color const uchar opacity=255, // Opacity const double tension=0.5, // Smoothing parameter value const double step=10, // Approximation step const bool redraw=false, // Chart redraw flag const ENUM_LINE_STYLE style=STYLE_SOLID, // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value const ENUM_LINE_END end_style=LINE_END_ROUND);// Line style is one of the ENUM_LINE_END enumeration's values //--- Draw a polyline having a specified width using smoothing algorithm with the preliminary filtration bool DrawPolylineThickOnBG(const int &array_x[], // Array with the X coordinates of polyline points const int &array_y[], // Array with the Y coordinates of polyline points const int size, // Line width const color clr, // Color const uchar opacity=255, // Opacity const bool redraw=false, // Chart redraw flag const uint style=STYLE_SOLID, // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value ENUM_LINE_END end_style=LINE_END_ROUND); // Line style is one of the ENUM_LINE_END enumeration's values //--- Draw a polygon using AntiAliasing algorithm bool DrawPolygonAAOnBG(int &array_x[], // Array with the X coordinates of polygon points int &array_y[], // Array with the Y coordinates of polygon points const color clr, // Color const uchar opacity=255, // Opacity const bool redraw=false, // Chart redraw flag const uint style=UINT_MAX); // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value //--- Draw a polygon using Wu algorithm bool DrawPolygonWuOnBG(int &array_x[], // Array with the X coordinates of polygon points int &array_y[], // Array with the Y coordinates of polygon points const color clr, // Color const uchar opacity=255, // Opacity const bool redraw=false, // Chart redraw flag const uint style=UINT_MAX); // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value //--- Draw a polygon with a specified width consecutively using two smoothing algorithms. //--- First, individual segments are smoothed based on Bezier curves. //--- Then, the raster smoothing algorithm is applied to the polygon built from these segments to improve the rendering quality. bool DrawPolygonSmoothOnBG(int &array_x[], // Array with the X coordinates of polyline points int &array_y[], // Array with the Y coordinates of polyline points const int size, // Line width const color clr, // Color const uchar opacity=255, // Opacity const double tension=0.5, // Smoothing parameter value const double step=10, // Approximation step const bool redraw=false, // Chart redraw flag const ENUM_LINE_STYLE style=STYLE_SOLID, // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value const ENUM_LINE_END end_style=LINE_END_ROUND);// Line style is one of the ENUM_LINE_END enumeration's values //--- Draw a polygon having a specified width using smoothing algorithm with the preliminary filtration bool DrawPolygonThickOnBG(const int &array_x[], // array with the X coordinates of polygon points const int &array_y[], // array with the Y coordinates of polygon points const int size, // line width const color clr, // Color const uchar opacity=255, // Opacity const bool redraw=false, // Chart redraw flag const uint style=STYLE_SOLID, // line style ENUM_LINE_END end_style=LINE_END_ROUND); // line ends style //--- Draw a triangle using AntiAliasing algorithm bool DrawTriangleAAOnBG(const int x1, // X coordinate of the triangle first vertex const int y1, // Y coordinate of the triangle first vertex const int x2, // X coordinate of the triangle second vertex const int y2, // Y coordinate of the triangle second vertex const int x3, // X coordinate of the triangle third vertex const int y3, // Y coordinate of the triangle third vertex const color clr, // Color const uchar opacity=255, // Opacity const bool redraw=false, // Chart redraw flag const uint style=UINT_MAX); // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value //--- Draw a triangle using Wu algorithm bool DrawTriangleWuOnBG(const int x1, // X coordinate of the triangle first vertex const int y1, // Y coordinate of the triangle first vertex const int x2, // X coordinate of the triangle second vertex const int y2, // Y coordinate of the triangle second vertex const int x3, // X coordinate of the triangle third vertex const int y3, // Y coordinate of the triangle third vertex const color clr, // Color const uchar opacity=255, // Opacity const bool redraw=false, // Chart redraw flag const uint style=UINT_MAX); // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value //--- Draw a circle using AntiAliasing algorithm bool DrawCircleAAOnBG(const int x, // X coordinate of the circle center const int y, // Y coordinate of the circle center const double r, // Circle radius const color clr, // Color const uchar opacity=255, // Opacity const bool redraw=false, // Chart redraw flag const uint style=UINT_MAX); // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value //--- Draw a circle using Wu algorithm bool DrawCircleWuOnBG(const int x, // X coordinate of the circle center const int y, // Y coordinate of the circle center const double r, // Circle radius const color clr, // Color const uchar opacity=255, // Opacity const bool redraw=false, // Chart redraw flag const uint style=UINT_MAX); // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value //--- Draw an ellipse by two points using AntiAliasing algorithm bool DrawEllipseAAOnBG(const double x1, // X coordinate of the first point defining the ellipse const double y1, // Y coordinate of the first point defining the ellipse const double x2, // X coordinate of the second point defining the ellipse const double y2, // Y coordinate of the second point defining the ellipse const color clr, // Color const uchar opacity=255, // Opacity const bool redraw=false, // Chart redraw flag const uint style=UINT_MAX); // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value //--- Draw an ellipse by two points using Wu algorithm bool DrawEllipseWuOnBG(const int x1, // X coordinate of the first point defining the ellipse const int y1, // Y coordinate of the first point defining the ellipse const int x2, // X coordinate of the second point defining the ellipse const int y2, // Y coordinate of the second point defining the ellipse const color clr, // Color const uchar opacity=255, // Opacity const bool redraw=false, // Chart redraw flag const uint style=UINT_MAX); // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value }; //+------------------------------------------------------------------+
これらの各メソッドの実装は、同様の描画メソッドの実装と同様です。ただし、ほとんどすべての描画メソッドには固有のニュアンスがあります(2つの類似した描画メソッドの保存領域のサイズは、それぞれの特徴によって異なる場合があります)。
これらのメソッドの実装を見てみましょう。
以下は、指定された座標で点の色を設定するメソッドです。
//+------------------------------------------------------------------+ //| Set the color of the dot with the specified coordinates | //+------------------------------------------------------------------+ bool CFrameQuad::SetPixelOnBG(const int x,const int y,const color clr,const uchar opacity=255,const bool redraw=false) { //--- Set the coordinates of the outlining rectangle this.m_quad_x=x; this.m_quad_y=y; //--- Set the width and height of the image outlining the rectangle (to be used as the size of the saved area) this.m_quad_width=1; this.m_quad_height=1; //--- Calculate coordinate offsets for the saved area depending on the anchor point int shift_x=0,shift_y=0; this.m_element.GetShiftXYbySize(this.m_quad_width,this.m_quad_height,TEXT_ANCHOR_LEFT_TOP,shift_x,shift_y); //--- If the pixel array is not empty, the background under the image has already been saved - //--- restore the previously saved background (by the previous coordinates and offsets) if(::ArraySize(this.m_array)>0) { if(!CPixelCopier::CopyImgDataToCanvas(int(this.m_x_last+this.m_shift_x_prev),int(this.m_y_last+this.m_shift_y_prev))) return false; } //--- If a background area with calculated coordinates and size under the future image is successfully saved if(!CPixelCopier::CopyImgDataToArray(int(this.m_quad_x+shift_x),int(this.m_quad_y+shift_y),this.m_quad_width,this.m_quad_height)) return false; //--- Draw the shape and update the element this.m_element.SetPixel(x,y,clr,opacity); this.m_element.Update(redraw); this.m_anchor_last=TEXT_ANCHOR_LEFT_TOP; this.m_x_last=this.m_quad_x; this.m_y_last=this.m_quad_y; this.m_shift_x_prev=shift_x; this.m_shift_y_prev=shift_y; return true; } //+------------------------------------------------------------------+
メソッドのロジックは、コードで十分に詳細にコメントされています。もっと満遍なく考えてみましょう。ここでは、まず背景の長方形領域の左上端のX座標とY座標を設定して、描画された点の下で後に背景を復元するのに備えて配列に保存します。これはドット(1ピクセルの画像)のみであるため、保存された領域の座標は描画されたドットの座標と一致し、サイズは1ピクセルのサイズ(1 x 1)と一致します。
次に、背景が以前に保存されているかどうかを確認します(背景保存先の配列サイズがゼロ以外)。保存されている場合、以前に保存したフォームオブジェクトの背景を復元します(復元された領域の座標とサイズはクラス変数ですでに設定されています)。背景が正常に復元されたら、フォームの背景をドットの新しい座標で保存し、ドットを描画します。新しく描画されたドットによって消去された背景を後で復元するために、新しい座標、保存された領域のサイズ、シフトをクラス変数に保存します。
以下は、垂直線の線分を描画するメソッドです。
//+------------------------------------------------------------------+ //| Draw a segment of a vertical line | //+------------------------------------------------------------------+ bool CFrameQuad::DrawLineVerticalOnBG(const int x, // X coordinate of the segment const int y1, // Y coordinate of the segment first point const int y2, // Y coordinate of the segment second point const color clr, // Color const uchar opacity=255, // Opacity const bool redraw=false) // Chart redraw flag { //--- Set the coordinates of the outlining rectangle this.m_quad_x=x; this.m_quad_y=::fmin(y1,y2); //--- Set the width and height of the image outlining the rectangle (to be used as the size of the saved area) this.m_quad_width=1; this.m_quad_height=::fabs(y2-y1)+1; //--- Calculate coordinate offsets for the saved area depending on the anchor point int shift_x=0,shift_y=0; this.m_element.GetShiftXYbySize(this.m_quad_width,this.m_quad_height,TEXT_ANCHOR_LEFT_TOP,shift_x,shift_y); //--- If the pixel array is not empty, the background under the image has already been saved - //--- restore the previously saved background (by the previous coordinates and offsets) if(::ArraySize(this.m_array)>0) { if(!CPixelCopier::CopyImgDataToCanvas(int(this.m_x_last+this.m_shift_x_prev),int(this.m_y_last+this.m_shift_y_prev))) return false; } //--- If the background area with the calculated coordinates and size under the future image is successfully saved if(!CPixelCopier::CopyImgDataToArray(int(this.m_quad_x+shift_x),int(this.m_quad_y+shift_y),this.m_quad_width,this.m_quad_height)) return false; //--- Draw the shape and update the element this.m_element.DrawLineVertical(x,y1,y2,clr,opacity); this.m_element.Update(redraw); this.m_anchor_last=TEXT_ANCHOR_LEFT_TOP; this.m_x_last=this.m_quad_x; this.m_y_last=this.m_quad_y; this.m_shift_x_prev=shift_x; this.m_shift_y_prev=shift_y; return true; } //+------------------------------------------------------------------+
ここで、形状の輪郭を描く長方形の座標とサイズの計算は、前のメソッドとは異なります。1ピクセルの幅で垂直線を引くので、これは自然なことです。線の高さは、線の2つのY座標の最大値と最小値の差として計算する必要があります。保存領域のY座標は、2つのY座標の最小値(描画された線の上の点)に対応します。
以下は、水平線の線分を描画するメソッドです。
//+------------------------------------------------------------------+ //| Draw a segment of a horizontal line | //+------------------------------------------------------------------+ bool CFrameQuad::DrawLineHorizontalOnBG(const int x1, // X coordinate of the segment first point const int x2, // X coordinate of the segment second point const int y, // Segment Y coordinate const color clr, // Color const uchar opacity=255, // Opacity const bool redraw=false) // Chart redraw flag { //--- Set the coordinates of the outlining rectangle this.m_quad_x=::fmin(x1,x2); this.m_quad_y=y; //--- Set the width and height of the image outlining the rectangle (to be used as the size of the saved area) this.m_quad_width=::fabs(x2-x1)+1; this.m_quad_height=1; //--- Calculate coordinate offsets for the saved area depending on the anchor point int shift_x=0,shift_y=0; this.m_element.GetShiftXYbySize(this.m_quad_width,this.m_quad_height,TEXT_ANCHOR_LEFT_TOP,shift_x,shift_y); //--- If the pixel array is not empty, the background under the image has already been saved - //--- restore the previously saved background (by the previous coordinates and offsets) if(::ArraySize(this.m_array)>0) { if(!CPixelCopier::CopyImgDataToCanvas(int(this.m_x_last+this.m_shift_x_prev),int(this.m_y_last+this.m_shift_y_prev))) return false; } //--- If the background area with the calculated coordinates and size under the future image is successfully saved if(!CPixelCopier::CopyImgDataToArray(int(this.m_quad_x+shift_x),int(this.m_quad_y+shift_y),this.m_quad_width,this.m_quad_height)) return false; //--- Draw the shape and update the element this.m_element.DrawLineHorizontal(x1,x2,y,clr,opacity); this.m_element.Update(redraw); this.m_anchor_last=TEXT_ANCHOR_LEFT_TOP; this.m_x_last=this.m_quad_x; this.m_y_last=this.m_quad_y; this.m_shift_x_prev=shift_x; this.m_shift_y_prev=shift_y; return true; } //+------------------------------------------------------------------+
ここで、座標と保存領域のサイズの計算は、これが水平線であり、ここでの高さが1ピクセルに等しいことを除いて、前のメソッドでの同じ計算と同様です。 保存された領域の幅とX座標を計算する必要があります。
以下は、フリーハンドの線分を描画するメソッドです。
//+------------------------------------------------------------------+ //| Draw a segment of a freehand line | //+------------------------------------------------------------------+ bool CFrameQuad::DrawLineOnBG(const int x1, // X coordinate of the segment first point const int y1, // Y coordinate of the segment first point const int x2, // X coordinate of the segment second point const int y2, // Y coordinate of the segment second point const color clr, // Color const uchar opacity=255, // Opacity const bool redraw=false) // Chart redraw flag { //--- Set the coordinates of the outlining rectangle this.m_quad_x=::fmin(x1,x2); this.m_quad_y=::fmin(y1,y2); //--- Set the width and height of the image outlining the rectangle (to be used as the size of the saved area) this.m_quad_width=::fabs(x2-x1)+1; this.m_quad_height=::fabs(y2-y1)+1; //--- Calculate coordinate offsets for the saved area depending on the anchor point int shift_x=0,shift_y=0; this.m_element.GetShiftXYbySize(this.m_quad_width,this.m_quad_height,TEXT_ANCHOR_LEFT_TOP,shift_x,shift_y); //--- If the pixel array is not empty, the background under the image has already been saved - //--- restore the previously saved background (by the previous coordinates and offsets) if(::ArraySize(this.m_array)>0) { if(!CPixelCopier::CopyImgDataToCanvas(int(this.m_x_last+this.m_shift_x_prev),int(this.m_y_last+this.m_shift_y_prev))) return false; } //--- If the background area with the calculated coordinates and size under the future image is successfully saved if(!CPixelCopier::CopyImgDataToArray(int(this.m_quad_x+shift_x),int(this.m_quad_y+shift_y),this.m_quad_width,this.m_quad_height)) return false; //--- Draw the shape and update the element this.m_element.DrawLine(x1,y1,x2,y2,clr,opacity); this.m_element.Update(redraw); this.m_anchor_last=TEXT_ANCHOR_LEFT_TOP; this.m_x_last=this.m_quad_x; this.m_y_last=this.m_quad_y; this.m_shift_x_prev=shift_x; this.m_shift_y_prev=shift_y; return true; } //+------------------------------------------------------------------+
ここで、保存された領域の座標とサイズは、描画された線の座標に基づいて計算されます。
以下は、ポリラインを描画するメソッドです。
//+------------------------------------------------------------------+ //| Draw a polyline | //+------------------------------------------------------------------+ bool CFrameQuad::DrawPolylineOnBG(int &array_x[], // Array with the X coordinates of polyline points int &array_y[], // Array with the Y coordinates of polyline points const color clr, // Color const uchar opacity=255, // Opacity const bool redraw=false) // Chart redraw flag { //--- Set the coordinates of the outlining rectangle int x=0,y=0; if(!ArrayMinimumValue(DFUN_ERR_LINE,array_x,x) || !ArrayMinimumValue(DFUN_ERR_LINE,array_y,y)) return false; this.m_quad_x=x; this.m_quad_y=y; //--- Set the width and height of the image outlining the rectangle (to be used as the size of the saved area) int max_x_value=0,min_x_value=0; if(!ArrayMaximumValue(DFUN_ERR_LINE,array_x,max_x_value) || !ArrayMinimumValue(DFUN_ERR_LINE,array_x,min_x_value)) return false; int max_y_value=0,min_y_value=0; if(!ArrayMaximumValue(DFUN_ERR_LINE,array_y,max_y_value) || !ArrayMinimumValue(DFUN_ERR_LINE,array_y,min_y_value)) return false; this.m_quad_width=(max_x_value-min_x_value)+1; this.m_quad_height=(max_y_value-min_y_value)+1; //--- Calculate coordinate offsets for the saved area depending on the anchor point int shift_x=0,shift_y=0; this.m_element.GetShiftXYbySize(this.m_quad_width,this.m_quad_height,TEXT_ANCHOR_LEFT_TOP,shift_x,shift_y); //--- If the pixel array is not empty, the background under the image has already been saved - //--- restore the previously saved background (by the previous coordinates and offsets) if(::ArraySize(this.m_array)>0) { if(!CPixelCopier::CopyImgDataToCanvas(int(this.m_x_last+this.m_shift_x_prev),int(this.m_y_last+this.m_shift_y_prev))) return false; } //--- If the background area with the calculated coordinates and size under the future image is successfully saved if(!CPixelCopier::CopyImgDataToArray(int(this.m_quad_x+shift_x),int(this.m_quad_y+shift_y),this.m_quad_width,this.m_quad_height)) return false; //--- Draw the shape and update the element this.m_element.DrawPolyline(array_x,array_y,clr,opacity); this.m_element.Update(redraw); this.m_anchor_last=TEXT_ANCHOR_LEFT_TOP; this.m_x_last=this.m_quad_x; this.m_y_last=this.m_quad_y; this.m_shift_x_prev=shift_x; this.m_shift_y_prev=shift_y; return true; } //+------------------------------------------------------------------+
ここで、座標と保存領域のサイズの計算の背後にある考え方は、上記で検討したメソッドと同じです。ただし、ポリライン(および他の多くの形状)の場合、折れ目の数や座標の数を知ることができないため、座標は変数の形式ではなく配列で渡されるため、実行は異なります。事前にメソッド引数に渡されます。これが、メソッドを呼び出す前に、2つの配列にX座標と各折れ目のドットの適切なY座標を入力する必要がある理由です。
このメソッドでは、以前に検討した関数を使用して配列から最大値と最小値を受け取り、関数に渡された配列から最小値または最大値を返します。得られた値は、保存されたフォームの背景領域の座標とサイズを計算するために使用されます。
以下は、平滑化を使用しない残りの形状描画メソッドです(座標の計算と保存された領域のサイズに注意してください )。
//+------------------------------------------------------------------+ //| Draw the rectangle | //+------------------------------------------------------------------+ bool CFrameQuad::DrawPolygonOnBG(int &array_x[], // Array with the X coordinates of polygon points int &array_y[], // Array with the Y coordinates of polygon points const color clr, // Color const uchar opacity=255, // Opacity const bool redraw=false) // Chart redraw flag { //--- Set the coordinates of the outlining rectangle int x=0,y=0; if(!ArrayMinimumValue(DFUN_ERR_LINE,array_x,x) || !ArrayMinimumValue(DFUN_ERR_LINE,array_y,y)) return false; this.m_quad_x=x; this.m_quad_y=y; //--- Set the width and height of the image outlining the rectangle (to be used as the size of the saved area) int max_x_value=0,min_x_value=0; if(!ArrayMaximumValue(DFUN_ERR_LINE,array_x,max_x_value) || !ArrayMinimumValue(DFUN_ERR_LINE,array_x,min_x_value)) return false; int max_y_value=0,min_y_value=0; if(!ArrayMaximumValue(DFUN_ERR_LINE,array_y,max_y_value) || !ArrayMinimumValue(DFUN_ERR_LINE,array_y,min_y_value)) return false; this.m_quad_width=(max_x_value-min_x_value)+1; if(this.m_quad_width==0) this.m_quad_width=1; this.m_quad_height=(max_y_value-min_y_value)+1; if(this.m_quad_height==0) this.m_quad_height=1; //--- Calculate coordinate offsets for the saved area depending on the anchor point int shift_x=0,shift_y=0; this.m_element.GetShiftXYbySize(this.m_quad_width,this.m_quad_height,TEXT_ANCHOR_LEFT_TOP,shift_x,shift_y); //--- If the pixel array is not empty, the background under the image has already been saved - //--- restore the previously saved background (by the previous coordinates and offsets) if(::ArraySize(this.m_array)>0) { if(!CPixelCopier::CopyImgDataToCanvas(int(this.m_x_last+this.m_shift_x_prev),int(this.m_y_last+this.m_shift_y_prev))) return false; } //--- If the background area with the calculated coordinates and size under the future image is successfully saved if(!CPixelCopier::CopyImgDataToArray(int(this.m_quad_x+shift_x),int(this.m_quad_y+shift_y),this.m_quad_width,this.m_quad_height)) return false; //--- Draw the shape and update the element this.m_element.DrawPolygon(array_x,array_y,clr,opacity); this.m_element.Update(redraw); this.m_anchor_last=TEXT_ANCHOR_LEFT_TOP; this.m_x_last=this.m_quad_x; this.m_y_last=this.m_quad_y; this.m_shift_x_prev=shift_x; this.m_shift_y_prev=shift_y; return true; } //+------------------------------------------------------------------+ //| Draw a rectangle using two points | //+------------------------------------------------------------------+ bool CFrameQuad::DrawRectangleOnBG(const int x1, // X coordinate of the first point defining the rectangle const int y1, // Y coordinate of the first point defining the rectangle const int x2, // X coordinate of the second point defining the rectangle const int y2, // Y coordinate of the second point defining the rectangle const color clr, // Color const uchar opacity=255, // Opacity const bool redraw=false) // Chart redraw flag { //--- Set the coordinates of the outlining rectangle this.m_quad_x=::fmin(x1,x2); this.m_quad_y=::fmin(y1,y2); //--- Set the width and height of the image outlining the rectangle (to be used as the size of the saved area) this.m_quad_width=::fabs(x2-x1)+1; this.m_quad_height=::fabs(y2-y1)+1; //--- Calculate coordinate offsets for the saved area depending on the anchor point int shift_x=0,shift_y=0; this.m_element.GetShiftXYbySize(this.m_quad_width,this.m_quad_height,TEXT_ANCHOR_LEFT_TOP,shift_x,shift_y); //--- If the pixel array is not empty, the background under the image has already been saved - //--- restore the previously saved background (by the previous coordinates and offsets) if(::ArraySize(this.m_array)>0) { if(!CPixelCopier::CopyImgDataToCanvas(int(this.m_x_last+this.m_shift_x_prev),int(this.m_y_last+this.m_shift_y_prev))) return false; } //--- If the background area with the calculated coordinates and size under the future image is successfully saved if(!CPixelCopier::CopyImgDataToArray(int(this.m_quad_x+shift_x),int(this.m_quad_y+shift_y),this.m_quad_width,this.m_quad_height)) return false; //--- Draw the shape and update the element this.m_element.DrawRectangle(x1,y1,x2,y2,clr,opacity); this.m_element.Update(redraw); this.m_anchor_last=TEXT_ANCHOR_LEFT_TOP; this.m_x_last=this.m_quad_x; this.m_y_last=this.m_quad_y; this.m_shift_x_prev=shift_x; this.m_shift_y_prev=shift_y; return true; } //+------------------------------------------------------------------+ //| Draw the circle | //+------------------------------------------------------------------+ bool CFrameQuad::DrawCircleOnBG(const int x, // X coordinate of the circle center const int y, // Y coordinate of the circle center const int r, // Circle radius const color clr, // Color const uchar opacity=255, // Opacity const bool redraw=false) // Chart redraw flag { //--- Set the coordinates of the outlining rectangle int rd=(r>0 ? r : 1); this.m_quad_x=x-rd; this.m_quad_y=y-rd; double x2=x+rd; double y2=y+rd; if(this.m_quad_x<0) this.m_quad_x=0; if(this.m_quad_y<0) this.m_quad_y=0; //--- Set the width and height of the image outlining the rectangle (to be used as the size of the saved area) this.m_quad_width=int(::ceil(x2-this.m_quad_x)+1); this.m_quad_height=int(::ceil(y2-this.m_quad_y)+1); //--- Calculate coordinate offsets for the saved area depending on the anchor point int shift_x=0,shift_y=0; this.m_element.GetShiftXYbySize(this.m_quad_width,this.m_quad_height,TEXT_ANCHOR_LEFT_TOP,shift_x,shift_y); //--- If the pixel array is not empty, the background under the image has already been saved - //--- restore the previously saved background (by the previous coordinates and offsets) if(::ArraySize(this.m_array)>0) { if(!CPixelCopier::CopyImgDataToCanvas(int(this.m_x_last+this.m_shift_x_prev),int(this.m_y_last+this.m_shift_y_prev))) return false; } //--- If the background area with the calculated coordinates and size under the future image is successfully saved if(!CPixelCopier::CopyImgDataToArray(int(this.m_quad_x+shift_x),int(this.m_quad_y+shift_y),this.m_quad_width,this.m_quad_height)) return false; //--- Draw the shape and update the element this.m_element.DrawCircle(x,y,rd,clr,opacity); this.m_element.Update(redraw); this.m_anchor_last=TEXT_ANCHOR_CENTER; this.m_x_last=this.m_quad_x; this.m_y_last=this.m_quad_y; this.m_shift_x_prev=shift_x; this.m_shift_y_prev=shift_y; return true; } //+------------------------------------------------------------------+ //| Draw a triangle | //+------------------------------------------------------------------+ bool CFrameQuad::DrawTriangleOnBG(const int x1, // X coordinate of the triangle first vertex const int y1, // Y coordinate of the triangle first vertex const int x2, // X coordinate of the triangle second vertex const int y2, // Y coordinate of the triangle second vertex const int x3, // X coordinate of the triangle third vertex const int y3, // Y coordinate of the triangle third vertex const color clr, // Color const uchar opacity=255, // Opacity const bool redraw=false) // Chart redraw flag { //--- Set the coordinates of the outlining rectangle this.m_quad_x=::fmin(::fmin(x1,x2),x3); this.m_quad_y=::fmin(::fmin(y1,y2),y3); int max_x=::fmax(::fmax(x1,x2),x3); int max_y=::fmax(::fmax(y1,y2),y3); //--- Set the width and height of the image outlining the rectangle (to be used as the size of the saved area) this.m_quad_width=int(max_x-this.m_quad_x)+1; this.m_quad_height=int(max_y-this.m_quad_y)+1; //--- Calculate coordinate offsets for the saved area depending on the anchor point int shift_x=0,shift_y=0; this.m_element.GetShiftXYbySize(this.m_quad_width,this.m_quad_height,TEXT_ANCHOR_LEFT_TOP,shift_x,shift_y); //--- If the pixel array is not empty, the background under the image has already been saved - //--- restore the previously saved background (by the previous coordinates and offsets) if(::ArraySize(this.m_array)>0) { if(!CPixelCopier::CopyImgDataToCanvas(int(this.m_x_last+this.m_shift_x_prev),int(this.m_y_last+this.m_shift_y_prev))) return false; } //--- If the background area with the calculated coordinates and size under the future image is successfully saved if(!CPixelCopier::CopyImgDataToArray(int(this.m_quad_x+shift_x),int(this.m_quad_y+shift_y),this.m_quad_width,this.m_quad_height)) return false; //--- Draw the shape and update the element this.m_element.DrawTriangle(x1,y1,x2,y2,x3,y3,clr,opacity); this.m_element.Update(redraw); this.m_anchor_last=TEXT_ANCHOR_LEFT_TOP; this.m_x_last=this.m_quad_x; this.m_y_last=this.m_quad_y; this.m_shift_x_prev=shift_x; this.m_shift_y_prev=shift_y; return true; } //+------------------------------------------------------------------+ //| Draw an ellipse using two points | //+------------------------------------------------------------------+ bool CFrameQuad::DrawEllipseOnBG(const int x1, // X coordinate of the first point defining the ellipse const int y1, // Y coordinate of the first point defining the ellipse const int x2, // X coordinate of the second point defining the ellipse const int y2, // Y coordinate of the second point defining the ellipse const color clr, // Color const uchar opacity=255, // Opacity const bool redraw=false) // Chart redraw flag { //--- Set the coordinates of the outlining rectangle this.m_quad_x=::fmin(x1,x2); this.m_quad_y=::fmin(y1,y2); //--- Set the width and height of the image outlining the rectangle (to be used as the size of the saved area) this.m_quad_width=::fabs(x2-x1)+1; this.m_quad_height=::fabs(y2-y1)+1; //--- Calculate coordinate offsets for the saved area depending on the anchor point int shift_x=0,shift_y=0; this.m_element.GetShiftXYbySize(this.m_quad_width,this.m_quad_height,TEXT_ANCHOR_LEFT_TOP,shift_x,shift_y); //--- If the pixel array is not empty, the background under the image has already been saved - //--- restore the previously saved background (by the previous coordinates and offsets) if(::ArraySize(this.m_array)>0) { if(!CPixelCopier::CopyImgDataToCanvas(int(this.m_x_last+this.m_shift_x_prev),int(this.m_y_last+this.m_shift_y_prev))) return false; } //--- If the background area with the calculated coordinates and size under the future image is successfully saved if(!CPixelCopier::CopyImgDataToArray(int(this.m_quad_x+shift_x),int(this.m_quad_y+shift_y),this.m_quad_width,this.m_quad_height)) return false; //--- Draw the shape and update the element this.m_element.DrawEllipse(x1,y1,x2,y2,clr,opacity); this.m_element.Update(redraw); this.m_anchor_last=TEXT_ANCHOR_LEFT_TOP; this.m_x_last=this.m_quad_x; this.m_y_last=this.m_quad_y; this.m_shift_x_prev=shift_x; this.m_shift_y_prev=shift_y; return true; } //+------------------------------------------------------------------+ //| Draw an arc of an ellipse inscribed in a rectangle | //| with the corners in (x1,y1) and (x2,y2). | //| The arc boundaries are cropped from the ellipse center | //| moving to two points with the coordinates of (x3,y3) and (x4,y4) | //+------------------------------------------------------------------+ bool CFrameQuad::DrawArcOnBG(const int x1, // X coordinate of the top left corner forming the rectangle const int y1, // Y coordinate of the top left corner forming the rectangle const int x2, // X coordinate of the bottom right corner forming the rectangle const int y2, // Y coordinate of the bottom right corner forming the rectangle const int x3, // X coordinate of the first point, to which a line from the rectangle center is drawn in order to obtain the arc boundary const int y3, // Y coordinate of the first point, to which a line from the rectangle center is drawn in order to obtain the arc boundary const int x4, // X coordinate of the second point, to which a line from the rectangle center is drawn in order to obtain the arc boundary const int y4, // Y coordinate of the second point, to which a line from the rectangle center is drawn in order to obtain the arc boundary const color clr, // Color const uchar opacity=255, // Opacity const bool redraw=false) // Chart redraw flag { //--- Set the coordinates of the outlining rectangle this.m_quad_x=::fmin(x1,x2)-1; this.m_quad_y=::fmin(y1,y2)-1; //--- Set the width and height of the image outlining the rectangle (to be used as the size of the saved area) this.m_quad_width=::fabs(x2-x1)+2; this.m_quad_height=::fabs(y2-y1)+2; //--- Calculate coordinate offsets for the saved area depending on the anchor point int shift_x=0,shift_y=0; this.m_element.GetShiftXYbySize(this.m_quad_width,this.m_quad_height,TEXT_ANCHOR_LEFT_TOP,shift_x,shift_y); //--- If the pixel array is not empty, the background under the image has already been saved - //--- restore the previously saved background (by the previous coordinates and offsets) if(::ArraySize(this.m_array)>0) { if(!CPixelCopier::CopyImgDataToCanvas(int(this.m_x_last+this.m_shift_x_prev),int(this.m_y_last+this.m_shift_y_prev))) return false; } //--- If the background area with the calculated coordinates and size under the future image is successfully saved if(!CPixelCopier::CopyImgDataToArray(int(this.m_quad_x+shift_x),int(this.m_quad_y+shift_y),this.m_quad_width,this.m_quad_height)) return false; //--- Draw the shape and update the element this.m_element.DrawArc(x1,y1,x2,y2,x3,y3,x4,y4,clr,opacity); this.m_element.Update(redraw); this.m_anchor_last=TEXT_ANCHOR_LEFT_TOP; this.m_x_last=this.m_quad_x; this.m_y_last=this.m_quad_y; this.m_shift_x_prev=shift_x; this.m_shift_y_prev=shift_y; return true; } //+------------------------------------------------------------------+ //| Draw a filled sector of an ellipse inscribed in a rectangle | //| with the corners in (x1,y1) and (x2,y2). | //| The sector boundaries are cropped from the ellipse center, | //| moving to two points with the coordinates of (x3,y3) and (x4,y4) | //+------------------------------------------------------------------+ bool CFrameQuad::DrawPieOnBG(const int x1, // X coordinate of the upper left corner of the rectangle const int y1, // Y coordinate of the upper left corner of the rectangle const int x2, // X coordinate of the bottom right corner of the rectangle const int y2, // Y coordinate of the bottom right corner of the rectangle const int x3, // X coordinate of the first point to find the arc boundaries const int y3, // Y coordinate of the first point to find the arc boundaries const int x4, // X coordinate of the second point to find the arc boundaries const int y4, // Y coordinate of the second point to find the arc boundaries const color clr, // Color const color fill_clr, // Fill color const uchar opacity=255, // Opacity const bool redraw=false) // Chart redraw flag { //--- Set the coordinates of the outlining rectangle this.m_quad_x=::fmin(x1,x2)-1; this.m_quad_y=::fmin(y1,y2)-1; //--- Set the width and height of the image outlining the rectangle (to be used as the size of the saved area) this.m_quad_width=::fabs(x2-x1)+2; this.m_quad_height=::fabs(y2-y1)+2; //--- Calculate coordinate offsets for the saved area depending on the anchor point int shift_x=0,shift_y=0; this.m_element.GetShiftXYbySize(this.m_quad_width,this.m_quad_height,TEXT_ANCHOR_LEFT_TOP,shift_x,shift_y); //--- If the pixel array is not empty, the background under the image has already been saved - //--- restore the previously saved background (by the previous coordinates and offsets) if(::ArraySize(this.m_array)>0) { if(!CPixelCopier::CopyImgDataToCanvas(int(this.m_x_last+this.m_shift_x_prev),int(this.m_y_last+this.m_shift_y_prev))) return false; } //--- If the background area with the calculated coordinates and size under the future image is successfully saved if(!CPixelCopier::CopyImgDataToArray(int(this.m_quad_x+shift_x),int(this.m_quad_y+shift_y),this.m_quad_width,this.m_quad_height)) return false; //--- Draw the shape and update the element this.m_element.DrawPie(x1,y1,x2,y2,x3,y3,x4,y4,clr,fill_clr,opacity); this.m_element.Update(redraw); this.m_anchor_last=TEXT_ANCHOR_LEFT_TOP; this.m_x_last=this.m_quad_x; this.m_y_last=this.m_quad_y; this.m_shift_x_prev=shift_x; this.m_shift_y_prev=shift_y; return true; } //+------------------------------------------------------------------+
塗りつぶされたプリミティブを平滑化を使用せずに描画するメソッドを考えてみましょう。
以下は、領域を塗りつぶすメソッドです。
//+------------------------------------------------------------------+ //| Fill in the area | //+------------------------------------------------------------------+ bool CFrameQuad::FillOnBG(const int x, // X coordinate of the filling start point const int y, // Y coordinate of the filling start point const color clr, // Color const uchar opacity=255, // Opacity const uint threshould=0, // Threshold const bool redraw=false) // Chart redraw flag { //--- Set the coordinates of the outlining rectangle this.m_quad_x=0; this.m_quad_y=0; //--- Set the width and height of the image outlining the rectangle (to be used as the size of the saved area) this.m_quad_width=0; this.m_quad_height=0; //--- Calculate coordinate offsets for the saved area depending on the anchor point int shift_x=0,shift_y=0; this.m_element.GetShiftXYbySize(this.m_quad_width,this.m_quad_height,TEXT_ANCHOR_LEFT_TOP,shift_x,shift_y); //--- If the pixel array is not empty, the background under the image has already been saved - //--- restore the previously saved background (by the previous coordinates and offsets) if(::ArraySize(this.m_array)>0) { if(!CPixelCopier::CopyImgDataToCanvas(int(this.m_x_last+this.m_shift_x_prev),int(this.m_y_last+this.m_shift_y_prev))) return false; } //--- If the background area with the calculated coordinates and size under the future image is successfully saved if(!CPixelCopier::CopyImgDataToArray(int(this.m_quad_x+shift_x),int(this.m_quad_y+shift_y),this.m_quad_width,this.m_quad_height)) return false; //--- Draw the shape and update the element this.m_element.Fill(x,y,clr,opacity,threshould); this.m_element.Update(redraw); this.m_anchor_last=TEXT_ANCHOR_LEFT_TOP; this.m_x_last=this.m_quad_x; this.m_y_last=this.m_quad_y; this.m_shift_x_prev=shift_x; this.m_shift_y_prev=shift_y; return true; } //+------------------------------------------------------------------+
このメソッドは任意の囲まれた領域を塗りつぶすため、保存された領域のサイズを事前に知ることはできません。したがって、ここではフォーム全体を保存する必要があります。これを実現するために、座標とサイズをゼロに設定しましょう。これらの値の場合、メソッドは画像の長方形の領域を保存し、フォームの背景全体を配列に保存します。
塗りつぶされたプリミティブを描画する残りのメソッドについては、座標と保存領域サイズの計算は、前に検討した単純な平滑化されていないプリミティブの計算と一致します。メソッドをそのまま見てみましょう。
//+------------------------------------------------------------------+ //| Draw a filled rectangle | //+------------------------------------------------------------------+ bool CFrameQuad::DrawRectangleFillOnBG(const int x1, // X coordinate of the first point defining the rectangle const int y1, // Y coordinate of the first point defining the rectangle const int x2, // X coordinate of the second point defining the rectangle const int y2, // Y coordinate of the second point defining the rectangle const color clr, // Color const uchar opacity=255, // Opacity const bool redraw=false) // Chart redraw flag { //--- Set the coordinates of the outlining rectangle this.m_quad_x=::fmin(x1,x2); this.m_quad_y=::fmin(y1,y2); //--- Set the width and height of the image outlining the rectangle (to be used as the size of the saved area) this.m_quad_width=::fabs(x2-x1)+1; this.m_quad_height=::fabs(y2-y1)+1; //--- Calculate coordinate offsets for the saved area depending on the anchor point int shift_x=0,shift_y=0; this.m_element.GetShiftXYbySize(this.m_quad_width,this.m_quad_height,TEXT_ANCHOR_LEFT_TOP,shift_x,shift_y); //--- If the pixel array is not empty, the background under the image has already been saved - //--- restore the previously saved background (by the previous coordinates and offsets) if(::ArraySize(this.m_array)>0) { if(!CPixelCopier::CopyImgDataToCanvas(int(this.m_x_last+this.m_shift_x_prev),int(this.m_y_last+this.m_shift_y_prev))) return false; } //--- If the background area with the calculated coordinates and size under the future image is successfully saved if(!CPixelCopier::CopyImgDataToArray(int(this.m_quad_x+shift_x),int(this.m_quad_y+shift_y),this.m_quad_width,this.m_quad_height)) return false; //--- Draw the shape and update the element this.m_element.DrawRectangleFill(x1,y1,x2,y2,clr,opacity); this.m_element.Update(redraw); this.m_anchor_last=TEXT_ANCHOR_LEFT_TOP; this.m_x_last=this.m_quad_x; this.m_y_last=this.m_quad_y; this.m_shift_x_prev=shift_x; this.m_shift_y_prev=shift_y; return true; } //+------------------------------------------------------------------+ //| Draw a filled circle | //+------------------------------------------------------------------+ bool CFrameQuad::DrawCircleFillOnBG(const int x, // X coordinate of the circle center const int y, // Y coordinate of the circle center const int r, // Circle radius const color clr, // Color const uchar opacity=255, // Opacity const bool redraw=false) // Chart redraw flag { //--- Set the coordinates of the outlining rectangle int rd=(r>0 ? r : 1); this.m_quad_x=x-rd; this.m_quad_y=y-rd; double x2=x+rd; double y2=y+rd; if(this.m_quad_x<0) this.m_quad_x=0; if(this.m_quad_y<0) this.m_quad_y=0; //--- Set the width and height of the image outlining the rectangle (to be used as the size of the saved area) this.m_quad_width=int(::ceil(x2-this.m_quad_x)+1); this.m_quad_height=int(::ceil(y2-this.m_quad_y)+1); //--- Calculate coordinate offsets for the saved area depending on the anchor point int shift_x=0,shift_y=0; this.m_element.GetShiftXYbySize(this.m_quad_width,this.m_quad_height,TEXT_ANCHOR_LEFT_TOP,shift_x,shift_y); //--- If the pixel array is not empty, the background under the image has already been saved - //--- restore the previously saved background (by the previous coordinates and offsets) if(::ArraySize(this.m_array)>0) { if(!CPixelCopier::CopyImgDataToCanvas(int(this.m_x_last+this.m_shift_x_prev),int(this.m_y_last+this.m_shift_y_prev))) return false; } //--- If the background area with the calculated coordinates and size under the future image is successfully saved if(!CPixelCopier::CopyImgDataToArray(int(this.m_quad_x+shift_x),int(this.m_quad_y+shift_y),this.m_quad_width,this.m_quad_height)) return false; //--- Draw the shape and update the element this.m_element.DrawCircleFill(x,y,rd,clr,opacity); this.m_element.Update(redraw); this.m_anchor_last=TEXT_ANCHOR_LEFT_TOP; this.m_x_last=this.m_quad_x; this.m_y_last=this.m_quad_y; this.m_shift_x_prev=shift_x; this.m_shift_y_prev=shift_y; return true; } //+------------------------------------------------------------------+ //| Draw a filled triangle | //+------------------------------------------------------------------+ bool CFrameQuad::DrawTriangleFillOnBG(const int x1, // X coordinate of the triangle first vertex const int y1, // Y coordinate of the triangle first vertex const int x2, // X coordinate of the triangle second vertex const int y2, // Y coordinate of the triangle second vertex const int x3, // X coordinate of the triangle third vertex const int y3, // Y coordinate of the triangle third vertex const color clr, // Color const uchar opacity=255, // Opacity const bool redraw=false) // Chart redraw flag { //--- Set the coordinates of the outlining rectangle this.m_quad_x=::fmin(::fmin(x1,x2),x3)-1; this.m_quad_y=::fmin(::fmin(y1,y2),y3)-1; int max_x=::fmax(::fmax(x1,x2),x3)+1; int max_y=::fmax(::fmax(y1,y2),y3)+1; //--- Set the width and height of the image outlining the rectangle (to be used as the size of the saved area) this.m_quad_width=int(max_x-this.m_quad_x)+1; this.m_quad_height=int(max_y-this.m_quad_y)+1; //--- Calculate coordinate offsets for the saved area depending on the anchor point int shift_x=0,shift_y=0; this.m_element.GetShiftXYbySize(this.m_quad_width,this.m_quad_height,TEXT_ANCHOR_LEFT_TOP,shift_x,shift_y); //--- If the pixel array is not empty, the background under the image has already been saved - //--- restore the previously saved background (by the previous coordinates and offsets) if(::ArraySize(this.m_array)>0) { if(!CPixelCopier::CopyImgDataToCanvas(int(this.m_x_last+this.m_shift_x_prev),int(this.m_y_last+this.m_shift_y_prev))) return false; } //--- If the background area with the calculated coordinates and size under the future image is successfully saved if(!CPixelCopier::CopyImgDataToArray(int(this.m_quad_x+shift_x),int(this.m_quad_y+shift_y),this.m_quad_width,this.m_quad_height)) return false; //--- Draw the shape and update the element this.m_element.DrawTriangleFill(x1,y1,x2,y2,x3,y3,clr,opacity); this.m_element.Update(redraw); this.m_anchor_last=TEXT_ANCHOR_LEFT_TOP; this.m_x_last=this.m_quad_x; this.m_y_last=this.m_quad_y; this.m_shift_x_prev=shift_x; this.m_shift_y_prev=shift_y; return true; } //+------------------------------------------------------------------+ //| Draw a filled polygon | //+------------------------------------------------------------------+ bool CFrameQuad::DrawPolygonFillOnBG(int &array_x[], // Array with the X coordinates of polygon points int &array_y[], // Array with the Y coordinates of polygon points const color clr, // Color const uchar opacity=255, // Opacity const bool redraw=false) // Chart redraw flag { //--- Set the coordinates of the outlining rectangle int x=0,y=0; if(!ArrayMinimumValue(DFUN_ERR_LINE,array_x,x) || !ArrayMinimumValue(DFUN_ERR_LINE,array_y,y)) return false; this.m_quad_x=x; this.m_quad_y=y; //--- Set the width and height of the image outlining the rectangle (to be used as the size of the saved area) int max_x_value=0,min_x_value=0; if(!ArrayMaximumValue(DFUN_ERR_LINE,array_x,max_x_value) || !ArrayMinimumValue(DFUN_ERR_LINE,array_x,min_x_value)) return false; int max_y_value=0,min_y_value=0; if(!ArrayMaximumValue(DFUN_ERR_LINE,array_y,max_y_value) || !ArrayMinimumValue(DFUN_ERR_LINE,array_y,min_y_value)) return false; this.m_quad_width=(max_x_value-min_x_value)+1; this.m_quad_height=(max_y_value-min_y_value)+1; //--- Calculate coordinate offsets for the saved area depending on the anchor point int shift_x=0,shift_y=0; this.m_element.GetShiftXYbySize(this.m_quad_width,this.m_quad_height,TEXT_ANCHOR_LEFT_TOP,shift_x,shift_y); //--- If the pixel array is not empty, the background under the image has already been saved - //--- restore the previously saved background (by the previous coordinates and offsets) if(::ArraySize(this.m_array)>0) { if(!CPixelCopier::CopyImgDataToCanvas(int(this.m_x_last+this.m_shift_x_prev),int(this.m_y_last+this.m_shift_y_prev))) return false; } //--- If the background area with the calculated coordinates and size under the future image is successfully saved if(!CPixelCopier::CopyImgDataToArray(int(this.m_quad_x+shift_x),int(this.m_quad_y+shift_y),this.m_quad_width,this.m_quad_height)) return false; //--- Draw the shape and update the element this.m_element.DrawPolygonFill(array_x,array_y,clr,opacity); this.m_element.Update(redraw); this.m_anchor_last=TEXT_ANCHOR_LEFT_TOP; this.m_x_last=this.m_quad_x; this.m_y_last=this.m_quad_y; this.m_shift_x_prev=shift_x; this.m_shift_y_prev=shift_y; return true; } //+------------------------------------------------------------------+ //| Draw a filled ellipse inscribed in a rectangle | //| with the given coordinates | //+------------------------------------------------------------------+ bool CFrameQuad::DrawEllipseFillOnBG(const int x1, // X coordinate of the top left corner forming the rectangle const int y1, // Y coordinate of the top left corner forming the rectangle const int x2, // X coordinate of the bottom right corner forming the rectangle const int y2, // Y coordinate of the bottom right corner forming the rectangle const color clr, // Color const uchar opacity=255, // Opacity const bool redraw=false) // Chart redraw flag { //--- Set the coordinates of the outlining rectangle this.m_quad_x=::fmin(x1,x2); this.m_quad_y=::fmin(y1,y2); //--- Set the width and height of the image outlining the rectangle (to be used as the size of the saved area) this.m_quad_width=::fabs(x2-x1)+1; this.m_quad_height=::fabs(y2-y1)+1; //--- Calculate coordinate offsets for the saved area depending on the anchor point int shift_x=0,shift_y=0; this.m_element.GetShiftXYbySize(this.m_quad_width,this.m_quad_height,TEXT_ANCHOR_LEFT_TOP,shift_x,shift_y); //--- If the pixel array is not empty, the background under the image has already been saved - //--- restore the previously saved background (by the previous coordinates and offsets) if(::ArraySize(this.m_array)>0) { if(!CPixelCopier::CopyImgDataToCanvas(int(this.m_x_last+this.m_shift_x_prev),int(this.m_y_last+this.m_shift_y_prev))) return false; } //--- If the background area with the calculated coordinates and size under the future image is successfully saved if(!CPixelCopier::CopyImgDataToArray(int(this.m_quad_x+shift_x),int(this.m_quad_y+shift_y),this.m_quad_width,this.m_quad_height)) return false; //--- Draw the shape and update the element this.m_element.DrawEllipseFill(x1,y1,x2,y2,clr,opacity); this.m_element.Update(redraw); this.m_anchor_last=TEXT_ANCHOR_LEFT_TOP; this.m_x_last=this.m_quad_x; this.m_y_last=this.m_quad_y; this.m_shift_x_prev=shift_x; this.m_shift_y_prev=shift_y; return true; } //+------------------------------------------------------------------+
以下は、平滑化を使用してプリミティブを描画するメソッドです。
以下は、アンチエイリアスアルゴリズムを使用して点を描画するメソッドです。
//+------------------------------------------------------------------+ //| Draw a point using AntiAliasing algorithm | //+------------------------------------------------------------------+ bool CFrameQuad::SetPixelAAOnBG(const double x, // Point X coordinate const double y, // Point Y coordinate const color clr, // Color const uchar opacity=255, // Opacity const bool redraw=false) // Chart redraw flag { //--- Set the coordinates of the outlining rectangle this.m_quad_x=x-1; if(this.m_quad_x<0) this.m_quad_x=0; this.m_quad_y=y-1; if(this.m_quad_y<0) this.m_quad_y=0; //--- Set the width and height of the image outlining the rectangle (to be used as the size of the saved area) this.m_quad_width=3; this.m_quad_height=3; //--- Calculate coordinate offsets for the saved area depending on the anchor point int shift_x=0,shift_y=0; this.m_element.GetShiftXYbySize(this.m_quad_width,this.m_quad_height,TEXT_ANCHOR_LEFT_TOP,shift_x,shift_y); //--- If the pixel array is not empty, the background under the image has already been saved - //--- restore the previously saved background (by the previous coordinates and offsets) if(::ArraySize(this.m_array)>0) { if(!CPixelCopier::CopyImgDataToCanvas(int(this.m_x_last+this.m_shift_x_prev),int(this.m_y_last+this.m_shift_y_prev))) return false; } //--- If a background area with calculated coordinates and size under the future image is successfully saved if(!CPixelCopier::CopyImgDataToArray(int(this.m_quad_x+shift_x),int(this.m_quad_y+shift_y),this.m_quad_width,this.m_quad_height)) return false; //--- Draw the shape and update the element this.m_element.SetPixelAA(x,y,clr,opacity); this.m_element.Update(redraw); this.m_anchor_last=TEXT_ANCHOR_LEFT_TOP; this.m_x_last=this.m_quad_x; this.m_y_last=this.m_quad_y; this.m_shift_x_prev=shift_x; this.m_shift_y_prev=shift_y; return true; } //+------------------------------------------------------------------+
保存領域の座標とサイズの計算は、平滑化を使用せずに点を描画するメソッドでの同じ計算とは異なります。平滑化された点は、3つの隣接するピクセル(合計9、つまり3 x 3ピクセル)に配置されることがあるため、保存される領域の寸法は、高さ、幅とも3ピクセルである必要があります。X座標とY座標は、それぞれ、点自体の座標から1ピクセル左、1ピクセル上にある必要があります。したがって、点が平滑化アルゴリズムによってぼかされて複数のピクセルに描画された場合、点の輪郭を描く保存領域の長方形には描画された点のすべての辺に1ピクセルの余白があります。これにより、描画された点によって消去された背景の不完全な復元を平滑化で取り除くことができます。
以下は、アンチエイリアスアルゴリズムを使用してフリーハンドの線分を描画するメソッドです。
//+------------------------------------------------------------------+ //| Draw a segment of a freehand line | //| using AntiAliasing algorithm | //+------------------------------------------------------------------+ bool CFrameQuad::DrawLineAAOnBG(const int x1, // X coordinate of the segment first point const int y1, // Y coordinate of the segment first point const int x2, // X coordinate of the segment second point const int y2, // Y coordinate of the segment second point const color clr, // Color const uchar opacity=255, // Opacity const bool redraw=false, // Chart redraw flag const uint style=UINT_MAX) // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value { //--- Set the coordinates of the outlining rectangle this.m_quad_x=::fmin(x1,x2); this.m_quad_y=::fmin(y1,y2); //--- Set the width and height of the image outlining the rectangle (to be used as the size of the saved area) this.m_quad_width=::fabs(x2-x1)+1; this.m_quad_height=::fabs(y2-y1)+1; //--- Calculate coordinate offsets for the saved area depending on the anchor point int shift_x=0,shift_y=0; this.m_element.GetShiftXYbySize(this.m_quad_width,this.m_quad_height,TEXT_ANCHOR_LEFT_TOP,shift_x,shift_y); //--- If the pixel array is not empty, the background under the image has already been saved - //--- restore the previously saved background (by the previous coordinates and offsets) if(::ArraySize(this.m_array)>0) { if(!CPixelCopier::CopyImgDataToCanvas(int(this.m_x_last+this.m_shift_x_prev),int(this.m_y_last+this.m_shift_y_prev))) return false; } //--- If the background area with the calculated coordinates and size under the future image is successfully saved if(!CPixelCopier::CopyImgDataToArray(int(this.m_quad_x+shift_x),int(this.m_quad_y+shift_y),this.m_quad_width,this.m_quad_height)) return false; //--- Draw the shape and update the element this.m_element.DrawLineAA(x1,y1,x2,y2,clr,opacity,style); this.m_element.Update(redraw); this.m_anchor_last=TEXT_ANCHOR_LEFT_TOP; this.m_x_last=this.m_quad_x; this.m_y_last=this.m_quad_y; this.m_shift_x_prev=shift_x; this.m_shift_y_prev=shift_y; return true; } //+------------------------------------------------------------------+
メソッドをテストしたところ、描画された線のエッジがぼやけていないことがわかりました。したがって、保存領域サイズの計算は、平滑化を使用せずに線を描画するメソッドの計算と一致します。
以下は、Wuのアルゴリズムを使用してフリーハンドの線分を描画するメソッドです。
//+------------------------------------------------------------------+ //| Draw a segment of a freehand line using the | //| Wu algorithm | //+------------------------------------------------------------------+ bool CFrameQuad::DrawLineWuOnBG(const int x1, // X coordinate of the segment first point const int y1, // Y coordinate of the segment first point const int x2, // X coordinate of the segment second point const int y2, // Y coordinate of the segment second point const color clr, // Color const uchar opacity=255, // Opacity const bool redraw=false, // Chart redraw flag const uint style=UINT_MAX) // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value { //--- Set the coordinates of the outlining rectangle this.m_quad_x=::fmin(x1,x2); this.m_quad_y=::fmin(y1,y2); //--- Set the width and height of the image outlining the rectangle (to be used as the size of the saved area) this.m_quad_width=::fabs(x2-x1)+1; this.m_quad_height=::fabs(y2-y1)+1; //--- Calculate coordinate offsets for the saved area depending on the anchor point int shift_x=0,shift_y=0; this.m_element.GetShiftXYbySize(this.m_quad_width,this.m_quad_height,TEXT_ANCHOR_LEFT_TOP,shift_x,shift_y); //--- If the pixel array is not empty, the background under the image has already been saved - //--- restore the previously saved background (by the previous coordinates and offsets) if(::ArraySize(this.m_array)>0) { if(!CPixelCopier::CopyImgDataToCanvas(int(this.m_x_last+this.m_shift_x_prev),int(this.m_y_last+this.m_shift_y_prev))) return false; } //--- If the background area with the calculated coordinates and size under the future image is successfully saved if(!CPixelCopier::CopyImgDataToArray(int(this.m_quad_x+shift_x),int(this.m_quad_y+shift_y),this.m_quad_width,this.m_quad_height)) return false; //--- Draw the shape and update the element this.m_element.DrawLineWu(x1,y1,x2,y2,clr,opacity,style); this.m_element.Update(redraw); this.m_anchor_last=TEXT_ANCHOR_LEFT_TOP; this.m_x_last=this.m_quad_x; this.m_y_last=this.m_quad_y; this.m_shift_x_prev=shift_x; this.m_shift_y_prev=shift_y; return true; } //+------------------------------------------------------------------+
計算は、同じ理由で前のメソッドと似ています。
以下は、予備ろ過を伴う平滑化アルゴリズムを使用して、指定された幅を持つフリーハンドの線分を描画するメソッドです。
//+------------------------------------------------------------------+ //| Draw a segment of a freehand line having a specified width | //| using a smoothing algorithm | //| with the preliminary sorting | //+------------------------------------------------------------------+ bool CFrameQuad::DrawLineThickOnBG(const int x1, // X coordinate of the segment first point const int y1, // Y coordinate of the segment first point const int x2, // X coordinate of the segment second point const int y2, // Y coordinate of the segment second point const int size, // Line width const color clr, // Color const uchar opacity=255, // Opacity const bool redraw=false, // Chart redraw flag const uint style=STYLE_SOLID, // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value ENUM_LINE_END end_style=LINE_END_ROUND) // Line style is one of the ENUM_LINE_END enumeration's values { //--- Calculate the adjustment of the outlining rectangle coordinates depending on the line size int correct=int(::ceil((double)size/2.0))+1; //--- Set the coordinates of the outlining rectangle this.m_quad_x=::fmin(x1,x2)-correct; this.m_quad_y=::fmin(y1,y2)-correct; //--- Set the width and height of the image outlining the rectangle (to be used as the size of the saved area) this.m_quad_width=::fabs(x2-x1)+1+correct*2; this.m_quad_height=::fabs(y2-y1)+1+correct*2; //--- Calculate coordinate offsets for the saved area depending on the anchor point int shift_x=0,shift_y=0; this.m_element.GetShiftXYbySize(this.m_quad_width,this.m_quad_height,TEXT_ANCHOR_LEFT_TOP,shift_x,shift_y); //--- If the pixel array is not empty, the background under the image has already been saved - //--- restore the previously saved background (by the previous coordinates and offsets) if(::ArraySize(this.m_array)>0) { if(!CPixelCopier::CopyImgDataToCanvas(int(this.m_x_last+this.m_shift_x_prev),int(this.m_y_last+this.m_shift_y_prev))) return false; } //--- If the background area with the calculated coordinates and size under the future image is successfully saved if(!CPixelCopier::CopyImgDataToArray(int(this.m_quad_x+shift_x),int(this.m_quad_y+shift_y),this.m_quad_width,this.m_quad_height)) return false; //--- Draw the shape and update the element this.m_element.DrawLineThick(x1,y1,x2,y2,size,clr,opacity,style,end_style); this.m_element.Update(redraw); this.m_anchor_last=TEXT_ANCHOR_LEFT_TOP; this.m_x_last=this.m_quad_x; this.m_y_last=this.m_quad_y; this.m_shift_x_prev=shift_x; this.m_shift_y_prev=shift_y; return true; } //+------------------------------------------------------------------+
このメソッドの保存領域の計算は上記とは異なります。このような平滑化アルゴリズムを使用した線は、編集可能な値とその端の外観を備えているため、保存される領域の幅は、線とそのエッジのサイズ(幅)を考慮する必要があります(線のエッジは丸めることができるため、線のサイズ (長さ)は、2つの丸め半径、つまり線幅として設定された値だけ増加します。
以下は、予備ろ過を伴う平滑化アルゴリズムを使用して、指定された幅を持つフリーハンドの垂直線分を描画するメソッドです。
//+---------------------------------------------------------------------+ //| Draw a vertical segment of a freehand line having a specified width | //| using a smoothing algorithm | //| with the preliminary sorting | //+---------------------------------------------------------------------+ bool CFrameQuad::DrawLineThickVerticalOnBG(const int x, // X coordinate of the segment const int y1, // Y coordinate of the segment first point const int y2, // Y coordinate of the segment second point const int size, // line width const color clr, // Color const uchar opacity=255, // Opacity const bool redraw=false, // Chart redraw flag const uint style=STYLE_SOLID, // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value const ENUM_LINE_END end_style=LINE_END_ROUND)// Line style is one of the ENUM_LINE_END enumeration's values { //--- Calculate the adjustment of the outlining rectangle coordinates depending on the line size and the type of its ends int correct_x=(int)::ceil((double)size/2.0); int correct_y=(end_style==LINE_END_BUTT ? 0 : correct_x); //--- Set the coordinates of the outlining rectangle this.m_quad_x=x-correct_x; this.m_quad_y=::fmin(y1,y2)-correct_y; //--- Set the width and height of the image outlining the rectangle (to be used as the size of the saved area) this.m_quad_width=size; this.m_quad_height=::fabs(y2-y1)+1+correct_y*2; //--- Calculate coordinate offsets for the saved area depending on the anchor point int shift_x=0,shift_y=0; this.m_element.GetShiftXYbySize(this.m_quad_width,this.m_quad_height,TEXT_ANCHOR_LEFT_TOP,shift_x,shift_y); //--- If the pixel array is not empty, the background under the image has already been saved - //--- restore the previously saved background (by the previous coordinates and offsets) if(::ArraySize(this.m_array)>0) { if(!CPixelCopier::CopyImgDataToCanvas(int(this.m_x_last+this.m_shift_x_prev),int(this.m_y_last+this.m_shift_y_prev))) return false; } //--- If the background area with the calculated coordinates and size under the future image is successfully saved if(!CPixelCopier::CopyImgDataToArray(int(this.m_quad_x+shift_x),int(this.m_quad_y+shift_y),this.m_quad_width,this.m_quad_height)) return false; //--- Draw the shape and update the element this.m_element.DrawLineThickVertical(x,y1,y2,size,clr,opacity,style,end_style); this.m_element.Update(redraw); this.m_anchor_last=TEXT_ANCHOR_LEFT_TOP; this.m_x_last=this.m_quad_x; this.m_y_last=this.m_quad_y; this.m_shift_x_prev=shift_x; this.m_shift_y_prev=shift_y; return true; } //+------------------------------------------------------------------+
計算は、前のメソッドで説明したものと同じです。
以下は、平滑化されたプリミティブおよびその他のプリミティブを描画する残りのメソッドです。
//+-----------------------------------------------------------------------+ //| Draws a horizontal segment of a freehand line having a specified width| //| using a smoothing algorithm | //| with the preliminary sorting | //+-----------------------------------------------------------------------+ bool CFrameQuad::DrawLineThickHorizontalOnBG(const int x1, // X coordinate of the segment first point const int x2, // X coordinate of the segment second point const int y, // Segment Y coordinate const int size, // line width const color clr, // Color const uchar opacity=255, // Opacity const bool redraw=false, // Chart redraw flag const uint style=STYLE_SOLID, // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value const ENUM_LINE_END end_style=LINE_END_ROUND)// Line style is one of the ENUM_LINE_END enumeration's values { //--- Calculate the adjustment of the outlining rectangle coordinates depending on the line size and the type of its ends int correct_y=(int)::ceil((double)size/2.0); int correct_x=(end_style==LINE_END_BUTT ? 0 : correct_y); //--- Set the coordinates of the outlining rectangle this.m_quad_x=::fmin(x1,x2)-correct_x; this.m_quad_y=y-correct_y; //--- Set the width and height of the image outlining the rectangle (to be used as the size of the saved area) this.m_quad_width=::fabs(x2-x1)+1+correct_x*2; this.m_quad_height=size; //--- Calculate coordinate offsets for the saved area depending on the anchor point int shift_x=0,shift_y=0; this.m_element.GetShiftXYbySize(this.m_quad_width,this.m_quad_height,TEXT_ANCHOR_LEFT_TOP,shift_x,shift_y); //--- If the pixel array is not empty, the background under the image has already been saved - //--- restore the previously saved background (by the previous coordinates and offsets) if(::ArraySize(this.m_array)>0) { if(!CPixelCopier::CopyImgDataToCanvas(int(this.m_x_last+this.m_shift_x_prev),int(this.m_y_last+this.m_shift_y_prev))) return false; } //--- If the background area with the calculated coordinates and size under the future image is successfully saved if(!CPixelCopier::CopyImgDataToArray(int(this.m_quad_x+shift_x),int(this.m_quad_y+shift_y),this.m_quad_width,this.m_quad_height)) return false; //--- Draw the shape and update the element this.m_element.DrawLineThickHorizontal(x1,x2,y,size,clr,opacity,style,end_style); this.m_element.Update(redraw); this.m_anchor_last=TEXT_ANCHOR_LEFT_TOP; this.m_x_last=this.m_quad_x; this.m_y_last=this.m_quad_y; this.m_shift_x_prev=shift_x; this.m_shift_y_prev=shift_y; return true; } //+------------------------------------------------------------------+ //| Draw a polyline using | //| AntiAliasing algorithm | //+------------------------------------------------------------------+ bool CFrameQuad::DrawPolylineAAOnBG(int &array_x[], // Array with the X coordinates of polyline points int &array_y[], // Array with the Y coordinates of polyline points const color clr, // Color const uchar opacity=255, // Opacity const bool redraw=false, // Chart redraw flag const uint style=UINT_MAX) // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value { //--- Set the coordinates of the outlining rectangle int x=0,y=0; if(!ArrayMinimumValue(DFUN_ERR_LINE,array_x,x) || !ArrayMinimumValue(DFUN_ERR_LINE,array_y,y)) return false; this.m_quad_x=x; this.m_quad_y=y; //--- Set the width and height of the image outlining the rectangle (to be used as the size of the saved area) int max_x_value=0,min_x_value=0; if(!ArrayMaximumValue(DFUN_ERR_LINE,array_x,max_x_value) || !ArrayMinimumValue(DFUN_ERR_LINE,array_x,min_x_value)) return false; int max_y_value=0,min_y_value=0; if(!ArrayMaximumValue(DFUN_ERR_LINE,array_y,max_y_value) || !ArrayMinimumValue(DFUN_ERR_LINE,array_y,min_y_value)) return false; this.m_quad_width=(max_x_value-min_x_value)+1; this.m_quad_height=(max_y_value-min_y_value)+1; //--- Calculate coordinate offsets for the saved area depending on the anchor point int shift_x=0,shift_y=0; this.m_element.GetShiftXYbySize(this.m_quad_width,this.m_quad_height,TEXT_ANCHOR_LEFT_TOP,shift_x,shift_y); //--- If the pixel array is not empty, the background under the image has already been saved - //--- restore the previously saved background (by the previous coordinates and offsets) if(::ArraySize(this.m_array)>0) { if(!CPixelCopier::CopyImgDataToCanvas(int(this.m_x_last+this.m_shift_x_prev),int(this.m_y_last+this.m_shift_y_prev))) return false; } //--- If the background area with the calculated coordinates and size under the future image is successfully saved if(!CPixelCopier::CopyImgDataToArray(int(this.m_quad_x+shift_x),int(this.m_quad_y+shift_y),this.m_quad_width,this.m_quad_height)) return false; //--- Draw the shape and update the element this.m_element.DrawPolylineAA(array_x,array_y,clr,opacity,style); this.m_element.Update(redraw); this.m_anchor_last=TEXT_ANCHOR_LEFT_TOP; this.m_x_last=this.m_quad_x; this.m_y_last=this.m_quad_y; this.m_shift_x_prev=shift_x; this.m_shift_y_prev=shift_y; return true; } //+------------------------------------------------------------------+ //| Draws a polyline using Wu algorithm | //+------------------------------------------------------------------+ bool CFrameQuad::DrawPolylineWuOnBG(int &array_x[], // Array with the X coordinates of polyline points int &array_y[], // Array with the Y coordinates of polyline points const color clr, // Color const uchar opacity=255, // Opacity const bool redraw=false, // Chart redraw flag const uint style=UINT_MAX) // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value { //--- Set the coordinates of the outlining rectangle int x=0,y=0; if(!ArrayMinimumValue(DFUN_ERR_LINE,array_x,x) || !ArrayMinimumValue(DFUN_ERR_LINE,array_y,y)) return false; this.m_quad_x=x; this.m_quad_y=y; //--- Set the width and height of the image outlining the rectangle (to be used as the size of the saved area) int max_x_value=0,min_x_value=0; if(!ArrayMaximumValue(DFUN_ERR_LINE,array_x,max_x_value) || !ArrayMinimumValue(DFUN_ERR_LINE,array_x,min_x_value)) return false; int max_y_value=0,min_y_value=0; if(!ArrayMaximumValue(DFUN_ERR_LINE,array_y,max_y_value) || !ArrayMinimumValue(DFUN_ERR_LINE,array_y,min_y_value)) return false; this.m_quad_width=(max_x_value-min_x_value)+1; this.m_quad_height=(max_y_value-min_y_value)+1; //--- Calculate coordinate offsets for the saved area depending on the anchor point int shift_x=0,shift_y=0; this.m_element.GetShiftXYbySize(this.m_quad_width,this.m_quad_height,TEXT_ANCHOR_LEFT_TOP,shift_x,shift_y); //--- If the pixel array is not empty, the background under the image has already been saved - //--- restore the previously saved background (by the previous coordinates and offsets) if(::ArraySize(this.m_array)>0) { if(!CPixelCopier::CopyImgDataToCanvas(int(this.m_x_last+this.m_shift_x_prev),int(this.m_y_last+this.m_shift_y_prev))) return false; } //--- If the background area with the calculated coordinates and size under the future image is successfully saved if(!CPixelCopier::CopyImgDataToArray(int(this.m_quad_x+shift_x),int(this.m_quad_y+shift_y),this.m_quad_width,this.m_quad_height)) return false; //--- Draw the shape and update the element this.m_element.DrawPolylineWu(array_x,array_y,clr,opacity,style); this.m_element.Update(redraw); this.m_anchor_last=TEXT_ANCHOR_LEFT_TOP; this.m_x_last=this.m_quad_x; this.m_y_last=this.m_quad_y; this.m_shift_x_prev=shift_x; this.m_shift_y_prev=shift_y; return true; } //+------------------------------------------------------------------+ //| Draw a polyline with a specified width using | //| two smoothing algorithms in series. | //| First, individual segments are smoothed | //| based on Bezier curves. | //| Then, to improve the rendering quality, | //| a raster smoothing algorithm is applied | //| made of the polyline segments | //+------------------------------------------------------------------+ bool CFrameQuad::DrawPolylineSmoothOnBG(const int &array_x[], // Array with the X coordinates of polyline points const int &array_y[], // Array with the Y coordinates of polyline points const int size, // Line width const color clr, // Color const uchar opacity=255, // Chart redraw flag const double tension=0.5, // Smoothing parameter value const double step=10, // Approximation step const bool redraw=false, // Chart redraw flag const ENUM_LINE_STYLE style=STYLE_SOLID, // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value const ENUM_LINE_END end_style=LINE_END_ROUND)// Line style is one of the ENUM_LINE_END enumeration's values { //--- Set the coordinates of the outlining rectangle this.m_quad_x=0; this.m_quad_y=0; //--- Set the width and height of the image outlining the rectangle (to be used as the size of the saved area) this.m_quad_width=this.m_element.Width(); this.m_quad_height=this.m_element.Height(); //--- Calculate coordinate offsets for the saved area depending on the anchor point int shift_x=0,shift_y=0; this.m_element.GetShiftXYbySize(this.m_quad_width,this.m_quad_height,TEXT_ANCHOR_LEFT_TOP,shift_x,shift_y); //--- If the pixel array is not empty, the background under the image has already been saved - //--- restore the previously saved background (by the previous coordinates and offsets) if(::ArraySize(this.m_array)>0) { if(!CPixelCopier::CopyImgDataToCanvas(int(this.m_x_last+this.m_shift_x_prev),int(this.m_y_last+this.m_shift_y_prev))) return false; } //--- If the background area with the calculated coordinates and size under the future image is successfully saved if(!CPixelCopier::CopyImgDataToArray(int(this.m_quad_x+shift_x),int(this.m_quad_y+shift_y),this.m_quad_width,this.m_quad_height)) return false; //--- Draw the shape and update the element this.m_element.DrawPolylineSmooth(array_x,array_y,size,clr,opacity,tension,step,style,end_style); this.m_element.Update(redraw); this.m_anchor_last=TEXT_ANCHOR_LEFT_TOP; this.m_x_last=this.m_quad_x; this.m_y_last=this.m_quad_y; this.m_shift_x_prev=shift_x; this.m_shift_y_prev=shift_y; return true; } //+------------------------------------------------------------------+ //| Draw a polyline with a specified width using | //| a smoothing algorithm with the preliminary sorting | //+------------------------------------------------------------------+ bool CFrameQuad::DrawPolylineThickOnBG(const int &array_x[], // Array with the X coordinates of polyline points const int &array_y[], // Array with the Y coordinates of polyline points const int size, // Line width const color clr, // Color const uchar opacity=255, // Opacity const bool redraw=false, // Chart redraw flag const uint style=STYLE_SOLID, // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value ENUM_LINE_END end_style=LINE_END_ROUND)// Line style is one of the ENUM_LINE_END enumeration's values { //--- Calculate the adjustment of the outlining rectangle coordinates depending on the line size int correct=int(::ceil((double)size/2.0))+1; //--- Set the coordinates of the outlining rectangle int x=0,y=0; if(!ArrayMinimumValue(DFUN_ERR_LINE,array_x,x) || !ArrayMinimumValue(DFUN_ERR_LINE,array_y,y)) return false; this.m_quad_x=x-correct; this.m_quad_y=y-correct; //--- Set the width and height of the image outlining the rectangle (to be used as the size of the saved area) int max_x_value=0,min_x_value=0; if(!ArrayMaximumValue(DFUN_ERR_LINE,array_x,max_x_value) || !ArrayMinimumValue(DFUN_ERR_LINE,array_x,min_x_value)) return false; int max_y_value=0,min_y_value=0; if(!ArrayMaximumValue(DFUN_ERR_LINE,array_y,max_y_value) || !ArrayMinimumValue(DFUN_ERR_LINE,array_y,min_y_value)) return false; this.m_quad_width=(max_x_value-min_x_value)+1+correct*2; this.m_quad_height=(max_y_value-min_y_value)+1+correct*2; //--- Calculate coordinate offsets for the saved area depending on the anchor point int shift_x=0,shift_y=0; this.m_element.GetShiftXYbySize(this.m_quad_width,this.m_quad_height,TEXT_ANCHOR_LEFT_TOP,shift_x,shift_y); //--- If the pixel array is not empty, the background under the image has already been saved - //--- restore the previously saved background (by the previous coordinates and offsets) if(::ArraySize(this.m_array)>0) { if(!CPixelCopier::CopyImgDataToCanvas(int(this.m_x_last+this.m_shift_x_prev),int(this.m_y_last+this.m_shift_y_prev))) return false; } //--- If the background area with the calculated coordinates and size under the future image is successfully saved if(!CPixelCopier::CopyImgDataToArray(int(this.m_quad_x+shift_x),int(this.m_quad_y+shift_y),this.m_quad_width,this.m_quad_height)) return false; //--- Draw the shape and update the element this.m_element.DrawPolylineThick(array_x,array_y,size,clr,opacity,style,end_style); this.m_element.Update(redraw); this.m_anchor_last=TEXT_ANCHOR_LEFT_TOP; this.m_x_last=this.m_quad_x; this.m_y_last=this.m_quad_y; this.m_shift_x_prev=shift_x; this.m_shift_y_prev=shift_y; return true; } //+------------------------------------------------------------------+ //| Draw a polygon using | //| AntiAliasing algorithm | //+------------------------------------------------------------------+ bool CFrameQuad::DrawPolygonAAOnBG(int &array_x[], // Array with the X coordinates of polygon points int &array_y[], // Array with the Y coordinates of polygon points const color clr, // Color const uchar opacity=255, // Opacity const bool redraw=false, // Chart redraw flag const uint style=UINT_MAX) // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value { //--- Set the coordinates of the outlining rectangle int x=0,y=0; if(!ArrayMinimumValue(DFUN_ERR_LINE,array_x,x) || !ArrayMinimumValue(DFUN_ERR_LINE,array_y,y)) return false; this.m_quad_x=x; this.m_quad_y=y; //--- Set the width and height of the image outlining the rectangle (to be used as the size of the saved area) int max_x_value=0,min_x_value=0; if(!ArrayMaximumValue(DFUN_ERR_LINE,array_x,max_x_value) || !ArrayMinimumValue(DFUN_ERR_LINE,array_x,min_x_value)) return false; int max_y_value=0,min_y_value=0; if(!ArrayMaximumValue(DFUN_ERR_LINE,array_y,max_y_value) || !ArrayMinimumValue(DFUN_ERR_LINE,array_y,min_y_value)) return false; this.m_quad_width=(max_x_value-min_x_value)+1; if(this.m_quad_width==0) this.m_quad_width=1; this.m_quad_height=(max_y_value-min_y_value)+1; if(this.m_quad_height==0) this.m_quad_height=1; //--- Calculate coordinate offsets for the saved area depending on the anchor point int shift_x=0,shift_y=0; this.m_element.GetShiftXYbySize(this.m_quad_width,this.m_quad_height,TEXT_ANCHOR_LEFT_TOP,shift_x,shift_y); //--- If the pixel array is not empty, the background under the image has already been saved - //--- restore the previously saved background (by the previous coordinates and offsets) if(::ArraySize(this.m_array)>0) { if(!CPixelCopier::CopyImgDataToCanvas(int(this.m_x_last+this.m_shift_x_prev),int(this.m_y_last+this.m_shift_y_prev))) return false; } //--- If the background area with the calculated coordinates and size under the future image is successfully saved if(!CPixelCopier::CopyImgDataToArray(int(this.m_quad_x+shift_x),int(this.m_quad_y+shift_y),this.m_quad_width,this.m_quad_height)) return false; //--- Draw the shape and update the element this.m_element.DrawPolygonAA(array_x,array_y,clr,opacity,style); this.m_element.Update(redraw); this.m_anchor_last=TEXT_ANCHOR_LEFT_TOP; this.m_x_last=this.m_quad_x; this.m_y_last=this.m_quad_y; this.m_shift_x_prev=shift_x; this.m_shift_y_prev=shift_y; return true; } //+------------------------------------------------------------------+ //| Draw a polygon using Wu algorithm | //+------------------------------------------------------------------+ bool CFrameQuad::DrawPolygonWuOnBG(int &array_x[], // Array with the X coordinates of polygon points int &array_y[], // Array with the Y coordinates of polygon points const color clr, // Color const uchar opacity=255, // Opacity const bool redraw=false, // Chart redraw flag const uint style=UINT_MAX) // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value { //--- Set the coordinates of the outlining rectangle int x=0,y=0; if(!ArrayMinimumValue(DFUN_ERR_LINE,array_x,x) || !ArrayMinimumValue(DFUN_ERR_LINE,array_y,y)) return false; this.m_quad_x=x; this.m_quad_y=y; //--- Set the width and height of the image outlining the rectangle (to be used as the size of the saved area) int max_x_value=0,min_x_value=0; if(!ArrayMaximumValue(DFUN_ERR_LINE,array_x,max_x_value) || !ArrayMinimumValue(DFUN_ERR_LINE,array_x,min_x_value)) return false; int max_y_value=0,min_y_value=0; if(!ArrayMaximumValue(DFUN_ERR_LINE,array_y,max_y_value) || !ArrayMinimumValue(DFUN_ERR_LINE,array_y,min_y_value)) return false; this.m_quad_width=(max_x_value-min_x_value)+1; if(this.m_quad_width==0) this.m_quad_width=1; this.m_quad_height=(max_y_value-min_y_value)+1; if(this.m_quad_height==0) this.m_quad_height=1; //--- Calculate coordinate offsets for the saved area depending on the anchor point int shift_x=0,shift_y=0; this.m_element.GetShiftXYbySize(this.m_quad_width,this.m_quad_height,TEXT_ANCHOR_LEFT_TOP,shift_x,shift_y); //--- If the pixel array is not empty, the background under the image has already been saved - //--- restore the previously saved background (by the previous coordinates and offsets) if(::ArraySize(this.m_array)>0) { if(!CPixelCopier::CopyImgDataToCanvas(int(this.m_x_last+this.m_shift_x_prev),int(this.m_y_last+this.m_shift_y_prev))) return false; } //--- If the background area with the calculated coordinates and size under the future image is successfully saved if(!CPixelCopier::CopyImgDataToArray(int(this.m_quad_x+shift_x),int(this.m_quad_y+shift_y),this.m_quad_width,this.m_quad_height)) return false; //--- Draw the shape and update the element this.m_element.DrawPolygonWu(array_x,array_y,clr,opacity,style); this.m_element.Update(redraw); this.m_anchor_last=TEXT_ANCHOR_LEFT_TOP; this.m_x_last=this.m_quad_x; this.m_y_last=this.m_quad_y; this.m_shift_x_prev=shift_x; this.m_shift_y_prev=shift_y; return true; } //+------------------------------------------------------------------+ //| Draw a polygon with a specified width using | //| two smoothing algorithms in series. | //| First, individual segments are smoothed based on Bezier curves. | //| Then, to improve the rendering quality, | //| a raster smoothing algorithm is applied | //| made of the polyline segments. | //+------------------------------------------------------------------+ bool CFrameQuad::DrawPolygonSmoothOnBG(int &array_x[], // Array with the X coordinates of polyline points int &array_y[], // Array with the Y coordinates of polyline points const int size, // Line width const color clr, // Color const uchar opacity=255, // Chart redraw flag const double tension=0.5, // Smoothing parameter value const double step=10, // Approximation step const bool redraw=false, // Chart redraw flag const ENUM_LINE_STYLE style=STYLE_SOLID, // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value const ENUM_LINE_END end_style=LINE_END_ROUND)// Line style is one of the ENUM_LINE_END enumeration's values { //--- Set the coordinates of the outlining rectangle this.m_quad_x=0; this.m_quad_y=0; //--- Set the width and height of the image outlining the rectangle (to be used as the size of the saved area) this.m_quad_width=this.m_element.Width(); this.m_quad_height=this.m_element.Height(); //--- Calculate coordinate offsets for the saved area depending on the anchor point int shift_x=0,shift_y=0; this.m_element.GetShiftXYbySize(this.m_quad_width,this.m_quad_height,TEXT_ANCHOR_LEFT_TOP,shift_x,shift_y); //--- If the pixel array is not empty, the background under the image has already been saved - //--- restore the previously saved background (by the previous coordinates and offsets) if(::ArraySize(this.m_array)>0) { if(!CPixelCopier::CopyImgDataToCanvas(int(this.m_x_last+this.m_shift_x_prev),int(this.m_y_last+this.m_shift_y_prev))) return false; } //--- If the background area with the calculated coordinates and size under the future image is successfully saved if(!CPixelCopier::CopyImgDataToArray(int(this.m_quad_x+shift_x),int(this.m_quad_y+shift_y),this.m_quad_width,this.m_quad_height)) return false; //--- Draw the shape and update the element this.m_element.DrawPolygonSmooth(array_x,array_y,size,clr,opacity,tension,step,style,end_style); this.m_element.Update(redraw); this.m_anchor_last=TEXT_ANCHOR_LEFT_TOP; this.m_x_last=this.m_quad_x; this.m_y_last=this.m_quad_y; this.m_shift_x_prev=shift_x; this.m_shift_y_prev=shift_y; return true; } //+------------------------------------------------------------------+ //| Draw a polygon with a specified width using | //| a smoothing algorithm with the preliminary sorting | //+------------------------------------------------------------------+ bool CFrameQuad::DrawPolygonThickOnBG(const int &array_x[], // array with the X coordinates of polygon points const int &array_y[], // array with the Y coordinates of polygon points const int size, // line width const color clr, // Color const uchar opacity=255, // Opacity const bool redraw=false, // Chart redraw flag const uint style=STYLE_SOLID, // line style ENUM_LINE_END end_style=LINE_END_ROUND) // line ends style { //--- Calculate the adjustment of the outlining rectangle coordinates depending on the line size int correct=int(::ceil((double)size/2.0))+1; //--- Set the coordinates of the outlining rectangle int x=0,y=0; if(!ArrayMinimumValue(DFUN_ERR_LINE,array_x,x) || !ArrayMinimumValue(DFUN_ERR_LINE,array_y,y)) return false; this.m_quad_x=x-correct; this.m_quad_y=y-correct; //--- Set the width and height of the image outlining the rectangle (to be used as the size of the saved area) int max_x_value=0,min_x_value=0; if(!ArrayMaximumValue(DFUN_ERR_LINE,array_x,max_x_value) || !ArrayMinimumValue(DFUN_ERR_LINE,array_x,min_x_value)) return false; int max_y_value=0,min_y_value=0; if(!ArrayMaximumValue(DFUN_ERR_LINE,array_y,max_y_value) || !ArrayMinimumValue(DFUN_ERR_LINE,array_y,min_y_value)) return false; this.m_quad_width=(max_x_value-min_x_value)+1+correct*2; this.m_quad_height=(max_y_value-min_y_value)+1+correct*2; //--- Calculate coordinate offsets for the saved area depending on the anchor point int shift_x=0,shift_y=0; this.m_element.GetShiftXYbySize(this.m_quad_width,this.m_quad_height,TEXT_ANCHOR_LEFT_TOP,shift_x,shift_y); //--- If the pixel array is not empty, the background under the image has already been saved - //--- restore the previously saved background (by the previous coordinates and offsets) if(::ArraySize(this.m_array)>0) { if(!CPixelCopier::CopyImgDataToCanvas(int(this.m_x_last+this.m_shift_x_prev),int(this.m_y_last+this.m_shift_y_prev))) return false; } //--- If the background area with the calculated coordinates and size under the future image is successfully saved if(!CPixelCopier::CopyImgDataToArray(int(this.m_quad_x+shift_x),int(this.m_quad_y+shift_y),this.m_quad_width,this.m_quad_height)) return false; //--- Draw the shape and update the element this.m_element.DrawPolygonThick(array_x,array_y,size,clr,opacity,style,end_style); this.m_element.Update(redraw); this.m_anchor_last=TEXT_ANCHOR_LEFT_TOP; this.m_x_last=this.m_quad_x; this.m_y_last=this.m_quad_y; this.m_shift_x_prev=shift_x; this.m_shift_y_prev=shift_y; return true; } //+------------------------------------------------------------------+ //| Draw a triangle using | //| AntiAliasing algorithm | //+------------------------------------------------------------------+ bool CFrameQuad::DrawTriangleAAOnBG(const int x1, // X coordinate of the triangle first vertex const int y1, // Y coordinate of the triangle first vertex const int x2, // X coordinate of the triangle second vertex const int y2, // Y coordinate of the triangle second vertex const int x3, // X coordinate of the triangle third vertex const int y3, // Y coordinate of the triangle third vertex const color clr, // Color const uchar opacity=255, // Opacity const bool redraw=false, // Chart redraw flag const uint style=UINT_MAX) // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value { //--- Set the coordinates of the outlining rectangle this.m_quad_x=::fmin(::fmin(x1,x2),x3); this.m_quad_y=::fmin(::fmin(y1,y2),y3); int max_x=::fmax(::fmax(x1,x2),x3); int max_y=::fmax(::fmax(y1,y2),y3); //--- Set the width and height of the image outlining the rectangle (to be used as the size of the saved area) this.m_quad_width=int(max_x-this.m_quad_x)+1; this.m_quad_height=int(max_y-this.m_quad_y)+1; //--- Calculate coordinate offsets for the saved area depending on the anchor point int shift_x=0,shift_y=0; this.m_element.GetShiftXYbySize(this.m_quad_width,this.m_quad_height,TEXT_ANCHOR_LEFT_TOP,shift_x,shift_y); //--- If the pixel array is not empty, the background under the image has already been saved - //--- restore the previously saved background (by the previous coordinates and offsets) if(::ArraySize(this.m_array)>0) { if(!CPixelCopier::CopyImgDataToCanvas(int(this.m_x_last+this.m_shift_x_prev),int(this.m_y_last+this.m_shift_y_prev))) return false; } //--- If the background area with the calculated coordinates and size under the future image is successfully saved if(!CPixelCopier::CopyImgDataToArray(int(this.m_quad_x+shift_x),int(this.m_quad_y+shift_y),this.m_quad_width,this.m_quad_height)) return false; //--- Draw the shape and update the element this.m_element.DrawTriangleAA(x1,y1,x2,y2,x3,y3,clr,opacity,style); this.m_element.Update(redraw); this.m_anchor_last=TEXT_ANCHOR_LEFT_TOP; this.m_x_last=this.m_quad_x; this.m_y_last=this.m_quad_y; this.m_shift_x_prev=shift_x; this.m_shift_y_prev=shift_y; return true; } //+------------------------------------------------------------------+ //| Draw a triangle using Wu algorithm | //+------------------------------------------------------------------+ bool CFrameQuad::DrawTriangleWuOnBG(const int x1, // X coordinate of the triangle first vertex const int y1, // Y coordinate of the triangle first vertex const int x2, // X coordinate of the triangle second vertex const int y2, // Y coordinate of the triangle second vertex const int x3, // X coordinate of the triangle third vertex const int y3, // Y coordinate of the triangle third vertex const color clr, // Color const uchar opacity=255, // Opacity const bool redraw=false, // Chart redraw flag const uint style=UINT_MAX) // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value { //--- Set the coordinates of the outlining rectangle this.m_quad_x=::fmin(::fmin(x1,x2),x3); this.m_quad_y=::fmin(::fmin(y1,y2),y3); int max_x=::fmax(::fmax(x1,x2),x3); int max_y=::fmax(::fmax(y1,y2),y3); //--- Set the width and height of the image outlining the rectangle (to be used as the size of the saved area) this.m_quad_width=int(max_x-this.m_quad_x)+1; this.m_quad_height=int(max_y-this.m_quad_y)+1; //--- Calculate coordinate offsets for the saved area depending on the anchor point int shift_x=0,shift_y=0; this.m_element.GetShiftXYbySize(this.m_quad_width,this.m_quad_height,TEXT_ANCHOR_LEFT_TOP,shift_x,shift_y); //--- If the pixel array is not empty, the background under the image has already been saved - //--- restore the previously saved background (by the previous coordinates and offsets) if(::ArraySize(this.m_array)>0) { if(!CPixelCopier::CopyImgDataToCanvas(int(this.m_x_last+this.m_shift_x_prev),int(this.m_y_last+this.m_shift_y_prev))) return false; } //--- If the background area with the calculated coordinates and size under the future image is successfully saved if(!CPixelCopier::CopyImgDataToArray(int(this.m_quad_x+shift_x),int(this.m_quad_y+shift_y),this.m_quad_width,this.m_quad_height)) return false; //--- Draw the shape and update the element this.m_element.DrawTriangleWu(x1,y1,x2,y2,x3,y3,clr,opacity,style); this.m_element.Update(redraw); this.m_anchor_last=TEXT_ANCHOR_LEFT_TOP; this.m_x_last=this.m_quad_x; this.m_y_last=this.m_quad_y; this.m_shift_x_prev=shift_x; this.m_shift_y_prev=shift_y; return true; } //+------------------------------------------------------------------+ //| Draw a circle using | //| AntiAliasing algorithm | //+------------------------------------------------------------------+ bool CFrameQuad::DrawCircleAAOnBG(const int x, // X coordinate of the circle center const int y, // Y coordinate of the circle center const double r, // Circle radius const color clr, // Color const uchar opacity=255, // Opacity const bool redraw=false, // Chart redraw flag const uint style=UINT_MAX) // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value { //--- Set the coordinates of the outlining rectangle double rd=(r>0 ? r : 1); this.m_quad_x=x-rd; this.m_quad_y=y-rd; double x2=x+rd; double y2=y+rd; if(this.m_quad_x<0) this.m_quad_x=0; if(this.m_quad_y<0) this.m_quad_y=0; //--- Set the width and height of the image outlining the rectangle (to be used as the size of the saved area) this.m_quad_width=int(::ceil(x2-this.m_quad_x)+1); this.m_quad_height=int(::ceil(y2-this.m_quad_y)+1); //--- Calculate coordinate offsets for the saved area depending on the anchor point int shift_x=0,shift_y=0; this.m_element.GetShiftXYbySize(this.m_quad_width,this.m_quad_height,TEXT_ANCHOR_LEFT_TOP,shift_x,shift_y); //--- If the pixel array is not empty, the background under the image has already been saved - //--- restore the previously saved background (by the previous coordinates and offsets) if(::ArraySize(this.m_array)>0) { if(!CPixelCopier::CopyImgDataToCanvas(int(this.m_x_last+this.m_shift_x_prev),int(this.m_y_last+this.m_shift_y_prev))) return false; } //--- If the background area with the calculated coordinates and size under the future image is successfully saved if(!CPixelCopier::CopyImgDataToArray(int(this.m_quad_x+shift_x),int(this.m_quad_y+shift_y),this.m_quad_width,this.m_quad_height)) return false; //--- Draw the shape and update the element this.m_element.DrawCircleAA(x,y,rd,clr,opacity); this.m_element.Update(redraw); this.m_anchor_last=TEXT_ANCHOR_LEFT_TOP; this.m_x_last=this.m_quad_x; this.m_y_last=this.m_quad_y; this.m_shift_x_prev=shift_x; this.m_shift_y_prev=shift_y; return true; } //+------------------------------------------------------------------+ //| Draw a circle using Wu algorithm | //+------------------------------------------------------------------+ bool CFrameQuad::DrawCircleWuOnBG(const int x, // X coordinate of the circle center const int y, // Y coordinate of the circle center const double r, // Circle radius const color clr, // Color const uchar opacity=255, // Opacity const bool redraw=false, // Chart redraw flag const uint style=UINT_MAX) // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value { //--- Set the coordinates of the outlining rectangle double rd=(r>0 ? r : 1); this.m_quad_x=x-rd; this.m_quad_y=y-rd; double x2=x+rd; double y2=y+rd; if(this.m_quad_x<0) this.m_quad_x=0; if(this.m_quad_y<0) this.m_quad_y=0; //--- Set the width and height of the image outlining the rectangle (to be used as the size of the saved area) this.m_quad_width=int(::ceil(x2-this.m_quad_x)+1); this.m_quad_height=int(::ceil(y2-this.m_quad_y)+1); //--- Calculate coordinate offsets for the saved area depending on the anchor point int shift_x=0,shift_y=0; this.m_element.GetShiftXYbySize(this.m_quad_width,this.m_quad_height,TEXT_ANCHOR_LEFT_TOP,shift_x,shift_y); //--- If the pixel array is not empty, the background under the image has already been saved - //--- restore the previously saved background (by the previous coordinates and offsets) if(::ArraySize(this.m_array)>0) { if(!CPixelCopier::CopyImgDataToCanvas(int(this.m_x_last+this.m_shift_x_prev),int(this.m_y_last+this.m_shift_y_prev))) return false; } //--- If the background area with the calculated coordinates and size under the future image is successfully saved if(!CPixelCopier::CopyImgDataToArray(int(this.m_quad_x+shift_x),int(this.m_quad_y+shift_y),this.m_quad_width,this.m_quad_height)) return false; //--- Draw the shape and update the element this.m_element.DrawCircleWu(x,y,rd,clr,opacity); this.m_element.Update(redraw); this.m_anchor_last=TEXT_ANCHOR_LEFT_TOP; this.m_x_last=this.m_quad_x; this.m_y_last=this.m_quad_y; this.m_shift_x_prev=shift_x; this.m_shift_y_prev=shift_y; return true; } //+------------------------------------------------------------------+ //| Draw an ellipse using two points while applying | //| AntiAliasing algorithm | //+------------------------------------------------------------------+ bool CFrameQuad::DrawEllipseAAOnBG(const double x1, // X coordinate of the first point defining the ellipse const double y1, // Y coordinate of the first point defining the ellipse const double x2, // X coordinate of the second point defining the ellipse const double y2, // Y coordinate of the second point defining the ellipse const color clr, // Color const uchar opacity=255, // Opacity const bool redraw=false, // Chart redraw flag const uint style=UINT_MAX) // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value { //--- Set the coordinates of the outlining rectangle this.m_quad_x=::fmin(x1,x2)-1; this.m_quad_y=::fmin(y1,y2)-1; //--- Set the width and height of the image outlining the rectangle (to be used as the size of the saved area) this.m_quad_width=int(::ceil(::fabs(x2-x1)))+1; this.m_quad_height=int(::ceil(::fabs(y2-y1)))+1; if(this.m_quad_width<3) this.m_quad_width=3; if(this.m_quad_height<3) this.m_quad_height=3; //--- Calculate coordinate offsets for the saved area depending on the anchor point int shift_x=0,shift_y=0; this.m_element.GetShiftXYbySize(this.m_quad_width,this.m_quad_height,TEXT_ANCHOR_LEFT_TOP,shift_x,shift_y); //--- If the pixel array is not empty, the background under the image has already been saved - //--- restore the previously saved background (by the previous coordinates and offsets) if(::ArraySize(this.m_array)>0) { if(!CPixelCopier::CopyImgDataToCanvas(int(this.m_x_last+this.m_shift_x_prev),int(this.m_y_last+this.m_shift_y_prev))) return false; } //--- If the background area with the calculated coordinates and size under the future image is successfully saved if(!CPixelCopier::CopyImgDataToArray(int(this.m_quad_x+shift_x),int(this.m_quad_y+shift_y),this.m_quad_width,this.m_quad_height)) return false; //--- Draw the shape and update the element this.m_element.DrawEllipseAA(x1,y1,x2,y2,clr,opacity,style); this.m_element.Update(redraw); this.m_anchor_last=TEXT_ANCHOR_LEFT_TOP; this.m_x_last=this.m_quad_x; this.m_y_last=this.m_quad_y; this.m_shift_x_prev=shift_x; this.m_shift_y_prev=shift_y; return true; } //+------------------------------------------------------------------+ //| Draw an ellipse using two points while applying | //| Wu algorithm | //+------------------------------------------------------------------+ bool CFrameQuad::DrawEllipseWuOnBG(const int x1, // X coordinate of the first point defining the ellipse const int y1, // Y coordinate of the first point defining the ellipse const int x2, // X coordinate of the second point defining the ellipse const int y2, // Y coordinate of the second point defining the ellipse const color clr, // Color const uchar opacity=255, // Opacity const bool redraw=false, // Chart redraw flag const uint style=UINT_MAX) // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value { //--- Set the coordinates of the outlining rectangle this.m_quad_x=::fmin(x1,x2); this.m_quad_y=::fmin(y1,y2); //--- Set the width and height of the image outlining the rectangle (to be used as the size of the saved area) this.m_quad_width=::fabs(x2-x1)+1; if(this.m_quad_width<3) this.m_quad_width=3; this.m_quad_height=::fabs(y2-y1)+1; if(this.m_quad_height<3) this.m_quad_height=3; //--- Calculate coordinate offsets for the saved area depending on the anchor point int shift_x=0,shift_y=0; this.m_element.GetShiftXYbySize(this.m_quad_width,this.m_quad_height,TEXT_ANCHOR_LEFT_TOP,shift_x,shift_y); //--- If the pixel array is not empty, the background under the image has already been saved - //--- restore the previously saved background (by the previous coordinates and offsets) if(::ArraySize(this.m_array)>0) { if(!CPixelCopier::CopyImgDataToCanvas(int(this.m_x_last+this.m_shift_x_prev),int(this.m_y_last+this.m_shift_y_prev))) return false; } //--- If the background area with the calculated coordinates and size under the future image is successfully saved if(!CPixelCopier::CopyImgDataToArray(int(this.m_quad_x+shift_x),int(this.m_quad_y+shift_y),this.m_quad_width,this.m_quad_height)) return false; //--- Draw the shape and update the element this.m_element.DrawEllipseWu(x1,y1,x2,y2,clr,opacity,style); this.m_element.Update(redraw); this.m_anchor_last=TEXT_ANCHOR_LEFT_TOP; this.m_x_last=this.m_quad_x; this.m_y_last=this.m_quad_y; this.m_shift_x_prev=shift_x; this.m_shift_y_prev=shift_y; return true; } //+------------------------------------------------------------------+
ここでのすべてのメソッドの保存された背景領域の計算アルゴリズムは、上記で検討したメソッドの計算アルゴリズムとほぼ同じです。
楕円の描画メソッド(DrawEllipseAAOnBGおよびDrawEllipseWuOnBG)では、楕円が描画される長方形が3ピクセル未満の場合、形状は描画されません。したがって、ここでの計算には、サイズが3ピクセル未満であることのチェックが含まれています。これが私のバグなのか、CCanvasクラスメソッドの機能なのかはまだわかりません。これは後で明らかにしたいと思います。
現在必要なアニメーションフレームオブジェクトのすべてのクラスを開発しました。
次に、作成したアニメーションフレームオブジェクトを保存、アクセス、管理するためのクラスを作成します。
このクラスには、作成されたアニメーションフレームオブジェクト(テキストと長方形のオブジェクト)を格納するための2つの(今のところ)リストと、新しいオブジェクトを作成および管理するためのメソッドが含まれます。続いて、クラスは1つのフォームに属するすべてのアニメーションオブジェクトを格納します。したがって、各フォームは、動的に作成してフォームアニメーションのリストに追加できる独自のアニメーションオブジェクトのセットを備えています。
フォームアニメーションクラス
\MQL5\Include\DoEasy\Objects\Graph\Animations\で、CAnimationsクラスの新しいAnimations.mqhファイルを作成します。
基本アニメーションフレームオブジェクトの新しく作成された子孫クラスファイルのみをクラスファイルに含める必要があります。クラス自体は、CObject標準ライブラリのベースオブジェクトの子孫である必要があります。
//+------------------------------------------------------------------+ //| Animations.mqh | //| Copyright 2021, MetaQuotes Ltd. | //| https://mql5.com/en/users/artmedia70 | //+------------------------------------------------------------------+ #property copyright "Copyright 2021, MetaQuotes Ltd." #property link "https://mql5.com/en/users/artmedia70" #property version "1.00" #property strict // Necessary for mql4 //+------------------------------------------------------------------+ //| Include files | //+------------------------------------------------------------------+ #include "FrameText.mqh" #include "FrameQuad.mqh" //+------------------------------------------------------------------+ //| Pixel copier class | //+------------------------------------------------------------------+ class CAnimations : public CObject { }
クラスのprivateセクションで、アニメーションオブジェクトの作成元となるグラフィカル要素オブジェクトへのポインタ、2種類のアニメーションフレームオブジェクトを格納するための2つのリスト、リスト内の指定されたオブジェクトの存在を示すフラグを返すためのメソッド、既存のアニメーションフレームオブジェクトへのポインタを返すメソッド、またはリストにない場合は事前に作成するメソッドを宣言します。
//+------------------------------------------------------------------+ //| Pixel copier class | //+------------------------------------------------------------------+ class CAnimations : public CObject { private: CGCnvElement *m_element; // Pointer to the graphical element CArrayObj m_list_frames_text; // List of text animation frames CArrayObj m_list_frames_quad; // List of rectangle animation frames //--- Return the flag indicating the presence of the frame object with the specified ID in the list bool IsPresentFrame(const ENUM_ANIMATION_FRAME_TYPE frame_type,const int id); //--- Return or create a new animation frame object CFrame *GetOrCreateFrame(const string soutce,const int id,const ENUM_ANIMATION_FRAME_TYPE frame_type,const bool create_new); public:
以下では、すべてのメソッドを検討します。
クラスのpublicセクションで、リスト内のオブジェクトを作成および操作するためのメソッドと、背景を保存および復元しながらプリミティブを描画するメソッドを宣言します。
public: CAnimations(CGCnvElement *element); CAnimations(){;} //--- Create a new (1) rectangle and (2) text animation frame object CFrame *CreateNewFrameText(const int id); CFrame *CreateNewFrameQuad(const int id); //--- Return the animation frame objects by ID CFrame *GetFrame(const ENUM_ANIMATION_FRAME_TYPE frame_type,const int id); //--- Return the list of (1) text and (2) rectangle animation frames CArrayObj *GetListFramesText(void) { return &this.m_list_frames_text; } CArrayObj *GetListFramesQuad(void) { return &this.m_list_frames_quad; } //+------------------------------------------------------------------+ //| The methods of drawing, while saving and restoring the background| //+------------------------------------------------------------------+ //+------------------------------------------------------------------+ //| Display a text on the background | //+------------------------------------------------------------------+ bool TextOnBG(const int id, const string text, const int x, const int y, const ENUM_TEXT_ANCHOR anchor, const color clr, const uchar opacity, const bool create_new=true, const bool redraw=false); //+------------------------------------------------------------------+ //| Methods of drawing primitives without smoothing | //+------------------------------------------------------------------+ //--- Set the color of the dot with the specified coordinates bool SetPixelOnBG(const int id,const int x,const int y,const color clr,const uchar opacity=255,const bool create_new=true,const bool redraw=false); //--- Draw a segment of a vertical line bool DrawLineVerticalOnBG(const int id, // Frame ID const int x, // Segment X coordinate const int y1, // Y coordinate of the segment first point const int y2, // Y coordinate of the segment second point const color clr, // Color const uchar opacity=255, // Opacity const bool create_new=true, // New object creation flag const bool redraw=false); // Chart redraw flag //--- Draw a segment of a horizontal line bool DrawLineHorizontalOnBG(const int id, // Frame ID const int x1, // X coordinate of the segment first point const int x2, // X coordinate of the segment second point const int y, // Segment Y coordinate const color clr, // Color const uchar opacity=255, // Opacity const bool create_new=true, // New object creation flag const bool redraw=false); // Chart redraw flag //--- Draw a segment of a freehand line bool DrawLineOnBG(const int id, // Frame ID const int x1, // X coordinate of the segment first point const int y1, // Y coordinate of the segment first point const int x2, // X coordinate of the segment second point const int y2, // Y coordinate of the segment second point const color clr, // Color const uchar opacity=255, // Opacity const bool create_new=true, // New object creation flag const bool redraw=false); // Chart redraw flag //--- Draw a polyline bool DrawPolylineOnBG(const int id, // Frame ID int &array_x[], // Array with the X coordinates of polyline points int &array_y[], // Array with the Y coordinates of polyline points const color clr, // Color const uchar opacity=255, // Opacity const bool create_new=true, // New object creation flag const bool redraw=false); // Chart redraw flag //--- Draw a polygon bool DrawPolygonOnBG(const int id, // Frame ID int &array_x[], // Array with the X coordinates of polygon points int &array_y[], // Array with the Y coordinates of polygon points const color clr, // Color const uchar opacity=255, // Opacity const bool create_new=true, // New object creation flag const bool redraw=false); // Chart redraw flag //--- Draw a rectangle using two points bool DrawRectangleOnBG(const int id, // Frame ID const int x1, // X coordinate of the first point defining the rectangle const int y1, // Y coordinate of the first point defining the rectangle const int x2, // X coordinate of the second point defining the rectangle const int y2, // Y coordinate of the second point defining the rectangle const color clr, // Color const uchar opacity=255, // Opacity const bool create_new=true, // New object creation flag const bool redraw=false); // Chart redraw flag //--- Draw a circle bool DrawCircleOnBG(const int id, // Frame ID const int x, // X coordinate of the circle center const int y, // Y coordinate of the circle center const int r, // Circle radius const color clr, // Color const uchar opacity=255, // Opacity const bool create_new=true, // New object creation flag const bool redraw=false); // Chart redraw flag //--- Draw a triangle bool DrawTriangleOnBG(const int id, // Frame ID const int x1, // X coordinate of the triangle first vertex const int y1, // Y coordinate of the triangle first vertex const int x2, // X coordinate of the triangle second vertex const int y2, // Y coordinate of the triangle second vertex const int x3, // X coordinate of the triangle third vertex const int y3, // Y coordinate of the triangle third vertex const color clr, // Color const uchar opacity=255, // Opacity const bool create_new=true, // New object creation flag const bool redraw=false); // Chart redraw flag //--- Draw an ellipse using two points bool DrawEllipseOnBG(const int id, // Frame ID const int x1, // X coordinate of the first point defining the ellipse const int y1, // Y coordinate of the first point defining the ellipse const int x2, // X coordinate of the second point defining the ellipse const int y2, // Y coordinate of the second point defining the ellipse const color clr, // Color const uchar opacity=255, // Opacity const bool create_new=true, // New object creation flag const bool redraw=false); // Chart redraw flag //--- Draw an arc of an ellipse inscribed in a rectangle with corners at (x1,y1) and (x2,y2). //--- The arc boundaries are clipped by lines from the center of the ellipse, which extend to two points with coordinates (x3,y3) and (x4,y4) bool DrawArcOnBG(const int id, // Frame ID const int x1, // X coordinate of the top left corner forming the rectangle const int y1, // Y coordinate of the top left corner forming the rectangle const int x2, // X coordinate of the bottom right corner forming the rectangle const int y2, // Y coordinate of the bottom right corner forming the rectangle const int x3, // X coordinate of the first point, to which a line from the rectangle center is drawn in order to obtain the arc boundary const int y3, // Y coordinate of the first point, to which a line from the rectangle center is drawn in order to obtain the arc boundary const int x4, // X coordinate of the second point, to which a line from the rectangle center is drawn in order to obtain the arc boundary const int y4, // Y coordinate of the second point, to which a line from the rectangle center is drawn in order to obtain the arc boundary const color clr, // Color const uchar opacity=255, // Opacity const bool create_new=true, // New object creation flag const bool redraw=false); // Chart redraw flag //--- Draw a filled sector of an ellipse inscribed in a rectangle with corners at (x1,y1) and (x2,y2). //--- The sector boundaries are clipped by lines from the center of the ellipse, which extend to two points with coordinates (x3,y3) and (x4,y4) bool DrawPieOnBG(const int id, // Frame ID const int x1, // X coordinate of the upper left corner of the rectangle const int y1, // Y coordinate of the upper left corner of the rectangle const int x2, // X coordinate of the bottom right corner of the rectangle const int y2, // Y coordinate of the bottom right corner of the rectangle const int x3, // X coordinate of the first point to find the arc boundaries const int y3, // Y coordinate of the first point to find the arc boundaries const int x4, // X coordinate of the second point to find the arc boundaries const int y4, // Y coordinate of the second point to find the arc boundaries const color clr, // Color const color fill_clr, // Fill color const uchar opacity=255, // Opacity const bool create_new=true, // New object creation flag const bool redraw=false); // Chart redraw flag //+------------------------------------------------------------------+ //| Methods of drawing filled primitives without smoothing | //+------------------------------------------------------------------+ //--- Fill in the area bool FillOnBG(const int id, // Frame ID const int x, // X coordinate of the filling start point const int y, // Y coordinate of the filling start point const color clr, // Color const uchar opacity=255, // Opacity const uint threshould=0, // Threshold const bool create_new=true, // New object creation flag const bool redraw=false); // Chart redraw flag //--- Draw a filled rectangle bool DrawRectangleFillOnBG(const int id, // Frame ID const int x1, // X coordinate of the first point defining the rectangle const int y1, // Y coordinate of the first point defining the rectangle const int x2, // X coordinate of the second point defining the rectangle const int y2, // Y coordinate of the second point defining the rectangle const color clr, // Color const uchar opacity=255, // Opacity const bool create_new=true, // New object creation flag const bool redraw=false); // Chart redraw flag //--- Draw a filled circle bool DrawCircleFillOnBG(const int id, // Frame ID const int x, // X coordinate of the circle center const int y, // Y coordinate of the circle center const int r, // Circle radius const color clr, // Color const uchar opacity=255, // Opacity const bool create_new=true, // New object creation flag const bool redraw=false); // Chart redraw flag //--- Draw a filled triangle bool DrawTriangleFillOnBG(const int id, // Frame ID const int x1, // X coordinate of the triangle first vertex const int y1, // Y coordinate of the triangle first vertex const int x2, // X coordinate of the triangle second vertex const int y2, // Y coordinate of the triangle second vertex const int x3, // X coordinate of the triangle third vertex const int y3, // Y coordinate of the triangle third vertex const color clr, // Color const uchar opacity=255, // Opacity const bool create_new=true, // New object creation flag const bool redraw=false); // Chart redraw flag //--- Draw a filled polygon bool DrawPolygonFillOnBG(const int id, // Frame ID int &array_x[], // Array with the X coordinates of polygon points int &array_y[], // Array with the Y coordinates of polygon points const color clr, // Color const uchar opacity=255, // Opacity const bool create_new=true, // New object creation flag const bool redraw=false); // Chart redraw flag //--- Draw a filled ellipse inscribed in a rectangle with the specified coordinates bool DrawEllipseFillOnBG(const int id, // Frame ID const int x1, // X coordinate of the top left corner forming the rectangle const int y1, // Y coordinate of the top left corner forming the rectangle const int x2, // X coordinate of the bottom right corner forming the rectangle const int y2, // Y coordinate of the bottom right corner forming the rectangle const color clr, // Color const uchar opacity=255, // Opacity const bool create_new=true, // New object creation flag const bool redraw=false); // Chart redraw flag //+------------------------------------------------------------------+ //| Methods of drawing primitives using smoothing | //+------------------------------------------------------------------+ //--- Draw a point using AntiAliasing algorithm bool SetPixelAAOnBG(const int id, // Frame ID const double x, // Point X coordinate const double y, // Point Y coordinate const color clr, // Color const uchar opacity=255, // Opacity const bool create_new=true, // New object creation flag const bool redraw=false); // Chart redraw flag //--- Draw a segment of a freehand line using AntiAliasing algorithm bool DrawLineAAOnBG(const int id, // Frame ID const int x1, // X coordinate of the segment first point const int y1, // Y coordinate of the segment first point const int x2, // X coordinate of the segment second point const int y2, // Y coordinate of the segment second point const color clr, // Color const uchar opacity=255, // Opacity const bool create_new=true, // New object creation flag const bool redraw=false, // Chart redraw flag const uint style=UINT_MAX); // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value //--- Draw a segment of a freehand line using Wu algorithm bool DrawLineWuOnBG(const int id, // Frame ID const int x1, // X coordinate of the segment first point const int y1, // Y coordinate of the segment first point const int x2, // X coordinate of the segment second point const int y2, // Y coordinate of the segment second point const color clr, // Color const uchar opacity=255, // Opacity const bool create_new=true, // New object creation flag const bool redraw=false, // Chart redraw flag const uint style=UINT_MAX); // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value //--- Draws a segment of a freehand line having a specified width using smoothing algorithm with the preliminary filtration bool DrawLineThickOnBG(const int id, // Frame ID const int x1, // X coordinate of the segment first point const int y1, // Y coordinate of the segment first point const int x2, // X coordinate of the segment second point const int y2, // Y coordinate of the segment second point const int size, // Line width const color clr, // Color const uchar opacity=255, // Opacity const bool create_new=true, // New object creation flag const bool redraw=false, // Chart redraw flag const uint style=STYLE_SOLID, // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value ENUM_LINE_END end_style=LINE_END_ROUND); // Line style is one of the ENUM_LINE_END enumeration's values //--- Draw a vertical segment of a freehand line having a specified width using smoothing algorithm with the preliminary filtration bool DrawLineThickVerticalOnBG(const int id, // Frame ID const int x, // Segment X coordinate const int y1, // Y coordinate of the segment first point const int y2, // Y coordinate of the segment second point const int size, // line width const color clr, // Color const uchar opacity=255, // Opacity const bool create_new=true, // New object creation flag const bool redraw=false, // Chart redraw flag const uint style=STYLE_SOLID, // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value const ENUM_LINE_END end_style=LINE_END_ROUND); // Line style is one of the ENUM_LINE_END enumeration's values //--- Draw a horizontal segment of a freehand line having a specified width using smoothing algorithm with the preliminary filtration bool DrawLineThickHorizontalOnBG(const int id, // Frame ID const int x1, // X coordinate of the segment first point const int x2, // X coordinate of the segment second point const int y, // Segment Y coordinate const int size, // line width const color clr, // Color const uchar opacity=255, // Opacity const bool create_new=true, // New object creation flag const bool redraw=false, // Chart redraw flag const uint style=STYLE_SOLID, // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value const ENUM_LINE_END end_style=LINE_END_ROUND); // Line style is one of the ENUM_LINE_END enumeration's values //--- Draws a polyline using AntiAliasing algorithm bool DrawPolylineAAOnBG(const int id, // Frame ID int &array_x[], // Array with the X coordinates of polyline points int &array_y[], // Array with the Y coordinates of polyline points const color clr, // Color const uchar opacity=255, // Opacity const bool create_new=true, // New object creation flag const bool redraw=false, // Chart redraw flag const uint style=UINT_MAX); // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value //--- Draws a polyline using Wu algorithm bool DrawPolylineWuOnBG(const int id, // Frame ID int &array_x[], // Array with the X coordinates of polyline points int &array_y[], // Array with the Y coordinates of polyline points const color clr, // Color const uchar opacity=255, // Opacity const bool create_new=true, // New object creation flag const bool redraw=false, // Chart redraw flag const uint style=UINT_MAX); // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value //--- Draw a polyline with a specified width consecutively using two antialiasing algorithms. //--- First, individual line segments are smoothed based on Bezier curves. //--- Then, the raster antialiasing algorithm is applied to the polyline built from these segments to improve the rendering quality bool DrawPolylineSmoothOnBG(const int id, // Frame ID const int &array_x[], // Array with the X coordinates of polyline points const int &array_y[], // Array with the Y coordinates of polyline points const int size, // Line width const color clr, // Color const uchar opacity=255, // Opacity const double tension=0.5, // Smoothing parameter value const double step=10, // Approximation step const bool create_new=true, // New object creation flag const bool redraw=false, // Chart redraw flag const ENUM_LINE_STYLE style=STYLE_SOLID, // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value const ENUM_LINE_END end_style=LINE_END_ROUND);// Line style is one of the ENUM_LINE_END enumeration's values //--- Draw a polyline having a specified width using smoothing algorithm with the preliminary filtration bool DrawPolylineThickOnBG(const int id, // Frame ID const int &array_x[], // Array with the X coordinates of polyline points const int &array_y[], // Array with the Y coordinates of polyline points const int size, // Line width const color clr, // Color const uchar opacity=255, // Opacity const bool create_new=true, // New object creation flag const bool redraw=false, // Chart redraw flag const uint style=STYLE_SOLID, // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value ENUM_LINE_END end_style=LINE_END_ROUND); // Line style is one of the ENUM_LINE_END enumeration's values //--- Draw a polygon using AntiAliasing algorithm bool DrawPolygonAAOnBG(const int id, // Frame ID int &array_x[], // Array with the X coordinates of polygon points int &array_y[], // Array with the Y coordinates of polygon points const color clr, // Color const uchar opacity=255, // Opacity const bool create_new=true, // New object creation flag const bool redraw=false, // Chart redraw flag const uint style=UINT_MAX); // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value //--- Draw a polygon using Wu algorithm bool DrawPolygonWuOnBG(const int id, // Frame ID int &array_x[], // Array with the X coordinates of polygon points int &array_y[], // Array with the Y coordinates of polygon points const color clr, // Color const uchar opacity=255, // Opacity const bool create_new=true, // New object creation flag const bool redraw=false, // Chart redraw flag const uint style=UINT_MAX); // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value //--- Draw a polygon with a specified width consecutively using two smoothing algorithms. //--- First, individual segments are smoothed based on Bezier curves. //--- Then, the raster smoothing algorithm is applied to the polygon built from these segments to improve the rendering quality. bool DrawPolygonSmoothOnBG(const int id, // Frame ID int &array_x[], // Array with the X coordinates of polyline points int &array_y[], // Array with the Y coordinates of polyline points const int size, // Line width const color clr, // Color const uchar opacity=255, // Opacity const double tension=0.5, // Smoothing parameter value const double step=10, // Approximation step const bool create_new=true, // New object creation flag const bool redraw=false, // Chart redraw flag const ENUM_LINE_STYLE style=STYLE_SOLID, // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value const ENUM_LINE_END end_style=LINE_END_ROUND);// Line style is one of the ENUM_LINE_END enumeration's values //--- Draw a polygon having a specified width using smoothing algorithm with the preliminary filtration bool DrawPolygonThickOnBG(const int id, // Frame ID const int &array_x[], // array with the X coordinates of polygon points const int &array_y[], // array with the Y coordinates of polygon points const int size, // line width const color clr, // Color const uchar opacity=255, // Opacity const bool create_new=true, // New object creation flag const bool redraw=false, // Chart redraw flag const uint style=STYLE_SOLID, // line style ENUM_LINE_END end_style=LINE_END_ROUND); // line ends style //--- Draw a triangle using AntiAliasing algorithm bool DrawTriangleAAOnBG(const int id, // Frame ID const int x1, // X coordinate of the triangle first vertex const int y1, // Y coordinate of the triangle first vertex const int x2, // X coordinate of the triangle second vertex const int y2, // Y coordinate of the triangle second vertex const int x3, // X coordinate of the triangle third vertex const int y3, // Y coordinate of the triangle third vertex const color clr, // Color const uchar opacity=255, // Opacity const bool create_new=true, // New object creation flag const bool redraw=false, // Chart redraw flag const uint style=UINT_MAX); // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value //--- Draw a triangle using Wu algorithm bool DrawTriangleWuOnBG(const int id, // Frame ID const int x1, // X coordinate of the triangle first vertex const int y1, // Y coordinate of the triangle first vertex const int x2, // X coordinate of the triangle second vertex const int y2, // Y coordinate of the triangle second vertex const int x3, // X coordinate of the triangle third vertex const int y3, // Y coordinate of the triangle third vertex const color clr, // Color const uchar opacity=255, // Opacity const bool create_new=true, // New object creation flag const bool redraw=false, // Chart redraw flag const uint style=UINT_MAX); // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value //--- Draw a circle using AntiAliasing algorithm bool DrawCircleAAOnBG(const int id, // Frame ID const int x, // X coordinate of the circle center const int y, // Y coordinate of the circle center const double r, // Circle radius const color clr, // Color const uchar opacity=255, // Opacity const bool create_new=true, // New object creation flag const bool redraw=false, // Chart redraw flag const uint style=UINT_MAX); // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value //--- Draw a circle using Wu algorithm bool DrawCircleWuOnBG(const int id, // Frame ID const int x, // X coordinate of the circle center const int y, // Y coordinate of the circle center const double r, // Circle radius const color clr, // Color const uchar opacity=255, // Opacity const bool create_new=true, // New object creation flag const bool redraw=false, // Chart redraw flag const uint style=UINT_MAX); // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value //--- Draw an ellipse by two points using AntiAliasing algorithm bool DrawEllipseAAOnBG(const int id, // Frame ID const double x1, // X coordinate of the first point defining the ellipse const double y1, // Y coordinate of the first point defining the ellipse const double x2, // X coordinate of the second point defining the ellipse const double y2, // Y coordinate of the second point defining the ellipse const color clr, // Color const uchar opacity=255, // Opacity const bool create_new=true, // New object creation flag const bool redraw=false, // Chart redraw flag const uint style=UINT_MAX); // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value //--- Draw an ellipse by two points using Wu algorithm bool DrawEllipseWuOnBG(const int id, // Frame ID const int x1, // X coordinate of the first point defining the ellipse const int y1, // Y coordinate of the first point defining the ellipse const int x2, // X coordinate of the second point defining the ellipse const int y2, // Y coordinate of the second point defining the ellipse const color clr, // Color const uchar opacity=255, // Opacity const bool create_new=true, // New object creation flag const bool redraw=false, // Chart redraw flag const uint style=UINT_MAX); // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value }; //+------------------------------------------------------------------+
宣言されたメソッドの実装について考えてみましょう。
以下は、パラメトリックコンストラクタです。
//+------------------------------------------------------------------+ //| Parametric constructor | //+------------------------------------------------------------------+ CAnimations::CAnimations(CGCnvElement *element) { this.m_element=element; } //+------------------------------------------------------------------+
引数で渡されたグラフィック要素オブジェクトへのポインタの値はm_elementポインタに設定されます。
以下は、タイプとIDでアニメーションフレームオブジェクトへのポインタを返すメソッドです。
//+------------------------------------------------------------------+ //| Return the animation frame objects by type and ID | //+------------------------------------------------------------------+ CFrame *CAnimations::GetFrame(const ENUM_ANIMATION_FRAME_TYPE frame_type,const int id) { //--- Declare the pointer to the animation frame object CFrame *frame=NULL; //--- Depending on the necessary object type, receive their number in the appropriate list int total= ( frame_type==ANIMATION_FRAME_TYPE_TEXT ? this.m_list_frames_text.Total() : frame_type==ANIMATION_FRAME_TYPE_QUAD ? this.m_list_frames_quad.Total() : 0 ); //--- Get the next object in the loop ... for(int i=0;i<total;i++) { //--- ... by the list corresponding to the animation frame type switch(frame_type) { case ANIMATION_FRAME_TYPE_TEXT : frame=this.m_list_frames_text.At(i); break; case ANIMATION_FRAME_TYPE_QUAD : frame=this.m_list_frames_quad.At(i); break; default: break; } //--- if failed to get the pointer, move on to the next one if(frame==NULL) continue; //--- If the object ID correspond to the required one, //--- return the pointer to the detected object if(frame.ID()==id) return frame; } //--- Nothing is found - return NULL return NULL; } //+------------------------------------------------------------------+
メソッドロジックはコードコメントで詳細に説明されており、説明は不要です。
以下は、リスト内に指定されたタイプとIDを持つフレームオブジェクトの存在を示すフラグを返すメソッドです。
//+-----------------------------------------------------------------------+ //| Return the flag indicating the presence of the animation frame object | //| with the specified type and ID | //+-----------------------------------------------------------------------+ bool CAnimations::IsPresentFrame(const ENUM_ANIMATION_FRAME_TYPE frame_type,const int id) { return(this.GetFrame(frame_type,id)!=NULL); } //+------------------------------------------------------------------+
このメソッドは、上記で検討したGetFrame()メソッドを呼び出した結果のboolを返します、メソッドは、GetFrame()メソッドがNULL以外の結果を返す場合(必要なオブジェクトがリストに存在する場合)、trueを返し、それ以外の場合はfalse を返しました。
以下は、新しいテキストアニメーションフレームオブジェクトを作成するメソッドです。
//+------------------------------------------------------------------+ //| Create a new text animation frame object | //+------------------------------------------------------------------+ CFrame *CAnimations::CreateNewFrameText(const int id) { //--- If the object with such an ID is already present, inform of that in the journal and return NULL if(this.IsPresentFrame(ANIMATION_FRAME_TYPE_TEXT,id)) { ::Print(DFUN,CMessage::Text(MSG_FORM_OBJECT_FRAME_ALREADY_IN_LIST),(string)id); return NULL; } //--- Create a new text animation frame object with the specified ID CFrame *frame=new CFrameText(id,this.m_element); //--- If failed to create an object, inform of that and return NULL if(frame==NULL) { ::Print(DFUN,CMessage::Text(MSG_FORM_OBJECT_ERR_FAILED_CREATE_FRAME)); return NULL; } //--- If failed to add the created object to the list, inform of that, remove the object and return NULL if(!this.m_list_frames_text.Add(frame)) { ::Print(DFUN,CMessage::Text(MSG_LIB_SYS_FAILED_OBJ_ADD_TO_LIST)," ID: ",id); delete frame; return NULL; } //--- Return the pointer to a newly created object return frame; } //+------------------------------------------------------------------+
メソッドのロジックは、コードのコメントで完全に説明されています。
以下は、新しい長方形のアニメーションフレームオブジェクトを作成するメソッドです。
//+------------------------------------------------------------------+ //| Create a new rectangle animation frame object | //+------------------------------------------------------------------+ CFrame *CAnimations::CreateNewFrameQuad(const int id) { //--- If the object with such an ID is already present, inform of that in the journal and return NULL if(this.IsPresentFrame(ANIMATION_FRAME_TYPE_QUAD,id)) { ::Print(DFUN,CMessage::Text(MSG_FORM_OBJECT_FRAME_ALREADY_IN_LIST),(string)id); return NULL; } //--- Create a new rectangle animation frame object with the specified ID CFrame *frame=new CFrameQuad(id,this.m_element); //--- If failed to create an object, inform of that and return NULL if(frame==NULL) { ::Print(DFUN,CMessage::Text(MSG_FORM_OBJECT_ERR_FAILED_CREATE_FRAME)); return NULL; } //--- If failed to add the created object to the list, inform of that, remove the object and return NULL if(!this.m_list_frames_quad.Add(frame)) { ::Print(DFUN,CMessage::Text(MSG_LIB_SYS_FAILED_OBJ_ADD_TO_LIST)," ID: ",id); delete frame; return NULL; } //--- Return the pointer to a newly created object return frame; } //+------------------------------------------------------------------+
メソッドは上記で検討したものと同じです。
以下は、ポインタを返すまたは新しいアニメーションフレームオブジェクトを作成するメソッドです。
//+------------------------------------------------------------------+ //| Return or create a new animation frame object | //+------------------------------------------------------------------+ CFrame *CAnimations::GetOrCreateFrame(const string source,const int id,const ENUM_ANIMATION_FRAME_TYPE frame_type,const bool create_new) { //--- Declare null pointers to objects CFrameQuad *frame_q=NULL; CFrameText *frame_t=NULL; //--- Depending on the required object type switch(frame_type) { //--- If this is a text animation frame, case ANIMATION_FRAME_TYPE_TEXT : //--- get the pointer to an object with a specified ID frame_t=this.GetFrame(ANIMATION_FRAME_TYPE_TEXT,id); //--- If the pointer is obtained, return it if(frame_t!=NULL) return frame_t; //--- If the flag of creating a new object is not set, report an error and return NULL if(!create_new) { ::Print(source,CMessage::Text(MSG_FORM_OBJECT_FRAME_NOT_EXIST_LIST),(string)id); return NULL; } //--- Return the result of creating a new text animation frame object (pointer to the created object) return this.CreateNewFrameText(id); //--- If this is a rectangle animation frame case ANIMATION_FRAME_TYPE_QUAD : //--- get the pointer to an object with a specified ID frame_q=this.GetFrame(ANIMATION_FRAME_TYPE_QUAD,id); //--- If the pointer is obtained, return it if(frame_q!=NULL) return frame_q; //--- If the flag of creating a new object is not set, report an error and return NULL if(!create_new) { ::Print(source,CMessage::Text(MSG_FORM_OBJECT_FRAME_NOT_EXIST_LIST),(string)id); return NULL; } //--- Return the result of creating a new rectangle animation frame object (pointer to the created object) return this.CreateNewFrameQuad(id); //--- In the remaining cases, return NULL default: return NULL; } } //+------------------------------------------------------------------+
メソッドのロジックは、コードのコメントで説明されています。アニメーションフレームを操作する場合は、事前にフレームを作成し、そのフレームへのポインタを取得して、取得したオブジェクトを管理できます。オブジェクトを動的に作成する必要がある場合、このメソッドを使用すると、最初に新しいオブジェクトを作成し(指定されたIDを持つオブジェクトが存在しない場合)、そのオブジェクトへのポインタを返すことができます。したがって、必要に応じてオブジェクトの動的作成を調整し、オブジェクトへのポインタをすぐに取得して管理することができます。
以下は、アニメーションフレームオブジェクトを操作するメソッドです。
以下は、背景を保存および復元しながら背景にテキストを表示するメソッドです。
//+--------------------------------------------------------------------------------+ //| Display the text on the background, while saving and restoring the background | //+--------------------------------------------------------------------------------+ bool CAnimations::TextOnBG(const int id, const string text, const int x, const int y, const ENUM_TEXT_ANCHOR anchor, const color clr, const uchar opacity, const bool create_new=true, const bool redraw=false) { CFrameText *frame=this.GetOrCreateFrame(DFUN,id,ANIMATION_FRAME_TYPE_TEXT,create_new); if(frame==NULL) return false; return frame.TextOnBG(text,x,y,anchor,clr,opacity,redraw); } //+------------------------------------------------------------------+
このメソッドは、オブジェクトID、表示されたテキストパラメータ(テキスト自体、X座標とY座標、アンカーポイント、色、不透明度)、指定されたIDで新しいオブジェクトを作成する必要があることを示すフラグを受け取ります。 IDがリストに存在せず、チャートの再描画フラグが表示されます。
次に、必要なオブジェクトへのポインタを取得します(または、オブジェクトがない場合はオブジェクトを作成します)。ポインタの取得に失敗した場合は、falseを返します。
ポインタを受け取った場合は、取得したテキストアニメーションフレームオブジェクトのTextOnBG()メソッドの結果を返します。
<分節4170>
以下は、指定された座標で点の色を設定するメソッドです。
//+------------------------------------------------------------------+ //| Set the color of the dot with the specified coordinates | //+------------------------------------------------------------------+ bool CAnimations::SetPixelOnBG(const int id,const int x,const int y,const color clr,const uchar opacity=255,const bool create_new=true,const bool redraw=false) { CFrameQuad *frame=this.GetOrCreateFrame(DFUN,id,ANIMATION_FRAME_TYPE_QUAD,create_new); if(frame==NULL) return false; return frame.SetPixelOnBG(x,y,clr,opacity,redraw); } //+------------------------------------------------------------------+
メソッドのロジックは、上記で検討したメソッドと同じです。このメソッドは、オブジェクトID、描画された形状のX座標とY座標、その色と不透明度、指定されたIDを持つオブジェクトがリストに存在しない場合にそのIDを持つ新しいオブジェクトを作成する必要があることを示すフラグ、チャートの再描画フラグを受け取ります。
次に、必要なオブジェクトへのポインタを取得します(または、オブジェクトがない場合はオブジェクトを作成します)。ポインタの取得に失敗した場合は、falseを返します。
ポインタを受け取った場合は、取得したアニメーション長方形フレームオブジェクトのSetPixelOnBG()メソッドの結果を返します。
以下は、プリミティブを描画する他のメソッドです。
残りの形状描画メソッドのロジックは、上記で検討したメソッドと同じです。コードをみてみましょう。
//+------------------------------------------------------------------+ //| Draw a segment of a vertical line | //+------------------------------------------------------------------+ bool CAnimations::DrawLineVerticalOnBG(const int id, // Frame ID const int x, // Segment X coordinate const int y1, // Y coordinate of the segment first point const int y2, // Y coordinate of the segment second point const color clr, // Color const uchar opacity=255, // Opacity const bool create_new=true, // New object creation flag const bool redraw=false) // Chart redraw flag { CFrameQuad *frame=this.GetOrCreateFrame(DFUN,id,ANIMATION_FRAME_TYPE_QUAD,create_new); if(frame==NULL) return false; return frame.DrawLineVerticalOnBG(x,y1,y2,clr,opacity,redraw); } //+------------------------------------------------------------------+ //| Draw a segment of a horizontal line | //+------------------------------------------------------------------+ bool CAnimations::DrawLineHorizontalOnBG(const int id, // Frame ID const int x1, // X coordinate of the segment first point const int x2, // X coordinate of the segment second point const int y, // Segment Y coordinate const color clr, // Color const uchar opacity=255, // Opacity const bool create_new=true, // New object creation flag const bool redraw=false) // Chart redraw flag { CFrameQuad *frame=this.GetOrCreateFrame(DFUN,id,ANIMATION_FRAME_TYPE_QUAD,create_new); if(frame==NULL) return false; return frame.DrawLineHorizontalOnBG(x1,x2,y,clr,opacity,redraw); } //+------------------------------------------------------------------+ //| Draw a segment of a freehand line | //+------------------------------------------------------------------+ bool CAnimations::DrawLineOnBG(const int id, // Frame ID const int x1, // X coordinate of the segment first point const int y1, // Y coordinate of the segment first point const int x2, // X coordinate of the segment second point const int y2, // Y coordinate of the segment second point const color clr, // Color const uchar opacity=255, // Opacity const bool create_new=true, // New object creation flag const bool redraw=false) // Chart redraw flag { CFrameQuad *frame=this.GetOrCreateFrame(DFUN,id,ANIMATION_FRAME_TYPE_QUAD,create_new); if(frame==NULL) return false; return frame.DrawLineOnBG(x1,y1,x2,y2,clr,opacity,redraw); } //+------------------------------------------------------------------+ //| Draw a polyline | //+------------------------------------------------------------------+ bool CAnimations::DrawPolylineOnBG(const int id, // Frame ID int &array_x[], // Array with the X coordinates of polyline points int &array_y[], // Array with the Y coordinates of polyline points const color clr, // Color const uchar opacity=255, // Opacity const bool create_new=true, // New object creation flag const bool redraw=false) // Chart redraw flag { CFrameQuad *frame=this.GetOrCreateFrame(DFUN,id,ANIMATION_FRAME_TYPE_QUAD,create_new); if(frame==NULL) return false; return frame.DrawPolylineOnBG(array_x,array_y,clr,opacity,redraw); } //+------------------------------------------------------------------+ //| Draw the rectangle | //+------------------------------------------------------------------+ bool CAnimations::DrawPolygonOnBG(const int id, // Frame ID int &array_x[], // Array with the X coordinates of polygon points int &array_y[], // Array with the Y coordinates of polygon points const color clr, // Color const uchar opacity=255, // Opacity const bool create_new=true, // New object creation flag const bool redraw=false) // Chart redraw flag { CFrameQuad *frame=this.GetOrCreateFrame(DFUN,id,ANIMATION_FRAME_TYPE_QUAD,create_new); if(frame==NULL) return false; return frame.DrawPolygonOnBG(array_x,array_y,clr,opacity,redraw); } //+------------------------------------------------------------------+ //| Draw a rectangle using two points | //+------------------------------------------------------------------+ bool CAnimations::DrawRectangleOnBG(const int id, // Frame ID const int x1, // X coordinate of the first point defining the rectangle const int y1, // Y coordinate of the first point defining the rectangle const int x2, // X coordinate of the second point defining the rectangle const int y2, // Y coordinate of the second point defining the rectangle const color clr, // Color const uchar opacity=255, // Opacity const bool create_new=true, // New object creation flag const bool redraw=false) // Chart redraw flag { CFrameQuad *frame=this.GetOrCreateFrame(DFUN,id,ANIMATION_FRAME_TYPE_QUAD,create_new); if(frame==NULL) return false; return frame.DrawRectangleOnBG(x1,y1,x2,y2,clr,opacity,redraw); } //+------------------------------------------------------------------+ //| Draw the circle | //+------------------------------------------------------------------+ bool CAnimations::DrawCircleOnBG(const int id, // Frame ID const int x, // X coordinate of the circle center const int y, // Y coordinate of the circle center const int r, // Circle radius const color clr, // Color const uchar opacity=255, // Opacity const bool create_new=true, // New object creation flag const bool redraw=false) // Chart redraw flag { CFrameQuad *frame=this.GetOrCreateFrame(DFUN,id,ANIMATION_FRAME_TYPE_QUAD,create_new); if(frame==NULL) return false; return frame.DrawCircleOnBG(x,y,r,clr,opacity,redraw); } //+------------------------------------------------------------------+ //| Draw a triangle | //+------------------------------------------------------------------+ bool CAnimations::DrawTriangleOnBG(const int id, // Frame ID const int x1, // X coordinate of the triangle first vertex const int y1, // Y coordinate of the triangle first vertex const int x2, // X coordinate of the triangle second vertex const int y2, // Y coordinate of the triangle second vertex const int x3, // X coordinate of the triangle third vertex const int y3, // Y coordinate of the triangle third vertex const color clr, // Color const uchar opacity=255, // Opacity const bool create_new=true, // New object creation flag const bool redraw=false) // Chart redraw flag { CFrameQuad *frame=this.GetOrCreateFrame(DFUN,id,ANIMATION_FRAME_TYPE_QUAD,create_new); if(frame==NULL) return false; return frame.DrawTriangleOnBG(x1,y1,x2,y2,x3,y3,clr,opacity,redraw); } //+------------------------------------------------------------------+ //| Draw an ellipse using two points | //+------------------------------------------------------------------+ bool CAnimations::DrawEllipseOnBG(const int id, // Frame ID const int x1, // X coordinate of the first point defining the ellipse const int y1, // Y coordinate of the first point defining the ellipse const int x2, // X coordinate of the second point defining the ellipse const int y2, // Y coordinate of the second point defining the ellipse const color clr, // Color const uchar opacity=255, // Opacity const bool create_new=true, // New object creation flag const bool redraw=false) // Chart redraw flag { CFrameQuad *frame=this.GetOrCreateFrame(DFUN,id,ANIMATION_FRAME_TYPE_QUAD,create_new); if(frame==NULL) return false; return frame.DrawEllipseOnBG(x1,y1,x2,y2,clr,opacity,redraw); } //+------------------------------------------------------------------+ //| Draw an arc of an ellipse inscribed in a rectangle | //| with the corners in (x1,y1) and (x2,y2). | //| The arc boundaries are cropped from the ellipse center | //| moving to two points with the coordinates of (x3,y3) and (x4,y4) | //+------------------------------------------------------------------+ bool CAnimations::DrawArcOnBG(const int id, // Frame ID const int x1, // X coordinate of the top left corner forming the rectangle const int y1, // Y coordinate of the top left corner forming the rectangle const int x2, // X coordinate of the bottom right corner forming the rectangle const int y2, // Y coordinate of the bottom right corner forming the rectangle const int x3, // X coordinate of the first point, to which a line from the rectangle center is drawn in order to obtain the arc boundary const int y3, // Y coordinate of the first point, to which a line from the rectangle center is drawn in order to obtain the arc boundary const int x4, // X coordinate of the second point, to which a line from the rectangle center is drawn in order to obtain the arc boundary const int y4, // Y coordinate of the second point, to which a line from the rectangle center is drawn in order to obtain the arc boundary const color clr, // Color const uchar opacity=255, // Opacity const bool create_new=true, // New object creation flag const bool redraw=false) // Chart redraw flag { CFrameQuad *frame=this.GetOrCreateFrame(DFUN,id,ANIMATION_FRAME_TYPE_QUAD,create_new); if(frame==NULL) return false; return frame.DrawArcOnBG(x1,y1,x2,y2,x3,y3,x4,y4,clr,opacity,redraw); } //+------------------------------------------------------------------+ //| Draw a filled sector of an ellipse inscribed in a rectangle | //| with the corners in (x1,y1) and (x2,y2). | //| The sector boundaries are cropped from the ellipse center, | //| moving to two points with the coordinates of (x3,y3) and (x4,y4) | //+------------------------------------------------------------------+ bool CAnimations::DrawPieOnBG(const int id, // Frame ID const int x1, // X coordinate of the upper left corner of the rectangle const int y1, // Y coordinate of the upper left corner of the rectangle const int x2, // X coordinate of the bottom right corner of the rectangle const int y2, // Y coordinate of the bottom right corner of the rectangle const int x3, // X coordinate of the first point to find the arc boundaries const int y3, // Y coordinate of the first point to find the arc boundaries const int x4, // X coordinate of the second point to find the arc boundaries const int y4, // Y coordinate of the second point to find the arc boundaries const color clr, // Color const color fill_clr, // Fill color const uchar opacity=255, // Opacity const bool create_new=true, // New object creation flag const bool redraw=false) // Chart redraw flag { CFrameQuad *frame=this.GetOrCreateFrame(DFUN,id,ANIMATION_FRAME_TYPE_QUAD,create_new); if(frame==NULL) return false; return frame.DrawPieOnBG(x1,y1,x2,y2,x3,y3,x4,y4,clr,fill_clr,opacity,redraw); } //+------------------------------------------------------------------+ //| Fill in the area | //+------------------------------------------------------------------+ bool CAnimations::FillOnBG(const int id, // Frame ID const int x, // X coordinate of the filling start point const int y, // Y coordinate of the filling start point const color clr, // Color const uchar opacity=255, // Opacity const uint threshould=0, // Threshold const bool create_new=true, // New object creation flag const bool redraw=false) // Chart redraw flag { CFrameQuad *frame=this.GetOrCreateFrame(DFUN,id,ANIMATION_FRAME_TYPE_QUAD,create_new); if(frame==NULL) return false; return frame.FillOnBG(x,y,clr,opacity,threshould,redraw); } //+------------------------------------------------------------------+ //| Draw a filled rectangle | //+------------------------------------------------------------------+ bool CAnimations::DrawRectangleFillOnBG(const int id, // Frame ID const int x1, // X coordinate of the first point defining the rectangle const int y1, // Y coordinate of the first point defining the rectangle const int x2, // X coordinate of the second point defining the rectangle const int y2, // Y coordinate of the second point defining the rectangle const color clr, // Color const uchar opacity=255, // Opacity const bool create_new=true, // New object creation flag const bool redraw=false) // Chart redraw flag { CFrameQuad *frame=this.GetOrCreateFrame(DFUN,id,ANIMATION_FRAME_TYPE_QUAD,create_new); if(frame==NULL) return false; return frame.DrawRectangleFillOnBG(x1,y1,x2,y2,clr,opacity,redraw); } //+------------------------------------------------------------------+ //| Draw a filled circle | //+------------------------------------------------------------------+ bool CAnimations::DrawCircleFillOnBG(const int id, // Frame ID const int x, // X coordinate of the circle center const int y, // Y coordinate of the circle center const int r, // Circle radius const color clr, // Color const uchar opacity=255, // Opacity const bool create_new=true, // New object creation flag const bool redraw=false) // Chart redraw flag { CFrameQuad *frame=this.GetOrCreateFrame(DFUN,id,ANIMATION_FRAME_TYPE_QUAD,create_new); if(frame==NULL) return false; return frame.DrawCircleFillOnBG(x,y,r,clr,opacity,redraw); } //+------------------------------------------------------------------+ //| Draw a filled triangle | //+------------------------------------------------------------------+ bool CAnimations::DrawTriangleFillOnBG(const int id, // Frame ID const int x1, // X coordinate of the triangle first vertex const int y1, // Y coordinate of the triangle first vertex const int x2, // X coordinate of the triangle second vertex const int y2, // Y coordinate of the triangle second vertex const int x3, // X coordinate of the triangle third vertex const int y3, // Y coordinate of the triangle third vertex const color clr, // Color const uchar opacity=255, // Opacity const bool create_new=true, // New object creation flag const bool redraw=false) // Chart redraw flag { CFrameQuad *frame=this.GetOrCreateFrame(DFUN,id,ANIMATION_FRAME_TYPE_QUAD,create_new); if(frame==NULL) return false; return frame.DrawTriangleFillOnBG(x1,y1,x2,y2,x3,y3,clr,opacity,redraw); } //+------------------------------------------------------------------+ //| Draw a filled polygon | //+------------------------------------------------------------------+ bool CAnimations::DrawPolygonFillOnBG(const int id, // Frame ID int &array_x[], // Array with the X coordinates of polygon points int &array_y[], // Array with the Y coordinates of polygon points const color clr, // Color const uchar opacity=255, // Opacity const bool create_new=true, // New object creation flag const bool redraw=false) // Chart redraw flag { CFrameQuad *frame=this.GetOrCreateFrame(DFUN,id,ANIMATION_FRAME_TYPE_QUAD,create_new); if(frame==NULL) return false; return frame.DrawPolygonFillOnBG(array_x,array_y,clr,opacity,redraw); } //+------------------------------------------------------------------+ //| Draw a filled ellipse inscribed in a rectangle | //| with the given coordinates | //+------------------------------------------------------------------+ bool CAnimations::DrawEllipseFillOnBG(const int id, // Frame ID const int x1, // X coordinate of the top left corner forming the rectangle const int y1, // Y coordinate of the top left corner forming the rectangle const int x2, // X coordinate of the bottom right corner forming the rectangle const int y2, // Y coordinate of the bottom right corner forming the rectangle const color clr, // Color const uchar opacity=255, // Opacity const bool create_new=true, // New object creation flag const bool redraw=false) // Chart redraw flag { CFrameQuad *frame=this.GetOrCreateFrame(DFUN,id,ANIMATION_FRAME_TYPE_QUAD,create_new); if(frame==NULL) return false; return frame.DrawEllipseFillOnBG(x1,y1,x2,y2,clr,opacity,redraw); } //+------------------------------------------------------------------+ //| Draw a point using AntiAliasing algorithm | //+------------------------------------------------------------------+ bool CAnimations::SetPixelAAOnBG(const int id, // Frame ID const double x, // Point X coordinate const double y, // Point Y coordinate const color clr, // Color const uchar opacity=255, // Opacity const bool create_new=true, // New object creation flag const bool redraw=false) // Chart redraw flag { CFrameQuad *frame=this.GetOrCreateFrame(DFUN,id,ANIMATION_FRAME_TYPE_QUAD,create_new); if(frame==NULL) return false; return frame.SetPixelAAOnBG(x,y,clr,opacity,redraw); } //+------------------------------------------------------------------+ //| Draw a segment of a freehand line using the | //| AntiAliasing algorithm | //+------------------------------------------------------------------+ bool CAnimations::DrawLineAAOnBG(const int id, // Frame ID const int x1, // X coordinate of the segment first point const int y1, // Y coordinate of the segment first point const int x2, // X coordinate of the segment second point const int y2, // Y coordinate of the segment second point const color clr, // Color const uchar opacity=255, // Opacity const bool create_new=true, // New object creation flag const bool redraw=false, // Chart redraw flag const uint style=UINT_MAX) // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value { CFrameQuad *frame=this.GetOrCreateFrame(DFUN,id,ANIMATION_FRAME_TYPE_QUAD,create_new); if(frame==NULL) return false; return frame.DrawLineAAOnBG(x1,y1,x2,y2,clr,opacity,redraw,style); } //+------------------------------------------------------------------+ //| Draw a segment of a freehand line using the | //| Wu algorithm | //+------------------------------------------------------------------+ bool CAnimations::DrawLineWuOnBG(const int id, // Frame ID const int x1, // X coordinate of the segment first point const int y1, // Y coordinate of the segment first point const int x2, // X coordinate of the segment second point const int y2, // Y coordinate of the segment second point const color clr, // Color const uchar opacity=255, // Opacity const bool create_new=true, // New object creation flag const bool redraw=false, // Chart redraw flag const uint style=UINT_MAX) // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value { CFrameQuad *frame=this.GetOrCreateFrame(DFUN,id,ANIMATION_FRAME_TYPE_QUAD,create_new); if(frame==NULL) return false; return frame.DrawLineWuOnBG(x1,y1,x2,y2,clr,opacity,redraw,style); } //+------------------------------------------------------------------+ //| Draw a segment of a freehand line having a specified width | //| using a smoothing algorithm | //| with the preliminary sorting | //+------------------------------------------------------------------+ bool CAnimations::DrawLineThickOnBG(const int id, // Frame ID const int x1, // X coordinate of the segment first point const int y1, // Y coordinate of the segment first point const int x2, // X coordinate of the segment second point const int y2, // Y coordinate of the segment second point const int size, // Line width const color clr, // Color const uchar opacity=255, // Opacity const bool create_new=true, // New object creation flag const bool redraw=false, // Chart redraw flag const uint style=STYLE_SOLID, // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value ENUM_LINE_END end_style=LINE_END_ROUND) // Line style is one of the ENUM_LINE_END enumeration's values { CFrameQuad *frame=this.GetOrCreateFrame(DFUN,id,ANIMATION_FRAME_TYPE_QUAD,create_new); if(frame==NULL) return false; return frame.DrawLineThickOnBG(x1,y1,x2,y2,size,clr,opacity,redraw,style,end_style); } //+---------------------------------------------------------------------+ //| Draw a vertical segment of a freehand line having a specified width | //| using a smoothing algorithm | //| with the preliminary sorting | //+---------------------------------------------------------------------+ bool CAnimations::DrawLineThickVerticalOnBG(const int id, // Frame ID const int x, // Segment X coordinate const int y1, // Y coordinate of the segment first point const int y2, // Y coordinate of the segment second point const int size, // line width const color clr, // Color const uchar opacity=255, // Opacity const bool create_new=true, // New object creation flag const bool redraw=false, // Chart redraw flag const uint style=STYLE_SOLID, // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value const ENUM_LINE_END end_style=LINE_END_ROUND) // Line style is one of the ENUM_LINE_END enumeration's values { CFrameQuad *frame=this.GetOrCreateFrame(DFUN,id,ANIMATION_FRAME_TYPE_QUAD,create_new); if(frame==NULL) return false; return frame.DrawLineThickVerticalOnBG(x,y1,y2,size,clr,opacity,redraw,style,end_style); } //+-----------------------------------------------------------------------+ //| Draws a horizontal segment of a freehand line having a specified width| //| using a smoothing algorithm | //| with the preliminary sorting | //+-----------------------------------------------------------------------+ bool CAnimations::DrawLineThickHorizontalOnBG(const int id, // Frame ID const int x1, // X coordinate of the segment first point const int x2, // X coordinate of the segment second point const int y, // Segment Y coordinate const int size, // line width const color clr, // Color const uchar opacity=255, // Opacity const bool create_new=true, // New object creation flag const bool redraw=false, // Chart redraw flag const uint style=STYLE_SOLID, // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value const ENUM_LINE_END end_style=LINE_END_ROUND) // Line style is one of the ENUM_LINE_END enumeration's values { CFrameQuad *frame=this.GetOrCreateFrame(DFUN,id,ANIMATION_FRAME_TYPE_QUAD,create_new); if(frame==NULL) return false; return frame.DrawLineThickHorizontalOnBG(x1,x2,y,size,clr,opacity,redraw,style,end_style); } //+------------------------------------------------------------------+ //| Draw a polyline using | //| AntiAliasing algorithm | //+------------------------------------------------------------------+ bool CAnimations::DrawPolylineAAOnBG(const int id, // Frame ID int &array_x[], // Array with the X coordinates of polyline points int &array_y[], // Array with the Y coordinates of polyline points const color clr, // Color const uchar opacity=255, // Opacity const bool create_new=true, // New object creation flag const bool redraw=false, // Chart redraw flag const uint style=UINT_MAX) // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value { CFrameQuad *frame=this.GetOrCreateFrame(DFUN,id,ANIMATION_FRAME_TYPE_QUAD,create_new); if(frame==NULL) return false; return frame.DrawPolylineAAOnBG(array_x,array_y,clr,opacity,redraw,style); } //+------------------------------------------------------------------+ //| Draws a polyline using Wu algorithm | //+------------------------------------------------------------------+ //--- bool CAnimations::DrawPolylineWuOnBG(const int id, // Frame ID int &array_x[], // Array with the X coordinates of polyline points int &array_y[], // Array with the Y coordinates of polyline points const color clr, // Color const uchar opacity=255, // Opacity const bool create_new=true, // New object creation flag const bool redraw=false, // Chart redraw flag const uint style=UINT_MAX) // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value { CFrameQuad *frame=this.GetOrCreateFrame(DFUN,id,ANIMATION_FRAME_TYPE_QUAD,create_new); if(frame==NULL) return false; return frame.DrawPolylineWuOnBG(array_x,array_y,clr,opacity,redraw,style); } //+------------------------------------------------------------------+ //| Draw a polyline with a specified width using | //| two smoothing algorithms in series. | //| First, individual segments are smoothed | //| based on Bezier curves. | //| Then, to improve the rendering quality, | //| a raster smoothing algorithm | //| made of the polyline segments is applied | //+------------------------------------------------------------------+ bool CAnimations::DrawPolylineSmoothOnBG(const int id, // Frame ID const int &array_x[], // Array with the X coordinates of polyline points const int &array_y[], // Array with the Y coordinates of polyline points const int size, // Line width const color clr, // Color const uchar opacity=255, // Opacity const double tension=0.5, // Smoothing parameter value const double step=10, // Approximation step const bool create_new=true, // New object creation flag const bool redraw=false, // Chart redraw flag const ENUM_LINE_STYLE style=STYLE_SOLID, // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value const ENUM_LINE_END end_style=LINE_END_ROUND) // Line style is one of the ENUM_LINE_END enumeration's values { CFrameQuad *frame=this.GetOrCreateFrame(DFUN,id,ANIMATION_FRAME_TYPE_QUAD,create_new); if(frame==NULL) return false; return frame.DrawPolylineSmoothOnBG(array_x,array_y,size,clr,opacity,tension,step,redraw,style,end_style); } //+------------------------------------------------------------------+ //| Draw a polyline with a specified width using | //| a smoothing algorithm with the preliminary sorting | //+------------------------------------------------------------------+ bool CAnimations::DrawPolylineThickOnBG(const int id, // Frame ID const int &array_x[], // Array with the X coordinates of polyline points const int &array_y[], // Array with the Y coordinates of polyline points const int size, // Line width const color clr, // Color const uchar opacity=255, // Opacity const bool create_new=true, // New object creation flag const bool redraw=false, // Chart redraw flag const uint style=STYLE_SOLID, // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value ENUM_LINE_END end_style=LINE_END_ROUND) // Line style is one of the ENUM_LINE_END enumeration's values { CFrameQuad *frame=this.GetOrCreateFrame(DFUN,id,ANIMATION_FRAME_TYPE_QUAD,create_new); if(frame==NULL) return false; return frame.DrawPolylineThickOnBG(array_x,array_y,size,clr,opacity,redraw,style,end_style); } //+------------------------------------------------------------------+ //| Draw a polygon using | //| AntiAliasing algorithm | //+------------------------------------------------------------------+ bool CAnimations::DrawPolygonAAOnBG(const int id, // Frame ID int &array_x[], // Array with the X coordinates of polygon points int &array_y[], // Array with the Y coordinates of polygon points const color clr, // Color const uchar opacity=255, // Opacity const bool create_new=true, // New object creation flag const bool redraw=false, // Chart redraw flag const uint style=UINT_MAX) // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value { CFrameQuad *frame=this.GetOrCreateFrame(DFUN,id,ANIMATION_FRAME_TYPE_QUAD,create_new); if(frame==NULL) return false; return frame.DrawPolygonAAOnBG(array_x,array_y,clr,opacity,redraw,style); } //+------------------------------------------------------------------+ //| Draw a polygon using Wu algorithm | //+------------------------------------------------------------------+ bool CAnimations::DrawPolygonWuOnBG(const int id, // Frame ID int &array_x[], // Array with the X coordinates of polygon points int &array_y[], // Array with the Y coordinates of polygon points const color clr, // Color const uchar opacity=255, // Opacity const bool create_new=true, // New object creation flag const bool redraw=false, // Chart redraw flag const uint style=UINT_MAX) // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value { CFrameQuad *frame=this.GetOrCreateFrame(DFUN,id,ANIMATION_FRAME_TYPE_QUAD,create_new); if(frame==NULL) return false; return frame.DrawPolygonWuOnBG(array_x,array_y,clr,opacity,redraw,style); } //+------------------------------------------------------------------+ //| Draw a polygon with a specified width using | //| two smoothing algorithms in series. | //| First, individual segments are smoothed based on Bezier curves. | //| Then, to improve the rendering quality, | //| a raster smoothing algorithm is applied | //| made of the polyline segments. | //+------------------------------------------------------------------+ bool CAnimations::DrawPolygonSmoothOnBG(const int id, // Frame ID int &array_x[], // Array with the X coordinates of polyline points int &array_y[], // Array with the Y coordinates of polyline points const int size, // Line width const color clr, // Color const uchar opacity=255, // Opacity const double tension=0.5, // Smoothing parameter value const double step=10, // Approximation step const bool create_new=true, // New object creation flag const bool redraw=false, // Chart redraw flag const ENUM_LINE_STYLE style=STYLE_SOLID, // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value const ENUM_LINE_END end_style=LINE_END_ROUND) // Line style is one of the ENUM_LINE_END enumeration's values { CFrameQuad *frame=this.GetOrCreateFrame(DFUN,id,ANIMATION_FRAME_TYPE_QUAD,create_new); if(frame==NULL) return false; return frame.DrawPolygonSmoothOnBG(array_x,array_y,size,clr,opacity,tension,step,redraw,style,end_style); } //+------------------------------------------------------------------+ //| Draw a polygon with a specified width using | //| a smoothing algorithm with the preliminary sorting | //+------------------------------------------------------------------+ //--- Draw a polygon having a specified width using smoothing algorithm with the preliminary filtration bool CAnimations::DrawPolygonThickOnBG(const int id, // Frame ID const int &array_x[], // array with the X coordinates of polygon points const int &array_y[], // array with the Y coordinates of polygon points const int size, // line width const color clr, // Color const uchar opacity=255, // Opacity const bool create_new=true, // New object creation flag const bool redraw=false, // Chart redraw flag const uint style=STYLE_SOLID, // line style ENUM_LINE_END end_style=LINE_END_ROUND) // line ends style { CFrameQuad *frame=this.GetOrCreateFrame(DFUN,id,ANIMATION_FRAME_TYPE_QUAD,create_new); if(frame==NULL) return false; return frame.DrawPolygonThickOnBG(array_x,array_y,size,clr,opacity,redraw,style,end_style); } //+------------------------------------------------------------------+ //| Draw a triangle using | //| AntiAliasing algorithm | //+------------------------------------------------------------------+ bool CAnimations::DrawTriangleAAOnBG(const int id, // Frame ID const int x1, // X coordinate of the triangle first vertex const int y1, // Y coordinate of the triangle first vertex const int x2, // X coordinate of the triangle second vertex const int y2, // Y coordinate of the triangle second vertex const int x3, // X coordinate of the triangle third vertex const int y3, // Y coordinate of the triangle third vertex const color clr, // Color const uchar opacity=255, // Opacity const bool create_new=true, // New object creation flag const bool redraw=false, // Chart redraw flag const uint style=UINT_MAX) // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value { CFrameQuad *frame=this.GetOrCreateFrame(DFUN,id,ANIMATION_FRAME_TYPE_QUAD,create_new); if(frame==NULL) return false; return frame.DrawTriangleAAOnBG(x1,y1,x2,y2,x3,y3,clr,opacity,redraw,style); } //+------------------------------------------------------------------+ //| Draw a triangle using Wu algorithm | //+------------------------------------------------------------------+ bool CAnimations::DrawTriangleWuOnBG(const int id, // Frame ID const int x1, // X coordinate of the triangle first vertex const int y1, // Y coordinate of the triangle first vertex const int x2, // X coordinate of the triangle second vertex const int y2, // Y coordinate of the triangle second vertex const int x3, // X coordinate of the triangle third vertex const int y3, // Y coordinate of the triangle third vertex const color clr, // Color const uchar opacity=255, // Opacity const bool create_new=true, // New object creation flag const bool redraw=false, // Chart redraw flag const uint style=UINT_MAX) // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value { CFrameQuad *frame=this.GetOrCreateFrame(DFUN,id,ANIMATION_FRAME_TYPE_QUAD,create_new); if(frame==NULL) return false; return frame.DrawTriangleWuOnBG(x1,y1,x2,y2,x3,y3,clr,opacity,redraw,style); } //+------------------------------------------------------------------+ //| Draw a circle using | //| AntiAliasing algorithm | //+------------------------------------------------------------------+ bool CAnimations::DrawCircleAAOnBG(const int id, // Frame ID const int x, // X coordinate of the circle center const int y, // Y coordinate of the circle center const double r, // Circle radius const color clr, // Color const uchar opacity=255, // Opacity const bool create_new=true, // New object creation flag const bool redraw=false, // Chart redraw flag const uint style=UINT_MAX) // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value { CFrameQuad *frame=this.GetOrCreateFrame(DFUN,id,ANIMATION_FRAME_TYPE_QUAD,create_new); if(frame==NULL) return false; return frame.DrawCircleAAOnBG(x,y,r,clr,opacity,redraw,style); } //+------------------------------------------------------------------+ //| Draw a circle using Wu algorithm | //+------------------------------------------------------------------+ bool CAnimations::DrawCircleWuOnBG(const int id, // Frame ID const int x, // X coordinate of the circle center const int y, // Y coordinate of the circle center const double r, // Circle radius const color clr, // Color const uchar opacity=255, // Opacity const bool create_new=true, // New object creation flag const bool redraw=false, // Chart redraw flag const uint style=UINT_MAX) // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value { CFrameQuad *frame=this.GetOrCreateFrame(DFUN,id,ANIMATION_FRAME_TYPE_QUAD,create_new); if(frame==NULL) return false; return frame.DrawCircleWuOnBG(x,y,r,clr,opacity,redraw,style); } //+------------------------------------------------------------------+ //| Draw an ellipse using two points while applying | //| AntiAliasing algorithm | //+------------------------------------------------------------------+ bool CAnimations::DrawEllipseAAOnBG(const int id, // Frame ID const double x1, // X coordinate of the first point defining the ellipse const double y1, // Y coordinate of the first point defining the ellipse const double x2, // X coordinate of the second point defining the ellipse const double y2, // Y coordinate of the second point defining the ellipse const color clr, // Color const uchar opacity=255, // Opacity const bool create_new=true, // New object creation flag const bool redraw=false, // Chart redraw flag const uint style=UINT_MAX) // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value { CFrameQuad *frame=this.GetOrCreateFrame(DFUN,id,ANIMATION_FRAME_TYPE_QUAD,create_new); if(frame==NULL) return false; return frame.DrawEllipseAAOnBG(x1,y1,x2,y2,clr,opacity,redraw,style); } //+------------------------------------------------------------------+ //| Draw an ellipse using two points | //| using Wu algorithm | //+------------------------------------------------------------------+ bool CAnimations::DrawEllipseWuOnBG(const int id, // Frame ID const int x1, // X coordinate of the first point defining the ellipse const int y1, // Y coordinate of the first point defining the ellipse const int x2, // X coordinate of the second point defining the ellipse const int y2, // Y coordinate of the second point defining the ellipse const color clr, // Color const uchar opacity=255, // Opacity const bool create_new=true, // New object creation flag const bool redraw=false, // Chart redraw flag const uint style=UINT_MAX) // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value { CFrameQuad *frame=this.GetOrCreateFrame(DFUN,id,ANIMATION_FRAME_TYPE_QUAD,create_new); if(frame==NULL) return false; return frame.DrawEllipseWuOnBG(x1,y1,x2,y2,clr,opacity,redraw,style); } //+------------------------------------------------------------------+
新しく作成されたアニメーションオブジェクトのクラスは、フォームオブジェクトの不可欠な部分であるため、各フォームには、画像を作成する独自のメソッドがあります。
フォームオブジェクトクラスの\MQL5\Include\DoEasy\Objects\Graph\Form.mqhファイルを開き、必要な改善を追加します。
アニメーションオブジェクトクラスのファイルをインクルードします。
//+------------------------------------------------------------------+ //| Form.mqh | //| Copyright 2021, MetaQuotes Ltd. | //| https://mql5.com/en/users/artmedia70 | //+------------------------------------------------------------------+ #property copyright "Copyright 2021, MetaQuotes Ltd." #property link "https://mql5.com/en/users/artmedia70" #property version "1.00" #property strict // Necessary for mql4 //+------------------------------------------------------------------+ //| Include files | //+------------------------------------------------------------------+ #include "GCnvElement.mqh" #include "ShadowObj.mqh" #include "Animations\Animations.mqh" //+------------------------------------------------------------------+
ピクセルコピーオブジェクトクラスを削除します(別のファイルに移動しました):
//+------------------------------------------------------------------+ //| Include files | //+------------------------------------------------------------------+ #include "GCnvElement.mqh" #include "ShadowObj.mqh" #include "Animations\Animations.mqh" //+------------------------------------------------------------------+ //| Pixel copier class | //+------------------------------------------------------------------+ class CPixelCopier : public CObject { private: ... } //+------------------------------------------------------------------+ //+------------------------------------------------------------------+ //| Form object class | //+------------------------------------------------------------------+
クラスのprivateセクションで、ピクセルコピー機リストの代わりに
CArrayObj m_list_pc_obj; // List of pixel copier objects
アニメーションクラスオブジェクトへのポインタを宣言します。
//+------------------------------------------------------------------+ //| Form.mqh | //| Copyright 2021, MetaQuotes Ltd. | //| https://mql5.com/en/users/artmedia70 | //+------------------------------------------------------------------+ #property copyright "Copyright 2021, MetaQuotes Ltd." #property link "https://mql5.com/en/users/artmedia70" #property version "1.00" #property strict // Necessary for mql4 //+------------------------------------------------------------------+ //| Include files | //+------------------------------------------------------------------+ #include "GCnvElement.mqh" #include "ShadowObj.mqh" #include "Animations\Animations.mqh" //+------------------------------------------------------------------+ //| Form object class | //+------------------------------------------------------------------+ class CForm : public CGCnvElement { private: CArrayObj m_list_elements; // List of attached elements CAnimations *m_animations; // Pointer to the animation object CShadowObj *m_shadow_obj; // Pointer to the shadow object color m_color_frame; // Form frame color int m_frame_width_left; // Form frame width to the left int m_frame_width_right; // Form frame width to the right int m_frame_width_top; // Form frame width at the top int m_frame_width_bottom; // Form frame width at the bottom //--- Initialize the variables void Initialize(void); //--- Return the name of the dependent object string CreateNameDependentObject(const string base_name) const { return ::StringSubstr(this.NameObj(),::StringLen(::MQLInfoString(MQL_PROGRAM_NAME))+1)+"_"+base_name; } //--- Create a new graphical object CGCnvElement *CreateNewGObject(const ENUM_GRAPH_ELEMENT_TYPE type, const int element_num, const string name, const int x, const int y, const int w, const int h, const color colour, const uchar opacity, const bool movable, const bool activity); //--- Create a shadow object void CreateShadowObj(const color colour,const uchar opacity); public:
すでに不要なIsPresentPC()メソッドの宣言をprivateセクションから削除し、その実装をコードリストから削除します。
//--- Create a shadow object void CreateShadowObj(const color colour,const uchar opacity); //--- Return the flag indicating the presence of the copier object with the specified ID in the list bool IsPresentPC(const int id); public:
クラスのpublicセクションから不要なメソッドを削除します。
//--- Return (1) itself, the list of (2) attached objects, (3) pixel copier objects and (4) the shadow object CForm *GetObject(void) { return &this; } CArrayObj *GetList(void) { return &this.m_list_elements; } CArrayObj *GetListPC(void) { return &this.m_list_pc_obj; } CGCnvElement *GetShadowObj(void) { return this.m_shadow_obj; }
およびアニメーションオブジェクトへのポインタとテキストおよび長方形のアニメーションフレームのリストを返す新しいメソッドを追加します。
CGCnvElement *GetShadowObj(void) { return this.m_shadow_obj; } //--- Return the pointer to (1) the animation object, the list of (2) text and (3) rectangle animation frames CAnimations *GetAnimationsObj(void) { return this.m_animations; } CArrayObj *GetListFramesText(void) { return(this.m_animations!=NULL ? this.m_animations.GetListFramesText() : NULL); } CArrayObj *GetListFramesQuad(void) { return(this.m_animations!=NULL ? this.m_animations.GetListFramesQuad() : NULL); } //--- Set the form (1) color scheme and (2) style
新しいピクセルコピーオブジェクトを作成するためのメソッドの宣言を削除します。
//--- Create a new pixel copier object CPixelCopier *CreateNewPixelCopier(const int id,const int x_coord,const int y_coord,const int width,const int height); //--- Draw an object shadow
クラス本体の外部に記述されたメソッドの実装も削除されます。
クラスのpublicセクションにある画像ピクセルを操作するためのメソッドのブロックで、アニメーションフレームオブジェクトを作成するための新しいメソッドを記述し、作成されたオブジェクトへのポインタを返し、背景を保存および復元するメソッドを描画します。
//+------------------------------------------------------------------+ //| Methods of working with image pixels | //+------------------------------------------------------------------+ //--- Create a new (1) rectangle and (2) text animation frame object bool CreateNewFrameText(const int id,const int x_coord,const int y_coord,const string text) { return(this.m_animations!=NULL ? this.m_animations.CreateNewFrameText(id)!=NULL : false); } bool CreateNewFrameQuad(const int id,const int x_coord,const int y_coord,const int width,const int height) { return(this.m_animations!=NULL ? this.m_animations.CreateNewFrameQuad(id)!=NULL : false); } //--- Return the frame object of the (1) text and (2) rectangle animation by ID CFrame *GetFrameText(const int id) { return(this.m_animations!=NULL ? this.m_animations.GetFrame(ANIMATION_FRAME_TYPE_TEXT,id) : NULL); } CFrame *GetFrameQuad(const int id) { return(this.m_animations!=NULL ? this.m_animations.GetFrame(ANIMATION_FRAME_TYPE_QUAD,id) : NULL); } //--- Display the text on the background while saving and restoring the background bool TextOnBG(const int id, const string text, const int x, const int y, const ENUM_TEXT_ANCHOR anchor, const color clr, const uchar opacity=255, const bool create_new=true, const bool redraw=false) { return(this.m_animations!=NULL ? this.m_animations.TextOnBG(id,text,x,y,anchor,clr,opacity,create_new,redraw) : false); } //--- Set the color of the point with the specified coordinates while saving and restoring the background bool SetPixelOnBG(const int id,const int x,const int y,const color clr,const uchar opacity=255,const bool create_new=true,const bool redraw=false) { return(this.m_animations!=NULL ? this.m_animations.SetPixelOnBG(id,x,y,clr,opacity,create_new,redraw) : false); } //--- Draw a segment of a vertical line bool DrawLineVerticalOnBG(const int id, // Frame ID const int x, // Segment X coordinate const int y1, // Y coordinate of the segment first point const int y2, // Y coordinate of the segment second point const color clr, // Color const uchar opacity=255, // Opacity const bool create_new=true, // New object creation flag const bool redraw=false) // Chart redraw flag { return(this.m_animations!=NULL ? this.m_animations.DrawLineVerticalOnBG(id,x,y1,y2,clr,opacity,create_new,redraw) : false); } //--- Draw a segment of a horizontal line while saving and restoring the background bool DrawLineHorizontalOnBG(const int id, // Frame ID const int x1, // X coordinate of the segment first point const int x2, // X coordinate of the segment second point const int y, // Segment Y coordinate const color clr, // Color const uchar opacity=255, // Opacity const bool create_new=true, // New object creation flag const bool redraw=false) // Chart redraw flag { return(this.m_animations!=NULL ? this.m_animations.DrawLineHorizontalOnBG(id,x1,x2,y,clr,opacity,create_new,redraw) : false); } //--- Draw a segment of a freehand line while saving and restoring the background bool DrawLineOnBG(const int id, // Frame ID const int x1, // X coordinate of the segment first point const int y1, // Y coordinate of the segment first point const int x2, // X coordinate of the segment second point const int y2, // Y coordinate of the segment second point const color clr, // Color const uchar opacity=255, // Opacity const bool create_new=true, // New object creation flag const bool redraw=false) // Chart redraw flag { return(this.m_animations!=NULL ? this.m_animations.DrawLineOnBG(id,x1,y1,x2,y2,clr,opacity,create_new,redraw) : false); } //--- Draw a polyline while saving and restoring the background bool DrawPolylineOnBG(const int id, // Frame ID int &array_x[], // Array with the X coordinates of polyline points int &array_y[], // Array with the Y coordinates of polyline points const color clr, // Color const uchar opacity=255, // Opacity const bool create_new=true, // New object creation flag const bool redraw=false) // Chart redraw flag { return(this.m_animations!=NULL ? this.m_animations.DrawPolylineOnBG(id,array_x,array_y,clr,opacity,create_new,redraw) : false); } //--- Draw a polygon while saving and restoring the background bool DrawPolygonOnBG(const int id, // Frame ID int &array_x[], // Array with the X coordinates of polygon points int &array_y[], // Array with the Y coordinates of polygon points const color clr, // Color const uchar opacity=255, // Opacity const bool create_new=true, // New object creation flag const bool redraw=false) // Chart redraw flag { return(this.m_animations!=NULL ? this.m_animations.DrawPolygonOnBG(id,array_x,array_y,clr,opacity,create_new,redraw) : false); } //--- Draw a rectangle by two points while saving and restoring the background bool DrawRectangleOnBG(const int id, // Frame ID const int x1, // X coordinate of the first point defining the rectangle const int y1, // Y coordinate of the first point defining the rectangle const int x2, // X coordinate of the second point defining the rectangle const int y2, // Y coordinate of the second point defining the rectangle const color clr, // Color const uchar opacity=255, // Opacity const bool create_new=true, // New object creation flag const bool redraw=false) // Chart redraw flag { return(this.m_animations!=NULL ? this.m_animations.DrawRectangleOnBG(id,x1,y1,x2,y2,clr,opacity,create_new,redraw) : false); } //--- Draw a circle while saving and restoring the background bool DrawCircleOnBG(const int id, // Frame ID const int x, // X coordinate of the circle center const int y, // Y coordinate of the circle center const int r, // Circle radius const color clr, // Color const uchar opacity=255, // Opacity const bool create_new=true, // New object creation flag const bool redraw=false) // Chart redraw flag { return(this.m_animations!=NULL ? this.m_animations.DrawCircleOnBG(id,x,y,r,clr,opacity,create_new,redraw) : false); } //--- Draw a triangle while saving and restoring the background bool DrawTriangleOnBG(const int id, // Frame ID const int x1, // X coordinate of the triangle first vertex const int y1, // Y coordinate of the triangle first vertex const int x2, // X coordinate of the triangle second vertex const int y2, // Y coordinate of the triangle second vertex const int x3, // X coordinate of the triangle third vertex const int y3, // Y coordinate of the triangle third vertex const color clr, // Color const uchar opacity=255, // Opacity const bool create_new=true, // New object creation flag const bool redraw=false) // Chart redraw flag { return(this.m_animations!=NULL ? this.m_animations.DrawTriangleOnBG(id,x1,y1,x2,y2,x3,y3,clr,opacity,create_new,redraw) : false); } //--- Draw an ellipse by two points while saving and restoring the background bool DrawEllipseOnBG(const int id, // Frame ID const int x1, // X coordinate of the first point defining the ellipse const int y1, // Y coordinate of the first point defining the ellipse const int x2, // X coordinate of the second point defining the ellipse const int y2, // Y coordinate of the second point defining the ellipse const color clr, // Color const uchar opacity=255, // Opacity const bool create_new=true, // New object creation flag const bool redraw=false) // Chart redraw flag { return(this.m_animations!=NULL ? this.m_animations.DrawEllipseOnBG(id,x1,y1,x2,y2,clr,opacity,create_new,redraw) : false); } //--- Draw an arc of an ellipse inscribed in a rectangle with corners at (x1,y1) and (x2,y2) while saving and restoring the background. //--- The arc boundaries are clipped by lines from the center of the ellipse, which extend to two points with coordinates (x3,y3) and (x4,y4) bool DrawArcOnBG(const int id, // Frame ID const int x1, // X coordinate of the top left corner forming the rectangle const int y1, // Y coordinate of the top left corner forming the rectangle const int x2, // X coordinate of the bottom right corner forming the rectangle const int y2, // Y coordinate of the bottom right corner forming the rectangle const int x3, // X coordinate of the first point, to which a line from the rectangle center is drawn in order to obtain the arc boundary const int y3, // Y coordinate of the first point, to which a line from the rectangle center is drawn in order to obtain the arc boundary const int x4, // X coordinate of the second point, to which a line from the rectangle center is drawn in order to obtain the arc boundary const int y4, // Y coordinate of the second point, to which a line from the rectangle center is drawn in order to obtain the arc boundary const color clr, // Color const uchar opacity=255, // Opacity const bool create_new=true, // New object creation flag const bool redraw=false) // Chart redraw flag { return(this.m_animations!=NULL ? this.m_animations.DrawArcOnBG(id,x1,y1,x2,y2,x3,y3,x4,y4,clr,opacity,create_new,redraw) : false); } //--- Draw a filled sector of an ellipse inscribed in a rectangle with corners at (x1,y1) and (x2,y2) while saving and restoring the background. //--- The sector boundaries are clipped by lines from the center of the ellipse, which extend to two points with coordinates (x3,y3) and (x4,y4) bool DrawPieOnBG(const int id, // Frame ID const int x1, // X coordinate of the upper left corner of the rectangle const int y1, // Y coordinate of the upper left corner of the rectangle const int x2, // X coordinate of the bottom right corner of the rectangle const int y2, // Y coordinate of the bottom right corner of the rectangle const int x3, // X coordinate of the first point to find the arc boundaries const int y3, // Y coordinate of the first point to find the arc boundaries const int x4, // X coordinate of the second point to find the arc boundaries const int y4, // Y coordinate of the second point to find the arc boundaries const color clr, // Color const color fill_clr, // Fill color const uchar opacity=255, // Opacity const bool create_new=true, // New object creation flag const bool redraw=false) // Chart redraw flag { return(this.m_animations!=NULL ? this.m_animations.DrawPieOnBG(id,x1,y1,x2,y2,x3,y3,x4,y4,clr,fill_clr,opacity,create_new,redraw) : false); } //--- Fill the area while saving and restoring the background bool FillOnBG(const int id, // Frame ID const int x, // X coordinate of the filling start point const int y, // Y coordinate of the filling start point const color clr, // Color const uchar opacity=255, // Opacity const uint threshould=0, // Threshold const bool create_new=true, // New object creation flag const bool redraw=false) // Chart redraw flag { return(this.m_animations!=NULL ? this.m_animations.FillOnBG(id,x,y,clr,opacity,threshould,create_new,redraw) : false); } //--- Draw a filled rectangle while saving and restoring the background bool DrawRectangleFillOnBG(const int id, // Frame ID const int x1, // X coordinate of the first point defining the rectangle const int y1, // Y coordinate of the first point defining the rectangle const int x2, // X coordinate of the second point defining the rectangle const int y2, // Y coordinate of the second point defining the rectangle const color clr, // Color const uchar opacity=255, // Opacity const bool create_new=true, // New object creation flag const bool redraw=false) // Chart redraw flag { return(this.m_animations!=NULL ? this.m_animations.DrawRectangleFillOnBG(id,x1,y1,x2,y2,clr,opacity,create_new,redraw) : false); } //--- Draw a filled circle while saving and restoring the background bool DrawCircleFillOnBG(const int id, // Frame ID const int x, // X coordinate of the circle center const int y, // Y coordinate of the circle center const int r, // Circle radius const color clr, // Color const uchar opacity=255, // Opacity const bool create_new=true, // New object creation flag const bool redraw=false) // Chart redraw flag { return(this.m_animations!=NULL ? this.m_animations.DrawCircleFillOnBG(id,x,y,r,clr,opacity,create_new,redraw) : false); } //--- Draw a filled triangle while saving and restoring the background bool DrawTriangleFillOnBG(const int id, // Frame ID const int x1, // X coordinate of the triangle first vertex const int y1, // Y coordinate of the triangle first vertex const int x2, // X coordinate of the triangle second vertex const int y2, // Y coordinate of the triangle second vertex const int x3, // X coordinate of the triangle third vertex const int y3, // Y coordinate of the triangle third vertex const color clr, // Color const uchar opacity=255, // Opacity const bool create_new=true, // New object creation flag const bool redraw=false) // Chart redraw flag { return(this.m_animations!=NULL ? this.m_animations.DrawTriangleFillOnBG(id,x1,y1,x2,y2,x3,y3,clr,opacity,create_new,redraw) : false); } //--- Draw a filled polygon while saving and restoring the background bool DrawPolygonFillOnBG(const int id, // Frame ID int &array_x[], // Array with the X coordinates of polygon points int &array_y[], // Array with the Y coordinates of polygon points const color clr, // Color const uchar opacity=255, // Opacity const bool create_new=true, // New object creation flag const bool redraw=false) // Chart redraw flag { return(this.m_animations!=NULL ? this.m_animations.DrawPolygonFillOnBG(id,array_x,array_y,clr,opacity,create_new,redraw) : false); } //--- Draw a filled ellipse inscribed in a rectangle with the specified coordinates while saving and restoring the background bool DrawEllipseFillOnBG(const int id, // Frame ID const int x1, // X coordinate of the top left corner forming the rectangle const int y1, // Y coordinate of the top left corner forming the rectangle const int x2, // X coordinate of the bottom right corner forming the rectangle const int y2, // Y coordinate of the bottom right corner forming the rectangle const color clr, // Color const uchar opacity=255, // Opacity const bool create_new=true, // New object creation flag const bool redraw=false) // Chart redraw flag { return(this.m_animations!=NULL ? this.m_animations.DrawEllipseFillOnBG(id,x1,y1,x2,y2,clr,opacity,create_new,redraw) : false); } //--- Draw a point using AntiAliasing algorithm while saving and restoring the background bool SetPixelAAOnBG(const int id, // Frame ID const double x, // Point X coordinate const double y, // Point Y coordinate const color clr, // Color const uchar opacity=255, // Opacity const bool create_new=true, // New object creation flag const bool redraw=false) // Chart redraw flag { return(this.m_animations!=NULL ? this.m_animations.SetPixelAAOnBG(id,x,y,clr,opacity,create_new,redraw) : false); } //--- Draw a segment of a freehand line using AntiAliasing algorithm while saving and restoring the background bool DrawLineAAOnBG(const int id, // Frame ID const int x1, // X coordinate of the segment first point const int y1, // Y coordinate of the segment first point const int x2, // X coordinate of the segment second point const int y2, // Y coordinate of the segment second point const color clr, // Color const uchar opacity=255, // Opacity const bool create_new=true, // New object creation flag const bool redraw=false, // Chart redraw flag const uint style=UINT_MAX) // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value { return(this.m_animations!=NULL ? this.m_animations.DrawLineAAOnBG(id,x1,y1,x2,y2,clr,opacity,create_new,redraw,style) : false); } //--- Draw a segment of a freehand line using Wu algorithm while saving and restoring the background bool DrawLineWuOnBG(const int id, // Frame ID const int x1, // X coordinate of the segment first point const int y1, // Y coordinate of the segment first point const int x2, // X coordinate of the segment second point const int y2, // Y coordinate of the segment second point const color clr, // Color const uchar opacity=255, // Opacity const bool create_new=true, // New object creation flag const bool redraw=false, // Chart redraw flag const uint style=UINT_MAX) // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value { return(this.m_animations!=NULL ? this.m_animations.DrawLineWuOnBG(id,x1,y1,x2,y2,clr,opacity,create_new,redraw,style) : false); } //--- Draw a segment of a freehand line having a specified width using smoothing algorithm with the preliminary filtration while saving and restoring the background bool DrawLineThickOnBG(const int id, // Frame ID const int x1, // X coordinate of the segment first point const int y1, // Y coordinate of the segment first point const int x2, // X coordinate of the segment second point const int y2, // Y coordinate of the segment second point const int size, // Line width const color clr, // Color const uchar opacity=255, // Opacity const bool create_new=true, // New object creation flag const bool redraw=false, // Chart redraw flag const uint style=STYLE_SOLID, // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value ENUM_LINE_END end_style=LINE_END_ROUND) // Line style is one of the ENUM_LINE_END enumeration's values { return(this.m_animations!=NULL ? this.m_animations.DrawLineThickOnBG(id,x1,y1,x2,y2,size,clr,opacity,create_new,redraw,style,end_style) : false); } //--- Draw a vertical segment of a freehand line having a specified width using smoothing algorithm with the preliminary filtration while saving and restoring the background bool DrawLineThickVerticalOnBG(const int id, // Frame ID const int x, // Segment X coordinate const int y1, // Y coordinate of the segment first point const int y2, // Y coordinate of the segment second point const int size, // line width const color clr, // Color const uchar opacity=255, // Opacity const bool create_new=true, // New object creation flag const bool redraw=false, // Chart redraw flag const uint style=STYLE_SOLID, // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value const ENUM_LINE_END end_style=LINE_END_ROUND) // Line style is one of the ENUM_LINE_END enumeration's values { return(this.m_animations!=NULL ? this.m_animations.DrawLineThickVerticalOnBG(id,x,y1,y2,size,clr,opacity,create_new,redraw,style,end_style) : false); } //--- Draw a horizontal segment of a freehand line having a specified width using smoothing algorithm with the preliminary filtration while saving and restoring the background bool DrawLineThickHorizontalOnBG(const int id, // Frame ID const int x1, // X coordinate of the segment first point const int x2, // X coordinate of the segment second point const int y, // Segment Y coordinate const int size, // line width const color clr, // Color const uchar opacity=255, // Opacity const bool create_new=true, // New object creation flag const bool redraw=false, // Chart redraw flag const uint style=STYLE_SOLID, // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value const ENUM_LINE_END end_style=LINE_END_ROUND) // Line style is one of the ENUM_LINE_END enumeration's values { return(this.m_animations!=NULL ? this.m_animations.DrawLineThickHorizontalOnBG(id,x1,x2,y,size,clr,opacity,create_new,redraw,style,end_style) : false); } //--- Draw a polyline using AntiAliasing algorithm while saving and restoring the background bool DrawPolylineAAOnBG(const int id, // Frame ID int &array_x[], // Array with the X coordinates of polyline points int &array_y[], // Array with the Y coordinates of polyline points const color clr, // Color const uchar opacity=255, // Opacity const bool create_new=true, // New object creation flag const bool redraw=false, // Chart redraw flag const uint style=UINT_MAX) // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value { return(this.m_animations!=NULL ? this.m_animations.DrawPolylineAAOnBG(id,array_x,array_y,clr,opacity,create_new,redraw,style) : false); } //--- Draw a polyline using Wu algorithm while saving and restoring the background bool DrawPolylineWuOnBG(const int id, // Frame ID int &array_x[], // Array with the X coordinates of polyline points int &array_y[], // Array with the Y coordinates of polyline points const color clr, // Color const uchar opacity=255, // Opacity const bool create_new=true, // New object creation flag const bool redraw=false, // Chart redraw flag const uint style=UINT_MAX) // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value { return(this.m_animations!=NULL ? this.m_animations.DrawPolylineWuOnBG(id,array_x,array_y,clr,opacity,create_new,redraw,style) : false); } //--- Draw a polyline with a specified width consecutively using two smoothing algorithms while saving and restoring the background. //--- First, individual line segments are smoothed based on Bezier curves. //--- Then, the raster antialiasing algorithm is applied to the polyline built from these segments to improve the rendering quality bool DrawPolylineSmoothOnBG(const int id, // Frame ID const int &array_x[], // Array with the X coordinates of polyline points const int &array_y[], // Array with the Y coordinates of polyline points const int size, // Line width const color clr, // Color const uchar opacity=255, // Opacity const double tension=0.5, // Smoothing parameter value const double step=10, // Approximation step const bool create_new=true, // New object creation flag const bool redraw=false, // Chart redraw flag const ENUM_LINE_STYLE style=STYLE_SOLID, // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value const ENUM_LINE_END end_style=LINE_END_ROUND)// Line style is one of the ENUM_LINE_END enumeration's values { return(this.m_animations!=NULL ? this.m_animations.DrawPolylineSmoothOnBG(id,array_x,array_y,size,clr,opacity,tension,step,create_new,redraw,style,end_style) : false); } //--- Draw a polyline having a specified width using smoothing algorithm with the preliminary filtration while saving and restoring the background bool DrawPolylineThickOnBG(const int id, // Frame ID const int &array_x[], // Array with the X coordinates of polyline points const int &array_y[], // Array with the Y coordinates of polyline points const int size, // Line width const color clr, // Color const uchar opacity=255, // Opacity const bool create_new=true, // New object creation flag const bool redraw=false, // Chart redraw flag const uint style=STYLE_SOLID, // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value ENUM_LINE_END end_style=LINE_END_ROUND) // Line style is one of the ENUM_LINE_END enumeration's values { return(this.m_animations!=NULL ? this.m_animations.DrawPolylineThickOnBG(id,array_x,array_y,size,clr,opacity,create_new,redraw,style,end_style) : false); } //--- Draw a polygon using AntiAliasing algorithm while saving and restoring the background bool DrawPolygonAAOnBG(const int id, // Frame ID int &array_x[], // Array with the X coordinates of polygon points int &array_y[], // Array with the Y coordinates of polygon points const color clr, // Color const uchar opacity=255, // Opacity const bool create_new=true, // New object creation flag const bool redraw=false, // Chart redraw flag const uint style=UINT_MAX) // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value { return(this.m_animations!=NULL ? this.m_animations.DrawPolygonAAOnBG(id,array_x,array_y,clr,opacity,create_new,redraw,style) : false); } //--- Draw a polygon using Wu algorithm while saving and restoring the background bool DrawPolygonWuOnBG(const int id, // Frame ID int &array_x[], // Array with the X coordinates of polygon points int &array_y[], // Array with the Y coordinates of polygon points const color clr, // Color const uchar opacity=255, // Opacity const bool create_new=true, // New object creation flag const bool redraw=false, // Chart redraw flag const uint style=UINT_MAX) // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value { return(this.m_animations!=NULL ? this.m_animations.DrawPolygonWuOnBG(id,array_x,array_y,clr,opacity,create_new,redraw,style) : false); } //--- Draw a polygon with a specified width consecutively using two smoothing algorithms while saving and restoring the background. //--- First, individual segments are smoothed based on Bezier curves. //--- Then, the raster smoothing algorithm is applied to the polygon built from these segments to improve the rendering quality. bool DrawPolygonSmoothOnBG(const int id, // Frame ID int &array_x[], // Array with the X coordinates of polyline points int &array_y[], // Array with the Y coordinates of polyline points const int size, // Line width const color clr, // Color const uchar opacity=255, // Opacity const double tension=0.5, // Smoothing parameter value const double step=10, // Approximation step const bool create_new=true, // New object creation flag const bool redraw=false, // Chart redraw flag const ENUM_LINE_STYLE style=STYLE_SOLID, // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value const ENUM_LINE_END end_style=LINE_END_ROUND)// Line style is one of the ENUM_LINE_END enumeration's values { return(this.m_animations!=NULL ? this.m_animations.DrawPolygonSmoothOnBG(id,array_x,array_y,size,clr,opacity,tension,step,create_new,redraw,style,end_style) : false); } //--- Draw a polygon of a specified width using a smoothing algorithm with the preliminary filtration while saving and restoring the background bool DrawPolygonThickOnBG(const int id, // Frame ID const int &array_x[], // array with the X coordinates of polygon points const int &array_y[], // array with the Y coordinates of polygon points const int size, // line width const color clr, // Color const uchar opacity=255, // Opacity const bool create_new=true, // New object creation flag const bool redraw=false, // Chart redraw flag const uint style=STYLE_SOLID, // line style ENUM_LINE_END end_style=LINE_END_ROUND) // line ends style { return(this.m_animations!=NULL ? this.m_animations.DrawPolygonThickOnBG(id,array_x,array_y,size,clr,opacity,create_new,redraw,style,end_style) : false); } //--- Draw a triangle using AntiAliasing algorithm while saving and restoring the background bool DrawTriangleAAOnBG(const int id, // Frame ID const int x1, // X coordinate of the triangle first vertex const int y1, // Y coordinate of the triangle first vertex const int x2, // X coordinate of the triangle second vertex const int y2, // Y coordinate of the triangle second vertex const int x3, // X coordinate of the triangle third vertex const int y3, // Y coordinate of the triangle third vertex const color clr, // Color const uchar opacity=255, // Opacity const bool create_new=true, // New object creation flag const bool redraw=false, // Chart redraw flag const uint style=UINT_MAX) // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value { return(this.m_animations!=NULL ? this.m_animations.DrawTriangleAAOnBG(id,x1,y1,x2,y2,x3,y3,clr,opacity,create_new,redraw,style) : false); } //--- Draw a triangle using Wu algorithm while saving and restoring the background bool DrawTriangleWuOnBG(const int id, // Frame ID const int x1, // X coordinate of the triangle first vertex const int y1, // Y coordinate of the triangle first vertex const int x2, // X coordinate of the triangle second vertex const int y2, // Y coordinate of the triangle second vertex const int x3, // X coordinate of the triangle third vertex const int y3, // Y coordinate of the triangle third vertex const color clr, // Color const uchar opacity=255, // Opacity const bool create_new=true, // New object creation flag const bool redraw=false, // Chart redraw flag const uint style=UINT_MAX) // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value { return(this.m_animations!=NULL ? this.m_animations.DrawTriangleWuOnBG(id,x1,y1,x2,y2,x3,y3,clr,opacity,create_new,redraw,style) : false); } //--- Draw a circle using AntiAliasing algorithm while saving and restoring the background bool DrawCircleAAOnBG(const int id, // Frame ID const int x, // X coordinate of the circle center const int y, // Y coordinate of the circle center const double r, // Circle radius const color clr, // Color const uchar opacity=255, // Opacity const bool create_new=true, // New object creation flag const bool redraw=false, // Chart redraw flag const uint style=UINT_MAX) // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value { return(this.m_animations!=NULL ? this.m_animations.DrawCircleAAOnBG(id,x,y,r,clr,opacity,create_new,redraw,style) : false); } //--- Draw a circle using Wu algorithm while saving and restoring the background bool DrawCircleWuOnBG(const int id, // Frame ID const int x, // X coordinate of the circle center const int y, // Y coordinate of the circle center const double r, // Circle radius const color clr, // Color const uchar opacity=255, // Opacity const bool create_new=true, // New object creation flag const bool redraw=false, // Chart redraw flag const uint style=UINT_MAX) // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value { return(this.m_animations!=NULL ? this.m_animations.DrawCircleWuOnBG(id,x,y,r,clr,opacity,create_new,redraw,style) : false); } //--- Draw an ellipse by two points using AntiAliasing algorithm while saving and restoring the background bool DrawEllipseAAOnBG(const int id, // Frame ID const double x1, // X coordinate of the first point defining the ellipse const double y1, // Y coordinate of the first point defining the ellipse const double x2, // X coordinate of the second point defining the ellipse const double y2, // Y coordinate of the second point defining the ellipse const color clr, // Color const uchar opacity=255, // Opacity const bool create_new=true, // New object creation flag const bool redraw=false, // Chart redraw flag const uint style=UINT_MAX) // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value { return(this.m_animations!=NULL ? this.m_animations.DrawEllipseAAOnBG(id,x1,y1,x2,y2,clr,opacity,create_new,redraw,style) : false); } //--- Draw an ellipse by two points using Wu algorithm while saving and restoring the background bool DrawEllipseWuOnBG(const int id, // Frame ID const int x1, // X coordinate of the first point defining the ellipse const int y1, // Y coordinate of the first point defining the ellipse const int x2, // X coordinate of the second point defining the ellipse const int y2, // Y coordinate of the second point defining the ellipse const color clr, // Color const uchar opacity=255, // Opacity const bool create_new=true, // New object creation flag const bool redraw=false, // Chart redraw flag const uint style=UINT_MAX) // Line style is one of the ENUM_LINE_STYLE enumeration's values or a custom value { return(this.m_animations!=NULL ? this.m_animations.DrawEllipseWuOnBG(id,x1,y1,x2,y2,clr,opacity,create_new,redraw,style) : false); } //+------------------------------------------------------------------+
すべてのメソッドは、上記で作成したCAnimationsアニメーションオブジェクトから適切なメソッドの結果を返します。
クラスデストラクタで、アニメーションオブジェクトを削除します。
//+------------------------------------------------------------------+ //| Destructor | //+------------------------------------------------------------------+ CForm::~CForm() { if(this.m_shadow_obj!=NULL) delete this.m_shadow_obj; if(this.m_animations!=NULL) delete this.m_animations; } //+------------------------------------------------------------------+
初期化メソッドで、新しいアニメーションオブジェクトを作成します。
//+------------------------------------------------------------------+ //| Initialize the variables | //+------------------------------------------------------------------+ void CForm::Initialize(void) { this.m_list_elements.Clear(); this.m_list_elements.Sort(); this.m_shadow_obj=NULL; this.m_shadow=false; this.m_frame_width_right=2; this.m_frame_width_left=2; this.m_frame_width_top=2; this.m_frame_width_bottom=2; this.m_animations=new CAnimations(CGCnvElement::GetObject()); } //+------------------------------------------------------------------+
これで、新しいフォームオブジェクトを作成するときに、新しいアニメーションオブジェクトが自動的に作成されます。新しいアニメーションフレームをアニメーションオブジェクトに動的に追加したり、事前定義されたフォームを作成したりできます。プログラムの実行が完了すると、メモリリークを回避するために、アニメーションオブジェクトが破棄されます。
作成したクラスをテストする準備ができました。
4つのフォームが描かれたテストEAがあります。4番目(下)のフォームをクリックすると、H-グラデーションラベルが移動します(H-水平塗りつぶしタイプの場合)。このラベルは、テキストアニメーションフレームオブジェクトとして作成および移動されます。3番目のフォーム(垂直塗りつぶし)は、さまざまな描画形状を表示するために使用されます。形状を描画する前に、まずフォームテキストをテキストアニメーションフレームとして表示します。その上に形状が描かれています。描画された形状の種類を切り替えるには、キーを押します。テキストには、選択した描画された形状が表示されます。形状をマウスでクリックするたびに、描画された形状の点の座標が変更されます。
検証
テストを実行するには、前の記事のEAを使用して、\MQL5\Experts\TestDoEasy\Part79\にTestDoEasyPart79.mq5として保存します。
グローバル変数の領域で、描画された形状の初期座標を指定するためのマクロ置換を入力し、描画された形状のさまざまな点の座標およびそれらの変更値を格納するための変数を宣言します(合計5つの点が使用されます) 。
//+------------------------------------------------------------------+ //| TestDoEasyPart79.mq5 | //| Copyright 2021, MetaQuotes Ltd. | //| https://mql5.com/en/users/artmedia70 | //+------------------------------------------------------------------+ #property copyright "Copyright 2021, MetaQuotes Ltd." #property link "https://mql5.com/en/users/artmedia70" #property version "1.00" //--- includes #include <Arrays\ArrayObj.mqh> #include <DoEasy\Services\Select.mqh> #include <DoEasy\Objects\Graph\Form.mqh> //--- defines #define FORMS_TOTAL (4) // Number of created forms #define START_X (4) // Initial X coordinate of the shape #define START_Y (4) // Initial Y coordinate of the shape //--- input parameters sinput bool InpMovable = true; // Movable forms flag sinput ENUM_INPUT_YES_NO InpUseColorBG = INPUT_YES; // Use chart background color to calculate shadow color sinput color InpColorForm3 = clrCadetBlue; // Third form shadow color (if not background color) //--- global variables CArrayObj list_forms; color array_clr[]; int nx1=0, ny1=0, nx2=0, ny2=0, nx3=0, ny3=0, nx4=0, ny4=0, nx5=0, ny5=0; int coordX1=START_X+nx1; int coordY1=START_Y+ny1; int coordX2=START_X+nx2*2; int coordY2=START_Y+ny2*2; int coordX3=START_X+nx3*3; int coordY3=START_Y+ny3*3; int coordX4=START_X+nx4*4; int coordY4=START_Y+ny4*4; int coordX5=START_X+nx5*5; int coordY5=START_Y+ny5*5; double RD=1; //+------------------------------------------------------------------+
OnInit()ハンドラの最後の2つのフォームを作成するブロックでは、テキストはテキストアニメーションオブジェクトを使用して作成されます。
//--- If this is the third form if(i==2) { //--- Set the opacity of 200 form.SetOpacity(200); //--- The form background color is set as the first color from the color array form.SetColorBackground(array_clr[0]); //--- Form outlining frame color form.SetColorFrame(clrDarkBlue); //--- Draw the shadow drawing flag form.SetShadow(true); //--- Calculate the shadow color as the chart background color converted to the monochrome one color clrS=form.ChangeColorSaturation(form.ColorBackground(),-100); //--- If the settings specify the usage of the chart background color, replace the monochrome color with 20 units //--- Otherwise, use the color specified in the settings for drawing the shadow color clr=(InpUseColorBG ? form.ChangeColorLightness(clrS,-20) : InpColorForm3); //--- Draw the form shadow with the right-downwards offset from the form by three pixels along all axes //--- Set the shadow opacity to 200, while the blur radius is equal to 4 form.DrawShadow(3,3,clr,200,4); //--- Fill the form background with a vertical gradient form.Erase(array_clr,form.Opacity()); //--- Draw an outlining rectangle at the edges of the form form.DrawRectangle(0,0,form.Width()-1,form.Height()-1,form.ColorFrame(),form.Opacity()); //--- Display the text describing the gradient type and update the form //--- Text parameters: the text coordinates and the anchor point in the form center //--- Create a new text animation frame with the ID of 0 and display the text on the form form.TextOnBG(0,TextByLanguage("V-Градиент","V-Gradient"),form.Width()/2,form.Height()/2,TEXT_ANCHOR_CENTER,C'211,233,149',255,true,false); } //--- If this is the fourth (bottom) form if(i==3) { //--- Set the opacity of 200 form.SetOpacity(200); //--- The form background color is set as the first color from the color array form.SetColorBackground(array_clr[0]); //--- Form outlining frame color form.SetColorFrame(clrDarkBlue); //--- Draw the shadow drawing flag form.SetShadow(true); //--- Calculate the shadow color as the chart background color converted to the monochrome one color clrS=form.ChangeColorSaturation(form.ColorBackground(),-100); //--- If the settings specify the usage of the chart background color, replace the monochrome color with 20 units //--- Otherwise, use the color specified in the settings for drawing the shadow color clr=(InpUseColorBG ? form.ChangeColorLightness(clrS,-20) : InpColorForm3); //--- Draw the form shadow with the right-downwards offset from the form by three pixels along all axes //--- Set the shadow opacity to 200, while the blur radius is equal to 4 form.DrawShadow(3,3,clr,200,4); //--- Fill the form background with a horizontal gradient form.Erase(array_clr,form.Opacity(),false); //--- Draw an outlining rectangle at the edges of the form form.DrawRectangle(0,0,form.Width()-1,form.Height()-1,form.ColorFrame(),form.Opacity()); //--- Display the text describing the gradient type and update the form //--- Text parameters: the text coordinates and the anchor point in the form center //--- Create a new text animation frame with the ID of 0 and display the text on the form form.TextOnBG(0,TextByLanguage("H-Градиент","H-Gradient"),form.Width()/2,form.Height()/2,TEXT_ANCHOR_CENTER,C'211,233,149',255,true,true); } //--- Add objects to the list
これらのテキストオブジェクトは事前にここで作成しました。描画された形状は、フォーム領域をクリックすると動的に作成されます。
キーストロークを処理するには、次のコードブロックをOnChartEvent()ハンドラに追加します。
//--- Drawing mode depending on the pressed key static ENUM_FIGURE_TYPE figure_type_prev=WRONG_VALUE; static ENUM_FIGURE_TYPE figure_type=figure_type_prev; string figure=FigureTypeDescription(figure_type); //--- If a key is pressed if(id==CHARTEVENT_KEYDOWN) { //--- Get a drawn shape type depending on a pressed key figure_type=FigureType(lparam); //--- If the shape type has changed if(figure_type!=figure_type_prev) { //--- Get the text of the drawn shape type description figure=FigureTypeDescription(figure_type); //--- In the loop by all forms, for(int i=0;i<list_forms.Total();i++) { //--- get the pointer to the next form object CForm *form=list_forms.At(i); if(form==NULL) continue; //--- If the form ID is 2, if(form.ID()==2) { //--- Reset all coordinate shifts to zero and display the text describing the drawn shape type nx1=ny1=nx2=ny2=nx3=ny3=nx4=ny4=nx5=ny5=0; form.TextOnBG(0,figure,form.TextLastX(),form.TextLastY(),form.TextAnchor(),C'211,233,149',255,false,true); } } //--- Write the new shape type figure_type_prev=figure_type; } } //--- If clicking an object
フォームごとにクリック処理ブロックのコードを少し変更します。これで、テキストは、クリックされているフォームのテキストアニメーションオブジェクトを使用して表示されます。
//--- If clicking an object if(id==CHARTEVENT_OBJECT_CLICK) { //--- If the clicked object belongs to the EA if(StringFind(sparam,MQLInfoString(MQL_PROGRAM_NAME))==0) { //--- Get the object ID from it int form_id=(int)StringToInteger(StringSubstr(sparam,StringLen(sparam)-1))-1; //--- Find this form object in the loop by all forms created in the EA for(int i=0;i<list_forms.Total();i++) { CForm *form=list_forms.At(i); if(form==NULL) continue; //--- If the clicked object has the ID of 2 and the form has the same ID if(form_id==2 && form.ID()==2) { //--- Handle clicking the form - draw the corresponding shape FigureProcessing(form,figure_type); } //--- If the clicked object has the ID of 3 and the form has the same ID if(form_id==3 && form.ID()==3) { ////--- Get the anchor point of the last drawn text ENUM_TEXT_ANCHOR anchor=form.TextAnchor(); ////--- Get the coordinates of the last drawn text int text_x=form.TextLastX(); int text_y=form.TextLastY(); //--- Set the text anchor initial point (0 = LEFT_TOP) out of nine possible ones static int n=0; //--- Depending on the n variable, set the new text anchor point switch(n) { case 0 : anchor=TEXT_ANCHOR_LEFT_TOP; text_x=1; text_y=1; break; case 1 : anchor=TEXT_ANCHOR_CENTER_TOP; text_x=form.Width()/2; text_y=1; break; case 2 : anchor=TEXT_ANCHOR_RIGHT_TOP; text_x=form.Width()-2; text_y=1; break; case 3 : anchor=TEXT_ANCHOR_LEFT_CENTER; text_x=1; text_y=form.Height()/2; break; case 4 : anchor=TEXT_ANCHOR_CENTER; text_x=form.Width()/2; text_y=form.Height()/2; break; case 5 : anchor=TEXT_ANCHOR_RIGHT_CENTER; text_x=form.Width()-2; text_y=form.Height()/2; break; case 6 : anchor=TEXT_ANCHOR_LEFT_BOTTOM; text_x=1; text_y=form.Height()-2; break; case 7 : anchor=TEXT_ANCHOR_CENTER_BOTTOM;text_x=form.Width()/2; text_y=form.Height()-2; break; case 8 : anchor=TEXT_ANCHOR_RIGHT_BOTTOM; text_x=form.Width()-2; text_y=form.Height()-2; break; default: anchor=TEXT_ANCHOR_CENTER; text_x=form.Width()/2; text_y=form.Height()/2; break; } form.TextOnBG(0,TextByLanguage("H-Градиент","H-Gradient"),text_x,text_y,anchor,C'211,233,149',255,true,true); //--- Increase the object click counter (and also the pointer to the text anchor point), //--- and if the value exceeds 8, reset the value to zero (from 0 to 8 = nine anchor points) n++; if(n>8) n=0; } } } }
3番目のフォーム(ID 2)のクリックは、FigureProcessing()関数で処理されます。4番目のフォーム(ID 3)をクリックすると、nに応じてテキストのアンカー角度を定義し、テキストを表示できます。ただし、テキストはテキストアニメーションフレームオブジェクトクラスを使用して表示されるようになりました。
以下は、押されたキーに応じて形状タイプを返す補助関数です。
//+------------------------------------------------------------------+ //| Return the shape depending on the pressed key | //+------------------------------------------------------------------+ ENUM_FIGURE_TYPE FigureType(const long key_code) { switch((int)key_code) { //--- "1" = Dot case 49 : return FIGURE_TYPE_PIXEL; //--- "2" = Dot with AntiAlliasing case 50 : return FIGURE_TYPE_PIXEL_AA; //--- "3" = Vertical line case 51 : return FIGURE_TYPE_LINE_VERTICAL; //--- "4" = Vertical segment of a freehand line having a specified width using a smoothing algorithm case 52 : return FIGURE_TYPE_LINE_VERTICAL_THICK; //--- "5" = Horizontal line case 53 : return FIGURE_TYPE_LINE_HORIZONTAL; //--- "6" = Horizontal segment of a freehand line having a specified width using a smoothing algorithm case 54 : return FIGURE_TYPE_LINE_HORIZONTAL_THICK; //--- "7" = Freehand line case 55 : return FIGURE_TYPE_LINE; //--- "8" = Line with AntiAlliasing case 56 : return FIGURE_TYPE_LINE_AA; //--- "9" = Line with WU case 57 : return FIGURE_TYPE_LINE_WU; //--- "0" = Segment of a freehand line having a specified width using a smoothing algorithm case 48 : return FIGURE_TYPE_LINE_THICK; //--- "q" = Polyline case 81 : return FIGURE_TYPE_POLYLINE; //--- "w" = Polyline with AntiAlliasing case 87 : return FIGURE_TYPE_POLYLINE_AA; //--- "e" = Polyline with WU case 69 : return FIGURE_TYPE_POLYLINE_WU; //--- "r" = Polyline with a specified width using two smoothing algorithms case 82 : return FIGURE_TYPE_POLYLINE_SMOOTH; //--- "t" = Polyline with a specified width using a smoothing algorithm case 84 : return FIGURE_TYPE_POLYLINE_THICK; //--- "y" = Polygon case 89 : return FIGURE_TYPE_POLYGON; //--- "u" = Filled polygon case 85 : return FIGURE_TYPE_POLYGON_FILL; //--- "i" = Polygon with AntiAlliasing case 73 : return FIGURE_TYPE_POLYGON_AA; //--- "o" = Polygon with WU case 79 : return FIGURE_TYPE_POLYGON_WU; //--- "p" = Polygon with a specified width using two smoothing algorithms case 80 : return FIGURE_TYPE_POLYGON_SMOOTH; //--- "a" = Polygon with a specified width using a smoothing algorithm case 65 : return FIGURE_TYPE_POLYGON_THICK; //--- "s" = Rectangle case 83 : return FIGURE_TYPE_RECTANGLE; //--- "d" = Filled rectangle case 68 : return FIGURE_TYPE_RECTANGLE_FILL; //--- "f" = Circle case 70 : return FIGURE_TYPE_CIRCLE; //--- "g" = Filled circle case 71 : return FIGURE_TYPE_CIRCLE_FILL; //--- "h" = Circle with AntiAlliasing case 72 : return FIGURE_TYPE_CIRCLE_AA; //--- "j" = Circle with WU case 74 : return FIGURE_TYPE_CIRCLE_WU; //--- "k" = Triangle case 75 : return FIGURE_TYPE_TRIANGLE; //--- "l" = Filled triangle case 76 : return FIGURE_TYPE_TRIANGLE_FILL; //--- "z" = Triangle with AntiAlliasing case 90 : return FIGURE_TYPE_TRIANGLE_AA; //--- "x" = Triangle with WU case 88 : return FIGURE_TYPE_TRIANGLE_WU; //--- "c" = Ellipse case 67 : return FIGURE_TYPE_ELLIPSE; //--- "v" = Filled ellipse case 86 : return FIGURE_TYPE_ELLIPSE_FILL; //--- "b" = Ellipse with AntiAlliasing case 66 : return FIGURE_TYPE_ELLIPSE_AA; //--- "n" = Ellipse with WU case 78 : return FIGURE_TYPE_ELLIPSE_WU; //--- "m" = Ellipse arc case 77 : return FIGURE_TYPE_ARC; //--- "," = Ellipse sector case 188 : return FIGURE_TYPE_PIE; //--- Default = Dot default : return FIGURE_TYPE_PIXEL; } } //+------------------------------------------------------------------+
フォームオブジェクトのクリックを処理する関数は非常にかさばりますが、描画されたフォームが対応する押された各ボタンを処理するスイッチオペレーターを備えているため、シンプルです。処理は簡単です。初期座標を設定し、許容値の範囲外であることを確認し、これらのパラメータを使用して図を描き、パラメータ値のシフトを増やします。次にフォームをクリックすると、前の形状が復元された背景で上書きされ、その点の新しい座標を使用して新しい形状が描画されます。
//+------------------------------------------------------------------+ //| Handle the selected shape | //+------------------------------------------------------------------+ void FigureProcessing(CForm *form,const ENUM_FIGURE_TYPE figure_type) { int array_x[5]={0,0,0,0,0}; int array_y[5]={0,0,0,0,0}; switch(figure_type) { //--- "1" = Dot case FIGURE_TYPE_PIXEL : coordX1=START_X+nx1; coordY1=START_Y+ny1; if(coordX1>form.Width()-START_X-1) { nx1=0; coordX1=START_X; } if(coordY1>form.Height()-START_Y-1) { ny1=0; coordY1=START_Y; } form.SetPixelOnBG(0,coordX1,coordY1,clrWheat); nx1++; ny1++; break; //--- "2" = Dot with AntiAlliasing case FIGURE_TYPE_PIXEL_AA : coordX1=START_X+nx1; coordY1=START_Y+ny1; if(coordX1>form.Width()-START_X-1) { nx1=0; coordX1=START_X; } if(coordY1>form.Height()-START_Y-1) { ny1=0; coordY1=START_Y; } form.SetPixelAAOnBG(0,coordX1,coordY1,clrWheat); nx1++; ny1++; break; //--- "3" = Vertical line case FIGURE_TYPE_LINE_VERTICAL : coordX1=START_X+nx1; coordY1=START_Y; coordY2=form.Height()-START_Y-1; if(coordX1>form.Width()-START_X-1) { nx1=0; coordX1=START_X; } form.DrawLineVerticalOnBG(0,coordX1,coordY1,coordY2,clrWheat); nx1++; break; //--- "4" = Vertical segment of a freehand line having a specified width using a smoothing algorithm case FIGURE_TYPE_LINE_VERTICAL_THICK : coordX1=START_X+nx1; coordY1=START_Y; coordY2=form.Height()-START_Y-1; if(coordX1>form.Width()-START_X-1) { nx1=0; coordX1=START_X; } form.DrawLineThickVerticalOnBG(0,coordX1,coordY1,coordY2,5,clrWheat,255,true,false,STYLE_SOLID,LINE_END_SQUARE); nx1++; break; //--- "5" = Horizontal line case FIGURE_TYPE_LINE_HORIZONTAL : coordX1=START_X; coordX2=form.Width()-START_X-1; coordY1=START_Y+ny1; if(coordY1>form.Height()-START_Y-1) { ny1=0; coordY1=START_Y; } form.DrawLineHorizontalOnBG(0,coordX1,coordX2,coordY1,clrWheat); ny1++; break; //--- "6" = Horizontal segment of a freehand line having a specified width using a smoothing algorithm case FIGURE_TYPE_LINE_HORIZONTAL_THICK : coordX1=START_X; coordX2=form.Width()-START_X-1; coordY1=START_Y+ny1; if(coordY1>form.Height()-START_Y-1) { ny1=0; coordY1=START_Y; } form.DrawLineThickHorizontalOnBG(0,coordX1,coordX2,coordY1,5,clrWheat,255,true,false,STYLE_SOLID,LINE_END_ROUND); ny1++; break; //--- "7" = Freehand line case FIGURE_TYPE_LINE : coordX1=START_X+nx1; coordY1=START_Y+ny1; coordX2=START_X+nx2*2; coordY2=START_Y+ny2*2; if(coordX1>form.Width()-START_X-1) { nx1=0; coordX1=START_X; } if(coordY1>form.Height()-START_Y-1) { ny1=0; coordY1=START_Y; } if(coordX2>form.Width()-START_X-1) { nx2=0; coordX2=START_X; } if(coordY2>form.Height()-START_Y-1) { ny2=0; coordY2=START_Y; } form.DrawLineOnBG(0,coordX1,coordY1,coordX2,coordY2,clrWheat); nx1++; ny1++; nx2++; ny2++; break; //--- "8" = Line with AntiAlliasing case FIGURE_TYPE_LINE_AA : coordX1=START_X+nx1; coordY1=START_Y+ny1; coordX2=START_X+nx2*2; coordY2=START_Y+ny2*2; if(coordX1>form.Width()-START_X-1) { nx1=0; coordX1=START_X; } if(coordY1>form.Height()-START_Y-1) { ny1=0; coordY1=START_Y; } if(coordX2>form.Width()-START_X-1) { nx2=0; coordX2=START_X; } if(coordY2>form.Height()-START_Y-1) { ny2=0; coordY2=START_Y; } form.DrawLineAAOnBG(0,coordX1,coordY1,coordX2,coordY2,clrWheat); nx1++; ny1++; nx2++; ny2++; break; //--- "9" = Line with WU case FIGURE_TYPE_LINE_WU : coordX1=START_X+nx1; coordY1=START_Y+ny1; coordX2=START_X+nx2*2; coordY2=START_Y+ny2*2; if(coordX1>form.Width()-START_X-1) { nx1=0; coordX1=START_X; } if(coordY1>form.Height()-START_Y-1) { ny1=0; coordY1=START_Y; } if(coordX2>form.Width()-START_X-1) { nx2=0; coordX2=START_X; } if(coordY2>form.Height()-START_Y-1) { ny2=0; coordY2=START_Y; } form.DrawLineWuOnBG(0,coordX1,coordY1,coordX2,coordY2,clrWheat); nx1++; ny1++; nx2++; ny2++; break; //--- "0" = Segment of a freehand line having a specified width using a smoothing algorithm case FIGURE_TYPE_LINE_THICK : coordX1=START_X+nx1; coordY1=START_Y+ny1; coordX2=START_X+nx2*2; coordY2=START_Y+ny2*2; if(coordX1>form.Width()-START_X-1) { nx1=0; coordX1=START_X; } if(coordY1>form.Height()-START_Y-1) { ny1=0; coordY1=START_Y; } if(coordX2>form.Width()-START_X-1) { nx2=0; coordX2=START_X; } if(coordY2>form.Height()-START_Y-1) { ny2=0; coordY2=START_Y; } form.DrawLineThickOnBG(0,coordX1,coordY1,coordX2,coordY2,3,clrWheat,255,true,false,STYLE_SOLID,LINE_END_SQUARE); nx1++; ny1++; nx2++; ny2++; break; //--- "q" = Polyline case FIGURE_TYPE_POLYLINE : coordX1=START_X+nx1; coordY1=START_Y+ny1; coordX2=coordX1+nx2*8; coordY2=coordY1; coordX3=coordX2; coordY3=coordY2+ny3*2; coordX4=coordX1; coordY4=coordY3; coordX5=coordX1; coordY5=coordY1; //--- Fill in the arrays with coordinate values array_x[0]=coordX1; array_x[1]=coordX2; array_x[2]=coordX3; array_x[3]=coordX4; array_x[4]=coordX5; array_y[0]=coordY1; array_y[1]=coordY2; array_y[2]=coordY3; array_y[3]=coordY4; array_y[4]=coordY5; //--- check x1 and y1 coordinates for being outside the form if(array_x[0]>form.Width()-START_X-1) { nx1=0; array_x[0]=START_X; } if(array_y[0]>form.Height()-START_Y-1) { ny1=0; array_y[0]=START_Y; } //--- check x2 and y2 coordinates for being outside the form if(array_x[1]>form.Width()-START_X-1) { nx2=0; array_x[1]=START_X; } if(array_y[1]>form.Height()-START_Y-1) { ny2=0; array_y[1]=array_y[0]; } //--- check x3 and y3 coordinates for being outside the form if(array_x[2]>form.Width()-START_X-1) { nx3=0; array_x[2]=array_x[1]; } if(array_y[2]>form.Height()-START_Y-1) { ny3=0; array_y[2]=array_y[1]; } //--- check x4 and y4 coordinates for being outside the form if(array_x[3]>form.Width()-START_X-1) { nx4=0; array_x[3]=START_X; } if(array_y[3]>form.Height()-START_Y-1) { ny4=0; array_y[3]=array_y[2]; } //--- check x5 and y5 coordinates for being outside the form if(array_x[4]>form.Height()-START_X-1) { nx5=0; array_x[4]=array_x[0]; } if(array_y[4]>form.Height()-START_Y-1) { ny5=0; array_y[4]=array_y[0]; } //--- Draw a shape form.DrawPolylineOnBG(0,array_x,array_y,clrWheat); nx1++; ny1++; nx2++; ny2++; nx3++; ny3++; nx4++; ny4++; nx5++; ny5++; break; //--- "w" = Polyline with AntiAlliasing case FIGURE_TYPE_POLYLINE_AA : coordX1=START_X+nx1; coordY1=START_Y+ny1; coordX2=coordX1+nx2*8; coordY2=coordY1; coordX3=coordX2; coordY3=coordY2+ny3*2; coordX4=coordX1; coordY4=coordY3; coordX5=coordX1; coordY5=coordY1; //--- Fill in the arrays with coordinate values array_x[0]=coordX1; array_x[1]=coordX2; array_x[2]=coordX3; array_x[3]=coordX4; array_x[4]=coordX5; array_y[0]=coordY1; array_y[1]=coordY2; array_y[2]=coordY3; array_y[3]=coordY4; array_y[4]=coordY5; //--- check x1 and y1 coordinates for being outside the form if(array_x[0]>form.Width()-START_X-1) { nx1=0; array_x[0]=START_X; } if(array_y[0]>form.Height()-START_Y-1) { ny1=0; array_y[0]=START_Y; } //--- check x2 and y2 coordinates for being outside the form if(array_x[1]>form.Width()-START_X-1) { nx2=0; array_x[1]=START_X; } if(array_y[1]>form.Height()-START_Y-1) { ny2=0; array_y[1]=array_y[0]; } //--- check x3 and y3 coordinates for being outside the form if(array_x[2]>form.Width()-START_X-1) { nx3=0; array_x[2]=array_x[1]; } if(array_y[2]>form.Height()-START_Y-1) { ny3=0; array_y[2]=array_y[1]; } //--- check x4 and y4 coordinates for being outside the form if(array_x[3]>form.Width()-START_X-1) { nx4=0; array_x[3]=START_X; } if(array_y[3]>form.Height()-START_Y-1) { ny4=0; array_y[3]=array_y[2]; } //--- check x5 and y5 coordinates for being outside the form if(array_x[4]>form.Height()-START_X-1) { nx5=0; array_x[4]=array_x[0]; } if(array_y[4]>form.Height()-START_Y-1) { ny5=0; array_y[4]=array_y[0]; } //--- Draw a shape form.DrawPolylineAAOnBG(0,array_x,array_y,clrWheat); nx1++; ny1++; nx2++; ny2++; nx3++; ny3++; nx4++; ny4++; nx5++; ny5++; break; //--- "e" = Polyline with WU case FIGURE_TYPE_POLYLINE_WU : coordX1=START_X+nx1; coordY1=START_Y+ny1; coordX2=coordX1+nx2*8; coordY2=coordY1; coordX3=coordX2; coordY3=coordY2+ny3*2; coordX4=coordX1; coordY4=coordY3; coordX5=coordX1; coordY5=coordY1; //--- Fill in the arrays with coordinate values array_x[0]=coordX1; array_x[1]=coordX2; array_x[2]=coordX3; array_x[3]=coordX4; array_x[4]=coordX5; array_y[0]=coordY1; array_y[1]=coordY2; array_y[2]=coordY3; array_y[3]=coordY4; array_y[4]=coordY5; //--- check x1 and y1 coordinates for being outside the form if(array_x[0]>form.Width()-START_X-1) { nx1=0; array_x[0]=START_X; } if(array_y[0]>form.Height()-START_Y-1) { ny1=0; array_y[0]=START_Y; } //--- check x2 and y2 coordinates for being outside the form if(array_x[1]>form.Width()-START_X-1) { nx2=0; array_x[1]=START_X; } if(array_y[1]>form.Height()-START_Y-1) { ny2=0; array_y[1]=array_y[0]; } //--- check x3 and y3 coordinates for being outside the form if(array_x[2]>form.Width()-START_X-1) { nx3=0; array_x[2]=array_x[1]; } if(array_y[2]>form.Height()-START_Y-1) { ny3=0; array_y[2]=array_y[1]; } //--- check x4 and y4 coordinates for being outside the form if(array_x[3]>form.Width()-START_X-1) { nx4=0; array_x[3]=START_X; } if(array_y[3]>form.Height()-START_Y-1) { ny4=0; array_y[3]=array_y[2]; } //--- check x5 and y5 coordinates for being outside the form if(array_x[4]>form.Height()-START_X-1) { nx5=0; array_x[4]=array_x[0]; } if(array_y[4]>form.Height()-START_Y-1) { ny5=0; array_y[4]=array_y[0]; } //--- Draw a shape form.DrawPolylineWuOnBG(0,array_x,array_y,clrWheat); nx1++; ny1++; nx2++; ny2++; nx3++; ny3++; nx4++; ny4++; nx5++; ny5++; break; //--- "r" = Polyline with a specified width using two smoothing algorithms case FIGURE_TYPE_POLYLINE_SMOOTH : coordX1=START_X+nx1; coordY1=START_Y+ny1; coordX2=coordX1+nx2*8; coordY2=coordY1; coordX3=coordX2; coordY3=coordY2+ny3*2; coordX4=coordX1; coordY4=coordY3; coordX5=coordX1; coordY5=coordY1; //--- Fill in the arrays with coordinate values array_x[0]=coordX1; array_x[1]=coordX2; array_x[2]=coordX3; array_x[3]=coordX4; array_x[4]=coordX5; array_y[0]=coordY1; array_y[1]=coordY2; array_y[2]=coordY3; array_y[3]=coordY4; array_y[4]=coordY5; //--- check x1 and y1 coordinates for being outside the form if(array_x[0]>form.Width()-START_X-1) { nx1=0; array_x[0]=START_X; } if(array_y[0]>form.Height()-START_Y-1) { ny1=0; array_y[0]=START_Y; } //--- check x2 and y2 coordinates for being outside the form if(array_x[1]>form.Width()-START_X-1) { nx2=0; array_x[1]=START_X; } if(array_y[1]>form.Height()-START_Y-1) { ny2=0; array_y[1]=array_y[0]; } //--- check x3 and y3 coordinates for being outside the form if(array_x[2]>form.Width()-START_X-1) { nx3=0; array_x[2]=array_x[1]; } if(array_y[2]>form.Height()-START_Y-1) { ny3=0; array_y[2]=array_y[1]; } //--- check x4 and y4 coordinates for being outside the form if(array_x[3]>form.Width()-START_X-1) { nx4=0; array_x[3]=START_X; } if(array_y[3]>form.Height()-START_Y-1) { ny4=0; array_y[3]=array_y[2]; } //--- check x5 and y5 coordinates for being outside the form if(array_x[4]>form.Height()-START_X-1) { nx5=0; array_x[4]=array_x[0]; } if(array_y[4]>form.Height()-START_Y-1) { ny5=0; array_y[4]=array_y[0]; } //--- Draw a shape form.DrawPolylineSmoothOnBG(0,array_x,array_y,1,clrWheat,255,0.5,30.0,true,false,STYLE_SOLID,LINE_END_BUTT); nx1++; ny1++; nx2++; ny2++; nx3++; ny3++; nx4++; ny4++; nx5++; ny5++; break; //--- "t" = Polyline with a specified width using a smoothing algorithm case FIGURE_TYPE_POLYLINE_THICK : coordX1=START_X+nx1; coordY1=START_Y+ny1; coordX2=coordX1+nx2*8; coordY2=coordY1; coordX3=coordX2; coordY3=coordY2+ny3*2; coordX4=coordX1; coordY4=coordY3; coordX5=coordX1; coordY5=coordY1; //--- Fill in the arrays with coordinate values array_x[0]=coordX1; array_x[1]=coordX2; array_x[2]=coordX3; array_x[3]=coordX4; array_x[4]=coordX5; array_y[0]=coordY1; array_y[1]=coordY2; array_y[2]=coordY3; array_y[3]=coordY4; array_y[4]=coordY5; //--- check x1 and y1 coordinates for being outside the form if(array_x[0]>form.Width()-START_X-1) { nx1=0; array_x[0]=START_X; } if(array_y[0]>form.Height()-START_Y-1) { ny1=0; array_y[0]=START_Y; } //--- check x2 and y2 coordinates for being outside the form if(array_x[1]>form.Width()-START_X-1) { nx2=0; array_x[1]=START_X; } if(array_y[1]>form.Height()-START_Y-1) { ny2=0; array_y[1]=array_y[0]; } //--- check x3 and y3 coordinates for being outside the form if(array_x[2]>form.Width()-START_X-1) { nx3=0; array_x[2]=array_x[1]; } if(array_y[2]>form.Height()-START_Y-1) { ny3=0; array_y[2]=array_y[1]; } //--- check x4 and y4 coordinates for being outside the form if(array_x[3]>form.Width()-START_X-1) { nx4=0; array_x[3]=START_X; } if(array_y[3]>form.Height()-START_Y-1) { ny4=0; array_y[3]=array_y[2]; } //--- check x5 and y5 coordinates for being outside the form if(array_x[4]>form.Height()-START_X-1) { nx5=0; array_x[4]=array_x[0]; } if(array_y[4]>form.Height()-START_Y-1) { ny5=0; array_y[4]=array_y[0]; } //--- Draw a shape form.DrawPolylineThickOnBG(0,array_x,array_y,3,clrWheat,255,true,false,STYLE_SOLID,LINE_END_BUTT); nx1++; ny1++; nx2++; ny2++; nx3++; ny3++; nx4++; ny4++; nx5++; ny5++; break; //--- "y" = Polygon case FIGURE_TYPE_POLYGON : coordX1=START_X+nx1; coordY1=START_Y+ny1; coordX2=coordX1+nx2*8; coordY2=coordY1; coordX3=coordX2; coordY3=coordY2+ny3*2; coordX4=coordX1; coordY4=coordY3; coordX5=coordX1; coordY5=coordY1; //--- Fill in the arrays with coordinate values array_x[0]=coordX1; array_x[1]=coordX2; array_x[2]=coordX3; array_x[3]=coordX4; array_x[4]=coordX5; array_y[0]=coordY1; array_y[1]=coordY2; array_y[2]=coordY3; array_y[3]=coordY4; array_y[4]=coordY5; //--- check x1 and y1 coordinates for being outside the form if(array_x[0]>form.Width()-START_X-1) { nx1=0; array_x[0]=START_X; } if(array_y[0]>form.Height()-START_Y-1) { ny1=0; array_y[0]=START_Y; } //--- check x2 and y2 coordinates for being outside the form if(array_x[1]>form.Width()-START_X-1) { nx2=0; array_x[1]=START_X; } if(array_y[1]>form.Height()-START_Y-1) { ny2=0; array_y[1]=array_y[0]; } //--- check x3 and y3 coordinates for being outside the form if(array_x[2]>form.Width()-START_X-1) { nx3=0; array_x[2]=array_x[1]; } if(array_y[2]>form.Height()-START_Y-1) { ny3=0; array_y[2]=array_y[1]; } //--- check x4 and y4 coordinates for being outside the form if(array_x[3]>form.Width()-START_X-1) { nx4=0; array_x[3]=START_X; } if(array_y[3]>form.Height()-START_Y-1) { ny4=0; array_y[3]=array_y[2]; } //--- check x5 and y5 coordinates for being outside the form if(array_x[4]>form.Height()-START_X-1) { nx5=0; array_x[4]=array_x[0]; } if(array_y[4]>form.Height()-START_Y-1) { ny5=0; array_y[4]=array_y[0]; } //--- Draw a shape form.DrawPolygonOnBG(0,array_x,array_y,clrWheat); nx1++; ny1++; nx2++; ny2++; nx3++; ny3++; nx4++; ny4++; nx5++; ny5++; break; //--- "u" = Filled polygon case FIGURE_TYPE_POLYGON_FILL : return; coordX1=START_X+nx1; coordY1=START_Y+ny1; coordX2=coordX1+nx2*4; coordY2=coordY1; coordX3=coordX2; coordY3=coordY2+ny3*2; coordX4=coordX1; coordY4=coordY3; //--- Fill in the arrays with coordinate values array_x[0]=coordX1; array_x[1]=coordX2; array_x[2]=coordX3; array_x[3]=coordX4; array_x[4]=coordX5; array_y[0]=coordY1; array_y[1]=coordY2; array_y[2]=coordY3; array_y[3]=coordY4; array_y[4]=coordY5; //--- check x1 and y1 coordinates for being outside the form if(array_x[0]>form.Width()-START_X-1) { nx1=0; array_x[0]=START_X; } if(array_y[0]>form.Height()-START_Y-1) { ny1=0; array_y[0]=START_Y; } //--- check x2 and y2 coordinates for being outside the form if(array_x[1]>form.Width()-START_X-1) { nx2=0; array_x[1]=START_X; } if(array_y[1]>form.Height()-START_Y-1) { ny2=0; array_y[1]=array_y[0]; } //--- check x3 and y3 coordinates for being outside the form if(array_x[2]>form.Width()-START_X-1) { nx3=0; array_x[2]=array_x[1]; } if(array_y[2]>form.Height()-START_Y-1) { ny3=0; array_y[2]=array_y[1]; } //--- check x4 and y4 coordinates for being outside the form if(array_x[3]>form.Width()-START_X-1) { nx4=0; array_x[3]=START_X; } if(array_y[3]>form.Height()-START_Y-1) { ny4=0; array_y[3]=array_y[2]; } //--- Draw a shape form.DrawPolygonFillOnBG(0,array_x,array_y,clrWheat); nx1++; ny1++; nx2++; ny2++; nx3++; ny3++; nx4++; ny4++; break; //--- "i" = Polygon with AntiAlliasing case FIGURE_TYPE_POLYGON_AA : coordX1=START_X+nx1; coordY1=START_Y+ny1; coordX2=coordX1+nx2*8; coordY2=coordY1; coordX3=coordX2; coordY3=coordY2+ny3*2; coordX4=coordX1; coordY4=coordY3; coordX5=coordX1; coordY5=coordY1; //--- Fill in the arrays with coordinate values array_x[0]=coordX1; array_x[1]=coordX2; array_x[2]=coordX3; array_x[3]=coordX4; array_x[4]=coordX5; array_y[0]=coordY1; array_y[1]=coordY2; array_y[2]=coordY3; array_y[3]=coordY4; array_y[4]=coordY5; //--- check x1 and y1 coordinates for being outside the form if(array_x[0]>form.Width()-START_X-1) { nx1=0; array_x[0]=START_X; } if(array_y[0]>form.Height()-START_Y-1) { ny1=0; array_y[0]=START_Y; } //--- check x2 and y2 coordinates for being outside the form if(array_x[1]>form.Width()-START_X-1) { nx2=0; array_x[1]=START_X; } if(array_y[1]>form.Height()-START_Y-1) { ny2=0; array_y[1]=array_y[0]; } //--- check x3 and y3 coordinates for being outside the form if(array_x[2]>form.Width()-START_X-1) { nx3=0; array_x[2]=array_x[1]; } if(array_y[2]>form.Height()-START_Y-1) { ny3=0; array_y[2]=array_y[1]; } //--- check x4 and y4 coordinates for being outside the form if(array_x[3]>form.Width()-START_X-1) { nx4=0; array_x[3]=START_X; } if(array_y[3]>form.Height()-START_Y-1) { ny4=0; array_y[3]=array_y[2]; } //--- check x5 and y5 coordinates for being outside the form if(array_x[4]>form.Height()-START_X-1) { nx5=0; array_x[4]=array_x[0]; } if(array_y[4]>form.Height()-START_Y-1) { ny5=0; array_y[4]=array_y[0]; } //--- Draw a shape form.DrawPolygonAAOnBG(0,array_x,array_y,clrWheat); nx1++; ny1++; nx2++; ny2++; nx3++; ny3++; nx4++; ny4++; nx5++; ny5++; break; //--- "o" = Polygon with WU case FIGURE_TYPE_POLYGON_WU : coordX1=START_X+nx1; coordY1=START_Y+ny1; coordX2=coordX1+nx2*8; coordY2=coordY1; coordX3=coordX2; coordY3=coordY2+ny3*2; coordX4=coordX1; coordY4=coordY3; coordX5=coordX1; coordY5=coordY1; //--- Fill in the arrays with coordinate values array_x[0]=coordX1; array_x[1]=coordX2; array_x[2]=coordX3; array_x[3]=coordX4; array_x[4]=coordX5; array_y[0]=coordY1; array_y[1]=coordY2; array_y[2]=coordY3; array_y[3]=coordY4; array_y[4]=coordY5; //--- check x1 and y1 coordinates for being outside the form if(array_x[0]>form.Width()-START_X-1) { nx1=0; array_x[0]=START_X; } if(array_y[0]>form.Height()-START_Y-1) { ny1=0; array_y[0]=START_Y; } //--- check x2 and y2 coordinates for being outside the form if(array_x[1]>form.Width()-START_X-1) { nx2=0; array_x[1]=START_X; } if(array_y[1]>form.Height()-START_Y-1) { ny2=0; array_y[1]=array_y[0]; } //--- check x3 and y3 coordinates for being outside the form if(array_x[2]>form.Width()-START_X-1) { nx3=0; array_x[2]=array_x[1]; } if(array_y[2]>form.Height()-START_Y-1) { ny3=0; array_y[2]=array_y[1]; } //--- check x4 and y4 coordinates for being outside the form if(array_x[3]>form.Width()-START_X-1) { nx4=0; array_x[3]=START_X; } if(array_y[3]>form.Height()-START_Y-1) { ny4=0; array_y[3]=array_y[2]; } //--- check x5 and y5 coordinates for being outside the form if(array_x[4]>form.Height()-START_X-1) { nx5=0; array_x[4]=array_x[0]; } if(array_y[4]>form.Height()-START_Y-1) { ny5=0; array_y[4]=array_y[0]; } //--- Draw a shape form.DrawPolygonWuOnBG(0,array_x,array_y,clrWheat); nx1++; ny1++; nx2++; ny2++; nx3++; ny3++; nx4++; ny4++; nx5++; ny5++; break; //--- "p" = Polygon with a specified width using two smoothing algorithms case FIGURE_TYPE_POLYGON_SMOOTH : coordX1=START_X+nx1; coordY1=START_Y+ny1; coordX2=coordX1+nx2*8; coordY2=coordY1; coordX3=coordX2; coordY3=coordY2+ny3*2; coordX4=coordX1; coordY4=coordY3; coordX5=coordX1; coordY5=coordY1; //--- Fill in the arrays with coordinate values array_x[0]=coordX1; array_x[1]=coordX2; array_x[2]=coordX3; array_x[3]=coordX4; array_x[4]=coordX5; array_y[0]=coordY1; array_y[1]=coordY2; array_y[2]=coordY3; array_y[3]=coordY4; array_y[4]=coordY5; //--- check x1 and y1 coordinates for being outside the form if(array_x[0]>form.Width()-START_X-1) { nx1=0; array_x[0]=START_X; } if(array_y[0]>form.Height()-START_Y-1) { ny1=0; array_y[0]=START_Y; } //--- check x2 and y2 coordinates for being outside the form if(array_x[1]>form.Width()-START_X-1) { nx2=0; array_x[1]=START_X; } if(array_y[1]>form.Height()-START_Y-1) { ny2=0; array_y[1]=array_y[0]; } //--- check x3 and y3 coordinates for being outside the form if(array_x[2]>form.Width()-START_X-1) { nx3=0; array_x[2]=array_x[1]; } if(array_y[2]>form.Height()-START_Y-1) { ny3=0; array_y[2]=array_y[1]; } //--- check x4 and y4 coordinates for being outside the form if(array_x[3]>form.Width()-START_X-1) { nx4=0; array_x[3]=START_X; } if(array_y[3]>form.Height()-START_Y-1) { ny4=0; array_y[3]=array_y[2]; } //--- check x5 and y5 coordinates for being outside the form if(array_x[4]>form.Height()-START_X-1) { nx5=0; array_x[4]=array_x[0]; } if(array_y[4]>form.Height()-START_Y-1) { ny5=0; array_y[4]=array_y[0]; } //--- Draw a shape form.DrawPolygonSmoothOnBG(0,array_x,array_y,3,clrWheat,255,0.5,10.0,true,false,STYLE_SOLID,LINE_END_BUTT); nx1++; ny1++; nx2++; ny2++; nx3++; ny3++; nx4++; ny4++; nx5++; ny5++; break; //--- "a" = Polygon with a specified width using a smoothing algorithm case FIGURE_TYPE_POLYGON_THICK : coordX1=START_X+nx1; coordY1=START_Y+ny1; coordX2=coordX1+nx2*8; coordY2=coordY1; coordX3=coordX2; coordY3=coordY2+ny3*2; coordX4=coordX1; coordY4=coordY3; coordX5=coordX1; coordY5=coordY1; //--- Fill in the arrays with coordinate values array_x[0]=coordX1; array_x[1]=coordX2; array_x[2]=coordX3; array_x[3]=coordX4; array_x[4]=coordX5; array_y[0]=coordY1; array_y[1]=coordY2; array_y[2]=coordY3; array_y[3]=coordY4; array_y[4]=coordY5; //--- check x1 and y1 coordinates for being outside the form if(array_x[0]>form.Width()-START_X-1) { nx1=0; array_x[0]=START_X; } if(array_y[0]>form.Height()-START_Y-1) { ny1=0; array_y[0]=START_Y; } //--- check x2 and y2 coordinates for being outside the form if(array_x[1]>form.Width()-START_X-1) { nx2=0; array_x[1]=START_X; } if(array_y[1]>form.Height()-START_Y-1) { ny2=0; array_y[1]=array_y[0]; } //--- check x3 and y3 coordinates for being outside the form if(array_x[2]>form.Width()-START_X-1) { nx3=0; array_x[2]=array_x[1]; } if(array_y[2]>form.Height()-START_Y-1) { ny3=0; array_y[2]=array_y[1]; } //--- check x4 and y4 coordinates for being outside the form if(array_x[3]>form.Width()-START_X-1) { nx4=0; array_x[3]=START_X; } if(array_y[3]>form.Height()-START_Y-1) { ny4=0; array_y[3]=array_y[2]; } //--- check x5 and y5 coordinates for being outside the form if(array_x[4]>form.Height()-START_X-1) { nx5=0; array_x[4]=array_x[0]; } if(array_y[4]>form.Height()-START_Y-1) { ny5=0; array_y[4]=array_y[0]; } //--- Draw a shape form.DrawPolygonThickOnBG(0,array_x,array_y,3,clrWheat,255,true,false,STYLE_SOLID,LINE_END_BUTT); nx1++; ny1++; nx2++; ny2++; nx3++; ny3++; nx4++; ny4++; nx5++; ny5++; break; //--- "s" = Rectangle case FIGURE_TYPE_RECTANGLE : coordX1=START_X+nx1; coordY1=START_Y+ny1; coordX2=START_X+nx2*2; coordY2=START_Y+ny2*2; if(coordX1>form.Width()-START_X-1) { nx1=0; coordX1=START_X; } if(coordY1>form.Height()-START_Y-1) { ny1=0; coordY1=START_Y; } if(coordX2>form.Width()-START_X-1) { nx2=0; coordX2=START_X; } if(coordY2>form.Height()-START_Y-1) { ny2=0; coordY2=START_Y; } form.DrawRectangleOnBG(0,coordX1,coordY1,coordX2,coordY2,clrWheat); nx1++; ny1++; nx2++; ny2++; break; //--- "d" = Filled rectangle case FIGURE_TYPE_RECTANGLE_FILL : coordX1=START_X+nx1; coordY1=START_Y+ny1; coordX2=START_X+nx2*2; coordY2=START_Y+ny2*2; if(coordX1>form.Width()-START_X-1) { nx1=0; coordX1=START_X; } if(coordY1>form.Height()-START_Y-1) { ny1=0; coordY1=START_Y; } if(coordX2>form.Width()-START_X-1) { nx2=0; coordX2=START_X; } if(coordY2>form.Height()-START_Y-1) { ny2=0; coordY2=START_Y; } form.DrawRectangleFillOnBG(0,coordX1,coordY1,coordX2,coordY2,clrWheat); nx1++; ny1++; nx2++; ny2++; break; //--- "f" = Circle case FIGURE_TYPE_CIRCLE : coordX1=START_X+nx1; coordY1=START_Y+ny1; RD=nx2*2; if(coordX1>form.Width()-START_X-1) { nx1=0; coordX1=START_X; } if(coordY1>form.Height()-START_Y-1) { ny1=0; coordY1=START_Y; } if(RD>form.Height()/2) { nx2=0; RD=1; } form.DrawCircleOnBG(0,coordX1,coordY1,(int)RD,clrWheat); nx1++; ny1++; nx2++; break; //--- "g" = Filled circle case FIGURE_TYPE_CIRCLE_FILL : coordX1=START_X+nx1; coordY1=START_Y+ny1; RD=nx2*2; if(coordX1>form.Width()-START_X-1) { nx1=0; coordX1=START_X; } if(coordY1>form.Height()-START_Y-1) { ny1=0; coordY1=START_Y; } if(RD>form.Height()/2) { nx2=0; RD=1; } form.DrawCircleFillOnBG(0,coordX1,coordY1,(int)RD,clrWheat); nx1++; ny1++; nx2++; break; //--- "h" = Circle with AntiAlliasing case FIGURE_TYPE_CIRCLE_AA : coordX1=START_X+nx1; coordY1=START_Y+ny1; RD=nx2*2; if(coordX1>form.Width()-START_X-1) { nx1=0; coordX1=START_X; } if(coordY1>form.Height()-START_Y-1) { ny1=0; coordY1=START_Y; } if(RD>form.Height()/2) { nx2=0; RD=1; } form.DrawCircleAAOnBG(0,coordX1,coordY1,RD,clrWheat,255,true,false,STYLE_SOLID); nx1++; ny1++; nx2++; break; //--- "j" = Circle with WU case FIGURE_TYPE_CIRCLE_WU : coordX1=START_X+nx1; coordY1=START_Y+ny1; RD=nx2*2; if(coordX1>form.Width()-START_X-1) { nx1=0; coordX1=START_X; } if(coordY1>form.Height()-START_Y-1) { ny1=0; coordY1=START_Y; } if(RD>form.Height()/2) { nx2=0; RD=1; } form.DrawCircleWuOnBG(0,coordX1,coordY1,RD,clrWheat,255,true,false,STYLE_SOLID); nx1++; ny1++; nx2++; break; //--- "k" = Triangle case FIGURE_TYPE_TRIANGLE : coordX1=START_X+nx1; coordY1=START_Y+ny1; coordX2=coordX1+nx2*4; coordY2=START_Y+ny2*2; coordX3=coordX1+nx3*2; coordY3=coordY2+ny3*2; if(coordX1>form.Width()-START_X-1) { nx1=0; coordX1=START_X; } if(coordY1>form.Height()-START_Y-1) { ny1=0; coordY1=START_Y; } if(coordX2>form.Width()-START_X-1) { nx2=0; coordX2=START_X; } if(coordY2>form.Height()-START_Y-1) { ny2=0; coordY2=START_Y; } if(coordX3>form.Width()-START_X-1) { nx3=0; coordX3=START_X; } if(coordY3>form.Height()-START_Y-1) { ny3=0; coordY3=START_Y; } form.DrawTriangleOnBG(0,coordX1,coordY1,coordX2,coordY2,coordX3,coordY3,clrWheat); nx1++; ny1++; nx2++; ny2++; nx3++; ny3++; break; //--- "l" = Filled triangle case FIGURE_TYPE_TRIANGLE_FILL : coordX1=START_X+nx1; coordY1=START_Y+ny1; coordX2=coordX1+nx2*4; coordY2=START_Y+ny2*2; coordX3=coordX1+nx3*2; coordY3=coordY2+ny3*2; if(coordX1>form.Width()-START_X-1) { nx1=0; coordX1=START_X; } if(coordY1>form.Height()-START_Y-1) { ny1=0; coordY1=START_Y; } if(coordX2>form.Width()-START_X-1) { nx2=0; coordX2=START_X; } if(coordY2>form.Height()-START_Y-1) { ny2=0; coordY2=START_Y; } if(coordX3>form.Width()-START_X-1) { nx3=0; coordX3=START_X; } if(coordY3>form.Height()-START_Y-1) { ny3=0; coordY3=START_Y; } form.DrawTriangleFillOnBG(0,coordX1,coordY1,coordX2,coordY2,coordX3,coordY3,clrWheat); nx1++; ny1++; nx2++; ny2++; nx3++; ny3++; break; //--- "z" = Triangle with AntiAlliasing case FIGURE_TYPE_TRIANGLE_AA : coordX1=START_X+nx1; coordY1=START_Y+ny1; coordX2=coordX1+nx2*4; coordY2=START_Y+ny2*2; coordX3=coordX1+nx3*2; coordY3=coordY2+ny3*2; if(coordX1>form.Width()-START_X-1) { nx1=0; coordX1=START_X; } if(coordY1>form.Height()-START_Y-1) { ny1=0; coordY1=START_Y; } if(coordX2>form.Width()-START_X-1) { nx2=0; coordX2=START_X; } if(coordY2>form.Height()-START_Y-1) { ny2=0; coordY2=START_Y; } if(coordX3>form.Width()-START_X-1) { nx3=0; coordX3=START_X; } if(coordY3>form.Height()-START_Y-1) { ny3=0; coordY3=START_Y; } form.DrawTriangleAAOnBG(0,coordX1,coordY1,coordX2,coordY2,coordX3,coordY3,clrWheat,255,true,false,STYLE_SOLID); nx1++; ny1++; nx2++; ny2++; nx3++; ny3++; break; //--- "x" = Triangle with WU case FIGURE_TYPE_TRIANGLE_WU : coordX1=START_X+nx1; coordY1=START_Y+ny1; coordX2=coordX1+nx2*4; coordY2=START_Y+ny2*2; coordX3=coordX1+nx3*2; coordY3=coordY2+ny3*2; if(coordX1>form.Width()-START_X-1) { nx1=0; coordX1=START_X; } if(coordY1>form.Height()-START_Y-1) { ny1=0; coordY1=START_Y; } if(coordX2>form.Width()-START_X-1) { nx2=0; coordX2=START_X; } if(coordY2>form.Height()-START_Y-1) { ny2=0; coordY2=START_Y; } if(coordX3>form.Width()-START_X-1) { nx3=0; coordX3=START_X; } if(coordY3>form.Height()-START_Y-1) { ny3=0; coordY3=START_Y; } form.DrawTriangleWuOnBG(0,coordX1,coordY1,coordX2,coordY2,coordX3,coordY3,clrWheat,255,true,false,STYLE_SOLID); nx1++; ny1++; nx2++; ny2++; nx3++; ny3++; break; //--- "c" = Ellipse case FIGURE_TYPE_ELLIPSE : coordX1=START_X+nx1; coordY1=START_Y+ny1; coordX2=START_X+nx2*2; coordY2=START_Y+ny2*2; if(coordX1>form.Width()-START_X-1) { nx1=0; coordX1=START_X; } if(coordY1>form.Height()-START_Y-1) { ny1=0; coordY1=START_Y; } if(coordX2>form.Width()-START_X-1) { nx2=0; coordX2=START_X; } if(coordY2>form.Height()-START_Y-1) { ny2=0; coordY2=START_Y; } form.DrawEllipseOnBG(0,coordX1,coordY1,coordX2,coordY2,clrWheat); nx1++; ny1++; nx2++; ny2++; break; //--- "v" = Filled ellipse case FIGURE_TYPE_ELLIPSE_FILL : coordX1=START_X+nx1; coordY1=START_Y+ny1; coordX2=START_X+nx2*2; coordY2=START_Y+ny2*2; if(coordX1>form.Width()-START_X-1) { nx1=0; coordX1=START_X; } if(coordY1>form.Height()-START_Y-1) { ny1=0; coordY1=START_Y; } if(coordX2>form.Width()-START_X-1) { nx2=0; coordX2=START_X; } if(coordY2>form.Height()-START_Y-1) { ny2=0; coordY2=START_Y; } form.DrawEllipseFillOnBG(0,coordX1,coordY1,coordX2,coordY2,clrWheat); nx1++; ny1++; nx2++; ny2++; break; //--- "b" = Ellipse with AntiAlliasing case FIGURE_TYPE_ELLIPSE_AA : return; coordX1=START_X+nx1; coordY1=START_Y+ny1; coordX2=coordX1+nx2*2; coordY2=coordY1+ny2*2; if(coordX1>form.Width()-START_X-1) { nx1=0; coordX1=START_X; } if(coordY1>form.Height()-START_Y-1) { ny1=0; coordY1=START_Y; } if(coordX2>form.Width()-START_X-1) { nx2=0; coordX2=START_X; } if(coordY2>form.Height()-START_Y-1) { ny2=0; coordY2=START_Y; } form.DrawEllipseAAOnBG(0,coordX1,coordY1,coordX2,coordY2,clrWheat,255,true,false,STYLE_SOLID); nx1++; ny1++; nx2++; ny2++; break; //--- "n" = Ellipse with WU case FIGURE_TYPE_ELLIPSE_WU : coordX1=START_X+nx1; coordY1=START_Y+ny1; coordX2=coordX1+nx2*2; coordY2=coordY1+ny2*2; if(coordX1>form.Width()-START_X-1) { nx1=0; coordX1=START_X; } if(coordY1>form.Height()-START_Y-1) { ny1=0; coordY1=START_Y; } if(coordX2>form.Width()-START_X-1) { nx2=0; coordX2=START_X; } if(coordY2>form.Height()-START_Y-1) { ny2=0; coordY2=START_Y; } form.DrawEllipseWuOnBG(0,coordX1,coordY1,coordX2,coordY2,clrWheat,255,true,false,STYLE_SOLID); nx1++; ny1++; nx2++; ny2++; break; //--- "m" = Ellipse arc case FIGURE_TYPE_ARC : coordX1=START_X+nx1; coordY1=START_Y+ny1; coordX2=form.Width()-START_X-1-nx2; coordY2=form.Height()-START_Y-1-ny2; coordX3=coordX1; coordY3=coordY1; coordX4=coordX2; coordY4=coordY2; if(coordX1>form.Width()-START_X-1) { nx1=0; coordX3=coordX1=START_X; } if(coordY1>form.Height()-START_Y-1) { ny1=0; coordY3=coordY1=START_Y; } if(coordX2>form.Width()-START_X-1) { nx2=0; coordX4=coordX2=START_X; } if(coordY2>form.Height()-START_Y-1) { ny2=0; coordY4=coordY2=START_Y; } form.DrawArcOnBG(0,coordX1,coordY1,coordX2,coordY2,coordX3,coordY3,coordX4,coordY4,clrWheat); nx1++; ny1++; nx2++; ny2++; break; //--- "," = Ellipse sector case FIGURE_TYPE_PIE : coordX1=START_X+nx1; coordY1=START_Y+ny1; coordX2=form.Width()-START_X-1-nx2; coordY2=form.Height()-START_Y-1-ny2; coordX3=coordX1; coordY3=coordY1; coordX4=coordX2; coordY4=coordY1; if(coordX1>form.Width()-START_X-1) { nx1=0; coordX3=coordX1=START_X; } if(coordY1>form.Height()-START_Y-1) { ny1=0; coordY3=coordY4=coordY1=START_Y; } if(coordX2>form.Width()-START_X-1) { nx2=0; coordX4=coordX2=START_X; } if(coordY2>form.Height()-START_Y-1) { ny2=0; coordY2=START_Y; } form.DrawPieOnBG(0,coordX1,coordY1,coordX2,coordY2,coordX3,coordY3,coordX4,coordY4,clrWheat,clrLightSteelBlue); nx1++; ny1++; nx2++; ny2++; break; //--- Default = Nothing default : break; } } //+------------------------------------------------------------------+
関数のコードはシンプルでわかりやすいと思います。いずれにせよ、コメントセクションを使用してください。
簡単なテストでは同じパラメータの一般的な処理は実行していません。switch演算子のcaseですべてを明示的に記述する方がはるかに簡単で高速です。コードの反復性は重要ではありません。作成されたクラスの機能を単純に確認することがより重要です。
EAをコンパイルし、チャート上で起動します。起動後、キーをいくつか押して、描画モードが変更され、3番目のフォームのラベルに表示されていることを確認します。4番目のフォームをクリックすると、テキストは前の記事の過去のEAと同じように移動します。ただし、このテキストはアニメーションテキストフレームオブジェクトクラスを介してレンダリングされるようになっています。
必要な描画モードを選択した後、3番目のフォームをクリックし始めると(描画モードの説明が記載されたラベルが表示されます)、選択した形状がラベルの上に描画され、フォーム全体が毎回違う形状点座標で描画されます 。
すべての描画メソッドがスムーズに機能するわけではありません。たとえば、CCanvasクラスのFillPolygon()メソッドは、初期パラメータがオブジェクトクリックで指定された場合に単に無限ループに陥り、EllipseAA()メソッドはゼロ除算エラーを生成します。このメソッドには、これが発生する可能性のある潜在的な点があります。
//+------------------------------------------------------------------+ //| Draw ellipse with antialiasing | //+------------------------------------------------------------------+ void CCanvas::EllipseAA(const double x1,const double y1,const double x2,const double y2,const uint clr,const uint style=UINT_MAX) { double rx = (x2-x1)/2; double ry = (y2-y1)/2; //--- preliminary calculations double x=(x2>x1) ? x1+rx : x2+rx; double y=(y2>y1) ? y1+ry : y2+ry; double rx2=rx*rx; double ry2=ry*ry; //--- set the line style uint prev_style=m_style; if(style!=UINT_MAX) LineStyleSet(style); uint mask=1<<m_style_idx; //--- draw double quarter=round(rx2/sqrt(rx2+ry2)); for(double dx=0; dx<=quarter; dx++) { double dy=ry*sqrt(1-dx*dx/rx2); if((m_style&mask)==mask) PixelSet4AA(x,y,dx,dy,clr); mask<<=1; if(mask==0x1000000) mask=1; } quarter=round(ry2/sqrt(rx2+ry2)); for(double dy=0; dy<=quarter; dy++) { double dx=rx*sqrt(1-dy*dy/ry2); if((m_style&mask)==mask) PixelSet4AA(x,y,dx,dy,clr); mask<<=1; if(mask==0x1000000) mask=1; } //--- set the previous line style if(style!=UINT_MAX) m_style=prev_style; } //+------------------------------------------------------------------+
この問題をプロファイルのスレッドで報告しました。開発者からの返答があるまで、次の記事でそのようなエラーを回避しようとします。
これに関して、一部の描画メソッドは、フォームオブジェクトのマウスクリックのハンドラで呼び出されず、代わりに、関数は単に戻ります。とにかく、これは後で修正されます。描画された形状の下の背景が復元され、すべてが意図したとおりに表示されていることがわかります。描画モードの切り替えに問題があるため、切り替え後、背景は復元されません。背景を復元して画像を削除するメソッドがないためです。これは次の記事で行います。ここでは、テストの目的で、フォームに別の形状を表示する前に、時間枠を切り替えて背景を完全に復元しています。
次の段階
次の記事では、アニメーションクラスの開発を続けます。
ライブラリの現在のバージョンのすべてのファイルは、テストおよびダウンロードできるように、MQL5のテストEAファイルと一緒に以下に添付されています。
質問や提案はコメント欄にお願いします。
**連載のこれまでの記事:
DoEasyライブラリのグラフィックス(第73部): グラフィック要素のフォームオブジェクト
DoEasyライブラリのグラフィックス(第74部): CCanvasクラスを使用した基本的グラフィック要素
DoEasyライブラリのグラフィックス(第75部): 基本的なグラフィック要素でプリミティブとテキストを処理するメソッド
DoEasyライブラリのグラフィックス(第76部): フォームオブジェクトと事前定義されたカラースキーム
DoEasyライブラリのグラフィックス(第77部): 影オブジェクトクラス
DoEasyライブラリのグラフィックス(第78部): ライブラリのアニメーションの原則イメージスライス
MetaQuotes Ltdによってロシア語から翻訳されました。
元の記事: https://www.mql5.com/ru/articles/9652
- 無料取引アプリ
- 8千を超えるシグナルをコピー
- 金融ニュースで金融マーケットを探索