<commit_before>/*
 * Copyright 2014 Milian Wolff <mail@milianw.de>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Library General Public License as
 * published by the Free Software Foundation; either version 2 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public
 * License along with this program; if not, write to the
 * Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 */

/**
 * @file heaptrack_interpret.cpp
 *
 * @brief Interpret raw heaptrack data and add Dwarf based debug information.
 */

#include <iostream>
#include <sstream>
#include <unordered_map>
#include <vector>
#include <tuple>
#include <algorithm>

#include <cxxabi.h>
#include <boost/algorithm/string/predicate.hpp>

#include "libbacktrace/backtrace.h"
#include "linereader.h"

using namespace std;

namespace {

string demangle(const char* function)
{
    if (!function) {
        return {};
    } else if (function[0] != '_' || function[1] != 'Z') {
        return {function};
    }

    string ret;
    int status = 0;
    char* demangled = abi::__cxa_demangle(function, 0, 0, &status);
    if (demangled) {
        ret = demangled;
        free(demangled);
    }
    return ret;
}

struct AddressInformation
{
    string function;
    string file;
    int line = 0;
};

struct Module
{
    Module(string _fileName, uintptr_t addressStart, uintptr_t addressEnd, backtrace_state* backtraceState)
        : fileName(move(_fileName))
        , addressStart(addressStart)
        , addressEnd(addressEnd)
        , backtraceState(backtraceState)
    {
    }

    AddressInformation resolveAddress(uintptr_t address) const
    {
        AddressInformation info;
        if (!backtraceState) {
            return info;
        }

        backtrace_pcinfo(backtraceState, address,
                         [] (void *data, uintptr_t /*addr*/, const char *file, int line, const char *function) -> int {
                            auto info = reinterpret_cast<AddressInformation*>(data);
                            info->function = demangle(function);
                            info->file = file ? file : "";
                            info->line = line;
                            return 0;
                         }, &emptyErrorCallback, &info);

        if (info.function.empty()) {
            backtrace_syminfo(backtraceState, address,
                              [] (void *data, uintptr_t /*pc*/, const char *symname, uintptr_t /*symval*/, uintptr_t /*symsize*/) {
                                if (symname) {
                                    reinterpret_cast<AddressInformation*>(data)->function = demangle(symname);
                                }
                              }, &errorCallback, &info);
        }

        return info;
    }

    static void errorCallback(void */*data*/, const char *msg, int errnum)
    {
        cerr << "Module backtrace error (code " << errnum << "): " << msg << endl;
    }

    static void emptyErrorCallback(void */*data*/, const char */*msg*/, int /*errnum*/)
    {
    }

    bool operator<(const Module& module) const
    {
        return make_tuple(addressStart, addressEnd, fileName)
             < make_tuple(module.addressStart, module.addressEnd, module.fileName);
    }

    bool operator!=(const Module& module) const
    {
        return make_tuple(addressStart, addressEnd, fileName)
            != make_tuple(module.addressStart, module.addressEnd, module.fileName);
    }

    backtrace_state* backtraceState;
    string fileName;
    uintptr_t addressStart;
    uintptr_t addressEnd;
};

struct Allocation
{
    // backtrace entry point
    size_t ipIndex;
    // number of allocations
    size_t allocations;
    // amount of bytes leaked
    size_t leaked;
};

/**
 * Information for a single call to an allocation function
 */
struct AllocationInfo
{
    size_t ipIndex;
    size_t size;
};

struct ResolvedIP
{
    size_t moduleIndex = 0;
    size_t fileIndex = 0;
    size_t functionIndex = 0;
    int line = 0;
};

struct AccumulatedTraceData
{
    AccumulatedTraceData()
    {
        m_modules.reserve(256);
        m_backtraceStates.reserve(64);
        m_internedData.reserve(4096);
        m_encounteredIps.reserve(32768);
    }

    ~AccumulatedTraceData()
    {
        cout << dec;
        cout << "# strings: " << m_internedData.size() << '\n';
        cout << "# ips: " << m_encounteredIps.size() << '\n';
    }

    ResolvedIP resolve(const uintptr_t ip)
    {
        if (m_modulesDirty) {
            // sort by addresses, required for binary search below
            sort(m_modules.begin(), m_modules.end());

            for (size_t i = 0; i < m_modules.size(); ++i) {
                const auto& m1 = m_modules[i];
                for (size_t j = i + 1; j < m_modules.size(); ++j) {
                    if (i == j) {
                        continue;
                    }
                    const auto& m2 = m_modules[j];
                    if ((m1.addressStart <= m2.addressStart && m1.addressEnd > m2.addressStart) ||
                        (m1.addressStart < m2.addressEnd && m1.addressEnd >= m2.addressEnd))
                    {
                        cerr << "OVERLAPPING MODULES: " << hex
                             << m1.fileName << " (" << m1.addressStart << " to " << m1.addressEnd << ") and "
                             << m2.fileName << " (" << m2.addressStart << " to " << m2.addressEnd << ")\n"
                             << dec;
                    } else if (m2.addressStart >= m1.addressEnd) {
                        break;
                    }
                }
            }

            m_modulesDirty = false;
        }

        ResolvedIP data;
        // find module for this instruction pointer
        auto module = lower_bound(m_modules.begin(), m_modules.end(), ip,
                                    [] (const Module& module, const uintptr_t ip) -> bool {
                                        return module.addressEnd < ip;
                                    });
        if (module != m_modules.end() && module->addressStart <= ip && module->addressEnd >= ip) {
            data.moduleIndex = intern(module->fileName);
            const auto info = module->resolveAddress(ip);
            data.fileIndex = intern(info.file);
            data.functionIndex = intern(info.function);
            data.line = info.line;
        }
        return data;
    }

    size_t intern(const string& str)
    {
        if (str.empty()) {
            return 0;
        }

        auto it = m_internedData.find(str);
        if (it != m_internedData.end()) {
            return it->second;
        }
        const size_t id = m_internedData.size() + 1;
        m_internedData.insert(it, make_pair(str, id));
        cout << "s " << str << '\n';
        return id;
    }

    void addModule(const string& fileName, const bool isExe, const uintptr_t addressStart, const uintptr_t addressEnd)
    {
        backtrace_state* backtraceState = findBacktraceState(fileName, addressStart, isExe);

        m_modules.emplace_back(fileName, addressStart, addressEnd, backtraceState);
        m_modulesDirty = true;
    }

    void clearModules()
    {
        // TODO: optimize this, reuse modules that are still valid
        m_modules.clear();
        m_modulesDirty = true;
    }

    size_t addIp(const uintptr_t instructionPointer)
    {
        if (!instructionPointer) {
            return 0;
        }

        auto it = m_encounteredIps.find(instructionPointer);
        if (it != m_encounteredIps.end()) {
            return it->second;
        }

        const size_t ipId = m_encounteredIps.size() + 1;
        m_encounteredIps.insert(it, make_pair(instructionPointer, ipId));

        const auto ip = resolve(instructionPointer);
        cout << "i " << instructionPointer << ' ' << ip.moduleIndex;
        if (ip.functionIndex || ip.fileIndex) {
            cout << ' ' << ip.functionIndex;
            if (ip.fileIndex) {
                cout << ' ' << ip.fileIndex << ' ' << ip.line;
            }
        }
        cout << '\n';
        return ipId;
    }

private:
    /**
     * Prevent the same file from being initialized multiple times.
     * This drastically cuts the memory consumption down
     */
    backtrace_state* findBacktraceState(const string& fileName, uintptr_t addressStart, bool isExe)
    {
        if (boost::algorithm::starts_with(fileName, "linux-vdso.so")) {
            // prevent warning, since this will always fail
            return nullptr;
        }

        auto it = m_backtraceStates.find(fileName);
        if (it != m_backtraceStates.end()) {
            return it->second;
        }
        auto state = backtrace_create_state(fileName.c_str(), /* we are single threaded, so: not thread safe */ false,
                                            [] (void *data, const char *msg, int errnum) {
                                                const Module* module = reinterpret_cast<Module*>(data);
                                                cerr << "Failed to create backtrace state for file " << module->fileName
                                                        << ": " << msg << " (error code " << errnum << ")" << endl;
                                            }, this);

        if (state) {
            // when we could initialize the backtrace state, we initialize it with the first address
            // we get since that is the lowest one
            backtrace_fileline_initialize(state, addressStart, isExe,
                                        [] (void *data, const char *msg, int errnum) {
                                            const Module* module = reinterpret_cast<Module*>(data);
                                            cerr << "Failed to initialize backtrace fileline for module "
                                                 << module->fileName
                                                 << ": " << msg << " (error code " << errnum << ")" << endl;
                                        }, this);
        }

        m_backtraceStates.insert(it, make_pair(fileName, state));

        return state;
    }

    vector<Module> m_modules;
    unordered_map<string, backtrace_state*> m_backtraceStates;
    bool m_modulesDirty = false;

    unordered_map<string, size_t> m_internedData;
    unordered_map<uintptr_t, size_t> m_encounteredIps;
};

}

int main(int /*argc*/, char** /*argv*/)
{
    // optimize: we only have a single thread
    ios_base::sync_with_stdio(false);

    AccumulatedTraceData data;

    LineReader reader;
    cin >> hex;
    cout << hex;

    while (reader.getLine(cin)) {
        if (reader.mode() == 'm') {
            string fileName;
            reader >> fileName;
            if (fileName == "-") {
                data.clearModules();
            } else {
                bool isExe = false;
                uintptr_t addressStart = 0;
                uintptr_t addressEnd = 0;
                if (!(reader >> isExe) || !(reader >> addressStart) || !(reader >> addressEnd)) {
                    cerr << "failed to parse line: " << reader.line() << endl;
                    return 1;
                }
                data.addModule(fileName, isExe, addressStart, addressEnd);
            }
        } else if (reader.mode() == 't') {
            uintptr_t instructionPointer = 0;
            size_t parentIndex = 0;
            if (!(reader >> instructionPointer) || !(reader >> parentIndex)) {
                cerr << "failed to parse line: " << reader.line() << endl;
                return 1;
            }
            // ensure ip is encountered
            const auto ipId = data.addIp(instructionPointer);
            // trace point, map current output index to parent index
            cout << "t " << ipId << ' ' << parentIndex << '\n';
        } else {
            cout << reader.line() << '\n';
        }
    }

    return 0;
}
<commit_msg>Fixup callback handlers, the wrong data was passed in.<commit_after>/*
 * Copyright 2014 Milian Wolff <mail@milianw.de>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Library General Public License as
 * published by the Free Software Foundation; either version 2 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public
 * License along with this program; if not, write to the
 * Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 */

/**
 * @file heaptrack_interpret.cpp
 *
 * @brief Interpret raw heaptrack data and add Dwarf based debug information.
 */

#include <iostream>
#include <sstream>
#include <unordered_map>
#include <vector>
#include <tuple>
#include <algorithm>

#include <cxxabi.h>
#include <boost/algorithm/string/predicate.hpp>

#include "libbacktrace/backtrace.h"
#include "linereader.h"

using namespace std;

namespace {

string demangle(const char* function)
{
    if (!function) {
        return {};
    } else if (function[0] != '_' || function[1] != 'Z') {
        return {function};
    }

    string ret;
    int status = 0;
    char* demangled = abi::__cxa_demangle(function, 0, 0, &status);
    if (demangled) {
        ret = demangled;
        free(demangled);
    }
    return ret;
}

struct AddressInformation
{
    string function;
    string file;
    int line = 0;
};

struct Module
{
    Module(string _fileName, uintptr_t addressStart, uintptr_t addressEnd, backtrace_state* backtraceState)
        : fileName(move(_fileName))
        , addressStart(addressStart)
        , addressEnd(addressEnd)
        , backtraceState(backtraceState)
    {
    }

    AddressInformation resolveAddress(uintptr_t address) const
    {
        AddressInformation info;
        if (!backtraceState) {
            return info;
        }

        backtrace_pcinfo(backtraceState, address,
                         [] (void *data, uintptr_t /*addr*/, const char *file, int line, const char *function) -> int {
                            auto info = reinterpret_cast<AddressInformation*>(data);
                            info->function = demangle(function);
                            info->file = file ? file : "";
                            info->line = line;
                            return 0;
                         }, &emptyErrorCallback, &info);

        if (info.function.empty()) {
            backtrace_syminfo(backtraceState, address,
                              [] (void *data, uintptr_t /*pc*/, const char *symname, uintptr_t /*symval*/, uintptr_t /*symsize*/) {
                                if (symname) {
                                    reinterpret_cast<AddressInformation*>(data)->function = demangle(symname);
                                }
                              }, &errorCallback, &info);
        }

        return info;
    }

    static void errorCallback(void */*data*/, const char *msg, int errnum)
    {
        cerr << "Module backtrace error (code " << errnum << "): " << msg << endl;
    }

    static void emptyErrorCallback(void */*data*/, const char */*msg*/, int /*errnum*/)
    {
    }

    bool operator<(const Module& module) const
    {
        return make_tuple(addressStart, addressEnd, fileName)
             < make_tuple(module.addressStart, module.addressEnd, module.fileName);
    }

    bool operator!=(const Module& module) const
    {
        return make_tuple(addressStart, addressEnd, fileName)
            != make_tuple(module.addressStart, module.addressEnd, module.fileName);
    }

    backtrace_state* backtraceState;
    string fileName;
    uintptr_t addressStart;
    uintptr_t addressEnd;
};

struct Allocation
{
    // backtrace entry point
    size_t ipIndex;
    // number of allocations
    size_t allocations;
    // amount of bytes leaked
    size_t leaked;
};

/**
 * Information for a single call to an allocation function
 */
struct AllocationInfo
{
    size_t ipIndex;
    size_t size;
};

struct ResolvedIP
{
    size_t moduleIndex = 0;
    size_t fileIndex = 0;
    size_t functionIndex = 0;
    int line = 0;
};

struct AccumulatedTraceData
{
    AccumulatedTraceData()
    {
        m_modules.reserve(256);
        m_backtraceStates.reserve(64);
        m_internedData.reserve(4096);
        m_encounteredIps.reserve(32768);
    }

    ~AccumulatedTraceData()
    {
        cout << dec;
        cout << "# strings: " << m_internedData.size() << '\n';
        cout << "# ips: " << m_encounteredIps.size() << '\n';
    }

    ResolvedIP resolve(const uintptr_t ip)
    {
        if (m_modulesDirty) {
            // sort by addresses, required for binary search below
            sort(m_modules.begin(), m_modules.end());

            for (size_t i = 0; i < m_modules.size(); ++i) {
                const auto& m1 = m_modules[i];
                for (size_t j = i + 1; j < m_modules.size(); ++j) {
                    if (i == j) {
                        continue;
                    }
                    const auto& m2 = m_modules[j];
                    if ((m1.addressStart <= m2.addressStart && m1.addressEnd > m2.addressStart) ||
                        (m1.addressStart < m2.addressEnd && m1.addressEnd >= m2.addressEnd))
                    {
                        cerr << "OVERLAPPING MODULES: " << hex
                             << m1.fileName << " (" << m1.addressStart << " to " << m1.addressEnd << ") and "
                             << m2.fileName << " (" << m2.addressStart << " to " << m2.addressEnd << ")\n"
                             << dec;
                    } else if (m2.addressStart >= m1.addressEnd) {
                        break;
                    }
                }
            }

            m_modulesDirty = false;
        }

        ResolvedIP data;
        // find module for this instruction pointer
        auto module = lower_bound(m_modules.begin(), m_modules.end(), ip,
                                    [] (const Module& module, const uintptr_t ip) -> bool {
                                        return module.addressEnd < ip;
                                    });
        if (module != m_modules.end() && module->addressStart <= ip && module->addressEnd >= ip) {
            data.moduleIndex = intern(module->fileName);
            const auto info = module->resolveAddress(ip);
            data.fileIndex = intern(info.file);
            data.functionIndex = intern(info.function);
            data.line = info.line;
        }
        return data;
    }

    size_t intern(const string& str)
    {
        if (str.empty()) {
            return 0;
        }

        auto it = m_internedData.find(str);
        if (it != m_internedData.end()) {
            return it->second;
        }
        const size_t id = m_internedData.size() + 1;
        m_internedData.insert(it, make_pair(str, id));
        cout << "s " << str << '\n';
        return id;
    }

    void addModule(const string& fileName, const bool isExe, const uintptr_t addressStart, const uintptr_t addressEnd)
    {
        backtrace_state* backtraceState = findBacktraceState(fileName, addressStart, isExe);

        m_modules.emplace_back(fileName, addressStart, addressEnd, backtraceState);
        m_modulesDirty = true;
    }

    void clearModules()
    {
        // TODO: optimize this, reuse modules that are still valid
        m_modules.clear();
        m_modulesDirty = true;
    }

    size_t addIp(const uintptr_t instructionPointer)
    {
        if (!instructionPointer) {
            return 0;
        }

        auto it = m_encounteredIps.find(instructionPointer);
        if (it != m_encounteredIps.end()) {
            return it->second;
        }

        const size_t ipId = m_encounteredIps.size() + 1;
        m_encounteredIps.insert(it, make_pair(instructionPointer, ipId));

        const auto ip = resolve(instructionPointer);
        cout << "i " << instructionPointer << ' ' << ip.moduleIndex;
        if (ip.functionIndex || ip.fileIndex) {
            cout << ' ' << ip.functionIndex;
            if (ip.fileIndex) {
                cout << ' ' << ip.fileIndex << ' ' << ip.line;
            }
        }
        cout << '\n';
        return ipId;
    }

private:
    /**
     * Prevent the same file from being initialized multiple times.
     * This drastically cuts the memory consumption down
     */
    backtrace_state* findBacktraceState(const string& fileName, uintptr_t addressStart, bool isExe)
    {
        if (boost::algorithm::starts_with(fileName, "linux-vdso.so")) {
            // prevent warning, since this will always fail
            return nullptr;
        }

        auto it = m_backtraceStates.find(fileName);
        if (it != m_backtraceStates.end()) {
            return it->second;
        }

        struct CallbackData {
            const string* fileName;
        };
        CallbackData data = {&fileName};

        auto state = backtrace_create_state(fileName.c_str(), /* we are single threaded, so: not thread safe */ false,
                                            [] (void *rawData, const char *msg, int errnum) {
                                                auto data = reinterpret_cast<const CallbackData*>(rawData);
                                                cerr << "Failed to create backtrace state for module "
                                                     << *data->fileName << ": " << msg
                                                     << " (error code " << errnum << ")" << endl;
                                            }, &data);

        if (state) {
            // when we could initialize the backtrace state, we initialize it with the first address
            // we get since that is the lowest one
            backtrace_fileline_initialize(state, addressStart, isExe,
                                            [] (void *rawData, const char *msg, int errnum) {
                                                auto data = reinterpret_cast<CallbackData*>(rawData);
                                                cerr << "Failed to initialize backtrace fileline for module "
                                                     << *data->fileName << ": " << msg
                                                     << " (error code " << errnum << ")" << endl;
                                            }, &data);
        }

        m_backtraceStates.insert(it, make_pair(fileName, state));

        return state;
    }

    vector<Module> m_modules;
    unordered_map<string, backtrace_state*> m_backtraceStates;
    bool m_modulesDirty = false;

    unordered_map<string, size_t> m_internedData;
    unordered_map<uintptr_t, size_t> m_encounteredIps;
};

}

int main(int /*argc*/, char** /*argv*/)
{
    // optimize: we only have a single thread
    ios_base::sync_with_stdio(false);

    AccumulatedTraceData data;

    LineReader reader;
    cin >> hex;
    cout << hex;

    while (reader.getLine(cin)) {
        if (reader.mode() == 'm') {
            string fileName;
            reader >> fileName;
            if (fileName == "-") {
                data.clearModules();
            } else {
                bool isExe = false;
                uintptr_t addressStart = 0;
                uintptr_t addressEnd = 0;
                if (!(reader >> isExe) || !(reader >> addressStart) || !(reader >> addressEnd)) {
                    cerr << "failed to parse line: " << reader.line() << endl;
                    return 1;
                }
                data.addModule(fileName, isExe, addressStart, addressEnd);
            }
        } else if (reader.mode() == 't') {
            uintptr_t instructionPointer = 0;
            size_t parentIndex = 0;
            if (!(reader >> instructionPointer) || !(reader >> parentIndex)) {
                cerr << "failed to parse line: " << reader.line() << endl;
                return 1;
            }
            // ensure ip is encountered
            const auto ipId = data.addIp(instructionPointer);
            // trace point, map current output index to parent index
            cout << "t " << ipId << ' ' << parentIndex << '\n';
        } else {
            cout << reader.line() << '\n';
        }
    }

    return 0;
}
<|endoftext|>


