<commit_before>#include "persistence.h"
#include <algorithm>

BMCell::BMCell() {
    first = 0;
    second = 0;
}

///////////////////////////////////////////////////////////////////////////////

BMCol::BMCol() {
    header = BMCell();
    faces = std::vector<BMCell>();
}

///////////////////////////////////////////////////////////////////////////////

void BMCol::print() {
    std::cout << "----" << std::endl;
    header.print();
    std::cout << "...." << std::endl;
    for(auto & e: faces) {
        e.print();
    }
}

///////////////////////////////////////////////////////////////////////////////

BMatrix::BMatrix(std::vector<BMCol> &_cols) {
    this->cols = _cols;
}

void BMatrix::append(const BMatrix &other) {
    for(auto& e : other.cols) {
        this->cols.push_back(e);
    }
}

void BMatrix::sort() {
    std::sort(cols.begin(), cols.end());
}

///////////////////////////////////////////////////////////////////////////////

PersistentHomology::PersistentHomology()  {
}

PersistentHomology::~PersistentHomology()  {
}

BMatrix PersistentHomology::compute_matrix(const SimplicialComplex &sc) {
    std::map<std::string, int> mapping;
    return PersistentHomology::compute_matrix(sc, 0, mapping);
}

BMatrix PersistentHomology::compute_matrix(
    const SimplicialComplex &sc,
    int complexID,
    std::map<std::string, int> &simplex_mapping
){
	int filtration_size = sc.allSimplicis.size();

	// construct mapping between simplices and their IDs

    // if simplex_mapping is empty, it means this is not a subcomplex. Then we
    // just build the mapping for the whole complex.
    if(simplex_mapping.size() == 0) {
        for(int i = 0; i < filtration_size; i++)
            simplex_mapping[sc.allSimplicis[i].id()] = i+1;
    }

	// initialize reduction to boundaries - just a vector of lists
    std::vector<BMCol> cols;
    cols.resize(filtration_size+1);

	// reserve 1st entry as dummy simplex, in line with reduced persistence
	cols[0] = BMCol();

	// for each simplex, take its boundary and assign those simplices to its list
	for(int i = 0; i < filtration_size; i++)  {
		int idx = i+1;
		Simplex simplex = sc.allSimplicis[i];
        int globalID = simplex_mapping[simplex.id()];

        cols[idx] = BMCol();
        cols[idx].header = BMCell(globalID, complexID);

		// if 0-simplex, then reserve face as dummy simplex
		if(simplex.dim()==0)  {
			cols[idx].faces.push_back(BMCell(0, complexID));
			continue;
		}

		std::vector<Simplex> faces = simplex.faces();
		for(int f = 0; f < faces.size(); f++)  {
			Simplex next_face = faces[f];
			int face_id = simplex_mapping[next_face.id()];
			cols[idx].faces.push_back(BMCell(face_id, complexID));
		}
		// sort list, so we can efficiently add cycles and inspect death cycles
        std::sort(cols[idx].faces.begin(), cols[idx].faces.end());
	}

    BMatrix bm(cols);

    // reduce the boundary matrix
    reduce_matrix2(bm);

    return bm;
}

//void PersistentHomology::reduce_matrix(BoundaryMatrix &bm) {
	//std::cout << "doing reduction..." << std::endl;
	//ComputationTimer persistence_timer("persistence computation time");
	//persistence_timer.start();

    //int filtration_size = bm.data.size()-1; // minus the empty simplex
    //std::vector< std::list<int> > &reduction = bm.data;

	//// initialize death cycle reference - nothing there yet, so just give it all -1
    //std::vector<int> death_cycle_ref(filtration_size+1);
	//for(int i = 0; i < filtration_size+1; i++)
		//death_cycle_ref[i] = -1;

	//// perform reduction
    //for(int i = 0; i < filtration_size; i++)  {
        //int idx = i+1;
        //std::cout << "idx: " << idx << std::endl;

        //// until we are either definitively a birth cycle or a death cycle ...
        //int low_i = reduction[idx].back();
        //int num_chains_added = 0;

        //while(reduction[idx].size() > 0 && death_cycle_ref[low_i] != -1)  {
            //num_chains_added++;
            //// add the prior death cycle to us
            //int death_cycle_ind = death_cycle_ref[low_i];

            //PHCycle::iterator our_cycle_iter = reduction[idx].begin(), added_cycle_iter = reduction[death_cycle_ind].begin();
            //while(added_cycle_iter != reduction[death_cycle_ind].end())  {
                //if(our_cycle_iter == reduction[idx].end())  {
                    //reduction[idx].push_back(*added_cycle_iter);
                    //++added_cycle_iter;
                    //continue;
                //}
                //int sigma_1 = *our_cycle_iter, sigma_2 = *added_cycle_iter;
                //if(sigma_1 == sigma_2)  {
                    //our_cycle_iter = reduction[idx].erase(our_cycle_iter);
                    //++added_cycle_iter;
                //}
                //else if(sigma_1 < sigma_2)
                    //++our_cycle_iter;
                //else  {
                    //reduction[idx].insert(our_cycle_iter, sigma_2);
                    //++added_cycle_iter;
                //}
            //}
            //low_i = reduction[idx].back();
        //}

        //// if we are a death cycle then add us to the list, add as persistence pairings
        //if(reduction[idx].size() > 0)  {
            //death_cycle_ref[low_i] = idx;
            //// kill cycle at low_i, since it represents a birth
            //reduction[low_i] = PHCycle();
        //}
    //}

	//persistence_timer.end();
	//persistence_timer.dump_time();
//}

BMCol PersistentHomology::reduce_column(BMCol &left_col, BMCol &right_col) {
    BMCol result;
    result.header = left_col.header;

    auto & left = left_col.faces;
    auto & right = right_col.faces;

    int il = 0;
    int ir = 0;
    while(il < left.size() && ir < right.size()) {
        if(left[il] < right[ir]) {
            result.faces.push_back(left[il]);
            il += 1;
        } else if(right[ir] < left[il]) {
            result.faces.push_back(right[ir]);
            ir += 1;
        } else {
            il += 1;
            ir += 1;
        }
    }
    return result;
}

void PersistentHomology::reduce_matrix2(BMatrix &bm) {
	std::cout << "doing reduction2..." << std::endl;
	ComputationTimer persistence_timer("persistence computation time");
	persistence_timer.start();

    int filtration_size = bm.cols.size()-1; // minus the empty simplex
    std::map<BMCell, int> low_to_col; // from low[i] to col indices

    int i = -1;
    BMCell minusOne = BMCell(-1, -1);
    for(auto &col : bm.cols) {
        i ++;
        if(col.faces.size() == 0) continue;

        BMCell mx = col.faces.back();
        while(low_to_col.find(mx) != low_to_col.end()) {
            auto& col_to_reduce = bm.cols[low_to_col[mx]];
            auto new_col = reduce_column(col, col_to_reduce);
            col = new_col;
            if(col.faces.size() == 0) {
                mx = minusOne;
                break;
            }
            mx = col.faces.back();
        }

        if(mx == minusOne) {
            //if(low_to_col.find(bm.header[i]) != low_to_col.end()) {
                //low_to_col.erase();
            //}
        } else {
            low_to_col[mx] = i;
        }
    }

	persistence_timer.end();
	persistence_timer.dump_time();
}

BMatrix PersistentHomology::compute_matrix( Cover &cover ) {
    std::cout << "calculating reduction matrix for cover\n";

    std::vector<BMatrix> rm_vec; // reduced matrices vector
    for(int i = 0; i < cover.subComplexCount(); ++ i) {
        std::cout << "subcomplex: " << i << std::endl;
        //cover.subComplexes[cover.IDs[i]].print();

        BMatrix bm = PersistentHomology::compute_matrix(
            cover.subComplexes[i],
            i,
            cover.SimplexIDMap
        );
        rm_vec.push_back(bm);
    }

    std::cout << "gluing...\n";
    BMatrix bm = rm_vec[0];
    if(rm_vec.size() > 1) {
        for(int i = 1; i < rm_vec.size(); i ++) {
            bm.append(rm_vec[i]);
        }
    }
    bm.sort();

    std::cout << "reducing glued matrix\n";
    reduce_matrix2(bm);
    return bm;
}

PersistenceDiagram* PersistentHomology::read_persistence_diagram
(BMatrix &reduction, SimplicialComplex &sc) {

	int filtration_size = sc.allSimplicis.size();

	std::vector< std::pair<int,int> > persistence_pairing;

    for(int i = 1; i < reduction.cols.size(); i++)  {

        // until we are either definitively a birth cycle or a death cycle ...
        if(reduction.cols[i].faces.size() == 0) {
            continue;
        }

        int low_i = reduction.cols[i].faces.back().first;

        // if we are a death cycle then add us to the list, add as persistence pairings
        if(reduction.cols[i].faces.size() > 0)  {
            if(low_i > 0)
                persistence_pairing.push_back(std::pair<int,int>(
                            low_i-1,
                            reduction.cols[i].header.first-1));
        }
    }

	std::vector<PersistentPair> persistent_pairs;
	for(int i = 0; i < persistence_pairing.size(); i++)  {
		std::pair<int,int> pairing = persistence_pairing[i];
		Simplex birth_simplex = sc.allSimplicis[pairing.first], death_simplex = sc.allSimplicis[pairing.second];
		if(death_simplex.get_simplex_distance() == birth_simplex.get_simplex_distance())
			continue;

		PersistentPair persistent_pair(birth_simplex.dim(), birth_simplex.get_simplex_distance(), death_simplex.get_simplex_distance());

		persistent_pairs.push_back(persistent_pair);
	}

	PersistenceDiagram *pd = new PersistenceDiagram(persistent_pairs);
	return pd;
}
<commit_msg>don't append redundent zero cols of boundary matrix<commit_after>#include "persistence.h"
#include <algorithm>

BMCell::BMCell() {
    first = 0;
    second = 0;
}
///////////////////////////////////////////////////////////////////////////////

BMCol::BMCol() {
    header = BMCell(0, 0);
    faces = std::vector<BMCell>();
}

///////////////////////////////////////////////////////////////////////////////

void BMCol::print() {
    std::cout << "----" << std::endl;
    header.print();
    std::cout << "...." << std::endl;
    for(auto & e: faces) {
        e.print();
    }
}

///////////////////////////////////////////////////////////////////////////////

BMatrix::BMatrix(std::vector<BMCol> &_cols) {
    this->cols = _cols;
}

void BMatrix::append(const BMatrix &other) {
    // TODO use move_iterator for better performance
    BMCell zero(0,0);
    for(auto& e : other.cols) {
        if(e.header == zero) continue;
        this->cols.push_back(e);
    }
}

void BMatrix::sort() {
    std::sort(cols.begin(), cols.end());
}

///////////////////////////////////////////////////////////////////////////////

PersistentHomology::PersistentHomology()  {
}

PersistentHomology::~PersistentHomology()  {
}

BMatrix PersistentHomology::compute_matrix(const SimplicialComplex &sc) {
    std::map<std::string, int> mapping;
    return PersistentHomology::compute_matrix(sc, 0, mapping);
}

