double OsmAnd::Utilities::parseLength(const QString& value, double defValue, bool* wasParsed/* = nullptr*/) { int first, last; if (wasParsed) *wasParsed = false; if (!extractFirstNumberPosition(value, first, last, false, true)) return defValue; bool ok; auto result = value.midRef(first, last - first + 1).toDouble(&ok); if (!ok) return defValue; if (wasParsed) *wasParsed = true; if (value.contains(QLatin1String("ft")) || value.contains('"')) result *= 0.3048; if (value.contains('\'')) { auto inchesSubstr = value.mid(value.indexOf('"') + 1); if (!extractFirstNumberPosition(inchesSubstr, first, last, false, true)) { if (wasParsed) *wasParsed = false; return defValue; } bool ok; auto inches = inchesSubstr.midRef(first, last - first + 1).toDouble(&ok); if (ok) result += inches * 0.0254; } return result; }
bool OsmAnd::MapStyleEvaluator_P::evaluate( const MapObject* const mapObject, const std::shared_ptr<const IMapStyle::IRuleNode>& ruleNode, const std::shared_ptr<const InputValues>& inputValues, bool& outDisabled, IntermediateEvaluationResult* const outResultStorage, OnDemand<IntermediateEvaluationResult>& constantEvaluationResult) const { // Check all values of a rule until all are checked. const auto& ruleNodeValues = ruleNode->getValuesRef(); for (const auto& ruleValueEntry : rangeOf(constOf(ruleNodeValues))) { const auto valueDefId = ruleValueEntry.key(); const auto& valueDef = owner->mapStyle->getValueDefinitionRefById(valueDefId); // Test only input values if (valueDef->valueClass != MapStyleValueDefinition::Class::Input) continue; const auto constantRuleValue = evaluateConstantValue( mapObject, valueDef->dataType, ruleValueEntry.value(), inputValues, constantEvaluationResult); InputValue inputValue; inputValues->get(valueDefId, inputValue); bool evaluationResult = false; if (valueDefId == _builtinValueDefs->id_INPUT_MINZOOM) { assert(!constantRuleValue.isComplex); evaluationResult = (constantRuleValue.asSimple.asInt <= inputValue.asInt); } else if (valueDefId == _builtinValueDefs->id_INPUT_MAXZOOM) { assert(!constantRuleValue.isComplex); evaluationResult = (constantRuleValue.asSimple.asInt >= inputValue.asInt); } else if (valueDefId == _builtinValueDefs->id_INPUT_ADDITIONAL) { if (!mapObject) evaluationResult = true; else { assert(!constantRuleValue.isComplex); const auto valueString = owner->mapStyle->getStringById(constantRuleValue.asSimple.asUInt); auto equalSignIdx = valueString.indexOf(QLatin1Char('=')); if (equalSignIdx >= 0) { const auto& tagRef = valueString.midRef(0, equalSignIdx); const auto& valueRef = valueString.midRef(equalSignIdx + 1); evaluationResult = mapObject->containsAttribute(tagRef, valueRef, true); } else evaluationResult = mapObject->containsTag(valueString, true); } } else if (valueDefId == _builtinValueDefs->id_INPUT_TEST) { evaluationResult = (inputValue.asInt == 1); } else if (valueDef->dataType == MapStyleValueDataType::Float) { const auto lvalue = constantRuleValue.isComplex ? constantRuleValue.asComplex.asFloat.evaluate(owner->ptScaleFactor) : constantRuleValue.asSimple.asFloat; evaluationResult = qFuzzyCompare(lvalue, inputValue.asFloat); } else { const auto lvalue = constantRuleValue.isComplex ? constantRuleValue.asComplex.asInt.evaluate(owner->ptScaleFactor) : constantRuleValue.asSimple.asInt; evaluationResult = (lvalue == inputValue.asInt); } // If at least one value of rule does not match, it's failure if (!evaluationResult) return false; } // In case rule sets "disable", stop processing const auto citDisabledValue = ruleNodeValues.constFind(_builtinValueDefs->id_OUTPUT_DISABLE); if (citDisabledValue != ruleNodeValues.cend()) { const auto disableValue = evaluateConstantValue( mapObject, _builtinValueDefs->OUTPUT_DISABLE->dataType, *citDisabledValue, inputValues, constantEvaluationResult); assert(!disableValue.isComplex); if (disableValue.asSimple.asUInt != 0) { outDisabled = true; return false; } } if (outResultStorage && !ruleNode->getIsSwitch()) fillResultFromRuleNode(ruleNode, *outResultStorage, true); bool atLeastOneConditionalMatched = false; const auto& oneOfConditionalSubnodes = ruleNode->getOneOfConditionalSubnodesRef(); for (const auto& oneOfConditionalSubnode : constOf(oneOfConditionalSubnodes)) { const auto evaluationResult = evaluate( mapObject, oneOfConditionalSubnode, inputValues, outDisabled, outResultStorage, constantEvaluationResult); if (evaluationResult) { atLeastOneConditionalMatched = true; break; } } if (!atLeastOneConditionalMatched && ruleNode->getIsSwitch()) return false; if (outResultStorage && ruleNode->getIsSwitch()) { // Fill values from <switch> keeping values previously set by <case> fillResultFromRuleNode(ruleNode, *outResultStorage, false); } const auto& applySubnodes = ruleNode->getApplySubnodesRef(); for (const auto& applySubnode : constOf(applySubnodes)) { evaluate( mapObject, applySubnode, inputValues, outDisabled, outResultStorage, constantEvaluationResult); } if (outDisabled) return false; return true; }