| 3139 | } |
| 3140 | |
| 3141 | void MapEditorController::connectPathsClicked() |
| 3142 | { |
| 3143 | std::vector<Object*> objects; |
| 3144 | std::vector<Object*> undo_objects; |
| 3145 | std::vector<Object*> deleted_objects; |
| 3146 | |
| 3147 | // Collect all objects in question |
| 3148 | objects.reserve(map->getNumSelectedObjects()); |
| 3149 | undo_objects.reserve(map->getNumSelectedObjects()); |
| 3150 | for (auto* object : map->selectedObjects()) |
| 3151 | { |
| 3152 | if (object->getSymbol()->getContainedTypes() & Symbol::Line && object->getType() == Object::Path) |
| 3153 | { |
| 3154 | object->update(); |
| 3155 | objects.push_back(object); |
| 3156 | undo_objects.push_back(nullptr); |
| 3157 | } |
| 3158 | } |
| 3159 | |
| 3160 | AddObjectsUndoStep* add_step = nullptr; |
| 3161 | MapPart* part = map->getCurrentPart(); |
| 3162 | |
| 3163 | /// \todo Fix connectPathsClicked() |
| 3164 | #ifndef __clang_analyzer__ |
| 3165 | while (true) |
| 3166 | { |
| 3167 | // Find the closest pair of open ends of objects with the same symbol, |
| 3168 | // which is closer than a threshold |
| 3169 | PathObject* best_object_a = nullptr; |
| 3170 | PathObject* best_object_b = nullptr; |
| 3171 | int best_object_a_index = 0; |
| 3172 | int best_object_b_index = 0; |
| 3173 | auto best_part_a = PathPartVector::size_type { 0 }; |
| 3174 | auto best_part_b = PathPartVector::size_type { 0 }; |
| 3175 | bool best_part_a_begin = false; |
| 3176 | bool best_part_b_begin = false; |
| 3177 | float best_dist_sq = std::numeric_limits<float>::max(); |
| 3178 | |
| 3179 | for (int i = 0; i < (int)objects.size(); ++i) |
| 3180 | { |
| 3181 | PathObject* a = reinterpret_cast<PathObject*>(objects[i]); |
| 3182 | |
| 3183 | // Choose connection threshold as maximum of 0.35mm, 1.5 * largest line extent, and 6 pixels |
| 3184 | // TODO: instead of 6 pixels, use a physical size as soon as screen dpi is in the settings |
| 3185 | auto close_distance_sq = qMax(0.35, 1.5 * a->getSymbol()->calculateLargestLineExtent()); |
| 3186 | close_distance_sq = qMax(close_distance_sq, 0.001 * main_view->pixelToLength(6)); |
| 3187 | close_distance_sq = qPow(close_distance_sq, 2); |
| 3188 | |
| 3189 | auto num_parts = a->parts().size(); |
| 3190 | for (PathPartVector::size_type path_part_a = 0; path_part_a < num_parts; ++path_part_a) |
| 3191 | { |
| 3192 | PathPart& part = a->parts()[path_part_a]; |
| 3193 | if (!part.isClosed()) |
| 3194 | { |
| 3195 | PathObject* b; |
| 3196 | int b_index; |
| 3197 | int path_part_b; |
| 3198 | bool path_part_b_begin; |
nothing calls this directly
no test coverage detected