Program Listing for File segment2D.hpp

Return to documentation for file (/tmp/ws/src/slg_msgs/include/slg_msgs/segment2D.hpp)

/*
 * SEGMENT 2D CLASS
 *
 * Copyright (c) 2017-2022 Alberto José Tudela Roldán <ajtudela@gmail.com>
 *
 * This file is part of slg_msgs.
 *
 * All rights reserved.
 *
 */

#ifndef SLG_MSGS__SEGMENT2D_HPP_
#define SLG_MSGS__SEGMENT2D_HPP_

#include <vector>
#include <algorithm>
#include <numeric>

#include <slg_msgs/msg/segment.hpp>

#include "point2D.hpp"

namespace slg{
class Segment2D{
    public:
        Segment2D() : id(0),
                      label(BACKGROUND),
                      angular_distance_to_closest_boundary(0.0),
                      last_point_prior_seg(Point2D(0, 0)),
                      first_point_next_seg(Point2D(0, 0)),
                      last_centroid(Point2D(0, 0)) {}

        Segment2D(int newId, Point2D prevPoint, Point2D currPoint, Point2D nextPoint) :
                    id(newId),
                    label(BACKGROUND),
                    angular_distance_to_closest_boundary(0.0),
                    points({currPoint}),
                    last_point_prior_seg(prevPoint),
                    first_point_next_seg(nextPoint),
                    last_centroid(currPoint) {}

        Segment2D(const Segment2D& seg) :
                    id(seg.get_id()),
                    label(seg.get_label()),
                    angular_distance_to_closest_boundary(0.0),
                    points(seg.get_points()),
                    last_point_prior_seg(seg.get_prior_segment()),
                    first_point_next_seg(seg.get_next_segment()),
                    last_centroid(seg.get_last_centroid()) {}

        Segment2D(const slg_msgs::msg::Segment& segmentMsg) :
                    id(segmentMsg.id),
                    label(slg::Label(segmentMsg.label)),
                    angular_distance_to_closest_boundary(segmentMsg.angular_distance),
                    last_point_prior_seg(segmentMsg.last_point_prior_segment),
                    first_point_next_seg(segmentMsg.first_point_next_segment)
                    {
                        points.insert(points.begin(), std::begin(segmentMsg.points), std::end(segmentMsg.points));
                    }

        ~Segment2D(){}

        operator slg_msgs::msg::Segment() const{
            slg_msgs::msg::Segment segmentMsg;

            // Transform the segment in message
            segmentMsg.id = id;
            segmentMsg.label = label;
            segmentMsg.angular_distance = angular_distance_to_closest_boundary;
            segmentMsg.last_point_prior_segment.x = last_point_prior_seg.x;
            segmentMsg.last_point_prior_segment.y = last_point_prior_seg.y;
            segmentMsg.first_point_next_segment.x = first_point_next_seg.x;
            segmentMsg.first_point_next_segment.y = first_point_next_seg.y;

            for (const auto& point : points){
                segmentMsg.points.push_back(point);
            }

            return segmentMsg;
        }

        Segment2D& operator= (const Segment2D & seg){
            if (this != &seg){
                this->id = seg.get_id();
                this->label = seg.get_label();
                this->points = seg.get_points();
                this->last_point_prior_seg = seg.get_prior_segment();
                this->first_point_next_seg = seg.get_next_segment();
                this->last_centroid = seg.get_last_centroid();
            }
            return *this;
        }

        Segment2D& operator= (const slg_msgs::msg::Segment & segmentMsg){
            *this = Segment2D(segmentMsg);
            return *this;
        }

        int size()              const       { return points.size(); }
        bool empty()            const       { return points.empty(); }
        void clear()                        { points.clear(); id = 0; label = BACKGROUND; }
        double width()          const       { return (points.back() - points.front()).length(); }
        double width_squared()  const       { return (points.back() - points.front()).length_squared(); }
        Point2D first_point()   const       { return points.front(); }
        Point2D last_point()    const       { return points.back(); }
        Point2D vector()        const       { return points.back() - points.front(); }
        double min_angle()      const       { return points.front().angle(); }
        double max_angle()      const       { return points.back().angle(); }
        double mean_angle()     const       { return (points.front().angle() + points.back().angle()) / 2.0; }
        int get_id()            const       { return id; }
        Label get_label()       const       { return label; }
        std::vector<Point2D> get_points() const{ return points; }
        Point2D get_prior_segment() const       { return last_point_prior_seg; }
        Point2D get_next_segment()  const       { return first_point_next_seg; }
        Point2D get_last_centroid() const       { return last_centroid; }
        double get_angular_distance_to_closest_boundary() const {return angular_distance_to_closest_boundary; }
        void set_id(int id)                 { this->id = id; }
        void set_label(Label label)         { this->label = label; }
        void set_prior_segment(Point2D point)   { last_point_prior_seg = point; }
        void set_next_segment(Point2D point)    { first_point_next_seg = point; }
        void set_last_centroid(Point2D point)   { last_centroid = point; }
        void set_angular_distance_to_closest_boundary(double angle) {angular_distance_to_closest_boundary = angle; }

        double orientation(){
            return (vector().y != 0.0) ? Point2D(-1, - vector().x / vector().y).angle() : 0.0;
        }

        Point2D projection(const Point2D& p) const {
            Point2D a = points.back() - points.front();
            Point2D b = p - points.front();
            return points.front() + a.dot(b) * a / a.length_squared();
        }

        double distance_to(const Point2D& p) const {
            return (p - projection(p)).length();
        }

        Point2D centroid() const{
            Point2D sum = std::accumulate(points.begin(), points.end(), Point2D(0.0, 0.0));
            return sum / points.size();
        }

        double height() const{
            auto maxPoint = std::max_element(points.begin(), points.end(), [](Point2D p1, Point2D p2){return p1.y < p2.y;});
            return distance_to(*maxPoint);
        }

        void add_point(Point2D point){
            points.push_back(point);
            last_centroid = centroid();
        }

        void add_points(std::vector<Point2D> newPoints){
            points.insert(points.end(), newPoints.begin(), newPoints.end());
        }

        void merge(Segment2D seg){
            if (label != seg.get_label()) label = BACKGROUND;

            std::vector<Point2D> newPoints = seg.get_points();
            points.insert(points.end(), newPoints.begin(), newPoints.end());
            first_point_next_seg = seg.get_next_segment();
            last_centroid = centroid();
        }

        Segment2D left_split(int index){
            std::vector<Point2D> left(points.begin(), points.begin() + index);

            Segment2D splited_segment;
            splited_segment.add_points(left);
            splited_segment.set_id(this->id);
            splited_segment.set_label(this->label);
            splited_segment.set_prior_segment(this->last_point_prior_seg);
            splited_segment.set_next_segment(points[index+1]);

            return splited_segment;
        }

        Segment2D right_split(int index){
            std::vector<Point2D> right(points.begin() + index, points.end());

            Segment2D splited_segment;
            splited_segment.add_points(right);
            splited_segment.set_id(this->id);
            splited_segment.set_label(this->label);
            splited_segment.set_prior_segment(points[index-1]);
            splited_segment.set_next_segment(this->first_point_next_seg);

            return splited_segment;
        }

    private:
        int id;
        Label label;
        double angular_distance_to_closest_boundary;
        std::vector<Point2D> points;
        Point2D last_point_prior_seg, first_point_next_seg, last_centroid;
};
}  // namespace slg

#endif  // SLG_MSGS__SEGMENT2D_HPP_