Canvas - это круто! - страница 101

 
Nikolai Semko #:
Для тестера работает и канвас. Писал об этом много раз. Просто частоту его вывода нужно контролировать по реальному времени. Только в тестере в советниках не работают события, поэтому управление в панелях управления невозможно. Но возможно с горем пополам в индикаторах
Я знаю, совсем другое имел ввиду.Всё там работает кроме считывания координат,события просто самому нужно прописывать.Мои панели полноценно работают в тестере, (тип- советник )только,что мышкой двигать их нельзя,так как заставить его считывать координаты никаким кастылём у меня не получилось ,тестер тупо не видит курсор,да я бы  нашел решение но увы желание пропало ерундой заниматься 
 
Dz Mak #:
Я знаю, совсем другое имел ввиду.Всё там работает кроме считывания координат,события просто самому нужно прописывать.Мои панели полноценно работают в тестере, (тип- советник )только,что мышкой двигать их нельзя,так как заставить его считывать координаты никаким кастылём у меня не получилось ,тестер тупо не видит курсор,да я бы  нашел решение но увы желание пропало ерундой заниматься 

не понял
в индикаторе в тестере не работает событие CHARTEVENT_MOUSE_MOVE, но работает событие CHARTEVENT_CLICK, по которому можно считать координаты мышки. В этом есть возможность управления в тестере. Т.е. когда двигаешь мышкой при нажатой левой клавиши мышки, то все работает. 

 
Nikolai Semko #:

не понял
в индикаторе в тестере не работает событие CHARTEVENT_MOUSE_MOVE, но работает событие CHARTEVENT_CLICK, по которому можно считать координаты мышки. В этом есть возможность управления в тестере. Т.е. когда двигаешь мышкой при нажатой левой клавиши мышки, то все работает. 

События  нужно самому писать.Потому,что события chart event  не работают в тестере,если файл -советник,а работает в индикаторах.Вместо chart event в тестере нужно считывать состояния объектов и окружения по этому можно вручную прописать свой "chart event "для тестера, тогда любая панель там будет работать.По факту для тестера chart event  вообще не нужен,он там бесполезен,если это советник.Кароче всё там можно заставить работать,если захотеть.
 
Nikolai Semko #:

Николай здравия!

я бегло просмотрел всю эту ветку, но ответа на свой вопрос не нашёл!

Подскажите пожалуйста - КАК на канвасе можно сделать обычную "обводку" для текста :

(данная метка выполнена на Канвасе)

вся соль в том, что ЕСЛИ делать N-копий текста и размещать его "по кругу" вокруг основного текста, то при крупном размере шрифта (более 50 пунктов ... а у меня ^ 150 пунктов) и многострочной надписью, в 5-7 строк (логи на скрин),
то при создании ОБЪЕКТАМИ - ноут может и подвиснуть .... приходилось перезапускатьь терминал ... а на канвасе - ноут тихий, но время создания такой текстовой многострочной метки = 5 минут !!!

...оптимизировал код , теперь на канвасе создаёт 7 строк лога за 101 секунду (чуть дольше минуты).

это всёравно очень долго!

Есть ЛИ способы или методы более быстрого создания обводки для текста ?!

(ранее видел такой фокус - 1 раз создать Канвас, и в нём менять размеры / пиксели / цвета ...) ... щас попробую, отпишусь позже, ...
...а пока всё-же интересны мнения специалистов по этому вопросу !

Благодарю!

 
Vitaliy Kostrubko #:
Подскажите пожалуйста - КАК на канвасе можно сделать обычную "обводку" для текста
Я не спец по канвасу. Скорее всего, есть стандартные возможности. Но чисто геометрическая идея - нарисуйте текст на N% большего размера чёрным, а поверх нормального размера белым. Скорее всего, чёрный текст придётся сжать немного по горизонтали, чтобы совпадало. Итого - всего 2 рисования.
 
Vitaliy Kostrubko #:

Николай здравия!

я бегло просмотрел всю эту ветку, но ответа на свой вопрос не нашёл!

Подскажите пожалуйста - КАК на канвасе можно сделать обычную "обводку" для текста :

(данная метка выполнена на Канвасе)

