<commit_before>#include "page.h"
#include "bloom_filter.h"
#include <fstream>
#include <cassert>
#include <algorithm>
#include <cstring>

using namespace dariadb::storage;

class PageCursor : public dariadb::storage::Cursor {
public:
	PageCursor(Page*page, const dariadb::IdArray&ids, dariadb::Time from, dariadb::Time to, dariadb::Flag flag) :
		link(page),
		_ids(ids),
		_from(from),
		_to(to),
		_flag(flag)
	{
		reset_pos();
	}

	~PageCursor() {
		if (link != nullptr) {
			link->dec_reader();
			link = nullptr;
		}
	}

	bool is_end()const override {
		return _is_end;
	}

	void readNext(Cursor::Callback*cbk)  override {
		std::lock_guard<dariadb::utils::Locker> lg(_locker);
		for (; !_is_end; _index_it++) {
			if (_index_it == _index_end) {
				Chunk_Ptr empty;
				cbk->call(empty);
				_is_end = true;
				break;
			}
			if (!_index_it->is_init) {
				Chunk_Ptr empty;
				cbk->call(empty);
				_is_end = true;
				continue;
			}

			if ((_ids.size() != 0) && (std::find(_ids.begin(), _ids.end(), _index_it->info.first.id) == _ids.end())) {
				continue;
			}

			if (!dariadb::storage::bloom_check(_index_it->info.flag_bloom, _flag)) {
				continue;
			}

			if ((dariadb::utils::inInterval(_from, _to, _index_it->info.minTime)) || (dariadb::utils::inInterval(_from, _to, _index_it->info.maxTime))) {
				auto ptr = new Chunk(_index_it->info, link->chunks + _index_it->offset, link->header->chunk_size);
				Chunk_Ptr c{ ptr };
				assert(c->last.time != 0);
				cbk->call(c);
				_index_it++;
				break;
			}
		}
	}
	void reset_pos() override { //start read from begining;
		_is_end = false;
		_index_end = link->index + link->header->chunk_per_storage;
		_index_it = link->index;

	}
protected:
	Page* link;
	bool _is_end;
	Page_ChunkIndex *_index_it, *_index_end;
	dariadb::IdArray _ids;
	dariadb::Time _from, _to;
	dariadb::Flag _flag;
	dariadb::utils::Locker _locker;
};

Page::~Page() {
	region=nullptr;
	header=nullptr;
	index=nullptr;
	chunks=nullptr;
	mmap->close();
}

Page* Page::create(std::string file_name, uint64_t sz, uint32_t chunk_per_storage, uint32_t chunk_size) {
	auto res = new Page;
	auto mmap = utils::fs::MappedFile::touch(file_name, sz);
	auto region = mmap->data();
	std::fill(region, region + sz, 0);

	res->mmap = mmap;
	res->region = region;
	res->header = reinterpret_cast<PageHeader*>(region);
	res->index = reinterpret_cast<Page_ChunkIndex*>(region + sizeof(PageHeader));
	res->chunks = reinterpret_cast<uint8_t*>(region + sizeof(PageHeader) + sizeof(Page_ChunkIndex)*chunk_per_storage);

	res->header->chunk_per_storage = chunk_per_storage;
	res->header->chunk_size = chunk_size;
	res->header->maxTime = dariadb::Time(0);
	res->header->minTime = std::numeric_limits<dariadb::Time>::max();
    res->header->is_overwrite=false;
	return res;
}

Page* Page::open(std::string file_name) {
	auto res = new Page;
	auto mmap = utils::fs::MappedFile::open(file_name);

	auto region = mmap->data();

	res->mmap = mmap;
	res->region = region;
	res->header = reinterpret_cast<PageHeader*>(region);
	res->index = reinterpret_cast<Page_ChunkIndex*>(region + sizeof(PageHeader));
	res->chunks = reinterpret_cast<uint8_t*>(region + sizeof(PageHeader) + sizeof(Page_ChunkIndex)*res->header->chunk_per_storage);
	if (res->header->chunk_size == 0) {
		throw MAKE_EXCEPTION("(res->header->chunk_size == 0)");
	}
	return res;
}

PageHeader Page::readHeader(std::string file_name) {
	std::ifstream istream;
	istream.open(file_name, std::fstream::in | std::fstream::binary);
	if (!istream.is_open()) {
		std::stringstream ss;
		ss << "can't open file. filename=" << file_name;
		throw MAKE_EXCEPTION(ss.str());
	}
	PageHeader result;
	memset(&result, 0, sizeof(PageHeader));
	istream.read((char *)&result, sizeof(PageHeader));
	istream.close();
	return result;

}

uint32_t Page::get_oldes_index() {
    auto min_time = std::numeric_limits<dariadb::Time>::max();
    uint32_t pos = 0;
    auto index_end = index + header->chunk_per_storage;
    uint32_t i = 0;
    for (auto index_it = index; index_it != index_end; ++index_it, ++i) {
        if (index_it->info.minTime<min_time) {
            pos = i;
            min_time = index_it->info.minTime;
        }
    }
    return pos;
}

bool Page::append(const Chunk_Ptr&ch, MODE mode) {
    std::lock_guard<dariadb::utils::Locker> lg(_locker);
	auto index_rec = (ChunkIndexInfo*)ch.get();
	auto buffer = ch->_buffer_t.data();

	assert(ch->last.time != 0);
	assert(header->chunk_size == ch->_buffer_t.size());
	if (is_full()) {
        if (mode == MODE::SINGLE) {
            header->is_overwrite=true;
            header->pos_index=0;
        }
		else {
			return false;
		}
	}
	index[header->pos_index].info = *index_rec;

    index[header->pos_index].is_init = true;

    if(!header->is_overwrite){
        index[header->pos_index].offset = header->pos_chunks;
        header->pos_chunks += header->chunk_size;
        header->addeded_chunks++;
    }
	memcpy(this->chunks + index[header->pos_index].offset, buffer, sizeof(uint8_t)*header->chunk_size);

	header->pos_index++;
	header->minTime = std::min(header->minTime,ch->minTime);
	header->maxTime = std::max(header->maxTime, ch->maxTime);

	return true;
}

bool Page::is_full()const {
	return !(header->pos_index < header->chunk_per_storage);
}

Cursor_ptr Page::get_chunks(const dariadb::IdArray&ids, dariadb::Time from, dariadb::Time to, dariadb::Flag flag) {
    std::lock_guard<dariadb::utils::Locker> lg(_locker);

	auto raw_ptr = new PageCursor(this,ids,from,to,flag );
	Cursor_ptr result{ raw_ptr };

	header->count_readers++;

	return result;
}

ChuncksList Page::get_open_chunks() {
    std::lock_guard<dariadb::utils::Locker> lg(_locker);
	auto index_end = this->index + this->header->pos_index;
	auto index_it = this->index;
	ChuncksList result;
	for (; index_it != index_end; index_it++) {
		if (!index_it->is_init) {
			continue;
		}
		if (!index_it->info.is_readonly) {
			index_it->is_init = false;
            auto ptr=new Chunk(index_it->info, this->chunks + index_it->offset, this->header->chunk_size);
            Chunk_Ptr c = Chunk_Ptr(ptr);
			result.push_back(c);
		}
	}
	return result;
}

void Page::dec_reader(){
    std::lock_guard<dariadb::utils::Locker> lg(_locker);
	header->count_readers--;
}

Cursor_ptr dariadb::storage::Page::chunksByIterval(const IdArray & ids, Flag flag, Time from, Time to)
{
	return get_chunks(ids, from, to, flag);
}

IdToChunkMap dariadb::storage::Page::chunksBeforeTimePoint(const IdArray & ids, Flag flag, Time timePoint)
{
	IdToChunkMap result;

	ChuncksList ch_list;
	auto cursor = this->get_chunks(ids, header->minTime, timePoint, flag);
	if (cursor == nullptr) {
		return result;
	}
	cursor->readAll(&ch_list);

	for (auto&v : ch_list) {
		auto find_res = result.find(v->first.id);
		if (find_res == result.end()) {
			result.insert(std::make_pair(v->first.id, v));
		}
		else {
			if (find_res->second->maxTime < v->maxTime) {
				result[v->first.id] = v;
			}
		}
	}
	return result;
}
class CountOfIdCallback :public Cursor::Callback {
public:
	dariadb::IdSet ids;
	CountOfIdCallback() {
	}
	~CountOfIdCallback() {
	}

	virtual void call(Chunk_Ptr & ptr) override {
		if (ptr != nullptr) {
			ids.insert(ptr->first.id);
		}
	}
};

dariadb::IdArray dariadb::storage::Page::getIds()
{
	auto cursor = get_chunks(dariadb::IdArray{}, header->minTime, header->maxTime, 0);

	CountOfIdCallback*clbk_raw = new CountOfIdCallback;
	std::unique_ptr<Cursor::Callback> clbk{ clbk_raw };

	cursor->readAll(clbk.get());

	return dariadb::IdArray{ clbk_raw->ids.begin(),clbk_raw->ids.end() };
}<commit_msg>PageCursor read alg change.<commit_after>#include "page.h"
#include "bloom_filter.h"
#include <fstream>
#include <cassert>
#include <algorithm>
#include <cstring>

using namespace dariadb::storage;

class PageCursor : public dariadb::storage::Cursor {
public:
	PageCursor(Page*page, const dariadb::IdArray&ids, dariadb::Time from, dariadb::Time to, dariadb::Flag flag) :
		link(page),
		_ids(ids),
		_from(from),
		_to(to),
		_flag(flag)
	{
		reset_pos();
	}

	~PageCursor() {
		if (link != nullptr) {
			link->dec_reader();
			link = nullptr;
		}
	}

	bool is_end()const override {
		return _is_end;
	}

	void readNext(Cursor::Callback*cbk)  override {
		std::lock_guard<dariadb::utils::Locker> lg(_locker);
		for (; !_is_end; _index_it++) {
			if (_index_it == _index_end) {
				Chunk_Ptr empty;
				cbk->call(empty);
				_is_end = true;
				break;
			}
			if (!_index_it->is_init) {
				Chunk_Ptr empty;
				cbk->call(empty);
				_is_end = true;
				continue;
			}

			if ((_ids.size() != 0) && (std::find(_ids.begin(), _ids.end(), _index_it->info.first.id) == _ids.end())) {
				continue;
			}

			if (!dariadb::storage::bloom_check(_index_it->info.flag_bloom, _flag)) {
				continue;
			}

			if (check_index_rec(_index_it)) {
				auto ptr = new Chunk(_index_it->info, link->chunks + _index_it->offset, link->header->chunk_size);
				Chunk_Ptr c{ ptr };
				assert(c->last.time != 0);
				cbk->call(c);
				_index_it++;
				break;
			}
			else {//end of data;
				_is_end = true;
				Chunk_Ptr empty;
				cbk->call(empty);
				break;
			}
		}
	}

	bool check_index_rec(Page_ChunkIndex*it) const{
		return ((dariadb::utils::inInterval(_from, _to, it->info.minTime)) || (dariadb::utils::inInterval(_from, _to, it->info.maxTime)));
	}

	void reset_pos() override { //start read from begining;
		_is_end = false;
		_index_end = link->index + link->header->chunk_per_storage;
		_index_it = link->index;

		//move to data begining
		for (; !_is_end; _index_it++) {
			if (_index_it == _index_end) {
				_is_end = true;
				break;
			}
			if (check_index_rec(_index_it)) {
				break;
			}
		}
	}
protected:
	Page* link;
	bool _is_end;
	Page_ChunkIndex *_index_it, *_index_end;
	dariadb::IdArray _ids;
	dariadb::Time _from, _to;
	dariadb::Flag _flag;
	dariadb::utils::Locker _locker;
};

Page::~Page() {
	region=nullptr;
	header=nullptr;
	index=nullptr;
	chunks=nullptr;
	mmap->close();
}

Page* Page::create(std::string file_name, uint64_t sz, uint32_t chunk_per_storage, uint32_t chunk_size) {
	auto res = new Page;
	auto mmap = utils::fs::MappedFile::touch(file_name, sz);
	auto region = mmap->data();
	std::fill(region, region + sz, 0);

	res->mmap = mmap;
	res->region = region;
	res->header = reinterpret_cast<PageHeader*>(region);
	res->index = reinterpret_cast<Page_ChunkIndex*>(region + sizeof(PageHeader));
	res->chunks = reinterpret_cast<uint8_t*>(region + sizeof(PageHeader) + sizeof(Page_ChunkIndex)*chunk_per_storage);

	res->header->chunk_per_storage = chunk_per_storage;
	res->header->chunk_size = chunk_size;
	res->header->maxTime = dariadb::Time(0);
	res->header->minTime = std::numeric_limits<dariadb::Time>::max();
    res->header->is_overwrite=false;
	return res;
}

Page* Page::open(std::string file_name) {
	auto res = new Page;
	auto mmap = utils::fs::MappedFile::open(file_name);

	auto region = mmap->data();

	res->mmap = mmap;
	res->region = region;
	res->header = reinterpret_cast<PageHeader*>(region);
	res->index = reinterpret_cast<Page_ChunkIndex*>(region + sizeof(PageHeader));
	res->chunks = reinterpret_cast<uint8_t*>(region + sizeof(PageHeader) + sizeof(Page_ChunkIndex)*res->header->chunk_per_storage);
	if (res->header->chunk_size == 0) {
		throw MAKE_EXCEPTION("(res->header->chunk_size == 0)");
	}
	return res;
}