<commit_before>/*=========================================================================

  Program: Visomics

  Copyright (c) Kitware, Inc.

  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at

      http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.

=========================================================================*/

// Qt includes
#include <QAction>
#include <QDebug>
#include <QDesktopServices>
#include <QFileDialog>
#include <QTableView>
#include <QLayout>
#include <QStandardItemModel>
#include <QWidget>
#include <QHeaderView>

// Visomics includes
#include "voDataObject.h"
#include "voIOManager.h"
#include "voTableView.h"
#include "voUtils.h"

// VTK includes
#include <vtkIdTypeArray.h>
#include <vtkQtTableRepresentation.h>
#include <vtkQtTableView.h>
#include <vtkTable.h>

// --------------------------------------------------------------------------
class voTableViewPrivate
{
public:
  voTableViewPrivate();

  QTableView*        TableView;
  QStandardItemModel Model;
};

// --------------------------------------------------------------------------
// voTableViewPrivate methods

// --------------------------------------------------------------------------
voTableViewPrivate::voTableViewPrivate()
{
  this->TableView = 0;
}

// --------------------------------------------------------------------------
// voTableView methods

// --------------------------------------------------------------------------
voTableView::voTableView(QWidget* newParent):
    Superclass(newParent), d_ptr(new voTableViewPrivate)
{
}

// --------------------------------------------------------------------------
voTableView::~voTableView()
{
}

// --------------------------------------------------------------------------
QList<QAction*> voTableView::actions()
{
  QList<QAction*> actionList = this->Superclass::actions();

  QAction * exportToCsvAction = new QAction(QIcon(":/Icons/csv_text.png"), "Export as CSV", this);
  exportToCsvAction->setToolTip("Export current table view as CSV text file.");
  connect(exportToCsvAction, SIGNAL(triggered()), this, SLOT(onExportToCsvActionTriggered()));
  actionList << exportToCsvAction;

  return actionList;
}

// --------------------------------------------------------------------------
void voTableView::onExportToCsvActionTriggered()
{
  QString defaultFileName = QDesktopServices::storageLocation(QDesktopServices::DesktopLocation)
      + "/" + voUtils::cleanString(this->objectName()) + ".csv";

  QString fileName = QFileDialog::getSaveFileName(
        0, tr("Save table data..."), defaultFileName, "Comma Separated Value (*.csv)");
  if(fileName.isEmpty())
    {
    return;
    }
  vtkTable * table = vtkTable::SafeDownCast(this->dataObject()->dataAsVTKDataObject());
  Q_ASSERT(table);
  voIOManager::writeTableToCVSFile(table, fileName);
}

// --------------------------------------------------------------------------
void voTableView::setupUi(QLayout *layout)
{
  Q_D(voTableView);

  d->TableView = new QTableView();
  d->TableView->setModel(&d->Model);

  layout->addWidget(d->TableView);
}

// --------------------------------------------------------------------------
void voTableView::setDataObjectInternal(const voDataObject& dataObject)
{
  Q_D(voTableView);

  vtkTable * table = vtkTable::SafeDownCast(dataObject.dataAsVTKDataObject());
  if (!table)
    {
    qCritical() << "voTableView - Failed to setDataObject - vtkTable data is expected !";
    return;
    }

  // Update the model if necessary
  //if (t->GetMTime() > this->LastModelMTime)
  //  {
    // Note: this will clear the current selection.
    vtkIdType num_rows = table->GetNumberOfRows();
    vtkIdType num_cols = table->GetNumberOfColumns();
    d->Model.setRowCount(static_cast<int>(num_rows));
    d->Model.setColumnCount(static_cast<int>(num_cols - 1));
    for (vtkIdType c = 1; c < num_cols; ++c)
      {
      d->Model.setHeaderData(static_cast<int>(c-1), Qt::Horizontal, QString(table->GetColumnName(c)));
      for (vtkIdType r = 0; r < num_rows; ++r)
        {
        QStandardItem* item = new QStandardItem(QString(table->GetValue(r, c).ToString()));
        item->setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable); // Item is view-only
        d->Model.setItem(static_cast<int>(r), static_cast<int>(c-1), item);
        }
      }
    for (vtkIdType r = 0; r < num_rows; ++r)
      {
      d->Model.setHeaderData(static_cast<int>(r), Qt::Vertical, QString(table->GetValue(r, 0).ToString()));
      }
  //  this->LastModelMTime = table->GetMTime();
  //  }

    d->TableView->horizontalHeader()->setMinimumSectionSize(100);
    d->TableView->resizeColumnsToContents();

  // Retrieve the selected subtable
  //vtkSmartPointer<vtkTable> ot = vtkSmartPointer<vtkTable>::New();
  //this->selectedTable(ot);
  //this->Outputs["output"] = ot;
}

// --------------------------------------------------------------------------
//void voTableView::selectedTable(vtkTable* table)
//{
//  vtkTable* t = vtkTable::SafeDownCast(this->input().data());
//  if (!t)
//    {
//    return;
//    }

//  QSet<vtkIdType> rows;
//  QSet<vtkIdType> cols;

//  // Always select the first column (headers)
//  cols << 0;

//  const QModelIndexList selected = this->View->selectionModel()->selectedIndexes();
//  if (selected.size() == 0)
//    {
//    table->ShallowCopy(t);
//    return;
//    }
//  foreach (QModelIndex ind, selected)
//    {
//    cols << ind.row();
//    rows << ind.column();
//    }

//  foreach (vtkIdType c, cols)
//    {
//    vtkAbstractArray* col = t->GetColumn(c);
//    vtkAbstractArray* new_col = col->NewInstance();
//    new_col->SetName(col->GetName());
//    new_col->SetNumberOfTuples(rows.size());
//    table->AddColumn(new_col);
//    int ind = 0;
//    foreach (vtkIdType r, rows)
//      {
//      new_col->InsertTuple(ind, r, col);
//      ++ind;
//      }
//    new_col->Delete();
//    }
//}
<commit_msg>Remove old code, reformat voTableView::setDataObject()<commit_after>/*=========================================================================

  Program: Visomics

  Copyright (c) Kitware, Inc.

  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at

      http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.

=========================================================================*/

// Qt includes
#include <QAction>
#include <QDebug>
#include <QDesktopServices>
#include <QFileDialog>
#include <QTableView>
#include <QLayout>
#include <QStandardItemModel>
#include <QWidget>
#include <QHeaderView>

// Visomics includes
#include "voDataObject.h"
#include "voIOManager.h"
#include "voTableView.h"
#include "voUtils.h"

// VTK includes
#include <vtkIdTypeArray.h>
#include <vtkQtTableRepresentation.h>
#include <vtkQtTableView.h>
#include <vtkTable.h>

// --------------------------------------------------------------------------
class voTableViewPrivate
{
public:
  voTableViewPrivate();

  QTableView*        TableView;
  QStandardItemModel Model;
};

// --------------------------------------------------------------------------
// voTableViewPrivate methods

// --------------------------------------------------------------------------
voTableViewPrivate::voTableViewPrivate()
{
  this->TableView = 0;
}

// --------------------------------------------------------------------------
// voTableView methods

// --------------------------------------------------------------------------
voTableView::voTableView(QWidget* newParent):
    Superclass(newParent), d_ptr(new voTableViewPrivate)
{
}

// --------------------------------------------------------------------------
voTableView::~voTableView()
{
}

// --------------------------------------------------------------------------
QList<QAction*> voTableView::actions()
{
  QList<QAction*> actionList = this->Superclass::actions();

  QAction * exportToCsvAction = new QAction(QIcon(":/Icons/csv_text.png"), "Export as CSV", this);
  exportToCsvAction->setToolTip("Export current table view as CSV text file.");
  connect(exportToCsvAction, SIGNAL(triggered()), this, SLOT(onExportToCsvActionTriggered()));
  actionList << exportToCsvAction;

  return actionList;
}

// --------------------------------------------------------------------------
void voTableView::onExportToCsvActionTriggered()
{
  QString defaultFileName = QDesktopServices::storageLocation(QDesktopServices::DesktopLocation)
      + "/" + voUtils::cleanString(this->objectName()) + ".csv";

  QString fileName = QFileDialog::getSaveFileName(
        0, tr("Save table data..."), defaultFileName, "Comma Separated Value (*.csv)");
  if(fileName.isEmpty())
    {
    return;
    }
  vtkTable * table = vtkTable::SafeDownCast(this->dataObject()->dataAsVTKDataObject());
  Q_ASSERT(table);
  voIOManager::writeTableToCVSFile(table, fileName);
}

// --------------------------------------------------------------------------
void voTableView::setupUi(QLayout *layout)
{
  Q_D(voTableView);

  d->TableView = new QTableView();
  d->TableView->setModel(&d->Model);

  layout->addWidget(d->TableView);
}

