<commit_before>#include "gboost.h"
#include "solver.h"
#include "core/tpool.h"
#include "core/logger.h"
#include "gboost_stump.h"
#include "core/ibstream.h"
#include "core/obstream.h"

using namespace nano;

static auto measure(const task_t& task, const fold_t& fold, const tensor4d_t& outputs, const loss_t& loss)
{
        const auto& tpool = tpool_t::instance();

        std::vector<stats_t> errors(tpool.workers());
        std::vector<stats_t> values(tpool.workers());

        loopit(task.size(fold), [&] (const size_t i, const size_t t)
        {
                assert(t < tpool.workers());
                const auto input = task.input(fold, i);
                const auto target = task.target(fold, i);
                const auto output = outputs.tensor(i);

                errors[t](loss.error(target, output));
                values[t](loss.value(target, output));
        });

        for (size_t t = 1; t < tpool.workers(); ++ t)
        {
                errors[0](errors[t]);
                values[0](values[t]);
        }

        return std::make_pair(errors[0], values[0]);
}

static void update(const task_t& task, const fold_t& fold, tensor4d_t& outputs, const stump_t& stump)
{
        loopi(task.size(fold), [&] (const size_t i)
        {
                const auto input = task.input(fold, i);
                const auto oindex = input(stump.m_feature) < stump.m_threshold ? 0 : 1;
                outputs.array(i) += stump.m_outputs.array(oindex);
        });
}

// todo: break the computation in smaller functions (move them to gboost.h)

void gboost_stump_t::to_json(json_t& json) const
{
        nano::to_json(json,
                "rounds", m_rounds,
                "patience", m_patience,
                "stump", m_stype, "stumps", join(enum_values<stump>()),
                "solver", m_solver, "solvers", join(get_solvers().ids()),
                "regularization", m_rtype, "regularizations", join(enum_values<regularization>()));
}

void gboost_stump_t::from_json(const json_t& json)
{
        nano::from_json(json,
                "rounds", m_rounds,
                "patience", m_patience,
                "stump", m_stype,
                "solver", m_solver,
                "regularization", m_rtype);
}

trainer_result_t gboost_stump_t::train(const task_t& task, const size_t fold, const loss_t& loss)
{
        // check if the solver is properly set
        rsolver_t solver;
        critical(solver = get_solvers().get(m_solver),
                strcat("search solver (", m_solver, ")."));

        m_idims = task.idims();
        m_odims = task.odims();

        m_stumps.clear();

        trainer_result_t result("<config>");
        timer_t timer;

        const auto fold_train = fold_t{fold, protocol::train};
        const auto fold_valid = fold_t{fold, protocol::valid};
        const auto fold_test = fold_t{fold, protocol::test};

        tensor4d_t outputs_train(cat_dims(task.size(fold_train), m_odims));
        tensor4d_t outputs_valid(cat_dims(task.size(fold_valid), m_odims));
        tensor4d_t outputs_test(cat_dims(task.size(fold_test), m_odims));

        outputs_train.zero();
        outputs_valid.zero();
        outputs_test.zero();

        stats_t errors_train, errors_valid, errors_test;
        stats_t values_train, values_valid, values_test;

        std::tie(errors_train, values_train) = ::measure(task, fold_train, outputs_train, loss);
        std::tie(errors_valid, values_valid) = ::measure(task, fold_valid, outputs_valid, loss);
        std::tie(errors_test, values_test) = ::measure(task, fold_test, outputs_test, loss);

        result.update(trainer_state_t{timer.milliseconds(), 0,
                {values_train.avg(), errors_train.avg()},
                {values_valid.avg(), errors_valid.avg()},
                {values_test.avg(), errors_test.avg()}},
                m_patience);

        log_info() << result << ".";

        tensor4d_t residuals_train(cat_dims(task.size(fold_train), m_odims));
        tensor3d_t residuals_pos1(m_odims), residuals_pos2(m_odims);
        tensor3d_t residuals_neg1(m_odims), residuals_neg2(m_odims);

        stump_t stump;
        tensor4d_t stump_outputs_train(cat_dims(task.size(fold_train), m_odims));

        tensor4d_t targets(cat_dims(task.size(fold_train), m_odims));
        for (size_t i = 0, size = task.size(fold_train); i < size; ++ i)
        {
                const auto target = task.target(fold_train, i);
                targets.tensor(i) = target.tensor();
        }

        gboost_lsearch_function_t func(targets, outputs_train, stump_outputs_train, loss);

        for (auto round = 0; round < m_rounds && !result.is_done(); ++ round)
        {
                for (size_t i = 0, size = task.size(fold_train); i < size; ++ i)
                {
                        const auto input = task.input(fold_train, i);
                        const auto target = task.target(fold_train, i);
                        const auto output = outputs_train.tensor(i);

                        const auto vgrad = loss.vgrad(target, output);
                        residuals_train.vector(i) = -vgrad.vector();
                }

                scalar_t best_value = std::numeric_limits<scalar_t>::max();

                // todo: generalize this - e.g. to use features that are products of two input features
                for (auto feature = 0; feature < nano::size(m_idims); ++ feature)
                {
                        scalars_t fvalues(task.size(fold_train));
                        for (size_t i = 0, size = task.size(fold_train); i < size; ++ i)
                        {
                                const auto input = task.input(fold_train, i);
                                fvalues[i] = input(feature);
                        }

                        auto thresholds = fvalues;
                        std::sort(thresholds.begin(), thresholds.end());
                        thresholds.erase(std::unique(thresholds.begin(), thresholds.end()), thresholds.end());

                        for (size_t t = 0; t + 1 < thresholds.size(); ++ t)
                        {
                                const auto threshold = (thresholds[t + 0] + thresholds[t + 1]) / 2;

                                residuals_pos1.zero(), residuals_pos2.zero();
                                residuals_neg1.zero(), residuals_neg2.zero();

                                int cnt_pos = 0, cnt_neg = 0;
                                for (size_t i = 0, size = task.size(fold_train); i < size; ++ i)
                                {
                                        const auto residual = residuals_train.array(i);
                                        if (fvalues[i] < threshold)
                                        {
                                                cnt_neg ++;
                                                residuals_neg1.array() += residual;
                                                residuals_neg2.array() += residual * residual;
                                        }
                                        else
                                        {
                                                cnt_pos ++;
                                                residuals_pos1.array() += residual;
                                                residuals_pos2.array() += residual * residual;
                                        }
                                }

                                const auto value =
                                        (residuals_pos2.array().sum() - residuals_pos1.array().square().sum() / cnt_pos) +
                                        (residuals_neg2.array().sum() - residuals_neg1.array().square().sum() / cnt_neg);

                                //log_info() << "feature = " << feature
                                //        << ", threshold = " << threshold
                                //        << ", value = " << value
                                //        << ", count = " << cnt_neg << "+" << cnt_pos << "=" << task.size(fold_train);

                                if (value < best_value)
                                {
                                        best_value = value;
                                        stump.m_feature = feature;
                                        stump.m_threshold = threshold;
                                        stump.m_outputs.resize(cat_dims(2, m_odims));
                                        stump.m_outputs.vector(0) = residuals_neg1.vector() / cnt_neg;
                                        stump.m_outputs.vector(1) = residuals_pos1.vector() / cnt_pos;
                                }

                                // todo: fit both real and discrete stumps
                        }
                }

                // line-search
                for (size_t i = 0, size = task.size(fold_train); i < size; ++ i)
                {
                        const auto input = task.input(fold_train, i);
                        const auto oindex = input(stump.m_feature) < stump.m_threshold ? 0 : 1;
                        stump_outputs_train.tensor(i) = stump.m_outputs.tensor(oindex);
                }

                const auto state = solver->minimize(100, epsilon2<scalar_t>(), func, vector_t::Constant(1, 0));
                const auto step = state.x(0);

                stump.m_outputs.vector() *= step;
                m_stumps.push_back(stump);

                // update current outputs
                update(task, fold_train, outputs_train, stump);
                update(task, fold_valid, outputs_valid, stump);
                update(task, fold_test, outputs_test, stump);

                std::tie(errors_train, values_train) = ::measure(task, fold_train, outputs_train, loss);
                std::tie(errors_valid, values_valid) = ::measure(task, fold_valid, outputs_valid, loss);
                std::tie(errors_test, values_test) = ::measure(task, fold_test, outputs_test, loss);

                result.update(trainer_state_t{timer.milliseconds(), round + 1,
                        {values_train.avg(), errors_train.avg()},
                        {values_valid.avg(), errors_valid.avg()},
                        {values_test.avg(), errors_test.avg()}},
                        m_patience);

                log_info() << result
                        << ",feature=" << stump.m_feature
                        << ",solver=(" << state.m_status
                        << ",i=" << state.m_iterations
                        << ",x=" << state.x(0)
                        << ",f=" << state.f
                        << ",g=" << state.convergence_criteria() << ").";
        }

        // keep only the stumps up to optimum epoch (on the validation dataset)
        m_stumps.erase(
                m_stumps.begin() + result.optimum().m_epoch,
                m_stumps.end());

        return result;
}

tensor3d_t gboost_stump_t::output(const tensor3d_t& input) const
{
        assert(input.dims() == m_idims);

        tensor3d_t output(m_odims);
        output.zero();

        const auto idata = input.array();
        auto odata = output.array();

        for (const auto& stump : m_stumps)
        {
                const auto oindex = idata(stump.m_feature) < stump.m_threshold ? 0 : 1;
                odata.array() += stump.m_outputs.array(oindex);
        }

        return output;
}

bool gboost_stump_t::save(obstream_t& stream) const
{
        if (    !stream.write(m_idims) ||
                !stream.write(m_odims) ||
                !stream.write(m_rounds) ||
                !stream.write(m_stype) ||
                !stream.write(m_rtype) ||
                !stream.write(m_stumps.size()))
        {
                return false;
        }

        for (const auto& stump : m_stumps)
        {
                assert(stump.m_feature >= 0 && stump.m_feature < nano::size(m_idims));
                assert(stump.m_outputs.dims() == cat_dims(2, m_odims));

                if (    !stream.write(stump.m_feature) ||
                        !stream.write(stump.m_threshold) ||
                        !stream.write_tensor(stump.m_outputs))
                {
                       return false;
                }
        }

        return true;
}

bool gboost_stump_t::load(ibstream_t& stream)
{
        size_t n_stumps = 0;
        if (    !stream.read(m_idims) ||
                !stream.read(m_odims) ||
                !stream.read(m_rounds) ||
                !stream.read(m_stype) ||
                !stream.read(m_rtype) ||
                !stream.read(n_stumps))
        {
                return false;
        }

        m_stumps.resize(n_stumps);
        for (auto& stump : m_stumps)
        {
                if (    !stream.read(stump.m_feature) ||
                        !stream.read(stump.m_threshold) ||
                        !stream.read_tensor(stump.m_outputs) ||
                        stump.m_feature < 0 ||
                        stump.m_feature >= nano::size(m_idims) ||
                        stump.m_outputs.dims() != cat_dims(2, m_odims))
                {
                        return false;
                }
        }

        // todo: more verbose loading (#stumps, feature or coefficient statistics, idims...)

        return true;
}

probes_t gboost_stump_t::probes() const
{
        // todo: add probes here to measure the training and the evaluation time
        probes_t probes;
        return probes;
}
<commit_msg>fix display the progress in gboost stump<commit_after>#include "gboost.h"
#include "solver.h"
#include "core/tpool.h"
#include "core/logger.h"
#include "gboost_stump.h"
#include "core/ibstream.h"
#include "core/obstream.h"

using namespace nano;

static auto measure(const task_t& task, const fold_t& fold, const tensor4d_t& outputs, const loss_t& loss)
{
        const auto& tpool = tpool_t::instance();

        std::vector<stats_t> errors(tpool.workers());
        std::vector<stats_t> values(tpool.workers());

        loopit(task.size(fold), [&] (const size_t i, const size_t t)
        {
                assert(t < tpool.workers());
                const auto input = task.input(fold, i);
                const auto target = task.target(fold, i);
                const auto output = outputs.tensor(i);

                errors[t](loss.error(target, output));
                values[t](loss.value(target, output));
        });

        for (size_t t = 1; t < tpool.workers(); ++ t)
        {
                errors[0](errors[t]);
                values[0](values[t]);
        }

        return std::make_pair(errors[0], values[0]);
}

static void update(const task_t& task, const fold_t& fold, tensor4d_t& outputs, const stump_t& stump)
{
        loopi(task.size(fold), [&] (const size_t i)
        {
                const auto input = task.input(fold, i);
                const auto oindex = input(stump.m_feature) < stump.m_threshold ? 0 : 1;
                outputs.array(i) += stump.m_outputs.array(oindex);
        });
}

// todo: break the computation in smaller functions (move them to gboost.h)

void gboost_stump_t::to_json(json_t& json) const
{
        nano::to_json(json,
                "rounds", m_rounds,
                "patience", m_patience,
                "stump", m_stype, "stumps", join(enum_values<stump>()),
                "solver", m_solver, "solvers", join(get_solvers().ids()),
                "regularization", m_rtype, "regularizations", join(enum_values<regularization>()));
}

void gboost_stump_t::from_json(const json_t& json)
{
        nano::from_json(json,
                "rounds", m_rounds,
                "patience", m_patience,
                "stump", m_stype,
                "solver", m_solver,
                "regularization", m_rtype);
}

trainer_result_t gboost_stump_t::train(const task_t& task, const size_t fold, const loss_t& loss)
{
        // check if the solver is properly set
        rsolver_t solver;
        critical(solver = get_solvers().get(m_solver),
                strcat("search solver (", m_solver, ")."));

        m_idims = task.idims();
        m_odims = task.odims();

        m_stumps.clear();

        trainer_result_t result("<config>");
        timer_t timer;

        const auto fold_tr = fold_t{fold, protocol::train};
        const auto fold_vd = fold_t{fold, protocol::valid};
        const auto fold_te = fold_t{fold, protocol::test};

        tensor4d_t outputs_tr(cat_dims(task.size(fold_tr), m_odims));
        tensor4d_t outputs_vd(cat_dims(task.size(fold_vd), m_odims));
        tensor4d_t outputs_te(cat_dims(task.size(fold_te), m_odims));

        outputs_tr.zero();
        outputs_vd.zero();
        outputs_te.zero();

        stats_t errors_tr, errors_vd, errors_te;
        stats_t values_tr, values_vd, values_te;

        std::tie(errors_tr, values_tr) = ::measure(task, fold_tr, outputs_tr, loss);
        std::tie(errors_vd, values_vd) = ::measure(task, fold_vd, outputs_vd, loss);
        std::tie(errors_te, values_te) = ::measure(task, fold_te, outputs_te, loss);

        const auto measure_tr = trainer_measurement_t{values_tr.avg(), errors_tr.avg()};
        const auto measure_vd = trainer_measurement_t{values_vd.avg(), errors_vd.avg()};
        const auto measure_te = trainer_measurement_t{values_te.avg(), errors_te.avg()};

        const auto status = result.update(
                trainer_state_t{timer.milliseconds(), 0, measure_tr, measure_vd, measure_te},
                m_patience);

        log_info() << "[" << 0 << "/" << m_rounds
                << "]:tr=" << measure_tr
                << ",vd=" << measure_vd << "|" << status
                << ",te=" << measure_te << ".";

        tensor4d_t residuals_train(cat_dims(task.size(fold_tr), m_odims));
        tensor3d_t residuals_pos1(m_odims), residuals_pos2(m_odims);
        tensor3d_t residuals_neg1(m_odims), residuals_neg2(m_odims);

        stump_t stump;
        tensor4d_t stump_outputs_tr(cat_dims(task.size(fold_tr), m_odims));

        tensor4d_t targets(cat_dims(task.size(fold_tr), m_odims));
        for (size_t i = 0, size = task.size(fold_tr); i < size; ++ i)
        {
                const auto target = task.target(fold_tr, i);
                targets.tensor(i) = target;
        }

        gboost_lsearch_function_t func(targets, outputs_tr, stump_outputs_tr, loss);

        for (auto round = 0; round < m_rounds && !result.is_done(); ++ round)
        {
                for (size_t i = 0, size = task.size(fold_tr); i < size; ++ i)
                {
                        const auto input = task.input(fold_tr, i);
                        const auto target = task.target(fold_tr, i);
                        const auto output = outputs_tr.tensor(i);

                        const auto vgrad = loss.vgrad(target, output);
                        residuals_train.vector(i) = -vgrad.vector();
                }

                scalar_t best_value = std::numeric_limits<scalar_t>::max();

                // todo: generalize this - e.g. to use features that are products of two input features
                for (auto feature = 0; feature < nano::size(m_idims); ++ feature)
                {
                        scalars_t fvalues(task.size(fold_tr));
                        for (size_t i = 0, size = task.size(fold_tr); i < size; ++ i)
                        {
                                const auto input = task.input(fold_tr, i);
                                fvalues[i] = input(feature);
                        }

                        auto thresholds = fvalues;
                        std::sort(thresholds.begin(), thresholds.end());
                        thresholds.erase(std::unique(thresholds.begin(), thresholds.end()), thresholds.end());

                        for (size_t t = 0; t + 1 < thresholds.size(); ++ t)
                        {
                                const auto threshold = (thresholds[t + 0] + thresholds[t + 1]) / 2;

                                residuals_pos1.zero(), residuals_pos2.zero();
                                residuals_neg1.zero(), residuals_neg2.zero();

                                int cnt_pos = 0, cnt_neg = 0;
                                for (size_t i = 0, size = task.size(fold_tr); i < size; ++ i)
                                {
                                        const auto residual = residuals_train.array(i);
                                        if (fvalues[i] < threshold)
                                        {
                                                cnt_neg ++;
                                                residuals_neg1.array() += residual;
                                                residuals_neg2.array() += residual * residual;
                                        }
                                        else
                                        {
                                                cnt_pos ++;
                                                residuals_pos1.array() += residual;
                                                residuals_pos2.array() += residual * residual;
                                        }
                                }

                                const auto value =
                                        (residuals_pos2.array().sum() - residuals_pos1.array().square().sum() / cnt_pos) +
                                        (residuals_neg2.array().sum() - residuals_neg1.array().square().sum() / cnt_neg);

                                //log_info() << "feature = " << feature
                                //        << ", threshold = " << threshold
                                //        << ", value = " << value
                                //        << ", count = " << cnt_neg << "+" << cnt_pos << "=" << task.size(fold_tr);

                                if (value < best_value)
                                {
                                        best_value = value;
                                        stump.m_feature = feature;
                                        stump.m_threshold = threshold;
                                        stump.m_outputs.resize(cat_dims(2, m_odims));
                                        stump.m_outputs.vector(0) = residuals_neg1.vector() / cnt_neg;
                                        stump.m_outputs.vector(1) = residuals_pos1.vector() / cnt_pos;
                                }

                                // todo: fit both real and discrete stumps
                        }
                }

                // line-search
                for (size_t i = 0, size = task.size(fold_tr); i < size; ++ i)
                {
                        const auto input = task.input(fold_tr, i);
                        const auto oindex = input(stump.m_feature) < stump.m_threshold ? 0 : 1;
                        stump_outputs_tr.tensor(i) = stump.m_outputs.tensor(oindex);
                }

                const auto state = solver->minimize(100, epsilon2<scalar_t>(), func, vector_t::Constant(1, 0));
                const auto step = state.x(0);

                // todo: break if the line-search fails (e.g. if state.m_iterations == 0

                stump.m_outputs.vector() *= step;
                m_stumps.push_back(stump);

                // update current outputs
                update(task, fold_tr, outputs_tr, stump);
                update(task, fold_vd, outputs_vd, stump);
                update(task, fold_te, outputs_te, stump);

                std::tie(errors_tr, values_tr) = ::measure(task, fold_tr, outputs_tr, loss);
                std::tie(errors_vd, values_vd) = ::measure(task, fold_vd, outputs_vd, loss);
                std::tie(errors_te, values_te) = ::measure(task, fold_te, outputs_te, loss);

                const auto measure_tr = trainer_measurement_t{values_tr.avg(), errors_tr.avg()};
                const auto measure_vd = trainer_measurement_t{values_vd.avg(), errors_vd.avg()};
                const auto measure_te = trainer_measurement_t{values_te.avg(), errors_te.avg()};

                const auto status = result.update(
                        trainer_state_t{timer.milliseconds(), round + 1, measure_tr, measure_vd, measure_te},
                        m_patience);

                log_info() << "[" << (round + 1) << "/" << m_rounds
                        << "]:tr=" << measure_tr
                        << ",vd=" << measure_vd << "|" << status
                        << ",te=" << measure_te
                        << ",feature=" << stump.m_feature
                        << ",solver=(" << state.m_status
                        << ",i=" << state.m_iterations
                        << ",x=" << state.x(0)
                        << ",f=" << state.f
                        << ",g=" << state.convergence_criteria() << ").";
        }

        // keep only the stumps up to optimum epoch (on the validation dataset)
        m_stumps.erase(
                m_stumps.begin() + result.optimum().m_epoch,
                m_stumps.end());

        return result;
}

tensor3d_t gboost_stump_t::output(const tensor3d_t& input) const
{
        assert(input.dims() == m_idims);

        tensor3d_t output(m_odims);
        output.zero();

        const auto idata = input.array();
        auto odata = output.array();

        for (const auto& stump : m_stumps)
        {
                const auto oindex = idata(stump.m_feature) < stump.m_threshold ? 0 : 1;
                odata.array() += stump.m_outputs.array(oindex);
        }

        return output;
}

bool gboost_stump_t::save(obstream_t& stream) const
{
        if (    !stream.write(m_idims) ||
                !stream.write(m_odims) ||
                !stream.write(m_rounds) ||
                !stream.write(m_stype) ||
                !stream.write(m_rtype) ||
                !stream.write(m_stumps.size()))
        {
                return false;
        }

        for (const auto& stump : m_stumps)
        {
                assert(stump.m_feature >= 0 && stump.m_feature < nano::size(m_idims));
                assert(stump.m_outputs.dims() == cat_dims(2, m_odims));

                if (    !stream.write(stump.m_feature) ||
                        !stream.write(stump.m_threshold) ||
                        !stream.write_tensor(stump.m_outputs))
                {
                       return false;
                }
        }

        return true;
}

bool gboost_stump_t::load(ibstream_t& stream)
{
        size_t n_stumps = 0;
        if (    !stream.read(m_idims) ||
                !stream.read(m_odims) ||
                !stream.read(m_rounds) ||
                !stream.read(m_stype) ||
                !stream.read(m_rtype) ||
                !stream.read(n_stumps))
        {
                return false;
        }

        m_stumps.resize(n_stumps);
        for (auto& stump : m_stumps)
        {
                if (    !stream.read(stump.m_feature) ||
                        !stream.read(stump.m_threshold) ||
                        !stream.read_tensor(stump.m_outputs) ||
                        stump.m_feature < 0 ||
                        stump.m_feature >= nano::size(m_idims) ||
                        stump.m_outputs.dims() != cat_dims(2, m_odims))
                {
                        return false;
                }
        }

        // todo: more verbose loading (#stumps, feature or coefficient statistics, idims...)

        return true;
}

probes_t gboost_stump_t::probes() const
{
        // todo: add probes here to measure the training and the evaluation time
        probes_t probes;
        return probes;
}
<|endoftext|>


<commit_before>//
// This file is part of the Marble Virtual Globe.
//
// This program is free software licensed under the GNU LGPL. You can
// find a copy of this license in LICENSE.txt in the top directory of
// the source code.
//
// Copyright 2008      Torsten Rahn   <rahn@kde.org>
//

// Self
#include "AbstractFloatItem.h"

// Qt
#include <QtGui/QMenu>
#include <QtGui/QAction>
#include <QtGui/QDialog>

// Marble
#include "DialogConfigurationInterface.h"
#include "MarbleDebug.h"

namespace Marble
{

class AbstractFloatItemPrivate
{
  public:
    AbstractFloatItemPrivate() : m_contextMenu( 0 )
    {
    }

    ~AbstractFloatItemPrivate()
    {
        delete m_contextMenu;
    }

    static QPen         s_pen;
    static QFont        s_font;

    QMenu* m_contextMenu;
};

QPen         AbstractFloatItemPrivate::s_pen = QPen( Qt::black );
#ifdef Q_OS_MACX
    QFont AbstractFloatItemPrivate::s_font = QFont( "Sans Serif", 10 );
#else
    QFont AbstractFloatItemPrivate::s_font = QFont( "Sans Serif", 8 );
#endif

AbstractFloatItem::AbstractFloatItem( const MarbleModel *marbleModel, const QPointF &point, const QSizeF &size )
    : RenderPlugin( marbleModel ),
      FrameGraphicsItem(),
      d( new AbstractFloatItemPrivate() )
{
    setCacheMode( MarbleGraphicsItem::ItemCoordinateCache );
    setFrame( RectFrame );
    setPadding( 4.0 );
    setContentSize( size );
    setPosition( point );
}

AbstractFloatItem::~AbstractFloatItem()
{
    delete d;
}

QPen AbstractFloatItem::pen() const
{
    return d->s_pen;
}

void AbstractFloatItem::setPen( const QPen &pen )
{
    d->s_pen = pen;
    update();
}

QFont AbstractFloatItem::font() const
{
    return d->s_font;
}

void AbstractFloatItem::setFont( const QFont &font )
{
    d->s_font = font;
    update();
}

QString AbstractFloatItem::renderPolicy() const
{
    return "ALWAYS";
}

QStringList AbstractFloatItem::renderPosition() const
{
    return QStringList( "FLOAT_ITEM" );
}

void AbstractFloatItem::setVisible( bool visible )
{
    // Reimplemented since AbstractFloatItem does multiple inheritance
    // and the (set)Visible() methods are available in both base classes!
    RenderPlugin::setVisible( visible );
}

bool AbstractFloatItem::visible() const
{
    // Reimplemented since AbstractFloatItem does multiple inheritance
    // and the (set)Visible() methods are available in both base classes!
    return RenderPlugin::visible();
}

void AbstractFloatItem::setPositionLocked( bool lock )
{
    ScreenGraphicsItem::GraphicsItemFlags flags = this->flags();

    if ( lock ) {
        flags &= ~ScreenGraphicsItem::ItemIsMovable;
    }
    else {
        flags |= ScreenGraphicsItem::ItemIsMovable;
    }

    setFlags( flags );
}

bool AbstractFloatItem::positionLocked()
{
    return ( flags() & ScreenGraphicsItem::ItemIsMovable ) ? false : true;
}

bool AbstractFloatItem::eventFilter( QObject *object, QEvent *e )
{
    if ( !enabled() || !visible() ) {
        return false;
    }

    if( e->type() == QEvent::ContextMenu )
    {
        QWidget *widget = dynamic_cast<QWidget *>( object );
        QContextMenuEvent *menuEvent = dynamic_cast<QContextMenuEvent *> ( e );
        if( widget != NULL && menuEvent != NULL && contains( menuEvent->pos() ) )
        {
            contextMenuEvent( widget, menuEvent );
            return true;
        }
        return false;
    }
    else if( e->type() == QEvent::ToolTip )
    {
        QHelpEvent *helpEvent = dynamic_cast<QHelpEvent *>( e );
        if( helpEvent != NULL && contains( helpEvent->pos() ) )
        {
            toolTipEvent( helpEvent );
            return true;
        }
        return false;
    }
    else
        return ScreenGraphicsItem::eventFilter( object, e );
}

void AbstractFloatItem::contextMenuEvent ( QWidget *w, QContextMenuEvent *e )
{
    contextMenu()->exec( w->mapToGlobal( e->pos() ) );
}

void AbstractFloatItem::toolTipEvent ( QHelpEvent *e )
{
    Q_UNUSED( e );
}

bool AbstractFloatItem::render( GeoPainter *painter, ViewportParams *viewport,
             const QString& renderPos, GeoSceneLayer * layer )
{
    if ( !enabled() || !visible() ) {
        return true;
    }

    if ( renderPos == "FLOAT_ITEM" ) {
        paintEvent( painter, viewport, renderPos, layer );
        return true;
    }

    return false;
}

void AbstractFloatItem::show()
{
    setVisible( true );
}

void AbstractFloatItem::hide()
{
    setVisible( false );
}

QMenu* AbstractFloatItem::contextMenu()
{
    if ( !d->m_contextMenu )
    {
        d->m_contextMenu = new QMenu;

        QAction *lockAction = d->m_contextMenu->addAction( tr( "&Lock" ) );
        lockAction->setCheckable( true );
        lockAction->setChecked( positionLocked() );
        connect( lockAction, SIGNAL( triggered( bool ) ), this, SLOT( setPositionLocked( bool ) ) );
        QAction *hideAction = d->m_contextMenu->addAction( tr( "&Hide" ) );
        connect( hideAction, SIGNAL( triggered() ), this, SLOT( hide() ) );
        DialogConfigurationInterface *configInterface = qobject_cast<DialogConfigurationInterface *>( this );
        QDialog *dialog = configInterface ? configInterface->configDialog() : 0;
        if( dialog )
        {
            d->m_contextMenu->addSeparator();
            QAction *configAction = d->m_contextMenu->addAction( tr( "&Configure..." ) );
            connect( configAction, SIGNAL( triggered() ), dialog, SLOT( exec() ) );
        }
    }

    Q_ASSERT( d->m_contextMenu );
    return d->m_contextMenu;
}

}

#include "AbstractFloatItem.moc"
<commit_msg>no need to check for renderPosition<commit_after>//
// This file is part of the Marble Virtual Globe.
//
// This program is free software licensed under the GNU LGPL. You can
// find a copy of this license in LICENSE.txt in the top directory of
// the source code.
//
// Copyright 2008      Torsten Rahn   <rahn@kde.org>
//

// Self
#include "AbstractFloatItem.h"

// Qt
#include <QtGui/QMenu>
#include <QtGui/QAction>
#include <QtGui/QDialog>

// Marble
#include "DialogConfigurationInterface.h"
#include "MarbleDebug.h"

namespace Marble
{

class AbstractFloatItemPrivate
{
  public:
    AbstractFloatItemPrivate() : m_contextMenu( 0 )
    {
    }

    ~AbstractFloatItemPrivate()
    {
        delete m_contextMenu;
    }

    static QPen         s_pen;
    static QFont        s_font;

    QMenu* m_contextMenu;
};

QPen         AbstractFloatItemPrivate::s_pen = QPen( Qt::black );
#ifdef Q_OS_MACX
    QFont AbstractFloatItemPrivate::s_font = QFont( "Sans Serif", 10 );
#else
    QFont AbstractFloatItemPrivate::s_font = QFont( "Sans Serif", 8 );
#endif

AbstractFloatItem::AbstractFloatItem( const MarbleModel *marbleModel, const QPointF &point, const QSizeF &size )
    : RenderPlugin( marbleModel ),
      FrameGraphicsItem(),
      d( new AbstractFloatItemPrivate() )
{
    setCacheMode( MarbleGraphicsItem::ItemCoordinateCache );
    setFrame( RectFrame );
    setPadding( 4.0 );
    setContentSize( size );
    setPosition( point );
}

AbstractFloatItem::~AbstractFloatItem()
{
    delete d;
}

QPen AbstractFloatItem::pen() const
{
    return d->s_pen;
}

void AbstractFloatItem::setPen( const QPen &pen )
{
    d->s_pen = pen;
    update();
}

QFont AbstractFloatItem::font() const
{
    return d->s_font;
}

void AbstractFloatItem::setFont( const QFont &font )
{
    d->s_font = font;
    update();
}

QString AbstractFloatItem::renderPolicy() const
{
    return "ALWAYS";
}

QStringList AbstractFloatItem::renderPosition() const
{
    return QStringList( "FLOAT_ITEM" );
}

void AbstractFloatItem::setVisible( bool visible )
{
    // Reimplemented since AbstractFloatItem does multiple inheritance
    // and the (set)Visible() methods are available in both base classes!
    RenderPlugin::setVisible( visible );
}

bool AbstractFloatItem::visible() const
{
    // Reimplemented since AbstractFloatItem does multiple inheritance
    // and the (set)Visible() methods are available in both base classes!
    return RenderPlugin::visible();
}

void AbstractFloatItem::setPositionLocked( bool lock )
{
    ScreenGraphicsItem::GraphicsItemFlags flags = this->flags();

    if ( lock ) {
        flags &= ~ScreenGraphicsItem::ItemIsMovable;
    }
    else {
        flags |= ScreenGraphicsItem::ItemIsMovable;
    }

    setFlags( flags );
}

bool AbstractFloatItem::positionLocked()
{
    return ( flags() & ScreenGraphicsItem::ItemIsMovable ) ? false : true;
}

bool AbstractFloatItem::eventFilter( QObject *object, QEvent *e )
{
    if ( !enabled() || !visible() ) {
        return false;
    }

    if( e->type() == QEvent::ContextMenu )
    {
        QWidget *widget = dynamic_cast<QWidget *>( object );
        QContextMenuEvent *menuEvent = dynamic_cast<QContextMenuEvent *> ( e );
        if( widget != NULL && menuEvent != NULL && contains( menuEvent->pos() ) )
        {
            contextMenuEvent( widget, menuEvent );
            return true;
        }
        return false;
    }
    else if( e->type() == QEvent::ToolTip )
    {
        QHelpEvent *helpEvent = dynamic_cast<QHelpEvent *>( e );
        if( helpEvent != NULL && contains( helpEvent->pos() ) )
        {
            toolTipEvent( helpEvent );
            return true;
        }
        return false;
    }
    else
        return ScreenGraphicsItem::eventFilter( object, e );
}

void AbstractFloatItem::contextMenuEvent ( QWidget *w, QContextMenuEvent *e )
{
    contextMenu()->exec( w->mapToGlobal( e->pos() ) );
}

void AbstractFloatItem::toolTipEvent ( QHelpEvent *e )
{
    Q_UNUSED( e );
}

bool AbstractFloatItem::render( GeoPainter *painter, ViewportParams *viewport,
             const QString& renderPos, GeoSceneLayer * layer )
{
    if ( !enabled() || !visible() ) {
        return true;
    }

    paintEvent( painter, viewport, renderPos, layer );
    return true;
}

void AbstractFloatItem::show()
{
    setVisible( true );
}

void AbstractFloatItem::hide()
{
    setVisible( false );
}

QMenu* AbstractFloatItem::contextMenu()
{
    if ( !d->m_contextMenu )
    {
        d->m_contextMenu = new QMenu;

        QAction *lockAction = d->m_contextMenu->addAction( tr( "&Lock" ) );
        lockAction->setCheckable( true );
        lockAction->setChecked( positionLocked() );
        connect( lockAction, SIGNAL( triggered( bool ) ), this, SLOT( setPositionLocked( bool ) ) );
        QAction *hideAction = d->m_contextMenu->addAction( tr( "&Hide" ) );
        connect( hideAction, SIGNAL( triggered() ), this, SLOT( hide() ) );
        DialogConfigurationInterface *configInterface = qobject_cast<DialogConfigurationInterface *>( this );
        QDialog *dialog = configInterface ? configInterface->configDialog() : 0;
        if( dialog )
        {
            d->m_contextMenu->addSeparator();
            QAction *configAction = d->m_contextMenu->addAction( tr( "&Configure..." ) );
            connect( configAction, SIGNAL( triggered() ), dialog, SLOT( exec() ) );
        }
    }

    Q_ASSERT( d->m_contextMenu );
    return d->m_contextMenu;
}

}

#include "AbstractFloatItem.moc"
<|endoftext|>


<commit_before>/*
    Copyright 2008 Henry de Valence <hdevalence@gmail.com>

    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) version 3, or any
    later version accepted by the membership of KDE e.V. (or its
    successor approved by the membership of KDE e.V.), which shall
    act as a proxy defined in Section 6 of version 3 of the license.

    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, see <http://www.gnu.org/licenses/>.
*/

#include "OnfRunner.h"

#include "MarbleAbstractRunner.h"
#include "MarbleRunnerResult.h"
#include "GeoOnfParser.h"
#include "GeoDataDocument.h"
#include "PlaceMarkContainer.h"

#include <QtCore/QString>
#include <QtCore/QBuffer>
#include <QtCore/QtDebug>

#include <QtNetwork/QHttp>

namespace Marble
{

/*
TODO: grade results individually instead of giving them all a score of 100
*/

OnfRunner::OnfRunner( QObject *parent ) : MarbleAbstractRunner( parent )
{
    qRegisterMetaType<MarbleRunnerResult>();
    m_http = new QHttp("gazetteer.openstreetmap.org");
    m_buffer = 0;

    connect( m_http, SIGNAL( requestFinished( int, bool ) ),
             this, SLOT( slotRequestFinished( int, bool ) ) );
}

OnfRunner::~OnfRunner()
{
    delete m_http;
    delete m_buffer;
}

QString OnfRunner::name() const
{
    return tr("OpenStreetMap Name Finder Runner");
}

void OnfRunner::fail()
{
    //The manager needs to know when parsing starts and stops
    //in order to have a balanced count of active runners. So
    //we emit runnerFinished() to balance the previous failed runnerStarted()
    MarbleRunnerResult fail;
    fail.setRunnerName( name() );
    emit runnerFinished( fail );
    return;
}

void OnfRunner::parse(const QString &input)
{
    emit runnerStarted( name() );
    if( input.isEmpty() ) {
        return;
    }
    //no point to keep downloading if we're doing a new one
    /* //causes crash
    if( m_http->currentId() != 0 ) {
        m_http->abort();
        //aborted parse request fails; this one keeps going.
        fail();
    }
    */
    //make a new buffer
    if( m_buffer ) {
        delete m_buffer;
    }
    m_buffer = new QBuffer;
    qDebug() << "ONF search: GET /namefinder/search.xml?find=" << input;
    m_http->get( "/namefinder/search.xml?find=" + input, m_buffer );
}

void OnfRunner::slotRequestFinished( int id, bool error )
{
    if( error ) {
        qDebug() << "ONF request" << id << "failed:" << m_http->error()
                 << m_http->errorString();
        fail();
        return;
    }

    qDebug() << "ONF search result buffer size:" << m_buffer->size();
    qDebug() << m_buffer->data();

    QByteArray array = m_buffer->data();
    QBuffer data( &array );
    data.open( QIODevice::ReadOnly );

    GeoOnfParser parser;
    if( !parser.read( &data ) ) {
        qWarning() << "Could not parse ONF buffer!!";
        fail();
        return;
    }

    GeoDataDocument *results = static_cast<GeoDataDocument*>( parser.releaseDocument() );
    Q_ASSERT( results );

    PlaceMarkContainer container( results->placemarks(), "ONF Search Results" );
    MarbleRunnerResult result;

    if( container.isEmpty() ) {
        result = MarbleRunnerResult( container, MarbleRunnerResult::NoMatch, name() );
    } else {
        result = MarbleRunnerResult( container, MarbleRunnerResult::PerfectMatch, name() );
    }

    emit runnerFinished( result );
    return;
}

} // namespace Marble

#include "OnfRunner.moc"<commit_msg>add whitespace at the eof<commit_after>/*
    Copyright 2008 Henry de Valence <hdevalence@gmail.com>

    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) version 3, or any
    later version accepted by the membership of KDE e.V. (or its
    successor approved by the membership of KDE e.V.), which shall
    act as a proxy defined in Section 6 of version 3 of the license.

    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, see <http://www.gnu.org/licenses/>.
*/

#include "OnfRunner.h"

#include "MarbleAbstractRunner.h"
#include "MarbleRunnerResult.h"
#include "GeoOnfParser.h"
#include "GeoDataDocument.h"
#include "PlaceMarkContainer.h"

#include <QtCore/QString>
#include <QtCore/QBuffer>
#include <QtCore/QtDebug>

#include <QtNetwork/QHttp>

namespace Marble
{

/*
TODO: grade results individually instead of giving them all a score of 100
*/

OnfRunner::OnfRunner( QObject *parent ) : MarbleAbstractRunner( parent )
{
    qRegisterMetaType<MarbleRunnerResult>();
    m_http = new QHttp("gazetteer.openstreetmap.org");
    m_buffer = 0;

    connect( m_http, SIGNAL( requestFinished( int, bool ) ),
             this, SLOT( slotRequestFinished( int, bool ) ) );
}

OnfRunner::~OnfRunner()
{
    delete m_http;
    delete m_buffer;
}

QString OnfRunner::name() const
{
    return tr("OpenStreetMap Name Finder Runner");
}

void OnfRunner::fail()
{
    //The manager needs to know when parsing starts and stops
    //in order to have a balanced count of active runners. So
    //we emit runnerFinished() to balance the previous failed runnerStarted()
    MarbleRunnerResult fail;
    fail.setRunnerName( name() );
    emit runnerFinished( fail );
    return;
}

void OnfRunner::parse(const QString &input)
{
    emit runnerStarted( name() );
    if( input.isEmpty() ) {
        return;
    }
    //no point to keep downloading if we're doing a new one
    /* //causes crash
    if( m_http->currentId() != 0 ) {
        m_http->abort();
        //aborted parse request fails; this one keeps going.
        fail();
    }
    */
    //make a new buffer
    if( m_buffer ) {
        delete m_buffer;
    }
    m_buffer = new QBuffer;
    qDebug() << "ONF search: GET /namefinder/search.xml?find=" << input;
    m_http->get( "/namefinder/search.xml?find=" + input, m_buffer );
}

void OnfRunner::slotRequestFinished( int id, bool error )
{
    if( error ) {
        qDebug() << "ONF request" << id << "failed:" << m_http->error()
                 << m_http->errorString();
        fail();
        return;
    }

    qDebug() << "ONF search result buffer size:" << m_buffer->size();
    qDebug() << m_buffer->data();

    QByteArray array = m_buffer->data();
    QBuffer data( &array );
    data.open( QIODevice::ReadOnly );

    GeoOnfParser parser;
    if( !parser.read( &data ) ) {
        qWarning() << "Could not parse ONF buffer!!";
        fail();
        return;
    }

    GeoDataDocument *results = static_cast<GeoDataDocument*>( parser.releaseDocument() );
    Q_ASSERT( results );

    PlaceMarkContainer container( results->placemarks(), "ONF Search Results" );
    MarbleRunnerResult result;

    if( container.isEmpty() ) {
        result = MarbleRunnerResult( container, MarbleRunnerResult::NoMatch, name() );
    } else {
        result = MarbleRunnerResult( container, MarbleRunnerResult::PerfectMatch, name() );
    }

    emit runnerFinished( result );
    return;
}

} // namespace Marble

#include "OnfRunner.moc"
<|endoftext|>


<commit_before>#include "object/object.h"
#include "math/intersect.h"