PageHeader Page::readHeader(std::string file_name) {
	std::ifstream istream;
	istream.open(file_name, std::fstream::in | std::fstream::binary);
	if (!istream.is_open()) {
		std::stringstream ss;
		ss << "can't open file. filename=" << file_name;
		throw MAKE_EXCEPTION(ss.str());
	}
	PageHeader result;
	memset(&result, 0, sizeof(PageHeader));
	istream.read((char *)&result, sizeof(PageHeader));
	istream.close();
	return result;

}

uint32_t Page::get_oldes_index() {
    auto min_time = std::numeric_limits<dariadb::Time>::max();
    uint32_t pos = 0;
    auto index_end = index + header->chunk_per_storage;
    uint32_t i = 0;
    for (auto index_it = index; index_it != index_end; ++index_it, ++i) {
        if (index_it->info.minTime<min_time) {
            pos = i;
            min_time = index_it->info.minTime;
        }
    }
    return pos;
}

bool Page::append(const Chunk_Ptr&ch, MODE mode) {
    std::lock_guard<dariadb::utils::Locker> lg(_locker);
	auto index_rec = (ChunkIndexInfo*)ch.get();
	auto buffer = ch->_buffer_t.data();

	assert(ch->last.time != 0);
	assert(header->chunk_size == ch->_buffer_t.size());
	if (is_full()) {
        if (mode == MODE::SINGLE) {
            header->is_overwrite=true;
            header->pos_index=0;
        }
		else {
			return false;
		}
	}
	index[header->pos_index].info = *index_rec;

    index[header->pos_index].is_init = true;

    if(!header->is_overwrite){
        index[header->pos_index].offset = header->pos_chunks;
        header->pos_chunks += header->chunk_size;
        header->addeded_chunks++;
    }
	memcpy(this->chunks + index[header->pos_index].offset, buffer, sizeof(uint8_t)*header->chunk_size);

	header->pos_index++;
	header->minTime = std::min(header->minTime,ch->minTime);
	header->maxTime = std::max(header->maxTime, ch->maxTime);

	return true;
}

bool Page::is_full()const {
	return !(header->pos_index < header->chunk_per_storage);
}

Cursor_ptr Page::get_chunks(const dariadb::IdArray&ids, dariadb::Time from, dariadb::Time to, dariadb::Flag flag) {
    std::lock_guard<dariadb::utils::Locker> lg(_locker);

	auto raw_ptr = new PageCursor(this,ids,from,to,flag );
	Cursor_ptr result{ raw_ptr };

	header->count_readers++;

	return result;
}

ChuncksList Page::get_open_chunks() {
    std::lock_guard<dariadb::utils::Locker> lg(_locker);
	auto index_end = this->index + this->header->pos_index;
	auto index_it = this->index;
	ChuncksList result;
	for (; index_it != index_end; index_it++) {
		if (!index_it->is_init) {
			continue;
		}
		if (!index_it->info.is_readonly) {
			index_it->is_init = false;
            auto ptr=new Chunk(index_it->info, this->chunks + index_it->offset, this->header->chunk_size);
            Chunk_Ptr c = Chunk_Ptr(ptr);
			result.push_back(c);
		}
	}
	return result;
}

void Page::dec_reader(){
    std::lock_guard<dariadb::utils::Locker> lg(_locker);
	header->count_readers--;
}

Cursor_ptr dariadb::storage::Page::chunksByIterval(const IdArray & ids, Flag flag, Time from, Time to)
{
	return get_chunks(ids, from, to, flag);
}

IdToChunkMap dariadb::storage::Page::chunksBeforeTimePoint(const IdArray & ids, Flag flag, Time timePoint)
{
	IdToChunkMap result;

	ChuncksList ch_list;
	auto cursor = this->get_chunks(ids, header->minTime, timePoint, flag);
	if (cursor == nullptr) {
		return result;
	}
	cursor->readAll(&ch_list);

	for (auto&v : ch_list) {
		auto find_res = result.find(v->first.id);
		if (find_res == result.end()) {
			result.insert(std::make_pair(v->first.id, v));
		}
		else {
			if (find_res->second->maxTime < v->maxTime) {
				result[v->first.id] = v;
			}
		}
	}
	return result;
}
class CountOfIdCallback :public Cursor::Callback {
public:
	dariadb::IdSet ids;
	CountOfIdCallback() {
	}
	~CountOfIdCallback() {
	}

	virtual void call(Chunk_Ptr & ptr) override {
		if (ptr != nullptr) {
			ids.insert(ptr->first.id);
		}
	}
};

dariadb::IdArray dariadb::storage::Page::getIds()
{
	auto cursor = get_chunks(dariadb::IdArray{}, header->minTime, header->maxTime, 0);

	CountOfIdCallback*clbk_raw = new CountOfIdCallback;
	std::unique_ptr<Cursor::Callback> clbk{ clbk_raw };

	cursor->readAll(clbk.get());

	return dariadb::IdArray{ clbk_raw->ids.begin(),clbk_raw->ids.end() };
}<|endoftext|>


<commit_before>#include <QDebug>
#include <cdio/cdio.h>
#include "CdromManager.h"
#include "MetadataManager.h"
#include "Player.h"

#ifdef EMS_CDROM_RIPPER
#include "CdromRipper.h"
#endif

#define INTERFACE "com.EnnaMediaServer.Cdrom"
#define SIGNAL_NAME_INSERT "inserted"
#define SIGNAL_NAME_REMOVE "removed"

/* ---------------------------------------------------------
 *                          UTILS
 * --------------------------------------------------------- */
static inline int cddb_sum(int n)
{
    int result = 0;
    while (n > 0)
    {
        result += n % 10;
        n /= 10;
    }
    return result;
}

void CdromManager::getAvailableCdroms(QVector<EMSCdrom> *cdromsOut)
{
    cdromsOut->clear();
    mutex.lock();
    for (int i=0; i<cdroms.size(); i++)
    {
        cdromsOut->append(cdroms.at(i));
    }
    mutex.unlock();
}

bool CdromManager::getCdrom(QString device, EMSCdrom *cdrom)
{
    bool found = false;

    mutex.lock();
    for (int i=0; i<cdroms.size(); i++)
    {
        if (cdroms.at(i).device == device)
        {
            *cdrom = cdroms.at(i);
            found = true;
            break;
        }
    }
    mutex.unlock();

    return found;
}

bool CdromManager::isRipInProgress()
{
#ifdef EMS_CDROM_RIPPER
    if (m_cdromRipper)
        return true;
#endif
    return false;
}

void CdromManager::setRipAudioFormat(const QString &ripAudioFormat)
{
    m_ripAudioFormat = ripAudioFormat;
}

/* ---------------------------------------------------------
 *                    INSERT/REMOVE HOOK
 * --------------------------------------------------------- */
void CdromManager::dbusMessageInsert(QString message)
{
    EMSCdrom newCD;
    unsigned int sum = 0;

    /* Check the new CD is not already in the list */
    if (getCdrom(message, &newCD))
    {
        qCritical() << "CD already in the list of current CDROM.";
        return;
    }

    /* The given message only contain the device name */
    newCD.device = message;
    qDebug() << "New CDROM inserted : " << newCD.device;

    /* Open the CD and get track data (number, duration, ...) */
    CdIo_t *cdrom = cdio_open(newCD.device.toStdString().c_str(), DRIVER_UNKNOWN);
    if (!cdrom)
    {
        qCritical() << "Unable to open device " << newCD.device;
        return;
    }

    /* Check that the inserted cdrom is a CD-DA */
    discmode_t mode = cdio_get_discmode(cdrom);
    if (mode != CDIO_DISC_MODE_CD_DA)
    {
        /* Ignore not valid CDROM */
        qDebug() << "Inserted disk is not an audio CD " << QString("(%1)").arg(mode);
        return;
    }

    /* Get size of the disck */
    track_t trackNumber = cdio_get_num_tracks(cdrom);
    if (trackNumber <= 1)
    {
        qCritical() << "Unable to read CDROM TOC";
    }
    qDebug() << "Found " << QString("%1").arg(trackNumber) << " tracks in " << newCD.device;

    /* Retrieve each track data */
    for (track_t i=1; i<=trackNumber; i++)
    {
        EMSTrack track;
        track.filename = newCD.device;
        track.type = TRACK_TYPE_CDROM;
        track.position = i;
        lsn_t lsnBegin = cdio_get_track_lsn(cdrom, i);
        lsn_t lsnEnd = cdio_get_track_last_lsn(cdrom, i);
        track.duration = (lsnEnd - lsnBegin + 1) / CDIO_CD_FRAMES_PER_SEC; /* One sector = 1/75s */
        track.format = QString("cdda");
        track.sample_rate = 44100;

        /* Add the new track in the list only if it is an audio track */
        track_format_t format = cdio_get_track_format(cdrom, i);
        if (format == TRACK_FORMAT_AUDIO)
        {
            newCD.tracks.append(track);
        }

        /* For disc id computation */
        lba_t lba = cdio_lsn_to_lba (lsnBegin);
        sum += cddb_sum(lba / CDIO_CD_FRAMES_PER_SEC);

        QPair<lsn_t, lsn_t> trackSectors(lsnBegin, lsnEnd);
        newCD.trackSectors[i] = trackSectors;
    }

    /* Compute the discid
     * Code copied from libcdio/example/discid.c
     */
    unsigned start_sec = cdio_get_track_lba(cdrom, 1) / CDIO_CD_FRAMES_PER_SEC;
    unsigned leadout_sec = cdio_get_track_lba(cdrom, CDIO_CDROM_LEADOUT_TRACK) / CDIO_CD_FRAMES_PER_SEC;
    unsigned total = leadout_sec - start_sec;
    unsigned id = ((sum % 0xff) << 24 | total << 8 | trackNumber);

    newCD.disc_id = QString().sprintf("%08X %d", id, trackNumber);
    for (track_t i=1; i <=trackNumber; i++)
    {
        lba_t lba = cdio_get_track_lba(cdrom, i);
        newCD.disc_id += QString().sprintf(" %ld", (long) lba);
    }
    newCD.disc_id += QString().sprintf(" %u", leadout_sec);
    cdio_destroy(cdrom);

    qDebug() << "Computed DISCID is " << newCD.disc_id;

    /* Add the new CDROM in the list and emit signal to warn listeners */
    mutex.lock();
    cdroms.append(newCD);
    mutex.unlock();
    emit cdromInserted(newCD);

    /* Ask metadata to all plugins which can handle "discid" lookup
     */
    QStringList capabilities;
    capabilities << "discid";
    for(int i=0; i<newCD.tracks.size(); i++)
    {
        emit cdromTrackNeedUpdate(newCD.tracks.at(i), capabilities);
    }
}

void CdromManager::cdromTrackUpdated(EMSTrack track, bool complete)
{
    bool found = false;
    unsigned cdromID = 0;

    if (track.type != TRACK_TYPE_CDROM)
    {
        return;
    }

    if (!complete)
    {
        return;
    }

    if (track.name.isEmpty())
    {
        track.name = QString("Track %1").arg(track.position);
    }

    /* Retrieve the corresponding cdrom in the list of cdroms */
    mutex.lock();
    for (int i=0; i<cdroms.size(); i++)
    {
        if (cdroms.at(i).device == track.filename)
        {
            cdromID = i;
            found = true;
            break;
        }
    }

    if (found)
    {
        EMSCdrom cdrom = cdroms.at(cdromID);

        for(int i=0; i<cdrom.tracks.size(); i++)
        {
            /* If an album has been found, make sure it is the same as for
             * the other track.
             */
            if (!track.album.name.isEmpty())
            {
                if (cdrom.tracks.at(i).album.name.isEmpty())
                {
                    EMSTrack other = cdrom.tracks.at(i);
                    other.album = track.album;
                    other.genres = track.genres;
                    other.artists = track.artists;
                    cdrom.tracks.replace(i, other);
                }
            } else if (!cdrom.tracks.at(i).album.name.isEmpty())
            {
                track.album = cdrom.tracks.at(i).album;
                track.genres = cdrom.tracks.at(i).genres;
                track.artists = cdrom.tracks.at(i).artists;
            }

            /* Replace the new Cdrom */
            if(cdrom.tracks.at(i).position == track.position)
            {
                cdrom.tracks.replace(i, track);
            }

        }
        cdroms[cdromID] = cdrom;
    }

    if (found)
    {
        emit cdromChanged(cdroms.at(cdromID));
    }
    mutex.unlock();
}

void CdromManager::dbusMessageRemove(QString message)
{
    bool found = false;
    EMSCdrom cdrom;
    mutex.lock();
    for (int i=0; i<cdroms.size(); i++)
    {
        if (cdroms.at(i).device == message)
        {
            cdrom = cdroms.at(i);
            cdroms.removeAt(i);
            found = true;
            break;
        }
    }
    mutex.unlock();

    if (!found)
    {
        /* Ejected CDROM is not found */
        return;
    }

    qDebug() << "CDROM ejected : " << cdrom.device;

    /* Remove played CDROM from the current playlist */
    EMSPlaylist playlist = Player::instance()->getCurentPlaylist();
    for (int i=0; i<playlist.tracks.size(); i++)
    {
        EMSTrack track = playlist.tracks.at(i);
        if (track.type == TRACK_TYPE_CDROM && track.filename == cdrom.device)
        {
            Player::instance()->removeTrack(track);
        }
    }

    emit cdromEjected(cdrom);
}

/* ---------------------------------------------------------
 *                  START/STOP CDROM MANAGER
 * --------------------------------------------------------- */

CdromManager* CdromManager::_instance = 0;