// --------------------------------------------------------------------------
void voTableView::setDataObjectInternal(const voDataObject& dataObject)
{
  Q_D(voTableView);

  vtkTable * table = vtkTable::SafeDownCast(dataObject.dataAsVTKDataObject());
  if (!table)
    {
    qCritical() << "voTableView - Failed to setDataObject - vtkTable data is expected !";
    return;
    }

  vtkIdType num_rows = table->GetNumberOfRows();
  vtkIdType num_cols = table->GetNumberOfColumns();
  d->Model.setRowCount(static_cast<int>(num_rows));
  d->Model.setColumnCount(static_cast<int>(num_cols - 1));
  for (vtkIdType c = 1; c < num_cols; ++c)
    {
    d->Model.setHeaderData(static_cast<int>(c-1), Qt::Horizontal, QString(table->GetColumnName(c)));
    for (vtkIdType r = 0; r < num_rows; ++r)
      {
      QStandardItem* item = new QStandardItem(QString(table->GetValue(r, c).ToString()));
      item->setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable); // Item is view-only
      d->Model.setItem(static_cast<int>(r), static_cast<int>(c-1), item);
      }
    }
  for (vtkIdType r = 0; r < num_rows; ++r)
    {
    d->Model.setHeaderData(static_cast<int>(r), Qt::Vertical, QString(table->GetValue(r, 0).ToString()));
    }

  d->TableView->horizontalHeader()->setMinimumSectionSize(100);
  d->TableView->resizeColumnsToContents();

  // Retrieve the selected subtable
  //vtkSmartPointer<vtkTable> ot = vtkSmartPointer<vtkTable>::New();
  //this->selectedTable(ot);
  //this->Outputs["output"] = ot;
}

// --------------------------------------------------------------------------
//void voTableView::selectedTable(vtkTable* table)
//{
//  vtkTable* t = vtkTable::SafeDownCast(this->input().data());
//  if (!t)
//    {
//    return;
//    }

//  QSet<vtkIdType> rows;
//  QSet<vtkIdType> cols;

//  // Always select the first column (headers)
//  cols << 0;

//  const QModelIndexList selected = this->View->selectionModel()->selectedIndexes();
//  if (selected.size() == 0)
//    {
//    table->ShallowCopy(t);
//    return;
//    }
//  foreach (QModelIndex ind, selected)
//    {
//    cols << ind.row();
//    rows << ind.column();
//    }

//  foreach (vtkIdType c, cols)
//    {
//    vtkAbstractArray* col = t->GetColumn(c);
//    vtkAbstractArray* new_col = col->NewInstance();
//    new_col->SetName(col->GetName());
//    new_col->SetNumberOfTuples(rows.size());
//    table->AddColumn(new_col);
//    int ind = 0;
//    foreach (vtkIdType r, rows)
//      {
//      new_col->InsertTuple(ind, r, col);
//      ++ind;
//      }
//    new_col->Delete();
//    }
//}
<|endoftext|>


<commit_before>/*
 * CheckpointEntry.cpp
 *
 *  Created on Sep 27, 2016
 *      Author: Pete Schultz
 */

#include "CheckpointEntryDataStore.hpp"
#include "structures/Buffer.hpp"
#include "utils/BufferUtilsMPI.hpp"
#include "utils/BufferUtilsPvp.hpp"

namespace PV {

void CheckpointEntryDataStore::initialize(DataStore *dataStore, PVLayerLoc const *layerLoc) {
   mDataStore = dataStore;
   mLayerLoc  = layerLoc;
}

void CheckpointEntryDataStore::write(
      std::string const &checkpointDirectory,
      double simTime,
      bool verifyWritesFlag) const {
   int const numBuffers   = mDataStore->getNumBuffers();
   int const numLevels    = mDataStore->getNumLevels();
   FileStream *fileStream = nullptr;
   if (getCommunicator()->commRank() == 0) {
      std::string path   = generatePath(checkpointDirectory, "pvp");
      fileStream         = new FileStream(path.c_str(), std::ios_base::out, verifyWritesFlag);
      int const numBands = numBuffers * numLevels;
      int *params        = pvp_set_nonspiking_act_params(
            getCommunicator(), simTime, mLayerLoc, PV_FLOAT_TYPE, numLevels);
      pvAssert(params && params[1] == NUM_BIN_PARAMS);
      fileStream->write(params, params[0]);
   }
   int const nxExt       = mLayerLoc->nx + mLayerLoc->halo.lt + mLayerLoc->halo.rt;
   int const nyExt       = mLayerLoc->ny + mLayerLoc->halo.dn + mLayerLoc->halo.up;
   int const nf          = mLayerLoc->nf;
   int const numElements = nxExt * nyExt * nf;
   for (int b = 0; b < numBuffers; b++) {
      for (int l = 0; l < numLevels; l++) {
         double lastUpdateTime            = mDataStore->getLastUpdateTime(b, l);
         pvdata_t const *localData        = mDataStore->buffer(b, l);
         Buffer<pvdata_t> localPvpBuffer  = Buffer<pvdata_t>{localData, nxExt, nyExt, nf};
         Buffer<pvdata_t> globalPvpBuffer = BufferUtils::gather<pvdata_t>(
               getCommunicator(), localPvpBuffer, mLayerLoc->nx, mLayerLoc->ny);
         if (fileStream) {
            BufferUtils::writeFrame(*fileStream, &globalPvpBuffer, lastUpdateTime);
         }
      }
   }
   delete fileStream;
}

void CheckpointEntryDataStore::read(std::string const &checkpointDirectory, double *simTimePtr)
      const {
   int const numBuffers   = mDataStore->getNumBuffers();
   int const numLevels    = mDataStore->getNumLevels();
   int const numBands     = numBuffers * numLevels;
   FileStream *fileStream = nullptr;
   if (getCommunicator()->commRank() == 0) {
      std::string path        = generatePath(checkpointDirectory, "pvp");
      fileStream              = new FileStream(path.c_str(), std::ios_base::in, false);
      std::vector<int> header = BufferUtils::readHeader(*fileStream);
      pvErrorIf(
            header.at(INDEX_NBANDS) != numBands,
            "readDataStoreFromFile error reading \"%s\": delays*batchwidth in file is %d, "
            "but delays*batchwidth in layer is %d\n",
            path,
            header.at(INDEX_NBANDS),
            numBands);
   }
   int const nxExtGlobal = mLayerLoc->nxGlobal + mLayerLoc->halo.lt + mLayerLoc->halo.rt;
   int const nyExtGlobal = mLayerLoc->nyGlobal + mLayerLoc->halo.dn + mLayerLoc->halo.up;
   int const nf          = mLayerLoc->nf;
   Buffer<pvdata_t> pvpBuffer;
   std::vector<double> updateTimes;
   updateTimes.resize(numBands);
   for (int b = 0; b < numBuffers; b++) {
      for (int l = 0; l < numLevels; l++) {
         if (fileStream) {
            pvpBuffer.resize(nxExtGlobal, nyExtGlobal, nf);
            double updateTime                 = BufferUtils::readFrame(*fileStream, &pvpBuffer);
            updateTimes.at(b * numLevels + l) = updateTime;
         }
         else {
            int const nxExtLocal = mLayerLoc->nx + mLayerLoc->halo.lt + mLayerLoc->halo.rt;
            int const nyExtLocal = mLayerLoc->ny + mLayerLoc->halo.dn + mLayerLoc->halo.up;
            pvpBuffer.resize(nxExtLocal, nyExtLocal, nf);
         }
         BufferUtils::scatter(getCommunicator(), pvpBuffer, mLayerLoc->nx, mLayerLoc->ny);
         pvdata_t *localData = mDataStore->buffer(b, l);
         memcpy(
               localData,
               pvpBuffer.asVector().data(),
               (std::size_t)pvpBuffer.getTotalElements() * sizeof(pvdata_t));
      }
   }
   MPI_Bcast(
         updateTimes.data(), numBands, MPI_DOUBLE, 0 /*root*/, getCommunicator()->communicator());
   for (int b = 0; b < numBuffers; b++) {
      for (int l = 0; l < numLevels; l++) {
         mDataStore->setLastUpdateTime(b, l, updateTimes[b * numLevels + l]);
      }
   }
   delete fileStream;
}

void CheckpointEntryDataStore::remove(std::string const &checkpointDirectory) const {
   deleteFile(checkpointDirectory, "pvp");
}

} // end namespace PV
<commit_msg>Hotfix to fix build errors on certain machines.<commit_after>/*
 * CheckpointEntry.cpp
 *
 *  Created on Sep 27, 2016
 *      Author: Pete Schultz
 */

#include "CheckpointEntryDataStore.hpp"
#include "structures/Buffer.hpp"
#include "utils/BufferUtilsMPI.hpp"
#include "utils/BufferUtilsPvp.hpp"

