|
| 1 | +#define MAP_WIDTH_PX 128 |
| 2 | +#define MAP_HEIGHT_PX 103 |
| 3 | + |
| 4 | +#define MAP_MIN_LAT -0.5 //bottom of map |
| 5 | +#define MAP_MAX_LAT 0.5 //top of map |
| 6 | +#define MAP_MIN_LONG -0.5 //left of map |
| 7 | +#define MAP_MAX_LONG 0.5 //right of map |
| 8 | + |
| 9 | +#define sclk 13 // Don't change |
| 10 | +#define mosi 11 // Don't change |
| 11 | +#define cs 10 |
| 12 | +#define dc A0 |
| 13 | +#define rst A1 // you can also connect this to the Arduino reset |
| 14 | + |
| 15 | +#include <Adafruit_GFX.h> // Core graphics library |
| 16 | +#include <Adafruit_QDTech.h> // Hardware-specific library |
| 17 | +#include <SPI.h> |
| 18 | + |
| 19 | +Adafruit_QDTech tft = Adafruit_QDTech(cs, dc, rst); |
| 20 | + |
| 21 | +//2D array of fake locations outside map centered around 0 lat, 0 long |
| 22 | +//fakeLocations[latitude][longitude]. i.e. fakeLocations[y coord][x coord] |
| 23 | +const float fakeLocations[16][2] = { |
| 24 | + { 1, -1 }, |
| 25 | + { 1, -0.25 }, |
| 26 | + { 1, 0 }, |
| 27 | + { 1, 0.25 }, |
| 28 | + |
| 29 | + { 1, 1}, |
| 30 | + { 0.25, 1 }, |
| 31 | + { 0, 1}, |
| 32 | + { -0.25, 1}, |
| 33 | + |
| 34 | + { -1, 1}, |
| 35 | + { -1, 0.25}, |
| 36 | + { -1, 0}, |
| 37 | + { -1, -0.25}, |
| 38 | + |
| 39 | + { -1, -1 }, |
| 40 | + { -0.25, -1 }, |
| 41 | + { 0, -1 }, |
| 42 | + { 0.25, -1 }, |
| 43 | +}; |
| 44 | + |
| 45 | +void clearTFTMap() { |
| 46 | + tft.fillRect(0, 0, 128, 103, QDTech_BLACK); //clear the map drawn on the TFT screen |
| 47 | +} |
| 48 | + |
| 49 | +void drawArrow(byte screenX, byte screenY, byte dir) { |
| 50 | + //dir is the direction of the arrow. North-West is 0, North is 1, North east is 2 such that: |
| 51 | + // NW N NE 0 1 2 |
| 52 | + // W E = 7 3 |
| 53 | + // SW S SE 6 5 4 |
| 54 | + |
| 55 | + //Note: Dir could be inferred from screenX and screenY... |
| 56 | + switch (dir) { |
| 57 | + case 0: //NW |
| 58 | + // fillTriangle(x0, y0, x1, y1, x2, y2, colour) |
| 59 | + tft.fillTriangle(screenX, screenY, screenX + 2, screenY + 5, screenX + 5, screenY + 2, QDTech_RED); |
| 60 | + break; |
| 61 | + case 1: //N |
| 62 | + tft.fillTriangle(screenX, screenY, screenX - 2, screenY + 5, screenX + 2, screenY + 5, QDTech_RED); |
| 63 | + break; |
| 64 | + case 2: //NE |
| 65 | + tft.fillTriangle(screenX, screenY, screenX - 2, screenY + 5, screenX - 5, screenY + 2, QDTech_RED); |
| 66 | + break; |
| 67 | + case 3: //E |
| 68 | + tft.fillTriangle(screenX, screenY, screenX - 5, screenY - 2, screenX - 5, screenY + 2, QDTech_RED); |
| 69 | + break; |
| 70 | + case 4: //SE |
| 71 | + tft.fillTriangle(screenX, screenY, screenX - 2, screenY - 5, screenX - 5, screenY - 2, QDTech_RED); |
| 72 | + break; |
| 73 | + case 5: //S |
| 74 | + tft.fillTriangle(screenX, screenY, screenX + 2, screenY - 5, screenX - 2, screenY - 5, QDTech_RED); |
| 75 | + break; |
| 76 | + case 6: //SW |
| 77 | + tft.fillTriangle(screenX, screenY, screenX + 2, screenY - 5, screenX + 5, screenY - 2, QDTech_RED); |
| 78 | + break; |
| 79 | + case 7: //W |
| 80 | + tft.fillTriangle(screenX, screenY, screenX + 5, screenY + 2, screenX + 5, screenY - 2, QDTech_RED); |
| 81 | + break; |
| 82 | + } |
| 83 | +} |
| 84 | + |
| 85 | +void displayLocationOnMap(float currentLatitude, float currentLongitude) { |
| 86 | + //Relative X position on map between 0 and 1 |
| 87 | + float relativeXPosOnMap = (currentLongitude - MAP_MIN_LONG) / (MAP_MAX_LONG - MAP_MIN_LONG); |
| 88 | + //Calculate screen X coordinates for current GPS location |
| 89 | + int screenXPos = relativeXPosOnMap * float(MAP_WIDTH_PX); |
| 90 | + |
| 91 | + //Relative Y position on map between 0 and 1 |
| 92 | + //1.0 - the relative Position because Y-coordinates on screen are inversed relative to latitude (and the standard 'Cartesian' coordinate system |
| 93 | + //i.e. Y-coordinate increases as you go down the screen. Latitude increases as you go up the screen. |
| 94 | + //There are many ways to fix this problem. e.g. change MAP_MIN_LAT to MAP_MAX_LAT or switching the denominators should have the same result |
| 95 | + float relativeYPosOnMap = 1.0 - ((currentLatitude - MAP_MIN_LAT) / (MAP_MAX_LAT - MAP_MIN_LAT)); |
| 96 | + //Calculate screen Y coordinates for current GPS location. |
| 97 | + int screenYPos = relativeYPosOnMap * float(MAP_HEIGHT_PX); |
| 98 | + |
| 99 | + //For debugging |
| 100 | + //Serial.println("RelXPos: " + String(relativeXPosOnMap)); |
| 101 | + //Serial.println("RelYPos: " + String(relativeYPosOnMap)); |
| 102 | + //Serial.println("MapXPos: " + String(screenXPos)); |
| 103 | + //Serial.println("MapYPos: " + String(screenYPos)); |
| 104 | + |
| 105 | + //if tracker is on-screen |
| 106 | + if (relativeXPosOnMap >= 0 && relativeXPosOnMap <= 1 && relativeYPosOnMap >= 0 && relativeYPosOnMap <= 1) { |
| 107 | + //Draw pixel on map at current location |
| 108 | + tft.drawPixel(screenXPos, screenYPos, QDTech_BLACK); //Clear the pixel first |
| 109 | + tft.drawPixel(screenXPos, screenYPos, QDTech_RED); |
| 110 | + |
| 111 | + ////if tracker is off-screen//// |
| 112 | + ////corners of map. i.e. position is completely outside the map's boundaries |
| 113 | + //if tracker is top-left |
| 114 | + } else if (relativeXPosOnMap < 0 && relativeYPosOnMap < 0) { |
| 115 | + drawArrow(0, 0, 0); |
| 116 | + //if tracker is top-right |
| 117 | + } else if (relativeXPosOnMap > 1 && relativeYPosOnMap < 0) { |
| 118 | + drawArrow(MAP_WIDTH_PX, 0, 2); |
| 119 | + //if tracker is bottom-right |
| 120 | + } else if (relativeXPosOnMap > 1 && relativeYPosOnMap > 1) { |
| 121 | + drawArrow(MAP_WIDTH_PX, MAP_HEIGHT_PX - 1, 4); |
| 122 | + //if tracker is bottom-left |
| 123 | + } else if (relativeXPosOnMap < 0 && relativeYPosOnMap > 1) { |
| 124 | + drawArrow(0, MAP_HEIGHT_PX - 1, 6); |
| 125 | + |
| 126 | + ////edges of map. i.e. position is outside the map in one axis but within the map on the other axis |
| 127 | + //if tracker is top-middle |
| 128 | + } else if (relativeXPosOnMap >= 0 && relativeXPosOnMap <= 1 && relativeYPosOnMap < 0) { |
| 129 | + drawArrow(screenXPos, 0, 1); |
| 130 | + //if tracker is middle-right |
| 131 | + } else if (relativeXPosOnMap > 1 && relativeYPosOnMap <= 1 && relativeYPosOnMap >= 0) { |
| 132 | + drawArrow(MAP_WIDTH_PX, screenYPos, 3); |
| 133 | + //if tracker is bottom-middle |
| 134 | + } else if (relativeXPosOnMap >= 0 && relativeXPosOnMap <= 1 && relativeYPosOnMap > 1) { |
| 135 | + drawArrow(screenXPos, MAP_HEIGHT_PX - 1, 5); |
| 136 | + //if tracker is middle-left |
| 137 | + } else if (relativeXPosOnMap < 0 && relativeYPosOnMap <= 1 && relativeYPosOnMap >= 0) { |
| 138 | + drawArrow(0, screenYPos, 7); |
| 139 | + } |
| 140 | +} |
| 141 | + |
| 142 | +void setup() { |
| 143 | + tft.init(); |
| 144 | + tft.setRotation(0); // 0 = Portrait, 1 = Landscape |
| 145 | + tft.fillScreen(QDTech_BLACK); |
| 146 | + tft.setTextWrap(false); |
| 147 | + tft.setCursor(0, 0); |
| 148 | + tft.setTextColor(QDTech_WHITE); |
| 149 | + tft.setTextSize(1); |
| 150 | + tft.drawFastHLine(0, 103, 128, QDTech_WHITE); //Note: draw on line 103, which is the 104th line |
| 151 | + |
| 152 | + //Draw arrows rotating in centre of map |
| 153 | + //With clearing the map |
| 154 | + for (byte i = 0; i <= 7; i++) { |
| 155 | + clearTFTMap(); //Clear the map |
| 156 | + drawArrow(MAP_WIDTH_PX / 2, MAP_HEIGHT_PX / 2, i); |
| 157 | + delay(200); |
| 158 | + } |
| 159 | + delay(1000); |
| 160 | + |
| 161 | + //Without clearing the map - for arrow comparison |
| 162 | + clearTFTMap(); //Clear the map |
| 163 | + for (byte i = 0; i <= 7; i++) { |
| 164 | + drawArrow(MAP_WIDTH_PX / 2, (i + 1) * 11, i); |
| 165 | + delay(200); |
| 166 | + } |
| 167 | + delay(1000); |
| 168 | + |
| 169 | + //Draw arrows in corners with drawArrow() |
| 170 | + clearTFTMap(); //Clear the map |
| 171 | + drawArrow(0, 0, 0); |
| 172 | + delay(500); |
| 173 | + drawArrow(MAP_WIDTH_PX, 0, 2); |
| 174 | + delay(500); |
| 175 | + drawArrow(MAP_WIDTH_PX, MAP_HEIGHT_PX, 4); |
| 176 | + delay(500); |
| 177 | + drawArrow(0, MAP_HEIGHT_PX, 6); |
| 178 | + delay(1000); |
| 179 | + |
| 180 | + //Draw arrows in corners with displayLocationOnMap(float latitude, float longitude) |
| 181 | + //Should be the same result as above |
| 182 | + clearTFTMap(); //Clear the map |
| 183 | + displayLocationOnMap(1.0, -1.0); |
| 184 | + delay(500); |
| 185 | + displayLocationOnMap(1.0, 1.0); |
| 186 | + delay(500); |
| 187 | + displayLocationOnMap(-1.0, 1.0); |
| 188 | + delay(500); |
| 189 | + displayLocationOnMap(-1.0, -1.0); |
| 190 | + delay(1000); |
| 191 | + |
| 192 | + //Draw test locations from fakeLocations 2D array on map |
| 193 | + clearTFTMap(); //Clear the map |
| 194 | + for (byte i = 0; i < 16; i++) { |
| 195 | + //displayLocationOnMap(float latitude, float longitude) |
| 196 | + displayLocationOnMap(fakeLocations[i][0], fakeLocations[i][1]); |
| 197 | + //tft.println(String(fakeLocations[i][0]) + "," + String(fakeLocations[i][1])); |
| 198 | + delay(200); |
| 199 | + } |
| 200 | +} |
| 201 | + |
| 202 | +void loop() { |
| 203 | + |
| 204 | +} |
| 205 | + |
0 commit comments