вся соль в том, что ЕСЛИ делать N-копий текста и размещать его "по кругу" вокруг основного текста, то при крупном размере шрифта (более 50 пунктов ... а у меня ^ 150 пунктов) и многострочной надписью, в 5-7 строк (логи на скрин),
то при создании ОБЪЕКТАМИ - ноут может и подвиснуть .... приходилось перезапускатьь терминал ... а на канвасе - ноут тихий, но время создания такой текстовой многострочной метки = 5 минут !!!

...оптимизировал код , теперь на канвасе создаёт 7 строк лога за 101 секунду (чуть дольше минуты).

это всёравно очень долго!

Есть ЛИ способы или методы более быстрого создания обводки для текста ?!

(ранее видел такой фокус - 1 раз создать Канвас, и в нём менять размеры / пиксели / цвета ...) ... щас попробую, отпишусь позже, ...
...а пока всё-же интересны мнения специалистов по этому вопросу !

Благодарю!

никак..ждите когда Blend2D всё-таки интегрируют или используйте его DLL уже сейчас. Хинт: шрифт это векторный контур (path). Отрисовать его без заливки толстой линией, затем сверху наложить обычный образ, с тонкой обводкой и заливкой

 
Vitaliy Kostrubko #:

Николай здравия!

я бегло просмотрел всю эту ветку, но ответа на свой вопрос не нашёл!

Подскажите пожалуйста - КАК на канвасе можно сделать обычную "обводку" для текста :

(данная метка выполнена на Канвасе)

вся соль в том, что ЕСЛИ делать N-копий текста и размещать его "по кругу" вокруг основного текста, то при крупном размере шрифта (более 50 пунктов ... а у меня ^ 150 пунктов) и многострочной надписью, в 5-7 строк (логи на скрин),
то при создании ОБЪЕКТАМИ - ноут может и подвиснуть .... приходилось перезапускатьь терминал ... а на канвасе - ноут тихий, но время создания такой текстовой многострочной метки = 5 минут !!!

...оптимизировал код , теперь на канвасе создаёт 7 строк лога за 101 секунду (чуть дольше минуты).

это всёравно очень долго!

Есть ЛИ способы или методы более быстрого создания обводки для текста ?!

(ранее видел такой фокус - 1 раз создать Канвас, и в нём менять размеры / пиксели / цвета ...) ... щас попробую, отпишусь позже, ...
...а пока всё-же интересны мнения специалистов по этому вопросу !

Благодарю!

Здравия!
101 сек - не понимаю почему так долго. Думаю есть какая-то симантическая ошибка в Вашем коде. 100-200 миллисекунд - в это еще можно поверить. 
Но с другой стороны - рендеринг шрифта, как минимум в MQL5, происходит ужасающе медленно. Я как-то проверял и офигел. Примено в 100 раз медленнее чем я ожидал. Даже была мысль написать библиотеку быстрого вывода шрифтов и его плавного масштабирования. Но не нашел мотивации, так как нет таких задач где много меняющегося текста. 
В Вашем случае первое что приходит в голову - просто найти нужный контурный шрифт ttf и импоритровать его. Думаю это самое простое решение. 
например:
https://ofont.ru/category/5


Но если Вам нужны размытые края, то наверное лучший способ сначала в канвас вывести нужный текст одного цвета(например черного), размыть его (любая качественная LLM с этим легко справиться если сформулировать ей задачу, отталкиваясь от наличия уже готового bitmap-массива bmp[w*h], в котором нужно размыть изображение максимально эффективным способом и заданной дисперсией). А потом в это же место забабахать уже нормальный текс того же размера, но противоположного цвета.
Ну или как сказал Макс, ждать пока MQ разродятся программным доступом к возможностям Blend2D. Но этого можно ждать ужасающе долго. ))

 
Nikolai Semko #:

Но если Вам нужны размытые края, то наверное лучший способ сначала в канвас вывести нужный текст одного цвета(например черного), размыть его (любая качественная LLM с этим легко справиться если сформулировать ей задачу, отталкиваясь от наличия уже готового bitmap-массива bmp[w*h], в котором нужно размыть изображение максимально эффективным способом и заданной дисперсией). А потом в это же место забабахать уже нормальный текс того же размера, но противоположного цвета.


вот попробовал спросить у claude.ai.
И что она мне ответила:
https://claude.ai/share/cad08fbb-2502-47bf-b99d-c325ee968609
вдруг ссылка в России не будет открываться, тогда вот код, который был сгенерирован, но я его не проверял. Проверьте сами пожалуйста:

//+------------------------------------------------------------------+
//| Gaussian Blur function for bitmap array                          |
//| bmp[] - ARGB pixel array (uint format: 0xAARRGGBB)              |
//| width, height - image dimensions                                  |
//| blur_dispersion - variance (sigma^2) for Gaussian kernel         |
//+------------------------------------------------------------------+
void BlurBmp(uint &bmp[], int width, int height, double blur_dispersion)
{
   if(width <= 0 || height <= 0 || blur_dispersion <= 0.0)
      return;
   
   double sigma = MathSqrt(blur_dispersion);
   
   // Calculate kernel radius (3*sigma covers ~99.7% of distribution)
   int radius = (int)MathCeil(3.0 * sigma);
   if(radius < 1) radius = 1;
   
   int kernel_size = 2 * radius + 1;
   
   // Build 1D Gaussian kernel
   double kernel[];
   ArrayResize(kernel, kernel_size);
   
   double sum = 0.0;
   for(int i = 0; i < kernel_size; i++)
   {
      int x = i - radius;
      kernel[i] = MathExp(-(x * x) / (2.0 * blur_dispersion));
      sum += kernel[i];
   }
   
   // Normalize kernel
   for(int i = 0; i < kernel_size; i++)
      kernel[i] /= sum;
   
   // Temporary buffer
   uint temp[];
   ArrayResize(temp, ArraySize(bmp));
   ArrayCopy(temp, bmp);
   
   // Horizontal pass
   for(int y = 0; y < height; y++)
   {
      for(int x = 0; x < width; x++)
      {
         double r = 0.0, g = 0.0, b = 0.0, a = 0.0;
         
         for(int k = 0; k < kernel_size; k++)
         {
            int sample_x = x + k - radius;
            
            // Clamp to image bounds
            if(sample_x < 0) sample_x = 0;
            if(sample_x >= width) sample_x = width - 1;
            
            uint pixel = temp[y * width + sample_x];
            double weight = kernel[k];
            
            a += ((pixel >> 24) & 0xFF) * weight;
            r += ((pixel >> 16) & 0xFF) * weight;
            g += ((pixel >> 8) & 0xFF) * weight;
            b += (pixel & 0xFF) * weight;
         }
         
         bmp[y * width + x] = ((uint)a << 24) | ((uint)r << 16) | 
                               ((uint)g << 8) | (uint)b;
      }
   }
   
   // Copy for vertical pass
   ArrayCopy(temp, bmp);
   
   // Vertical pass
   for(int y = 0; y < height; y++)
   {
      for(int x = 0; x < width; x++)
      {
         double r = 0.0, g = 0.0, b = 0.0, a = 0.0;
         
         for(int k = 0; k < kernel_size; k++)
         {
            int sample_y = y + k - radius;
            
            // Clamp to image bounds
            if(sample_y < 0) sample_y = 0;
            if(sample_y >= height) sample_y = height - 1;
            
            uint pixel = temp[sample_y * width + x];
            double weight = kernel[k];
            
            a += ((pixel >> 24) & 0xFF) * weight;
            r += ((pixel >> 16) & 0xFF) * weight;
            g += ((pixel >> 8) & 0xFF) * weight;
            b += (pixel & 0xFF) * weight;
         }
         
         bmp[y * width + x] = ((uint)a << 24) | ((uint)r << 16) | 
                               ((uint)g << 8) | (uint)b;
      }
   }
}


MQL5 image blur function
  • claude.ai
Shared via Claude, an AI assistant from Anthropic
 
Nikolai Semko #:

вот попробовал спросить у claude.ai.
И что она мне ответила:
https://claude.ai/share/cad08fbb-2502-47bf-b99d-c325ee968609
вдруг ссылка в России не будет открываться, тогда вот код, который был сгенерирован, но я его не проверял. Проверьте сами пожалуйста:


ой, я забыл в задании сделать акцент, чтобы размытие было через альфаканал, чтобы не было артефактов при наложении с другим изображением. 
вот его исправленный вариант через альфа-канал(прозрачность)
void BlurBmp(uint &bmp[], int width, int height, double blur_dispersion)
{
   if(width <= 0 || height <= 0 || blur_dispersion <= 0.0)
      return;
   
   double sigma = MathSqrt(blur_dispersion);
   int radius = (int)MathCeil(3.0 * sigma);
   if(radius < 1) radius = 1;
   
   int kernel_size = 2 * radius + 1;
   
   double kernel[];
   ArrayResize(kernel, kernel_size);
   
   double sum = 0.0;
   for(int i = 0; i < kernel_size; i++)
   {
      int x = i - radius;
      kernel[i] = MathExp(-(x * x) / (2.0 * blur_dispersion));
      sum += kernel[i];
   }
   
   for(int i = 0; i < kernel_size; i++)
      kernel[i] /= sum;
   
   uint temp[];
   ArrayResize(temp, ArraySize(bmp));
   ArrayCopy(temp, bmp);
   
   // Horizontal pass with alpha weighting
   for(int y = 0; y < height; y++)
   {
      for(int x = 0; x < width; x++)
      {
         double r = 0.0, g = 0.0, b = 0.0, a = 0.0;
         double weight_sum = 0.0;
         
         for(int k = 0; k < kernel_size; k++)
         {
            int sample_x = x + k - radius;
            if(sample_x < 0) sample_x = 0;
            if(sample_x >= width) sample_x = width - 1;
            
            uint pixel = temp[y * width + sample_x];
            double kernel_weight = kernel[k];
            double alpha = ((pixel >> 24) & 0xFF) / 255.0;
            
            // Combined weight: kernel * alpha
            double total_weight = kernel_weight * alpha;
            
            r += ((pixel >> 16) & 0xFF) * total_weight;
            g += ((pixel >> 8) & 0xFF) * total_weight;
            b += (pixel & 0xFF) * total_weight;
            a += alpha * kernel_weight;
            
            weight_sum += total_weight;
         }
         
         // Normalize by accumulated weight
         if(weight_sum > 0.0001)
         {
            r /= weight_sum;
            g /= weight_sum;
            b /= weight_sum;
         }
         
         bmp[y * width + x] = ((uint)(a * 255.0) << 24) | 
                              ((uint)r << 16) | 
                              ((uint)g << 8) | 
                              (uint)b;
      }
   }
   
   ArrayCopy(temp, bmp);
   
   // Vertical pass with alpha weighting
   for(int y = 0; y < height; y++)
   {
      for(int x = 0; x < width; x++)
      {
         double r = 0.0, g = 0.0, b = 0.0, a = 0.0;
         double weight_sum = 0.0;
         
         for(int k = 0; k < kernel_size; k++)
         {
            int sample_y = y + k - radius;
            if(sample_y < 0) sample_y = 0;
            if(sample_y >= height) sample_y = height - 1;
            
            uint pixel = temp[sample_y * width + x];
            double kernel_weight = kernel[k];
            double alpha = ((pixel >> 24) & 0xFF) / 255.0;
            
            double total_weight = kernel_weight * alpha;
            
            r += ((pixel >> 16) & 0xFF) * total_weight;
            g += ((pixel >> 8) & 0xFF) * total_weight;
            b += (pixel & 0xFF) * total_weight;
            a += alpha * kernel_weight;
            
            weight_sum += total_weight;
         }
         
         if(weight_sum > 0.0001)
         {
            r /= weight_sum;
            g /= weight_sum;
            b /= weight_sum;
         }
         
         bmp[y * width + x] = ((uint)(a * 255.0) << 24) | 
                              ((uint)r << 16) | 
                              ((uint)g << 8) | 
                              (uint)b;
      }
   }
}
 

Лишняя строка, но впечатляет!


ОФФТОП.

Интересно, какой быстрый (критерий ниже) алгоритм был бы предложен для сжатия тиков: bid/ask/time_msc?

Форум по трейдингу, автоматическим торговым системам и тестированию торговых стратегий

Библиотеки: MathTicker - генератор тиков в математическом режиме

Forester, 2025.11.17 09:36

// Возвращает размер массива в байтах.
template <typename T>
ulong GetSize( const T &Array[] ) { return((ulong)sizeof(T) * ArraySize(Array)); }

template <typename T1, typename T2>
double Criterion( const T1 &Decompression[], const T2 &Compression[], const ulong Interval )
{
  const double Performance = (double)ArraySize(Decompression) / Interval;

  return(Performance * ((double)GetSize(Decompression) / GetSize(Compression)));
}

По ссылке текущий рекордсмен по декомпрессии (восстребована гораздо больше), созданный человеком.