forked from zjwzjw20062007/MQL5Book
		
	
		
			
	
	
		
			623 lines
		
	
	
	
		
			17 KiB
		
	
	
	
		
			MQL5
		
	
	
	
	
	
		
		
			
		
	
	
			623 lines
		
	
	
	
		
			17 KiB
		
	
	
	
		
			MQL5
		
	
	
	
	
	
| 
								 | 
							
								//+------------------------------------------------------------------+
							 | 
						||
| 
								 | 
							
								//|                                                ShapesDrawing.mqh |
							 | 
						||
| 
								 | 
							
								//|                              Copyright (c) 2022, MetaQuotes Ltd. |
							 | 
						||
| 
								 | 
							
								//|                                             https://www.mql5.com |
							 | 
						||
| 
								 | 
							
								//+------------------------------------------------------------------+
							 | 
						||
| 
								 | 
							
								#include "..\..\Include\AutoPtr.mqh"
							 | 
						||
| 
								 | 
							
								#include "..\..\Include\Defines.mqh"
							 | 
						||
| 
								 | 
							
								#include "..\..\Include\MqlError.mqh"
							 | 
						||
| 
								 | 
							
								#include "..\..\Include\TypeName.mqh"
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#define PROXIMITY 50 // drag hot-spot in pixels
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								//+------------------------------------------------------------------+
							 | 
						||
| 
								 | 
							
								//| Some of possible color mixing rules for overlapping Shapes       |
							 | 
						||
| 
								 | 
							
								//+------------------------------------------------------------------+
							 | 
						||
| 
								 | 
							
								enum COLOR_EFFECT
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								   PLAIN,
							 | 
						||
| 
								 | 
							
								   COMPLEMENT,
							 | 
						||
| 
								 | 
							
								   BLENDING_XOR,
							 | 
						||
| 
								 | 
							
								   DIMMING_SUM,
							 | 
						||
| 
								 | 
							
								   LIGHTEN_OR,
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								class Shape;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								//+------------------------------------------------------------------+
							 | 
						||
| 
								 | 
							
								//| Basic interface for drawing primitives                           |
							 | 
						||
| 
								 | 
							
								//+------------------------------------------------------------------+
							 | 
						||
| 
								 | 
							
								interface Drawing
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								   void point(const float x1, const float y1, const uint pixel);
							 | 
						||
| 
								 | 
							
								   void line(const int x1, const int y1, const int x2, const int y2, const color clr);
							 | 
						||
| 
								 | 
							
								   void rect(const int x1, const int y1, const int x2, const int y2, const color clr);
							 | 
						||
| 
								 | 
							
								   Shape *findAt(const int x, const int y, const Shape *priority = NULL);
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								//+------------------------------------------------------------------+
							 | 
						||
| 
								 | 
							
								//| Base shape class for drawing                                     |
							 | 
						||
| 
								 | 
							
								//+------------------------------------------------------------------+
							 | 
						||
| 
								 | 
							
								class Shape
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								public:
							 | 
						||
| 
								 | 
							
								   class Registrator
							 | 
						||
