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