aboutsummaryrefslogtreecommitdiffstats
path: root/contrib/python/contourpy/src/base.h
blob: e626e9943188fd67ce6ff7ee4ec84a93d6044876 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
// BaseContourGenerator class provides functionality common to multiple contouring algorithms.
// Uses the Curiously Recurring Template Pattern idiom whereby classes derived from this are
// declared as
//     class Derived : public BaseContourGenerator<Derived>
//
// It provides static polymorphism at compile-time rather than the more common dynamic polymorphism
// at run-time using virtual functions.  Hence it avoids the runtime overhead of calling virtual
// functions.

#ifndef CONTOURPY_BASE_H
#define CONTOURPY_BASE_H

#include "chunk_local.h"
#include "contour_generator.h"
#include "fill_type.h"
#include "line_type.h"
#include "outer_or_hole.h"
#include "z_interp.h"
#include <vector>

namespace contourpy {

template <typename Derived>
class BaseContourGenerator : public ContourGenerator
{
public:
    ~BaseContourGenerator();

    static FillType default_fill_type();
    static LineType default_line_type();

    py::tuple get_chunk_count() const;  // Return (y_chunk_count, x_chunk_count)
    py::tuple get_chunk_size() const;   // Return (y_chunk_size, x_chunk_size)

    bool get_corner_mask() const;

    FillType get_fill_type() const;
    LineType get_line_type() const;

    bool get_quad_as_tri() const;

    ZInterp get_z_interp() const;

    py::sequence filled(double lower_level, double upper_level);
    py::sequence lines(double level);

    static bool supports_fill_type(FillType fill_type);
    static bool supports_line_type(LineType line_type);

    void write_cache() const;  // For debug purposes only.

protected:
    BaseContourGenerator(
        const CoordinateArray& x, const CoordinateArray& y, const CoordinateArray& z,
        const MaskArray& mask, bool corner_mask, LineType line_type, FillType fill_type,
        bool quad_as_tri, ZInterp z_interp, index_t x_chunk_size, index_t y_chunk_size);

    typedef uint32_t CacheItem;
    typedef CacheItem ZLevel;

    // C++11 scoped enum for direction of movement from one quad to the next.
    enum class Direction
    {
        Left = 1,
        Straight = 0,
        Right = -1
    };

    struct Location
    {
        Location(index_t quad_, index_t forward_, index_t left_, bool is_upper_, bool on_boundary_)
            : quad(quad_), forward(forward_), left(left_), is_upper(is_upper_),
              on_boundary(on_boundary_)
        {}

        friend std::ostream &operator<<(std::ostream &os, const Location& location)
        {
            os << "quad=" << location.quad << " forward=" << location.forward << " left="
                << location.left << " is_upper=" << location.is_upper << " on_boundary="
                << location.on_boundary;
            return os;
        }

        index_t quad, forward, left;
        bool is_upper, on_boundary;
    };

    // Calculate, set and return z-level at middle of quad.
    ZLevel calc_and_set_middle_z_level(index_t quad);

    // Calculate and return z at middle of quad.
    double calc_middle_z(index_t quad) const;

    void closed_line(const Location& start_location, OuterOrHole outer_or_hole, ChunkLocal& local);

    void closed_line_wrapper(
        const Location& start_location, OuterOrHole outer_or_hole, ChunkLocal& local);

    // If point/line/hole counts not consistent, throw runtime error.
    void check_consistent_counts(const ChunkLocal& local) const;

    index_t find_look_S(index_t look_N_quad) const;

    // Return true if finished (i.e. back to start quad, direction and upper).
    bool follow_boundary(
        Location& location, const Location& start_location, ChunkLocal& local,
        count_t& point_count);

    // Return true if finished (i.e. back to start quad, direction and upper).
    bool follow_interior(
        Location& location, const Location& start_location, ChunkLocal& local,
        count_t& point_count);

    index_t get_boundary_start_point(const Location& location) const;

    // These are quad chunk limits, not point chunk limits.
    // chunk is index in range 0.._n_chunks-1.
    void get_chunk_limits(index_t chunk, ChunkLocal& local) const;

    index_t get_interior_start_left_point(
        const Location& location, bool& start_corner_diagonal) const;

    double get_interp_fraction(double z0, double z1, double level) const;

    double get_middle_x(index_t quad) const;
    double get_middle_y(index_t quad) const;

    index_t get_n_chunks() const;

    void get_point_xy(index_t point, double*& points) const;

    double get_point_x(index_t point) const;
    double get_point_y(index_t point) const;
    double get_point_z(index_t point) const;

    bool has_direct_line_offsets() const;
    bool has_direct_outer_offsets() const;
    bool has_direct_points() const;

    void init_cache_grid(const MaskArray& mask);

    // Either for a single chunk, or the whole domain (all chunks) if local == nullptr.
    void init_cache_levels_and_starts(const ChunkLocal* local = nullptr);

    // Increments local.points twice.
    void interp(index_t point0, index_t point1, bool is_upper, double*& points) const;

    // Increments local.points twice.
    void interp(
        index_t point0, double x1, double y1, double z1, bool is_upper, double*& points) const;

    bool is_filled() const;

    bool is_point_in_chunk(index_t point, const ChunkLocal& local) const;

    bool is_quad_in_bounds(
        index_t quad, index_t istart, index_t iend, index_t jstart, index_t jend) const;

    bool is_quad_in_chunk(index_t quad, const ChunkLocal& local) const;

    void line(const Location& start_location, ChunkLocal& local);

    void march_chunk(ChunkLocal& local, std::vector<py::list>& return_lists);

    py::sequence march_wrapper();

    void move_to_next_boundary_edge(index_t& quad, index_t& forward, index_t& left) const;

    void set_look_flags(index_t hole_start_quad);

    void write_cache_quad(index_t quad) const;

    ZLevel z_to_zlevel(double z_value) const;


private:
    const CoordinateArray _x, _y, _z;
    const double* _xptr;                   // For quick access to _x.data().
    const double* _yptr;
    const double* _zptr;
    const index_t _nx, _ny;                // Number of points in each direction.
    const index_t _n;                      // Total number of points (and quads).
    const index_t _x_chunk_size, _y_chunk_size;
    const index_t _nx_chunks, _ny_chunks;  // Number of chunks in each direction.
    const index_t _n_chunks;               // Total number of chunks.
    const bool _corner_mask;
    const LineType _line_type;
    const FillType _fill_type;
    const bool _quad_as_tri;
    const ZInterp _z_interp;

    CacheItem* _cache;

    // Current contouring operation.
    bool _filled;
    double _lower_level, _upper_level;

    // Current contouring operation, based on return type and filled or lines.
    bool _identify_holes;
    bool _output_chunked;             // Implies empty chunks will have py::none().
    bool _direct_points;              // Whether points array is written direct to Python.
    bool _direct_line_offsets;        // Whether line offsets array is written direct to Python.
    bool _direct_outer_offsets;       // Whether outer offsets array is written direct to Python.
    bool _outer_offsets_into_points;  // Otherwise into line offsets.  Only used if _identify_holes.
    bool _nan_separated;              // Whether adjacent lines' points are separated by nans.
    unsigned int _return_list_count;
};

} // namespace contourpy

#endif // CONTOURPY_BASE_H