Limit triangle generator to right triangles

This commit is contained in:
2026-08-07 22:03:21 -04:00
parent 10edcf6305
commit d32f7f1b4b
5 changed files with 42 additions and 76 deletions
+26 -63
View File
@@ -1,27 +1,23 @@
#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);
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 is always the longest side (horizontal base)
// side a guaranteed longest
uint16_t base_side = tri->side_a;
uint16_t left_side = tri->side_c; // C → A (side c connects vertices B and A)
uint8_t left_angle = tri->angle_B; // at vertex B
// 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);
// 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 the triangle both horizontally and vertically
// 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;
@@ -30,14 +26,14 @@ static void triangle_layer_update_proc(Layer *layer, GContext *ctx) {
uint16_t apex_x = start_x + apex_offset;
uint16_t apex_y = base_y - height;
// draw the three sides
// 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));
}
TriangleLayer *triangle_layer_create(GRect frame, GColor color) {
TriangleLayer *tri = malloc(sizeof(TriangleLayer));
RightTriangleLayer *right_triangle_layer_create(GRect frame, GColor color) {
RightTriangleLayer *tri = malloc(sizeof(RightTriangleLayer));
if (!tri)
return NULL;
@@ -45,63 +41,30 @@ TriangleLayer *triangle_layer_create(GRect frame, GColor color) {
tri->color = color;
// determine angles
uint8_t r1, r2;
do {
r1 = 5 + (rand() % 166); // 5170 (angle_A ≥ 5)
r2 = (r1 + 5) + (rand() % (171 - r1)); // r1+5 … 175 (angles B,C ≥ 5)
} while (r1 == 60 && r2 == 120); // ensure never equilateral
tri->angle_A = 90;
tri->angle_B = rand() % 86; // acute angle at left base vertex
tri->angle_C = 90 - tri->angle_B; // acute angle at right base vertex
tri->angle_A = r1;
tri->angle_B = r2 - r1;
tri->angle_C = 180 - r2;
// choose hypotenuse length randomly
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;
tri->side_a = min_hyp + (rand() % (max_hyp - min_hyp + 1));
// determine side lengths (law of sines)
int32_t sin_A = sin_lookup(((int32_t)tri->angle_A * TRIG_MAX_ANGLE) / 360);
// 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);
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);
// ensure side_a is always longest
if (tri->side_b > tri->side_a) {
uint16_t tmp_s = tri->side_a;
tri->side_a = tri->side_b;
tri->side_b = tmp_s;
uint8_t tmp_a = tri->angle_A;
tri->angle_A = tri->angle_B;
tri->angle_B = tmp_a;
}
if (tri->side_c > tri->side_a) {
uint16_t tmp_s = tri->side_a;
tri->side_a = tri->side_c;
tri->side_c = tmp_s;
uint8_t tmp_a = tri->angle_A;
tri->angle_A = tri->angle_C;
tri->angle_C = tmp_a;
}
// 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 triangle_layer_destroy(TriangleLayer *tri) {
void right_triangle_layer_destroy(RightTriangleLayer *tri) {
if (!tri)
return;
layer_destroy(tri->layer);