MapCoord SnappingToolHelper::snapToObject(MapCoordF position, MapWidget* widget, SnappingToolHelperSnapInfo* info, Object* exclude_object, float snap_distance) { if (snap_distance < 0) snap_distance = 0.001f * widget->getMapView()->pixelToLength(Settings::getInstance().getMapEditorSnapDistancePx()); float closest_distance_sq = snap_distance * snap_distance; auto result_position = MapCoord { position }; SnappingToolHelperSnapInfo result_info; result_info.type = NoSnapping; result_info.object = NULL; result_info.coord_index = -1; result_info.path_coord.pos = MapCoordF(0, 0); result_info.path_coord.index = -1; result_info.path_coord.clen = -1; result_info.path_coord.param = -1; if (filter & (ObjectCorners | ObjectPaths)) { // Find map objects at the given position SelectionInfoVector objects; map->findAllObjectsAt(position, snap_distance, true, false, false, true, objects); // Find closest snap spot from map objects for (SelectionInfoVector::const_iterator it = objects.begin(), end = objects.end(); it != end; ++it) { Object* object = it->second; if (object == exclude_object) continue; float distance_sq; if (object->getType() == Object::Point && filter & ObjectCorners) { PointObject* point = object->asPoint(); distance_sq = point->getCoordF().distanceSquaredTo(position); if (distance_sq < closest_distance_sq) { closest_distance_sq = distance_sq; result_position = point->getCoord(); result_info.type = ObjectCorners; result_info.object = object; result_info.coord_index = 0; } } else if (object->getType() == Object::Path) { PathObject* path = object->asPath(); if (filter & ObjectPaths) { PathCoord path_coord; path->calcClosestPointOnPath(position, distance_sq, path_coord); if (distance_sq < closest_distance_sq) { closest_distance_sq = distance_sq; result_position = MapCoord(path_coord.pos); result_info.object = object; if (path_coord.param == 0.0) { result_info.type = ObjectCorners; result_info.coord_index = path_coord.index; } else { result_info.type = ObjectPaths; result_info.coord_index = -1; result_info.path_coord = path_coord; } } } else { MapCoordVector::size_type index; path->calcClosestCoordinate(position, distance_sq, index); if (distance_sq < closest_distance_sq) { closest_distance_sq = distance_sq; result_position = path->getCoordinate(index); result_info.type = ObjectCorners; result_info.object = object; result_info.coord_index = index; } } } else if (object->getType() == Object::Text) { // No snapping to texts continue; } } } // Find closest grid snap position if ((filter & GridCorners) && widget->getMapView()->isGridVisible() && map->getGrid().isSnappingEnabled() && map->getGrid().getDisplayMode() == MapGrid::AllLines) { MapCoordF closest_grid_point = map->getGrid().getClosestPointOnGrid(position, map); float distance_sq = closest_grid_point.distanceSquaredTo(position); if (distance_sq < closest_distance_sq) { closest_distance_sq = distance_sq; result_position = MapCoord(closest_grid_point); result_info.type = GridCorners; result_info.object = NULL; result_info.coord_index = -1; } } // Return if (snap_mark != result_position || snapped_type != result_info.type) { snap_mark = result_position; snapped_type = result_info.type; emit displayChanged(); } if (info != NULL) *info = result_info; return result_position; }