<commit_before>/*=============================================================================
	Copyright (c) 2012-2013 Richard Otis

    Distributed under the Boost Software License, Version 1.0. (See accompanying
    file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
=============================================================================*/

// Model for magnetic ordering according to Inden-Hillert-Jarl (IHJ)
// Reference: Inden, 1976. Hillert and Jarl, 1978.
// Handling for anti-ferromagnetic (AFM) states done according to Hertzman and Sundman, 1982.
// Implementation follows from a review of the IHJ model by W. Xiong et al., 2012.
// Note: This is the IHJ model, not Xiong's model.

#include "libgibbs/include/libgibbs_pch.hpp"
#include "libgibbs/include/models.hpp"
#include "libgibbs/include/optimizer/opt_Gibbs.hpp"
#include <string>
#include <sstream>
#include <set>
#include <limits>
#include <boost/multi_index_container.hpp>
#include <boost/multi_index/composite_key.hpp>
#include <boost/multi_index/member.hpp>
#include <boost/multi_index/ordered_index.hpp>
#include <boost/tuple/tuple.hpp>

using boost::spirit::utree;
typedef boost::spirit::utree_type utree_type;
using boost::multi_index_container;
using namespace boost::multi_index;

// Apply op with root_tree as left hand side and new_tree as right hand side
utree a_o (const utree &root_tree, const utree &new_tree, const std::string &op) {
	utree temp_tree;
	temp_tree.push_back(op);
	temp_tree.push_back(root_tree);
	temp_tree.push_back(new_tree);
	return temp_tree;
}
// Apply op with root_tree as left hand side
utree a_o (const utree &root_tree, const std::string &op) {
	utree temp_tree;
	temp_tree.push_back(op);
	temp_tree.push_back(root_tree);
	return temp_tree;
}

utree max_magnetic_entropy(const utree &beta);
utree magnetic_polynomial(const utree &tc_tree, const double &p, const double &afm_factor);
utree get_afm_factor(const utree &tree, const double &afm_factor);

IHJMagneticModel::IHJMagneticModel(
		const std::string &phasename,
		const sublattice_set &subl_set,
		const parameter_set &param_set,
		const double &afm_factor,
		const double &sro_enthalpy_order_fraction
		) : EnergyModel(phasename, subl_set, param_set) {
	if (afm_factor == 0 || sro_enthalpy_order_fraction == 0) {
		// There is no magnetic contribution
		model_ast = utree(0);
		return;
	}
	sublattice_set_view ssv;
	parameter_set_view psv;
	parameter_set_view psv_subview_tc, psv_subview_bm;
	utree Curie_temperature, mean_magnetic_moment;
	std::string scantype;
	boost::multi_index::index<sublattice_set,phases>::type::iterator ic0,ic1;
	boost::multi_index::index<parameter_set_view,type_index>::type::iterator it0, it1;
	boost::multi_index::index<parameter_set,phase_index>::type::iterator pa_start,pa_end;

	// Get all the sublattices for this phase
	boost::tuples::tie(ic0,ic1)=get<phases>(subl_set).equal_range(phasename);
	// Construct a view from the iterators
	while (ic0 != ic1) {
		ssv.insert(&*ic0);
		++ic0;
	}
	// Get all the parameters for this phase
	boost::tuples::tie(pa_start,pa_end)=get<phase_index>(param_set).equal_range(phasename);
	// Construct a view from the iterators
	while (pa_start != pa_end) {
		psv.insert(&*pa_start);
		++pa_start;
	}

	// build subview to the parameter "TC"
	scantype = "TC";
	boost::tuples::tie(it0,it1)=get<type_index>(psv).equal_range(scantype);

	// Construct a subview from the view
	while (it0 != it1) {
		psv_subview_tc.insert(*it0);
		++it0;
	}
	Curie_temperature = permute_site_fractions(ssv, sublattice_set_view(), psv_subview_tc, (int)0);
	Curie_temperature = a_o(Curie_temperature,
			permute_site_fractions_with_interactions(ssv, sublattice_set_view(), psv_subview_tc, (int)0),
			"+"
	);
	Curie_temperature = simplify_utree(Curie_temperature);
	std::cout << "Curie_temperature: " << Curie_temperature << std::endl;
	if (is_zero_tree(Curie_temperature)) {
		// Transition temperature is always zero, no magnetic contribution
		model_ast = utree(0);
		return;
	}

	// Now find parameters of type "BMAGN"
	scantype = "BMAGN";
	boost::tuples::tie(it0,it1)=get<type_index>(psv).equal_range(scantype);

	// Construct a subview from the view
	while (it0 != it1) {
		psv_subview_bm.insert(*it0);
		++it0;
	}
	mean_magnetic_moment = permute_site_fractions(ssv, sublattice_set_view(), psv_subview_bm, (int)0);
	mean_magnetic_moment = a_o(mean_magnetic_moment,
				permute_site_fractions_with_interactions(ssv, sublattice_set_view(), psv_subview_bm, (int)0),
				"+"
		);
	mean_magnetic_moment = simplify_utree(mean_magnetic_moment);
	if (is_zero_tree(mean_magnetic_moment)) {
		// Mean magnetic moment is always zero, no magnetic contribution
		model_ast = utree(0);
		return;
	}
	else {
		// Apply AFM factor
		mean_magnetic_moment = a_o(get_afm_factor(mean_magnetic_moment, afm_factor), mean_magnetic_moment, "*");
	}

	model_ast = a_o("T", max_magnetic_entropy(mean_magnetic_moment), "*");
	model_ast = a_o(model_ast, magnetic_polynomial(Curie_temperature, sro_enthalpy_order_fraction, afm_factor), "*");

	normalize_utree(model_ast, ssv);
}

utree magnetic_polynomial(const utree &tc_tree, const double &p, const double &afm_factor) {
	// These are constant factors from the heat capacity integration
	double A = (518.0/1125.0) + ((11692.0/15975.0)*((1.0/p) - 1.0));
	double B = 79.0/(140*p);
	double C = (474.0/497.0)*((1.0/p)-1.0);
	utree ret_tree, tau, subcritical_tree, supercritical_tree;

	tau = a_o("T", tc_tree, "/");
	// If tau < 0, apply the anti-ferromagnetic (AFM) factor
	tau = a_o(get_afm_factor(tau, afm_factor), tau, "*");

	// TODO: This is a mess. Using the utree visitation interface might make this better.

	// First calculate the polynomial for 0 < tau < 1
	utree taum1 = a_o(B, a_o(tau, -1, "**"), "*");
	utree tau3 = a_o(1.0/6.0, a_o(tau, 3, "**"), "*");
	utree tau9 = a_o(1.0/135.0, a_o(tau, 9, "**"), "*");
	utree tau15 = a_o(1.0/600.0, a_o(tau, 15, "**"), "*");
	utree total_taus = a_o(C, a_o(a_o(tau3, tau9, "+"), tau15, "+"), "*");

	total_taus = a_o(taum1, total_taus, "+");
	total_taus = a_o(-1.0/A, total_taus, "*");
	subcritical_tree = a_o(1.0, total_taus, "-");

	// Now calculate the polynomial for tau >= 1
	utree taum5 = a_o(1.0/10.0, a_o(tau, -5, "**"), "*");
	utree taum15 = a_o(1.0/315.0, a_o(tau, -15, "**"), "*");
	utree taum25 = a_o(1.0/1500.0, a_o(tau, -25, "**"), "*");
	total_taus = a_o(a_o(taum5, taum15, "+"), taum25, "+");
	supercritical_tree = a_o(-1.0/A, total_taus, "*");

	ret_tree.push_back("@");
	ret_tree.push_back(tau);
	ret_tree.push_back(-std::numeric_limits<double>::max());
	ret_tree.push_back(1);
	ret_tree.push_back(subcritical_tree);
	ret_tree.push_back("@");
	ret_tree.push_back(tau);
	ret_tree.push_back(1);
	ret_tree.push_back(std::numeric_limits<double>::max());
	ret_tree.push_back(supercritical_tree);

	return ret_tree;
}

utree max_magnetic_entropy(const utree &beta) {
	// beta is the mean magnetic moment
	// The return value is the maximum magnetic entropy of an element undergoing the FM disordering transition
	utree ret_tree;
	ret_tree = a_o(SI_GAS_CONSTANT, a_o(a_o(beta, 1.0, "+"), "LN"), "*"); // R*ln(beta + 1)

	return ret_tree;
}

// Calculate the anti-ferromagnetic (AFM) factor
utree get_afm_factor(const utree &tree, const double &afm_factor) {
	utree afm_factor_tree;
	afm_factor_tree.push_back("@");
	afm_factor_tree.push_back(tree);
	afm_factor_tree.push_back(-std::numeric_limits<double>::max());
	afm_factor_tree.push_back(0);
	afm_factor_tree.push_back(1.0/afm_factor);
	afm_factor_tree.push_back("@");
	afm_factor_tree.push_back(tree);
	afm_factor_tree.push_back(0);
	afm_factor_tree.push_back(std::numeric_limits<double>::max());
	afm_factor_tree.push_back(1);
	return afm_factor_tree;
}
<commit_msg>Fix how AFM factor is applied to TC<commit_after>/*=============================================================================
	Copyright (c) 2012-2013 Richard Otis

    Distributed under the Boost Software License, Version 1.0. (See accompanying
    file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
=============================================================================*/

// Model for magnetic ordering according to Inden-Hillert-Jarl (IHJ)
// Reference: Inden, 1976. Hillert and Jarl, 1978.
// Handling for anti-ferromagnetic (AFM) states done according to Hertzman and Sundman, 1982.
// Implementation follows from a review of the IHJ model by W. Xiong et al., 2012.
// Note: This is the IHJ model, not Xiong's model.

#include "libgibbs/include/libgibbs_pch.hpp"
#include "libgibbs/include/models.hpp"
#include "libgibbs/include/optimizer/opt_Gibbs.hpp"
#include <string>
#include <sstream>
#include <set>
#include <limits>
#include <boost/multi_index_container.hpp>
#include <boost/multi_index/composite_key.hpp>
#include <boost/multi_index/member.hpp>
#include <boost/multi_index/ordered_index.hpp>
#include <boost/tuple/tuple.hpp>

using boost::spirit::utree;
typedef boost::spirit::utree_type utree_type;
using boost::multi_index_container;
using namespace boost::multi_index;

// Apply op with root_tree as left hand side and new_tree as right hand side
utree a_o (const utree &root_tree, const utree &new_tree, const std::string &op) {
	utree temp_tree;
	temp_tree.push_back(op);
	temp_tree.push_back(root_tree);
	temp_tree.push_back(new_tree);
	return temp_tree;
}
// Apply op with root_tree as left hand side
utree a_o (const utree &root_tree, const std::string &op) {
	utree temp_tree;
	temp_tree.push_back(op);
	temp_tree.push_back(root_tree);
	return temp_tree;
}

utree max_magnetic_entropy(const utree &beta);
utree magnetic_polynomial(const utree &tc_tree, const double &p, const double &afm_factor);
utree get_afm_factor(const utree &tree, const double &afm_factor);

IHJMagneticModel::IHJMagneticModel(
		const std::string &phasename,
		const sublattice_set &subl_set,
		const parameter_set &param_set,
		const double &afm_factor,
		const double &sro_enthalpy_order_fraction
		) : EnergyModel(phasename, subl_set, param_set) {
	if (afm_factor == 0 || sro_enthalpy_order_fraction == 0) {
		// There is no magnetic contribution
		model_ast = utree(0);
		return;
	}
	sublattice_set_view ssv;
	parameter_set_view psv;
	parameter_set_view psv_subview_tc, psv_subview_bm;
	utree Curie_temperature, mean_magnetic_moment;
	std::string scantype;
	boost::multi_index::index<sublattice_set,phases>::type::iterator ic0,ic1;
	boost::multi_index::index<parameter_set_view,type_index>::type::iterator it0, it1;
	boost::multi_index::index<parameter_set,phase_index>::type::iterator pa_start,pa_end;

	// Get all the sublattices for this phase
	boost::tuples::tie(ic0,ic1)=get<phases>(subl_set).equal_range(phasename);
	// Construct a view from the iterators
	while (ic0 != ic1) {
		ssv.insert(&*ic0);
		++ic0;
	}
	// Get all the parameters for this phase
	boost::tuples::tie(pa_start,pa_end)=get<phase_index>(param_set).equal_range(phasename);
	// Construct a view from the iterators
	while (pa_start != pa_end) {
		psv.insert(&*pa_start);
		++pa_start;
	}

	// build subview to the parameter "TC"
	scantype = "TC";
	boost::tuples::tie(it0,it1)=get<type_index>(psv).equal_range(scantype);

	// Construct a subview from the view
	while (it0 != it1) {
		psv_subview_tc.insert(*it0);
		++it0;
	}
	Curie_temperature = permute_site_fractions(ssv, sublattice_set_view(), psv_subview_tc, (int)0);
	Curie_temperature = a_o(Curie_temperature,
			permute_site_fractions_with_interactions(ssv, sublattice_set_view(), psv_subview_tc, (int)0),
			"+"
	);
	Curie_temperature = simplify_utree(Curie_temperature);
	if (is_zero_tree(Curie_temperature)) {
		// Transition temperature is always zero, no magnetic contribution
		model_ast = utree(0);
		return;
	}
	// Apply AFM factor to TC
	Curie_temperature = a_o(get_afm_factor(Curie_temperature, afm_factor), Curie_temperature, "*");

	// Now find parameters of type "BMAGN"
	scantype = "BMAGN";
	boost::tuples::tie(it0,it1)=get<type_index>(psv).equal_range(scantype);

	// Construct a subview from the view
	while (it0 != it1) {
		psv_subview_bm.insert(*it0);
		++it0;
	}
	mean_magnetic_moment = permute_site_fractions(ssv, sublattice_set_view(), psv_subview_bm, (int)0);
	mean_magnetic_moment = a_o(mean_magnetic_moment,
				permute_site_fractions_with_interactions(ssv, sublattice_set_view(), psv_subview_bm, (int)0),
				"+"
		);
	mean_magnetic_moment = simplify_utree(mean_magnetic_moment);
	if (is_zero_tree(mean_magnetic_moment)) {
		// Mean magnetic moment is always zero, no magnetic contribution
		model_ast = utree(0);
		return;
	}
	else {
		// Apply AFM factor
		mean_magnetic_moment = a_o(get_afm_factor(mean_magnetic_moment, afm_factor), mean_magnetic_moment, "*");
	}
	model_ast = a_o("T", max_magnetic_entropy(mean_magnetic_moment), "*");
	model_ast = a_o(model_ast, magnetic_polynomial(Curie_temperature, sro_enthalpy_order_fraction, afm_factor), "*");

	normalize_utree(model_ast, ssv);
}

