| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| |
|
| | #include <QLocale> |
| | #include <QRegularExpression> |
| | #include <QString> |
| |
|
| | #include <fmt/format.h> |
| |
|
| | #include <Base/Console.h> |
| | #include <Base/UnitsApi.h> |
| |
|
| | #include "DrawViewDimension.h" |
| | #include "DimensionFormatter.h" |
| | #include "Preferences.h" |
| |
|
| | |
| |
|
| | using namespace TechDraw; |
| |
|
| | bool DimensionFormatter::isMultiValueSchema() const |
| | { |
| | const bool angularMeasure = |
| | (m_dimension->Type.isValue("Angle") || m_dimension->Type.isValue("Angle3Pt")); |
| |
|
| | return (Base::UnitsApi::isMultiUnitAngle() && angularMeasure) |
| | || (Base::UnitsApi::isMultiUnitLength() && !angularMeasure); |
| | } |
| |
|
| | std::string DimensionFormatter::formatValue(const qreal value, |
| | const QString& qFormatSpec, |
| | const Format partial, |
| | const bool isDim) const |
| | { |
| | bool distanceMeasure{true}; |
| | const bool angularMeasure = |
| | m_dimension->Type.isValue("Angle") || m_dimension->Type.isValue("Angle3Pt"); |
| | const bool areaMeasure = m_dimension->Type.isValue("Area"); |
| |
|
| | Base::Unit unit{Base::Unit::Length}; |
| | if (angularMeasure) { |
| | unit = Base::Unit::Angle; |
| | distanceMeasure = false; |
| | } |
| | else if (areaMeasure) { |
| | unit = Base::Unit::Area; |
| | distanceMeasure = false; |
| | } |
| |
|
| | Base::Quantity asQuantity {value, unit}; |
| |
|
| | QStringList qsl = getPrefixSuffixSpec(qFormatSpec); |
| | const std::string formatPrefix = qsl[0].toStdString(); |
| | const std::string formatSuffix = qsl[1].toStdString(); |
| | QString formatSpecifier = qsl[2]; |
| |
|
| | |
| | |
| | std::string basicString = formatPrefix + asQuantity.getUserString() + formatSuffix; |
| |
|
| | if (isMultiValueSchema() || partial == Format::UNALTERED) { |
| | return basicString; |
| | } |
| |
|
| | if (formatSpecifier.isEmpty()) { |
| | Base::Console().warning("Warning - no numeric format in Format Spec %s - %s\n", |
| | qPrintable(qFormatSpec), |
| | m_dimension->getNameInDocument()); |
| | return qFormatSpec.toStdString(); |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | if (m_dimension->useDecimals() |
| | && formatSpecifier.contains(QStringLiteral("%g"), Qt::CaseInsensitive)) { |
| | const int globalPrecision = Base::UnitsApi::getDecimals(); |
| | |
| | const QString newSpecifier = |
| | QString::fromStdString("%." + std::to_string(globalPrecision) + "f"); |
| | formatSpecifier.replace(QStringLiteral("%g"), newSpecifier, Qt::CaseInsensitive); |
| | } |
| |
|
| | double factor{1.0}; |
| | std::string unitText{""}; |
| | asQuantity.getUserString(factor, unitText); |
| | std::string super2{"²"}; |
| | std::string squareTag{"^2"}; |
| |
|
| | if (unitText.empty()) { |
| | if (distanceMeasure) { |
| | unitText = Base::UnitsApi::getBasicLengthUnit(); |
| | } else if (areaMeasure) { |
| | unitText = Base::UnitsApi::getBasicLengthUnit() + squareTag; |
| | } else if (angularMeasure) { |
| | unitText = "°"; |
| | } |
| | } |
| |
|
| | double userVal = asQuantity.getValue(); |
| |
|
| | if (distanceMeasure || areaMeasure) { |
| | userVal /= factor; |
| | } |
| |
|
| | |
| | if (areaMeasure) { |
| | size_t tagPosition = unitText.find(squareTag); |
| | if (tagPosition != std::string::npos) { |
| | unitText = unitText.replace(tagPosition, 2, super2); |
| | } |
| | } |
| |
|
| | QString formattedValue = formatValueToSpec(userVal, formatSpecifier); |
| |
|
| | |
| | constexpr QChar dp = QChar::fromLatin1('.'); |
| | if (const QLocale loc; loc.decimalPoint() != dp) { |
| | formattedValue.replace(dp, loc.decimalPoint()); |
| | } |
| |
|
| | |
| | std::string formattedValueString = formattedValue.toStdString(); |
| |
|
| | if (partial == Format::UNALTERED) { |
| | return basicString; |
| | } |
| |
|
| | if (partial == Format::FORMATTED) { |
| | std::string unitStr {}; |
| |
|
| | if (angularMeasure) { |
| | unitStr = "°"; |
| | } |
| | else if ((m_dimension->showUnits() || areaMeasure) |
| | && !(isDim && m_dimension->haveTolerance())) { |
| | unitStr = " " + unitText; |
| | } |
| |
|
| | return formatPrefix + formattedValueString + unitStr + formatSuffix; |
| | } |
| |
|
| | if (partial == Format::UNIT) { |
| | return angularMeasure || m_dimension->showUnits() || areaMeasure ? unitText : ""; |
| | } |
| |
|
| | return formattedValueString; |
| | } |
| |
|
| |
|
| | |
| | |
| | std::string DimensionFormatter::getFormattedToleranceValue(const Format partial) const |
| | { |
| | QString FormatSpec = QString::fromUtf8(m_dimension->FormatSpecOverTolerance.getStrValue().data()); |
| | QString ToleranceString; |
| |
|
| | if (m_dimension->ArbitraryTolerances.getValue()) |
| | ToleranceString = FormatSpec; |
| | else |
| | ToleranceString = QString::fromUtf8(formatValue(m_dimension->OverTolerance.getValue(), |
| | FormatSpec, |
| | partial, |
| | false).c_str()); |
| |
|
| | return ToleranceString.toStdString(); |
| | } |
| |
|
| | |
| | std::pair<std::string, std::string> DimensionFormatter::getFormattedToleranceValues(const Format partial) const |
| | { |
| | QString underFormatSpec = QString::fromUtf8(m_dimension->FormatSpecUnderTolerance.getStrValue().data()); |
| | QString overFormatSpec = QString::fromUtf8(m_dimension->FormatSpecOverTolerance.getStrValue().data()); |
| | std::pair<std::string, std::string> tolerances; |
| | QString underTolerance, overTolerance; |
| |
|
| | if (m_dimension->ArbitraryTolerances.getValue()) { |
| | underTolerance = underFormatSpec; |
| | overTolerance = overFormatSpec; |
| | } else { |
| | underTolerance = QString::fromUtf8(formatValue(m_dimension->UnderTolerance.getValue(), |
| | underFormatSpec, |
| | partial, |
| | false).c_str()); |
| | overTolerance = QString::fromUtf8(formatValue(m_dimension->OverTolerance.getValue(), |
| | overFormatSpec, |
| | partial, |
| | false).c_str()); |
| | } |
| |
|
| | tolerances.first = underTolerance.toStdString(); |
| | tolerances.second = overTolerance.toStdString(); |
| |
|
| | return tolerances; |
| | } |
| |
|
| | |
| | std::string DimensionFormatter::getFormattedDimensionValue(const Format partial) const |
| | { |
| | QString qFormatSpec = QString::fromUtf8(m_dimension->FormatSpec.getStrValue().data()); |
| |
|
| | if ( (m_dimension->Arbitrary.getValue() && !m_dimension->EqualTolerance.getValue()) |
| | || (m_dimension->Arbitrary.getValue() && m_dimension->TheoreticalExact.getValue()) ) { |
| | return m_dimension->FormatSpec.getStrValue(); |
| | } |
| |
|
| | if (m_dimension->Arbitrary.getValue()) { |
| | return m_dimension->FormatSpec.getStrValue(); |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| |
|
| | |
| | if (m_dimension->EqualTolerance.getValue() && |
| | !m_dimension->TheoreticalExact.getValue() && |
| | (!DrawUtil::fpCompare(m_dimension->OverTolerance.getValue(), 0.0) || |
| | m_dimension->ArbitraryTolerances.getValue())) { |
| | QString labelText = QString::fromUtf8(formatValue(m_dimension->getDimValue(), |
| | qFormatSpec, |
| | Format::FORMATTED, |
| | true).c_str()); |
| | QString unitText = QString::fromUtf8(formatValue(m_dimension->getDimValue(), |
| | qFormatSpec, |
| | Format::UNIT, |
| | false).c_str()); |
| | QString tolerance = QString::fromStdString(getFormattedToleranceValue(Format::FORMATTED).c_str()); |
| |
|
| | |
| | |
| | QRegularExpression plus(QStringLiteral("^\\s*\\+")); |
| | tolerance.remove(plus); |
| |
|
| | return (labelText + |
| | QString::fromUtf8(" \xC2\xB1 ") + |
| | tolerance).toStdString(); |
| |
|
| | |
| | if (partial == Format::UNIT) { |
| | return unitText.toStdString(); |
| | } |
| |
|
| | return ""; |
| | } |
| |
|
| | |
| | std::string formattedValue = formatValue(m_dimension->getDimValue(), qFormatSpec, partial, true); |
| |
|
| | return formattedValue; |
| | } |
| |
|
| | |
| | |
| | |
| | QString DimensionFormatter::formatValueToSpec(const double value, QString formatSpecifier) const |
| | { |
| | QString formattedValue; |
| |
|
| | constexpr auto format = [](QString f, double value){ |
| | return QString::fromStdString(fmt::sprintf(f.toStdString(), value)); |
| | }; |
| |
|
| | QRegularExpression wrRegExp(QStringLiteral("%(?<dec>.*)(?<spec>[wWrR])")); |
| | QRegularExpressionMatch wrMatch = wrRegExp.match(formatSpecifier); |
| |
|
| | if (! wrMatch.hasMatch()) { |
| | if (isNumericFormat(formatSpecifier)) { |
| | formattedValue = format(formatSpecifier, value); |
| | } |
| | return formattedValue; |
| | } |
| |
|
| | QString spec = wrMatch.captured(QStringLiteral("spec")).toLower(); |
| | QString dec = wrMatch.captured(QStringLiteral("dec")); |
| |
|
| | if (spec == QStringLiteral("w")) { |
| | formattedValue = format(QStringLiteral("%") + dec + QStringLiteral("f"), value); |
| | if (formattedValue.contains(QStringLiteral("."))){ |
| | |
| | while(formattedValue.endsWith(QStringLiteral("0"))) |
| | { |
| | formattedValue.chop(1); |
| | } |
| | |
| | if(formattedValue.endsWith(QStringLiteral("."))) |
| | { |
| | formattedValue.chop(1); |
| | } |
| | } |
| | } |
| | else if (spec == QStringLiteral("r")) { |
| | |
| | double rounder = dec.toDouble(); |
| | double roundValue = std::round(value / rounder) * rounder; |
| | |
| | int dotIndex = dec.indexOf(QStringLiteral(".")); |
| | int nDecimals = 0; |
| | if (dotIndex >= 0){ |
| | |
| | while(dec.endsWith(QStringLiteral("0"))) |
| | { |
| | dec.chop(1); |
| | } |
| | nDecimals = dec.size() - dotIndex - 1; |
| | } |
| | formatSpecifier = QStringLiteral("%.") + QString::number(nDecimals) + QStringLiteral("f"); |
| | formattedValue = format(formatSpecifier, roundValue); |
| | } |
| |
|
| | return formattedValue; |
| | } |
| |
|
| | bool DimensionFormatter::isNumericFormat(const QString& formatSpecifier) const |
| | { |
| | |
| | const QRegularExpression rxFormat(QStringLiteral("%[+-]?[0-9]*\\.*[0-9]*[aefgwAEFGW]")); |
| | QRegularExpressionMatch rxMatch; |
| | return formatSpecifier.indexOf(rxFormat, 0, &rxMatch) != -1; |
| | } |
| |
|
| | |
| | QStringList DimensionFormatter::getPrefixSuffixSpec(const QString& fSpec) const |
| | { |
| | QStringList result; |
| | |
| | QRegularExpression rxFormat(QStringLiteral("%[+-]?[0-9]*\\.*[0-9]*[aefgrwAEFGRW]")); |
| | QRegularExpressionMatch rxMatch; |
| | int pos = fSpec.indexOf(rxFormat, 0, &rxMatch); |
| | if (pos != -1) { |
| | QString match = rxMatch.captured(0); |
| | QString formatPrefix = fSpec.left(pos); |
| | result.append(formatPrefix); |
| | QString formatSuffix = fSpec.right(fSpec.size() - pos - match.size()); |
| | result.append(formatSuffix); |
| | result.append(match); |
| | } else { |
| | Base::Console().warning("Warning - no numeric format in formatSpec %s - %s\n", |
| | qPrintable(fSpec), m_dimension->getNameInDocument()); |
| | result.append(QString()); |
| | result.append(QString()); |
| | result.append(fSpec); |
| | } |
| | return result; |
| | } |
| |
|
| | std::string DimensionFormatter::getDefaultFormatSpec(bool isToleranceFormat) const |
| | { |
| | std::string prefFormat = Preferences::formatSpec(); |
| | QString formatSpec; |
| | QString qPrefix; |
| | if (prefFormat.empty()) { |
| | QString format1 = QStringLiteral("%."); |
| | QString format2 = QStringLiteral("f"); |
| | int precision; |
| | if (m_dimension->useDecimals()) { |
| | precision = Base::UnitsApi::getDecimals(); |
| | } else { |
| | precision = Preferences::altDecimals(); |
| | } |
| | QString formatPrecision = QString::number(precision); |
| |
|
| | std::string prefix = m_dimension->getPrefixForDimType(); |
| |
|
| | if (!prefix.empty()) { |
| | qPrefix = QString::fromUtf8(prefix.data(), prefix.size()); |
| | } |
| |
|
| | formatSpec = qPrefix + format1 + formatPrecision + format2; |
| | } else { |
| |
|
| | std::string prefix = m_dimension->getPrefixForDimType(); |
| | qPrefix = QString::fromUtf8(prefix.data(), prefix.size()); |
| | formatSpec = qPrefix + QString::fromStdString(prefFormat); |
| |
|
| | } |
| |
|
| | if (isToleranceFormat) { |
| | formatSpec.replace(QStringLiteral("%"), QStringLiteral("%+")); |
| | } |
| |
|
| | return formatSpec.toStdString(); |
| | } |
| |
|
| |
|