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