-
Notifications
You must be signed in to change notification settings - Fork 335
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
9 changed files
with
155 additions
and
161 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -7,6 +7,3 @@ void setup(){ | |
} | ||
|
||
void loop(){} | ||
|
||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -7,6 +7,3 @@ void setup(){ | |
} | ||
|
||
void loop(){} | ||
|
||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,150 +1,150 @@ | ||
// STARRY HORIZON for Watchy by SQFMI | ||
// Copyright 2021 Dan Delany [email protected] | ||
// Released under free MIT License : https://github.com/dandelany/watchy-faces/blob/main/LICENSE | ||
|
||
#include <Watchy.h> //include the Watchy library | ||
#include <Fonts/FreeSansBold9pt7b.h> //include any fonts you want to use | ||
#include "MadeSunflower39pt7b.h" | ||
#include "stars.h" | ||
|
||
#define STAR_COUNT 900 | ||
|
||
const int horizonY = 150; | ||
const int planetR = 650; | ||
|
||
struct xyPoint { | ||
int x; | ||
int y; | ||
}; | ||
|
||
//Star myStars[STAR_COUNT]; | ||
void initStars() { | ||
// The random star field is loaded from PROGMEM - see stars.h | ||
// this is the function that was used to generate the stars in stars.h | ||
// it does not run normally but can be used to re-generate stars with different parameters | ||
// tweak as needed, call this function in init, open serial monitor, and paste the results into stars.h | ||
srand(5287); // randomSeed() is not stable on ESP32, use srand | ||
printf("const Star STARS[] PROGMEM = {\n"); | ||
for(int i = 0; i < STAR_COUNT; i++) { | ||
int starX = (rand() % 260) - 30; | ||
int starY = (rand() % 260) - 30; | ||
int radius = 0; | ||
if (i > STAR_COUNT * 0.99) radius = 2; | ||
else if (i > STAR_COUNT * 0.80) radius = 1; | ||
printf(" { %d, %d, %d },\n", starX, starY, radius); | ||
// myStars[i] = { starX, starY, radius }; | ||
} | ||
printf("};\n"); | ||
} | ||
|
||
struct xyPoint rotatePointAround(int x, int y, int ox, int oy, double angle) { | ||
// rotate X,Y point around given origin point by a given angle | ||
// based on https://gist.github.com/LyleScott/e36e08bfb23b1f87af68c9051f985302#file-rotate_2d_point-py-L38 | ||
double qx = (double)ox + (cos(angle) * (double)(x - ox)) + (sin(angle) * (double)(y - oy)); | ||
double qy = (double)oy + (-sin(angle) * (double)(x - ox)) + (cos(angle) * (double)(y - oy)); | ||
struct xyPoint newPoint; | ||
newPoint.x = (int)qx; | ||
newPoint.y = (int)qy; | ||
return newPoint; | ||
} | ||
|
||
class StarryHorizon : public Watchy { | ||
public: | ||
StarryHorizon() { | ||
// uncomment to re-generate stars | ||
// initStars(); | ||
} | ||
void drawWatchFace(){ | ||
display.fillScreen(GxEPD_BLACK); | ||
display.fillCircle(100, horizonY + planetR, planetR, GxEPD_WHITE); | ||
drawGrid(); | ||
drawStars(STARS); | ||
drawTime(); | ||
drawDate(); | ||
} | ||
void drawGrid() { | ||
int prevY = horizonY; | ||
for(int i = 0; i < 40; i+= 1) { | ||
int y = prevY + int(abs(sin(double(i) / 10) * 10)); | ||
if(y <= 200) { | ||
display.drawFastHLine(0, y, 200, GxEPD_BLACK); | ||
} | ||
prevY = y; | ||
} | ||
int vanishY = horizonY - 25; | ||
for (int x = -230; x < 430; x += 20) { | ||
display.drawLine(x, 200, 100, vanishY, GxEPD_BLACK); | ||
} | ||
} | ||
void drawStars(const Star stars[]) { | ||
// draw field of stars | ||
// rotate stars so that they make an entire revolution once per hour | ||
int minute = (int)currentTime.Minute; | ||
double minuteAngle = ((2.0 * M_PI) / 60.0) * (double)minute; | ||
// printf("Minute %d, angle %f\n", (int)currentTime.Minute, minuteAngle); | ||
|
||
for(int starI = 0; starI < STAR_COUNT; starI++) { | ||
int starX = stars[starI].x; | ||
int starY = stars[starI].y; | ||
int starR = stars[starI].r; | ||
|
||
struct xyPoint rotated = rotatePointAround(starX, starY, 100, 100, minuteAngle); | ||
if(rotated.x < 0 || rotated.y < 0 || rotated.x > 200 || rotated.y > horizonY) { | ||
continue; | ||
} | ||
if(starR == 0) { | ||
display.drawPixel(rotated.x, rotated.y, GxEPD_WHITE); | ||
} else { | ||
display.fillCircle(rotated.x, rotated.y, starR, GxEPD_WHITE); | ||
} | ||
} | ||
} | ||
void drawTime() { | ||
display.setFont(&MADE_Sunflower_PERSONAL_USE39pt7b); | ||
display.setTextColor(GxEPD_WHITE); | ||
display.setTextWrap(false); | ||
char* timeStr; | ||
asprintf(&timeStr, "%d:%02d", currentTime.Hour, currentTime.Minute); | ||
drawCenteredString(timeStr, 100, 115, false); | ||
free(timeStr); | ||
} | ||
|
||
void drawDate() { | ||
String monthStr = monthShortStr(currentTime.Month); | ||
String dayOfWeek = dayShortStr(currentTime.Wday); | ||
display.setFont(&FreeSansBold9pt7b); | ||
display.setTextColor(GxEPD_WHITE); | ||
display.setTextWrap(false); | ||
char* dateStr; | ||
asprintf(&dateStr, "%s %s %d", dayOfWeek, monthStr, currentTime.Day); | ||
drawCenteredString(dateStr, 100, 140, true); | ||
free(dateStr); | ||
} | ||
|
||
void drawCenteredString(const String &str, int x, int y, bool drawBg) { | ||
int16_t x1, y1; | ||
uint16_t w, h; | ||
|
||
display.getTextBounds(str, x, y, &x1, &y1, &w, &h); | ||
// printf("bounds: %d x %d y, %d x1 %d y1, %d w, %d h\n", 0, 100, x1, y1, w, h); | ||
display.setCursor(x - w / 2, y); | ||
if(drawBg) { | ||
int padY = 3; | ||
int padX = 10; | ||
display.fillRect(x - (w / 2 + padX), y - (h + padY), w + padX*2, h + padY*2, GxEPD_BLACK); | ||
} | ||
// uncomment to draw bounding box | ||
// display.drawRect(x - w / 2, y - h, w, h, GxEPD_WHITE); | ||
display.print(str); | ||
} | ||
}; | ||
|
||
StarryHorizon face; //instantiate watchface | ||
|
||
void setup() { | ||
face.init(); //call init in setup | ||
} | ||
|
||
void loop() { | ||
// this should never run, Watchy deep sleeps after init(); | ||
} | ||
// STARRY HORIZON for Watchy by SQFMI | ||
// Copyright 2021 Dan Delany [email protected] | ||
// Released under free MIT License : https://github.com/dandelany/watchy-faces/blob/main/LICENSE | ||
|
||
#include <Watchy.h> //include the Watchy library | ||
#include <Fonts/FreeSansBold9pt7b.h> //include any fonts you want to use | ||
#include "MadeSunflower39pt7b.h" | ||
#include "stars.h" | ||
|
||
#define STAR_COUNT 900 | ||
|
||
const int horizonY = 150; | ||
const int planetR = 650; | ||
|
||
struct xyPoint { | ||
int x; | ||
int y; | ||
}; | ||
|
||
//Star myStars[STAR_COUNT]; | ||
void initStars() { | ||
// The random star field is loaded from PROGMEM - see stars.h | ||
// this is the function that was used to generate the stars in stars.h | ||
// it does not run normally but can be used to re-generate stars with different parameters | ||
// tweak as needed, call this function in init, open serial monitor, and paste the results into stars.h | ||
srand(5287); // randomSeed() is not stable on ESP32, use srand | ||
printf("const Star STARS[] PROGMEM = {\n"); | ||
for(int i = 0; i < STAR_COUNT; i++) { | ||
int starX = (rand() % 260) - 30; | ||
int starY = (rand() % 260) - 30; | ||
int radius = 0; | ||
if (i > STAR_COUNT * 0.99) radius = 2; | ||
else if (i > STAR_COUNT * 0.80) radius = 1; | ||
printf(" { %d, %d, %d },\n", starX, starY, radius); | ||
// myStars[i] = { starX, starY, radius }; | ||
} | ||
printf("};\n"); | ||
} | ||
|
||
struct xyPoint rotatePointAround(int x, int y, int ox, int oy, double angle) { | ||
// rotate X,Y point around given origin point by a given angle | ||
// based on https://gist.github.com/LyleScott/e36e08bfb23b1f87af68c9051f985302#file-rotate_2d_point-py-L38 | ||
double qx = (double)ox + (cos(angle) * (double)(x - ox)) + (sin(angle) * (double)(y - oy)); | ||
double qy = (double)oy + (-sin(angle) * (double)(x - ox)) + (cos(angle) * (double)(y - oy)); | ||
struct xyPoint newPoint; | ||
newPoint.x = (int)qx; | ||
newPoint.y = (int)qy; | ||
return newPoint; | ||
} | ||
|
||
class StarryHorizon : public Watchy { | ||
public: | ||
StarryHorizon() { | ||
// uncomment to re-generate stars | ||
// initStars(); | ||
} | ||
void drawWatchFace(){ | ||
display.fillScreen(GxEPD_BLACK); | ||
display.fillCircle(100, horizonY + planetR, planetR, GxEPD_WHITE); | ||
drawGrid(); | ||
drawStars(STARS); | ||
drawTime(); | ||
drawDate(); | ||
} | ||
void drawGrid() { | ||
int prevY = horizonY; | ||
for(int i = 0; i < 40; i+= 1) { | ||
int y = prevY + int(abs(sin(double(i) / 10) * 10)); | ||
if(y <= 200) { | ||
display.drawFastHLine(0, y, 200, GxEPD_BLACK); | ||
} | ||
prevY = y; | ||
} | ||
int vanishY = horizonY - 25; | ||
for (int x = -230; x < 430; x += 20) { | ||
display.drawLine(x, 200, 100, vanishY, GxEPD_BLACK); | ||
} | ||
} | ||
void drawStars(const Star stars[]) { | ||
// draw field of stars | ||
// rotate stars so that they make an entire revolution once per hour | ||
int minute = (int)currentTime.Minute; | ||
double minuteAngle = ((2.0 * M_PI) / 60.0) * (double)minute; | ||
// printf("Minute %d, angle %f\n", (int)currentTime.Minute, minuteAngle); | ||
|
||
for(int starI = 0; starI < STAR_COUNT; starI++) { | ||
int starX = stars[starI].x; | ||
int starY = stars[starI].y; | ||
int starR = stars[starI].r; | ||
|
||
struct xyPoint rotated = rotatePointAround(starX, starY, 100, 100, minuteAngle); | ||
if(rotated.x < 0 || rotated.y < 0 || rotated.x > 200 || rotated.y > horizonY) { | ||
continue; | ||
} | ||
if(starR == 0) { | ||
display.drawPixel(rotated.x, rotated.y, GxEPD_WHITE); | ||
} else { | ||
display.fillCircle(rotated.x, rotated.y, starR, GxEPD_WHITE); | ||
} | ||
} | ||
} | ||
void drawTime() { | ||
display.setFont(&MADE_Sunflower_PERSONAL_USE39pt7b); | ||
display.setTextColor(GxEPD_WHITE); | ||
display.setTextWrap(false); | ||
char* timeStr; | ||
asprintf(&timeStr, "%d:%02d", currentTime.Hour, currentTime.Minute); | ||
drawCenteredString(timeStr, 100, 115, false); | ||
free(timeStr); | ||
} | ||
|
||
void drawDate() { | ||
String monthStr = monthShortStr(currentTime.Month); | ||
String dayOfWeek = dayShortStr(currentTime.Wday); | ||
display.setFont(&FreeSansBold9pt7b); | ||
display.setTextColor(GxEPD_WHITE); | ||
display.setTextWrap(false); | ||
char* dateStr; | ||
asprintf(&dateStr, "%s %s %d", dayOfWeek, monthStr, currentTime.Day); | ||
drawCenteredString(dateStr, 100, 140, true); | ||
free(dateStr); | ||
} | ||
|
||
void drawCenteredString(const String &str, int x, int y, bool drawBg) { | ||
int16_t x1, y1; | ||
uint16_t w, h; | ||
|
||
display.getTextBounds(str, x, y, &x1, &y1, &w, &h); | ||
// printf("bounds: %d x %d y, %d x1 %d y1, %d w, %d h\n", 0, 100, x1, y1, w, h); | ||
display.setCursor(x - w / 2, y); | ||
if(drawBg) { | ||
int padY = 3; | ||
int padX = 10; | ||
display.fillRect(x - (w / 2 + padX), y - (h + padY), w + padX*2, h + padY*2, GxEPD_BLACK); | ||
} | ||
// uncomment to draw bounding box | ||
// display.drawRect(x - w / 2, y - h, w, h, GxEPD_WHITE); | ||
display.print(str); | ||
} | ||
}; | ||
|
||
StarryHorizon face; //instantiate watchface | ||
|
||
void setup() { | ||
face.init(); //call init in setup | ||
} | ||
|
||
void loop() { | ||
// this should never run, Watchy deep sleeps after init(); | ||
} |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters