Coverage Report

Created: 2026-08-14 09:29

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
378
{
22
378
    const auto flatType = wkbFlatten(eGType);
23
378
    GeometryType geometryType = GeometryType::Unknown;
24
378
    if (flatType <= 17)
25
339
        geometryType = (GeometryType)flatType;
26
378
    return geometryType;
27
378
}
28
29
void GeometryWriter::writePoint(const OGRPoint *p)
30
181
{
31
181
    m_xy.push_back(p->getX());
32
181
    m_xy.push_back(p->getY());
33
181
    if (m_hasZ)
34
0
        m_z.push_back(p->getZ());
35
181
    if (m_hasM)
36
0
        m_m.push_back(p->getM());
37
181
}
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
79
{
48
79
    uint32_t numPoints = sc->getNumPoints();
49
79
    const auto xyLength = m_xy.size();
50
79
    m_xy.resize(xyLength + (numPoints * 2));
51
79
    const auto zLength = m_z.size();
52
79
    double *padfZOut = nullptr;
53
79
    if (m_hasZ)
54
0
    {
55
0
        m_z.resize(zLength + numPoints);
56
0
        padfZOut = m_z.data() + zLength;
57
0
    }
58
79
    const auto mLength = m_m.size();
59
79
    double *padfMOut = nullptr;
60
79
    if (m_hasM)
61
0
    {
62
0
        m_m.resize(mLength + numPoints);
63
0
        padfMOut = m_m.data() + mLength;
64
0
    }
65
79
    sc->getPoints(reinterpret_cast<double *>(
66
79
                      reinterpret_cast<OGRRawPoint *>(m_xy.data() + xyLength)),
67
79
                  sizeof(OGRRawPoint),
68
79
                  reinterpret_cast<double *>(
69
79
                      reinterpret_cast<OGRRawPoint *>(m_xy.data() + xyLength)) +
70
79
                      1,
71
79
                  sizeof(OGRRawPoint), padfZOut, sizeof(double), padfMOut,
72
79
                  sizeof(double));
73
79
    return numPoints;
74
79
}
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
260
{
163
260
    bool unknownGeometryType = false;
164
260
    if (depth == 0 && m_geometryType == GeometryType::Unknown)
165
260
    {
166
260
        m_geometryType =
167
260
            translateOGRwkbGeometryType(m_ogrGeometry->getGeometryType());
168
260
        unknownGeometryType = true;
169
260
    }
170
260
    switch (m_geometryType)
171
260
    {
172
181
        case GeometryType::Point:
173
181
            writePoint(m_ogrGeometry->toPoint());
174
181
            break;
175
0
        case GeometryType::MultiPoint:
176
0
            writeMultiPoint(m_ogrGeometry->toMultiPoint());
177
0
            break;
178
8
        case GeometryType::LineString:
179
8
            writeSimpleCurve(m_ogrGeometry->toLineString());
180
8
            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
71
        case GeometryType::CircularString:
193
71
            writeSimpleCurve(m_ogrGeometry->toCircularString());
194
71
            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
260
    }
220
260
    const auto pEnds = m_ends.empty() ? nullptr : &m_ends;
221
260
    const auto pXy = m_xy.empty() ? nullptr : &m_xy;
222
260
    const auto pZ = m_z.empty() ? nullptr : &m_z;
223
260
    const auto pM = m_m.empty() ? nullptr : &m_m;
224
260
    const auto geometryType = depth > 0 || unknownGeometryType
225
260
                                  ? m_geometryType
226
260
                                  : GeometryType::Unknown;
227
260
    return FlatGeobuf::CreateGeometryDirect(m_fbb, pEnds, pXy, pZ, pM, nullptr,
228
260
                                            nullptr, geometryType);
229
260
}