CdromManager::CdromManager(QObject *parent) : QObject(parent),
                                              bus(QDBusConnection::systemBus())
{
    cdio_init();

    qRegisterMetaType<EMSCdrom>("EMSCdrom");

    connect(this, SIGNAL(cdromTrackNeedUpdate(EMSTrack,QStringList)), MetadataManager::instance(), SLOT(update(EMSTrack,QStringList)));
    connect(MetadataManager::instance(), SIGNAL(updated(EMSTrack,bool)), this, SLOT(cdromTrackUpdated(EMSTrack,bool)));
}

CdromManager::~CdromManager()
{
    disconnect(this, SIGNAL(cdromTrackNeedUpdate(EMSTrack,QStringList)), MetadataManager::instance(), SLOT(update(EMSTrack,QStringList)));
    disconnect(MetadataManager::instance(), SIGNAL(updated(EMSTrack,bool)), this, SLOT(cdromTrackUpdated(EMSTrack,bool)));

#ifdef EMS_CDROM_RIPPER
    delete m_cdromRipper;
#endif
}

bool CdromManager::startMonitor()
{
    if (!bus.isConnected())
    {
        qCritical() << "Could not connect to session bus ! No CDROM management.";
        return false;
    }
    else
    {
        bus.connect(QString(), QString(), INTERFACE , SIGNAL_NAME_INSERT, this, SLOT(dbusMessageInsert(QString)));
        bus.connect(QString(), QString(), INTERFACE , SIGNAL_NAME_REMOVE, this, SLOT(dbusMessageRemove(QString)));
    }

    /* In case of CDROM already present, trigger actions using udevadm
     * Note: EMS must be launched with root rights or be able to trigger action using udev.
     */
    QProcess cmd;
    cmd.execute(QString("/bin/udevadm"), QString("trigger --action=change --sysname-match=sr[0-9]").split(' '));

    return true;
}

void CdromManager::stopMonitor()
{
    if (bus.isConnected())
    {
        bus.disconnect(QString(), QString(), INTERFACE , SIGNAL_NAME_INSERT, this, SLOT(dbusMessageInsert(QString)));
        bus.disconnect(QString(), QString(), INTERFACE , SIGNAL_NAME_REMOVE, this, SLOT(dbusMessageRemove(QString)));
    }
}

void CdromManager::startRip()
{
#ifdef EMS_CDROM_RIPPER

    /* Get first available CDROM */
    QVector<EMSCdrom> cdroms;
    getAvailableCdroms(&cdroms);

    /* Start the thread */
    if ((cdroms.size() > 0) && (!isRipInProgress()))
    {
        EMSCdrom cdrom = cdroms.at(0);
        m_cdromRipper = new CdromRipper(this);

        connect(m_cdromRipper, &CdromRipper::resultReady, this, &CdromManager::handleCdromRipperResults);
        connect(m_cdromRipper, &CdromRipper::finished, m_cdromRipper, &QObject::deleteLater);
        connect(m_cdromRipper, &CdromRipper::ripProgressChanged, this, &CdromManager::ripProgress);

        m_cdromRipper->setCdrom(cdrom);
        m_cdromRipper->setAudioFormat(m_ripAudioFormat);
        m_cdromRipper->start();
    }

#endif
}

void CdromManager::ripProgress(EMSRipProgress ripProgress)
{
    emit ripProgressChanged(ripProgress);
}

void CdromManager::handleCdromRipperResults(const QString &result )
{
#ifdef EMS_CDROM_RIPPER

    if (m_cdromRipper)
    {
        qDebug() << "CdromManager handle cdrom ripper results: " << result;
        delete m_cdromRipper;
        m_cdromRipper = Q_NULLPTR;
    }
#endif
}
<commit_msg>Connect slot with direct connexion to let the gracenote search information in CDromManager thread and avoid to lost connexion with client<commit_after>#include <QDebug>
#include <cdio/cdio.h>
#include "CdromManager.h"
#include "MetadataManager.h"
#include "Player.h"

#ifdef EMS_CDROM_RIPPER
#include "CdromRipper.h"
#endif

#define INTERFACE "com.EnnaMediaServer.Cdrom"
#define SIGNAL_NAME_INSERT "inserted"
#define SIGNAL_NAME_REMOVE "removed"

/* ---------------------------------------------------------
 *                          UTILS
 * --------------------------------------------------------- */
static inline int cddb_sum(int n)
{
    int result = 0;
    while (n > 0)
    {
        result += n % 10;
        n /= 10;
    }
    return result;
}

void CdromManager::getAvailableCdroms(QVector<EMSCdrom> *cdromsOut)
{
    cdromsOut->clear();
    mutex.lock();
    for (int i=0; i<cdroms.size(); i++)
    {
        cdromsOut->append(cdroms.at(i));
    }
    mutex.unlock();
}

bool CdromManager::getCdrom(QString device, EMSCdrom *cdrom)
{
    bool found = false;

    mutex.lock();
    for (int i=0; i<cdroms.size(); i++)
    {
        if (cdroms.at(i).device == device)
        {
            *cdrom = cdroms.at(i);
            found = true;
            break;
        }
    }
    mutex.unlock();

    return found;
}

bool CdromManager::isRipInProgress()
{
#ifdef EMS_CDROM_RIPPER
    if (m_cdromRipper)
        return true;
#endif
    return false;
}

void CdromManager::setRipAudioFormat(const QString &ripAudioFormat)
{
    m_ripAudioFormat = ripAudioFormat;
}

/* ---------------------------------------------------------
 *                    INSERT/REMOVE HOOK
 * --------------------------------------------------------- */
void CdromManager::dbusMessageInsert(QString message)
{
    EMSCdrom newCD;
    unsigned int sum = 0;

    /* Check the new CD is not already in the list */
    if (getCdrom(message, &newCD))
    {
        qCritical() << "CD already in the list of current CDROM.";
        return;
    }

    /* The given message only contain the device name */
    newCD.device = message;
    qDebug() << "New CDROM inserted : " << newCD.device;

    /* Open the CD and get track data (number, duration, ...) */
    CdIo_t *cdrom = cdio_open(newCD.device.toStdString().c_str(), DRIVER_UNKNOWN);
    if (!cdrom)
    {
        qCritical() << "Unable to open device " << newCD.device;
        return;
    }

    /* Check that the inserted cdrom is a CD-DA */
    discmode_t mode = cdio_get_discmode(cdrom);
    if (mode != CDIO_DISC_MODE_CD_DA)
    {
        /* Ignore not valid CDROM */
        qDebug() << "Inserted disk is not an audio CD " << QString("(%1)").arg(mode);
        return;
    }

    /* Get size of the disck */
    track_t trackNumber = cdio_get_num_tracks(cdrom);
    if (trackNumber <= 1)
    {
        qCritical() << "Unable to read CDROM TOC";
    }
    qDebug() << "Found " << QString("%1").arg(trackNumber) << " tracks in " << newCD.device;

    /* Retrieve each track data */
    for (track_t i=1; i<=trackNumber; i++)
    {
        EMSTrack track;
        track.filename = newCD.device;
        track.type = TRACK_TYPE_CDROM;
        track.position = i;
        lsn_t lsnBegin = cdio_get_track_lsn(cdrom, i);
        lsn_t lsnEnd = cdio_get_track_last_lsn(cdrom, i);
        track.duration = (lsnEnd - lsnBegin + 1) / CDIO_CD_FRAMES_PER_SEC; /* One sector = 1/75s */
        track.format = QString("cdda");
        track.sample_rate = 44100;

        /* Add the new track in the list only if it is an audio track */
        track_format_t format = cdio_get_track_format(cdrom, i);
        if (format == TRACK_FORMAT_AUDIO)
        {
            newCD.tracks.append(track);
        }

        /* For disc id computation */
        lba_t lba = cdio_lsn_to_lba (lsnBegin);
        sum += cddb_sum(lba / CDIO_CD_FRAMES_PER_SEC);

        QPair<lsn_t, lsn_t> trackSectors(lsnBegin, lsnEnd);
        newCD.trackSectors[i] = trackSectors;
    }

    /* Compute the discid
     * Code copied from libcdio/example/discid.c
     */
    unsigned start_sec = cdio_get_track_lba(cdrom, 1) / CDIO_CD_FRAMES_PER_SEC;
    unsigned leadout_sec = cdio_get_track_lba(cdrom, CDIO_CDROM_LEADOUT_TRACK) / CDIO_CD_FRAMES_PER_SEC;
    unsigned total = leadout_sec - start_sec;
    unsigned id = ((sum % 0xff) << 24 | total << 8 | trackNumber);

    newCD.disc_id = QString().sprintf("%08X %d", id, trackNumber);
    for (track_t i=1; i <=trackNumber; i++)
    {
        lba_t lba = cdio_get_track_lba(cdrom, i);
        newCD.disc_id += QString().sprintf(" %ld", (long) lba);
    }
    newCD.disc_id += QString().sprintf(" %u", leadout_sec);
    cdio_destroy(cdrom);

    qDebug() << "Computed DISCID is " << newCD.disc_id;

    /* Add the new CDROM in the list and emit signal to warn listeners */
    mutex.lock();
    cdroms.append(newCD);
    mutex.unlock();
    emit cdromInserted(newCD);

    /* Ask metadata to all plugins which can handle "discid" lookup
     */
    QStringList capabilities;
    capabilities << "discid";
    for(int i=0; i<newCD.tracks.size(); i++)
    {
        emit cdromTrackNeedUpdate(newCD.tracks.at(i), capabilities);
    }
}

void CdromManager::cdromTrackUpdated(EMSTrack track, bool complete)
{
    bool found = false;
    unsigned cdromID = 0;

    if (track.type != TRACK_TYPE_CDROM)
    {
        return;
    }

    if (!complete)
    {
        return;
    }

    if (track.name.isEmpty())
    {
        track.name = QString("Track %1").arg(track.position);
    }

    /* Retrieve the corresponding cdrom in the list of cdroms */
    mutex.lock();
    for (int i=0; i<cdroms.size(); i++)
    {
        if (cdroms.at(i).device == track.filename)
        {
            cdromID = i;
            found = true;
            break;
        }
    }

    if (found)
    {
        EMSCdrom cdrom = cdroms.at(cdromID);

        for(int i=0; i<cdrom.tracks.size(); i++)
        {
            /* If an album has been found, make sure it is the same as for
             * the other track.
             */
            if (!track.album.name.isEmpty())
            {
                if (cdrom.tracks.at(i).album.name.isEmpty())
                {
                    EMSTrack other = cdrom.tracks.at(i);
                    other.album = track.album;
                    other.genres = track.genres;
                    other.artists = track.artists;
                    cdrom.tracks.replace(i, other);
                }
            } else if (!cdrom.tracks.at(i).album.name.isEmpty())
            {
                track.album = cdrom.tracks.at(i).album;
                track.genres = cdrom.tracks.at(i).genres;
                track.artists = cdrom.tracks.at(i).artists;
            }

            /* Replace the new Cdrom */
            if(cdrom.tracks.at(i).position == track.position)
            {
                cdrom.tracks.replace(i, track);
            }

        }
        cdroms[cdromID] = cdrom;
    }

    if (found)
    {
        emit cdromChanged(cdroms.at(cdromID));
    }
    mutex.unlock();
}

void CdromManager::dbusMessageRemove(QString message)
{
    bool found = false;
    EMSCdrom cdrom;
    mutex.lock();
    for (int i=0; i<cdroms.size(); i++)
    {
        if (cdroms.at(i).device == message)
        {
            cdrom = cdroms.at(i);
            cdroms.removeAt(i);
            found = true;
            break;
        }
    }
    mutex.unlock();

    if (!found)
    {
        /* Ejected CDROM is not found */
        return;
    }

    qDebug() << "CDROM ejected : " << cdrom.device;

    /* Remove played CDROM from the current playlist */
    EMSPlaylist playlist = Player::instance()->getCurentPlaylist();
    for (int i=0; i<playlist.tracks.size(); i++)
    {
        EMSTrack track = playlist.tracks.at(i);
        if (track.type == TRACK_TYPE_CDROM && track.filename == cdrom.device)
        {
            Player::instance()->removeTrack(track);
        }
    }

    emit cdromEjected(cdrom);
}

/* ---------------------------------------------------------
 *                  START/STOP CDROM MANAGER
 * --------------------------------------------------------- */

CdromManager* CdromManager::_instance = 0;

CdromManager::CdromManager(QObject *parent) : QObject(parent),
                                              bus(QDBusConnection::systemBus())
{
    cdio_init();

    qRegisterMetaType<EMSCdrom>("EMSCdrom");

    connect(this, SIGNAL(cdromTrackNeedUpdate(EMSTrack,QStringList)), MetadataManager::instance(), SLOT(update(EMSTrack,QStringList)), Qt::DirectConnection);
    connect(MetadataManager::instance(), SIGNAL(updated(EMSTrack,bool)), this, SLOT(cdromTrackUpdated(EMSTrack,bool)));
}

CdromManager::~CdromManager()
{
#ifdef EMS_CDROM_RIPPER
    delete m_cdromRipper;
#endif
}

bool CdromManager::startMonitor()
{
    if (!bus.isConnected())
    {
        qCritical() << "Could not connect to session bus ! No CDROM management.";
        return false;
    }
    else
    {
        bus.connect(QString(), QString(), INTERFACE , SIGNAL_NAME_INSERT, this, SLOT(dbusMessageInsert(QString)));
        bus.connect(QString(), QString(), INTERFACE , SIGNAL_NAME_REMOVE, this, SLOT(dbusMessageRemove(QString)));
    }

    /* In case of CDROM already present, trigger actions using udevadm
     * Note: EMS must be launched with root rights or be able to trigger action using udev.
     */
    QProcess cmd;
    cmd.execute(QString("/bin/udevadm"), QString("trigger --action=change --sysname-match=sr[0-9]").split(' '));

    return true;
}

