.obj ファイルのパーサーを作成していますが、ファイルの一部に次の形式のファイルがあります。
f [整数]/[整数] [整数]/[整数] [整数]/[整数]
整数の長さは不明です。[int]/[int] の各ペアでは、両方を別々の配列に配置する必要があります。それらを整数として分離する最も簡単な方法は何ですか?
fscanfでそれを行うことができます:
int matched = fscanf(fptr, "f %d/%d %d/%d %d/%d", &a, &b, &c, &d, &e, &f);
if (matched != 6) fail();
または ifstream と sscanf:
char buf[100];
yourIfstream.getLine(buf, sizeof(buf));
int matched = sscanf(buf, "f %d/%d %d/%d %d/%d", &a, &b, &c, &d, &e, &f);
if (matched != 6) fail();
最も簡単な方法は、C++11 の正規表現を使用することです。
static const std::regex ex("f (-?\\d+)//(-?\\d+) (-?\\d+)//(-?\\d+) (-?\\d+)//(-?\\d+)");
std::smatch match;
if(!std::regex_match(line, match, ex))
throw std::runtime_error("invalid face data");
int v0 = std::stoi(match[1]), t0 = std::stoi(match[2]),
v1 = std::stoi(match[3]), t1 = std::stoi(match[4]),
v2 = std::stoi(match[5]), t2 = std::stoi(match[6]);
あなたのケースではこれで十分かもしれませんが、これらのインデックス タプルを読み取るためのより柔軟な方法を追加せずにはいられません。これにより、非三角形の面やさまざまな面の指定形式により適切に対処できます。これは、すでにフェイス ラインを に入れ、std::istringstream
フェイス タグをすでに食べていることを前提としています。OBJ ファイルを読み取る最も簡単な方法は依然として次のとおりであるため、これは通常のケースです。
for(std::string line,tag; std::getline(file, line); )
{
std::istringstream sline(line);
sline >> tag;
if(tag == "v")
...
else if(tag == "f")
...
}
顔データを読み取るには ("f"
もちろんケース内)、まず各インデックス タプルを個別に読み取ります。次に、可能なインデックス形式ごとに正規表現を使用してこのインデックスを解析し、それらを適切に処理して、個々の頂点、texcoord、および法線インデックスを 3 要素で返しますstd::tuple
。
for(std::string corner; sline>>corner; )
{
static const std::regex vtn_ex("(-?\\d+)/(-?\\d+)/(-?\\d+)");
static const std::regex vn_ex("(-?\\d+)//(-?\\d+)");
static const std::regex vt_ex("(-?\\d+)/(-?\\d+)/?");
std::smatch match;
std::tuple<int,int,int> idx;
if(std::regex_match(corner, match, vtn_ex))
idx = std::make_tuple(std::stoi(match[1]),
std::stoi(match[2]), std::stoi(match[3]));
else if(std::regex_match(corner, match, vn_ex))
idx = std::make_tuple(std::stoi(match[1]), 0, std::stoi(match[2]));
else if(std::regex_match(corner, match, vt_ex))
idx = std::make_tuple(std::stoi(match[1]), std::stoi(match[2]), 0);
else
idx = std::make_tuple(std::stoi(str), 0, 0);
//do whatever you want with the indices in std::get<...>(idx)
};
もちろん、これにより、ループの反復ごとに新しい文字列とストリームを割り当てる必要がなくなるなど、パフォーマンスに基づいた最適化 (必要な場合) の可能性が提供されます。しかし、適切な OBJ ローダーに必要な柔軟性を提供する最も簡単な方法です。しかし、頂点と texcoords のみを持つ三角形の上記のバージョンで十分な場合もあります。