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