/src/gdal/alg/polygonize_polygonizer.h
Line | Count | Source |
1 | | /****************************************************************************** |
2 | | * Project: GDAL |
3 | | * Purpose: Implements The Two-Arm Chains EdgeTracing Algorithm |
4 | | * Author: kikitte.lee |
5 | | * |
6 | | ****************************************************************************** |
7 | | * Copyright (c) 2023, kikitte.lee <kikitte.lee@gmail.com> |
8 | | * |
9 | | * SPDX-License-Identifier: MIT |
10 | | ****************************************************************************/ |
11 | | |
12 | | #ifndef POLYGONIZE_POLYGONIZER_H_INCLUDED |
13 | | #define POLYGONIZE_POLYGONIZER_H_INCLUDED |
14 | | |
15 | | /*! @cond Doxygen_Suppress */ |
16 | | |
17 | | // Implements Junhua Teng, Fahui Wang, Yu Liu: An Efficient Algorithm for |
18 | | // Raster-to-Vector Data Conversion: https://doi.org/10.1080/10824000809480639 |
19 | | |
20 | | #include <array> |
21 | | #include <cstdint> |
22 | | #include <vector> |
23 | | #include <limits> |
24 | | #include <map> |
25 | | |
26 | | #include "cpl_error.h" |
27 | | #include "ogr_api.h" |
28 | | #include "ogr_geometry.h" |
29 | | #include "ogrsf_frmts.h" |
30 | | |
31 | | namespace gdal |
32 | | { |
33 | | namespace polygonizer |
34 | | { |
35 | | |
36 | | using IndexType = std::uint32_t; |
37 | | using Point = std::array<IndexType, 2>; |
38 | | using Arc = std::vector<Point>; |
39 | | |
40 | | struct IndexedArc |
41 | | { |
42 | | Arc *poArc; |
43 | | std::size_t iIndex; |
44 | | }; |
45 | | |
46 | | /** |
47 | | * A raster polygon(RPolygon) is formed by a list of arcs in order. |
48 | | * Each arc has two properties: |
49 | | * 1. does the arc follows the right-hand rule respect to the area it bounds |
50 | | * 2. the next arc of the current arc |
51 | | */ |
52 | | struct RPolygon |
53 | | { |
54 | | IndexType iBottomRightRow{0}; |
55 | | IndexType iBottomRightCol{0}; |
56 | | |
57 | | struct ArcStruct |
58 | | { |
59 | | std::unique_ptr<Arc> poArc{}; |
60 | | // each element is the next arc index of the current arc |
61 | | unsigned nConnection = 0; |
62 | | // does arc follows the right-hand rule with |
63 | | bool bFollowRighthand = false; |
64 | | |
65 | | ArcStruct(unsigned nConnectionIn, bool bFollowRighthandIn) |
66 | 0 | : poArc(std::make_unique<Arc>()), nConnection(nConnectionIn), |
67 | 0 | bFollowRighthand(bFollowRighthandIn) |
68 | 0 | { |
69 | 0 | } |
70 | | }; |
71 | | |
72 | | // arc object list |
73 | | std::vector<ArcStruct> oArcs{}; |
74 | | |
75 | 0 | RPolygon() = default; |
76 | | |
77 | | RPolygon(const RPolygon &) = delete; |
78 | | |
79 | | RPolygon &operator=(const RPolygon &) = delete; |
80 | | |
81 | | /** |
82 | | * create a new arc object |
83 | | */ |
84 | | IndexedArc newArc(bool bFollowRighthand); |
85 | | |
86 | | /** |
87 | | * set the next arc index of the current arc |
88 | | */ |
89 | | void setArcConnection(const IndexedArc &oArc, const IndexedArc &oNextArc); |
90 | | |
91 | | /** |
92 | | * update the bottom-right most cell index of the current polygon |
93 | | */ |
94 | | void updateBottomRightPos(IndexType iRow, IndexType iCol); |
95 | | }; |
96 | | |
97 | | /** |
98 | | * Arm class is used to record the tracings of both arcs and polygons. |
99 | | */ |
100 | | struct TwoArm |
101 | | { |
102 | | IndexType iRow{0}; |
103 | | IndexType iCol{0}; |
104 | | |
105 | | RPolygon *poPolyInside{nullptr}; |
106 | | RPolygon *poPolyAbove{nullptr}; |
107 | | RPolygon *poPolyLeft{nullptr}; |
108 | | |
109 | | IndexedArc oArcHorOuter{}; |
110 | | IndexedArc oArcHorInner{}; |
111 | | IndexedArc oArcVerInner{}; |
112 | | IndexedArc oArcVerOuter{}; |
113 | | |
114 | | bool bSolidHorizontal{false}; |
115 | | bool bSolidVertical{false}; |
116 | | }; |
117 | | |
118 | | template <typename DataType> class PolygonReceiver |
119 | | { |
120 | | public: |
121 | 0 | PolygonReceiver() = default; Unexecuted instantiation: gdal::polygonizer::PolygonReceiver<long>::PolygonReceiver() Unexecuted instantiation: gdal::polygonizer::PolygonReceiver<float>::PolygonReceiver() Unexecuted instantiation: gdal::polygonizer::PolygonReceiver<double>::PolygonReceiver() |
122 | | |
123 | | PolygonReceiver(const PolygonReceiver<DataType> &) = delete; |
124 | | |
125 | 0 | virtual ~PolygonReceiver() = default; Unexecuted instantiation: gdal::polygonizer::PolygonReceiver<long>::~PolygonReceiver() Unexecuted instantiation: gdal::polygonizer::PolygonReceiver<float>::~PolygonReceiver() Unexecuted instantiation: gdal::polygonizer::PolygonReceiver<double>::~PolygonReceiver() |
126 | | |
127 | | PolygonReceiver<DataType> & |
128 | | operator=(const PolygonReceiver<DataType> &) = delete; |
129 | | |
130 | | virtual void receive(RPolygon *poPolygon, DataType nPolygonCellValue) = 0; |
131 | | }; |
132 | | |
133 | | /** |
134 | | * Polygonizer is used to manage polygon memory and do the edge tracing process |
135 | | */ |
136 | | template <typename PolyIdType, typename DataType> class Polygonizer |
137 | | { |
138 | | public: |
139 | | static constexpr PolyIdType THE_OUTER_POLYGON_ID = |
140 | | std::numeric_limits<PolyIdType>::max(); |
141 | | |
142 | | private: |
143 | | using PolygonMap = std::map<PolyIdType, RPolygon *>; |
144 | | using PolygonMapEntry = typename PolygonMap::value_type; |
145 | | |
146 | | PolyIdType nInvalidPolyId_; |
147 | | RPolygon *poTheOuterPolygon_{nullptr}; |
148 | | PolygonMap oPolygonMap_{}; |
149 | | |
150 | | PolygonReceiver<DataType> *poPolygonReceiver_; |
151 | | |
152 | | RPolygon *getPolygon(PolyIdType nPolygonId); |
153 | | |
154 | | RPolygon *createPolygon(PolyIdType nPolygonId); |
155 | | |
156 | | void destroyPolygon(PolyIdType nPolygonId); |
157 | | |
158 | | public: |
159 | | explicit Polygonizer(PolyIdType nInvalidPolyId, |
160 | | PolygonReceiver<DataType> *poPolygonReceiver); |
161 | | |
162 | | Polygonizer(const Polygonizer<PolyIdType, DataType> &) = delete; |
163 | | |
164 | | ~Polygonizer(); |
165 | | |
166 | | Polygonizer<PolyIdType, DataType> & |
167 | | operator=(const Polygonizer<PolyIdType, DataType> &) = delete; |
168 | | |
169 | | RPolygon *getTheOuterPolygon() const |
170 | 0 | { |
171 | 0 | return poTheOuterPolygon_; |
172 | 0 | } Unexecuted instantiation: gdal::polygonizer::Polygonizer<int, long>::getTheOuterPolygon() const Unexecuted instantiation: gdal::polygonizer::Polygonizer<int, double>::getTheOuterPolygon() const Unexecuted instantiation: gdal::polygonizer::Polygonizer<int, float>::getTheOuterPolygon() const |
173 | | |
174 | | bool processLine(const PolyIdType *panThisLineId, |
175 | | const DataType *panLastLineVal, TwoArm *poThisLineArm, |
176 | | TwoArm *poLastLineArm, IndexType nCurrentRow, |
177 | | IndexType nCols); |
178 | | }; |
179 | | |
180 | | /** |
181 | | * Write raster polygon object to OGR layer. |
182 | | */ |
183 | | template <typename DataType> |
184 | | class OGRPolygonWriter : public PolygonReceiver<DataType> |
185 | | { |
186 | | OGRLayer *poOutLayer_ = nullptr; |
187 | | GDALDataset *poOutDS_ = nullptr; |
188 | | const int iPixValField_; |
189 | | const GDALGeoTransform gt_; |
190 | | int nCommitInterval_ = 0; |
191 | | GIntBig nFeaturesWrittenInTransaction_ = 0; |
192 | | std::unique_ptr<OGRFeature> poFeature_{}; |
193 | | OGRPolygon *poPolygon_ = |
194 | | nullptr; // = poFeature_->GetGeometryRef(), owned by poFeature |
195 | | |
196 | | CPLErr eErr_{CE_None}; |
197 | | |
198 | | public: |
199 | | OGRPolygonWriter(OGRLayerH hOutLayer, int iPixValField, |
200 | | const GDALGeoTransform >, int nCommitInterval); |
201 | | ~OGRPolygonWriter() override; |
202 | | |
203 | | OGRPolygonWriter(const OGRPolygonWriter<DataType> &) = delete; |
204 | | |
205 | | OGRPolygonWriter<DataType> & |
206 | | operator=(const OGRPolygonWriter<DataType> &) = delete; |
207 | | |
208 | | bool Finalize(); |
209 | | |
210 | | void receive(RPolygon *poPolygon, DataType nPolygonCellValue) override; |
211 | | |
212 | | inline CPLErr getErr() |
213 | 0 | { |
214 | 0 | return eErr_; |
215 | 0 | } Unexecuted instantiation: gdal::polygonizer::OGRPolygonWriter<long>::getErr() Unexecuted instantiation: gdal::polygonizer::OGRPolygonWriter<double>::getErr() Unexecuted instantiation: gdal::polygonizer::OGRPolygonWriter<float>::getErr() |
216 | | }; |
217 | | |
218 | | } // namespace polygonizer |
219 | | } // namespace gdal |
220 | | |
221 | | /*! @endcond */ |
222 | | |
223 | | #endif /* POLYGONIZE_POLYGONIZER_H_INCLUDED */ |