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