namespace PV {

void CheckpointEntryDataStore::initialize(DataStore *dataStore, PVLayerLoc const *layerLoc) {
   mDataStore = dataStore;
   mLayerLoc  = layerLoc;
}

void CheckpointEntryDataStore::write(
      std::string const &checkpointDirectory,
      double simTime,
      bool verifyWritesFlag) const {
   int const numBuffers   = mDataStore->getNumBuffers();
   int const numLevels    = mDataStore->getNumLevels();
   FileStream *fileStream = nullptr;
   if (getCommunicator()->commRank() == 0) {
      std::string path   = generatePath(checkpointDirectory, "pvp");
      fileStream         = new FileStream(path.c_str(), std::ios_base::out, verifyWritesFlag);
      int const numBands = numBuffers * numLevels;
      int *params        = pvp_set_nonspiking_act_params(
            getCommunicator(), simTime, mLayerLoc, PV_FLOAT_TYPE, numLevels);
      pvAssert(params && params[1] == NUM_BIN_PARAMS);
      fileStream->write(params, params[0]);
   }
   int const nxExt       = mLayerLoc->nx + mLayerLoc->halo.lt + mLayerLoc->halo.rt;
   int const nyExt       = mLayerLoc->ny + mLayerLoc->halo.dn + mLayerLoc->halo.up;
   int const nf          = mLayerLoc->nf;
   int const numElements = nxExt * nyExt * nf;
   for (int b = 0; b < numBuffers; b++) {
      for (int l = 0; l < numLevels; l++) {
         double lastUpdateTime            = mDataStore->getLastUpdateTime(b, l);
         pvdata_t const *localData        = mDataStore->buffer(b, l);
         Buffer<pvdata_t> localPvpBuffer  = Buffer<pvdata_t>{localData, nxExt, nyExt, nf};
         Buffer<pvdata_t> globalPvpBuffer = BufferUtils::gather<pvdata_t>(
               getCommunicator(), localPvpBuffer, mLayerLoc->nx, mLayerLoc->ny);
         if (fileStream) {
            BufferUtils::writeFrame(*fileStream, &globalPvpBuffer, lastUpdateTime);
         }
      }
   }
   delete fileStream;
}

void CheckpointEntryDataStore::read(std::string const &checkpointDirectory, double *simTimePtr)
      const {
   int const numBuffers   = mDataStore->getNumBuffers();
   int const numLevels    = mDataStore->getNumLevels();
   int const numBands     = numBuffers * numLevels;
   FileStream *fileStream = nullptr;
   if (getCommunicator()->commRank() == 0) {
      std::string path        = generatePath(checkpointDirectory, "pvp");
      fileStream              = new FileStream(path.c_str(), std::ios_base::in, false);
      std::vector<int> header = BufferUtils::readHeader(*fileStream);
      pvErrorIf(
            header.at(INDEX_NBANDS) != numBands,
            "readDataStoreFromFile error reading \"%s\": delays*batchwidth in file is %d, "
            "but delays*batchwidth in layer is %d\n",
            path.c_str(),
            header.at(INDEX_NBANDS),
            numBands);
   }
   int const nxExtGlobal = mLayerLoc->nxGlobal + mLayerLoc->halo.lt + mLayerLoc->halo.rt;
   int const nyExtGlobal = mLayerLoc->nyGlobal + mLayerLoc->halo.dn + mLayerLoc->halo.up;
   int const nf          = mLayerLoc->nf;
   Buffer<pvdata_t> pvpBuffer;
   std::vector<double> updateTimes;
   updateTimes.resize(numBands);
   for (int b = 0; b < numBuffers; b++) {
      for (int l = 0; l < numLevels; l++) {
         if (fileStream) {
            pvpBuffer.resize(nxExtGlobal, nyExtGlobal, nf);
            double updateTime                 = BufferUtils::readFrame(*fileStream, &pvpBuffer);
            updateTimes.at(b * numLevels + l) = updateTime;
         }
         else {
            int const nxExtLocal = mLayerLoc->nx + mLayerLoc->halo.lt + mLayerLoc->halo.rt;
            int const nyExtLocal = mLayerLoc->ny + mLayerLoc->halo.dn + mLayerLoc->halo.up;
            pvpBuffer.resize(nxExtLocal, nyExtLocal, nf);
         }
         BufferUtils::scatter(getCommunicator(), pvpBuffer, mLayerLoc->nx, mLayerLoc->ny);
         pvdata_t *localData = mDataStore->buffer(b, l);
         memcpy(
               localData,
               pvpBuffer.asVector().data(),
               (std::size_t)pvpBuffer.getTotalElements() * sizeof(pvdata_t));
      }
   }
   MPI_Bcast(
         updateTimes.data(), numBands, MPI_DOUBLE, 0 /*root*/, getCommunicator()->communicator());
   for (int b = 0; b < numBuffers; b++) {
      for (int l = 0; l < numLevels; l++) {
         mDataStore->setLastUpdateTime(b, l, updateTimes[b * numLevels + l]);
      }
   }
   delete fileStream;
}

void CheckpointEntryDataStore::remove(std::string const &checkpointDirectory) const {
   deleteFile(checkpointDirectory, "pvp");
}

} // end namespace PV
<|endoftext|>


<commit_before>/*****************************************************************************
 *
 * This file is part of Mapnik (c++ mapping toolkit)
 *
 * Copyright (C) 2015 Artem Pavlenko
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *****************************************************************************/

#ifndef MAPNIK_JSON_EXTRACT_BOUNDING_BOX_GRAMMAR_HPP
#define MAPNIK_JSON_EXTRACT_BOUNDING_BOX_GRAMMAR_HPP

// mapnik
#include <mapnik/json/error_handler.hpp>
#include <mapnik/box2d.hpp>
#include <iostream>

// boost
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-parameter"
#pragma GCC diagnostic ignored "-Wunused-local-typedef"
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix_function.hpp>
#include <boost/fusion/adapted/std_tuple.hpp>
#pragma GCC diagnostic pop

// stl
#include <tuple>

namespace mapnik { namespace json {

using position = std::tuple<double,double>;
using boxes = std::vector<std::pair<box2d<double>, std::pair<std::size_t, std::size_t>>>;

namespace qi = boost::spirit::qi;
namespace standard_wide =  boost::spirit::standard_wide;
using standard_wide::space_type;

struct calculate_bounding_box_impl
{
    using result_type = void;
    template <typename T0, typename T1>
    result_type operator() (T0 & bbox, T1 const& pos) const
    {
        if (pos)
        {
            double x = std::get<0>(*pos);
            double y = std::get<1>(*pos);
            if (!bbox.valid())
            {
                bbox.init(x, y, x, y); // TODO: add init(x,y) convinience method
            }
            else
            {
                bbox.expand_to_include(x, y);
            }
        }
    }
};

struct push_box_impl
{
    using result_type = void;
    template <typename T0, typename T1, typename T2, typename T3>
    void operator() (T0 & boxes, T1 const& begin, T2 const& box, T3 const& range) const
    {
        boxes.emplace_back(box, std::make_pair(std::distance(begin, range.begin()), std::distance(range.begin(), range.end())));
    }
};

template <typename Iterator, typename ErrorHandler = error_handler<Iterator> >
struct extract_bounding_box_grammar :
        qi::grammar<Iterator, void(boxes&) ,space_type>
{
    extract_bounding_box_grammar();
    // rules
    qi::rule<Iterator, void(boxes&), space_type> start;
    qi::rule<Iterator, qi::locals<Iterator>, void(boxes&), space_type> features;
    qi::rule<Iterator, qi::locals<int, box2d<double>>, void(boxes&, Iterator const&), space_type> feature;
    qi::rule<Iterator, qi::locals<box2d<double>>, box2d<double>(), space_type> coords;
    qi::rule<Iterator, boost::optional<position>(), space_type> pos;
    qi::rule<Iterator, void(box2d<double>&), space_type> ring;
    qi::rule<Iterator, void(box2d<double>&), space_type> rings;
    qi::rule<Iterator, void(box2d<double>&), space_type> rings_array;

    // phoenix functions
    boost::phoenix::function<push_box_impl> push_box;
    boost::phoenix::function<calculate_bounding_box_impl> calculate_bounding_box;
    // error handler
    boost::phoenix::function<ErrorHandler> const error_handler;
};

}}

#endif // MAPNIK_JSON_EXTRACT_BOUNDING_BOX_GRAMMAR_HPP
<commit_msg>ignore invalid bounding boxes from "geometry": null<commit_after>/*****************************************************************************
 *
 * This file is part of Mapnik (c++ mapping toolkit)
 *
 * Copyright (C) 2015 Artem Pavlenko
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *****************************************************************************/

#ifndef MAPNIK_JSON_EXTRACT_BOUNDING_BOX_GRAMMAR_HPP
#define MAPNIK_JSON_EXTRACT_BOUNDING_BOX_GRAMMAR_HPP

// mapnik
#include <mapnik/json/error_handler.hpp>
#include <mapnik/box2d.hpp>
#include <iostream>

// boost
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-parameter"
#pragma GCC diagnostic ignored "-Wunused-local-typedef"
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix_function.hpp>
#include <boost/fusion/adapted/std_tuple.hpp>
#pragma GCC diagnostic pop

// stl
#include <tuple>

namespace mapnik { namespace json {

using position = std::tuple<double,double>;
using boxes = std::vector<std::pair<box2d<double>, std::pair<std::size_t, std::size_t>>>;

namespace qi = boost::spirit::qi;
namespace standard_wide =  boost::spirit::standard_wide;
using standard_wide::space_type;

struct calculate_bounding_box_impl
{
    using result_type = void;
    template <typename T0, typename T1>
    result_type operator() (T0 & bbox, T1 const& pos) const
    {
        if (pos)
        {
            double x = std::get<0>(*pos);
            double y = std::get<1>(*pos);
            if (!bbox.valid())
            {
                bbox.init(x, y, x, y); // TODO: add init(x,y) convinience method
            }
            else
            {
                bbox.expand_to_include(x, y);
            }
        }
    }
};

struct push_box_impl
{
    using result_type = void;
    template <typename T0, typename T1, typename T2, typename T3>
    void operator() (T0 & boxes, T1 const& begin, T2 const& box, T3 const& range) const
    {
        if (box.valid()) boxes.emplace_back(box, std::make_pair(std::distance(begin, range.begin()), std::distance(range.begin(), range.end())));
    }
};

template <typename Iterator, typename ErrorHandler = error_handler<Iterator> >
struct extract_bounding_box_grammar :
        qi::grammar<Iterator, void(boxes&) ,space_type>
{
    extract_bounding_box_grammar();
    // rules
    qi::rule<Iterator, void(boxes&), space_type> start;
    qi::rule<Iterator, qi::locals<Iterator>, void(boxes&), space_type> features;
    qi::rule<Iterator, qi::locals<int, box2d<double>>, void(boxes&, Iterator const&), space_type> feature;
    qi::rule<Iterator, qi::locals<box2d<double>>, box2d<double>(), space_type> coords;
    qi::rule<Iterator, boost::optional<position>(), space_type> pos;
    qi::rule<Iterator, void(box2d<double>&), space_type> ring;
    qi::rule<Iterator, void(box2d<double>&), space_type> rings;
    qi::rule<Iterator, void(box2d<double>&), space_type> rings_array;

    // phoenix functions
    boost::phoenix::function<push_box_impl> push_box;
    boost::phoenix::function<calculate_bounding_box_impl> calculate_bounding_box;
    // error handler
    boost::phoenix::function<ErrorHandler> const error_handler;
};

}}

#endif // MAPNIK_JSON_EXTRACT_BOUNDING_BOX_GRAMMAR_HPP
<|endoftext|>


<commit_before>#include "filedecompressor.h"
#include <QMap>
#include <QBuffer>

FileDecompressor::FileDecompressor()
{

}

FileDecompressor::~FileDecompressor()
{

}

