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