<commit_before>//------------------------------------------------------------------------------
// SourceManager.cpp
// Source file management.
//
// File is under the MIT license; see LICENSE for details.
//------------------------------------------------------------------------------
#include "SourceManager.h"

#include <algorithm>
#include <fstream>

#include "util/HashMap.h"

namespace slang {

SourceManager::SourceManager() {
    // add a dummy entry to the start of the directory list so that our file IDs line up
    FileInfo file;
    bufferEntries.emplace_back(file);
}

std::string SourceManager::makeAbsolutePath(StringRef path) const {
    if (!path)
        return "";

    return Path::makeAbsolute(path).str();
}

void SourceManager::addSystemDirectory(StringRef path) {
    systemDirectories.push_back(Path::makeAbsolute(path));
}

void SourceManager::addUserDirectory(StringRef path) {
    userDirectories.push_back(Path::makeAbsolute(path));
}

uint32_t SourceManager::getLineNumber(SourceLocation location) const {
    SourceLocation fileLocation = getFullyExpandedLoc(location);
    uint32_t rawLineNumber = getRawLineNumber(fileLocation);
    if (rawLineNumber == 0)
        return 0;

    FileData* fd = getFileData(fileLocation.buffer());
    auto lineDirective = fd->getPreviousLineDirective(rawLineNumber);

    if (!lineDirective)
        return rawLineNumber;
    else
        return lineDirective->lineOfDirective + (rawLineNumber - lineDirective->lineInFile) - 1;
}

uint32_t SourceManager::getColumnNumber(SourceLocation location) const {
    FileData* fd = getFileData(location.buffer());
    if (!fd)
        return 0;

    // walk backward to find start of line
    uint32_t lineStart = location.offset();
    ASSERT(lineStart < fd->mem.count());
    while (lineStart > 0 && fd->mem[lineStart - 1] != '\n' && fd->mem[lineStart - 1] != '\r')
        lineStart--;

    return location.offset() - lineStart + 1;
}

StringRef SourceManager::getFileName(SourceLocation location) const {
    SourceLocation fileLocation = getFullyExpandedLoc(location);

    // Avoid computing line offsets if we just need a name of `line-less file
    FileData* fd = getFileData(fileLocation.buffer());
    if (!fd)
        return nullptr;
    else if (fd->lineDirectives.empty())
        return StringRef(fd->name);

    auto lineDirective = fd->getPreviousLineDirective(getRawLineNumber(fileLocation));
    if (!lineDirective)
        return StringRef(fd->name);
    else
        return StringRef(lineDirective->name);
}

SourceLocation SourceManager::getIncludedFrom(BufferID buffer) const {
    if (!buffer)
        return SourceLocation();

    ASSERT(buffer.id < bufferEntries.size());
    return std::get<FileInfo>(bufferEntries[buffer.id]).includedFrom;
}

bool SourceManager::isFileLoc(SourceLocation location) const {
    auto buffer = location.buffer();
    if (!buffer)
        return false;

    ASSERT(buffer.id < bufferEntries.size());
    return std::get_if<FileInfo>(&bufferEntries[buffer.id]) != nullptr;
}

bool SourceManager::isMacroLoc(SourceLocation location) const {
    auto buffer = location.buffer();
    if (!buffer)
        return false;

    ASSERT(buffer.id < bufferEntries.size());
    return std::get_if<ExpansionInfo>(&bufferEntries[buffer.id]) != nullptr;
}

bool SourceManager::isIncludedFileLoc(SourceLocation location) const {
    return getIncludedFrom(location.buffer()).valid();
}

bool SourceManager::isBeforeInCompilationUnit(SourceLocation left, SourceLocation right) const {
    // Simple check: if they're in the same buffer, just do an easy compare
    if (left.buffer() == right.buffer())
        return left.offset() < right.offset();

    // TODO: add a cache for this?

    auto moveUp = [this](SourceLocation& sl) {
        if (!isFileLoc(sl))
            sl = getExpansionLoc(sl);
        else {
            SourceLocation included = getIncludedFrom(sl.buffer());
            if (!included)
                return true;
            sl = included;
        }
        return false;
    };

    // Otherwise we have to build the full include / expansion chain and compare.
    SmallHashMap<BufferID, uint32_t, 16> leftChain;
    do {
        leftChain.emplace(left.buffer(), left.offset());
    }
    while (left.buffer() != right.buffer() && !moveUp(left));

    SmallHashMap<BufferID, uint32_t, 16>::iterator it;
    while ((it = leftChain.find(right.buffer())) == leftChain.end()) {
        if (moveUp(right))
            break;
    }

    if (it != leftChain.end())
        left = SourceLocation(it->first, it->second);

    // At this point, we either have a nearest common ancestor, or the two
    // locations are simply in totally different compilation units.
    ASSERT(left.buffer() == right.buffer());
    return left.offset() < right.offset();
}

SourceLocation SourceManager::getExpansionLoc(SourceLocation location) const {
    auto buffer = location.buffer();
    if (!buffer)
        return SourceLocation();

    ASSERT(buffer.id < bufferEntries.size());
    return std::get<ExpansionInfo>(bufferEntries[buffer.id]).expansionStart;
}

SourceRange SourceManager::getExpansionRange(SourceLocation location) const {
    auto buffer = location.buffer();
    if (!buffer)
        return SourceRange();

    ASSERT(buffer.id < bufferEntries.size());
    const ExpansionInfo& info = std::get<ExpansionInfo>(bufferEntries[buffer.id]);
    return SourceRange(info.expansionStart, info.expansionEnd);
}

SourceLocation SourceManager::getOriginalLoc(SourceLocation location) const {
    auto buffer = location.buffer();
    if (!buffer)
        return SourceLocation();

    ASSERT(buffer.id < bufferEntries.size());
    return std::get<ExpansionInfo>(bufferEntries[buffer.id]).originalLoc + location.offset();
}

SourceLocation SourceManager::getFullyExpandedLoc(SourceLocation location) const {
    while (isMacroLoc(location))
        location = getExpansionLoc(location);
    return location;
}

StringRef SourceManager::getSourceText(BufferID buffer) const {
    FileData* fd = getFileData(buffer);
    if (!fd)
        return nullptr;

    return StringRef(fd->mem);
}

SourceLocation SourceManager::createExpansionLoc(SourceLocation originalLoc, SourceLocation expansionStart,
                                                 SourceLocation expansionEnd) {
    bufferEntries.emplace_back(ExpansionInfo(originalLoc, expansionStart, expansionEnd));
    return SourceLocation(BufferID::get((uint32_t)(bufferEntries.size() - 1)), 0);
}

SourceBuffer SourceManager::assignText(StringRef text, SourceLocation includedFrom) {
    // Generate a placeholder name for this "file"
    return assignText(StringRef("<unnamed_buffer" + std::to_string(unnamedBufferCount++) + ">"), text, includedFrom);
}

SourceBuffer SourceManager::assignText(StringRef path, StringRef text, SourceLocation includedFrom) {
    SmallVectorSized<char, 2> buffer;
    buffer.appendRange(text);
    if (buffer.empty() || buffer.back() != '\0')
        buffer.append('\0');

    return assignBuffer(path, std::move(buffer), includedFrom);
}

SourceBuffer SourceManager::appendText(BufferID buffer, StringRef text) {
    ASSERT(buffer);
    FileInfo& fi = std::get<FileInfo>(bufferEntries[buffer.id]);
    SourceLocation includeLoc = SourceLocation(buffer, fi.data->mem.count());
    return assignText(text, includeLoc);
}

SourceBuffer SourceManager::assignBuffer(StringRef path, Vector<char>&& buffer, SourceLocation includedFrom) {
    Path fullPath = path;
    std::string canonicalStr = fullPath.str();
    auto it = lookupCache.find(canonicalStr);
    ASSERT(it == lookupCache.end());

    return cacheBuffer(std::move(canonicalStr), fullPath, includedFrom, std::move(buffer));
}

SourceBuffer SourceManager::readSource(StringRef path) {
    ASSERT(path);
    return openCached(path, SourceLocation());
}

SourceBuffer SourceManager::readHeader(StringRef path, SourceLocation includedFrom, bool isSystemPath) {
    // if the header is specified as an absolute path, just do a straight lookup
    ASSERT(path);
    Path p = path;
    if (p.isAbsolute())
        return openCached(p, includedFrom);

    // system path lookups only look in system directories
    if (isSystemPath) {
        for (auto& d : systemDirectories) {
            SourceBuffer result = openCached(d + p, includedFrom);
            if (result.id)
                return result;
        }
        return SourceBuffer();
    }

    // search relative to the current file
    FileData* fd = getFileData(includedFrom.buffer());
    if (fd && fd->directory) {
        SourceBuffer result = openCached((*fd->directory) + p, includedFrom);
        if (result.id)
            return result;
    }

    // search additional include directories
    for (auto& d : userDirectories) {
        SourceBuffer result = openCached(d + p, includedFrom);
        if (result.id)
            return result;
    }

    return SourceBuffer();
}

void SourceManager::addLineDirective(SourceLocation location, uint32_t lineNum,
                                     StringRef name, uint8_t level) {
    SourceLocation fileLocation = getFullyExpandedLoc(location);
    FileData* fd = getFileData(fileLocation.buffer());
    if (!fd)
        return;

    uint32_t sourceLineNum = getRawLineNumber(fileLocation);
    fd->lineDirectives.emplace_back(sourceLineNum, lineNum, name, level);
}

SourceManager::FileData* SourceManager::getFileData(BufferID buffer) const {
    if (!buffer)
        return nullptr;

    ASSERT(buffer.id < bufferEntries.size());
    return std::get<FileInfo>(bufferEntries[buffer.id]).data;
}

SourceBuffer SourceManager::createBufferEntry(FileData* fd, SourceLocation includedFrom) {
    ASSERT(fd);
    bufferEntries.emplace_back(FileInfo(fd, includedFrom));
    return SourceBuffer {
        StringRef(fd->mem),
        BufferID::get((uint32_t)(bufferEntries.size() - 1))
    };
}

SourceBuffer SourceManager::openCached(const Path& fullPath, SourceLocation includedFrom) {
    Path absPath;
    try {
        absPath = Path::makeAbsolute(fullPath);
    }
    catch (std::runtime_error&) {
        return SourceBuffer();
    }

    // first see if we have this file cached
    std::string canonicalStr = absPath.str();
    auto it = lookupCache.find(canonicalStr);
    if (it != lookupCache.end()) {
        FileData* fd = it->second.get();
        if (!fd)
            return SourceBuffer();
        return createBufferEntry(fd, includedFrom);
    }

    // do the read
    Vector<char> buffer;
    if (!readFile(absPath, buffer)) {
        lookupCache.emplace(std::move(canonicalStr), nullptr);
        return SourceBuffer();
    }

    return cacheBuffer(std::move(canonicalStr), absPath, includedFrom, std::move(buffer));
}

SourceBuffer SourceManager::cacheBuffer(std::string&& canonicalPath, const Path& path, SourceLocation includedFrom, Vector<char>&& buffer) {
    std::string name = path.filename();
    auto fd = std::make_unique<FileData>(
        &*directories.insert(path.parentPath()).first,
        name,
        std::move(buffer)
    );

    FileData* fdPtr = lookupCache.emplace(std::move(canonicalPath), std::move(fd)).first->second.get();
    return createBufferEntry(fdPtr, includedFrom);
}

bool SourceManager::readFile(const Path& path, Vector<char>& buffer) {
    size_t size;
    try {
        size = path.fileSize();
    }
    catch (std::runtime_error&) {
        return false;
    }

    // + 1 for null terminator
    buffer.extend((uint32_t)size + 1);
    std::ifstream stream(path.str(), std::ios::binary);
    stream.read(buffer.begin(), size);

    // null-terminate the buffer while we're at it
    buffer.begin()[(uint32_t)size] = '\0';

    return stream.good();
}

void SourceManager::computeLineOffsets(const Vector<char>& buffer, std::vector<uint32_t>& offsets) {
    // first line always starts at offset 0
    offsets.push_back(0);

    const char* ptr = buffer.begin();
    const char* end = buffer.end();
    while (ptr != end) {
        if (ptr[0] == '\n' || ptr[0] == '\r') {
            // if we see \r\n or \n\r skip both chars
            if ((ptr[1] == '\n' || ptr[1] == '\r') && ptr[0] != ptr[1])
                ptr++;
            ptr++;
            offsets.push_back((uint32_t)(ptr - buffer.begin()));
        }
        else {
            ptr++;
        }
    }
}

const SourceManager::FileData::LineDirectiveInfo*
SourceManager::FileData::getPreviousLineDirective(uint32_t rawLineNumber) const {
    auto it = std::lower_bound(lineDirectives.begin(), lineDirectives.end(),
        LineDirectiveInfo(rawLineNumber, 0, "", 0), LineDirectiveComparator());

    if (it != lineDirectives.begin()) {
        // lower_bound will give us an iterator to the first directive after the command
        // let's instead get a pointer to the one right before it
        if (it == lineDirectives.end()) {
            // Check to see whether the actual last directive is before the
            // given line number
            if (lineDirectives.back().lineInFile >= rawLineNumber)
                return nullptr;
        }
        return &*(it - 1);
    }
    else {
        return nullptr;
    }
}

uint32_t SourceManager::getRawLineNumber(SourceLocation location) const {
    FileData* fd = getFileData(location.buffer());
    if (!fd)
        return 0;

    // compute line offsets if we haven't already
    if (fd->lineOffsets.empty())
        computeLineOffsets(fd->mem, fd->lineOffsets);

    // Find the first line offset that is greater than the given location offset. That iterator
    // then tells us how many lines away from the beginning we are.
    auto it = std::lower_bound(fd->lineOffsets.begin(), fd->lineOffsets.end(), location.offset());

    // We want to ensure the line we return is strictly greater than the given location offset.
    // So if it is equal, add one to the lower bound we got
    return (uint32_t)(it - fd->lineOffsets.begin()) + (*it == location.offset());
}

}
<commit_msg>Fix bug in line number calculation<commit_after>//------------------------------------------------------------------------------
// SourceManager.cpp
// Source file management.
//
// File is under the MIT license; see LICENSE for details.
//------------------------------------------------------------------------------
#include "SourceManager.h"

#include <algorithm>
#include <fstream>

#include "util/HashMap.h"

namespace slang {

SourceManager::SourceManager() {
    // add a dummy entry to the start of the directory list so that our file IDs line up
    FileInfo file;
    bufferEntries.emplace_back(file);
}

std::string SourceManager::makeAbsolutePath(StringRef path) const {
    if (!path)
        return "";

    return Path::makeAbsolute(path).str();
}

void SourceManager::addSystemDirectory(StringRef path) {
    systemDirectories.push_back(Path::makeAbsolute(path));
}

void SourceManager::addUserDirectory(StringRef path) {
    userDirectories.push_back(Path::makeAbsolute(path));
}

uint32_t SourceManager::getLineNumber(SourceLocation location) const {
    SourceLocation fileLocation = getFullyExpandedLoc(location);
    uint32_t rawLineNumber = getRawLineNumber(fileLocation);
    if (rawLineNumber == 0)
        return 0;

    FileData* fd = getFileData(fileLocation.buffer());
    auto lineDirective = fd->getPreviousLineDirective(rawLineNumber);

    if (!lineDirective)
        return rawLineNumber;
    else
        return lineDirective->lineOfDirective + (rawLineNumber - lineDirective->lineInFile) - 1;
}

uint32_t SourceManager::getColumnNumber(SourceLocation location) const {
    FileData* fd = getFileData(location.buffer());
    if (!fd)
        return 0;

    // walk backward to find start of line
    uint32_t lineStart = location.offset();
    ASSERT(lineStart < fd->mem.count());
    while (lineStart > 0 && fd->mem[lineStart - 1] != '\n' && fd->mem[lineStart - 1] != '\r')
        lineStart--;

    return location.offset() - lineStart + 1;
}

StringRef SourceManager::getFileName(SourceLocation location) const {
    SourceLocation fileLocation = getFullyExpandedLoc(location);

    // Avoid computing line offsets if we just need a name of `line-less file
    FileData* fd = getFileData(fileLocation.buffer());
    if (!fd)
        return nullptr;
    else if (fd->lineDirectives.empty())
        return StringRef(fd->name);

    auto lineDirective = fd->getPreviousLineDirective(getRawLineNumber(fileLocation));
    if (!lineDirective)
        return StringRef(fd->name);
    else
        return StringRef(lineDirective->name);
}

SourceLocation SourceManager::getIncludedFrom(BufferID buffer) const {
    if (!buffer)
        return SourceLocation();

    ASSERT(buffer.id < bufferEntries.size());
    return std::get<FileInfo>(bufferEntries[buffer.id]).includedFrom;
}

bool SourceManager::isFileLoc(SourceLocation location) const {
    auto buffer = location.buffer();
    if (!buffer)
        return false;

    ASSERT(buffer.id < bufferEntries.size());
    return std::get_if<FileInfo>(&bufferEntries[buffer.id]) != nullptr;
}

bool SourceManager::isMacroLoc(SourceLocation location) const {
    auto buffer = location.buffer();
    if (!buffer)
        return false;

    ASSERT(buffer.id < bufferEntries.size());
    return std::get_if<ExpansionInfo>(&bufferEntries[buffer.id]) != nullptr;
}

bool SourceManager::isIncludedFileLoc(SourceLocation location) const {
    return getIncludedFrom(location.buffer()).valid();
}

bool SourceManager::isBeforeInCompilationUnit(SourceLocation left, SourceLocation right) const {
    // Simple check: if they're in the same buffer, just do an easy compare
    if (left.buffer() == right.buffer())
        return left.offset() < right.offset();

    // TODO: add a cache for this?

    auto moveUp = [this](SourceLocation& sl) {
        if (!isFileLoc(sl))
            sl = getExpansionLoc(sl);
        else {
            SourceLocation included = getIncludedFrom(sl.buffer());
            if (!included)
                return true;
            sl = included;
        }
        return false;
    };

    // Otherwise we have to build the full include / expansion chain and compare.
    SmallHashMap<BufferID, uint32_t, 16> leftChain;
    do {
        leftChain.emplace(left.buffer(), left.offset());
    }
    while (left.buffer() != right.buffer() && !moveUp(left));

    SmallHashMap<BufferID, uint32_t, 16>::iterator it;
    while ((it = leftChain.find(right.buffer())) == leftChain.end()) {
        if (moveUp(right))
            break;
    }

    if (it != leftChain.end())
        left = SourceLocation(it->first, it->second);

    // At this point, we either have a nearest common ancestor, or the two
    // locations are simply in totally different compilation units.
    ASSERT(left.buffer() == right.buffer());
    return left.offset() < right.offset();
}

SourceLocation SourceManager::getExpansionLoc(SourceLocation location) const {
    auto buffer = location.buffer();
    if (!buffer)
        return SourceLocation();

    ASSERT(buffer.id < bufferEntries.size());
    return std::get<ExpansionInfo>(bufferEntries[buffer.id]).expansionStart;
}

SourceRange SourceManager::getExpansionRange(SourceLocation location) const {
    auto buffer = location.buffer();
    if (!buffer)
        return SourceRange();

    ASSERT(buffer.id < bufferEntries.size());
    const ExpansionInfo& info = std::get<ExpansionInfo>(bufferEntries[buffer.id]);
    return SourceRange(info.expansionStart, info.expansionEnd);
}

SourceLocation SourceManager::getOriginalLoc(SourceLocation location) const {
    auto buffer = location.buffer();
    if (!buffer)
        return SourceLocation();

    ASSERT(buffer.id < bufferEntries.size());
    return std::get<ExpansionInfo>(bufferEntries[buffer.id]).originalLoc + location.offset();
}

SourceLocation SourceManager::getFullyExpandedLoc(SourceLocation location) const {
    while (isMacroLoc(location))
        location = getExpansionLoc(location);
    return location;
}

StringRef SourceManager::getSourceText(BufferID buffer) const {
    FileData* fd = getFileData(buffer);
    if (!fd)
        return nullptr;

    return StringRef(fd->mem);
}

SourceLocation SourceManager::createExpansionLoc(SourceLocation originalLoc, SourceLocation expansionStart,
                                                 SourceLocation expansionEnd) {
    bufferEntries.emplace_back(ExpansionInfo(originalLoc, expansionStart, expansionEnd));
    return SourceLocation(BufferID::get((uint32_t)(bufferEntries.size() - 1)), 0);
}

SourceBuffer SourceManager::assignText(StringRef text, SourceLocation includedFrom) {
    // Generate a placeholder name for this "file"
    return assignText(StringRef("<unnamed_buffer" + std::to_string(unnamedBufferCount++) + ">"), text, includedFrom);
}

SourceBuffer SourceManager::assignText(StringRef path, StringRef text, SourceLocation includedFrom) {
    SmallVectorSized<char, 2> buffer;
    buffer.appendRange(text);
    if (buffer.empty() || buffer.back() != '\0')
        buffer.append('\0');

    return assignBuffer(path, std::move(buffer), includedFrom);
}

SourceBuffer SourceManager::appendText(BufferID buffer, StringRef text) {
    ASSERT(buffer);
    FileInfo& fi = std::get<FileInfo>(bufferEntries[buffer.id]);
    SourceLocation includeLoc = SourceLocation(buffer, fi.data->mem.count());
    return assignText(text, includeLoc);
}

SourceBuffer SourceManager::assignBuffer(StringRef path, Vector<char>&& buffer, SourceLocation includedFrom) {
    Path fullPath = path;
    std::string canonicalStr = fullPath.str();
    auto it = lookupCache.find(canonicalStr);
    ASSERT(it == lookupCache.end());

    return cacheBuffer(std::move(canonicalStr), fullPath, includedFrom, std::move(buffer));
}

SourceBuffer SourceManager::readSource(StringRef path) {
    ASSERT(path);
    return openCached(path, SourceLocation());
}

SourceBuffer SourceManager::readHeader(StringRef path, SourceLocation includedFrom, bool isSystemPath) {
    // if the header is specified as an absolute path, just do a straight lookup
    ASSERT(path);
    Path p = path;
    if (p.isAbsolute())
        return openCached(p, includedFrom);

    // system path lookups only look in system directories
    if (isSystemPath) {
        for (auto& d : systemDirectories) {
            SourceBuffer result = openCached(d + p, includedFrom);
            if (result.id)
                return result;
        }
        return SourceBuffer();
    }

    // search relative to the current file
    FileData* fd = getFileData(includedFrom.buffer());
    if (fd && fd->directory) {
        SourceBuffer result = openCached((*fd->directory) + p, includedFrom);
        if (result.id)
            return result;
    }

    // search additional include directories
    for (auto& d : userDirectories) {
        SourceBuffer result = openCached(d + p, includedFrom);
        if (result.id)
            return result;
    }

    return SourceBuffer();
}

void SourceManager::addLineDirective(SourceLocation location, uint32_t lineNum,
                                     StringRef name, uint8_t level) {
    SourceLocation fileLocation = getFullyExpandedLoc(location);
    FileData* fd = getFileData(fileLocation.buffer());
    if (!fd)
        return;

    uint32_t sourceLineNum = getRawLineNumber(fileLocation);
    fd->lineDirectives.emplace_back(sourceLineNum, lineNum, name, level);
}

SourceManager::FileData* SourceManager::getFileData(BufferID buffer) const {
    if (!buffer)
        return nullptr;

    ASSERT(buffer.id < bufferEntries.size());
    return std::get<FileInfo>(bufferEntries[buffer.id]).data;
}

SourceBuffer SourceManager::createBufferEntry(FileData* fd, SourceLocation includedFrom) {
    ASSERT(fd);
    bufferEntries.emplace_back(FileInfo(fd, includedFrom));
    return SourceBuffer {
        StringRef(fd->mem),
        BufferID::get((uint32_t)(bufferEntries.size() - 1))
    };
}

SourceBuffer SourceManager::openCached(const Path& fullPath, SourceLocation includedFrom) {
    Path absPath;
    try {
        absPath = Path::makeAbsolute(fullPath);
    }
    catch (std::runtime_error&) {
        return SourceBuffer();
    }

    // first see if we have this file cached
    std::string canonicalStr = absPath.str();
    auto it = lookupCache.find(canonicalStr);
    if (it != lookupCache.end()) {
        FileData* fd = it->second.get();
        if (!fd)
            return SourceBuffer();
        return createBufferEntry(fd, includedFrom);
    }

    // do the read
    Vector<char> buffer;
    if (!readFile(absPath, buffer)) {
        lookupCache.emplace(std::move(canonicalStr), nullptr);
        return SourceBuffer();
    }

    return cacheBuffer(std::move(canonicalStr), absPath, includedFrom, std::move(buffer));
}

SourceBuffer SourceManager::cacheBuffer(std::string&& canonicalPath, const Path& path, SourceLocation includedFrom, Vector<char>&& buffer) {
    std::string name = path.filename();
    auto fd = std::make_unique<FileData>(
        &*directories.insert(path.parentPath()).first,
        name,
        std::move(buffer)
    );

    FileData* fdPtr = lookupCache.emplace(std::move(canonicalPath), std::move(fd)).first->second.get();
    return createBufferEntry(fdPtr, includedFrom);
}

bool SourceManager::readFile(const Path& path, Vector<char>& buffer) {
    size_t size;
    try {
        size = path.fileSize();
    }
    catch (std::runtime_error&) {
        return false;
    }

    // + 1 for null terminator
    buffer.extend((uint32_t)size + 1);
    std::ifstream stream(path.str(), std::ios::binary);
    stream.read(buffer.begin(), size);

    // null-terminate the buffer while we're at it
    buffer.begin()[(uint32_t)size] = '\0';

    return stream.good();
}

void SourceManager::computeLineOffsets(const Vector<char>& buffer, std::vector<uint32_t>& offsets) {
    // first line always starts at offset 0
    offsets.push_back(0);

    const char* ptr = buffer.begin();
    const char* end = buffer.end();
    while (ptr != end) {
        if (ptr[0] == '\n' || ptr[0] == '\r') {
            // if we see \r\n or \n\r skip both chars
            if ((ptr[1] == '\n' || ptr[1] == '\r') && ptr[0] != ptr[1])
                ptr++;
            ptr++;
            offsets.push_back((uint32_t)(ptr - buffer.begin()));
        }
        else {
            ptr++;
        }
    }
}

const SourceManager::FileData::LineDirectiveInfo*
SourceManager::FileData::getPreviousLineDirective(uint32_t rawLineNumber) const {
    auto it = std::lower_bound(lineDirectives.begin(), lineDirectives.end(),
        LineDirectiveInfo(rawLineNumber, 0, "", 0), LineDirectiveComparator());

    if (it != lineDirectives.begin()) {
        // lower_bound will give us an iterator to the first directive after the command
        // let's instead get a pointer to the one right before it
        if (it == lineDirectives.end()) {
            // Check to see whether the actual last directive is before the
            // given line number
            if (lineDirectives.back().lineInFile >= rawLineNumber)
                return nullptr;
        }
        return &*(it - 1);
    }
    else {
        return nullptr;
    }
}

uint32_t SourceManager::getRawLineNumber(SourceLocation location) const {
    FileData* fd = getFileData(location.buffer());
    if (!fd)
        return 0;

    // compute line offsets if we haven't already
    if (fd->lineOffsets.empty())
        computeLineOffsets(fd->mem, fd->lineOffsets);

    // Find the first line offset that is greater than the given location offset. That iterator
    // then tells us how many lines away from the beginning we are.
    auto it = std::lower_bound(fd->lineOffsets.begin(), fd->lineOffsets.end(), location.offset());

    // We want to ensure the line we return is strictly greater than the given location offset.
    // So if it is equal, add one to the lower bound we got
    uint32_t line = uint32_t(it - fd->lineOffsets.begin());
    if (it != fd->lineOffsets.end() && *it == location.offset())
        line++;
    return line;
}

}
<|endoftext|>


<commit_before>//=============================================================================
//
// Adventure Game Studio (AGS)
//
// Copyright (C) 1999-2011 Chris Jones and 2011-20xx others
// The full list of copyright holders can be found in the Copyright.txt
// file, which is part of this source code distribution.
//
// The AGS source code is provided under the Artistic License 2.0.
// A copy of this license can be found in the file License.txt and at
// http://www.opensource.org/licenses/artistic-license-2.0.php
//
//=============================================================================
//
// C-Script run-time interpreter (c) 2001 Chris Jones
//
// You must DISABLE OPTIMIZATIONS AND REGISTER VARIABLES in your compiler
// when compiling this, or strange results can happen.
//
// There is a problem with importing functions on 16-bit compilers: the
// script system assumes that all parameters are passed as 4 bytes, which
// ints are not on 16-bit systems. Be sure to define all parameters as longs,
// or join the 21st century and switch to DJGPP or Visual C++.
//
//=============================================================================

#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include "script/script_runtime.h"
#include "script/script_common.h"
#include "script/cc_error.h"
#include "script/cc_options.h"
#include "ac/dynobj/cc_dynamicarray.h"
#include "ac/dynobj/managedobjectpool.h"
#include "script/systemimports.h"
#include "ac/statobj/staticobject.h"

extern ccInstance *current_instance; // in script/cc_instance

bool ccAddExternalStaticFunction(const char *name, ScriptAPIFunction *pfn)
{
    return simp.add(name, RuntimeScriptValue().SetStaticFunction(pfn), NULL) == 0;
}

bool ccAddExternalPluginFunction(const char *name, void *pfn)
{
    return simp.add(name, RuntimeScriptValue().SetPluginFunction(pfn), NULL) == 0;
}

bool ccAddExternalStaticObject(const char *name, void *ptr, ICCStaticObject *manager)
{
    return simp.add(name, RuntimeScriptValue().SetStaticObject(ptr, manager), NULL) == 0;
}

bool ccAddExternalStaticArray(const char *name, void *ptr, StaticArray *array_mgr)
{
    return simp.add(name, RuntimeScriptValue().SetStaticArray(ptr, array_mgr), NULL) == 0;
}

bool ccAddExternalDynamicObject(const char *name, void *ptr, ICCDynamicObject *manager)
{
    return simp.add(name, RuntimeScriptValue().SetDynamicObject(ptr, manager), NULL) == 0;
}

bool ccAddExternalObjectFunction(const char *name, ScriptAPIObjectFunction *pfn)
{
    return simp.add(name, RuntimeScriptValue().SetObjectFunction(pfn), NULL) == 0;
}

bool ccAddExternalScriptSymbol(const char *name, const RuntimeScriptValue &prval, ccInstance *inst)
{
    return simp.add(name, prval, inst) == 0;
}

void ccRemoveExternalSymbol(const char *namof)
{
    simp.remove(namof);
}

void ccRemoveAllSymbols()
{
    simp.clear();
}

ccInstance *loadedInstances[MAX_LOADED_INSTANCES] = {NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL};

void nullfree(void *data)
{
    if (data != NULL)
        free(data);
}

void *ccGetSymbolAddress(char *namof)
{
    const ScriptImport *import = simp.getByName(namof);
    if (import)
    {
        return import->Value.Ptr;
    }
    return NULL;
}

bool ccAddExternalFunctionForPlugin(const char *name, void *pfn)
{
    return simp_for_plugin.add(name, RuntimeScriptValue().SetPluginFunction(pfn), NULL) == 0;
}

void *ccGetSymbolAddressForPlugin(char *namof)
{
    const ScriptImport *import = simp_for_plugin.getByName(namof);
    if (import)
    {
        return import->Value.Ptr;
    }
    return NULL;
}

new_line_hook_type new_line_hook = NULL;

char ccRunnerCopyright[] = "ScriptExecuter32 v" SCOM_VERSIONSTR " (c) 2001 Chris Jones";
int maxWhileLoops = 0;

// If a while loop does this many iterations without the
// NofityScriptAlive function getting called, the script
// aborts. Set to 0 to disable.
void ccSetScriptAliveTimer (int numloop) {
    maxWhileLoops = numloop;
}

void ccNotifyScriptStillAlive () {
    if (current_instance != NULL)
        current_instance->flags |= INSTF_RUNNING;
}

void ccSetDebugHook(new_line_hook_type jibble)
{
    new_line_hook = jibble;
}

int call_function(intptr_t addr, const RuntimeScriptValue *object, int numparm, const RuntimeScriptValue *parms)
{
    if (!addr)
    {
        cc_error("null function pointer in call_function");
        return -1;
    }
    if (numparm > 0 && !parms)
    {
        cc_error("invalid parameters array in call_function");
        return -1;
    }

    intptr_t parm_value[9];
    if (object)
    {
        parm_value[0] = (intptr_t)object->GetPtrWithOffset();
        numparm++;
    }

    for (int ival = object ? 1 : 0, iparm = 0; ival < numparm; ++ival, ++iparm)
    {
        switch (parms[iparm].Type)
        {
        case kScValInteger:
        case kScValFloat:   // AGS passes floats, copying their values into long variable
        case kScValPluginArg:
            parm_value[ival] = (intptr_t)parms[iparm].IValue;
            break;
            break;
        default:
            parm_value[ival] = (intptr_t)parms[iparm].GetPtrWithOffset();
            break;
        }
    }

    //
    // AN IMPORTANT NOTE ON PARAM TYPE
    // of 2012-11-10
    //
    //// NOTE of 2012-12-20:
    //// Everything said below is applicable only for calling
    //// exported plugin functions.
    //
    // Here we are sending parameters of type intptr_t to registered
    // function of unknown kind. Intptr_t is 32-bit for x32 build and
    // 64-bit for x64 build.
    // The exported functions usually have two types of parameters:
    // pointer and 'int' (32-bit). For x32 build those two have the
    // same size, but for x64 build first has 64-bit size while the
    // second remains 32-bit.
    // In formal case that would cause 'overflow' - function will
    // receive more data than needed (written to stack), with some
    // values shifted further by 32 bits.
    //
    // Upon testing, however, it was revealed that AMD64 processor,
    // the only platform we support x64 Linux AGS build on right now,
    // treats all the function parameters pushed to stack as 64-bit
    // values (few first parameters are sent via registers, and hence
    // are least concern anyway). Therefore, no 'overflow' occurs,
    // and 64-bit values are being effectively truncated to 32-bit
    // integers in the callee.
    //
    // Since this is still quite unreliable, this should be
    // reimplemented when there's enough free time available for
    // developers both for coding & testing.
    //
    // Most basic idea is to pass array of RuntimeScriptValue
    // objects (that hold type description) and get same RSV as a
    // return result. Keep in mind, though, that this solution will
    // require fixing ALL exported functions, so a good amount of
    // time and energy should be allocated for this task.
    //

    switch (numparm)
    {
    case 0:
        {
            int (*fparam) ();
            fparam = (int (*)())addr;
            return fparam();
        }
    case 1:
        {
            int (*fparam) (intptr_t);
            fparam = (int (*)(intptr_t))addr;
            return fparam(parm_value[0]);
        }
    case 2:
        {
            int (*fparam) (intptr_t, intptr_t);
            fparam = (int (*)(intptr_t, intptr_t))addr;
            return fparam(parm_value[0], parm_value[1]);
        }
    case 3:
        {
            int (*fparam) (intptr_t, intptr_t, intptr_t);
            fparam = (int (*)(intptr_t, intptr_t, intptr_t))addr;
            return fparam(parm_value[0], parm_value[1], parm_value[2]);
        }
    case 4:
        {
            int (*fparam) (intptr_t, intptr_t, intptr_t, intptr_t);
            fparam = (int (*)(intptr_t, intptr_t, intptr_t, intptr_t))addr;
            return fparam(parm_value[0], parm_value[1], parm_value[2], parm_value[3]);
        }
    case 5:
        {
            int (*fparam) (intptr_t, intptr_t, intptr_t, intptr_t, intptr_t);
            fparam = (int (*)(intptr_t, intptr_t, intptr_t, intptr_t, intptr_t))addr;
            return fparam(parm_value[0], parm_value[1], parm_value[2], parm_value[3], parm_value[4]);
        }
    case 6:
        {
            int (*fparam) (intptr_t, intptr_t, intptr_t, intptr_t, intptr_t, intptr_t);
            fparam = (int (*)(intptr_t, intptr_t, intptr_t, intptr_t, intptr_t, intptr_t))addr;
            return fparam(parm_value[0], parm_value[1], parm_value[2], parm_value[3], parm_value[4], parm_value[5]);
        }
    case 7:
        {
            int (*fparam) (intptr_t, intptr_t, intptr_t, intptr_t, intptr_t, intptr_t, intptr_t);
            fparam = (int (*)(intptr_t, intptr_t, intptr_t, intptr_t, intptr_t, intptr_t, intptr_t))addr;
            return fparam(parm_value[0], parm_value[1], parm_value[2], parm_value[3], parm_value[4], parm_value[5], parm_value[6]);
        }
    case 8:
        {
            int (*fparam) (intptr_t, intptr_t, intptr_t, intptr_t, intptr_t, intptr_t, intptr_t, intptr_t);
            fparam = (int (*)(intptr_t, intptr_t, intptr_t, intptr_t, intptr_t, intptr_t, intptr_t, intptr_t))addr;
            return fparam(parm_value[0], parm_value[1], parm_value[2], parm_value[3], parm_value[4], parm_value[5], parm_value[6], parm_value[7]);
        }
    case 9:
        {
            int (*fparam) (intptr_t, intptr_t, intptr_t, intptr_t, intptr_t, intptr_t, intptr_t, intptr_t, intptr_t);
            fparam = (int (*)(intptr_t, intptr_t, intptr_t, intptr_t, intptr_t, intptr_t, intptr_t, intptr_t, intptr_t))addr;
            return fparam(parm_value[0], parm_value[1], parm_value[2], parm_value[3], parm_value[4], parm_value[5], parm_value[6], parm_value[7], parm_value[8]);
        }
    }

    cc_error("too many arguments in call to function");
    return -1;
}
<commit_msg>Engine: Fixed non-function symbols not being exported to plugins.<commit_after>//=============================================================================
//
// Adventure Game Studio (AGS)
//
// Copyright (C) 1999-2011 Chris Jones and 2011-20xx others
// The full list of copyright holders can be found in the Copyright.txt
// file, which is part of this source code distribution.
//
// The AGS source code is provided under the Artistic License 2.0.
// A copy of this license can be found in the file License.txt and at
// http://www.opensource.org/licenses/artistic-license-2.0.php
//
//=============================================================================
//
// C-Script run-time interpreter (c) 2001 Chris Jones
//
// You must DISABLE OPTIMIZATIONS AND REGISTER VARIABLES in your compiler
// when compiling this, or strange results can happen.
//
// There is a problem with importing functions on 16-bit compilers: the
// script system assumes that all parameters are passed as 4 bytes, which
// ints are not on 16-bit systems. Be sure to define all parameters as longs,
// or join the 21st century and switch to DJGPP or Visual C++.
//
//=============================================================================

