#include "triangles.h" #include static void right_triangle_layer_update_proc(Layer *layer, GContext *ctx) { // retrieve the RightTriangleLayer pointer stored in the layer's data slot RightTriangleLayer *tri = *(RightTriangleLayer **)layer_get_data(layer); if (!tri) return; GRect bounds = layer_get_bounds(layer); graphics_context_set_stroke_color(ctx, tri->color); // side a guaranteed longest uint16_t base_side = tri->side_a; // compute height and apex offset from side lengths uint16_t height = (uint16_t)(((uint32_t)tri->side_b * tri->side_c) / tri->side_a); uint16_t apex_offset = (uint16_t)(((uint32_t)tri->side_c * tri->side_c) / tri->side_a); // center 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 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)); // circle theta angle graphics_context_set_stroke_color(ctx, GColorRed); graphics_draw_circle(ctx, GPoint(tri->theta_angle_is_left ? start_x : end_x, base_y), 4); } RightTriangleLayer *right_triangle_layer_create(GRect frame, GColor color) { RightTriangleLayer *tri = malloc(sizeof(RightTriangleLayer)); if (!tri) return NULL; // set color tri->color = color; // determine angles tri->angle_A = 90; // right angle at apex tri->theta_angle_is_left = rand() % 2; uint16_t min_hyp = (frame.size.w < frame.size.h) ? frame.size.w / 2 : frame.size.h / 2; uint16_t max_hyp = (frame.size.w < frame.size.h) ? frame.size.w : frame.size.h; // regenerate until no two sides share a length do { tri->angle_B = 5 + rand() % 81; // acute angle at left base vertex tri->angle_C = 90 - tri->angle_B; // acute angle at right base vertex // choose hypotenuse length randomly tri->side_a = min_hyp + (rand() % (max_hyp - min_hyp + 1)); // legs: side_b = hyp × sin(B), side_c = hyp × sin(C) = hyp × cos(B) 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); tri->side_b = (uint16_t)(((uint32_t)sin_B * tri->side_a) / TRIG_MAX_RATIO); tri->side_c = (uint16_t)(((uint32_t)sin_C * tri->side_a) / TRIG_MAX_RATIO); } while (tri->side_a == tri->side_b || tri->side_a == tri->side_c || tri->side_b == tri->side_c); // create layer with room for a pointer-sized data slot & store the RightTriangleLayer* there tri->layer = layer_create_with_data(frame, sizeof(RightTriangleLayer *)); *(RightTriangleLayer **)layer_get_data(tri->layer) = tri; layer_set_update_proc(tri->layer, right_triangle_layer_update_proc); return tri; } void right_triangle_layer_destroy(RightTriangleLayer *tri) { if (!tri) return; layer_destroy(tri->layer); free(tri); }