Initial triangle generation

This commit is contained in:
2026-08-06 23:36:41 -04:00
parent cc0af89820
commit 38af0bcdea
3 changed files with 135 additions and 1 deletions
+7 -1
View File
@@ -1,4 +1,4 @@
#include "src/resource_ids.auto.h" #include "triangles.h"
#include <pebble.h> #include <pebble.h>
#include <stdlib.h> #include <stdlib.h>
@@ -36,6 +36,7 @@ static TextLayer *s_drop_txt_under_layer;
static Layer *s_division_layer; static Layer *s_division_layer;
static Layer *s_alarm_highlight_layer; static Layer *s_alarm_highlight_layer;
static MenuLayer *s_drop_menu_layer; static MenuLayer *s_drop_menu_layer;
static TriangleLayer *s_triangle_layer;
// fonts // fonts
//// setter //// setter
@@ -546,11 +547,16 @@ static void alarm_window_load() {
layer_set_update_proc(s_alarm_highlight_layer, alarm_highlight_layer_update_proc); layer_set_update_proc(s_alarm_highlight_layer, alarm_highlight_layer_update_proc);
layer_add_child(window_layer, s_alarm_highlight_layer); layer_add_child(window_layer, s_alarm_highlight_layer);
// triangle
s_triangle_layer = triangle_layer_create(GRect(0, s_top_bar_grect.size.h + 1, PBL_DISPLAY_WIDTH, PBL_DISPLAY_HEIGHT - (s_top_bar_grect.size.h * 2)));
layer_add_child(window_layer, s_triangle_layer->layer);
schedule_fallback_alarm(); schedule_fallback_alarm();
tick_timer_service_subscribe(SECOND_UNIT, alarm_seconds_handler); tick_timer_service_subscribe(SECOND_UNIT, alarm_seconds_handler);
} }
static void alarm_window_unload() { static void alarm_window_unload() {
triangle_layer_destroy(s_triangle_layer);
layer_destroy(s_alarm_highlight_layer); layer_destroy(s_alarm_highlight_layer);
layer_destroy(s_division_layer); layer_destroy(s_division_layer);
text_layer_destroy(s_parenthesis_txt_layer); text_layer_destroy(s_parenthesis_txt_layer);
+108
View File
@@ -0,0 +1,108 @@
#include "triangles.h"
#include <pebble.h>
static void triangle_layer_update_proc(Layer *layer, GContext *ctx) {
// retrieve the TriangleLayer pointer stored in the layer's data slot
TriangleLayer *tri = *(TriangleLayer **)layer_get_data(layer);
if (!tri)
return;
GRect bounds = layer_get_bounds(layer);
graphics_context_set_stroke_color(ctx, tri->color);
// pick the longest side as the horizontal base
uint16_t base_side, left_side;
uint8_t left_angle;
if (tri->side_a >= tri->side_b && tri->side_a >= tri->side_c) {
base_side = tri->side_a;
left_side = tri->side_c; // C → A
left_angle = tri->angle_B; // at vertex B
} else if (tri->side_b >= tri->side_a && tri->side_b >= tri->side_c) {
base_side = tri->side_b;
left_side = tri->side_c; // C → B
left_angle = tri->angle_A; // at vertex A
} else {
base_side = tri->side_c;
left_side = tri->side_b; // B → C
left_angle = tri->angle_A; // at vertex A
}
// draw the base, centered horizontally
// TODO center whole triangle vertically
uint16_t padded_base = (base_side % 2 == 0) ? base_side : base_side + 1;
uint16_t margin = (bounds.size.w / 2) - (padded_base / 2);
uint16_t start_x = margin + 1;
uint16_t end_x = margin + base_side;
uint16_t base_y = bounds.size.h - 5; // small bottom margin
graphics_draw_line(ctx, GPoint(start_x, base_y), GPoint(end_x, base_y));
// determine height and apex coordinates
int32_t sin_left = sin_lookup(((int32_t)left_angle * TRIG_MAX_ANGLE) / 360);
int32_t cos_left = cos_lookup(((int32_t)left_angle * TRIG_MAX_ANGLE) / 360);
uint16_t height = (uint16_t)(((uint32_t)left_side * (uint32_t)sin_left) / TRIG_MAX_RATIO);
uint16_t apex_offset = (uint16_t)(((uint32_t)left_side * (uint32_t)cos_left) / TRIG_MAX_RATIO);
uint16_t apex_x = start_x + apex_offset;
uint16_t apex_y = base_y - height;
// draw the remaining sides
graphics_draw_line(ctx, GPoint(start_x, base_y), GPoint(apex_x, apex_y));
graphics_draw_line(ctx, GPoint(end_x, base_y), GPoint(apex_x, apex_y));
}
TriangleLayer *triangle_layer_create(GRect frame) {
TriangleLayer *tri = malloc(sizeof(TriangleLayer));
if (!tri)
return NULL;
// determine angles
uint8_t r1, r2;
do {
r1 = 1 + (rand() % 179); // 1178
r2 = 1 + (rand() % 179); // 1178
if (r1 > r2) {
uint8_t tmp = r1;
r1 = r2;
r2 = tmp;
}
} while (r1 == 60 && r2 == 120); // ensure never equilateral
tri->angle_A = r1;
tri->angle_B = r2 - r1;
tri->angle_C = 180 - r2;
// determine side lengths (law of sines)
int32_t sin_A = sin_lookup(((int32_t)tri->angle_A * TRIG_MAX_ANGLE) / 360);
int32_t sin_B = sin_lookup(((int32_t)tri->angle_B * TRIG_MAX_ANGLE) / 360);
int32_t sin_C = sin_lookup(((int32_t)tri->angle_C * TRIG_MAX_ANGLE) / 360);
int32_t max_sin = sin_A;
if (sin_B > max_sin)
max_sin = sin_B;
if (sin_C > max_sin)
max_sin = sin_C;
// longest side randomly chosen
#define MIN_SIDE 10
uint16_t max_side = (frame.size.w < frame.size.h) ? frame.size.w : frame.size.h;
max_side = max_side - 12; // basic margin
uint16_t largest_side = MIN_SIDE + (rand() % (max_side - MIN_SIDE + 1));
tri->side_a = (uint16_t)(((uint32_t)sin_A * largest_side) / (uint32_t)max_sin);
tri->side_b = (uint16_t)(((uint32_t)sin_B * largest_side) / (uint32_t)max_sin);
tri->side_c = (uint16_t)(((uint32_t)sin_C * largest_side) / (uint32_t)max_sin);
// create layer with room for a pointer-sized data slot & store the TriangleLayer* there
tri->layer = layer_create_with_data(frame, sizeof(TriangleLayer *));
*(TriangleLayer **)layer_get_data(tri->layer) = tri;
layer_set_update_proc(tri->layer, triangle_layer_update_proc);
return tri;
}
void triangle_layer_destroy(TriangleLayer *tri) {
if (!tri)
return;
layer_destroy(tri->layer);
free(tri);
}
+20
View File
@@ -0,0 +1,20 @@
#pragma once
#include <pebble.h>
typedef struct {
Layer *layer;
GColor color;
// angles; none of these are shown to the user, but they are needed to make the triangle
uint8_t angle_A;
uint8_t angle_B;
uint8_t angle_C;
// side lengths; two of these are shown to the user (up to 3 digits)
uint16_t side_a;
uint16_t side_b;
uint16_t side_c;
} __attribute__((__packed__)) TriangleLayer;
TriangleLayer *triangle_layer_create(GRect frame);
void triangle_layer_destroy(TriangleLayer *tri);