#include "polyline.h" #include #include "rays/color.h" #include "rays/debug.h" using namespace ClipperLib; namespace Rays { struct Polyline::Data { typedef std::vector ColorList; typedef std::vector TexCoordList; PointList points; std::unique_ptr pcolors; std::unique_ptr ptexcoords; bool loop = false, fill = false, hole = false; void reset ( const auto* points_, const Color* colors_, const Coord3* texcoords_, size_t size_, bool loop_, bool fill_, bool hole_, auto to_point_fun) { ColorList* colors = colors_ ? &this->colors() : NULL; TexCoordList* texcoords = texcoords_ ? &this->texcoords() : NULL; int size = (int) size_; loop = loop_; fill = fill_; hole = hole_; if (!is_valid()) argument_error(__FILE__, __LINE__, "hole polyline must be looped"); points.clear(); points.reserve(size); if (hole) { for (int i = size - 1; i >= 0; --i) points.emplace_back(to_point_fun(points_[i])); } else { for (int i = 0; i < size; ++i) points.emplace_back(to_point_fun(points_[i])); } if (colors) { colors->clear(); colors->reserve(size); if (hole) { for (int i = size - 1; i >= 0; --i) colors->emplace_back(colors_[i]); } else { for (int i = 0; i < size; ++i) colors->emplace_back(colors_[i]); } } if (texcoords) { texcoords->clear(); texcoords->reserve(size); if (hole) { for (int i = size - 1; i >= 0; --i) texcoords->emplace_back(texcoords_[i]); } else { for (int i = 0; i < size; ++i) texcoords->emplace_back(texcoords_[i]); } } } ColorList& colors () { if (!pcolors) pcolors.reset(new ColorList()); return *pcolors; } TexCoordList& texcoords () { if (!ptexcoords) ptexcoords.reset(new TexCoordList()); return *ptexcoords; } bool is_valid () const { return loop || !hole; } private: #if 0 void reset_values (size_t size_, bool hole, auto fun) { int size = (int) size_; if (hole) for (int i = size - 1; i >= 0; --i) fun((size_t) i); else for (int i = 0; i < size; ++i) fun((size_t) i); } #endif };// Polyline::Data Polyline Polyline_create (const Path& path, bool loop, bool hole) { Path cleaned; ClipperLib::CleanPolygon(path, cleaned); Polyline pl; pl.self->reset( &cleaned[0], NULL, NULL, cleaned.size(), loop, loop, hole, [](const IntPoint& point) {return from_clipper(point);}); return pl; } template static void reset_path (Path* path, I begin, I end) { path->clear(); for (auto it = begin; it != end; ++it) path->emplace_back(to_clipper(*it)); } void Polyline_get_path (Path* path, const Polyline& polyline, bool hole) { const auto& points = polyline.self->points; if (hole) reset_path(path, points.rbegin(), points.rend()); else reset_path(path, points. begin(), points. end()); } Polyline::Polyline () { } Polyline::Polyline ( const Point* points, size_t size, bool loop, const Color* colors, const Coord3* texcoords, bool hole) { self->reset( points, colors, texcoords, size, loop, loop, hole, [](const Point& p) {return p;}); } Polyline::Polyline ( const Point* points, size_t size, bool loop, bool fill, const Color* colors, const Coord3* texcoords, bool hole) { self->reset( points, colors, texcoords, size, loop, fill, hole, [](const Point& p) {return p;}); } Polyline::~Polyline () { } bool Polyline::expand ( Polygon* result, coord width, CapType cap, JoinType join, coord miter_limit) const { return Polyline_expand(result, *this, width, cap, join, miter_limit); } Bounds Polyline::bounds () const { if (empty()) return Bounds(-1, -1, -1); auto it = begin(); Bounds b(*it++, 0); for (auto end = this->end(); it != end; ++it) b |= *it; return b; } bool Polyline::loop () const { return self->loop; } bool Polyline::fill () const { return self->fill; } bool Polyline::hole () const { return self->hole; } const Point* Polyline::points () const { const auto& v = self->points; return !v.empty() ? &v[0] : NULL; } const Color* Polyline::colors () const { const auto& pv = self->pcolors; return pv && !pv->empty() ? &(*pv)[0] : NULL; } const Coord3* Polyline::texcoords () const { const auto& pv = self->ptexcoords; return pv && !pv->empty() ? &(*pv)[0] : NULL; } size_t Polyline::size () const { return self->points.size(); } bool Polyline::empty () const { return size() <= 0; } Polyline::const_iterator Polyline::begin () const { return self->points.begin(); } Polyline::const_iterator Polyline::end () const { return self->points.end(); } const Point& Polyline::operator [] (size_t index) const { return self->points[index]; } Polyline::operator bool () const { return self->is_valid(); } bool Polyline::operator ! () const { return !operator bool(); } }// Rays