Рисование геометрических фигур на TFT дисплее, на примере SSD1289.

Рисование геометрических фигур на TFT дисплее, на примере SSD1289.

В прошлой статье мы научились выводить на TFT дисплей символы и строки, в этой будем учиться рисовать геометрические фигуры. Геометрических фигур, которые могут пригодиться при создании графического интерфейса, не так уж много, основные из них, это прямоугольник и круг именно их мы и будем учиться рисовать, в двух вариантах закрашенные и не закрашенные. Скажу сразу, что в статье подробно будут описаны алгоритмы рисования лишь некоторых геометрических фигур, чего должно хватить для понимания общих принципов построения растрового изображения. Начнём с самой простой фигуры — закрашенного прямоугольника.
Из прошлой статьи мы помним, что если задать координаты точки, затем просто отправлять цвет, то SSD1289 сам по выбранному, при инициализации алгоритму, будет закрашивать точки. Но в этом случае есть одна особенность, контроллер переходит на следующую строку, только когда достигает конца текущей строки.
Нарисовать закрашенный прямоугольник, нам помогут следующие регистры.
Рисование геометрических фигур на TFT дисплее, на примере SSD1289.

С помощью этих регистров мы можем задать начало и конец области, в которую будем писать, затем в цикле, нужное количество раз, отправим цвет, а контроллер все сделает сам, по заданному при инициализации алгоритму. Но теперь он будет переходить на следующую строку, когда достигнет конца, указанной нами области.
Для записи границ области по Х, предназначен один регистр R44, а для записи границ по Y - два регистра R45 и R46. Давайте описанное выше оформим в виде функции, для удобства, код, который отвечает за выделение рабочей области, вынесем в отдельную функцию Set_Work_Area().

void Set_Work_Area(uint16_t y1, uint16_t x1, uint16_t x2, uint16_t y2)
{
	
	Lcd_Write_Reg(0x0044,((x2 << 8) | x1));
	Lcd_Write_Reg(0x0045,y1);
	Lcd_Write_Reg(0x0046,y2);
	Set_Cursor(x1, y1);
}
///////////////////////////////////////
void Draw_Area(uint16_t left, uint16_t top, uint16_t right, uint16_t bottom, uint16_t color)
{
	register uint16_t x,y;
	Set_Work_Area(left, top, right, bottom);
	
	for(y=top; y<=bottom; y++)
	{
		for(x=left; x<=right; x++)
		{
			Lcd_Write_Data(color);
	        }
	}	
	Set_Work_Area(0, 0, 319, 239);
}

Рисование геометрических фигур на TFT дисплее, на примере SSD1289.

Теперь когда мы научились рисовать закрашенный прямоугольник, давайте попробуем нарисовать не закрашенный. Но для этого нам сначала необходимо научиться рисовать линии. С помощью знаний, которыми мы уже обладаем, мы легко можем нарисовать горизонтальную или вертикальную линию, но не линию, расположенную под углом к горизонту. Для построения линии, расположенной под углом к горизонту мы воспользуемся растровым алгоритмом Брезенхема, вернее, его модификацией. Дело в том что изначально алгоритм, содержит в себе деление и операции с плавающей точкой, чего нам, при написании прошивки для микроконтроллера хотелось бы избежать. Как это сделать можно почитать в википедии.
Если коротко, то принцип работы алгоритма Брезенхема заключается в следующем, мы берём отрезок с начальной координатой х и у. К иксу в цикле прибавляем по единичке в направлении конца отрезка, при этом на каждом шаге вычисляем ошибку — расстояние между реальной координатой в этом месте и ближайшей ячейкой сетки. Если ошибка не превышает половину высоты ячейки, то мы её закрашиваем.

Рисование геометрических фигур на TFT дисплее, на примере SSD1289.

На картинке выше жёлтым цветом показана линия до растеризации, зелёным и красным — расстояние до центров ближайших ячеек.
А вот и код для рисования линии.

void Draw_Line (uint8_t size,uint16_t x1,uint16_t y1,uint16_t x2,uint16_t y2,uint16_t color)
{
	int deltaX = abs(x2 - x1);
	int deltaY = abs(y2 - y1);
	int signX = x1 < x2 ? 1 : -1;
	int signY = y1 < y2 ? 1 : -1;
	int error = deltaX - deltaY;
	
	for (;;)
	{
		Draw_Point(size,x1,y1,color);
		
		if(x1 == x2 && y1 == y2)
		break;
		
		int error2 = error * 2;
		
		if(error2 > -deltaY)
		{
			error -= deltaY;
			x1 += signX;
		}
		
		if(error2 < deltaX)
		{
			error += deltaX;
			y1 += signY;
		}
	}
}

Для того чтобы нарисовать прямоугольник нам понадобится 4 линии, для удобства вынесем в отдельные функции рисование горизонтальных и вертикальных линий,

void Draw_Horizont_Line(uint8_t size,uint16_t x1,uint16_t y1,uint16_t y2,uint16_t color)
{
	Draw_Line( size, x1, y1, x1, y2, color);
}
///////////////////////////////
void Draw_Vertical_Line(uint8_t size,uint16_t x1,uint16_t x2,uint16_t y1,uint16_t color)
{
	Draw_Line( size, x1, y1, x2, y1, color);
}
///////////////////////////////
void Draw_Reactangle(uint8_t size,uint16_t left,uint16_t top,uint16_t right,uint16_t bottom,uint16_t color)
{
	Draw_Horizont_Line( size, top, left, right, color);
	Draw_Horizont_Line( size, bottom, left, right, color);
	Draw_Vertical_Line( size, top, bottom, left, color);
	Draw_Vertical_Line( size, top, bottom, right, color);
		
}

Рисование геометрических фигур на TFT дисплее, на примере SSD1289.

А для того чтобы нарисовать треугольник потребуется всего 3 линии)))

void Draw_Triangle( uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint16_t x3, uint16_t y3, uint8_t size, uint16_t color)
{
	Draw_Line(size, x1, y1, x2, y2, color);
	Draw_Line(size, x2, y2, x3, y3, color);
	Draw_Line(size, x3, y3, x1, y1, color);
}

Рисование геометрических фигур на TFT дисплее, на примере SSD1289.

По алгоритму Брезенхема также можно построить окружность. На каждом шаге алгоритма, рассматриваются три точки и более подходящая находится путём сравнения расстояния от центра окружности до выбранной точки с радиусом окружности.

void Draw_Circle (uint8_t size,uint16_t x0,uint16_t y0,uint16_t radius,uint16_t color)
{
	int x = 0;
	int y = radius;
	int delta = 2 - 2 * radius;
	int error = 0;
	while(y >= 0)
	{
		Draw_Point(size,x0 + x, y0 + y,color);
		Draw_Point(size,x0 + x, y0 - y,color);
		Draw_Point(size,x0 - x, y0 + y,color);
		Draw_Point(size,x0 - x, y0 - y,color);
		error = 2 * (delta + y) - 1;
		if(delta < 0 && error <= 0)
		{
			++x;
			delta += 2 * x + 1;
			continue;
		}
		error = 2 * (delta - x) - 1;
		if(delta > 0 && error > 0)
		{
			--y;
			delta += 1 - 2 * y;
			continue;
		}
		++x;
		delta += 2 * (x - y);
		--y;
	}
}

Рисование геометрических фигур на TFT дисплее, на примере SSD1289.

Под конец написания статьи нашел функцию, которая рисует закрашенные и не закрашенные кружки, отвечает за это аргумент fill.

void Draw_Circle1(unsigned int x,unsigned int y,char radius,char fill, char size, unsigned int color)
{
	int a_,b_,P;
	a_ = 0;
	b_ = radius;
	P = 1 - radius;
	while (a_ <= b_)
	{
		if(fill == 1)
		{
                        Draw_Area(y-a_,x-b_,y+a_,x+b_,color);
			Draw_Area(y-b_,x-a_,y+b_,x+a_,color);
		}
		else
		{
			Draw_Point(size, a_+x, b_+y, color);
			Draw_Point(size, b_+x, a_+y, color);
			Draw_Point(size, x-a_, b_+y, color);
			Draw_Point(size, x-b_, a_+y, color);
			Draw_Point(size, b_+x, y-a_, color);
			Draw_Point(size, a_+x, y-b_, color);
			Draw_Point(size, x-a_, y-b_, color);
			Draw_Point(size, x-b_, y-a_, color);
		}
		if (P < 0 )
		{
			P = (P + 3) + (2* a_);
			a_ ++;
		}
		else
		{
			P = (P + 5) + (2* (a_ - b_));
			a_ ++;
			b_ --;
		}
	}
}
////////////////////////////////////

Рисование геометрических фигур на TFT дисплее, на примере SSD1289.

Пожалуй это все, что хотелось рассказать про рисование геометрических фигур, а в следующей статье мы узнаем как работает резистивный сенсорный экран.
Ссылка на код, написанный к статьям про SSD1289, здесь.
Проект для Atmega16 в Atmel Studio 6.2 в архиве ssd1289_i8080_geometric.rar [47,74 Kb] (cкачиваний: 37)
комментарии
0