<commit_before>// This file is part of BlueSky
//
// BlueSky is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public License
// as published by the Free Software Foundation; either version 3
// of the License, or (at your option) any later version.
//
// BlueSky is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with BlueSky; if not, see <http://www.gnu.org/licenses/>.

#include "bs_messaging.h"
#include "bs_object_base.h"
#include "bs_kernel.h"

#include "boost/signal.hpp"

#define SLOT_EXEC_LAYER sync_layer

using namespace std;
using namespace blue_sky;
using namespace Loki;

namespace blue_sky {

void bs_slot::dispose() const {
	delete this;
}

/*-----------------------------------------------------------------
 * BS signal helpers
 *----------------------------------------------------------------*/
// define execution layer -- sync or async
template< class slot_ptr >
class async_layer {
	class slot2com : public combase {
	public:
		slot2com(const slot_ptr& slot, const sp_mobj& sender, int signal_code, const sp_obj& param)
			: slot_(slot), sender_(sender), sc_(signal_code), param_(param)
		{}

		sp_com execute() {
			slot_->execute(sender_, sc_, param_);
			return NULL;
		}

		void unexecute() {}
		bool can_unexecute() const { return false; }

		void dispose() const {
			//DEBUG
			//cout << "dispose() for slot_wrapper " << this << " called" << endl;
			delete this;
		}

	private:
		slot_ptr slot_;
		sp_mobj sender_;
		int sc_;
		sp_obj param_;
	};

public:

	void fire_slot(
		const sp_slot& slot, const sp_mobj& sender, int signal_code, const sp_obj& param
	) const {
		if(slot)
			// execute slot as kernel task
			BS_KERNEL.add_task(new slot2com(slot, sender, signal_code, param));
	}
};

template< class slot_ptr >
class sync_layer {
public:

	void fire_slot(
		const slot_ptr& slot, const sp_mobj& sender, int signal_code, const sp_obj& param
	) const {
		if(slot)
			// directly execute slot
			slot->execute(sender, signal_code, param);
	}
};

// slot holder that uses execution layer to fire slot
template< class slot_ptr = sp_slot, template < class > class exec_layer = SLOT_EXEC_LAYER  >
class slot_holder : public exec_layer< slot_ptr > {
public:
	typedef const bs_imessaging* sender_ptr;
	typedef exec_layer< slot_ptr > base_t;
	using base_t::fire_slot;

	slot_holder(const slot_ptr& slot, const sender_ptr& sender = NULL)
		: slot_(slot), sender_(sender)
	{}

	bool operator==(const slot_holder& rhs) const {
		return (slot_ == rhs.slot_);
	}

	bool operator==(const slot_ptr& slot) const {
		return (slot_ == slot);
	}

	bool operator<(const slot_holder& rhs) const {
		return (slot_ < rhs.slot_);
	}

	void operator()(const sp_mobj& sender, int signal_code, sp_obj param) const {
		if((!sender_) || (sender == sender_))
			fire_slot(slot_, sender, signal_code, param);
	}

protected:
	slot_ptr slot_;
	// if sender != NULL then only signals from this sender will be triggered
	// if we store sp_mobj then object will live forever, because every slot holds smart pointer to sender
	// thats why only pure pointer to object is stored
	// when sender is deleted, all slot_holders will be destroyed and there will be no dead references
	const bs_imessaging* sender_;
};

/*-----------------------------------------------------------------
 * BS signal implementation details
 *----------------------------------------------------------------*/
class bs_signal::signal_impl
{
public:
	//send signal command
	typedef boost::signal< void (const sp_mobj& sender, int signal_code, const sp_obj& param) > signal_engine;

	signal_engine my_signal_;
	//sp_mobj sender_;
	int signal_code_;
	sp_obj param_;

	//default ctor
	signal_impl() : signal_code_(0) {}

	// ctor with sig code initialization
	signal_impl(int sig_code)
		: signal_code_(sig_code)
	{}

//	signal_impl(const sp_mobj& sender, int sig_code)
//		: signal_code_(sig_code), sender_(sender),
//	{}

	//non-const function because boost::signals doesn't support mt
	void execute(const sp_mobj& sender) {
		//if(sender)
		my_signal_(sender, signal_code_, param_);
	}

	void fire(const sp_mobj& sender, const sp_obj& param) {
		param_ = param;
		execute(sender);
	}

	// if sender != NULL then slot will be activated only for given sender
	bool connect(const sp_slot& slot, const sp_mobj& sender = NULL) {
		if(!slot) return false;
		//my_signal_.connect(bs_slot::slot_wrapper(slot));
		my_signal_.connect(slot_holder<>(slot, sender));
		return true;
	}

	bool disconnect(const sp_slot& slot) {
		if(!slot) return false;
		my_signal_.disconnect(slot_holder<>(slot));
		return true;
	}

	ulong num_slots() const {
		return static_cast< ulong >(my_signal_.num_slots());
	}
};

//=============================== bs_signal implementation =============================================================
bs_signal::bs_signal(int signal_code)
	: pimpl_(new signal_impl(signal_code), mutex(), bs_static_cast())
{}

void bs_signal::init(int signal_code) const {
	lpimpl lp(pimpl_);
	if(signal_code > 0)
		lp->signal_code_ = signal_code;
	else
		throw bs_kernel_exception ("bs_signal::init", no_error, "Wrong signal code given");
}

void bs_signal::fire(const sp_mobj& sender, const sp_obj& param) const {
	//lock during recepients call because boost:signals doesn't support mt
	//lpimpl lp(pimpl_);
	//lp->param_ = param;
	//lp->execute();
	pimpl_.lock()->fire(sender, param);
	//give_kernel::Instance().add_task(this);
}

bool bs_signal::connect(const sp_slot& slot, const sp_mobj& sender) const {
	return pimpl_.lock()->connect(slot, sender);
}

bool bs_signal::disconnect(const sp_slot& slot) const
{
	return pimpl_.lock()->disconnect(slot);
}

ulong bs_signal::num_slots() const {
	return pimpl_->num_slots();
}

void bs_signal::dispose() const {
	delete this;
}

int bs_signal::get_code() const {
	return pimpl_->signal_code_;
}

//============================== bs_messaging implementation ===========================================================
//empty ctor
bs_messaging::bs_messaging() {}

//empty dtor
//bs_messaging::~bs_messaging() {}

//ctor that adds all signals in a half-open range
bs_messaging::bs_messaging(const sig_range_t& sig_range) {
	add_signal(sig_range);
}

//copy ctor implementation
bs_messaging::bs_messaging(const bs_messaging& mes)
	: bs_refcounter(mes), bs_imessaging(), signals_(mes.signals_)
{}

void bs_messaging::swap(bs_messaging& rhs) {
	std::swap(signals_, rhs.signals_);
}

//bs_messaging& bs_messaging::operator=(const bs_messaging& lhs) {
//	bs_messaging(lhs).swap(*this);
//	return *this;
//}

bool bs_messaging::fire_signal(int signal_code, const sp_obj& params) const
{
	bs_signals_map::const_iterator sig = signals_.find(signal_code);
	if(sig == signals_.end()) return false;

	//if(!sig->second->sender_binded())
	//	sig->second->init(this);
	sig->second->fire(this, params);
	//kernel &k = give_kernel::Instance();
	//sig->second.lock()->set_param(params);
	//k.add_task(sig->second);
	return true;
}

bool bs_messaging::add_signal(int signal_code)
{
	if(signals_.find(signal_code) != signals_.end()) return false;

	pair< sp_signal, bool > sig;
	sig =  BS_KERNEL.reg_signal(BS_GET_TI(*this), signal_code);
	signals_[signal_code] = sig.first;
	//new bs_signal(signal_code);
	return sig.second;
}

ulong bs_messaging::add_signal(const sig_range_t& sr) {
	ulong cnt = 0;
	for(int i = sr.first; i < sr.second; ++i)
		cnt += static_cast< ulong >(add_signal(i));
	return cnt;
}

bool bs_messaging::remove_signal(int signal_code)
{
	bs_signals_map::const_iterator sig = signals_.find(signal_code);
	if(sig != signals_.end())
	{
		signals_.erase(signal_code);
		BS_KERNEL.rem_signal(BS_GET_TI(*this), signal_code);
		return true;
	}
	return false;
}

std::vector< int > bs_messaging::get_signal_list() const
{
	std::vector< int > res;
	res.reserve(signals_.size());
	for (bs_signals_map::const_iterator p = signals_.begin(); p != signals_.end(); ++p)
		res.push_back(p->first);
	return res;
}

bool bs_messaging::subscribe(int signal_code, const sp_slot& slot) const {
	if(!slot) return false;
	bs_signals_map::const_iterator sig = signals_.find(signal_code);
	if(sig != signals_.end()) {
		sig->second->connect(slot, this);
		return true;
	}
	return false;
}

bool bs_messaging::unsubscribe(int signal_code, const smart_ptr< bs_slot, true >& slot) const
{
	if(!slot) return false;
	bs_signals_map::const_iterator sig = signals_.find(signal_code);
	if(sig != signals_.end()) {
		sig->second->disconnect(slot);
		return true;
	}
	return false;
}

ulong bs_messaging::num_slots(int signal_code) const {
	bs_signals_map::const_iterator sig = signals_.find(signal_code);
	if(sig != signals_.end())
		return sig->second->num_slots();
	else return 0;
}

void bs_messaging::dispose() const {
	delete this;
}

}	//end of namespace blue_sky
<commit_msg>signal: lock slot during execution<commit_after>// This file is part of BlueSky
//
// BlueSky is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public License
// as published by the Free Software Foundation; either version 3
// of the License, or (at your option) any later version.
//
// BlueSky is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with BlueSky; if not, see <http://www.gnu.org/licenses/>.

#include "bs_messaging.h"
#include "bs_object_base.h"
#include "bs_kernel.h"

#include "boost/signal.hpp"

#define SLOT_EXEC_LAYER sync_layer

using namespace std;
using namespace blue_sky;
using namespace Loki;

namespace blue_sky {

void bs_slot::dispose() const {
	delete this;
}

/*-----------------------------------------------------------------
 * BS signal helpers
 *----------------------------------------------------------------*/
// define execution layer -- sync or async
template< class slot_ptr >
class async_layer {
	class slot2com : public combase {
	public:
		slot2com(const slot_ptr& slot, const sp_mobj& sender, int signal_code, const sp_obj& param)
			: slot_(slot), sender_(sender), sc_(signal_code), param_(param)
		{}

		sp_com execute() {
			slot_.lock()->execute(sender_, sc_, param_);
			return NULL;
		}

		void unexecute() {}
		bool can_unexecute() const { return false; }

		void dispose() const {
			//DEBUG
			//cout << "dispose() for slot_wrapper " << this << " called" << endl;
			delete this;
		}

	private:
		slot_ptr slot_;
		sp_mobj sender_;
		int sc_;
		sp_obj param_;
	};

public:

	void fire_slot(
		const sp_slot& slot, const sp_mobj& sender, int signal_code, const sp_obj& param
	) const {
		if(slot)
			// execute slot as kernel task
			BS_KERNEL.add_task(new slot2com(slot, sender, signal_code, param));
	}
};

template< class slot_ptr >
class sync_layer {
public:

	void fire_slot(
		const slot_ptr& slot, const sp_mobj& sender, int signal_code, const sp_obj& param
	) const {
		if(slot)
			// directly execute slot
			slot.lock()->execute(sender, signal_code, param);
	}
};

// slot holder that uses execution layer to fire slot
template< class slot_ptr = sp_slot, template < class > class exec_layer = SLOT_EXEC_LAYER  >
class slot_holder : public exec_layer< slot_ptr > {
public:
	typedef const bs_imessaging* sender_ptr;
	typedef exec_layer< slot_ptr > base_t;
	using base_t::fire_slot;

	slot_holder(const slot_ptr& slot, const sender_ptr& sender = NULL)
		: slot_(slot), sender_(sender)
	{}

	bool operator==(const slot_holder& rhs) const {
		return (slot_ == rhs.slot_);
	}

	bool operator==(const slot_ptr& slot) const {
		return (slot_ == slot);
	}