BMatrix PersistentHomology::compute_matrix(
    const SimplicialComplex &sc,
    int complexID,
    std::map<std::string, int> &simplex_mapping
){
	int filtration_size = sc.allSimplicis.size();

	// construct mapping between simplices and their IDs

    // if simplex_mapping is empty, it means this is not a subcomplex. Then we
    // just build the mapping for the whole complex.
    if(simplex_mapping.size() == 0) {
        for(int i = 0; i < filtration_size; i++)
            simplex_mapping[sc.allSimplicis[i].id()] = i+1;
    }

	// initialize reduction to boundaries - just a vector of lists
    std::vector<BMCol> cols;
    cols.resize(filtration_size+1);

	// reserve 1st entry as dummy simplex, in line with reduced persistence
	cols[0] = BMCol();

	// for each simplex, take its boundary and assign those simplices to its list
	for(int i = 0; i < filtration_size; i++)  {
		int idx = i+1;
		Simplex simplex = sc.allSimplicis[i];
        int globalID = simplex_mapping[simplex.id()];

        cols[idx] = BMCol();
        cols[idx].header = BMCell(globalID, complexID);

		// if 0-simplex, then reserve face as dummy simplex
		if(simplex.dim()==0)  {
			cols[idx].faces.push_back(BMCell(0, complexID));
			continue;
		}

		std::vector<Simplex> faces = simplex.faces();
		for(int f = 0; f < faces.size(); f++)  {
			Simplex next_face = faces[f];
			int face_id = simplex_mapping[next_face.id()];
			cols[idx].faces.push_back(BMCell(face_id, complexID));
		}
		// sort list, so we can efficiently add cycles and inspect death cycles
        std::sort(cols[idx].faces.begin(), cols[idx].faces.end());
	}

    BMatrix bm(cols);

    // reduce the boundary matrix
    reduce_matrix2(bm);

    return bm;
}

BMCol PersistentHomology::reduce_column(BMCol &left_col, BMCol &right_col) {
    BMCol result;
    result.header = left_col.header;

    auto & left = left_col.faces;
    auto & right = right_col.faces;

    int il = 0;
    int ir = 0;
    while(il < left.size() && ir < right.size()) {
        if(left[il] < right[ir]) {
            result.faces.push_back(left[il]);
            il += 1;
        } else if(right[ir] < left[il]) {
            result.faces.push_back(right[ir]);
            ir += 1;
        } else {
            il += 1;
            ir += 1;
        }
    }
    return result;
}

void PersistentHomology::reduce_matrix2(BMatrix &bm) {
	std::cout << "doing reduction2..." << std::endl;
	ComputationTimer persistence_timer("persistence computation time");
	persistence_timer.start();

    int filtration_size = bm.cols.size()-1; // minus the empty simplex
    std::map<BMCell, int> low_to_col; // from low[i] to col indices

    int i = -1;
    BMCell minusOne = BMCell(-1, -1);
    for(auto &col : bm.cols) {
        i ++;
        if(col.faces.size() == 0) continue;

        BMCell mx = col.faces.back();
        while(low_to_col.find(mx) != low_to_col.end()) {
            auto& col_to_reduce = bm.cols[low_to_col[mx]];
            auto new_col = reduce_column(col, col_to_reduce);
            col = new_col;
            if(col.faces.size() == 0) {
                mx = minusOne;
                break;
            }
            mx = col.faces.back();
        }

        if(mx == minusOne) {
            //if(low_to_col.find(bm.header[i]) != low_to_col.end()) {
                //low_to_col.erase();
            //}
        } else {
            low_to_col[mx] = i;
        }
    }

	persistence_timer.end();
	persistence_timer.dump_time();
}

BMatrix PersistentHomology::compute_matrix( Cover &cover ) {
    std::cout << "calculating reduction matrix for cover\n";

    std::vector<BMatrix> rm_vec; // reduced matrices vector
    for(int i = 0; i < cover.subComplexCount(); ++ i) {
        std::cout << "subcomplex: " << i << std::endl;
        //cover.subComplexes[cover.IDs[i]].print();

        BMatrix bm = PersistentHomology::compute_matrix(
            cover.subComplexes[i],
            i,
            cover.SimplexIDMap
        );
        rm_vec.push_back(bm);
    }

    //TODO calculate boundary matrix for intersection

    std::cout << "gluing...\n";
    BMatrix bm = rm_vec[0];
    std::cout << bm.size() << std::endl;
    if(rm_vec.size() > 1) {
        for(int i = 1; i < rm_vec.size(); i ++) {
            bm.append(rm_vec[i]);
        }
    }
    bm.sort();
    std::cout << bm.size() << std::endl;

    std::cout << "reducing glued matrix\n";
    reduce_matrix2(bm);
    return bm;
}

PersistenceDiagram* PersistentHomology::read_persistence_diagram
(BMatrix &reduction, SimplicialComplex &sc) {

	int filtration_size = sc.allSimplicis.size();

	std::vector< std::pair<int,int> > persistence_pairing;

    for(int i = 1; i < reduction.cols.size(); i++)  {

        // until we are either definitively a birth cycle or a death cycle ...
        if(reduction.cols[i].faces.size() == 0) {
            continue;
        }

        int low_i = reduction.cols[i].faces.back().first;

        // if we are a death cycle then add us to the list, add as persistence pairings
        if(reduction.cols[i].faces.size() > 0)  {
            if(low_i > 0)
                persistence_pairing.push_back(std::pair<int,int>(
                            low_i-1,
                            reduction.cols[i].header.first-1));
        }
    }

	std::vector<PersistentPair> persistent_pairs;
	for(int i = 0; i < persistence_pairing.size(); i++)  {
		std::pair<int,int> pairing = persistence_pairing[i];
		Simplex birth_simplex = sc.allSimplicis[pairing.first], death_simplex = sc.allSimplicis[pairing.second];
		if(death_simplex.get_simplex_distance() == birth_simplex.get_simplex_distance())
			continue;

		PersistentPair persistent_pair(birth_simplex.dim(), birth_simplex.get_simplex_distance(), death_simplex.get_simplex_distance());

		persistent_pairs.push_back(persistent_pair);
	}

	PersistenceDiagram *pd = new PersistenceDiagram(persistent_pairs);
	return pd;
}
<|endoftext|>


<commit_before>#include "MovieStreamer.hpp"
#include <QtMultimedia/QAbstractVideoSurface>
#include <QtMultimedia/QMediaPlayer>
#include <QtMultimediaWidgets/QVideoWidget>
#include <QApplication>
#include <QThread>
#include <QMediaPlaylist>
#include <FAST/Data/Image.hpp>

namespace fast {

class VideoSurface : public QAbstractVideoSurface {

    public:
        MovieStreamer* streamer;

    QList<QVideoFrame::PixelFormat> supportedPixelFormats(
            QAbstractVideoBuffer::HandleType handleType = QAbstractVideoBuffer::NoHandle) const {
        Q_UNUSED(handleType);

        // Return the formats you will support
        return QList<QVideoFrame::PixelFormat>()
                << QVideoFrame::Format_RGB565
                << QVideoFrame::Format_RGB24
                << QVideoFrame::Format_RGB32
                << QVideoFrame::Format_RGB555;
    }

    bool present(const QVideoFrame &frame) {
        Reporter::info() << "Movie frame received!" << Reporter::end();
        Reporter::info() << "Format: " << frame.pixelFormat() << Reporter::end();
        if(frame.pixelFormat() == QVideoFrame::PixelFormat::Format_Invalid) {
            // Movie is finished
            Reporter::info() << "Movie finished." << Reporter::end();
            streamer->addLastFrame();
            streamer->setFinished(true);
            return false;
        }

        QVideoFrame cloneFrame(frame);
        cloneFrame.map(QAbstractVideoBuffer::ReadOnly);
        const int width = frame.width();
        const int height = frame.height();
        QImage image(cloneFrame.bits(), width, height, frame.bytesPerLine(), QVideoFrame::imageFormatFromPixelFormat(frame.pixelFormat()));

        QImage::Format format;
        if(streamer->getGrayscale()) {
            format = QImage::Format_Grayscale8;
        } else {
            format = QImage::Format_RGB888;
        }
        QImage convertedImage = image.convertToFormat(format);
        try {
            streamer->addNewImageFrame(convertedImage.constBits(), width, height);
            Reporter::info() << "Finished processing movie frame" << Reporter::end();
        } catch(ThreadStopped &e) {
        }

        return true;
    }

    void stateChanged(QMediaPlayer::State state) {
        if(state == QMediaPlayer::StoppedState) {
            streamer->addLastFrame();
            Reporter::info() << "QMediaPlayer state changed to stopped - stopping stream" << Reporter::end();
            streamer->setFinished(true);
        }
    }

    ~VideoSurface() {
        Reporter::info() << "Video surface of movie streamer was destroyed" << Reporter::end();
    }
};

void MovieStreamer::addLastFrame() {
    if(m_currentImage) {
        m_currentImage->setLastFrame("MovieStreamer");
		addOutputData(0, m_currentImage);
        ++m_framesAdded;
        Reporter::info() << "Added last frame with a total of: " << m_framesAdded << Reporter::end();
        // Make sure we end the waiting thread if first frame has not been inserted
        frameAdded();
    }
}

void MovieStreamer::addNewImageFrame(const uchar* data, int width, int height) {
    auto output = Image::create(
            width,
            height,
            TYPE_UINT8,
            mGrayscale ? 1 : 3,
            getMainDevice(),
            data
    );
    std::chrono::duration<double, std::milli> elapsed = std::chrono::high_resolution_clock::now() - m_startTime;
    output->setCreationTimestamp((uint64_t)elapsed.count());

    if(m_currentImage) {
        addOutputData(0, m_currentImage);
        ++m_framesAdded;
        Reporter::info() << "Added frames: " << m_framesAdded << Reporter::end();
        // Make sure we end the waiting thread if first frame has not been inserted
        frameAdded();
    }
    m_currentImage = output;
}

void MovieStreamer::setFilename(std::string filename) {
    mFilename = filename;
    mIsModified = true;
}

void MovieStreamer::loadAttributes() {
    setFilename(getStringAttribute("filename"));
    setGrayscale(getBooleanAttribute("grayscale"));
}

MovieStreamer::MovieStreamer() {
    createOutputPort<Image>(0);

    createStringAttribute("filename", "Filename", "Filepath to movie file", "");
    createBooleanAttribute("grayscale", "Grayscale", "Convert movie to grayscale while streaming", mGrayscale);
    createBooleanAttribute("loop", "Loop", "Loop movie", m_loop);
}

MovieStreamer::MovieStreamer(std::string filename, bool grayscale, bool loop) {
    createOutputPort(0, "Image");
    setFilename(filename);
    setLoop(loop);
    setGrayscale(grayscale);
}

MovieStreamerWorker::MovieStreamerWorker(MovieStreamer* streamer) {
    mStreamer = streamer;
}

MovieStreamerWorker::~MovieStreamerWorker() {
    delete m_myVideoSurface;
    Reporter::info() << "Movie streamer worker destroyed" << Reporter::end();
}

void MovieStreamerWorker::run() {
    m_player = new QMediaPlayer();
    QObject::connect(this, &MovieStreamerWorker::finished, m_player, &QMediaPlayer::deleteLater);
    //std::this_thread::sleep_for(std::chrono::milliseconds(3000));
    m_myVideoSurface = new VideoSurface();
    m_myVideoSurface->streamer = mStreamer;
    m_player->setMuted(true);
    m_player->setVideoOutput(m_myVideoSurface);
    QObject::connect(m_player, &QMediaPlayer::stateChanged, std::bind(&VideoSurface::stateChanged, m_myVideoSurface, std::placeholders::_1));
    std::string prefix = "";
    if(mStreamer->getFilename()[0] != '/' && mStreamer->getFilename()[1] == ':') // On windows w want file:///C:/asd/asd..
        prefix = "/";
    auto playlist = new QMediaPlaylist();
    playlist->addMedia(QUrl(("file://" + prefix + mStreamer->getFilename()).c_str()));
    if(mStreamer->getLoop()) {
        playlist->setPlaybackMode(QMediaPlaylist::Loop);
    }
    m_player->setPlaylist(playlist);
    m_player->play(); // This does not block
    Reporter::info() << "Play returned" << Reporter::end();
}

void MovieStreamer::execute() {
    if(!m_streamIsStarted) {
        if(!fileExists(mFilename))
            throw FileNotFoundException(mFilename);
        thread = new QThread;
        MovieStreamerWorker* worker = new MovieStreamerWorker(this);
        worker->moveToThread(thread);
        //QObject::connect(worker, SIGNAL(error(QString)), this, SLOT(errorString(QString)));
        QObject::connect(thread, SIGNAL(started()), worker, SLOT(run()));
        QObject::connect(worker, SIGNAL(finished()), thread, SLOT(quit()));
        QObject::connect(worker, SIGNAL(finished()), worker, SLOT(deleteLater()));
        QObject::connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
        QObject::connect(thread, SIGNAL(finished()), worker, SLOT(deleteLater()));
        m_startTime = std::chrono::high_resolution_clock::now();
        thread->start();
        reportInfo() << "FINISHED QThread setup in MovieStreamer" << reportEnd();
        m_streamIsStarted = true;
    }

    waitForFirstFrame();
    reportInfo() << "Finished movie streamer execute" << reportEnd();
}

bool MovieStreamer::hasReachedEnd() {
    return m_finished;
}

void MovieStreamer::setGrayscale(bool grayscale) {
    mGrayscale = grayscale;
}

std::string MovieStreamer::getFilename() const {
    return mFilename;
}

bool MovieStreamer::getGrayscale() const {
    return mGrayscale;
}

void MovieStreamer::setFinished(bool finished) {
    m_finished = finished;
}

MovieStreamer::~MovieStreamer() {
    reportInfo() << "Destroying movie streamer" << reportEnd();
    if(thread != nullptr)
		thread->quit();
    stop();
}

int MovieStreamer::getFramesAdded() const {
    return m_framesAdded;
}

void MovieStreamer::setLoop(bool loop) {
    m_loop = loop;
    setModified(true);
}

bool MovieStreamer::getLoop() const {
    return m_loop;
}

}<commit_msg>Fixed bug with relative paths in MovieStreamer<commit_after>#include "MovieStreamer.hpp"
#include <QtMultimedia/QAbstractVideoSurface>
#include <QtMultimedia/QMediaPlayer>
#include <QtMultimediaWidgets/QVideoWidget>
#include <QApplication>
#include <QThread>
#include <QDir>
#include <QMediaPlaylist>
#include <FAST/Data/Image.hpp>

