21 #define _USE_MATH_DEFINES // for M_PI
24 #include "allheaders.h"
52 static bool atan_table_init =
false;
53 atan_table_mutex.
Lock();
54 if (!atan_table_init) {
59 atan_table_init =
true;
67 return FCOORD(cos_table[theta], sin_table[theta]);
82 &cn_features, fx_info,
nullptr);
86 int num_features = fx_info->
NumCN;
87 if (num_features > 0) {
94 topleft.
x = box.
left();
95 topleft.
y = box.
top();
98 TPOINT original_topleft, original_botright;
101 sample->set_bounding_box(
TBOX(original_topleft.
x, original_botright.
y,
102 original_botright.
x, original_topleft.
y));
133 FCOORD center, second_moments;
135 if (fx_info !=
nullptr) {
145 1.0f, 1.0f, 128.0f, 128.0f);
147 if (nonlinear_norm) {
155 0.0f, 0.0f, x_coords, y_coords);
158 center.
x(), center.
y(),
159 51.2f / second_moments.
x(),
160 51.2f / second_moments.
y(),
167 static uint8_t NormalizeDirection(uint8_t dir,
const FCOORD& unnormed_pos,
169 const DENORM* root_denorm) {
173 unnormed_end += unnormed_pos;
174 FCOORD normed_pos, normed_end;
175 denorm.
NormTransform(root_denorm, unnormed_pos, &normed_pos);
176 denorm.
NormTransform(root_denorm, unnormed_end, &normed_end);
177 normed_end -= normed_pos;
184 static FCOORD MeanDirectionVector(
const LLSQ& point_diffs,
const LLSQ& dirs,
188 if (dirs.
count() > 0) {
193 double mean_dir = 0.0;
195 mean_dir = mean_pt.
x();
197 mean_dir = mean_pt.
y() + 128;
204 FCOORD feature_dir(end_pt - start_pt);
206 if (fit_vector.
x() == 0.0f && fit_vector.
y() == 0.0f) {
208 fit_vector = feature_dir;
213 FCOORD fit_vector2 = !fit_vector;
216 if (fit_vector % feature_dir < 0.0)
217 fit_vector = -fit_vector;
218 if (fit_vector2 % feature_dir < 0.0)
219 fit_vector2 = -fit_vector2;
222 if (fit_vector2 % feature_dir > fit_vector % feature_dir)
223 fit_vector = fit_vector2;
233 static int ComputeFeatures(
const FCOORD& start_pt,
const FCOORD& end_pt,
234 double feature_length,
236 FCOORD feature_vector(end_pt - start_pt);
237 if (feature_vector.x() == 0.0f && feature_vector.y() == 0.0f)
return 0;
239 uint8_t theta = feature_vector.to_direction();
241 double target_length = feature_vector.length();
242 int num_features =
IntCastRounded(target_length / feature_length);
243 if (num_features == 0)
return 0;
245 double lambda_step = 1.0 / num_features;
246 double lambda = lambda_step / 2.0;
247 for (
int f = 0; f < num_features; ++f, lambda += lambda_step) {
248 FCOORD feature_pt(start_pt);
249 feature_pt += feature_vector * lambda;
270 static int GatherPoints(
const C_OUTLINE* outline,
double feature_length,
272 int start_index,
int end_index,
276 ICOORD step = outline->
step(start_index % step_length);
285 for (index = start_index; index <= end_index; ++index, *pos += step) {
286 step = outline->
step(index % step_length);
288 if (edge_weight == 0) {
295 if (num_points == 0) {
297 prev_normed = *pos_normed;
299 FCOORD offset = *pos_normed - prev_normed;
300 float length = offset.
length();
301 if (length > feature_length) {
307 points->
add(pos_normed->
x(), pos_normed->
y(), edge_weight);
309 if (direction >= 0) {
310 direction = NormalizeDirection(direction, f_pos, denorm, root_denorm);
313 dirs->
add(direction,
Modulo(direction + 128, 256));
326 static void ExtractFeaturesFromRun(
328 const DENORM& denorm,
double feature_length,
bool force_poly,
332 if (outline !=
nullptr && !force_poly) {
336 int total_features = 0;
346 if (end_index <= start_index)
347 end_index += step_length;
351 denorm.
NormTransform(root_denorm, prev_normed_pos, &prev_normed_pos);
354 FCOORD normed_pos(0.0f, 0.0f);
355 int index = GatherPoints(outline, feature_length, denorm, root_denorm,
356 start_index, end_index, &pos, &normed_pos,
358 while (index <= end_index) {
366 FCOORD next_normed_pos(0.0f, 0.0f);
367 index = GatherPoints(outline, feature_length, denorm, root_denorm,
368 index, end_index, &pos, &next_normed_pos,
369 &next_points, &next_dirs);
370 LLSQ sum_points(prev_points);
374 sum_points.add(points);
375 sum_points.add(next_points);
376 sum_dirs.add(next_dirs);
377 bool made_features =
false;
379 if (sum_points.count() > 0) {
381 FCOORD fit_pt = sum_points.mean_point();
382 FCOORD fit_vector = MeanDirectionVector(sum_points, sum_dirs,
383 prev_normed_pos, normed_pos);
391 if (total_features == 0 && startpt != endpt) {
395 if (index > end_index && startpt != endpt) {
399 int num_features = ComputeFeatures(start_pos, end_pos, feature_length,
401 if (num_features > 0) {
403 prev_points = points;
405 prev_normed_pos = normed_pos;
406 points = next_points;
408 made_features =
true;
409 total_features += num_features;
412 normed_pos = next_normed_pos;
414 if (!made_features) {
417 points.
add(next_points);
423 const EDGEPT* pt = startpt;
429 ComputeFeatures(start_pos, end_pos, feature_length, features);
430 }
while ((pt = pt->
next) != endpt);
448 DENORM bl_denorm, cn_denorm;
450 &bl_denorm, &cn_denorm, results);
451 if (outline_cn_counts !=
nullptr)
456 EDGEPT* loop_pt = ol->FindBestStartPt();
458 if (pt ==
nullptr)
continue;
464 last_pt = last_pt->
next;
465 }
while (last_pt != loop_pt && !last_pt->
IsHidden() &&
467 last_pt = last_pt->
prev;
475 }
while ((pt = pt->
next) != loop_pt);
476 if (outline_cn_counts !=
nullptr)