diff --git a/glomap/estimators/global_rotation_averaging.cc b/glomap/estimators/global_rotation_averaging.cc index 75b46d04..8246b272 100644 --- a/glomap/estimators/global_rotation_averaging.cc +++ b/glomap/estimators/global_rotation_averaging.cc @@ -121,7 +121,7 @@ void RotationEstimator::InitializeFromMaximumSpanningTree( // Directly use the relative pose for estimation rotation const ImagePair& image_pair = view_graph.image_pairs.at( - ImagePair::ImagePairToPairId(curr, parents[curr])); + colmap::ImagePairToPairId(curr, parents[curr])); if (image_pair.image_id1 == curr) { // 1_R_w = 2_R_1^T * 2_R_w cam_from_worlds[curr].rotation = diff --git a/glomap/estimators/gravity_refinement.cc b/glomap/estimators/gravity_refinement.cc index bb19e28d..29f7adb6 100644 --- a/glomap/estimators/gravity_refinement.cc +++ b/glomap/estimators/gravity_refinement.cc @@ -9,12 +9,10 @@ namespace glomap { void GravityRefiner::RefineGravity(const ViewGraph& view_graph, std::unordered_map& frames, std::unordered_map& images) { - const std::unordered_map& image_pairs = - view_graph.image_pairs; const std::unordered_map>& - adjacency_list = view_graph.GetAdjacencyList(); + adjacency_list = view_graph.CreateImageAdjacencyList(); if (adjacency_list.empty()) { - LOG(INFO) << "Adjacency list not established" << std::endl; + LOG(INFO) << "Adjacency list not established"; return; } @@ -24,16 +22,16 @@ void GravityRefiner::RefineGravity(const ViewGraph& view_graph, IdentifyErrorProneGravity(view_graph, frames, images, error_prone_frames); if (error_prone_frames.empty()) { - LOG(INFO) << "No error prone frames found" << std::endl; + LOG(INFO) << "No error prone frames found"; return; } // Get the relevant pair ids for frames std::unordered_map> adjacency_list_frames_to_pair_id; for (auto& [image_id, neighbors] : adjacency_list) { - for (auto neighbor : neighbors) { + for (const auto& neighbor : neighbors) { adjacency_list_frames_to_pair_id[images[image_id].frame_id].insert( - ImagePair::ImagePairToPairId(image_id, neighbor)); + colmap::ImagePairToPairId(image_id, neighbor)); } } @@ -59,8 +57,8 @@ void GravityRefiner::RefineGravity(const ViewGraph& view_graph, int counter = 0; Eigen::Vector3d gravity = frames[frame_id].gravity_info.GetGravity(); for (const auto& pair_id : neighbors) { - image_t image_id1 = image_pairs.at(pair_id).image_id1; - image_t image_id2 = image_pairs.at(pair_id).image_id2; + const image_t image_id1 = view_graph.image_pairs.at(pair_id).image_id1; + const image_t image_id2 = view_graph.image_pairs.at(pair_id).image_id2; if (!images.at(image_id1).HasGravity() || !images.at(image_id2).HasGravity()) continue; @@ -82,17 +80,18 @@ void GravityRefiner::RefineGravity(const ViewGraph& view_graph, // consider a single cost term if (images.at(image_id1).frame_id == frame_id) { gravities.emplace_back( - (colmap::Inverse(image_pairs.at(pair_id).cam2_from_cam1 * + (colmap::Inverse(view_graph.image_pairs.at(pair_id).cam2_from_cam1 * cam1_from_rig1) .rotation.toRotationMatrix() * images[image_id2].GetRAlign()) .col(1)); } else if (images.at(image_id2).frame_id == frame_id) { - gravities.emplace_back(((colmap::Inverse(cam2_from_rig2) * - image_pairs.at(pair_id).cam2_from_cam1) - .rotation.toRotationMatrix() * - images[image_id1].GetRAlign()) - .col(1)); + gravities.emplace_back( + ((colmap::Inverse(cam2_from_rig2) * + view_graph.image_pairs.at(pair_id).cam2_from_cam1) + .rotation.toRotationMatrix() * + images[image_id1].GetRAlign()) + .col(1)); } ceres::CostFunction* coor_cost = @@ -123,9 +122,8 @@ void GravityRefiner::RefineGravity(const ViewGraph& view_graph, frames[frame_id].gravity_info.SetGravity(gravity); } } - std::cout << std::endl; LOG(INFO) << "Number of rectified frames: " << counter_rect << " / " - << error_prone_frames.size() << std::endl; + << error_prone_frames.size(); } void GravityRefiner::IdentifyErrorProneGravity( @@ -179,7 +177,6 @@ void GravityRefiner::IdentifyErrorProneGravity( error_prone_frames.insert(frame_id); } } - LOG(INFO) << "Number of error prone frames: " << error_prone_frames.size() - << std::endl; + LOG(INFO) << "Number of error prone frames: " << error_prone_frames.size(); } } // namespace glomap diff --git a/glomap/io/colmap_converter.cc b/glomap/io/colmap_converter.cc index 3fcb0959..13dc8308 100644 --- a/glomap/io/colmap_converter.cc +++ b/glomap/io/colmap_converter.cc @@ -361,7 +361,7 @@ void ConvertDatabaseToGlomap(const colmap::Database& database, // Initialize the image pair auto ite = image_pairs.insert( - std::make_pair(ImagePair::ImagePairToPairId(image_id1, image_id2), + std::make_pair(colmap::ImagePairToPairId(image_id1, image_id2), ImagePair(image_id1, image_id2))); ImagePair& image_pair = ite.first->second; @@ -419,8 +419,6 @@ void ConvertDatabaseToGlomap(const colmap::Database& database, } image_pair.matches.conservativeResize(count, 2); } - std::cout << std::endl; - LOG(INFO) << "Pairs read done. " << invalid_count << " / " << view_graph.image_pairs.size() << " are invalid"; } diff --git a/glomap/io/pose_io.cc b/glomap/io/pose_io.cc index 49835a8c..d2349f3c 100644 --- a/glomap/io/pose_io.cc +++ b/glomap/io/pose_io.cc @@ -56,7 +56,7 @@ void ReadRelPose(const std::string& file_path, image_t index1 = name_idx[file1]; image_t index2 = name_idx[file2]; - image_pair_t pair_id = ImagePair::ImagePairToPairId(index1, index2); + const image_pair_t pair_id = colmap::ImagePairToPairId(index1, index2); // rotation Rigid3d pose_rel; @@ -81,7 +81,7 @@ void ReadRelPose(const std::string& file_path, } counter++; } - LOG(INFO) << counter << " relpose are loaded" << std::endl; + LOG(INFO) << counter << " relative poses are loaded"; } void ReadRelWeight(const std::string& file_path, @@ -118,7 +118,7 @@ void ReadRelWeight(const std::string& file_path, image_t index1 = name_idx[file1]; image_t index2 = name_idx[file2]; - image_pair_t pair_id = ImagePair::ImagePairToPairId(index1, index2); + image_pair_t pair_id = colmap::ImagePairToPairId(index1, index2); if (view_graph.image_pairs.find(pair_id) == view_graph.image_pairs.end()) continue; @@ -127,7 +127,7 @@ void ReadRelWeight(const std::string& file_path, view_graph.image_pairs[pair_id].weight = std::stod(item); counter++; } - LOG(INFO) << counter << " weights are used are loaded" << std::endl; + LOG(INFO) << counter << " weights are used are loaded"; } // TODO: now, we only store 1 single gravity per rig. @@ -172,7 +172,7 @@ void ReadGravity(const std::string& gravity_path, } } } - LOG(INFO) << counter << " images are loaded with gravity" << std::endl; + LOG(INFO) << counter << " images are loaded with gravity"; } void WriteGlobalRotation(const std::string& file_path, @@ -185,7 +185,7 @@ void WriteGlobalRotation(const std::string& file_path, } } for (const auto& image_id : existing_images) { - const auto image = images.at(image_id); + const auto& image = images.at(image_id); if (!image.IsRegistered()) continue; file << image.file_name; Rigid3d cam_from_world = image.CamFromWorld(); @@ -205,8 +205,8 @@ void WriteRelPose(const std::string& file_path, std::map name_pair; for (const auto& [pair_id, image_pair] : view_graph.image_pairs) { if (image_pair.is_valid) { - const auto image1 = images.at(image_pair.image_id1); - const auto image2 = images.at(image_pair.image_id2); + const auto& image1 = images.at(image_pair.image_id1); + const auto& image2 = images.at(image_pair.image_id2); name_pair[image1.file_name + " " + image2.file_name] = pair_id; } } @@ -226,6 +226,6 @@ void WriteRelPose(const std::string& file_path, file << "\n"; } - LOG(INFO) << name_pair.size() << " relpose are written" << std::endl; + LOG(INFO) << name_pair.size() << " relpose are written"; } -} // namespace glomap \ No newline at end of file +} // namespace glomap diff --git a/glomap/processors/image_pair_inliers.cc b/glomap/processors/image_pair_inliers.cc index c32878f1..a0e14594 100644 --- a/glomap/processors/image_pair_inliers.cc +++ b/glomap/processors/image_pair_inliers.cc @@ -212,4 +212,4 @@ void ImagePairsInlierCount(ViewGraph& view_graph, } } -} // namespace glomap \ No newline at end of file +} // namespace glomap diff --git a/glomap/processors/reconstruction_pruning.cc b/glomap/processors/reconstruction_pruning.cc index 014a10e5..6fc0eb2f 100644 --- a/glomap/processors/reconstruction_pruning.cc +++ b/glomap/processors/reconstruction_pruning.cc @@ -23,8 +23,8 @@ image_t PruneWeaklyConnectedImages(std::unordered_map& frames, image_t image_id2 = track.observations[j].first; frame_t frame_id2 = images[image_id2].frame_id; if (frame_id1 == frame_id2) continue; - image_pair_t pair_id = - ImagePair::ImagePairToPairId(frame_id1, frame_id2); + const image_pair_t pair_id = + colmap::ImagePairToPairId(frame_id1, frame_id2); if (pair_covisibility_count.find(pair_id) == pair_covisibility_count.end()) { pair_covisibility_count[pair_id] = 1; @@ -44,8 +44,7 @@ image_t PruneWeaklyConnectedImages(std::unordered_map& frames, // then require each pair to have at least 5 points if (count >= 5) { counter++; - image_t image_id1, image_id2; - ImagePair::PairIdToImagePair(pair_id, image_id1, image_id2); + const auto [image_id1, image_id2] = colmap::PairIdToImagePair(pair_id); if (frame_observation_count[image_id1] < min_num_observations || frame_observation_count[image_id2] < min_num_observations) @@ -76,10 +75,9 @@ image_t PruneWeaklyConnectedImages(std::unordered_map& frames, ViewGraph visibility_graph; for (auto& [pair_id, image_pair] : visibility_graph_frame.image_pairs) { - frame_t frame_id1, frame_id2; - ImagePair::PairIdToImagePair(pair_id, frame_id1, frame_id2); - image_t image_id1 = frame_id_to_begin_img[frame_id1]; - image_t image_id2 = frame_id_to_begin_img[frame_id2]; + const auto [frame_id1, frame_id2] = colmap::PairIdToImagePair(pair_id); + const image_t image_id1 = frame_id_to_begin_img[frame_id1]; + const image_t image_id2 = frame_id_to_begin_img[frame_id2]; visibility_graph.image_pairs.insert( std::make_pair(pair_id, ImagePair(image_id1, image_id2))); visibility_graph.image_pairs[pair_id].weight = image_pair.weight; @@ -96,7 +94,7 @@ image_t PruneWeaklyConnectedImages(std::unordered_map& frames, if (image_id == begin_image_id || images.find(image_id) == images.end()) continue; image_pair_t pair_id = - ImagePair::ImagePairToPairId(begin_image_id, image_id); + colmap::ImagePairToPairId(begin_image_id, image_id); visibility_graph.image_pairs.insert( std::make_pair(pair_id, ImagePair(begin_image_id, image_id))); @@ -132,4 +130,4 @@ image_t PruneWeaklyConnectedImages(std::unordered_map& frames, // return visibility_graph.MarkConnectedComponents(images, min_num_images); } -} // namespace glomap \ No newline at end of file +} // namespace glomap diff --git a/glomap/processors/relpose_filter.cc b/glomap/processors/relpose_filter.cc index 8af7cf80..1f14cd07 100644 --- a/glomap/processors/relpose_filter.cc +++ b/glomap/processors/relpose_filter.cc @@ -64,4 +64,4 @@ void RelPoseFilter::FilterInlierRatio(ViewGraph& view_graph, << " relative poses with inlier ratio < " << min_inlier_ratio; } -} // namespace glomap \ No newline at end of file +} // namespace glomap diff --git a/glomap/processors/view_graph_manipulation.cc b/glomap/processors/view_graph_manipulation.cc index e63a57a2..24c36726 100644 --- a/glomap/processors/view_graph_manipulation.cc +++ b/glomap/processors/view_graph_manipulation.cc @@ -17,7 +17,7 @@ image_pair_t ViewGraphManipulater::SparsifyGraph( // Keep track of chosen edges std::unordered_set chosen_edges; const std::unordered_map>& - adjacency_list = view_graph.GetAdjacencyList(); + adjacency_list = view_graph.CreateImageAdjacencyList(); // Here, the average is the mean of the degrees double average_degree = 0; @@ -47,6 +47,7 @@ image_pair_t ViewGraphManipulater::SparsifyGraph( continue; } + // TODO: Replace rand() with thread-safe random number generator. if (rand() / double(RAND_MAX) < (expected_degree * average_degree) / (degree1 * degree2)) { chosen_edges.insert(pair_id); @@ -208,9 +209,7 @@ void ViewGraphManipulater::UpdateImagePairsConfig( // pairs are valid, then set the camera to valid std::unordered_map camera_validity; for (auto& [camera_id, counter] : camera_counter) { - if (counter.first == 0) { - camera_validity[camera_id] = false; - } else if (counter.second * 1. / counter.first > 0.5) { + if (counter.second * 1. / counter.first > 0.5) { camera_validity[camera_id] = true; } else { camera_validity[camera_id] = false; diff --git a/glomap/scene/image_pair.h b/glomap/scene/image_pair.h index 67bf2ed3..31b01386 100644 --- a/glomap/scene/image_pair.h +++ b/glomap/scene/image_pair.h @@ -9,19 +9,24 @@ namespace glomap { -// FUTURE: add covariance to the relative pose +// TODO: add covariance to the relative pose struct ImagePair { - ImagePair() : pair_id(-1), image_id1(-1), image_id2(-1) {} - ImagePair(image_t img_id1, image_t img_id2, Rigid3d pose_rel = Rigid3d()) - : pair_id(ImagePairToPairId(img_id1, img_id2)), - image_id1(img_id1), - image_id2(img_id2), - cam2_from_cam1(pose_rel) {} + ImagePair() + : image_id1(colmap::kInvalidImageId), + image_id2(colmap::kInvalidImageId), + pair_id(colmap::kInvalidImagePairId) {} + ImagePair(image_t image_id1, + image_t image_id2, + Rigid3d cam2_from_cam1 = Rigid3d()) + : image_id1(image_id1), + image_id2(image_id2), + pair_id(colmap::ImagePairToPairId(image_id1, image_id2)), + cam2_from_cam1(cam2_from_cam1) {} // Ids are kept constant - const image_pair_t pair_id; const image_t image_id1; const image_t image_id2; + const image_pair_t pair_id; // indicator whether the image pair is valid bool is_valid = true; @@ -40,7 +45,7 @@ struct ImagePair { Eigen::Matrix3d H = Eigen::Matrix3d::Zero(); // Relative pose. - Rigid3d cam2_from_cam1; + Rigid3d cam2_from_cam1 = Rigid3d(); // Matches between the two images. // First column is the index of the feature in the first image. @@ -49,27 +54,6 @@ struct ImagePair { // Row index of inliers in the matches matrix. std::vector inliers; - - static inline image_pair_t ImagePairToPairId(const image_t image_id1, - const image_t image_id2); - - static inline void PairIdToImagePair(const image_pair_t pair_id, - image_t& image_id1, - image_t& image_id2); }; -image_pair_t ImagePair::ImagePairToPairId(const image_t image_id1, - const image_t image_id2) { - return colmap::ImagePairToPairId(image_id1, image_id2); -} - -void ImagePair::PairIdToImagePair(const image_pair_t pair_id, - image_t& image_id1, - image_t& image_id2) { - std::pair image_id_pair = - colmap::PairIdToImagePair(pair_id); - image_id1 = image_id_pair.first; - image_id2 = image_id_pair.second; -} - } // namespace glomap diff --git a/glomap/scene/view_graph.cc b/glomap/scene/view_graph.cc index 60009116..5e8e855e 100644 --- a/glomap/scene/view_graph.cc +++ b/glomap/scene/view_graph.cc @@ -3,18 +3,65 @@ #include namespace glomap { +namespace { + +void BreadthFirstSearch( + const std::unordered_map>& + adjacency_list, + image_t root, + std::unordered_map& visited, + std::unordered_set& component) { + std::queue queue; + queue.push(root); + visited[root] = true; + component.insert(root); + + while (!queue.empty()) { + const image_t curr = queue.front(); + queue.pop(); + + for (const image_t neighbor : adjacency_list.at(curr)) { + if (!visited[neighbor]) { + queue.push(neighbor); + visited[neighbor] = true; + component.insert(neighbor); + } + } + } +} + +std::vector> FindConnectedComponents( + const std::unordered_map>& + adjacency_list) { + std::vector> connected_components; + std::unordered_map visited; + visited.reserve(adjacency_list.size()); + for (const auto& [frame_id, neighbors] : adjacency_list) { + visited[frame_id] = false; + } + + for (auto& [frame_id, _] : adjacency_list) { + if (!visited[frame_id]) { + std::unordered_set component; + BreadthFirstSearch(adjacency_list, frame_id, visited, component); + connected_components.push_back(std::move(component)); + } + } + + return connected_components; +} + +} // namespace int ViewGraph::KeepLargestConnectedComponents( std::unordered_map& frames, std::unordered_map& images) { - EstablishAdjacencyList(); - EstablishAdjacencyListFrame(images); - - int num_comp = FindConnectedComponent(); + const std::vector> connected_components = + FindConnectedComponents(CreateFrameAdjacencyList(images)); int max_idx = -1; int max_img = 0; - for (int comp = 0; comp < num_comp; comp++) { + for (int comp = 0; comp < connected_components.size(); comp++) { if (connected_components[comp].size() > max_img) { max_img = connected_components[comp].size(); max_idx = comp; @@ -23,7 +70,8 @@ int ViewGraph::KeepLargestConnectedComponents( if (max_img == 0) return 0; - std::unordered_set largest_component = connected_components[max_idx]; + const std::unordered_set& largest_component = + connected_components[max_idx]; // Set all frames to not registered for (auto& [frame_id, frame] : frames) { @@ -34,13 +82,11 @@ int ViewGraph::KeepLargestConnectedComponents( frames[frame_id].is_registered = true; } // set all pairs not in the largest component to invalid - num_pairs = 0; for (auto& [pair_id, image_pair] : image_pairs) { if (!images[image_pair.image_id1].IsRegistered() || !images[image_pair.image_id2].IsRegistered()) { image_pair.is_valid = false; } - if (image_pair.is_valid) num_pairs++; } for (auto& [image_id, image] : images) { @@ -49,32 +95,13 @@ int ViewGraph::KeepLargestConnectedComponents( return max_img; } -int ViewGraph::FindConnectedComponent() { - connected_components.clear(); - std::unordered_map visited; - for (auto& [frame_id, neighbors] : adjacency_list_frame) { - visited[frame_id] = false; - } - - for (auto& [frame_id, neighbors] : adjacency_list_frame) { - if (!visited[frame_id]) { - std::unordered_set component; - BFS(frame_id, visited, component); - connected_components.push_back(component); - } - } - - return connected_components.size(); -} - int ViewGraph::MarkConnectedComponents( std::unordered_map& frames, std::unordered_map& images, int min_num_img) { - EstablishAdjacencyList(); - EstablishAdjacencyListFrame(images); - - int num_comp = FindConnectedComponent(); + const std::vector> connected_components = + FindConnectedComponents(CreateFrameAdjacencyList(images)); + const int num_comp = connected_components.size(); std::vector> cluster_num_img(num_comp); for (int comp = 0; comp < num_comp; comp++) { @@ -97,48 +124,31 @@ int ViewGraph::MarkConnectedComponents( return comp; } -void ViewGraph::BFS(image_t root, - std::unordered_map& visited, - std::unordered_set& component) { - std::queue q; - q.push(root); - visited[root] = true; - component.insert(root); - - while (!q.empty()) { - image_t curr = q.front(); - q.pop(); - - for (image_t neighbor : adjacency_list_frame[curr]) { - if (!visited[neighbor]) { - q.push(neighbor); - visited[neighbor] = true; - component.insert(neighbor); - } - } - } -} - -void ViewGraph::EstablishAdjacencyList() { - adjacency_list.clear(); - for (auto& [pair_id, image_pair] : image_pairs) { +std::unordered_map> +ViewGraph::CreateImageAdjacencyList() const { + std::unordered_map> adjacency_list; + for (const auto& [_, image_pair] : image_pairs) { if (image_pair.is_valid) { adjacency_list[image_pair.image_id1].insert(image_pair.image_id2); adjacency_list[image_pair.image_id2].insert(image_pair.image_id1); } } + return adjacency_list; } -void ViewGraph::EstablishAdjacencyListFrame( - std::unordered_map& images) { - adjacency_list_frame.clear(); - for (auto& [pair_id, image_pair] : image_pairs) { +std::unordered_map> +ViewGraph::CreateFrameAdjacencyList( + const std::unordered_map& images) const { + std::unordered_map> adjacency_list; + for (const auto& [_, image_pair] : image_pairs) { if (image_pair.is_valid) { - frame_t frame_id1 = images[image_pair.image_id1].frame_id; - frame_t frame_id2 = images[image_pair.image_id2].frame_id; - adjacency_list_frame[frame_id1].insert(frame_id2); - adjacency_list_frame[frame_id2].insert(frame_id1); + const frame_t frame_id1 = images.at(image_pair.image_id1).frame_id; + const frame_t frame_id2 = images.at(image_pair.image_id2).frame_id; + adjacency_list[frame_id1].insert(frame_id2); + adjacency_list[frame_id2].insert(frame_id1); } } + return adjacency_list; } + } // namespace glomap diff --git a/glomap/scene/view_graph.h b/glomap/scene/view_graph.h index 21c1a16c..74497e24 100644 --- a/glomap/scene/view_graph.h +++ b/glomap/scene/view_graph.h @@ -1,73 +1,37 @@ #pragma once -#include "glomap/scene/camera.h" #include "glomap/scene/image.h" #include "glomap/scene/image_pair.h" #include "glomap/scene/types.h" -#include "glomap/types.h" + +#include +#include namespace glomap { -class ViewGraph { - public: - // Methods - inline void RemoveInvalidPair(image_pair_t pair_id); +struct ViewGraph { + std::unordered_map image_pairs; + + // Create the adjacency list for the images in the view graph. + std::unordered_map> + CreateImageAdjacencyList() const; + + // Create the adjacency list for the frames in the view graph. + std::unordered_map> + CreateFrameAdjacencyList( + const std::unordered_map& images) const; - // Mark the image which is not connected to any other images as not registered - // Return: the number of images in the largest connected component + // Mark the images which are not connected to any other images as not + // registered Returns the number of images in the largest connected component. int KeepLargestConnectedComponents( std::unordered_map& frames, std::unordered_map& images); - // Mark the cluster of the cameras (cluster_id sort by the the number of - // images) + // Mark connected clusters of images, where the cluster_id is sorted by the + // the number of images. int MarkConnectedComponents(std::unordered_map& frames, std::unordered_map& images, int min_num_img = -1); - - // Establish the adjacency list - void EstablishAdjacencyList(); - - // Establish the frame based adjacency list - void EstablishAdjacencyListFrame(std::unordered_map& images); - - inline const std::unordered_map>& - GetAdjacencyList() const; - inline const std::unordered_map>& - GetAdjacencyListFrame() const; - - // Data - std::unordered_map image_pairs; - - image_t num_images = 0; - image_pair_t num_pairs = 0; - - private: - int FindConnectedComponent(); - - void BFS(image_t root, - std::unordered_map& visited, - std::unordered_set& component); - - // Data for processing - std::unordered_map> adjacency_list; - std::unordered_map> adjacency_list_frame; - std::vector> connected_components; }; -const std::unordered_map>& -ViewGraph::GetAdjacencyList() const { - return adjacency_list; -} - -const std::unordered_map>& -ViewGraph::GetAdjacencyListFrame() const { - return adjacency_list_frame; -} - -void ViewGraph::RemoveInvalidPair(image_pair_t pair_id) { - ImagePair& pair = image_pairs.at(pair_id); - pair.is_valid = false; -} - } // namespace glomap