mirror of
https://github.com/google/pebble.git
synced 2025-03-20 19:01:21 +00:00
118 lines
4.5 KiB
C
118 lines
4.5 KiB
C
/*
|
|
* Copyright 2024 Google LLC
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
#include "applib/graphics/perimeter.h"
|
|
|
|
#include "clar.h"
|
|
#include "util/trig.h"
|
|
|
|
#include <string.h>
|
|
#include <stdio.h>
|
|
|
|
#include <math.h>
|
|
#ifndef M_PI
|
|
// M_PI doesn't exist in Linux
|
|
#define M_PI 3.14159265358979323846 /* pi */
|
|
#endif
|
|
#define DEG2RAD(a) (M_PI/180*(a))
|
|
|
|
// Stubs
|
|
////////////////////////////////////
|
|
#include "stubs_heap.h"
|
|
#include "stubs_passert.h"
|
|
#include "stubs_logging.h"
|
|
#include "stubs_app_state.h"
|
|
#include "stubs_compiled_with_legacy2_sdk.h"
|
|
|
|
#define BETWEEN(val, low, high) \
|
|
(val >= low && val <= high) ? true : false
|
|
|
|
// Tests
|
|
////////////////////////////////////
|
|
|
|
GRangeHorizontal perimeter_for_circle(GRangeVertical vertical_range, GPoint center, int32_t radius);
|
|
GRangeHorizontal perimeter_for_display_round(const GPerimeter *perimeter,
|
|
const GSize *ctx_size,
|
|
GRangeVertical vertical_range,
|
|
uint16_t inset);
|
|
GRangeHorizontal perimeter_for_display_rect(const GPerimeter *perimeter,
|
|
const GSize *ctx_size,
|
|
GRangeVertical vertical_range,
|
|
uint16_t inset);
|
|
|
|
void test_perimeter__perimeter_for_circle(void) {
|
|
GRect bounds = GRect(0,0,180,180);
|
|
GPoint center = grect_center_point(&bounds);
|
|
int16_t radius = bounds.size.w / 2;
|
|
|
|
// test robustness of perimeter_horizontal_range_for_circle
|
|
for (int y = 0; y < bounds.size.h; y++) {
|
|
GRangeHorizontal h_range = perimeter_for_circle(
|
|
(GRangeVertical) {.origin_y = y, .size_h = 0}, center, radius);
|
|
|
|
// internally we use integer_sqrt, which causes precision loss
|
|
// so we need to mirror some of the fixed point truncation here
|
|
int16_t height = 90 - y;
|
|
int16_t width = sqrt(radius * radius - height * height);
|
|
int16_t test_origin = 90 - width;
|
|
|
|
// Due to integer math and truncation, we need to test +-1
|
|
cl_assert(BETWEEN(h_range.origin_x, test_origin - 1, test_origin + 1));
|
|
cl_assert(BETWEEN(h_range.size_w, (width - 1) * 2, (width + 1) * 2));
|
|
}
|
|
}
|
|
|
|
#define cl_assert_equal_rangehorizontal(r1, r2) \
|
|
do { \
|
|
cl_assert_equal_i((r1).origin_x, (r2).origin_x); \
|
|
cl_assert_equal_i((r1).size_w, (r2).size_w); \
|
|
} while(0)
|
|
|
|
void test_perimeter__perimeter_for_display_rect(void) {
|
|
GPerimeter p = {
|
|
.callback = perimeter_for_display_rect,
|
|
};
|
|
const GSize ctx_size = GSize(DISP_COLS, DISP_ROWS);
|
|
GRangeVertical r = {.origin_y = 10, .size_h = 10};
|
|
|
|
GRangeHorizontal expected = (GRangeHorizontal){.origin_x = 0, .size_w = DISP_COLS};
|
|
cl_assert_equal_rangehorizontal(expected, perimeter_for_display_rect(&p, &ctx_size, r, 0));
|
|
expected = (GRangeHorizontal){.origin_x = 5, .size_w = DISP_COLS - 10};
|
|
cl_assert_equal_rangehorizontal(expected, perimeter_for_display_rect(&p, &ctx_size, r, 5));
|
|
cl_assert_equal_i(0, perimeter_for_display_rect(&p, &ctx_size, r, 500).size_w);
|
|
}
|
|
|
|
void test_perimeter__perimeter_for_display_round(void) {
|
|
GPerimeter p = {
|
|
.callback = perimeter_for_display_round,
|
|
};
|
|
GRangeVertical r = {.origin_y = 10, .size_h = 10};
|
|
const GSize ctx_size = GSize(DISP_COLS, DISP_ROWS);
|
|
const GRect disp = GRect(0, 0, DISP_COLS, DISP_ROWS);
|
|
|
|
GRangeHorizontal expected =
|
|
perimeter_for_circle(r, grect_center_point(&disp), grect_shortest_side(disp) / 2);
|
|
cl_assert_equal_rangehorizontal(expected, perimeter_for_display_round(&p, &ctx_size, r, 0));
|
|
expected = perimeter_for_circle(r, grect_center_point(&disp), grect_shortest_side(disp) / 2 - 5);
|
|
cl_assert_equal_rangehorizontal(expected, perimeter_for_display_round(&p, &ctx_size, r, 5));
|
|
cl_assert_equal_i(0, perimeter_for_display_round(&p, &ctx_size, r, 500).size_w);
|
|
}
|
|
|
|
void test_perimeter__g_perimeter_for_display(void) {
|
|
GPerimeterCallback expected = PBL_IF_RECT_ELSE(perimeter_for_display_rect,
|
|
perimeter_for_display_round);
|
|
cl_assert_equal_p(expected, g_perimeter_for_display->callback);
|
|
}
|