Files
Trigalarm/src/c/triangles.c
T

83 lines
3.1 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#include "triangles.h"
#include <pebble.h>
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);
}