namespace fast {

class VideoSurface : public QAbstractVideoSurface {

    public:
        MovieStreamer* streamer;

    QList<QVideoFrame::PixelFormat> supportedPixelFormats(
            QAbstractVideoBuffer::HandleType handleType = QAbstractVideoBuffer::NoHandle) const {
        Q_UNUSED(handleType);

        // Return the formats you will support
        return QList<QVideoFrame::PixelFormat>()
                << QVideoFrame::Format_RGB565
                << QVideoFrame::Format_RGB24
                << QVideoFrame::Format_RGB32
                << QVideoFrame::Format_RGB555;
    }

    bool present(const QVideoFrame &frame) {
        Reporter::info() << "Movie frame received!" << Reporter::end();
        Reporter::info() << "Format: " << frame.pixelFormat() << Reporter::end();
        if(frame.pixelFormat() == QVideoFrame::PixelFormat::Format_Invalid) {
            // Movie is finished
            Reporter::info() << "Movie finished." << Reporter::end();
            streamer->addLastFrame();
            streamer->setFinished(true);
            return false;
        }

        QVideoFrame cloneFrame(frame);
        cloneFrame.map(QAbstractVideoBuffer::ReadOnly);
        const int width = frame.width();
        const int height = frame.height();
        QImage image(cloneFrame.bits(), width, height, frame.bytesPerLine(), QVideoFrame::imageFormatFromPixelFormat(frame.pixelFormat()));

        QImage::Format format;
        if(streamer->getGrayscale()) {
            format = QImage::Format_Grayscale8;
        } else {
            format = QImage::Format_RGB888;
        }
        QImage convertedImage = image.convertToFormat(format);
        try {
            streamer->addNewImageFrame(convertedImage.constBits(), width, height);
            Reporter::info() << "Finished processing movie frame" << Reporter::end();
        } catch(ThreadStopped &e) {
        }

        return true;
    }

    void stateChanged(QMediaPlayer::State state) {
        if(state == QMediaPlayer::StoppedState) {
            streamer->addLastFrame();
            Reporter::info() << "QMediaPlayer state changed to stopped - stopping stream" << Reporter::end();
            streamer->setFinished(true);
        }
    }

    ~VideoSurface() {
        Reporter::info() << "Video surface of movie streamer was destroyed" << Reporter::end();
    }
};

void MovieStreamer::addLastFrame() {
    if(m_currentImage) {
        m_currentImage->setLastFrame("MovieStreamer");
		addOutputData(0, m_currentImage);
        ++m_framesAdded;
        Reporter::info() << "Added last frame with a total of: " << m_framesAdded << Reporter::end();
        // Make sure we end the waiting thread if first frame has not been inserted
        frameAdded();
    }
}

void MovieStreamer::addNewImageFrame(const uchar* data, int width, int height) {
    auto output = Image::create(
            width,
            height,
            TYPE_UINT8,
            mGrayscale ? 1 : 3,
            getMainDevice(),
            data
    );
    std::chrono::duration<double, std::milli> elapsed = std::chrono::high_resolution_clock::now() - m_startTime;
    output->setCreationTimestamp((uint64_t)elapsed.count());

    if(m_currentImage) {
        addOutputData(0, m_currentImage);
        ++m_framesAdded;
        Reporter::info() << "Added frames: " << m_framesAdded << Reporter::end();
        // Make sure we end the waiting thread if first frame has not been inserted
        frameAdded();
    }
    m_currentImage = output;
}

void MovieStreamer::setFilename(std::string filename) {
    mFilename = filename;
    mIsModified = true;
}

void MovieStreamer::loadAttributes() {
    setFilename(getStringAttribute("filename"));
    setGrayscale(getBooleanAttribute("grayscale"));
}

MovieStreamer::MovieStreamer() {
    createOutputPort<Image>(0);

    createStringAttribute("filename", "Filename", "Filepath to movie file", "");
    createBooleanAttribute("grayscale", "Grayscale", "Convert movie to grayscale while streaming", mGrayscale);
    createBooleanAttribute("loop", "Loop", "Loop movie", m_loop);
}

MovieStreamer::MovieStreamer(std::string filename, bool grayscale, bool loop) {
    createOutputPort(0, "Image");
    setFilename(filename);
    setLoop(loop);
    setGrayscale(grayscale);
}

MovieStreamerWorker::MovieStreamerWorker(MovieStreamer* streamer) {
    mStreamer = streamer;
}

MovieStreamerWorker::~MovieStreamerWorker() {
    delete m_myVideoSurface;
    Reporter::info() << "Movie streamer worker destroyed" << Reporter::end();
}

void MovieStreamerWorker::run() {
    m_player = new QMediaPlayer();
    QObject::connect(this, &MovieStreamerWorker::finished, m_player, &QMediaPlayer::deleteLater);
    //std::this_thread::sleep_for(std::chrono::milliseconds(3000));
    m_myVideoSurface = new VideoSurface();
    m_myVideoSurface->streamer = mStreamer;
    m_player->setMuted(true);
    m_player->setVideoOutput(m_myVideoSurface);
    QObject::connect(m_player, &QMediaPlayer::stateChanged, std::bind(&VideoSurface::stateChanged, m_myVideoSurface, std::placeholders::_1));
    std::string prefix = "";
    if(mStreamer->getFilename()[0] != '/' && mStreamer->getFilename()[1] == ':') { // On windows w want file:///C:/asd/asd..
        prefix = "/";
    } else if (mStreamer->getFilename()[0] != '/' && mStreamer->getFilename()[1] != ':') {
        // Relative path, make into absolute path:
#ifdef WIN32
        prefix = "/" + QDir::currentPath().toStdString() + "/";
#else
        prefix = QDir::currentPath().toStdString() + "/";
#endif
    }
    auto playlist = new QMediaPlaylist();
    playlist->addMedia(QUrl(("file://" + prefix + mStreamer->getFilename()).c_str()));
    if(mStreamer->getLoop()) {
        playlist->setPlaybackMode(QMediaPlaylist::Loop);
    }
    m_player->setPlaylist(playlist);
    m_player->play(); // This does not block
    Reporter::info() << "Play returned" << Reporter::end();
}

void MovieStreamer::execute() {
    if(!m_streamIsStarted) {
        if(!fileExists(mFilename))
            throw FileNotFoundException(mFilename);
        thread = new QThread;
        MovieStreamerWorker* worker = new MovieStreamerWorker(this);
        worker->moveToThread(thread);
        //QObject::connect(worker, SIGNAL(error(QString)), this, SLOT(errorString(QString)));
        QObject::connect(thread, SIGNAL(started()), worker, SLOT(run()));
        QObject::connect(worker, SIGNAL(finished()), thread, SLOT(quit()));
        QObject::connect(worker, SIGNAL(finished()), worker, SLOT(deleteLater()));
        QObject::connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
        QObject::connect(thread, SIGNAL(finished()), worker, SLOT(deleteLater()));
        m_startTime = std::chrono::high_resolution_clock::now();
        thread->start();
        reportInfo() << "FINISHED QThread setup in MovieStreamer" << reportEnd();
        m_streamIsStarted = true;
    }

    waitForFirstFrame();
    reportInfo() << "Finished movie streamer execute" << reportEnd();
}

bool MovieStreamer::hasReachedEnd() {
    return m_finished;
}

void MovieStreamer::setGrayscale(bool grayscale) {
    mGrayscale = grayscale;
}

std::string MovieStreamer::getFilename() const {
    return mFilename;
}

bool MovieStreamer::getGrayscale() const {
    return mGrayscale;
}

void MovieStreamer::setFinished(bool finished) {
    m_finished = finished;
}

MovieStreamer::~MovieStreamer() {
    reportInfo() << "Destroying movie streamer" << reportEnd();
    if(thread != nullptr)
		thread->quit();
    stop();
}

int MovieStreamer::getFramesAdded() const {
    return m_framesAdded;
}

void MovieStreamer::setLoop(bool loop) {
    m_loop = loop;
    setModified(true);
}

bool MovieStreamer::getLoop() const {
    return m_loop;
}

}<|endoftext|>


<commit_before>/* Copyright © 2001-2014, Canal TP and/or its affiliates. All rights reserved.

This file is part of Navitia,
    the software to build cool stuff with public transport.

Hope you'll enjoy and contribute to this project,
    powered by Canal TP (www.canaltp.fr).
Help us simplify mobility and open public transport:
    a non ending quest to the responsive locomotion way of traveling!

LICENCE: This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.

You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.

Stay tuned using
twitter @navitia
IRC #navitia on freenode
https://groups.google.com/d/forum/navitia
www.navitia.io
*/