#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include "script/script_runtime.h"
#include "script/script_common.h"
#include "script/cc_error.h"
#include "script/cc_options.h"
#include "ac/dynobj/cc_dynamicarray.h"
#include "ac/dynobj/managedobjectpool.h"
#include "script/systemimports.h"
#include "ac/statobj/staticobject.h"

extern ccInstance *current_instance; // in script/cc_instance

bool ccAddExternalStaticFunction(const char *name, ScriptAPIFunction *pfn)
{
    return simp.add(name, RuntimeScriptValue().SetStaticFunction(pfn), NULL) == 0;
}

bool ccAddExternalPluginFunction(const char *name, void *pfn)
{
    return simp.add(name, RuntimeScriptValue().SetPluginFunction(pfn), NULL) == 0;
}

bool ccAddExternalStaticObject(const char *name, void *ptr, ICCStaticObject *manager)
{
    return simp.add(name, RuntimeScriptValue().SetStaticObject(ptr, manager), NULL) == 0;
}

bool ccAddExternalStaticArray(const char *name, void *ptr, StaticArray *array_mgr)
{
    return simp.add(name, RuntimeScriptValue().SetStaticArray(ptr, array_mgr), NULL) == 0;
}

bool ccAddExternalDynamicObject(const char *name, void *ptr, ICCDynamicObject *manager)
{
    return simp.add(name, RuntimeScriptValue().SetDynamicObject(ptr, manager), NULL) == 0;
}

bool ccAddExternalObjectFunction(const char *name, ScriptAPIObjectFunction *pfn)
{
    return simp.add(name, RuntimeScriptValue().SetObjectFunction(pfn), NULL) == 0;
}

bool ccAddExternalScriptSymbol(const char *name, const RuntimeScriptValue &prval, ccInstance *inst)
{
    return simp.add(name, prval, inst) == 0;
}

void ccRemoveExternalSymbol(const char *namof)
{
    simp.remove(namof);
}

void ccRemoveAllSymbols()
{
    simp.clear();
}

ccInstance *loadedInstances[MAX_LOADED_INSTANCES] = {NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL};

void nullfree(void *data)
{
    if (data != NULL)
        free(data);
}

void *ccGetSymbolAddress(char *namof)
{
    const ScriptImport *import = simp.getByName(namof);
    if (import)
    {
        return import->Value.Ptr;
    }
    return NULL;
}

bool ccAddExternalFunctionForPlugin(const char *name, void *pfn)
{
    return simp_for_plugin.add(name, RuntimeScriptValue().SetPluginFunction(pfn), NULL) == 0;
}

void *ccGetSymbolAddressForPlugin(char *namof)
{
    const ScriptImport *import = simp_for_plugin.getByName(namof);
    if (import)
    {
        return import->Value.Ptr;
    }
    else
    {
        // Also search the internal symbol table for non-function symbols
        import = simp.getByName(namof);
        if (import)
        {
            return import->Value.Ptr;
        }
    }
    return NULL;
}

new_line_hook_type new_line_hook = NULL;

char ccRunnerCopyright[] = "ScriptExecuter32 v" SCOM_VERSIONSTR " (c) 2001 Chris Jones";
int maxWhileLoops = 0;

// If a while loop does this many iterations without the
// NofityScriptAlive function getting called, the script
// aborts. Set to 0 to disable.
void ccSetScriptAliveTimer (int numloop) {
    maxWhileLoops = numloop;
}

void ccNotifyScriptStillAlive () {
    if (current_instance != NULL)
        current_instance->flags |= INSTF_RUNNING;
}

void ccSetDebugHook(new_line_hook_type jibble)
{
    new_line_hook = jibble;
}

int call_function(intptr_t addr, const RuntimeScriptValue *object, int numparm, const RuntimeScriptValue *parms)
{
    if (!addr)
    {
        cc_error("null function pointer in call_function");
        return -1;
    }
    if (numparm > 0 && !parms)
    {
        cc_error("invalid parameters array in call_function");
        return -1;
    }

    intptr_t parm_value[9];
    if (object)
    {
        parm_value[0] = (intptr_t)object->GetPtrWithOffset();
        numparm++;
    }

    for (int ival = object ? 1 : 0, iparm = 0; ival < numparm; ++ival, ++iparm)
    {
        switch (parms[iparm].Type)
        {
        case kScValInteger:
        case kScValFloat:   // AGS passes floats, copying their values into long variable
        case kScValPluginArg:
            parm_value[ival] = (intptr_t)parms[iparm].IValue;
            break;
            break;
        default:
            parm_value[ival] = (intptr_t)parms[iparm].GetPtrWithOffset();
            break;
        }
    }

    //
    // AN IMPORTANT NOTE ON PARAM TYPE
    // of 2012-11-10
    //
    //// NOTE of 2012-12-20:
    //// Everything said below is applicable only for calling
    //// exported plugin functions.
    //
    // Here we are sending parameters of type intptr_t to registered
    // function of unknown kind. Intptr_t is 32-bit for x32 build and
    // 64-bit for x64 build.
    // The exported functions usually have two types of parameters:
    // pointer and 'int' (32-bit). For x32 build those two have the
    // same size, but for x64 build first has 64-bit size while the
    // second remains 32-bit.
    // In formal case that would cause 'overflow' - function will
    // receive more data than needed (written to stack), with some
    // values shifted further by 32 bits.
    //
    // Upon testing, however, it was revealed that AMD64 processor,
    // the only platform we support x64 Linux AGS build on right now,
    // treats all the function parameters pushed to stack as 64-bit
    // values (few first parameters are sent via registers, and hence
    // are least concern anyway). Therefore, no 'overflow' occurs,
    // and 64-bit values are being effectively truncated to 32-bit
    // integers in the callee.
    //
    // Since this is still quite unreliable, this should be
    // reimplemented when there's enough free time available for
    // developers both for coding & testing.
    //
    // Most basic idea is to pass array of RuntimeScriptValue
    // objects (that hold type description) and get same RSV as a
    // return result. Keep in mind, though, that this solution will
    // require fixing ALL exported functions, so a good amount of
    // time and energy should be allocated for this task.
    //

    switch (numparm)
    {
    case 0:
        {
            int (*fparam) ();
            fparam = (int (*)())addr;
            return fparam();
        }
    case 1:
        {
            int (*fparam) (intptr_t);
            fparam = (int (*)(intptr_t))addr;
            return fparam(parm_value[0]);
        }
    case 2:
        {
            int (*fparam) (intptr_t, intptr_t);
            fparam = (int (*)(intptr_t, intptr_t))addr;
            return fparam(parm_value[0], parm_value[1]);
        }
    case 3:
        {
            int (*fparam) (intptr_t, intptr_t, intptr_t);
            fparam = (int (*)(intptr_t, intptr_t, intptr_t))addr;
            return fparam(parm_value[0], parm_value[1], parm_value[2]);
        }
    case 4:
        {
            int (*fparam) (intptr_t, intptr_t, intptr_t, intptr_t);
            fparam = (int (*)(intptr_t, intptr_t, intptr_t, intptr_t))addr;
            return fparam(parm_value[0], parm_value[1], parm_value[2], parm_value[3]);
        }
    case 5:
        {
            int (*fparam) (intptr_t, intptr_t, intptr_t, intptr_t, intptr_t);
            fparam = (int (*)(intptr_t, intptr_t, intptr_t, intptr_t, intptr_t))addr;
            return fparam(parm_value[0], parm_value[1], parm_value[2], parm_value[3], parm_value[4]);
        }
    case 6:
        {
            int (*fparam) (intptr_t, intptr_t, intptr_t, intptr_t, intptr_t, intptr_t);
            fparam = (int (*)(intptr_t, intptr_t, intptr_t, intptr_t, intptr_t, intptr_t))addr;
            return fparam(parm_value[0], parm_value[1], parm_value[2], parm_value[3], parm_value[4], parm_value[5]);
        }
    case 7:
        {
            int (*fparam) (intptr_t, intptr_t, intptr_t, intptr_t, intptr_t, intptr_t, intptr_t);
            fparam = (int (*)(intptr_t, intptr_t, intptr_t, intptr_t, intptr_t, intptr_t, intptr_t))addr;
            return fparam(parm_value[0], parm_value[1], parm_value[2], parm_value[3], parm_value[4], parm_value[5], parm_value[6]);
        }
    case 8:
        {
            int (*fparam) (intptr_t, intptr_t, intptr_t, intptr_t, intptr_t, intptr_t, intptr_t, intptr_t);
            fparam = (int (*)(intptr_t, intptr_t, intptr_t, intptr_t, intptr_t, intptr_t, intptr_t, intptr_t))addr;
            return fparam(parm_value[0], parm_value[1], parm_value[2], parm_value[3], parm_value[4], parm_value[5], parm_value[6], parm_value[7]);
        }
    case 9:
        {
            int (*fparam) (intptr_t, intptr_t, intptr_t, intptr_t, intptr_t, intptr_t, intptr_t, intptr_t, intptr_t);
            fparam = (int (*)(intptr_t, intptr_t, intptr_t, intptr_t, intptr_t, intptr_t, intptr_t, intptr_t, intptr_t))addr;
            return fparam(parm_value[0], parm_value[1], parm_value[2], parm_value[3], parm_value[4], parm_value[5], parm_value[6], parm_value[7], parm_value[8]);
        }
    }

    cc_error("too many arguments in call to function");
    return -1;
}
<|endoftext|>


<commit_before>#include <Internal/CharacterControlManagerImpl.hpp>
#include <Internal/PhysicsModuleImplementation.hpp>
#include <cstdint>
namespace DoremiEngine
{
    namespace Physics
    {
        CharacterControlManagerImpl::CharacterControlManagerImpl(InternalPhysicsUtils& p_utils) : m_utils(p_utils)
        {
            m_manager = PxCreateControllerManager(*m_utils.m_worldScene);
        }
        CharacterControlManagerImpl::~CharacterControlManagerImpl() {}

