Coverage Report

Created: 2025-12-03 08:24

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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
}