#include "departure_boards.h"
#include "request_handle.h"
#include "routing/get_stop_times.h"
#include "type/pb_converter.h"
#include "routing/dataraptor.h"
#include "utils/paginate.h"
#include "routing/dataraptor.h"

#include <boost/lexical_cast.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/container/flat_set.hpp>

namespace pt = boost::posix_time;

namespace navitia { namespace timetables {

static void
render(PbCreator& pb_creator,
          const std::map<stop_point_route, pbnavitia::ResponseStatus>& response_status,
          const std::map<stop_point_route, vector_dt_st>& map_route_stop_point,
          DateTime datetime,
          DateTime max_datetime,
          boost::optional<const std::string> calendar_id,
          uint32_t depth) {
    pb_creator.action_period = pt::time_period(to_posix_time(datetime, pb_creator.data),
                                               to_posix_time(max_datetime, pb_creator.data));

    for(auto id_vec : map_route_stop_point) {
        auto schedule = pb_creator.add_stop_schedules();
        //Each schedule has a stop_point and a route
        pb_creator.fill(pb_creator.data.pt_data->stop_points[id_vec.first.first.val],
                schedule->mutable_stop_point(), depth);

        auto m_route = schedule->mutable_route();
        pb_creator.fill(pb_creator.data.pt_data->routes[id_vec.first.second.val], m_route, depth);
        if (pb_creator.data.pt_data->routes[id_vec.first.second.val]->line != nullptr){
            auto m_line = m_route->mutable_line();
            pb_creator.fill(pb_creator.data.pt_data->routes[id_vec.first.second.val]->line, m_line, 0);
        }
        auto pt_display_information = schedule->mutable_pt_display_informations();

        pb_creator.fill(pb_creator.data.pt_data->routes[id_vec.first.second.val], pt_display_information, 0);

        //Now we fill the date_times
        for(auto dt_st : id_vec.second) {
            auto date_time = schedule->add_date_times();
            const auto& st_calendar = navitia::StopTimeCalandar(dt_st.second, dt_st.first, calendar_id);
            pb_creator.fill(&st_calendar, date_time, 0);
            if (dt_st.second != nullptr) {
                auto vj = dt_st.second->vehicle_journey;
                if(vj != nullptr) {
                    for (const auto& comment: pb_creator.data.pt_data->comments.get(*vj)) {
                        pb_creator.fill(&comment, date_time->mutable_properties()->add_notes(), 0);
                    }
                }
            }
        }
        const auto& it = response_status.find(id_vec.first);
        if(it != response_status.end()){
            schedule->set_response_status(it->second);
        }
    }
}

static time_duration to_navitia(const boost::posix_time::time_duration& dur) {
    return navitia::seconds(dur.total_seconds());
}

time_duration length_of_time(const time_duration& duration_1,
                       const time_duration& duration_2) {
    if (duration_1 <= duration_2) {
        return duration_2 - duration_1;
    } else {
        return duration_2 + (hours(24) - duration_1);
    }
}

bool between_opening_and_closing(const time_duration& me,
                                 const time_duration& opening,
                                 const time_duration& closing) {
    if (opening < closing) {
        return (opening <= me && me <= closing);
    } else {
        return (opening <= me || me <= closing);
    }
}

bool line_closed (const time_duration& duration,
             const time_duration& opening,
             const time_duration& closing,
             const pt::ptime& date) {
    const auto begin = to_navitia(date.time_of_day());
    return !between_opening_and_closing(begin, opening, closing)
            && !between_opening_and_closing((begin + duration), opening, closing)
            && duration < (length_of_time(opening, closing) + length_of_time(begin, opening));
}

static bool line_closed (const time_duration& duration,
                  const type::Route* route,
                  const pt::ptime& date) {
    if (route->line->opening_time && route->line->closing_time) {
        const auto opening = to_navitia(*route->line->opening_time);
        const auto closing = to_navitia(*route->line->closing_time);
        return line_closed(duration, opening, closing, date);
    }
    return false;
}

void departure_board(PbCreator& pb_creator, const std::string& request,
                boost::optional<const std::string> calendar_id,
                const std::vector<std::string>& forbidden_uris,
                const pt::ptime date,
                uint32_t duration, uint32_t depth,
                int count, int start_page, const type::RTLevel rt_level, const size_t items_per_route_point) {

    RequestHandle handler(pb_creator, request, forbidden_uris, date, duration, calendar_id);

    if (pb_creator.has_error() || (handler.journey_pattern_points.size() == 0)) {
        return;
    }

    if (calendar_id) {
        //check whether that calendar exists, to raise an early error
        if (pb_creator.data.pt_data->calendars_map.find(*calendar_id) == pb_creator.data.pt_data->calendars_map.end()) {
            pb_creator.fill_pb_error(pbnavitia::Error::bad_filter, "stop_schedules : calendar does not exist");
            return;
        }
    }
    //  <stop_point_route, status>
    std::map<stop_point_route, pbnavitia::ResponseStatus> response_status;

    std::map<stop_point_route, vector_dt_st> map_route_stop_point;

    //Mapping route/stop_point
    boost::container::flat_set<stop_point_route> sps_routes;
    for(auto jpp_idx : handler.journey_pattern_points) {
        const auto& jpp = pb_creator.data.dataRaptor->jp_container.get(jpp_idx);
        const auto& jp = pb_creator.data.dataRaptor->jp_container.get(jpp.jp_idx);
        stop_point_route key = {jpp.sp_idx, jp.route_idx};
        sps_routes.insert(key);
    }
    size_t total_result = sps_routes.size();
    sps_routes = paginate(sps_routes, count, start_page);
    auto sort_predicate = [](routing::datetime_stop_time dt1, routing::datetime_stop_time dt2) {
                    return dt1.first < dt2.first;
                };
    // we group the stoptime belonging to the same pair (stop_point, route)
    // since we want to display the departures grouped by route
    // the route being a loose commercial direction
    for (const auto& sp_route: sps_routes) {
        std::vector<routing::datetime_stop_time> stop_times;
        const type::StopPoint* stop_point = pb_creator.data.pt_data->stop_points[sp_route.first.val];
        const type::Route* route = pb_creator.data.pt_data->routes[sp_route.second.val];
        const auto& jpps = pb_creator.data.dataRaptor->jpps_from_sp[sp_route.first];
        std::vector<routing::JppIdx> routepoint_jpps;
        for (const auto& jpp_from_sp: jpps) {
            const routing::JppIdx& jpp_idx = jpp_from_sp.idx;
            const auto& jpp = pb_creator.data.dataRaptor->jp_container.get(jpp_idx);
            const auto& jp = pb_creator.data.dataRaptor->jp_container.get(jpp.jp_idx);
            if (jp.route_idx != sp_route.second) { continue; }

            routepoint_jpps.push_back(jpp_idx);
        }

        if (! calendar_id) {
            stop_times = routing::get_stop_times(routing::StopEvent::pick_up, routepoint_jpps, handler.date_time,
                    handler.max_datetime, items_per_route_point, pb_creator.data, rt_level);
            std::sort(stop_times.begin(), stop_times.end(), sort_predicate);
        } else {
            stop_times = routing::get_calendar_stop_times(routepoint_jpps, DateTimeUtils::hour(handler.date_time),
                    DateTimeUtils::hour(handler.max_datetime), pb_creator.data, *calendar_id);
            // for calendar we want the first stop time to start from handler.date_time
            std::sort(stop_times.begin(), stop_times.end(), routing::CalendarScheduleSort(handler.date_time));
            if (stop_times.size() > items_per_route_point) {
                stop_times.resize(items_per_route_point);
            }
        }

        //we compute the route status
        for (const auto& jpp_idx: routepoint_jpps) {
            const auto& jpp = pb_creator.data.dataRaptor->jp_container.get(jpp_idx);
            const auto& jp = pb_creator.data.dataRaptor->jp_container.get(jpp.jp_idx);
            const auto& last_jpp = pb_creator.data.dataRaptor->jp_container.get(jp.jpps.back());
            if (sp_route.first == last_jpp.sp_idx) {
                if (stop_point->stop_area == route->destination) {
                    response_status[sp_route] = pbnavitia::ResponseStatus::terminus;
                } else {
                    response_status[sp_route] = pbnavitia::ResponseStatus::partial_terminus;
                }
            }
        }

        //If there is no departure for a request with "RealTime", Test existance of any departure with "base_schedule"
        //If departure with base_schedule is not empty, additional_information = active_disruption
        //Else additional_information = no_departure_this_day
        if (stop_times.empty() && (response_status.find(sp_route) == response_status.end())) {
            auto resp_status = pbnavitia::ResponseStatus::no_departure_this_day;
            if (line_closed(navitia::seconds(duration), route, date)) {
                  resp_status = pbnavitia::ResponseStatus::no_active_circulation_this_day;
            }
            if (rt_level != navitia::type::RTLevel::Base) {
                auto tmp_stop_times = routing::get_stop_times(routing::StopEvent::pick_up, routepoint_jpps, handler.date_time,
                                                              handler.max_datetime, 1, pb_creator.data,
                                                              navitia::type::RTLevel::Base);
                if (!tmp_stop_times.empty()) { resp_status = pbnavitia::ResponseStatus::active_disruption; }
            }
            response_status[sp_route] = resp_status;
        }

        map_route_stop_point[sp_route] = stop_times;
    }

    render(pb_creator, response_status, map_route_stop_point, handler.date_time, handler.max_datetime,
              calendar_id, depth);

    pb_creator.make_paginate(total_result, start_page, count, std::max(pb_creator.departure_boards_size(),
                                                                       pb_creator.stop_schedules_size()));
}
}
}
<commit_msg>small refactoring to make the code cleared<commit_after>/* Copyright © 2001-2014, Canal TP and/or its affiliates. All rights reserved.

This file is part of Navitia,
    the software to build cool stuff with public transport.

Hope you'll enjoy and contribute to this project,
    powered by Canal TP (www.canaltp.fr).
Help us simplify mobility and open public transport:
    a non ending quest to the responsive locomotion way of traveling!

LICENCE: This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.

You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.

Stay tuned using
twitter @navitia
IRC #navitia on freenode
https://groups.google.com/d/forum/navitia
www.navitia.io
*/

#include "departure_boards.h"
#include "request_handle.h"
#include "routing/get_stop_times.h"
#include "type/pb_converter.h"
#include "routing/dataraptor.h"
#include "utils/paginate.h"
#include "routing/dataraptor.h"

#include <boost/lexical_cast.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/container/flat_set.hpp>

namespace pt = boost::posix_time;