        int CharacterControlManagerImpl::AddController(int p_id, int p_matID, XMFLOAT3 p_position, XMFLOAT2 p_dimensions)
        {
            // Set start attributes of the controller
            PxCapsuleControllerDesc desc;
            desc.setToDefault();
            desc.position = PxExtendedVec3(p_position.x, p_position.y, p_position.z);
            desc.height = p_dimensions.x;
            desc.radius = p_dimensions.y;
            desc.material = m_utils.m_physicsMaterialManager->GetMaterial(p_matID); // DANGER! Assumes it already has material
            if(desc.material == NULL)
            {
                throw std::runtime_error("No physics material exists with that ID");
            }
            desc.stepOffset = 0.1;
            desc.reportCallback = m_controllerCallback;
            desc.behaviorCallback = this;

            // Hard coded up vector
            desc.upDirection = PxVec3(0, 1, 0);

            m_controllers[p_id] = m_manager->createController(desc);
            m_IDsByControllers[m_controllers[p_id]] = p_id;

            SetCallback(p_id, (1 << 0), (1 << 0));

            // Redundant return?
            return p_id;
        }

        int CharacterControlManagerImpl::MoveController(int p_id, XMFLOAT3 p_discplacement, float p_dt)
        {
            /*
            Some variable that apperas to define when the controller stops moving
            Tweak as necessary. Possibly could be moved to some other place.*/
            float m_minDistTraveled = 0;
            // EMPTY FILTERS!
            PxControllerFilters filters;
            // Check if controller exists
            if(m_controllers.find(p_id) == m_controllers.end())
            {
                // Controller did not exist
                throw std::runtime_error("No controller exists with id: " + p_id);
            }
            m_controllers[p_id]->move(PxVec3(p_discplacement.x, p_discplacement.y, p_discplacement.z), 0, p_dt, filters);
            // Redundant return?
            return p_id;
        }

        XMFLOAT3 CharacterControlManagerImpl::GetPosition(int p_id)
        {
            // Check if controller exists
            if(m_controllers.find(p_id) == m_controllers.end())
            {
                // Controller did not exist
                throw std::runtime_error("No controller exists with id: " + p_id);
            }
            PxExtendedVec3 p = m_controllers[p_id]->getPosition();
            return XMFLOAT3(p.x, p.y, p.z);
        }

        XMFLOAT4 CharacterControlManagerImpl::GetOrientation(int p_id)
        {
            // Check if controller exists
            if(m_controllers.find(p_id) == m_controllers.end())
            {
                // Controller did not exist
                throw std::runtime_error("No controller exists with id: " + p_id);
            }
            PxQuat q = m_controllers[p_id]->getActor()->getGlobalPose().q;
            return XMFLOAT4(q.x, q.y, q.z, q.w);
        }

        void CharacterControlManagerImpl::SetCallback(int p_bodyID, int p_filterGroup, int p_filterMask)
        {
            // Check if controller exists
            if(m_controllers.find(p_bodyID) == m_controllers.end())
            {
                // Controller did not exist
                throw std::runtime_error("No controller exists with id: " + p_bodyID);
            }
            PxFilterData filterData;
            filterData.word0 = p_filterGroup; // Own ID
            filterData.word1 = p_filterMask; // ID mask to filter pairs that trigger contact callback
            PxRigidActor* actor = m_controllers[p_bodyID]->getActor();
            uint32_t numShapes = actor->getNbShapes();
            // Magic allocation of memory (i think)
            PxShape** shapes = (PxShape**)m_utils.m_allocator.allocate(sizeof(PxShape*) * numShapes, 0, __FILE__, __LINE__);
            actor->getShapes(shapes, numShapes);
            for(uint32_t i = 0; i < numShapes; i++)
            {
                PxShape* shape = shapes[i];
                shape->setSimulationFilterData(filterData);
            }
            if(shapes)
            {
                m_utils.m_allocator.deallocate(shapes);
                shapes = NULL;
            }
        }

        void CharacterControlManagerImpl::SetCallbackClass(PxUserControllerHitReport* p_callback) { m_controllerCallback = p_callback; }

        unordered_map<PxController*, int> CharacterControlManagerImpl::GetIdsByControllers() { return m_IDsByControllers; }

        PxControllerBehaviorFlags CharacterControlManagerImpl::getBehaviorFlags(const PxShape& shape, const PxActor& actor)
        {
            return PxControllerBehaviorFlag::eCCT_CAN_RIDE_ON_OBJECT;
        }
        PxControllerBehaviorFlags CharacterControlManagerImpl::getBehaviorFlags(const PxController& controller)
        {
            return PxControllerBehaviorFlags(0);
        }
        PxControllerBehaviorFlags CharacterControlManagerImpl::getBehaviorFlags(const PxObstacle& obstacle) { return PxControllerBehaviorFlags(0); }
    }
}<commit_msg>PhysicsModule: fixed exception throwing<commit_after>#include <Internal/CharacterControlManagerImpl.hpp>
#include <Internal/PhysicsModuleImplementation.hpp>
#include <cstdint>
namespace DoremiEngine
{
    namespace Physics
    {
        CharacterControlManagerImpl::CharacterControlManagerImpl(InternalPhysicsUtils& p_utils) : m_utils(p_utils)
        {
            m_manager = PxCreateControllerManager(*m_utils.m_worldScene);
        }
        CharacterControlManagerImpl::~CharacterControlManagerImpl() {}

        int CharacterControlManagerImpl::AddController(int p_id, int p_matID, XMFLOAT3 p_position, XMFLOAT2 p_dimensions)
        {
            // Set start attributes of the controller
            PxCapsuleControllerDesc desc;
            desc.setToDefault();
            desc.position = PxExtendedVec3(p_position.x, p_position.y, p_position.z);
            desc.height = p_dimensions.x;
            desc.radius = p_dimensions.y;
            desc.material = m_utils.m_physicsMaterialManager->GetMaterial(p_matID); // DANGER! Assumes it already has material
            if(desc.material == NULL)
            {
                throw std::runtime_error("No physics material exists with that ID");
            }
            desc.stepOffset = 0.1;
            desc.reportCallback = m_controllerCallback;
            desc.behaviorCallback = this;

            // Hard coded up vector
            desc.upDirection = PxVec3(0, 1, 0);

            m_controllers[p_id] = m_manager->createController(desc);
            m_IDsByControllers[m_controllers[p_id]] = p_id;

            SetCallback(p_id, (1 << 0), (1 << 0));

            // Redundant return?
            return p_id;
        }

        int CharacterControlManagerImpl::MoveController(int p_id, XMFLOAT3 p_discplacement, float p_dt)
        {
            /*
            Some variable that apperas to define when the controller stops moving
            Tweak as necessary. Possibly could be moved to some other place.*/
            float m_minDistTraveled = 0;
            // EMPTY FILTERS!
            PxControllerFilters filters;
            // Check if controller exists
            if(m_controllers.find(p_id) == m_controllers.end())
            {
                // Controller did not exist
                throw std::runtime_error("No controller exists with id: " + to_string(p_id));
            }
            m_controllers[p_id]->move(PxVec3(p_discplacement.x, p_discplacement.y, p_discplacement.z), 0, p_dt, filters);
            // Redundant return?
            return p_id;
        }

        XMFLOAT3 CharacterControlManagerImpl::GetPosition(int p_id)
        {
            // Check if controller exists
            if(m_controllers.find(p_id) == m_controllers.end())
            {
                // Controller did not exist
                throw std::runtime_error("No controller exists with id: " + to_string(p_id));
            }
            PxExtendedVec3 p = m_controllers[p_id]->getPosition();
            return XMFLOAT3(p.x, p.y, p.z);
        }

        XMFLOAT4 CharacterControlManagerImpl::GetOrientation(int p_id)
        {
            // Check if controller exists
            if(m_controllers.find(p_id) == m_controllers.end())
            {
                // Controller did not exist
                throw std::runtime_error("No controller exists with id: " + to_string(p_id));
            }
            PxQuat q = m_controllers[p_id]->getActor()->getGlobalPose().q;
            return XMFLOAT4(q.x, q.y, q.z, q.w);
        }

        void CharacterControlManagerImpl::SetCallback(int p_bodyID, int p_filterGroup, int p_filterMask)
        {
            // Check if controller exists
            if(m_controllers.find(p_bodyID) == m_controllers.end())
            {
                // Controller did not exist
                throw std::runtime_error("No controller exists with id: " + to_string(p_bodyID));
            }
            PxFilterData filterData;
            filterData.word0 = p_filterGroup; // Own ID
            filterData.word1 = p_filterMask; // ID mask to filter pairs that trigger contact callback
            PxRigidActor* actor = m_controllers[p_bodyID]->getActor();
            uint32_t numShapes = actor->getNbShapes();
            // Magic allocation of memory (i think)
            PxShape** shapes = (PxShape**)m_utils.m_allocator.allocate(sizeof(PxShape*) * numShapes, 0, __FILE__, __LINE__);
            actor->getShapes(shapes, numShapes);
            for(uint32_t i = 0; i < numShapes; i++)
            {
                PxShape* shape = shapes[i];
                shape->setSimulationFilterData(filterData);
            }
            if(shapes)
            {
                m_utils.m_allocator.deallocate(shapes);
                shapes = NULL;
            }
        }

        void CharacterControlManagerImpl::SetCallbackClass(PxUserControllerHitReport* p_callback) { m_controllerCallback = p_callback; }

        unordered_map<PxController*, int> CharacterControlManagerImpl::GetIdsByControllers() { return m_IDsByControllers; }

        PxControllerBehaviorFlags CharacterControlManagerImpl::getBehaviorFlags(const PxShape& shape, const PxActor& actor)
        {
            return PxControllerBehaviorFlag::eCCT_CAN_RIDE_ON_OBJECT;
        }
        PxControllerBehaviorFlags CharacterControlManagerImpl::getBehaviorFlags(const PxController& controller)
        {
            return PxControllerBehaviorFlags(0);
        }
        PxControllerBehaviorFlags CharacterControlManagerImpl::getBehaviorFlags(const PxObstacle& obstacle) { return PxControllerBehaviorFlags(0); }
    }
}<|endoftext|>


<commit_before>/*
 *  coords_view.cpp
 *  PHD Guiding
 *
 *  Created by Oleg Kutkov
 *  Copyright (c) 2017 Crimean Astrophysical observatory
 *  All rights reserved.
 *
 *  This source code is distributed under the following "BSD" license
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *    Redistributions of source code must retain the above copyright notice,
 *     this list of conditions and the following disclaimer.
 *    Redistributions 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.
 *    Neither the name of Bret McKee, Dad Dog Development Ltd, nor the names of its
 *     contributors may 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 COPYRIGHT HOLDER 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.
 *
 *
 */

#include "phd.h"
#include "coords_view.h"

BEGIN_EVENT_TABLE(CoordsView, wxWindow)
    EVT_PAINT(CoordsView::OnPaint)
END_EVENT_TABLE()

CoordsView::CoordsView(wxWindow *parent):
	wxWindow(parent,wxID_ANY,wxDefaultPosition,wxDefaultSize, wxFULL_REPAINT_ON_RESIZE, "Scope position")
{
	SetBackgroundStyle(wxBG_STYLE_PAINT);
	this->visible = false;
}

CoordsView::~CoordsView()
{
}

void CoordsView::UpdateData(double ha, double ra, double dec, double ra_sp, double dec_sp)
{
	curr_ha = ha;
	curr_ra = ra;
	curr_dec = dec;
	curr_ra_sp = ra_sp;
	curr_dec_sp = dec_sp;

    if (this->visible) {
        Refresh();
	}
}

void CoordsView::SetState(bool is_active)
{
    this->visible = is_active;
    if (is_active)
        Refresh();
}

inline double frac(const double& x)
{
     return x - floor(x);
}

inline void degree_to_coord(const double deg, int &h, int &m, int &s)
{
	h = deg / 15;
	m = abs((int)(frac(deg / 15) * 60));
	s = abs((int)(frac(frac(deg / 15) * 60) * 60));
}

