Files
Trigalarm/src/c/triangles.c
T

105 lines
3.8 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 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); // 10160 (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);
}