From 5a309cd83c174e15d881007620871c2bf5355dbf Mon Sep 17 00:00:00 2001
From: andreucm <acoromin@iri.upc.edu>
Date: Wed, 30 Mar 2016 18:05:35 +0200
Subject: [PATCH] Just a working copy of corner detection. Doesn't compilr, Not
 tested yet

---
 src/corner_finder_range_diff.cpp | 63 ++++++++++++++------------------
 src/corner_finder_range_diff.h   |  4 +-
 src/laser_scan.cpp               | 50 +++++++++++++++++++++++++
 src/laser_scan.h                 | 38 +++++++++++++++++--
 src/line_segment.cpp             | 13 +++++++
 src/line_segment.h               |  8 ++++
 6 files changed, 134 insertions(+), 42 deletions(-)

diff --git a/src/corner_finder_range_diff.cpp b/src/corner_finder_range_diff.cpp
index ac7419d..b97b1ad 100644
--- a/src/corner_finder_range_diff.cpp
+++ b/src/corner_finder_range_diff.cpp
@@ -17,57 +17,48 @@ int CornerFinderRangeDiff::findCorners(const laserscanutils::LaserScan & _scan,
                                        std::list<laserscanutils::CornerPoint> & _corner_list)
 {
     //constants TODO: should be moved as a set algorithm params
-    ScalarT ZERO_RANGE_DIFF = 0.02; 
-    unsigned int CORNER_WINDOW_SIZE = 5; //minimum size of line supproting corner
+    unsigned int HALF_WINDOW_SIZE = 5; //minimum size of line supproting corner
+    ScalarT LINE_FIT_ERROR = 0.05; //maximum allowed mean point-line error to consider a line is straight enough
+    ScalarT MIN_ANGLE = 30*M_PI/180.; //minimum allowed absoulte angle between lines around the corner
     
     //variables
-    ScalarT range_diff; 
+    ScalarT e1,e2, angle; 
     LineSegment line1, line2;
+    CornerPoint new_corner; 
     
     //check if _scan is already raw processed
     if ( !_scan.isRawProcessed() ) return -1; 
     
     //run over all scan data
-    for (unsigned int ii = CORNER_WINDOW_SIZE; ii<_scan.ranges_.size()-CORNER_WINDOW_SIZE; ii++)
+    for (unsigned int ii = HALF_WINDOW_SIZE; ii<_scan.ranges_.size()-HALF_WINDOW_SIZE; ii++)
     {
-        //check if ranges ii and ii-1 are both correct and there is no jump between them
-        if (  ( _scan.ranges_[ii-1] > 0 ) && ( _scan.ranges_[ii] > 0 ) && ( _scan.jumps_mask_[ii] == false ) )
+        //check correctness and jumps
+        if ( ( _scan.checkScanCorrectness(ii, HALF_WINDOW_SIZE) == true ) 
+             &&
+             ( _scan.checkScanJumps(ii, HALF_WINDOW_SIZE) == false ) )
         {
-            //compute range difference
-            range_diff = _scan.ranges_[ii] - _scan.ranges_[ii-1];
+            //fit lines at left and right of the point
+            line_finder_.fitLine(_scan.points_.block(0,ii-HALF_WINDOW_SIZE,3,HALF_WINDOW_SIZE+1), line1);
+            line_finder_.fitLine(_scan.points_.block(0,ii,3,HALF_WINDOW_SIZE+1), line2);    
             
-            //corners have range diff close to zero TODO: this condition is to be discussed
-            if(range_diff < ZERO_RANGE_DIFF) 
+            //check line error 
+            e1 = line1.fit_error_ / ( (ScalarT)HALF_WINDOW_SIZE * 2 + 1);
+            e2 = line2.fit_error_ / ( (ScalarT)HALF_WINDOW_SIZE * 2 + 1);
+            if ( ( e1 < LINE_FIT_ERROR ) && ( e2 < LINE_FIT_ERROR ) )
             {
-                //fit lines at eft and right of the point
-                line_finder_.fitLine(_scan.points_.block(0,ii-CORNER_WINDOW_SIZE,3,CORNER_WINDOW_SIZE*2), line1);
-                line_finder_.fitLine(_scan.points_.block(0,ii-CORNER_WINDOW_SIZE,3,CORNER_WINDOW_SIZE*2), line2);    
-                
-                //check angle between lines
-                //check fit errors
-                
-//                 if ( fit errors < FIT_ERROR) && (angle in (0,135)U(225,360) ) //CORNER_MIN_ANGLE
-//                 {
-//                     //corner found
-//                     //set corner
-//                     // _corner_list.push_back(); 
-//                 }                
+                //check angles between lines 
+                angle = line1.angleToLine(line2); //angle is in [0,2pi]
+                if ( ( angle < M_PI-MIN_ANGLE ) || ( angle > M_PI+MIN_ANGLE ) )
+                {
+//                     //corner found !!
+//                     new_corner.point_ << _scan.points_all_.block<1,3>(0,);
+//                     //new_corner.orientation_ = ;
+//                     new_corner.aperture_ = angle; 
+//                     _corner_list.push_back(new_corner); 
+                }
             }
         }
     }
-    
-/*
-    range_diff_i = range_i - range_(i-1)
-    
-    if(range_diff_i < ZERO_RANGE_DIFF) 
-    {
-        v1,b1 = check {r_{i-CORNER_WINDOW_SIZE}, r_i} is line (with FIT_ERROR)
-        v2,b2 = check {r_i, r_{i-CORNER_WINDOW_SIZE}} is line (with FIT_ERROR)
-        
-        angle = getAngle(b1,b2);
-        
-    }
-*/
 }
 
 void CornerFinderRangeDiff::print() const