namespace aten
{
	bool face::hit(
		const ray& r,
		real t_min, real t_max,
		hitrecord& rec) const
	{
		bool isHit = false;

#if 0
		const auto v0 = vtx[idx[0]];
		const auto v1 = vtx[idx[1]];
		const auto v2 = vtx[idx[2]];
#else
		const auto& v0 = vtx[0];
		const auto& v1 = vtx[1];
		const auto& v2 = vtx[2];
#endif

		const auto res = intersertTriangle(r, v0->pos, v1->pos, v2->pos);

		if (res.isIntersect) {
			if (res.t < rec.t) {
				rec.t = res.t;

				auto p = r.org + rec.t * r.dir;

				// NOTE
				// http://d.hatena.ne.jp/Zellij/20131207/p1

				// dSWn(barycentric coordinates).
				// v0.
				// p = (1 - a - b)*v0 + a*v1 + b*v2
				rec.p = (1 - res.a - res.b) * v0->pos + res.a * v1->pos + res.b * v2->pos;
				rec.normal = (1 - res.a - res.b) * v0->nml + res.a * v1->nml + res.b * v2->nml;
				auto uv = (1 - res.a - res.b) * v0->uv + res.a * v1->uv + res.b * v2->uv;

				rec.u = uv.x;
				rec.v = uv.y;

				// tangent coordinate.
				rec.du = normalize(getOrthoVector(rec.normal));
				rec.dv = normalize(cross(rec.normal, rec.du));

				rec.area = area;

				//rec.obj = parent;
				rec.obj = (hitable*)this;

				if (parent) {
					rec.mtrl = parent->mtrl;
				}

				isHit = true;
			}
		}

		return isHit;
	}

	void face::build(vertex* v0, vertex* v1, vertex* v2)
	{
		vec3 vmax(
			std::max(v0->pos.x, std::max(v1->pos.x, v2->pos.x)),
			std::max(v0->pos.y, std::max(v1->pos.y, v2->pos.y)),
			std::max(v0->pos.z, std::max(v1->pos.z, v2->pos.z)));

		vec3 vmin(
			std::min(v0->pos.x, std::min(v1->pos.x, v2->pos.x)),
			std::min(v0->pos.y, std::min(v1->pos.y, v2->pos.y)),
			std::min(v0->pos.z, std::min(v1->pos.z, v2->pos.z)));

		bbox.init(vmin, vmax);

		vtx[0] = v0;
		vtx[1] = v1;
		vtx[2] = v2;

		// Op`̖ʐ = Qӂ̊Oς̒ / 2;
		auto e0 = v1->pos - v0->pos;
		auto e1 = v2->pos - v0->pos;
		area = 0.5 * cross(e0, e1).length();
	}

	vec3 face::getRandomPosOn(sampler* sampler) const
	{
		// 0 <= a + b <= 1
		real a = sampler->nextSample();
		real b = sampler->nextSample();

		real d = a + b;

		if (d > 1) {
			a /= d;
			b /= d;
		}

		const auto& v0 = vtx[0];
		const auto& v1 = vtx[1];
		const auto& v2 = vtx[2];

		// dSWn(barycentric coordinates).
		// v0.
		// p = (1 - a - b)*v0 + a*v1 + b*v2
		vec3 p = (1 - a - b) * v0->pos + a * v1->pos + b * v2->pos;

		return std::move(p);
	}

	void shape::build()
	{
		m_node.build(
			(bvhnode**)&faces[0],
			(uint32_t)faces.size());

		m_aabb = m_node.getBoundingbox();

		area = 0;
		for (const auto f : faces) {
			area += f->area;
		}
	}

	bool shape::hit(
		const ray& r,
		real t_min, real t_max,
		hitrecord& rec) const
	{
		auto isHit = m_node.hit(r, t_min, t_max, rec);

		if (isHit) {
			rec.mtrl = mtrl;
		}

		return isHit;
	}

	void object::build()
	{
		m_node.build((bvhnode**)&shapes[0], (uint32_t)shapes.size());

		m_area = 0;
		m_triangles = 0;

		for (const auto s : shapes) {
			m_area += s->area;
			m_triangles += s->faces.size();
		}
	}

	bool object::hit(
		const ray& r,
		const mat4& mtxL2W,
		real t_min, real t_max,
		hitrecord& rec)
	{
		bool isHit = m_node.hit(r, t_min, t_max, rec);
		if (isHit) {
			face* f = (face*)rec.obj;

			auto v0 = mtxL2W.apply(f->vtx[0]->pos);
			auto v1 = mtxL2W.apply(f->vtx[1]->pos);
			auto v2 = mtxL2W.apply(f->vtx[2]->pos);

			// Op`̖ʐ = Qӂ̊Oς̒ / 2;
			auto e0 = v1 - v0;
			auto e1 = v2 - v0;
			auto area = 0.5 * cross(e0, e1).length();

			rec.area = area;

			// TODO
			// OPDFƂĈ̂ŁAmvZĂ܂.
			// ϐςׂ...
			rec.area *= m_triangles;

			// ŏIIɂ́Aςshapen.
			rec.obj = f->parent;
		}
		return isHit;
	}
}
<commit_msg>Use square of distance scale to compute area.<commit_after>#include "object/object.h"
#include "math/intersect.h"

namespace aten
{
	bool face::hit(
		const ray& r,
		real t_min, real t_max,
		hitrecord& rec) const
	{
		bool isHit = false;

#if 0
		const auto v0 = vtx[idx[0]];
		const auto v1 = vtx[idx[1]];
		const auto v2 = vtx[idx[2]];
#else
		const auto& v0 = vtx[0];
		const auto& v1 = vtx[1];
		const auto& v2 = vtx[2];
#endif

		const auto res = intersertTriangle(r, v0->pos, v1->pos, v2->pos);

		if (res.isIntersect) {
			if (res.t < rec.t) {
				rec.t = res.t;

				auto p = r.org + rec.t * r.dir;

				// NOTE
				// http://d.hatena.ne.jp/Zellij/20131207/p1

				// dSWn(barycentric coordinates).
				// v0.
				// p = (1 - a - b)*v0 + a*v1 + b*v2
				rec.p = (1 - res.a - res.b) * v0->pos + res.a * v1->pos + res.b * v2->pos;
				rec.normal = (1 - res.a - res.b) * v0->nml + res.a * v1->nml + res.b * v2->nml;
				auto uv = (1 - res.a - res.b) * v0->uv + res.a * v1->uv + res.b * v2->uv;

				rec.u = uv.x;
				rec.v = uv.y;

				// tangent coordinate.
				rec.du = normalize(getOrthoVector(rec.normal));
				rec.dv = normalize(cross(rec.normal, rec.du));

				rec.area = area;

				//rec.obj = parent;
				rec.obj = (hitable*)this;

				if (parent) {
					rec.mtrl = parent->mtrl;
				}

				isHit = true;
			}
		}

		return isHit;
	}

	void face::build(vertex* v0, vertex* v1, vertex* v2)
	{
		vec3 vmax(
			std::max(v0->pos.x, std::max(v1->pos.x, v2->pos.x)),
			std::max(v0->pos.y, std::max(v1->pos.y, v2->pos.y)),
			std::max(v0->pos.z, std::max(v1->pos.z, v2->pos.z)));

		vec3 vmin(
			std::min(v0->pos.x, std::min(v1->pos.x, v2->pos.x)),
			std::min(v0->pos.y, std::min(v1->pos.y, v2->pos.y)),
			std::min(v0->pos.z, std::min(v1->pos.z, v2->pos.z)));

		bbox.init(vmin, vmax);

		vtx[0] = v0;
		vtx[1] = v1;
		vtx[2] = v2;

		// Op`̖ʐ = Qӂ̊Oς̒ / 2;
		auto e0 = v1->pos - v0->pos;
		auto e1 = v2->pos - v0->pos;
		area = 0.5 * cross(e0, e1).length();
	}

	vec3 face::getRandomPosOn(sampler* sampler) const
	{
		// 0 <= a + b <= 1
		real a = sampler->nextSample();
		real b = sampler->nextSample();

		real d = a + b;

		if (d > 1) {
			a /= d;
			b /= d;
		}

		const auto& v0 = vtx[0];
		const auto& v1 = vtx[1];
		const auto& v2 = vtx[2];

		// dSWn(barycentric coordinates).
		// v0.
		// p = (1 - a - b)*v0 + a*v1 + b*v2
		vec3 p = (1 - a - b) * v0->pos + a * v1->pos + b * v2->pos;

		return std::move(p);
	}

	void shape::build()
	{
		m_node.build(
			(bvhnode**)&faces[0],
			(uint32_t)faces.size());

		m_aabb = m_node.getBoundingbox();

		area = 0;
		for (const auto f : faces) {
			area += f->area;
		}
	}

	bool shape::hit(
		const ray& r,
		real t_min, real t_max,
		hitrecord& rec) const
	{
		auto isHit = m_node.hit(r, t_min, t_max, rec);

		if (isHit) {
			rec.mtrl = mtrl;
		}

		return isHit;
	}

	void object::build()
	{
		m_node.build((bvhnode**)&shapes[0], (uint32_t)shapes.size());

		m_area = 0;
		m_triangles = 0;

		for (const auto s : shapes) {
			m_area += s->area;
			m_triangles += s->faces.size();
		}
	}

	bool object::hit(
		const ray& r,
		const mat4& mtxL2W,
		real t_min, real t_max,
		hitrecord& rec)
	{
		bool isHit = m_node.hit(r, t_min, t_max, rec);
		if (isHit) {
			face* f = (face*)rec.obj;

#if 0
			real originalArea = 0;
			{
				const auto& v0 = f->vtx[0]->pos;
				const auto& v1 = f->vtx[1]->pos;
				const auto& v2 = f->vtx[2]->pos;

				// Op`̖ʐ = Qӂ̊Oς̒ / 2;
				auto e0 = v1 - v0;
				auto e1 = v2 - v0;
				originalArea = 0.5 * cross(e0, e1).length();
			}

			real scaledArea = 0;
			{
				auto v0 = mtxL2W.apply(f->vtx[0]->pos);
				auto v1 = mtxL2W.apply(f->vtx[1]->pos);
				auto v2 = mtxL2W.apply(f->vtx[2]->pos);

				// Op`̖ʐ = Qӂ̊Oς̒ / 2;
				auto e0 = v1 - v0;
				auto e1 = v2 - v0;
				scaledArea = 0.5 * cross(e0, e1).length();
			}

			real ratio = scaledArea / originalArea;
#else
			real orignalLen = 0;
			{
				const auto& v0 = f->vtx[0]->pos;
				const auto& v1 = f->vtx[1]->pos;

				orignalLen = (v1 - v0).length();
			}

			real scaledLen = 0;
			{
				auto v0 = mtxL2W.apply(f->vtx[0]->pos);
				auto v1 = mtxL2W.apply(f->vtx[1]->pos);

				scaledLen = (v1 - v0).length();
			}

			real ratio = scaledLen / orignalLen;
			ratio = ratio * ratio;
#endif

			rec.area = m_area * ratio;

			// ŏIIɂ́Aςshapen.
			rec.obj = f->parent;
		}
		return isHit;
	}
}
<|endoftext|>


<commit_before>/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** Commercial Usage
**
** Licensees holding valid Qt Commercial licenses may use this file in
** accordance with the Qt Commercial License Agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Nokia.
**
** GNU Lesser General Public License Usage
**
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** If you are unsure which license is appropriate for your use, please
** contact the sales department at http://qt.nokia.com/contact.
**
**************************************************************************/

