基本几何对象(5)——Polygon

定义Polygon类,作为多边形,这是一个常用的几何对象。Polygon是有相同首尾点的Polyline,因此我选择在Polyline的尾部添加一个和头部点相同的点作为尾部点,而非像某些实现那样在获取第尾部点时返回头部点。

下面给出Polygon的声明。

class Polygon : public Polyline
{
    public:
        Polygon() {};

        Polygon(const Polygon &polygon);

        Polygon(std::vector<Point>::const_iterator begin, std::vector<Point>::const_iterator end);

        Polygon(const std::initializer_list<Point> &points);

        Polygon(const Polyline &polyline);

        Polygon(const AABBRect &rect);

        Polygon &operator=(const Polygon &polygon);

        const Type type() const override;

        Polygon *clone() const override;

        void reorder_points(const bool cw = true);

        // 判断点顺序是否为顺时针
        bool is_cw() const;

        void append(const Point &point) override;

        void append(const Polyline &polyline) override;

        void append(std::vector<Point>::const_iterator begin, std::vector<Point>::const_iterator end) override;

        void insert(const size_t index, const Point &point) override;

        void insert(const size_t index, const Polyline &polyline) override;

        void insert(const size_t index, std::vector<Point>::const_iterator begin, std::vector<Point>::const_iterator end) override;

        void remove(const size_t index) override;

        void remove(const size_t index, const size_t count) override;

        Point pop(const size_t index) override;

        Polygon operator+(const Point &point) const;

        Polygon operator-(const Point &point) const;

        void operator+=(const Point &point);

        void operator-=(const Point &point);

        const double area() const;

        size_t next_point_index(const size_t index) const;

        const Point &next_point(const size_t index) const;

        Point &next_point(const size_t index);

        size_t last_point_index(const size_t index) const;

        const Point &last_point(const size_t index) const;

        Point &last_point(const size_t index);

        size_t index(const double x, const double y) const;

        size_t index(const Point &point) const;
};

下面给出Polygon的实现。

Polygon::Polygon(const Polygon &polygon)
    :Polyline(polygon)
{}

Polygon::Polygon(std::vector<Point>::const_iterator begin, std::vector<Point>::const_iterator end)
    :Polyline(begin, end)
{
    assert(size() >= 3);
    if (_points.back() != _points.front())
    {
        _points.emplace_back(_points.front());
    }
}

Polygon::Polygon(const std::initializer_list<Point> &points)
    :Polyline(points)
{
    assert(size() > 2);
    if (_points.back() != _points.front())
    {
        _points.emplace_back(_points.front());
    }
}

Polygon::Polygon(const Polyline &polyline)
    :Polyline(polyline)
{
    if (_points.back() != _points.front())
    {
        _points.emplace_back(_points.front());
    }
}

Polygon::Polygon(const AABBRect& rect)
    :Polyline(rect.cbegin(), rect.cend())
{}

Polygon &Polygon::operator=(const Polygon &polygon)
{
    if (this != &polygon)
    {
        Polyline::operator=(polygon);
    }
    return *this;
}

const Type Polygon::type() const
{
    return Type::POLYGON;
}

Polygon *Polygon::clone() const
{
    return new Polygon(*this);
}

void Polygon::reorder_points(const bool cw)
{
    if (size() < 4)
    {
        return;
    }
    
    double result = 0;
    for (size_t i = 0, count = size() - 1; i < count; ++i)
    {
        result += (_points[i].x * _points[i + 1].y - _points[i + 1].x * _points[i].y);
    }
    if (cw)
    {
        if (result > 0)
        {
            std::reverse(_points.begin(), _points.end());
        }
    }
    else
    {
        if (result < 0)
        {
            std::reverse(_points.begin(), _points.end());
        }
    }
}

bool Polygon::is_cw() const
{
    if (size() < 4)
    {
        return false;
    }
    
    double result = 0;
    for (size_t i = 0, count = size() - 1; i < count; ++i)
    {
        result += (_points[i].x * _points[i + 1].y - _points[i + 1].x * _points[i].y);
    }
    return result < 0;
}

void Polygon::append(const Point &point)
{
    if (size() < 2)
    {
        Polyline::append(point);
    }
    else
    {
        if (_points.front() == _points.back())
        {
            Polyline::insert(size() - 1, point);
        }
        else
        {
            _points.emplace_back(point);
            _points.emplace_back(_points.front());
        }
    }
}

void Polygon::append(const Polyline &polyline)
{
    if (empty())
    {
        Polyline::append(polyline);
        if (_points.front() != _points.back())
        {
            _points.emplace_back(_points.front());
        }
    }
    else
    {
        if (_points.front() == _points.back())
        {
            Polyline::insert(size() - 1, polyline);
        }
        else
        {
            Polyline::append(polyline);
            _points.emplace_back(_points.front());
        }
    }
}

