21 #define _USE_MATH_DEFINES // for M_PI
25 #include "allheaders.h"
51 static std::mutex atan_table_mutex;
52 static bool atan_table_init =
false;
53 std::lock_guard<std::mutex> guard(atan_table_mutex);
54 if (!atan_table_init) {
59 atan_table_init =
true;
66 return FCOORD(cos_table[theta], sin_table[theta]);
81 &cn_features, fx_info,
nullptr);
85 int num_features = fx_info->
NumCN;
86 if (num_features > 0) {
93 topleft.
x = box.
left();
94 topleft.
y = box.
top();
97 TPOINT original_topleft, original_botright;
100 sample->set_bounding_box(
TBOX(original_topleft.
x, original_botright.
y,
101 original_botright.
x, original_topleft.
y));
132 FCOORD center, second_moments;
134 if (fx_info !=
nullptr) {
144 1.0f, 1.0f, 128.0f, 128.0f);
146 if (nonlinear_norm) {
154 0.0f, 0.0f, x_coords, y_coords);
157 center.
x(), center.
y(),
158 51.2f / second_moments.
x(),
159 51.2f / second_moments.
y(),
166 static uint8_t NormalizeDirection(uint8_t dir,
const FCOORD& unnormed_pos,
168 const DENORM* root_denorm) {
172 unnormed_end += unnormed_pos;
173 FCOORD normed_pos, normed_end;
174 denorm.
NormTransform(root_denorm, unnormed_pos, &normed_pos);
175 denorm.
NormTransform(root_denorm, unnormed_end, &normed_end);
176 normed_end -= normed_pos;
183 static FCOORD MeanDirectionVector(
const LLSQ& point_diffs,
const LLSQ& dirs,
187 if (dirs.
count() > 0) {
192 double mean_dir = 0.0;
194 mean_dir = mean_pt.
x();
196 mean_dir = mean_pt.
y() + 128;
203 FCOORD feature_dir(end_pt - start_pt);
205 if (fit_vector.
x() == 0.0f && fit_vector.
y() == 0.0f) {
207 fit_vector = feature_dir;
212 FCOORD fit_vector2 = !fit_vector;
215 if (fit_vector % feature_dir < 0.0)
216 fit_vector = -fit_vector;
217 if (fit_vector2 % feature_dir < 0.0)
218 fit_vector2 = -fit_vector2;
221 if (fit_vector2 % feature_dir > fit_vector % feature_dir)
222 fit_vector = fit_vector2;
232 static int ComputeFeatures(
const FCOORD& start_pt,
const FCOORD& end_pt,
233 double feature_length,
235 FCOORD feature_vector(end_pt - start_pt);
236 if (feature_vector.x() == 0.0f && feature_vector.y() == 0.0f)
return 0;
238 uint8_t theta = feature_vector.to_direction();
240 double target_length = feature_vector.length();
241 int num_features =
IntCastRounded(target_length / feature_length);
242 if (num_features == 0)
return 0;
244 double lambda_step = 1.0 / num_features;
245 double lambda = lambda_step / 2.0;
246 for (
int f = 0; f < num_features; ++f, lambda += lambda_step) {
247 FCOORD feature_pt(start_pt);
248 feature_pt += feature_vector * lambda;
269 static int GatherPoints(
const C_OUTLINE* outline,
double feature_length,
271 int start_index,
int end_index,
275 ICOORD step = outline->
step(start_index % step_length);
284 for (index = start_index; index <= end_index; ++index, *pos += step) {
285 step = outline->
step(index % step_length);
287 if (edge_weight == 0) {
294 if (num_points == 0) {
296 prev_normed = *pos_normed;
298 FCOORD offset = *pos_normed - prev_normed;
299 float length = offset.
length();
300 if (length > feature_length) {
306 points->
add(pos_normed->
x(), pos_normed->
y(), edge_weight);
308 if (direction >= 0) {
309 direction = NormalizeDirection(direction, f_pos, denorm, root_denorm);
312 dirs->
add(direction,
Modulo(direction + 128, 256));
325 static void ExtractFeaturesFromRun(
327 const DENORM& denorm,
double feature_length,
bool force_poly,
331 if (outline !=
nullptr && !force_poly) {
335 int total_features = 0;
345 if (end_index <= start_index)
346 end_index += step_length;
350 denorm.
NormTransform(root_denorm, prev_normed_pos, &prev_normed_pos);
353 FCOORD normed_pos(0.0f, 0.0f);
354 int index = GatherPoints(outline, feature_length, denorm, root_denorm,
355 start_index, end_index, &pos, &normed_pos,
357 while (index <= end_index) {
365 FCOORD next_normed_pos(0.0f, 0.0f);
366 index = GatherPoints(outline, feature_length, denorm, root_denorm,
367 index, end_index, &pos, &next_normed_pos,
368 &next_points, &next_dirs);
369 LLSQ sum_points(prev_points);
373 sum_points.add(points);
374 sum_points.add(next_points);
375 sum_dirs.add(next_dirs);
376 bool made_features =
false;
378 if (sum_points.count() > 0) {
380 FCOORD fit_pt = sum_points.mean_point();
381 FCOORD fit_vector = MeanDirectionVector(sum_points, sum_dirs,
382 prev_normed_pos, normed_pos);
390 if (total_features == 0 && startpt != endpt) {
394 if (index > end_index && startpt != endpt) {
398 int num_features = ComputeFeatures(start_pos, end_pos, feature_length,
400 if (num_features > 0) {
402 prev_points = points;
404 prev_normed_pos = normed_pos;
405 points = next_points;
407 made_features =
true;
408 total_features += num_features;
411 normed_pos = next_normed_pos;
413 if (!made_features) {
416 points.
add(next_points);
422 const EDGEPT* pt = startpt;
428 ComputeFeatures(start_pos, end_pos, feature_length, features);
429 }
while ((pt = pt->
next) != endpt);
447 DENORM bl_denorm, cn_denorm;
449 &bl_denorm, &cn_denorm, results);
450 if (outline_cn_counts !=
nullptr)
455 EDGEPT* loop_pt = ol->FindBestStartPt();
457 if (pt ==
nullptr)
continue;
463 last_pt = last_pt->
next;
464 }
while (last_pt != loop_pt && !last_pt->
IsHidden() &&
466 last_pt = last_pt->
prev;
474 }
while ((pt = pt->
next) != loop_pt);
475 if (outline_cn_counts !=
nullptr)