void CoordsView::OnPaint(wxPaintEvent& WXUNUSED(evt))
{
	wxAutoBufferedPaintDC dc(this);

	dc.SetBackground(wxColour(0,0,0));

	dc.Clear();

	if (!pFrame || !pFrame->pGuider || pFrame->pGuider->GetState() == STATE_UNINITIALIZED) return;

#if defined (__APPLE__)
    const wxFont& smallFont = *wxSMALL_FONT;
#else
    const wxFont& smallFont = *wxSWISS_FONT;
#endif

	const int ysize = this->GetSize().GetY();

	wxFont largeFont = smallFont.Scaled(1.25);

    dc.SetFont(largeFont);

	dc.SetTextForeground(*wxWHITE);

	dc.DrawText("t: ", 10, 5);
	dc.DrawText(wxString::Format(wxT("%3.2f"), curr_ha), 55, 5);

	dc.DrawText("RA: ", 10, 30);

	int ra_h, ra_m, ra_s;
	degree_to_coord(curr_ra, ra_h, ra_m, ra_s);

	dc.DrawText(wxString::Format(wxT("%02i h  %02i m  %02i s"), ra_h, ra_m, ra_s), 55, 30);

	dc.DrawText("DEC: ", 10, 55);

	int dec_h, dec_m, dec_s;
	degree_to_coord(curr_dec, dec_h, dec_m, dec_s);

	dc.DrawText(wxString::Format(wxT("%02i h  %02i m  %02i s"), dec_h, dec_m, dec_s), 55, 55);

	dc.DrawText("RA SPEED: ", 10, 85);
	dc.DrawText(wxString::Format(wxT("%.2f arcsec/sec"), curr_ra_sp), 105, 85);

	dc.DrawText("DEC SPEED: ", 10, 115);
	dc.DrawText(wxString::Format(wxT("%.2f arcsec/sec"), curr_dec_sp), 105, 115);
}

<commit_msg>text position changed<commit_after>/*
 *  coords_view.cpp
 *  PHD Guiding
 *
 *  Created by Oleg Kutkov
 *  Copyright (c) 2017 Crimean Astrophysical observatory
 *  All rights reserved.
 *
 *  This source code is distributed under the following "BSD" license
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *    Redistributions of source code must retain the above copyright notice,
 *     this list of conditions and the following disclaimer.
 *    Redistributions 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.
 *    Neither the name of Bret McKee, Dad Dog Development Ltd, nor the names of its
 *     contributors may 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 COPYRIGHT HOLDER 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.
 *
 *
 */

#include "phd.h"
#include "coords_view.h"

BEGIN_EVENT_TABLE(CoordsView, wxWindow)
    EVT_PAINT(CoordsView::OnPaint)
END_EVENT_TABLE()

CoordsView::CoordsView(wxWindow *parent):
	wxWindow(parent,wxID_ANY,wxDefaultPosition,wxDefaultSize, wxFULL_REPAINT_ON_RESIZE, "Scope position")
{
	SetBackgroundStyle(wxBG_STYLE_PAINT);
	this->visible = false;
}

CoordsView::~CoordsView()
{
}

void CoordsView::UpdateData(double ha, double ra, double dec, double ra_sp, double dec_sp)
{
	curr_ha = ha;
	curr_ra = ra;
	curr_dec = dec;
	curr_ra_sp = ra_sp;
	curr_dec_sp = dec_sp;

    if (this->visible) {
        Refresh();
	}
}

void CoordsView::SetState(bool is_active)
{
    this->visible = is_active;
    if (is_active)
        Refresh();
}

inline double frac(const double& x)
{
     return x - floor(x);
}

inline void degree_to_coord(const double deg, int &h, int &m, int &s)
{
	h = deg / 15;
	m = abs((int)(frac(deg / 15) * 60));
	s = abs((int)(frac(frac(deg / 15) * 60) * 60));
}

void CoordsView::OnPaint(wxPaintEvent& WXUNUSED(evt))
{
	wxAutoBufferedPaintDC dc(this);

	dc.SetBackground(wxColour(0,0,0));

	dc.Clear();

	if (!pFrame || !pFrame->pGuider || pFrame->pGuider->GetState() == STATE_UNINITIALIZED) return;

#if defined (__APPLE__)
    const wxFont& smallFont = *wxSMALL_FONT;
#else
    const wxFont& smallFont = *wxSWISS_FONT;
#endif

	const int ysize = this->GetSize().GetY();

	wxFont largeFont = smallFont.Scaled(1.25);

    dc.SetFont(largeFont);

	dc.SetTextForeground(*wxWHITE);

	dc.DrawText("t: ", 10, 5);
	dc.DrawText(wxString::Format(wxT("%3.2f"), curr_ha), 55, 5);

	dc.DrawText("RA: ", 10, 30);

	int ra_h, ra_m, ra_s;
	degree_to_coord(curr_ra, ra_h, ra_m, ra_s);

	dc.DrawText(wxString::Format(wxT("%02i h  %02i m  %02i s"), ra_h, ra_m, ra_s), 55, 30);

	dc.DrawText("DEC: ", 10, 55);

	int dec_h, dec_m, dec_s;
	degree_to_coord(curr_dec, dec_h, dec_m, dec_s);

	dc.DrawText(wxString::Format(wxT("%02i h  %02i m  %02i s"), dec_h, dec_m, dec_s), 55, 55);

	dc.DrawText("RA SPEED: ", 10, 85);
	dc.DrawText(wxString::Format(wxT("%.2f arcsec/sec"), curr_ra_sp), 120, 85);

	dc.DrawText("DEC SPEED: ", 10, 115);
	dc.DrawText(wxString::Format(wxT("%.2f arcsec/sec"), curr_dec_sp), 120, 115);
}

<|endoftext|>


<commit_before>#ifdef WIN32
#include <windows.h>
#define CURL_STATICLIB // this has to match the way the curl library was built.
#else
#include <stdlib.h>
#endif

#include <curl/curl.h>
#include <string.h>

#include "safe_fopen.h"

struct Downloaded_Data
{
    char* text;
    int size;
};

static size_t WriteCallback(char *contents, size_t size, size_t nmemb, void *userdata)
{
    Downloaded_Data *downloaded_data = (Downloaded_Data*)userdata;
    size_t data_size = size * nmemb;

    if(downloaded_data->text)
    {
        free(downloaded_data->text);
        downloaded_data->text = NULL;
    }

    if(size == 0) return 0;

    downloaded_data->text = (char*)malloc(data_size + 1);

    if(!downloaded_data->text) return 0;

    downloaded_data->size = data_size;
    memcpy(downloaded_data->text, contents, data_size);
    downloaded_data->text[data_size] = 0;

    return data_size;
}

void print_help()
{
    printf("This utility accepts arguments in the following format:\n");
    printf("config_fetch http://url.to.config.file [path_to_cache_file]\n");
    printf("config_fetch -help");
}

bool print_cached_file(const char *cached_path)
{
    FILE *fp;
    int character;

    fp = safe_fopen_no_create_follow(cached_path, "rb");

    if(!fp)
    {
        printf("Error: Failed to open cache file for reading.\n");
        return false;
    }

    while((character = getc(fp)) != EOF)
    {
        putchar(character);
    }

    fclose(fp);

    return true;
}

int main(int argc, char **argv) {
    CURL *handle = NULL;
    int rval = -1;
    const char *cache_path;
    Downloaded_Data downloaded_data;
    FILE *fp = NULL;
    long http_code;
    int cb = 0;

    downloaded_data.text = NULL;
    downloaded_data.size = 0;

    if(argc < 2 || argc > 3)
    {
        print_help();
        return -1;
    }

    if(strncmp(argv[1], "-h", 2) == 0)
    {
        print_help();
        return 0;
    }

    if(argc == 3)
        cache_path = argv[2];
    else
        cache_path = "config_cache.local";

#ifndef WIN32
	curl_global_init(CURL_GLOBAL_NOTHING);
#endif
    handle = curl_easy_init();

    if(!handle)
    {
        fprintf(stderr, "Error attempting to initialize CURL library.\n");
        return -1;
    }

    curl_easy_setopt(handle, CURLOPT_URL, argv[1]);
    curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, WriteCallback);
    curl_easy_setopt(handle, CURLOPT_WRITEDATA, &downloaded_data);
    curl_easy_setopt(handle, CURLOPT_FOLLOWLOCATION, -1);

    rval = curl_easy_perform(handle);
    if(rval || !downloaded_data.text)
    {
        print_cached_file(cache_path);
        goto Cleanup;
    }

    rval = curl_easy_getinfo(handle, CURLINFO_RESPONSE_CODE, &http_code);
    if(rval)
    {
        print_cached_file(cache_path);
        goto Cleanup;
    }

    if(http_code != 200)
    {
        print_cached_file(cache_path);
        goto Cleanup;
    }

    cb = fwrite(downloaded_data.text, 1, downloaded_data.size, stdout);
    if (cb != downloaded_data.size) {
        fprintf(stderr, "error: could not write entire config to stdout\n");
    }

    fp = safe_fcreate_replace_if_exists(cache_path, "wb");
    if(!fp) goto Cleanup;

    cb = fwrite(downloaded_data.text, 1, downloaded_data.size, fp);
    if (cb != downloaded_data.size) {
        fprintf(stderr, "error: could not write entire config to cache file!\n");
    }

    fclose(fp);

Cleanup:
    if(downloaded_data.text) free(downloaded_data.text);
    curl_easy_cleanup(handle);
    curl_global_cleanup();

	return rval;	// 0 on success
}
<commit_msg>fix config_fetch so that doesn't just write the last buffer to disk/stdout #4018 ===VersionHistory:None== bug never shipped<commit_after>#ifdef WIN32
#include <windows.h>
#define CURL_STATICLIB // this has to match the way the curl library was built.
#else
#include <stdlib.h>
#endif

#include <curl/curl.h>
#include <string.h>
#include <string>

#include "safe_fopen.h"

static size_t WriteCallback(char *contents, size_t size, size_t nmemb, void *userdata)
{
	std::string * ptext = (std::string *)userdata;
	size_t data_size = size * nmemb;
	ptext->append(contents, size * nmemb);
	return data_size;
}

void print_help()
{
    printf("This utility accepts arguments in the following format:\n");
    printf("config_fetch http://url.to.config.file [path_to_cache_file]\n");
    printf("config_fetch -help");
}

bool print_cached_file(const char *cached_path)
{
    FILE *fp;
    int character;

    fp = safe_fopen_no_create_follow(cached_path, "rb");
    if(!fp)
    {
        printf("Error: Failed to open cache file for reading.\n");
        return false;
    }

    while((character = getc(fp)) != EOF)
    {
        putchar(character);
    }

    fclose(fp);

    return true;
}

int main(int argc, char **argv) {
    CURL *handle = NULL;
    int rval = -1;
    const char *cache_path;
    std::string downloaded_data;
    FILE *fp = NULL;
    long http_code;
    int cb = 0;

    if(argc < 2 || argc > 3)
    {
        print_help();
        return -1;
    }

    if(strncmp(argv[1], "-h", 2) == 0)
    {
        print_help();
        return 0;
    }

    if(argc == 3)
        cache_path = argv[2];
    else
        cache_path = "config_cache.local";

#ifndef WIN32
	curl_global_init(CURL_GLOBAL_NOTHING);
#endif
    handle = curl_easy_init();
    if(!handle)
    {
        fprintf(stderr, "Error attempting to initialize CURL library.\n");
        return -1;
    }

    curl_easy_setopt(handle, CURLOPT_URL, argv[1]);
    curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, WriteCallback);
    curl_easy_setopt(handle, CURLOPT_WRITEDATA, &downloaded_data);
    curl_easy_setopt(handle, CURLOPT_FOLLOWLOCATION, -1);

    rval = curl_easy_perform(handle);
    if(rval || downloaded_data.empty())
    {
        print_cached_file(cache_path);
        goto Cleanup;
    }

    rval = curl_easy_getinfo(handle, CURLINFO_RESPONSE_CODE, &http_code);
    if(rval)
    {
        print_cached_file(cache_path);
        goto Cleanup;
    }

    if(http_code != 200)
    {
        print_cached_file(cache_path);
        goto Cleanup;
    }

    cb = fwrite(downloaded_data.c_str(), 1, downloaded_data.size(), stdout);
    if (cb != (int)downloaded_data.size())
    {
        fprintf(stderr, "error: could not write entire config to stdout\n");
    }

    fp = safe_fcreate_replace_if_exists(cache_path, "wb");
    if(!fp) goto Cleanup;

    cb = fwrite(downloaded_data.c_str(), 1, downloaded_data.size(), fp);
    if (cb != (int)downloaded_data.size())
    {
        fprintf(stderr, "error: could not write entire config to cache file!\n");
    }

    fclose(fp);