void FileDecompressor::decompress()
{
    //Opens HZIP file
    qDebug() << endl << endl;
    QString filePath;
    QFileDialog dialog;
    dialog.setFileMode(QFileDialog::AnyFile);
    dialog.setNameFilter("HuffmanZip (*.hzip)");
    int result = dialog.exec();
    if (result)
        filePath = dialog.selectedFiles().first();
    else
        filePath = "";
    //Now we need to separate HEADER from DATA

    std::ifstream inputFile;
    inputFile.open(filePath.toStdString().c_str(), std::ifstream::binary);

    stringstream strStream;
    strStream << inputFile.rdbuf();
    string allfile = strStream.str();

    qDebug() << "ARCHIVO COMPLETO " << allfile.size();

    std::string width;
    getline(strStream, width);
    std::string height;
    getline(strStream, height);
    std::string huffmancodes;
    getline(strStream, huffmancodes);
    std::string data;
    int position = width.size()+1+height.size()+1+huffmancodes.size()+1;
    allfile.erase (0,position);
    qDebug() << "DESPUES DE CORTAR "<< allfile.size();
    data = allfile;

    inputFile.close();

    this->width = atoi(width.c_str());
    this->height = atoi(height.c_str());
    QString mixedcodes = QString::fromUtf8( huffmancodes.data(), huffmancodes.size() );
    QStringList newHeader = mixedcodes.split("#");

    this->header = newHeader;

    this->decodificate(data);
    this->headerInterpreter();
    this->generateFile();
}

void FileDecompressor::decodificate(std::string data)
{
    QString image;
    for (int i = 0; i < data.size(); i++) {
        char mander = data.at(i);
        char mask = 1 << 7;
        for(int e = 0; e<8; e++){
            if((mander & mask)==mask)
                image.append("1");
            else
                image.append("0");
            mander = (mander << 1);
        }
    }
    this->imagedata = image;
}

void FileDecompressor::headerInterpreter()
{
    QStringList::iterator it;
    for(it=this->header.begin(); it!=this->header.end(); it++)
    {
        this->codes.insert(it->mid(6), it->mid(0,6).prepend("#"));
    }
}

void FileDecompressor::generateFile()
{
    qDebug() << "CANTIDAD DE BITS" << this->imagedata.size();
    QString aux;
    QVector<QColor> colors;
    QString::iterator it;
    for(it=this->imagedata.begin(); it!=this->imagedata.end(); it++)
    {
        aux += *it;
        if(this->codes.contains(aux))
        {
            colors.push_back(QColor(this->codes.find(aux).value()));
            aux.clear();
        }
    }
    qDebug() << colors.size();

    //qDebug() << colors;

    QImage img(this->width, this->height, QImage::Format_ARGB32);
    QByteArray ba;
    QBuffer buffer(&ba);
    qDebug() << "LLEGA";
    //Esto va a tardar por la resolucion de la imagen, no es que se colgo el programa
    int k = 0;
    for(int i=0; i<this->height; i++)
    {
        for(int j=0; j<this->width; j++)
        {
            //Por cada pixel asigno un valor del Map. Deberia haber la misma cantidad de pixeles que tamaño del map.

            img.setPixel(j,i,colors.at(k).rgb());
            k++;
        }

    }
    qDebug() << "SALE?";

    //Tengo que ver como guardar la imagen
    //img.save(&buffer, "PNG");
}

<commit_msg>Changed file compression<commit_after>#include "filedecompressor.h"
#include <QMap>
#include <QBuffer>

FileDecompressor::FileDecompressor()
{

}

FileDecompressor::~FileDecompressor()
{

}

void FileDecompressor::decompress()
{
    //Opens HZIP file
    qDebug() << endl << endl;
    QString filePath;
    QFileDialog dialog;
    dialog.setFileMode(QFileDialog::AnyFile);
    dialog.setNameFilter("HuffmanZip (*.hzip)");
    int result = dialog.exec();
    if (result)
        filePath = dialog.selectedFiles().first();
    else
        filePath = "";
    //Now we need to separate HEADER from DATA

    std::ifstream inputFile;
    inputFile.open(filePath.toStdString().c_str(), std::ifstream::binary);

    stringstream strStream;
    strStream << inputFile.rdbuf();
    string allfile = strStream.str();

    qDebug() << "ARCHIVO COMPLETO " << allfile.size();

    std::string width;
    getline(strStream, width);
    std::string height;
    getline(strStream, height);
    std::string huffmancodes;
    getline(strStream, huffmancodes);
    std::string data;
    int position = width.size()+1+height.size()+1+huffmancodes.size()+1;
    allfile.erase (0,position);
    qDebug() << "DESPUES DE CORTAR "<< allfile.size();
    data = allfile;

    inputFile.close();

    this->width = atoi(width.c_str());
    this->height = atoi(height.c_str());
    QString mixedcodes = QString::fromUtf8( huffmancodes.data(), huffmancodes.size() );
    QStringList newHeader = mixedcodes.split("#");

    this->header = newHeader;

    this->decodificate(data);
    this->headerInterpreter();
    this->generateFile();
}

void FileDecompressor::decodificate(std::string data)
{
    QString image;
    for (int i = 0; i < data.size(); i++) {
        char mander = data.at(i);
        char mask = 1 << 7;
        for(int e = 0; e<8; e++){
            if((mander & mask)==mask)
                image.append("1");
            else
                image.append("0");
            mander = (mander << 1);
        }
    }
    this->imagedata = image;
}

void FileDecompressor::headerInterpreter()
{
    QStringList::iterator it;
    for(it=this->header.begin(); it!=this->header.end(); it++)
    {
        this->codes.insert(it->mid(6), it->mid(0,6).prepend("#"));
    }
}

void FileDecompressor::generateFile()
{
    qDebug() << "CANTIDAD DE BITS" << this->imagedata.size();
    QString aux;
    QVector<QColor> colors;
    QString::iterator it;
    for(it=this->imagedata.begin(); it!=this->imagedata.end(); it++)
    {
        aux += *it;
        if(this->codes.contains(aux))
        {
            colors.push_back(QColor(this->codes.find(aux).value()));
            aux.clear();
        }
    }
    qDebug() << colors.size();

    //qDebug() << colors;

    QImage img(this->width, this->height, QImage::Format_RGB32);
    QByteArray ba;
    QBuffer buffer(&ba);
    qDebug() << "LLEGA";
    //Esto va a tardar por la resolucion de la imagen, no es que se colgo el programa
    int k = 0;
    for(int i=0; i<this->height; i++)
    {
        for(int j=0; j<this->width; j++)
        {
            //Por cada pixel asigno un valor del Map. Deberia haber la misma cantidad de pixeles que tamaño del map.
            img.setPixel(j,i,colors.at(k).rgb());
            k++;
        }

    }
    qDebug() << "SALE?";

    //Tengo que ver como guardar la imagen

    img.save("asd.png",0,0);/*
    img.save(&buffer, "PNG");
    QFile file("hola.png");
    file.open(QIODevice::WriteOnly);
    file.write(ba);
    file.close();*/

}

<|endoftext|>


<commit_before>/*===========================================================================*\
 *                                                                           *
 *                               OpenMesh                                    *
 *        Copyright (C) 2003 by Computer Graphics Group, RWTH Aachen         *
 *                           www.openmesh.org                                *
 *                                                                           *
 *---------------------------------------------------------------------------*
 *                                                                           *
 *                                License                                    *
 *                                                                           *
 *  This library is free software; you can redistribute it and/or modify it  *
 *  under the terms of the GNU Lesser General Public License as published    *
 *  by the Free Software Foundation, version 2.1.                            *
 *                                                                           *
 *  This library is distributed in the hope that it will be useful, but      *
 *  WITHOUT ANY WARRANTY; without even the implied warranty of               *
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU        *
 *  Lesser General Public License for more details.                          *
 *                                                                           *
 *  You should have received a copy of the GNU Lesser General Public         *
 *  License along with this library; if not, write to the Free Software      *
 *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.                *
 *                                                                           *
\*===========================================================================*/

//== INCLUDES =================================================================

// OpenMesh
#include <OpenMesh/Core/IO/reader/OBJReader.hh>
#include <OpenMesh/Core/IO/IOManager.hh>
#include <OpenMesh/Core/System/omstream.hh>
#include <OpenMesh/Core/Utils/vector_cast.hh>
#include <OpenMesh/Core/Utils/color_cast.hh>
// STL
#if defined(OM_CC_MIPS)
#  include <ctype.h>
/// \bug Workaround for STLPORT 4.6: isspace seems not to be in namespace std!
#elif defined(_STLPORT_VERSION) && (_STLPORT_VERSION==0x460)
#  include <cctype>
#else
#  include <cctype>
using std::isspace;
#endif

#ifndef WIN32
#include <string.h>
#endif

//=== NAMESPACES ==============================================================

