@@ -635,6 +635,160 @@ bool ContinuousClustering::hasTransformRobotFrameFromSensorFrame()
635
635
return sgps_ego_robot_frame_from_sensor_frame_ != nullptr ;
636
636
}
637
637
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
+
638
792
void ContinuousClustering::associatePointsInColumn (AssociationJob&& job)
639
793
{
640
794
// collect new point trees
@@ -668,150 +822,11 @@ void ContinuousClustering::associatePointsInColumn(AssociationJob&& job)
668
822
669
823
// calculate minimum possible azimuth angle
670
824
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
- }
719
825
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);
814
828
829
+ // point could not be associated to any other point in field of view
815
830
if (point.tree_root_ .column_index == -1 )
816
831
{
817
832
// this point could not be associated to any tree -> init new tree
0 commit comments