utree magnetic_polynomial(const utree &tc_tree, const double &p, const double &afm_factor) {
	// These are constant factors from the heat capacity integration
	double A = (518.0/1125.0) + ((11692.0/15975.0)*((1.0/p) - 1.0));
	double B = 79.0/(140*p);
	double C = (474.0/497.0)*((1.0/p)-1.0);
	utree ret_tree, tau, subcritical_tree, supercritical_tree;

	tau = a_o("T", tc_tree, "/");

	// TODO: This is a mess. Using the utree visitation interface might make this better.

	// First calculate the polynomial for 0 < tau < 1
	utree taum1 = a_o(B, a_o(tau, -1.0, "**"), "*");
	utree tau3 = a_o(1.0/6.0, a_o(tau, 3.0, "**"), "*");
	utree tau9 = a_o(1.0/135.0, a_o(tau, 9.0, "**"), "*");
	utree tau15 = a_o(1.0/600.0, a_o(tau, 15.0, "**"), "*");
	utree total_taus = a_o(C, a_o(a_o(tau3, tau9, "+"), tau15, "+"), "*");

	total_taus = a_o(taum1, total_taus, "+");
	total_taus = a_o(-1.0/A, total_taus, "*");
	subcritical_tree = a_o(1.0, total_taus, "-");

	// Now calculate the polynomial for tau >= 1
	utree taum5 = a_o(1.0/10.0, a_o(tau, -5.0, "**"), "*");
	utree taum15 = a_o(1.0/315.0, a_o(tau, -15.0, "**"), "*");
	utree taum25 = a_o(1.0/1500.0, a_o(tau, -25.0, "**"), "*");
	total_taus = a_o(a_o(taum5, taum15, "+"), taum25, "+");
	supercritical_tree = a_o(-1.0/A, total_taus, "*");

	ret_tree.push_back("@");
	ret_tree.push_back(tau);
	ret_tree.push_back(-std::numeric_limits<double>::max());
	ret_tree.push_back(1);
	ret_tree.push_back(subcritical_tree);
	ret_tree.push_back("@");
	ret_tree.push_back(tau);
	ret_tree.push_back(1);
	ret_tree.push_back(std::numeric_limits<double>::max());
	ret_tree.push_back(supercritical_tree);

	return ret_tree;
}

utree max_magnetic_entropy(const utree &beta) {
	// beta is the mean magnetic moment
	// The return value is the maximum magnetic entropy of an element undergoing the FM disordering transition
	utree ret_tree;
	ret_tree = a_o(SI_GAS_CONSTANT, a_o(a_o(beta, 1.0, "+"), "LN"), "*"); // R*ln(beta + 1)

	return ret_tree;
}

// Calculate the anti-ferromagnetic (AFM) factor
utree get_afm_factor(const utree &tree, const double &afm_factor) {
	utree afm_factor_tree;
	afm_factor_tree.push_back("@");
	afm_factor_tree.push_back(tree);
	afm_factor_tree.push_back(-std::numeric_limits<double>::max());
	afm_factor_tree.push_back(0);
	afm_factor_tree.push_back(1.0/afm_factor);
	afm_factor_tree.push_back("@");
	afm_factor_tree.push_back(tree);
	afm_factor_tree.push_back(0);
	afm_factor_tree.push_back(std::numeric_limits<double>::max());
	afm_factor_tree.push_back(1);
	return afm_factor_tree;
}
<|endoftext|>


<commit_before>#include <bts/blockchain/account_record.hpp>
#include <bts/blockchain/chain_interface.hpp>

namespace bts { namespace blockchain {

    share_type account_record::delegate_pay_balance()const
    {
        FC_ASSERT( is_delegate() );
        return delegate_info->pay_balance;
    }

    bool account_record::is_delegate()const
    {
        return delegate_info.valid();
    }

    int64_t account_record::net_votes()const
    {
        FC_ASSERT( is_delegate() );
        return delegate_info->votes_for;
    }

    void account_record::adjust_votes_for( const share_type delta )
    {
        FC_ASSERT( is_delegate() );
        delegate_info->votes_for += delta;
    }

    bool account_record::is_retracted()const
    {
        return active_key() == public_key_type();
    }

    address account_record::active_address()const
    {
        return address( active_key() );
    }

    void account_record::set_active_key( const time_point_sec now, const public_key_type& new_key )
    { try {
        FC_ASSERT( now != fc::time_point_sec() );
        active_key_history[ now ] = new_key;
    } FC_CAPTURE_AND_RETHROW( (now)(new_key) ) }

    public_key_type account_record::active_key()const
    {
        FC_ASSERT( !active_key_history.empty() );
        return active_key_history.rbegin()->second;
    }

    uint8_t account_record::delegate_pay_rate()const
    {
        if( !is_delegate() )
            return -1;

        return delegate_info->pay_rate;
    }

    void account_record::set_signing_key( uint32_t block_num, const public_key_type& signing_key )
    {
        FC_ASSERT( is_delegate() );
        delegate_info->signing_key_history[ block_num ] = signing_key;
    }

    public_key_type account_record::signing_key()const
    {
        FC_ASSERT( is_delegate() );
        FC_ASSERT( !delegate_info->signing_key_history.empty() );
        return delegate_info->signing_key_history.crbegin()->second;
    }

    address account_record::signing_address()const
    {
        return address( signing_key() );
    }

    void account_record::sanity_check( const chain_interface& db )const
    { try {
        FC_ASSERT( id > 0 );
        FC_ASSERT( !name.empty() );
        FC_ASSERT( !active_key_history.empty() );
        if( delegate_info.valid() )
        {
            FC_ASSERT( delegate_info->votes_for >= 0 );
            FC_ASSERT( delegate_info->pay_rate <= 100 );
            FC_ASSERT( !delegate_info->signing_key_history.empty() );
            FC_ASSERT( delegate_info->pay_balance >= 0 );
        }
    } FC_CAPTURE_AND_RETHROW( (*this) ) }

    oaccount_record account_record::lookup( const chain_interface& db, const account_id_type id )
    { try {
        return db.account_lookup_by_id( id );
    } FC_CAPTURE_AND_RETHROW( (id) ) }

    oaccount_record account_record::lookup( const chain_interface& db, const string& name )
    { try {
        return db.account_lookup_by_name( name );
    } FC_CAPTURE_AND_RETHROW( (name) ) }

    oaccount_record account_record::lookup( const chain_interface& db, const address& addr )
    { try {
        return db.account_lookup_by_address( addr );
    } FC_CAPTURE_AND_RETHROW( (addr) ) }

    void account_record::store( chain_interface& db, const account_id_type id, const account_record& record )
    { try {
        const oaccount_record prev_record = db.lookup<account_record>( id );
        if( prev_record.valid() )
        {
            if( prev_record->name != record.name )
                db.account_erase_from_name_map( prev_record->name );

            if( prev_record->owner_address() != record.owner_address() )
                db.account_erase_from_address_map( prev_record->owner_address() );

            if( fc::ripemd160::hash( prev_record->active_key_history ) != fc::ripemd160::hash( record.active_key_history ) )
            {
                for( const auto& item : prev_record->active_key_history )
                {
                    const public_key_type& active_key = item.second;
                    db.account_erase_from_address_map( address( active_key ) );
                }
            }

            if( prev_record->is_delegate() )
            {
                if( !record.is_delegate() || fc::ripemd160::hash( prev_record->delegate_info->signing_key_history )
                                             != fc::ripemd160::hash( record.delegate_info->signing_key_history ) )
                {
                    for( const auto& item : prev_record->delegate_info->signing_key_history )
                    {
                        const public_key_type& signing_key = item.second;
                        db.account_erase_from_address_map( address( signing_key ) );
                    }
                }

                if( !prev_record->is_retracted() )
                {
                    if( record.is_retracted() || !record.is_delegate() || prev_record->net_votes() != record.net_votes() )
                        db.account_erase_from_vote_set( vote_del( prev_record->net_votes(), prev_record->id ) );
                }
            }
        }

        db.account_insert_into_id_map( id, record );
        db.account_insert_into_name_map( record.name, id );
        db.account_insert_into_address_map( record.owner_address(), id );

        for( const auto& item : record.active_key_history )
        {
            const public_key_type& active_key = item.second;
            if( active_key != public_key_type() ) db.account_insert_into_address_map( address( active_key ), id );
        }

        if( record.is_delegate() )
        {
            for( const auto& item : record.delegate_info->signing_key_history )
            {
                const public_key_type& signing_key = item.second;
                if( signing_key != public_key_type() ) db.account_insert_into_address_map( address( signing_key ), id );
            }

            if( !record.is_retracted() )
                db.account_insert_into_vote_set( vote_del( record.net_votes(), id ) );
        }
    } FC_CAPTURE_AND_RETHROW( (id)(record) ) }

    void account_record::remove( chain_interface& db, const account_id_type id )
    { try {
        const oaccount_record prev_record = db.lookup<account_record>( id );
        if( prev_record.valid() )
        {
            db.account_erase_from_id_map( id );
            db.account_erase_from_name_map( prev_record->name );
            db.account_erase_from_address_map( prev_record->owner_address() );

            for( const auto& item : prev_record->active_key_history )
            {
                const public_key_type& active_key = item.second;
                db.account_erase_from_address_map( address( active_key ) );
            }

            if( prev_record->is_delegate() )
            {
                for( const auto& item : prev_record->delegate_info->signing_key_history )
                {
                    const public_key_type& signing_key = item.second;
                    db.account_erase_from_address_map( address( signing_key ) );
                }

                if( !prev_record->is_retracted() )
                    db.account_erase_from_vote_set( vote_del( prev_record->net_votes(), prev_record->id ) );
            }
        }
    } FC_CAPTURE_AND_RETHROW( (id) ) }

} } // bts::blockchain
<commit_msg>Simplify account_record indexing<commit_after>#include <bts/blockchain/account_record.hpp>
#include <bts/blockchain/chain_interface.hpp>

namespace bts { namespace blockchain {

    share_type account_record::delegate_pay_balance()const
    {
        FC_ASSERT( is_delegate() );
        return delegate_info->pay_balance;
    }

    bool account_record::is_delegate()const
    {
        return delegate_info.valid();
    }

    int64_t account_record::net_votes()const
    {
        FC_ASSERT( is_delegate() );
        return delegate_info->votes_for;
    }

    void account_record::adjust_votes_for( const share_type delta )
    {
        FC_ASSERT( is_delegate() );
        delegate_info->votes_for += delta;
    }

    bool account_record::is_retracted()const
    {
        return active_key() == public_key_type();
    }

    address account_record::active_address()const
    {
        return address( active_key() );
    }

    void account_record::set_active_key( const time_point_sec now, const public_key_type& new_key )
    { try {
        FC_ASSERT( now != fc::time_point_sec() );
        active_key_history[ now ] = new_key;
    } FC_CAPTURE_AND_RETHROW( (now)(new_key) ) }

    public_key_type account_record::active_key()const
    {
        FC_ASSERT( !active_key_history.empty() );
        return active_key_history.rbegin()->second;
    }

    uint8_t account_record::delegate_pay_rate()const
    {
        if( !is_delegate() )
            return -1;

        return delegate_info->pay_rate;
    }