Cleanup:
    // if(downloaded_data.text) free(downloaded_data.text);
    curl_easy_cleanup(handle);
    curl_global_cleanup();

	return rval;	// 0 on success
}
<|endoftext|>


<commit_before>// This file is part of OpenMVG, an Open Multiple View Geometry C++ library.

// Copyright (c) 2012, 2017 Pierre MOULON.

// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

#include "openMVG/cameras/Camera_Spherical.hpp"
#include "openMVG/features/feature.hpp"
#include "openMVG/features/sift/SIFT_Anatomy_Image_Describer.hpp"
#include "openMVG/features/svg_features.hpp"
#include "openMVG/image/image_io.hpp"
#include "openMVG/image/image_concat.hpp"
#include "openMVG/matching/regions_matcher.hpp"
#include "openMVG/matching/svg_matches.hpp"
#include "openMVG/multiview/conditioning.hpp"
#include "openMVG/multiview/essential.hpp"
#include "openMVG/multiview/triangulation.hpp"
#include "openMVG/multiview/solver_essential_spherical.hpp"
#include "openMVG/robust_estimation/robust_estimator_ACRansac.hpp"
#include "openMVG/robust_estimation/robust_estimator_ACRansacKernelAdaptator.hpp"
#include "openMVG/sfm/pipelines/sfm_robust_model_estimation.hpp"
#include "openMVG/sfm/sfm_data.hpp"
#include "openMVG/sfm/sfm_data_BA_ceres.hpp"
#include "openMVG/sfm/sfm_data_io.hpp"

#include "third_party/cmdLine/cmdLine.h"
#include "third_party/stlplus3/filesystemSimplified/file_system.hpp"

#include <iostream>
#include <string>

using namespace openMVG;
using namespace openMVG::cameras;
using namespace openMVG::geometry;
using namespace openMVG::image;
using namespace openMVG::matching;
using namespace openMVG::robust;
using namespace openMVG::sfm;
using namespace std;

int main(int argc, char **argv) {

  CmdLine cmd;

  string jpg_filenameL, jpg_filenameR;

  cmd.add( make_option('a', jpg_filenameL, "input_a") );
  cmd.add( make_option('b', jpg_filenameR, "input_b") );

  std::cout << "Compute the relative pose between two spherical image."
   << "\nUse an Acontrario robust estimation based on angular errors." << std::endl;

  try
  {
    if (argc == 1)
    {
      const std::string sInputDir = std::string(THIS_SOURCE_DIR);
      jpg_filenameL = sInputDir + "/SponzaLion000.jpg";
      jpg_filenameR = sInputDir + "/SponzaLion001.jpg";
    }
    else
    {
      cmd.process(argc, argv);
    }
  } catch (const std::string& s)
  {
    std::cout << "Invalid usage of arguments -a IMGA -b IMGB" << std::endl;
    return EXIT_FAILURE;
  }

  Image<unsigned char> imageL, imageR;
  ReadImage(jpg_filenameL.c_str(), &imageL);
  ReadImage(jpg_filenameR.c_str(), &imageR);

  // Setup 2 camera intrinsics
  cameras::Intrinsic_Spherical
    cameraL(imageL.Width(), imageL.Height()),
    cameraR(imageR.Width(), imageR.Height());

  //--
  // Detect regions thanks to an image_describer
  //--
  using namespace openMVG::features;
  std::unique_ptr<Image_describer> image_describer
    (new SIFT_Anatomy_Image_describer(SIFT_Anatomy_Image_describer::Params(-1)));
  std::map<IndexT, std::unique_ptr<features::Regions> > regions_perImage;
  image_describer->Describe(imageL, regions_perImage[0]);
  image_describer->Describe(imageR, regions_perImage[1]);

  const SIFT_Regions
   *regionsL = dynamic_cast<const SIFT_Regions*>(regions_perImage.at(0).get()),
   *regionsR = dynamic_cast<const SIFT_Regions*>(regions_perImage.at(1).get());

  const PointFeatures
    featsL = regions_perImage.at(0)->GetRegionsPositions(),
    featsR = regions_perImage.at(1)->GetRegionsPositions();

  std::cout
    << "Left image SIFT count: " << featsL.size() << std::endl
    << "Right image SIFT count: "<< featsR.size() << std::endl;

  // Show both images side by side
  {
    Image<unsigned char> concat;
    ConcatH(imageL, imageR, concat);
    string out_filename = "01_concat.jpg";
    WriteImage(out_filename.c_str(), concat);
  }

  //- Draw features on the two image (side by side)
  {
    Features2SVG
    (
      jpg_filenameL,
      {imageL.Width(), imageL.Height()},
      regionsL->GetRegionsPositions(),
      jpg_filenameR,
      {imageR.Width(), imageR.Height()},
      regionsR->GetRegionsPositions(),
      "02_features.svg"
    );
  }

  std::vector<IndMatch> vec_PutativeMatches;
  //-- Perform matching -> find Nearest neighbor, filtered with Distance ratio
  {
    // Find corresponding points
    matching::DistanceRatioMatch(
      0.8, matching::ANN_L2,
      *regions_perImage.at(0).get(),
      *regions_perImage.at(1).get(),
      vec_PutativeMatches);

    IndMatchDecorator<float> matchDeduplicator(vec_PutativeMatches, featsL, featsR);
    matchDeduplicator.getDeduplicated(vec_PutativeMatches);

    // Draw correspondences after Nearest Neighbor ratio filter
    const bool bVertical = true;
    Matches2SVG
    (
      jpg_filenameL,
      {imageL.Width(), imageL.Height()},
      regionsL->GetRegionsPositions(),
      jpg_filenameR,
      {imageR.Width(), imageR.Height()},
      regionsR->GetRegionsPositions(),
      vec_PutativeMatches,
      "03_Matches.svg",
      bVertical
    );
  }

  // Essential geometry filtering of putative matches
  {
    //A. get back interest point and send it to the robust estimation framework
    Mat
      xL(2, vec_PutativeMatches.size()),
      xR(2, vec_PutativeMatches.size());

    for (size_t k = 0; k < vec_PutativeMatches.size(); ++k)  {
      const PointFeature & imaL = featsL[vec_PutativeMatches[k].i_];
      const PointFeature & imaR = featsR[vec_PutativeMatches[k].j_];
      xL.col(k) = imaL.coords().cast<double>();
      xR.col(k) = imaR.coords().cast<double>();
    }

    //-- Convert planar to spherical coordinates
    Mat xL_spherical(3,vec_PutativeMatches.size()), xR_spherical(3,vec_PutativeMatches.size());
    for (size_t iCol = 0; iCol < vec_PutativeMatches.size(); ++iCol)
    {
      xL_spherical.col(iCol) = cameraL(xL.col(iCol));
      xR_spherical.col(iCol) = cameraR(xR.col(iCol));
    }

    //-- Essential matrix robust estimation from spherical bearing vectors
    {
      std::vector<uint32_t> vec_inliers;

      // Define the AContrario angular error adaptor
      using KernelType =
        openMVG::robust::ACKernelAdaptor_AngularRadianError<
          // Use the 8 point solver in order to estimate E
          openMVG::spherical_cam::EightPointRelativePoseSolver,
          openMVG::spherical_cam::AngularError,
          Mat3>;

      KernelType kernel(xL_spherical, xR_spherical);

      // Robust estimation of the Essential matrix and it's precision
      Mat3 E;
      const double precision = std::numeric_limits<double>::infinity();
      const std::pair<double,double> ACRansacOut =
        ACRANSAC(kernel, vec_inliers, 1024, &E, precision, true);
      const double & threshold = ACRansacOut.first;

      std::cout << "\n Angular threshold found: " << R2D(threshold) << "(Degree)"<<std::endl;
      std::cout << "\n #Putatives/#inliers : " << xL_spherical.cols() << "/" << vec_inliers.size() << "\n" << std::endl;

      const bool bVertical = true;
      InlierMatches2SVG
      (
        jpg_filenameL,
        {imageL.Width(), imageL.Height()},
        regionsL->GetRegionsPositions(),
        jpg_filenameR,
        {imageR.Width(), imageR.Height()},
        regionsR->GetRegionsPositions(),
        vec_PutativeMatches,
        vec_inliers,
        "04_inliers.svg",
        bVertical
      );

      if (vec_inliers.size() > 60) // 60 is used to filter solution with few common geometric matches (unstable solution)
      {
        // Decompose the essential matrix and keep the best solution (if any)
        Mat3 R;
        Vec3 t;
        std::vector<uint32_t> inliers_indexes;
        std::vector<Vec3> inliers_X;
        if (openMVG::sfm::estimate_Rt_fromE(xL_spherical, xR_spherical, E, vec_inliers,
                                            &R, &t, &inliers_indexes, &inliers_X))
        {
          // Lets make a BA on the scene to check if it relative pose and structure can be refined

          // Setup a SfM scene with two view corresponding the pictures
          SfM_Data tiny_scene;
          tiny_scene.views[0].reset(new View("", 0, 0, 0, imageL.Width(), imageL.Height()));
          tiny_scene.views[1].reset(new View("", 1, 0, 1, imageR.Width(), imageR.Height()));
          // Setup shared intrinsics camera data
          tiny_scene.intrinsics[0].reset(new Intrinsic_Spherical(imageR.Width(), imageR.Height()));

          // Setup poses camera data
          const Pose3 pose0 = tiny_scene.poses[tiny_scene.views[0]->id_pose] = Pose3(Mat3::Identity(), Vec3::Zero());
          const Pose3 pose1 = tiny_scene.poses[tiny_scene.views[1]->id_pose] = Pose3(R, - R.transpose() * t);

          // Add a new landmark (3D point with its image observations)
          for (int i = 0; i < inliers_indexes.size(); ++i)
          {
            Landmark landmark;
            landmark.X = inliers_X[i];
            landmark.obs[tiny_scene.views[0]->id_view] = Observation(xL.col(inliers_indexes[i]), 0);
            landmark.obs[tiny_scene.views[1]->id_view] = Observation(xR.col(inliers_indexes[i]), 0);
            tiny_scene.structure.insert(std::make_pair(tiny_scene.structure.size(), landmark));
          }

          Save(tiny_scene, "EssentialGeometry_start.ply", ESfM_Data(ALL));

          std::vector<double> residuals;
          // Perform Bundle Adjustment of the scene
          Bundle_Adjustment_Ceres bundle_adjustment_obj;
          if (bundle_adjustment_obj.Adjust(tiny_scene,
            Optimize_Options(
              Intrinsic_Parameter_Type::NONE,
              Extrinsic_Parameter_Type::ADJUST_ALL,
              Structure_Parameter_Type::ADJUST_ALL)))
          {
            // Compute reprojection error
            const Pose3 pose0 = tiny_scene.poses[tiny_scene.views[0]->id_pose];
            const Pose3 pose1 = tiny_scene.poses[tiny_scene.views[1]->id_pose];

            for (Landmarks::const_iterator iter = tiny_scene.GetLandmarks().begin();
              iter != tiny_scene.GetLandmarks().end(); ++iter)
            {
              const IndexT trackId = iter->first;
              const Landmark & landmark = iter->second;
              const Observations & obs = landmark.obs;
              Observations::const_iterator iterObs_xI = obs.find(tiny_scene.views[0]->id_view);
              Observations::const_iterator iterObs_xJ = obs.find(tiny_scene.views[1]->id_view);

              const Observation & ob_x0 = iterObs_xI->second;
              const Observation & ob_x1 = iterObs_xJ->second;

              const Vec2 residual_I = cameraL.residual(pose0, landmark.X, ob_x0.x);
              const Vec2 residual_J = cameraR.residual(pose1, landmark.X, ob_x1.x);
              residuals.push_back(residual_I.norm());
              residuals.push_back(residual_J.norm());
            }
            std::cout << "Residual statistics (pixels):" << std::endl;
            minMaxMeanMedian<double>( residuals.begin(), residuals.end());

            Save(tiny_scene, "EssentialGeometry_refined.ply", ESfM_Data(ALL));
          }
        }
      }
    }
  }
  return EXIT_SUCCESS;
}
<commit_msg>Enhance reproducibility.<commit_after>// This file is part of OpenMVG, an Open Multiple View Geometry C++ library.