	bool operator<(const slot_holder& rhs) const {
		return (slot_ < rhs.slot_);
	}

	void operator()(const sp_mobj& sender, int signal_code, sp_obj param) const {
		if((!sender_) || (sender == sender_))
			fire_slot(slot_, sender, signal_code, param);
	}

protected:
	slot_ptr slot_;
	// if sender != NULL then only signals from this sender will be triggered
	// if we store sp_mobj then object will live forever, because every slot holds smart pointer to sender
	// thats why only pure pointer to object is stored
	// when sender is deleted, all slot_holders will be destroyed and there will be no dead references
	const bs_imessaging* sender_;
};

/*-----------------------------------------------------------------
 * BS signal implementation details
 *----------------------------------------------------------------*/
class bs_signal::signal_impl
{
public:
	//send signal command
	typedef boost::signal< void (const sp_mobj& sender, int signal_code, const sp_obj& param) > signal_engine;

	signal_engine my_signal_;
	//sp_mobj sender_;
	int signal_code_;
	sp_obj param_;

	//default ctor
	signal_impl() : signal_code_(0) {}

	// ctor with sig code initialization
	signal_impl(int sig_code)
		: signal_code_(sig_code)
	{}

//	signal_impl(const sp_mobj& sender, int sig_code)
//		: signal_code_(sig_code), sender_(sender),
//	{}

	//non-const function because boost::signals doesn't support mt
	void execute(const sp_mobj& sender) {
		//if(sender)
		my_signal_(sender, signal_code_, param_);
	}

	void fire(const sp_mobj& sender, const sp_obj& param) {
		param_ = param;
		execute(sender);
	}

	// if sender != NULL then slot will be activated only for given sender
	bool connect(const sp_slot& slot, const sp_mobj& sender = NULL) {
		if(!slot) return false;
		//my_signal_.connect(bs_slot::slot_wrapper(slot));
		my_signal_.connect(slot_holder<>(slot, sender));
		return true;
	}

	bool disconnect(const sp_slot& slot) {
		if(!slot) return false;
		my_signal_.disconnect(slot_holder<>(slot));
		return true;
	}

	ulong num_slots() const {
		return static_cast< ulong >(my_signal_.num_slots());
	}
};

//=============================== bs_signal implementation =============================================================
bs_signal::bs_signal(int signal_code)
	: pimpl_(new signal_impl(signal_code), mutex(), bs_static_cast())
{}

void bs_signal::init(int signal_code) const {
	lpimpl lp(pimpl_);
	if(signal_code > 0)
		lp->signal_code_ = signal_code;
	else
		throw bs_kernel_exception ("bs_signal::init", no_error, "Wrong signal code given");
}

void bs_signal::fire(const sp_mobj& sender, const sp_obj& param) const {
	//lock during recepients call because boost:signals doesn't support mt
	//lpimpl lp(pimpl_);
	//lp->param_ = param;
	//lp->execute();
	pimpl_.lock()->fire(sender, param);
	//give_kernel::Instance().add_task(this);
}

bool bs_signal::connect(const sp_slot& slot, const sp_mobj& sender) const {
	return pimpl_.lock()->connect(slot, sender);
}

bool bs_signal::disconnect(const sp_slot& slot) const
{
	return pimpl_.lock()->disconnect(slot);
}

ulong bs_signal::num_slots() const {
	return pimpl_->num_slots();
}

void bs_signal::dispose() const {
	delete this;
}

int bs_signal::get_code() const {
	return pimpl_->signal_code_;
}

//============================== bs_messaging implementation ===========================================================
//empty ctor
bs_messaging::bs_messaging() {}

//empty dtor
//bs_messaging::~bs_messaging() {}

//ctor that adds all signals in a half-open range
bs_messaging::bs_messaging(const sig_range_t& sig_range) {
	add_signal(sig_range);
}

//copy ctor implementation
bs_messaging::bs_messaging(const bs_messaging& mes)
	: bs_refcounter(mes), bs_imessaging(), signals_(mes.signals_)
{}

void bs_messaging::swap(bs_messaging& rhs) {
	std::swap(signals_, rhs.signals_);
}

//bs_messaging& bs_messaging::operator=(const bs_messaging& lhs) {
//	bs_messaging(lhs).swap(*this);
//	return *this;
//}

bool bs_messaging::fire_signal(int signal_code, const sp_obj& params) const
{
	bs_signals_map::const_iterator sig = signals_.find(signal_code);
	if(sig == signals_.end()) return false;

	//if(!sig->second->sender_binded())
	//	sig->second->init(this);
	sig->second->fire(this, params);
	//kernel &k = give_kernel::Instance();
	//sig->second.lock()->set_param(params);
	//k.add_task(sig->second);
	return true;
}

bool bs_messaging::add_signal(int signal_code)
{
	if(signals_.find(signal_code) != signals_.end()) return false;

	pair< sp_signal, bool > sig;
	sig =  BS_KERNEL.reg_signal(BS_GET_TI(*this), signal_code);
	signals_[signal_code] = sig.first;
	//new bs_signal(signal_code);
	return sig.second;
}

ulong bs_messaging::add_signal(const sig_range_t& sr) {
	ulong cnt = 0;
	for(int i = sr.first; i < sr.second; ++i)
		cnt += static_cast< ulong >(add_signal(i));
	return cnt;
}

bool bs_messaging::remove_signal(int signal_code)
{
	bs_signals_map::const_iterator sig = signals_.find(signal_code);
	if(sig != signals_.end())
	{
		signals_.erase(signal_code);
		BS_KERNEL.rem_signal(BS_GET_TI(*this), signal_code);
		return true;
	}
	return false;
}

std::vector< int > bs_messaging::get_signal_list() const
{
	std::vector< int > res;
	res.reserve(signals_.size());
	for (bs_signals_map::const_iterator p = signals_.begin(); p != signals_.end(); ++p)
		res.push_back(p->first);
	return res;
}

bool bs_messaging::subscribe(int signal_code, const sp_slot& slot) const {
	if(!slot) return false;
	bs_signals_map::const_iterator sig = signals_.find(signal_code);
	if(sig != signals_.end()) {
		sig->second->connect(slot, this);
		return true;
	}
	return false;
}

bool bs_messaging::unsubscribe(int signal_code, const smart_ptr< bs_slot, true >& slot) const
{
	if(!slot) return false;
	bs_signals_map::const_iterator sig = signals_.find(signal_code);
	if(sig != signals_.end()) {
		sig->second->disconnect(slot);
		return true;
	}
	return false;
}

ulong bs_messaging::num_slots(int signal_code) const {
	bs_signals_map::const_iterator sig = signals_.find(signal_code);
	if(sig != signals_.end())
		return sig->second->num_slots();
	else return 0;
}

void bs_messaging::dispose() const {
	delete this;
}

}	//end of namespace blue_sky
<|endoftext|>


<commit_before>/******************************************************************************
* Copyright (c) 2013, Howard Butler (hobu.inc@gmail.com)
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following
* conditions are met:
*
*     * Redistributions of source code must retain the above copyright
*       notice, this list of conditions and the following disclaimer.
*     * Redistributions in binary form must reproduce the above copyright
*       notice, this list of conditions and the following disclaimer in
*       the documentation and/or other materials provided
*       with the distribution.
*     * Neither the name of Hobu, Inc. or Flaxen Geo Consulting nor the
*       names of its contributors may be used to endorse or promote
*       products derived from this software without specific prior
*       written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
****************************************************************************/

#include "InfoKernel.hpp"

#include <algorithm>

#include <pdal/KDIndex.hpp>
#include <pdal/PipelineWriter.hpp>
#include <pdal/PDALUtils.hpp>
#include <pdal/pdal_config.hpp>
#include <pdal/StageFactory.hpp>
#ifdef PDAL_HAVE_LIBXML2
#include <pdal/XMLSchema.hpp>
#endif
#include <pdal/pdal_macros.hpp>

