diff options
author | shumkovnd <shumkovnd@yandex-team.com> | 2023-11-10 14:39:34 +0300 |
---|---|---|
committer | shumkovnd <shumkovnd@yandex-team.com> | 2023-11-10 16:42:24 +0300 |
commit | 77eb2d3fdcec5c978c64e025ced2764c57c00285 (patch) | |
tree | c51edb0748ca8d4a08d7c7323312c27ba1a8b79a /contrib/python/matplotlib/py3/src/tri/_tri.h | |
parent | dd6d20cadb65582270ac23f4b3b14ae189704b9d (diff) | |
download | ydb-77eb2d3fdcec5c978c64e025ced2764c57c00285.tar.gz |
KIKIMR-19287: add task_stats_drawing script
Diffstat (limited to 'contrib/python/matplotlib/py3/src/tri/_tri.h')
-rw-r--r-- | contrib/python/matplotlib/py3/src/tri/_tri.h | 799 |
1 files changed, 799 insertions, 0 deletions
diff --git a/contrib/python/matplotlib/py3/src/tri/_tri.h b/contrib/python/matplotlib/py3/src/tri/_tri.h new file mode 100644 index 0000000000..c176b4c0e8 --- /dev/null +++ b/contrib/python/matplotlib/py3/src/tri/_tri.h @@ -0,0 +1,799 @@ +/* + * Unstructured triangular grid functions, particularly contouring. + * + * There are two main classes: Triangulation and TriContourGenerator. + * + * Triangulation + * ------------- + * Triangulation is an unstructured triangular grid with npoints and ntri + * triangles. It consists of point x and y coordinates, and information about + * the triangulation stored in an integer array of shape (ntri,3) called + * triangles. Each triangle is represented by three point indices (in the + * range 0 to npoints-1) that comprise the triangle, ordered anticlockwise. + * There is an optional mask of length ntri which can be used to mask out + * triangles and has the same result as removing those triangles from the + * 'triangles' array. + * + * A particular edge of a triangulation is termed a TriEdge, which is a + * triangle index and an edge index in the range 0 to 2. TriEdge(tri,edge) + * refers to the edge that starts at point index triangles(tri,edge) and ends + * at point index triangles(tri,(edge+1)%3). + * + * Various derived fields are calculated when they are first needed. The + * triangle connectivity is stored in a neighbors array of shape (ntri,3) such + * that neighbors(tri,edge) is the index of the triangle that adjoins the + * TriEdge(tri,edge), or -1 if there is no such neighbor. + * + * A triangulation has one or more boundaries, each of which is a 1D array of + * the TriEdges that comprise the boundary, in order following the boundary + * with non-masked triangles on the left. + * + * TriContourGenerator + * ------------------- + * A TriContourGenerator generates contours for a particular Triangulation. + * The process followed is different for non-filled and filled contours, with + * one and two contour levels respectively. In both cases boundary contour + * lines are found first, then interior lines. + * + * Boundary lines start and end on a boundary. They are found by traversing + * the triangulation boundary edges until a suitable start point is found, and + * then the contour line is followed across the interior of the triangulation + * until it ends on another boundary edge. For a non-filled contour this + * completes a line, whereas a filled contour continues by following the + * boundary around until either another boundary start point is found or the + * start of the contour line is reached. Filled contour generation stores + * boolean flags to indicate which boundary edges have already been traversed + * so that they are not dealt with twice. Similar flags are used to indicate + * which triangles have been used when following interior lines. + * + * Interior lines do not intersect any boundaries. They are found by + * traversing all triangles that have not yet been visited until a suitable + * starting point is found, and then the contour line is followed across the + * interior of the triangulation until it returns to the start point. For + * filled contours this process is repeated for both lower and upper contour + * levels, and the direction of traversal is reversed for upper contours. + * + * Working out in which direction a contour line leaves a triangle uses the + * a lookup table. A triangle has three points, each of which has a z-value + * which is either less than the contour level or not. Hence there are 8 + * configurations to deal with, 2 of which do not have a contour line (all + * points below or above (including the same as) the contour level) and 6 that + * do. See the function get_exit_edge for details. + */ +#ifndef MPL_TRI_H +#define MPL_TRI_H + +#include <pybind11/pybind11.h> +#include <pybind11/numpy.h> + +#include <iostream> +#include <list> +#include <map> +#include <set> +#include <vector> + +namespace py = pybind11; + + +/* An edge of a triangle consisting of an triangle index in the range 0 to + * ntri-1 and an edge index in the range 0 to 2. Edge i goes from the + * triangle's point i to point (i+1)%3. */ +struct TriEdge +{ + TriEdge(); + TriEdge(int tri_, int edge_); + bool operator<(const TriEdge& other) const; + bool operator==(const TriEdge& other) const; + bool operator!=(const TriEdge& other) const; + friend std::ostream& operator<<(std::ostream& os, const TriEdge& tri_edge); + + int tri, edge; +}; + +// 2D point with x,y coordinates. +struct XY +{ + XY(); + XY(const double& x_, const double& y_); + double angle() const; // Angle in radians with respect to x-axis. + double cross_z(const XY& other) const; // z-component of cross product. + bool is_right_of(const XY& other) const; // Compares x then y. + bool operator==(const XY& other) const; + bool operator!=(const XY& other) const; + XY operator*(const double& multiplier) const; + const XY& operator+=(const XY& other); + const XY& operator-=(const XY& other); + XY operator+(const XY& other) const; + XY operator-(const XY& other) const; + friend std::ostream& operator<<(std::ostream& os, const XY& xy); + + double x, y; +}; + +// 3D point with x,y,z coordinates. +struct XYZ +{ + XYZ(const double& x_, const double& y_, const double& z_); + XYZ cross(const XYZ& other) const; + double dot(const XYZ& other) const; + XYZ operator-(const XYZ& other) const; + friend std::ostream& operator<<(std::ostream& os, const XYZ& xyz); + + double x, y, z; +}; + +// 2D bounding box, which may be empty. +class BoundingBox +{ +public: + BoundingBox(); + void add(const XY& point); + void expand(const XY& delta); + + // Consider these member variables read-only. + bool empty; + XY lower, upper; +}; + +/* A single line of a contour, which may be a closed line loop or an open line + * strip. Identical adjacent points are avoided using push_back(), and a closed + * line loop should also not have identical first and last points. */ +class ContourLine : public std::vector<XY> +{ +public: + ContourLine(); + void push_back(const XY& point); + void write() const; +}; + +// A Contour is a collection of zero or more ContourLines. +typedef std::vector<ContourLine> Contour; + +// Debug contour writing function. +void write_contour(const Contour& contour); + + + + +/* Triangulation with npoints points and ntri triangles. Derived fields are + * calculated when they are first needed. */ +class Triangulation +{ +public: + typedef py::array_t<double, py::array::c_style | py::array::forcecast> CoordinateArray; + typedef py::array_t<double, py::array::c_style | py::array::forcecast> TwoCoordinateArray; + typedef py::array_t<int, py::array::c_style | py::array::forcecast> TriangleArray; + typedef py::array_t<bool, py::array::c_style | py::array::forcecast> MaskArray; + typedef py::array_t<int, py::array::c_style | py::array::forcecast> EdgeArray; + typedef py::array_t<int, py::array::c_style | py::array::forcecast> NeighborArray; + + /* A single boundary is a vector of the TriEdges that make up that boundary + * following it around with unmasked triangles on the left. */ + typedef std::vector<TriEdge> Boundary; + typedef std::vector<Boundary> Boundaries; + + /* Constructor with optional mask, edges and neighbors. The latter two + * are calculated when first needed. + * x: double array of shape (npoints) of points' x-coordinates. + * y: double array of shape (npoints) of points' y-coordinates. + * triangles: int array of shape (ntri,3) of triangle point indices. + * Those ordered clockwise are changed to be anticlockwise. + * mask: Optional bool array of shape (ntri) indicating which triangles + * are masked. + * edges: Optional int array of shape (?,2) of start and end point + * indices, each edge (start,end and end,start) appearing only + * once. + * neighbors: Optional int array of shape (ntri,3) indicating which + * triangles are the neighbors of which TriEdges, or -1 if + * there is no such neighbor. + * correct_triangle_orientations: Whether or not should correct triangle + * orientations so that vertices are + * ordered anticlockwise. */ + Triangulation(const CoordinateArray& x, + const CoordinateArray& y, + const TriangleArray& triangles, + const MaskArray& mask, + const EdgeArray& edges, + const NeighborArray& neighbors, + bool correct_triangle_orientations); + + /* Calculate plane equation coefficients for all unmasked triangles from + * the point (x,y) coordinates and point z-array of shape (npoints) passed + * in via the args. Returned array has shape (npoints,3) and allows + * z-value at (x,y) coordinates in triangle tri to be calculated using + * z = array[tri,0]*x + array[tri,1]*y + array[tri,2]. */ + TwoCoordinateArray calculate_plane_coefficients(const CoordinateArray& z); + + // Return the boundaries collection, creating it if necessary. + const Boundaries& get_boundaries() const; + + // Return which boundary and boundary edge the specified TriEdge is. + void get_boundary_edge(const TriEdge& triEdge, + int& boundary, + int& edge) const; + + /* Return the edges array, creating it if necessary. */ + EdgeArray& get_edges(); + + /* Return the triangle index of the neighbor of the specified triangle + * edge. */ + int get_neighbor(int tri, int edge) const; + + /* Return the TriEdge that is the neighbor of the specified triangle edge, + * or TriEdge(-1,-1) if there is no such neighbor. */ + TriEdge get_neighbor_edge(int tri, int edge) const; + + /* Return the neighbors array, creating it if necessary. */ + NeighborArray& get_neighbors(); + + // Return the number of points in this triangulation. + int get_npoints() const; + + // Return the number of triangles in this triangulation. + int get_ntri() const; + + /* Return the index of the point that is at the start of the specified + * triangle edge. */ + int get_triangle_point(int tri, int edge) const; + int get_triangle_point(const TriEdge& tri_edge) const; + + // Return the coordinates of the specified point index. + XY get_point_coords(int point) const; + + // Indicates if the specified triangle is masked or not. + bool is_masked(int tri) const; + + /* Set or clear the mask array. Clears various derived fields so they are + * recalculated when next needed. + * mask: bool array of shape (ntri) indicating which triangles are + * masked, or an empty array to clear mask. */ + void set_mask(const MaskArray& mask); + + // Debug function to write boundaries. + void write_boundaries() const; + +private: + // An edge of a triangulation, composed of start and end point indices. + struct Edge + { + Edge() : start(-1), end(-1) {} + Edge(int start_, int end_) : start(start_), end(end_) {} + bool operator<(const Edge& other) const { + return start != other.start ? start < other.start : end < other.end; + } + int start, end; + }; + + /* An edge of a boundary of a triangulation, composed of a boundary index + * and an edge index within that boundary. Used to index into the + * boundaries collection to obtain the corresponding TriEdge. */ + struct BoundaryEdge + { + BoundaryEdge() : boundary(-1), edge(-1) {} + BoundaryEdge(int boundary_, int edge_) + : boundary(boundary_), edge(edge_) {} + int boundary, edge; + }; + + /* Calculate the boundaries collection. Should normally be accessed via + * get_boundaries(), which will call this function if necessary. */ + void calculate_boundaries(); + + /* Calculate the edges array. Should normally be accessed via + * get_edges(), which will call this function if necessary. */ + void calculate_edges(); + + /* Calculate the neighbors array. Should normally be accessed via + * get_neighbors(), which will call this function if necessary. */ + void calculate_neighbors(); + + /* Correct each triangle so that the vertices are ordered in an + * anticlockwise manner. */ + void correct_triangles(); + + /* Determine which edge index (0,1 or 2) the specified point index is in + * the specified triangle, or -1 if the point is not in the triangle. */ + int get_edge_in_triangle(int tri, int point) const; + + bool has_edges() const; + + bool has_mask() const; + + bool has_neighbors() const; + + + // Variables shared with python, always set. + CoordinateArray _x, _y; // double array (npoints). + TriangleArray _triangles; // int array (ntri,3) of triangle point indices, + // ordered anticlockwise. + + // Variables shared with python, may be unset (size == 0). + MaskArray _mask; // bool array (ntri). + + // Derived variables shared with python, may be unset (size == 0). + // If unset, are recalculated when needed. + EdgeArray _edges; // int array (?,2) of start & end point indices. + NeighborArray _neighbors; // int array (ntri,3), neighbor triangle indices + // or -1 if no neighbor. + + // Variables internal to C++ only. + Boundaries _boundaries; + + // Map used to look up BoundaryEdges from TriEdges. Normally accessed via + // get_boundary_edge(). + typedef std::map<TriEdge, BoundaryEdge> TriEdgeToBoundaryMap; + TriEdgeToBoundaryMap _tri_edge_to_boundary_map; +}; + + + +// Contour generator for a triangulation. +class TriContourGenerator +{ +public: + typedef Triangulation::CoordinateArray CoordinateArray; + typedef Triangulation::TwoCoordinateArray TwoCoordinateArray; + typedef py::array_t<unsigned char> CodeArray; + + /* Constructor. + * triangulation: Triangulation to generate contours for. + * z: Double array of shape (npoints) of z-values at triangulation + * points. */ + TriContourGenerator(Triangulation& triangulation, + const CoordinateArray& z); + + /* Create and return a non-filled contour. + * level: Contour level. + * Returns new python list [segs0, segs1, ...] where + * segs0: double array of shape (?,2) of point coordinates of first + * contour line, etc. */ + py::tuple create_contour(const double& level); + + /* Create and return a filled contour. + * lower_level: Lower contour level. + * upper_level: Upper contour level. + * Returns new python tuple (segs, kinds) where + * segs: double array of shape (n_points,2) of all point coordinates, + * kinds: ubyte array of shape (n_points) of all point code types. */ + py::tuple create_filled_contour(const double& lower_level, + const double& upper_level); + +private: + typedef Triangulation::Boundary Boundary; + typedef Triangulation::Boundaries Boundaries; + + /* Clear visited flags. + * include_boundaries: Whether to clear boundary flags or not, which are + * only used for filled contours. */ + void clear_visited_flags(bool include_boundaries); + + /* Convert a non-filled Contour from C++ to Python. + * Returns new python tuple ([segs0, segs1, ...], [kinds0, kinds1...]) + * where + * segs0: double array of shape (n_points,2) of point coordinates of first + * contour line, etc. + * kinds0: ubyte array of shape (n_points) of kinds codes of first contour + * line, etc. */ + py::tuple contour_line_to_segs_and_kinds(const Contour& contour); + + /* Convert a filled Contour from C++ to Python. + * Returns new python tuple ([segs], [kinds]) where + * segs: double array of shape (n_points,2) of all point coordinates, + * kinds: ubyte array of shape (n_points) of all point code types. */ + py::tuple contour_to_segs_and_kinds(const Contour& contour); + + /* Return the point on the specified TriEdge that intersects the specified + * level. */ + XY edge_interp(int tri, int edge, const double& level); + + /* Find and follow non-filled contour lines that start and end on a + * boundary of the Triangulation. + * contour: Contour to add new lines to. + * level: Contour level. */ + void find_boundary_lines(Contour& contour, + const double& level); + + /* Find and follow filled contour lines at either of the specified contour + * levels that start and end of a boundary of the Triangulation. + * contour: Contour to add new lines to. + * lower_level: Lower contour level. + * upper_level: Upper contour level. */ + void find_boundary_lines_filled(Contour& contour, + const double& lower_level, + const double& upper_level); + + /* Find and follow lines at the specified contour level that are + * completely in the interior of the Triangulation and hence do not + * intersect any boundary. + * contour: Contour to add new lines to. + * level: Contour level. + * on_upper: Whether on upper or lower contour level. + * filled: Whether contours are filled or not. */ + void find_interior_lines(Contour& contour, + const double& level, + bool on_upper, + bool filled); + + /* Follow contour line around boundary of the Triangulation from the + * specified TriEdge to its end which can be on either the lower or upper + * levels. Only used for filled contours. + * contour_line: Contour line to append new points to. + * tri_edge: On entry, TriEdge to start from. On exit, TriEdge that is + * finished on. + * lower_level: Lower contour level. + * upper_level: Upper contour level. + * on_upper: Whether starts on upper level or not. + * Return true if finishes on upper level, false if lower. */ + bool follow_boundary(ContourLine& contour_line, + TriEdge& tri_edge, + const double& lower_level, + const double& upper_level, + bool on_upper); + + /* Follow contour line across interior of Triangulation. + * contour_line: Contour line to append new points to. + * tri_edge: On entry, TriEdge to start from. On exit, TriEdge that is + * finished on. + * end_on_boundary: Whether this line ends on a boundary, or loops back + * upon itself. + * level: Contour level to follow. + * on_upper: Whether following upper or lower contour level. */ + void follow_interior(ContourLine& contour_line, + TriEdge& tri_edge, + bool end_on_boundary, + const double& level, + bool on_upper); + + // Return the Triangulation boundaries. + const Boundaries& get_boundaries() const; + + /* Return the edge by which the a level leaves a particular triangle, + * which is 0, 1 or 2 if the contour passes through the triangle or -1 + * otherwise. + * tri: Triangle index. + * level: Contour level to follow. + * on_upper: Whether following upper or lower contour level. */ + int get_exit_edge(int tri, const double& level, bool on_upper) const; + + // Return the z-value at the specified point index. + const double& get_z(int point) const; + + /* Return the point at which the a level intersects the line connecting the + * two specified point indices. */ + XY interp(int point1, int point2, const double& level) const; + + + + // Variables shared with python, always set. + Triangulation _triangulation; + CoordinateArray _z; // double array (npoints). + + // Variables internal to C++ only. + typedef std::vector<bool> InteriorVisited; // Size 2*ntri + typedef std::vector<bool> BoundaryVisited; + typedef std::vector<BoundaryVisited> BoundariesVisited; + typedef std::vector<bool> BoundariesUsed; + + InteriorVisited _interior_visited; + BoundariesVisited _boundaries_visited; // Only used for filled contours. + BoundariesUsed _boundaries_used; // Only used for filled contours. +}; + + + +/* TriFinder class implemented using the trapezoid map algorithm from the book + * "Computational Geometry, Algorithms and Applications", second edition, by + * M. de Berg, M. van Kreveld, M. Overmars and O. Schwarzkopf. + * + * The domain of interest is composed of vertical-sided trapezoids that are + * bounded to the left and right by points of the triangulation, and below and + * above by edges of the triangulation. Each triangle is represented by 1 or + * more of these trapezoids. Edges are inserted one a time in a random order. + * + * As the trapezoid map is created, a search tree is also created which allows + * fast lookup O(log N) of the trapezoid containing the point of interest. + * There are 3 types of node in the search tree: all leaf nodes represent + * trapezoids and all branch nodes have 2 child nodes and are either x-nodes or + * y-nodes. X-nodes represent points in the triangulation, and their 2 children + * refer to those parts of the search tree to the left and right of the point. + * Y-nodes represent edges in the triangulation, and their 2 children refer to + * those parts of the search tree below and above the edge. + * + * Nodes can be repeated throughout the search tree, and each is reference + * counted through the multiple parent nodes it is a child of. + * + * The algorithm is only intended to work with valid triangulations, i.e. it + * must not contain duplicate points, triangles formed from colinear points, or + * overlapping triangles. It does have some tolerance to triangles formed from + * colinear points but only in the simplest of cases. No explicit testing of + * the validity of the triangulation is performed as this is a computationally + * more complex task than the trifinding itself. */ +class TrapezoidMapTriFinder +{ +public: + typedef Triangulation::CoordinateArray CoordinateArray; + typedef py::array_t<int, py::array::c_style | py::array::forcecast> TriIndexArray; + + /* Constructor. A separate call to initialize() is required to initialize + * the object before use. + * triangulation: Triangulation to find triangles in. */ + TrapezoidMapTriFinder(Triangulation& triangulation); + + ~TrapezoidMapTriFinder(); + + /* Return an array of triangle indices. Takes 1D arrays x and y of + * point coordinates, and returns an array of the same size containing the + * indices of the triangles at those points. */ + TriIndexArray find_many(const CoordinateArray& x, const CoordinateArray& y); + + /* Return a reference to a new python list containing the following + * statistics about the tree: + * 0: number of nodes (tree size) + * 1: number of unique nodes (number of unique Node objects in tree) + * 2: number of trapezoids (tree leaf nodes) + * 3: number of unique trapezoids + * 4: maximum parent count (max number of times a node is repeated in + * tree) + * 5: maximum depth of tree (one more than the maximum number of + * comparisons needed to search through the tree) + * 6: mean of all trapezoid depths (one more than the average number of + * comparisons needed to search through the tree) */ + py::list get_tree_stats(); + + /* Initialize this object before use. May be called multiple times, if, + * for example, the triangulation is changed by setting the mask. */ + void initialize(); + + // Print the search tree as text to stdout; useful for debug purposes. + void print_tree(); + +private: + /* A Point consists of x,y coordinates as well as the index of a triangle + * associated with the point, so that a search at this point's coordinates + * can return a valid triangle index. */ + struct Point : XY + { + Point() : XY(), tri(-1) {} + Point(const double& x, const double& y) : XY(x,y), tri(-1) {} + explicit Point(const XY& xy) : XY(xy), tri(-1) {} + + int tri; + }; + + /* An Edge connects two Points, left and right. It is always true that + * right->is_right_of(*left). Stores indices of triangles below and above + * the Edge which are used to map from trapezoid to triangle index. Also + * stores pointers to the 3rd points of the below and above triangles, + * which are only used to disambiguate triangles with colinear points. */ + struct Edge + { + Edge(const Point* left_, + const Point* right_, + int triangle_below_, + int triangle_above_, + const Point* point_below_, + const Point* point_above_); + + // Return -1 if point to left of edge, 0 if on edge, +1 if to right. + int get_point_orientation(const XY& xy) const; + + // Return slope of edge, even if vertical (divide by zero is OK here). + double get_slope() const; + + /* Return y-coordinate of point on edge with specified x-coordinate. + * x must be within the x-limits of this edge. */ + double get_y_at_x(const double& x) const; + + // Return true if the specified point is either of the edge end points. + bool has_point(const Point* point) const; + + bool operator==(const Edge& other) const; + + friend std::ostream& operator<<(std::ostream& os, const Edge& edge) + { + return os << *edge.left << "->" << *edge.right; + } + + void print_debug() const; + + + const Point* left; // Not owned. + const Point* right; // Not owned. + int triangle_below; // Index of triangle below (to right of) Edge. + int triangle_above; // Index of triangle above (to left of) Edge. + const Point* point_below; // Used only for resolving ambiguous cases; + const Point* point_above; // is 0 if corresponding triangle is -1 + }; + + class Node; // Forward declaration. + + // Helper structure used by TrapezoidMapTriFinder::get_tree_stats. + struct NodeStats + { + NodeStats() + : node_count(0), trapezoid_count(0), max_parent_count(0), + max_depth(0), sum_trapezoid_depth(0.0) + {} + + long node_count, trapezoid_count, max_parent_count, max_depth; + double sum_trapezoid_depth; + std::set<const Node*> unique_nodes, unique_trapezoid_nodes; + }; + + struct Trapezoid; // Forward declaration. + + /* Node of the trapezoid map search tree. There are 3 possible types: + * Type_XNode, Type_YNode and Type_TrapezoidNode. Data members are + * represented using a union: an XNode has a Point and 2 child nodes + * (left and right of the point), a YNode has an Edge and 2 child nodes + * (below and above the edge), and a TrapezoidNode has a Trapezoid. + * Each Node has multiple parents so it can appear in the search tree + * multiple times without having to create duplicate identical Nodes. + * The parent collection acts as a reference count to the number of times + * a Node occurs in the search tree. When the parent count is reduced to + * zero a Node can be safely deleted. */ + class Node + { + public: + Node(const Point* point, Node* left, Node* right);// Type_XNode. + Node(const Edge* edge, Node* below, Node* above); // Type_YNode. + Node(Trapezoid* trapezoid); // Type_TrapezoidNode. + + ~Node(); + + void add_parent(Node* parent); + + /* Recurse through the search tree and assert that everything is valid. + * Reduces to a no-op if NDEBUG is defined. */ + void assert_valid(bool tree_complete) const; + + // Recurse through the tree to return statistics about it. + void get_stats(int depth, NodeStats& stats) const; + + // Return the index of the triangle corresponding to this node. + int get_tri() const; + + bool has_child(const Node* child) const; + bool has_no_parents() const; + bool has_parent(const Node* parent) const; + + /* Recurse through the tree and print a textual representation to + * stdout. Argument depth used to indent for readability. */ + void print(int depth = 0) const; + + /* Remove a parent from this Node. Return true if no parents remain + * so that this Node can be deleted. */ + bool remove_parent(Node* parent); + + void replace_child(Node* old_child, Node* new_child); + + // Replace this node with the specified new_node in all parents. + void replace_with(Node* new_node); + + /* Recursive search through the tree to find the Node containing the + * specified XY point. */ + const Node* search(const XY& xy); + + /* Recursive search through the tree to find the Trapezoid containing + * the left endpoint of the specified Edge. Return 0 if fails, which + * can only happen if the triangulation is invalid. */ + Trapezoid* search(const Edge& edge); + + /* Copy constructor and assignment operator defined but not implemented + * to prevent objects being copied. */ + Node(const Node& other); + Node& operator=(const Node& other); + + private: + typedef enum { + Type_XNode, + Type_YNode, + Type_TrapezoidNode + } Type; + Type _type; + + union { + struct { + const Point* point; // Not owned. + Node* left; // Owned. + Node* right; // Owned. + } xnode; + struct { + const Edge* edge; // Not owned. + Node* below; // Owned. + Node* above; // Owned. + } ynode; + Trapezoid* trapezoid; // Owned. + } _union; + + typedef std::list<Node*> Parents; + Parents _parents; // Not owned. + }; + + /* A Trapezoid is bounded by Points to left and right, and Edges below and + * above. Has up to 4 neighboring Trapezoids to lower/upper left/right. + * Lower left neighbor is Trapezoid to left that shares the below Edge, or + * is 0 if there is no such Trapezoid (and similar for other neighbors). + * To obtain the index of the triangle corresponding to a particular + * Trapezoid, use the Edge member variables below.triangle_above or + * above.triangle_below. */ + struct Trapezoid + { + Trapezoid(const Point* left_, + const Point* right_, + const Edge& below_, + const Edge& above_); + + /* Assert that this Trapezoid is valid. Reduces to a no-op if NDEBUG + * is defined. */ + void assert_valid(bool tree_complete) const; + + /* Return one of the 4 corner points of this Trapezoid. Only used for + * debugging purposes. */ + XY get_lower_left_point() const; + XY get_lower_right_point() const; + XY get_upper_left_point() const; + XY get_upper_right_point() const; + + void print_debug() const; + + /* Set one of the 4 neighbor trapezoids and the corresponding reverse + * Trapezoid of the new neighbor (if it is not 0), so that they are + * consistent. */ + void set_lower_left(Trapezoid* lower_left_); + void set_lower_right(Trapezoid* lower_right_); + void set_upper_left(Trapezoid* upper_left_); + void set_upper_right(Trapezoid* upper_right_); + + /* Copy constructor and assignment operator defined but not implemented + * to prevent objects being copied. */ + Trapezoid(const Trapezoid& other); + Trapezoid& operator=(const Trapezoid& other); + + + const Point* left; // Not owned. + const Point* right; // Not owned. + const Edge& below; + const Edge& above; + + // 4 neighboring trapezoids, can be 0, not owned. + Trapezoid* lower_left; // Trapezoid to left that shares below + Trapezoid* lower_right; // Trapezoid to right that shares below + Trapezoid* upper_left; // Trapezoid to left that shares above + Trapezoid* upper_right; // Trapezoid to right that shares above + + Node* trapezoid_node; // Node that owns this Trapezoid. + }; + + + // Add the specified Edge to the search tree, returning true if successful. + bool add_edge_to_tree(const Edge& edge); + + // Clear all memory allocated by this object. + void clear(); + + // Return the triangle index at the specified point, or -1 if no triangle. + int find_one(const XY& xy); + + /* Determine the trapezoids that the specified Edge intersects, returning + * true if successful. */ + bool find_trapezoids_intersecting_edge(const Edge& edge, + std::vector<Trapezoid*>& trapezoids); + + + + // Variables shared with python, always set. + Triangulation& _triangulation; + + // Variables internal to C++ only. + Point* _points; // Array of all points in triangulation plus corners of + // enclosing rectangle. Owned. + + typedef std::vector<Edge> Edges; + Edges _edges; // All Edges in triangulation plus bottom and top Edges of + // enclosing rectangle. + + Node* _tree; // Root node of the trapezoid map search tree. Owned. +}; + +#endif |