Skip to content

Commit cb87cf7

Browse files
committed
Refactor code: split point association into smaller functions
1 parent 5fec711 commit cb87cf7

File tree

2 files changed

+161
-142
lines changed

2 files changed

+161
-142
lines changed

include/continuous_clustering/clustering/continuous_clustering.hpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,10 @@ class ContinuousClustering
225225
}
226226

227227
// continuous clustering
228+
inline bool checkClusteringCondition(const Point& point, const Point& point_other) const;
229+
inline void associatePointToPointTree(Point& point, Point& point_other, float max_angle_diff);
230+
inline void associatePointTreeToPointTree(const Point& point, const Point& point_other);
231+
inline void traverseFieldOfView(Point& point, float max_angle_diff, int ring_buffer_first_local_column_index);
228232
inline void associatePointsInColumn(AssociationJob&& job);
229233
inline void findFinishedTreesAndAssignSameId(TreeCombinationJob&& job);
230234
inline void collectPointsForCusterAndPublish(PublishingJob&& job);

src/clustering/continuous_clustering.cpp

Lines changed: 157 additions & 142 deletions
Original file line numberDiff line numberDiff line change
@@ -635,6 +635,160 @@ bool ContinuousClustering::hasTransformRobotFrameFromSensorFrame()
635635
return sgps_ego_robot_frame_from_sensor_frame_ != nullptr;
636636
}
637637

