下图是开源库的输出示例,虽然只有三行,但是因为数字和逗号紧连着,想把数字剥离出来还是要下一番功夫的。思路是:将其先输出到一个txt文件中,然后再读入,用字符串处理技术将其中的各种信息剥离出来。
第一步,数据输出为txt
gsNURBSinfo(gsMultiPatch<T> const& m_patch,
gsMultiBasis<T> const& m_basis)
{
// 先输出
std::ofstream out_info("NURBSinfo.txt");
out_info << m_basis.basis(0);
out_info.close();
// 再读入
getKnotVectorInfo();
}
这里将输出的程序写在构造函数里了(因为编程需要,此段代码只是从本人项目中冗长的代码中截取的一小段,看官无需考虑这个问题),数据读入为一个单独的函数。
一些本文用到的变量,定义在类里的,也可以不考虑,代码注释中会介绍
public:
std::string basis_type; // 基函数的类型
index_t nurbs_dim; // 基函数的维度,index_t是int的派生,可以看做是int
index_t nurbs_node; // 结点总数
real_t tran_number; // 用于数据类型转换的局部变量,real_t是double的派生,可以看做是double
IGAinfo info_iga; // 单个节点向量的信息,定义了一个对象
vector<IGAinfo> igainfo; // 容纳所有的节点向量的容器
//vector basis_info;
第二步,读入数据,并拆解
首先来解析第一行,“TensorBSplineBasis: dim=2, size=36.”,
其中“TensorBSplineBasis:”这一串字符会因项目模型的不同而不同,需要保存下来;
另外注意到“dim=2,”这里的数字“2”后面还有一个“,”,共同构成了一个字符串,需要把数字“2”提取出来;
同样需要提取“size=36.”中的数字“36”。
// 打开刚才输出的txt文件
std::ifstream info_in("NURBSinfo.txt");
// 设置几个局部变量
std::string line;
std::stringstream ss_buff;
std::string temps;
// 拾取该行字符串数据
getline(info_in, line);
ss_buff.str("");
ss_buff.str(line);
// ===========================================
// 第一行数据
// std::string basis_type; // 类中定义的成员变量,原程序中不在此位置
ss_buff >> basis_type; // “TensorBSplineBasis:”
// ===========================================
ss_buff >> temps; // “dim=2,”
// 获取数值
std::string dim_str;
for (auto ce : temps)// 基于范围的for循环,遍历每一个字符
{
if (isdigit(ce)) // 如果是数字
{
dim_str += ce;// 把数字型的字符保存下来
}
}
// 字符串类型转为数字类型的函数
nurbs_dim = trans_str_to_any(dim_str);//dim_str是string型,nurbs_dim是int型
// ===========================================
ss_buff >> temps; // size=36.
std::string size_str
for (auto cf : temps)
{
if (isdigit(cf))
{
size_str += cf;
}
}
nurbs_node = trans_str_to_any(size_str);// size_str是string型,nurbs_node是int型
ss_buff.clear();
}
在以上的过程中为了将字符串类型的数字转化为数字类型,定义了trans_str_to_any() 函数,函数的实现如下,这里使用的是函数模板,需要返回值是什么类型就可以是什么类型。类型转化主要是通过 stringstream 这个流实现的,真的很好用啊。
template<typename T>
T gsNURBSinfo<T>::trans_str_to_any(std::string s_str)
{
T res;
std::stringstream Repeater;
Repeater << s_str;//string型
Repeater >> res; // 任意T类型,由目标返回值类型决定
return res;
}
然后来解析第二行,“ Direction 0: [ 0 0 0 0.25 0.5 0.75 1 1 1 ] (deg=2, size=9, minSpan=0.25, maxSpan=0.25)”
这一行要复杂得多,“[ ]”中的数据量根据模型的不同是变化的。最难的不是获取“[ ]”中的数据,而是获取“minSpan=0.25,”中的“0.25”,试想一下,你会怎么做,这是一个字符串,数字夹在了字符中间,可以使用 isdigit() 函数提取数字,但是“.”不是数字。看我操作
// 获取一行待处理的数据
getline(info_in, line);
// 使用关键字判断是不是需要的数据行
if (line.find("Direction") != std::string::npos)
{
ss_buff.str("");
ss_buff.str(line);
ss_buff >> temps; // Direction
ss_buff >> temps; // 0:
info_iga.knot_direction = knot_dir;
// 提取“[ ]”中的数据
ss_buff >> temps; // [
ss_buff >> temps; // 0
std::string judge_symbol("]");
while(temps != judge_symbol)
{ // temps中如果不是"]"就循环
tran_number = trans_str_to_any(temps); // tran_number是double型
info_iga.knot_vector.push_back(tran_number);//info_iga.knot_vector是vector型
ss_buff >> temps; // 依次是0 0 0.25 0.5 0.75 1 1 1 ]
}
// =============================================
ss_buff >> temps; // (deg=2,
std::string dig_str;
for (auto ca : temps)
{ // 提取数字2
if (isdigit(ca))
{
dig_str += ca;
}
}
info_iga.knot_degree = trans_str_to_any(dig_str);// info_iga.knot_degree是int型
// ============================================
ss_buff >> temps; // size=9,
std::string siz_str;
for (auto cb : temps)
{ // 提取数字9
if (isdigit(cb))
{
siz_str += cb;
}
}
info_iga.knot_size = trans_str_to_any(siz_str);
// ============================================
ss_buff >> temps; // minSpan=0.25,
std::string mins_str;
for (char cc : temps)
{ // 提取数字0.25
if (isdigit(cc) || cc == '.')
{
mins_str += cc;
}
}
info_iga.knot_minSpan = trans_str_to_any(mins_str);
// ===========================================
ss_buff >> temps; // maxSpan=0.25)
std::string maxs_str;
for (char cd : temps)
{ // 提取数字0.25
if (isdigit(cd) || cd == '.')
{
maxs_str += cd;
}
}
info_iga.knot_maxSpan = trans_str_to_any(maxs_str);
// ===========================================
ss_buff.clear();
igainfo.push_back(info_iga);
info_iga.initialize();
++knot_dir;
}
第三行和第二行的操作是完全一致的。
可以输出一下结果
// gsInfo是cout的派生
gsInfo << basis_type << " ";
gsInfo << "dim=" << nurbs_dim << ", ";
gsInfo << "size=" << nurbs_node << ".\n";
for (index_t j = 0; j < igainfo.size(); ++j)
{
gsInfo << " Direction " << j << ": [ ";
for (index_t k = 0; k < igainfo[j].knot_vector.size(); ++k)
{
gsInfo << igainfo[j].knot_vector[k] << " ";
}
gsInfo << "] (";
gsInfo << "deg=" << igainfo[j].knot_degree
<< ", size=" << igainfo[j].knot_size
<< ", minSpan=" << igainfo[j].knot_minSpan
<< ", maxSpan=" << igainfo[j].knot_maxSpan;
gsInfo << ")\n";
}
template
< class T>
void gsNURBSinfo<T>::getKnotVectorInfo()
{
std::ifstream info_in("NURBSinfo.txt");
std::string line;
std::stringstream ss_buff;
std::string temps;
index_t knot_dir = 0;
while (!info_in.eof())
{
getline(info_in, line);
if (line.find("Direction") != std::string::npos)
{
ss_buff.str("");
ss_buff.str(line);
ss_buff >> temps; // Direction
ss_buff >> temps; // 0:
info_iga.knot_direction = knot_dir;
// 节点向量
ss_buff >> temps; // [
ss_buff >> temps; // 0
std::string judge_symbol("]");
while(temps != judge_symbol)
{
tran_number = trans_str_to_any(temps);
info_iga.knot_vector.push_back(tran_number); // 节点向量
ss_buff >> temps; // 0 0 1 1 1 ]
}
// =============================================
ss_buff >> temps; // (deg=2,
std::string dig_str;
for (auto ca : temps)
{
if (isdigit(ca))
{
dig_str += ca;
}
}
info_iga.knot_degree = trans_str_to_any(dig_str);
// ============================================
ss_buff >> temps; // size=9,
std::string siz_str;
for (auto cb : temps)
{
if (isdigit(cb))
{
siz_str += cb;
}
}
info_iga.knot_size = trans_str_to_any(siz_str);
// ============================================
ss_buff >> temps; // minSpan=0.25
std::string mins_str;
//char m_dot('.');
for (char cc : temps)
{
if (isdigit(cc) || cc == '.')
{
mins_str += cc;
}
}
info_iga.knot_minSpan = trans_str_to_any(mins_str);
// ===========================================
ss_buff >> temps; // maxSpan=0.25)
std::string maxs_str;
for (char cd : temps)
{
if (isdigit(cd) || cd == '.')
{
maxs_str += cd;
}
}
info_iga.knot_maxSpan = trans_str_to_any(maxs_str);
ss_buff.clear();
igainfo.push_back(info_iga);
info_iga.initialize();
//igainfo[knot_dir]=(info_iga);
++knot_dir;
}
else if (!line.empty())
{ // TensorBSplineBasis: dim=2, size=36.
ss_buff.str("");
ss_buff.str(line);
ss_buff >> basis_type; // TensorBSplineBasis:
// ===========================================
ss_buff >> temps; // dim=2,
// 获取数值
std::string dim_str;
for (auto ce : temps)
{
if (isdigit(ce)) // 如果是数字
{
dim_str += ce;
}
}
nurbs_dim = trans_str_to_any(dim_str);
// ===========================================
ss_buff >> temps; // size=4.
std::string size_str;
for (auto cf : temps)
{
if (isdigit(cf))
{
size_str += cf;
}
}
nurbs_node = trans_str_to_any(size_str);
ss_buff.clear();
}
}
gsInfo << basis_type << " ";
gsInfo << "dim=" << nurbs_dim << ", ";
gsInfo << "size=" << nurbs_node << ".\n";
for (index_t j = 0; j < igainfo.size(); ++j)
{
gsInfo << " Direction " << j << ": [ ";
for (index_t k = 0; k < igainfo[j].knot_vector.size(); ++k)
{
gsInfo << igainfo[j].knot_vector[k] << " ";
}
gsInfo << "] (";
gsInfo << "deg=" << igainfo[j].knot_degree
<< ", size=" << igainfo[j].knot_size
<< ", minSpan=" << igainfo[j].knot_minSpan
<< ", maxSpan=" << igainfo[j].knot_maxSpan;
gsInfo << ")\n";
}
}
// 字符串转换为数字的函数模板
template<typename T>
T gsNURBSinfo<T>::trans_str_to_any(std::string s_str)
{
T res;
std::stringstream Repeater;
Repeater << s_str;
Repeater >> res;
return res;
}
}