Zach Rispoli

27 Jan 2015

My Pebble Watch app is a mobile version of a clock assignment I did last semester with some added features.

The clock is a twelve-handed spinning spirograph-like ball that ‘ticks’ every second. Each hand is actually a point that is connected to all of the other points by lines. By moving each hand around the face of the clock depending on the number of seconds passed in the day, complex patterns emerge. Because of this, each second of the day generates a unique pattern.

Each unique pattern is also given a unique name. For example, the second at 7:49am (and 45 seconds) is named “kicute” looks like this:

IMG_2315

The name generation is done with a very very simple algorithm that chooses consonants and vowels back and forth. I’ve been using this little trick for years now because of it’s simplicity and the cute/exotic names it comes up with.

#include 

static Window *s_main_window;
static Layer *s_canvas_layer;
static TextLayer *name_layer;

void handle_second_tick(struct tm *tick_time, TimeUnits units_changed) {
  layer_mark_dirty(s_canvas_layer);
}

static void drawLineToFromAngle(float t, float f, GContext *ctx, GPoint center) {
  //https://github.com/pebble/pebble-sdk-examples/blob/629cd4bb6a8d4686e48889c5a3870f92e5d915b0/watchfaces/simple_analog/src/simple_analog.c
  
  GPoint p0 = GPoint(
    (int16_t)(-cos_lookup(TRIG_MAX_ANGLE * (t / 360.0)) * (int32_t)65 / TRIG_MAX_RATIO) + center.x,
    (int16_t)( sin_lookup(TRIG_MAX_ANGLE * (t / 360.0)) * (int32_t)65 / TRIG_MAX_RATIO) + center.y
  );
  
  GPoint p1 = GPoint(
    (int16_t)(-cos_lookup(TRIG_MAX_ANGLE * (f / 360.0)) * (int32_t)65 / TRIG_MAX_RATIO) + center.x,
    (int16_t)( sin_lookup(TRIG_MAX_ANGLE * (f / 360.0)) * (int32_t)65 / TRIG_MAX_RATIO) + center.y
  );

  graphics_context_set_stroke_color(ctx, GColorBlack);
  graphics_draw_line(ctx, p0, p1);
}

static void canvas_update_proc(Layer *this_layer, GContext *ctx) {
  GRect bounds = layer_get_bounds(this_layer);
  GPoint center = GPoint(bounds.size.w / 2, (bounds.size.h / 2) - 12);

  time_t now = time(NULL);
  struct tm *t = localtime(&now);
  int s = t->tm_sec;
  int m = t->tm_min;
  int h = t->tm_hour;
  
  // second name
  static char name[] = "XXXXXX";
  static char vowels[] = "AEIOU";
  for(int i = 1; i < 6; i+=2) {
    name[i] = vowels[(s+m*60+h*60*60 + i+10) % 5];
  }
  for(int i = 0; i < 6; i+=2) {
    name[i] = 65 + ((s+m*60+h*60*60 * (i+10)) % 25);
  }
  text_layer_set_text(name_layer, name);
  
  // mandala
  for(int i = 0; i < 360; i += 30) {
  for(int j = 0; j < 360; j += 30) {
    drawLineToFromAngle(i+s, j, ctx, center);
  }}
}

static void main_window_load(Window *window) {
  Layer *window_layer = window_get_root_layer(window);
  GRect window_bounds = layer_get_bounds(window_layer);

  // Create Layer
  s_canvas_layer = layer_create(GRect(0, 0, window_bounds.size.w, window_bounds.size.h));
  layer_add_child(window_layer, s_canvas_layer);
  
  // Name
  name_layer = text_layer_create(GRect(2, 140, 144, 18));
  text_layer_set_background_color(name_layer, GColorClear);
  text_layer_set_text_color(name_layer, GColorBlack);
  text_layer_set_text_alignment(name_layer, GTextAlignmentCenter);
  text_layer_set_font(name_layer, fonts_get_system_font(FONT_KEY_GOTHIC_18_BOLD));

  layer_add_child(window_get_root_layer(window), text_layer_get_layer(name_layer));
  
  // Set the update_proc
  layer_set_update_proc(s_canvas_layer, canvas_update_proc);
}

static void main_window_unload(Window *window) {
  // Destroy Layer
  layer_destroy(s_canvas_layer);
}

static void init(void) {
  // Create main Window
  s_main_window = window_create();
  window_set_window_handlers(s_main_window, (WindowHandlers) {
    .load = main_window_load,
    .unload = main_window_unload,
  });
  window_stack_push(s_main_window, true);
  
  tick_timer_service_subscribe(SECOND_UNIT, &handle_second_tick);
}

static void deinit(void) {
  // Destroy main Window
  window_destroy(s_main_window);
}

int main(void) {
  init();
  app_event_loop();
  deinit();
}