#include "triangles.h" #include 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 } // calculate height and horizontal apex offset first 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); // center the triangle both horizontally and 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 + height) / 2; uint16_t apex_x = start_x + apex_offset; uint16_t apex_y = base_y - height; // draw the three sides graphics_draw_line(ctx, GPoint(start_x, base_y), GPoint(end_x, base_y)); 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, GColor color) { TriangleLayer *tri = malloc(sizeof(TriangleLayer)); if (!tri) return NULL; // set color tri->color = color; // determine angles uint8_t r1, r2; do { r1 = 10 + (rand() % 151); // 10–160 (angle_A ≥ 10) r2 = (r1 + 10) + (rand() % (161 - r1)); // r1+10 … 170 (angles B,C ≥ 10) } 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 uint16_t min_length_of_longest_side = (frame.size.w < frame.size.h) ? frame.size.w / 2 : frame.size.h / 2; uint16_t max_length_of_longest_side = (frame.size.w < frame.size.h) ? frame.size.w : frame.size.h; uint16_t largest_side = min_length_of_longest_side + (rand() % (max_length_of_longest_side - min_length_of_longest_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); }