void CdromManager::stopMonitor()
{
    if (bus.isConnected())
    {
        bus.disconnect(QString(), QString(), INTERFACE , SIGNAL_NAME_INSERT, this, SLOT(dbusMessageInsert(QString)));
        bus.disconnect(QString(), QString(), INTERFACE , SIGNAL_NAME_REMOVE, this, SLOT(dbusMessageRemove(QString)));
    }
}

void CdromManager::startRip()
{
#ifdef EMS_CDROM_RIPPER

    /* Get first available CDROM */
    QVector<EMSCdrom> cdroms;
    getAvailableCdroms(&cdroms);

    /* Start the thread */
    if ((cdroms.size() > 0) && (!isRipInProgress()))
    {
        EMSCdrom cdrom = cdroms.at(0);
        m_cdromRipper = new CdromRipper(this);

        connect(m_cdromRipper, &CdromRipper::resultReady, this, &CdromManager::handleCdromRipperResults);
        connect(m_cdromRipper, &CdromRipper::finished, m_cdromRipper, &QObject::deleteLater);
        connect(m_cdromRipper, &CdromRipper::ripProgressChanged, this, &CdromManager::ripProgress);

        m_cdromRipper->setCdrom(cdrom);
        m_cdromRipper->setAudioFormat(m_ripAudioFormat);
        m_cdromRipper->start();
    }

#endif
}

void CdromManager::ripProgress(EMSRipProgress ripProgress)
{
    emit ripProgressChanged(ripProgress);
}

void CdromManager::handleCdromRipperResults(const QString &result )
{
#ifdef EMS_CDROM_RIPPER

    if (m_cdromRipper)
    {
        qDebug() << "CdromManager handle cdrom ripper results: " << result;
        delete m_cdromRipper;
        m_cdromRipper = Q_NULLPTR;
    }
#endif
}
<|endoftext|>


<commit_before>/*M///////////////////////////////////////////////////////////////////////////////////////
//
//  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
//
//  By downloading, copying, installing or using the software you agree to this license.
//  If you do not agree to this license, do not download, install,
//  copy or use the software.
//
//
//                           License Agreement
//                For Open Source Computer Vision Library
//
// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
// Copyright (C) 2009-2011, Willow Garage Inc., all rights reserved.
// Third party copyrights are property of their respective owners.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
//   * Redistribution's of source code must retain the above copyright notice,
//     this list of conditions and the following disclaimer.
//
//   * Redistribution's in binary form must reproduce the above copyright notice,
//     this list of conditions and the following disclaimer in the documentation
//     and/or other materials provided with the distribution.
//
//   * The name of the copyright holders may not be used to endorse or promote products
//     derived from this software without specific prior written permission.
//
// This software is provided by the copyright holders and contributors "as is" and
// any express or implied warranties, including, but not limited to, the implied
// warranties of merchantability and fitness for a particular purpose are disclaimed.
// In no event shall the Intel Corporation or contributors be liable for any direct,
// indirect, incidental, special, exemplary, or consequential damages
// (including, but not limited to, procurement of substitute goods or services;
// loss of use, data, or profits; or business interruption) however caused
// and on any theory of liability, whether in contract, strict liability,
// or tort (including negligence or otherwise) arising in any way out of
// the use of this software, even if advised of the possibility of such damage.
//
//M*/

#include "precomp.hpp"
#include "opencv2/videostab/stabilizer.hpp"

using namespace std;

namespace cv
{
namespace videostab
{

StabilizerBase::StabilizerBase()
{
    setLog(new NullLog());
    setFrameSource(new NullFrameSource());
    setMotionEstimator(new PyrLkRobustMotionEstimator());
    setDeblurer(new NullDeblurer());
    setInpainter(new NullInpainter());
    setRadius(15);
    setTrimRatio(0);
    setCorrectionForInclusion(false);
    setBorderMode(BORDER_REPLICATE);
}

void StabilizerBase::setUp(int cacheSize, const Mat &frame)
{
    InpainterBase *_inpainter = static_cast<InpainterBase*>(inpainter_);
    doInpainting_ = dynamic_cast<NullInpainter*>(_inpainter) == 0;
    if (doInpainting_)
    {
        inpainter_->setRadius(radius_);
        inpainter_->setFrames(frames_);
        inpainter_->setMotions(motions_);
        inpainter_->setStabilizedFrames(stabilizedFrames_);
        inpainter_->setStabilizationMotions(stabilizationMotions_);
        inpainter_->update();
    }

    DeblurerBase *deblurer = static_cast<DeblurerBase*>(deblurer_);
    doDeblurring_ = dynamic_cast<NullDeblurer*>(deblurer) == 0;
    if (doDeblurring_)
    {
        blurrinessRates_.resize(cacheSize);
        float blurriness = calcBlurriness(frame);
        for (int i  = -radius_; i <= 0; ++i)
            at(i, blurrinessRates_) = blurriness;
        deblurer_->setRadius(radius_);
        deblurer_->setFrames(frames_);
        deblurer_->setMotions(motions_);
        deblurer_->setBlurrinessRates(blurrinessRates_);
        deblurer_->update();
    }

    log_->print("processing frames");
}

Mat StabilizerBase::nextStabilizedFrame()
{
    if (curStabilizedPos_ == curPos_ && curStabilizedPos_ != -1)
        return Mat(); // we've processed all frames already

    bool processed;
    do processed = doOneIteration();
    while (processed && curStabilizedPos_ == -1);

    if (curStabilizedPos_ == -1)
        return Mat(); // frame source is empty

    const Mat &stabilizedFrame = at(curStabilizedPos_, stabilizedFrames_);
    int dx = static_cast<int>(floor(trimRatio_ * stabilizedFrame.cols));
    int dy = static_cast<int>(floor(trimRatio_ * stabilizedFrame.rows));
    return stabilizedFrame(Rect(dx, dy, stabilizedFrame.cols - 2*dx, stabilizedFrame.rows - 2*dy));
}

bool StabilizerBase::doOneIteration()
{
    Mat frame = frameSource_->nextFrame();
    if (!frame.empty())
    {
        curPos_++;

        if (curPos_ > 0)
        {
            at(curPos_, frames_) = frame;

            if (doDeblurring_)
                at(curPos_, blurrinessRates_) = calcBlurriness(frame);

            estimateMotion();

            if (curPos_ >= radius_)
            {
                curStabilizedPos_ = curPos_ - radius_;
                stabilizeFrame();
            }
        }
        else
            setUp(frame);

        log_->print(".");
        return true;
    }

    if (curStabilizedPos_ < curPos_)
    {
        curStabilizedPos_++;
        at(curStabilizedPos_ + radius_, frames_) = at(curPos_, frames_);
        at(curStabilizedPos_ + radius_ - 1, motions_) = at(curPos_ - 1, motions_);
        stabilizeFrame();

        log_->print(".");
        return true;
    }

    return false;
}

void StabilizerBase::stabilizeFrame(const Mat &stabilizationMotion)
{
    Mat stabilizationMotion_;
    if (doCorrectionForInclusion_)
        stabilizationMotion_ = ensureInclusionConstraint(stabilizationMotion, frameSize_, trimRatio_);
    else
        stabilizationMotion_ = stabilizationMotion.clone();

    at(curStabilizedPos_, stabilizationMotions_) = stabilizationMotion_;

    if (doDeblurring_)
    {
        at(curStabilizedPos_, frames_).copyTo(preProcessedFrame_);
        deblurer_->deblur(curStabilizedPos_, preProcessedFrame_);
    }
    else
        preProcessedFrame_ = at(curStabilizedPos_, frames_);

    // apply stabilization transformation
    warpAffine(
            preProcessedFrame_, at(curStabilizedPos_, stabilizedFrames_),
            stabilizationMotion_(Rect(0,0,3,2)), frameSize_, INTER_LINEAR, borderMode_);

    if (doInpainting_)
    {
        warpAffine(
                frameMask_, at(curStabilizedPos_, stabilizedMasks_),
                stabilizationMotion_(Rect(0,0,3,2)), frameSize_, INTER_NEAREST);

        erode(at(curStabilizedPos_, stabilizedMasks_), at(curStabilizedPos_, stabilizedMasks_),
              Mat());

        at(curStabilizedPos_, stabilizedMasks_).copyTo(inpaintingMask_);

        inpainter_->inpaint(
            curStabilizedPos_, at(curStabilizedPos_, stabilizedFrames_), inpaintingMask_);
    }
}

OnePassStabilizer::OnePassStabilizer()
{
    setMotionFilter(new GaussianMotionFilter());
    resetImpl();
}

void OnePassStabilizer::resetImpl()
{
    curPos_ = -1;
    curStabilizedPos_ = -1;
    frames_.clear();
    motions_.clear();
    stabilizedFrames_.clear();
    stabilizationMotions_.clear();
    doDeblurring_ = false;
    doInpainting_ = false;
}

void OnePassStabilizer::setUp(Mat &firstFrame)
{
    frameSize_ = firstFrame.size();
    frameMask_.create(frameSize_, CV_8U);
    frameMask_.setTo(255);

    int cacheSize = 2*radius_ + 1;

    frames_.resize(cacheSize);
    stabilizedFrames_.resize(cacheSize);
    stabilizedMasks_.resize(cacheSize);
    motions_.resize(cacheSize);
    stabilizationMotions_.resize(cacheSize);

    for (int i = -radius_; i < 0; ++i)
    {
        at(i, motions_) = Mat::eye(3, 3, CV_32F);
        at(i, frames_) = firstFrame;
    }

    at(0, frames_) = firstFrame;

    motionFilter_->setRadius(radius_);
    motionFilter_->update();

    StabilizerBase::setUp(cacheSize, firstFrame);
}

void OnePassStabilizer::estimateMotion()
{
    at(curPos_ - 1, motions_) = motionEstimator_->estimate(
            at(curPos_ - 1, frames_), at(curPos_, frames_));
}

void OnePassStabilizer::stabilizeFrame()
{
    Mat stabilizationMotion = motionFilter_->stabilize(curStabilizedPos_, &motions_[0], (int)motions_.size());
    StabilizerBase::stabilizeFrame(stabilizationMotion);
}

TwoPassStabilizer::TwoPassStabilizer()
{
    setMotionStabilizer(new GaussianMotionFilter());
    setEstimateTrimRatio(false);
    resetImpl();
}

Mat TwoPassStabilizer::nextFrame()
{
    runPrePassIfNecessary();
    return StabilizerBase::nextStabilizedFrame();
}

vector<Mat> TwoPassStabilizer::motions() const
{
    if (frameCount_ == 0)
        return vector<Mat>();
    vector<Mat> res(frameCount_ - 1);
    copy(motions_.begin(), motions_.begin() + frameCount_ - 1, res.begin());
    return res;
}

void TwoPassStabilizer::resetImpl()
{
    isPrePassDone_ = false;
    frameCount_ = 0;
    curPos_ = -1;
    curStabilizedPos_ = -1;
    frames_.clear();
    motions_.clear();
    stabilizedFrames_.clear();
    stabilizationMotions_.clear();
    doDeblurring_ = false;
    doInpainting_ = false;
}

void TwoPassStabilizer::runPrePassIfNecessary()
{
    if (!isPrePassDone_)
    {
        log_->print("first pass: estimating motions");

        Mat prevFrame, frame;

        while (!(frame = frameSource_->nextFrame()).empty())
        {
            if (frameCount_ > 0)
                motions_.push_back(motionEstimator_->estimate(prevFrame, frame));
            else
            {
                frameSize_ = frame.size();
                frameMask_.create(frameSize_, CV_8U);
                frameMask_.setTo(255);
            }

            prevFrame = frame;
            frameCount_++;

            log_->print(".");
        }

        for (int i = 0; i < radius_; ++i)
            motions_.push_back(Mat::eye(3, 3, CV_32F));
        log_->print("\n");

        IMotionStabilizer *_motionStabilizer = static_cast<IMotionStabilizer*>(motionStabilizer_);
        MotionFilterBase *motionFilterBase = dynamic_cast<MotionFilterBase*>(_motionStabilizer);
        if (motionFilterBase)
        {
            motionFilterBase->setRadius(radius_);
            motionFilterBase->update();
        }

        stabilizationMotions_.resize(frameCount_);
        motionStabilizer_->stabilize(&motions_[0], frameCount_, &stabilizationMotions_[0]);

        if (mustEstTrimRatio_)
        {
            trimRatio_ = 0;
            for (int i = 0; i < frameCount_; ++i)
            {
                Mat S = stabilizationMotions_[i];
                trimRatio_ = std::max(trimRatio_, estimateOptimalTrimRatio(S, frameSize_));
            }
            log_->print("estimated trim ratio: %f\n", static_cast<double>(trimRatio_));
        }

        isPrePassDone_ = true;
        frameSource_->reset();
    }
}

void TwoPassStabilizer::setUp(Mat &firstFrame)
{
    int cacheSize = 2*radius_ + 1;

    frames_.resize(cacheSize);
    stabilizedFrames_.resize(cacheSize);
    stabilizedMasks_.resize(cacheSize);

    for (int i = -radius_; i <= 0; ++i)
        at(i, frames_) = firstFrame;

    StabilizerBase::setUp(cacheSize, firstFrame);
}

void TwoPassStabilizer::stabilizeFrame()
{
    StabilizerBase::stabilizeFrame(stabilizationMotions_[curStabilizedPos_]);
}

} // namespace videostab
} // namespace cv
<commit_msg>Suppress clang build warning<commit_after>/*M///////////////////////////////////////////////////////////////////////////////////////
//
//  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
//
//  By downloading, copying, installing or using the software you agree to this license.
//  If you do not agree to this license, do not download, install,
//  copy or use the software.
//
//
//                           License Agreement
//                For Open Source Computer Vision Library
//
// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
// Copyright (C) 2009-2011, Willow Garage Inc., all rights reserved.
// Third party copyrights are property of their respective owners.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
//   * Redistribution's of source code must retain the above copyright notice,
//     this list of conditions and the following disclaimer.
//
//   * Redistribution's in binary form must reproduce the above copyright notice,
//     this list of conditions and the following disclaimer in the documentation
//     and/or other materials provided with the distribution.
//
//   * The name of the copyright holders may not be used to endorse or promote products
//     derived from this software without specific prior written permission.
//
// This software is provided by the copyright holders and contributors "as is" and
// any express or implied warranties, including, but not limited to, the implied
// warranties of merchantability and fitness for a particular purpose are disclaimed.
// In no event shall the Intel Corporation or contributors be liable for any direct,
// indirect, incidental, special, exemplary, or consequential damages
// (including, but not limited to, procurement of substitute goods or services;
// loss of use, data, or profits; or business interruption) however caused
// and on any theory of liability, whether in contract, strict liability,
// or tort (including negligence or otherwise) arising in any way out of
// the use of this software, even if advised of the possibility of such damage.
//
//M*/

