| @@ -640,53 +640,21 @@ bool RackWidget::requestModulePos(ModuleWidget* mw, math::Vec pos) { | |||||
| } | } | ||||
| static math::Vec eachNearestGridPos(math::Vec pos, std::function<bool(math::Vec pos)> f) { | static math::Vec eachNearestGridPos(math::Vec pos, std::function<bool(math::Vec pos)> f) { | ||||
| // Dijkstra's algorithm to generate a sorted list of Vecs closest to `pos`. | |||||
| math::Vec leftPos = pos.div(RACK_GRID_SIZE).floor().mult(RACK_GRID_SIZE); | |||||
| math::Vec rightPos = leftPos + math::Vec(RACK_GRID_WIDTH, 0); | |||||
| // Comparison of distance of Vecs to `pos` | |||||
| auto cmpNearest = [&](const math::Vec& a, const math::Vec& b) { | |||||
| return a.minus(pos).square() > b.minus(pos).square(); | |||||
| }; | |||||
| // Comparison of dictionary order of Vecs | |||||
| auto cmp = [](const math::Vec& a, const math::Vec& b) { | |||||
| if (a.y != b.y) | |||||
| return a.y < b.y; | |||||
| return a.x < b.x; | |||||
| }; | |||||
| // Priority queue sorted by distance from `pos` | |||||
| std::priority_queue<math::Vec, std::vector<math::Vec>, decltype(cmpNearest)> queue(cmpNearest); | |||||
| // Set of already-tested Vecs | |||||
| std::set<math::Vec, decltype(cmp)> visited(cmp); | |||||
| // Seed priority queue with closest Vec | |||||
| math::Vec closestPos = pos.div(RACK_GRID_SIZE).round().mult(RACK_GRID_SIZE); | |||||
| queue.push(closestPos); | |||||
| while (!queue.empty()) { | |||||
| math::Vec testPos = queue.top(); | |||||
| // Check testPos | |||||
| if (f(testPos)) | |||||
| return testPos; | |||||
| // Move testPos to visited set | |||||
| queue.pop(); | |||||
| visited.insert(testPos); | |||||
| // Add adjacent Vecs | |||||
| static const std::vector<math::Vec> deltas = { | |||||
| math::Vec(1, 0).mult(RACK_GRID_SIZE), | |||||
| math::Vec(0, 1).mult(RACK_GRID_SIZE), | |||||
| math::Vec(-1, 0).mult(RACK_GRID_SIZE), | |||||
| math::Vec(0, -1).mult(RACK_GRID_SIZE), | |||||
| }; | |||||
| for (math::Vec delta : deltas) { | |||||
| math::Vec newPos = testPos.plus(delta); | |||||
| if (visited.find(newPos) == visited.end()) { | |||||
| queue.push(newPos); | |||||
| } | |||||
| } | |||||
| while (true) { | |||||
| if (f(leftPos)) | |||||
| return leftPos; | |||||
| leftPos.x -= RACK_GRID_WIDTH; | |||||
| if (f(rightPos)) | |||||
| return rightPos; | |||||
| rightPos.x += RACK_GRID_WIDTH; | |||||
| } | } | ||||
| // We failed to find a box. This shouldn't happen on an infinite rack. | |||||
| assert(false); | assert(false); | ||||
| return math::Vec(); | |||||
| return leftPos; | |||||
| } | } | ||||
| void RackWidget::setModulePosNearest(ModuleWidget* mw, math::Vec pos) { | void RackWidget::setModulePosNearest(ModuleWidget* mw, math::Vec pos) { | ||||