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