    void account_record::set_signing_key( uint32_t block_num, const public_key_type& signing_key )
    {
        FC_ASSERT( is_delegate() );
        delegate_info->signing_key_history[ block_num ] = signing_key;
    }

    public_key_type account_record::signing_key()const
    {
        FC_ASSERT( is_delegate() );
        FC_ASSERT( !delegate_info->signing_key_history.empty() );
        return delegate_info->signing_key_history.crbegin()->second;
    }

    address account_record::signing_address()const
    {
        return address( signing_key() );
    }

    void account_record::sanity_check( const chain_interface& db )const
    { try {
        FC_ASSERT( id > 0 );
        FC_ASSERT( !name.empty() );
        FC_ASSERT( !active_key_history.empty() );
        if( delegate_info.valid() )
        {
            FC_ASSERT( delegate_info->votes_for >= 0 );
            FC_ASSERT( delegate_info->pay_rate <= 100 );
            FC_ASSERT( !delegate_info->signing_key_history.empty() );
            FC_ASSERT( delegate_info->pay_balance >= 0 );
        }
    } FC_CAPTURE_AND_RETHROW( (*this) ) }

    oaccount_record account_record::lookup( const chain_interface& db, const account_id_type id )
    { try {
        return db.account_lookup_by_id( id );
    } FC_CAPTURE_AND_RETHROW( (id) ) }

    oaccount_record account_record::lookup( const chain_interface& db, const string& name )
    { try {
        return db.account_lookup_by_name( name );
    } FC_CAPTURE_AND_RETHROW( (name) ) }

    oaccount_record account_record::lookup( const chain_interface& db, const address& addr )
    { try {
        return db.account_lookup_by_address( addr );
    } FC_CAPTURE_AND_RETHROW( (addr) ) }

    void account_record::store( chain_interface& db, const account_id_type id, const account_record& record )
    { try {
        const oaccount_record prev_record = db.lookup<account_record>( id );
        if( prev_record.valid() )
        {
            if( prev_record->name != record.name )
                db.account_erase_from_name_map( prev_record->name );

            if( prev_record->owner_address() != record.owner_address() )
                db.account_erase_from_address_map( prev_record->owner_address() );

            if( prev_record->active_key() != record.active_key() )
            {
                for( const auto& item : prev_record->active_key_history )
                {
                    const public_key_type& active_key = item.second;
                    db.account_erase_from_address_map( address( active_key ) );
                }
            }

            if( prev_record->is_delegate() )
            {
                if( !record.is_delegate() || prev_record->signing_key() != record.signing_key() )
                {
                    for( const auto& item : prev_record->delegate_info->signing_key_history )
                    {
                        const public_key_type& signing_key = item.second;
                        db.account_erase_from_address_map( address( signing_key ) );
                    }
                }

                if( !prev_record->is_retracted() )
                {
                    if( record.is_retracted() || !record.is_delegate() || prev_record->net_votes() != record.net_votes() )
                        db.account_erase_from_vote_set( vote_del( prev_record->net_votes(), prev_record->id ) );
                }
            }
        }

        db.account_insert_into_id_map( id, record );
        db.account_insert_into_name_map( record.name, id );
        db.account_insert_into_address_map( record.owner_address(), id );

        for( const auto& item : record.active_key_history )
        {
            const public_key_type& active_key = item.second;
            if( active_key != public_key_type() ) db.account_insert_into_address_map( address( active_key ), id );
        }

        if( record.is_delegate() )
        {
            for( const auto& item : record.delegate_info->signing_key_history )
            {
                const public_key_type& signing_key = item.second;
                if( signing_key != public_key_type() ) db.account_insert_into_address_map( address( signing_key ), id );
            }

            if( !record.is_retracted() )
                db.account_insert_into_vote_set( vote_del( record.net_votes(), id ) );
        }
    } FC_CAPTURE_AND_RETHROW( (id)(record) ) }

    void account_record::remove( chain_interface& db, const account_id_type id )
    { try {
        const oaccount_record prev_record = db.lookup<account_record>( id );
        if( prev_record.valid() )
        {
            db.account_erase_from_id_map( id );
            db.account_erase_from_name_map( prev_record->name );
            db.account_erase_from_address_map( prev_record->owner_address() );

            for( const auto& item : prev_record->active_key_history )
            {
                const public_key_type& active_key = item.second;
                db.account_erase_from_address_map( address( active_key ) );
            }

            if( prev_record->is_delegate() )
            {
                for( const auto& item : prev_record->delegate_info->signing_key_history )
                {
                    const public_key_type& signing_key = item.second;
                    db.account_erase_from_address_map( address( signing_key ) );
                }

                if( !prev_record->is_retracted() )
                    db.account_erase_from_vote_set( vote_del( prev_record->net_votes(), prev_record->id ) );
            }
        }
    } FC_CAPTURE_AND_RETHROW( (id) ) }

} } // bts::blockchain
<|endoftext|>


<commit_before>#ifndef LIB_DATA_HPP__
#define LIB_DATA_HPP__

#include <lib/include/types.hpp>
#include <lib/include/compconfig.hpp>
#include <map>
#include <vector>

namespace lib
{
	class DataValue;
	typedef LIB_API std::map<str, DataValue> DataMap;
	enum class LIB_API DataType : u8
	{
		T_Empty,
		T_s8,
		T_u8,
		T_s16,
		T_u16,
		T_s32,
		T_u32,
		T_f64,
		T_string,
		T_Tree
	};

	class LIB_API DataValue
	{
	public:
		explicit inline DataValue() : m_dtype{ DataType::T_Empty }, f64_{ 0 } {}
		explicit inline DataValue(const s8 value_) : m_dtype{ DataType::T_s8 }, s8_{ value_ } {}
		explicit inline DataValue(const u8 value_) : m_dtype{ DataType::T_u8 }, u8_{ value_ } {}
		explicit inline DataValue(const s16 value_) : m_dtype{ DataType::T_s16 }, s16_{ value_ } {}
		explicit inline DataValue(const u16 value_) : m_dtype{ DataType::T_u16 }, u16_{ value_ } {}
		explicit inline DataValue(const s32 value_) : m_dtype{ DataType::T_s32 }, s32_{ value_ } {}
		explicit inline DataValue(const u32 value_) : m_dtype{ DataType::T_u32 }, u32_{ value_ } {}
		explicit inline DataValue(const f64 value_) : m_dtype{ DataType::T_f64 }, f64_{ value_ } {}
		explicit inline DataValue(const str &value_) : m_dtype{ DataType::T_string }, ptr_{ new str(value_) } {}
		explicit inline DataValue(const DataMap &value_) : m_dtype{ DataType::T_Tree }, ptr_{ new DataMap(value_) } {}

		explicit inline DataValue(const DataValue &value_): m_dtype{ value_.m_dtype }
		{
			switch (m_dtype)
			{
				case DataType::T_s8:
				case DataType::T_u8:
				case DataType::T_s16:
				case DataType::T_u16:
				case DataType::T_s32:
				case DataType::T_u32:
				case DataType::T_f64:
					f64_ = value_.f64_;
					break;
				case DataType::T_string:
					ptr_ = new str(value_.getString());
					break;
				case DataType::T_Tree:
					ptr_ = new DataMap(*value_.getMap());
					break;
				case DataType::T_Empty:
				default:
					break;
			}
		}

		inline DataValue(DataValue &&other)
		{
			std::swap(m_dtype, other.m_dtype);
			f64_ = other.f64_;
		}

		~DataValue();

		bool operator==(const s8 value_) const;
		bool operator==(const u8 value_) const;
		bool operator==(const s16 value_) const;
		bool operator==(const u16 value_) const;
		bool operator==(const s32 value_) const;
		bool operator==(const u32 value_) const;
		bool operator==(const f64 value_) const;
		bool operator==(const str &value_) const;
		bool operator==(const DataMap &value_) const;
		bool operator==(const DataValue &other) const;
		DataValue &operator=(DataValue &&other);

		const s8 gets8() const;
		const u8 getu8() const;
		const s16 gets16() const;
		const u16 getu16() const;
		const s32 gets32() const;
		const u32 getu32() const;
		const f64 getf64() const;
		const str getString() const;
		const DataMap *getMap() const;
		DataMap *getMap();

		friend std::ostream &operator<<(std::ostream &output, const DataValue &this_);

		template <typename T> inline const T get() const;
		template <> inline const s8 get() const { return gets8(); }
		template <> inline const u8 get() const { return getu8(); }
		template <> inline const s16 get() const { return gets16(); }
		template <> inline const u16 get() const { return getu16(); }
		template <> inline const s32 get() const { return gets32(); }
		template <> inline const u32 get() const { return getu32(); }
		template <> inline const f64 get() const { return getf64(); }

		inline const bool iss8() const { return m_dtype == DataType::T_s8; }
		inline const bool isu8() const { return m_dtype == DataType::T_s8; }
		inline const bool iss16() const { return m_dtype == DataType::T_s16; }
		inline const bool isu16() const { return m_dtype == DataType::T_u16; }
		inline const bool iss32() const { return m_dtype == DataType::T_s32; }
		inline const bool isu32() const { return m_dtype == DataType::T_u32; }
		inline const bool isf64() const { return m_dtype == DataType::T_f64; }
		inline const bool isstring() const { return m_dtype == DataType::T_string; }
		inline const bool ismap() const { return m_dtype == DataType::T_Tree; }

		template <typename T>
		const bool is() const;

		template <> inline const bool is<s8>() const { return iss8(); }
		template <> inline const bool is<u8>() const { return isu8(); }
		template <> inline const bool is<s16>() const { return iss16(); }
		template <> inline const bool is<u16>() const { return isu16(); }
		template <> inline const bool is<s32>() const { return iss32(); }
		template <> inline const bool is<u32>() const { return isu32(); }
		template <> inline const bool is<f64>() const { return isf64(); }

		static DataMap fromStringVector(const std::vector<str> &data, u32 &count);

	private:
		union
		{
			s8 s8_;
			u8 u8_;
			s16 s16_;
			u16 u16_;
			s32 s32_;
			u32 u32_;
			f64 f64_;
			void *ptr_;
		};
		DataType m_dtype{ DataType::T_Empty };
	};
}

#endif
<commit_msg>Added assignment operator<commit_after>#ifndef LIB_DATA_HPP__
#define LIB_DATA_HPP__

#include <lib/include/types.hpp>
#include <lib/include/compconfig.hpp>
#include <map>
#include <vector>

namespace lib
{
	class DataValue;
	typedef LIB_API std::map<str, DataValue> DataMap;
	enum class LIB_API DataType : u8
	{
		T_Empty,
		T_s8,
		T_u8,
		T_s16,
		T_u16,
		T_s32,
		T_u32,
		T_f64,
		T_string,
		T_Tree
	};

	class LIB_API DataValue
	{
	public:
		explicit inline DataValue() : m_dtype{ DataType::T_Empty }, f64_{ 0 } {}
		explicit inline DataValue(const s8 value_) : m_dtype{ DataType::T_s8 }, s8_{ value_ } {}
		explicit inline DataValue(const u8 value_) : m_dtype{ DataType::T_u8 }, u8_{ value_ } {}
		explicit inline DataValue(const s16 value_) : m_dtype{ DataType::T_s16 }, s16_{ value_ } {}
		explicit inline DataValue(const u16 value_) : m_dtype{ DataType::T_u16 }, u16_{ value_ } {}
		explicit inline DataValue(const s32 value_) : m_dtype{ DataType::T_s32 }, s32_{ value_ } {}
		explicit inline DataValue(const u32 value_) : m_dtype{ DataType::T_u32 }, u32_{ value_ } {}
		explicit inline DataValue(const f64 value_) : m_dtype{ DataType::T_f64 }, f64_{ value_ } {}
		explicit inline DataValue(const str &value_) : m_dtype{ DataType::T_string }, ptr_{ new str(value_) } {}
		explicit inline DataValue(const DataMap &value_) : m_dtype{ DataType::T_Tree }, ptr_{ new DataMap(value_) } {}

		explicit inline DataValue(const DataValue &value_): m_dtype{ value_.m_dtype }
		{
			switch (m_dtype)
			{
				case DataType::T_s8:
				case DataType::T_u8:
				case DataType::T_s16:
				case DataType::T_u16:
				case DataType::T_s32:
				case DataType::T_u32:
				case DataType::T_f64:
					f64_ = value_.f64_;
					break;
				case DataType::T_string:
					ptr_ = new str(value_.getString());
					break;
				case DataType::T_Tree:
					ptr_ = new DataMap(*value_.getMap());
					break;
				case DataType::T_Empty:
				default:
					break;
			}
		}

		inline DataValue(DataValue &&other)
		{
			std::swap(m_dtype, other.m_dtype);
			f64_ = other.f64_;
		}

		inline DataValue &operator=(const DataValue &rh)
		{
			DataValue temp{ rh };
			std::swap(*this, temp);
			return *this;
		}