namespace OpenMesh {
namespace IO {

//=== INSTANCIATE =============================================================

_OBJReader_  __OBJReaderInstance;
_OBJReader_& OBJReader() { return __OBJReaderInstance; }

//=== IMPLEMENTATION ==========================================================

_OBJReader_::
_OBJReader_()
{
  IOManager().register_module(this);
}

//-----------------------------------------------------------------------------

bool
_OBJReader_::
read(const std::string& _filename, BaseImporter& _bi, Options& _opt)
{
  std::fstream in( _filename.c_str(), std::ios_base::in );

  if (!in)
  {
    omerr() << "[OBJReader] : cannot not open file "
          << _filename
          << std::endl;
    return false;
  }

  {
#if defined(WIN32)
    std::string::size_type dot = _filename.find_last_of("\\/");
#else
    std::string::size_type dot = _filename.rfind("/");
#endif
    path_ = (dot == std::string::npos)
      ? "./"
      : std::string(_filename.substr(0,dot+1));
  }

  bool result = read(in, _bi, _opt);

  in.close();
  return result;
}

//-----------------------------------------------------------------------------

bool
_OBJReader_::
read_material(std::fstream& _in)
{
  std::string line;
  std::string keyWrd;

  std::string key;
  Material    mat;
  float       f1,f2,f3;
  bool        indef = false;

  mat.cleanup();

  while( _in && !_in.eof() )
  {
    std::getline(_in,line);
    if ( _in.bad() ){
      omerr() << "  Warning! Could not read file properly!\n";
      return false;
    }

    if ( line.empty() )
      continue;

    std::stringstream stream(line);

    stream >> keyWrd;

    if( isspace(line[0]) || line[0] == '#' )
    {
      if (indef && !key.empty() && mat.is_valid())
      {
        materials_[key] = mat;
        mat.cleanup();
      }
    }

    else if (keyWrd == "newmtl") // begin new material definition
    {
      stream >> key;
      indef = true;
    }

    else if (keyWrd == "Kd") // diffuse color
    {
      stream >> f1; stream >> f2; stream >> f3;

      if( !stream.fail() )
        mat.set_Kd(f1,f2,f3);
    }

    else if (keyWrd == "Ka") // ambient color
    {
      stream >> f1; stream >> f2; stream >> f3;

      if( !stream.fail() )
        mat.set_Ka(f1,f2,f3);
    }

    else if (keyWrd == "Ks") // specular color
    {
      stream >> f1; stream >> f2; stream >> f3;

      if( !stream.fail() )
        mat.set_Ks(f1,f2,f3);
    }
#if 0
    else if (keyWrd == "illum") // diffuse/specular shading model
    {
      ; // just skip this
    }

    else if (keyWrd == "Ns") // Shininess [0..200]
    {
      ; // just skip this
    }

    else if (keyWrd == "map_") // map images
    {
      // map_Kd, diffuse map
      // map_Ks, specular map
      // map_Ka, ambient map
      // map_Bump, bump map
      // map_d,  opacity map
      ; // just skip this
    }
#endif

    else if (keyWrd == "Tr") // transparency value
    {
      stream >> f1;

      if( !stream.fail() )
        mat.set_Tr(f1);
    }
    else if (keyWrd == "d") // transparency value
    {
      stream >> f1;

      if( !stream.fail() )
        mat.set_Tr(f1);
    }

    if ( _in && indef && mat.is_valid() && !key.empty())
      materials_[key] = mat;
  }
  return true;
}

//-----------------------------------------------------------------------------

bool
_OBJReader_::
read(std::fstream& _in, BaseImporter& _bi, Options& _opt)
{
  omlog() << "[OBJReader] : read file\n";

  std::string line;
  std::string keyWrd;

  float                  x, y, z, u, v;

  BaseImporter::VHandles vhandles;
  std::vector<Vec3f>     normals;
  std::vector<Vec2f>     texcoords;

  std::vector<Vec2f>     face_texcoords;

  std::map<std::string,Material> materials;
  std::string            matname;

  while( _in && !_in.eof() )
  {
    std::getline(_in,line);
    if ( _in.bad() ){
      omerr() << "  Warning! Could not read file properly!\n";
      return false;
    }

    // Trim Both leading and trailing spaces

    size_t start = line.find_first_not_of(" \t");
    size_t end   = line.find_last_not_of(" \t");

    if(( std::string::npos == start ) || ( std::string::npos == end))
      line = "";
    else
      line = line.substr( start, end-start+1 );

    // comment
    if ( line.size() == 0 || line[0] == '#' || isspace(line[0]) ) {
      continue;
    }

    std::stringstream stream(line);

    stream >> keyWrd;

    // material file
    if (keyWrd == "mtllib")
    {
      std::string matFile;

      stream >> matFile;

      matFile = path_ + matFile;

      omlog() << "Load material file " << matFile << std::endl;

      std::fstream matStream( matFile.c_str(), std::ios_base::in );

      if ( matStream ){

        if ( !read_material( matStream ) )
	        omerr() << "  Warning! Could not read file properly!\n";
        matStream.close();
	      omlog() << "  " << materials_.size() << " materials loaded.\n";

      }else
	      omerr() << "  Warning! Material file '" << matFile << "' not found!\n";
    }

    // usemtl
    else if (keyWrd == "usemtl")
    {
      stream >> matname;
      if (materials_.find(matname)==materials_.end())
      {
        omerr() << "Warning! Material '" << matname
              << "' not defined in material file.\n";
        matname="";
      }
    }

    // vertex
    else if (keyWrd == "v")
    {
      stream >> x; stream >> y; stream >> z;

      if ( !stream.fail() )
        _bi.add_vertex(OpenMesh::Vec3f(x,y,z));
    }

    // texture coord
    else if (keyWrd == "vt")
    {
      stream >> u; stream >> v;

      if ( !stream.fail() ){

        texcoords.push_back(OpenMesh::Vec2f(u, v));
        _opt += Options::VertexTexCoord;

      }else{

        omerr() << "Only single 2D texture coordinate per vertex"
              << "allowed!" << std::endl;
        return false;
      }
    }

    // normal
    else if (keyWrd == "vn")
    {
      stream >> x; stream >> y; stream >> z;

      if ( !stream.fail() ){
        normals.push_back(OpenMesh::Vec3f(x,y,z));
        _opt += Options::VertexNormal;
      }
    }

    // face
    else if (keyWrd == "f")
    {
      int component(0), nV(0);
      int value;

      vhandles.clear();
      face_texcoords.clear();

      // read full line after detecting a face
      std::string faceLine;
      std::getline(stream,faceLine);
      std::stringstream lineData( faceLine );

      // work on the line until nothing left to read
      while ( !lineData.eof() )
      {
        // read one block from the line ( vertex/texCoord/normal )
        std::string vertex;
        lineData >> vertex;

        do{

          //get the component (vertex/texCoord/normal)
          size_t found=vertex.find("/");

          // parts are seperated by '/' So if no '/' found its the last component
          if( found != std::string::npos ){

            // read the index value
            std::stringstream tmp( vertex.substr(0,found) );

            // If we get an empty string this property is undefined in the file
            if ( vertex.substr(0,found).empty() ) {
              // Switch to next field
              vertex = vertex.substr(found+1);

              // Now we are at the next component
              ++component;

              // Skip further processing of this component
              continue;
            }

            // Read current value
            tmp >> value;

            // remove the read part from the string
            vertex = vertex.substr(found+1);

          } else {

            // last component of the vertex, read it.
            std::stringstream tmp( vertex );
            tmp >> value;

            // Clear vertex after finished reading the line
            vertex="";

            // Nothing to read here ( garbage at end of line )
            if ( tmp.fail() ) {
              continue;
            }
          }

          // store the component ( each component is referenced by the index here! )
          switch (component)
          {
            case 0: // vertex
              if ( value < 0 ) {
//                 std::cerr << "Handling negativ vertex index value" << std::endl;
                value = _bi.n_vertices() + value + 1;
              }
              vhandles.push_back(VertexHandle(value-1));
              break;

            case 1: // texture coord
              if ( value < 0 ) {
//                 std::cerr << "Handling negativ texture coordinate index value)" << std::endl;
                value = _bi.n_vertices() + value + 1;
              }
              assert(!vhandles.empty());
              assert((unsigned int)(value-1) < texcoords.size());
              _bi.set_texcoord(vhandles.back(), texcoords[value-1]);
	      face_texcoords.push_back( texcoords[value-1] );
              break;

            case 2: // normal
              if ( value < 0 ) {
//                 std::cerr << "Handling negativ normal index value)" << std::endl;
                value = _bi.n_vertices() + value + 1;
              }
              assert(!vhandles.empty());
              assert((unsigned int)(value-1) < normals.size());
              _bi.set_normal(vhandles.back(), normals[value-1]);
              break;
          }

          // Prepare for reading next component
          ++component;

          // Read until line does not contain any other info
        } while ( !vertex.empty() );

        component = 0;
        nV++;
      }

      size_t n_faces = _bi.n_faces();
      FaceHandle fh = _bi.add_face(vhandles);

      if( !vhandles.empty() )
	_bi.add_face_texcoords( fh, vhandles[0], face_texcoords );

      if ( !matname.empty() && materials_[matname].has_Kd() )
      {
        std::vector<FaceHandle> newfaces;

        for( size_t i=0; i < _bi.n_faces()-n_faces; ++i )
          newfaces.push_back(FaceHandle(n_faces+i));

        Material & mat = materials_[matname];

        Vec3uc fc = color_cast<Vec3uc, Vec3f>(mat.Kd());

        for (std::vector<FaceHandle>::iterator it = newfaces.begin();
                                               it != newfaces.end(); ++it)
          _bi.set_color( *it, fc );

        _opt += Options::FaceColor;
      }
    }
  }

  return true;
}

//=============================================================================
} // namespace IO
} // namespace OpenMesh
//=============================================================================
<commit_msg>Improved OBJ Reader to not segfault on problems regarding texture coordinates<commit_after>/*===========================================================================*\
 *                                                                           *
 *                               OpenMesh                                    *
 *        Copyright (C) 2003 by Computer Graphics Group, RWTH Aachen         *
 *                           www.openmesh.org                                *
 *                                                                           *
 *---------------------------------------------------------------------------*
 *                                                                           *
 *                                License                                    *
 *                                                                           *
 *  This library is free software; you can redistribute it and/or modify it  *
 *  under the terms of the GNU Lesser General Public License as published    *
 *  by the Free Software Foundation, version 2.1.                            *
 *                                                                           *
 *  This library is distributed in the hope that it will be useful, but      *
 *  WITHOUT ANY WARRANTY; without even the implied warranty of               *
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU        *
 *  Lesser General Public License for more details.                          *
 *                                                                           *
 *  You should have received a copy of the GNU Lesser General Public         *
 *  License along with this library; if not, write to the Free Software      *
 *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.                *
 *                                                                           *
\*===========================================================================*/

//== INCLUDES =================================================================

// OpenMesh
#include <OpenMesh/Core/IO/reader/OBJReader.hh>
#include <OpenMesh/Core/IO/IOManager.hh>
#include <OpenMesh/Core/System/omstream.hh>
#include <OpenMesh/Core/Utils/vector_cast.hh>
#include <OpenMesh/Core/Utils/color_cast.hh>
// STL
#if defined(OM_CC_MIPS)
#  include <ctype.h>
/// \bug Workaround for STLPORT 4.6: isspace seems not to be in namespace std!
#elif defined(_STLPORT_VERSION) && (_STLPORT_VERSION==0x460)
#  include <cctype>
#else
#  include <cctype>
using std::isspace;
#endif

