gcc_pure ClosingPair FindRange(const ClosingPair &p) const { for (const auto &i : closing_pairs) { if (i.first > p.first) break; if (i.second >= p.second) return i; } return ClosingPair(0, 0); }
bool OLCTriangle::FindClosingPairs(unsigned old_size) { if (predict) { return closing_pairs.Insert(ClosingPair(0, n_points-1)); } struct TracePointNode { const TracePoint *point; unsigned index; }; struct TracePointNodeAccessor { gcc_pure int GetX(const TracePointNode &node) const { return node.point->GetFlatLocation().x; } gcc_pure int GetY(const TracePointNode &node) const { return node.point->GetFlatLocation().y; } }; QuadTree<TracePointNode, TracePointNodeAccessor> search_point_tree; for (unsigned i = old_size; i < n_points; ++i) { TracePointNode node; node.point = &GetPoint(i); node.index = i; search_point_tree.insert(node); } search_point_tree.Optimise(); bool new_pair = false; for (unsigned i = old_size; i < n_points; ++i) { TracePointNode point; point.point = &GetPoint(i); point.index = i; const SearchPoint start = *point.point; const unsigned max_range = trace_master.ProjectRange(start.GetLocation(), max_distance); const unsigned half_max_range_sq = max_range * max_range / 2; const int min_altitude = GetMinimumFinishAltitude(*point.point); const int max_altitude = GetMaximumStartAltitude(*point.point); unsigned last = 0, first = i; const auto visitor = [this, i, start, half_max_range_sq, min_altitude, max_altitude, &first, &last] (const TracePointNode &node) { const auto &dest = *node.point; if (node.index + 2 < i && dest.GetIntegerAltitude() <= max_altitude && IsInRange(start, dest, half_max_range_sq, max_distance)) { // point i is last point first = std::min(node.index, first); last = i; } else if (node.index > i + 2 && dest.GetIntegerAltitude() >= min_altitude && IsInRange(start, dest, half_max_range_sq, max_distance)) { // point i is first point first = i; last = std::max(node.index, last); } }; search_point_tree.VisitWithinRange(point, max_range, visitor); if (last != 0 && closing_pairs.Insert(ClosingPair(first, last))) new_pair = true; } return new_pair; }
void OLCTriangle::SolveTriangle(bool exhaustive) { unsigned tp1 = 0, tp2 = 0, tp3 = 0, start = 0, finish = 0; if (exhaustive || !predict) { ClosingPairs relaxed_pairs; unsigned relax = n_points * 0.03; // for all closed trace loops for (auto closing_pair = closing_pairs.closing_pairs.begin(); closing_pair != closing_pairs.closing_pairs.end(); ++closing_pair) { auto already_relaxed = relaxed_pairs.FindRange(*closing_pair); if (already_relaxed.first != 0 || already_relaxed.second != 0) // this pair is already relaxed... continue with next continue; unsigned relax_first = closing_pair->first; unsigned relax_last = closing_pair->second; const unsigned max_first = closing_pair->first + relax; const unsigned max_last = closing_pair->second + relax; for (auto relaxed = std::next(closing_pair); relaxed != closing_pairs.closing_pairs.end() && relaxed->first <= max_first && relaxed->second <= max_last; ++relaxed) relax_last = std::max(relax_last, relaxed->second); relaxed_pairs.Insert(ClosingPair(relax_first, relax_last)); } // TODO: reverse sort relaxed pairs according to number of contained points ClosingPairs close_look; for (const auto relaxed_pair : relaxed_pairs.closing_pairs) { std::tuple<unsigned, unsigned, unsigned, unsigned> triangle; triangle = RunBranchAndBound(relaxed_pair.first, relaxed_pair.second, best_d, exhaustive); if (std::get<3>(triangle) > best_d) { // solution is better than best_d // only if triangle is inside a unrelaxed pair... auto unrelaxed = closing_pairs.FindRange(ClosingPair(std::get<0>(triangle), std::get<2>(triangle))); if (unrelaxed.first != 0 || unrelaxed.second != 0) { // fortunately it is inside a unrelaxed closing pair :-) start = unrelaxed.first; tp1 = std::get<0>(triangle); tp2 = std::get<1>(triangle); tp3 = std::get<2>(triangle); finish = unrelaxed.second; best_d = std::get<3>(triangle); } else { // otherwise we should solve the triangle again for every unrelaxed pair // contained inside the current relaxed pair. *damn!* for (const auto closing_pair : closing_pairs.closing_pairs) { if (closing_pair.first >= relaxed_pair.first && closing_pair.second <= relaxed_pair.second) close_look.Insert(closing_pair); } } } } for (const auto &close_look_pair : close_look.closing_pairs) { std::tuple<unsigned, unsigned, unsigned, unsigned> triangle; triangle = RunBranchAndBound(close_look_pair.first, close_look_pair.second, best_d, exhaustive); if (std::get<3>(triangle) > best_d) { // solution is better than best_d start = close_look_pair.first; tp1 = std::get<0>(triangle); tp2 = std::get<1>(triangle); tp3 = std::get<2>(triangle); finish = close_look_pair.second; best_d = std::get<3>(triangle); } } } else { /** * We're currently running in predictive, non-exhaustive mode, so we use * one closing pair only (0 -> n_points-1) which allows us to suspend the * solver... */ std::tuple<unsigned, unsigned, unsigned, unsigned> triangle; triangle = RunBranchAndBound(0, n_points - 1, best_d, false); if (std::get<3>(triangle) > best_d) { // solution is better than best_d start = 0; tp1 = std::get<0>(triangle); tp2 = std::get<1>(triangle); tp3 = std::get<2>(triangle); finish = n_points - 1; best_d = std::get<3>(triangle); } } if (best_d > 0) { solution.resize(5); solution[0] = TraceManager::GetPoint(start); solution[1] = TraceManager::GetPoint(tp1); solution[2] = TraceManager::GetPoint(tp2); solution[3] = TraceManager::GetPoint(tp3); solution[4] = TraceManager::GetPoint(finish); is_complete = true; } }