#include "Basic.h" #include /** * @brief map 映射函数,把x的值,映射到out_min到out_max的范围内 * @param x 需要映射的值 * @param in_min x有可能的最小值 * @param in_max x有可能的最大值 * @param out_min 输出的最小值 * @param out_max 输出的最大值 * @return 映射结果 */ M_d64 map(M_d64 x, M_d64 in_min, M_d64 in_max, M_d64 out_min, M_d64 out_max) { return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min; } /** * @brief Sleep_ms 不占用线程的延时函数 * @param msec 需要延时的毫秒数 */ void Sleep_ms(M_u16 msec){ QTime _Timer = QTime::currentTime().addMSecs(msec); while( QTime::currentTime() < _Timer ) QCoreApplication::processEvents(QEventLoop::AllEvents, 100); } /** * @brief 获取 32 位数据的第 N 位状态 * @param data 32 位数据源(支持 uint32_t 或 int32_t) * @param bitIndex 位索引(0 = 最低位/第1位,31 = 最高位/第32位) * @param defaultValue 索引越界时的默认返回值(默认 false) * @return bool 位状态:true = 1,false = 0 */ bool getBitOf32Data(uint32_t data, int bitIndex, bool defaultValue) { // 1. 边界检查:32位数据的索引范围是 0~31,超出则返回默认值 if (bitIndex < 0 || bitIndex > 31) { qWarning() << "[getBitOf32Data] 位索引越界!当前索引:" << bitIndex << ",允许范围:0~31"; return defaultValue; } // 2. 位运算核心逻辑: // - (1U << bitIndex):生成“指定位为1,其他位为0”的掩码(1U 确保无符号移位,避免符号位问题) // - (data & 掩码):按位与操作,若结果非0,说明指定位为1;否则为0 return (static_cast(data) & (1U << bitIndex)) != 0; } /** * @brief 将 32 位数据的第 N 位设为 1 * @param data 原始 32 位数据(按引用修改) * @param bitIndex 位索引(0 = 最低位,31 = 最高位) * @return bool 成功返回 true;若索引越界返回 false,且不修改 data */ bool setBitOf32Data(uint32_t &data, int bitIndex) { if (bitIndex < 0 || bitIndex > 31) { qWarning().noquote() << "[setBitOf32Data] 位索引越界!索引:" << bitIndex; return false; } data |= (1U << bitIndex); // 置 1 return true; } /** * @brief 将 32 位数据的第 N 位清 0 * @param data 原始 32 位数据(按引用修改) * @param bitIndex 位索引(0 = 最低位,31 = 最高位) * @return bool 成功返回 true;若索引越界返回 false,且不修改 data */ bool clearBitOf32Data(uint32_t &data, int bitIndex) { if (bitIndex < 0 || bitIndex > 31) { qWarning().noquote() << "[clearBitOf32Data] 位索引越界!索引:" << bitIndex; return false; } data &= ~(1U << bitIndex); // 清 0 return true; } /** * @brief 将 32 位数据的第 N 位设为指定状态 * @param data 原始 32 位数据(按引用修改) * @param bitIndex 位索引(0 = 最低位,31 = 最高位) * @param bitValue 要写入的位值:true = 1,false = 0 * @return bool 成功返回 true;若索引越界返回 false,且不修改 data */ bool writeBitOf32Data(uint32_t &data, int bitIndex, bool bitValue) { return bitValue ? setBitOf32Data(data, bitIndex) : clearBitOf32Data(data, bitIndex); } /** * @brief 将 QVariant 按“先转字符串判断小数点”逻辑格式化 * @param variant:待转换的 QVariant 数据 * @param decimalDigits:需要保留的小数位数(默认2位,可自定义) * @return 格式化后的字符串 */ QString variantToFormattedString(const QVariant& variant, int decimalDigits) { // 1. 安全校验:小数位数不能为负数 if (decimalDigits < 0) { decimalDigits = 0; } // 2. 第一步:先将 QVariant 转为原始字符串(不做任何数值格式化) QString originalStr = variant.toString(); // 处理空字符串情况 if (originalStr.isEmpty()) { return ""; } // 3. 第二步:过滤非数字字符串(仅对数字字符串做小数处理) // 正则匹配:整数(如 "123"、"-456")或浮点数(如 "123.45"、".67"、"89.") QRegExp numRegExp("^-?\\d+(\\.\\d*)?$"); if (!numRegExp.exactMatch(originalStr)) { return originalStr; } // 4. 第三步:判断字符串是否含小数点,按需格式化 if (originalStr.contains('.')) { // 有小数点:解析为浮点数,保留指定小数位数(四舍五入) bool ok = false; double num = originalStr.toDouble(&ok); if (ok) { // 用 'f' 格式确保固定小数位数(如 decimalDigits=3 时,123.4→123.400) return QString::number(num, 'f', decimalDigits); } else { // 极端情况:匹配正则但无法解析(如 ".abc",实际正则已过滤),返回原字符串 return originalStr; } } else { // 无小数点:直接返回原始整数字符串(不受小数位数影响) return originalStr; } } /** * 通过索引提取uint32_t的8位部分 * @param data 要提取的32位无符号整数 * @param index 索引:0=HH(高8位), 1=HL(次高8位), 2=LH(次低8位), 3=LL(低8位) * @return 对应的8位部分 * @throws std::out_of_range 当索引超出0-3范围时 */ uint8_t extractUInt32_8BitPart(uint32_t data, uint8_t index) { switch(index) { case 0: // HH - 高8位 return (data >> 24) & 0xFF; case 1: // HL - 次高8位 return (data >> 16) & 0xFF; case 2: // LH - 次低8位 return (data >> 8) & 0xFF; case 3: // LL - 低8位 return data & 0xFF; default: return 00; } } /** * 通过索引提取uint32_t的16位部分 * @param data 要提取的32位无符号整数 * @param index 索引:0=高16位, 1=低16位 * @return 对应的16位部分(uint16_t类型) * @throws std::out_of_range 当索引超出0-1范围时 */ uint16_t extractUInt32_16BitPart(uint32_t data, int index) { switch(index) { case 0: // 高16位 return static_cast((data >> 16) & 0xFFFF); case 1: // 低16位 return static_cast(data & 0xFFFF); default: return 00; } } /** * @brief getNodeValue 获取节点内的值 * @param nodeId 欲获取的节点文本 * @return 类型:QVariant 节点的值 */ QVariant getNodeValue(const QString &nodeId){ QString mNodeID = nodeId; if(!mNodeID.contains("ns=6;s=::AsGlobalPV:")) mNodeID = "ns=6;s=::AsGlobalPV:"+mNodeID; return gOPC_NodeValue[mNodeID]; } /** * @brief getColorStr 获取颜色文本 * @param Str 欲获取的文本内容 * @return 返回颜色文本 */ QString getColorStr(QString str) { /* 颜色文本的表现形式: color: rgb(255, 0, 0); color: #ff0000; 颜色文本格式: color: rgb(255, 0, 0); color: rgb(255, 0, 0) rgb(255, 0, 0) rgb(255, 0, 0); 255, 0, 0 255, 0, 0; color: #ff0000 color: #ff0000; #ff0000 #ff0000; ff0000 ff0000; */ str = str.trimmed(); /* 1. 先尝试匹配 rgb(r, g, b) 形式 */ static QRegularExpression reRgb( R"(^\s*(?:color\s*:\s*)?rgb\s*\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\);?\s*$)", QRegularExpression::CaseInsensitiveOption); auto match = reRgb.match(str); if (match.hasMatch()) { int r = match.captured(1).toInt(); int g = match.captured(2).toInt(); int b = match.captured(3).toInt(); return QString("color: rgb(%1, %2, %3);").arg(r).arg(g).arg(b); } /* 2. 再尝试匹配 #hex 或裸 hex 形式 */ static QRegularExpression reHex( R"(^\s*(?:color\s*:\s*)?(?:#)?([0-9a-f]{6});?\s*$)", QRegularExpression::CaseInsensitiveOption); match = reHex.match(str); if (match.hasMatch()) { QString hex = match.captured(1).toLower(); return QString("color: #%1;").arg(hex); } /* 3. 都不符合,原样返回(或按需返回空串) */ return str; } /** * @brief getColor * @param str 任意颜色字符串 * @return QColor(无效 QColor 表示解析失败) */ QColor getColor(const QString &str) { QString s = str.trimmed(); /* 1. rgb(r, g, b) */ static QRegularExpression reRgb( R"(^\s*(?:color\s*:\s*)?rgb\s*\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\);?\s*$)", QRegularExpression::CaseInsensitiveOption); auto m = reRgb.match(s); if (m.hasMatch()) { int r = m.captured(1).toInt(); int g = m.captured(2).toInt(); int b = m.captured(3).toInt(); return QColor(r, g, b); } /* 2. #RRGGBB 或 RRGGBB */ static QRegularExpression reHex( R"(^\s*(?:color\s*:\s*)?(?:#)?([0-9a-fA-F]{6});?\s*$)"); m = reHex.match(s); if (m.hasMatch()) return QColor('#' + m.captured(1)); // QColor 接受 "#ff0000" /* 3. 解析失败 */ return QColor(); // 无效颜色 }