		~DataValue();

		bool operator==(const s8 value_) const;
		bool operator==(const u8 value_) const;
		bool operator==(const s16 value_) const;
		bool operator==(const u16 value_) const;
		bool operator==(const s32 value_) const;
		bool operator==(const u32 value_) const;
		bool operator==(const f64 value_) const;
		bool operator==(const str &value_) const;
		bool operator==(const DataMap &value_) const;
		bool operator==(const DataValue &other) const;
		DataValue &operator=(DataValue &&other);

		const s8 gets8() const;
		const u8 getu8() const;
		const s16 gets16() const;
		const u16 getu16() const;
		const s32 gets32() const;
		const u32 getu32() const;
		const f64 getf64() const;
		const str getString() const;
		const DataMap *getMap() const;
		DataMap *getMap();

		friend std::ostream &operator<<(std::ostream &output, const DataValue &this_);

		template <typename T> inline const T get() const;
		template <> inline const s8 get() const { return gets8(); }
		template <> inline const u8 get() const { return getu8(); }
		template <> inline const s16 get() const { return gets16(); }
		template <> inline const u16 get() const { return getu16(); }
		template <> inline const s32 get() const { return gets32(); }
		template <> inline const u32 get() const { return getu32(); }
		template <> inline const f64 get() const { return getf64(); }

		inline const bool iss8() const { return m_dtype == DataType::T_s8; }
		inline const bool isu8() const { return m_dtype == DataType::T_s8; }
		inline const bool iss16() const { return m_dtype == DataType::T_s16; }
		inline const bool isu16() const { return m_dtype == DataType::T_u16; }
		inline const bool iss32() const { return m_dtype == DataType::T_s32; }
		inline const bool isu32() const { return m_dtype == DataType::T_u32; }
		inline const bool isf64() const { return m_dtype == DataType::T_f64; }
		inline const bool isstring() const { return m_dtype == DataType::T_string; }
		inline const bool ismap() const { return m_dtype == DataType::T_Tree; }

		template <typename T>
		const bool is() const;

		template <> inline const bool is<s8>() const { return iss8(); }
		template <> inline const bool is<u8>() const { return isu8(); }
		template <> inline const bool is<s16>() const { return iss16(); }
		template <> inline const bool is<u16>() const { return isu16(); }
		template <> inline const bool is<s32>() const { return iss32(); }
		template <> inline const bool is<u32>() const { return isu32(); }
		template <> inline const bool is<f64>() const { return isf64(); }

		static DataMap fromStringVector(const std::vector<str> &data, u32 &count);

	private:
		union
		{
			s8 s8_;
			u8 u8_;
			s16 s16_;
			u16 u16_;
			s32 s32_;
			u32 u32_;
			f64 f64_;
			void *ptr_;
		};
		DataType m_dtype{ DataType::T_Empty };
	};
}

#endif
<|endoftext|>


<commit_before>/*
 *   Copyright (C) 2014 Pelagicore AB
 *   All rights reserved.
 */
#include <iostream>
#include <stdio.h>
#include <sys/types.h>
#include <signal.h>
#include "dbusgateway.h"
#include "debug.h"

DBusGateway::DBusGateway(ControllerAbstractInterface *controllerInterface,
                         SystemcallAbstractInterface *systemcallInterface,
                         ProxyType type,
                         const std::string &gatewayDir,
                         const std::string &name):
    Gateway(controllerInterface),
    m_systemcallInterface(systemcallInterface),
    m_type(type),
    m_pid(-1),
    m_infp(-1),
    m_outfp(-1),
    m_hasBeenConfigured(false)
{
    if (m_type == SessionProxy) {
        m_socket = gatewayDir
            + std::string("/sess_")
            + name
            + std::string(".sock");
    } else {
        m_socket = gatewayDir
            + std::string("/sys_")
            + name
            + std::string(".sock");
    }
}

DBusGateway::~DBusGateway()
{
}

std::string DBusGateway::id()
{
    return "dbus-proxy";
}

bool DBusGateway::setConfig(const std::string &config)
{
    m_config = config;

    if(m_config.length() > 1) {
        m_hasBeenConfigured = true;
        return true;
    }

    return false;
}

bool DBusGateway::activate()
{
    if(!m_hasBeenConfigured) {
        log_error ("'Activate' called on non-configured gateway %s",
                   id().c_str());
        return false;
    }

    // set DBUS ENV
    std::string variable = "DBUS_";
    if (m_type == SessionProxy) {
        variable += "SESSION";
    } else {
        variable += "SYSTEM";
    }
    variable += "_BUS_ADDRESS";

    std::string value = "unix:path=/gateways/";
    value += socketName();
    m_controllerInterface->setEnvironmentVariable(variable, value);

    // Open pipe
    std::string command = "dbus-proxy ";
    command += m_socket + " " + typeString();
    m_pid = m_systemcallInterface->makePopenCall(command,
                                                 &m_infp,
                                                 &m_outfp);
    if(m_pid == -1) {
        log_error ("Failed to launch %s", command.c_str());
        return false;
    }

    size_t count = sizeof(char) * m_config.length();

    ssize_t written = write(m_infp,
                            m_config.c_str(),
                            count);

    // writing didn't work at all
    if(written == -1) {
        log_error ("Failed to write to STDIN of dbus-proxy!");
        return false;
    }

    // writing has written exact amout of bytes
    if(written == (ssize_t)count) {
        return true;
    }

    // something went wrong during the write
    log_error ("Failed to write to STDIN of dbus-proxy!");

    return false;
}

bool DBusGateway::teardown() {

    bool success = true;

    if(m_pid != -1) {
        if(!m_systemcallInterface->makePcloseCall(m_pid, m_infp, m_outfp)) {
            log_error("makePcloseCall() returned error\n");
            success = false;
        }
    }

    if(unlink(m_socket.c_str()) == -1) {
        log_error("Could not remove %s\n", m_socket.c_str());
        success = false;
    }

    return success;
}

const char *DBusGateway::typeString()
{
    if (m_type == SessionProxy) {
        return "session";
    } else {
        return "system";
    }
}

const char *DBusGateway::socketName()
{
    // Return the filename after stripping directory info
    std::string socket(m_socket.c_str());
    return socket.substr(socket.rfind('/') + 1).c_str();
}

std::string DBusGateway::environment()
{
    return "";
}
<commit_msg>Output error when not being able to close connection to dbus-proxy<commit_after>/*
 *   Copyright (C) 2014 Pelagicore AB
 *   All rights reserved.
 */
#include <iostream>
#include <stdio.h>
#include <sys/types.h>
#include <signal.h>
#include "dbusgateway.h"
#include "debug.h"

DBusGateway::DBusGateway(ControllerAbstractInterface *controllerInterface,
                         SystemcallAbstractInterface *systemcallInterface,
                         ProxyType type,
                         const std::string &gatewayDir,
                         const std::string &name):
    Gateway(controllerInterface),
    m_systemcallInterface(systemcallInterface),
    m_type(type),
    m_pid(-1),
    m_infp(-1),
    m_outfp(-1),
    m_hasBeenConfigured(false)
{
    if (m_type == SessionProxy) {
        m_socket = gatewayDir
            + std::string("/sess_")
            + name
            + std::string(".sock");
    } else {
        m_socket = gatewayDir
            + std::string("/sys_")
            + name
            + std::string(".sock");
    }
}

DBusGateway::~DBusGateway()
{
}

std::string DBusGateway::id()
{
    return "dbus-proxy";
}

bool DBusGateway::setConfig(const std::string &config)
{
    m_config = config;

    if(m_config.length() > 1) {
        m_hasBeenConfigured = true;
        return true;
    }

    return false;
}

bool DBusGateway::activate()
{
    if(!m_hasBeenConfigured) {
        log_error ("'Activate' called on non-configured gateway %s",
                   id().c_str());
        return false;
    }

    // set DBUS ENV
    std::string variable = "DBUS_";
    if (m_type == SessionProxy) {
        variable += "SESSION";
    } else {
        variable += "SYSTEM";
    }
    variable += "_BUS_ADDRESS";

    std::string value = "unix:path=/gateways/";
    value += socketName();
    m_controllerInterface->setEnvironmentVariable(variable, value);

    // Open pipe
    std::string command = "dbus-proxy ";
    command += m_socket + " " + typeString();
    m_pid = m_systemcallInterface->makePopenCall(command,
                                                 &m_infp,
                                                 &m_outfp);
    if(m_pid == -1) {
        log_error ("Failed to launch %s", command.c_str());
        return false;
    }

    size_t count = sizeof(char) * m_config.length();

    ssize_t written = write(m_infp,
                            m_config.c_str(),
                            count);

    // writing didn't work at all
    if(written == -1) {
        log_error ("Failed to write to STDIN of dbus-proxy!");
        return false;
    }

    // writing has written exact amout of bytes
    if(written == (ssize_t)count) {
        return true;
    }

    // something went wrong during the write
    log_error ("Failed to write to STDIN of dbus-proxy!");

    return false;
}

bool DBusGateway::teardown() {

    bool success = true;

    if(m_pid != -1) {
        if(!m_systemcallInterface->makePcloseCall(m_pid, m_infp, m_outfp)) {
            log_error("makePcloseCall() returned error\n");
            success = false;
        }
    } else {
        log_error("Failed to close connection to dbus-proxy!");
        success = false;
    }

    if(unlink(m_socket.c_str()) == -1) {
        log_error("Could not remove %s\n", m_socket.c_str());
        success = false;
    }

    return success;
}

const char *DBusGateway::typeString()
{
    if (m_type == SessionProxy) {
        return "session";
    } else {
        return "system";
    }
}

const char *DBusGateway::socketName()
{
    // Return the filename after stripping directory info
    std::string socket(m_socket.c_str());
    return socket.substr(socket.rfind('/') + 1).c_str();
}

std::string DBusGateway::environment()
{
    return "";
}
<|endoftext|>


<commit_before>#include "Runtime/World/CPathFindRegion.hpp"

#include "Runtime/World/CPathFindArea.hpp"

namespace urde {

CPFNode::CPFNode(CMemoryInStream& in) {
  x0_position.readBig(in);
  xc_normal.readBig(in);
}

CPFLink::CPFLink(CMemoryInStream& in) {
  x0_node = in.readUint32Big();
  x4_region = in.readUint32Big();
  x8_2dWidth = in.readFloatBig();
  xc_oo2dWidth = in.readFloatBig();
}

CPFRegion::CPFRegion(CMemoryInStream& in) {
  x0_numNodes = in.readUint32Big();
  x4_startNode = reinterpret_cast<CPFNode*>(in.readUint32Big());
  x8_numLinks = in.readUint32Big();
  xc_startLink = reinterpret_cast<CPFLink*>(in.readUint32Big());
  x10_flags = in.readUint32Big();
  x14_height = in.readFloatBig();
  x18_normal.readBig(in);
  x24_regionIdx = in.readUint32Big();
  x28_centroid.readBig(in);
  x34_aabb.readBoundingBoxBig(in);
  x4c_regionData = reinterpret_cast<CPFRegionData*>(in.readUint32Big());
}

const CPFLink* CPFRegion::GetPathLink() const { return &xc_startLink[x4c_regionData->GetPathLink()]; }

void CPFRegion::Fixup(CPFArea& area, u32& maxRegionNodes) {
  if (x0_numNodes)
    x4_startNode = &area.x140_nodes[reinterpret_cast<uintptr_t>(x4_startNode)];
  else
    x4_startNode = nullptr;
  if (x8_numLinks)
    xc_startLink = &area.x148_links[reinterpret_cast<uintptr_t>(xc_startLink)];
  else
    xc_startLink = nullptr;
  x4c_regionData = &area.x178_regionDatas[x24_regionIdx];
  if (x0_numNodes > maxRegionNodes)
    maxRegionNodes = x0_numNodes;
}

bool CPFRegion::IsPointInside(const zeus::CVector3f& point) const {
  if (!x34_aabb.pointInside(point))
    return false;
  u32 i;
  for (i = 0; i < x0_numNodes; ++i) {
    CPFNode& node = x4_startNode[i];
    if ((point - node.GetPos()).dot(node.GetNormal()) < 0.f)
      break;
  }
  if (i != x0_numNodes)
    return false;
  zeus::CVector3f nodeToPoint = point - x4_startNode->GetPos();
  return nodeToPoint.dot(x18_normal) >= 0.f &&
         (nodeToPoint - x14_height * zeus::skUp).dot(x18_normal) <= 0.f;
}

float CPFRegion::PointHeight(const zeus::CVector3f& point) const {
  return (point - x4_startNode->GetPos()).dot(x18_normal);
}

bool CPFRegion::FindClosestPointOnPolygon(const std::vector<zeus::CVector3f>& polyPoints, const zeus::CVector3f& normal,
                                          const zeus::CVector3f& point, bool excludePolyPoints) const {
  bool found = false;
  size_t i;
  for (i = 0; i < polyPoints.size(); ++i) {
    const zeus::CVector3f& p0 = polyPoints[i];
    const zeus::CVector3f& p1 = polyPoints[(i + 1) % polyPoints.size()];
    if ((p1 - p0).cross(normal).dot(point - p0) < 0.f)
      break;
  }

  if (i == polyPoints.size()) {
    float distToPoly = (polyPoints.front() - point).dot(normal);
    float distToPolySq = distToPoly * distToPoly;
    if (distToPolySq < x4c_regionData->GetBestPointDistanceSquared()) {
      found = true;
      x4c_regionData->SetBestPointDistanceSquared(distToPolySq);
      x4c_regionData->SetBestPoint(normal * distToPoly + point);
    }
  } else {
    bool projected = false;
    for (i = 0; i < polyPoints.size(); ++i) {
      const zeus::CVector3f& p0 = polyPoints[i];
      const zeus::CVector3f& p1 = polyPoints[(i + 1) % polyPoints.size()];
      zeus::CVector3f p0ToP1 = p1 - p0;
      zeus::CVector3f p1ToPoint = point - p1;
      zeus::CVector3f sum = p1ToPoint + p0ToP1;
      if (p0ToP1.cross(normal).dot(p1ToPoint) < 0.f && p0ToP1.dot(p1ToPoint) <= 0.f && sum.dot(p0ToP1) >= 0.f) {
        projected = true;
        p0ToP1.normalize();
        sum -= p0ToP1.dot(sum) * p0ToP1;
        float distSq = sum.magSquared();
        if (distSq < x4c_regionData->GetBestPointDistanceSquared()) {
          found = true;
          x4c_regionData->SetBestPointDistanceSquared(distSq);
          x4c_regionData->SetBestPoint(point - sum);
        }
        break;
      }
    }

    if (!projected && !excludePolyPoints) {
      for (i = 0; i < polyPoints.size(); ++i) {
        const zeus::CVector3f& p0 = polyPoints[i];
        float distSq = (point - p0).magSquared();
        if (distSq < x4c_regionData->GetBestPointDistanceSquared()) {
          found = true;
          x4c_regionData->SetBestPointDistanceSquared(distSq);
          x4c_regionData->SetBestPoint(p0);
        }
      }
    }
  }
  return found;
}

bool CPFRegion::FindBestPoint(std::vector<zeus::CVector3f>& polyPoints, const zeus::CVector3f& point, u32 flags,
                              float paddingSq) const {
  bool found = false;
  bool isFlyer = (flags & 0x2) != 0;
  x4c_regionData->SetBestPointDistanceSquared(paddingSq);
  if (!isFlyer) {
    for (u32 i = 0; i < x0_numNodes; ++i) {
      CPFNode& node = x4_startNode[i];
      CPFNode& nextNode = x4_startNode[(i + 1) % x0_numNodes];
      polyPoints.clear();
      polyPoints.push_back(node.GetPos());
      polyPoints.push_back(node.GetPos());
      polyPoints.back().z() += x14_height;
      polyPoints.push_back(nextNode.GetPos());
      polyPoints.back().z() += x14_height;
      polyPoints.push_back(nextNode.GetPos());
      found |= FindClosestPointOnPolygon(polyPoints, node.GetNormal(), point, true);
    }
  }

  polyPoints.clear();
  for (u32 i = 0; i < x0_numNodes; ++i) {
    CPFNode& node = x4_startNode[i];
    polyPoints.push_back(node.GetPos());
  }
  found |= FindClosestPointOnPolygon(polyPoints, x18_normal, point, false);

  if (!isFlyer) {
    polyPoints.clear();
    for (int i = int(x0_numNodes) - 1; i >= 0; --i) {
      CPFNode& node = x4_startNode[i];
      polyPoints.push_back(node.GetPos());
      polyPoints.back().z() += x14_height;
    }
    found |= FindClosestPointOnPolygon(polyPoints, -x18_normal, point, false);
  }

  return found;
}

void CPFRegion::SetLinkTo(u32 idx) {
  if (x8_numLinks <= 0) {
    return;
  }

  for (u32 i = 0; i < x8_numLinks; ++i) {
    if (xc_startLink[i].GetRegion() == idx) {
      Data()->SetPathLink(i);
      return;
    }
  }
}

void CPFRegion::DropToGround(zeus::CVector3f& point) const {
  point.z() -= (point - x4_startNode->GetPos()).dot(x18_normal) / x18_normal.z();
}

zeus::CVector3f CPFRegion::GetLinkMidPoint(const CPFLink& link) const {
  const CPFNode& node = x4_startNode[link.GetNode()];
  const CPFNode& nextNode = x4_startNode[(link.GetNode() + 1) % x0_numNodes];
  return (node.GetPos() + nextNode.GetPos()) * 0.5f;
}

zeus::CVector3f CPFRegion::FitThroughLink2d(const zeus::CVector3f& p1, const CPFLink& link, const zeus::CVector3f& p2,
                                            float chRadius) const {
  CPFNode& node = x4_startNode[link.GetNode()];
  CPFNode& nextNode = x4_startNode[(link.GetNode() + 1) % x0_numNodes];
  zeus::CVector3f nodeDelta = nextNode.GetPos() - node.GetPos();
  float t = 0.5f;
  if (chRadius < 0.5f * link.Get2dWidth()) {
    zeus::CVector2f delta2d = nodeDelta.toVec2f();
    delta2d *= link.GetOO2dWidth();
    zeus::CVector3f nodeToP1 = p1 - node.GetPos();
    float f27 = nodeToP1.dot(node.GetNormal());
    float f31 = delta2d.dot(nodeToP1.toVec2f());
    zeus::CVector3f nodeToP2 = p2 - node.GetPos();
    float f26 = -nodeToP2.dot(node.GetNormal());
    float f1b = delta2d.dot(nodeToP2.toVec2f());
    float f3 = f27 + f26;
    if (f3 > FLT_EPSILON)
      t = zeus::clamp(chRadius, 1.f / f3 * (f26 * f31 + f27 * f1b), link.Get2dWidth() - chRadius) * link.GetOO2dWidth();
  }
  return nodeDelta * t + node.GetPos();
}

zeus::CVector3f CPFRegion::FitThroughLink3d(const zeus::CVector3f& p1, const CPFLink& link, float regionHeight,
                                            const zeus::CVector3f& p2, float chRadius, float chHalfHeight) const {
  CPFNode& node = x4_startNode[link.GetNode()];
  CPFNode& nextNode = x4_startNode[(link.GetNode() + 1) % x0_numNodes];
  zeus::CVector3f nodeDelta = nextNode.GetPos() - node.GetPos();
  float f25 = (p1 - node.GetPos()).dot(node.GetNormal());
  float f24 = (node.GetPos() - p2).dot(node.GetNormal());
  float f23 = f25 + f24;
#if 0
  if (chRadius < 0.5f * link.Get2dWidth()) {
    zeus::CVector2f delta2d(nodeDelta.x, nodeDelta.y);
    delta2d *= link.GetOO2dWidth();
    zeus::CVector3f nodeToP1 = p1 - node.GetPos();
    float f29 = delta2d.dot(zeus::CVector2f(nodeToP1.y, nodeToP1.y));
    zeus::CVector3f nodeToP2 = p2 - node.GetPos();
    float f1b = delta2d.dot(zeus::CVector2f(nodeToP2.y, nodeToP2.y));
    if (f23 > FLT_EPSILON) {
      zeus::clamp(chRadius, 1.f / f23 * f24 * f29 + f25 * f1b, link.Get2dWidth() - chRadius) *
          link.GetOO2dWidth();
    }
  }
#endif
  zeus::CVector3f midPoint = nodeDelta * 0.5f + node.GetPos();
  float z;
  if (chHalfHeight < 0.5f * regionHeight) {
    float minZ = chHalfHeight + midPoint.z();
    z = 0.5f * (p1.z() + p2.z());
    if (f23 > FLT_EPSILON)
      z = (f24 * p1.z() + f25 * p2.z()) / f23;
    z = zeus::clamp(minZ, z, regionHeight + midPoint.z() - chHalfHeight);
  } else {
    z = (p1.z() + p2.z()) * 0.5f;
  }
  return {midPoint.x(), midPoint.y(), z};
}

bool CPFRegion::IsPointInsidePaddedAABox(const zeus::CVector3f& point, float padding) const {
  return point.x() >= x34_aabb.min.x() - padding && point.x() <= x34_aabb.max.x() + padding &&
         point.y() >= x34_aabb.min.y() - padding && point.y() <= x34_aabb.max.y() + padding &&
         point.z() >= x34_aabb.min.z() - padding && point.z() <= x34_aabb.max.z() + padding;
}

} // namespace urde
<commit_msg>CPathFindRegion: Brace statements where applicable<commit_after>#include "Runtime/World/CPathFindRegion.hpp"

#include "Runtime/World/CPathFindArea.hpp"

namespace urde {

CPFNode::CPFNode(CMemoryInStream& in) {
  x0_position.readBig(in);
  xc_normal.readBig(in);
}

CPFLink::CPFLink(CMemoryInStream& in) {
  x0_node = in.readUint32Big();
  x4_region = in.readUint32Big();
  x8_2dWidth = in.readFloatBig();
  xc_oo2dWidth = in.readFloatBig();
}

CPFRegion::CPFRegion(CMemoryInStream& in) {
  x0_numNodes = in.readUint32Big();
  x4_startNode = reinterpret_cast<CPFNode*>(in.readUint32Big());
  x8_numLinks = in.readUint32Big();
  xc_startLink = reinterpret_cast<CPFLink*>(in.readUint32Big());
  x10_flags = in.readUint32Big();
  x14_height = in.readFloatBig();
  x18_normal.readBig(in);
  x24_regionIdx = in.readUint32Big();
  x28_centroid.readBig(in);
  x34_aabb.readBoundingBoxBig(in);
  x4c_regionData = reinterpret_cast<CPFRegionData*>(in.readUint32Big());
}

const CPFLink* CPFRegion::GetPathLink() const { return &xc_startLink[x4c_regionData->GetPathLink()]; }

void CPFRegion::Fixup(CPFArea& area, u32& maxRegionNodes) {
  if (x0_numNodes != 0) {
    x4_startNode = &area.x140_nodes[reinterpret_cast<uintptr_t>(x4_startNode)];
  } else {
    x4_startNode = nullptr;
  }

  if (x8_numLinks != 0) {
    xc_startLink = &area.x148_links[reinterpret_cast<uintptr_t>(xc_startLink)];
  } else {
    xc_startLink = nullptr;
  }

  x4c_regionData = &area.x178_regionDatas[x24_regionIdx];
  if (x0_numNodes > maxRegionNodes) {
    maxRegionNodes = x0_numNodes;
  }
}

bool CPFRegion::IsPointInside(const zeus::CVector3f& point) const {
  if (!x34_aabb.pointInside(point)) {
    return false;
  }

  u32 i;
  for (i = 0; i < x0_numNodes; ++i) {
    const CPFNode& node = x4_startNode[i];
    if ((point - node.GetPos()).dot(node.GetNormal()) < 0.f) {
      break;
    }
  }

  if (i != x0_numNodes) {
    return false;
  }

  const zeus::CVector3f nodeToPoint = point - x4_startNode->GetPos();
  return nodeToPoint.dot(x18_normal) >= 0.f && (nodeToPoint - x14_height * zeus::skUp).dot(x18_normal) <= 0.f;
}

float CPFRegion::PointHeight(const zeus::CVector3f& point) const {
  return (point - x4_startNode->GetPos()).dot(x18_normal);
}

bool CPFRegion::FindClosestPointOnPolygon(const std::vector<zeus::CVector3f>& polyPoints, const zeus::CVector3f& normal,
                                          const zeus::CVector3f& point, bool excludePolyPoints) const {
  bool found = false;
  size_t i;
  for (i = 0; i < polyPoints.size(); ++i) {
    const zeus::CVector3f& p0 = polyPoints[i];
    const zeus::CVector3f& p1 = polyPoints[(i + 1) % polyPoints.size()];
    if ((p1 - p0).cross(normal).dot(point - p0) < 0.f) {
      break;
    }
  }

  if (i == polyPoints.size()) {
    const float distToPoly = (polyPoints.front() - point).dot(normal);
    const float distToPolySq = distToPoly * distToPoly;
    if (distToPolySq < x4c_regionData->GetBestPointDistanceSquared()) {
      found = true;
      x4c_regionData->SetBestPointDistanceSquared(distToPolySq);
      x4c_regionData->SetBestPoint(normal * distToPoly + point);
    }
  } else {
    bool projected = false;
    for (i = 0; i < polyPoints.size(); ++i) {
      const zeus::CVector3f& p0 = polyPoints[i];
      const zeus::CVector3f& p1 = polyPoints[(i + 1) % polyPoints.size()];
      zeus::CVector3f p0ToP1 = p1 - p0;
      zeus::CVector3f p1ToPoint = point - p1;
      zeus::CVector3f sum = p1ToPoint + p0ToP1;

      if (p0ToP1.cross(normal).dot(p1ToPoint) < 0.f && p0ToP1.dot(p1ToPoint) <= 0.f && sum.dot(p0ToP1) >= 0.f) {
        projected = true;
        p0ToP1.normalize();
        sum -= p0ToP1.dot(sum) * p0ToP1;
        const float distSq = sum.magSquared();
        if (distSq < x4c_regionData->GetBestPointDistanceSquared()) {
          found = true;
          x4c_regionData->SetBestPointDistanceSquared(distSq);
          x4c_regionData->SetBestPoint(point - sum);
        }
        break;
      }
    }

    if (!projected && !excludePolyPoints) {
      for (i = 0; i < polyPoints.size(); ++i) {
        const zeus::CVector3f& p0 = polyPoints[i];
        const float distSq = (point - p0).magSquared();
        if (distSq < x4c_regionData->GetBestPointDistanceSquared()) {
          found = true;
          x4c_regionData->SetBestPointDistanceSquared(distSq);
          x4c_regionData->SetBestPoint(p0);
        }
      }
    }
  }
  return found;
}

bool CPFRegion::FindBestPoint(std::vector<zeus::CVector3f>& polyPoints, const zeus::CVector3f& point, u32 flags,
                              float paddingSq) const {
  bool found = false;
  const bool isFlyer = (flags & 0x2) != 0;

  x4c_regionData->SetBestPointDistanceSquared(paddingSq);

  if (!isFlyer) {
    for (u32 i = 0; i < x0_numNodes; ++i) {
      const CPFNode& node = x4_startNode[i];
      const CPFNode& nextNode = x4_startNode[(i + 1) % x0_numNodes];
      polyPoints.clear();
      polyPoints.push_back(node.GetPos());
      polyPoints.push_back(node.GetPos());
      polyPoints.back().z() += x14_height;
      polyPoints.push_back(nextNode.GetPos());
      polyPoints.back().z() += x14_height;
      polyPoints.push_back(nextNode.GetPos());
      found |= FindClosestPointOnPolygon(polyPoints, node.GetNormal(), point, true);
    }
  }

  polyPoints.clear();
  for (u32 i = 0; i < x0_numNodes; ++i) {
    const CPFNode& node = x4_startNode[i];
    polyPoints.push_back(node.GetPos());
  }
  found |= FindClosestPointOnPolygon(polyPoints, x18_normal, point, false);

  if (!isFlyer) {
    polyPoints.clear();
    for (int i = int(x0_numNodes) - 1; i >= 0; --i) {
      const CPFNode& node = x4_startNode[i];
      polyPoints.push_back(node.GetPos());
      polyPoints.back().z() += x14_height;
    }
    found |= FindClosestPointOnPolygon(polyPoints, -x18_normal, point, false);
  }

  return found;
}

void CPFRegion::SetLinkTo(u32 idx) {
  if (x8_numLinks <= 0) {
    return;
  }

  for (u32 i = 0; i < x8_numLinks; ++i) {
    if (xc_startLink[i].GetRegion() == idx) {
      Data()->SetPathLink(i);
      return;
    }
  }
}

void CPFRegion::DropToGround(zeus::CVector3f& point) const {
  point.z() -= (point - x4_startNode->GetPos()).dot(x18_normal) / x18_normal.z();
}

zeus::CVector3f CPFRegion::GetLinkMidPoint(const CPFLink& link) const {
  const CPFNode& node = x4_startNode[link.GetNode()];
  const CPFNode& nextNode = x4_startNode[(link.GetNode() + 1) % x0_numNodes];
  return (node.GetPos() + nextNode.GetPos()) * 0.5f;
}

zeus::CVector3f CPFRegion::FitThroughLink2d(const zeus::CVector3f& p1, const CPFLink& link, const zeus::CVector3f& p2,
                                            float chRadius) const {
  const CPFNode& node = x4_startNode[link.GetNode()];
  const CPFNode& nextNode = x4_startNode[(link.GetNode() + 1) % x0_numNodes];
  const zeus::CVector3f nodeDelta = nextNode.GetPos() - node.GetPos();
  float t = 0.5f;

  if (chRadius < 0.5f * link.Get2dWidth()) {
    zeus::CVector2f delta2d = nodeDelta.toVec2f();
    delta2d *= link.GetOO2dWidth();
    const zeus::CVector3f nodeToP1 = p1 - node.GetPos();
    const float f27 = nodeToP1.dot(node.GetNormal());
    const float f31 = delta2d.dot(nodeToP1.toVec2f());
    const zeus::CVector3f nodeToP2 = p2 - node.GetPos();
    const float f26 = -nodeToP2.dot(node.GetNormal());
    const float f1b = delta2d.dot(nodeToP2.toVec2f());
    const float f3 = f27 + f26;
    if (f3 > FLT_EPSILON) {
      t = zeus::clamp(chRadius, 1.f / f3 * (f26 * f31 + f27 * f1b), link.Get2dWidth() - chRadius) * link.GetOO2dWidth();
    }
  }
  return nodeDelta * t + node.GetPos();
}

zeus::CVector3f CPFRegion::FitThroughLink3d(const zeus::CVector3f& p1, const CPFLink& link, float regionHeight,
                                            const zeus::CVector3f& p2, float chRadius, float chHalfHeight) const {
  const CPFNode& node = x4_startNode[link.GetNode()];
  const CPFNode& nextNode = x4_startNode[(link.GetNode() + 1) % x0_numNodes];
  const zeus::CVector3f nodeDelta = nextNode.GetPos() - node.GetPos();
  const float f25 = (p1 - node.GetPos()).dot(node.GetNormal());
  const float f24 = (node.GetPos() - p2).dot(node.GetNormal());
  const float f23 = f25 + f24;

#if 0
  if (chRadius < 0.5f * link.Get2dWidth()) {
    zeus::CVector2f delta2d(nodeDelta.x, nodeDelta.y);
    delta2d *= link.GetOO2dWidth();
    const zeus::CVector3f nodeToP1 = p1 - node.GetPos();
    const float f29 = delta2d.dot(zeus::CVector2f(nodeToP1.y, nodeToP1.y));
    const zeus::CVector3f nodeToP2 = p2 - node.GetPos();
    const float f1b = delta2d.dot(zeus::CVector2f(nodeToP2.y, nodeToP2.y));
    if (f23 > FLT_EPSILON) {
      zeus::clamp(chRadius, 1.f / f23 * f24 * f29 + f25 * f1b, link.Get2dWidth() - chRadius) * link.GetOO2dWidth();
    }
  }
#endif

  const zeus::CVector3f midPoint = nodeDelta * 0.5f + node.GetPos();
  float z;
  if (chHalfHeight < 0.5f * regionHeight) {
    const float minZ = chHalfHeight + midPoint.z();
    z = 0.5f * (p1.z() + p2.z());
    if (f23 > FLT_EPSILON) {
      z = (f24 * p1.z() + f25 * p2.z()) / f23;
    }
    z = zeus::clamp(minZ, z, regionHeight + midPoint.z() - chHalfHeight);
  } else {
    z = (p1.z() + p2.z()) * 0.5f;
  }
  return {midPoint.x(), midPoint.y(), z};
}

bool CPFRegion::IsPointInsidePaddedAABox(const zeus::CVector3f& point, float padding) const {
  return point.x() >= x34_aabb.min.x() - padding && point.x() <= x34_aabb.max.x() + padding &&
         point.y() >= x34_aabb.min.y() - padding && point.y() <= x34_aabb.max.y() + padding &&
         point.z() >= x34_aabb.min.z() - padding && point.z() <= x34_aabb.max.z() + padding;
}

} // namespace urde
<|endoftext|>


<commit_before>#include <fstream>
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
#include <getopt.h>
#include <math.h>

#include "Scorer.h"
#include "Timer.h"
#include "Util.h"

#include "ScorerFactory.h"

using namespace std;

Scorer* scorer;
int bootstrap = 0;
void evaluate(const string& candFile);
void addStats(vector<int>& stats1, const vector<int>& stats2);
float average(const vector<float>& list);
float stdDeviation(const vector<float>& list, float avg);
string int2string(int n);

bool moreFiles = false;
bool moreScorers = false;

void usage()
{
  cerr<<"usage: evaluator [options] --reference ref1[,ref2[,ref3...]] --candidate cand1[,cand2[,cand3...]] "<<endl;
  cerr<<"[--sctype|-s] the scorer type (default BLEU)"<<endl;
  cerr<<"[--scconfig|-c] configuration string passed to scorer"<<endl;
  cerr<<"\tThis is of the form NAME1:VAL1,NAME2:VAL2 etc "<<endl;
  cerr<<"[--reference|-R] comma separated list of reference files"<<endl;
  cerr<<"[--candidate|-C] comma separated list of candidate files"<<endl;
  cerr<<"[--bootstrap|-b] number of booststraped samples (default 0 - no bootstraping)"<<endl;
  cerr<<"[--rseed|-r] the random seed for bootstraping (defaults to system clock)"<<endl;
  cerr<<"[--help|-h] print this message and exit"<<endl;
  cerr<<endl;
  cerr<<"Evaluator is able to compute more metrics at once. To do this,"<<endl;
  cerr<<"separate scorers with semicolon (note that comma is used to separate"<<endl;
  cerr<<"scorers in the interpolated scorer)."<<endl;
  cerr<<endl;
  cerr<<"If you specify only one metric and one candidate file, only the final score"<<endl;
  cerr<<"will be printed to stdout. Otherwise each line will contain metric name"<<endl;
  cerr<<"and/or filename and the final score. Since most of the metrics prints some"<<endl;
  cerr<<"debuging info, consider redirecting stderr to /dev/null."<<endl;
  exit(1);
}

static struct option long_options[] = {
  {"sctype",required_argument,0,'s'},
  {"scconfig",required_argument,0,'c'},
  {"reference",required_argument,0,'R'},
  {"candidate",required_argument,0,'C'},
  {"bootstrap",required_argument,0,'b'},
  {"rseed",required_argument,0,'r'},
  {"help",no_argument,0,'h'},
  {0, 0, 0, 0}
};
int option_index;

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

  //defaults
  string scorerType("BLEU");
  string scorerConfig("");
  string reference("");
  string candidate("");

  int seed = 0;
  bool hasSeed = false;

  int c;
  while ((c=getopt_long (argc,argv, "s:c:R:C:b:r:h", long_options, &option_index)) != -1) {
    switch(c) {
      case 's':
        scorerType = string(optarg);
        break;
      case 'c':
        scorerConfig = string(optarg);
        break;
      case 'R':
        reference = string(optarg);
        break;
      case 'C':
        candidate = string(optarg);
        break;
      case 'b':
        bootstrap = atoi(optarg);
        break;
      case 'r':
        seed = strtol(optarg, NULL, 10);
        hasSeed = true;
        break;
      default:
        usage();
    }
  }

  if (bootstrap)
  {
    if (hasSeed) {
      cerr << "Seeding random numbers with " << seed << endl;
      srandom(seed);
    } else {
      cerr << "Seeding random numbers with system clock " << endl;
      srandom(time(NULL));
    }
  }

  try {
    vector<string> refFiles;
    vector<string> candFiles;
    vector<string> scorerTypes;

    if (reference.length() == 0) throw runtime_error("You have to specify at least one reference file.");
    split(reference,',',refFiles);

    if (candidate.length() == 0) throw runtime_error("You have to specify at least one candidate file.");
    split(candidate,',',candFiles);

    if (scorerType.length() == 0) throw runtime_error("You have to specify at least one scorer.");
    split(scorerType,';',scorerTypes);

    if (candFiles.size() > 1) moreFiles = true;
    if (scorerTypes.size() > 1) moreScorers = true;

    for (vector<string>::const_iterator fileIt = candFiles.begin(); fileIt != candFiles.end(); ++fileIt)
    {
        for (vector<string>::const_iterator scorerIt = scorerTypes.begin(); scorerIt != scorerTypes.end(); ++scorerIt)
        {
            scorer = ScorerFactory::getScorer(*scorerIt,scorerConfig);
            scorer->setReferenceFiles(refFiles);
            evaluate(*fileIt);
            delete scorer;
        }
    }

    return EXIT_SUCCESS;
  } catch (const exception& e) {
    cerr << "Exception: " << e.what() << endl;
    return EXIT_FAILURE;
  }

}

void evaluate(const string& candFile)
{
  ifstream cand(candFile.c_str());
  if (!cand.good()) throw runtime_error("Error opening candidate file");

  vector<ScoreStats> entries;

  // Loading sentences and preparing statistics
  ScoreStats scoreentry;
  string line;
  while (getline(cand, line))
  {
    scorer->prepareStats(entries.size(), line, scoreentry);
    entries.push_back(scoreentry);
  }

  int n = entries.size();
  if (bootstrap)
  {
    vector<float> scores;
    for (int i = 0; i < bootstrap; ++i)
    {
      // TODO: Use smart pointer for exceptional-safety.
      ScoreData* scoredata = new ScoreData(*scorer);
      for (int j = 0; j < n; ++j)
      {
        int randomIndex = random() % n;
        string str_j = int2string(j);
        scoredata->add(entries[randomIndex], str_j);
      }
      scorer->setScoreData(scoredata);
      candidates_t candidates(n, 0);
      float score = scorer->score(candidates);
      scores.push_back(score);
      delete scoredata;
    }

    float avg = average(scores);
    float dev = stdDeviation(scores, avg);

    if (moreFiles) cout << candFile << "\t";
    if (moreScorers) cout << scorer->getName() << "\t";

    cout.setf(ios::fixed,ios::floatfield);
    cout.precision(4);
    cout << avg << " [+-" << dev << "]"<< endl;
  }
  else
  {
    // TODO: Use smart pointer for exceptional-safety.
    ScoreData* scoredata = new ScoreData(*scorer);
    for (int sid = 0; sid < n; ++sid)
    {
      string str_sid = int2string(sid);
      scoredata->add(entries[sid], str_sid);
    }
    scorer->setScoreData(scoredata);
    candidates_t candidates(n, 0);
    float score = scorer->score(candidates);
    delete scoredata;

    if (moreFiles) cout << candFile << "\t";
    if (moreScorers) cout << scorer->getName() << "\t";

    cout.setf(ios::fixed,ios::floatfield);
    cout.precision(4);
    cout << score << endl;
  }
}

string int2string(int n)
{
  stringstream ss;
  ss << n;
  return ss.str();
}

float average(const vector<float>& list)
{
  float sum = 0;
  for (vector<float>::const_iterator it = list.begin(); it != list.end(); ++it)
    sum += *it;

  return sum / list.size();
}

float stdDeviation(const vector<float>& list, float avg)
{
  vector<float> tmp;
  for (vector<float>::const_iterator it = list.begin(); it != list.end(); ++it)
    tmp.push_back(pow(*it - avg, 2));

  return sqrt(average(tmp));
}
<commit_msg>mert/evaluator should now compute confidence interval correctly<commit_after>#include <fstream>
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
#include <getopt.h>
#include <math.h>

#include "Scorer.h"
#include "Timer.h"
#include "Util.h"

#include "ScorerFactory.h"

using namespace std;

Scorer* scorer;
int bootstrap = 0;
void evaluate(const string& candFile);
void addStats(vector<int>& stats1, const vector<int>& stats2);
float average(const vector<float>& list);
float stdDeviation(const vector<float>& list, float avg);
string int2string(int n);

bool moreFiles = false;
bool moreScorers = false;

float alpha = 0.05;

void usage()
{
  cerr<<"usage: evaluator [options] --reference ref1[,ref2[,ref3...]] --candidate cand1[,cand2[,cand3...]] "<<endl;
  cerr<<"[--sctype|-s] the scorer type (default BLEU)"<<endl;
  cerr<<"[--scconfig|-c] configuration string passed to scorer"<<endl;
  cerr<<"\tThis is of the form NAME1:VAL1,NAME2:VAL2 etc "<<endl;
  cerr<<"[--reference|-R] comma separated list of reference files"<<endl;
  cerr<<"[--candidate|-C] comma separated list of candidate files"<<endl;
  cerr<<"[--bootstrap|-b] number of booststraped samples (default 0 - no bootstraping)"<<endl;
  cerr<<"[--rseed|-r] the random seed for bootstraping (defaults to system clock)"<<endl;
  cerr<<"[--help|-h] print this message and exit"<<endl;
  cerr<<endl;
  cerr<<"Evaluator is able to compute more metrics at once. To do this,"<<endl;
  cerr<<"separate scorers with semicolon (note that comma is used to separate"<<endl;
  cerr<<"scorers in the interpolated scorer)."<<endl;
  cerr<<endl;
  cerr<<"If you specify only one metric and one candidate file, only the final score"<<endl;
  cerr<<"will be printed to stdout. Otherwise each line will contain metric name"<<endl;
  cerr<<"and/or filename and the final score. Since most of the metrics prints some"<<endl;
  cerr<<"debuging info, consider redirecting stderr to /dev/null."<<endl;
  exit(1);
}

static struct option long_options[] = {
  {"sctype",required_argument,0,'s'},
  {"scconfig",required_argument,0,'c'},
  {"reference",required_argument,0,'R'},
  {"candidate",required_argument,0,'C'},
  {"bootstrap",required_argument,0,'b'},
  {"rseed",required_argument,0,'r'},
  {"help",no_argument,0,'h'},
  {0, 0, 0, 0}
};
int option_index;

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

  //defaults
  string scorerType("BLEU");
  string scorerConfig("");
  string reference("");
  string candidate("");

  int seed = 0;
  bool hasSeed = false;

  int c;
  while ((c=getopt_long (argc,argv, "s:c:R:C:b:r:h", long_options, &option_index)) != -1) {
    switch(c) {
      case 's':
        scorerType = string(optarg);
        break;
      case 'c':
        scorerConfig = string(optarg);
        break;
      case 'R':
        reference = string(optarg);
        break;
      case 'C':
        candidate = string(optarg);
        break;
      case 'b':
        bootstrap = atoi(optarg);
        break;
      case 'r':
        seed = strtol(optarg, NULL, 10);
        hasSeed = true;
        break;
      default:
        usage();
    }
  }

  if (bootstrap)
  {
    if (hasSeed) {
      cerr << "Seeding random numbers with " << seed << endl;
      srandom(seed);
    } else {
      cerr << "Seeding random numbers with system clock " << endl;
      srandom(time(NULL));
    }
  }

  try {
    vector<string> refFiles;
    vector<string> candFiles;
    vector<string> scorerTypes;

    if (reference.length() == 0) throw runtime_error("You have to specify at least one reference file.");
    split(reference,',',refFiles);

    if (candidate.length() == 0) throw runtime_error("You have to specify at least one candidate file.");
    split(candidate,',',candFiles);

    if (scorerType.length() == 0) throw runtime_error("You have to specify at least one scorer.");
    split(scorerType,';',scorerTypes);

    if (candFiles.size() > 1) moreFiles = true;
    if (scorerTypes.size() > 1) moreScorers = true;

    for (vector<string>::const_iterator fileIt = candFiles.begin(); fileIt != candFiles.end(); ++fileIt)
    {
        for (vector<string>::const_iterator scorerIt = scorerTypes.begin(); scorerIt != scorerTypes.end(); ++scorerIt)
        {
            scorer = ScorerFactory::getScorer(*scorerIt,scorerConfig);
            scorer->setReferenceFiles(refFiles);
            evaluate(*fileIt);
            delete scorer;
        }
    }

    return EXIT_SUCCESS;
  } catch (const exception& e) {
    cerr << "Exception: " << e.what() << endl;
    return EXIT_FAILURE;
  }

}

void evaluate(const string& candFile)
{
  ifstream cand(candFile.c_str());
  if (!cand.good()) throw runtime_error("Error opening candidate file");

  vector<ScoreStats> entries;

  // Loading sentences and preparing statistics
  ScoreStats scoreentry;
  string line;
  while (getline(cand, line))
  {
    scorer->prepareStats(entries.size(), line, scoreentry);
    entries.push_back(scoreentry);
  }

  int n = entries.size();
  if (bootstrap)
  {
    vector<float> scores;
    for (int i = 0; i < bootstrap; ++i)
    {
      // TODO: Use smart pointer for exceptional-safety.
      ScoreData* scoredata = new ScoreData(*scorer);
      for (int j = 0; j < n; ++j)
      {
        int randomIndex = random() % n;
        string str_j = int2string(j);
        scoredata->add(entries[randomIndex], str_j);
      }
      scorer->setScoreData(scoredata);
      candidates_t candidates(n, 0);
      float score = scorer->score(candidates);
      scores.push_back(score);
      delete scoredata;
    }

    float avg = average(scores);

    sort(scores.begin(), scores.end());

    int lbIdx = scores.size() * (alpha / 2);
    int rbIdx = scores.size() * (1 - alpha / 2);

    float lb = scores[lbIdx];
    float rb = scores[rbIdx];

    if (moreFiles) cout << candFile << "\t";
    if (moreScorers) cout << scorer->getName() << "\t";

    cout.setf(ios::fixed,ios::floatfield);
    cout.precision(4);
    cout << avg << "\t[" << lb << "," << rb << "]"<< endl;
  }
  else
  {
    // TODO: Use smart pointer for exceptional-safety.
    ScoreData* scoredata = new ScoreData(*scorer);
    for (int sid = 0; sid < n; ++sid)
    {
      string str_sid = int2string(sid);
      scoredata->add(entries[sid], str_sid);
    }
    scorer->setScoreData(scoredata);
    candidates_t candidates(n, 0);
    float score = scorer->score(candidates);
    delete scoredata;

    if (moreFiles) cout << candFile << "\t";
    if (moreScorers) cout << scorer->getName() << "\t";

    cout.setf(ios::fixed,ios::floatfield);
    cout.precision(4);
    cout << score << endl;
  }
}

string int2string(int n)
{
  stringstream ss;
  ss << n;
  return ss.str();
}

float average(const vector<float>& list)
{
  float sum = 0;
  for (vector<float>::const_iterator it = list.begin(); it != list.end(); ++it)
    sum += *it;

  return sum / list.size();
}
<|endoftext|>


