aboutsummaryrefslogtreecommitdiffstats
path: root/contrib/python/matplotlib/py3/src/tri
diff options
context:
space:
mode:
authormaxim-yurchuk <maxim-yurchuk@yandex-team.com>2025-02-11 13:26:52 +0300
committermaxim-yurchuk <maxim-yurchuk@yandex-team.com>2025-02-11 13:57:59 +0300
commitf895bba65827952ed934b2b46f9a45e30a191fd2 (patch)
tree03260c906d9ec41cdc03e2a496b15d407459cec0 /contrib/python/matplotlib/py3/src/tri
parent5f7060466f7b9707818c2091e1a25c14f33c3474 (diff)
downloadydb-f895bba65827952ed934b2b46f9a45e30a191fd2.tar.gz
Remove deps on pandas
<https://github.com/ydb-platform/ydb/pull/14418> <https://github.com/ydb-platform/ydb/pull/14419> \-- аналогичные правки в gh Хочу залить в обход синка, чтобы посмотреть удалится ли pandas в нашей gh репе через piglet commit_hash:abca127aa37d4dbb94b07e1e18cdb8eb5b711860
Diffstat (limited to 'contrib/python/matplotlib/py3/src/tri')
-rw-r--r--contrib/python/matplotlib/py3/src/tri/_tri.cpp2074
-rw-r--r--contrib/python/matplotlib/py3/src/tri/_tri.h799
-rw-r--r--contrib/python/matplotlib/py3/src/tri/_tri_wrapper.cpp58
3 files changed, 0 insertions, 2931 deletions
diff --git a/contrib/python/matplotlib/py3/src/tri/_tri.cpp b/contrib/python/matplotlib/py3/src/tri/_tri.cpp
deleted file mode 100644
index 2674a3140b..0000000000
--- a/contrib/python/matplotlib/py3/src/tri/_tri.cpp
+++ /dev/null
@@ -1,2074 +0,0 @@
-/* This file contains liberal use of asserts to assist code development and
- * debugging. Standard matplotlib builds disable asserts so they cause no
- * performance reduction. To enable the asserts, you need to undefine the
- * NDEBUG macro, which is achieved by adding the following
- * undef_macros=['NDEBUG']
- * to the appropriate make_extension call in setupext.py, and then rebuilding.
- */
-#include "../mplutils.h"
-#include "_tri.h"
-
-#include <algorithm>
-#include <random>
-#include <set>
-
-
-TriEdge::TriEdge()
- : tri(-1), edge(-1)
-{}
-
-TriEdge::TriEdge(int tri_, int edge_)
- : tri(tri_), edge(edge_)
-{}
-
-bool TriEdge::operator<(const TriEdge& other) const
-{
- if (tri != other.tri)
- return tri < other.tri;
- else
- return edge < other.edge;
-}
-
-bool TriEdge::operator==(const TriEdge& other) const
-{
- return tri == other.tri && edge == other.edge;
-}
-
-bool TriEdge::operator!=(const TriEdge& other) const
-{
- return !operator==(other);
-}
-
-std::ostream& operator<<(std::ostream& os, const TriEdge& tri_edge)
-{
- return os << tri_edge.tri << ' ' << tri_edge.edge;
-}
-
-
-
-XY::XY()
-{}
-
-XY::XY(const double& x_, const double& y_)
- : x(x_), y(y_)
-{}
-
-double XY::angle() const
-{
- return atan2(y, x);
-}
-
-double XY::cross_z(const XY& other) const
-{
- return x*other.y - y*other.x;
-}
-
-bool XY::is_right_of(const XY& other) const
-{
- if (x == other.x)
- return y > other.y;
- else
- return x > other.x;
-}
-
-bool XY::operator==(const XY& other) const
-{
- return x == other.x && y == other.y;
-}
-
-bool XY::operator!=(const XY& other) const
-{
- return x != other.x || y != other.y;
-}
-
-XY XY::operator*(const double& multiplier) const
-{
- return XY(x*multiplier, y*multiplier);
-}
-
-const XY& XY::operator+=(const XY& other)
-{
- x += other.x;
- y += other.y;
- return *this;
-}
-
-const XY& XY::operator-=(const XY& other)
-{
- x -= other.x;
- y -= other.y;
- return *this;
-}
-
-XY XY::operator+(const XY& other) const
-{
- return XY(x + other.x, y + other.y);
-}
-
-XY XY::operator-(const XY& other) const
-{
- return XY(x - other.x, y - other.y);
-}
-
-std::ostream& operator<<(std::ostream& os, const XY& xy)
-{
- return os << '(' << xy.x << ' ' << xy.y << ')';
-}
-
-
-
-XYZ::XYZ(const double& x_, const double& y_, const double& z_)
- : x(x_), y(y_), z(z_)
-{}
-
-XYZ XYZ::cross(const XYZ& other) const
-{
- return XYZ(y*other.z - z*other.y,
- z*other.x - x*other.z,
- x*other.y - y*other.x);
-}
-
-double XYZ::dot(const XYZ& other) const
-{
- return x*other.x + y*other.y + z*other.z;
-}
-
-XYZ XYZ::operator-(const XYZ& other) const
-{
- return XYZ(x - other.x, y - other.y, z - other.z);
-}
-
-std::ostream& operator<<(std::ostream& os, const XYZ& xyz)
-{
- return os << '(' << xyz.x << ' ' << xyz.y << ' ' << xyz.z << ')';
-}
-
-
-
-BoundingBox::BoundingBox()
- : empty(true), lower(0.0, 0.0), upper(0.0, 0.0)
-{}
-
-void BoundingBox::add(const XY& point)
-{
- if (empty) {
- empty = false;
- lower = upper = point;
- } else {
- if (point.x < lower.x) lower.x = point.x;
- else if (point.x > upper.x) upper.x = point.x;
-
- if (point.y < lower.y) lower.y = point.y;
- else if (point.y > upper.y) upper.y = point.y;
- }
-}
-
-void BoundingBox::expand(const XY& delta)
-{
- if (!empty) {
- lower -= delta;
- upper += delta;
- }
-}
-
-
-
-ContourLine::ContourLine()
- : std::vector<XY>()
-{}
-
-void ContourLine::push_back(const XY& point)
-{
- if (empty() || point != back())
- std::vector<XY>::push_back(point);
-}
-
-void ContourLine::write() const
-{
- std::cout << "ContourLine of " << size() << " points:";
- for (const_iterator it = begin(); it != end(); ++it)
- std::cout << ' ' << *it;
- std::cout << std::endl;
-}
-
-
-
-void write_contour(const Contour& contour)
-{
- std::cout << "Contour of " << contour.size() << " lines." << std::endl;
- for (Contour::const_iterator it = contour.begin(); it != contour.end(); ++it)
- it->write();
-}
-
-
-
-Triangulation::Triangulation(const CoordinateArray& x,
- const CoordinateArray& y,
- const TriangleArray& triangles,
- const MaskArray& mask,
- const EdgeArray& edges,
- const NeighborArray& neighbors,
- bool correct_triangle_orientations)
- : _x(x),
- _y(y),
- _triangles(triangles),
- _mask(mask),
- _edges(edges),
- _neighbors(neighbors)
-{
- if (_x.ndim() != 1 || _y.ndim() != 1 || _x.shape(0) != _y.shape(0))
- throw std::invalid_argument("x and y must be 1D arrays of the same length");
-
- if (_triangles.ndim() != 2 || _triangles.shape(1) != 3)
- throw std::invalid_argument("triangles must be a 2D array of shape (?,3)");
-
- // Optional mask.
- if (_mask.size() > 0 &&
- (_mask.ndim() != 1 || _mask.shape(0) != _triangles.shape(0)))
- throw std::invalid_argument(
- "mask must be a 1D array with the same length as the triangles array");
-
- // Optional edges.
- if (_edges.size() > 0 &&
- (_edges.ndim() != 2 || _edges.shape(1) != 2))
- throw std::invalid_argument("edges must be a 2D array with shape (?,2)");
-
- // Optional neighbors.
- if (_neighbors.size() > 0 &&
- (_neighbors.ndim() != 2 || _neighbors.shape() != _triangles.shape()))
- throw std::invalid_argument(
- "neighbors must be a 2D array with the same shape as the triangles array");
-
- if (correct_triangle_orientations)
- correct_triangles();
-}
-
-void Triangulation::calculate_boundaries()
-{
- get_neighbors(); // Ensure _neighbors has been created.
-
- // Create set of all boundary TriEdges, which are those which do not
- // have a neighbor triangle.
- typedef std::set<TriEdge> BoundaryEdges;
- BoundaryEdges boundary_edges;
- for (int tri = 0; tri < get_ntri(); ++tri) {
- if (!is_masked(tri)) {
- for (int edge = 0; edge < 3; ++edge) {
- if (get_neighbor(tri, edge) == -1) {
- boundary_edges.insert(TriEdge(tri, edge));
- }
- }
- }
- }
-
- // Take any boundary edge and follow the boundary until return to start
- // point, removing edges from boundary_edges as they are used. At the same
- // time, initialise the _tri_edge_to_boundary_map.
- while (!boundary_edges.empty()) {
- // Start of new boundary.
- BoundaryEdges::iterator it = boundary_edges.begin();
- int tri = it->tri;
- int edge = it->edge;
- _boundaries.push_back(Boundary());
- Boundary& boundary = _boundaries.back();
-
- while (true) {
- boundary.push_back(TriEdge(tri, edge));
- boundary_edges.erase(it);
- _tri_edge_to_boundary_map[TriEdge(tri, edge)] =
- BoundaryEdge(_boundaries.size()-1, boundary.size()-1);
-
- // Move to next edge of current triangle.
- edge = (edge+1) % 3;
-
- // Find start point index of boundary edge.
- int point = get_triangle_point(tri, edge);
-
- // Find next TriEdge by traversing neighbors until find one
- // without a neighbor.
- while (get_neighbor(tri, edge) != -1) {
- tri = get_neighbor(tri, edge);
- edge = get_edge_in_triangle(tri, point);
- }
-
- if (TriEdge(tri,edge) == boundary.front())
- break; // Reached beginning of this boundary, so finished it.
- else
- it = boundary_edges.find(TriEdge(tri, edge));
- }
- }
-}
-
-void Triangulation::calculate_edges()
-{
- assert(!has_edges() && "Expected empty edges array");
-
- // Create set of all edges, storing them with start point index less than
- // end point index.
- typedef std::set<Edge> EdgeSet;
- EdgeSet edge_set;
- for (int tri = 0; tri < get_ntri(); ++tri) {
- if (!is_masked(tri)) {
- for (int edge = 0; edge < 3; edge++) {
- int start = get_triangle_point(tri, edge);
- int end = get_triangle_point(tri, (edge+1)%3);
- edge_set.insert(start > end ? Edge(start,end) : Edge(end,start));
- }
- }
- }
-
- // Convert to python _edges array.
- py::ssize_t dims[2] = {static_cast<py::ssize_t>(edge_set.size()), 2};
- _edges = EdgeArray(dims);
- auto edges = _edges.mutable_data();
-
- int i = 0;
- for (EdgeSet::const_iterator it = edge_set.begin(); it != edge_set.end(); ++it) {
- edges[i++] = it->start;
- edges[i++] = it->end;
- }
-}
-
-void Triangulation::calculate_neighbors()
-{
- assert(!has_neighbors() && "Expected empty neighbors array");
-
- // Create _neighbors array with shape (ntri,3) and initialise all to -1.
- py::ssize_t dims[2] = {get_ntri(), 3};
- _neighbors = NeighborArray(dims);
- auto* neighbors = _neighbors.mutable_data();
-
- int tri, edge;
- std::fill(neighbors, neighbors+3*get_ntri(), -1);
-
- // For each triangle edge (start to end point), find corresponding neighbor
- // edge from end to start point. Do this by traversing all edges and
- // storing them in a map from edge to TriEdge. If corresponding neighbor
- // edge is already in the map, don't need to store new edge as neighbor
- // already found.
- typedef std::map<Edge, TriEdge> EdgeToTriEdgeMap;
- EdgeToTriEdgeMap edge_to_tri_edge_map;
- for (tri = 0; tri < get_ntri(); ++tri) {
- if (!is_masked(tri)) {
- for (edge = 0; edge < 3; ++edge) {
- int start = get_triangle_point(tri, edge);
- int end = get_triangle_point(tri, (edge+1)%3);
- EdgeToTriEdgeMap::iterator it =
- edge_to_tri_edge_map.find(Edge(end,start));
- if (it == edge_to_tri_edge_map.end()) {
- // No neighbor edge exists in the edge_to_tri_edge_map, so
- // add this edge to it.
- edge_to_tri_edge_map[Edge(start,end)] = TriEdge(tri,edge);
- } else {
- // Neighbor edge found, set the two elements of _neighbors
- // and remove edge from edge_to_tri_edge_map.
- neighbors[3*tri + edge] = it->second.tri;
- neighbors[3*it->second.tri + it->second.edge] = tri;
- edge_to_tri_edge_map.erase(it);
- }
- }
- }
- }
-
- // Note that remaining edges in the edge_to_tri_edge_map correspond to
- // boundary edges, but the boundaries are calculated separately elsewhere.
-}
-
-Triangulation::TwoCoordinateArray Triangulation::calculate_plane_coefficients(
- const CoordinateArray& z)
-{
- if (z.ndim() != 1 || z.shape(0) != _x.shape(0))
- throw std::invalid_argument(
- "z must be a 1D array with the same length as the triangulation x and y arrays");
-
- int dims[2] = {get_ntri(), 3};
- Triangulation::TwoCoordinateArray planes_array(dims);
- auto planes = planes_array.mutable_unchecked<2>();
- auto triangles = _triangles.unchecked<2>();
- auto x = _x.unchecked<1>();
- auto y = _y.unchecked<1>();
- auto z_ptr = z.unchecked<1>();
-
- int point;
- for (int tri = 0; tri < get_ntri(); ++tri) {
- if (is_masked(tri)) {
- planes(tri, 0) = 0.0;
- planes(tri, 1) = 0.0;
- planes(tri, 2) = 0.0;
- }
- else {
- // Equation of plane for all points r on plane is r.normal = p
- // where normal is vector normal to the plane, and p is a
- // constant. Rewrite as
- // r_x*normal_x + r_y*normal_y + r_z*normal_z = p
- // and rearrange to give
- // r_z = (-normal_x/normal_z)*r_x + (-normal_y/normal_z)*r_y +
- // p/normal_z
- point = triangles(tri, 0);
- XYZ point0(x(point), y(point), z_ptr(point));
- point = triangles(tri, 1);
- XYZ side01 = XYZ(x(point), y(point), z_ptr(point)) - point0;
- point = triangles(tri, 2);
- XYZ side02 = XYZ(x(point), y(point), z_ptr(point)) - point0;
-
- XYZ normal = side01.cross(side02);
-
- if (normal.z == 0.0) {
- // Normal is in x-y plane which means triangle consists of
- // colinear points. To avoid dividing by zero, we use the
- // Moore-Penrose pseudo-inverse.
- double sum2 = (side01.x*side01.x + side01.y*side01.y +
- side02.x*side02.x + side02.y*side02.y);
- double a = (side01.x*side01.z + side02.x*side02.z) / sum2;
- double b = (side01.y*side01.z + side02.y*side02.z) / sum2;
- planes(tri, 0) = a;
- planes(tri, 1) = b;
- planes(tri, 2) = point0.z - a*point0.x - b*point0.y;
- }
- else {
- planes(tri, 0) = -normal.x / normal.z; // x
- planes(tri, 1) = -normal.y / normal.z; // y
- planes(tri, 2) = normal.dot(point0) / normal.z; // constant
- }
- }
- }
-
- return planes_array;
-}
-
-void Triangulation::correct_triangles()
-{
- auto triangles = _triangles.mutable_data();
- auto neighbors = _neighbors.mutable_data();
-
- for (int tri = 0; tri < get_ntri(); ++tri) {
- XY point0 = get_point_coords(triangles[3*tri]);
- XY point1 = get_point_coords(triangles[3*tri+1]);
- XY point2 = get_point_coords(triangles[3*tri+2]);
- if ( (point1 - point0).cross_z(point2 - point0) < 0.0) {
- // Triangle points are clockwise, so change them to anticlockwise.
- std::swap(triangles[3*tri+1], triangles[3*tri+2]);
- if (has_neighbors())
- std::swap(neighbors[3*tri+1], neighbors[3*tri+2]);
- }
- }
-}
-
-const Triangulation::Boundaries& Triangulation::get_boundaries() const
-{
- if (_boundaries.empty())
- const_cast<Triangulation*>(this)->calculate_boundaries();
- return _boundaries;
-}
-
-void Triangulation::get_boundary_edge(const TriEdge& triEdge,
- int& boundary,
- int& edge) const
-{
- get_boundaries(); // Ensure _tri_edge_to_boundary_map has been created.
- TriEdgeToBoundaryMap::const_iterator it =
- _tri_edge_to_boundary_map.find(triEdge);
- assert(it != _tri_edge_to_boundary_map.end() &&
- "TriEdge is not on a boundary");
- boundary = it->second.boundary;
- edge = it->second.edge;
-}
-
-int Triangulation::get_edge_in_triangle(int tri, int point) const
-{
- assert(tri >= 0 && tri < get_ntri() && "Triangle index out of bounds");
- assert(point >= 0 && point < get_npoints() && "Point index out of bounds.");
-
- auto triangles = _triangles.data();
-
- for (int edge = 0; edge < 3; ++edge) {
- if (triangles[3*tri + edge] == point)
- return edge;
- }
- return -1; // point is not in triangle.
-}
-
-Triangulation::EdgeArray& Triangulation::get_edges()
-{
- if (!has_edges())
- calculate_edges();
- return _edges;
-}
-
-int Triangulation::get_neighbor(int tri, int edge) const
-{
- assert(tri >= 0 && tri < get_ntri() && "Triangle index out of bounds");
- assert(edge >= 0 && edge < 3 && "Edge index out of bounds");
- if (!has_neighbors())
- const_cast<Triangulation&>(*this).calculate_neighbors();
- return _neighbors.data()[3*tri + edge];
-}
-
-TriEdge Triangulation::get_neighbor_edge(int tri, int edge) const
-{
- int neighbor_tri = get_neighbor(tri, edge);
- if (neighbor_tri == -1)
- return TriEdge(-1,-1);
- else
- return TriEdge(neighbor_tri,
- get_edge_in_triangle(neighbor_tri,
- get_triangle_point(tri,
- (edge+1)%3)));
-}
-
-Triangulation::NeighborArray& Triangulation::get_neighbors()
-{
- if (!has_neighbors())
- calculate_neighbors();
- return _neighbors;
-}
-
-int Triangulation::get_npoints() const
-{
- return _x.shape(0);
-}
-
-int Triangulation::get_ntri() const
-{
- return _triangles.shape(0);
-}
-
-XY Triangulation::get_point_coords(int point) const
-{
- assert(point >= 0 && point < get_npoints() && "Point index out of bounds.");
- return XY(_x.data()[point], _y.data()[point]);
-}
-
-int Triangulation::get_triangle_point(int tri, int edge) const
-{
- assert(tri >= 0 && tri < get_ntri() && "Triangle index out of bounds");
- assert(edge >= 0 && edge < 3 && "Edge index out of bounds");
- return _triangles.data()[3*tri + edge];
-}
-
-int Triangulation::get_triangle_point(const TriEdge& tri_edge) const
-{
- return get_triangle_point(tri_edge.tri, tri_edge.edge);
-}
-
-bool Triangulation::has_edges() const
-{
- return _edges.size() > 0;
-}
-
-bool Triangulation::has_mask() const
-{
- return _mask.size() > 0;
-}
-
-bool Triangulation::has_neighbors() const
-{
- return _neighbors.size() > 0;
-}
-
-bool Triangulation::is_masked(int tri) const
-{
- assert(tri >= 0 && tri < get_ntri() && "Triangle index out of bounds.");
- return has_mask() && _mask.data()[tri];
-}
-
-void Triangulation::set_mask(const MaskArray& mask)
-{
- if (mask.size() > 0 &&
- (mask.ndim() != 1 || mask.shape(0) != _triangles.shape(0)))
- throw std::invalid_argument(
- "mask must be a 1D array with the same length as the triangles array");
-
- _mask = mask;
-
- // Clear derived fields so they are recalculated when needed.
- _edges = EdgeArray();
- _neighbors = NeighborArray();
- _boundaries.clear();
-}
-
-void Triangulation::write_boundaries() const
-{
- const Boundaries& bs = get_boundaries();
- std::cout << "Number of boundaries: " << bs.size() << std::endl;
- for (Boundaries::const_iterator it = bs.begin(); it != bs.end(); ++it) {
- const Boundary& b = *it;
- std::cout << " Boundary of " << b.size() << " points: ";
- for (Boundary::const_iterator itb = b.begin(); itb != b.end(); ++itb) {
- std::cout << *itb << ", ";
- }
- std::cout << std::endl;
- }
-}
-
-
-
-TriContourGenerator::TriContourGenerator(Triangulation& triangulation,
- const CoordinateArray& z)
- : _triangulation(triangulation),
- _z(z),
- _interior_visited(2*_triangulation.get_ntri()),
- _boundaries_visited(0),
- _boundaries_used(0)
-{
- if (_z.ndim() != 1 || _z.shape(0) != _triangulation.get_npoints())
- throw std::invalid_argument(
- "z must be a 1D array with the same length as the x and y arrays");
-}
-
-void TriContourGenerator::clear_visited_flags(bool include_boundaries)
-{
- // Clear _interiorVisited.
- std::fill(_interior_visited.begin(), _interior_visited.end(), false);
-
- if (include_boundaries) {
- if (_boundaries_visited.empty()) {
- const Boundaries& boundaries = get_boundaries();
-
- // Initialise _boundaries_visited.
- _boundaries_visited.reserve(boundaries.size());
- for (Boundaries::const_iterator it = boundaries.begin();
- it != boundaries.end(); ++it)
- _boundaries_visited.push_back(BoundaryVisited(it->size()));
-
- // Initialise _boundaries_used.
- _boundaries_used = BoundariesUsed(boundaries.size());
- }
-
- // Clear _boundaries_visited.
- for (BoundariesVisited::iterator it = _boundaries_visited.begin();
- it != _boundaries_visited.end(); ++it)
- std::fill(it->begin(), it->end(), false);
-
- // Clear _boundaries_used.
- std::fill(_boundaries_used.begin(), _boundaries_used.end(), false);
- }
-}
-
-py::tuple TriContourGenerator::contour_line_to_segs_and_kinds(const Contour& contour)
-{
- // Convert all of the lines generated by a call to create_contour() into
- // their Python equivalents for return to the calling function.
- // A line is either a closed line loop (in which case the last point is
- // identical to the first) or an open line strip. Two NumPy arrays are
- // created for each line:
- // vertices is a double array of shape (npoints, 2) containing the (x, y)
- // coordinates of the points in the line
- // codes is a uint8 array of shape (npoints,) containing the 'kind codes'
- // which are defined in the Path class
- // and they are appended to the Python lists vertices_list and codes_list
- // respectively for return to the Python calling function.
-
- py::list vertices_list(contour.size());
- py::list codes_list(contour.size());
-
- for (Contour::size_type i = 0; i < contour.size(); ++i) {
- const ContourLine& contour_line = contour[i];
- py::ssize_t npoints = static_cast<py::ssize_t>(contour_line.size());
-
- py::ssize_t segs_dims[2] = {npoints, 2};
- CoordinateArray segs(segs_dims);
- double* segs_ptr = segs.mutable_data();
-
- py::ssize_t codes_dims[1] = {npoints};
- CodeArray codes(codes_dims);
- unsigned char* codes_ptr = codes.mutable_data();
-
- for (ContourLine::const_iterator it = contour_line.begin();
- it != contour_line.end(); ++it) {
- *segs_ptr++ = it->x;
- *segs_ptr++ = it->y;
- *codes_ptr++ = (it == contour_line.begin() ? MOVETO : LINETO);
- }
-
- // Closed line loop has identical first and last (x, y) points.
- if (contour_line.size() > 1 &&
- contour_line.front() == contour_line.back())
- *(codes_ptr-1) = CLOSEPOLY;
-
- vertices_list[i] = segs;
- codes_list[i] = codes;
- }
-
- return py::make_tuple(vertices_list, codes_list);
-}
-
-py::tuple TriContourGenerator::contour_to_segs_and_kinds(const Contour& contour)
-{
- // Convert all of the polygons generated by a call to
- // create_filled_contour() into their Python equivalents for return to the
- // calling function. All of the polygons' points and kinds codes are
- // combined into single NumPy arrays for each; this avoids having
- // to determine which polygons are holes as this will be determined by the
- // renderer. If there are ntotal points in all of the polygons, the two
- // NumPy arrays created are:
- // vertices is a double array of shape (ntotal, 2) containing the (x, y)
- // coordinates of the points in the polygons
- // codes is a uint8 array of shape (ntotal,) containing the 'kind codes'
- // which are defined in the Path class
- // and they are returned in the Python lists vertices_list and codes_list
- // respectively.
-
- Contour::const_iterator line;
- ContourLine::const_iterator point;
-
- // Find total number of points in all contour lines.
- py::ssize_t n_points = 0;
- for (line = contour.begin(); line != contour.end(); ++line)
- n_points += static_cast<py::ssize_t>(line->size());
-
- // Create segs array for point coordinates.
- py::ssize_t segs_dims[2] = {n_points, 2};
- TwoCoordinateArray segs(segs_dims);
- double* segs_ptr = segs.mutable_data();
-
- // Create kinds array for code types.
- py::ssize_t codes_dims[1] = {n_points};
- CodeArray codes(codes_dims);
- unsigned char* codes_ptr = codes.mutable_data();
-
- for (line = contour.begin(); line != contour.end(); ++line) {
- for (point = line->begin(); point != line->end(); point++) {
- *segs_ptr++ = point->x;
- *segs_ptr++ = point->y;
- *codes_ptr++ = (point == line->begin() ? MOVETO : LINETO);
- }
-
- if (line->size() > 1)
- *(codes_ptr-1) = CLOSEPOLY;
- }
-
- py::list vertices_list(1);
- vertices_list[0] = segs;
-
- py::list codes_list(1);
- codes_list[0] = codes;
-
- return py::make_tuple(vertices_list, codes_list);
-}
-
-py::tuple TriContourGenerator::create_contour(const double& level)
-{
- clear_visited_flags(false);
- Contour contour;
-
- find_boundary_lines(contour, level);
- find_interior_lines(contour, level, false, false);
-
- return contour_line_to_segs_and_kinds(contour);
-}
-
-py::tuple TriContourGenerator::create_filled_contour(const double& lower_level,
- const double& upper_level)
-{
- if (lower_level >= upper_level)
- throw std::invalid_argument("filled contour levels must be increasing");
-
- clear_visited_flags(true);
- Contour contour;
-
- find_boundary_lines_filled(contour, lower_level, upper_level);
- find_interior_lines(contour, lower_level, false, true);
- find_interior_lines(contour, upper_level, true, true);
-
- return contour_to_segs_and_kinds(contour);
-}
-
-XY TriContourGenerator::edge_interp(int tri, int edge, const double& level)
-{
- return interp(_triangulation.get_triangle_point(tri, edge),
- _triangulation.get_triangle_point(tri, (edge+1)%3),
- level);
-}
-
-void TriContourGenerator::find_boundary_lines(Contour& contour,
- const double& level)
-{
- // Traverse boundaries to find starting points for all contour lines that
- // intersect the boundaries. For each starting point found, follow the
- // line to its end before continuing.
- const Triangulation& triang = _triangulation;
- const Boundaries& boundaries = get_boundaries();
- for (Boundaries::const_iterator it = boundaries.begin();
- it != boundaries.end(); ++it) {
- const Boundary& boundary = *it;
- bool startAbove, endAbove = false;
- for (Boundary::const_iterator itb = boundary.begin();
- itb != boundary.end(); ++itb) {
- if (itb == boundary.begin())
- startAbove = get_z(triang.get_triangle_point(*itb)) >= level;
- else
- startAbove = endAbove;
- endAbove = get_z(triang.get_triangle_point(itb->tri,
- (itb->edge+1)%3)) >= level;
- if (startAbove && !endAbove) {
- // This boundary edge is the start point for a contour line,
- // so follow the line.
- contour.push_back(ContourLine());
- ContourLine& contour_line = contour.back();
- TriEdge tri_edge = *itb;
- follow_interior(contour_line, tri_edge, true, level, false);
- }
- }
- }
-}
-
-void TriContourGenerator::find_boundary_lines_filled(Contour& contour,
- const double& lower_level,
- const double& upper_level)
-{
- // Traverse boundaries to find starting points for all contour lines that
- // intersect the boundaries. For each starting point found, follow the
- // line to its end before continuing.
- const Triangulation& triang = _triangulation;
- const Boundaries& boundaries = get_boundaries();
- for (Boundaries::size_type i = 0; i < boundaries.size(); ++i) {
- const Boundary& boundary = boundaries[i];
- for (Boundary::size_type j = 0; j < boundary.size(); ++j) {
- if (!_boundaries_visited[i][j]) {
- // z values of start and end of this boundary edge.
- double z_start = get_z(triang.get_triangle_point(boundary[j]));
- double z_end = get_z(triang.get_triangle_point(
- boundary[j].tri, (boundary[j].edge+1)%3));
-
- // Does this boundary edge's z increase through upper level
- // and/or decrease through lower level?
- bool incr_upper = (z_start < upper_level && z_end >= upper_level);
- bool decr_lower = (z_start >= lower_level && z_end < lower_level);
-
- if (decr_lower || incr_upper) {
- // Start point for contour line, so follow it.
- contour.push_back(ContourLine());
- ContourLine& contour_line = contour.back();
- TriEdge start_tri_edge = boundary[j];
- TriEdge tri_edge = start_tri_edge;
-
- // Traverse interior and boundaries until return to start.
- bool on_upper = incr_upper;
- do {
- follow_interior(contour_line, tri_edge, true,
- on_upper ? upper_level : lower_level, on_upper);
- on_upper = follow_boundary(contour_line, tri_edge,
- lower_level, upper_level, on_upper);
- } while (tri_edge != start_tri_edge);
-
- // Close polygon.
- contour_line.push_back(contour_line.front());
- }
- }
- }
- }
-
- // Add full boundaries that lie between the lower and upper levels. These
- // are boundaries that have not been touched by an internal contour line
- // which are stored in _boundaries_used.
- for (Boundaries::size_type i = 0; i < boundaries.size(); ++i) {
- if (!_boundaries_used[i]) {
- const Boundary& boundary = boundaries[i];
- double z = get_z(triang.get_triangle_point(boundary[0]));
- if (z >= lower_level && z < upper_level) {
- contour.push_back(ContourLine());
- ContourLine& contour_line = contour.back();
- for (Boundary::size_type j = 0; j < boundary.size(); ++j)
- contour_line.push_back(triang.get_point_coords(
- triang.get_triangle_point(boundary[j])));
-
- // Close polygon.
- contour_line.push_back(contour_line.front());
- }
- }
- }
-}
-
-void TriContourGenerator::find_interior_lines(Contour& contour,
- const double& level,
- bool on_upper,
- bool filled)
-{
- const Triangulation& triang = _triangulation;
- int ntri = triang.get_ntri();
- for (int tri = 0; tri < ntri; ++tri) {
- int visited_index = (on_upper ? tri+ntri : tri);
-
- if (_interior_visited[visited_index] || triang.is_masked(tri))
- continue; // Triangle has already been visited or is masked.
-
- _interior_visited[visited_index] = true;
-
- // Determine edge via which to leave this triangle.
- int edge = get_exit_edge(tri, level, on_upper);
- assert(edge >= -1 && edge < 3 && "Invalid exit edge");
- if (edge == -1)
- continue; // Contour does not pass through this triangle.
-
- // Found start of new contour line loop.
- contour.push_back(ContourLine());
- ContourLine& contour_line = contour.back();
- TriEdge tri_edge = triang.get_neighbor_edge(tri, edge);
- follow_interior(contour_line, tri_edge, false, level, on_upper);
-
- // Close line loop
- contour_line.push_back(contour_line.front());
- }
-}
-
-bool TriContourGenerator::follow_boundary(ContourLine& contour_line,
- TriEdge& tri_edge,
- const double& lower_level,
- const double& upper_level,
- bool on_upper)
-{
- const Triangulation& triang = _triangulation;
- const Boundaries& boundaries = get_boundaries();
-
- // Have TriEdge to start at, need equivalent boundary edge.
- int boundary, edge;
- triang.get_boundary_edge(tri_edge, boundary, edge);
- _boundaries_used[boundary] = true;
-
- bool stop = false;
- bool first_edge = true;
- double z_start, z_end = 0;
- while (!stop)
- {
- assert(!_boundaries_visited[boundary][edge] && "Boundary already visited");
- _boundaries_visited[boundary][edge] = true;
-
- // z values of start and end points of boundary edge.
- if (first_edge)
- z_start = get_z(triang.get_triangle_point(tri_edge));
- else
- z_start = z_end;
- z_end = get_z(triang.get_triangle_point(tri_edge.tri,
- (tri_edge.edge+1)%3));
-
- if (z_end > z_start) { // z increasing.
- if (!(!on_upper && first_edge) &&
- z_end >= lower_level && z_start < lower_level) {
- stop = true;
- on_upper = false;
- } else if (z_end >= upper_level && z_start < upper_level) {
- stop = true;
- on_upper = true;
- }
- } else { // z decreasing.
- if (!(on_upper && first_edge) &&
- z_start >= upper_level && z_end < upper_level) {
- stop = true;
- on_upper = true;
- } else if (z_start >= lower_level && z_end < lower_level) {
- stop = true;
- on_upper = false;
- }
- }
-
- first_edge = false;
-
- if (!stop) {
- // Move to next boundary edge, adding point to contour line.
- edge = (edge+1) % (int)boundaries[boundary].size();
- tri_edge = boundaries[boundary][edge];
- contour_line.push_back(triang.get_point_coords(
- triang.get_triangle_point(tri_edge)));
- }
- }
-
- return on_upper;
-}
-
-void TriContourGenerator::follow_interior(ContourLine& contour_line,
- TriEdge& tri_edge,
- bool end_on_boundary,
- const double& level,
- bool on_upper)
-{
- int& tri = tri_edge.tri;
- int& edge = tri_edge.edge;
-
- // Initial point.
- contour_line.push_back(edge_interp(tri, edge, level));
-
- while (true) {
- int visited_index = tri;
- if (on_upper)
- visited_index += _triangulation.get_ntri();
-
- // Check for end not on boundary.
- if (!end_on_boundary && _interior_visited[visited_index])
- break; // Reached start point, so return.
-
- // Determine edge by which to leave this triangle.
- edge = get_exit_edge(tri, level, on_upper);
- assert(edge >= 0 && edge < 3 && "Invalid exit edge");
-
- _interior_visited[visited_index] = true;
-
- // Append new point to point set.
- assert(edge >= 0 && edge < 3 && "Invalid triangle edge");
- contour_line.push_back(edge_interp(tri, edge, level));
-
- // Move to next triangle.
- TriEdge next_tri_edge = _triangulation.get_neighbor_edge(tri,edge);
-
- // Check if ending on a boundary.
- if (end_on_boundary && next_tri_edge.tri == -1)
- break;
-
- tri_edge = next_tri_edge;
- assert(tri_edge.tri != -1 && "Invalid triangle for internal loop");
- }
-}
-
-const TriContourGenerator::Boundaries& TriContourGenerator::get_boundaries() const
-{
- return _triangulation.get_boundaries();
-}
-
-int TriContourGenerator::get_exit_edge(int tri,
- const double& level,
- bool on_upper) const
-{
- assert(tri >= 0 && tri < _triangulation.get_ntri() &&
- "Triangle index out of bounds.");
-
- unsigned int config =
- (get_z(_triangulation.get_triangle_point(tri, 0)) >= level) |
- (get_z(_triangulation.get_triangle_point(tri, 1)) >= level) << 1 |
- (get_z(_triangulation.get_triangle_point(tri, 2)) >= level) << 2;
-
- if (on_upper) config = 7-config;
-
- switch (config) {
- case 0: return -1;
- case 1: return 2;
- case 2: return 0;
- case 3: return 2;
- case 4: return 1;
- case 5: return 1;
- case 6: return 0;
- case 7: return -1;
- default: assert(0 && "Invalid config value"); return -1;
- }
-}
-
-const double& TriContourGenerator::get_z(int point) const
-{
- assert(point >= 0 && point < _triangulation.get_npoints() &&
- "Point index out of bounds.");
- return _z.data()[point];
-}
-
-XY TriContourGenerator::interp(int point1,
- int point2,
- const double& level) const
-{
- assert(point1 >= 0 && point1 < _triangulation.get_npoints() &&
- "Point index 1 out of bounds.");
- assert(point2 >= 0 && point2 < _triangulation.get_npoints() &&
- "Point index 2 out of bounds.");
- assert(point1 != point2 && "Identical points");
- double fraction = (get_z(point2) - level) / (get_z(point2) - get_z(point1));
- return _triangulation.get_point_coords(point1)*fraction +
- _triangulation.get_point_coords(point2)*(1.0 - fraction);
-}
-
-
-
-TrapezoidMapTriFinder::TrapezoidMapTriFinder(Triangulation& triangulation)
- : _triangulation(triangulation),
- _points(0),
- _tree(0)
-{}
-
-TrapezoidMapTriFinder::~TrapezoidMapTriFinder()
-{
- clear();
-}
-
-bool
-TrapezoidMapTriFinder::add_edge_to_tree(const Edge& edge)
-{
- std::vector<Trapezoid*> trapezoids;
- if (!find_trapezoids_intersecting_edge(edge, trapezoids))
- return false;
- assert(!trapezoids.empty() && "No trapezoids intersect edge");
-
- const Point* p = edge.left;
- const Point* q = edge.right;
- Trapezoid* left_old = 0; // old trapezoid to the left.
- Trapezoid* left_below = 0; // below trapezoid to the left.
- Trapezoid* left_above = 0; // above trapezoid to the left.
-
- // Iterate through trapezoids intersecting edge from left to right.
- // Replace each old trapezoid with 2+ new trapezoids, and replace its
- // corresponding nodes in the search tree with new nodes.
- size_t ntraps = trapezoids.size();
- for (size_t i = 0; i < ntraps; ++i) {
- Trapezoid* old = trapezoids[i]; // old trapezoid to replace.
- bool start_trap = (i == 0);
- bool end_trap = (i == ntraps-1);
- bool have_left = (start_trap && edge.left != old->left);
- bool have_right = (end_trap && edge.right != old->right);
-
- // Old trapezoid is replaced by up to 4 new trapezoids: left is to the
- // left of the start point p, below/above are below/above the edge
- // inserted, and right is to the right of the end point q.
- Trapezoid* left = 0;
- Trapezoid* below = 0;
- Trapezoid* above = 0;
- Trapezoid* right = 0;
-
- // There are 4 different cases here depending on whether the old
- // trapezoid in question is the start and/or end trapezoid of those
- // that intersect the edge inserted. There is some code duplication
- // here but it is much easier to understand this way rather than
- // interleave the 4 different cases with many more if-statements.
- if (start_trap && end_trap) {
- // Edge intersects a single trapezoid.
- if (have_left)
- left = new Trapezoid(old->left, p, old->below, old->above);
- below = new Trapezoid(p, q, old->below, edge);
- above = new Trapezoid(p, q, edge, old->above);
- if (have_right)
- right = new Trapezoid(q, old->right, old->below, old->above);
-
- // Set pairs of trapezoid neighbours.
- if (have_left) {
- left->set_lower_left(old->lower_left);
- left->set_upper_left(old->upper_left);
- left->set_lower_right(below);
- left->set_upper_right(above);
- }
- else {
- below->set_lower_left(old->lower_left);
- above->set_upper_left(old->upper_left);
- }
-
- if (have_right) {
- right->set_lower_right(old->lower_right);
- right->set_upper_right(old->upper_right);
- below->set_lower_right(right);
- above->set_upper_right(right);
- }
- else {
- below->set_lower_right(old->lower_right);
- above->set_upper_right(old->upper_right);
- }
- }
- else if (start_trap) {
- // Old trapezoid is the first of 2+ trapezoids that the edge
- // intersects.
- if (have_left)
- left = new Trapezoid(old->left, p, old->below, old->above);
- below = new Trapezoid(p, old->right, old->below, edge);
- above = new Trapezoid(p, old->right, edge, old->above);
-
- // Set pairs of trapezoid neighbours.
- if (have_left) {
- left->set_lower_left(old->lower_left);
- left->set_upper_left(old->upper_left);
- left->set_lower_right(below);
- left->set_upper_right(above);
- }
- else {
- below->set_lower_left(old->lower_left);
- above->set_upper_left(old->upper_left);
- }
-
- below->set_lower_right(old->lower_right);
- above->set_upper_right(old->upper_right);
- }
- else if (end_trap) {
- // Old trapezoid is the last of 2+ trapezoids that the edge
- // intersects.
- if (left_below->below == old->below) {
- below = left_below;
- below->right = q;
- }
- else
- below = new Trapezoid(old->left, q, old->below, edge);
-
- if (left_above->above == old->above) {
- above = left_above;
- above->right = q;
- }
- else
- above = new Trapezoid(old->left, q, edge, old->above);
-
- if (have_right)
- right = new Trapezoid(q, old->right, old->below, old->above);
-
- // Set pairs of trapezoid neighbours.
- if (have_right) {
- right->set_lower_right(old->lower_right);
- right->set_upper_right(old->upper_right);
- below->set_lower_right(right);
- above->set_upper_right(right);
- }
- else {
- below->set_lower_right(old->lower_right);
- above->set_upper_right(old->upper_right);
- }
-
- // Connect to new trapezoids replacing prevOld.
- if (below != left_below) {
- below->set_upper_left(left_below);
- if (old->lower_left == left_old)
- below->set_lower_left(left_below);
- else
- below->set_lower_left(old->lower_left);
- }
-
- if (above != left_above) {
- above->set_lower_left(left_above);
- if (old->upper_left == left_old)
- above->set_upper_left(left_above);
- else
- above->set_upper_left(old->upper_left);
- }
- }
- else { // Middle trapezoid.
- // Old trapezoid is neither the first nor last of the 3+ trapezoids
- // that the edge intersects.
- if (left_below->below == old->below) {
- below = left_below;
- below->right = old->right;
- }
- else
- below = new Trapezoid(old->left, old->right, old->below, edge);
-
- if (left_above->above == old->above) {
- above = left_above;
- above->right = old->right;
- }
- else
- above = new Trapezoid(old->left, old->right, edge, old->above);
-
- // Connect to new trapezoids replacing prevOld.
- if (below != left_below) { // below is new.
- below->set_upper_left(left_below);
- if (old->lower_left == left_old)
- below->set_lower_left(left_below);
- else
- below->set_lower_left(old->lower_left);
- }
-
- if (above != left_above) { // above is new.
- above->set_lower_left(left_above);
- if (old->upper_left == left_old)
- above->set_upper_left(left_above);
- else
- above->set_upper_left(old->upper_left);
- }
-
- below->set_lower_right(old->lower_right);
- above->set_upper_right(old->upper_right);
- }
-
- // Create new nodes to add to search tree. Below and above trapezoids
- // may already have owning trapezoid nodes, in which case reuse them.
- Node* new_top_node = new Node(
- &edge,
- below == left_below ? below->trapezoid_node : new Node(below),
- above == left_above ? above->trapezoid_node : new Node(above));
- if (have_right)
- new_top_node = new Node(q, new_top_node, new Node(right));
- if (have_left)
- new_top_node = new Node(p, new Node(left), new_top_node);
-
- // Insert new_top_node in correct position or positions in search tree.
- Node* old_node = old->trapezoid_node;
- if (old_node == _tree)
- _tree = new_top_node;
- else
- old_node->replace_with(new_top_node);
-
- // old_node has been removed from all of its parents and is no longer
- // needed.
- assert(old_node->has_no_parents() && "Node should have no parents");
- delete old_node;
-
- // Clearing up.
- if (!end_trap) {
- // Prepare for next loop.
- left_old = old;
- left_above = above;
- left_below = below;
- }
- }
-
- return true;
-}
-
-void
-TrapezoidMapTriFinder::clear()
-{
- delete [] _points;
- _points = 0;
-
- _edges.clear();
-
- delete _tree;
- _tree = 0;
-}
-
-TrapezoidMapTriFinder::TriIndexArray
-TrapezoidMapTriFinder::find_many(const CoordinateArray& x,
- const CoordinateArray& y)
-{
- if (x.ndim() != 1 || x.shape(0) != y.shape(0))
- throw std::invalid_argument(
- "x and y must be array-like with same shape");
-
- // Create integer array to return.
- auto n = x.shape(0);
- TriIndexArray tri_indices_array(n);
- auto tri_indices = tri_indices_array.mutable_unchecked<1>();
- auto x_data = x.data();
- auto y_data = y.data();
-
- // Fill returned array.
- for (py::ssize_t i = 0; i < n; ++i)
- tri_indices(i) = find_one(XY(x_data[i], y_data[i]));
-
- return tri_indices_array;
-}
-
-int
-TrapezoidMapTriFinder::find_one(const XY& xy)
-{
- const Node* node = _tree->search(xy);
- assert(node != 0 && "Search tree for point returned null node");
- return node->get_tri();
-}
-
-bool
-TrapezoidMapTriFinder::find_trapezoids_intersecting_edge(
- const Edge& edge,
- std::vector<Trapezoid*>& trapezoids)
-{
- // This is the FollowSegment algorithm of de Berg et al, with some extra
- // checks to deal with simple colinear (i.e. invalid) triangles.
- trapezoids.clear();
- Trapezoid* trapezoid = _tree->search(edge);
- if (trapezoid == 0) {
- assert(trapezoid != 0 && "search(edge) returns null trapezoid");
- return false;
- }
-
- trapezoids.push_back(trapezoid);
- while (edge.right->is_right_of(*trapezoid->right)) {
- int orient = edge.get_point_orientation(*trapezoid->right);
- if (orient == 0) {
- if (edge.point_below == trapezoid->right)
- orient = +1;
- else if (edge.point_above == trapezoid->right)
- orient = -1;
- else {
- assert(0 && "Unable to deal with point on edge");
- return false;
- }
- }
-
- if (orient == -1)
- trapezoid = trapezoid->lower_right;
- else if (orient == +1)
- trapezoid = trapezoid->upper_right;
-
- if (trapezoid == 0) {
- assert(0 && "Expected trapezoid neighbor");
- return false;
- }
- trapezoids.push_back(trapezoid);
- }
-
- return true;
-}
-
-py::list
-TrapezoidMapTriFinder::get_tree_stats()
-{
- NodeStats stats;
- _tree->get_stats(0, stats);
-
- py::list ret(7);
- ret[0] = stats.node_count;
- ret[1] = stats.unique_nodes.size(),
- ret[2] = stats.trapezoid_count,
- ret[3] = stats.unique_trapezoid_nodes.size(),
- ret[4] = stats.max_parent_count,
- ret[5] = stats.max_depth,
- ret[6] = stats.sum_trapezoid_depth / stats.trapezoid_count;
- return ret;
-}
-
-void
-TrapezoidMapTriFinder::initialize()
-{
- clear();
- const Triangulation& triang = _triangulation;
-
- // Set up points array, which contains all of the points in the
- // triangulation plus the 4 corners of the enclosing rectangle.
- int npoints = triang.get_npoints();
- _points = new Point[npoints + 4];
- BoundingBox bbox;
- for (int i = 0; i < npoints; ++i) {
- XY xy = triang.get_point_coords(i);
- // Avoid problems with -0.0 values different from 0.0
- if (xy.x == -0.0)
- xy.x = 0.0;
- if (xy.y == -0.0)
- xy.y = 0.0;
- _points[i] = Point(xy);
- bbox.add(xy);
- }
-
- // Last 4 points are corner points of enclosing rectangle. Enclosing
- // rectangle made slightly larger in case corner points are already in the
- // triangulation.
- if (bbox.empty) {
- bbox.add(XY(0.0, 0.0));
- bbox.add(XY(1.0, 1.0));
- }
- else {
- const double small = 0.1; // Any value > 0.0
- bbox.expand( (bbox.upper - bbox.lower)*small );
- }
- _points[npoints ] = Point(bbox.lower); // SW point.
- _points[npoints+1] = Point(bbox.upper.x, bbox.lower.y); // SE point.
- _points[npoints+2] = Point(bbox.lower.x, bbox.upper.y); // NW point.
- _points[npoints+3] = Point(bbox.upper); // NE point.
-
- // Set up edges array.
- // First the bottom and top edges of the enclosing rectangle.
- _edges.push_back(Edge(&_points[npoints], &_points[npoints+1],-1,-1,0,0));
- _edges.push_back(Edge(&_points[npoints+2],&_points[npoints+3],-1,-1,0,0));
-
- // Add all edges in the triangulation that point to the right. Do not
- // explicitly include edges that point to the left as the neighboring
- // triangle will supply that, unless there is no such neighbor.
- int ntri = triang.get_ntri();
- for (int tri = 0; tri < ntri; ++tri) {
- if (!triang.is_masked(tri)) {
- for (int edge = 0; edge < 3; ++edge) {
- Point* start = _points + triang.get_triangle_point(tri,edge);
- Point* end = _points +
- triang.get_triangle_point(tri,(edge+1)%3);
- Point* other = _points +
- triang.get_triangle_point(tri,(edge+2)%3);
- TriEdge neighbor = triang.get_neighbor_edge(tri,edge);
- if (end->is_right_of(*start)) {
- const Point* neighbor_point_below = (neighbor.tri == -1) ?
- 0 : _points + triang.get_triangle_point(
- neighbor.tri, (neighbor.edge+2)%3);
- _edges.push_back(Edge(start, end, neighbor.tri, tri,
- neighbor_point_below, other));
- }
- else if (neighbor.tri == -1)
- _edges.push_back(Edge(end, start, tri, -1, other, 0));
-
- // Set triangle associated with start point if not already set.
- if (start->tri == -1)
- start->tri = tri;
- }
- }
- }
-
- // Initial trapezoid is enclosing rectangle.
- _tree = new Node(new Trapezoid(&_points[npoints], &_points[npoints+1],
- _edges[0], _edges[1]));
- _tree->assert_valid(false);
-
- // Randomly shuffle all edges other than first 2.
- std::mt19937 rng(1234);
- std::shuffle(_edges.begin()+2, _edges.end(), rng);
-
- // Add edges, one at a time, to tree.
- size_t nedges = _edges.size();
- for (size_t index = 2; index < nedges; ++index) {
- if (!add_edge_to_tree(_edges[index]))
- throw std::runtime_error("Triangulation is invalid");
- _tree->assert_valid(index == nedges-1);
- }
-}
-
-void
-TrapezoidMapTriFinder::print_tree()
-{
- assert(_tree != 0 && "Null Node tree");
- _tree->print();
-}
-
-TrapezoidMapTriFinder::Edge::Edge(const Point* left_,
- const Point* right_,
- int triangle_below_,
- int triangle_above_,
- const Point* point_below_,
- const Point* point_above_)
- : left(left_),
- right(right_),
- triangle_below(triangle_below_),
- triangle_above(triangle_above_),
- point_below(point_below_),
- point_above(point_above_)
-{
- assert(left != 0 && "Null left point");
- assert(right != 0 && "Null right point");
- assert(right->is_right_of(*left) && "Incorrect point order");
- assert(triangle_below >= -1 && "Invalid triangle below index");
- assert(triangle_above >= -1 && "Invalid triangle above index");
-}
-
-int
-TrapezoidMapTriFinder::Edge::get_point_orientation(const XY& xy) const
-{
- double cross_z = (xy - *left).cross_z(*right - *left);
- return (cross_z > 0.0) ? +1 : ((cross_z < 0.0) ? -1 : 0);
-}
-
-double
-TrapezoidMapTriFinder::Edge::get_slope() const
-{
- // Divide by zero is acceptable here.
- XY diff = *right - *left;
- return diff.y / diff.x;
-}
-
-double
-TrapezoidMapTriFinder::Edge::get_y_at_x(const double& x) const
-{
- if (left->x == right->x) {
- // If edge is vertical, return lowest y from left point.
- assert(x == left->x && "x outside of edge");
- return left->y;
- }
- else {
- // Equation of line: left + lambda*(right - left) = xy.
- // i.e. left.x + lambda(right.x - left.x) = x and similar for y.
- double lambda = (x - left->x) / (right->x - left->x);
- assert(lambda >= 0 && lambda <= 1.0 && "Lambda out of bounds");
- return left->y + lambda*(right->y - left->y);
- }
-}
-
-bool
-TrapezoidMapTriFinder::Edge::has_point(const Point* point) const
-{
- assert(point != 0 && "Null point");
- return (left == point || right == point);
-}
-
-bool
-TrapezoidMapTriFinder::Edge::operator==(const Edge& other) const
-{
- return this == &other;
-}
-
-void
-TrapezoidMapTriFinder::Edge::print_debug() const
-{
- std::cout << "Edge " << *this << " tri_below=" << triangle_below
- << " tri_above=" << triangle_above << std::endl;
-}
-
-TrapezoidMapTriFinder::Node::Node(const Point* point, Node* left, Node* right)
- : _type(Type_XNode)
-{
- assert(point != 0 && "Invalid point");
- assert(left != 0 && "Invalid left node");
- assert(right != 0 && "Invalid right node");
- _union.xnode.point = point;
- _union.xnode.left = left;
- _union.xnode.right = right;
- left->add_parent(this);
- right->add_parent(this);
-}
-
-TrapezoidMapTriFinder::Node::Node(const Edge* edge, Node* below, Node* above)
- : _type(Type_YNode)
-{
- assert(edge != 0 && "Invalid edge");
- assert(below != 0 && "Invalid below node");
- assert(above != 0 && "Invalid above node");
- _union.ynode.edge = edge;
- _union.ynode.below = below;
- _union.ynode.above = above;
- below->add_parent(this);
- above->add_parent(this);
-}
-
-TrapezoidMapTriFinder::Node::Node(Trapezoid* trapezoid)
- : _type(Type_TrapezoidNode)
-{
- assert(trapezoid != 0 && "Null Trapezoid");
- _union.trapezoid = trapezoid;
- trapezoid->trapezoid_node = this;
-}
-
-TrapezoidMapTriFinder::Node::~Node()
-{
- switch (_type) {
- case Type_XNode:
- if (_union.xnode.left->remove_parent(this))
- delete _union.xnode.left;
- if (_union.xnode.right->remove_parent(this))
- delete _union.xnode.right;
- break;
- case Type_YNode:
- if (_union.ynode.below->remove_parent(this))
- delete _union.ynode.below;
- if (_union.ynode.above->remove_parent(this))
- delete _union.ynode.above;
- break;
- case Type_TrapezoidNode:
- delete _union.trapezoid;
- break;
- }
-}
-
-void
-TrapezoidMapTriFinder::Node::add_parent(Node* parent)
-{
- assert(parent != 0 && "Null parent");
- assert(parent != this && "Cannot be parent of self");
- assert(!has_parent(parent) && "Parent already in collection");
- _parents.push_back(parent);
-}
-
-void
-TrapezoidMapTriFinder::Node::assert_valid(bool tree_complete) const
-{
-#ifndef NDEBUG
- // Check parents.
- for (Parents::const_iterator it = _parents.begin();
- it != _parents.end(); ++it) {
- Node* parent = *it;
- assert(parent != this && "Cannot be parent of self");
- assert(parent->has_child(this) && "Parent missing child");
- }
-
- // Check children, and recurse.
- switch (_type) {
- case Type_XNode:
- assert(_union.xnode.left != 0 && "Null left child");
- assert(_union.xnode.left->has_parent(this) && "Incorrect parent");
- assert(_union.xnode.right != 0 && "Null right child");
- assert(_union.xnode.right->has_parent(this) && "Incorrect parent");
- _union.xnode.left->assert_valid(tree_complete);
- _union.xnode.right->assert_valid(tree_complete);
- break;
- case Type_YNode:
- assert(_union.ynode.below != 0 && "Null below child");
- assert(_union.ynode.below->has_parent(this) && "Incorrect parent");
- assert(_union.ynode.above != 0 && "Null above child");
- assert(_union.ynode.above->has_parent(this) && "Incorrect parent");
- _union.ynode.below->assert_valid(tree_complete);
- _union.ynode.above->assert_valid(tree_complete);
- break;
- case Type_TrapezoidNode:
- assert(_union.trapezoid != 0 && "Null trapezoid");
- assert(_union.trapezoid->trapezoid_node == this &&
- "Incorrect trapezoid node");
- _union.trapezoid->assert_valid(tree_complete);
- break;
- }
-#endif
-}
-
-void
-TrapezoidMapTriFinder::Node::get_stats(int depth,
- NodeStats& stats) const
-{
- stats.node_count++;
- if (depth > stats.max_depth)
- stats.max_depth = depth;
- bool new_node = stats.unique_nodes.insert(this).second;
- if (new_node)
- stats.max_parent_count = std::max(stats.max_parent_count,
- static_cast<long>(_parents.size()));
-
- switch (_type) {
- case Type_XNode:
- _union.xnode.left->get_stats(depth+1, stats);
- _union.xnode.right->get_stats(depth+1, stats);
- break;
- case Type_YNode:
- _union.ynode.below->get_stats(depth+1, stats);
- _union.ynode.above->get_stats(depth+1, stats);
- break;
- default: // Type_TrapezoidNode:
- stats.unique_trapezoid_nodes.insert(this);
- stats.trapezoid_count++;
- stats.sum_trapezoid_depth += depth;
- break;
- }
-}
-
-int
-TrapezoidMapTriFinder::Node::get_tri() const
-{
- switch (_type) {
- case Type_XNode:
- return _union.xnode.point->tri;
- case Type_YNode:
- if (_union.ynode.edge->triangle_above != -1)
- return _union.ynode.edge->triangle_above;
- else
- return _union.ynode.edge->triangle_below;
- default: // Type_TrapezoidNode:
- assert(_union.trapezoid->below.triangle_above ==
- _union.trapezoid->above.triangle_below &&
- "Inconsistent triangle indices from trapezoid edges");
- return _union.trapezoid->below.triangle_above;
- }
-}
-
-bool
-TrapezoidMapTriFinder::Node::has_child(const Node* child) const
-{
- assert(child != 0 && "Null child node");
- switch (_type) {
- case Type_XNode:
- return (_union.xnode.left == child || _union.xnode.right == child);
- case Type_YNode:
- return (_union.ynode.below == child ||
- _union.ynode.above == child);
- default: // Type_TrapezoidNode:
- return false;
- }
-}
-
-bool
-TrapezoidMapTriFinder::Node::has_no_parents() const
-{
- return _parents.empty();
-}
-
-bool
-TrapezoidMapTriFinder::Node::has_parent(const Node* parent) const
-{
- return (std::find(_parents.begin(), _parents.end(), parent) !=
- _parents.end());
-}
-
-void
-TrapezoidMapTriFinder::Node::print(int depth /* = 0 */) const
-{
- for (int i = 0; i < depth; ++i) std::cout << " ";
- switch (_type) {
- case Type_XNode:
- std::cout << "XNode " << *_union.xnode.point << std::endl;
- _union.xnode.left->print(depth + 1);
- _union.xnode.right->print(depth + 1);
- break;
- case Type_YNode:
- std::cout << "YNode " << *_union.ynode.edge << std::endl;
- _union.ynode.below->print(depth + 1);
- _union.ynode.above->print(depth + 1);
- break;
- case Type_TrapezoidNode:
- std::cout << "Trapezoid ll="
- << _union.trapezoid->get_lower_left_point() << " lr="
- << _union.trapezoid->get_lower_right_point() << " ul="
- << _union.trapezoid->get_upper_left_point() << " ur="
- << _union.trapezoid->get_upper_right_point() << std::endl;
- break;
- }
-}
-
-bool
-TrapezoidMapTriFinder::Node::remove_parent(Node* parent)
-{
- assert(parent != 0 && "Null parent");
- assert(parent != this && "Cannot be parent of self");
- Parents::iterator it = std::find(_parents.begin(), _parents.end(), parent);
- assert(it != _parents.end() && "Parent not in collection");
- _parents.erase(it);
- return _parents.empty();
-}
-
-void
-TrapezoidMapTriFinder::Node::replace_child(Node* old_child, Node* new_child)
-{
- switch (_type) {
- case Type_XNode:
- assert((_union.xnode.left == old_child ||
- _union.xnode.right == old_child) && "Not a child Node");
- assert(new_child != 0 && "Null child node");
- if (_union.xnode.left == old_child)
- _union.xnode.left = new_child;
- else
- _union.xnode.right = new_child;
- break;
- case Type_YNode:
- assert((_union.ynode.below == old_child ||
- _union.ynode.above == old_child) && "Not a child node");
- assert(new_child != 0 && "Null child node");
- if (_union.ynode.below == old_child)
- _union.ynode.below = new_child;
- else
- _union.ynode.above = new_child;
- break;
- case Type_TrapezoidNode:
- assert(0 && "Invalid type for this operation");
- break;
- }
- old_child->remove_parent(this);
- new_child->add_parent(this);
-}
-
-void
-TrapezoidMapTriFinder::Node::replace_with(Node* new_node)
-{
- assert(new_node != 0 && "Null replacement node");
- // Replace child of each parent with new_node. As each has parent has its
- // child replaced it is removed from the _parents collection.
- while (!_parents.empty())
- _parents.front()->replace_child(this, new_node);
-}
-
-const TrapezoidMapTriFinder::Node*
-TrapezoidMapTriFinder::Node::search(const XY& xy)
-{
- switch (_type) {
- case Type_XNode:
- if (xy == *_union.xnode.point)
- return this;
- else if (xy.is_right_of(*_union.xnode.point))
- return _union.xnode.right->search(xy);
- else
- return _union.xnode.left->search(xy);
- case Type_YNode: {
- int orient = _union.ynode.edge->get_point_orientation(xy);
- if (orient == 0)
- return this;
- else if (orient < 0)
- return _union.ynode.above->search(xy);
- else
- return _union.ynode.below->search(xy);
- }
- default: // Type_TrapezoidNode:
- return this;
- }
-}
-
-TrapezoidMapTriFinder::Trapezoid*
-TrapezoidMapTriFinder::Node::search(const Edge& edge)
-{
- switch (_type) {
- case Type_XNode:
- if (edge.left == _union.xnode.point)
- return _union.xnode.right->search(edge);
- else {
- if (edge.left->is_right_of(*_union.xnode.point))
- return _union.xnode.right->search(edge);
- else
- return _union.xnode.left->search(edge);
- }
- case Type_YNode:
- if (edge.left == _union.ynode.edge->left) {
- // Coinciding left edge points.
- if (edge.get_slope() == _union.ynode.edge->get_slope()) {
- if (_union.ynode.edge->triangle_above ==
- edge.triangle_below)
- return _union.ynode.above->search(edge);
- else if (_union.ynode.edge->triangle_below ==
- edge.triangle_above)
- return _union.ynode.below->search(edge);
- else {
- assert(0 &&
- "Invalid triangulation, common left points");
- return 0;
- }
- }
- if (edge.get_slope() > _union.ynode.edge->get_slope())
- return _union.ynode.above->search(edge);
- else
- return _union.ynode.below->search(edge);
- }
- else if (edge.right == _union.ynode.edge->right) {
- // Coinciding right edge points.
- if (edge.get_slope() == _union.ynode.edge->get_slope()) {
- if (_union.ynode.edge->triangle_above ==
- edge.triangle_below)
- return _union.ynode.above->search(edge);
- else if (_union.ynode.edge->triangle_below ==
- edge.triangle_above)
- return _union.ynode.below->search(edge);
- else {
- assert(0 &&
- "Invalid triangulation, common right points");
- return 0;
- }
- }
- if (edge.get_slope() > _union.ynode.edge->get_slope())
- return _union.ynode.below->search(edge);
- else
- return _union.ynode.above->search(edge);
- }
- else {
- int orient =
- _union.ynode.edge->get_point_orientation(*edge.left);
- if (orient == 0) {
- // edge.left lies on _union.ynode.edge
- if (_union.ynode.edge->point_above != 0 &&
- edge.has_point(_union.ynode.edge->point_above))
- orient = -1;
- else if (_union.ynode.edge->point_below != 0 &&
- edge.has_point(_union.ynode.edge->point_below))
- orient = +1;
- else {
- assert(0 && "Invalid triangulation, point on edge");
- return 0;
- }
- }
- if (orient < 0)
- return _union.ynode.above->search(edge);
- else
- return _union.ynode.below->search(edge);
- }
- default: // Type_TrapezoidNode:
- return _union.trapezoid;
- }
-}
-
-TrapezoidMapTriFinder::Trapezoid::Trapezoid(const Point* left_,
- const Point* right_,
- const Edge& below_,
- const Edge& above_)
- : left(left_), right(right_), below(below_), above(above_),
- lower_left(0), lower_right(0), upper_left(0), upper_right(0),
- trapezoid_node(0)
-{
- assert(left != 0 && "Null left point");
- assert(right != 0 && "Null right point");
- assert(right->is_right_of(*left) && "Incorrect point order");
-}
-
-void
-TrapezoidMapTriFinder::Trapezoid::assert_valid(bool tree_complete) const
-{
-#ifndef NDEBUG
- assert(left != 0 && "Null left point");
- assert(right != 0 && "Null right point");
-
- if (lower_left != 0) {
- assert(lower_left->below == below &&
- lower_left->lower_right == this &&
- "Incorrect lower_left trapezoid");
- assert(get_lower_left_point() == lower_left->get_lower_right_point() &&
- "Incorrect lower left point");
- }
-
- if (lower_right != 0) {
- assert(lower_right->below == below &&
- lower_right->lower_left == this &&
- "Incorrect lower_right trapezoid");
- assert(get_lower_right_point() == lower_right->get_lower_left_point() &&
- "Incorrect lower right point");
- }
-
- if (upper_left != 0) {
- assert(upper_left->above == above &&
- upper_left->upper_right == this &&
- "Incorrect upper_left trapezoid");
- assert(get_upper_left_point() == upper_left->get_upper_right_point() &&
- "Incorrect upper left point");
- }
-
- if (upper_right != 0) {
- assert(upper_right->above == above &&
- upper_right->upper_left == this &&
- "Incorrect upper_right trapezoid");
- assert(get_upper_right_point() == upper_right->get_upper_left_point() &&
- "Incorrect upper right point");
- }
-
- assert(trapezoid_node != 0 && "Null trapezoid_node");
-
- if (tree_complete) {
- assert(below.triangle_above == above.triangle_below &&
- "Inconsistent triangle indices from trapezoid edges");
- }
-#endif
-}
-
-XY
-TrapezoidMapTriFinder::Trapezoid::get_lower_left_point() const
-{
- double x = left->x;
- return XY(x, below.get_y_at_x(x));
-}
-
-XY
-TrapezoidMapTriFinder::Trapezoid::get_lower_right_point() const
-{
- double x = right->x;
- return XY(x, below.get_y_at_x(x));
-}
-
-XY
-TrapezoidMapTriFinder::Trapezoid::get_upper_left_point() const
-{
- double x = left->x;
- return XY(x, above.get_y_at_x(x));
-}
-
-XY
-TrapezoidMapTriFinder::Trapezoid::get_upper_right_point() const
-{
- double x = right->x;
- return XY(x, above.get_y_at_x(x));
-}
-
-void
-TrapezoidMapTriFinder::Trapezoid::print_debug() const
-{
- std::cout << "Trapezoid " << this
- << " left=" << *left
- << " right=" << *right
- << " below=" << below
- << " above=" << above
- << " ll=" << lower_left
- << " lr=" << lower_right
- << " ul=" << upper_left
- << " ur=" << upper_right
- << " node=" << trapezoid_node
- << " llp=" << get_lower_left_point()
- << " lrp=" << get_lower_right_point()
- << " ulp=" << get_upper_left_point()
- << " urp=" << get_upper_right_point() << std::endl;
-}
-
-void
-TrapezoidMapTriFinder::Trapezoid::set_lower_left(Trapezoid* lower_left_)
-{
- lower_left = lower_left_;
- if (lower_left != 0)
- lower_left->lower_right = this;
-}
-
-void
-TrapezoidMapTriFinder::Trapezoid::set_lower_right(Trapezoid* lower_right_)
-{
- lower_right = lower_right_;
- if (lower_right != 0)
- lower_right->lower_left = this;
-}
-
-void
-TrapezoidMapTriFinder::Trapezoid::set_upper_left(Trapezoid* upper_left_)
-{
- upper_left = upper_left_;
- if (upper_left != 0)
- upper_left->upper_right = this;
-}
-
-void
-TrapezoidMapTriFinder::Trapezoid::set_upper_right(Trapezoid* upper_right_)
-{
- upper_right = upper_right_;
- if (upper_right != 0)
- upper_right->upper_left = this;
-}
diff --git a/contrib/python/matplotlib/py3/src/tri/_tri.h b/contrib/python/matplotlib/py3/src/tri/_tri.h
deleted file mode 100644
index c176b4c0e8..0000000000
--- a/contrib/python/matplotlib/py3/src/tri/_tri.h
+++ /dev/null
@@ -1,799 +0,0 @@
-/*
- * 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
diff --git a/contrib/python/matplotlib/py3/src/tri/_tri_wrapper.cpp b/contrib/python/matplotlib/py3/src/tri/_tri_wrapper.cpp
deleted file mode 100644
index 1b0c3d7555..0000000000
--- a/contrib/python/matplotlib/py3/src/tri/_tri_wrapper.cpp
+++ /dev/null
@@ -1,58 +0,0 @@
-#include "_tri.h"
-
-PYBIND11_MODULE(_tri, m) {
- py::class_<Triangulation>(m, "Triangulation")
- .def(py::init<const Triangulation::CoordinateArray&,
- const Triangulation::CoordinateArray&,
- const Triangulation::TriangleArray&,
- const Triangulation::MaskArray&,
- const Triangulation::EdgeArray&,
- const Triangulation::NeighborArray&,
- bool>(),
- py::arg("x"),
- py::arg("y"),
- py::arg("triangles"),
- py::arg("mask"),
- py::arg("edges"),
- py::arg("neighbors"),
- py::arg("correct_triangle_orientations"),
- "Create a new C++ Triangulation object.\n"
- "This should not be called directly, use the python class\n"
- "matplotlib.tri.Triangulation instead.\n")
- .def("calculate_plane_coefficients", &Triangulation::calculate_plane_coefficients,
- "Calculate plane equation coefficients for all unmasked triangles.")
- .def("get_edges", &Triangulation::get_edges,
- "Return edges array.")
- .def("get_neighbors", &Triangulation::get_neighbors,
- "Return neighbors array.")
- .def("set_mask", &Triangulation::set_mask,
- "Set or clear the mask array.");
-
- py::class_<TriContourGenerator>(m, "TriContourGenerator")
- .def(py::init<Triangulation&,
- const TriContourGenerator::CoordinateArray&>(),
- py::arg("triangulation"),
- py::arg("z"),
- "Create a new C++ TriContourGenerator object.\n"
- "This should not be called directly, use the functions\n"
- "matplotlib.axes.tricontour and tricontourf instead.\n")
- .def("create_contour", &TriContourGenerator::create_contour,
- "Create and return a non-filled contour.")
- .def("create_filled_contour", &TriContourGenerator::create_filled_contour,
- "Create and return a filled contour.");
-
- py::class_<TrapezoidMapTriFinder>(m, "TrapezoidMapTriFinder")
- .def(py::init<Triangulation&>(),
- py::arg("triangulation"),
- "Create a new C++ TrapezoidMapTriFinder object.\n"
- "This should not be called directly, use the python class\n"
- "matplotlib.tri.TrapezoidMapTriFinder instead.\n")
- .def("find_many", &TrapezoidMapTriFinder::find_many,
- "Find indices of triangles containing the point coordinates (x, y).")
- .def("get_tree_stats", &TrapezoidMapTriFinder::get_tree_stats,
- "Return statistics about the tree used by the trapezoid map.")
- .def("initialize", &TrapezoidMapTriFinder::initialize,
- "Initialize this object, creating the trapezoid map from the triangulation.")
- .def("print_tree", &TrapezoidMapTriFinder::print_tree,
- "Print the search tree as text to stdout; useful for debug purposes.");
-}