Canvas - это круто!

Авторизуйтесь или зарегистрируйтесь, чтобы добавить комментарий
Nikolai Semko
6602
Nikolai Semko  

Поставил себе задачу: коротким кодом эффектно продемонстрировать возможности пользовательской графики через класс 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
56063
Andrey Khatimlianskii  

Круто, безусловно!

И даже для полезных вещей может использоваться ;)

Nikolai Semko
6602
Nikolai Semko  
Andrey Khatimlianskii:

Круто, безусловно!

И даже для полезных вещей может использоваться ;)

Для того чтобы народ начал юзать канвас в полезных вещах, нужно начать с демонстрации бесполезных вещей. :))

fxsaber
16830
fxsaber  
Nikolai Semko:

Необходимо перед компиляцией в файле Canvas.mqh перенести массив m_pixels[] из protected: в public:

Можно ничего не менять в СБ.

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)]);
Nikolai Semko
6602
Nikolai Semko  
fxsaber:

Можно ничего не менять в СБ.


Прикольно! :))

Но к сожалению, это не бесплатно.

Проверил. Общее замедление на MT5 составило ~11%

fxsaber
16830
fxsaber  
Nikolai Semko:

Прикольно! :))

Но к сожалению, это не бесплатно.

Проверил. Общее замедление на MT5 составило ~11%

В Вашем случае от CCanvas используется 1%. Без CCanvas попробуйте. Код будет ни капли не сложнее, а скорость еще повысится.

Nikolai Semko
6602
Nikolai Semko  
fxsaber:

В Вашем случае от CCanvas используется 1%. Без CCanvas попробуйте. Код будет ни капли не сложнее, а скорость еще повысится.

Конечно, можно обойтись и без класса CCanvas. Но код увеличиться, а выйгрыша по скорости не будет, т.к. по сути из класса CCanvas я использую только массив точек графического ресурса m_pixels[] ( ну и еще функции Update() и Destroy(), но ими можно пренебречь, т.к. на них не сэкономишь). 

А массив - он и в Африке массив. Как на нем можно повысить скорость? Никак. Просто класс CCanvas берет на себя некоторую рутину при создании ресурса, его обновлению (точнее пересозданию) и удалению.

Или Вы хотите сказать, что C.m_pixels[] компилируется не как прямой доступ к массиву? По-моему, как прямой. Без всяких там промежуточных телодвижений. Или я ошибаюсь?

А еще логичнее было бы разработчикам этого класса запихнуть CreateBitmapLabel в конструктор самого класса, чтоб не маячил. Если создается новый экземпляр класса без параметров, то создается холст с размером в окно ( как в моем случае), а при желании можно при создании экземпляра класса и параметры указывать. Лично у себя я так и сделал.

fxsaber
16830
fxsaber  
Nikolai Semko:

Конечно, можно обойтись и без класса CCanvas. Но код увеличиться, а выйгрыша по скорости не будет, т.к. по сути из класса CCanvas я использую только массив точек графического ресурса m_pixels[] ( ну и еще функции Update() и Destroy(), но ими можно пренебречь, т.к. на них не сэкономишь). 

А массив - он и в Африке массив. Как на нем можно повысить скорость? Никак. Просто класс CCanvas берет на себя некоторую рутину при создании ресурса, его обновлению (точнее пересозданию) и удалению.

Или Вы хотите сказать, что C.m_pixels[] компилируется не как прямой доступ к массиву? По-моему, как прямой. Без всяких там промежуточных телодвижений. Или я ошибаюсь?

CCanvas - обертка ResourceCreate.  Поэтому, например, есть у Вас уже 20 готовых картинок в виде массивов. Если захотите их сменять через канвас, то надо будет постоянно делать дорогой ArrayCopy+Update.

А если делать без CCanvas, то все выльется только в ResourceCreate+ChartRerdraw. В кодобазу выкладывал несколько работ с динамическим рисованием. Там было очевидно, что CCanvas не годится.

Rashid Umarov
Админ
16684
Rashid Umarov  
Nikolai Semko:

Необходимо перед компиляцией в файле Canvas.mqh перенести массив m_pixels[] из protected: в public:

А PixelSet точно не поможет?

Nikolai Semko
6602
Nikolai Semko  
Rashid Umarov:

А PixelSet точно не поможет?

Конечно поможет, но будут жуткие тормоза. Во-первых вызов функции это уже не бесплатно, т.к. осуществляется передача и сохранение параметров (в PixelSet это происходит даже не по ссылке), все регистры нужно в стек засунуть, а потом обратно вытащить. Во-вторых, в самой функции происходят проверки на попадания X и Y в заданный диапазон, в-третьих, происходит вычисление индекса массива. А это все мне не требуется, т.к. индекс уже имеется, а быть вне диапазона в моем алгоритме невозможно.  

Evgeniy Zhdan
16257
Evgeniy Zhdan  
Классный радужный график! Еще бы сделать чтобы свечи плясали под музыку и крутились между собой!