Blame loader.cpp

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