namespace navitia { namespace timetables {

static void
render(PbCreator& pb_creator,
          const std::map<stop_point_route, pbnavitia::ResponseStatus>& response_status,
          const std::map<stop_point_route, vector_dt_st>& map_route_stop_point,
          DateTime datetime,
          DateTime max_datetime,
          boost::optional<const std::string> calendar_id,
          uint32_t depth) {
    pb_creator.action_period = pt::time_period(to_posix_time(datetime, pb_creator.data),
                                               to_posix_time(max_datetime, pb_creator.data));

    for(auto id_vec : map_route_stop_point) {
        auto schedule = pb_creator.add_stop_schedules();
        //Each schedule has a stop_point and a route
        pb_creator.fill(pb_creator.data.pt_data->stop_points[id_vec.first.first.val],
                schedule->mutable_stop_point(), depth);

        auto m_route = schedule->mutable_route();
        pb_creator.fill(pb_creator.data.pt_data->routes[id_vec.first.second.val], m_route, depth);
        if (pb_creator.data.pt_data->routes[id_vec.first.second.val]->line != nullptr){
            auto m_line = m_route->mutable_line();
            pb_creator.fill(pb_creator.data.pt_data->routes[id_vec.first.second.val]->line, m_line, 0);
        }
        auto pt_display_information = schedule->mutable_pt_display_informations();

        pb_creator.fill(pb_creator.data.pt_data->routes[id_vec.first.second.val], pt_display_information, 0);

        //Now we fill the date_times
        for(auto dt_st : id_vec.second) {
            auto date_time = schedule->add_date_times();
            const auto& st_calendar = navitia::StopTimeCalandar(dt_st.second, dt_st.first, calendar_id);
            pb_creator.fill(&st_calendar, date_time, 0);
            if (dt_st.second != nullptr) {
                auto vj = dt_st.second->vehicle_journey;
                if(vj != nullptr) {
                    for (const auto& comment: pb_creator.data.pt_data->comments.get(*vj)) {
                        pb_creator.fill(&comment, date_time->mutable_properties()->add_notes(), 0);
                    }
                }
            }
        }
        const auto& it = response_status.find(id_vec.first);
        if(it != response_status.end()){
            schedule->set_response_status(it->second);
        }
    }
}

static time_duration to_navitia(const boost::posix_time::time_duration& dur) {
    return navitia::seconds(dur.total_seconds());
}

time_duration length_of_time(const time_duration& duration_1,
                       const time_duration& duration_2) {
    if (duration_1 <= duration_2) {
        return duration_2 - duration_1;
    } else {
        return duration_2 + (hours(24) - duration_1);
    }
}

bool between_opening_and_closing(const time_duration& me,
                                 const time_duration& opening,
                                 const time_duration& closing) {
    if (opening < closing) {
        return (opening <= me && me <= closing);
    } else {
        return (opening <= me || me <= closing);
    }
}

bool line_closed (const time_duration& duration,
             const time_duration& opening,
             const time_duration& closing,
             const pt::ptime& date) {
    const auto begin = to_navitia(date.time_of_day());
    return !between_opening_and_closing(begin, opening, closing)
            && !between_opening_and_closing((begin + duration), opening, closing)
            && duration < (length_of_time(opening, closing) + length_of_time(begin, opening));
}

static bool line_closed (const time_duration& duration,
                  const type::Route* route,
                  const pt::ptime& date) {
    if (route->line->opening_time && route->line->closing_time) {
        const auto opening = to_navitia(*route->line->opening_time);
        const auto closing = to_navitia(*route->line->closing_time);
        return line_closed(duration, opening, closing, date);
    }
    return false;
}

static std::vector<routing::JppIdx> get_jpp_from_route_point(const stop_point_route& sp_route,
                                                             const navitia::routing::dataRAPTOR& data_raptor) {
    const auto& jpps = data_raptor.jpps_from_sp[sp_route.first];
    std::vector<routing::JppIdx> routepoint_jpps;
    for (const auto& jpp_from_sp: jpps) {
        const routing::JppIdx& jpp_idx = jpp_from_sp.idx;
        const auto& jpp = data_raptor.jp_container.get(jpp_idx);
        const auto& jp = data_raptor.jp_container.get(jpp.jp_idx);
        if (jp.route_idx != sp_route.second) { continue; }

        routepoint_jpps.push_back(jpp_idx);
    }
    return routepoint_jpps;
}

void departure_board(PbCreator& pb_creator, const std::string& request,
                boost::optional<const std::string> calendar_id,
                const std::vector<std::string>& forbidden_uris,
                const pt::ptime date,
                uint32_t duration, uint32_t depth,
                int count, int start_page, const type::RTLevel rt_level, const size_t items_per_route_point) {

    RequestHandle handler(pb_creator, request, forbidden_uris, date, duration, calendar_id);

    if (pb_creator.has_error() || (handler.journey_pattern_points.size() == 0)) {
        return;
    }

    if (calendar_id) {
        //check whether that calendar exists, to raise an early error
        if (pb_creator.data.pt_data->calendars_map.find(*calendar_id) == pb_creator.data.pt_data->calendars_map.end()) {
            pb_creator.fill_pb_error(pbnavitia::Error::bad_filter, "stop_schedules : calendar does not exist");
            return;
        }
    }
    //  <stop_point_route, status>
    std::map<stop_point_route, pbnavitia::ResponseStatus> response_status;

    std::map<stop_point_route, vector_dt_st> map_route_stop_point;

    //Mapping route/stop_point
    boost::container::flat_set<stop_point_route> sps_routes;
    for(auto jpp_idx : handler.journey_pattern_points) {
        const auto& jpp = pb_creator.data.dataRaptor->jp_container.get(jpp_idx);
        const auto& jp = pb_creator.data.dataRaptor->jp_container.get(jpp.jp_idx);
        stop_point_route key = {jpp.sp_idx, jp.route_idx};
        sps_routes.insert(key);
    }
    size_t total_result = sps_routes.size();
    sps_routes = paginate(sps_routes, count, start_page);
    auto sort_predicate = [](routing::datetime_stop_time dt1, routing::datetime_stop_time dt2) {
                    return dt1.first < dt2.first;
                };
    // we group the stoptime belonging to the same pair (stop_point, route)
    // since we want to display the departures grouped by route
    // the route being a loose commercial direction
    for (const auto& sp_route: sps_routes) {
        const type::StopPoint* stop_point = pb_creator.data.pt_data->stop_points[sp_route.first.val];
        const type::Route* route = pb_creator.data.pt_data->routes[sp_route.second.val];
        const auto routepoint_jpps = get_jpp_from_route_point(sp_route, *pb_creator.data.dataRaptor);

        std::vector<routing::datetime_stop_time> stop_times;
        if (! calendar_id) {
            stop_times = routing::get_stop_times(routing::StopEvent::pick_up, routepoint_jpps, handler.date_time,
                    handler.max_datetime, items_per_route_point, pb_creator.data, rt_level);
            std::sort(stop_times.begin(), stop_times.end(), sort_predicate);
        } else {
            stop_times = routing::get_calendar_stop_times(routepoint_jpps, DateTimeUtils::hour(handler.date_time),
                    DateTimeUtils::hour(handler.max_datetime), pb_creator.data, *calendar_id);
            // for calendar we want the first stop time to start from handler.date_time
            std::sort(stop_times.begin(), stop_times.end(), routing::CalendarScheduleSort(handler.date_time));
            if (stop_times.size() > items_per_route_point) {
                stop_times.resize(items_per_route_point);
            }
        }

        //we compute the route status
        if (stop_point->stop_area == route->destination) {
            response_status[sp_route] = pbnavitia::ResponseStatus::terminus;
        } else {
            // we try to find if the stop point is a terminus for at least one jp passing through the stop
            // in this case, the stop is a partial terminus
            for (const auto& jpp_idx: routepoint_jpps) {
                const auto& jpp = pb_creator.data.dataRaptor->jp_container.get(jpp_idx);
                const auto& jp = pb_creator.data.dataRaptor->jp_container.get(jpp.jp_idx);
                const auto& last_jpp = pb_creator.data.dataRaptor->jp_container.get(jp.jpps.back());
                if (sp_route.first == last_jpp.sp_idx) {
                    response_status[sp_route] = pbnavitia::ResponseStatus::partial_terminus;
                    break;
                }
            }
        }

        //If there is no departure for a request with "RealTime", Test existance of any departure with "base_schedule"
        //If departure with base_schedule is not empty, additional_information = active_disruption
        //Else additional_information = no_departure_this_day
        if (stop_times.empty() && (response_status.find(sp_route) == response_status.end())) {
            auto resp_status = pbnavitia::ResponseStatus::no_departure_this_day;
            if (line_closed(navitia::seconds(duration), route, date)) {
                  resp_status = pbnavitia::ResponseStatus::no_active_circulation_this_day;
            }
            if (rt_level != navitia::type::RTLevel::Base) {
                auto tmp_stop_times = routing::get_stop_times(routing::StopEvent::pick_up, routepoint_jpps, handler.date_time,
                                                              handler.max_datetime, 1, pb_creator.data,
                                                              navitia::type::RTLevel::Base);
                if (!tmp_stop_times.empty()) { resp_status = pbnavitia::ResponseStatus::active_disruption; }
            }
            response_status[sp_route] = resp_status;
        }

        map_route_stop_point[sp_route] = stop_times;
    }

    render(pb_creator, response_status, map_route_stop_point, handler.date_time, handler.max_datetime,
              calendar_id, depth);

    pb_creator.make_paginate(total_result, start_page, count, std::max(pb_creator.departure_boards_size(),
                                                                       pb_creator.stop_schedules_size()));
}
}
}
<|endoftext|>


<commit_before>/*!
*	@file	psalm.cpp
*	@brief	Main file for "psalm"
*
*	"psalm" (Pretty Subdivision ALgorithms on Meshes) is a CLI tool that
*	implements the Doo-Sabin and Catmull-Clark subdivision schemes.
*/

#include <iostream>
#include <sstream>
#include <fstream>
#include <algorithm>
#include <set>
#include <cerrno>

#include <unistd.h>
#include <getopt.h>
#include <libgen.h>

#include "mesh.h"

psalm::mesh scene_mesh;
std::string input;
std::string output;

/*!
*	Shows usage information for the program.
*/

void show_usage()
{
	std::cout	<< "psalm\n\n"
			<< "Usage: psalm [arguments] [file...]\n\n"
			<< "Arguments:\n\n"
			<< "-a, --algorithm <algorithm>\tSelect subdivision algorithm to use on the\n"
			<< "\t\t\t\tinput mesh. Valid values for <algorithm> are:\n\n"
			<< "\t\t\t\t\t* catmull-clark, catmull, clark, cc\n"
			<< "\t\t\t\t\t* doo-sabin, doo, sabin, ds\n"
			<< "\t\t\t\t\t* loop, l\n\n"
			<< "\t\t\t\tDefault algorithm: Catmull-Clark\n\n"
			<< "-e, --extra-weights <file>\tOverride the default weights of subdivision\n"
			<< "\t\t\t\tschemes by reading them from <file>. The exact\n"
			<< "\t\t\t\tformat of this file depends on the subdivision\n"
			<< "\t\t\t\talgorithm that is used.\n\n"
			<< "-w, --weights <weights>\t\tSelect type of weights to that are used for\n"
			<< "\t\t\t\tthe subdivision scheme. Valid values are:\n\n"
			<< "\t\t\t\t\t[for the Doo-Sabin algorithm]\n"
			<< "\t\t\t\t\t* catmull-clark, catmull, clark, cc\n"
			<< "\t\t\t\t\t* doo-sabin, doo, sabin, ds\n\n"
			<< "\t\t\t\t\t[for all algorithms]\n"
			<< "\t\t\t\t\t* default\n\n"
			<< "-t, --type <type>\t\tSelect type of input data. Valid values for\n"
			<< "\t\t\t\tthe <type> parameter are:\n\n"
			<< "\t\t\t\t\t* ply (Standford PLY files)\n"
			<< "\t\t\t\t\t* obj (Wavefront OBJ files)\n"
			<< "\t\t\t\t\t* off (Geomview object files)\n\n"
			<< "-i, --ignore <list of numbers>\tIgnore any face whose number of sides matches\n"
			<< "\t\t\t\tone of the numbers in the list. Use commas to\n"
			<< "\t\t\t\tseparate list values.\n\n"
			<< "-o, --output <file>\t\tSet output file\n\n"
			<< "-n, --steps <n>\t\t\tSet number of subdivision steps to perform on\n"
			<< "\t\t\t\tthe input mesh.\n\n"
			<< "\t\t\t\tDefault value: 0\n\n"
			<< "-h, --help\t\t\tShow this screen\n"
			<< "\n";
}