| 
								 | 
							
								   {
							 | 
						||
| 
								 | 
							
								      static Registrator *regs[];
							 | 
						||
| 
								 | 
							
								      int shapeCount;
							 | 
						||
| 
								 | 
							
								   public:
							 | 
						||
| 
								 | 
							
								      const string type;
							 | 
						||
| 
								 | 
							
								      Registrator(const string t) : type(t), shapeCount(0)
							 | 
						||
| 
								 | 
							
								      {
							 | 
						||
| 
								 | 
							
								         const int n = ArraySize(regs);
							 | 
						||
| 
								 | 
							
								         ArrayResize(regs, n + 1);
							 | 
						||
| 
								 | 
							
								         regs[n] = &this;
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								      
							 | 
						||
| 
								 | 
							
								      static int getTypeCount()
							 | 
						||
| 
								 | 
							
								      {
							 | 
						||
| 
								 | 
							
								         return ArraySize(regs);
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								      
							 | 
						||
| 
								 | 
							
								      static Registrator *get(const int i)
							 | 
						||
| 
								 | 
							
								      {
							 | 
						||
| 
								 | 
							
								         return regs[i];
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      int increment()
							 | 
						||
| 
								 | 
							
								      {
							 | 
						||
| 
								 | 
							
								         return ++shapeCount;
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								      
							 | 
						||
| 
								 | 
							
								      int getShapeCount() const
							 | 
						||
| 
								 | 
							
								      {
							 | 
						||
| 
								 | 
							
								         return shapeCount;
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								      
							 | 
						||
| 
								 | 
							
								      virtual Shape *create(const int px, const int py, const color back,
							 | 
						||
| 
								 | 
							
								         const int ¶meters[]) = 0;
							 | 
						||
| 
								 | 
							
								   };
							 | 
						||
| 
								 | 
							
								   
							 | 
						||
| 
								 | 
							
								protected:
							 | 
						||
| 
								 | 
							
								   int x, y;
							 | 
						||
| 
								 | 
							
								   color backgroundColor;
							 | 
						||
| 
								 | 
							
								   const string type;
							 | 
						||
| 
								 | 
							
								   string name;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								   Shape(int px, int py, color back, string t) :
							 | 
						||
| 
								 | 
							
								      x(px), y(py),
							 | 
						||
| 
								 | 
							
								      backgroundColor(back),
							 | 
						||
| 
								 | 
							
								      type(t)
							 | 
						||
| 
								 | 
							
								   {
							 | 
						||
| 
								 | 
							
								   }
							 | 
						||
| 
								 | 
							
								   
							 | 
						||
| 
								 | 
							
								public:
							 | 
						||
| 
								 | 
							
								   ~Shape()
							 | 
						||
| 
								 | 
							
								   {
							 | 
						||
| 
								 | 
							
								      ObjectDelete(0, name);
							 | 
						||
| 
								 | 
							
								   }
							 | 
						||
| 
								 | 
							
								   
							 | 
						||
| 
								 | 
							
								   virtual void draw(Drawing *drawing) = 0;
							 | 
						||
| 
								 | 
							
								   virtual void setup(const int ¶meters[]) = 0;
							 | 
						||
| 
								 | 
							
								   
							 | 
						||
| 
								 | 
							
								   virtual bool contains(const int _x, const int _y)
							 | 
						||
| 
								 | 
							
								   {
							 | 
						||
| 
								 | 
							
								      return fabs(x - _x) <= PROXIMITY && fabs(y - _y) <= PROXIMITY;
							 | 
						||
| 
								 | 
							
								   }
							 | 
						||
| 
								 | 
							
								   
							 | 
						||
| 
								 | 
							
								   // TODO: read from and write to a file
							 | 
						||
| 
								 | 
							
								   //virtual void load(const int handle) = 0;
							 | 
						||
| 
								 | 
							
								   //virtual void save(const int handle) = 0;
							 | 
						||
| 
								 | 
							
								   
							 | 
						||
| 
								 | 
							
								   Shape *setColor(const color c)
							 | 
						||
| 
								 | 
							
								   {
							 | 
						||
| 
								 | 
							
								      backgroundColor = c;
							 | 
						||
| 
								 | 
							
								      return &this;
							 | 
						||
| 
								 | 
							
								   }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								   Shape *moveX(const int _x)
							 | 
						||
| 
								 | 
							
								   {
							 | 
						||
| 
								 | 
							
								      x += _x;
							 | 
						||
| 
								 | 
							
								      return &this;
							 | 
						||
| 
								 | 
							
								   }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								   Shape *moveY(const int _y)
							 | 
						||
| 
								 | 
							
								   {
							 | 
						||
| 
								 | 
							
								      y += _y;
							 | 
						||
| 
								 | 
							
								      return &this;
							 | 
						||
| 
								 | 
							
								   }
							 | 
						||
| 
								 | 
							
								   
							 | 
						||
| 
								 | 
							
								   Shape *move(const int _x, const int _y)
							 | 
						||
| 
								 | 
							
								   {
							 | 
						||
| 
								 | 
							
								      x += _x;
							 | 
						||
| 
								 | 
							
								      y += _y;
							 | 
						||
| 
								 | 
							
								      return &this;
							 | 
						||
| 
								 | 
							
								   }
							 | 
						||
| 
								 | 
							
								   
							 | 
						||
| 
								 | 
							
								   virtual Shape *resize(const int _x, const int _y)
							 | 
						||
| 
								 | 
							
								   {
							 | 
						||
| 
								 | 
							
								      return &this;
							 | 
						||
| 
								 | 
							
								   }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								   string toString() const
							 | 
						||
| 
								 | 
							
								   {
							 | 
						||
| 
								 | 
							
								      return type + " " + (string)x + " " + (string)y + " " + (string)backgroundColor;
							 | 
						||
| 
								 | 
							
								   }
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								//+------------------------------------------------------------------+
							 | 
						||
| 
								 | 
							
								//| Templatized helper class for Shape-derived classes registration  |
							 | 
						||
| 
								 | 
							
								//+------------------------------------------------------------------+
							 | 
						||
| 
								 | 
							
								template<typename T>
							 | 
						||
| 
								 | 
							
								class MyRegistrator : public Shape::Registrator
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								public:
							 | 
						||
| 
								 | 
							
								   MyRegistrator() : Registrator(TYPENAME(T))
							 | 
						||
| 
								 | 
							
								   {
							 | 
						||
| 
								 | 
							
								   }
							 | 
						||
| 
								 | 
							
								   
							 | 
						||
| 
								 | 
							
								   virtual Shape *create(const int px, const int py, const color back,
							 | 
						||
| 
								 | 
							
								      const int ¶meters[]) override
							 | 
						||
| 
								 | 
							
								   {
							 | 
						||
| 
								 | 
							
								      T *temp = new T(px, py, back);
							 | 
						||
| 
								 | 
							
								      temp.setup(parameters);
							 | 
						||
| 
								 | 
							
								      return temp;
							 | 
						||
| 
								 | 
							
								   }
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								//+------------------------------------------------------------------+
							 | 
						||
| 
								 | 
							
								//| Rectangle shape                                                  |
							 | 
						||
| 
								 | 
							
								//+------------------------------------------------------------------+
							 | 
						||
| 
								 | 
							
								class Rectangle : public Shape
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								   static MyRegistrator<Rectangle> r;
							 | 
						||
| 
								 | 
							
								   
							 | 
						||
| 
								 | 
							
								protected:
							 | 
						||
| 
								 | 
							
								   int dx, dy; // size (width, height)
							 | 
						||
| 
								 | 
							
								   
							 | 
						||
| 
								 | 
							
								   Rectangle(int px, int py, color back, string t) :
							 | 
						||
| 
								 | 
							
								      Shape(px, py, back, t), dx(1), dy(1)
							 | 
						||
| 
								 | 
							
								   {
							 | 
						||
| 
								 | 
							
								   }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								public:
							 | 
						||
| 
								 | 
							
								   Rectangle(int px, int py, color back) :
							 | 
						||
| 
								 | 
							
								      Shape(px, py, back, TYPENAME(this)), dx(1), dy(1)
							 | 
						||
| 
								 | 
							
								   {
							 | 
						||
| 
								 | 
							
								      name = TYPENAME(this) + (string)r.increment();
							 | 
						||
| 
								 | 
							
								   }
							 | 
						||
| 
								 | 
							
								   
							 | 
						||
| 
								 | 
							
								   virtual void setup(const int ¶meters[]) override
							 | 
						||
| 
								 | 
							
								   {
							 | 
						||
| 
								 | 
							
								      if(ArraySize(parameters) < 2)
							 | 
						||
| 
								 | 
							
								      {
							 | 
						||
| 
								 | 
							
								         Print("Insufficient parameters for Rectangle");
							 | 
						||
| 
								 | 
							
								         return;
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								      dx = parameters[0];
							 | 
						||
| 
								 | 
							
								      dy = parameters[1];
							 | 
						||
| 
								 | 
							
								   }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								   virtual void draw(Drawing *drawing) override
							 | 
						||
| 
								 | 
							
								   {
							 | 
						||
| 
								 | 
							
								      drawing.rect(x - dx / 2, y - dx / 2, x + dx / 2, y + dy / 2, backgroundColor);
							 | 
						||
| 
								 | 
							
								   }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								   virtual Shape *resize(const int _x, const int _y) override
							 | 
						||
| 
								 | 
							
								   {
							 | 
						||
| 
								 | 
							
								      dx += _x;
							 | 
						||
| 
								 | 
							
								      dy += _y;
							 | 
						||
| 
								 | 
							
								      if(dx < 0) dx = -dx;
							 | 
						||
| 
								 | 
							
								      if(dy < 0) dy = -dy;
							 | 
						||
| 
								 | 
							
								      return &this;
							 | 
						||
| 
								 | 
							
								   }
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								//+------------------------------------------------------------------+
							 | 
						||
| 
								 | 
							
								//| Square shape                                                     |
							 | 
						||
| 
								 | 
							
								//+------------------------------------------------------------------+
							 | 
						||
| 
								 | 
							
								class Square : public Rectangle
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								   static MyRegistrator<Square> r;
							 | 
						||
| 
								 | 
							
								public:
							 | 
						||
| 
								 | 
							
								   Square(int px, int py, color back) :
							 | 
						||
| 
								 | 
							
								      Rectangle(px, py, back, TYPENAME(this))
							 | 
						||
| 
								 | 
							
								   {
							 | 
						||
| 
								 | 
							
								      name = TYPENAME(this) + (string)r.increment();
							 | 
						||
| 
								 | 
							
								   }
							 | 
						||
| 
								 | 
							
								   
							 | 
						||
| 
								 | 
							
								   virtual void setup(const int ¶meters[]) override
							 | 
						||
| 
								 | 
							
								   {
							 | 
						||
| 
								 | 
							
								      if(ArraySize(parameters) < 1)
							 | 
						||
| 
								 | 
							
								      {
							 | 
						||
| 
								 | 
							
								         Print("Insufficient parameters for Square");
							 | 
						||
| 
								 | 
							
								         return;
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								      dx = dy = parameters[0];
							 | 
						||
| 
								 | 
							
								   }
							 | 
						||
| 
								 | 
							
								   
							 | 
						||
| 
								 | 
							
								   void draw(Drawing *drawing) override
							 | 
						||
| 
								 | 
							
								   {
							 | 
						||
| 
								 | 
							
								      Rectangle::draw(drawing);
							 | 
						||
| 
								 | 
							
								   }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								   virtual Shape *resize(const int _x, const int _y) override
							 | 
						||
| 
								 | 
							
								   {
							 | 
						||
| 
								 | 
							
								      const int d = _x + _y;
							 | 
						||
| 
								 | 
							
								      dx += d;
							 | 
						||
| 
								 | 
							
								      dy += d;
							 | 
						||
| 
								 | 
							
								      if(dx < 0) dx = -dx;
							 | 
						||
| 
								 | 
							
								      if(dy < 0) dy = -dy;
							 | 
						||
| 
								 | 
							
								      return &this;
							 | 
						||
| 
								 | 
							
								   }
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								//+------------------------------------------------------------------+
							 | 
						||
| 
								 | 
							
								//| Ellipse shape                                                    |
							 | 
						||
| 
								 | 
							
								//+------------------------------------------------------------------+
							 | 
						||
| 
								 | 
							
								class Ellipse : public Shape
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								   static MyRegistrator<Ellipse> r;
							 | 
						||
| 
								 | 
							
								protected:
							 | 
						||
| 
								 | 
							
								   int dx, dy; // large and small radiuses
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								   Ellipse(int px, int py, color back, string t) :
							 | 
						||
| 
								 | 
							
								      Shape(px, py, back, t), dx(1), dy(1)
							 | 
						||
| 
								 | 
							
								   {
							 | 
						||
| 
								 | 
							
								   }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								public:
							 | 
						||
| 
								 | 
							
								   Ellipse(int px, int py, color back) :
							 | 
						||
| 
								 | 
							
								      Shape(px, py, back, TYPENAME(this)), dx(1), dy(1)
							 | 
						||
| 
								 | 
							
								   {
							 | 
						||
| 
								 | 
							
								      name = TYPENAME(this) + (string)r.increment();
							 | 
						||
| 
								 | 
							
								   }
							 | 
						||
| 
								 | 
							
								   
							 | 
						||
| 
								 | 
							
								   virtual void setup(const int ¶meters[]) override
							 | 
						||
| 
								 | 
							
								   {
							 | 
						||
| 
								 | 
							
								      if(ArraySize(parameters) < 2)
							 | 
						||
| 
								 | 
							
								      {
							 | 
						||
| 
								 | 
							
								         Print("Insufficient parameters for Ellipse");
							 | 
						||
| 
								 | 
							
								         return;
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								      dx = parameters[0]; // first radius
							 | 
						||
| 
								 | 
							
								      dy = parameters[1]; // second radius
							 | 
						||
| 
								 | 
							
								   }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								   void draw(Drawing *drawing) override
							 | 
						||
| 
								 | 
							
								   {
							 | 
						||
| 
								 | 
							
								      // (x, y) is a center
							 | 
						||
| 
								 | 
							
								      // p0: x + dx, y
							 | 
						||
| 
								 | 
							
								      // p1: x - dx, y
							 | 
						||
| 
								 | 
							
								      // p2: x, y + dy
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      const int hh = dy * dy;
							 | 
						||
| 
								 | 
							
								      const int ww = dx * dx;
							 | 
						||
| 
								 | 
							
								      const int hhww = hh * ww;
							 | 
						||
| 
								 | 
							
								      int x0 = dx;
							 | 
						||
| 
								 | 
							
								      int step = 0;
							 | 
						||
| 
								 | 
							
								      
							 | 
						||
| 
								 | 
							
								      // main horizontal diameter
							 | 
						||
| 
								 | 
							
								      drawing.line(x - dx, y, x + dx, y, backgroundColor);
							 | 
						||
| 
								 | 
							
								      
							 | 
						||
| 
								 | 
							
								      // smaller horizontal lines in upper and lower halves keep symmetry
							 | 
						||
| 
								 | 
							
								      for(int j = 1; j <= dy; j++)
							 | 
						||
| 
								 | 
							
								      {
							 | 
						||
| 
								 | 
							
								         for(int x1 = x0 - (step - 1); x1 > 0; --x1)
							 | 
						||
| 
								 | 
							
								         {
							 | 
						||
| 
								 | 
							
								            if(x1 * x1 * hh + j * j * ww <= hhww)
							 | 
						||
| 
								 | 
							
								            {
							 | 
						||
| 
								 | 
							
								               step = x0 - x1;
							 | 
						||
| 
								 | 
							
								               break;
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								         }
							 | 
						||
| 
								 | 
							
								         x0 -= step;
							 | 
						||
| 
								 | 
							
								         
							 | 
						||
| 
								 | 
							
								         drawing.line(x - x0, y - j, x + x0, y - j, backgroundColor);
							 | 
						||
| 
								 | 
							
								         drawing.line(x - x0, y + j, x + x0, y + j, backgroundColor);
							 | 
						||
| 
								 | 
							
								         // TODO: edge smoothing by xx
							 | 
						||
| 
								 | 
							
								         // float xx = (float)sqrt((hhww - j * j * ww) / hh);
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								   }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								   virtual Shape *resize(const int _x, const int _y) override
							 | 
						||
| 
								 | 
							
								   {
							 | 
						||
| 
								 | 
							
								      dx += _x;
							 | 
						||
| 
								 | 
							
								      dy += _y;
							 | 
						||
| 
								 | 
							
								      if(dx < 0) dx = -dx;
							 | 
						||
| 
								 | 
							
								      if(dy < 0) dy = -dy;
							 | 
						||
| 
								 | 
							
								      return &this;
							 | 
						||
| 
								 | 
							
								   }
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								//+------------------------------------------------------------------+
							 | 
						||
| 
								 | 
							
								//| Circle shape                                                     |
							 | 
						||
| 
								 | 
							
								//+------------------------------------------------------------------+
							 | 
						||
| 
								 | 
							
								class Circle : public Ellipse
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								   static MyRegistrator<Circle> r;
							 | 
						||
| 
								 | 
							
								public:
							 | 
						||
| 
								 | 
							
								   Circle(int px, int py, color back) :
							 | 
						||
| 
								 | 
							
								      Ellipse(px, py, back, TYPENAME(this))
							 | 
						||
| 
								 | 
							
								   {
							 | 
						||
| 
								 | 
							
								      name = TYPENAME(this) + (string)r.increment();
							 | 
						||
| 
								 | 
							
								   }
							 | 
						||
| 
								 | 
							
								   
							 | 
						||
| 
								 | 
							
								   virtual void setup(const int ¶meters[]) override
							 | 
						||
| 
								 | 
							
								   {
							 | 
						||
| 
								 | 
							
								      if(ArraySize(parameters) < 1)
							 | 
						||
| 
								 | 
							
								      {
							 | 
						||
| 
								 | 
							
								         Print("Insufficient parameters for Circle");
							 | 
						||
| 
								 | 
							
								         return;
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								      dx = dy = parameters[0];
							 | 
						||
| 
								 | 
							
								   }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								   void draw(Drawing *drawing) override
							 | 
						||
| 
								 | 
							
								   {
							 | 
						||
| 
								 | 
							
								      Ellipse::draw(drawing);
							 | 
						||
| 
								 | 
							
								   }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								   virtual Shape *resize(const int _x, const int _y) override
							 | 
						||
| 
								 | 
							
								   {
							 | 
						||
| 
								 | 
							
								      const int d = _x + _y;
							 | 
						||
| 
								 | 
							
								      dx += d;
							 | 
						||
| 
								 | 
							
								      dy += d;
							 | 
						||
| 
								 | 
							
								      if(dx < 0) dx = -dx;
							 | 
						||
| 
								 | 
							
								      if(dy < 0) dy = -dy;
							 | 
						||
| 
								 | 
							
								      return &this;
							 | 
						||
| 
								 | 
							
								   }
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								//+------------------------------------------------------------------+
							 | 
						||
| 
								 | 
							
								//| Triangle shape                                                   |
							 | 
						||
| 
								 | 
							
								//+------------------------------------------------------------------+
							 | 
						||
| 
								 | 
							
								class Triangle: public Shape
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								   static MyRegistrator<Triangle> r;
							 | 
						||
| 
								 | 
							
								protected:
							 | 
						||
| 
								 | 
							
								   int dx;  // single side (equilateral)
							 | 
						||
| 
								 | 
							
								public:
							 | 
						||
| 
								 | 
							
								   Triangle(int px, int py, color back) :
							 | 
						||
| 
								 | 
							
								      Shape(px, py, back, TYPENAME(this)), dx(1)
							 | 
						||
| 
								 | 
							
								   {
							 | 
						||
| 
								 | 
							
								      name = TYPENAME(this) + (string)r.increment();
							 | 
						||
| 
								 | 
							
								   }
							 | 
						||
| 
								 | 
							
								   
							 | 
						||
| 
								 | 
							
								   virtual void setup(const int ¶meters[]) override
							 | 
						||
| 
								 | 
							
								   {
							 | 
						||
| 
								 | 
							
								      if(ArraySize(parameters) < 1)
							 | 
						||
| 
								 | 
							
								      {
							 | 
						||
| 
								 | 
							
								         Print("Insufficient parameters for Triangle");
							 | 
						||
| 
								 | 
							
								         return;
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								      dx = parameters[0];
							 | 
						||
| 
								 | 
							
								   }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								   virtual void draw(Drawing *drawing) override
							 | 
						||
| 
								 | 
							
								   {
							 | 
						||
| 
								 | 
							
								      if(dx <= 3)
							 | 
						||
| 
								 | 
							
								      {
							 | 
						||
| 
								 | 
							
								         drawing.point(x, y, ColorToARGB(backgroundColor));
							 | 
						||
| 
								 | 
							
								         return;
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								      
							 | 
						||
| 
								 | 
							
								      // (x, y) is a center
							 | 
						||
| 
								 | 
							
								      // R = a * sqrt(3) / 3
							 | 
						||
| 
								 | 
							
								      // p0: x, y + R
							 | 
						||
| 
								 | 
							
								      // p1: x - R * cos(30), y - R * sin(30)
							 | 
						||
| 
								 | 
							
								      // p2: x + R * cos(30), y - R * sin(30)
							 | 
						||
| 
								 | 
							
								      // height by Pythagorean theorem: dx * dx = dx * dx / 4 + h * h
							 | 
						||
| 
								 | 
							
								      // sqrt(dx * dx * 3/4) = h
							 | 
						||
| 
								 | 
							
								      const double R = dx * sqrt(3) / 3;
							 | 
						||
| 
								 | 
							
								      const double H = sqrt(dx * dx * 3 / 4);
							 | 
						||
| 
								 | 
							
								      const double angle = H / (dx / 2);
							 | 
						||
| 
								 | 
							
								      
							 | 
						||
| 
								 | 
							
								      // main vertical line (triangle height)
							 | 
						||
| 
								 | 
							
								      const int base = y + (int)(R - H);
							 | 
						||
| 
								 | 
							
								      drawing.line(x, y + (int)R, x, base, backgroundColor);
							 | 
						||
| 
								 | 
							
								      
							 | 
						||
| 
								 | 
							
								      // go left and right sideways with shorter vertical lines, with symmetry
							 | 
						||
| 
								 | 
							
								      for(int j = 1; j <= dx / 2; ++j)
							 | 
						||
| 
								 | 
							
								      {
							 | 
						||
| 
								 | 
							
								         drawing.line(x - j, y + (int)(R - angle * j), x - j, base, backgroundColor);
							 | 
						||
| 
								 | 
							
								         drawing.line(x + j, y + (int)(R - angle * j), x + j, base, backgroundColor);
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								   }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								   virtual Shape *resize(const int _x, const int _y) override
							 | 
						||
| 
								 | 
							
								   {
							 | 
						||
| 
								 | 
							
								      const int d = _x + _y;
							 | 
						||
| 
								 | 
							
								      dx += d;
							 | 
						||
| 
								 | 
							
								      if(dx < 0) dx = -dx;
							 | 
						||
| 
								 | 
							
								      return &this;
							 | 
						||
| 
								 | 
							
								   }
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								//+------------------------------------------------------------------+
							 | 
						||
| 
								 | 
							
								//| Our implementation of Drawing interface based on bitmap resource |
							 | 
						||
| 
								 | 
							
								//+------------------------------------------------------------------+
							 | 
						||
| 
								 | 
							
								class MyDrawing: public Drawing
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								   const string sheet;  // resource
							 | 
						||
| 
								 | 
							
								   uint data[];
							 | 
						||
| 
								 | 
							
								   int width, height;
							 | 
						||
| 
								 | 
							
								   AutoPtr<Shape> shapes[];
							 | 
						||
| 
								 | 
							
								   const uint bg;
							 | 
						||
| 
								 | 
							
								   COLOR_EFFECT xormode;
							 | 
						||
| 
								 | 
							
								   bool smoothing;
							 | 
						||
| 
								 | 
							
								   
							 | 
						||
| 
								 | 
							
								public:
							 | 
						||
| 
								 | 
							
								   MyDrawing(const string resource, uint &array[], const int w, const int h, const uint clr):
							 | 
						||
| 
								 | 
							
								      sheet(resource), width(w), height(h), bg(clr),
							 | 
						||
| 
								 | 
							
								      xormode(PLAIN), smoothing(false)
							 | 
						||
| 
								 | 
							
								   {
							 | 
						||
| 
								 | 
							
								      ArraySwap(data, array);
							 | 
						||
| 
								 | 
							
								   }
							 | 
						||
| 
								 | 
							
								   
							 | 
						||
| 
								 | 
							
								   ~MyDrawing()
							 | 
						||
| 
								 | 
							
								   {
							 | 
						||
| 
								 | 
							
								      ResourceFree(sheet);
							 | 
						||
| 
								 | 
							
								   }
							 | 
						||
| 
								 | 
							
								   
							 | 
						||
| 
								 | 
							
								   void resize(const int w, const int h)
							 | 
						||
| 
								 | 
							
								   {
							 | 
						||
| 
								 | 
							
								      width = w;
							 | 
						||
| 
								 | 
							
								      height = h;
							 | 
						||
| 
								 | 
							
								      ArrayResize(data, w * h);
							 | 
						||
| 
								 | 
							
								   }
							 | 
						||
| 
								 | 
							
								   
							 | 
						||
| 
								 | 
							
								   string resource() const
							 | 
						||
| 
								 | 
							
								   {
							 | 
						||
| 
								 | 
							
								      return sheet;
							 | 
						||
| 
								 | 
							
								   }
							 | 
						||
| 
								 | 
							
								   
							 | 
						||
| 
								 | 
							
								   Shape *push(Shape *shape)
							 | 
						||
| 
								 | 
							
								   {
							 | 
						||
| 
								 | 
							
								      shapes[EXPAND(shapes)] = shape;
							 | 
						||
| 
								 | 
							
								      return shape;
							 | 
						||
| 
								 | 
							
								   }
							 | 
						||
| 
								 | 
							
								   
							 | 
						||
| 
								 | 
							
								   void setColorEffect(const COLOR_EFFECT x)
							 | 
						||
| 
								 | 
							
								   {
							 | 
						||
| 
								 | 
							
								      xormode = x;
							 | 
						||
| 
								 | 
							
								   }
							 | 
						||
| 
								 | 
							
								   
							 | 
						||
| 
								 | 
							
								   void draw(const bool refresh = false)
							 | 
						||
| 
								 | 
							
								   {
							 | 
						||
| 
								 | 
							
								      if(refresh)
							 | 
						||
| 
								 | 
							
								      {
							 | 
						||
| 
								 | 
							
								         ArrayInitialize(data, bg);
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								      for(int i = 0; i < ArraySize(shapes); ++i)
							 | 
						||
| 
								 | 
							
								      {
							 | 
						||
| 
								 | 
							
								         shapes[i][].draw(&this);
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								      ResourceCreate(sheet, data, width, height, 0, 0, width, COLOR_FORMAT_ARGB_NORMALIZE);
							 | 
						||
| 
								 | 
							
								      ChartRedraw();
							 | 
						||
| 
								 | 
							
								   }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								   void _point(const int x1, const int y1, const uint pixel)
							 | 
						||
| 
								 | 
							
								   {
							 | 
						||
| 
								 | 
							
								      const int index = y1 * width + x1;
							 | 
						||
| 
								 | 
							
								      if(index >= 0 && index < ArraySize(data))
							 | 
						||
| 
								 | 
							
								      {
							 | 
						||
| 
								 | 
							
								         switch(xormode)
							 | 
						||
| 
								 | 
							
								         {
							 | 
						||
| 
								 | 
							
								         case COMPLEMENT:
							 | 
						||
| 
								 | 
							
								            data[index] = (pixel ^ (1 - data[index])); // complementary
							 | 
						||
| 
								 | 
							
								            break;
							 | 
						||
| 
								 | 
							
								         case BLENDING_XOR:
							 | 
						||
| 
								 | 
							
								            data[index] = (pixel & 0xFF000000) | (pixel ^ data[index]); // blending (XOR)
							 | 
						||
| 
								 | 
							
								            break;
							 | 
						||
| 
								 | 
							
								         case DIMMING_SUM:
							 | 
						||
| 
								 | 
							
								            data[index] =  (pixel + data[index]); // dimming (SUM)
							 | 
						||
| 
								 | 
							
								            break;
							 | 
						||
| 
								 | 
							
								         case LIGHTEN_OR:
							 | 
						||
| 
								 | 
							
								            data[index] =  (pixel & 0xFF000000) | (pixel | data[index]); // lighten (OR)
							 | 
						||
| 
								 | 
							
								            break;
							 | 
						||
| 
								 | 
							
								         case PLAIN:
							 | 
						||
| 
								 | 
							
								         default:
							 | 
						||
| 
								 | 
							
								            data[index] = pixel;
							 | 
						||
| 
								 | 
							
								         }
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								   }
							 | 
						||
| 
								 | 
							
								   
							 | 
						||
| 
								 | 
							
								   virtual void point(const float x1, const float y1, const uint pixel) override
							 | 
						||
| 
								 | 
							
								   {
							 | 
						||
| 
								 | 
							
								      const int x_main = (int)MathRound(x1);
							 | 
						||
| 
								 | 
							
								      const int y_main = (int)MathRound(y1);
							 | 
						||
| 
								 | 
							
								      _point(x_main, y_main, pixel);
							 | 
						||
| 
								 | 
							
								      
							 | 
						||
| 
								 | 
							
								      if(smoothing) // test implementation of antialiasing (used in diagonal lines)
							 | 
						||
| 
								 | 
							
								      {
							 | 
						||
| 
								 | 
							
								         const int factorx = (int)((x1 - x_main) * 255);
							 | 
						||
| 
								 | 
							
								         if(fabs(factorx) >= 10)
							 | 
						||
| 
								 | 
							
								         {
							 | 
						||
| 
								 | 
							
								            _point(x_main + factorx / fabs(factorx), y_main, ((int)fabs(factorx) << 24) | (pixel & 0xFFFFFF));
							 | 
						||
| 
								 | 
							
								         }
							 | 
						||
| 
								 | 
							
								         const int factory = (int)((y1 - y_main) * 255);
							 | 
						||
| 
								 | 
							
								         if(fabs(factory) >= 10)
							 | 
						||
| 
								 | 
							
								         {
							 | 
						||
| 
								 | 
							
								            _point(x_main, y_main + factory / fabs(factory), ((int)fabs(factory) << 24) | (pixel & 0xFFFFFF));
							 | 
						||
| 
								 | 
							
								         }
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								   }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								   virtual void line(const int x1, const int y1, const int x2, const int y2, const color clr) override
							 | 
						||
| 
								 | 
							
								   {
							 | 
						||
| 
								 | 
							
								      if(x1 == x2) rect(x1, y1, x1, y2, clr);
							 | 
						||
| 
								 | 
							
								      else if(y1 == y2) rect(x1, y1, x2, y1, clr);
							 | 
						||
| 
								 | 
							
								      else
							 | 
						||
| 
								 | 
							
								      {
							 | 
						||
| 
								 | 
							
								         smoothing = true;
							 | 
						||
| 
								 | 
							
								         const uint pixel = ColorToARGB(clr);
							 | 
						||
| 
								 | 
							
								         double angle = 1.0 * (y2 - y1) / (x2 - x1);
							 | 
						||
| 
								 | 
							
								         if(fabs(angle) < 1) // step by larger axis, that is x
							 | 
						||
| 
								 | 
							
								         {
							 | 
						||
| 
								 | 
							
								            const int sign = x2 > x1 ? +1 : -1;
							 | 
						||
| 
								 | 
							
								            for(int i = 0; i <= fabs(x2 - x1); ++i)
							 | 
						||
| 
								 | 
							
								            {
							 | 
						||
| 
								 | 
							
								               const float p = (float)(y1 + sign * i * angle);
							 | 
						||
| 
								 | 
							
								               point(x1 + sign * i, p, pixel);
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								         }
							 | 
						||
| 
								 | 
							
								         else // step by y
							 | 
						||
| 
								 | 
							
								         {
							 | 
						||
| 
								 | 
							
								            const int sign = y2 > y1 ? +1 : -1;
							 | 
						||
| 
								 | 
							
								            for(int i = 0; i <= fabs(y2 - y1); ++i)
							 | 
						||
| 
								 | 
							
								            {
							 | 
						||
| 
								 | 
							
								               const float p = (float)(x1 + sign * i / angle);
							 | 
						||
| 
								 | 
							
								               point(p, y1 + sign * i, pixel);
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								         }
							 | 
						||
| 
								 | 
							
								         smoothing = false;
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								   }
							 | 
						||
| 
								 | 
							
								   
							 | 
						||
| 
								 | 
							
								   virtual void rect(const int x1, const int y1, const int x2, const int y2, const color clr) override
							 | 
						||
| 
								 | 
							
								   {
							 | 
						||
| 
								 | 
							
								      // line(x1, y1, x2, y2, clr); // debug
							 | 
						||
| 
								 | 
							
								      const uint pixel = ColorToARGB(clr);
							 | 
						||
| 
								 | 
							
								      for(int i = fmin(x1, x2); i <= fmax(x1, x2); ++i)
							 | 
						||
| 
								 | 
							
								      {
							 | 
						||
| 
								 | 
							
								         for(int j = fmin(y1, y2); j <= fmax(y1, y2); ++j)
							 | 
						||
| 
								 | 
							
								         {
							 | 
						||
| 
								 | 
							
								            point(i, j, pixel);
							 | 
						||
| 
								 | 
							
								         }
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								   }
							 | 
						||
| 
								 | 
							
								   
							 | 
						||
| 
								 | 
							
								   virtual Shape *findAt(const int x, const int y, const Shape *priority = NULL) override
							 | 
						||
| 
								 | 
							
								   {
							 | 
						||
| 
								 | 
							
								      Shape *result = NULL;
							 | 
						||
| 
								 | 
							
								      for(int i = 0; i < ArraySize(shapes); ++i)
							 | 
						||
| 
								 | 
							
								      {
							 | 
						||
| 
								 | 
							
								         if(shapes[i][].contains(x, y))
							 | 
						||
| 
								 | 
							
								         {
							 | 
						||
| 
								 | 
							
								            if(priority == shapes[i][])
							 | 
						||
| 
								 | 
							
								            {
							 | 
						||
| 
								 | 
							
								               return (Shape *)priority;
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								            else
							 | 
						||
| 
								 | 
							
								            {
							 | 
						||
| 
								 | 
							
								               result = shapes[i][];
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								         }
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								      return result;
							 | 
						||
| 
								 | 
							
								   }
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								//+------------------------------------------------------------------+
							 | 
						||
| 
								 | 
							
								//| Static in-class variables (Shape classes self-registration)      |
							 | 
						||
| 
								 | 
							
								//+------------------------------------------------------------------+
							 | 
						||
| 
								 | 
							
								static Shape::Registrator *Shape::Registrator::regs[] = {};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								static MyRegistrator<Rectangle> Rectangle::r;
							 | 
						||
| 
								 | 
							
								static MyRegistrator<Square> Square::r;
							 | 
						||
| 
								 | 
							
								static MyRegistrator<Ellipse> Ellipse::r;
							 | 
						||
| 
								 | 
							
								static MyRegistrator<Circle> Circle::r;
							 | 
						||
| 
								 | 
							
								static MyRegistrator<Triangle> Triangle::r;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								//+------------------------------------------------------------------+
							 |