638+
bool ContinuousClustering::checkClusteringCondition(const Point& point, const Point& point_other) const
639+
{
640+
return (point.xyz - point_other.xyz).lengthSquared() < max_distance_squared;
641+
}
642+
643+
void ContinuousClustering::associatePointToPointTree(Point& point, Point& point_other, float max_angle_diff)
644+
{
645+
// this point is not associated to any point tree -> associate it
646+
// Furthermore, we also have to check that clusters are forcibly published when they span a
647+
// full rotation. For this we take two measures: (1) don't associate this point to the point
648+
// tree when it would cover more than one rotation; (2) don't associate this point to the
649+
// point tree, when its cluster is considered to be finished. Normally, the latter can not
650+
// happen because a cluster is only considered to be finished when no more point can be
651+
// associated (LiDAR rotated far enough away from a cluster's point trees). It can only
652+
// happen when a cluster is forcibly considered to be finished because it already spans a
653+
// full rotation. Then we do not want to associate more points to it.
654+
Point& point_root =
655+
range_image_[point_other.tree_root_.column_index * num_rows_ + point_other.tree_root_.row_index];
656+
uint32_t new_cluster_width = point.global_column_index - point_root.global_column_index + 1;
657+
bool point_tree_is_smaller_than_one_rotation = new_cluster_width <= num_columns_; // (1)
658+
bool point_tree_is_finished_forcibly = point_root.belongs_to_finished_cluster; // (2)
659+
if (point_tree_is_smaller_than_one_rotation && !point_tree_is_finished_forcibly)
660+
{
661+
point.tree_root_ = point_other.tree_root_;
662+
point.tree_id = point_root.global_column_index * num_rows_ + point_root.row_index;
663+
point_other.child_points.emplace_back(static_cast<uint16_t>(point.row_index), point.local_column_index);
664+
665+
// keep track of cluster width
666+
point_root.cluster_width = new_cluster_width;
667+
668+
// new point was associated to tree -> check if finish time will be delayed
669+
point_root.finished_at_continuous_azimuth_angle =
670+
std::max(point_root.finished_at_continuous_azimuth_angle, point.continuous_azimuth_angle + max_angle_diff);
671+
point_root.tree_num_points++;
672+
}
673+
}
674+
675+
void ContinuousClustering::associatePointTreeToPointTree(const Point& point, const Point& point_other)
676+
{
677+
// tree root of this point must be different to the other point (because of check above
678+
// *1) so we must add a mutual link between the trees roots
679+
680+
// get tree root of current and other point
681+
Point& point_root = range_image_[point.tree_root_.column_index * num_rows_ + point.tree_root_.row_index];
682+
Point& point_root_other =
683+
range_image_[point_other.tree_root_.column_index * num_rows_ + point_other.tree_root_.row_index];
684+
685+
// similar to above (unassociated point is added to point tree) we also don't want to
686+
// introduce links between point trees when either of them was forcibly finished because its
687+
// corresponding cluster already covers a full rotation
688+
bool neither_cluster_was_forcibly_finished =
689+
!point_root.belongs_to_finished_cluster && !point_root_other.belongs_to_finished_cluster;
690+
if (neither_cluster_was_forcibly_finished)
691+
{
692+
// add mutual link
693+
point_root.associated_trees.insert(point_other.tree_root_);
694+
point_root_other.associated_trees.insert(point.tree_root_);
695+
}
696+
}
697+
698+
void ContinuousClustering::traverseFieldOfView(Point& point,
699+
float max_angle_diff,
700+
int ring_buffer_first_local_column_index)
701+
{
702+
// go left each column until azimuth angle difference gets too large
703+
double min_possible_continuous_azimuth_angle = point.continuous_azimuth_angle - max_angle_diff;
704+
int num_steps_back = 0;
705+
int64_t other_column_index = point.local_column_index;
706+
while (num_steps_back <= config_.clustering.max_steps_in_row)
707+
{
708+
bool at_least_one_point_of_this_column_in_azimuth_range = false;
709+
for (int direction = -1; direction <= 1; direction += 2)
710+
{
711+
// do not go down in first column (these points are not associated to tree yet!)
712+
if (direction == 1 && num_steps_back == 0)
713+
continue;
714+
715+
// go up/down each row until the inclination angle difference gets too large
716+
int num_steps_vertical = direction == 1 || num_steps_back == 0 ? 1 : 0;
717+
int other_row_index = direction == 1 || num_steps_back == 0 ? point.row_index + direction : point.row_index;
718+
while (other_row_index >= 0 && other_row_index < num_rows_ &&
719+
num_steps_vertical <= config_.clustering.max_steps_in_column)
720+
{
721+
// get other point
722+
Point& point_other = range_image_[other_column_index * num_rows_ + other_row_index];
723+
724+
// count number of visited points for analyzing
725+
point.number_of_visited_neighbors += 1;
726+
727+
// no cluster can be associated because the inclination angle diff gets too large
728+
if (std::abs(point_other.inclination_angle - point.inclination_angle) > max_angle_diff)
729+
break;
730+
731+
// if this point is still in azimuth range then also search one column before
732+
if (point_other.continuous_azimuth_angle >= min_possible_continuous_azimuth_angle)
733+
at_least_one_point_of_this_column_in_azimuth_range = true;
734+
else
735+
{
736+
other_row_index += direction;
737+
num_steps_vertical++;
738+
continue;
739+
}
740+
741+
// if this point is ignored or has already the same tree root then do nothing (*1)
742+
if (point_other.is_ignored ||
743+
(point.tree_root_.column_index >= 0 && point_other.tree_root_ == point.tree_root_))
744+
{
745+
other_row_index += direction;
746+
num_steps_vertical++;
747+
continue;
748+
}
749+
750+
// if distance is small enough then try to associate to tree
751+
if (checkClusteringCondition(point, point_other))
752+
{
753+
// check if point is already associated to any point tree
754+
if (point.tree_root_.column_index == -1)
755+
associatePointToPointTree(point, point_other, max_angle_diff);
756+
else
757+
associatePointTreeToPointTree(point, point_other);
758+
}
759+
760+
// stop searching if point was already associated and minimum number of columns were processed
761+
if (point.tree_root_.column_index != -1 && config_.clustering.stop_after_association_enabled &&
762+
num_steps_vertical >= config_.clustering.stop_after_association_min_steps)
763+
break;
764+
765+
other_row_index += direction;
766+
num_steps_vertical++;
767+
}
768+
}
769+
770+
// stop searching if point was already associated and minimum number of points were processed
771+
if (point.tree_root_.column_index != -1 && config_.clustering.stop_after_association_enabled &&
772+
num_steps_back >= config_.clustering.stop_after_association_min_steps)
773+
break;
774+
775+
// stop searching in previous columns because in previous run all points were already out of angle range
776+
if (num_steps_back > 0 && !at_least_one_point_of_this_column_in_azimuth_range)
777+
break;
778+
779+
// stop searching if we are at the beginning of the ring buffer
780+
if (other_column_index == ring_buffer_first_local_column_index)
781+
break;
782+
783+
other_column_index--;
784+
num_steps_back++;
785+
786+
// jump to the end of the ring buffer
787+
if (other_column_index < 0)
788+
other_column_index += ring_buffer_max_columns;
789+
}
790+
}
791+
638792
void ContinuousClustering::associatePointsInColumn(AssociationJob&& job)
639793
{
640794
// collect new point trees
@@ -668,150 +822,11 @@ void ContinuousClustering::associatePointsInColumn(AssociationJob&& job)
668822

669823
// calculate minimum possible azimuth angle
670824
float max_angle_diff = std::asin(config_.clustering.max_distance / point.distance);
671-
double min_possible_continuous_azimuth_angle = point.continuous_azimuth_angle - max_angle_diff;
672-
673-
// go left each column until azimuth angle difference gets too large
674-
int num_steps_back = 0;
675-
int64_t other_column_index = ring_buffer_current_local_column_index;
676-
while (num_steps_back <= config_.clustering.max_steps_in_row)
677-
{
678-
bool at_least_one_point_of_this_column_in_azimuth_range = false;
679-
for (int direction = -1; direction <= 1; direction += 2)
680-
{
681-
// do not go down in first column (these points are not associated to tree yet!)
682-
if (direction == 1 && num_steps_back == 0)
683-
continue;
684-
685-
// go up/down each row until the inclination angle difference gets too large
686-
int num_steps_vertical = direction == 1 || num_steps_back == 0 ? 1 : 0;
687-
int other_row_index = direction == 1 || num_steps_back == 0 ? row_index + direction : row_index;
688-
while (other_row_index >= 0 && other_row_index < num_rows_ &&
689-
num_steps_vertical <= config_.clustering.max_steps_in_column)
690-
{
691-
// get other point
692-
Point& point_other = range_image_[other_column_index * num_rows_ + other_row_index];
693-
694-
// count number of visited points for analyzing
695-
point.number_of_visited_neighbors += 1;
696-
697-
// no cluster can be associated because the inclination angle diff gets too large
698-
if (std::abs(point_other.inclination_angle - point.inclination_angle) > max_angle_diff)
699-
break;
700-
701-
// if this point is still in azimuth range then also search one column before
702-
if (point_other.continuous_azimuth_angle >= min_possible_continuous_azimuth_angle)
703-
at_least_one_point_of_this_column_in_azimuth_range = true;
704-
else
705-
{
706-
other_row_index += direction;
707-
num_steps_vertical++;
708-
continue;
709-
}
710-
711-
// if this point is ignored or has already the same tree root then do nothing (*1)
712-
if (point_other.is_ignored ||
713-
(point.tree_root_.column_index >= 0 && point_other.tree_root_ == point.tree_root_))
714-
{
715-
other_row_index += direction;
716-
num_steps_vertical++;
717-
continue;
718-
}
719825

720-
// calculate the distance to other point
721-
float distance_squared = (point.xyz - point_other.xyz).lengthSquared();
722-
723-
// if distance is small enough then try to associate to tree
724-
if (distance_squared < max_distance_squared)
725-
{
726-
if (point.tree_root_.column_index == -1)
727-
{
728-
// this point is not associated to any point tree -> associate it
729-
730-
// Furthermore, we also have to check that clusters are forcibly published when they span a
731-
// full rotation. For this we take two measures: (1) don't associate this point to the point
732-
// tree when it would cover more than one rotation; (2) don't associate this point to the
733-
// point tree, when its cluster is considered to be finished. Normally, the latter can not
734-
// happen because a cluster is only considered to be finished when no more point can be
735-
// associated (LiDAR rotated far enough away from a cluster's point trees). It can only
736-
// happen when a cluster is forcibly considered to be finished because it already spans a
737-
// full rotation. Then we do not want to associate more points to it.
738-
Point& point_root = range_image_[point_other.tree_root_.column_index * num_rows_ +
739-
point_other.tree_root_.row_index];
740-
uint32_t new_cluster_width = point.global_column_index - point_root.global_column_index + 1;
741-
bool point_tree_is_smaller_than_one_rotation = new_cluster_width <= num_columns_; // (1)
742-
bool point_tree_is_finished_forcibly = point_root.belongs_to_finished_cluster; // (2)
743-
if (point_tree_is_smaller_than_one_rotation && !point_tree_is_finished_forcibly)
744-
{
745-
point.tree_root_ = point_other.tree_root_;
746-
point.tree_id = point_root.global_column_index * num_rows_ + point_root.row_index;
747-
point_other.child_points.push_back(index);
748-
749-
// keep track of cluster width
750-
point_root.cluster_width = new_cluster_width;
751-
752-
// new point was associated to tree -> check if finish time will be delayed
753-
point_root.finished_at_continuous_azimuth_angle =
754-
std::max(point_root.finished_at_continuous_azimuth_angle,
755-
point.continuous_azimuth_angle + max_angle_diff);
756-
point_root.tree_num_points++;
757-
}
758-
}
759-
else
760-
{
761-
// tree root of this point must be different to the other point (because of check above
762-
// *1) so we must add a mutual link between the trees roots
763-
764-
// get tree root of current and other point
765-
Point& point_root =
766-
range_image_[point.tree_root_.column_index * num_rows_ + point.tree_root_.row_index];
767-
Point& point_root_other = range_image_[point_other.tree_root_.column_index * num_rows_ +
768-
point_other.tree_root_.row_index];
769-
770-
// similar to above (unassociated point is added to point tree) we also don't want to
771-
// introduce links between point trees when either of them was forcibly finished because its
772-
// corresponding cluster already covers a full rotation
773-
bool neither_cluster_was_forcibly_finished = !point_root.belongs_to_finished_cluster &&
774-
!point_root_other.belongs_to_finished_cluster;
775-
if (neither_cluster_was_forcibly_finished)
776-
{
777-
// add mutual link
778-
point_root.associated_trees.insert(point_other.tree_root_);
779-
point_root_other.associated_trees.insert(point.tree_root_);
780-
}
781-
}
782-
}
783-
784-
// stop searching if point was already associated and minimum number of columns were processed
785-
if (point.tree_root_.column_index != -1 && config_.clustering.stop_after_association_enabled &&
786-
num_steps_vertical >= config_.clustering.stop_after_association_min_steps)
787-
break;
788-
789-
other_row_index += direction;
790-
num_steps_vertical++;
791-
}
792-
}
793-
794-
// stop searching if point was already associated and minimum number of points were processed
795-
if (point.tree_root_.column_index != -1 && config_.clustering.stop_after_association_enabled &&
796-
num_steps_back >= config_.clustering.stop_after_association_min_steps)
797-
break;
798-
799-
// stop searching in previous columns because in previous run all points were already out of angle range
800-
if (num_steps_back > 0 && !at_least_one_point_of_this_column_in_azimuth_range)
801-
break;
802-
803-
// stop searching if we are at the beginning of the ring buffer
804-
if (other_column_index == ring_buffer_first_local_column_index)
805-
break;
806-
807-
other_column_index--;
808-
num_steps_back++;
809-
810-
// jump to the end of the ring buffer
811-
if (other_column_index < 0)
812-
other_column_index += ring_buffer_max_columns;
813-
}
826+
// traverse field of view
827+
traverseFieldOfView(point, max_angle_diff, ring_buffer_first_local_column_index);
814828

829+
// point could not be associated to any other point in field of view
815830
if (point.tree_root_.column_index == -1)
816831
{
817832
// this point could not be associated to any tree -> init new tree

0 commit comments

Comments
 (0)