namespace pdal
{

static PluginInfo const s_info = PluginInfo(
    "kernels.info",
    "Info Kernel",
    "http://pdal.io/kernels/kernels.info.html" );

CREATE_STATIC_PLUGIN(1, 0, InfoKernel, Kernel, s_info)

std::string InfoKernel::getName() const { return s_info.name; }

InfoKernel::InfoKernel()
    : m_showStats(false)
    , m_showSchema(false)
    , m_showAll(false)
    , m_showMetadata(false)
    , m_boundary(false)
    , m_showSummary(false)
    , m_needPoints(false)
    , m_statsStage(NULL)
{}

void InfoKernel::validateSwitches(ProgramArgs& args)
{
    int functions = 0;

    if (!m_usestdin && m_inputFile.empty())
        throw pdal_error("No input file specified.");

    // All isn't really all.
    if (m_showAll)
    {
        m_showStats = true;
        m_showMetadata = true;
        m_showSchema = true;
    }

    if (m_boundary)
    {
        functions++;
        m_needPoints = true;
    }
    if (m_queryPoint.size())
    {
        functions++;
        m_needPoints = true;
    }
    if (m_pointIndexes.size())
    {
        functions++;
        m_needPoints = true;
    }
    if (m_showSchema)
        functions++;
    if (m_showMetadata)
        functions++;
    if (m_showSummary)
        functions++;
    if (m_showStats || functions == 0 )
    {
        functions++;
        m_showStats = true;
        m_needPoints = true;
    }

    if (m_pointIndexes.size() && m_queryPoint.size())
        throw pdal_error("--point option incompatible with --query option.");

    if (m_showSummary && functions > 1)
        throw pdal_error("--summary option incompatible with other "
            "specified options.");
}

void InfoKernel::addSwitches(ProgramArgs& args)
{
    args.add("input,i", "input file name", m_inputFile).setOptionalPositional();
    args.add("all", "dump statistics, schema and metadata", m_showAll);
    args.add("point,p", "point to dump\n--point=\"1-5,10,100-200\"",
        m_pointIndexes);
    args.add("query",
         "Return points in order of distance from the specified "
         "location (2D or 3D)\n"
         "--query Xcoord,Ycoord[,Zcoord][/count]",
         m_queryPoint);
    args.add("stats", "dump stats on all points (reads entire dataset)",
        m_showStats);
    args.add("boundary", "compute a hexagonal hull/boundary of dataset",
        m_boundary);
    args.add("dimensions", "dimensions on which to compute statistics",
        m_dimensions);
    args.add("schema", "dump the schema", m_showSchema);
    args.add("pipeline-serialization", "Output file for pipeline serialization",
         m_pipelineFile);
    args.add("summary", "dump summary of the info", m_showSummary);
    args.add("metadata", "dump file metadata info", m_showMetadata);
    args.add("pointcloudschema", "dump PointCloudSchema XML output",
        m_PointCloudSchemaOutput).setHidden();
}

// Support for parsing point numbers.  Points can be specified singly or as
// dash-separated ranges.  i.e. 6-7,8,19-20
namespace {

using namespace std;

uint32_t parseInt(const string& s)
{
    uint32_t i;

    if (!Utils::fromString(s, i))
        throw pdal_error(string("Invalid integer: ") + s);
    return i;
}

void addRange(const string& begin, const string& end, vector<PointId>& points)
{
    PointId low = parseInt(begin);
    PointId high = parseInt(end);
    if (low > high)
        throw pdal_error(string("Range invalid: ") + begin + "-" + end);
    while (low <= high)
        points.push_back(low++);
}

vector<PointId> getListOfPoints(std::string p)
{
    vector<PointId> output;

    //Remove whitespace from string with awful remove/erase idiom.
    p.erase(remove_if(p.begin(), p.end(), ::isspace), p.end());

    vector<string> ranges = Utils::split2(p, ',');
    for (string s : ranges)
    {
        vector<string> limits = Utils::split(s, '-');
        if (limits.size() == 1)
            output.push_back(parseInt(limits[0]));
        else if (limits.size() == 2)
            addRange(limits[0], limits[1], output);
        else
            throw pdal_error(string("Invalid point range: ") + s);
    }
    return output;
}

} //namespace

MetadataNode InfoKernel::dumpPoints(PointViewPtr inView) const
{
    MetadataNode root;
    PointViewPtr outView = inView->makeNew();

    // Stick points in a inViewfer.
    std::vector<PointId> points = getListOfPoints(m_pointIndexes);
    for (size_t i = 0; i < points.size(); ++i)
    {
        PointId id = (PointId)points[i];
        if (id < inView->size())
            outView->appendPoint(*inView.get(), id);
    }

    MetadataNode tree = Utils::toMetadata(outView);
    std::string prefix("point ");
    for (size_t i = 0; i < outView->size(); ++i)
    {
        MetadataNode n = tree.findChild(std::to_string(i));
        n.add("PointId", points[i]);
        root.add(n.clone("point"));
    }
    return root;
}

MetadataNode InfoKernel::dumpSummary(const QuickInfo& qi)
{
    MetadataNode summary;
    summary.add("num_points", qi.m_pointCount);
    summary.add("spatial_reference", qi.m_srs.getWKT());
    MetadataNode srs = pdal::Utils::toMetadata(qi.m_srs);
    summary.add(srs);
    MetadataNode bounds = summary.add("bounds");
    MetadataNode x = bounds.add("X");
    x.add("min", qi.m_bounds.minx);
    x.add("max", qi.m_bounds.maxx);
    MetadataNode y = bounds.add("Y");
    y.add("min", qi.m_bounds.miny);
    y.add("max", qi.m_bounds.maxy);
    MetadataNode z = bounds.add("Z");
    z.add("min", qi.m_bounds.minz);
    z.add("max", qi.m_bounds.maxz);

    std::string dims;
    auto di = qi.m_dimNames.begin();
    while (di != qi.m_dimNames.end())
    {
        dims += *di;
        ++di;
        if (di != qi.m_dimNames.end())
           dims += ", ";
    }
    summary.add("dimensions", dims);
    return summary;
}

PipelineManagerPtr InfoKernel::makePipeline(const std::string& filename,
    bool noPoints)
{
    if (!pdal::FileUtils::fileExists(filename))
        throw pdal_error("File not found: " + filename);

    PipelineManagerPtr output(new PipelineManager);

    if (filename == "STDIN")
    {
        output->readPipeline(std::cin);
    }
    else if (FileUtils::extension(filename) == ".xml" ||
        FileUtils::extension(filename) == ".json")
    {
        output->readPipeline(filename);
    }
    else
    {
        StageFactory factory;
        std::string driver = factory.inferReaderDriver(filename);

        if (driver.empty())
            throw pdal_error("Cannot determine input file type of " + filename);
        Stage& reader = output->addReader(driver);
        Options ro;
        ro.add("filename", filename);
        if (noPoints)
            ro.add("count", 0);
        reader.setOptions(ro);
        m_reader = &reader;
    }
    return output;
}

void InfoKernel::setup(const std::string& filename)
{
    m_manager = makePipeline(filename, !m_needPoints);
    Stage *stage = m_manager->getStage();

    if (m_showStats)
    {
        m_statsStage = &(m_manager->addFilter("filters.stats"));
        if (m_dimensions.size())
        {
            Options ops;
            ops.add("dimensions", m_dimensions);
            m_statsStage->addOptions(ops);
        }

        m_statsStage->setInput(*stage);
        stage = m_statsStage;
    }
    if (m_boundary)
    {
        m_hexbinStage = &(m_manager->addFilter("filters.hexbin"));
        if (!m_hexbinStage) {
            throw pdal_error("Unable to compute boundary -- "
                "http://github.com/hobu/hexer is not linked. "
                "See the \"boundary\" member in \"stats\" for a coarse "
                "bounding box");
        }
        m_hexbinStage->setInput(*stage);
    }
}

MetadataNode InfoKernel::run(const std::string& filename)
{
    MetadataNode root;

    root.add("filename", filename);
    if (m_showSummary)
    {
        QuickInfo qi = m_reader->preview();
        MetadataNode summary = dumpSummary(qi).clone("summary");
        root.add(summary);
    }
    else
    {
        applyExtraStageOptionsRecursive(m_manager->getStage());
        if (m_needPoints || m_showMetadata)
            m_manager->execute();
        else
            m_manager->prepare();
        dump(root);
    }
    root.add("pdal_version", pdal::GetFullVersionString());
    return root;
}

void InfoKernel::dump(MetadataNode& root)
{
    if (m_showSchema)
        root.add(Utils::toMetadata(m_manager->pointTable()).clone("schema"));

    if (m_PointCloudSchemaOutput.size() > 0)
    {
#ifdef PDAL_HAVE_LIBXML2
        XMLSchema schema(m_manager->pointTable().layout());

        std::ostream *out = FileUtils::createFile(m_PointCloudSchemaOutput);
        std::string xml(schema.xml());
        out->write(xml.c_str(), xml.size());
        FileUtils::closeFile(out);
#else
        std::cerr << "libxml2 support not enabled, no schema is produced" <<
            std::endl;
#endif

    }
    if (m_showStats)
        root.add(m_statsStage->getMetadata().clone("stats"));

    if (m_pipelineFile.size() > 0)
        PipelineWriter::writePipeline(m_manager->getStage(), m_pipelineFile);

    if (m_pointIndexes.size())
    {
        PointViewSet viewSet = m_manager->views();
        assert(viewSet.size() == 1);
        root.add(dumpPoints(*viewSet.begin()).clone("points"));
    }

    if (m_queryPoint.size())
    {
        PointViewSet viewSet = m_manager->views();
        assert(viewSet.size() == 1);
        root.add(dumpQuery(*viewSet.begin()));
    }

    if (m_showMetadata)
        root.add(m_reader->getMetadata().clone("metadata"));

    if (m_boundary)
    {
        PointViewSet viewSet = m_manager->views();
        assert(viewSet.size() == 1);
        root.add(m_hexbinStage->getMetadata().clone("boundary"));
    }
}

MetadataNode InfoKernel::dumpQuery(PointViewPtr inView) const
{
    int count;
    std::string location;

    // See if there's a provided point count.
    StringList parts = Utils::split2(m_queryPoint, '/');
    if (parts.size() == 2)
    {
        location = parts[0];
        count = atoi(parts[1].c_str());
    }
    else if (parts.size() == 1)
    {
        location = parts[0];
        count = inView->size();
    }
    else
        count = 0;
    if (count == 0)
        throw pdal_error("Invalid location specificiation. "
            "--query=\"X,Y[/count]\"");

    auto seps = [](char c){ return (c == ',' || c == '|' || c == ' '); };

    std::vector<std::string> tokens = Utils::split2(location, seps);
    std::vector<double> values;
    for (auto ti = tokens.begin(); ti != tokens.end(); ++ti)
    {
        double d;
        if (Utils::fromString(*ti, d))
            values.push_back(d);
    }

    if (values.size() != 2 && values.size() != 3)
        throw pdal_error("--points must be two or three values");

    PointViewPtr outView = inView->makeNew();

    std::vector<PointId> ids;
    if (values.size() >= 3)
    {
        KD3Index kdi(*inView);
        kdi.build();
        ids = kdi.neighbors(values[0], values[1], values[2], count);
    }
    else
    {
        KD2Index kdi(*inView);
        kdi.build();
        ids = kdi.neighbors(values[0], values[1], count);
    }

    for (auto i = ids.begin(); i != ids.end(); ++i)
        outView->appendPoint(*inView.get(), *i);

    return Utils::toMetadata(outView);
}

int InfoKernel::execute()
{
    std::string filename = m_usestdin ? std::string("STDIN") : m_inputFile;
    setup(filename);
    MetadataNode root = run(filename);
    Utils::toJSON(root, std::cout);

    return 0;
}

} // namespace pdal
<commit_msg>Fix #1201 -- info on pipeline segfault<commit_after>/******************************************************************************
* Copyright (c) 2013, Howard Butler (hobu.inc@gmail.com)
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following
* conditions are met:
*
*     * Redistributions of source code must retain the above copyright
*       notice, this list of conditions and the following disclaimer.
*     * Redistributions in binary form must reproduce the above copyright
*       notice, this list of conditions and the following disclaimer in
*       the documentation and/or other materials provided
*       with the distribution.
*     * Neither the name of Hobu, Inc. or Flaxen Geo Consulting nor the
*       names of its contributors may be used to endorse or promote
*       products derived from this software without specific prior
*       written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
****************************************************************************/

#include "InfoKernel.hpp"

#include <algorithm>

#include <pdal/KDIndex.hpp>
#include <pdal/PipelineWriter.hpp>
#include <pdal/PDALUtils.hpp>
#include <pdal/pdal_config.hpp>
#include <pdal/StageFactory.hpp>
#ifdef PDAL_HAVE_LIBXML2
#include <pdal/XMLSchema.hpp>
#endif
#include <pdal/pdal_macros.hpp>