#if defined __clang__
#  pragma GCC diagnostic ignored "-Wdelete-non-virtual-dtor"
#endif

#include "precomp.hpp"
#include "opencv2/videostab/stabilizer.hpp"

using namespace std;

namespace cv
{
namespace videostab
{

StabilizerBase::StabilizerBase()
{
    setLog(new NullLog());
    setFrameSource(new NullFrameSource());
    setMotionEstimator(new PyrLkRobustMotionEstimator());
    setDeblurer(new NullDeblurer());
    setInpainter(new NullInpainter());
    setRadius(15);
    setTrimRatio(0);
    setCorrectionForInclusion(false);
    setBorderMode(BORDER_REPLICATE);
}

void StabilizerBase::setUp(int cacheSize, const Mat &frame)
{
    InpainterBase *_inpainter = static_cast<InpainterBase*>(inpainter_);
    doInpainting_ = dynamic_cast<NullInpainter*>(_inpainter) == 0;
    if (doInpainting_)
    {
        inpainter_->setRadius(radius_);
        inpainter_->setFrames(frames_);
        inpainter_->setMotions(motions_);
        inpainter_->setStabilizedFrames(stabilizedFrames_);
        inpainter_->setStabilizationMotions(stabilizationMotions_);
        inpainter_->update();
    }

    DeblurerBase *deblurer = static_cast<DeblurerBase*>(deblurer_);
    doDeblurring_ = dynamic_cast<NullDeblurer*>(deblurer) == 0;
    if (doDeblurring_)
    {
        blurrinessRates_.resize(cacheSize);
        float blurriness = calcBlurriness(frame);
        for (int i  = -radius_; i <= 0; ++i)
            at(i, blurrinessRates_) = blurriness;
        deblurer_->setRadius(radius_);
        deblurer_->setFrames(frames_);
        deblurer_->setMotions(motions_);
        deblurer_->setBlurrinessRates(blurrinessRates_);
        deblurer_->update();
    }

    log_->print("processing frames");
}

Mat StabilizerBase::nextStabilizedFrame()
{
    if (curStabilizedPos_ == curPos_ && curStabilizedPos_ != -1)
        return Mat(); // we've processed all frames already

    bool processed;
    do processed = doOneIteration();
    while (processed && curStabilizedPos_ == -1);

    if (curStabilizedPos_ == -1)
        return Mat(); // frame source is empty

    const Mat &stabilizedFrame = at(curStabilizedPos_, stabilizedFrames_);
    int dx = static_cast<int>(floor(trimRatio_ * stabilizedFrame.cols));
    int dy = static_cast<int>(floor(trimRatio_ * stabilizedFrame.rows));
    return stabilizedFrame(Rect(dx, dy, stabilizedFrame.cols - 2*dx, stabilizedFrame.rows - 2*dy));
}

bool StabilizerBase::doOneIteration()
{
    Mat frame = frameSource_->nextFrame();
    if (!frame.empty())
    {
        curPos_++;

        if (curPos_ > 0)
        {
            at(curPos_, frames_) = frame;

            if (doDeblurring_)
                at(curPos_, blurrinessRates_) = calcBlurriness(frame);

            estimateMotion();

            if (curPos_ >= radius_)
            {
                curStabilizedPos_ = curPos_ - radius_;
                stabilizeFrame();
            }
        }
        else
            setUp(frame);

        log_->print(".");
        return true;
    }

    if (curStabilizedPos_ < curPos_)
    {
        curStabilizedPos_++;
        at(curStabilizedPos_ + radius_, frames_) = at(curPos_, frames_);
        at(curStabilizedPos_ + radius_ - 1, motions_) = at(curPos_ - 1, motions_);
        stabilizeFrame();

        log_->print(".");
        return true;
    }

    return false;
}

void StabilizerBase::stabilizeFrame(const Mat &stabilizationMotion)
{
    Mat stabilizationMotion_;
    if (doCorrectionForInclusion_)
        stabilizationMotion_ = ensureInclusionConstraint(stabilizationMotion, frameSize_, trimRatio_);
    else
        stabilizationMotion_ = stabilizationMotion.clone();

    at(curStabilizedPos_, stabilizationMotions_) = stabilizationMotion_;

    if (doDeblurring_)
    {
        at(curStabilizedPos_, frames_).copyTo(preProcessedFrame_);
        deblurer_->deblur(curStabilizedPos_, preProcessedFrame_);
    }
    else
        preProcessedFrame_ = at(curStabilizedPos_, frames_);

    // apply stabilization transformation
    warpAffine(
            preProcessedFrame_, at(curStabilizedPos_, stabilizedFrames_),
            stabilizationMotion_(Rect(0,0,3,2)), frameSize_, INTER_LINEAR, borderMode_);

    if (doInpainting_)
    {
        warpAffine(
                frameMask_, at(curStabilizedPos_, stabilizedMasks_),
                stabilizationMotion_(Rect(0,0,3,2)), frameSize_, INTER_NEAREST);

        erode(at(curStabilizedPos_, stabilizedMasks_), at(curStabilizedPos_, stabilizedMasks_),
              Mat());

        at(curStabilizedPos_, stabilizedMasks_).copyTo(inpaintingMask_);

        inpainter_->inpaint(
            curStabilizedPos_, at(curStabilizedPos_, stabilizedFrames_), inpaintingMask_);
    }
}

OnePassStabilizer::OnePassStabilizer()
{
    setMotionFilter(new GaussianMotionFilter());
    resetImpl();
}

void OnePassStabilizer::resetImpl()
{
    curPos_ = -1;
    curStabilizedPos_ = -1;
    frames_.clear();
    motions_.clear();
    stabilizedFrames_.clear();
    stabilizationMotions_.clear();
    doDeblurring_ = false;
    doInpainting_ = false;
}

void OnePassStabilizer::setUp(Mat &firstFrame)
{
    frameSize_ = firstFrame.size();
    frameMask_.create(frameSize_, CV_8U);
    frameMask_.setTo(255);

    int cacheSize = 2*radius_ + 1;

    frames_.resize(cacheSize);
    stabilizedFrames_.resize(cacheSize);
    stabilizedMasks_.resize(cacheSize);
    motions_.resize(cacheSize);
    stabilizationMotions_.resize(cacheSize);

    for (int i = -radius_; i < 0; ++i)
    {
        at(i, motions_) = Mat::eye(3, 3, CV_32F);
        at(i, frames_) = firstFrame;
    }

    at(0, frames_) = firstFrame;

    motionFilter_->setRadius(radius_);
    motionFilter_->update();

    StabilizerBase::setUp(cacheSize, firstFrame);
}

void OnePassStabilizer::estimateMotion()
{
    at(curPos_ - 1, motions_) = motionEstimator_->estimate(
            at(curPos_ - 1, frames_), at(curPos_, frames_));
}

void OnePassStabilizer::stabilizeFrame()
{
    Mat stabilizationMotion = motionFilter_->stabilize(curStabilizedPos_, &motions_[0], (int)motions_.size());
    StabilizerBase::stabilizeFrame(stabilizationMotion);
}

TwoPassStabilizer::TwoPassStabilizer()
{
    setMotionStabilizer(new GaussianMotionFilter());
    setEstimateTrimRatio(false);
    resetImpl();
}

Mat TwoPassStabilizer::nextFrame()
{
    runPrePassIfNecessary();
    return StabilizerBase::nextStabilizedFrame();
}

vector<Mat> TwoPassStabilizer::motions() const
{
    if (frameCount_ == 0)
        return vector<Mat>();
    vector<Mat> res(frameCount_ - 1);
    copy(motions_.begin(), motions_.begin() + frameCount_ - 1, res.begin());
    return res;
}

void TwoPassStabilizer::resetImpl()
{
    isPrePassDone_ = false;
    frameCount_ = 0;
    curPos_ = -1;
    curStabilizedPos_ = -1;
    frames_.clear();
    motions_.clear();
    stabilizedFrames_.clear();
    stabilizationMotions_.clear();
    doDeblurring_ = false;
    doInpainting_ = false;
}

void TwoPassStabilizer::runPrePassIfNecessary()
{
    if (!isPrePassDone_)
    {
        log_->print("first pass: estimating motions");

        Mat prevFrame, frame;

        while (!(frame = frameSource_->nextFrame()).empty())
        {
            if (frameCount_ > 0)
                motions_.push_back(motionEstimator_->estimate(prevFrame, frame));
            else
            {
                frameSize_ = frame.size();
                frameMask_.create(frameSize_, CV_8U);
                frameMask_.setTo(255);
            }

            prevFrame = frame;
            frameCount_++;

            log_->print(".");
        }

        for (int i = 0; i < radius_; ++i)
            motions_.push_back(Mat::eye(3, 3, CV_32F));
        log_->print("\n");

        IMotionStabilizer *_motionStabilizer = static_cast<IMotionStabilizer*>(motionStabilizer_);
        MotionFilterBase *motionFilterBase = dynamic_cast<MotionFilterBase*>(_motionStabilizer);
        if (motionFilterBase)
        {
            motionFilterBase->setRadius(radius_);
            motionFilterBase->update();
        }

        stabilizationMotions_.resize(frameCount_);
        motionStabilizer_->stabilize(&motions_[0], frameCount_, &stabilizationMotions_[0]);

        if (mustEstTrimRatio_)
        {
            trimRatio_ = 0;
            for (int i = 0; i < frameCount_; ++i)
            {
                Mat S = stabilizationMotions_[i];
                trimRatio_ = std::max(trimRatio_, estimateOptimalTrimRatio(S, frameSize_));
            }
            log_->print("estimated trim ratio: %f\n", static_cast<double>(trimRatio_));
        }

        isPrePassDone_ = true;
        frameSource_->reset();
    }
}

void TwoPassStabilizer::setUp(Mat &firstFrame)
{
    int cacheSize = 2*radius_ + 1;

    frames_.resize(cacheSize);
    stabilizedFrames_.resize(cacheSize);
    stabilizedMasks_.resize(cacheSize);

    for (int i = -radius_; i <= 0; ++i)
        at(i, frames_) = firstFrame;

    StabilizerBase::setUp(cacheSize, firstFrame);
}

void TwoPassStabilizer::stabilizeFrame()
{
    StabilizerBase::stabilizeFrame(stabilizationMotions_[curStabilizedPos_]);
}

} // namespace videostab
} // namespace cv
<|endoftext|>


<commit_before>/*=========================================================================
 *
 *  Copyright RTK Consortium
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0.txt
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *
 *=========================================================================*/

#include "rtkCudaWarpBackProjectionImageFilter.h"
#include "rtkCudaUtilities.hcu"
#include "rtkCudaWarpBackProjectionImageFilter.hcu"

#include <itkImageRegionIterator.h>
#include <itkImageRegionConstIterator.h>
#include <itkMacro.h>
#include <itkImageAlgorithm.h>