diff --git a/src/corner_finder_range_diff.h b/src/corner_finder_range_diff.h
index 1a3e14f..4c8466a 100644
--- a/src/corner_finder_range_diff.h
+++ b/src/corner_finder_range_diff.h
@@ -61,10 +61,10 @@ class CornerFinderRangeDiff : public CornerFinder
         * Returns corners as a std::list<CornerPoint>
         * 
         * \Requires: 
-        *    \param _points: 3xN matrix, set of points. Each column is a 2D point in homogeneous (x,y,1). Ordering is not required.
+        *    \param _scan: A LaserScan object, already raw processed. If not raw processed, this method returns -1
         * 
         * \Provides: 
-        *    \param _corner_list set of corners extracted from _points
+        *    \param _corner_list set of corners extracted from _scan
         *    \return Number of corners extracted.
         *
         */
diff --git a/src/laser_scan.cpp b/src/laser_scan.cpp
index 0e3729f..3c4c1de 100644
--- a/src/laser_scan.cpp
+++ b/src/laser_scan.cpp
@@ -100,6 +100,56 @@ void LaserScan::ranges2xy(Eigen::Matrix4s _device_T)
     is_raw_processed_ = true; 
 }
 
+bool LaserScan::checkScanCorrectness(unsigned int _idx, unsigned int _idx_range) const
+{
+    bool correct = true; 
+    
+    //first of all check if scan has been raw processed
+    if ( ! is_raw_processed_ ) return false;
+
+    //set loop bounds
+    unsigned int ii_init = std::max( 0 , (_idx-_idx_range) );
+    unsigned int ii_end = std::min( ranges_.size()-1 , (_idx+_idx_range) );
+    
+    //proceed
+    for (unsigned int ii=ii_init; ii<=ii_end; ii++ )
+    {
+        if (ranges_[ii] < 0)
+        {
+            correct = false; 
+            break; 
+        }
+    }
+    
+    //return
+    return correct; 
+}
+
+bool LaserScan::checkScanJumps(unsigned int _idx, unsigned int _idx_range) const
+{
+    bool jump = false; 
+    
+    //first of all check if scan has been raw processed
+    if ( ! is_raw_processed_ ) return true;
+    
+    //set loop bounds
+    unsigned int ii_init = std::max( 0 , (_idx-_idx_range) );
+    unsigned int ii_end = std::min( ranges_.size()-1 , (_idx+_idx_range) );
+    
+    //proceed
+    for (unsigned int ii=ii_init; ii<=ii_end; ii++ )
+    {
+        if ( jumps_mask_[ii] )
+        {
+            jump = true; 
+            break; 
+        }
+    }
+    
+    //return
+    return jump; 
+}
+
 void LaserScan::findSegments(std::list<laserscanutils::ScanSegment> & _segment_list)
 {
     std::list<unsigned int>::iterator jumps_it, next_jumps_it, jumps_last; 
diff --git a/src/laser_scan.h b/src/laser_scan.h
index 415bfd7..9b6c39c 100644
--- a/src/laser_scan.h
+++ b/src/laser_scan.h
@@ -9,6 +9,7 @@
 #include <vector>
 #include <list>
 #include <iostream>
+#include <algorithm> //std::min, max
 
 namespace laserscanutils
 {
@@ -51,16 +52,27 @@ class LaserScan
         //Ordered raw range data
         std::vector<float> ranges_raw_; 
         
-        //Ordered and marked range data. Bad values (NaN's, Inf's, out of range) are indicated with -1
+        //Ordered and marked range data. Bad values (NaN's, Inf's, out of range) are indicated with -1. 
+        //Same size as ranges_raw_
         std::vector<float> ranges_; 
+
+        //Ordered, Marked 2D points, each one expressed in homogeneous coordinates (x,y,1)^T. 
+        //NaN's, inf's and out of range are marked as points at infty->last component set to 0.
+        //Same size as ranges_raw_
+        //Eigen::MatrixXs points_all_;
         
-        //ordered 2D points, each one expressed in homogeneous coordinates (x,y,1)^T. NaN and inf's are filtered out. 
+        //Ordered, Correct 2D points, each one expressed in homogeneous coordinates (x,y,1)^T. 
+        //NaN's, inf's and out of range are filtered out, implying:
+        //          - not necessarily regular angular increments between consecutive points
+        //          - size equal or smaller than ranges_raw_
         Eigen::MatrixXs points_;
         
-        //For each element in ranges_, r_i, indicates if there is a jump (true) between that element and the previouos.
+        //For each element in ranges_, r_i, indicates if there is a jump (true) between that element and the previouos. 
+        //Same size as ranges_raw_
         std::vector<bool> jumps_mask_; 
         
         //list of indexes over points_ where a scan jump is found. Indexes indicate the second point of the jump (start of a scan segment)
+        //size smaller than ranges_raw_
         std::list<unsigned int> jumps_indexes_; 
 
             
@@ -108,8 +120,26 @@ class LaserScan
         **/
         void ranges2xy(Eigen::Matrix4s _device_T = Eigen::Matrix4s::Identity());   
         //TODO void processRaw()-> from ranges_raw_ fills: ranges_, points_, jumps_indexes and jumps_mask
+        
+        /** \brief Check for scan correctness 
+         * 
+         * Check for scan correctness
+         * Returns True if all scan points in [ _idx-_idx_range , _idx+_idx_range ] are ok
+         * Otherwise returns false. 
+         * 
+         **/
+        bool checkScanCorrectness(unsigned int _idx, unsigned int _idx_range) const; 
 
-        /** \brief Find segments based on jumps of consecutive scan points
+        /** \brief Check for scan jumps
+         * 
+         * Check for scan jumps
+         * Returns True if there is at least one jump in some point in [ _idx-_idx_range , _idx+_idx_range ]
+         * Otherwise returns false. 
+         * 
+         **/
+        bool checkScanJumps(unsigned int _idx, unsigned int _idx_range) const; 
+        
+        /** \brief Find segments based on jumps of consecutive scan points TODO. MOve away this method to anoter class SegmentFinder
         *
         * Find segments based on jumps of consecutive scan points
         * Do not compute segment parameters, just fill ScanSegment.points_
diff --git a/src/line_segment.cpp b/src/line_segment.cpp
index 4978256..8b0fcec 100644
--- a/src/line_segment.cpp
+++ b/src/line_segment.cpp
@@ -58,6 +58,19 @@ void LineSegment::pointProjectionToLine(const Eigen::Vector3s & _in_pt, Eigen::V
     _out_pt(0) = -( c + b*_out_pt(1) ) / a; 
 }
 
+double angleToLine(const laserscanutils::LineSegment & _line) const
+{
+    //compute each angle at 4-quadrant in [-pi,pi]
+    ScalarT angle_this = atan2(abc_(1)/abc_(2), abc_(0)/abc_(2)); 
+    ScalarT angle_line = atan2(_line.abc_(1)/_line.abc_(2), _line.abc_(0)/_line.abc_(2)); 
+    
+    //Fit angles to [0,2pi] domain
+    if ( angle_this < 0 ) angle_this = 2*M_PI + angle_this;
+    if ( angle_line < 0 ) angle_line = 2*M_PI + angle_line; 
+    
+    //return angle from this to _line, in [0,2pi]
+    return (angle_line-angle_this); 
+}
 
 void LineSegment::merge(const LineSegment & _segment)
 {
diff --git a/src/line_segment.h b/src/line_segment.h
index 585c778..9214900 100644
--- a/src/line_segment.h
+++ b/src/line_segment.h
@@ -50,6 +50,14 @@ class LineSegment
         **/
         void pointProjectionToLine(const Eigen::Vector3s & _in_pt, Eigen::Vector3s & _out_pt) const;
         
+        /** \brief Angle from this to line, in [0,2pi]
+         * 
+         * Returns the angle from this vector abc_ to the argument line's vector abc_
+         * Return value in [0,2pi]
+         * 
+         **/
+        double angleToLine(const laserscanutils::LineSegment & _line) const; 
+        
         //merges this LineSegment with the argument. 
         void merge(const LineSegment & _segment); 
       
-- 
GitLab