namespace pdal
{

static PluginInfo const s_info = PluginInfo(
    "kernels.info",
    "Info Kernel",
    "http://pdal.io/kernels/kernels.info.html" );

CREATE_STATIC_PLUGIN(1, 0, InfoKernel, Kernel, s_info)

std::string InfoKernel::getName() const { return s_info.name; }

InfoKernel::InfoKernel()
    : m_showStats(false)
    , m_showSchema(false)
    , m_showAll(false)
    , m_showMetadata(false)
    , m_boundary(false)
    , m_showSummary(false)
    , m_needPoints(false)
    , m_statsStage(NULL)
{}

void InfoKernel::validateSwitches(ProgramArgs& args)
{
    int functions = 0;

    if (!m_usestdin && m_inputFile.empty())
        throw pdal_error("No input file specified.");

    // All isn't really all.
    if (m_showAll)
    {
        m_showStats = true;
        m_showMetadata = true;
        m_showSchema = true;
    }

    if (m_boundary)
    {
        functions++;
        m_needPoints = true;
    }
    if (m_queryPoint.size())
    {
        functions++;
        m_needPoints = true;
    }
    if (m_pointIndexes.size())
    {
        functions++;
        m_needPoints = true;
    }
    if (m_showSchema)
        functions++;
    if (m_showMetadata)
        functions++;
    if (m_showSummary)
        functions++;
    if (m_showStats || functions == 0 )
    {
        functions++;
        m_showStats = true;
        m_needPoints = true;
    }

    if (m_pointIndexes.size() && m_queryPoint.size())
        throw pdal_error("--point option incompatible with --query option.");

    if (m_showSummary && functions > 1)
        throw pdal_error("--summary option incompatible with other "
            "specified options.");
}

void InfoKernel::addSwitches(ProgramArgs& args)
{
    args.add("input,i", "input file name", m_inputFile).setOptionalPositional();
    args.add("all", "dump statistics, schema and metadata", m_showAll);
    args.add("point,p", "point to dump\n--point=\"1-5,10,100-200\"",
        m_pointIndexes);
    args.add("query",
         "Return points in order of distance from the specified "
         "location (2D or 3D)\n"
         "--query Xcoord,Ycoord[,Zcoord][/count]",
         m_queryPoint);
    args.add("stats", "dump stats on all points (reads entire dataset)",
        m_showStats);
    args.add("boundary", "compute a hexagonal hull/boundary of dataset",
        m_boundary);
    args.add("dimensions", "dimensions on which to compute statistics",
        m_dimensions);
    args.add("schema", "dump the schema", m_showSchema);
    args.add("pipeline-serialization", "Output file for pipeline serialization",
         m_pipelineFile);
    args.add("summary", "dump summary of the info", m_showSummary);
    args.add("metadata", "dump file metadata info", m_showMetadata);
    args.add("pointcloudschema", "dump PointCloudSchema XML output",
        m_PointCloudSchemaOutput).setHidden();
}

// Support for parsing point numbers.  Points can be specified singly or as
// dash-separated ranges.  i.e. 6-7,8,19-20
namespace {

using namespace std;

uint32_t parseInt(const string& s)
{
    uint32_t i;

    if (!Utils::fromString(s, i))
        throw pdal_error(string("Invalid integer: ") + s);
    return i;
}

void addRange(const string& begin, const string& end, vector<PointId>& points)
{
    PointId low = parseInt(begin);
    PointId high = parseInt(end);
    if (low > high)
        throw pdal_error(string("Range invalid: ") + begin + "-" + end);
    while (low <= high)
        points.push_back(low++);
}

vector<PointId> getListOfPoints(std::string p)
{
    vector<PointId> output;

    //Remove whitespace from string with awful remove/erase idiom.
    p.erase(remove_if(p.begin(), p.end(), ::isspace), p.end());

    vector<string> ranges = Utils::split2(p, ',');
    for (string s : ranges)
    {
        vector<string> limits = Utils::split(s, '-');
        if (limits.size() == 1)
            output.push_back(parseInt(limits[0]));
        else if (limits.size() == 2)
            addRange(limits[0], limits[1], output);
        else
            throw pdal_error(string("Invalid point range: ") + s);
    }
    return output;
}

} //namespace

MetadataNode InfoKernel::dumpPoints(PointViewPtr inView) const
{
    MetadataNode root;
    PointViewPtr outView = inView->makeNew();

    // Stick points in a inViewfer.
    std::vector<PointId> points = getListOfPoints(m_pointIndexes);
    for (size_t i = 0; i < points.size(); ++i)
    {
        PointId id = (PointId)points[i];
        if (id < inView->size())
            outView->appendPoint(*inView.get(), id);
    }

    MetadataNode tree = Utils::toMetadata(outView);
    std::string prefix("point ");
    for (size_t i = 0; i < outView->size(); ++i)
    {
        MetadataNode n = tree.findChild(std::to_string(i));
        n.add("PointId", points[i]);
        root.add(n.clone("point"));
    }
    return root;
}

MetadataNode InfoKernel::dumpSummary(const QuickInfo& qi)
{
    MetadataNode summary;
    summary.add("num_points", qi.m_pointCount);
    summary.add("spatial_reference", qi.m_srs.getWKT());
    MetadataNode srs = pdal::Utils::toMetadata(qi.m_srs);
    summary.add(srs);
    MetadataNode bounds = summary.add("bounds");
    MetadataNode x = bounds.add("X");
    x.add("min", qi.m_bounds.minx);
    x.add("max", qi.m_bounds.maxx);
    MetadataNode y = bounds.add("Y");
    y.add("min", qi.m_bounds.miny);
    y.add("max", qi.m_bounds.maxy);
    MetadataNode z = bounds.add("Z");
    z.add("min", qi.m_bounds.minz);
    z.add("max", qi.m_bounds.maxz);

    std::string dims;
    auto di = qi.m_dimNames.begin();
    while (di != qi.m_dimNames.end())
    {
        dims += *di;
        ++di;
        if (di != qi.m_dimNames.end())
           dims += ", ";
    }
    summary.add("dimensions", dims);
    return summary;
}

PipelineManagerPtr InfoKernel::makePipeline(const std::string& filename,
    bool noPoints)
{
    if (!pdal::FileUtils::fileExists(filename))
        throw pdal_error("File not found: " + filename);

    PipelineManagerPtr output(new PipelineManager);

    if (filename == "STDIN")
    {
        output->readPipeline(std::cin);
    }
    else if (FileUtils::extension(filename) == ".xml" ||
        FileUtils::extension(filename) == ".json")
    {
        output->readPipeline(filename);
    }
    else
    {
        StageFactory factory;
        std::string driver = factory.inferReaderDriver(filename);

        if (driver.empty())
            throw pdal_error("Cannot determine input file type of " + filename);
        Stage& reader = output->addReader(driver);
        Options ro;
        ro.add("filename", filename);
        if (noPoints)
            ro.add("count", 0);
        reader.setOptions(ro);
        m_reader = &reader;
    }
    return output;
}

void InfoKernel::setup(const std::string& filename)
{
    m_manager = makePipeline(filename, !m_needPoints);
    Stage *stage = m_manager->getStage();

    if (m_showStats)
    {
        m_statsStage = &(m_manager->addFilter("filters.stats"));
        if (m_dimensions.size())
        {
            Options ops;
            ops.add("dimensions", m_dimensions);
            m_statsStage->addOptions(ops);
        }

        m_statsStage->setInput(*stage);
        stage = m_statsStage;
    }
    if (m_boundary)
    {
        m_hexbinStage = &(m_manager->addFilter("filters.hexbin"));
        if (!m_hexbinStage) {
            throw pdal_error("Unable to compute boundary -- "
                "http://github.com/hobu/hexer is not linked. "
                "See the \"boundary\" member in \"stats\" for a coarse "
                "bounding box");
        }
        m_hexbinStage->setInput(*stage);
    }
}

MetadataNode InfoKernel::run(const std::string& filename)
{
    MetadataNode root;

    root.add("filename", filename);
    if (m_showSummary)
    {
        QuickInfo qi = m_reader->preview();
        MetadataNode summary = dumpSummary(qi).clone("summary");
        root.add(summary);
    }
    else
    {
        applyExtraStageOptionsRecursive(m_manager->getStage());
        if (m_needPoints || m_showMetadata)
            m_manager->execute();
        else
            m_manager->prepare();
        dump(root);
    }
    root.add("pdal_version", pdal::GetFullVersionString());
    return root;
}

void InfoKernel::dump(MetadataNode& root)
{
    if (m_showSchema)
        root.add(Utils::toMetadata(m_manager->pointTable()).clone("schema"));

    if (m_PointCloudSchemaOutput.size() > 0)
    {
#ifdef PDAL_HAVE_LIBXML2
        XMLSchema schema(m_manager->pointTable().layout());

        std::ostream *out = FileUtils::createFile(m_PointCloudSchemaOutput);
        std::string xml(schema.xml());
        out->write(xml.c_str(), xml.size());
        FileUtils::closeFile(out);
#else
        std::cerr << "libxml2 support not enabled, no schema is produced" <<
            std::endl;
#endif

    }
    if (m_showStats)
        root.add(m_statsStage->getMetadata().clone("stats"));

    if (m_pipelineFile.size() > 0)
        PipelineWriter::writePipeline(m_manager->getStage(), m_pipelineFile);

    if (m_pointIndexes.size())
    {
        PointViewSet viewSet = m_manager->views();
        assert(viewSet.size() == 1);
        root.add(dumpPoints(*viewSet.begin()).clone("points"));
    }

    if (m_queryPoint.size())
    {
        PointViewSet viewSet = m_manager->views();
        assert(viewSet.size() == 1);
        root.add(dumpQuery(*viewSet.begin()));
    }

    if (m_showMetadata)
    {
        // If we have a reader cached, this means we
        // weren't reading a pipeline file directly. In that
        // case, use the metadata from the reader (old behavior).
        // Otherwise, return the full metadata of the entire pipeline
        if (m_reader)
            root.add(m_reader->getMetadata().clone("metadata"));
        else
            root.add(m_manager->getMetadata().clone("metadata"));
    }

    if (m_boundary)
    {
        PointViewSet viewSet = m_manager->views();
        assert(viewSet.size() == 1);
        root.add(m_hexbinStage->getMetadata().clone("boundary"));
    }
}

MetadataNode InfoKernel::dumpQuery(PointViewPtr inView) const
{
    int count;
    std::string location;

    // See if there's a provided point count.
    StringList parts = Utils::split2(m_queryPoint, '/');
    if (parts.size() == 2)
    {
        location = parts[0];
        count = atoi(parts[1].c_str());
    }
    else if (parts.size() == 1)
    {
        location = parts[0];
        count = inView->size();
    }
    else
        count = 0;
    if (count == 0)
        throw pdal_error("Invalid location specificiation. "
            "--query=\"X,Y[/count]\"");

    auto seps = [](char c){ return (c == ',' || c == '|' || c == ' '); };

    std::vector<std::string> tokens = Utils::split2(location, seps);
    std::vector<double> values;
    for (auto ti = tokens.begin(); ti != tokens.end(); ++ti)
    {
        double d;
        if (Utils::fromString(*ti, d))
            values.push_back(d);
    }

    if (values.size() != 2 && values.size() != 3)
        throw pdal_error("--points must be two or three values");

    PointViewPtr outView = inView->makeNew();

    std::vector<PointId> ids;
    if (values.size() >= 3)
    {
        KD3Index kdi(*inView);
        kdi.build();
        ids = kdi.neighbors(values[0], values[1], values[2], count);
    }
    else
    {
        KD2Index kdi(*inView);
        kdi.build();
        ids = kdi.neighbors(values[0], values[1], count);
    }

    for (auto i = ids.begin(); i != ids.end(); ++i)
        outView->appendPoint(*inView.get(), *i);

    return Utils::toMetadata(outView);
}

int InfoKernel::execute()
{
    std::string filename = m_usestdin ? std::string("STDIN") : m_inputFile;
    setup(filename);
    MetadataNode root = run(filename);
    Utils::toJSON(root, std::cout);

    return 0;
}

} // namespace pdal
<|endoftext|>


<commit_before>/*
    This file is part of KDE Kontact.

    Copyright (c) 2003 Cornelius Schumacher <schumacher@kde.org>

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.

    As a special exception, permission is given to link this program
    with any edition of Qt, and distribute the resulting executable,
    without including the source code for Qt in the source distribution.
*/

#include "aboutdialog.h"

#include "core.h"
#include "plugin.h"

#include <klocale.h>
#include <kiconloader.h>
#include <kinstance.h>
#include <kaboutdata.h>
#include <kactivelabel.h>
#include <ktextbrowser.h>

#include <QLayout>
#include <QLabel>
//Added by qt3to4:
#include <Q3TextEdit>
#include <QPixmap>
#include <QVBoxLayout>
#include <QList>
#include <QBoxLayout>

#include <kdebug.h>

using namespace Kontact;

AboutDialog::AboutDialog( Kontact::Core *core, const char *name )
  : KPageDialog( core )
    ,mCore( core )
{
  setCaption(i18n("About Kontact"));
  setButtons(Ok);
  setDefaultButton(Ok);
  setModal(false);
  showButtonSeparator(true);
  setFaceType(KPageDialog::List);
  addAboutData( i18n( "Kontact Container" ), QString( "kontact" ),
                KGlobal::instance()->aboutData() );

  QList<Plugin*> plugins = mCore->pluginList();
  QList<Plugin*>::ConstIterator end = plugins.end();
  QList<Plugin*>::ConstIterator it = plugins.begin();
  for ( ; it != end; ++it )
    addAboutPlugin( *it );

  addLicenseText( KGlobal::instance()->aboutData() );
}

void AboutDialog::addAboutPlugin( Kontact::Plugin *plugin )
{
  addAboutData( plugin->title(), plugin->icon(), plugin->aboutData() );
}

