我正在尝试modify此library添加在图形显示上旋转文字的功能。我正在使用电子纸显示器,但该库支持其他图形显示。我已经做到了旋转显示器上的文字,但我无法确定旋转中心的正确性。通过研究类似的问题,我发现我需要暂时将原点移动到旋转点。但是,我很难看到如何使用此代码执行此操作。 drawString
调用几个函数,直到最后一个函数来设置像素颜色(这是我插入代码以旋转受影响像素的位置)。我想我需要进一步向上游移动。
我添加了setTextRotation
,它预先计算了后来传递给setPixel
中前两行的sin / cos(位于下面代码块的底部)。在上面的第一个链接中可能更容易看到更改。我尝试求解(感谢Wolfram)一个方程系统来计算ax和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);
}