/*!
*	Reads a map of weights for a sudivision algorithm from a file. Each
*	line of the file must be of the following form:
*
*		<k> <a_1> ... <a_k>
*
*	Where <k> is the number of vertices for a face and <a_i> are the
*	weights that are used for the vertices of the face. The weights are
*	supposed to be arranged in counterclockwise order.
*
*	@param filename Filename of weights map
*	@return Associative array for quickly looking up the weights.
*/

psalm::weights_map load_weights_map(const std::string& filename)
{
	psalm::weights_map res;

	std::ifstream in;
	errno = 0;
	in.open(filename.c_str());

	if(!in.good() || errno)
	{
		std::string error = strerror(errno);
		std::cerr	<< "psalm: Could not load weights map file \""
				<< filename << "\": "
				<< error << "\n";

		return(res);
	}

	std::string line;
	std::istringstream converter;
	while(getline(in, line))
	{
		converter.clear();
		converter.str(line);

		std::vector<double> weights;
		size_t k = 0;

		// Read k and try to read k weights afterwards

		converter >> k;
		if(converter.fail())
		{
			std::cerr	<< "psalm: Unable to read number of weights "
					<< "from line \"" << line << "\"\n";
			return(res);
		}

		double w = 0.0;
		for(size_t i = 0; i < k; i++)
		{
			converter >> w;
			if(converter.fail())
			{
				std::cerr	<< "psalm: Unable to read weights "
						<< "from line \"" << line << "\"\n";
				return(res);
			}

			weights.push_back(w);
		}

		res[k] = weights;
	}

	return(res);
}

/*!
*	Handles user interaction.
*
*	@param argc Number of command-line arguments
*	@param argv Vector of command-line arguments
*/

int main(int argc, char* argv[])
{
	static option cmd_line_opts[] =
	{
		{"output",		required_argument,	NULL,	'o'},
		{"steps",		required_argument,	NULL,	'n'},
		{"type",		required_argument,	NULL,	't'},
		{"ignore",		required_argument,	NULL,	'i'},
		{"algorithm",		required_argument,	NULL,	'a'},
		{"weights",		required_argument,	NULL,	'w'},
		{"extra-weights",	required_argument,	NULL,	'e'},

		{"help",		no_argument,		NULL,	'h'},

		{NULL, 0, NULL, 0}
	};

	short type	= psalm::mesh::TYPE_EXT;
	short algorithm	= psalm::mesh::ALG_CATMULL_CLARK;
	short weights	= psalm::mesh::W_DEFAULT;

	std::set<size_t> ignore_faces;
	psalm::weights_map extra_weights;

	size_t steps	= 0;

	int option = 0;
	while((option = getopt_long(argc, argv, "o:n:i:t:a:w:e:h", cmd_line_opts, NULL)) != -1)
	{
		switch(option)
		{
			case 'o':
				output = optarg;
				break;

			case 't':
			{
				std::string type_str = optarg;
				std::transform(type_str.begin(), type_str.end(), type_str.begin(), (int(*)(int)) tolower);

				if(type_str == "ply")
					type = psalm::mesh::TYPE_PLY;
				else if(type_str == "obj")
					type = psalm::mesh::TYPE_OBJ;
				else if(type_str == "off")
					type = psalm::mesh::TYPE_OFF;
				else
				{
					std::cerr << "psalm: \"" << type_str << "\" is an unknown mesh data type.\n";
					return(-1);
				}

				break;
			}

			case 'a':
			{
				std::string algorithm_str = optarg;
				std::transform(algorithm_str.begin(), algorithm_str.end(), algorithm_str.begin(), (int(*)(int)) tolower);

				if(	algorithm_str == "catmull-clark"	||
					algorithm_str == "catmull"		||
					algorithm_str == "clark"		||
					algorithm_str == "cc")
					algorithm = psalm::mesh::ALG_CATMULL_CLARK;
				else if(algorithm_str == "doo-sabin"		||
					algorithm_str == "doo"			||
					algorithm_str == "sabin"		||
					algorithm_str == "ds")
					algorithm = psalm::mesh::ALG_DOO_SABIN;
				else if(algorithm_str == "loop"	||
					algorithm_str == "l")
					algorithm = psalm::mesh::ALG_LOOP;
				else
				{
					std::cerr << "psalm: \"" << algorithm_str << "\" is an unknown algorithm.\n";
					return(-1);
				}

				break;
			}

			case 'e':
			{
				extra_weights = load_weights_map(optarg);
				if(extra_weights.size() == 0)
				{
					std::cerr << "psalm: Unwilling to continue with empty weights file.\n";
					return(-1);
				}
				break;
			}

			case 'w':
			{
				std::string weights_str = optarg;
				std::transform(weights_str.begin(), weights_str.end(), weights_str.begin(), (int(*)(int)) tolower);

				if(	weights_str == "catmull-clark"	||
					weights_str == "catmull"	||
					weights_str == "clark"		||
					weights_str == "cc")
					weights = psalm::mesh::W_CATMULL_CLARK;
				else if(weights_str == "doo-sabin"	||
					weights_str == "doo"		||
					weights_str == "sabin"		||
					weights_str == "ds")
					weights = psalm::mesh::W_DOO_SABIN;
				else if(weights_str == "default")
					weights = psalm::mesh::W_DEFAULT;
				else
				{
					std::cerr << "psalm: \"" << weights_str << "\" is an unknown weight scheme.\n";
					return(-1);
				}

				break;
			}

			case 'i':
			{
				std::istringstream ignore_faces_str(optarg);
				std::istringstream converter;
				std::string val_str;
				while(getline(ignore_faces_str, val_str, ','))
				{
					converter.clear();
					converter.str(val_str);

					size_t value;
					converter >> value;
					if(converter.fail())
					{
						std::cerr << "psalm: Unable to convert \"" << val_str << "\" to a number.\n";
						return(-1);
					}

					ignore_faces.insert(value);
				}

				break;
			}

			case 'n':
			{
				std::istringstream converter(optarg);
				converter >> steps;
				if(converter.fail())
				{
					std::cerr << "psalm: Unable to  convert \"" << optarg << "\" to a number.\n";
					return(-1);
				}
				break;
			}

			case 'h':
			case '?':
				show_usage();
				return(0);
		}
	}

	// Read further command-line parameters; these are all supposed to be
	// input files. If the user already specified an output file, only one
	// input file will be accepted.

	std::vector<std::string> files;
	while(optind < argc)
	{
		files.push_back(argv[optind++]);
		if(output.length() != 0 && files.size() > 1)
		{
			std::cerr << "psalm: Output file specified, but more than one input file present.\n";
			return(-1);
		}
	}

	// Replace the special file "-" by an empty string, thereby signalling
	// that standard input and standard output are to be used as file
	// streams.

	for(std::vector<std::string>::iterator it = files.begin(); it != files.end(); it++)
	{
		if(it->length() == 1 && (*it)[0] == '-')
			*it = "";
	}

	bool output_set = (output.length() > 0);
	if(output.length() == 1 && output[0] == '-')
		output = "";

	// Try to read from STDIN if no input files have been specified
	if(files.size() == 0)
		files.push_back("");

	// Apply subdivision algorithm to all files

	for(std::vector<std::string>::iterator it = files.begin(); it != files.end(); it++)
	{
		scene_mesh.load(*it, type);
		scene_mesh.subdivide(algorithm, steps, weights, &extra_weights);
		scene_mesh.prune(ignore_faces);

		// If an output file has been set (even if it is empty), it
		// will be used.
		if(output_set)
			scene_mesh.save(output, type);

		// If no output file has been set and the input file name is
		// not empty, the output will be written to a file.
		else if(it->length() > 0)
		{
			size_t ext_pos = (*it).find_last_of(".");
			if(ext_pos == std::string::npos)
				scene_mesh.save(*it+".subdivided", type);
			else
				scene_mesh.save( (*it).substr(0, ext_pos) + "_subdivided"
						+(*it).substr(ext_pos));
		}

		// If no output file has been set and the input file name is
		// empty, the output will be written to STDOUT.
		else
			scene_mesh.save("", type);
	}

	return(0);
}
<commit_msg>Fixed Linux compilation error<commit_after>/*!
*	@file	psalm.cpp
*	@brief	Main file for "psalm"
*
*	"psalm" (Pretty Subdivision ALgorithms on Meshes) is a CLI tool that
*	implements the Doo-Sabin and Catmull-Clark subdivision schemes.
*/

#include <iostream>
#include <sstream>
#include <fstream>
#include <algorithm>
#include <set>

#include <cerrno>
#include <cstring>

#include <unistd.h>
#include <getopt.h>
#include <libgen.h>

#include "mesh.h"

psalm::mesh scene_mesh;
std::string input;
std::string output;

/*!
*	Shows usage information for the program.
*/

void show_usage()
{
	std::cout	<< "psalm\n\n"
			<< "Usage: psalm [arguments] [file...]\n\n"
			<< "Arguments:\n\n"
			<< "-a, --algorithm <algorithm>\tSelect subdivision algorithm to use on the\n"
			<< "\t\t\t\tinput mesh. Valid values for <algorithm> are:\n\n"
			<< "\t\t\t\t\t* catmull-clark, catmull, clark, cc\n"
			<< "\t\t\t\t\t* doo-sabin, doo, sabin, ds\n"
			<< "\t\t\t\t\t* loop, l\n\n"
			<< "\t\t\t\tDefault algorithm: Catmull-Clark\n\n"
			<< "-e, --extra-weights <file>\tOverride the default weights of subdivision\n"
			<< "\t\t\t\tschemes by reading them from <file>. The exact\n"
			<< "\t\t\t\tformat of this file depends on the subdivision\n"
			<< "\t\t\t\talgorithm that is used.\n\n"
			<< "-w, --weights <weights>\t\tSelect type of weights to that are used for\n"
			<< "\t\t\t\tthe subdivision scheme. Valid values are:\n\n"
			<< "\t\t\t\t\t[for the Doo-Sabin algorithm]\n"
			<< "\t\t\t\t\t* catmull-clark, catmull, clark, cc\n"
			<< "\t\t\t\t\t* doo-sabin, doo, sabin, ds\n\n"
			<< "\t\t\t\t\t[for all algorithms]\n"
			<< "\t\t\t\t\t* default\n\n"
			<< "-t, --type <type>\t\tSelect type of input data. Valid values for\n"
			<< "\t\t\t\tthe <type> parameter are:\n\n"
			<< "\t\t\t\t\t* ply (Standford PLY files)\n"
			<< "\t\t\t\t\t* obj (Wavefront OBJ files)\n"
			<< "\t\t\t\t\t* off (Geomview object files)\n\n"
			<< "-i, --ignore <list of numbers>\tIgnore any face whose number of sides matches\n"
			<< "\t\t\t\tone of the numbers in the list. Use commas to\n"
			<< "\t\t\t\tseparate list values.\n\n"
			<< "-o, --output <file>\t\tSet output file\n\n"
			<< "-n, --steps <n>\t\t\tSet number of subdivision steps to perform on\n"
			<< "\t\t\t\tthe input mesh.\n\n"
			<< "\t\t\t\tDefault value: 0\n\n"
			<< "-h, --help\t\t\tShow this screen\n"
			<< "\n";
}

