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 : * Permission is hereby granted, free of charge, to any person obtaining a
11 : * copy of this software and associated documentation files (the "Software"),
12 : * to deal in the Software without restriction, including without limitation
13 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
14 : * and/or sell copies of the Software, and to permit persons to whom the
15 : * Software is furnished to do so, subject to the following conditions:
16 : *
17 : * The above copyright notice and this permission notice shall be included
18 : * in all copies or substantial portions of the Software.
19 : *
20 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
21 : * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
23 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
25 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
26 : * DEALINGS IN THE SOFTWARE.
27 : ****************************************************************************/
28 :
29 : #include "geometrywriter.h"
30 :
31 : using namespace flatbuffers;
32 : using namespace FlatGeobuf;
33 : using namespace ogr_flatgeobuf;
34 :
35 : GeometryType
36 249 : GeometryWriter::translateOGRwkbGeometryType(const OGRwkbGeometryType eGType)
37 : {
38 249 : const auto flatType = wkbFlatten(eGType);
39 249 : GeometryType geometryType = GeometryType::Unknown;
40 249 : if (flatType <= 17)
41 247 : geometryType = (GeometryType)flatType;
42 249 : return geometryType;
43 : }
44 :
45 115 : void GeometryWriter::writePoint(const OGRPoint *p)
46 : {
47 115 : m_xy.push_back(p->getX());
48 115 : m_xy.push_back(p->getY());
49 115 : if (m_hasZ)
50 25 : m_z.push_back(p->getZ());
51 115 : if (m_hasM)
52 22 : m_m.push_back(p->getM());
53 115 : }
54 :
55 9 : void GeometryWriter::writeMultiPoint(const OGRMultiPoint *mp)
56 : {
57 33 : for (const auto part : *mp)
58 24 : if (!part->IsEmpty())
59 23 : writePoint(part);
60 9 : }
61 :
62 176 : uint32_t GeometryWriter::writeSimpleCurve(const OGRSimpleCurve *sc)
63 : {
64 176 : uint32_t numPoints = sc->getNumPoints();
65 176 : const auto xyLength = m_xy.size();
66 176 : m_xy.resize(xyLength + (numPoints * 2));
67 176 : const auto zLength = m_z.size();
68 176 : double *padfZOut = nullptr;
69 176 : if (m_hasZ)
70 : {
71 73 : m_z.resize(zLength + numPoints);
72 73 : padfZOut = m_z.data() + zLength;
73 : }
74 176 : const auto mLength = m_m.size();
75 176 : double *padfMOut = nullptr;
76 176 : if (m_hasM)
77 : {
78 58 : m_m.resize(mLength + numPoints);
79 58 : padfMOut = m_m.data() + mLength;
80 : }
81 176 : sc->getPoints(reinterpret_cast<double *>(
82 176 : reinterpret_cast<OGRRawPoint *>(m_xy.data() + xyLength)),
83 : sizeof(OGRRawPoint),
84 : reinterpret_cast<double *>(
85 176 : reinterpret_cast<OGRRawPoint *>(m_xy.data() + xyLength)) +
86 : 1,
87 : sizeof(OGRRawPoint), padfZOut, sizeof(double), padfMOut,
88 : sizeof(double));
89 176 : return numPoints;
90 : }
91 :
92 13 : void GeometryWriter::writeMultiLineString(const OGRMultiLineString *mls)
93 : {
94 13 : uint32_t e = 0;
95 37 : for (const auto part : *mls)
96 24 : if (!part->IsEmpty())
97 23 : m_ends.push_back(e += writeSimpleCurve(part));
98 13 : }
99 :
100 78 : void GeometryWriter::writePolygon(const OGRPolygon *p)
101 : {
102 78 : const auto exteriorRing = p->getExteriorRing();
103 78 : const auto numInteriorRings = p->getNumInteriorRings();
104 78 : uint32_t e = writeSimpleCurve(exteriorRing);
105 : // NOTE: should not write ends if only exterior ring
106 78 : if (numInteriorRings > 0)
107 : {
108 16 : m_ends.push_back(e);
109 32 : for (int i = 0; i < numInteriorRings; i++)
110 16 : m_ends.push_back(e += writeSimpleCurve(p->getInteriorRing(i)));
111 : }
112 78 : }
113 :
114 : const Offset<Geometry>
115 21 : GeometryWriter::writeMultiPolygon(const OGRMultiPolygon *mp, int depth)
116 : {
117 42 : std::vector<Offset<Geometry>> parts;
118 55 : for (const auto part : *mp)
119 34 : if (!part->IsEmpty())
120 33 : parts.push_back(writePart(part, GeometryType::Polygon, depth + 1));
121 : return CreateGeometryDirect(m_fbb, nullptr, nullptr, nullptr, nullptr,
122 42 : nullptr, nullptr, m_geometryType, &parts);
123 : }
124 :
125 : const Offset<Geometry>
126 23 : GeometryWriter::writeGeometryCollection(const OGRGeometryCollection *gc,
127 : int depth)
128 : {
129 46 : std::vector<Offset<Geometry>> parts;
130 71 : for (const auto part : *gc)
131 48 : if (!part->IsEmpty())
132 47 : parts.push_back(writePart(part, depth + 1));
133 : return CreateGeometryDirect(m_fbb, nullptr, nullptr, nullptr, nullptr,
134 46 : nullptr, nullptr, m_geometryType, &parts);
135 : }
136 :
137 : const Offset<Geometry>
138 4 : GeometryWriter::writeCompoundCurve(const OGRCompoundCurve *cc, int depth)
139 : {
140 8 : std::vector<Offset<Geometry>> parts;
141 12 : for (const auto curve : *cc)
142 8 : parts.push_back(writePart(curve, depth + 1));
143 : return CreateGeometryDirect(m_fbb, nullptr, nullptr, nullptr, nullptr,
144 8 : nullptr, nullptr, m_geometryType, &parts);
145 : }
146 :
147 : const Offset<Geometry>
148 8 : GeometryWriter::writeCurvePolygon(const OGRCurvePolygon *cp, int depth)
149 : {
150 16 : std::vector<Offset<Geometry>> parts;
151 24 : for (const auto curve : *cp)
152 16 : parts.push_back(writePart(curve, depth + 1));
153 : return CreateGeometryDirect(m_fbb, nullptr, nullptr, nullptr, nullptr,
154 16 : nullptr, nullptr, m_geometryType, &parts);
155 : }
156 :
157 : const Offset<Geometry>
158 1 : GeometryWriter::writePolyhedralSurface(const OGRPolyhedralSurface *p, int depth)
159 : {
160 2 : std::vector<Offset<Geometry>> parts;
161 7 : for (const auto part : *p)
162 6 : parts.push_back(writePart(part, depth + 1));
163 : return CreateGeometryDirect(m_fbb, nullptr, nullptr, nullptr, nullptr,
164 2 : nullptr, nullptr, m_geometryType, &parts);
165 : }
166 :
167 2 : void GeometryWriter::writeTIN(const OGRTriangulatedSurface *ts)
168 : {
169 2 : const auto numGeometries = ts->getNumGeometries();
170 2 : if (numGeometries == 1)
171 1 : return (void)writeSimpleCurve(ts->getGeometryRef(0)->getExteriorRing());
172 1 : uint32_t e = 0;
173 3 : for (const auto part : *ts)
174 2 : m_ends.push_back(e += writeSimpleCurve(part->getExteriorRing()));
175 : }
176 :
177 307 : const Offset<Geometry> GeometryWriter::write(int depth)
178 : {
179 307 : bool unknownGeometryType = false;
180 307 : if (depth == 0 && m_geometryType == GeometryType::Unknown)
181 : {
182 5 : m_geometryType =
183 5 : translateOGRwkbGeometryType(m_ogrGeometry->getGeometryType());
184 5 : unknownGeometryType = true;
185 : }
186 307 : switch (m_geometryType)
187 : {
188 92 : case GeometryType::Point:
189 92 : writePoint(m_ogrGeometry->toPoint());
190 92 : break;
191 9 : case GeometryType::MultiPoint:
192 9 : writeMultiPoint(m_ogrGeometry->toMultiPoint());
193 9 : break;
194 36 : case GeometryType::LineString:
195 36 : writeSimpleCurve(m_ogrGeometry->toLineString());
196 36 : break;
197 13 : case GeometryType::MultiLineString:
198 13 : writeMultiLineString(m_ogrGeometry->toMultiLineString());
199 13 : break;
200 77 : case GeometryType::Polygon:
201 77 : writePolygon(m_ogrGeometry->toPolygon());
202 77 : break;
203 21 : case GeometryType::MultiPolygon:
204 21 : return writeMultiPolygon(m_ogrGeometry->toMultiPolygon(), depth);
205 15 : case GeometryType::GeometryCollection:
206 : return writeGeometryCollection(
207 15 : m_ogrGeometry->toGeometryCollection(), depth);
208 20 : case GeometryType::CircularString:
209 20 : writeSimpleCurve(m_ogrGeometry->toCircularString());
210 20 : break;
211 4 : case GeometryType::CompoundCurve:
212 4 : return writeCompoundCurve(m_ogrGeometry->toCompoundCurve(), depth);
213 8 : case GeometryType::CurvePolygon:
214 8 : return writeCurvePolygon(m_ogrGeometry->toCurvePolygon(), depth);
215 4 : case GeometryType::MultiCurve:
216 4 : return writeGeometryCollection(m_ogrGeometry->toMultiCurve(),
217 4 : depth);
218 4 : case GeometryType::MultiSurface:
219 4 : return writeGeometryCollection(m_ogrGeometry->toMultiSurface(),
220 4 : depth);
221 1 : case GeometryType::PolyhedralSurface:
222 1 : return writePolyhedralSurface(m_ogrGeometry->toPolyhedralSurface(),
223 1 : depth);
224 1 : case GeometryType::Triangle:
225 1 : writePolygon(m_ogrGeometry->toTriangle());
226 1 : break;
227 2 : case GeometryType::TIN:
228 2 : writeTIN(m_ogrGeometry->toTriangulatedSurface());
229 2 : break;
230 0 : default:
231 0 : CPLError(CE_Failure, CPLE_AppDefined,
232 : "GeometryWriter::write: Unknown type %d",
233 0 : (int)m_geometryType);
234 0 : return 0;
235 : }
236 250 : const auto pEnds = m_ends.empty() ? nullptr : &m_ends;
237 250 : const auto pXy = m_xy.empty() ? nullptr : &m_xy;
238 250 : const auto pZ = m_z.empty() ? nullptr : &m_z;
239 250 : const auto pM = m_m.empty() ? nullptr : &m_m;
240 148 : const auto geometryType = depth > 0 || unknownGeometryType
241 398 : ? m_geometryType
242 : : GeometryType::Unknown;
243 : return FlatGeobuf::CreateGeometryDirect(m_fbb, pEnds, pXy, pZ, pM, nullptr,
244 250 : nullptr, geometryType);
245 : }
|