void Polygon::append(std::vector<Point>::const_iterator begin, std::vector<Point>::const_iterator end)
{
    if (empty())
    {
        Polyline::append(begin, end);
        if (_points.front() != _points.back())
        {
            _points.emplace_back(_points.front());
        }
    }
    else
    {
        if (_points.front() == _points.back())
        {
            Polyline::insert(size() - 1, begin, end);
        }
        else
        {
            _points.insert(_points.end(), begin, end);
            _points.emplace_back(_points.front());
        }
    }
}

void Polygon::insert(const size_t index, const Point &point)
{
    Polyline::insert(index, point);
    if (index == 0)
    {
        _points.back() = _points.front();
    }
}

void Polygon::insert(const size_t index, const Polyline &polyline)
{
    Polyline::insert(index, polyline);
    if (index == 0)
    {
        _points.back() = _points.front();
    }
}

void Polygon::insert(const size_t index, std::vector<Point>::const_iterator begin, std::vector<Point>::const_iterator end)
{
    Polyline::insert(index, begin, end);
    if (index == 0)
    {
        _points.back() = _points.front();
    }
}

void Polygon::remove(const size_t index)
{
    Polyline::remove(index);
    if (index == 0)
    {
        _points.back() = _points.front();
    }
    else if (index == size())
    {
        _points.front() == _points.back();
    }
}

void Polygon::remove(const size_t index, const size_t count)
{
    Polyline::remove(index, count);
    if (size() > 2)
    {
        if (index == 0)
        {
            back() = front();
        }
        else if (index + count >= size())
        {
            front() = back();
        }
    }
}

Point Polygon::pop(const size_t index)
{
    Geo::Point point = Polyline::pop(index);
    if (index == 0)
    {
        _points.back() = _points.front();
    }
    else if (index == size())
    {
        _points.front() = _points.back();
    }
    return point;
}

Polygon Polygon::operator+(const Point &point) const
{
    std::vector<Point> temp(begin(), end());
    for (Point &p : temp)
    {
        p += point;
    }
    return Polygon(temp.begin(), temp.end());
}

Polygon Polygon::operator-(const Point &point) const
{
    std::vector<Point> temp(begin(), end());
    for (Point &p : temp)
    {
        p -= point;
    }
    return Polygon(temp.begin(), temp.end());
}

void Polygon::operator+=(const Point &point)
{
    for (Point &p : _points)
    {
        p += point;
    }
}

void Polygon::operator-=(const Point &point)
{
    for (Point &p : _points)
    {
        p -= point;
    }
}

const double Polygon::area() const
{
    if (size() < 4)
    {
        return 0;
    }
    double result = 0;
    for (size_t i = 0, count = size() - 1; i < count; ++i)
    {
        result += (_points[i].x * _points[i + 1].y - _points[i + 1].x * _points[i].y);
    }
    return std::abs(result) / 2.0;
}

size_t Polygon::next_point_index(const size_t index) const
{
    if (index < size() - 1)
    {
        return index + 1;
    }
    else
    {
        return 1;
    }
}

const Point &Polygon::next_point(const size_t index) const
{
    if (index < size() - 1)
    {
        return _points[index + 1];
    }
    else
    {
        return _points[1];
    }
}

Point &Polygon::next_point(const size_t index)
{
    if (index < size() - 1)
    {
        return _points[index + 1];
    }
    else
    {
        return _points[1];
    }
}

size_t Polygon::last_point_index(const size_t index) const
{
    if (index > 0)
    {
        return index - 1;
    }
    else
    {
        return size() - 2;
    }
}

const Point &Polygon::last_point(const size_t index) const
{
    if (index > 0)
    {
        return _points[index - 1];
    }
    else
    {
        return _points[_points.size() - 2];
    }
}

Point &Polygon::last_point(const size_t index)
{
    if (index > 0)
    {
        return _points[index - 1];
    }
    else
    {
        return _points[_points.size() - 2];
    }
}

size_t Polygon::index(const double x, const double y) const
{
    for (size_t i = 0, count = _points.size() - 1; i < count; ++i)
    {
        if (_points[i].x == x && _points[i].y == y)
        {
            return i;
        }
    }
    return SIZE_MAX;
}

size_t Polygon::index(const Point &point) const
{
    for (size_t i = 0, count = _points.size() - 1; i < count; ++i)
    {
        if (_points[i] == point)
        {
            return i;
        }
    }
    return SIZE_MAX;
}

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值