namespace rtk
{

CudaWarpBackProjectionImageFilter
::CudaWarpBackProjectionImageFilter()
{
  this->SetNumberOfRequiredInputs(1);
}

void
CudaWarpBackProjectionImageFilter
::SetInputVolume(const ImageType* Volume)
{
  this->SetInput(0, const_cast<ImageType*>(Volume));
}

void
CudaWarpBackProjectionImageFilter
::SetInputProjectionStack(const ImageType* ProjectionStack)
{
  this->SetInput(1, const_cast<ImageType*>(ProjectionStack));
}

void
CudaWarpBackProjectionImageFilter
::SetDisplacementField(const DVFType* DVF)
{
  this->SetInput("DisplacementField", const_cast<DVFType*>(DVF));
}

CudaWarpBackProjectionImageFilter::ImageType::Pointer
CudaWarpBackProjectionImageFilter
::GetInputVolume()
{
  return static_cast< ImageType * >
          ( this->itk::ProcessObject::GetInput(0) );
}

CudaWarpBackProjectionImageFilter::ImageType::Pointer
CudaWarpBackProjectionImageFilter
::GetInputProjectionStack()
{
  return static_cast< ImageType * >
          ( this->itk::ProcessObject::GetInput(1) );
}

CudaWarpBackProjectionImageFilter::DVFType::Pointer
CudaWarpBackProjectionImageFilter
::GetDisplacementField()
{
  return static_cast< DVFType * >
          ( this->itk::ProcessObject::GetInput("DisplacementField") );
}

void
CudaWarpBackProjectionImageFilter
::GenerateInputRequestedRegion()
{
  Superclass::GenerateInputRequestedRegion();

  // Since we do not know where the DVF points, the
  // whole input projection is required.
  this->GetInputProjectionStack()->SetRequestedRegionToLargestPossibleRegion();

  // To compute the DVF's requested region, we use the same method
  // as in itk::WarpImageFilter, except if the ITK version is too old to
  // contain the required methods
#if ITK_VERSION_MAJOR < 4 || (ITK_VERSION_MAJOR == 4 && ITK_VERSION_MINOR < 8)
  this->GetDisplacementField()->SetRequestedRegionToLargestPossibleRegion();
#else
  // If the output and the deformation field have the same
  // information, just propagate up the output requested region for the
  // deformation field. Otherwise, it is non-trivial to determine
  // the smallest region of the deformation field that fully
  // contains the physical space covered by the output's requested
  // region, se we do the easy thing and request the largest possible region
  DVFType::Pointer    fieldPtr = this->GetDisplacementField();
  ImageType::Pointer  outputPtr = this->GetOutput();
  if ( fieldPtr.IsNotNull() )
    {
    // tolerance for origin and spacing depends on the size of pixel
    // tolerance for direction is a fraction of the unit cube.
    const itk::SpacePrecisionType coordinateTol = this->GetCoordinateTolerance() * outputPtr->GetSpacing()[0]; // use first dimension spacing

    bool DefFieldSameInformation =
       (outputPtr->GetOrigin().GetVnlVector().is_equal(fieldPtr->GetOrigin().GetVnlVector(), coordinateTol))
    && (outputPtr->GetSpacing().GetVnlVector().is_equal(fieldPtr->GetSpacing().GetVnlVector(), coordinateTol))
    && (outputPtr->GetDirection().GetVnlMatrix().as_ref().is_equal(fieldPtr->GetDirection().GetVnlMatrix(), this->GetDirectionTolerance()));

    if (DefFieldSameInformation)
      {
      fieldPtr->SetRequestedRegion( outputPtr->GetRequestedRegion() );
      }
    else
      {
      typedef typename DVFType::RegionType DisplacementRegionType;

      DisplacementRegionType fieldRequestedRegion = itk::ImageAlgorithm::EnlargeRegionOverBox(outputPtr->GetRequestedRegion(),
                                                                                outputPtr.GetPointer(),
                                                                                fieldPtr.GetPointer());
      fieldPtr->SetRequestedRegion( fieldRequestedRegion );
      }
    if ( !fieldPtr->VerifyRequestedRegion() )
      {
      fieldPtr->SetRequestedRegion( fieldPtr->GetLargestPossibleRegion() );
      }
    }
#endif
}

void
CudaWarpBackProjectionImageFilter
::GPUGenerateData()
{
  const unsigned int Dimension = ImageType::ImageDimension;
  const unsigned int nProj = this->GetInputProjectionStack()->GetLargestPossibleRegion().GetSize(Dimension-1);
  const unsigned int iFirstProj = this->GetInputProjectionStack()->GetLargestPossibleRegion().GetIndex(Dimension-1);

  // Ramp factor is the correction for ramp filter which did not account for the
  // divergence of the beam
//  const GeometryPointer geometry = dynamic_cast<GeometryType *>(this->GetGeometry().GetPointer() );

  // Rotation center (assumed to be at 0 yet)
  ImageType::PointType rotCenterPoint;
  rotCenterPoint.Fill(0.0);
  itk::ContinuousIndex<double, Dimension> rotCenterIndex;
  this->GetInputVolume()->TransformPhysicalPointToContinuousIndex(rotCenterPoint, rotCenterIndex);

  // Include non-zero index in matrix
  itk::Matrix<double, 4, 4> matrixIdxVol;
  matrixIdxVol.SetIdentity();
  for(unsigned int i=0; i<3; i++)
    {
    matrixIdxVol[i][3] = this->GetOutput()->GetRequestedRegion().GetIndex()[i];
    rotCenterIndex[i] -= this->GetOutput()->GetRequestedRegion().GetIndex()[i];
    }

  // Cuda convenient format for dimensions
  int projectionSize[2];
  projectionSize[0] = this->GetInputProjectionStack()->GetBufferedRegion().GetSize()[0];
  projectionSize[1] = this->GetInputProjectionStack()->GetBufferedRegion().GetSize()[1];

  int volumeSize[3];
  volumeSize[0] = this->GetOutput()->GetBufferedRegion().GetSize()[0];
  volumeSize[1] = this->GetOutput()->GetBufferedRegion().GetSize()[1];
  volumeSize[2] = this->GetOutput()->GetBufferedRegion().GetSize()[2];

  int inputDVFSize[3];
  inputDVFSize[0] = this->GetDisplacementField()->GetBufferedRegion().GetSize()[0];
  inputDVFSize[1] = this->GetDisplacementField()->GetBufferedRegion().GetSize()[1];
  inputDVFSize[2] = this->GetDisplacementField()->GetBufferedRegion().GetSize()[2];

  // Split the DVF into three images (one per component)
  ImageType::Pointer xCompDVF = ImageType::New();
  ImageType::Pointer yCompDVF = ImageType::New();
  ImageType::Pointer zCompDVF = ImageType::New();
  ImageType::RegionType buffered = this->GetDisplacementField()->GetBufferedRegion();
  xCompDVF->SetRegions(buffered);
  yCompDVF->SetRegions(buffered);
  zCompDVF->SetRegions(buffered);
  xCompDVF->Allocate();
  yCompDVF->Allocate();
  zCompDVF->Allocate();
  itk::ImageRegionIterator<ImageType>     itxComp(xCompDVF, buffered);
  itk::ImageRegionIterator<ImageType>     ityComp(yCompDVF, buffered);
  itk::ImageRegionIterator<ImageType>     itzComp(zCompDVF, buffered);
  itk::ImageRegionConstIterator<DVFType>  itDVF(this->GetDisplacementField(), buffered);
  while(!itDVF.IsAtEnd())
    {
      itxComp.Set(itDVF.Get()[0]);
      ityComp.Set(itDVF.Get()[1]);
      itzComp.Set(itDVF.Get()[2]);
      ++itxComp;
      ++ityComp;
      ++itzComp;
      ++itDVF;
    }

  // Transform matrices that we will need during the warping process
  itk::Matrix<double, 4, 4> indexInputToIndexDVFMatrix;
  itk::Matrix<double, 4, 4> PPInputToIndexInputMatrix;
  itk::Matrix<double, 4, 4> indexInputToPPInputMatrix;

  indexInputToIndexDVFMatrix = rtk::GetPhysicalPointToIndexMatrix( this->GetDisplacementField().GetPointer() ).GetVnlMatrix()
                              * rtk::GetIndexToPhysicalPointMatrix( this->GetInputVolume().GetPointer() ).GetVnlMatrix()
                              * matrixIdxVol.GetVnlMatrix();

  PPInputToIndexInputMatrix = rtk::GetPhysicalPointToIndexMatrix( this->GetInputVolume().GetPointer() ).GetVnlMatrix();

  indexInputToPPInputMatrix = rtk::GetIndexToPhysicalPointMatrix( this->GetInputVolume().GetPointer() ).GetVnlMatrix()
                              * matrixIdxVol.GetVnlMatrix();

  // Convert the matrices to arrays of floats (skipping the last line, as we don't care)
  float fIndexInputToIndexDVFMatrix[12];
  float fPPInputToIndexInputMatrix[12];
  float fIndexInputToPPInputMatrix[12];
  for (int j = 0; j < 12; j++)
    {
    fIndexInputToIndexDVFMatrix[j] = (float) indexInputToIndexDVFMatrix[j/4][j%4];
    fPPInputToIndexInputMatrix[j] = (float) PPInputToIndexInputMatrix[j/4][j%4];
    fIndexInputToPPInputMatrix[j] = (float) indexInputToPPInputMatrix[j/4][j%4];
    }

  // Load the required images onto the GPU (handled by the CudaDataManager)
  float *pin  = *(float**)( this->GetInput()->GetCudaDataManager()->GetGPUBufferPointer() );
  float *pout = *(float**)( this->GetOutput()->GetCudaDataManager()->GetGPUBufferPointer() );

  float *stackGPUPointer = *(float**)( this->GetInputProjectionStack()->GetCudaDataManager()->GetGPUBufferPointer() );
  ptrdiff_t projSize = this->GetInputProjectionStack()->GetBufferedRegion().GetSize()[0] *
                       this->GetInputProjectionStack()->GetBufferedRegion().GetSize()[1];
  stackGPUPointer += projSize * (iFirstProj-this->GetInputProjectionStack()->GetBufferedRegion().GetIndex()[2]);

  float *pinxDVF = *(float**)( xCompDVF->GetCudaDataManager()->GetGPUBufferPointer() );
  float *pinyDVF = *(float**)( yCompDVF->GetCudaDataManager()->GetGPUBufferPointer() );
  float *pinzDVF = *(float**)( zCompDVF->GetCudaDataManager()->GetGPUBufferPointer() );

  // Go over each projection
  for(unsigned int iProj=iFirstProj; iProj<iFirstProj+nProj; iProj++, stackGPUPointer += projSize)
    {
    // Index to index matrix normalized to have a correct backprojection weight
    // (1 at the isocenter)
    ProjectionMatrixType matrix = GetIndexToIndexProjectionMatrix(iProj);

    // We correct the matrix for non zero indexes
    itk::Matrix<double, 3, 3> matrixIdxProj;
    matrixIdxProj.SetIdentity();
    for(unsigned int i=0; i<2; i++)
      //SR: 0.5 for 2D texture
      matrixIdxProj[i][2] = -1*(this->GetInputProjectionStack()->GetBufferedRegion().GetIndex()[i])+0.5;

    matrix = matrixIdxProj.GetVnlMatrix() * matrix.GetVnlMatrix() * matrixIdxVol.GetVnlMatrix();

    double perspFactor = matrix[Dimension-1][Dimension];
    for(unsigned int j=0; j<Dimension; j++)
      perspFactor += matrix[Dimension-1][j] * rotCenterIndex[j];
    matrix /= perspFactor;

    float fMatrix[12];
    for (int j = 0; j < 12; j++)
      fMatrix[j] = matrix[j/4][j%4];

    CUDA_warp_back_project(projectionSize,
                      volumeSize,
                      inputDVFSize,
                      fMatrix,
                      pin,
                      pout,
                      stackGPUPointer,
                      pinxDVF,
                      pinyDVF,
                      pinzDVF,
                      fIndexInputToIndexDVFMatrix,
                      fPPInputToIndexInputMatrix,
                      fIndexInputToPPInputMatrix
                      );
    pin = pout;
    }
}

} // end namespace rtk
<commit_msg>Removed useless typename<commit_after>/*=========================================================================
 *
 *  Copyright RTK Consortium
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0.txt
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *
 *=========================================================================*/

#include "rtkCudaWarpBackProjectionImageFilter.h"
#include "rtkCudaUtilities.hcu"
#include "rtkCudaWarpBackProjectionImageFilter.hcu"

#include <itkImageRegionIterator.h>
#include <itkImageRegionConstIterator.h>
#include <itkMacro.h>
#include <itkImageAlgorithm.h>

