Files
EJM_Display/PublicFunctions/Basic.cpp
2025-10-20 22:28:37 +08:00

272 lines
9.1 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "Basic.h"
#include <QColor>
/**
* @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 = 1false = 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<uint32_t>(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 = 1false = 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<uint16_t>((data >> 16) & 0xFFFF);
case 1: // 低16位
return static_cast<uint16_t>(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(); // 无效颜色
}