How to Rotate a GFX image Arduino ?

Hello All,

I am trying to rotate a GFX image (not bitmap) mapped to gyro data around the center of the GFX image x,y (see image pic). Turn left, rotate GFX left, etc… Max rotation will be only about 60-90 degrees, then image will recenter itself when user stops turning (kind of how your eyes can only turn so far in your head, and then you turn your head).

I am coding this bit by bit. I think i can map the gyro data without issue.

But, I want to be able to rotate my GFX first(as a test run), by degrees, from a center of 0 (dead ahead on the GFX image), to max left -90, to max right +90. I am having difficulty understanding how to rotate the GFX image . I only need to re-draw the radians and the arcs, as the circles that they sit on can remain static (you would not notice a circle turning on itself).

  1. to change position
  2. create new data for TFT
  3. erase old data from TFT
  4. display new data

I have read through many tutorials, I can rotate a bitmap and I can position a scan drawLine radian to follow degrees. But I can’t seem to get a handle on rotating my whole GFX image.

THX in advance for any pointers!

I have this code:

#include <Servo.h>
#include <UTFT_Geometry.h>
#include <UTFT.h>

extern uint8_t SmallFont[]; //comes w/UTFT
extern uint8_t BigFont[]; // comes w/UTFT

#define radiusMax 200
#define width 318
#define height 240
#define radius 140//


UTFT myGLCD(ILI9341_S5P, 12,  13,  10,   8,   9); // (ILI9341_S5P, MOSI, SCK, CS, RST,DC)

UTFT_Geometry geo(&myGLCD);

Servo  servo;


#define center_x  160    //width/2
#define center_y 230     //height position

void radarRings() {//draws two rings, two radians, and bunch of arcs
 //these circles can remain static
  myGLCD.setColor(0, 255, 0); // Sets color
  myGLCD.drawCircle (center_x, center_y, (radius / 2) ); 
  myGLCD.drawCircle (center_x, center_y, (radius) ); 
 
//these arcs will have to be re-drawn to match gyro data
  for (int i = -90; i <= 90; i += 20) { //i += is space between tick marks
    geo.drawArc(center_x, center_y, radius, i, i, (radius * 0.2)); //short radians
    geo.drawArc(center_x, center_y, radius / 2, i, i, (radius * 0.2));
  }

  geo.drawArc(center_x, center_y, radius - 30, -40, -40, (radius - 10 ));//long radians
  geo.drawArc(center_x, center_y, radius - 30,  40,  40, (radius -10 ));

  geo.drawArc(center_x, center_y, (radius + (radius * .1)), -90, -50, 1);//large radius markers
  geo.drawArc(center_x, center_y, (radius + (radius * .1)), -30, 30, 1);
  geo.drawArc(center_x, center_y, (radius + (radius * .1)), 50, 90, 1);

  geo.drawArc(center_x, center_y, (radius - (radius * .1)), -90, -50, 1);//large radius arcs
  geo.drawArc(center_x, center_y, (radius - (radius * .1)), -30, 30, 1);
  geo.drawArc(center_x, center_y, (radius - (radius * .1)), 50, 90, 1);

  geo.drawArc(center_x, center_y, (radius / 2 - (radius * .1)), -90, -50, 1);//small radius markers
  geo.drawArc(center_x, center_y, (radius / 2 - (radius * .1)), -30, 30, 1);
  geo.drawArc(center_x, center_y, (radius / 2 - (radius * .1)), 50, 90, 1);

  geo.drawArc(center_x, center_y, (radius / 2 + (radius * .1)), -90, -50, 1);//small radius arcs
  geo.drawArc(center_x, center_y, (radius / 2 + (radius * .1)), -30, 30, 1);
  geo.drawArc(center_x, center_y, (radius / 2 + (radius * .1)), 50, 90, 1);
 
}

void setup() {

  myGLCD.InitLCD();
  myGLCD.InitLCD(LANDSCAPE);
  myGLCD.fillScr(VGA_BLACK);

  radarRings();

void loop() {


}

I am guessing that I will need something like this:

 float scanCircle= map(, , , , *PI); // map gyro to position

 float xscanCircle  = ? // 
 float yscanCircle  = ? 
 
I think that if I had one x,y coordinate on the main radius circle, and drew the entire scanRings in relation to that, it would work......?

 Or will have to plot the new variables into  radarRings()// probably have to rewrite radarRings() so that this is possible?

  //write over new position radarRings GFX pixels
  
   
 else
  {  if no change don't write over old radarRings GFX pixels?}

So I tried some more. I know what I want to do:

I just set the second x,y, of the arcs +10 and +20 degrees and repeated the code block to display them. But this is not how I want to do it. Repeating all the unnecessary pixels is slow.

So I am trying to find a way to replace only the different pixels within the the GFX code, as the GFX display rotates to the right or left, I have to clear the different old pixels, and draw the different new ones. and do it for every ‘1’ up to ‘5’ degrees of turning to make the rotation look smooth. 10 is too blocky… confused a bit on how to approach this…

Will also have to map the turn speed, maybe +5 or -5 degrees for fast gyro turn, and +1 or -1 for slow gyro turn…

I think the code for this may be helpful:

Bodmer? Roboteer? are you still active?

Basics of image rotation

Not a task for the standard Arduino.

Hi THX for the link! Have not seen that before.

The reason I want to try is the "uncanny Eye' which I have running in combination code with neopixels and a Feather Music maker on another project on a ATSAMD21 processor. Now that 'Eye' bitmap data is sent all over a relatively small TFT using 8bit SPI in very smooth fashion, so I made the leap that I could do something similar with my small amount of data on a slightly bigger screen using a teensy 3.6.

I will read up more on what you have provided.

Well I think I found what I needed and wanted to let anyone with similar problem have part of the answer. It happens that there is a great TFT tutorial right here in the arduino pages which I have not read over for a while, but it cropped back up during my search for draw new erase old pixel/point:

I am using UTFT lib, myGLCD because drawing arcs with the geo.h is easy…

I modified it a bit to sling a circle around a 240x320 TFT (the red ILI9341 10-15$ ebay one…but not the super cheap red ebay one with fewer resistors and transistors on back…)

So this gets me erasing and drawing points very well. I just need to blend this with the arcDraw , tft.drawLine( 160, 240, 160 + radiusMax * cos( ( 360 - i ) * 3.14 / 180 ), 240 + radiusMax * sin( ( 360 - i ) * 3.14 / 180 ) );for creating lidar ring positioning radians, and map this to the Gyro inputs for speed of positioning, and draw new TFT GFX. Sounds like a cool challenge…

#include <UTFT_Geometry.h>
#include <UTFT.h>

#define width 310// minus a bit from 320 so that edges not lost
#define height 230//minus a bit from 240 so that edges not lost
#define radius 10  // drawCircle radius

UTFT myGLCD(ILI9341_S5P, 12,  13,  10,   8,   9); // (ILI9341_S5P, MOSI, SCK, CS, RST,DC)
UTFT_Geometry geo(&myGLCD);

// initial position of the point is the middle of the screen
// initial position of the point is the middle of the screen
int xPos = width / 2;
int yPos = height / 2;

// direction and speed
int xDir = 20;//1-20 works well
int yDir = 20;

// variables to keep track of the point's location
int xPrev = xPos;
int yPrev = yPos;

void setup() {
  myGLCD.InitLCD();
  myGLCD.InitLCD(LANDSCAPE);
  myGLCD.fillScr(VGA_BLACK);
  myGLCD.setColor(200, 0, 0);
}

void loop() {
  // update the location of the dot
  xPos = xPos + xDir;
  yPos = yPos + yDir;

  // check if the current location is different than the previous
  if (xPos != xPrev || yPos != yPrev) {
    myGLCD.setColor(0, 0, 0); // set the 'draw' color to black
    myGLCD.drawCircle(xPrev, yPrev, radius); // color in the previous point(s)
  }

  // draw a point in the current location
  myGLCD.setColor(255, 255, 255);
  myGLCD.drawCircle(xPos, yPos, radius);

  // if the x or x position is at the screen edges, reverse direction
  if (xPos >= width - 15 || xPos <= 20) { //screen borders minus (diameter +/- a bit) to avod wrap
    xDir = xDir * -1;
  }
  if (yPos >= height - 15 || yPos <= 20) {
    yDir = yDir * -1;
  }

  // update the point's previous location
  xPrev = xPos;
  yPrev = yPos;

  // a 33ms delay means the screen updates 30 times a second
  delay(33);
}

OK, put some of it together, got the arcs and rings rotating and looking OK for the general ‘compass’ look that I want.

I ended up using the code block below. I just have it going back and forth no more than 90 degrees for testing only. The arc motion will be better when I map it to a gyro and G-force sensor, so it will only rotate when certain requirements(yaw/force/etc) are met and not all the time…

first, might have to only update the arc draw within a millis timer ?

second, I have pixel log-jam on the sides and bottom of TFT. Tried re-positioning radius center and cutting off height. No change. This only happens with drawArcs. I think that they are not clearing pixels beyond screen height/width. I would like to eliminate this with code. (yes, I could put a screen cover over the bottom!)

any pointers on the two problems appreciated!

short vid:

void ticArcs(){
  //////////tics and arcs
  ticPos = ticPos + arcTicDir;

  if (ticPos != ticPrev) {

    myGLCD.setColor(0, 0, 0); // set the 'draw' color to black
    for (int i = -90; i <= 90; i += 20) { //i += is space between tick marks
      geo.drawArc(center_x, center_y, (radius + (radius * 0.07)), i + ticPrev, i + ticPrev, (radius * 0.1)); //distant radians
    }
    geo.drawArc(center_x, center_y, (radius + (radius * .12)), (-90 + ticPrev), (-50 + ticPrev), 1); //large outside arc markers
    geo.drawArc(center_x, center_y, (radius + (radius * .12)), (-30 + ticPrev), ( 30 + ticPrev), 1);
    geo.drawArc(center_x, center_y, (radius + (radius * .12)), (50 + ticPrev), (90 + ticPrev), 1);
  }


  myGLCD.setColor(0, 255, 0); // set the 'draw' color
  for (int i = -90; i <= 90; i += 20) { //i += is space between tick marks
    geo.drawArc(center_x, center_y, ( radius + (radius * 0.07)), i + ticPos, i + ticPos, (radius * 0.1)); //distant radians
  }
  geo.drawArc(center_x, center_y, (radius + (radius * .12)), ( -90 + ticPos), (-50 + ticPos), 1); //large outside arc markers
  geo.drawArc(center_x, center_y, (radius + (radius * .12)), (-30 + ticPos), ( 30 + ticPos), 1);
  geo.drawArc(center_x, center_y, (radius + (radius * .12)), (50 + ticPos), (90 + ticPos), 1);


  // if the arc position exceeds max, reverse direction
  if (ticPos <= -90 || ticPos >= 90) {
    arcTicDir = arcTicDir * -1;
  }
  ticPrev = ticPos;
 delay(40);//use millis??
}