<commit_before>/***********************************************************************
    filename:   BitmapImage.cpp
    created:    Wed Feb 16 2011
    author:     Paul D Turner <paul@cegui.org.uk>
*************************************************************************/
/***************************************************************************
 *   Copyright (C) 2004 - 2011 Paul D Turner & The CEGUI Development Team
 *
 *   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 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 "CEGUI/BitmapImage.h"
#include "CEGUI/GeometryBuffer.h"
#include "CEGUI/Texture.h"
#include "CEGUI/Vertex.h"
#include "CEGUI/ColourRect.h"
#include "CEGUI/XMLAttributes.h"
#include "CEGUI/System.h" // this being here is a bit nasty IMO
#include "CEGUI/CoordConverter.h"

#include <glm/glm.hpp>

// Start of CEGUI namespace section
namespace CEGUI
{
const String ImageTypeAttribute( "type" );
const String ImageNameAttribute( "name" );
const String ImageTextureAttribute( "texture" );
const String ImageXPosAttribute( "xPos" );
const String ImageYPosAttribute( "yPos" );
const String ImageWidthAttribute( "width" );
const String ImageHeightAttribute( "height" );
const String ImageXOffsetAttribute( "xOffset" );
const String ImageYOffsetAttribute( "yOffset" );
const String ImageAutoScaledAttribute( "autoScaled" );
const String ImageNativeHorzResAttribute( "nativeHorzRes" );
const String ImageNativeVertResAttribute( "nativeVertRes" );

//----------------------------------------------------------------------------//
BitmapImage::BitmapImage(const String& name) :
    Image(name),
    d_texture(0)
{
}

//----------------------------------------------------------------------------//
BitmapImage::BitmapImage(const XMLAttributes& attributes) :
    Image(attributes.getValueAsString(ImageNameAttribute),
          Vector2f(static_cast<float>(attributes.getValueAsInteger(ImageXOffsetAttribute, 0)),
                   static_cast<float>(attributes.getValueAsInteger(ImageYOffsetAttribute, 0))),
          Rectf(Vector2f(static_cast<float>(attributes.getValueAsInteger(ImageXPosAttribute, 0)),
                         static_cast<float>(attributes.getValueAsInteger(ImageYPosAttribute, 0))),
                Sizef(static_cast<float>(attributes.getValueAsInteger(ImageWidthAttribute, 0)),
                         static_cast<float>(attributes.getValueAsInteger(ImageHeightAttribute, 0))) ),
          PropertyHelper<AutoScaledMode>::fromString(attributes.getValueAsString(ImageAutoScaledAttribute)),
          Sizef(static_cast<float>(attributes.getValueAsInteger(ImageNativeHorzResAttribute, 640)),
                static_cast<float>(attributes.getValueAsInteger(ImageNativeVertResAttribute, 480)))  ),
    d_texture(&System::getSingleton().getRenderer()->getTexture(
              attributes.getValueAsString(ImageTextureAttribute)))
{
}

//----------------------------------------------------------------------------//
BitmapImage::BitmapImage(const String& name, Texture* texture,
                       const Rectf& pixel_area, const Vector2f& pixel_offset,
                       const AutoScaledMode autoscaled, const Sizef& native_res) :
    Image(name,
          pixel_offset,
          pixel_area,
          autoscaled,
          native_res),
    d_texture(texture)
{
}

//----------------------------------------------------------------------------//
void BitmapImage::setTexture(Texture* texture)
{
    d_texture = texture;
}

//----------------------------------------------------------------------------//
void BitmapImage::render(std::vector<GeometryBuffer*>& geometry_buffers,
                         const ImageRenderSettings& render_settings) const
{
    const QuadSplitMode quad_split_mode(TopLeftToBottomRight);

    Rectf dest(render_settings.d_destArea);
    // apply rendering offset to the destination Rect
    dest.offset(d_scaledOffset);

    const CEGUI::Rectf*const&  clip_area = render_settings.d_clipArea;
    // get the rect area that we will actually draw to (i.e. perform clipping)
    Rectf final_rect(clip_area ? dest.getIntersection(*clip_area) : dest );

    // check if rect was totally clipped
    if ((final_rect.getWidth() == 0) || (final_rect.getHeight() == 0))
        return;

    // Obtain correct scale values from the texture
    const Vector2f& texel_scale = d_texture->getTexelScaling();
    const Vector2f tex_per_pix(d_imageArea.getWidth() / dest.getWidth(), d_imageArea.getHeight() / dest.getHeight());

    // calculate final, clipped, texture co-ordinates
    const Rectf tex_rect((d_imageArea + ((final_rect - dest) * tex_per_pix)) * texel_scale);

    // URGENT FIXME: Shouldn't this be in the hands of the user?
    final_rect.d_min.d_x = CoordConverter::alignToPixels(final_rect.d_min.d_x);
    final_rect.d_min.d_y = CoordConverter::alignToPixels(final_rect.d_min.d_y);
    final_rect.d_max.d_x = CoordConverter::alignToPixels(final_rect.d_max.d_x);
    final_rect.d_max.d_y = CoordConverter::alignToPixels(final_rect.d_max.d_y);

    TexturedColouredVertex vbuffer[6];
    const CEGUI::ColourRect&  colours = render_settings.d_multiplyColours;

    // vertex 0
    vbuffer[0].position   = glm::vec3(final_rect.left(), final_rect.top(), 0.0f);
    vbuffer[0].colour_val = colours.d_top_left;
    vbuffer[0].tex_coords = glm::vec2(tex_rect.left(), tex_rect.top());

    // vertex 1
    vbuffer[1].position   = glm::vec3(final_rect.left(), final_rect.bottom(), 0.0f);
    vbuffer[1].colour_val = colours.d_bottom_left;
    vbuffer[1].tex_coords = glm::vec2(tex_rect.left(), tex_rect.bottom());

    // vertex 2
    vbuffer[2].position.x   = final_rect.right();
    vbuffer[2].position.z   = 0.0f;
    vbuffer[2].colour_val   = colours.d_bottom_right;
    vbuffer[2].tex_coords.x = tex_rect.right();

    // top-left to bottom-right diagonal
    if (quad_split_mode == TopLeftToBottomRight)
    {
        vbuffer[2].position.y   = final_rect.bottom();
        vbuffer[2].tex_coords.y = tex_rect.bottom();
    }
    // bottom-left to top-right diagonal
    else
    {
        vbuffer[2].position.y   = final_rect.top();
        vbuffer[2].tex_coords.y = tex_rect.top();
    }

    // vertex 3
    vbuffer[3].position   = glm::vec3(final_rect.right(), final_rect.top(), 0.0f);
    vbuffer[3].colour_val = colours.d_top_right;
    vbuffer[3].tex_coords = glm::vec2(tex_rect.right(), tex_rect.top());

    // vertex 4
    vbuffer[4].position.x   = final_rect.left();
    vbuffer[4].position.z   = 0.0f;
    vbuffer[4].colour_val   = colours.d_top_left;
    vbuffer[4].tex_coords.x = tex_rect.left();

    // top-left to bottom-right diagonal
    if (quad_split_mode == TopLeftToBottomRight)
    {
        vbuffer[4].position.y   = final_rect.top();
        vbuffer[4].tex_coords.y = tex_rect.top();
    }
    // bottom-left to top-right diagonal
    else
    {
        vbuffer[4].position.y   = final_rect.bottom();
        vbuffer[4].tex_coords.y = tex_rect.bottom();
    }

    // vertex 5
    vbuffer[5].position     = glm::vec3(final_rect.right(), final_rect.bottom(), 0.0f);
    vbuffer[5].colour_val   = colours.d_bottom_right;
    vbuffer[5].tex_coords   = glm::vec2(tex_rect.right(), tex_rect.bottom());

    CEGUI::GeometryBuffer& buffer = System::getSingleton().getRenderer()->createGeometryBufferTextured();
    geometry_buffers.push_back(&buffer);

    buffer.setClippingActive(render_settings.d_clippingEnabled);
    if(render_settings.d_clippingEnabled)
        buffer.setClippingRegion(*render_settings.d_clipArea);
    buffer.setTexture(d_texture);
    buffer.appendGeometry(vbuffer, 6);
}

//----------------------------------------------------------------------------//
const Texture* BitmapImage::getTexture() const
{
    return d_texture;
}

} // End of  CEGUI namespace section

<commit_msg>MOD: Formatting<commit_after>/***********************************************************************
    filename:   BitmapImage.cpp
    created:    Wed Feb 16 2011
    author:     Paul D Turner <paul@cegui.org.uk>
*************************************************************************/
/***************************************************************************
 *   Copyright (C) 2004 - 2011 Paul D Turner & The CEGUI Development Team
 *
 *   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 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 "CEGUI/BitmapImage.h"
#include "CEGUI/GeometryBuffer.h"
#include "CEGUI/Texture.h"
#include "CEGUI/Vertex.h"
#include "CEGUI/ColourRect.h"
#include "CEGUI/XMLAttributes.h"
#include "CEGUI/System.h" // this being here is a bit nasty IMO
#include "CEGUI/CoordConverter.h"

#include <glm/glm.hpp>

// Start of CEGUI namespace section
namespace CEGUI
{
const String ImageTypeAttribute( "type" );
const String ImageNameAttribute( "name" );
const String ImageTextureAttribute( "texture" );
const String ImageXPosAttribute( "xPos" );
const String ImageYPosAttribute( "yPos" );
const String ImageWidthAttribute( "width" );
const String ImageHeightAttribute( "height" );
const String ImageXOffsetAttribute( "xOffset" );
const String ImageYOffsetAttribute( "yOffset" );
const String ImageAutoScaledAttribute( "autoScaled" );
const String ImageNativeHorzResAttribute( "nativeHorzRes" );
const String ImageNativeVertResAttribute( "nativeVertRes" );

//----------------------------------------------------------------------------//
BitmapImage::BitmapImage(const String& name) :
    Image(name),
    d_texture(0)
{
}

//----------------------------------------------------------------------------//
BitmapImage::BitmapImage(const XMLAttributes& attributes) :
    Image(attributes.getValueAsString(ImageNameAttribute),
          Vector2f(static_cast<float>(attributes.getValueAsInteger(ImageXOffsetAttribute, 0)),
                   static_cast<float>(attributes.getValueAsInteger(ImageYOffsetAttribute, 0))),
          Rectf(Vector2f(static_cast<float>(attributes.getValueAsInteger(ImageXPosAttribute, 0)),
                         static_cast<float>(attributes.getValueAsInteger(ImageYPosAttribute, 0))),
                Sizef(static_cast<float>(attributes.getValueAsInteger(ImageWidthAttribute, 0)),
                      static_cast<float>(attributes.getValueAsInteger(ImageHeightAttribute, 0)))),
          PropertyHelper<AutoScaledMode>::fromString(attributes.getValueAsString(ImageAutoScaledAttribute)),
          Sizef(static_cast<float>(attributes.getValueAsInteger(ImageNativeHorzResAttribute, 640)),
                static_cast<float>(attributes.getValueAsInteger(ImageNativeVertResAttribute, 480)))),
    d_texture(&System::getSingleton().getRenderer()->getTexture(
              attributes.getValueAsString(ImageTextureAttribute)))
{
}

//----------------------------------------------------------------------------//
BitmapImage::BitmapImage(const String& name, Texture* texture,
                       const Rectf& pixel_area, const Vector2f& pixel_offset,
                       const AutoScaledMode autoscaled, const Sizef& native_res) :
    Image(name,
          pixel_offset,
          pixel_area,
          autoscaled,
          native_res),
    d_texture(texture)
{
}

//----------------------------------------------------------------------------//
void BitmapImage::setTexture(Texture* texture)
{
    d_texture = texture;
}

//----------------------------------------------------------------------------//
void BitmapImage::render(std::vector<GeometryBuffer*>& geometry_buffers,
                         const ImageRenderSettings& render_settings) const
{
    const QuadSplitMode quad_split_mode(TopLeftToBottomRight);

    Rectf dest(render_settings.d_destArea);
    // apply rendering offset to the destination Rect
    dest.offset(d_scaledOffset);

    const CEGUI::Rectf*const&  clip_area = render_settings.d_clipArea;
    // get the rect area that we will actually draw to (i.e. perform clipping)
    Rectf final_rect(clip_area ? dest.getIntersection(*clip_area) : dest );

    // check if rect was totally clipped
    if ((final_rect.getWidth() == 0) || (final_rect.getHeight() == 0))
        return;

    // Obtain correct scale values from the texture
    const Vector2f& texel_scale = d_texture->getTexelScaling();
    const Vector2f tex_per_pix(d_imageArea.getWidth() / dest.getWidth(), d_imageArea.getHeight() / dest.getHeight());

    // calculate final, clipped, texture co-ordinates
    const Rectf tex_rect((d_imageArea + ((final_rect - dest) * tex_per_pix)) * texel_scale);

    // URGENT FIXME: Shouldn't this be in the hands of the user?
    final_rect.d_min.d_x = CoordConverter::alignToPixels(final_rect.d_min.d_x);
    final_rect.d_min.d_y = CoordConverter::alignToPixels(final_rect.d_min.d_y);
    final_rect.d_max.d_x = CoordConverter::alignToPixels(final_rect.d_max.d_x);
    final_rect.d_max.d_y = CoordConverter::alignToPixels(final_rect.d_max.d_y);

    TexturedColouredVertex vbuffer[6];
    const CEGUI::ColourRect&  colours = render_settings.d_multiplyColours;

    // vertex 0
    vbuffer[0].position   = glm::vec3(final_rect.left(), final_rect.top(), 0.0f);
    vbuffer[0].colour_val = colours.d_top_left;
    vbuffer[0].tex_coords = glm::vec2(tex_rect.left(), tex_rect.top());

    // vertex 1
    vbuffer[1].position   = glm::vec3(final_rect.left(), final_rect.bottom(), 0.0f);
    vbuffer[1].colour_val = colours.d_bottom_left;
    vbuffer[1].tex_coords = glm::vec2(tex_rect.left(), tex_rect.bottom());

    // vertex 2
    vbuffer[2].position.x   = final_rect.right();
    vbuffer[2].position.z   = 0.0f;
    vbuffer[2].colour_val   = colours.d_bottom_right;
    vbuffer[2].tex_coords.x = tex_rect.right();

    // top-left to bottom-right diagonal
    if (quad_split_mode == TopLeftToBottomRight)
    {
        vbuffer[2].position.y   = final_rect.bottom();
        vbuffer[2].tex_coords.y = tex_rect.bottom();
    }
    // bottom-left to top-right diagonal
    else
    {
        vbuffer[2].position.y   = final_rect.top();
        vbuffer[2].tex_coords.y = tex_rect.top();
    }

    // vertex 3
    vbuffer[3].position   = glm::vec3(final_rect.right(), final_rect.top(), 0.0f);
    vbuffer[3].colour_val = colours.d_top_right;
    vbuffer[3].tex_coords = glm::vec2(tex_rect.right(), tex_rect.top());

    // vertex 4
    vbuffer[4].position.x   = final_rect.left();
    vbuffer[4].position.z   = 0.0f;
    vbuffer[4].colour_val   = colours.d_top_left;
    vbuffer[4].tex_coords.x = tex_rect.left();

    // top-left to bottom-right diagonal
    if (quad_split_mode == TopLeftToBottomRight)
    {
        vbuffer[4].position.y   = final_rect.top();
        vbuffer[4].tex_coords.y = tex_rect.top();
    }
    // bottom-left to top-right diagonal
    else
    {
        vbuffer[4].position.y   = final_rect.bottom();
        vbuffer[4].tex_coords.y = tex_rect.bottom();
    }

    // vertex 5
    vbuffer[5].position     = glm::vec3(final_rect.right(), final_rect.bottom(), 0.0f);
    vbuffer[5].colour_val   = colours.d_bottom_right;
    vbuffer[5].tex_coords   = glm::vec2(tex_rect.right(), tex_rect.bottom());

    CEGUI::GeometryBuffer& buffer = System::getSingleton().getRenderer()->createGeometryBufferTextured();
    geometry_buffers.push_back(&buffer);

    buffer.setClippingActive(render_settings.d_clippingEnabled);
    if(render_settings.d_clippingEnabled)
        buffer.setClippingRegion(*render_settings.d_clipArea);
    buffer.setTexture(d_texture);
    buffer.appendGeometry(vbuffer, 6);
}

//----------------------------------------------------------------------------//
const Texture* BitmapImage::getTexture() const
{
    return d_texture;
}

} // End of  CEGUI namespace section

<|endoftext|>