1 /******************************************************************************
2 *
3 * Project: LV BAG Translator
4 * Purpose: Implements OGRLVBAGDataSource.
5 * Author: Laixer B.V., info at laixer dot com
6 *
7 ******************************************************************************
8 * Copyright (c) 2020, Laixer B.V. <info at laixer dot com>
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 "ogr_lvbag.h"
30 #include "ogrsf_frmts.h"
31 #include "ogrunionlayer.h"
32 #include "ogrlayerpool.h"
33
34 #include <algorithm>
35
36 /************************************************************************/
37 /* OGRLVBAGDataSource() */
38 /************************************************************************/
39
OGRLVBAGDataSource()40 OGRLVBAGDataSource::OGRLVBAGDataSource() :
41 poPool{ new OGRLayerPool{ } },
42 papoLayers{ OGRLVBAG::LayerVector{ } }
43 {
44 const int nMaxSimultaneouslyOpened =
45 std::max(atoi(CPLGetConfigOption("OGR_LVBAG_MAX_OPENED", "100")), 1);
46 if( poPool->GetMaxSimultaneouslyOpened() != nMaxSimultaneouslyOpened )
47 poPool.reset(new OGRLayerPool(nMaxSimultaneouslyOpened));
48 }
49
50 /************************************************************************/
51 /* Open() */
52 /************************************************************************/
53
Open(const char * pszFilename,char ** papszOpenOptionsIn)54 int OGRLVBAGDataSource::Open( const char* pszFilename, char **papszOpenOptionsIn )
55 {
56 auto poLayer = std::unique_ptr<OGRLVBAGLayer>{
57 new OGRLVBAGLayer{ pszFilename, poPool.get(), papszOpenOptionsIn } };
58 if( poLayer && !poLayer->TouchLayer() )
59 return FALSE;
60
61 papoLayers.push_back({ OGRLVBAG::LayerType::LYR_RAW,
62 std::move(poLayer) });
63
64 if( (static_cast<int>(papoLayers.size()) + 1)
65 % poPool->GetMaxSimultaneouslyOpened() == 0
66 && poPool->GetSize() > 0 )
67 TryCoalesceLayers();
68
69 return TRUE;
70 }
71
72 /************************************************************************/
73 /* TryCoalesceLayers() */
74 /************************************************************************/
75
TryCoalesceLayers()76 void OGRLVBAGDataSource::TryCoalesceLayers()
77 {
78 std::vector<int> paGroup = {};
79 std::map<int, std::vector<int>> paMergeVector = {};
80
81 // FUTURE: This can be optimized
82 // Find similar layers by doing a triangular matrix
83 // comparison across all layers currently enlisted.
84 for( size_t i = 0; i < papoLayers.size(); ++i )
85 {
86 std::vector<int> paVector = {};
87 for( size_t j = 0; j < papoLayers.size(); ++j )
88 {
89 // cppcheck-suppress mismatchingContainers
90 if( std::find(paGroup.cbegin(), paGroup.cend(), static_cast<int>(j)) != paGroup.end() )
91 continue;
92
93 OGRLayer *poLayerLHS = papoLayers[i].second.get();
94 OGRLayer *poLayerRHS = papoLayers[j].second.get();
95
96 if( j > i
97 && EQUAL(poLayerLHS->GetName(), poLayerRHS->GetName()) )
98 {
99 if( poLayerLHS->GetGeomType() == poLayerRHS->GetGeomType()
100 && poLayerLHS->GetLayerDefn()->IsSame(
101 poLayerRHS->GetLayerDefn()) )
102 {
103 paVector.push_back(static_cast<int>(j));
104 paGroup.push_back(static_cast<int>(j));
105 }
106 }
107 }
108 if( !paVector.empty() )
109 paMergeVector.insert({ static_cast<int>(i), paVector });
110 }
111
112 if( paMergeVector.empty() )
113 return;
114
115 for( const auto &mergeLayer : paMergeVector )
116 {
117 const int baseLayerIdx = mergeLayer.first;
118 const std::vector<int> papoLayersIdx = mergeLayer.second;
119
120 int nSrcLayers = static_cast<int>(papoLayersIdx.size()) + 1;
121 OGRLayer **papoSrcLayers = static_cast<OGRLayer **>(
122 CPLRealloc(nullptr, sizeof(OGRLayer *) * nSrcLayers ));
123
124 CPLAssert(papoLayers[baseLayerIdx].second);
125
126 int idx = 0;
127 papoSrcLayers[idx++] = papoLayers[baseLayerIdx].second.release();
128 for( const auto &poLayerIdx : papoLayersIdx )
129 papoSrcLayers[idx++] = papoLayers[poLayerIdx].second.release();
130
131 OGRLayer *poBaseLayer = papoSrcLayers[0];
132
133 auto poLayer = std::unique_ptr<OGRUnionLayer>{
134 new OGRUnionLayer{ poBaseLayer->GetName(), nSrcLayers, papoSrcLayers, TRUE } };
135
136 OGRFeatureDefn *poBaseLayerDefn = poBaseLayer->GetLayerDefn();
137
138 const int nFields = poBaseLayerDefn->GetFieldCount();
139 OGRFieldDefn** papoFields = static_cast<OGRFieldDefn **>(
140 CPLRealloc(nullptr, sizeof(OGRFieldDefn *) * nFields ));
141 for( int i = 0; i < nFields; ++i )
142 papoFields[i] = poBaseLayerDefn->GetFieldDefn(i);
143
144 const int nGeomFields = poBaseLayerDefn->GetGeomFieldCount();
145 OGRUnionLayerGeomFieldDefn** papoGeomFields = static_cast<OGRUnionLayerGeomFieldDefn **>(
146 CPLRealloc(nullptr, sizeof(OGRUnionLayerGeomFieldDefn *) * nGeomFields ));
147 for( int i = 0; i < nGeomFields; ++i )
148 papoGeomFields[i] = new OGRUnionLayerGeomFieldDefn(
149 poBaseLayerDefn->GetGeomFieldDefn( i ) );
150
151 poLayer->SetFields(
152 FIELD_FROM_FIRST_LAYER,
153 nFields, papoFields,
154 nGeomFields, papoGeomFields);
155
156 for( int i = 0; i < nGeomFields; ++i )
157 delete papoGeomFields[i];
158 CPLFree(papoGeomFields);
159 CPLFree(papoFields);
160
161 papoLayers.push_back({ OGRLVBAG::LayerType::LYR_RAW,
162 OGRLayerUniquePtr{ poLayer.release() } });
163 }
164
165 // Erase all released pointers
166 auto it = papoLayers.begin();
167 while( it != papoLayers.end() )
168 {
169 if( !it->second )
170 it = papoLayers.erase(it);
171 else
172 ++it;
173 }
174 }
175
176 /************************************************************************/
177 /* GetLayer() */
178 /************************************************************************/
179
GetLayer(int iLayer)180 OGRLayer* OGRLVBAGDataSource::GetLayer( int iLayer )
181 {
182 if( iLayer < 0 || iLayer >= GetLayerCount() )
183 return nullptr;
184 return papoLayers[iLayer].second.get();
185 }
186
187 /************************************************************************/
188 /* GetLayerCount() */
189 /************************************************************************/
190
GetLayerCount()191 int OGRLVBAGDataSource::GetLayerCount()
192 {
193 TryCoalesceLayers();
194 return static_cast<int>(papoLayers.size());
195 }
196
197 /************************************************************************/
198 /* TestCapability() */
199 /************************************************************************/
200
TestCapability(const char *)201 int OGRLVBAGDataSource::TestCapability( const char * /* pszCap */ )
202 {
203 return FALSE;
204 }
205