#include "qmljscheck.h"
#include "qmljsbind.h"
#include "qmljsinterpreter.h"
#include "qmljsevaluate.h"
#include "parser/qmljsast_p.h"

#include <QtCore/QDebug>
#include <QtCore/QCoreApplication>
#include <QtGui/QColor>
#include <QtGui/QApplication>

#ifndef NO_DECLARATIVE_BACKEND
#  include <QtDeclarative/private/qmlstringconverters_p.h> // ### remove me
#endif

namespace QmlJS {
namespace Messages {
static const char *invalid_property_name =  QT_TRANSLATE_NOOP("QmlJS::Check", "'%1' is not a valid property name");
static const char *unknown_type = QT_TRANSLATE_NOOP("QmlJS::Check", "unknown type");
static const char *has_no_members = QT_TRANSLATE_NOOP("QmlJS::Check", "'%1' does not have members");
static const char *is_not_a_member = QT_TRANSLATE_NOOP("QmlJS::Check", "'%1' is not a member of '%2'");
static const char *easing_curve_not_a_string = QT_TRANSLATE_NOOP("QmlJS::Check", "easing-curve name is not a string");
static const char *unknown_easing_curve_name = QT_TRANSLATE_NOOP("QmlJS::Check", "unknown easing-curve name");
static const char *value_might_be_undefined = QT_TRANSLATE_NOOP("QmlJS::Check", "value might be 'undefined'");
} // namespace Messages

static inline QString tr(const char *msg)
{ return qApp->translate("QmlJS::Check", msg); }

} // namespace QmlJS

using namespace QmlJS;
using namespace QmlJS::AST;
using namespace QmlJS::Interpreter;

Check::Check(Document::Ptr doc, const Snapshot &snapshot)
    : _doc(doc)
    , _snapshot(snapshot)
    , _context(&_engine)
    , _link(&_context, doc, snapshot)
    , _scopeBuilder(doc, &_context)
{
}

Check::~Check()
{
}

QList<DiagnosticMessage> Check::operator()()
{
    _messages.clear();
    Node::accept(_doc->ast(), this);
    return _messages;
}

bool Check::visit(UiProgram *)
{
    // build the initial scope chain
    _link.scopeChainAt(_doc);

    return true;
}

bool Check::visit(UiObjectDefinition *ast)
{
    visitQmlObject(ast, ast->qualifiedTypeNameId, ast->initializer);
    return false;
}

bool Check::visit(UiObjectBinding *ast)
{
    checkScopeObjectMember(ast->qualifiedId);

    visitQmlObject(ast, ast->qualifiedTypeNameId, ast->initializer);
    return false;
}

void Check::visitQmlObject(Node *ast, UiQualifiedId *typeId,
                           UiObjectInitializer *initializer)
{
    // If the 'typeId' starts with a lower-case letter, it doesn't define
    // a new object instance. For instance: anchors { ... }
    if (typeId->name->asString().at(0).isLower() && ! typeId->next) {
        checkScopeObjectMember(typeId);
        // ### don't give up!
        return;
    }

    _scopeBuilder.push(ast);

    if (! _context.lookupType(_doc.data(), typeId)) {
        warning(typeId->identifierToken, tr(Messages::unknown_type));
        // suppress subsequent errors about scope object lookup by clearing
        // the scope object list
        // ### todo: better way?
        _context.scopeChain().qmlScopeObjects.clear();
        _context.scopeChain().update();
    }

    Node::accept(initializer, this);

    _scopeBuilder.pop();
}

void Check::errorOnWrongRhs(const SourceLocation &loc, const Value *lhsValue)
{
    if (lhsValue->asBooleanValue()) {
        error(loc, QCoreApplication::translate("QmlJS::Check", "boolean value expected"));
    } else if (lhsValue->asNumberValue()) {
        error(loc, QCoreApplication::translate("QmlJS::Check", "numerical value expected"));
    } else if (lhsValue->asStringValue()) {
        error(loc, QCoreApplication::translate("QmlJS::Check", "string value expected"));
    }
}

bool Check::visit(UiScriptBinding *ast)
{
    const Value *lhsValue = checkScopeObjectMember(ast->qualifiedId);
    if (lhsValue) {
        // ### Fix the evaluator to accept statements!
        if (ExpressionStatement *expStmt = cast<ExpressionStatement *>(ast->statement)) {
            ExpressionNode *expr = expStmt->expression;

            Evaluate evaluator(&_context);
            const Value *rhsValue = evaluator(expr);

            const SourceLocation loc = locationFromRange(expStmt->firstSourceLocation(),
                                                         expStmt->lastSourceLocation());
            checkPropertyAssignment(loc, lhsValue, rhsValue, expr);
        }

    }

    return true;
}

void Check::checkPropertyAssignment(const SourceLocation &location,
                                    const Interpreter::Value *lhsValue,
                                    const Interpreter::Value *rhsValue,
                                    ExpressionNode *ast)
{
    UnaryMinusExpression *unaryMinus = cast<UnaryMinusExpression *>(ast);

    // Qml is particularly strict with literals
    if (StringLiteral *stringLiteral = cast<StringLiteral *>(ast)) {
        const QString string = stringLiteral->value->asString();

        if (lhsValue->asStringValue()) {
            // okay
        } else if (lhsValue->asColorValue()) {
#ifndef NO_DECLARATIVE_BACKEND
            bool ok = false;
            QmlStringConverters::colorFromString(string, &ok);
            if (!ok)
                error(location, QCoreApplication::translate("QmlJS::Check", "not a valid color"));
#endif
        } else if (lhsValue->asEasingCurveNameValue()) {
            // ### do something with easing-curve attributes.
            // ### Incomplete documentation at: http://qt.nokia.com/doc/4.7-snapshot/qml-propertyanimation.html#easing-prop
            // ### The implementation is at: src/declarative/util/qmlanimation.cpp
            const QString curveName = string.left(string.indexOf(QLatin1Char('(')));
            if (!EasingCurveNameValue::curveNames().contains(curveName)) {
                error(location, tr(Messages::unknown_easing_curve_name));
            }
        } else {
            errorOnWrongRhs(location, lhsValue);
        }
    } else if ((ast->kind == Node::Kind_TrueLiteral
                || ast->kind == Node::Kind_FalseLiteral)
               && ! lhsValue->asBooleanValue()) {
        errorOnWrongRhs(location, lhsValue);
    } else if (cast<NumericLiteral *>(ast)
               && ! lhsValue->asNumberValue()) {
        errorOnWrongRhs(location, lhsValue);
    } else if (unaryMinus && cast<NumericLiteral *>(unaryMinus->expression)
               && ! lhsValue->asNumberValue()) {
        errorOnWrongRhs(location, lhsValue);
    } else {
        // rhs is not a literal
        if (lhsValue->asEasingCurveNameValue()) {
            const StringValue *rhsStringValue = rhsValue->asStringValue();
            if (!rhsStringValue) {
                if (rhsValue->asUndefinedValue())
                    warning(location, tr(Messages::value_might_be_undefined));
                else
                    error(location, tr(Messages::easing_curve_not_a_string));
                return;
            }
        }
    }
}

bool Check::visit(UiArrayBinding *ast)
{
    checkScopeObjectMember(ast->qualifiedId);

    return true;
}

const Value *Check::checkScopeObjectMember(const UiQualifiedId *id)
{
    QList<const ObjectValue *> scopeObjects = _context.scopeChain().qmlScopeObjects;
    if (scopeObjects.isEmpty())
        return 0;

    if (! id)
        return 0; // ### error?

    QString propertyName = id->name->asString();

    if (propertyName == QLatin1String("id") && ! id->next)
        return 0; // ### should probably be a special value

    // attached properties
    bool isAttachedProperty = false;
    if (! propertyName.isEmpty() && propertyName[0].isUpper()) {
        isAttachedProperty = true;
        scopeObjects += _context.scopeChain().qmlTypes;
    }

    if (scopeObjects.isEmpty())
        return 0;

    // global lookup for first part of id
    const Value *value = 0;
    for (int i = scopeObjects.size() - 1; i >= 0; --i) {
        value = scopeObjects[i]->lookupMember(propertyName, &_context);
        if (value)
            break;
    }
    if (!value) {
        error(id->identifierToken,
              tr(Messages::invalid_property_name).arg(propertyName));
    }

    // can't look up members for attached properties
    if (isAttachedProperty)
        return 0;

    // member lookup
    const UiQualifiedId *idPart = id;
    while (idPart->next) {
        const ObjectValue *objectValue = value_cast<const ObjectValue *>(value);
        if (! objectValue) {
            error(idPart->identifierToken,
                  tr(Messages::has_no_members).arg(propertyName));
            return 0;
        }

        idPart = idPart->next;
        propertyName = idPart->name->asString();

        value = objectValue->lookupMember(propertyName, &_context);
        if (! value) {
            error(idPart->identifierToken,
                  tr(Messages::is_not_a_member).arg(propertyName,
                                               objectValue->className()));
            return 0;
        }
    }

    return value;
}

void Check::error(const AST::SourceLocation &loc, const QString &message)
{
    _messages.append(DiagnosticMessage(DiagnosticMessage::Error, loc, message));
}

void Check::warning(const AST::SourceLocation &loc, const QString &message)
{
    _messages.append(DiagnosticMessage(DiagnosticMessage::Warning, loc, message));
}

SourceLocation Check::locationFromRange(const SourceLocation &start,
                                        const SourceLocation &end)
{
    return SourceLocation(start.offset,
                          end.end() - start.begin(),
                          start.startLine,
                          start.startColumn);
}
<commit_msg>Check that the id property is a plain lowercase identifier.<commit_after>/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** Commercial Usage
**
** Licensees holding valid Qt Commercial licenses may use this file in
** accordance with the Qt Commercial License Agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Nokia.
**
** GNU Lesser General Public License Usage
**
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** If you are unsure which license is appropriate for your use, please
** contact the sales department at http://qt.nokia.com/contact.
**
**************************************************************************/

#include "qmljscheck.h"
#include "qmljsbind.h"
#include "qmljsinterpreter.h"
#include "qmljsevaluate.h"
#include "parser/qmljsast_p.h"

#include <QtCore/QDebug>
#include <QtCore/QCoreApplication>
#include <QtGui/QColor>
#include <QtGui/QApplication>

#ifndef NO_DECLARATIVE_BACKEND
#  include <QtDeclarative/private/qmlstringconverters_p.h> // ### remove me
#endif

namespace QmlJS {
namespace Messages {
static const char *invalid_property_name =  QT_TRANSLATE_NOOP("QmlJS::Check", "'%1' is not a valid property name");
static const char *unknown_type = QT_TRANSLATE_NOOP("QmlJS::Check", "unknown type");
static const char *has_no_members = QT_TRANSLATE_NOOP("QmlJS::Check", "'%1' does not have members");
static const char *is_not_a_member = QT_TRANSLATE_NOOP("QmlJS::Check", "'%1' is not a member of '%2'");
static const char *easing_curve_not_a_string = QT_TRANSLATE_NOOP("QmlJS::Check", "easing-curve name is not a string");
static const char *unknown_easing_curve_name = QT_TRANSLATE_NOOP("QmlJS::Check", "unknown easing-curve name");
static const char *value_might_be_undefined = QT_TRANSLATE_NOOP("QmlJS::Check", "value might be 'undefined'");
} // namespace Messages

static inline QString tr(const char *msg)
{ return qApp->translate("QmlJS::Check", msg); }

} // namespace QmlJS

