Skip to content

Commit

Permalink
WIP optimisation of angle clustering
Browse files Browse the repository at this point in the history
  • Loading branch information
Ylannl committed May 25, 2020
1 parent f0cd2c8 commit a5f41ae
Show file tree
Hide file tree
Showing 2 changed files with 113 additions and 19 deletions.
116 changes: 99 additions & 17 deletions src/line_regulariser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -88,23 +88,25 @@ namespace linereg {
value = calc_segment(centroid, mean_angle, lines);
}

template <typename ClusterH> DistanceTable<ClusterH>::DistanceTable(std::set<ClusterH>& clusters) : clusters(clusters) {
template <typename ClusterH> DistanceTable<ClusterH>::DistanceTable(std::set<ClusterH>& clusters) : clusters(clusters) {};
template <typename ClusterH> void DistanceTable<ClusterH>::add_cluster_pair(ClusterH cluster_a, ClusterH cluster_b) {
// do not create entries for cluster pairs that both have an intersection line, these are not to be merged
// if (cluster_a->has_intersection_line && cluster_b->has_intersection_line) continue;
// push distance to heap
auto hhandle = distances.push(ClusterPairDist(
std::make_pair(cluster_a, cluster_b),
cluster_a->distance(cluster_b.get())
));
// store handle for both clusters
auto hh = std::make_shared<heap_handle>(hhandle);
cluster_to_dist_pairs[cluster_a].push_back(hh);
cluster_to_dist_pairs[cluster_b].push_back(hh);
}
template <typename ClusterH> void DistanceTable<ClusterH>::initialise() {
// compute only half of the distance table, since the other half will be exactly the same
for(auto cit_a = clusters.begin(); cit_a != clusters.end(); ++cit_a) {
for(auto cit_b = std::next(cit_a); cit_b != clusters.end(); ++cit_b) {
auto cluster_a = *cit_a;
auto cluster_b = *cit_b;
// do not create entries for cluster pairs that both have an intersection line, these are not to be merged
// if (cluster_a->has_intersection_line && cluster_b->has_intersection_line) continue;
// push distance to heap
auto hhandle = distances.push(ClusterPairDist(
std::make_pair(cluster_a, cluster_b),
cluster_a->distance(cluster_b.get())
));
// store handle for both clusters
auto hh = std::make_shared<heap_handle>(hhandle);
cluster_to_dist_pairs[cluster_a].push_back(hh);
cluster_to_dist_pairs[cluster_b].push_back(hh);
add_cluster_pair(*cit_a, *cit_b);
}
}
}
Expand Down Expand Up @@ -147,8 +149,86 @@ namespace linereg {
return min_pair;
}

template class DistanceTable<AngleClusterH>;
template class DistanceTable<DistClusterH>;
// template class DistanceTable<AngleClusterH>;
template struct DistanceTable<DistClusterH>;

AngleDistanceTable::AngleDistanceTable(std::set<AngleClusterH>& clusters) : DistanceTable<AngleClusterH>(clusters) {
std::vector<AngleClusterH> sorted(clusters.begin(), clusters.end());
// sort by orientation
std::sort(sorted.begin(), sorted.end(), [](AngleClusterH& a, AngleClusterH& b) {
return a->value < b->value;
});
// compute cluster pair from last to first
add_cluster_pair(*sorted.rbegin(), *sorted.begin());
// if clusters.size()>2 also compute cluster pairs for all other consecutive pairs
if (clusters.size() > 2) {
auto last = std::prev(sorted.end());
for(auto cit = sorted.begin(); cit != last; ++cit) {
add_cluster_pair(*cit, *std::next(cit));
}
}
}
void AngleDistanceTable::merge(AngleClusterH lhs, AngleClusterH rhs) {
// merges two clusters, then removes one from the distances map and update the affected distances
// merge
lhs->lines.insert(lhs->lines.end(), rhs->lines.begin(), rhs->lines.end());
// lhs->has_intersection_line = lhs->has_intersection_line || rhs->has_intersection_line;
lhs->calc_mean_value();

// find rhs_next
AngleClusterH rhs_next;
auto& rhs_hhandles = cluster_to_dist_pairs[rhs];
bool f0 = (***rhs_hhandles.begin()).clusters.first == lhs;
bool s0 = (***rhs_hhandles.begin()).clusters.second == lhs;
// bool f1 = (***rhs_hhandles.rbegin()).clusters.first == lhs;
// bool s1 = (***rhs_hhandles.rbegin()).clusters.second == lhs;
if (f0||s0) {
if ((***rhs_hhandles.rbegin()).clusters.first == rhs) {
rhs_next = (***rhs_hhandles.rbegin()).clusters.second;
} else {
rhs_next = (***rhs_hhandles.rbegin()).clusters.first;
}
} else {
if ((***rhs_hhandles.rbegin()).clusters.first == rhs) {
rhs_next = (***rhs_hhandles.begin()).clusters.second;
} else {
rhs_next = (***rhs_hhandles.begin()).clusters.first;
}
}

// remove rhs from datastructures
clusters.erase(rhs);
cluster_to_dist_pairs.erase(rhs);

// update lhs
auto& lhs_hhandles = cluster_to_dist_pairs[lhs];
std::shared_ptr<heap_handle> lhs_to_rhs_next;
for (auto& hhandle : lhs_hhandles) {
if (hhandle.use_count()==2) {
(**hhandle).dist = (**hhandle).clusters.first->distance((**hhandle).clusters.second.get());
distances.update(*hhandle);
} else {
lhs_to_rhs_next = hhandle;
distances.update(*hhandle, ClusterPairDist(std::make_pair(lhs, rhs_next), lhs->distance(rhs_next.get())));
}
}

// update rhs_next
auto& rhs_next_hhandles = cluster_to_dist_pairs[rhs_next];
auto i = rhs_next_hhandles.begin();
while (i != rhs_next_hhandles.end()) {
// remove the distpair to our former rhs
if (i->use_count()!=2)
{
rhs_next_hhandles.erase(i++);
distances.erase(**i);
} else {
++i;
}
}
// push the new dist to lhs
rhs_next_hhandles.push_back(lhs_to_rhs_next);
}

void LineRegulariser::perform_angle_clustering() {
//make clusters
Expand All @@ -163,7 +243,8 @@ namespace linereg {

if (angle_clusters.size()>1) {
// make distance table
DistanceTable adt(angle_clusters);
AngleDistanceTable adt(angle_clusters);
adt.initialise();

auto apair = adt.get_closest_pair();
while (apair.dist < angle_threshold) {
Expand Down Expand Up @@ -199,6 +280,7 @@ namespace linereg {
if (dclusters.size()>1) {
// make distance table
DistanceTable ddt(dclusters);
ddt.initialise();

// do clustering
auto dpair = ddt.get_closest_pair();
Expand Down
16 changes: 14 additions & 2 deletions src/line_regulariser.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,10 @@ namespace linereg {
ClusterPairDist(ClusterPair p, double d) : clusters(p), dist(d){}
ClusterPair clusters;
double dist;

bool has_cluster(ClusterH& cluster) {
return clusters.first == cluster || clusters.second == cluster;
}

bool operator<(ClusterPairDist const & rhs) const
{
Expand Down Expand Up @@ -83,7 +87,9 @@ namespace linereg {
std::set<ClusterH>& clusters;

DistanceTable(std::set<ClusterH>& clusters); //computes initial distances
void merge(ClusterH lhs, ClusterH rhs); // merges two clusters, then removes one from the distances map and update the affected distances
void add_cluster_pair(ClusterH cluster_a, ClusterH cluster_b); // create cluster pair and insert it
virtual void initialise();
virtual void merge(ClusterH lhs, ClusterH rhs); // merges two clusters, then removes one from the distances map and update the affected distances
ClusterPairDist get_closest_pair(); //returns the cluster pair with the smallest distance
};

Expand All @@ -93,9 +99,15 @@ namespace linereg {
typedef std::shared_ptr<AngleCluster> AngleClusterH;
typedef std::shared_ptr<DistCluster> DistClusterH;

extern template class DistanceTable<AngleClusterH>;
// extern template class DistanceTable<AngleClusterH>;
extern template class DistanceTable<DistClusterH>;

// specialised class for angle cluster, so that we can override the creation and merge function for more optimised code
struct AngleDistanceTable : DistanceTable<AngleClusterH> {
AngleDistanceTable(std::set<AngleClusterH>& clusters); //computes initial distances
void merge(AngleClusterH lhs, AngleClusterH rhs); // merges two clusters, then removes one from the distances map and update
};

double calc_mean_angle(const std::vector<linetype*>& lines);
Point_2 calc_centroid(const std::vector<linetype*>& lines);
Segment_2 calc_segment(Point_2 centroid, double mean_angle, const std::vector<linetype*>& lines, double extension=0);
Expand Down

0 comments on commit a5f41ae

Please sign in to comment.