Blame loader.cpp

57bda0
57bda0
#include <cstdio></cstdio>
57bda0
#include <fstream></fstream>
57bda0
#include <iostream></iostream>
57bda0
57bda0
#include "loader.h"
57bda0
57bda0
57bda0
class Loader::Internal {
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;
57bda0
    Point point;
57bda0
    
57bda0
    Internal(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; }
57bda0
            else if (mode <= 1 && isdigit(c)) { number = number*10 + (c - '0')*sign; sign = 1; mode = 1; }
57bda0
            else if (mode == 2 && isdigit(c)) { number += (c - '0')*(frac *= 0.1); }
57bda0
            else if (mode == 0) { error("expected number"); return c >= 0; }
57bda0
            else { break; }
57bda0
            get();
57bda0
        }
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);
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);
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
    }
57bda0
};
57bda0
57bda0
57bda0
bool Loader::load(Track &track, const std::string &filename) {
57bda0
    return Internal(track, filename).load();
57bda0
}
57bda0