Files
ViewDesignEngine/include/vde/foundation/format_utils.h
T
茂之钳 4c9ee4f760
CI / Build & Test (push) Failing after 29s
CI / Release Build (push) Failing after 38s
docs: doxygen annotations for curves + mesh + sketch
2026-07-24 11:04:04 +00:00

139 lines
4.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.
#pragma once
#include "vde/core/point.h"
#include <string>
#include <sstream>
#include <iomanip>
#include <cmath>
#include <cstdio>
namespace vde::foundation {
/**
* @brief 以 CAD 级别精度格式化双精度浮点数
*
* 输出科学计数法字符串,保证 12 位有效数字,满足 CAD 数据交换精度要求。
* NaN 被格式化为 "0.0"Inf/ -Inf 被裁剪为安全边界值。
*
* @param v 要格式化的双精度数
* @param precision 有效数字位数(默认 12)
* @return 格式化后的字符串,如 "1.234567890123e+02"
*
* @note 总是确保指数部分带符号(如 "e+00" 而非 "e00"),便于解析器统一处理
*
* @code{.cpp}
* auto s = fmt_double(3.14159265358979);
* // s == "3.141592653590e+00"
* @endcode
*
* @see fmt_iges_real, fmt_point
* @ingroup foundation
*/
inline std::string fmt_double(double v, int precision = 12) {
if (std::isnan(v)) return "0.0";
if (std::isinf(v)) return v > 0 ? "1e30" : "-1e30";
std::ostringstream ss;
ss << std::setprecision(precision) << std::scientific << v;
std::string s = ss.str();
// Ensure always has exponent sign (e.g., "1.0e+00" not "1.0e00")
auto epos = s.find('e');
if (epos != std::string::npos) {
if (epos + 1 < s.size() && s[epos + 1] != '-' && s[epos + 1] != '+') {
s.insert(epos + 1, "+");
}
}
return s;
}
/**
* @brief IGES 格式实数输出
*
* 与 fmt_double() 相同,但使用 IGES 标准的 'D' 指数标记代替 'E'。
*
* @param v 要格式化的双精度数
* @return IGES 格式字符串,如 "3.141592653590D+00"
*
* @code{.cpp}
* auto s = fmt_iges_real(3.14159265358979);
* // s == "3.141592653590D+00"
* @endcode
*
* @see fmt_double
* @ingroup foundation
*/
inline std::string fmt_iges_real(double v, int /*precision*/ = 12) {
auto s = fmt_double(v, 12);
auto pos = s.find('e');
if (pos != std::string::npos) s[pos] = 'D';
return s;
}
/**
* @brief 格式化三维点为逗号分隔字符串
*
* 输出 "x,y,z" 形式,常用于 IGES/STEP/OBJ 等文本格式的顶点坐标行。
*
* @param p 三维点
* @param use_d 若为 true,使用 IGES 风格 D 指数标记
* @return 逗号分隔的坐标字符串
*
* @code{.cpp}
* Point3D p(1.0, 2.5, -3.14);
* auto s = fmt_point(p);
* // s == "1.000000000000e+00,2.500000000000e+00,-3.140000000000e+00"
* @endcode
*
* @see fmt_double, fmt_iges_real
* @ingroup foundation
*/
inline std::string fmt_point(const core::Point3D& p, bool use_d = false) {
using FmtFn = std::string (*)(double, int);
FmtFn fn = use_d ? static_cast<FmtFn>(fmt_iges_real) : fmt_double;
return fn(p.x(), 12) + "," + fn(p.y(), 12) + "," + fn(p.z(), 12);
}
/**
* @brief 将字符串填充到恰好 72 个字符
*
* IGES 格式中每条数据行固定为 72 字符宽。不足用空格补齐,超出则截断。
*
* @param s 输入字符串
* @return 恰好 72 字符的字符串(不足右侧补空格,超出截断)
*
* @see format_iges_line
* @ingroup foundation
*/
inline std::string pad72(const std::string& s) {
std::string result = s;
if (result.size() > 72) result.resize(72);
result.resize(72, ' ');
return result;
}
/**
* @brief 格式化 IGES 段落行
*
* 生成一条完整的 IGES 80 列记录行:72 列数据 + 8 列序号(section_char + 7 位数字)。
*
* @param data 数据内容(最多 72 字符,超出截断)
* @param section_char 段落标识符(如 'P' 参数段, 'D' 目录段)
* @param seq 行序号(1-based
* @return 完整 IGES 行(含换行符),共 81 字符
*
* @code{.cpp}
* auto line = format_iges_line("110,1.0,2.0,3.0;", 'P', 1);
* // 输出: "110,1.0,2.0,3.0; P0000001\n"
* @endcode
*
* @see pad72
* @ingroup foundation
*/
inline std::string format_iges_line(const std::string& data, char section_char, int seq) {
std::string line = pad72(data);
char seq_buf[9];
std::snprintf(seq_buf, sizeof(seq_buf), "%c%07d", section_char, seq);
line += std::string(seq_buf);
return line + "\n";
}
} // namespace vde::foundation