namespace rtk
{

CudaWarpBackProjectionImageFilter
::CudaWarpBackProjectionImageFilter()
{
  this->SetNumberOfRequiredInputs(1);
}

void
CudaWarpBackProjectionImageFilter
::SetInputVolume(const ImageType* Volume)
{
  this->SetInput(0, const_cast<ImageType*>(Volume));
}

void
CudaWarpBackProjectionImageFilter
::SetInputProjectionStack(const ImageType* ProjectionStack)
{
  this->SetInput(1, const_cast<ImageType*>(ProjectionStack));
}

void
CudaWarpBackProjectionImageFilter
::SetDisplacementField(const DVFType* DVF)
{
  this->SetInput("DisplacementField", const_cast<DVFType*>(DVF));
}

CudaWarpBackProjectionImageFilter::ImageType::Pointer
CudaWarpBackProjectionImageFilter
::GetInputVolume()
{
  return static_cast< ImageType * >
          ( this->itk::ProcessObject::GetInput(0) );
}

CudaWarpBackProjectionImageFilter::ImageType::Pointer
CudaWarpBackProjectionImageFilter
::GetInputProjectionStack()
{
  return static_cast< ImageType * >
          ( this->itk::ProcessObject::GetInput(1) );
}

CudaWarpBackProjectionImageFilter::DVFType::Pointer
CudaWarpBackProjectionImageFilter
::GetDisplacementField()
{
  return static_cast< DVFType * >
          ( this->itk::ProcessObject::GetInput("DisplacementField") );
}

void
CudaWarpBackProjectionImageFilter
::GenerateInputRequestedRegion()
{
  Superclass::GenerateInputRequestedRegion();

  // Since we do not know where the DVF points, the
  // whole input projection is required.
  this->GetInputProjectionStack()->SetRequestedRegionToLargestPossibleRegion();

  // To compute the DVF's requested region, we use the same method
  // as in itk::WarpImageFilter, except if the ITK version is too old to
  // contain the required methods
#if ITK_VERSION_MAJOR < 4 || (ITK_VERSION_MAJOR == 4 && ITK_VERSION_MINOR < 8)
  this->GetDisplacementField()->SetRequestedRegionToLargestPossibleRegion();
#else
  // If the output and the deformation field have the same
  // information, just propagate up the output requested region for the
  // deformation field. Otherwise, it is non-trivial to determine
  // the smallest region of the deformation field that fully
  // contains the physical space covered by the output's requested
  // region, se we do the easy thing and request the largest possible region
  DVFType::Pointer    fieldPtr = this->GetDisplacementField();
  ImageType::Pointer  outputPtr = this->GetOutput();
  if ( fieldPtr.IsNotNull() )
    {
    // tolerance for origin and spacing depends on the size of pixel
    // tolerance for direction is a fraction of the unit cube.
    const itk::SpacePrecisionType coordinateTol = this->GetCoordinateTolerance() * outputPtr->GetSpacing()[0]; // use first dimension spacing

    bool DefFieldSameInformation =
       (outputPtr->GetOrigin().GetVnlVector().is_equal(fieldPtr->GetOrigin().GetVnlVector(), coordinateTol))
    && (outputPtr->GetSpacing().GetVnlVector().is_equal(fieldPtr->GetSpacing().GetVnlVector(), coordinateTol))
    && (outputPtr->GetDirection().GetVnlMatrix().as_ref().is_equal(fieldPtr->GetDirection().GetVnlMatrix(), this->GetDirectionTolerance()));

    if (DefFieldSameInformation)
      {
      fieldPtr->SetRequestedRegion( outputPtr->GetRequestedRegion() );
      }
    else
      {
      typedef DVFType::RegionType DisplacementRegionType;

      DisplacementRegionType fieldRequestedRegion = itk::ImageAlgorithm::EnlargeRegionOverBox(outputPtr->GetRequestedRegion(),
                                                                                outputPtr.GetPointer(),
                                                                                fieldPtr.GetPointer());
      fieldPtr->SetRequestedRegion( fieldRequestedRegion );
      }
    if ( !fieldPtr->VerifyRequestedRegion() )
      {
      fieldPtr->SetRequestedRegion( fieldPtr->GetLargestPossibleRegion() );
      }
    }
#endif
}

void
CudaWarpBackProjectionImageFilter
::GPUGenerateData()
{
  const unsigned int Dimension = ImageType::ImageDimension;
  const unsigned int nProj = this->GetInputProjectionStack()->GetLargestPossibleRegion().GetSize(Dimension-1);
  const unsigned int iFirstProj = this->GetInputProjectionStack()->GetLargestPossibleRegion().GetIndex(Dimension-1);

  // Ramp factor is the correction for ramp filter which did not account for the
  // divergence of the beam
//  const GeometryPointer geometry = dynamic_cast<GeometryType *>(this->GetGeometry().GetPointer() );

  // Rotation center (assumed to be at 0 yet)
  ImageType::PointType rotCenterPoint;
  rotCenterPoint.Fill(0.0);
  itk::ContinuousIndex<double, Dimension> rotCenterIndex;
  this->GetInputVolume()->TransformPhysicalPointToContinuousIndex(rotCenterPoint, rotCenterIndex);

  // Include non-zero index in matrix
  itk::Matrix<double, 4, 4> matrixIdxVol;
  matrixIdxVol.SetIdentity();
  for(unsigned int i=0; i<3; i++)
    {
    matrixIdxVol[i][3] = this->GetOutput()->GetRequestedRegion().GetIndex()[i];
    rotCenterIndex[i] -= this->GetOutput()->GetRequestedRegion().GetIndex()[i];
    }

  // Cuda convenient format for dimensions
  int projectionSize[2];
  projectionSize[0] = this->GetInputProjectionStack()->GetBufferedRegion().GetSize()[0];
  projectionSize[1] = this->GetInputProjectionStack()->GetBufferedRegion().GetSize()[1];

  int volumeSize[3];
  volumeSize[0] = this->GetOutput()->GetBufferedRegion().GetSize()[0];
  volumeSize[1] = this->GetOutput()->GetBufferedRegion().GetSize()[1];
  volumeSize[2] = this->GetOutput()->GetBufferedRegion().GetSize()[2];

  int inputDVFSize[3];
  inputDVFSize[0] = this->GetDisplacementField()->GetBufferedRegion().GetSize()[0];
  inputDVFSize[1] = this->GetDisplacementField()->GetBufferedRegion().GetSize()[1];
  inputDVFSize[2] = this->GetDisplacementField()->GetBufferedRegion().GetSize()[2];

  // Split the DVF into three images (one per component)
  ImageType::Pointer xCompDVF = ImageType::New();
  ImageType::Pointer yCompDVF = ImageType::New();
  ImageType::Pointer zCompDVF = ImageType::New();
  ImageType::RegionType buffered = this->GetDisplacementField()->GetBufferedRegion();
  xCompDVF->SetRegions(buffered);
  yCompDVF->SetRegions(buffered);
  zCompDVF->SetRegions(buffered);
  xCompDVF->Allocate();
  yCompDVF->Allocate();
  zCompDVF->Allocate();
  itk::ImageRegionIterator<ImageType>     itxComp(xCompDVF, buffered);
  itk::ImageRegionIterator<ImageType>     ityComp(yCompDVF, buffered);
  itk::ImageRegionIterator<ImageType>     itzComp(zCompDVF, buffered);
  itk::ImageRegionConstIterator<DVFType>  itDVF(this->GetDisplacementField(), buffered);
  while(!itDVF.IsAtEnd())
    {
      itxComp.Set(itDVF.Get()[0]);
      ityComp.Set(itDVF.Get()[1]);
      itzComp.Set(itDVF.Get()[2]);
      ++itxComp;
      ++ityComp;
      ++itzComp;
      ++itDVF;
    }

  // Transform matrices that we will need during the warping process
  itk::Matrix<double, 4, 4> indexInputToIndexDVFMatrix;
  itk::Matrix<double, 4, 4> PPInputToIndexInputMatrix;
  itk::Matrix<double, 4, 4> indexInputToPPInputMatrix;

  indexInputToIndexDVFMatrix = rtk::GetPhysicalPointToIndexMatrix( this->GetDisplacementField().GetPointer() ).GetVnlMatrix()
                              * rtk::GetIndexToPhysicalPointMatrix( this->GetInputVolume().GetPointer() ).GetVnlMatrix()
                              * matrixIdxVol.GetVnlMatrix();

  PPInputToIndexInputMatrix = rtk::GetPhysicalPointToIndexMatrix( this->GetInputVolume().GetPointer() ).GetVnlMatrix();

  indexInputToPPInputMatrix = rtk::GetIndexToPhysicalPointMatrix( this->GetInputVolume().GetPointer() ).GetVnlMatrix()
                              * matrixIdxVol.GetVnlMatrix();

  // Convert the matrices to arrays of floats (skipping the last line, as we don't care)
  float fIndexInputToIndexDVFMatrix[12];
  float fPPInputToIndexInputMatrix[12];
  float fIndexInputToPPInputMatrix[12];
  for (int j = 0; j < 12; j++)
    {
    fIndexInputToIndexDVFMatrix[j] = (float) indexInputToIndexDVFMatrix[j/4][j%4];
    fPPInputToIndexInputMatrix[j] = (float) PPInputToIndexInputMatrix[j/4][j%4];
    fIndexInputToPPInputMatrix[j] = (float) indexInputToPPInputMatrix[j/4][j%4];
    }

  // Load the required images onto the GPU (handled by the CudaDataManager)
  float *pin  = *(float**)( this->GetInput()->GetCudaDataManager()->GetGPUBufferPointer() );
  float *pout = *(float**)( this->GetOutput()->GetCudaDataManager()->GetGPUBufferPointer() );

  float *stackGPUPointer = *(float**)( this->GetInputProjectionStack()->GetCudaDataManager()->GetGPUBufferPointer() );
  ptrdiff_t projSize = this->GetInputProjectionStack()->GetBufferedRegion().GetSize()[0] *
                       this->GetInputProjectionStack()->GetBufferedRegion().GetSize()[1];
  stackGPUPointer += projSize * (iFirstProj-this->GetInputProjectionStack()->GetBufferedRegion().GetIndex()[2]);

  float *pinxDVF = *(float**)( xCompDVF->GetCudaDataManager()->GetGPUBufferPointer() );
  float *pinyDVF = *(float**)( yCompDVF->GetCudaDataManager()->GetGPUBufferPointer() );
  float *pinzDVF = *(float**)( zCompDVF->GetCudaDataManager()->GetGPUBufferPointer() );

  // Go over each projection
  for(unsigned int iProj=iFirstProj; iProj<iFirstProj+nProj; iProj++, stackGPUPointer += projSize)
    {
    // Index to index matrix normalized to have a correct backprojection weight
    // (1 at the isocenter)
    ProjectionMatrixType matrix = GetIndexToIndexProjectionMatrix(iProj);

    // We correct the matrix for non zero indexes
    itk::Matrix<double, 3, 3> matrixIdxProj;
    matrixIdxProj.SetIdentity();
    for(unsigned int i=0; i<2; i++)
      //SR: 0.5 for 2D texture
      matrixIdxProj[i][2] = -1*(this->GetInputProjectionStack()->GetBufferedRegion().GetIndex()[i])+0.5;

    matrix = matrixIdxProj.GetVnlMatrix() * matrix.GetVnlMatrix() * matrixIdxVol.GetVnlMatrix();

    double perspFactor = matrix[Dimension-1][Dimension];
    for(unsigned int j=0; j<Dimension; j++)
      perspFactor += matrix[Dimension-1][j] * rotCenterIndex[j];
    matrix /= perspFactor;

    float fMatrix[12];
    for (int j = 0; j < 12; j++)
      fMatrix[j] = matrix[j/4][j%4];

    CUDA_warp_back_project(projectionSize,
                      volumeSize,
                      inputDVFSize,
                      fMatrix,
                      pin,
                      pout,
                      stackGPUPointer,
                      pinxDVF,
                      pinyDVF,
                      pinzDVF,
                      fIndexInputToIndexDVFMatrix,
                      fPPInputToIndexInputMatrix,
                      fIndexInputToPPInputMatrix
                      );
    pin = pout;
    }
}

} // end namespace rtk
<|endoftext|>


<commit_before>#include <debug.hpp>
#include <itemsForm.hpp>

#include <algorithm>
#include <string>
#include <QJsonArray>
#include <QJsonDocument>
#include <QString>
#include <QFile>

ItemForm::ItemForm(void) {
    // TODO: Load this list from some default settings or leave empty
    Item* item1 = new Item("Item #1", 1, 1, Item::GRAM);
    Item* item25 = new Item("Item #25", 25, 25, Item::PIECE);
    Item* item125 = new Item("Item #125", 125, 125, Item::PIECE);

    Food* food1 = new Food("Food #1", 1, 1, Item::GRAM, 1, 1, 1, 1);
    Food* food25 = new Food("Food #25", 25, 25, Item::PIECE, 25, 25, 25, 25);
    Food* food125 = new Food("Food #125", 125, 125, Item::PIECE, 125, 125, 125, 125);

    Dish* dish1 = new Dish("Dish #1", food1, food1->getMass(), 1);
    Dish* dish25 = new Dish("Dish #25", food25, food25->getMass(), 1);
    Dish* dish125 = new Dish("Dish #125", food125, food125->getMass(), 1);

    avaliableItems.push_back(item1);
    item1->addItemList(&avaliableItems);
    avaliableItems.push_back(item25);
    item25->addItemList(&avaliableItems);
    avaliableItems.push_back(item125);
    item125->addItemList(&avaliableItems);

    avaliableItems.push_back(food1);
    food1->addItemList(&avaliableItems);
    avaliableItems.push_back(food25);
    food25->addItemList(&avaliableItems);
    avaliableItems.push_back(food125);
    food125->addItemList(&avaliableItems);

    avaliableDish.push_back(dish1);
    dish1->addDishList(&avaliableDish);
    avaliableDish.push_back(dish25);
    dish25->addDishList(&avaliableDish);
    avaliableDish.push_back(dish125);
    dish125->addDishList(&avaliableDish);

    PRINT_OBJ("ItemForm created");
}

ItemForm::~ItemForm(void) {
    for ( std::list<Item*>::iterator it = avaliableItems.begin(); it != avaliableItems.end(); ) {
        std::list<Item*>::iterator oldit = it++;

        delete *oldit;
    }

    PRINT_OBJ("ItemForm destroyed");
}

Item * ItemForm::readItem(const QJsonObject &json) {
    return new Item(json["name"].toString().toStdString(),
                    json["mass"].toInt(),
                    json["price"].toInt(),
                    static_cast<Item::MeasureType>(json["measureType"].toInt()));
}

Food * ItemForm::readFood(const QJsonObject &json) {
    return new Food(json["name"].toString().toStdString(),
                    json["mass"].toInt(),
                    json["price"].toInt(),
                    static_cast<Item::MeasureType>(json["measureType"].toInt()),
                    json["fats"].toInt(),
                    json["proteins"].toInt(),
                    json["carbohydrates"].toInt(),
                    json["calories"].toInt());
}

Dish * ItemForm::readDish(const QJsonObject &json) {
    QJsonArray itemsList = json["items"].toArray();
    Food * newFood = readFood(itemsList[0].toObject()["food"].toObject());
    Dish * newDish = new Dish(json["name"].toString().toStdString(), newFood,
                              itemsList[0].toObject()["amount"].toInt());

    avaliableItems.push_back(newFood);

    for ( int index = 1; index < itemsList.size(); index++ ) {
        newFood = readFood(itemsList[index].toObject()["food"].toObject());
        newDish->addFood(newFood, itemsList[index].toObject()["amount"].toInt());
        std::list<Item*>::iterator it = std::find(avaliableItems.begin(), avaliableItems.end(), dynamic_cast<Item *>(newFood));

        if ( it == avaliableItems.end() ) {
           avaliableItems.push_back(newFood);
        }
    }

    return newDish;
}

void ItemForm::writeItem(QJsonObject &json, Item &item) const {
    json["name"] = QString::fromStdString(item.getName());
    json["mass"] = static_cast<qint64>(item.getMass());
    json["price"] = static_cast<qint64>(item.getPrice());
    json["measureType"] = static_cast<int>(item.getUnitType());
}

