|
|
57bda0 |
|
|
|
57bda0 |
#include <cstdio></cstdio>
|
|
|
57bda0 |
#include <fstream></fstream>
|
|
|
57bda0 |
#include <iostream></iostream>
|
|
|
1bcd85 |
#include <iomanip></iomanip>
|
|
|
57bda0 |
|
|
|
57bda0 |
#include "loader.h"
|
|
|
57bda0 |
|
|
|
57bda0 |
|
|
|
8ee194 |
namespace {
|
|
|
8ee194 |
|
|
|
8ee194 |
class LoaderTrack {
|
|
|
57bda0 |
public:
|
|
|
57bda0 |
Track &track;
|
|
|
57bda0 |
const std::string &filename;
|
|
|
57bda0 |
|
|
|
57bda0 |
std::ifstream f;
|
|
|
57bda0 |
int row;
|
|
|
57bda0 |
int col;
|
|
|
57bda0 |
|
|
|
57bda0 |
bool valid_point;
|
|
|
57bda0 |
bool newline;
|
|
|
d2b2b5 |
TrackPoint point;
|
|
|
57bda0 |
|
|
|
8ee194 |
LoaderTrack(Track &track, const std::string &filename):
|
|
|
57bda0 |
track(track),
|
|
|
57bda0 |
filename(filename),
|
|
|
57bda0 |
row(1),
|
|
|
57bda0 |
col(),
|
|
|
57bda0 |
valid_point(),
|
|
|
57bda0 |
newline()
|
|
|
57bda0 |
{ }
|
|
|
57bda0 |
|
|
|
57bda0 |
void error(const std::string &msg) {
|
|
|
57bda0 |
std::cerr << "Error while loading track: " << filename
|
|
|
57bda0 |
<< ":" << row
|
|
|
57bda0 |
<< ":" << col
|
|
|
57bda0 |
<< ": " << msg
|
|
|
57bda0 |
<< std::endl;
|
|
|
57bda0 |
}
|
|
|
57bda0 |
|
|
|
57bda0 |
int get() {
|
|
|
57bda0 |
int c = f.get();
|
|
|
57bda0 |
if (c == '\n') ++row, col = 0, newline = true; else ++col;
|
|
|
57bda0 |
return c;
|
|
|
57bda0 |
}
|
|
|
57bda0 |
|
|
|
57bda0 |
bool read_pair(int &command, Real &number) {
|
|
|
57bda0 |
command = 0; number = 0;
|
|
|
57bda0 |
|
|
|
57bda0 |
char c = f.get(); ++row;
|
|
|
57bda0 |
if (c < 0) return false;
|
|
|
57bda0 |
|
|
|
57bda0 |
while(std::isspace(c)) c = get();
|
|
|
57bda0 |
if (c == '(') while(c != ')') c = get();
|
|
|
57bda0 |
while(std::isspace(c)) c = get();
|
|
|
57bda0 |
newline = false;
|
|
|
57bda0 |
|
|
|
57bda0 |
if (c < 0) { return false; }
|
|
|
57bda0 |
|
|
|
57bda0 |
command = c;
|
|
|
57bda0 |
|
|
|
57bda0 |
while(std::isspace(f.peek())) get();
|
|
|
57bda0 |
if (newline) return true;
|
|
|
57bda0 |
|
|
|
57bda0 |
Real sign = 1;
|
|
|
57bda0 |
Real frac = 1;
|
|
|
57bda0 |
int mode = 0;
|
|
|
57bda0 |
while(true) {
|
|
|
57bda0 |
c = f.peek();
|
|
|
57bda0 |
if (mode == 0 && c == '-') { sign = -1; mode = 1; }
|
|
|
57bda0 |
else if (mode == 0 && c == '+') { sign = +1; mode = 1; }
|
|
|
57bda0 |
else if (mode <= 1 && c == '.') { mode = 2; }
|
|
|
1bcd85 |
else if (mode <= 1 && c >= '0' && c <= '9') { number = number*10 + (c - '0'); mode = 1; }
|
|
|
1bcd85 |
else if (mode == 2 && c >= '0' && c <= '9') { number += (c - '0')*(frac *= 0.1); }
|
|
|
57bda0 |
else if (mode == 0) { error("expected number"); return c >= 0; }
|
|
|
57bda0 |
else { break; }
|
|
|
57bda0 |
get();
|
|
|
57bda0 |
}
|
|
|
1bcd85 |
number *= sign;
|
|
|
57bda0 |
|
|
|
57bda0 |
while(std::isspace(f.peek())) get();
|
|
|
57bda0 |
return true;
|
|
|
57bda0 |
}
|
|
|
57bda0 |
|
|
|
57bda0 |
void read_point_data(Real &data, int command, Real number) {
|
|
|
57bda0 |
if (!valid_point)
|
|
|
57bda0 |
error("arg " + std::string(1, command) + " was set in unknown command");
|
|
|
57bda0 |
data = number;
|
|
|
57bda0 |
}
|
|
|
57bda0 |
|
|
|
57bda0 |
bool load() {
|
|
|
57bda0 |
track.points.clear();
|
|
|
57bda0 |
|
|
|
57bda0 |
std::cout << "loading: " << filename << std::endl;
|
|
|
57bda0 |
|
|
|
57bda0 |
f.open(filename);
|
|
|
57bda0 |
if (!f) {
|
|
|
57bda0 |
error("cannot open file");
|
|
|
57bda0 |
f.close();
|
|
|
57bda0 |
return false;
|
|
|
57bda0 |
}
|
|
|
57bda0 |
|
|
|
57bda0 |
int command;
|
|
|
57bda0 |
Real number;
|
|
|
57bda0 |
point.speed = 600/60.0;
|
|
|
57bda0 |
while(read_pair(command, number)) {
|
|
|
57bda0 |
int inumber = (int)round(number);
|
|
|
1bcd85 |
//debug: std::cout << std::string(1, command) << " " << number << std::endl;
|
|
|
57bda0 |
bool arg = true;
|
|
|
57bda0 |
if (command == 'X') {
|
|
|
57bda0 |
read_point_data(point.position.x, command, number);
|
|
|
57bda0 |
} else
|
|
|
57bda0 |
if (command == 'Y') {
|
|
|
57bda0 |
read_point_data(point.position.y, command, number);
|
|
|
57bda0 |
} else
|
|
|
57bda0 |
if (command == 'Z') {
|
|
|
57bda0 |
read_point_data(point.position.z, command, number);
|
|
|
57bda0 |
} else
|
|
|
57bda0 |
if (command == 'A') {
|
|
|
57bda0 |
read_point_data(point.angle, command, number);
|
|
|
57bda0 |
} else
|
|
|
57bda0 |
if (command == 'F') {
|
|
|
57bda0 |
if (number < 1e-3) {
|
|
|
57bda0 |
error("feed rate too small");
|
|
|
57bda0 |
number = 1e-3;
|
|
|
57bda0 |
}
|
|
|
57bda0 |
read_point_data(point.speed, command, number/60.0);
|
|
|
57bda0 |
} else {
|
|
|
57bda0 |
arg = false;
|
|
|
57bda0 |
}
|
|
|
57bda0 |
|
|
|
57bda0 |
if (newline || !arg) {
|
|
|
57bda0 |
if (valid_point) track.points.push_back(point);
|
|
|
57bda0 |
|
|
|
57bda0 |
if (!arg) {
|
|
|
57bda0 |
valid_point = false;
|
|
|
57bda0 |
if (command == 'G' && (inumber == 0 || inumber == 1))
|
|
|
57bda0 |
valid_point = true;
|
|
|
57bda0 |
else
|
|
|
57bda0 |
error("Unknown command: " + std::string(1, command));
|
|
|
57bda0 |
}
|
|
|
57bda0 |
}
|
|
|
57bda0 |
}
|
|
|
57bda0 |
if (valid_point) track.points.push_back(point);
|
|
|
57bda0 |
|
|
|
57bda0 |
track.split(1, 0, 0);
|
|
|
57bda0 |
track.calc_length();
|
|
|
57bda0 |
track.split(0, 1, 0);
|
|
|
1bcd85 |
track.calc_length();
|
|
|
57bda0 |
|
|
|
57bda0 |
std::cout << "track length: " << ((track.points.empty() ? 0.0 : track.points.back().time)/60.0) << " min" << std::endl;
|
|
|
57bda0 |
|
|
|
57bda0 |
f.close();
|
|
|
57bda0 |
|
|
|
57bda0 |
std::cout << "loaded: " << filename << std::endl;
|
|
|
57bda0 |
return true;
|
|
|
57bda0 |
}
|
|
|
8ee194 |
}; // LoaderTrack
|
|
|
8ee194 |
|
|
|
8ee194 |
|
|
|
8ee194 |
class LoaderModel {
|
|
|
8ee194 |
public:
|
|
|
8ee194 |
Model &model;
|
|
|
8ee194 |
const std::string &filename;
|
|
|
8ee194 |
|
|
|
8ee194 |
FILE *f;
|
|
|
8ee194 |
|
|
|
8ee194 |
LoaderModel(Model &model, const std::string &filename):
|
|
|
8ee194 |
model(model),
|
|
|
8ee194 |
filename(filename),
|
|
|
8ee194 |
f()
|
|
|
8ee194 |
{ }
|
|
|
8ee194 |
|
|
|
8ee194 |
void error(const std::string &msg) {
|
|
|
8ee194 |
std::cerr << "Error while loading model: " << filename
|
|
|
8ee194 |
<< ": offset: " << (f ? ftell(f) : 0)
|
|
|
8ee194 |
<< ": " << msg
|
|
|
8ee194 |
<< std::endl;
|
|
|
8ee194 |
}
|
|
|
8ee194 |
|
|
|
8ee194 |
template<typename t=""></typename>
|
|
|
8ee194 |
bool read(T &data) {
|
|
|
8ee194 |
if (fread(&data, 1, sizeof(data), f) != sizeof(data)) {
|
|
|
8ee194 |
error("fread failed");
|
|
|
8ee194 |
return false;
|
|
|
8ee194 |
}
|
|
|
8ee194 |
return true;
|
|
|
8ee194 |
}
|
|
|
8ee194 |
|
|
|
8ee194 |
bool load() {
|
|
|
8ee194 |
model.triangles.clear();
|
|
|
8ee194 |
|
|
|
8ee194 |
std::cout << "loading: " << filename << std::endl;
|
|
|
8ee194 |
|
|
|
8ee194 |
f = fopen(filename.c_str(), "rb");
|
|
|
8ee194 |
if (!f) {
|
|
|
8ee194 |
error("cannot open file");
|
|
|
8ee194 |
return false;
|
|
|
8ee194 |
}
|
|
|
8ee194 |
|
|
|
8ee194 |
char header[80] = {};
|
|
|
8ee194 |
unsigned int count = 0;
|
|
|
e31ea0 |
float normal[3] = {};
|
|
|
e31ea0 |
float vertices[3][3] = {};
|
|
|
8ee194 |
unsigned short attribute = 0;
|
|
|
8ee194 |
Triangle t;
|
|
|
8ee194 |
|
|
|
8ee194 |
bool success = false;
|
|
|
e31ea0 |
int degenerated_count = 0;
|
|
|
8ee194 |
if (read(header) && read(count)) {
|
|
|
8ee194 |
success = true;
|
|
|
8ee194 |
for(unsigned int i = 0; i < count; ++i) {
|
|
|
e31ea0 |
if (!read(normal) || !read(vertices) || !read(attribute))
|
|
|
8ee194 |
{ success = false; break; }
|
|
|
e31ea0 |
for(int j = 0; j < 3; ++j)
|
|
|
e31ea0 |
for(int k = 0; k < 3; ++k)
|
|
|
e31ea0 |
t.vertices[j].c[k] = vertices[j][k];
|
|
|
e31ea0 |
if (t.check(1e-10))
|
|
|
e31ea0 |
model.triangles.push_back(t);
|
|
|
e31ea0 |
else
|
|
|
e31ea0 |
++degenerated_count;
|
|
|
8ee194 |
}
|
|
|
8ee194 |
}
|
|
|
8ee194 |
|
|
|
8ee194 |
fclose(f);
|
|
|
8ee194 |
|
|
|
e31ea0 |
if (degenerated_count)
|
|
|
e31ea0 |
std::cout << "skipped degenerated triangles: " << degenerated_count << std::endl;
|
|
|
e31ea0 |
std::cout << "loaded triangles: " << model.triangles.size() << std::endl;
|
|
|
e31ea0 |
model.normalize();
|
|
|
0a0ecd |
//model.transform(Matrix4::scaling(Vector3(1000, 1000, 1000)));
|
|
|
8ee194 |
|
|
|
8ee194 |
std::cout << "loaded: " << filename << std::endl;
|
|
|
8ee194 |
return success;
|
|
|
8ee194 |
}
|
|
|
8ee194 |
}; // LoaderModel
|
|
|
8ee194 |
|
|
|
8ee194 |
} // namespace
|
|
|
57bda0 |
|
|
|
57bda0 |
|
|
|
1bcd85 |
|
|
|
57bda0 |
bool Loader::load(Track &track, const std::string &filename) {
|
|
|
8ee194 |
return LoaderTrack(track, filename).load();
|
|
|
8ee194 |
}
|
|
|
8ee194 |
|
|
|
8ee194 |
bool Loader::load(Model &model, const std::string &filename) {
|
|
|
8ee194 |
return LoaderModel(model, filename).load();
|
|
|
57bda0 |
}
|
|
|
57bda0 |
|
|
|
1bcd85 |
bool Loader::save(const Track &track, const std::string &filename) {
|
|
|
1bcd85 |
std::cout << "saving: " << filename << std::endl;
|
|
|
1bcd85 |
|
|
|
1bcd85 |
std::ofstream f(filename);
|
|
|
1bcd85 |
if (!f) {
|
|
|
1bcd85 |
std::cerr << "cannot open file for write: " << filename << std::endl;
|
|
|
1bcd85 |
return false;
|
|
|
1bcd85 |
}
|
|
|
1bcd85 |
|
|
|
1bcd85 |
for(TrackPointList::const_iterator i = track.points.begin(); i != track.points.end(); ++i) {
|
|
|
1bcd85 |
f << std::fixed
|
|
|
1bcd85 |
<< std::setprecision(8)
|
|
|
1bcd85 |
<< "G01"
|
|
|
1bcd85 |
<< " X" << i->position.x
|
|
|
1bcd85 |
<< " Y" << i->position.y
|
|
|
1bcd85 |
<< " Z" << i->position.z
|
|
|
1bcd85 |
<< " A" << i->angle
|
|
|
1bcd85 |
<< " F" << (int)round(i->speed*60.0)
|
|
|
1bcd85 |
<< std::endl;
|
|
|
1bcd85 |
}
|
|
|
1bcd85 |
|
|
|
1bcd85 |
f.flush();
|
|
|
1bcd85 |
if (!f) {
|
|
|
1bcd85 |
std::cerr << "write error" << std::endl;
|
|
|
1bcd85 |
return false;
|
|
|
1bcd85 |
}
|
|
|
1bcd85 |
|
|
|
1bcd85 |
f.close();
|
|
|
1bcd85 |
std::cerr << "saved: " << filename << std::endl;
|
|
|
1bcd85 |
return true;
|
|
|
1bcd85 |
}
|
|
|
1bcd85 |
|