polyline解码需按vlq规则逐字节解析:每字节最高位为1时继续读取,为0时结束;用value |= (byte & 0x7f)

polyline解码函数必须处理VLQ字节流的边界对齐
Google Polyline编码本质是变长整数(VLQ)序列,每个整数代表一个微度坐标差值。解码时不能直接按字节读取,必须识别每个VLQ单元的结束位(最高位为0表示结束,1表示继续)。常见错误是把连续5个字节硬当成一个int32,结果在遇到短VLQ(如1~4字节)时读越界或错位。
实操建议:
- 用
uint8_t逐字节读取,检查每字节最高位:byte & 0x80非零则继续读下字节 - 累计位移时用
value |= (byte & 0x7F) ,shift每次加7,最大到28(5字节×7位) - 最后一步必须做符号扩展:若原始编码末字节最高位为1(即原数为负),需将结果补全至32位有符号整数范围
差分坐标还原时要防32位整数溢出
解码得到的是delta值序列:d0 = v0, di = vi - v_{i-1}。还原原始量化坐标时,累加过程可能溢出——例如从东经179.999999°(179999999 μ°)跳到西经179.999999°(-179999999 μ°),差值为-359999998,但若用int32_t存储中间累加和,两次加减后可能超出INT32_MIN/INT32_MAX。
实操建议:
- 还原坐标时用
int64_t暂存累加和,仅在写入最终数组前截断为int32_t - 不依赖
std::numeric_limits做运行时检查(嵌入式环境可能无STL),改用宏判断:#define INT32_OVERFLOW(x) ((x) > 2147483647LL || (x) - 闭合多段线(如地理围栏)需额外校验首尾坐标是否一致,避免因溢出导致
v0 != vn
经纬度反量化必须用定点数学避免浮点误差
量化公式是v = round(coordinate × 1e6),反量化必须严格逆向:不能直接coordinate = v / 1e6(触发double除法,且1e6无法精确表示为二进制浮点数)。实测在ARM Cortex-M4上,179999999 / 1000000.0会得179.99999899999998而非179.999999。
实操建议:
- 用整数除法+余数补偿:
deg = v / 1000000,frac = v % 1000000, 最终结果为deg + frac * 1e-6(注意1e-6应定义为static constexpr double kMicroDegree = 1.0 / 1000000.0;并确认编译器constexpr求值精度) - 若目标平台完全禁用浮点(如M0+),改用定点输出:直接返回
int32_t微度值,由上层业务决定是否转为浮点 - 测试用例必须覆盖临界值:
-180000000,0,180000000,验证反量化后不越界
嵌入式场景下必须规避动态内存与STL容器
标准Polyline解码库常依赖std::vector存坐标、std::string存编码串,这在MCU上不可行。EPolyline等轻量实现要求所有缓冲区静态声明,且函数可constexpr内联。
实操建议:
- 输入编码串必须是
const uint8_t*+size_t len,禁止std::string_view(C++17特性,部分MCU工具链不支持) - 输出坐标数组用指针+容量参数:
bool decode_polyline(const uint8_t* src, size_t len, int32_t* out_lat, int32_t* out_lng, size_t max_points, size_t* actual_points) - 内部临时变量全部栈分配,VLQ解码缓冲区最多5字节,差分还原用两个
int64_t变量足矣
关键点在于:VLQ字节流解析、差分累加的整数溢出防护、反量化时的定点数学替代,三者缺一不可。最容易被忽略的是差分还原阶段的中间类型选择——用int32_t累加看似省空间,实则埋下静默溢出隐患。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!









