GCC Code Coverage Report


Directory: ./
File: backend/src/geometry.cpp
Date: 2025-11-24 00:30:48
Exec Total Coverage
Lines: 0 103 0.0%
Functions: 0 9 0.0%
Branches: 0 110 0.0%

Line Branch Exec Source
1 #include "geometry.hpp"
2
3 #include <algorithm>
4 #include <charconv>
5 #include <cmath>
6
7 float yodau::backend::point::distance_to(const point& other) const {
8 const float dx = x - other.x;
9 const float dy = y - other.y;
10 return std::sqrt(dx * dx + dy * dy);
11 }
12
13 bool yodau::backend::point::compare(const point& other) const {
14 return std::fabs(x - other.x) < epsilon && std::fabs(y - other.y) < epsilon;
15 }
16
17 void yodau::backend::line::dump(std::ostream& out) const {
18 out << "Line(name=" << name << ", closed=" << (closed ? "true" : "false")
19 << ", points=[";
20 for (size_t i = 0; i < points.size(); i++) {
21 out << "(" << points[i].x << ", " << points[i].y << ")";
22 if (i < points.size() - 1) {
23 out << "; ";
24 }
25 }
26 out << "])";
27 }
28
29 void yodau::backend::line::normalize() {
30 const size_t n = points.size();
31 if (n < 2) {
32 return;
33 }
34 constexpr point origin { 0.0f, 0.0f };
35 constexpr point east { 100.0f, 0.0f };
36
37 if (closed) {
38 size_t best_idx = 0;
39 float best_distance = points[0].distance_to(origin);
40
41 for (size_t i = 1; i < n; i++) {
42 float distance = points[i].distance_to(origin);
43 if (distance < best_distance) {
44 best_distance = distance;
45 best_idx = i;
46 }
47 }
48
49 if (best_idx != 0) {
50 const auto it
51 = points.begin() + static_cast<std::ptrdiff_t>(best_idx);
52 std::ranges::rotate(points, it);
53 }
54 }
55
56 const size_t front = closed ? 1 : 0;
57
58 if (n >= 2 + front) {
59 const float first = points[front].distance_to(closed ? east : origin);
60 const float last = points.back().distance_to(closed ? east : origin);
61 if (last < first) {
62 std::reverse(
63 points.begin() + static_cast<std::ptrdiff_t>(front),
64 points.end()
65 );
66 }
67 }
68 }
69
70 bool yodau::backend::line::operator==(const line& other) const {
71 if (closed != other.closed || points.size() != other.points.size()) {
72 return false;
73 }
74 for (size_t i = 0; i < points.size(); i++) {
75 if (!points[i].compare(other.points[i])) {
76 return false;
77 }
78 }
79 return true;
80 }
81
82 yodau::backend::line_ptr yodau::backend::make_line(
83 std::vector<point> points, std::string name, bool closed
84 ) {
85 auto line_ptr = std::make_shared<line>();
86 line_ptr->points = std::move(points);
87 line_ptr->name = std::move(name);
88 line_ptr->closed = closed;
89 line_ptr->normalize();
90 return line_ptr;
91 }
92
93 std::vector<yodau::backend::point>
94 yodau::backend::parse_points(const std::string& points_str) {
95 std::string normalized = normalize_str(points_str);
96 std::string_view input { normalized };
97 std::vector<point> points;
98 size_t start = 0;
99 while (start < input.size()) {
100 size_t end = input.find(';', start);
101 if (end == std::string_view::npos) {
102 end = input.size();
103 }
104 std::string_view segment { input.substr(start, end - start) };
105 if (!segment.empty()) {
106 const size_t comma_pos = segment.find(',');
107 if (comma_pos == std::string_view::npos) {
108 throw std::runtime_error(
109 "Missing comma separator: " + std::string(segment)
110 );
111 }
112 std::string_view x_str = segment.substr(0, comma_pos);
113 std::string_view y_str = segment.substr(comma_pos + 1);
114 if (x_str.empty() || y_str.empty()) {
115 throw std::runtime_error(
116 "Empty coordinate in point: " + std::string(segment)
117 );
118 }
119 float x = parse_float(x_str);
120 float y = parse_float(y_str);
121 points.emplace_back(x, y);
122 }
123 start = end + 1;
124 }
125 if (points.empty()) {
126 throw std::runtime_error(
127 "No valid points found in input: " + points_str
128 );
129 }
130 return points;
131 }
132
133 std::string yodau::backend::normalize_str(const std::string_view str) {
134 std::string normalized;
135 normalized.reserve(str.size());
136 for (const char ch : str) {
137 if (std::isspace(ch) || ch == '(' || ch == ')') {
138 continue;
139 }
140 normalized.push_back(ch);
141 }
142 return normalized;
143 }
144
145 float yodau::backend::parse_float(const std::string_view num_str) {
146 float value {};
147 const char* first = num_str.data();
148 const char* last = num_str.data() + num_str.size();
149 auto [ptr, ec] = std::from_chars(first, last, value);
150 if (ec != std::errc() || ptr != last) {
151 throw std::runtime_error(
152 "Invalid float value: " + std::string(num_str)
153 );
154 }
155 return value;
156 }
157