// Copyright (c) 2012, 2017 Pierre MOULON.

// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

#include "openMVG/cameras/Camera_Spherical.hpp"
#include "openMVG/features/feature.hpp"
#include "openMVG/features/sift/SIFT_Anatomy_Image_Describer.hpp"
#include "openMVG/features/svg_features.hpp"
#include "openMVG/image/image_io.hpp"
#include "openMVG/image/image_concat.hpp"
#include "openMVG/matching/regions_matcher.hpp"
#include "openMVG/matching/svg_matches.hpp"
#include "openMVG/multiview/conditioning.hpp"
#include "openMVG/multiview/essential.hpp"
#include "openMVG/multiview/triangulation.hpp"
#include "openMVG/multiview/solver_essential_spherical.hpp"
#include "openMVG/robust_estimation/robust_estimator_ACRansac.hpp"
#include "openMVG/robust_estimation/robust_estimator_ACRansacKernelAdaptator.hpp"
#include "openMVG/sfm/pipelines/sfm_robust_model_estimation.hpp"
#include "openMVG/sfm/sfm_data.hpp"
#include "openMVG/sfm/sfm_data_BA_ceres.hpp"
#include "openMVG/sfm/sfm_data_io.hpp"

#include "third_party/cmdLine/cmdLine.h"
#include "third_party/stlplus3/filesystemSimplified/file_system.hpp"

#include <iostream>
#include <string>

using namespace openMVG;
using namespace openMVG::cameras;
using namespace openMVG::geometry;
using namespace openMVG::image;
using namespace openMVG::matching;
using namespace openMVG::robust;
using namespace openMVG::sfm;
using namespace std;

int main(int argc, char **argv) {

  CmdLine cmd;

  string jpg_filenameL, jpg_filenameR;

  cmd.add( make_option('a', jpg_filenameL, "input_a") );
  cmd.add( make_option('b', jpg_filenameR, "input_b") );

  std::cout << "Compute the relative pose between two spherical image."
   << "\nUse an Acontrario robust estimation based on angular errors." << std::endl;

  try
  {
    if (argc == 1)
    {
      const std::string sInputDir = std::string(THIS_SOURCE_DIR);
      jpg_filenameL = sInputDir + "/SponzaLion000.jpg";
      jpg_filenameR = sInputDir + "/SponzaLion001.jpg";
    }
    else
    {
      cmd.process(argc, argv);
    }
  } catch (const std::string& s)
  {
    std::cout << "Invalid usage of arguments -a IMGA -b IMGB" << std::endl;
    return EXIT_FAILURE;
  }

  Image<unsigned char> imageL, imageR;
  ReadImage(jpg_filenameL.c_str(), &imageL);
  ReadImage(jpg_filenameR.c_str(), &imageR);

  // Setup 2 camera intrinsics
  cameras::Intrinsic_Spherical
    cameraL(imageL.Width(), imageL.Height()),
    cameraR(imageR.Width(), imageR.Height());

  //--
  // Detect regions thanks to an image_describer
  //--
  using namespace openMVG::features;
  std::unique_ptr<Image_describer> image_describer
    (new SIFT_Anatomy_Image_describer(SIFT_Anatomy_Image_describer::Params(-1)));
  std::map<IndexT, std::unique_ptr<features::Regions> > regions_perImage;
  image_describer->Describe(imageL, regions_perImage[0]);
  image_describer->Describe(imageR, regions_perImage[1]);

  const SIFT_Regions
   *regionsL = dynamic_cast<const SIFT_Regions*>(regions_perImage.at(0).get()),
   *regionsR = dynamic_cast<const SIFT_Regions*>(regions_perImage.at(1).get());

  const PointFeatures
    featsL = regions_perImage.at(0)->GetRegionsPositions(),
    featsR = regions_perImage.at(1)->GetRegionsPositions();

  std::cout
    << "Left image SIFT count: " << featsL.size() << std::endl
    << "Right image SIFT count: "<< featsR.size() << std::endl;

  // Show both images side by side
  {
    Image<unsigned char> concat;
    ConcatH(imageL, imageR, concat);
    string out_filename = "01_concat.jpg";
    WriteImage(out_filename.c_str(), concat);
  }

  //- Draw features on the two image (side by side)
  {
    Features2SVG
    (
      jpg_filenameL,
      {imageL.Width(), imageL.Height()},
      regionsL->GetRegionsPositions(),
      jpg_filenameR,
      {imageR.Width(), imageR.Height()},
      regionsR->GetRegionsPositions(),
      "02_features.svg"
    );
  }

  std::vector<IndMatch> vec_PutativeMatches;
  //-- Perform matching -> find Nearest neighbor, filtered with Distance ratio
  {
    // Find corresponding points
    matching::DistanceRatioMatch(
      0.8, matching::BRUTE_FORCE_L2,
      *regions_perImage.at(0).get(),
      *regions_perImage.at(1).get(),
      vec_PutativeMatches);

    IndMatchDecorator<float> matchDeduplicator(vec_PutativeMatches, featsL, featsR);
    matchDeduplicator.getDeduplicated(vec_PutativeMatches);

    // Draw correspondences after Nearest Neighbor ratio filter
    const bool bVertical = true;
    Matches2SVG
    (
      jpg_filenameL,
      {imageL.Width(), imageL.Height()},
      regionsL->GetRegionsPositions(),
      jpg_filenameR,
      {imageR.Width(), imageR.Height()},
      regionsR->GetRegionsPositions(),
      vec_PutativeMatches,
      "03_Matches.svg",
      bVertical
    );
  }

  // Essential geometry filtering of putative matches
  {
    //A. get back interest point and send it to the robust estimation framework
    Mat
      xL(2, vec_PutativeMatches.size()),
      xR(2, vec_PutativeMatches.size());

    for (size_t k = 0; k < vec_PutativeMatches.size(); ++k)  {
      const PointFeature & imaL = featsL[vec_PutativeMatches[k].i_];
      const PointFeature & imaR = featsR[vec_PutativeMatches[k].j_];
      xL.col(k) = imaL.coords().cast<double>();
      xR.col(k) = imaR.coords().cast<double>();
    }

    //-- Convert planar to spherical coordinates
    Mat xL_spherical(3,vec_PutativeMatches.size()), xR_spherical(3,vec_PutativeMatches.size());
    for (size_t iCol = 0; iCol < vec_PutativeMatches.size(); ++iCol)
    {
      xL_spherical.col(iCol) = cameraL(xL.col(iCol));
      xR_spherical.col(iCol) = cameraR(xR.col(iCol));
    }

    //-- Essential matrix robust estimation from spherical bearing vectors
    {
      std::vector<uint32_t> vec_inliers;

      // Define the AContrario angular error adaptor
      using KernelType =
        openMVG::robust::ACKernelAdaptor_AngularRadianError<
          // Use the 8 point solver in order to estimate E
          openMVG::spherical_cam::EightPointRelativePoseSolver,
          openMVG::spherical_cam::AngularError,
          Mat3>;

      KernelType kernel(xL_spherical, xR_spherical);

      // Robust estimation of the Essential matrix and it's precision
      Mat3 E;
      const double precision = std::numeric_limits<double>::infinity();
      const std::pair<double,double> ACRansacOut =
        ACRANSAC(kernel, vec_inliers, 1024, &E, precision, true);
      const double & threshold = ACRansacOut.first;

      std::cout << "\n Angular threshold found: " << R2D(threshold) << "(Degree)"<<std::endl;
      std::cout << "\n #Putatives/#inliers : " << xL_spherical.cols() << "/" << vec_inliers.size() << "\n" << std::endl;

      const bool bVertical = true;
      InlierMatches2SVG
      (
        jpg_filenameL,
        {imageL.Width(), imageL.Height()},
        regionsL->GetRegionsPositions(),
        jpg_filenameR,
        {imageR.Width(), imageR.Height()},
        regionsR->GetRegionsPositions(),
        vec_PutativeMatches,
        vec_inliers,
        "04_inliers.svg",
        bVertical
      );

      if (vec_inliers.size() > 60) // 60 is used to filter solution with few common geometric matches (unstable solution)
      {
        // Decompose the essential matrix and keep the best solution (if any)
        Mat3 R;
        Vec3 t;
        std::vector<uint32_t> inliers_indexes;
        std::vector<Vec3> inliers_X;
        if (openMVG::sfm::estimate_Rt_fromE(xL_spherical, xR_spherical, E, vec_inliers,
                                            &R, &t, &inliers_indexes, &inliers_X))
        {
          // Lets make a BA on the scene to check if it relative pose and structure can be refined

          // Setup a SfM scene with two view corresponding the pictures
          SfM_Data tiny_scene;
          tiny_scene.views[0].reset(new View("", 0, 0, 0, imageL.Width(), imageL.Height()));
          tiny_scene.views[1].reset(new View("", 1, 0, 1, imageR.Width(), imageR.Height()));
          // Setup shared intrinsics camera data
          tiny_scene.intrinsics[0].reset(new Intrinsic_Spherical(imageR.Width(), imageR.Height()));

          // Setup poses camera data
          const Pose3 pose0 = tiny_scene.poses[tiny_scene.views[0]->id_pose] = Pose3(Mat3::Identity(), Vec3::Zero());
          const Pose3 pose1 = tiny_scene.poses[tiny_scene.views[1]->id_pose] = Pose3(R, - R.transpose() * t);

          // Add a new landmark (3D point with its image observations)
          for (int i = 0; i < inliers_indexes.size(); ++i)
          {
            Landmark landmark;
            landmark.X = inliers_X[i];
            landmark.obs[tiny_scene.views[0]->id_view] = Observation(xL.col(inliers_indexes[i]), 0);
            landmark.obs[tiny_scene.views[1]->id_view] = Observation(xR.col(inliers_indexes[i]), 0);
            tiny_scene.structure.insert(std::make_pair(tiny_scene.structure.size(), landmark));
          }

          Save(tiny_scene, "EssentialGeometry_start.ply", ESfM_Data(ALL));

          std::vector<double> residuals;
          // Perform Bundle Adjustment of the scene
          Bundle_Adjustment_Ceres bundle_adjustment_obj;
          if (bundle_adjustment_obj.Adjust(tiny_scene,
            Optimize_Options(
              Intrinsic_Parameter_Type::NONE,
              Extrinsic_Parameter_Type::ADJUST_ALL,
              Structure_Parameter_Type::ADJUST_ALL)))
          {
            // Compute reprojection error
            const Pose3 pose0 = tiny_scene.poses[tiny_scene.views[0]->id_pose];
            const Pose3 pose1 = tiny_scene.poses[tiny_scene.views[1]->id_pose];

            for (Landmarks::const_iterator iter = tiny_scene.GetLandmarks().begin();
              iter != tiny_scene.GetLandmarks().end(); ++iter)
            {
              const IndexT trackId = iter->first;
              const Landmark & landmark = iter->second;
              const Observations & obs = landmark.obs;
              Observations::const_iterator iterObs_xI = obs.find(tiny_scene.views[0]->id_view);
              Observations::const_iterator iterObs_xJ = obs.find(tiny_scene.views[1]->id_view);

              const Observation & ob_x0 = iterObs_xI->second;
              const Observation & ob_x1 = iterObs_xJ->second;

              const Vec2 residual_I = cameraL.residual(pose0, landmark.X, ob_x0.x);
              const Vec2 residual_J = cameraR.residual(pose1, landmark.X, ob_x1.x);
              residuals.push_back(residual_I.norm());
              residuals.push_back(residual_J.norm());
            }
            std::cout << "Residual statistics (pixels):" << std::endl;
            minMaxMeanMedian<double>( residuals.begin(), residuals.end());

            Save(tiny_scene, "EssentialGeometry_refined.ply", ESfM_Data(ALL));
          }
        }
      }
    }
  }
  return EXIT_SUCCESS;
}
<|endoftext|>