void AboutDialog::addAboutData( const QString &title, const QString &icon,
                                const KAboutData *about )
{
  QIcon pixmap = KGlobal::iconLoader()->loadIconSet( icon,
                                                    K3Icon::Desktop, 48 );

  QFrame *topFrame = new QFrame();
  KPageWidgetItem *pageItem = new KPageWidgetItem( topFrame, title );
  pageItem->setIcon(KIcon(pixmap));

  addPage( pageItem );

  QBoxLayout *topLayout = new QVBoxLayout( topFrame );

  if ( !about ) {
    QLabel *label = new QLabel( i18n( "No about information available." ),
                                topFrame );
    topLayout->addWidget( label );
  } else {
    QString text;

    text += "
" + about->programName() + "
";

    text += i18n( "Version %1
", about->version() );

    if ( !about->shortDescription().isEmpty() ) {
      text += "
" + about->shortDescription() + "
" +
               about->copyrightStatement() + "
";
    }

    QString home = about->homepage();
    if ( !home.isEmpty() ) {
      text += "" + home + "
";
    }

    text.replace( "\n", "
" );

    KActiveLabel *label = new KActiveLabel( text, topFrame );
    label->setAlignment( Qt::AlignTop );
    topLayout->addWidget( label );

    Q3TextEdit *personView = new Q3TextEdit( topFrame );
    personView->setReadOnly( true );
    topLayout->addWidget( personView, 1 );

    text = "";

    const QList<KAboutPerson> authors = about->authors();
    if ( !authors.isEmpty() ) {
      text += i18n( "
Authors:
" );

      QList<KAboutPerson>::ConstIterator it;
      for ( it = authors.begin(); it != authors.end(); ++it ) {
        text += formatPerson( (*it).name(), (*it).emailAddress() );
        if ( !(*it).task().isEmpty() )
          text += "" + (*it).task() + "
";
      }
    }

    const QList<KAboutPerson> credits = about->credits();
    if ( !credits.isEmpty() ) {
      text += i18n( "
Thanks to:
" );

      QList<KAboutPerson>::ConstIterator it;
      for ( it = credits.begin(); it != credits.end(); ++it ) {
        text += formatPerson( (*it).name(), (*it).emailAddress() );
        if ( !(*it).task().isEmpty() )
          text += "" + (*it).task() + "
";
      }
    }

    const QList<KAboutTranslator> translators = about->translators();
    if ( !translators.isEmpty() ) {
      text += i18n("
Translators:
");

      QList<KAboutTranslator>::ConstIterator it;
      for ( it = translators.begin(); it != translators.end(); ++it ) {
       text += formatPerson( (*it).name(), (*it).emailAddress() );
      }
    }

    personView->setText( text );
  }
}

QString AboutDialog::formatPerson( const QString &name, const QString &email )
{
  QString text = name;
  if ( !email.isEmpty() ) {
    text += " <" + email + ">";
  }

  text += "
";
  return text;
}

void AboutDialog::addLicenseText( const KAboutData *about )
{
  if ( !about || about->license().isEmpty() )
    return;

  QPixmap pixmap = KGlobal::iconLoader()->loadIcon( "signature",
                                                    K3Icon::Desktop, 48 );

  QString title = i18n( "%1 License", about->programName() );

  QFrame *topFrame = new QFrame();
  KPageWidgetItem *page = new KPageWidgetItem( topFrame, title );
  page->setIcon(KIcon(pixmap));
  addPage( page );
  QBoxLayout *topLayout = new QVBoxLayout( topFrame );

  KTextBrowser *textBrowser = new KTextBrowser( topFrame );
  textBrowser->setHtml( QString( "
%1
" ).arg( about->license() ) );

  topLayout->addWidget( textBrowser );
}

#include "aboutdialog.moc"
<commit_msg>Q3 support--<commit_after>/*
    This file is part of KDE Kontact.

    Copyright (c) 2003 Cornelius Schumacher <schumacher@kde.org>

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.

    As a special exception, permission is given to link this program
    with any edition of Qt, and distribute the resulting executable,
    without including the source code for Qt in the source distribution.
*/

#include "aboutdialog.h"

#include "core.h"
#include "plugin.h"

#include <klocale.h>
#include <kiconloader.h>
#include <kinstance.h>
#include <kaboutdata.h>
#include <kactivelabel.h>
#include <ktextbrowser.h>

#include <QLayout>
#include <QLabel>
//Added by qt3to4:
#include <QTextEdit>
#include <QPixmap>
#include <QVBoxLayout>
#include <QList>
#include <QBoxLayout>

#include <kdebug.h>

using namespace Kontact;

AboutDialog::AboutDialog( Kontact::Core *core, const char *name )
  : KPageDialog( core )
    ,mCore( core )
{
  setCaption(i18n("About Kontact"));
  setButtons(Ok);
  setDefaultButton(Ok);
  setModal(false);
  showButtonSeparator(true);
  setFaceType(KPageDialog::List);
  addAboutData( i18n( "Kontact Container" ), QString( "kontact" ),
                KGlobal::instance()->aboutData() );

  QList<Plugin*> plugins = mCore->pluginList();
  QList<Plugin*>::ConstIterator end = plugins.end();
  QList<Plugin*>::ConstIterator it = plugins.begin();
  for ( ; it != end; ++it )
    addAboutPlugin( *it );

  addLicenseText( KGlobal::instance()->aboutData() );
}

void AboutDialog::addAboutPlugin( Kontact::Plugin *plugin )
{
  addAboutData( plugin->title(), plugin->icon(), plugin->aboutData() );
}

void AboutDialog::addAboutData( const QString &title, const QString &icon,
                                const KAboutData *about )
{
  QIcon pixmap = KGlobal::iconLoader()->loadIconSet( icon,
                                                    K3Icon::Desktop, 48 );

  QFrame *topFrame = new QFrame();
  KPageWidgetItem *pageItem = new KPageWidgetItem( topFrame, title );
  pageItem->setIcon(KIcon(pixmap));

  addPage( pageItem );

  QBoxLayout *topLayout = new QVBoxLayout( topFrame );

  if ( !about ) {
    QLabel *label = new QLabel( i18n( "No about information available." ),
                                topFrame );
    topLayout->addWidget( label );
  } else {
    QString text;

    text += "
" + about->programName() + "
";

    text += i18n( "Version %1
", about->version() );

    if ( !about->shortDescription().isEmpty() ) {
      text += "
" + about->shortDescription() + "
" +
               about->copyrightStatement() + "
";
    }

    QString home = about->homepage();
    if ( !home.isEmpty() ) {
      text += "" + home + "
";
    }

    text.replace( "\n", "
" );

    KActiveLabel *label = new KActiveLabel( text, topFrame );
    label->setAlignment( Qt::AlignTop );
    topLayout->addWidget( label );

    QTextEdit *personView = new QTextEdit( topFrame );
    personView->setReadOnly( true );
    topLayout->addWidget( personView, 1 );

    text = "";

    const QList<KAboutPerson> authors = about->authors();
    if ( !authors.isEmpty() ) {
      text += i18n( "
Authors:
" );

      QList<KAboutPerson>::ConstIterator it;
      for ( it = authors.begin(); it != authors.end(); ++it ) {
        text += formatPerson( (*it).name(), (*it).emailAddress() );
        if ( !(*it).task().isEmpty() )
          text += "" + (*it).task() + "
";
      }
    }

    const QList<KAboutPerson> credits = about->credits();
    if ( !credits.isEmpty() ) {
      text += i18n( "
Thanks to:
" );

      QList<KAboutPerson>::ConstIterator it;
      for ( it = credits.begin(); it != credits.end(); ++it ) {
        text += formatPerson( (*it).name(), (*it).emailAddress() );
        if ( !(*it).task().isEmpty() )
          text += "" + (*it).task() + "
";
      }
    }

    const QList<KAboutTranslator> translators = about->translators();
    if ( !translators.isEmpty() ) {
      text += i18n("
Translators:
");

      QList<KAboutTranslator>::ConstIterator it;
      for ( it = translators.begin(); it != translators.end(); ++it ) {
       text += formatPerson( (*it).name(), (*it).emailAddress() );
      }
    }

    personView->setText( text );
  }
}

QString AboutDialog::formatPerson( const QString &name, const QString &email )
{
  QString text = name;
  if ( !email.isEmpty() ) {
    text += " <" + email + ">";
  }

  text += "
";
  return text;
}

void AboutDialog::addLicenseText( const KAboutData *about )
{
  if ( !about || about->license().isEmpty() )
    return;

  QPixmap pixmap = KGlobal::iconLoader()->loadIcon( "signature",
                                                    K3Icon::Desktop, 48 );

  QString title = i18n( "%1 License", about->programName() );

  QFrame *topFrame = new QFrame();
  KPageWidgetItem *page = new KPageWidgetItem( topFrame, title );
  page->setIcon(KIcon(pixmap));
  addPage( page );
  QBoxLayout *topLayout = new QVBoxLayout( topFrame );

  KTextBrowser *textBrowser = new KTextBrowser( topFrame );
  textBrowser->setHtml( QString( "
%1
" ).arg( about->license() ) );

  topLayout->addWidget( textBrowser );
}

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


<commit_before>#include "kontsevich_graph_series.hpp"
#include "util/cartesian_product.hpp"
#include <sstream>

template <class T>
size_t KontsevichGraphSeries<T>::precision() const
{
    return d_precision;
}

template <class T>
size_t KontsevichGraphSeries<T>::precision(size_t new_precision)
{
    return d_precision = new_precision;
}

template <class T>
void KontsevichGraphSeries<T>::reduce_mod_skew()
{
    auto current_term = this->begin();
    while (current_term != this->end())
    {
        current_term->second.reduce_mod_skew();
        ++current_term;
    }
}

template <class T>
KontsevichGraphSeries<T> KontsevichGraphSeries<T>::operator()(std::vector< KontsevichGraphSeries<T> > arguments) const
{
    KontsevichGraphSeries<T> result;
    // Theoretical precision of the result (may be the theoretical maximum):
    size_t new_precision = precision();
    for (auto& argument : arguments)
        new_precision = std::min(new_precision, argument.precision());
    result.precision(new_precision);
    // Return zero if the series itself or any of its arguments are zero:
    if (this->empty())
        return result;
    for (auto& argument : arguments)
        if (argument.empty())
            return result;
    // Practical precision (actually considering the data available):
    size_t practical_precision = std::min(this->rbegin()->first, new_precision);
    std::vector<size_t> argument_sizes(arguments.size());
    for (size_t i = 0; i != arguments.size(); ++i)
    {
        argument_sizes[i] = arguments[i].rbegin()->first + 1;
    }
    // Actual composition:
    for (size_t n = 0; n <= practical_precision; ++n)
    {
        auto entry = this->find(n);
        if (entry == this->end())
            continue;
        CartesianProduct multilinearity_indices(argument_sizes);
        for (auto arg_indices = multilinearity_indices.begin(); arg_indices != multilinearity_indices.end(); ++arg_indices) // Multi-linearity
        {
            size_t total_order = n;
            for (size_t i = 0; i != arguments.size(); ++i)
                total_order += (*arg_indices)[i];
            if (total_order > practical_precision)
                continue;
            std::vector< KontsevichGraphSum<T> > args(arguments.size());
            for (size_t i = 0; i != arguments.size(); ++i)
                args[i] = arguments[i][(*arg_indices)[i]];
            result[total_order] += entry->second(args);
        }
    }
    return result;
}

template <class T>
KontsevichGraphSeries<T> KontsevichGraphSeries<T>::skew_symmetrization() const
{
    KontsevichGraphSeries<T> total;
    total.precision(this->precision());
    for (auto current_term = this->begin(); current_term != this->end(); ++current_term)
        total[current_term->first] = current_term->second.skew_symmetrization();
    return total;
}

template <class T>
KontsevichGraphSeries<T> KontsevichGraphSeries<T>::inverse() const
{
    // TODO: only defined if series has one ground vertex
    KontsevichGraphSeries<T> result;
    result.precision(this->precision());
    result[0] = this->at(0);                       // TODO: properly test whether invertible
    for (size_t n = 1; n != precision() + 1; ++n)
    {
        for (size_t k = 0; k != n; ++k)
        {
            try {
                result[n] -= result[k]({ this->at(n-k) });
            }
            catch (std::out_of_range) {}
        }
    }
    return result;
}

template <class T>
KontsevichGraphSeries<T> KontsevichGraphSeries<T>::gauge_transform(const KontsevichGraphSeries<T>& gauge)
{
    // TODO: only defined if series has two ground vertices
    KontsevichGraphSeries<T> gauge_inverse = gauge.inverse();
    return gauge_inverse({ (*this)({ gauge, gauge }) });
}

template <class T>
KontsevichGraphSeries<T>& KontsevichGraphSeries<T>::operator+=(const KontsevichGraphSeries<T>& rhs)
{
    size_t practical_precision = this->rbegin()->first;
    for (size_t n = 0; n <= practical_precision; ++n)
    {
        try {
            (*this)[n] += rhs.at(n);
        }
        catch (std::out_of_range) {}
    }
    return *this;
}

template <class T>
KontsevichGraphSeries<T> operator+(KontsevichGraphSeries<T> lhs, const KontsevichGraphSeries<T> &rhs)
{
    lhs += rhs;
    return lhs;
}

template <class T>
KontsevichGraphSeries<T>& KontsevichGraphSeries<T>::operator-=(const KontsevichGraphSeries<T>& rhs)
{
    size_t practical_precision = this->rbegin()->first;
    for (size_t n = 0; n <= practical_precision; ++n)
    {
        try {
            (*this)[n] -= rhs.at(n);
        }
        catch (std::out_of_range) { }
    }
    return *this;
}

template <class T>
KontsevichGraphSeries<T> operator-(KontsevichGraphSeries<T> lhs, const KontsevichGraphSeries<T>& rhs)
{
    lhs -= rhs;
    return lhs;
}

template <class T>
bool KontsevichGraphSeries<T>::operator==(int other) const
{
    if (other != 0)
        return false;
    KontsevichGraphSeries<T> difference = *this;
    difference.reduce_mod_skew();
    for (auto term = this->begin(); term != this->end(); term++)
    {
        if (term->second.size() != 0)
            return false;
    }
    return true;
}

template <class T>
bool KontsevichGraphSeries<T>::operator!=(int other) const
{
    return !(*this == other);
}

template <class T>
KontsevichGraphSeries<T> KontsevichGraphSeries<T>::from_istream(std::istream& is, std::function<T(std::string)> const& parser, std::function<bool(KontsevichGraph, size_t)> const& filter)
{
    KontsevichGraphSeries<T> graph_series;
    KontsevichGraphSum<T> term;
    size_t order = 0;
    for (std::string line; getline(is, line); )
    {
        if (line.length() == 0 || line[0] == '#') // also skip comments
            continue;
        if (line[0] == 'h')
        {
            graph_series[order] = term;
            term = KontsevichGraphSum<T>({ });
            order = stoi(line.substr(2));
        }
        else
        {
            KontsevichGraph graph;
            std::stringstream ss(line);
            ss >> graph;
            graph.normalize();
            if (filter && !filter(graph, order))
                continue;
            std::string coefficient_str;
            ss >> coefficient_str;
            T coefficient = parser(coefficient_str);
            term += KontsevichGraphSum<T>({ { coefficient, graph } });
        }
    }
    graph_series[order] = term; // the last one
    graph_series.precision(order);
    return graph_series;
}

template <class T>
std::ostream& operator<<(std::ostream& os, const KontsevichGraphSeries<T>& series)
{
    if (series.size() == 0)
        return os << "0";
    auto final_term = series.end();
    --final_term;
    for (auto term = series.begin(); term != series.end(); term++)
    {
        if (term->first == 0)
            os << term->second;
        else
            os << "(" << term->second << ")*h^" << term->first;
        if (term != final_term)
            os << " + ";
    }
    return os;
}

template <class T>
KontsevichGraphSeries<T> schouten_bracket(const KontsevichGraphSeries<T>& left, const KontsevichGraphSeries<T>& right)
{
    KontsevichGraphSeries<T> result;
    size_t new_precision = std::min(left.precision(), right.precision());
    result.precision(new_precision);

    if (left.empty() || right.empty())
        return result;

    size_t practical_precision = std::min(left.rbegin()->first, new_precision);
    for (size_t n = 0; n <= practical_precision; ++n)
    {
        for (size_t k = 0; k <= n; ++k)
        {
            try {
                result[n] += schouten_bracket(left.at(n), right.at(n-k));
                if (n != n - k)
                    result[n] += schouten_bracket(left.at(n-k), right.at(n));
            }
            catch (std::out_of_range) {}
        }
    }
    return result;
}
<commit_msg>Fix Schouten bracket for series<commit_after>#include "kontsevich_graph_series.hpp"
#include "util/cartesian_product.hpp"
#include <sstream>

template <class T>
size_t KontsevichGraphSeries<T>::precision() const
{
    return d_precision;
}

template <class T>
size_t KontsevichGraphSeries<T>::precision(size_t new_precision)
{
    return d_precision = new_precision;
}

template <class T>
void KontsevichGraphSeries<T>::reduce_mod_skew()
{
    auto current_term = this->begin();
    while (current_term != this->end())
    {
        current_term->second.reduce_mod_skew();
        ++current_term;
    }
}

template <class T>
KontsevichGraphSeries<T> KontsevichGraphSeries<T>::operator()(std::vector< KontsevichGraphSeries<T> > arguments) const
{
    KontsevichGraphSeries<T> result;
    // Theoretical precision of the result (may be the theoretical maximum):
    size_t new_precision = precision();
    for (auto& argument : arguments)
        new_precision = std::min(new_precision, argument.precision());
    result.precision(new_precision);
    // Return zero if the series itself or any of its arguments are zero:
    if (this->empty())
        return result;
    for (auto& argument : arguments)
        if (argument.empty())
            return result;
    // Practical precision (actually considering the data available):
    size_t practical_precision = std::min(this->rbegin()->first, new_precision);
    std::vector<size_t> argument_sizes(arguments.size());
    for (size_t i = 0; i != arguments.size(); ++i)
    {
        argument_sizes[i] = arguments[i].rbegin()->first + 1;
    }
    // Actual composition:
    for (size_t n = 0; n <= practical_precision; ++n)
    {
        auto entry = this->find(n);
        if (entry == this->end())
            continue;
        CartesianProduct multilinearity_indices(argument_sizes);
        for (auto arg_indices = multilinearity_indices.begin(); arg_indices != multilinearity_indices.end(); ++arg_indices) // Multi-linearity
        {
            size_t total_order = n;
            for (size_t i = 0; i != arguments.size(); ++i)
                total_order += (*arg_indices)[i];
            if (total_order > practical_precision)
                continue;
            std::vector< KontsevichGraphSum<T> > args(arguments.size());
            for (size_t i = 0; i != arguments.size(); ++i)
                args[i] = arguments[i][(*arg_indices)[i]];
            result[total_order] += entry->second(args);
        }
    }
    return result;
}

template <class T>
KontsevichGraphSeries<T> KontsevichGraphSeries<T>::skew_symmetrization() const
{
    KontsevichGraphSeries<T> total;
    total.precision(this->precision());
    for (auto current_term = this->begin(); current_term != this->end(); ++current_term)
        total[current_term->first] = current_term->second.skew_symmetrization();
    return total;
}

template <class T>
KontsevichGraphSeries<T> KontsevichGraphSeries<T>::inverse() const
{
    // TODO: only defined if series has one ground vertex
    KontsevichGraphSeries<T> result;
    result.precision(this->precision());
    result[0] = this->at(0);                       // TODO: properly test whether invertible
    for (size_t n = 1; n != precision() + 1; ++n)
    {
        for (size_t k = 0; k != n; ++k)
        {
            try {
                result[n] -= result[k]({ this->at(n-k) });
            }
            catch (std::out_of_range) {}
        }
    }
    return result;
}

template <class T>
KontsevichGraphSeries<T> KontsevichGraphSeries<T>::gauge_transform(const KontsevichGraphSeries<T>& gauge)
{
    // TODO: only defined if series has two ground vertices
    KontsevichGraphSeries<T> gauge_inverse = gauge.inverse();
    return gauge_inverse({ (*this)({ gauge, gauge }) });
}

template <class T>
KontsevichGraphSeries<T>& KontsevichGraphSeries<T>::operator+=(const KontsevichGraphSeries<T>& rhs)
{
    size_t practical_precision = this->rbegin()->first;
    for (size_t n = 0; n <= practical_precision; ++n)
    {
        try {
            (*this)[n] += rhs.at(n);
        }
        catch (std::out_of_range) {}
    }
    return *this;
}

template <class T>
KontsevichGraphSeries<T> operator+(KontsevichGraphSeries<T> lhs, const KontsevichGraphSeries<T> &rhs)
{
    lhs += rhs;
    return lhs;
}

template <class T>
KontsevichGraphSeries<T>& KontsevichGraphSeries<T>::operator-=(const KontsevichGraphSeries<T>& rhs)
{
    size_t practical_precision = this->rbegin()->first;
    for (size_t n = 0; n <= practical_precision; ++n)
    {
        try {
            (*this)[n] -= rhs.at(n);
        }
        catch (std::out_of_range) { }
    }
    return *this;
}

template <class T>
KontsevichGraphSeries<T> operator-(KontsevichGraphSeries<T> lhs, const KontsevichGraphSeries<T>& rhs)
{
    lhs -= rhs;
    return lhs;
}

template <class T>
bool KontsevichGraphSeries<T>::operator==(int other) const
{
    if (other != 0)
        return false;
    KontsevichGraphSeries<T> difference = *this;
    difference.reduce_mod_skew();
    for (auto term = this->begin(); term != this->end(); term++)
    {
        if (term->second.size() != 0)
            return false;
    }
    return true;
}

template <class T>
bool KontsevichGraphSeries<T>::operator!=(int other) const
{
    return !(*this == other);
}

template <class T>
KontsevichGraphSeries<T> KontsevichGraphSeries<T>::from_istream(std::istream& is, std::function<T(std::string)> const& parser, std::function<bool(KontsevichGraph, size_t)> const& filter)
{
    KontsevichGraphSeries<T> graph_series;
    KontsevichGraphSum<T> term;
    size_t order = 0;
    for (std::string line; getline(is, line); )
    {
        if (line.length() == 0 || line[0] == '#') // also skip comments
            continue;
        if (line[0] == 'h')
        {
            graph_series[order] = term;
            term = KontsevichGraphSum<T>({ });
            order = stoi(line.substr(2));
        }
        else
        {
            KontsevichGraph graph;
            std::stringstream ss(line);
            ss >> graph;
            graph.normalize();
            if (filter && !filter(graph, order))
                continue;
            std::string coefficient_str;
            ss >> coefficient_str;
            T coefficient = parser(coefficient_str);
            term += KontsevichGraphSum<T>({ { coefficient, graph } });
        }
    }
    graph_series[order] = term; // the last one
    graph_series.precision(order);
    return graph_series;
}

template <class T>
std::ostream& operator<<(std::ostream& os, const KontsevichGraphSeries<T>& series)
{
    if (series.size() == 0)
        return os << "0";
    auto final_term = series.end();
    --final_term;
    for (auto term = series.begin(); term != series.end(); term++)
    {
        if (term->first == 0)
            os << term->second;
        else
            os << "(" << term->second << ")*h^" << term->first;
        if (term != final_term)
            os << " + ";
    }
    return os;
}

template <class T>
KontsevichGraphSeries<T> schouten_bracket(const KontsevichGraphSeries<T>& left, const KontsevichGraphSeries<T>& right)
{
    KontsevichGraphSeries<T> result;
    size_t new_precision = std::min(left.precision(), right.precision());
    result.precision(new_precision);

    if (left.empty() || right.empty())
        return result;

    size_t practical_precision = std::min(left.rbegin()->first, new_precision);
    for (size_t n = 0; n <= practical_precision; ++n)
    {
        for (size_t k = 0; k <= n; ++k)
        {
            try {
                result[n] += schouten_bracket(left.at(k), right.at(n-k));
            }
            catch (std::out_of_range) {}
        }
    }
    return result;
}
<|endoftext|>


<commit_before>/*
 * Software License Agreement (BSD License)
 *
 *  Point Cloud Library (PCL) - www.pointclouds.org
 *  Copyright (c) 2010-2011, Willow Garage, Inc.
 *
 *  All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions
 *  are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *   * Redistributions in binary form must reproduce the above
 *     copyright notice, this list of conditions and the following
 *     disclaimer in the documentation and/or other materials provided
 *     with the distribution.
 *   * Neither the name of Willow Garage, Inc. nor the names of its
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 *  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 *  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 *  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 *  POSSIBILITY OF SUCH DAMAGE.
 *
 * $Id$
 *
 */
#ifndef PCL_REGISTRATION_TRANSFORMATION_ESTIMATION_LM_HPP_
#define PCL_REGISTRATION_TRANSFORMATION_ESTIMATION_LM_HPP_

#include "pcl/registration/warp_point_rigid.h"
#include "pcl/registration/warp_point_rigid_6d.h"
#include "pcl/registration/distances.h"
#include <unsupported/Eigen/NonLinearOptimization>
//////////////////////////////////////////////////////////////////////////////////////////////
template <typename PointSource, typename PointTarget> void
pcl::registration::TransformationEstimationLM<PointSource, PointTarget>::estimateRigidTransformation (
    const pcl::PointCloud<PointSource> &cloud_src,
    const pcl::PointCloud<PointTarget> &cloud_tgt,
    Eigen::Matrix4f &transformation_matrix)
{

  // <cloud_src,cloud_src> is the source dataset
  if (cloud_src.points.size () != cloud_tgt.points.size ())
  {
    PCL_ERROR ("[pcl::registration::TransformationEstimationLM::estimateRigidTransformation] ");
    PCL_ERROR ("Number or points in source (%lu) differs than target (%lu)!\n",
               (unsigned long)cloud_src.points.size (), (unsigned long)cloud_tgt.points.size ());
    return;
  }
  if (cloud_src.points.size () < 4)     // need at least 4 samples
  {
    PCL_ERROR ("[pcl::registration::TransformationEstimationLM::estimateRigidTransformation] ");
    PCL_ERROR ("Need at least 4 points to estimate a transform! Source and target have %lu points!\n",
               (unsigned long)cloud_src.points.size ());
    return;
  }

  // If no warp function has been set, use the default (WarpPointRigid6D)
  if (!warp_point_)
    warp_point_.reset (new WarpPointRigid6D<PointSource, PointTarget>);

  int n_unknowns = warp_point_->getDimension ();
  int m = cloud_src.points.size ();
  Eigen::VectorXd x(n_unknowns);
  x.setZero ();

  // Set temporary pointers
  tmp_src_ = &cloud_src;
  tmp_tgt_ = &cloud_tgt;

  OptimizationFunctor functor (n_unknowns, m, this);
  Eigen::NumericalDiff<OptimizationFunctor> num_diff (functor);
  Eigen::LevenbergMarquardt<Eigen::NumericalDiff<OptimizationFunctor> > lm (num_diff);
  int info = lm.minimize (x);

  // Compute the norm of the residuals
  PCL_DEBUG ("[pcl::registration::TransformationEstimationLM::estimateRigidTransformation]");
  PCL_DEBUG ("LM solver finished with exit code %i, having a residual norm of %g. \n", info, lm.fvec.norm ());
  if(n_unknowns == 7)
    PCL_DEBUG ("Final solution: [%f %f %f %f] [%f %f %f]\n", x[0], x[1], x[2], x[3], x[4], x[5], x[6]);
  else
    PCL_DEBUG ("Final solution: [%f %f %f] [%f %f %f]\n", x[0], x[1], x[2], x[3], x[4], x[5]);

  // Return the correct transformation
  transformation_matrix.setZero ();

  Eigen::Quaternionf q (0, x[3], x[4], x[5]);
  q.w () = sqrt (1 - q.dot (q));   // Compute w from the unit quaternion
  transformation_matrix.topLeftCorner<3, 3> () = q.toRotationMatrix ();

  Eigen::Vector4f t (x[0], x[1], x[2], 1.0);
  transformation_matrix.block <4, 1> (0, 3) = t;

  tmp_src_ = NULL;
  tmp_tgt_ = NULL;
}

//////////////////////////////////////////////////////////////////////////////////////////////
template <typename PointSource, typename PointTarget> void
pcl::registration::TransformationEstimationLM<PointSource, PointTarget>::estimateRigidTransformation (
    const pcl::PointCloud<PointSource> &cloud_src,
    const std::vector<int> &indices_src,
    const pcl::PointCloud<PointTarget> &cloud_tgt,
    Eigen::Matrix4f &transformation_matrix)
{
  if (indices_src.size () != cloud_tgt.points.size ())
  {
    PCL_ERROR ("[pcl::registration::TransformationEstimationLM::estimateRigidTransformation] Number or points in source (%lu) differs than target (%lu)!\n", (unsigned long)indices_src.size (), (unsigned long)cloud_tgt.points.size ());
    return;
  }

  // <cloud_src,cloud_src> is the source dataset
  transformation_matrix.setIdentity ();

  const int nr_correspondences = (int)cloud_tgt.points.size ();
  std::vector<int> indices_tgt;
  indices_tgt.resize(nr_correspondences);
  for (int i = 0; i < nr_correspondences; ++i)
    indices_tgt[i] = i;

  estimateRigidTransformation(cloud_src, indices_src, cloud_tgt, indices_tgt, transformation_matrix);
}

//////////////////////////////////////////////////////////////////////////////////////////////
template <typename PointSource, typename PointTarget> inline void
pcl::registration::TransformationEstimationLM<PointSource, PointTarget>::estimateRigidTransformation (
    const pcl::PointCloud<PointSource> &cloud_src,
    const std::vector<int> &indices_src,
    const pcl::PointCloud<PointTarget> &cloud_tgt,
    const std::vector<int> &indices_tgt,
    Eigen::Matrix4f &transformation_matrix)
{
  if (indices_src.size () != indices_tgt.size ())
  {
    PCL_ERROR ("[pcl::registration::TransformationEstimationLM::estimateRigidTransformation] Number or points in source (%lu) differs than target (%lu)!\n", (unsigned long)indices_src.size (), (unsigned long)indices_tgt.size ());
    return;
  }

  if (indices_src.size () < 4)     // need at least 4 samples
  {
    PCL_ERROR ("[pcl::IterativeClosestPointNonLinear::estimateRigidTransformationLM] ");
    PCL_ERROR ("Need at least 4 points to estimate a transform! Source and target have %lu points!",
               (unsigned long)indices_src.size ());
    return;
  }

  // If no warp function has been set, use the default (WarpPointRigid6D)
  if (!warp_point_)
    warp_point_.reset (new WarpPointRigid6D<PointSource, PointTarget>);

  int n_unknowns = warp_point_->getDimension ();  // get dimension of unknown space
  int m = indices_src.size ();
  Eigen::VectorXd x(n_unknowns);
  x.setConstant (n_unknowns, 0);

  // Set temporary pointers
  tmp_src_ = &cloud_src;
  tmp_tgt_ = &cloud_tgt;
  tmp_idx_src_ = &indices_src;
  tmp_idx_tgt_ = &indices_tgt;

  OptimizationFunctorWithIndices functor (n_unknowns, m, this);
  Eigen::NumericalDiff<OptimizationFunctorWithIndices> num_diff (functor);
  Eigen::LevenbergMarquardt<Eigen::NumericalDiff<OptimizationFunctorWithIndices> > lm (num_diff);
  int info = lm.minimize (x);

  // Compute the norm of the residuals
  PCL_DEBUG ("[pcl::registration::TransformationEstimationLM::estimateRigidTransformation]");
  PCL_DEBUG ("LM solver finished with exit code %i, having a residual norm of %g. \n", info, lm.fvec.norm ());
  PCL_DEBUG ("Final solution: [%f %f %f] [%f %f %f]\n", x[0], x[1], x[2], x[3], x[4], x[5]);

  // Return the correct transformation
  transformation_matrix.setZero ();

  Eigen::Quaternionf q (0, x[3], x[4], x[5]);
  q.w () = sqrt (1 - q.dot (q));   // Compute w from the unit quaternion
  transformation_matrix.topLeftCorner<3, 3> () = q.toRotationMatrix ();

  Eigen::Vector4f t (x[0], x[1], x[2], 1.0);
  transformation_matrix.block <4, 1> (0, 3) = t;

  tmp_src_ = NULL;
  tmp_tgt_ = NULL;
  tmp_idx_src_ = tmp_idx_tgt_ = NULL;
}

//////////////////////////////////////////////////////////////////////////////////////////////
template <typename PointSource, typename PointTarget> inline void
pcl::registration::TransformationEstimationLM<PointSource, PointTarget>::estimateRigidTransformation (
    const pcl::PointCloud<PointSource> &cloud_src,
    const pcl::PointCloud<PointTarget> &cloud_tgt,
    const pcl::Correspondences &correspondences,
    Eigen::Matrix4f &transformation_matrix)
{
  const int nr_correspondences = (int)correspondences.size();
  std::vector<int> indices_src(nr_correspondences);
  std::vector<int> indices_tgt(nr_correspondences);
  for (int i = 0; i < nr_correspondences; ++i)
  {
    indices_src[i] = correspondences[i].index_query;
    indices_tgt[i] = correspondences[i].index_match;
  }

  estimateRigidTransformation(cloud_src, indices_src, cloud_tgt, indices_tgt, transformation_matrix);
}

//////////////////////////////////////////////////////////////////////////////////////////////
template <typename PointSource, typename PointTarget> int
pcl::registration::TransformationEstimationLM<PointSource, PointTarget>::OptimizationFunctor::operator() (const Eigen::VectorXd &x, Eigen::VectorXd &fvec) const
{
  const PointCloud<PointSource> & src_points = *estimator_->tmp_src_;
  const PointCloud<PointTarget> & tgt_points = *estimator_->tmp_tgt_;
  const std::vector<int> & src_indices = *estimator_->tmp_idx_src_;
  const std::vector<int> & tgt_indices = *estimator_->tmp_idx_tgt_;

  // Initialize the warp function with the given parameters
  Eigen::VectorXf params = x.cast<float> ();
  estimator_->warp_point_->setParam (params);

  // Transform each source point and compute its distance to the corresponding target point
  for (int i = 0; i < m_values; i++)
  {
    const PointSource & p_src = src_points.points[src_indices[i]];
    const PointTarget & p_tgt = tgt_points.points[tgt_indices[i]];

    // Transform the source point based on the current warp parameters
    PointSource p_src_warped;
    estimator_->warp_point_->warpPoint (p_src, p_src_warped);

    // Estimate the distance (cost function)
    fvec[i] = estimator_->computeDistance (p_src_warped, p_tgt);
  }
  return 0;
}

//////////////////////////////////////////////////////////////////////////////////////////////
template <typename PointSource, typename PointTarget> int
pcl::registration::TransformationEstimationLM<PointSource, PointTarget>::OptimizationFunctorWithIndices::operator() (const Eigen::VectorXd &x, Eigen::VectorXd &fvec) const
{
  const PointCloud<PointSource> & src_points = *estimator_->tmp_src_;
  const PointCloud<PointTarget> & tgt_points = *estimator_->tmp_tgt_;
  const std::vector<int> & src_indices = *estimator_->tmp_idx_src_;
  const std::vector<int> & tgt_indices = *estimator_->tmp_idx_tgt_;

  // Initialize the warp function with the given parameters
  Eigen::VectorXf params = x.cast<float> ();
  estimator_->warp_point_->setParam (params);

  // Transform each source point and compute its distance to the corresponding target point
  for (int i = 0; i < m_values; ++i)
  {
    const PointSource & p_src = src_points.points[src_indices[i]];
    const PointTarget & p_tgt = tgt_points.points[tgt_indices[i]];

    // Transform the source point based on the current warp parameters
    PointSource p_src_warped;
    estimator_->warp_point_->warpPoint (p_src, p_src_warped);

    // Estimate the distance (cost function)
    fvec[i] = estimator_->computeDistance (p_src_warped, p_tgt);
  }
  return (0);
}
/*
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
template <typename PointSource, typename PointTarget> inline double
pcl::registration::TransformationEstimationLM<PointSource, PointTarget>::computeMedian (double *fvec, int m)
{
  double median;
  // Copy the values to vectors for faster sorting
  std::vector<double> data (m);
  memcpy (&data[0], fvec, sizeof (double) * m);

  std::sort (data.begin (), data.end ());

  int mid = data.size () / 2;
  if (data.size () % 2 == 0)
    median = (data[mid-1] + data[mid]) / 2.0;
  else
    median = data[mid];
  return (median);
}
*/

//#define PCL_INSTANTIATE_TransformationEstimationLM(T,U) template class PCL_EXPORTS pcl::registration::TransformationEstimationLM<T,U>;

#endif /* PCL_REGISTRATION_TRANSFORMATION_ESTIMATION_LM_HPP_ */
<commit_msg>Fixed an overzealous copy-paste in transformation_estimation_lm.hpp<commit_after>/*
 * Software License Agreement (BSD License)
 *
 *  Point Cloud Library (PCL) - www.pointclouds.org
 *  Copyright (c) 2010-2011, Willow Garage, Inc.
 *
 *  All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions
 *  are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *   * Redistributions in binary form must reproduce the above
 *     copyright notice, this list of conditions and the following
 *     disclaimer in the documentation and/or other materials provided
 *     with the distribution.
 *   * Neither the name of Willow Garage, Inc. nor the names of its
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 *  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 *  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 *  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 *  POSSIBILITY OF SUCH DAMAGE.
 *
 * $Id$
 *
 */
#ifndef PCL_REGISTRATION_TRANSFORMATION_ESTIMATION_LM_HPP_
#define PCL_REGISTRATION_TRANSFORMATION_ESTIMATION_LM_HPP_

#include "pcl/registration/warp_point_rigid.h"
#include "pcl/registration/warp_point_rigid_6d.h"
#include "pcl/registration/distances.h"
#include <unsupported/Eigen/NonLinearOptimization>
//////////////////////////////////////////////////////////////////////////////////////////////
template <typename PointSource, typename PointTarget> void
pcl::registration::TransformationEstimationLM<PointSource, PointTarget>::estimateRigidTransformation (
    const pcl::PointCloud<PointSource> &cloud_src,
    const pcl::PointCloud<PointTarget> &cloud_tgt,
    Eigen::Matrix4f &transformation_matrix)
{

  // <cloud_src,cloud_src> is the source dataset
  if (cloud_src.points.size () != cloud_tgt.points.size ())
  {
    PCL_ERROR ("[pcl::registration::TransformationEstimationLM::estimateRigidTransformation] ");
    PCL_ERROR ("Number or points in source (%lu) differs than target (%lu)!\n",
               (unsigned long)cloud_src.points.size (), (unsigned long)cloud_tgt.points.size ());
    return;
  }
  if (cloud_src.points.size () < 4)     // need at least 4 samples
  {
    PCL_ERROR ("[pcl::registration::TransformationEstimationLM::estimateRigidTransformation] ");
    PCL_ERROR ("Need at least 4 points to estimate a transform! Source and target have %lu points!\n",
               (unsigned long)cloud_src.points.size ());
    return;
  }

  // If no warp function has been set, use the default (WarpPointRigid6D)
  if (!warp_point_)
    warp_point_.reset (new WarpPointRigid6D<PointSource, PointTarget>);

  int n_unknowns = warp_point_->getDimension ();
  int m = cloud_src.points.size ();
  Eigen::VectorXd x(n_unknowns);
  x.setZero ();

  // Set temporary pointers
  tmp_src_ = &cloud_src;
  tmp_tgt_ = &cloud_tgt;

  OptimizationFunctor functor (n_unknowns, m, this);
  Eigen::NumericalDiff<OptimizationFunctor> num_diff (functor);
  Eigen::LevenbergMarquardt<Eigen::NumericalDiff<OptimizationFunctor> > lm (num_diff);
  int info = lm.minimize (x);

  // Compute the norm of the residuals
  PCL_DEBUG ("[pcl::registration::TransformationEstimationLM::estimateRigidTransformation]");
  PCL_DEBUG ("LM solver finished with exit code %i, having a residual norm of %g. \n", info, lm.fvec.norm ());
  if(n_unknowns == 7)
    PCL_DEBUG ("Final solution: [%f %f %f %f] [%f %f %f]\n", x[0], x[1], x[2], x[3], x[4], x[5], x[6]);
  else
    PCL_DEBUG ("Final solution: [%f %f %f] [%f %f %f]\n", x[0], x[1], x[2], x[3], x[4], x[5]);

  // Return the correct transformation
  transformation_matrix.setZero ();

  Eigen::Quaternionf q (0, x[3], x[4], x[5]);
  q.w () = sqrt (1 - q.dot (q));   // Compute w from the unit quaternion
  transformation_matrix.topLeftCorner<3, 3> () = q.toRotationMatrix ();

  Eigen::Vector4f t (x[0], x[1], x[2], 1.0);
  transformation_matrix.block <4, 1> (0, 3) = t;

  tmp_src_ = NULL;
  tmp_tgt_ = NULL;
}

//////////////////////////////////////////////////////////////////////////////////////////////
template <typename PointSource, typename PointTarget> void
pcl::registration::TransformationEstimationLM<PointSource, PointTarget>::estimateRigidTransformation (
    const pcl::PointCloud<PointSource> &cloud_src,
    const std::vector<int> &indices_src,
    const pcl::PointCloud<PointTarget> &cloud_tgt,
    Eigen::Matrix4f &transformation_matrix)
{
  if (indices_src.size () != cloud_tgt.points.size ())
  {
    PCL_ERROR ("[pcl::registration::TransformationEstimationLM::estimateRigidTransformation] Number or points in source (%lu) differs than target (%lu)!\n", (unsigned long)indices_src.size (), (unsigned long)cloud_tgt.points.size ());
    return;
  }

  // <cloud_src,cloud_src> is the source dataset
  transformation_matrix.setIdentity ();

  const int nr_correspondences = (int)cloud_tgt.points.size ();
  std::vector<int> indices_tgt;
  indices_tgt.resize(nr_correspondences);
  for (int i = 0; i < nr_correspondences; ++i)
    indices_tgt[i] = i;

  estimateRigidTransformation(cloud_src, indices_src, cloud_tgt, indices_tgt, transformation_matrix);
}

//////////////////////////////////////////////////////////////////////////////////////////////
template <typename PointSource, typename PointTarget> inline void
pcl::registration::TransformationEstimationLM<PointSource, PointTarget>::estimateRigidTransformation (
    const pcl::PointCloud<PointSource> &cloud_src,
    const std::vector<int> &indices_src,
    const pcl::PointCloud<PointTarget> &cloud_tgt,
    const std::vector<int> &indices_tgt,
    Eigen::Matrix4f &transformation_matrix)
{
  if (indices_src.size () != indices_tgt.size ())
  {
    PCL_ERROR ("[pcl::registration::TransformationEstimationLM::estimateRigidTransformation] Number or points in source (%lu) differs than target (%lu)!\n", (unsigned long)indices_src.size (), (unsigned long)indices_tgt.size ());
    return;
  }

  if (indices_src.size () < 4)     // need at least 4 samples
  {
    PCL_ERROR ("[pcl::IterativeClosestPointNonLinear::estimateRigidTransformationLM] ");
    PCL_ERROR ("Need at least 4 points to estimate a transform! Source and target have %lu points!",
               (unsigned long)indices_src.size ());
    return;
  }

  // If no warp function has been set, use the default (WarpPointRigid6D)
  if (!warp_point_)
    warp_point_.reset (new WarpPointRigid6D<PointSource, PointTarget>);

  int n_unknowns = warp_point_->getDimension ();  // get dimension of unknown space
  int m = indices_src.size ();
  Eigen::VectorXd x(n_unknowns);
  x.setConstant (n_unknowns, 0);

  // Set temporary pointers
  tmp_src_ = &cloud_src;
  tmp_tgt_ = &cloud_tgt;
  tmp_idx_src_ = &indices_src;
  tmp_idx_tgt_ = &indices_tgt;

  OptimizationFunctorWithIndices functor (n_unknowns, m, this);
  Eigen::NumericalDiff<OptimizationFunctorWithIndices> num_diff (functor);
  Eigen::LevenbergMarquardt<Eigen::NumericalDiff<OptimizationFunctorWithIndices> > lm (num_diff);
  int info = lm.minimize (x);

  // Compute the norm of the residuals
  PCL_DEBUG ("[pcl::registration::TransformationEstimationLM::estimateRigidTransformation]");
  PCL_DEBUG ("LM solver finished with exit code %i, having a residual norm of %g. \n", info, lm.fvec.norm ());
  PCL_DEBUG ("Final solution: [%f %f %f] [%f %f %f]\n", x[0], x[1], x[2], x[3], x[4], x[5]);

  // Return the correct transformation
  transformation_matrix.setZero ();

  Eigen::Quaternionf q (0, x[3], x[4], x[5]);
  q.w () = sqrt (1 - q.dot (q));   // Compute w from the unit quaternion
  transformation_matrix.topLeftCorner<3, 3> () = q.toRotationMatrix ();

  Eigen::Vector4f t (x[0], x[1], x[2], 1.0);
  transformation_matrix.block <4, 1> (0, 3) = t;

  tmp_src_ = NULL;
  tmp_tgt_ = NULL;
  tmp_idx_src_ = tmp_idx_tgt_ = NULL;
}

//////////////////////////////////////////////////////////////////////////////////////////////
template <typename PointSource, typename PointTarget> inline void
pcl::registration::TransformationEstimationLM<PointSource, PointTarget>::estimateRigidTransformation (
    const pcl::PointCloud<PointSource> &cloud_src,
    const pcl::PointCloud<PointTarget> &cloud_tgt,
    const pcl::Correspondences &correspondences,
    Eigen::Matrix4f &transformation_matrix)
{
  const int nr_correspondences = (int)correspondences.size();
  std::vector<int> indices_src(nr_correspondences);
  std::vector<int> indices_tgt(nr_correspondences);
  for (int i = 0; i < nr_correspondences; ++i)
  {
    indices_src[i] = correspondences[i].index_query;
    indices_tgt[i] = correspondences[i].index_match;
  }

  estimateRigidTransformation(cloud_src, indices_src, cloud_tgt, indices_tgt, transformation_matrix);
}

//////////////////////////////////////////////////////////////////////////////////////////////
template <typename PointSource, typename PointTarget> int
pcl::registration::TransformationEstimationLM<PointSource, PointTarget>::OptimizationFunctor::operator() (const Eigen::VectorXd &x, Eigen::VectorXd &fvec) const
{
  const PointCloud<PointSource> & src_points = *estimator_->tmp_src_;
  const PointCloud<PointTarget> & tgt_points = *estimator_->tmp_tgt_;

  // Initialize the warp function with the given parameters
  Eigen::VectorXf params = x.cast<float> ();
  estimator_->warp_point_->setParam (params);

  // Transform each source point and compute its distance to the corresponding target point
  for (int i = 0; i < m_values; i++)
  {
    const PointSource & p_src = src_points.points[i];
    const PointTarget & p_tgt = tgt_points.points[i];

    // Transform the source point based on the current warp parameters
    PointSource p_src_warped;
    estimator_->warp_point_->warpPoint (p_src, p_src_warped);

    // Estimate the distance (cost function)
    fvec[i] = estimator_->computeDistance (p_src_warped, p_tgt);
  }
  return 0;
}

//////////////////////////////////////////////////////////////////////////////////////////////
template <typename PointSource, typename PointTarget> int
pcl::registration::TransformationEstimationLM<PointSource, PointTarget>::OptimizationFunctorWithIndices::operator() (const Eigen::VectorXd &x, Eigen::VectorXd &fvec) const
{
  const PointCloud<PointSource> & src_points = *estimator_->tmp_src_;
  const PointCloud<PointTarget> & tgt_points = *estimator_->tmp_tgt_;
  const std::vector<int> & src_indices = *estimator_->tmp_idx_src_;
  const std::vector<int> & tgt_indices = *estimator_->tmp_idx_tgt_;

  // Initialize the warp function with the given parameters
  Eigen::VectorXf params = x.cast<float> ();
  estimator_->warp_point_->setParam (params);

  // Transform each source point and compute its distance to the corresponding target point
  for (int i = 0; i < m_values; ++i)
  {
    const PointSource & p_src = src_points.points[src_indices[i]];
    const PointTarget & p_tgt = tgt_points.points[tgt_indices[i]];

    // Transform the source point based on the current warp parameters
    PointSource p_src_warped;
    estimator_->warp_point_->warpPoint (p_src, p_src_warped);

    // Estimate the distance (cost function)
    fvec[i] = estimator_->computeDistance (p_src_warped, p_tgt);
  }
  return (0);
}
/*
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
template <typename PointSource, typename PointTarget> inline double
pcl::registration::TransformationEstimationLM<PointSource, PointTarget>::computeMedian (double *fvec, int m)
{
  double median;
  // Copy the values to vectors for faster sorting
  std::vector<double> data (m);
  memcpy (&data[0], fvec, sizeof (double) * m);

  std::sort (data.begin (), data.end ());

  int mid = data.size () / 2;
  if (data.size () % 2 == 0)
    median = (data[mid-1] + data[mid]) / 2.0;
  else
    median = data[mid];
  return (median);
}
*/

//#define PCL_INSTANTIATE_TransformationEstimationLM(T,U) template class PCL_EXPORTS pcl::registration::TransformationEstimationLM<T,U>;

#endif /* PCL_REGISTRATION_TRANSFORMATION_ESTIMATION_LM_HPP_ */
<|endoftext|>