using namespace QmlJS;
using namespace QmlJS::AST;
using namespace QmlJS::Interpreter;

Check::Check(Document::Ptr doc, const Snapshot &snapshot)
    : _doc(doc)
    , _snapshot(snapshot)
    , _context(&_engine)
    , _link(&_context, doc, snapshot)
    , _scopeBuilder(doc, &_context)
{
}

Check::~Check()
{
}

QList<DiagnosticMessage> Check::operator()()
{
    _messages.clear();
    Node::accept(_doc->ast(), this);
    return _messages;
}

bool Check::visit(UiProgram *)
{
    // build the initial scope chain
    _link.scopeChainAt(_doc);

    return true;
}

bool Check::visit(UiObjectDefinition *ast)
{
    visitQmlObject(ast, ast->qualifiedTypeNameId, ast->initializer);
    return false;
}

bool Check::visit(UiObjectBinding *ast)
{
    checkScopeObjectMember(ast->qualifiedId);

    visitQmlObject(ast, ast->qualifiedTypeNameId, ast->initializer);
    return false;
}

void Check::visitQmlObject(Node *ast, UiQualifiedId *typeId,
                           UiObjectInitializer *initializer)
{
    // If the 'typeId' starts with a lower-case letter, it doesn't define
    // a new object instance. For instance: anchors { ... }
    if (typeId->name->asString().at(0).isLower() && ! typeId->next) {
        checkScopeObjectMember(typeId);
        // ### don't give up!
        return;
    }

    _scopeBuilder.push(ast);

    if (! _context.lookupType(_doc.data(), typeId)) {
        warning(typeId->identifierToken, tr(Messages::unknown_type));
        // suppress subsequent errors about scope object lookup by clearing
        // the scope object list
        // ### todo: better way?
        _context.scopeChain().qmlScopeObjects.clear();
        _context.scopeChain().update();
    }

    Node::accept(initializer, this);

    _scopeBuilder.pop();
}

void Check::errorOnWrongRhs(const SourceLocation &loc, const Value *lhsValue)
{
    if (lhsValue->asBooleanValue()) {
        error(loc, QCoreApplication::translate("QmlJS::Check", "boolean value expected"));
    } else if (lhsValue->asNumberValue()) {
        error(loc, QCoreApplication::translate("QmlJS::Check", "numerical value expected"));
    } else if (lhsValue->asStringValue()) {
        error(loc, QCoreApplication::translate("QmlJS::Check", "string value expected"));
    }
}

bool Check::visit(UiScriptBinding *ast)
{
    // special case for id property
    if (ast->qualifiedId->name->asString() == QLatin1String("id") && ! ast->qualifiedId->next) {
        if (! ast->statement)
            return false;

        const SourceLocation loc = locationFromRange(ast->statement->firstSourceLocation(),
                                                     ast->statement->lastSourceLocation());

        ExpressionStatement *expStmt = cast<ExpressionStatement *>(ast->statement);
        if (!expStmt) {
            error(loc, QCoreApplication::translate("QmlJS::Check", "expected id"));
            return false;
        }

        IdentifierExpression *idExp = cast<IdentifierExpression *>(expStmt->expression);
        if (! idExp) {
            error(loc, QCoreApplication::translate("QmlJS::Check", "expected id"));
            return false;
        }

        if (! idExp->name->asString()[0].isLower()) {
            error(loc, QCoreApplication::translate("QmlJS::Check", "ids must be lower case"));
            return false;
        }
    }

    const Value *lhsValue = checkScopeObjectMember(ast->qualifiedId);
    if (lhsValue) {
        // ### Fix the evaluator to accept statements!
        if (ExpressionStatement *expStmt = cast<ExpressionStatement *>(ast->statement)) {
            ExpressionNode *expr = expStmt->expression;

            Evaluate evaluator(&_context);
            const Value *rhsValue = evaluator(expr);

            const SourceLocation loc = locationFromRange(expStmt->firstSourceLocation(),
                                                         expStmt->lastSourceLocation());
            checkPropertyAssignment(loc, lhsValue, rhsValue, expr);
        }

    }

    return true;
}

void Check::checkPropertyAssignment(const SourceLocation &location,
                                    const Interpreter::Value *lhsValue,
                                    const Interpreter::Value *rhsValue,
                                    ExpressionNode *ast)
{
    UnaryMinusExpression *unaryMinus = cast<UnaryMinusExpression *>(ast);

    // Qml is particularly strict with literals
    if (StringLiteral *stringLiteral = cast<StringLiteral *>(ast)) {
        const QString string = stringLiteral->value->asString();

        if (lhsValue->asStringValue()) {
            // okay
        } else if (lhsValue->asColorValue()) {
#ifndef NO_DECLARATIVE_BACKEND
            bool ok = false;
            QmlStringConverters::colorFromString(string, &ok);
            if (!ok)
                error(location, QCoreApplication::translate("QmlJS::Check", "not a valid color"));
#endif
        } else if (lhsValue->asEasingCurveNameValue()) {
            // ### do something with easing-curve attributes.
            // ### Incomplete documentation at: http://qt.nokia.com/doc/4.7-snapshot/qml-propertyanimation.html#easing-prop
            // ### The implementation is at: src/declarative/util/qmlanimation.cpp
            const QString curveName = string.left(string.indexOf(QLatin1Char('(')));
            if (!EasingCurveNameValue::curveNames().contains(curveName)) {
                error(location, tr(Messages::unknown_easing_curve_name));
            }
        } else {
            errorOnWrongRhs(location, lhsValue);
        }
    } else if ((ast->kind == Node::Kind_TrueLiteral
                || ast->kind == Node::Kind_FalseLiteral)
               && ! lhsValue->asBooleanValue()) {
        errorOnWrongRhs(location, lhsValue);
    } else if (cast<NumericLiteral *>(ast)
               && ! lhsValue->asNumberValue()) {
        errorOnWrongRhs(location, lhsValue);
    } else if (unaryMinus && cast<NumericLiteral *>(unaryMinus->expression)
               && ! lhsValue->asNumberValue()) {
        errorOnWrongRhs(location, lhsValue);
    } else {
        // rhs is not a literal
        if (lhsValue->asEasingCurveNameValue()) {
            const StringValue *rhsStringValue = rhsValue->asStringValue();
            if (!rhsStringValue) {
                if (rhsValue->asUndefinedValue())
                    warning(location, tr(Messages::value_might_be_undefined));
                else
                    error(location, tr(Messages::easing_curve_not_a_string));
                return;
            }
        }
    }
}

bool Check::visit(UiArrayBinding *ast)
{
    checkScopeObjectMember(ast->qualifiedId);

    return true;
}

const Value *Check::checkScopeObjectMember(const UiQualifiedId *id)
{
    QList<const ObjectValue *> scopeObjects = _context.scopeChain().qmlScopeObjects;
    if (scopeObjects.isEmpty())
        return 0;

    if (! id)
        return 0; // ### error?

    QString propertyName = id->name->asString();

    if (propertyName == QLatin1String("id") && ! id->next)
        return 0; // ### should probably be a special value

    // attached properties
    bool isAttachedProperty = false;
    if (! propertyName.isEmpty() && propertyName[0].isUpper()) {
        isAttachedProperty = true;
        scopeObjects += _context.scopeChain().qmlTypes;
    }

    if (scopeObjects.isEmpty())
        return 0;

    // global lookup for first part of id
    const Value *value = 0;
    for (int i = scopeObjects.size() - 1; i >= 0; --i) {
        value = scopeObjects[i]->lookupMember(propertyName, &_context);
        if (value)
            break;
    }
    if (!value) {
        error(id->identifierToken,
              tr(Messages::invalid_property_name).arg(propertyName));
    }

    // can't look up members for attached properties
    if (isAttachedProperty)
        return 0;

    // member lookup
    const UiQualifiedId *idPart = id;
    while (idPart->next) {
        const ObjectValue *objectValue = value_cast<const ObjectValue *>(value);
        if (! objectValue) {
            error(idPart->identifierToken,
                  tr(Messages::has_no_members).arg(propertyName));
            return 0;
        }

        idPart = idPart->next;
        propertyName = idPart->name->asString();

        value = objectValue->lookupMember(propertyName, &_context);
        if (! value) {
            error(idPart->identifierToken,
                  tr(Messages::is_not_a_member).arg(propertyName,
                                               objectValue->className()));
            return 0;
        }
    }

    return value;
}

void Check::error(const AST::SourceLocation &loc, const QString &message)
{
    _messages.append(DiagnosticMessage(DiagnosticMessage::Error, loc, message));
}

void Check::warning(const AST::SourceLocation &loc, const QString &message)
{
    _messages.append(DiagnosticMessage(DiagnosticMessage::Warning, loc, message));
}

SourceLocation Check::locationFromRange(const SourceLocation &start,
                                        const SourceLocation &end)
{
    return SourceLocation(start.offset,
                          end.end() - start.begin(),
                          start.startLine,
                          start.startColumn);
}
<|endoftext|>


<commit_before>/* MIT License
 *
 * Copyright (c) 2016 Omar Alvarez <omar.alvarez@udc.es>
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

#include <chrono>

#include "gpusolver.h"

#define DEBUG

GPUSolver::GPUSolver() {

	/* Notes
	I've added some extra parameters in this interface to assist with dev, such as
	a kernel string to specify which kernel to run and local/global work sizes.

	The following are private members of the class, but I have them here to specify the
	global work size for now. This will probably be hard-coded later
	*/
	unsigned int z_n = 200;
	unsigned int z_k = 9;
	size_t z_collision_bit_length = z_n / (z_k + 1);
	eh_index z_N = 1 << (z_collision_bit_length + 1);
	//uint32_t global_work_size = z_N;

	//TODO This looks like IND_PER_BUCKET, enough for GPU?
	size_t global_work_size = 1 << 20;
    size_t local_work_size = 32;

	miner = new cl_zogminer();

	/* Checks each device for memory requirements and sets local/global sizes
	TODO: Implement device logic for equihash kernel
	@params: unsigned platformId
	@params: unsigned localWorkSizes
	@params: unsigned globalWorkSizes
	*/
	GPU = miner->configureGPU(0, local_work_size, global_work_size);
	if(!GPU)
		std::cout << "ERROR: No suitable GPU found! No work will be performed!" << std::endl;

	/*Initialize the kernel, compile it and create buffers
	Currently runs for the gpu-list-gen.c kernel DATA_SIZE=100 times
	TODO: pass base state and nonce's to kernel.
	@params: unsigned _platformId
	@params: unsigned _deviceId
	@params: string& _kernel - The name of the kernel for dev purposes
	*/
	std::vector<std::string> kernels {"initial_bucket_hashing", "bucket_collide_and_hash", "produce_solutions"};
	if(GPU)
		initOK = miner->init(0, 0, kernels);

}

