File indexing completed on 2025-07-06 04:18:04
0001 /* 0002 SPDX-FileCopyrightText: 2020 Volker Krause <vkrause@kde.org> 0003 0004 SPDX-License-Identifier: LGPL-2.0-or-later 0005 */ 0006 0007 #include "penwidthutil_p.h" 0008 #include "logging.h" 0009 #include "style/mapcssdeclaration_p.h" 0010 0011 #include <cmath> 0012 0013 using namespace KOSMIndoorMap; 0014 0015 struct { 0016 const char* unit; 0017 double factor; 0018 } static constexpr const unit_conversion_table[] = { 0019 { "cm", 0.01 }, 0020 { "ft", 0.3048 }, 0021 }; 0022 0023 double PenWidthUtil::penWidth(OSM::Element e, const MapCSSDeclaration *decl, Unit &unit) 0024 { 0025 // literal value, possibly with a unit 0026 if (decl->keyValue().isEmpty()) { 0027 if (decl->unit() != MapCSSDeclaration::NoUnit) { 0028 unit = decl->unit() == MapCSSDeclaration::Meters ? Unit::Meter : Unit::Pixel; 0029 } 0030 return decl->doubleValue(); 0031 } 0032 0033 // referenced value from a tag value 0034 // see https://wiki.openstreetmap.org/wiki/Map_Features/Units 0035 double unitConversionFactor = 1.0; 0036 double num = NAN; 0037 0038 const auto value = e.tagValue(decl->keyValue().constData()).constData(); 0039 const auto valueLen = std::strlen(value); 0040 const auto valueEnd = value + valueLen; 0041 const char* it = value; 0042 0043 while (it < valueEnd) { 0044 char* numEnd; 0045 num = std::isnan(num) ? std::strtod(it, &numEnd) : std::max(num, std::strtod(it, &numEnd)); 0046 if (it == numEnd) { 0047 break; 0048 } 0049 it = numEnd; 0050 0051 while (it != valueEnd && std::isspace(static_cast<unsigned char>(*it))) { 0052 ++it; 0053 } 0054 0055 // there is an explicit unit suffix; 0056 for (const auto &unit : unit_conversion_table) { 0057 const auto unitLen = std::strlen(unit.unit); 0058 if (std::strncmp(it, unit.unit, unitLen) == 0) { 0059 unitConversionFactor = unit.factor; 0060 it += unitLen; 0061 break; 0062 } 0063 } 0064 0065 if (it != valueEnd && (*it) == ';') { 0066 ++it; 0067 continue; 0068 } 0069 break; 0070 } 0071 0072 if (std::isnan(num)) { 0073 qCDebug(Log) << "Failed to parse width from tag value:" << value << decl->keyValue() << e.url(); 0074 return 0.0; 0075 } 0076 0077 // no explicit unit, use default unit for this tag 0078 if (it == value + valueLen) { 0079 if (std::strcmp(decl->keyValue().constData(), "gauge") == 0) { 0080 unitConversionFactor = 0.001; 0081 } 0082 } 0083 0084 unit = Unit::Meter; 0085 return num * unitConversionFactor; 0086 }