/*!
*	Reads a map of weights for a sudivision algorithm from a file. Each
*	line of the file must be of the following form:
*
*		<k> <a_1> ... <a_k>
*
*	Where <k> is the number of vertices for a face and <a_i> are the
*	weights that are used for the vertices of the face. The weights are
*	supposed to be arranged in counterclockwise order.
*
*	@param filename Filename of weights map
*	@return Associative array for quickly looking up the weights.
*/

psalm::weights_map load_weights_map(const std::string& filename)
{
	psalm::weights_map res;

	std::ifstream in;
	errno = 0;
	in.open(filename.c_str());

	if(!in.good() || errno)
	{
		std::string error = strerror(errno);
		std::cerr	<< "psalm: Could not load weights map file \""
				<< filename << "\": "
				<< error << "\n";

		return(res);
	}

	std::string line;
	std::istringstream converter;
	while(getline(in, line))
	{
		converter.clear();
		converter.str(line);

		std::vector<double> weights;
		size_t k = 0;

		// Read k and try to read k weights afterwards

		converter >> k;
		if(converter.fail())
		{
			std::cerr	<< "psalm: Unable to read number of weights "
					<< "from line \"" << line << "\"\n";
			return(res);
		}

		double w = 0.0;
		for(size_t i = 0; i < k; i++)
		{
			converter >> w;
			if(converter.fail())
			{
				std::cerr	<< "psalm: Unable to read weights "
						<< "from line \"" << line << "\"\n";
				return(res);
			}

			weights.push_back(w);
		}

		res[k] = weights;
	}

	return(res);
}

/*!
*	Handles user interaction.
*
*	@param argc Number of command-line arguments
*	@param argv Vector of command-line arguments
*/

int main(int argc, char* argv[])
{
	static option cmd_line_opts[] =
	{
		{"output",		required_argument,	NULL,	'o'},
		{"steps",		required_argument,	NULL,	'n'},
		{"type",		required_argument,	NULL,	't'},
		{"ignore",		required_argument,	NULL,	'i'},
		{"algorithm",		required_argument,	NULL,	'a'},
		{"weights",		required_argument,	NULL,	'w'},
		{"extra-weights",	required_argument,	NULL,	'e'},

		{"help",		no_argument,		NULL,	'h'},

		{NULL, 0, NULL, 0}
	};

	short type	= psalm::mesh::TYPE_EXT;
	short algorithm	= psalm::mesh::ALG_CATMULL_CLARK;
	short weights	= psalm::mesh::W_DEFAULT;

	std::set<size_t> ignore_faces;
	psalm::weights_map extra_weights;

	size_t steps	= 0;

	int option = 0;
	while((option = getopt_long(argc, argv, "o:n:i:t:a:w:e:h", cmd_line_opts, NULL)) != -1)
	{
		switch(option)
		{
			case 'o':
				output = optarg;
				break;

			case 't':
			{
				std::string type_str = optarg;
				std::transform(type_str.begin(), type_str.end(), type_str.begin(), (int(*)(int)) tolower);

				if(type_str == "ply")
					type = psalm::mesh::TYPE_PLY;
				else if(type_str == "obj")
					type = psalm::mesh::TYPE_OBJ;
				else if(type_str == "off")
					type = psalm::mesh::TYPE_OFF;
				else
				{
					std::cerr << "psalm: \"" << type_str << "\" is an unknown mesh data type.\n";
					return(-1);
				}

				break;
			}

			case 'a':
			{
				std::string algorithm_str = optarg;
				std::transform(algorithm_str.begin(), algorithm_str.end(), algorithm_str.begin(), (int(*)(int)) tolower);

				if(	algorithm_str == "catmull-clark"	||
					algorithm_str == "catmull"		||
					algorithm_str == "clark"		||
					algorithm_str == "cc")
					algorithm = psalm::mesh::ALG_CATMULL_CLARK;
				else if(algorithm_str == "doo-sabin"		||
					algorithm_str == "doo"			||
					algorithm_str == "sabin"		||
					algorithm_str == "ds")
					algorithm = psalm::mesh::ALG_DOO_SABIN;
				else if(algorithm_str == "loop"	||
					algorithm_str == "l")
					algorithm = psalm::mesh::ALG_LOOP;
				else
				{
					std::cerr << "psalm: \"" << algorithm_str << "\" is an unknown algorithm.\n";
					return(-1);
				}

				break;
			}

			case 'e':
			{
				extra_weights = load_weights_map(optarg);
				if(extra_weights.size() == 0)
				{
					std::cerr << "psalm: Unwilling to continue with empty weights file.\n";
					return(-1);
				}
				break;
			}

			case 'w':
			{
				std::string weights_str = optarg;
				std::transform(weights_str.begin(), weights_str.end(), weights_str.begin(), (int(*)(int)) tolower);

				if(	weights_str == "catmull-clark"	||
					weights_str == "catmull"	||
					weights_str == "clark"		||
					weights_str == "cc")
					weights = psalm::mesh::W_CATMULL_CLARK;
				else if(weights_str == "doo-sabin"	||
					weights_str == "doo"		||
					weights_str == "sabin"		||
					weights_str == "ds")
					weights = psalm::mesh::W_DOO_SABIN;
				else if(weights_str == "default")
					weights = psalm::mesh::W_DEFAULT;
				else
				{
					std::cerr << "psalm: \"" << weights_str << "\" is an unknown weight scheme.\n";
					return(-1);
				}

				break;
			}

			case 'i':
			{
				std::istringstream ignore_faces_str(optarg);
				std::istringstream converter;
				std::string val_str;
				while(getline(ignore_faces_str, val_str, ','))
				{
					converter.clear();
					converter.str(val_str);

					size_t value;
					converter >> value;
					if(converter.fail())
					{
						std::cerr << "psalm: Unable to convert \"" << val_str << "\" to a number.\n";
						return(-1);
					}

					ignore_faces.insert(value);
				}

				break;
			}

			case 'n':
			{
				std::istringstream converter(optarg);
				converter >> steps;
				if(converter.fail())
				{
					std::cerr << "psalm: Unable to  convert \"" << optarg << "\" to a number.\n";
					return(-1);
				}
				break;
			}

			case 'h':
			case '?':
				show_usage();
				return(0);
		}
	}

	// Read further command-line parameters; these are all supposed to be
	// input files. If the user already specified an output file, only one
	// input file will be accepted.

	std::vector<std::string> files;
	while(optind < argc)
	{
		files.push_back(argv[optind++]);
		if(output.length() != 0 && files.size() > 1)
		{
			std::cerr << "psalm: Output file specified, but more than one input file present.\n";
			return(-1);
		}
	}

	// Replace the special file "-" by an empty string, thereby signalling
	// that standard input and standard output are to be used as file
	// streams.

	for(std::vector<std::string>::iterator it = files.begin(); it != files.end(); it++)
	{
		if(it->length() == 1 && (*it)[0] == '-')
			*it = "";
	}

	bool output_set = (output.length() > 0);
	if(output.length() == 1 && output[0] == '-')
		output = "";

	// Try to read from STDIN if no input files have been specified
	if(files.size() == 0)
		files.push_back("");

	// Apply subdivision algorithm to all files

	for(std::vector<std::string>::iterator it = files.begin(); it != files.end(); it++)
	{
		scene_mesh.load(*it, type);
		scene_mesh.subdivide(algorithm, steps, weights, &extra_weights);
		scene_mesh.prune(ignore_faces);

		// If an output file has been set (even if it is empty), it
		// will be used.
		if(output_set)
			scene_mesh.save(output, type);

		// If no output file has been set and the input file name is
		// not empty, the output will be written to a file.
		else if(it->length() > 0)
		{
			size_t ext_pos = (*it).find_last_of(".");
			if(ext_pos == std::string::npos)
				scene_mesh.save(*it+".subdivided", type);
			else
				scene_mesh.save( (*it).substr(0, ext_pos) + "_subdivided"
						+(*it).substr(ext_pos));
		}

		// If no output file has been set and the input file name is
		// empty, the output will be written to STDOUT.
		else
			scene_mesh.save("", type);
	}

	return(0);
}
<|endoftext|>


<commit_before><commit_msg>Set online view position, dimensions and item details.<commit_after><|endoftext|>


<commit_before>// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "remoting/client/rectangle_update_decoder.h"

#include "base/logging.h"
#include "base/message_loop.h"
#include "media/base/callback.h"
#include "remoting/base/decoder.h"
#include "remoting/base/decoder_row_based.h"
#include "remoting/base/decoder_vp8.h"
#include "remoting/base/tracer.h"
#include "remoting/base/util.h"
#include "remoting/client/frame_consumer.h"

using media::AutoTaskRunner;

namespace remoting {

namespace {

class PartialFrameCleanup : public Task {
 public:
  PartialFrameCleanup(media::VideoFrame* frame, UpdatedRects* rects)
      : frame_(frame), rects_(rects) {
  }

  virtual void Run() {
    delete rects_;
    frame_ = NULL;
  }

