キャンバスがカッコいい!

 

CCanvas クラスを使ったカスタム・グラフィックスの 機能を短いコードで示すという課題を自分に課した。

その中で出てきたのがこちら。

このスクリプトは、MQL5とMQL4の両方で動作します。しかし、MT5ではもっと速いです。

各フレームはユニークであり、繰り返さない、つまりスクリプトは循環しない。

#include <Canvas\Canvas.mqh>

void OnStart()
  {
   ChartSetInteger(0,CHART_FOREGROUND,true);
   CCanvas C;
   int Width=(ushort)ChartGetInteger(0,CHART_WIDTH_IN_PIXELS);  // получаем Ширину окна
   int Height=(ushort)ChartGetInteger(0,CHART_HEIGHT_IN_PIXELS); // получаем Высоту окна
   if(!C.CreateBitmapLabel(0,0,"CanvasExamlple",0,0,Width,Height,COLOR_FORMAT_XRGB_NOALPHA)) // создаем канвас размером текущего окна
   Print("Error creating canvas: ",GetLastError()); 
   uint i=0,j=100000;
   int size=Width*Height;
   uchar h[25600];
   for (int w=0;w<25600;w++) 
   h[w]= uchar(128+128*sin(double(w)/256));//создаем массив для ускорения работы
   double X1=0,Y1=0,X2=0,Y2=0;
   while(!IsStopped())
     {
      int pos=int(i%size);
      if(pos==0)
        {
         C.Update();
         //Sleep(30);
         X1= Width-(sin((double)j/100)*(double)Width);
         Y1= Height-(cos((double)j/140)*(double)Height);
         X2= Width+(cos((double)j/80)*(double)Width);
         Y2= Height+(sin((double)j/20)*(double)Height);
         j++;
        }
      int X=pos%Width;
      int Y=int(pos/Width);
      double d= ((X1-X)*(X1-X)+(Y1-Y)*(Y1-Y))/(((X1-X)*(X1-X)+(Y1-Y)*(Y1-Y))+((X2-X)*(X2-X)+(Y2-Y)*(Y2-Y)));
      C.m_pixels[pos]=XRGB(h[int(d*11520)],h[int(d*17920)],h[int(d*6400)]);
      i++;
     }
   C.Destroy();
  }


コンパイル前に、Canvas.mqhの配列m_pixels[]をprotected: からpublicに移動する。

public:
   uint              m_pixels[];               // array of pixels

                     CCanvas(void);
                    ~CCanvas(void);
ファイル:
Swirl.mq5  3 kb
Swirl.ex5  16 kb
 

確かにカッコイイ!

そして、便利なものにも使える ;)

 
Andrey Khatimlianskii:

確かにカッコイイ!

そして、便利なものにも使える ;)

役に立つことにKanvasを使い始めてもらうためには、まず役に立たないことを示すことから始める必要があります。:))

 
Nikolai Semko:

コンパイル前のCanvas.mqhファイルで、配列m_pixels[]をprotected:からpublicに移動する必要があります。

SBでは何も変更する必要はありません。

class CCanvas2 : public CCanvas
{
private:
  int Pos;

public:
  CCanvas2* operator []( const int iPos )
  {
    this.Pos = iPos;
    
    return(&this);
  }
  
  void operator =( const uint Color )
  {
    this.m_pixels[this.Pos] = Color;
  }
};


CCanvas2 C;
//..
// C.m_pixels[pos]=XRGB(h[int(d*11520)],h[int(d*17920)],h[int(d*6400)]);
C[pos]=XRGB(h[int(d*11520)],h[int(d*17920)],h[int(d*6400)]);
 
fxsaber:

SBでは何も変えなくていいんです。


カッコイイ!:))

しかし、残念ながら、それは無料ではありません。

確認しました。MT5での全体的な速度低下は約11%でした。

 
Nikolai Semko:

カッコイイ!:))

しかし、残念ながら、それは無料ではありません。

確認しました。MT5でのトータルのスローダウンは〜11%でした。

あなたのケースでは、CCanvasの1%が使用されています。CCanvasなしで試してみてください。コードは少しも複雑にならず、スピードもさらに向上します。

 
fxsaber:

あなたの場合、CCanvasから1%が使用されています。CCanvasなしで試してみてください。コードは少しも複雑にならず、スピードはさらに向上します。

もちろん、CCanvasクラスがなくても大丈夫です。しかし、CCanvas クラスから実際に使用するのはグラフィック リソースのピクセルの m_pixels[] 配列だけなので、コードは増加しますが処理速度は向上しません (そして Update() と Destroy() 関数ですが、これらは全く役に立たず、ほとんど節約になりません)。

しかし、配列は配列であることに変わりはない。どうすれば速くなるのか?無理でしょう。CCanvas クラスは、リソースの作成、更新(というか再作成)、削除の際に、いくつかのルーチンを処理するだけです。

それとも、C.m_pixels[]は配列への直接アクセスとして コンパイルされていないということでしょうか?ダイレクトだと思います。中間的なジェスチャーは一切なし。それとも私が間違っているのでしょうか?

このクラスの開発者は、CreateBitmapLabelをクラスのコンストラクタ自体に突っ込んで、loomingを回避するのがより論理的でしょう。パラメータなしでクラスのインスタンスを新規作成すると、(私の場合のように)ウィンドウにサイズが表示されたキャンバスが作成されますが、必要であれば、クラスのインスタンス作成時にパラメータを指定することができます。私自身もそのようにしました。

 
Nikolai Semko:

もちろん、CCanvasクラスはなくても大丈夫です。しかし、CCanvasクラスから使用するのはグラフィックリソースの配列m_pixels[]だけなので、コードは増えますが、スピードは上がりません(Update()とDestroy()関数もありますが、お金の節約にはならないので無視してかまいません)。

しかし、配列は配列であることに変わりはない。どうすれば速くなるのか?無理でしょう。CCanvas クラスは、リソースの作成、更新(というか再作成)、削除の際に、いくつかのルーチンを処理するだけです。

それとも、C.m_pixels[]が配列の直接アクセスとして コンパイルされないということでしょうか?ダイレクトだと思います。中間的なジェスチャーは一切なし。それとも私の勘違いでしょうか?

CCanvasは、ResourceCreateのラッパーです。例えば、配列の形で20枚の画像が用意されているわけです。キャンバスで変更する場合は、高価なArrayCopy+Updateを行う必要があります。

また、CCanvasを使わずに行う場合は、ResourceCreate+ChartRerdrawのみが必要です。kodobaseに動的描画の仕事をいくつか投稿しています。そこで明らかになったのは、CCanvasがダメだということです。

 
Nikolai Semko:

コンパイル前にCanvas.mqhファイルの配列m_pixels[]をprotected:からpublicに移動する必要があります。

本当に PixelSetは 役に立たないのでしょうか?

 
Rashid Umarov:

本当に PixelSetは 役に立たないのでしょうか?

もちろん、役に立ちますが、恐ろしく遅いでしょう。まず、関数呼び出しは自由ではありません。パラメータが渡され格納されるため(PixelSetでは、これは参照によってさえ行われません)、すべてのレジスタはスタックに押し込まれ、再び引き出される必要があります。第二に,この関数自体がXとYが指定された範囲に収まっているかどうかをチェックし,第三に,配列のインデックスを計算する.そして、すでにインデックスがあり、私のアルゴリズムでは範囲外になることができないので、これらすべてが必要ではありません。

 
レインボーチャートがかっこいいまた、音楽に合わせてキャンドルを踊らせ、お互いにツイストさせたいと考えています
理由: