在图形显示上旋转文本

时间:2017-07-14 03:18:38

标签: c++ arduino esp8266 lcd arduino-esp8266

我正在尝试modifylibrary添加在图形显示上旋转文字的功能。我正在使用电子纸显示器,但该库支持其他图形显示。我已经做到了旋转显示器上的文字,但我无法确定旋转中心的正确性。通过研究类似的问题,我发现我需要暂时将原点移动到旋转点。但是,我很难看到如何使用此代码执行此操作。 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);
}

0 个答案:

没有答案