 private:
  scoped_refptr<media::VideoFrame> frame_;
  UpdatedRects* rects_;
};

}  // namespace

RectangleUpdateDecoder::RectangleUpdateDecoder(MessageLoop* message_loop,
                                               FrameConsumer* consumer)
    : message_loop_(message_loop),
      consumer_(consumer) {
}

RectangleUpdateDecoder::~RectangleUpdateDecoder() {
}

void RectangleUpdateDecoder::DecodePacket(const VideoPacket& packet,
                                          Task* done) {
  if (message_loop_ != MessageLoop::current()) {
    message_loop_->PostTask(
        FROM_HERE,
        NewTracedMethod(this,
                        &RectangleUpdateDecoder::DecodePacket, packet,
                        done));
    return;
  }
  AutoTaskRunner done_runner(done);

  TraceContext::tracer()->PrintString("Decode Packet called.");

  if (!IsValidPacket(packet)) {
    LOG(ERROR) << "Received invalid packet.";
    return;
  }

  Task* process_packet_data =
      NewTracedMethod(this,
                      &RectangleUpdateDecoder::ProcessPacketData,
                      packet, done_runner.release());

  if (packet.flags() | VideoPacket::FIRST_PACKET) {
    const VideoPacketFormat& format = packet.format();

    InitializeDecoder(format, process_packet_data);
  } else {
    process_packet_data->Run();
    delete process_packet_data;
  }
}

void RectangleUpdateDecoder::ProcessPacketData(
    const VideoPacket& packet, Task* done) {
  AutoTaskRunner done_runner(done);

  if (!decoder_->IsReadyForData()) {
    // TODO(ajwong): This whole thing should move into an invalid state.
    LOG(ERROR) << "Decoder is unable to process data. Dropping packet.";
    return;
  }

  TraceContext::tracer()->PrintString("Executing Decode.");
  decoder_->DecodeBytes(packet.data());

  if (packet.flags() | VideoPacket::LAST_PACKET) {
    decoder_->Reset();

    UpdatedRects* rects = new UpdatedRects();

    // Empty out the list of current updated rects so the decoder can keep
    // writing new ones while these are processed.
    rects->swap(updated_rects_);

    consumer_->OnPartialFrameOutput(frame_, rects,
                                    new PartialFrameCleanup(frame_, rects));
  }
}

// static
bool RectangleUpdateDecoder::IsValidPacket(const VideoPacket& packet) {
  if (!packet.IsInitialized()) {
    LOG(WARNING) << "Protobuf consistency checks fail.";
    return false;
  }

  // First packet must have a format.
  if (packet.flags() | VideoPacket::FIRST_PACKET) {
    if (!packet.has_format()) {
      LOG(WARNING) << "First packet must have format.";
      return false;
    }

    // TODO(ajwong): Verify that we don't need to whitelist encodings.
    const VideoPacketFormat& format = packet.format();
    if (!format.has_encoding() ||
        format.encoding() == VideoPacketFormat::ENCODING_INVALID) {
      LOG(WARNING) << "Invalid encoding specified.";
      return false;
    }
  }

  // We shouldn't generate null packets.
  if (!packet.has_data()) {
    LOG(WARNING) << "Packet w/o data received.";
    return false;
  }

  return true;
}

void RectangleUpdateDecoder::InitializeDecoder(const VideoPacketFormat& format,
                                               Task* done) {
  if (message_loop_ != MessageLoop::current()) {
    message_loop_->PostTask(
        FROM_HERE,
        NewTracedMethod(this,
                        &RectangleUpdateDecoder::InitializeDecoder,
                        format, done));
    return;
  }
  AutoTaskRunner done_runner(done);

  // Check if we need to request a new frame.
  if (!frame_ ||
      frame_->width() < static_cast<size_t>(format.width()) ||
      frame_->height() < static_cast<size_t>(format.height())) {
    if (frame_) {
      TraceContext::tracer()->PrintString("Releasing old frame.");
      consumer_->ReleaseFrame(frame_);
      frame_ = NULL;
    }
    TraceContext::tracer()->PrintString("Requesting new frame.");
    consumer_->AllocateFrame(media::VideoFrame::RGB32,
                             format.width(), format.height(),
                             base::TimeDelta(), base::TimeDelta(),
                             &frame_,
                             NewTracedMethod(
                                 this,
                                 &RectangleUpdateDecoder::InitializeDecoder,
                                 format,
                                 done_runner.release()));
    return;
  }

  // TODO(ajwong): We need to handle the allocator failing to create a frame
  // and properly disable this class.
  CHECK(frame_);

  if (decoder_.get()) {
    // TODO(ajwong): We need to handle changing decoders midstream correctly
    // since someone may feed us a corrupt stream, or manually create a
    // stream that changes decoders. At the very leask, we should not
    // crash the process.
    //
    // For now though, assume that only one encoding is used throughout.
    //
    // Note, this may be as simple as just deleting the current decoder.
    // However, we need to verify the flushing semantics of the decoder first.
    CHECK(decoder_->Encoding() == format.encoding());
  } else {
    // Initialize a new decoder based on this message encoding.
    if (format.encoding() == VideoPacketFormat::ENCODING_VERBATIM) {
      TraceContext::tracer()->PrintString("Creating Verbatim decoder.");
      decoder_.reset(DecoderRowBased::CreateVerbatimDecoder());
    } else if (format.encoding() == VideoPacketFormat::ENCODING_ZLIB) {
      TraceContext::tracer()->PrintString("Creating Zlib decoder");
      decoder_.reset(DecoderRowBased::CreateZlibDecoder());
    } else if (format.encoding() == VideoPacketFormat::ENCODING_VP8) {
      TraceContext::tracer()->PrintString("Creating VP8 decoder");
      decoder_.reset(new DecoderVp8());
    } else {
      NOTREACHED() << "Invalid Encoding found: " << format.encoding();
    }
  }

  // TODO(ajwong): This can happen in the face of corrupt input data.  Figure
  // out the right behavior and make this more resilient.
  CHECK(updated_rects_.empty());

  gfx::Rect rectangle_size(format.x(), format.y(),
                           format.width(), format.height());
  updated_rects_.push_back(rectangle_size);
  decoder_->Initialize(frame_, rectangle_size,
                       GetBytesPerPixel(format.pixel_format()));
  TraceContext::tracer()->PrintString("Decoder is Initialized");
}

}  // namespace remoting
<commit_msg>Fix arm build.<commit_after>// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "remoting/client/rectangle_update_decoder.h"

#include "base/logging.h"
#include "base/message_loop.h"
#include "media/base/callback.h"
#include "remoting/base/decoder.h"
#include "remoting/base/decoder_row_based.h"
#include "remoting/base/decoder_vp8.h"
#include "remoting/base/tracer.h"
#include "remoting/base/util.h"
#include "remoting/client/frame_consumer.h"

using media::AutoTaskRunner;

namespace remoting {

namespace {

class PartialFrameCleanup : public Task {
 public:
  PartialFrameCleanup(media::VideoFrame* frame, UpdatedRects* rects)
      : frame_(frame), rects_(rects) {
  }

  virtual void Run() {
    delete rects_;
    frame_ = NULL;
  }

 private:
  scoped_refptr<media::VideoFrame> frame_;
  UpdatedRects* rects_;
};

}  // namespace

RectangleUpdateDecoder::RectangleUpdateDecoder(MessageLoop* message_loop,
                                               FrameConsumer* consumer)
    : message_loop_(message_loop),
      consumer_(consumer) {
}

RectangleUpdateDecoder::~RectangleUpdateDecoder() {
}

void RectangleUpdateDecoder::DecodePacket(const VideoPacket& packet,
                                          Task* done) {
  if (message_loop_ != MessageLoop::current()) {
    message_loop_->PostTask(
        FROM_HERE,
        NewTracedMethod(this,
                        &RectangleUpdateDecoder::DecodePacket, packet,
                        done));
    return;
  }
  AutoTaskRunner done_runner(done);

  TraceContext::tracer()->PrintString("Decode Packet called.");

  if (!IsValidPacket(packet)) {
    LOG(ERROR) << "Received invalid packet.";
    return;
  }

  Task* process_packet_data =
      NewTracedMethod(this,
                      &RectangleUpdateDecoder::ProcessPacketData,
                      packet, done_runner.release());

  if (packet.flags() | VideoPacket::FIRST_PACKET) {
    const VideoPacketFormat& format = packet.format();

    InitializeDecoder(format, process_packet_data);
  } else {
    process_packet_data->Run();
    delete process_packet_data;
  }
}

void RectangleUpdateDecoder::ProcessPacketData(
    const VideoPacket& packet, Task* done) {
  AutoTaskRunner done_runner(done);

  if (!decoder_->IsReadyForData()) {
    // TODO(ajwong): This whole thing should move into an invalid state.
    LOG(ERROR) << "Decoder is unable to process data. Dropping packet.";
    return;
  }

  TraceContext::tracer()->PrintString("Executing Decode.");
  decoder_->DecodeBytes(packet.data());

  if (packet.flags() | VideoPacket::LAST_PACKET) {
    decoder_->Reset();

    UpdatedRects* rects = new UpdatedRects();

    // Empty out the list of current updated rects so the decoder can keep
    // writing new ones while these are processed.
    rects->swap(updated_rects_);

    consumer_->OnPartialFrameOutput(frame_, rects,
                                    new PartialFrameCleanup(frame_, rects));
  }
}

// static
bool RectangleUpdateDecoder::IsValidPacket(const VideoPacket& packet) {
  if (!packet.IsInitialized()) {
    LOG(WARNING) << "Protobuf consistency checks fail.";
    return false;
  }

  // First packet must have a format.
  if (packet.flags() | VideoPacket::FIRST_PACKET) {
    if (!packet.has_format()) {
      LOG(WARNING) << "First packet must have format.";
      return false;
    }

    // TODO(ajwong): Verify that we don't need to whitelist encodings.
    const VideoPacketFormat& format = packet.format();
    if (!format.has_encoding() ||
        format.encoding() == VideoPacketFormat::ENCODING_INVALID) {
      LOG(WARNING) << "Invalid encoding specified.";
      return false;
    }
  }

  // We shouldn't generate null packets.
  if (!packet.has_data()) {
    LOG(WARNING) << "Packet w/o data received.";
    return false;
  }

  return true;
}

void RectangleUpdateDecoder::InitializeDecoder(const VideoPacketFormat& format,
                                               Task* done) {
  if (message_loop_ != MessageLoop::current()) {
    message_loop_->PostTask(
        FROM_HERE,
        NewTracedMethod(this,
                        &RectangleUpdateDecoder::InitializeDecoder,
                        format, done));
    return;
  }
  AutoTaskRunner done_runner(done);

  // Check if we need to request a new frame.
  if (!frame_ ||
      frame_->width() < static_cast<size_t>(format.width()) ||
      frame_->height() < static_cast<size_t>(format.height())) {
    if (frame_) {
      TraceContext::tracer()->PrintString("Releasing old frame.");
      consumer_->ReleaseFrame(frame_);
      frame_ = NULL;
    }
    TraceContext::tracer()->PrintString("Requesting new frame.");
    consumer_->AllocateFrame(media::VideoFrame::RGB32,
                             format.width(), format.height(),
                             base::TimeDelta(), base::TimeDelta(),
                             &frame_,
                             NewTracedMethod(
                                 this,
                                 &RectangleUpdateDecoder::InitializeDecoder,
                                 format,
                                 done_runner.release()));
    return;
  }

  // TODO(ajwong): We need to handle the allocator failing to create a frame
  // and properly disable this class.
  CHECK(frame_);

  if (decoder_.get()) {
    // TODO(ajwong): We need to handle changing decoders midstream correctly
    // since someone may feed us a corrupt stream, or manually create a
    // stream that changes decoders. At the very leask, we should not
    // crash the process.
    //
    // For now though, assume that only one encoding is used throughout.
    //
    // Note, this may be as simple as just deleting the current decoder.
    // However, we need to verify the flushing semantics of the decoder first.
    CHECK(decoder_->Encoding() == format.encoding());
  } else {
    // Initialize a new decoder based on this message encoding.
    if (format.encoding() == VideoPacketFormat::ENCODING_VERBATIM) {
      TraceContext::tracer()->PrintString("Creating Verbatim decoder.");
      decoder_.reset(DecoderRowBased::CreateVerbatimDecoder());
    } else if (format.encoding() == VideoPacketFormat::ENCODING_ZLIB) {
      TraceContext::tracer()->PrintString("Creating Zlib decoder");
      decoder_.reset(DecoderRowBased::CreateZlibDecoder());
// TODO(sergeyu): Enable VP8 on ARM builds.
#if !defined(ARCH_CPU_ARM_FAMILY)
    } else if (format.encoding() == VideoPacketFormat::ENCODING_VP8) {
      TraceContext::tracer()->PrintString("Creating VP8 decoder");
      decoder_.reset(new DecoderVp8());
#endif
    } else {
      NOTREACHED() << "Invalid Encoding found: " << format.encoding();
    }
  }

  // TODO(ajwong): This can happen in the face of corrupt input data.  Figure
  // out the right behavior and make this more resilient.
  CHECK(updated_rects_.empty());

  gfx::Rect rectangle_size(format.x(), format.y(),
                           format.width(), format.height());
  updated_rects_.push_back(rectangle_size);
  decoder_->Initialize(frame_, rectangle_size,
                       GetBytesPerPixel(format.pixel_format()));
  TraceContext::tracer()->PrintString("Decoder is Initialized");
}

}  // namespace remoting
<|endoftext|>