/*************************************************************************/1/* Copyright (c) 2011-2021 Ivan Fratric and contributors. */2/* */3/* Permission is hereby granted, free of charge, to any person obtaining */4/* a copy of this software and associated documentation files (the */5/* "Software"), to deal in the Software without restriction, including */6/* without limitation the rights to use, copy, modify, merge, publish, */7/* distribute, sublicense, and/or sell copies of the Software, and to */8/* permit persons to whom the Software is furnished to do so, subject to */9/* the following conditions: */10/* */11/* The above copyright notice and this permission notice shall be */12/* included in all copies or substantial portions of the Software. */13/* */14/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */15/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */16/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/17/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */18/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */19/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */20/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */21/*************************************************************************/2223#ifndef POLYPARTITION_H24#define POLYPARTITION_H2526#include "core/math/vector2.h"27#include "core/templates/list.h"28#include "core/templates/rb_set.h"2930typedef double tppl_float;3132enum TPPLOrientation {33TPPL_ORIENTATION_CW = -1,34TPPL_ORIENTATION_NONE = 0,35TPPL_ORIENTATION_CCW = 1,36};3738enum TPPLVertexType {39TPPL_VERTEXTYPE_REGULAR = 0,40TPPL_VERTEXTYPE_START = 1,41TPPL_VERTEXTYPE_END = 2,42TPPL_VERTEXTYPE_SPLIT = 3,43TPPL_VERTEXTYPE_MERGE = 4,44};4546// 2D point structure.47typedef Vector2 TPPLPoint;4849// Polygon implemented as an array of points with a "hole" flag.50class TPPLPoly {51protected:52TPPLPoint *points;53long numpoints;54bool hole;5556public:57// Constructors and destructors.58TPPLPoly();59~TPPLPoly();6061TPPLPoly(const TPPLPoly &src);62TPPLPoly &operator=(const TPPLPoly &src);6364// Getters and setters.65long GetNumPoints() const {66return numpoints;67}6869bool IsHole() const {70return hole;71}7273void SetHole(bool p_hole) {74this->hole = p_hole;75}7677TPPLPoint &GetPoint(long i) {78return points[i];79}8081const TPPLPoint &GetPoint(long i) const {82return points[i];83}8485TPPLPoint *GetPoints() {86return points;87}8889TPPLPoint &operator[](int i) {90return points[i];91}9293const TPPLPoint &operator[](int i) const {94return points[i];95}9697// Clears the polygon points.98void Clear();99100// Inits the polygon with numpoints vertices.101void Init(long numpoints);102103// Creates a triangle with points p1, p2, and p3.104void Triangle(TPPLPoint &p1, TPPLPoint &p2, TPPLPoint &p3);105106// Inverts the orfer of vertices.107void Invert();108109// Returns the orientation of the polygon.110// Possible values:111// TPPL_ORIENTATION_CCW: Polygon vertices are in counter-clockwise order.112// TPPL_ORIENTATION_CW: Polygon vertices are in clockwise order.113// TPPL_ORIENTATION_NONE: The polygon has no (measurable) area.114TPPLOrientation GetOrientation() const;115116// Sets the polygon orientation.117// Possible values:118// TPPL_ORIENTATION_CCW: Sets vertices in counter-clockwise order.119// TPPL_ORIENTATION_CW: Sets vertices in clockwise order.120// TPPL_ORIENTATION_NONE: Reverses the orientation of the vertices if there121// is one, otherwise does nothing (if orientation is already NONE).122void SetOrientation(TPPLOrientation orientation);123124// Checks whether a polygon is valid or not.125inline bool Valid() const { return this->numpoints >= 3; }126};127128#ifdef TPPL_ALLOCATOR129typedef List<TPPLPoly, TPPL_ALLOCATOR(TPPLPoly)> TPPLPolyList;130#else131typedef List<TPPLPoly> TPPLPolyList;132#endif133134class TPPLPartition {135protected:136struct PartitionVertex {137bool isActive;138bool isConvex;139bool isEar;140141TPPLPoint p;142tppl_float angle;143PartitionVertex *previous;144PartitionVertex *next;145146PartitionVertex();147};148149struct MonotoneVertex {150TPPLPoint p;151long previous;152long next;153};154155class VertexSorter {156MonotoneVertex *vertices;157158public:159VertexSorter(MonotoneVertex *v) :160vertices(v) {}161bool operator()(long index1, long index2);162};163164struct Diagonal {165long index1;166long index2;167};168169#ifdef TPPL_ALLOCATOR170typedef List<Diagonal, TPPL_ALLOCATOR(Diagonal)> DiagonalList;171#else172typedef List<Diagonal> DiagonalList;173#endif174175// Dynamic programming state for minimum-weight triangulation.176struct DPState {177bool visible;178tppl_float weight;179long bestvertex;180};181182// Dynamic programming state for convex partitioning.183struct DPState2 {184bool visible;185long weight;186DiagonalList pairs;187};188189// Edge that intersects the scanline.190struct ScanLineEdge {191mutable long index;192TPPLPoint p1;193TPPLPoint p2;194195// Determines if the edge is to the left of another edge.196bool operator<(const ScanLineEdge &other) const;197198bool IsConvex(const TPPLPoint &p1, const TPPLPoint &p2, const TPPLPoint &p3) const;199};200201// Standard helper functions.202bool IsConvex(TPPLPoint &p1, TPPLPoint &p2, TPPLPoint &p3);203bool IsReflex(TPPLPoint &p1, TPPLPoint &p2, TPPLPoint &p3);204bool IsInside(TPPLPoint &p1, TPPLPoint &p2, TPPLPoint &p3, TPPLPoint &p);205206bool InCone(TPPLPoint &p1, TPPLPoint &p2, TPPLPoint &p3, TPPLPoint &p);207bool InCone(PartitionVertex *v, TPPLPoint &p);208209int Intersects(TPPLPoint &p11, TPPLPoint &p12, TPPLPoint &p21, TPPLPoint &p22);210211TPPLPoint Normalize(const TPPLPoint &p);212tppl_float Distance(const TPPLPoint &p1, const TPPLPoint &p2);213214// Helper functions for Triangulate_EC.215void UpdateVertexReflexity(PartitionVertex *v);216void UpdateVertex(PartitionVertex *v, PartitionVertex *vertices, long numvertices);217218// Helper functions for ConvexPartition_OPT.219void UpdateState(long a, long b, long w, long i, long j, DPState2 **dpstates);220void TypeA(long i, long j, long k, PartitionVertex *vertices, DPState2 **dpstates);221void TypeB(long i, long j, long k, PartitionVertex *vertices, DPState2 **dpstates);222223// Helper functions for MonotonePartition.224bool Below(TPPLPoint &p1, TPPLPoint &p2);225void AddDiagonal(MonotoneVertex *vertices, long *numvertices, long index1, long index2,226TPPLVertexType *vertextypes, RBSet<ScanLineEdge>::Element **edgeTreeIterators,227RBSet<ScanLineEdge> *edgeTree, long *helpers);228229// Triangulates a monotone polygon, used in Triangulate_MONO.230int TriangulateMonotone(TPPLPoly *inPoly, TPPLPolyList *triangles);231232public:233// Simple heuristic procedure for removing holes from a list of polygons.234// It works by creating a diagonal from the right-most hole vertex235// to some other visible vertex.236// Time complexity: O(h*(n^2)), h is the # of holes, n is the # of vertices.237// Space complexity: O(n)238// params:239// inpolys:240// A list of polygons that can contain holes.241// Vertices of all non-hole polys have to be in counter-clockwise order.242// Vertices of all hole polys have to be in clockwise order.243// outpolys:244// A list of polygons without holes.245// Returns 1 on success, 0 on failure.246int RemoveHoles(TPPLPolyList *inpolys, TPPLPolyList *outpolys);247248// Triangulates a polygon by ear clipping.249// Time complexity: O(n^2), n is the number of vertices.250// Space complexity: O(n)251// params:252// poly:253// An input polygon to be triangulated.254// Vertices have to be in counter-clockwise order.255// triangles:256// A list of triangles (result).257// Returns 1 on success, 0 on failure.258int Triangulate_EC(TPPLPoly *poly, TPPLPolyList *triangles);259260// Triangulates a list of polygons that may contain holes by ear clipping261// algorithm. It first calls RemoveHoles to get rid of the holes, and then262// calls Triangulate_EC for each resulting polygon.263// Time complexity: O(h*(n^2)), h is the # of holes, n is the # of vertices.264// Space complexity: O(n)265// params:266// inpolys:267// A list of polygons to be triangulated (can contain holes).268// Vertices of all non-hole polys have to be in counter-clockwise order.269// Vertices of all hole polys have to be in clockwise order.270// triangles:271// A list of triangles (result).272// Returns 1 on success, 0 on failure.273int Triangulate_EC(TPPLPolyList *inpolys, TPPLPolyList *triangles);274275// Creates an optimal polygon triangulation in terms of minimal edge length.276// Time complexity: O(n^3), n is the number of vertices277// Space complexity: O(n^2)278// params:279// poly:280// An input polygon to be triangulated.281// Vertices have to be in counter-clockwise order.282// triangles:283// A list of triangles (result).284// Returns 1 on success, 0 on failure.285int Triangulate_OPT(TPPLPoly *poly, TPPLPolyList *triangles);286287// Triangulates a polygon by first partitioning it into monotone polygons.288// Time complexity: O(n*log(n)), n is the number of vertices.289// Space complexity: O(n)290// params:291// poly:292// An input polygon to be triangulated.293// Vertices have to be in counter-clockwise order.294// triangles:295// A list of triangles (result).296// Returns 1 on success, 0 on failure.297int Triangulate_MONO(TPPLPoly *poly, TPPLPolyList *triangles);298299// Triangulates a list of polygons by first300// partitioning them into monotone polygons.301// Time complexity: O(n*log(n)), n is the number of vertices.302// Space complexity: O(n)303// params:304// inpolys:305// A list of polygons to be triangulated (can contain holes).306// Vertices of all non-hole polys have to be in counter-clockwise order.307// Vertices of all hole polys have to be in clockwise order.308// triangles:309// A list of triangles (result).310// Returns 1 on success, 0 on failure.311int Triangulate_MONO(TPPLPolyList *inpolys, TPPLPolyList *triangles);312313// Creates a monotone partition of a list of polygons that314// can contain holes. Triangulates a set of polygons by315// first partitioning them into monotone polygons.316// Time complexity: O(n*log(n)), n is the number of vertices.317// Space complexity: O(n)318// params:319// inpolys:320// A list of polygons to be triangulated (can contain holes).321// Vertices of all non-hole polys have to be in counter-clockwise order.322// Vertices of all hole polys have to be in clockwise order.323// monotonePolys:324// A list of monotone polygons (result).325// Returns 1 on success, 0 on failure.326int MonotonePartition(TPPLPolyList *inpolys, TPPLPolyList *monotonePolys);327328// Partitions a polygon into convex polygons by using the329// Hertel-Mehlhorn algorithm. The algorithm gives at most four times330// the number of parts as the optimal algorithm, however, in practice331// it works much better than that and often gives optimal partition.332// It uses triangulation obtained by ear clipping as intermediate result.333// Time complexity O(n^2), n is the number of vertices.334// Space complexity: O(n)335// params:336// poly:337// An input polygon to be partitioned.338// Vertices have to be in counter-clockwise order.339// parts:340// Resulting list of convex polygons.341// Returns 1 on success, 0 on failure.342int ConvexPartition_HM(TPPLPoly *poly, TPPLPolyList *parts);343344// Partitions a list of polygons into convex parts by using the345// Hertel-Mehlhorn algorithm. The algorithm gives at most four times346// the number of parts as the optimal algorithm, however, in practice347// it works much better than that and often gives optimal partition.348// It uses triangulation obtained by ear clipping as intermediate result.349// Time complexity O(n^2), n is the number of vertices.350// Space complexity: O(n)351// params:352// inpolys:353// An input list of polygons to be partitioned. Vertices of354// all non-hole polys have to be in counter-clockwise order.355// Vertices of all hole polys have to be in clockwise order.356// parts:357// Resulting list of convex polygons.358// Returns 1 on success, 0 on failure.359int ConvexPartition_HM(TPPLPolyList *inpolys, TPPLPolyList *parts);360361// Optimal convex partitioning (in terms of number of resulting362// convex polygons) using the Keil-Snoeyink algorithm.363// For reference, see M. Keil, J. Snoeyink, "On the time bound for364// convex decomposition of simple polygons", 1998.365// Time complexity O(n^3), n is the number of vertices.366// Space complexity: O(n^3)367// params:368// poly:369// An input polygon to be partitioned.370// Vertices have to be in counter-clockwise order.371// parts:372// Resulting list of convex polygons.373// Returns 1 on success, 0 on failure.374int ConvexPartition_OPT(TPPLPoly *poly, TPPLPolyList *parts);375};376377#endif378379380