#ifndef WIN32
#include <string.h>
#endif

//=== NAMESPACES ==============================================================

namespace OpenMesh {
namespace IO {

//=== INSTANCIATE =============================================================

_OBJReader_  __OBJReaderInstance;
_OBJReader_& OBJReader() { return __OBJReaderInstance; }

//=== IMPLEMENTATION ==========================================================

_OBJReader_::
_OBJReader_()
{
  IOManager().register_module(this);
}

//-----------------------------------------------------------------------------

bool
_OBJReader_::
read(const std::string& _filename, BaseImporter& _bi, Options& _opt)
{
  std::fstream in( _filename.c_str(), std::ios_base::in );

  if (!in)
  {
    omerr() << "[OBJReader] : cannot not open file "
          << _filename
          << std::endl;
    return false;
  }

  {
#if defined(WIN32)
    std::string::size_type dot = _filename.find_last_of("\\/");
#else
    std::string::size_type dot = _filename.rfind("/");
#endif
    path_ = (dot == std::string::npos)
      ? "./"
      : std::string(_filename.substr(0,dot+1));
  }

  bool result = read(in, _bi, _opt);

  in.close();
  return result;
}

//-----------------------------------------------------------------------------

bool
_OBJReader_::
read_material(std::fstream& _in)
{
  std::string line;
  std::string keyWrd;

  std::string key;
  Material    mat;
  float       f1,f2,f3;
  bool        indef = false;

  mat.cleanup();

  while( _in && !_in.eof() )
  {
    std::getline(_in,line);
    if ( _in.bad() ){
      omerr() << "  Warning! Could not read file properly!\n";
      return false;
    }

    if ( line.empty() )
      continue;

    std::stringstream stream(line);

    stream >> keyWrd;

    if( isspace(line[0]) || line[0] == '#' )
    {
      if (indef && !key.empty() && mat.is_valid())
      {
        materials_[key] = mat;
        mat.cleanup();
      }
    }

    else if (keyWrd == "newmtl") // begin new material definition
    {
      stream >> key;
      indef = true;
    }

    else if (keyWrd == "Kd") // diffuse color
    {
      stream >> f1; stream >> f2; stream >> f3;

      if( !stream.fail() )
        mat.set_Kd(f1,f2,f3);
    }

    else if (keyWrd == "Ka") // ambient color
    {
      stream >> f1; stream >> f2; stream >> f3;

      if( !stream.fail() )
        mat.set_Ka(f1,f2,f3);
    }

    else if (keyWrd == "Ks") // specular color
    {
      stream >> f1; stream >> f2; stream >> f3;

      if( !stream.fail() )
        mat.set_Ks(f1,f2,f3);
    }
#if 0
    else if (keyWrd == "illum") // diffuse/specular shading model
    {
      ; // just skip this
    }

    else if (keyWrd == "Ns") // Shininess [0..200]
    {
      ; // just skip this
    }

    else if (keyWrd == "map_") // map images
    {
      // map_Kd, diffuse map
      // map_Ks, specular map
      // map_Ka, ambient map
      // map_Bump, bump map
      // map_d,  opacity map
      ; // just skip this
    }
#endif

    else if (keyWrd == "Tr") // transparency value
    {
      stream >> f1;

      if( !stream.fail() )
        mat.set_Tr(f1);
    }
    else if (keyWrd == "d") // transparency value
    {
      stream >> f1;

      if( !stream.fail() )
        mat.set_Tr(f1);
    }

    if ( _in && indef && mat.is_valid() && !key.empty())
      materials_[key] = mat;
  }
  return true;
}

//-----------------------------------------------------------------------------

bool
_OBJReader_::
read(std::fstream& _in, BaseImporter& _bi, Options& _opt)
{
  omlog() << "[OBJReader] : read file\n";

  std::string line;
  std::string keyWrd;

  float                  x, y, z, u, v;

  BaseImporter::VHandles vhandles;
  std::vector<Vec3f>     normals;
  std::vector<Vec2f>     texcoords;

  std::vector<Vec2f>     face_texcoords;

  std::map<std::string,Material> materials;
  std::string            matname;

  while( _in && !_in.eof() )
  {
    std::getline(_in,line);
    if ( _in.bad() ){
      omerr() << "  Warning! Could not read file properly!\n";
      return false;
    }

    // Trim Both leading and trailing spaces

    size_t start = line.find_first_not_of(" \t");
    size_t end   = line.find_last_not_of(" \t");

    if(( std::string::npos == start ) || ( std::string::npos == end))
      line = "";
    else
      line = line.substr( start, end-start+1 );

    // comment
    if ( line.size() == 0 || line[0] == '#' || isspace(line[0]) ) {
      continue;
    }

    std::stringstream stream(line);

    stream >> keyWrd;

    // material file
    if (keyWrd == "mtllib")
    {
      std::string matFile;

      stream >> matFile;

      matFile = path_ + matFile;

      omlog() << "Load material file " << matFile << std::endl;

      std::fstream matStream( matFile.c_str(), std::ios_base::in );

      if ( matStream ){

        if ( !read_material( matStream ) )
	        omerr() << "  Warning! Could not read file properly!\n";
        matStream.close();
	      omlog() << "  " << materials_.size() << " materials loaded.\n";

      }else
	      omerr() << "  Warning! Material file '" << matFile << "' not found!\n";
    }

    // usemtl
    else if (keyWrd == "usemtl")
    {
      stream >> matname;
      if (materials_.find(matname)==materials_.end())
      {
        omerr() << "Warning! Material '" << matname
              << "' not defined in material file.\n";
        matname="";
      }
    }

    // vertex
    else if (keyWrd == "v")
    {
      stream >> x; stream >> y; stream >> z;

      if ( !stream.fail() )
        _bi.add_vertex(OpenMesh::Vec3f(x,y,z));
    }

    // texture coord
    else if (keyWrd == "vt")
    {
      stream >> u; stream >> v;

      if ( !stream.fail() ){

        texcoords.push_back(OpenMesh::Vec2f(u, v));
        _opt += Options::VertexTexCoord;

      }else{

        omerr() << "Only single 2D texture coordinate per vertex"
              << "allowed!" << std::endl;
        return false;
      }
    }

    // normal
    else if (keyWrd == "vn")
    {
      stream >> x; stream >> y; stream >> z;

      if ( !stream.fail() ){
        normals.push_back(OpenMesh::Vec3f(x,y,z));
        _opt += Options::VertexNormal;
      }
    }

    // face
    else if (keyWrd == "f")
    {
      int component(0), nV(0);
      int value;

      vhandles.clear();
      face_texcoords.clear();

      // read full line after detecting a face
      std::string faceLine;
      std::getline(stream,faceLine);
      std::stringstream lineData( faceLine );

      // work on the line until nothing left to read
      while ( !lineData.eof() )
      {
        // read one block from the line ( vertex/texCoord/normal )
        std::string vertex;
        lineData >> vertex;

        do{

          //get the component (vertex/texCoord/normal)
          size_t found=vertex.find("/");

          // parts are seperated by '/' So if no '/' found its the last component
          if( found != std::string::npos ){

            // read the index value
            std::stringstream tmp( vertex.substr(0,found) );

            // If we get an empty string this property is undefined in the file
            if ( vertex.substr(0,found).empty() ) {
              // Switch to next field
              vertex = vertex.substr(found+1);

              // Now we are at the next component
              ++component;

              // Skip further processing of this component
              continue;
            }

            // Read current value
            tmp >> value;

            // remove the read part from the string
            vertex = vertex.substr(found+1);

          } else {

            // last component of the vertex, read it.
            std::stringstream tmp( vertex );
            tmp >> value;

            // Clear vertex after finished reading the line
            vertex="";

            // Nothing to read here ( garbage at end of line )
            if ( tmp.fail() ) {
              continue;
            }
          }

          // store the component ( each component is referenced by the index here! )
          switch (component)
          {
            case 0: // vertex
              if ( value < 0 ) {
//                 std::cerr << "Handling negativ vertex index value" << std::endl;
                value = _bi.n_vertices() + value + 1;
              }
              vhandles.push_back(VertexHandle(value-1));
              break;

            case 1: // texture coord
              if ( value < 0 ) {
//                 std::cerr << "Handling negativ texture coordinate index value)" << std::endl;
                value = _bi.n_vertices() + value + 1;
              }
              assert(!vhandles.empty());
              if ( ! texcoords.empty() && (unsigned int)(value-1) < texcoords.size() ) {
                _bi.set_texcoord(vhandles.back(), texcoords[value-1]);
                face_texcoords.push_back( texcoords[value-1] );
              } else {
                omerr() << "Error setting Texture coordinates" << std::endl;
              }

              break;

            case 2: // normal
              if ( value < 0 ) {
//                 std::cerr << "Handling negativ normal index value)" << std::endl;
                value = _bi.n_vertices() + value + 1;
              }
              assert(!vhandles.empty());
              assert((unsigned int)(value-1) < normals.size());
              _bi.set_normal(vhandles.back(), normals[value-1]);
              break;
          }

          // Prepare for reading next component
          ++component;

          // Read until line does not contain any other info
        } while ( !vertex.empty() );

        component = 0;
        nV++;
      }

      size_t n_faces = _bi.n_faces();
      FaceHandle fh = _bi.add_face(vhandles);

      if( !vhandles.empty() )
	_bi.add_face_texcoords( fh, vhandles[0], face_texcoords );

      if ( !matname.empty() && materials_[matname].has_Kd() )
      {
        std::vector<FaceHandle> newfaces;

        for( size_t i=0; i < _bi.n_faces()-n_faces; ++i )
          newfaces.push_back(FaceHandle(n_faces+i));

        Material & mat = materials_[matname];

        Vec3uc fc = color_cast<Vec3uc, Vec3f>(mat.Kd());

        for (std::vector<FaceHandle>::iterator it = newfaces.begin();
                                               it != newfaces.end(); ++it)
          _bi.set_color( *it, fc );

        _opt += Options::FaceColor;
      }
    }
  }

  return true;
}

//=============================================================================
} // namespace IO
} // namespace OpenMesh
//=============================================================================
<|endoftext|>