void ItemForm::writeFood(QJsonObject &json, Food &food) const {
    json["name"] = QString::fromStdString(food.getName());
    json["mass"] = static_cast<qint64>(food.getMass());
    json["price"] = static_cast<qint64>(food.getPrice());
    json["measureType"] = static_cast<int>(food.getUnitType());
    json["fats"] = static_cast<qint64>(food.getFats());
    json["proteins"] = static_cast<qint64>(food.getProteins());
    json["carbohydrates"] = static_cast<qint64>(food.getCarbohydrates());
    json["calories"] = static_cast<qint64>(food.getCalories());
}

void ItemForm::writeDish(QJsonObject &json, Dish &dish) const {
    QJsonArray itemsList;

    json["name"] = QString::fromStdString(dish.getName());
    json["amountOfPeople"] = static_cast<qint64>(dish.getAmountOfPeople());

    for ( auto &entry: dish.getIngridientMap() ) {
        QJsonObject mapEntry;
        QJsonObject food;

        writeFood(food, *(entry.first));

        mapEntry["food"] = food;
        mapEntry["amount"] = static_cast<qint64>(entry.second);

        itemsList.append(mapEntry);
    }

    json["items"] = itemsList;
}

void ItemForm::saveItems(QJsonObject &json) {
    QJsonArray itemsList;

    for ( auto &entry: avaliableItems ) {
        QJsonObject itemObj;

        if ( !dynamic_cast<Food *>(entry) ) {
            writeItem(itemObj, *entry);

            itemsList.append(itemObj);
        }
    }

    json["itemList"] = itemsList;
}

void ItemForm::saveFood(QJsonObject &json) {
    QJsonArray foodList;

    for ( auto &entry: avaliableItems ) {
        QJsonObject foodObj;

        if ( dynamic_cast<Food *>(entry) ) {
            writeFood(foodObj, *dynamic_cast<Food *>(entry));

            foodList.append(foodObj);
        }
    }

    json["foodList"] = foodList;
}

void ItemForm::saveDish(QJsonObject &json) {
    QJsonArray dishList;

    for ( auto &entry: avaliableDish ) {
        QJsonObject itemObj;

        writeDish(itemObj, *entry);

        dishList.append(itemObj);
    }

    json["dishList"] = dishList;
}

bool ItemForm::saveData() {
    QJsonObject saveObj;
    QFile saveFile(QStringLiteral("save.json"));

    if ( !saveFile.open(QIODevice::WriteOnly) ) {
        PRINT_ERR("Couldn't open save file.");

        return false;
    }

    saveItems(saveObj);
    saveFood(saveObj);
    saveDish(saveObj);

    QJsonDocument saveDoc(saveObj);
    saveFile.write(saveDoc.toJson());

    return true;
}

void ItemForm::loadItems(const QJsonArray &jsonArray) {
    for ( int i = 0; i < jsonArray.size(); i++ ) {
        Item * newItem = readItem(jsonArray[i].toObject());
        std::list<Item*>::iterator it = std::find(avaliableItems.begin(), avaliableItems.end(), newItem);

        if ( it == avaliableItems.end() ) {
           avaliableItems.push_back(newItem);
        }
    }
}

void ItemForm::loadFood(const QJsonArray &jsonArray) {
    for ( int i = 0; i < jsonArray.size(); i++ ) {
        Food * newFood = readFood(jsonArray[i].toObject());
        std::list<Item*>::iterator it;

        for ( it = avaliableItems.begin(); ; it++ ) {
            if ( !(*it)->getName().compare(newFood->getName()) ) {
                delete newFood;

                break;
            } else if ( it == avaliableItems.end() ) {
                avaliableItems.push_back(newFood);
            }
        }
    }
}

void ItemForm::loadDish(const QJsonArray &jsonArray) {
    for ( int i = 0; i < jsonArray.size(); i++ ) {
        Dish * newDish = readDish(jsonArray[i].toObject());
        std::list<Dish*>::iterator it = std::find(avaliableDish.begin(), avaliableDish.end(), newDish);

        if ( it == avaliableDish.end() ) {
           avaliableDish.push_back(newDish);
        }
    }
}

bool ItemForm::loadData(void) {
    QFile loadFile(QStringLiteral("save.json"));

    if ( !loadFile.open(QIODevice::ReadOnly) ) {
        qWarning("Couldn't open save file.");
        return false;
    }

    QByteArray saveData = loadFile.readAll();

    QJsonDocument loadDoc(QJsonDocument::fromJson(saveData));

    loadDish(loadDoc.object()["dishList"].toArray());
    loadFood(loadDoc.object()["foodList"].toArray());
    loadItems(loadDoc.object()["itemList"].toArray());

    return true;
}
<commit_msg>itemsForm: Add lists to every now item, food, dish object<commit_after>#include <debug.hpp>
#include <itemsForm.hpp>

#include <algorithm>
#include <string>
#include <QJsonArray>
#include <QJsonDocument>
#include <QString>
#include <QFile>

ItemForm::ItemForm(void) {
    // TODO: Load this list from some default settings or leave empty
    Item* item1 = new Item("Item #1", 1, 1, Item::GRAM);
    Item* item25 = new Item("Item #25", 25, 25, Item::PIECE);
    Item* item125 = new Item("Item #125", 125, 125, Item::PIECE);

    Food* food1 = new Food("Food #1", 1, 1, Item::GRAM, 1, 1, 1, 1);
    Food* food25 = new Food("Food #25", 25, 25, Item::PIECE, 25, 25, 25, 25);
    Food* food125 = new Food("Food #125", 125, 125, Item::PIECE, 125, 125, 125, 125);

    Dish* dish1 = new Dish("Dish #1", food1, food1->getMass(), 1);
    Dish* dish25 = new Dish("Dish #25", food25, food25->getMass(), 1);
    Dish* dish125 = new Dish("Dish #125", food125, food125->getMass(), 1);

    avaliableItems.push_back(item1);
    item1->addItemList(&avaliableItems);
    avaliableItems.push_back(item25);
    item25->addItemList(&avaliableItems);
    avaliableItems.push_back(item125);
    item125->addItemList(&avaliableItems);

    avaliableItems.push_back(food1);
    food1->addItemList(&avaliableItems);
    avaliableItems.push_back(food25);
    food25->addItemList(&avaliableItems);
    avaliableItems.push_back(food125);
    food125->addItemList(&avaliableItems);

    avaliableDish.push_back(dish1);
    dish1->addDishList(&avaliableDish);
    avaliableDish.push_back(dish25);
    dish25->addDishList(&avaliableDish);
    avaliableDish.push_back(dish125);
    dish125->addDishList(&avaliableDish);

    PRINT_OBJ("ItemForm created");
}

ItemForm::~ItemForm(void) {
    for ( std::list<Item*>::iterator it = avaliableItems.begin(); it != avaliableItems.end(); ) {
        std::list<Item*>::iterator oldit = it++;

        delete *oldit;
    }

    PRINT_OBJ("ItemForm destroyed");
}

Item * ItemForm::readItem(const QJsonObject &json) {
    return new Item(json["name"].toString().toStdString(),
                    json["mass"].toInt(),
                    json["price"].toInt(),
                    static_cast<Item::MeasureType>(json["measureType"].toInt()));
}

Food * ItemForm::readFood(const QJsonObject &json) {
    return new Food(json["name"].toString().toStdString(),
                    json["mass"].toInt(),
                    json["price"].toInt(),
                    static_cast<Item::MeasureType>(json["measureType"].toInt()),
                    json["fats"].toInt(),
                    json["proteins"].toInt(),
                    json["carbohydrates"].toInt(),
                    json["calories"].toInt());
}

Dish * ItemForm::readDish(const QJsonObject &json) {
    QJsonArray itemsList = json["items"].toArray();
    Food * newFood = readFood(itemsList[0].toObject()["food"].toObject());
    Dish * newDish = new Dish(json["name"].toString().toStdString(), newFood,
                              itemsList[0].toObject()["amount"].toInt());

    avaliableItems.push_back(newFood);
    newFood->addItemList(&avaliableItems);

    for ( int index = 1; index < itemsList.size(); index++ ) {
        newFood = readFood(itemsList[index].toObject()["food"].toObject());
        newDish->addFood(newFood, itemsList[index].toObject()["amount"].toInt());
        std::list<Item*>::iterator it = std::find(avaliableItems.begin(), avaliableItems.end(), dynamic_cast<Item *>(newFood));

        if ( it == avaliableItems.end() ) {
           avaliableItems.push_back(newFood);
           newFood->addItemList(&avaliableItems);
        }
    }

    return newDish;
}

void ItemForm::writeItem(QJsonObject &json, Item &item) const {
    json["name"] = QString::fromStdString(item.getName());
    json["mass"] = static_cast<qint64>(item.getMass());
    json["price"] = static_cast<qint64>(item.getPrice());
    json["measureType"] = static_cast<int>(item.getUnitType());
}

void ItemForm::writeFood(QJsonObject &json, Food &food) const {
    json["name"] = QString::fromStdString(food.getName());
    json["mass"] = static_cast<qint64>(food.getMass());
    json["price"] = static_cast<qint64>(food.getPrice());
    json["measureType"] = static_cast<int>(food.getUnitType());
    json["fats"] = static_cast<qint64>(food.getFats());
    json["proteins"] = static_cast<qint64>(food.getProteins());
    json["carbohydrates"] = static_cast<qint64>(food.getCarbohydrates());
    json["calories"] = static_cast<qint64>(food.getCalories());
}

void ItemForm::writeDish(QJsonObject &json, Dish &dish) const {
    QJsonArray itemsList;

    json["name"] = QString::fromStdString(dish.getName());
    json["amountOfPeople"] = static_cast<qint64>(dish.getAmountOfPeople());

    for ( auto &entry: dish.getIngridientMap() ) {
        QJsonObject mapEntry;
        QJsonObject food;

        writeFood(food, *(entry.first));

        mapEntry["food"] = food;
        mapEntry["amount"] = static_cast<qint64>(entry.second);

        itemsList.append(mapEntry);
    }

    json["items"] = itemsList;
}

void ItemForm::saveItems(QJsonObject &json) {
    QJsonArray itemsList;

    for ( auto &entry: avaliableItems ) {
        QJsonObject itemObj;

        if ( !dynamic_cast<Food *>(entry) ) {
            writeItem(itemObj, *entry);

            itemsList.append(itemObj);
        }
    }

    json["itemList"] = itemsList;
}

void ItemForm::saveFood(QJsonObject &json) {
    QJsonArray foodList;

    for ( auto &entry: avaliableItems ) {
        QJsonObject foodObj;

        if ( dynamic_cast<Food *>(entry) ) {
            writeFood(foodObj, *dynamic_cast<Food *>(entry));

            foodList.append(foodObj);
        }
    }

    json["foodList"] = foodList;
}

void ItemForm::saveDish(QJsonObject &json) {
    QJsonArray dishList;

    for ( auto &entry: avaliableDish ) {
        QJsonObject itemObj;

        writeDish(itemObj, *entry);

        dishList.append(itemObj);
    }

    json["dishList"] = dishList;
}

bool ItemForm::saveData() {
    QJsonObject saveObj;
    QFile saveFile(QStringLiteral("save.json"));

    if ( !saveFile.open(QIODevice::WriteOnly) ) {
        PRINT_ERR("Couldn't open save file.");

        return false;
    }

    saveItems(saveObj);
    saveFood(saveObj);
    saveDish(saveObj);

    QJsonDocument saveDoc(saveObj);
    saveFile.write(saveDoc.toJson());

    return true;
}

void ItemForm::loadItems(const QJsonArray &jsonArray) {
    for ( int i = 0; i < jsonArray.size(); i++ ) {
        Item * newItem = readItem(jsonArray[i].toObject());
        std::list<Item*>::iterator it = std::find(avaliableItems.begin(), avaliableItems.end(), newItem);

        if ( it == avaliableItems.end() ) {
           avaliableItems.push_back(newItem);
           newItem->addItemList(&avaliableItems);
        }
    }
}

void ItemForm::loadFood(const QJsonArray &jsonArray) {
    for ( int i = 0; i < jsonArray.size(); i++ ) {
        Food * newFood = readFood(jsonArray[i].toObject());
        std::list<Item*>::iterator it;

        for ( it = avaliableItems.begin(); ; it++ ) {
            if ( !(*it)->getName().compare(newFood->getName()) ) {
                delete newFood;

                break;
            } else if ( it == avaliableItems.end() ) {
                avaliableItems.push_back(newFood);
                newFood->addItemList(&avaliableItems);
            }
        }
    }
}

void ItemForm::loadDish(const QJsonArray &jsonArray) {
    for ( int i = 0; i < jsonArray.size(); i++ ) {
        Dish * newDish = readDish(jsonArray[i].toObject());
        std::list<Dish*>::iterator it = std::find(avaliableDish.begin(), avaliableDish.end(), newDish);

        if ( it == avaliableDish.end() ) {
           avaliableDish.push_back(newDish);
           newDish->addDishList(&avaliableDish);
        }
    }
}

bool ItemForm::loadData(void) {
    QFile loadFile(QStringLiteral("save.json"));

    if ( !loadFile.open(QIODevice::ReadOnly) ) {
        qWarning("Couldn't open save file.");
        return false;
    }

    QByteArray saveData = loadFile.readAll();

    QJsonDocument loadDoc(QJsonDocument::fromJson(saveData));

    loadDish(loadDoc.object()["dishList"].toArray());
    loadFood(loadDoc.object()["foodList"].toArray());
    loadItems(loadDoc.object()["itemList"].toArray());

    return true;
}
<|endoftext|>