GPUSolver::GPUSolver(int64_t selGPU) {

	/* Notes
	I've added some extra parameters in this interface to assist with dev, such as
	a kernel string to specify which kernel to run and local/global work sizes.

	The following are private members of the class, but I have them here to specify the
	global work size for now. This will probably be hard-coded later
	*/
	unsigned int z_n = 200;
	unsigned int z_k = 9;
	size_t z_collision_bit_length = z_n / (z_k + 1);
	eh_index z_N = 1 << (z_collision_bit_length + 1);
	//uint32_t global_work_size = z_N;

	//TODO This looks like IND_PER_BUCKET, enough for GPU?
	size_t global_work_size = 1 << 17;
    size_t local_work_size = 32;

	miner = new cl_zogminer();

	/* Checks each device for memory requirements and sets local/global sizes
	TODO: Implement device logic for equihash kernel
	@params: unsigned platformId
	@params: unsigned localWorkSizes
	@params: unsigned globalWorkSizes
	*/
	GPU = miner->configureGPU(0, local_work_size, global_work_size);
	if(!GPU)
		std::cout << "ERROR: No suitable GPU found! No work will be performed!" << std::endl;

	/*Initialize the kernel, compile it and create buffers
	Currently runs for the gpu-list-gen.c kernel DATA_SIZE=100 times
	TODO: pass base state and nonce's to kernel.
	@params: unsigned _platformId
	@params: unsigned _deviceId
	@params: string& _kernel - The name of the kernel for dev purposes
	*/
	std::vector<std::string> kernels {"initial_bucket_hashing", "bucket_collide_and_hash", "produce_solutions"};
	if(GPU)
		initOK = miner->init(0, selGPU, kernels);

}

GPUSolver::~GPUSolver() {

	if(GPU)
		miner->finish();

	delete miner;

}

bool GPUSolver::run(unsigned int n, unsigned int k, const eh_HashState& base_state,
		            const std::function<bool(std::vector<unsigned char>)> validBlock,
				const std::function<bool(GPUSolverCancelCheck)> cancelled) {

    if (n == 200 && k == 9) {
        return GPUSolve200_9(base_state, validBlock, cancelled);
    } else {
        throw std::invalid_argument("Unsupported Equihash parameters");
    }

}

bool GPUSolver::GPUSolve200_9(const eh_HashState& base_state,
                 	const std::function<bool(std::vector<unsigned char>)> validBlock,
			const std::function<bool(GPUSolverCancelCheck)> cancelled) {

	/* Run the kernel
	TODO: Optimise and figure out how we want this to go
	@params eh_HashState& base_state - Sends to kernel in a buffer. Will update for specific kernels
	*/

	if(GPU && initOK) {
        auto t = std::chrono::high_resolution_clock::now();

		uint32_t n_sol;

    	miner->run(base_state, indices, &n_sol);

		auto d = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::high_resolution_clock::now() - t);
		auto milis = std::chrono::duration_cast<std::chrono::milliseconds>(d).count();
		if(!counter) {
			sum = 1000.f*n_sol/milis;
		} else {
			sum += 1000.f*n_sol/milis;
		}

		avg = sum/++counter;

		std::cout << "Kernel run took " << milis << " ms. (" << avg << " H/s)" << std::endl;

		size_t checkedSols = 0;
        for (size_t s = 0; s < n_sol; ++s) {
        	++checkedSols;
            std::cout << "Checking solution " << checkedSols << std::endl;
            std::vector<eh_index> index_vector(PROOFSIZE);
            for (size_t i = 0; i < PROOFSIZE; i++) {
            	index_vector[i] = indices[s * PROOFSIZE + i];
            }
            std::vector<unsigned char> sol_char = GetMinimalFromIndices(index_vector, DIGITBITS);
#ifdef DEBUG
            bool isValid;
            EhIsValidSolution(200, 9, base_state, sol_char, isValid);
            std::cout << "is valid: " << isValid << '\n';
            if (!isValid) {
				  //If we find invalid solution bail, it cannot be a valid POW
				  std::cout << "Invalid solution found!" << std::endl;
              	  return false;
            } else {
            	std::cout << "Valid solution found!" << std::endl;
            }
#endif
            if (validBlock(sol_char)) {
            	// If we find a POW solution, do not try other solutions
              	// because they become invalid as we created a new block in blockchain.
				  std::cout << "Valid block found!" << std::endl;
              	  return true;
            }
        }

	}

    return false;

}

<commit_msg>Remove debug flag<commit_after>/* MIT License
 *
 * Copyright (c) 2016 Omar Alvarez <omar.alvarez@udc.es>
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

#include <chrono>

#include "gpusolver.h"

//#define DEBUG

GPUSolver::GPUSolver() {

	/* Notes
	I've added some extra parameters in this interface to assist with dev, such as
	a kernel string to specify which kernel to run and local/global work sizes.

	The following are private members of the class, but I have them here to specify the
	global work size for now. This will probably be hard-coded later
	*/
	unsigned int z_n = 200;
	unsigned int z_k = 9;
	size_t z_collision_bit_length = z_n / (z_k + 1);
	eh_index z_N = 1 << (z_collision_bit_length + 1);
	//uint32_t global_work_size = z_N;

	//TODO This looks like IND_PER_BUCKET, enough for GPU?
	size_t global_work_size = 1 << 20;
    size_t local_work_size = 32;

	miner = new cl_zogminer();

	/* Checks each device for memory requirements and sets local/global sizes
	TODO: Implement device logic for equihash kernel
	@params: unsigned platformId
	@params: unsigned localWorkSizes
	@params: unsigned globalWorkSizes
	*/
	GPU = miner->configureGPU(0, local_work_size, global_work_size);
	if(!GPU)
		std::cout << "ERROR: No suitable GPU found! No work will be performed!" << std::endl;

	/*Initialize the kernel, compile it and create buffers
	Currently runs for the gpu-list-gen.c kernel DATA_SIZE=100 times
	TODO: pass base state and nonce's to kernel.
	@params: unsigned _platformId
	@params: unsigned _deviceId
	@params: string& _kernel - The name of the kernel for dev purposes
	*/
	std::vector<std::string> kernels {"initial_bucket_hashing", "bucket_collide_and_hash", "produce_solutions"};
	if(GPU)
		initOK = miner->init(0, 0, kernels);

}

GPUSolver::GPUSolver(int64_t selGPU) {

	/* Notes
	I've added some extra parameters in this interface to assist with dev, such as
	a kernel string to specify which kernel to run and local/global work sizes.

	The following are private members of the class, but I have them here to specify the
	global work size for now. This will probably be hard-coded later
	*/
	unsigned int z_n = 200;
	unsigned int z_k = 9;
	size_t z_collision_bit_length = z_n / (z_k + 1);
	eh_index z_N = 1 << (z_collision_bit_length + 1);
	//uint32_t global_work_size = z_N;

	//TODO This looks like IND_PER_BUCKET, enough for GPU?
	size_t global_work_size = 1 << 17;
    size_t local_work_size = 32;

	miner = new cl_zogminer();

	/* Checks each device for memory requirements and sets local/global sizes
	TODO: Implement device logic for equihash kernel
	@params: unsigned platformId
	@params: unsigned localWorkSizes
	@params: unsigned globalWorkSizes
	*/
	GPU = miner->configureGPU(0, local_work_size, global_work_size);
	if(!GPU)
		std::cout << "ERROR: No suitable GPU found! No work will be performed!" << std::endl;

	/*Initialize the kernel, compile it and create buffers
	Currently runs for the gpu-list-gen.c kernel DATA_SIZE=100 times
	TODO: pass base state and nonce's to kernel.
	@params: unsigned _platformId
	@params: unsigned _deviceId
	@params: string& _kernel - The name of the kernel for dev purposes
	*/
	std::vector<std::string> kernels {"initial_bucket_hashing", "bucket_collide_and_hash", "produce_solutions"};
	if(GPU)
		initOK = miner->init(0, selGPU, kernels);

}

GPUSolver::~GPUSolver() {

	if(GPU)
		miner->finish();

	delete miner;

}

bool GPUSolver::run(unsigned int n, unsigned int k, const eh_HashState& base_state,
		            const std::function<bool(std::vector<unsigned char>)> validBlock,
				const std::function<bool(GPUSolverCancelCheck)> cancelled) {

    if (n == 200 && k == 9) {
        return GPUSolve200_9(base_state, validBlock, cancelled);
    } else {
        throw std::invalid_argument("Unsupported Equihash parameters");
    }

}

bool GPUSolver::GPUSolve200_9(const eh_HashState& base_state,
                 	const std::function<bool(std::vector<unsigned char>)> validBlock,
			const std::function<bool(GPUSolverCancelCheck)> cancelled) {

	/* Run the kernel
	TODO: Optimise and figure out how we want this to go
	@params eh_HashState& base_state - Sends to kernel in a buffer. Will update for specific kernels
	*/

	if(GPU && initOK) {
        auto t = std::chrono::high_resolution_clock::now();

		uint32_t n_sol;

    	miner->run(base_state, indices, &n_sol);

		auto d = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::high_resolution_clock::now() - t);
		auto milis = std::chrono::duration_cast<std::chrono::milliseconds>(d).count();
		if(!counter) {
			sum = 1000.f*n_sol/milis;
		} else {
			sum += 1000.f*n_sol/milis;
		}

		avg = sum/++counter;

		std::cout << "Kernel run took " << milis << " ms. (" << avg << " H/s)" << std::endl;

		size_t checkedSols = 0;
        for (size_t s = 0; s < n_sol; ++s) {
        	++checkedSols;
            std::cout << "Checking solution " << checkedSols << std::endl;
            std::vector<eh_index> index_vector(PROOFSIZE);
            for (size_t i = 0; i < PROOFSIZE; i++) {
            	index_vector[i] = indices[s * PROOFSIZE + i];
            }
            std::vector<unsigned char> sol_char = GetMinimalFromIndices(index_vector, DIGITBITS);
#ifdef DEBUG
            bool isValid;
            EhIsValidSolution(200, 9, base_state, sol_char, isValid);
            std::cout << "is valid: " << isValid << '\n';
            if (!isValid) {
				  //If we find invalid solution bail, it cannot be a valid POW
				  std::cout << "Invalid solution found!" << std::endl;
              	  return false;
            } else {
            	std::cout << "Valid solution found!" << std::endl;
            }
#endif
            if (validBlock(sol_char)) {
            	// If we find a POW solution, do not try other solutions
              	// because they become invalid as we created a new block in blockchain.
				  std::cout << "Valid block found!" << std::endl;
              	  return true;
            }
        }

	}

    return false;

}

<|endoftext|>