Поворот текста на графическом дисплее

я пытаюсь модифицировать этот библиотека добавить возможность вращать текст на графическом дисплее. Я использую электронный дисплей, но библиотека поддерживает другие графические дисплеи. Я сделал это так далеко, как вращение текста на дисплее, но я не могу понять, как правильно вращать центр вращения. Из исследования похожих вопросов я вижу, что мне нужно временно переместить начало координат в точку вращения. Тем не менее, я не вижу, как это сделать с этим кодом. drawString вызывает несколько функций, пока, наконец, функция для установки цвета пикселя (вот где я вставил код для поворота затронутых пикселей). Я думаю, что мне нужно переместить вращение дальше вверх по течению.

я добавил setTextRotation который предварительно вычисляет грех / cos, который позже передается в первые две строки в setPixel (внизу блока кода ниже). Может быть легче увидеть изменения в первой ссылке выше. Я попытался решить (благодаря Вольфраму) систему уравнений, чтобы вычислить x и y, которые вызвали бы поворот пикселей в setPixel Функция имеет то же происхождение, что и исходные x и y, переданные drawString но не радость К тому же, я чувствую, что слишком сильно усложняю проблему.

Я не программист по профессии (и только один по хобби). Любой совет, как поступить?

Спасибо!

Соответствующие части (см. Ссылки выше для полного кода):

int16_t txtRotation=0;
float sin_angle=0;
float cos_angle=1;

void MiniGrafx::setTextRotation(int16_t r) {
int16_t txtAngle=r;
Serial.print ("Text Angle=");
Serial.println (txtAngle);
do
{
if (txtAngle>=360) txtAngle=txtAngle-360;
Serial.println (txtAngle);
}while (txtAngle>360);
do
{
if (txtAngle<=-360) txtAngle=txtAngle+360;
Serial.println (txtAngle);
}while (txtAngle<-360);
if (txtAngle<0) txtAngle=360+txtAngle;
txtRotation=txtAngle;

switch (txtRotation){
case 0:
sin_angle=0;
cos_angle=1;
break;
case 45:
sin_angle=0.707106781;
cos_angle=0.707106781;
break;
case 90:
sin_angle=1;
cos_angle=0;
break;
case 135:
sin_angle=0.707106781;
cos_angle=-0.707106781;
break;
case 180:
sin_angle=0;
cos_angle=-1;
break;
case 225:
sin_angle=-0.707106781;
cos_angle=-0.707106781;
break;
case 270:
sin_angle=-1;
cos_angle=0;
break;
case 315:
sin_angle=-0.707106781;
cos_angle=0.707106781;
break;
default: //compute sin and cos if not a cardinal direction.
float angle_rad=0.017453*(float)txtRotation; //convert degrees to radians
sin_angle = sin (angle_rad);          // Pre-calculate the time consuming sin
cos_angle = cos (angle_rad);          // Pre-calculate the time consuming cosine
break;
}

}

void MiniGrafx::drawString(int16_t xMove, int16_t yMove, String strUser) {
uint16_t lineHeight = pgm_read_byte(fontData + HEIGHT_POS);

// char* text must be freed!
char* text = utf8ascii(strUser);

uint16_t yOffset = 0;
// If the string should be centered vertically too
// we need to now how heigh the string is.
if (textAlignment == TEXT_ALIGN_CENTER_BOTH) {
uint16_t lb = 0;
// Find number of linebreaks in text
for (uint16_t i=0;text[i] != 0; i++) {
lb += (text[i] == 10);
}
// Calculate center
yOffset = (lb * lineHeight) >> 2;
}

uint16_t line = 0;
char* textPart = strtok(text,"\n");
while (textPart != NULL) {
uint16_t length = strlen(textPart);
drawStringInternal((xMove, yMove - yOffset + (line++) * lineHeight, textPart, length, getStringWidth(textPart, length));
textPart = strtok(NULL, "\n");
}
free(text);
}

void MiniGrafx::drawStringInternal(int16_t xMove, int16_t yMove, char* text, uint16_t textLength, uint16_t textWidth) {
uint8_t textHeight       = pgm_read_byte(fontData + HEIGHT_POS);
uint8_t firstChar        = pgm_read_byte(fontData + FIRST_CHAR_POS);
uint16_t sizeOfJumpTable = pgm_read_byte(fontData + CHAR_NUM_POS)  * JUMPTABLE_BYTES;

uint8_t cursorX         = 0;
uint8_t cursorY         = 0;

switch (textAlignment) {
case TEXT_ALIGN_CENTER_BOTH:
yMove -= textHeight >> 1;
// Fallthrough
case TEXT_ALIGN_CENTER:
xMove -= textWidth >> 1; // divide by 2
break;
case TEXT_ALIGN_RIGHT:
xMove -= textWidth;
break;
}

// Don't draw anything if it is not on the screen.
if (xMove + textWidth  < 0 || xMove > this->width ) {return;}
if (yMove + textHeight < 0 || yMove > this->height) {return;}

for (uint16_t j = 0; j < textLength; j++) {
int16_t xPos = xMove + cursorX;
int16_t yPos = yMove + cursorY;

byte code = text[j];
if (code >= firstChar) {
byte charCode = code - firstChar;

// 4 Bytes per char code
byte msbJumpToChar    = pgm_read_byte( fontData + JUMPTABLE_START + charCode * JUMPTABLE_BYTES );                  // MSB  \ JumpAddress
byte lsbJumpToChar    = pgm_read_byte( fontData + JUMPTABLE_START + charCode * JUMPTABLE_BYTES + JUMPTABLE_LSB);   // LSB /
byte charByteSize     = pgm_read_byte( fontData + JUMPTABLE_START + charCode * JUMPTABLE_BYTES + JUMPTABLE_SIZE);  // Size
byte currentCharWidth = pgm_read_byte( fontData + JUMPTABLE_START + charCode * JUMPTABLE_BYTES + JUMPTABLE_WIDTH); // Width

// Test if the char is drawable
if (!(msbJumpToChar == 255 && lsbJumpToChar == 255)) {
// Get the position of the char data
uint16_t charDataPosition = JUMPTABLE_START + sizeOfJumpTable + ((msbJumpToChar << 8) + lsbJumpToChar);
drawInternal(xPos, yPos, currentCharWidth, textHeight, fontData, charDataPosition, charByteSize);
}

cursorX += currentCharWidth;
}
}
}

void MiniGrafx::setTextAlignment(TEXT_ALIGNMENT textAlignment) {
this->textAlignment = textAlignment;
}

uint16_t MiniGrafx::getStringWidth(const char* text, uint16_t length) {
uint16_t firstChar        = pgm_read_byte(fontData + FIRST_CHAR_POS);

uint16_t stringWidth = 0;
uint16_t maxWidth = 0;

while (length--) {
stringWidth += pgm_read_byte(fontData + JUMPTABLE_START + (text[length] - firstChar) * JUMPTABLE_BYTES + JUMPTABLE_WIDTH);
if (text[length] == 10) {
maxWidth = max(maxWidth, stringWidth);
stringWidth = 0;
}
}
return max(maxWidth, stringWidth);
}

void inline MiniGrafx::drawInternal(int16_t xMove, int16_t yMove, int16_t width, int16_t height, const char *data, uint16_t offset, uint16_t bytesInData) {
if (width < 0 || height < 0) return;
if (yMove + height < 0 || yMove > this->height)  return;
if (xMove + width  < 0 || xMove > this->width)   return;

uint8_t  rasterHeight = 1 + ((height - 1) >> 3); // fast ceil(height / 8.0)
int8_t   yOffset      = yMove & 7;

bytesInData = bytesInData == 0 ? width * rasterHeight : bytesInData;

int16_t initYMove   = yMove;
int8_t  initYOffset = yOffset;

uint8_t arrayHeight = (int) ceil(height / 8.0);
for (uint16_t i = 0; i < bytesInData; i++) {
byte currentByte = pgm_read_byte(data + offset + i);

for (int b = 0; b < 8; b++) {
if(bitRead(currentByte, b)) {
uint16_t currentBit = i * 8 + b;
uint16_t pixelX = (i / arrayHeight);
uint16_t pixelY = (i % arrayHeight) * 8;
setPixel(pixelX + xMove, pixelY + yMove + b);
}
}
yield();

}
}

void MiniGrafx::setPixel(uint16_t x, uint16_t y) {

uint16_t newX = (int) (((float)x * cos_angle) - ((float)y * sin_angle));
uint16_t newY = (int) (((float)y * cos_angle) + ((float)x * sin_angle));

if (newX >= width || newY >= height || newX < 0 || newY < 0 || color < 0 || color > 15 || color == transparentColor) return;
uint16_t pos = (newY * width + newX) >> bitShift;
if (pos > bufferSize) {
return;
}
uint8_t shift = (newX & (pixelsPerByte - 1)) * bitsPerPixel;
uint8_t mask = bitMask << shift;
uint8_t palColor = color;
palColor = palColor << shift;
buffer[pos] = (buffer[pos] & ~mask) | (palColor & mask);
}

1

Решение

Задача ещё не решена.

Другие решения

Других решений пока нет …

По вопросам рекламы ammmcru@yandex.ru
Adblock
detector