/src/gdal/ogr/ogrsf_frmts/flatgeobuf/geometrywriter.cpp
Line | Count | Source |
1 | | /****************************************************************************** |
2 | | * |
3 | | * Project: FlatGeobuf driver |
4 | | * Purpose: Implements GeometryWriter class. |
5 | | * Author: Björn Harrtell <bjorn at wololo dot org> |
6 | | * |
7 | | ****************************************************************************** |
8 | | * Copyright (c) 2018-2019, Björn Harrtell <bjorn at wololo dot org> |
9 | | * |
10 | | * SPDX-License-Identifier: MIT |
11 | | ****************************************************************************/ |
12 | | |
13 | | #include "geometrywriter.h" |
14 | | |
15 | | using namespace flatbuffers; |
16 | | using namespace FlatGeobuf; |
17 | | using namespace ogr_flatgeobuf; |
18 | | |
19 | | GeometryType |
20 | | GeometryWriter::translateOGRwkbGeometryType(const OGRwkbGeometryType eGType) |
21 | 348 | { |
22 | 348 | const auto flatType = wkbFlatten(eGType); |
23 | 348 | GeometryType geometryType = GeometryType::Unknown; |
24 | 348 | if (flatType <= 17) |
25 | 297 | geometryType = (GeometryType)flatType; |
26 | 348 | return geometryType; |
27 | 348 | } |
28 | | |
29 | | void GeometryWriter::writePoint(const OGRPoint *p) |
30 | 187 | { |
31 | 187 | m_xy.push_back(p->getX()); |
32 | 187 | m_xy.push_back(p->getY()); |
33 | 187 | if (m_hasZ) |
34 | 0 | m_z.push_back(p->getZ()); |
35 | 187 | if (m_hasM) |
36 | 0 | m_m.push_back(p->getM()); |
37 | 187 | } |
38 | | |
39 | | void GeometryWriter::writeMultiPoint(const OGRMultiPoint *mp) |
40 | 0 | { |
41 | 0 | for (const auto part : *mp) |
42 | 0 | if (!part->IsEmpty()) |
43 | 0 | writePoint(part); |
44 | 0 | } |
45 | | |
46 | | uint32_t GeometryWriter::writeSimpleCurve(const OGRSimpleCurve *sc) |
47 | 40 | { |
48 | 40 | uint32_t numPoints = sc->getNumPoints(); |
49 | 40 | const auto xyLength = m_xy.size(); |
50 | 40 | m_xy.resize(xyLength + (numPoints * 2)); |
51 | 40 | const auto zLength = m_z.size(); |
52 | 40 | double *padfZOut = nullptr; |
53 | 40 | if (m_hasZ) |
54 | 0 | { |
55 | 0 | m_z.resize(zLength + numPoints); |
56 | 0 | padfZOut = m_z.data() + zLength; |
57 | 0 | } |
58 | 40 | const auto mLength = m_m.size(); |
59 | 40 | double *padfMOut = nullptr; |
60 | 40 | if (m_hasM) |
61 | 0 | { |
62 | 0 | m_m.resize(mLength + numPoints); |
63 | 0 | padfMOut = m_m.data() + mLength; |
64 | 0 | } |
65 | 40 | sc->getPoints(reinterpret_cast<double *>( |
66 | 40 | reinterpret_cast<OGRRawPoint *>(m_xy.data() + xyLength)), |
67 | 40 | sizeof(OGRRawPoint), |
68 | 40 | reinterpret_cast<double *>( |
69 | 40 | reinterpret_cast<OGRRawPoint *>(m_xy.data() + xyLength)) + |
70 | 40 | 1, |
71 | 40 | sizeof(OGRRawPoint), padfZOut, sizeof(double), padfMOut, |
72 | 40 | sizeof(double)); |
73 | 40 | return numPoints; |
74 | 40 | } |
75 | | |
76 | | void GeometryWriter::writeMultiLineString(const OGRMultiLineString *mls) |
77 | 0 | { |
78 | 0 | uint32_t e = 0; |
79 | 0 | for (const auto part : *mls) |
80 | 0 | if (!part->IsEmpty()) |
81 | 0 | m_ends.push_back(e += writeSimpleCurve(part)); |
82 | 0 | } |
83 | | |
84 | | void GeometryWriter::writePolygon(const OGRPolygon *p) |
85 | 0 | { |
86 | 0 | const auto exteriorRing = p->getExteriorRing(); |
87 | 0 | const auto numInteriorRings = p->getNumInteriorRings(); |
88 | 0 | uint32_t e = writeSimpleCurve(exteriorRing); |
89 | | // NOTE: should not write ends if only exterior ring |
90 | 0 | if (numInteriorRings > 0) |
91 | 0 | { |
92 | 0 | m_ends.push_back(e); |
93 | 0 | for (int i = 0; i < numInteriorRings; i++) |
94 | 0 | m_ends.push_back(e += writeSimpleCurve(p->getInteriorRing(i))); |
95 | 0 | } |
96 | 0 | } |
97 | | |
98 | | const Offset<Geometry> |
99 | | GeometryWriter::writeMultiPolygon(const OGRMultiPolygon *mp, int depth) |
100 | 0 | { |
101 | 0 | std::vector<Offset<Geometry>> parts; |
102 | 0 | for (const auto part : *mp) |
103 | 0 | if (!part->IsEmpty()) |
104 | 0 | parts.push_back(writePart(part, GeometryType::Polygon, depth + 1)); |
105 | 0 | return CreateGeometryDirect(m_fbb, nullptr, nullptr, nullptr, nullptr, |
106 | 0 | nullptr, nullptr, m_geometryType, &parts); |
107 | 0 | } |
108 | | |
109 | | const Offset<Geometry> |
110 | | GeometryWriter::writeGeometryCollection(const OGRGeometryCollection *gc, |
111 | | int depth) |
112 | 0 | { |
113 | 0 | std::vector<Offset<Geometry>> parts; |
114 | 0 | for (const auto part : *gc) |
115 | 0 | if (!part->IsEmpty()) |
116 | 0 | parts.push_back(writePart(part, depth + 1)); |
117 | 0 | return CreateGeometryDirect(m_fbb, nullptr, nullptr, nullptr, nullptr, |
118 | 0 | nullptr, nullptr, m_geometryType, &parts); |
119 | 0 | } |
120 | | |
121 | | const Offset<Geometry> |
122 | | GeometryWriter::writeCompoundCurve(const OGRCompoundCurve *cc, int depth) |
123 | 0 | { |
124 | 0 | std::vector<Offset<Geometry>> parts; |
125 | 0 | for (const auto curve : *cc) |
126 | 0 | parts.push_back(writePart(curve, depth + 1)); |
127 | 0 | return CreateGeometryDirect(m_fbb, nullptr, nullptr, nullptr, nullptr, |
128 | 0 | nullptr, nullptr, m_geometryType, &parts); |
129 | 0 | } |
130 | | |
131 | | const Offset<Geometry> |
132 | | GeometryWriter::writeCurvePolygon(const OGRCurvePolygon *cp, int depth) |
133 | 0 | { |
134 | 0 | std::vector<Offset<Geometry>> parts; |
135 | 0 | for (const auto curve : *cp) |
136 | 0 | parts.push_back(writePart(curve, depth + 1)); |
137 | 0 | return CreateGeometryDirect(m_fbb, nullptr, nullptr, nullptr, nullptr, |
138 | 0 | nullptr, nullptr, m_geometryType, &parts); |
139 | 0 | } |
140 | | |
141 | | const Offset<Geometry> |
142 | | GeometryWriter::writePolyhedralSurface(const OGRPolyhedralSurface *p, int depth) |
143 | 0 | { |
144 | 0 | std::vector<Offset<Geometry>> parts; |
145 | 0 | for (const auto part : *p) |
146 | 0 | parts.push_back(writePart(part, depth + 1)); |
147 | 0 | return CreateGeometryDirect(m_fbb, nullptr, nullptr, nullptr, nullptr, |
148 | 0 | nullptr, nullptr, m_geometryType, &parts); |
149 | 0 | } |
150 | | |
151 | | void GeometryWriter::writeTIN(const OGRTriangulatedSurface *ts) |
152 | 0 | { |
153 | 0 | const auto numGeometries = ts->getNumGeometries(); |
154 | 0 | if (numGeometries == 1) |
155 | 0 | return (void)writeSimpleCurve(ts->getGeometryRef(0)->getExteriorRing()); |
156 | 0 | uint32_t e = 0; |
157 | 0 | for (const auto part : *ts) |
158 | 0 | m_ends.push_back(e += writeSimpleCurve(part->getExteriorRing())); |
159 | 0 | } |
160 | | |
161 | | const Offset<Geometry> GeometryWriter::write(int depth) |
162 | 227 | { |
163 | 227 | bool unknownGeometryType = false; |
164 | 227 | if (depth == 0 && m_geometryType == GeometryType::Unknown) |
165 | 227 | { |
166 | 227 | m_geometryType = |
167 | 227 | translateOGRwkbGeometryType(m_ogrGeometry->getGeometryType()); |
168 | 227 | unknownGeometryType = true; |
169 | 227 | } |
170 | 227 | switch (m_geometryType) |
171 | 227 | { |
172 | 187 | case GeometryType::Point: |
173 | 187 | writePoint(m_ogrGeometry->toPoint()); |
174 | 187 | break; |
175 | 0 | case GeometryType::MultiPoint: |
176 | 0 | writeMultiPoint(m_ogrGeometry->toMultiPoint()); |
177 | 0 | break; |
178 | 4 | case GeometryType::LineString: |
179 | 4 | writeSimpleCurve(m_ogrGeometry->toLineString()); |
180 | 4 | break; |
181 | 0 | case GeometryType::MultiLineString: |
182 | 0 | writeMultiLineString(m_ogrGeometry->toMultiLineString()); |
183 | 0 | break; |
184 | 0 | case GeometryType::Polygon: |
185 | 0 | writePolygon(m_ogrGeometry->toPolygon()); |
186 | 0 | break; |
187 | 0 | case GeometryType::MultiPolygon: |
188 | 0 | return writeMultiPolygon(m_ogrGeometry->toMultiPolygon(), depth); |
189 | 0 | case GeometryType::GeometryCollection: |
190 | 0 | return writeGeometryCollection( |
191 | 0 | m_ogrGeometry->toGeometryCollection(), depth); |
192 | 36 | case GeometryType::CircularString: |
193 | 36 | writeSimpleCurve(m_ogrGeometry->toCircularString()); |
194 | 36 | break; |
195 | 0 | case GeometryType::CompoundCurve: |
196 | 0 | return writeCompoundCurve(m_ogrGeometry->toCompoundCurve(), depth); |
197 | 0 | case GeometryType::CurvePolygon: |
198 | 0 | return writeCurvePolygon(m_ogrGeometry->toCurvePolygon(), depth); |
199 | 0 | case GeometryType::MultiCurve: |
200 | 0 | return writeGeometryCollection(m_ogrGeometry->toMultiCurve(), |
201 | 0 | depth); |
202 | 0 | case GeometryType::MultiSurface: |
203 | 0 | return writeGeometryCollection(m_ogrGeometry->toMultiSurface(), |
204 | 0 | depth); |
205 | 0 | case GeometryType::PolyhedralSurface: |
206 | 0 | return writePolyhedralSurface(m_ogrGeometry->toPolyhedralSurface(), |
207 | 0 | depth); |
208 | 0 | case GeometryType::Triangle: |
209 | 0 | writePolygon(m_ogrGeometry->toTriangle()); |
210 | 0 | break; |
211 | 0 | case GeometryType::TIN: |
212 | 0 | writeTIN(m_ogrGeometry->toTriangulatedSurface()); |
213 | 0 | break; |
214 | 0 | default: |
215 | 0 | CPLError(CE_Failure, CPLE_AppDefined, |
216 | 0 | "GeometryWriter::write: Unknown type %d", |
217 | 0 | (int)m_geometryType); |
218 | 0 | return 0; |
219 | 227 | } |
220 | 227 | const auto pEnds = m_ends.empty() ? nullptr : &m_ends; |
221 | 227 | const auto pXy = m_xy.empty() ? nullptr : &m_xy; |
222 | 227 | const auto pZ = m_z.empty() ? nullptr : &m_z; |
223 | 227 | const auto pM = m_m.empty() ? nullptr : &m_m; |
224 | 227 | const auto geometryType = depth > 0 || unknownGeometryType |
225 | 227 | ? m_geometryType |
226 | 227 | : GeometryType::Unknown; |
227 | 227 | return FlatGeobuf::CreateGeometryDirect(m_fbb, pEnds, pXy, pZ, pM, nullptr, |
228 | 227 | nullptr, geometryType); |
229 | 227 | } |