<commit_before>#include <iomanip>
#include "GraphCalculator.hpp"
#include <blaze/Math.h>
#include <blaze/config/BLAS.h>

using MatrixXd = blaze::DynamicMatrix<double>;

void Realize(MatrixXd& A, const vector<Point>& P, long row, long N, double Cmx, double Cmy, long block, long num_cols_per_block)
{
	double dx = MaxNonZeroDistance(Cmx);
	double dy = MaxNonZeroDistance(Cmy);
	long dxi = long(dx+1);
	long dyi = long(dy+1);

// 	cout << "di = " << di << endl;

// 	cout << "Número de pixeles: " << 2*(dxi) << "*" << 2*dyi << " = " << 4*dxi*dyi << endl;

	for (const Point& p : P)
	{
		long minX = max(0L,long(p.x)-dxi);
		long maxX = min(N, long(p.x)+dxi);
		long minY = max(0L,long(p.y)-dyi);
		long maxY = min(N, long(p.y)+dyi);
		assert(maxX-minX > 0);
		assert(maxY-minY > 0);
		for (long x = minX; x < maxX; ++x)
		{
			for (long y = minY; y < maxY; ++y)
			{
				long index = x*N+y;
				index -= num_cols_per_block*block;

				if (index >= 0 && index < A.columns())
				{
					double XX = (p.x-x)*(p.x-x);
					double YY = (p.y-y)*(p.y-y);

					A(row,index) *= (1.0-exp(-Cmx*XX - Cmy*YY));
				}
			}
		}
	}

	for (size_t col = 0; col < A.columns(); ++col)
	{
		A(row,col) += 1.0;
	}
}

Matrix GraphCalculator::CalculateGraph()
{
	blaze::setNumThreads( blaze::getNumThreads() );
	Chronometer T;
	size_t numspecies = E.size();
	vector<double> Area(numspecies,0.0);
	MatrixXd M(numspecies,numspecies,0.0);

	MatrixXd A(numspecies,num_cols_per_block,-1.0);
	for (size_t block = 0; block < num_full_blocks; ++block)
	{
		A = -1.0;
		#pragma omp parallel for
		for (size_t species = 0; species < numspecies; ++species)
		{
			Realize(A,E[species],species,grid,Cmx,Cmy, block, num_cols_per_block);

			for (size_t col = 0; col < A.columns(); ++col)
				Area[species] += A(species,col);
		}

		M += blaze::declsym( A * blaze::trans(A) );
        double time = T.Peek();

		cout << "Done with block " << block+1 << " of " << num_full_blocks+num_partial_blocks
             << ". Expected remaining time: " << time*double(num_full_blocks+num_partial_blocks)/(block+1) - time << 's' << endl;
	}

	if (num_partial_blocks)
	{
		MatrixXd A(numspecies,num_cols_partial_block,-1.0);
		#pragma omp parallel for
		for (size_t species = 0; species < numspecies; ++species)
		{
			Realize(A,E[species],species,grid,Cmx,Cmy, num_full_blocks, num_cols_per_block);

			for (size_t col = 0; col < A.columns(); ++col)
				Area[species] += A(species,col);
		}

		M += blaze::declsym( A * blaze::trans(A) );
		cout << "Done with block " << num_full_blocks+1 << " of " << num_full_blocks+num_partial_blocks << '!' << endl;
	}

	cout << "Total Time taken: " << T.Reset() << endl;

	Matrix R(numspecies,Row(numspecies));
	for (size_t x = 0; x < numspecies; ++x)
	{
		if (Area[x] <= tolerance)
		{
			cerr << "Area of X = 0! Increase grid size!!" << endl;
		}
		for (size_t y = 0; y < numspecies; ++y)
		{
			if (Area[x] > tolerance)
				R[x][y] = sqrt(M(x,y)/Area[x]);
			else
				R[x][y] = M(x,y);
		}
	}

	return R;
}
<commit_msg>grr<commit_after>#include <iomanip>
#include "GraphCalculator.hpp"
#include <blaze/Math.h>
#include <blaze/config/BLAS.h>

using MatrixXd = blaze::DynamicMatrix<double>;

void Realize(MatrixXd& A, const vector<Point>& P, long row, long N, double Cmx, double Cmy, long block, long num_cols_per_block)
{
	double dx = MaxNonZeroDistance(Cmx);
	double dy = MaxNonZeroDistance(Cmy);
	long dxi = long(dx+1);
	long dyi = long(dy+1);

// 	cout << "di = " << di << endl;

// 	cout << "Número de pixeles: " << 2*(dxi) << "*" << 2*dyi << " = " << 4*dxi*dyi << endl;

	for (const Point& p : P)
	{
		long minX = max(0L,long(p.x)-dxi);
		long maxX = min(N, long(p.x)+dxi);
		long minY = max(0L,long(p.y)-dyi);
		long maxY = min(N, long(p.y)+dyi);
		assert(maxX-minX > 0);
		assert(maxY-minY > 0);
		for (long x = minX; x < maxX; ++x)
		{
			for (long y = minY; y < maxY; ++y)
			{
				long index = x*N+y;
				index -= num_cols_per_block*block;

				if (index >= 0 && index < A.columns())
				{
					double XX = (p.x-x)*(p.x-x);
					double YY = (p.y-y)*(p.y-y);

					A(row,index) *= (1.0-exp(-Cmx*XX - Cmy*YY));
				}
			}
		}
	}

	for (size_t col = 0; col < A.columns(); ++col)
	{
		A(row,col) += 1.0;
	}
}

Matrix GraphCalculator::CalculateGraph()
{
	cout << "Using: " << blaze::getNumThreads() << " threads" << endl;
	blaze::setNumThreads( blaze::getNumThreads() );
	Chronometer T;
	size_t numspecies = E.size();
	vector<double> Area(numspecies,0.0);
	MatrixXd M(numspecies,numspecies,0.0);

	MatrixXd A(numspecies,num_cols_per_block,-1.0);
	for (size_t block = 0; block < num_full_blocks; ++block)
	{
		A = -1.0;
		#pragma omp parallel for
		for (size_t species = 0; species < numspecies; ++species)
		{
			Realize(A,E[species],species,grid,Cmx,Cmy, block, num_cols_per_block);

			for (size_t col = 0; col < A.columns(); ++col)
				Area[species] += A(species,col);
		}

		M += blaze::declsym( A * blaze::trans(A) );
        double time = T.Peek();

		cout << "Done with block " << block+1 << " of " << num_full_blocks+num_partial_blocks
             << ". Expected remaining time: " << time*double(num_full_blocks+num_partial_blocks)/(block+1) - time << 's' << endl;
	}

	if (num_partial_blocks)
	{
		MatrixXd A(numspecies,num_cols_partial_block,-1.0);
		#pragma omp parallel for
		for (size_t species = 0; species < numspecies; ++species)
		{
			Realize(A,E[species],species,grid,Cmx,Cmy, num_full_blocks, num_cols_per_block);

			for (size_t col = 0; col < A.columns(); ++col)
				Area[species] += A(species,col);
		}

		M += blaze::declsym( A * blaze::trans(A) );
		cout << "Done with block " << num_full_blocks+1 << " of " << num_full_blocks+num_partial_blocks << '!' << endl;
	}

	cout << "Total Time taken: " << T.Reset() << endl;

	Matrix R(numspecies,Row(numspecies));
	for (size_t x = 0; x < numspecies; ++x)
	{
		if (Area[x] <= tolerance)
		{
			cerr << "Area of X = 0! Increase grid size!!" << endl;
		}
		for (size_t y = 0; y < numspecies; ++y)
		{
			if (Area[x] > tolerance)
				R[x][y] = sqrt(M(x,y)/Area[x]);
			else
				R[x][y] = M(x,y);
		}
	}

	return R;
}
<|endoftext|>


<commit_before><commit_msg>fastuidraw/private/signals: minor header inclusion fix<commit_after><|endoftext|>


<commit_before><commit_msg>extra check<commit_after><|endoftext|>


<commit_before><commit_msg>Optimize threadpool.<commit_after><|endoftext|>


<commit_before><commit_msg>DeviceServiceImpl: remove redundant empty line<commit_after><|endoftext|>


<commit_before>#include <numpy_eigen/boost_python_headers.hpp>
#include <sm/kinematics/Transformation.hpp>
#include <sm/kinematics/UncertainTransformation.hpp>
#include <sm/boost/serialization.hpp>
#include <sm/python/boost_serialization_pickle.hpp>

template<typename T>
void loadobj( T * obj, std::string fname) {
    sm::boost_serialization::load( *obj, fname );
}

template<typename T>
void saveobj( T * obj, std::string fname) {
    sm::boost_serialization::save( *obj, fname );
}

void exportTransformation()
{
  using namespace sm::kinematics;
  using namespace boost::python;
  void (Transformation::*setRandom1)() = &Transformation::setRandom;
  void (Transformation::*setRandom2)( double , double ) = &Transformation::setRandom;

  def("interpolateTransformations", &interpolateTransformations);
  def("slerpTransformations", &slerpTransformations);

  class_<Transformation, boost::shared_ptr<Transformation> >("Transformation", init<>())
    .def(init<const Eigen::Matrix4d &>())
    .def(init<const Eigen::Vector4d &, const Eigen::Vector3d>())
      .def("save", &saveobj<Transformation>)
      .def("load", &loadobj<Transformation>)
    .def("T", &Transformation::T)
    .def("C", &Transformation::C)
      .def("t", &Transformation::t, return_value_policy<copy_const_reference>())
      .def("q", &Transformation::q, return_value_policy<copy_const_reference>())
    .def("T3x4", &Transformation::T3x4)
    .def("inverse", &Transformation::inverse)
    .def("setIdentity", &Transformation::setIdentity)
    .def("setRandom", setRandom1)
    .def("setRandom", setRandom2)
    .def(self * UncertainTransformation())
    .def(self * self)
    .def(self * UncertainHomogeneousPoint())
    .def(self * HomogeneousPoint())
      // Boost Python is not able to deal with this overloading
      // it only invokes the one you have last
      // For useability, I'll just add the Vector3d version.
      //.def(self * Eigen::Vector4d())
    .def(self * Eigen::Vector3d())
    .def("checkTransformationIsValid", &Transformation::checkTransformationIsValid)
    .def("S", &Transformation::S)
      .def_pickle( sm::python::pickle_suite<Transformation>() )
      ;

  typedef UncertainTransformation::covariance_t covariance_t;

  class_<UncertainTransformation, boost::shared_ptr<UncertainTransformation> >("UncertainTransformation", init<>())
    .def(init<const Eigen::Matrix4d &, const covariance_t & >())
    .def(init<const Eigen::Matrix4d &, double, double>())
    .def(init<const Eigen::Vector4d &, const Eigen::Vector3d, const covariance_t &>())
    .def(init<const Eigen::Vector4d &, const Eigen::Vector3d, double, double>())
    .def(init<const Transformation &, const covariance_t &>())
    .def(init<const Transformation &, double, double>())
    .def(init<const Transformation &>())
    .def(init<const Eigen::Matrix4d &>())
    .def(init<const Eigen::Vector4d &, const Eigen::Vector3d>())
      .def("save", &saveobj<UncertainTransformation>)
      .def("load", &loadobj<UncertainTransformation>)
    .def(self * self)
    .def(self * UncertainHomogeneousPoint())
    .def(self * HomogeneousPoint())
    .def(self * Transformation())
    //.def(self * Eigen::Vector3d())
    //.def(self * Eigen::Vector4d())
    .def("inverse",&UncertainTransformation::inverse)
    .def("U", &UncertainTransformation::U, return_value_policy<copy_const_reference>())
    .def("setU", &UncertainTransformation::setU)
    .def("setUOplus", &UncertainTransformation::setUOplus)
    .def("T", &Transformation::T)
    .def("C", &Transformation::C)
    .def("t", &Transformation::t, return_value_policy<copy_const_reference>())
    .def("q", &Transformation::q, return_value_policy<copy_const_reference>())
    .def("T3x4", &Transformation::T3x4)
    .def("inverse", &Transformation::inverse)
    .def("setIdentity", &Transformation::setIdentity)
    .def("setRandom", setRandom1)
    .def("setRandom", setRandom2)
    .def("S", &Transformation::S)

    ;

}
<commit_msg>Fixed a regression in the python interface caused by the ordering of python funcetion exports<commit_after>#include <numpy_eigen/boost_python_headers.hpp>
#include <sm/kinematics/Transformation.hpp>
#include <sm/kinematics/UncertainTransformation.hpp>
#include <sm/boost/serialization.hpp>
#include <sm/python/boost_serialization_pickle.hpp>

template<typename T>
void loadobj( T * obj, std::string fname) {
    sm::boost_serialization::load( *obj, fname );
}

template<typename T>
void saveobj( T * obj, std::string fname) {
    sm::boost_serialization::save( *obj, fname );
}

void exportTransformation()
{
  using namespace sm::kinematics;
  using namespace boost::python;
  void (Transformation::*setRandom1)() = &Transformation::setRandom;
  void (Transformation::*setRandom2)( double , double ) = &Transformation::setRandom;

  def("interpolateTransformations", &interpolateTransformations);
  def("slerpTransformations", &slerpTransformations);

  class_<Transformation, boost::shared_ptr<Transformation> >("Transformation", init<>())
    .def(init<const Eigen::Matrix4d &>())
    .def(init<const Eigen::Vector4d &, const Eigen::Vector3d>())
      .def("save", &saveobj<Transformation>)
      .def("load", &loadobj<Transformation>)
    .def("T", &Transformation::T)
    .def("C", &Transformation::C)
      .def("t", &Transformation::t, return_value_policy<copy_const_reference>())
      .def("q", &Transformation::q, return_value_policy<copy_const_reference>())
    .def("T3x4", &Transformation::T3x4)
    .def("inverse", &Transformation::inverse)
    .def("setIdentity", &Transformation::setIdentity)
    .def("setRandom", setRandom1)
    .def("setRandom", setRandom2)
      // Boost Python is not able to deal with this overloading
      // it only invokes the one you have last
      // For useability, I'll just add the Vector3d version.
      // NOTE: It is important to have the Eigen::Vector3d export
      // defined before the others. Apparently boost searches through
      // the list in reverse order looking for a match. If the
      // Eigen export is first, the others are disabled.
      //.def(self * Eigen::Vector4d())
      .def(self * Eigen::Vector3d())
    .def(self * UncertainTransformation())
    .def(self * self)
    .def(self * UncertainHomogeneousPoint())
    .def(self * HomogeneousPoint())
    .def("checkTransformationIsValid", &Transformation::checkTransformationIsValid)
    .def("S", &Transformation::S)
      .def_pickle( sm::python::pickle_suite<Transformation>() )
      ;

  typedef UncertainTransformation::covariance_t covariance_t;

  class_<UncertainTransformation, boost::shared_ptr<UncertainTransformation> >("UncertainTransformation", init<>())
    .def(init<const Eigen::Matrix4d &, const covariance_t & >())
    .def(init<const Eigen::Matrix4d &, double, double>())
    .def(init<const Eigen::Vector4d &, const Eigen::Vector3d, const covariance_t &>())
    .def(init<const Eigen::Vector4d &, const Eigen::Vector3d, double, double>())
    .def(init<const Transformation &, const covariance_t &>())
    .def(init<const Transformation &, double, double>())
    .def(init<const Transformation &>())
    .def(init<const Eigen::Matrix4d &>())
    .def(init<const Eigen::Vector4d &, const Eigen::Vector3d>())
      .def("save", &saveobj<UncertainTransformation>)
      .def("load", &loadobj<UncertainTransformation>)
    .def(self * self)
    .def(self * UncertainHomogeneousPoint())
    .def(self * HomogeneousPoint())
    .def(self * Transformation())
    //.def(self * Eigen::Vector3d())
    //.def(self * Eigen::Vector4d())
    .def("inverse",&UncertainTransformation::inverse)
    .def("U", &UncertainTransformation::U, return_value_policy<copy_const_reference>())
    .def("setU", &UncertainTransformation::setU)
    .def("setUOplus", &UncertainTransformation::setUOplus)
    .def("T", &Transformation::T)
    .def("C", &Transformation::C)
    .def("t", &Transformation::t, return_value_policy<copy_const_reference>())
    .def("q", &Transformation::q, return_value_policy<copy_const_reference>())
    .def("T3x4", &Transformation::T3x4)
    .def("inverse", &Transformation::inverse)
    .def("setIdentity", &Transformation::setIdentity)
    .def("setRandom", setRandom1)
    .def("setRandom", setRandom2)
    .def("S", &Transformation::S)

    ;

}
<|endoftext|>


<commit_before>// -*- Mode: C++; tab-width: 2; -*-
// vi: set ts=2:
//
// $Id: geometricControl.C,v 1.14 2003/09/20 15:36:35 amoll Exp $

#include <BALL/VIEW/WIDGETS/geometricControl.h>
#include <BALL/VIEW/KERNEL/message.h>
#include <BALL/VIEW/KERNEL/representation.h>
#include <BALL/VIEW/KERNEL/mainControl.h>
#include <BALL/VIEW/DIALOGS/colorMeshDialog.h>
#include <BALL/KERNEL/atom.h>
#include <BALL/KERNEL/atomContainer.h>
#include <BALL/VIEW/DIALOGS/displayProperties.h>
#include <qpopupmenu.h>
#include <qmenubar.h>

using std::endl;

namespace BALL
{
	namespace VIEW
	{

GeometricControl::SelectableListViewItem::SelectableListViewItem(QListView* parent, const QString& text, const QString& type, Representation* representation, GeometricControl& control)
	throw()
	: QCheckListItem(parent, text, QCheckListItem::CheckBox),
		representation_(representation),
		control_reference_(control)
{
	setText(1, type);
}

void GeometricControl::SelectableListViewItem::stateChange(bool)
	throw()
{
	control_reference_.selectedRepresentation(*representation_, isOn());
}

GeometricControl::GeometricControl(QWidget* parent, const char* name)
	throw()
		:	GenericControl(parent, name),
			context_menu_(),
			context_representation_(0),
			colorMeshDlg_(new ColorMeshDialog(this, "ColorMeshDialog"))
{
#ifdef BALL_VIEW_DEBUG
	Log.error() << "new GeometricControl " << this << std::endl;
#endif
	listview->addColumn("[visible] Type");
	listview->addColumn("Properties");
	listview->setColumnWidth(0, 60);
	listview->setColumnWidth(1, 60);

	connect(listview, SIGNAL(selectionChanged()), this, SLOT(updateSelection()));
}

GeometricControl::~GeometricControl()
	throw()
{
  #ifdef BALL_VIEW_DEBUG
	  Log.error() << "Destructing object " << this << " of class GeometricControl" << std::endl;
  #endif
}

void GeometricControl::addRepresentation(Representation& rep)
	throw()
{
	if (representation_to_item_.has(&rep))
	{
		Log.error() << "Tried to add an already inserted Representation in " << __FILE__ << __LINE__ << std::endl;
		return;
	}
	generateListViewItem_(rep);

	// update the view
	listview->triggerUpdate();
}

void GeometricControl::removeRepresentation(Representation& rep)
	throw()
{
	QListViewItem* item = representation_to_item_[&rep];
	if (item != 0)
	{
		delete item;
		representation_to_item_.erase(&rep);
		listview->triggerUpdate();
		return;
	}

	return;
}

void GeometricControl::updateRepresentation(Representation& rep)
	throw()
{
	QListViewItem* item = representation_to_item_[&rep];
	if (item == 0) return;

	QString properties = rep.getProperties().c_str();
	if (item->text(1) == properties) return;

	item->setText(0, getRepresentationName_(rep).c_str());
	item->setText(1, properties);

	listview->triggerUpdate();

	RepresentationMessage* message = new RepresentationMessage(&rep, RepresentationMessage::SELECTED);
	notify_(message);
	return;
}

void GeometricControl::onNotify(Message *message)
	throw()
{
#ifdef BALL_VIEW_DEBUG
	Log.error() << "GeometricControl " << this << " onNotify " << message << std::endl;
#endif
	if (!RTTI::isKindOf<RepresentationMessage> (*message))
	{
		return;
	}

	Representation* rep =	(RTTI::castTo<RepresentationMessage> (*message))->getRepresentation();
	if (rep == 0) return;

	switch ((RTTI::castTo<RepresentationMessage> (*message))->getType())
	{
		case RepresentationMessage::ADD:
			addRepresentation(*rep);
			return;

		case RepresentationMessage::REMOVE:
			removeRepresentation(*rep);
			return;

		case RepresentationMessage::UPDATE:
			updateRepresentation(*rep);
			return;

		default:
			Log.error() << "Unknown Type of Representation in " << __FILE__ << __LINE__ << std::endl;
	}
}

void GeometricControl::buildContextMenu(Representation& rep)
	throw()
{
	insertContextMenuEntry("Delete", this, SLOT(deleteRepresentation_()));
	insertContextMenuEntry("Properties", this, SLOT(modifyRepresentation_()));

	// This is used to provide the coloring for meshes...
	if ((rep.getModelType() == MODEL_SE_SURFACE || rep.getModelType() == MODEL_SA_SURFACE)
			&& rep.getGeometricObjects().size() > 0)
	{
		colorMeshDlg_->setMesh((Mesh*)*(rep.getGeometricObjects().begin()), &rep);
		insertContextMenuEntry("Color Surface", colorMeshDlg_, SLOT(show()));
	}
}

void GeometricControl::insertContextMenuEntry(const String& name, const QObject* receiver, const char* slot, int entry_ID, int accel)
	throw()
{
	context_menu_.insertItem(name.c_str(), receiver, slot, accel, entry_ID);
}

Representation* GeometricControl::getRepresentation(QListViewItem& item)
	throw()
{
	return ((SelectableListViewItem*) &item)->getRepresentation();
}

String GeometricControl::getRepresentationName_(const Representation& rep)
	throw()
{
	String name;
	if (!rep.hasProperty(Representation::PROPERTY__IS_COORDINATE_SYSTEM))
	{
		name = rep.getModelName().c_str();
	}
	else
	{
		name = "Coordinate System";
	}

	if (rep.getComposites().size() > 0)
	{
		const Composite* c_ptr = *rep.getComposites().begin();
		while (rep.getComposites().has(c_ptr->getParent()))
		{
			c_ptr = c_ptr->getParent();
		}

		String composite_name;
		if (RTTI::isKindOf<Atom>(*c_ptr))
		{
			if (c_ptr->getParent() != 0)
			{
				((Composite*)c_ptr->getParent())->host(information_);
				composite_name = information_.getName();
				composite_name += ":";
				composite_name += ((const Atom*) c_ptr)->getName();
			}
			else
			{
				composite_name = ((const Atom*) c_ptr)->getFullName();
			}
		}
		else
		{
			((Composite*)c_ptr)->host(information_);
			composite_name = information_.getName();
		}

		name = name + "  " + composite_name;

		if (rep.getComposites().size() > 1) name += "...";
	}

	return name;
}

void GeometricControl::generateListViewItem_(Representation& rep)
	throw()
{
	QString properties = rep.getProperties().c_str();
	// create a new list item
	SelectableListViewItem* new_item =
		new SelectableListViewItem(listview, getRepresentationName_(rep).c_str(), properties, &rep, *this);

	CHECK_PTR(new_item);
	new_item->setOn(true);

	representation_to_item_[&rep] = new_item;
}

void GeometricControl::deleteRepresentation_()
{
	if (context_representation_ == 0)  return;

	SceneMessage *scene_message = new SceneMessage(SceneMessage::REDRAW);
	if (context_representation_->hasProperty(Representation::PROPERTY__IS_COORDINATE_SYSTEM))
	{
		scene_message->setType(SceneMessage::REMOVE_COORDINATE_SYSTEM);
	}

	RepresentationMessage* message = new RepresentationMessage(context_representation_, RepresentationMessage::REMOVE);
	notify_(message);

	getMainControl()->getPrimitiveManager().remove(*context_representation_);
	removeRepresentation(*context_representation_);

	notify_(scene_message);
	setStatusbarText("Deleted representation.");
}

void GeometricControl::selectedRepresentation(Representation& representation, bool state)
{
	if (state != representation.hasProperty(Representation::PROPERTY__HIDDEN)) return;

	if (!state)
	{
		setStatusbarText("Hide representation.");
	}
	else
	{
		setStatusbarText("Show representation.");
	}

	representation.toggleProperty(Representation::PROPERTY__HIDDEN);

	SceneMessage *scene_message = new SceneMessage(SceneMessage::REDRAW);
	notify_(scene_message);
}

void GeometricControl::onContextMenu_(QListViewItem* item,  const QPoint& point, int /* column */)
{
	if (item == 0) return;

	// clear the context menu
	context_menu_.clear();

	// get Representation address
	Representation* rep = getRepresentation(*item);
	if (rep == 0) return;
	// create the context menu
	context_representation_ = rep;
	context_item_ = item;

	buildContextMenu(*rep);

	// is the context menu not empty
	if (context_menu_.count())
	{
		context_menu_.exec(point);
	}
}

void GeometricControl::modifyRepresentation_()
	throw()
{
	if (context_representation_ == 0) return;
	ShowDisplayPropertiesMessage* message = new ShowDisplayPropertiesMessage;
	notify_(message);
}

void GeometricControl::updateSelection()
{
	QListViewItem* item = 0;
	QListViewItemIterator it(listview);
	for (; it.current(); ++it)
	{
		if (it.current()->isSelected())
		{
			if (item == 0)
			{
				item = it.current();
			}
			else
			{
				return;
			}
		}
	}

	if (item == 0)
	{
		setStatusbarText("");
		colorMeshDlg_->setMesh(0,0);
		return;
	}

	Representation* rep = getRepresentation(*item);

	RepresentationMessage* message = new RepresentationMessage(rep, RepresentationMessage::SELECTED);
	notify_(message);

	if (rep->getComposites().size() == 0)
	{
		setStatusbarText("");
		return;
	}

	String name;
	const Composite* c_ptr = *rep->getComposites().begin();

	while (!c_ptr->isRoot())
	{
		if (RTTI::isKindOf<AtomContainer> (*c_ptr))
		{
			name = ((const AtomContainer*) c_ptr)->getName() + "->" + name;
		}
		else if (RTTI::isKindOf<Atom> (*c_ptr))
		{
			name = ((const Atom*) c_ptr)->getName() + "->" + name;
		}

		c_ptr = c_ptr->getParent();
	}

	if (RTTI::isKindOf<AtomContainer>(*c_ptr))
	{
		name = ((const AtomContainer*)c_ptr)->getProperty("FROM_FILE").getString() + "->" + name;
	}

	name.trimRight("->");

	if (rep->getComposites().size() > 1) name += "...";

	setStatusbarText("Representation from " + name);

	// update ColorMeshDialog if representation is a surface
	if ((rep->getModelType() == MODEL_SE_SURFACE || rep->getModelType() == MODEL_SA_SURFACE) &&
			rep->getGeometricObjects().size() > 0)
	{
		colorMeshDlg_->setMesh((Mesh*)*(rep->getGeometricObjects().begin()), rep);
	}
}

} } // namespaces
<commit_msg>added support for CONTOUR_SURFACE<commit_after>// -*- Mode: C++; tab-width: 2; -*-
// vi: set ts=2:
//
// $Id: geometricControl.C,v 1.15 2003/10/05 15:36:41 amoll Exp $

#include <BALL/VIEW/WIDGETS/geometricControl.h>
#include <BALL/VIEW/KERNEL/message.h>
#include <BALL/VIEW/KERNEL/representation.h>
#include <BALL/VIEW/KERNEL/mainControl.h>
#include <BALL/VIEW/DIALOGS/colorMeshDialog.h>
#include <BALL/KERNEL/atom.h>
#include <BALL/KERNEL/atomContainer.h>
#include <BALL/VIEW/DIALOGS/displayProperties.h>
#include <qpopupmenu.h>
#include <qmenubar.h>

using std::endl;

namespace BALL
{
	namespace VIEW
	{

GeometricControl::SelectableListViewItem::SelectableListViewItem(QListView* parent, const QString& text, const QString& type, Representation* representation, GeometricControl& control)
	throw()
	: QCheckListItem(parent, text, QCheckListItem::CheckBox),
		representation_(representation),
		control_reference_(control)
{
	setText(1, type);
}

void GeometricControl::SelectableListViewItem::stateChange(bool)
	throw()
{
	control_reference_.selectedRepresentation(*representation_, isOn());
}

GeometricControl::GeometricControl(QWidget* parent, const char* name)
	throw()
		:	GenericControl(parent, name),
			context_menu_(),
			context_representation_(0),
			colorMeshDlg_(new ColorMeshDialog(this, "ColorMeshDialog"))
{
#ifdef BALL_VIEW_DEBUG
	Log.error() << "new GeometricControl " << this << std::endl;
#endif
	listview->addColumn("[visible] Type");
	listview->addColumn("Properties");
	listview->setColumnWidth(0, 60);
	listview->setColumnWidth(1, 60);

	connect(listview, SIGNAL(selectionChanged()), this, SLOT(updateSelection()));
}

GeometricControl::~GeometricControl()
	throw()
{
  #ifdef BALL_VIEW_DEBUG
	  Log.error() << "Destructing object " << this << " of class GeometricControl" << std::endl;
  #endif
}

void GeometricControl::addRepresentation(Representation& rep)
	throw()
{
	if (representation_to_item_.has(&rep))
	{
		Log.error() << "Tried to add an already inserted Representation in " << __FILE__ << __LINE__ << std::endl;
		return;
	}
	generateListViewItem_(rep);

	// update the view
	listview->triggerUpdate();
}

void GeometricControl::removeRepresentation(Representation& rep)
	throw()
{
	QListViewItem* item = representation_to_item_[&rep];
	if (item != 0)
	{
		delete item;
		representation_to_item_.erase(&rep);
		listview->triggerUpdate();
		return;
	}

	return;
}

void GeometricControl::updateRepresentation(Representation& rep)
	throw()
{
	QListViewItem* item = representation_to_item_[&rep];
	if (item == 0) return;

	QString properties = rep.getProperties().c_str();
	if (item->text(1) == properties) return;

	item->setText(0, getRepresentationName_(rep).c_str());
	item->setText(1, properties);

	listview->triggerUpdate();

	RepresentationMessage* message = new RepresentationMessage(&rep, RepresentationMessage::SELECTED);
	notify_(message);
	return;
}

void GeometricControl::onNotify(Message *message)
	throw()
{
#ifdef BALL_VIEW_DEBUG
	Log.error() << "GeometricControl " << this << " onNotify " << message << std::endl;
#endif
	if (!RTTI::isKindOf<RepresentationMessage> (*message))
	{
		return;
	}

	Representation* rep =	(RTTI::castTo<RepresentationMessage> (*message))->getRepresentation();
	if (rep == 0) return;

	switch ((RTTI::castTo<RepresentationMessage> (*message))->getType())
	{
		case RepresentationMessage::ADD:
			addRepresentation(*rep);
			return;

		case RepresentationMessage::REMOVE:
			removeRepresentation(*rep);
			return;

		case RepresentationMessage::UPDATE:
			updateRepresentation(*rep);
			return;

		default:
			Log.error() << "Unknown Type of Representation in " << __FILE__ << __LINE__ << std::endl;
	}
}

void GeometricControl::buildContextMenu(Representation& rep)
	throw()
{
	insertContextMenuEntry("Delete", this, SLOT(deleteRepresentation_()));
	insertContextMenuEntry("Properties", this, SLOT(modifyRepresentation_()));

	// This is used to provide the coloring for meshes...
	if ((rep.getModelType() == MODEL_SE_SURFACE ||
			 rep.getModelType() == MODEL_SA_SURFACE ||
			 rep.getModelType() == MODEL_CONTOUR_SURFACE)
			&& rep.getGeometricObjects().size() > 0)
	{
		colorMeshDlg_->setMesh((Mesh*)*(rep.getGeometricObjects().begin()), &rep);
		insertContextMenuEntry("Color Surface", colorMeshDlg_, SLOT(show()));
	}
}

void GeometricControl::insertContextMenuEntry(const String& name, const QObject* receiver, const char* slot, int entry_ID, int accel)
	throw()
{
	context_menu_.insertItem(name.c_str(), receiver, slot, accel, entry_ID);
}

Representation* GeometricControl::getRepresentation(QListViewItem& item)
	throw()
{
	return ((SelectableListViewItem*) &item)->getRepresentation();
}

String GeometricControl::getRepresentationName_(const Representation& rep)
	throw()
{
	String name;
	if (!rep.hasProperty(Representation::PROPERTY__IS_COORDINATE_SYSTEM))
	{
		name = rep.getModelName().c_str();
	}
	else
	{
		name = "Coordinate System";
	}

	if (rep.getComposites().size() > 0)
	{
		const Composite* c_ptr = *rep.getComposites().begin();
		while (rep.getComposites().has(c_ptr->getParent()))
		{
			c_ptr = c_ptr->getParent();
		}

		String composite_name;
		if (RTTI::isKindOf<Atom>(*c_ptr))
		{
			if (c_ptr->getParent() != 0)
			{
				((Composite*)c_ptr->getParent())->host(information_);
				composite_name = information_.getName();
				composite_name += ":";
				composite_name += ((const Atom*) c_ptr)->getName();
			}
			else
			{
				composite_name = ((const Atom*) c_ptr)->getFullName();
			}
		}
		else
		{
			((Composite*)c_ptr)->host(information_);
			composite_name = information_.getName();
		}

		name = name + "  " + composite_name;

		if (rep.getComposites().size() > 1) name += "...";
	}

	return name;
}

void GeometricControl::generateListViewItem_(Representation& rep)
	throw()
{
	QString properties = rep.getProperties().c_str();
	// create a new list item
	SelectableListViewItem* new_item =
		new SelectableListViewItem(listview, getRepresentationName_(rep).c_str(), properties, &rep, *this);

	CHECK_PTR(new_item);
	new_item->setOn(true);

	representation_to_item_[&rep] = new_item;
}

void GeometricControl::deleteRepresentation_()
{
	if (context_representation_ == 0)  return;

	SceneMessage *scene_message = new SceneMessage(SceneMessage::REDRAW);
	if (context_representation_->hasProperty(Representation::PROPERTY__IS_COORDINATE_SYSTEM))
	{
		scene_message->setType(SceneMessage::REMOVE_COORDINATE_SYSTEM);
	}

	RepresentationMessage* message = new RepresentationMessage(context_representation_, RepresentationMessage::REMOVE);
	notify_(message);

	getMainControl()->getPrimitiveManager().remove(*context_representation_);
	removeRepresentation(*context_representation_);

	notify_(scene_message);
	setStatusbarText("Deleted representation.");
}

void GeometricControl::selectedRepresentation(Representation& representation, bool state)
{
	if (state != representation.hasProperty(Representation::PROPERTY__HIDDEN)) return;

	if (!state)
	{
		setStatusbarText("Hide representation.");
	}
	else
	{
		setStatusbarText("Show representation.");
	}

	representation.toggleProperty(Representation::PROPERTY__HIDDEN);

	SceneMessage *scene_message = new SceneMessage(SceneMessage::REDRAW);
	notify_(scene_message);
}

void GeometricControl::onContextMenu_(QListViewItem* item,  const QPoint& point, int /* column */)
{
	if (item == 0) return;

	// clear the context menu
	context_menu_.clear();

	// get Representation address
	Representation* rep = getRepresentation(*item);
	if (rep == 0) return;
	// create the context menu
	context_representation_ = rep;
	context_item_ = item;

	buildContextMenu(*rep);

	// is the context menu not empty
	if (context_menu_.count())
	{
		context_menu_.exec(point);
	}
}

void GeometricControl::modifyRepresentation_()
	throw()
{
	if (context_representation_ == 0) return;
	ShowDisplayPropertiesMessage* message = new ShowDisplayPropertiesMessage;
	notify_(message);
}

void GeometricControl::updateSelection()
{
	QListViewItem* item = 0;
	QListViewItemIterator it(listview);
	for (; it.current(); ++it)
	{
		if (it.current()->isSelected())
		{
			if (item == 0)
			{
				item = it.current();
			}
			else
			{
				return;
			}
		}
	}

	if (item == 0)
	{
		setStatusbarText("");
		colorMeshDlg_->setMesh(0,0);
		return;
	}

	Representation* rep = getRepresentation(*item);

	RepresentationMessage* message = new RepresentationMessage(rep, RepresentationMessage::SELECTED);
	notify_(message);

	if (rep->getComposites().size() == 0)
	{
		setStatusbarText("");
		return;
	}

	String name;
	const Composite* c_ptr = *rep->getComposites().begin();

	while (!c_ptr->isRoot())
	{
		if (RTTI::isKindOf<AtomContainer> (*c_ptr))
		{
			name = ((const AtomContainer*) c_ptr)->getName() + "->" + name;
		}
		else if (RTTI::isKindOf<Atom> (*c_ptr))
		{
			name = ((const Atom*) c_ptr)->getName() + "->" + name;
		}

		c_ptr = c_ptr->getParent();
	}

	if (RTTI::isKindOf<AtomContainer>(*c_ptr))
	{
		name = ((const AtomContainer*)c_ptr)->getProperty("FROM_FILE").getString() + "->" + name;
	}

	name.trimRight("->");

	if (rep->getComposites().size() > 1) name += "...";

	setStatusbarText("Representation from " + name);

	// update ColorMeshDialog if representation is a surface
	if ((rep->getModelType() == MODEL_SE_SURFACE || rep->getModelType() == MODEL_SA_SURFACE) &&
			rep->getGeometricObjects().size() > 0)
	{
		colorMeshDlg_->setMesh((Mesh*)*(rep->getGeometricObjects().begin()), rep);
	}
}

} } // namespaces
<|endoftext|>


<commit_before>/**********************************************************************
 *
 * GEOS - Geometry Engine Open Source
 * http://geos.osgeo.org
 *
 * Copyright (C) 2010 Sandro Santilli <strk@kbt.io>
 * Copyright (C) 2005-2006 Refractions Research Inc.
 * Copyright (C) 2001-2002 Vivid Solutions Inc.
 *
 * This is free software; you can redistribute and/or modify it under
 * the terms of the GNU Lesser General Public Licence as published
 * by the Free Software Foundation.
 * See the COPYING file for more information.
 *
 **********************************************************************
 *
 * Last port: operation/polygonize/Polygonizer.java rev. 1.6 (JTS-1.10)
 *
 **********************************************************************/

#include <geos/geom/util/Densifier.h>
#include <geos/geom/CoordinateSequenceFactory.h>
#include <geos/geom/CoordinateList.h>
#include <geos/geom/Geometry.h>
#include <geos/geom/GeometryFactory.h>
#include <geos/geom/MultiPoint.h>
#include <geos/geom/MultiPolygon.h>
#include <geos/geom/MultiLineString.h>
#include <geos/geom/CoordinateSequence.h>
#include <geos/geom/CoordinateSequenceFactory.h>
#include <geos/geom/PrecisionModel.h>
#include <geos/geom/Polygon.h>
#include <geos/geom/Point.h>
#include <geos/geom/LineString.h>
#include <geos/geom/LinearRing.h>
#include <geos/geom/LineSegment.h>
#include <geos/geom/GeometryCollection.h>
#include <geos/util/Interrupt.h>
#include <geos/util/IllegalArgumentException.h>

#include <vector>

using namespace geos::geom;
using namespace geos::geom::util;

namespace geos {
namespace geom { // geos.geom
namespace util { // geos.geom.util

/* geom::util::Densifier::DensifyTransformer */
Densifier::DensifyTransformer::DensifyTransformer(double distanceTolerance):
	distanceTolerance(distanceTolerance)
{}

CoordinateSequence::Ptr
Densifier::DensifyTransformer::transformCoordinates(const CoordinateSequence *coords, const Geometry *parent)
{
	Coordinate::Vect emptyPts;
	Coordinate::Vect inputPts;
	coords->toVector(inputPts);
	std::unique_ptr<Coordinate::Vect> newPts = Densifier::densifyPoints(inputPts, distanceTolerance, parent->getPrecisionModel());
	if (const LineString* ls=dynamic_cast<const LineString*>(parent))
	{
		if (ls->getNumPoints() <= 1)
			newPts->clear();
	}
	CoordinateSequence::Ptr csp(factory->getCoordinateSequenceFactory()->create(newPts.release()));
	return csp;
}

Geometry::Ptr
Densifier::DensifyTransformer::transformPolygon(const Polygon *geom, const Geometry *parent)
{
	Geometry::Ptr roughGeom = GeometryTransformer::transformPolygon(geom, parent);
	// don't try and correct if the parent is going to do this
	if (const MultiPolygon* mp=dynamic_cast<const MultiPolygon*>(parent) )
	{
		return roughGeom;
	}
	Geometry::Ptr validGeom(createValidArea(roughGeom.get()));
	return validGeom;
}

Geometry::Ptr
Densifier::DensifyTransformer::transformMultiPolygon(const MultiPolygon *geom, const Geometry *parent)
{
	Geometry::Ptr roughGeom = GeometryTransformer::transformMultiPolygon(geom, parent);
	Geometry::Ptr validGeom(createValidArea(roughGeom.get()));
	return validGeom;
}

Geometry *
Densifier::DensifyTransformer::createValidArea(const Geometry *roughAreaGeom)
{
	return roughAreaGeom->buffer(0.0);
}

/* util::Densifier */

Densifier::Densifier(const Geometry *geom):
	inputGeom(geom)
{}

std::unique_ptr<Coordinate::Vect>
Densifier::densifyPoints(const Coordinate::Vect pts, double distanceTolerance, const PrecisionModel *precModel)
{
	geom::LineSegment seg;
	geom::CoordinateList coordList;
	geom::CoordinateList::iterator it = coordList.begin();
	for (int i = 0; i < pts.size()-1; i++)
	{
		seg.p0 = pts[i];
		seg.p1 = pts[i+1];
		coordList.insert(coordList.end(), seg.p0, false);
		double len = seg.getLength();
		int densifiedSegCount = (int) (len / distanceTolerance) + 1;
		if (densifiedSegCount > 1)
		{
			double densifiedSegLen = len / densifiedSegCount;
			for (int j = 1; j < densifiedSegCount; j++)
			{
				double segFract = (j * densifiedSegLen) / len;
				Coordinate p;
				seg.pointAlong(segFract, p);
				precModel->makePrecise(p);
				coordList.insert(coordList.end(), p, false);
			}
		}
	}
	coordList.insert(coordList.end(), pts[pts.size()-1], false);
	return coordList.toCoordinateArray();
}

/**
 * Densifies a geometry using a given distance tolerance,
 * and respecting the input geometry's {@link PrecisionModel}.
 *
 * @param geom the geometry to densify
 * @param distanceTolerance the distance tolerance to densify
 * @return the densified geometry
 */
Geometry::Ptr
Densifier::densify(const Geometry *geom, double distanceTolerance)
{
	util::Densifier densifier(geom);
	densifier.setDistanceTolerance(distanceTolerance);
	return densifier.getResultGeometry();
}

void
Densifier::setDistanceTolerance(double tol)
{
	if (tol <= 0.0)
		throw geos::util::IllegalArgumentException("Tolerance must be positive");
	distanceTolerance = tol;
}

Geometry::Ptr
Densifier::getResultGeometry() const
{
	DensifyTransformer dt(distanceTolerance);
	return dt.transform(inputGeom);
}

} // namespace geos.geom.util
} // namespace geos.geom
} // namespace geos
<commit_msg>Change coordinate list access to an iterator pattern<commit_after>/**********************************************************************
 *
 * GEOS - Geometry Engine Open Source
 * http://geos.osgeo.org
 *
 * Copyright (C) 2010 Sandro Santilli <strk@kbt.io>
 * Copyright (C) 2005-2006 Refractions Research Inc.
 * Copyright (C) 2001-2002 Vivid Solutions Inc.
 *
 * This is free software; you can redistribute and/or modify it under
 * the terms of the GNU Lesser General Public Licence as published
 * by the Free Software Foundation.
 * See the COPYING file for more information.
 *
 **********************************************************************
 *
 * Last port: operation/polygonize/Polygonizer.java rev. 1.6 (JTS-1.10)
 *
 **********************************************************************/

#include <geos/geom/util/Densifier.h>
#include <geos/geom/CoordinateSequenceFactory.h>
#include <geos/geom/CoordinateList.h>
#include <geos/geom/Geometry.h>
#include <geos/geom/GeometryFactory.h>
#include <geos/geom/MultiPoint.h>
#include <geos/geom/MultiPolygon.h>
#include <geos/geom/MultiLineString.h>
#include <geos/geom/CoordinateSequence.h>
#include <geos/geom/CoordinateSequenceFactory.h>
#include <geos/geom/PrecisionModel.h>
#include <geos/geom/Polygon.h>
#include <geos/geom/Point.h>
#include <geos/geom/LineString.h>
#include <geos/geom/LinearRing.h>
#include <geos/geom/LineSegment.h>
#include <geos/geom/GeometryCollection.h>
#include <geos/util/Interrupt.h>
#include <geos/util/IllegalArgumentException.h>

#include <vector>

using namespace geos::geom;
using namespace geos::geom::util;

namespace geos {
namespace geom { // geos.geom
namespace util { // geos.geom.util

/* geom::util::Densifier::DensifyTransformer */
Densifier::DensifyTransformer::DensifyTransformer(double distanceTolerance):
	distanceTolerance(distanceTolerance)
{}

CoordinateSequence::Ptr
Densifier::DensifyTransformer::transformCoordinates(const CoordinateSequence *coords, const Geometry *parent)
{
	Coordinate::Vect emptyPts;
	Coordinate::Vect inputPts;
	coords->toVector(inputPts);
	std::unique_ptr<Coordinate::Vect> newPts = Densifier::densifyPoints(inputPts, distanceTolerance, parent->getPrecisionModel());
	if (const LineString* ls=dynamic_cast<const LineString*>(parent))
	{
		if (ls->getNumPoints() <= 1)
			newPts->clear();
	}
	CoordinateSequence::Ptr csp(factory->getCoordinateSequenceFactory()->create(newPts.release()));
	return csp;
}

Geometry::Ptr
Densifier::DensifyTransformer::transformPolygon(const Polygon *geom, const Geometry *parent)
{
	Geometry::Ptr roughGeom = GeometryTransformer::transformPolygon(geom, parent);
	// don't try and correct if the parent is going to do this
	if (const MultiPolygon* mp=dynamic_cast<const MultiPolygon*>(parent) )
	{
		return roughGeom;
	}
	Geometry::Ptr validGeom(createValidArea(roughGeom.get()));
	return validGeom;
}

Geometry::Ptr
Densifier::DensifyTransformer::transformMultiPolygon(const MultiPolygon *geom, const Geometry *parent)
{
	Geometry::Ptr roughGeom = GeometryTransformer::transformMultiPolygon(geom, parent);
	Geometry::Ptr validGeom(createValidArea(roughGeom.get()));
	return validGeom;
}

Geometry *
Densifier::DensifyTransformer::createValidArea(const Geometry *roughAreaGeom)
{
	return roughAreaGeom->buffer(0.0);
}

/* util::Densifier */

Densifier::Densifier(const Geometry *geom):
	inputGeom(geom)
{}

std::unique_ptr<Coordinate::Vect>
Densifier::densifyPoints(const Coordinate::Vect pts, double distanceTolerance, const PrecisionModel *precModel)
{
	geom::LineSegment seg;
	geom::CoordinateList coordList;
	geom::CoordinateList::iterator it = coordList.begin();

	for (Coordinate::Vect::const_iterator it=pts.begin(), itEnd=pts.end()-1; it < itEnd; ++it)
	{
		seg.p0 = *it;
		seg.p1 = *(it+1);
		coordList.insert(coordList.end(), seg.p0, false);
		double len = seg.getLength();
		int densifiedSegCount = (int) (len / distanceTolerance) + 1;
		if (densifiedSegCount > 1)
		{
			double densifiedSegLen = len / densifiedSegCount;
			for (int j = 1; j < densifiedSegCount; j++)
			{
				double segFract = (j * densifiedSegLen) / len;
				Coordinate p;
				seg.pointAlong(segFract, p);
				precModel->makePrecise(p);
				coordList.insert(coordList.end(), p, false);
			}
		}
	}
	coordList.insert(coordList.end(), pts[pts.size()-1], false);
	return coordList.toCoordinateArray();
}

/**
 * Densifies a geometry using a given distance tolerance,
 * and respecting the input geometry's {@link PrecisionModel}.
 *
 * @param geom the geometry to densify
 * @param distanceTolerance the distance tolerance to densify
 * @return the densified geometry
 */
Geometry::Ptr
Densifier::densify(const Geometry *geom, double distanceTolerance)
{
	util::Densifier densifier(geom);
	densifier.setDistanceTolerance(distanceTolerance);
	return densifier.getResultGeometry();
}

void
Densifier::setDistanceTolerance(double tol)
{
	if (tol <= 0.0)
		throw geos::util::IllegalArgumentException("Tolerance must be positive");
	distanceTolerance = tol;
}

Geometry::Ptr
Densifier::getResultGeometry() const
{
	DensifyTransformer dt(distanceTolerance);
	return dt.transform(inputGeom);
}

} // namespace geos.geom.util
} // namespace geos.geom
} // namespace geos
<|endoftext|>


<commit_before>#include "xchainer/gradient_check.h"

#include <algorithm>
#include <memory>
#include <string>
#include <vector>

#include <gtest/gtest-spi.h>
#include <gtest/gtest.h>
#include <gsl/gsl>

#include "xchainer/array.h"
#include "xchainer/array_repr.h"
#include "xchainer/check_backward.h"
#include "xchainer/device.h"
#include "xchainer/op_node.h"
#include "xchainer/shape.h"

namespace xchainer {
namespace {

std::vector<Array> CorrectUnaryFunc(const std::vector<Array>& inputs) {
    const Array& lhs = inputs[0];

    Array out = Array::EmptyLike(lhs);
    out.set_requires_grad(lhs.requires_grad());

    if (out.requires_grad()) {
        std::shared_ptr<ArrayNode> lhs_node = lhs.mutable_node();
        std::shared_ptr<ArrayNode> out_node = out.RenewNode();
        int64_t out_rank = lhs_node->rank();
        auto next_nodes = std::vector<std::shared_ptr<ArrayNode>>{lhs_node};
        std::function<Array(const Array&)> empty_func;
        auto lhs_func = lhs.requires_grad() ? [lhs](const Array& gout) { return gout * lhs; } : empty_func;
        auto backward_functions = std::vector<std::function<Array(const Array&)>>{lhs_func};
        std::shared_ptr<OpNode> op_node = std::make_shared<OpNode>("correct_unary", out_rank, next_nodes, backward_functions);
        out_node->set_next_node(op_node);
        out_node->set_rank(out_rank + 1);
    }

    VisitDtype(lhs.dtype(), [&](auto pt) {
        using T = typename decltype(pt)::type;

        int64_t total_size = lhs.total_size();
        auto* ldata = static_cast<const T*>(lhs.data().get());
        auto* odata = static_cast<T*>(out.data().get());
        auto half = static_cast<T>(0.5);

        for (int64_t i = 0; i < total_size; i++) {
            odata[i] = ldata[i] * ldata[i] * half;
        }
    });

    return {out};
}

std::vector<Array> BrokenUnaryFunc(const std::vector<Array>& inputs) {
    const Array& lhs = inputs[0];

    Array out = Array::EmptyLike(lhs);
    out.set_requires_grad(lhs.requires_grad());

    if (out.requires_grad()) {
        std::shared_ptr<ArrayNode> lhs_node = lhs.mutable_node();
        std::shared_ptr<ArrayNode> out_node = out.RenewNode();
        int64_t out_rank = lhs_node->rank();
        auto next_nodes = std::vector<std::shared_ptr<ArrayNode>>{lhs_node};
        std::function<Array(const Array&)> empty_func;
        auto lhs_func = lhs.requires_grad() ? [](const Array& gout) { return gout * gout; } : empty_func;
        auto backward_functions = std::vector<std::function<Array(const Array&)>>{lhs_func};
        std::shared_ptr<OpNode> op_node = std::make_shared<OpNode>("broken_unary", out_rank, next_nodes, backward_functions);
        out_node->set_next_node(op_node);
        out_node->set_rank(out_rank + 1);
    }

    VisitDtype(lhs.dtype(), [&](auto pt) {
        using T = typename decltype(pt)::type;

        int64_t total_size = lhs.total_size();
        auto* ldata = static_cast<const T*>(lhs.data().get());
        auto* odata = static_cast<T*>(out.data().get());

        for (int64_t i = 0; i < total_size; i++) {
            odata[i] = ldata[i];
        }
    });

    return {out};
}

std::vector<Array> CorrectBinaryFunc(const std::vector<Array>& inputs) {
    const Array& lhs = inputs[0];
    const Array& rhs = inputs[1];

    CheckEqual(lhs.dtype(), rhs.dtype());
    CheckEqual(lhs.shape(), rhs.shape());

    Array out = Array::EmptyLike(lhs);
    out.set_requires_grad(lhs.requires_grad() || rhs.requires_grad());

    if (out.requires_grad()) {
        std::shared_ptr<ArrayNode> lhs_node = lhs.mutable_node();
        std::shared_ptr<ArrayNode> rhs_node = rhs.mutable_node();
        std::shared_ptr<ArrayNode> out_node = out.RenewNode();
        int64_t out_rank = std::max(lhs_node->rank(), rhs_node->rank());
        auto next_nodes = std::vector<std::shared_ptr<ArrayNode>>{lhs_node, rhs_node};
        std::function<Array(const Array&)> empty_func;
        auto lhs_func = lhs.requires_grad() ? [rhs](const Array& gout) { return gout * rhs; } : empty_func;
        auto rhs_func = rhs.requires_grad() ? [lhs](const Array& gout) { return gout * lhs; } : empty_func;
        auto backward_functions = std::vector<std::function<Array(const Array&)>>{lhs_func, rhs_func};
        std::shared_ptr<OpNode> op_node = std::make_shared<OpNode>("correct_binary", out_rank, next_nodes, backward_functions);
        out_node->set_next_node(op_node);
        out_node->set_rank(out_rank + 1);
    }

    VisitDtype(lhs.dtype(), [&](auto pt) {
        using T = typename decltype(pt)::type;

        int64_t total_size = lhs.total_size();
        auto* ldata = static_cast<const T*>(lhs.data().get());
        auto* rdata = static_cast<const T*>(rhs.data().get());
        auto* odata = static_cast<T*>(out.data().get());

        for (int64_t i = 0; i < total_size; i++) {
            odata[i] = ldata[i] * rdata[i];
        }
    });

    return {out};
}

std::vector<Array> BrokenBinaryFunc(const std::vector<Array>& inputs) {
    const Array& lhs = inputs[0];
    const Array& rhs = inputs[1];

    CheckEqual(lhs.dtype(), rhs.dtype());
    CheckEqual(lhs.shape(), rhs.shape());

    Array out = Array::EmptyLike(lhs);
    out.set_requires_grad(lhs.requires_grad() || rhs.requires_grad());

    if (out.requires_grad()) {
        std::shared_ptr<ArrayNode> lhs_node = lhs.mutable_node();
        std::shared_ptr<ArrayNode> rhs_node = rhs.mutable_node();
        std::shared_ptr<ArrayNode> out_node = out.RenewNode();
        int64_t out_rank = std::max(lhs_node->rank(), rhs_node->rank());
        auto next_nodes = std::vector<std::shared_ptr<ArrayNode>>{lhs_node, rhs_node};
        std::function<Array(const Array&)> empty_func;
        auto lhs_func = lhs.requires_grad() ? [rhs](const Array& gout) { return gout + rhs; } : empty_func;
        auto rhs_func = rhs.requires_grad() ? [lhs](const Array& gout) { return gout + lhs; } : empty_func;
        auto backward_functions = std::vector<std::function<Array(const Array&)>>{lhs_func, rhs_func};
        std::shared_ptr<OpNode> op_node = std::make_shared<OpNode>("test_mul", out_rank, next_nodes, backward_functions);
        out_node->set_next_node(op_node);
        out_node->set_rank(out_rank + 1);
    }

    VisitDtype(lhs.dtype(), [&](auto pt) {
        using T = typename decltype(pt)::type;

        int64_t total_size = lhs.total_size();
        auto* ldata = static_cast<const T*>(lhs.data().get());
        auto* rdata = static_cast<const T*>(rhs.data().get());
        auto* odata = static_cast<T*>(out.data().get());

        for (int64_t i = 0; i < total_size; i++) {
            odata[i] = ldata[i] * rdata[i];
        }
    });

    return {out};
}

class CheckBackwardTest : public ::testing::Test {
public:
    template <typename T>
    Array MakeArray(const Shape& shape, const T* data) {
        int64_t size = shape.total_size();
        auto a = std::make_unique<T[]>(size);
        std::copy(data, data + size, a.get());
        return Array::FromBuffer(shape, TypeToDtype<T>, std::move(a));
    }

    void CheckCorrectBackwardComputation(const std::vector<Array>& inputs, const std::vector<Array>& grad_outputs,
                                         const std::vector<Array>& eps, double atol, double rtol) {
        auto fprop = inputs.size() == 1 ? &CorrectUnaryFunc : &CorrectBinaryFunc;
        CheckBackwardComputation(fprop, inputs, grad_outputs, eps, atol, rtol);
    }

    void CheckBrokenBackwardComputation(const std::vector<Array>& inputs, const std::vector<Array>& grad_outputs,
                                        const std::vector<Array>& eps, double atol, double rtol) {
        auto fprop = inputs.size() == 1 ? &BrokenUnaryFunc : &BrokenBinaryFunc;
        if (std::any_of(inputs.begin(), inputs.end(), [](const Array& input) { return input.requires_grad(); })) {
            // Catch the gtest failure expected to be generated by CheckBackwardComputation but without failing this test
            EXPECT_NONFATAL_FAILURE(CheckBackwardComputation(fprop, inputs, grad_outputs, eps, atol, rtol), "Backward check failure");
        } else {
            // We cannot expect any failures in case none of the input std::vector<Array> require gradients
            CheckBackwardComputation(fprop, inputs, grad_outputs, eps, atol, rtol);
        }
    }
};

TEST_F(CheckBackwardTest, UnaryBackward) {
    Shape shape{2, 3};

    float data[]{1.f, 2.f, 3.f, 4.f, 5.f, 6.f};
    float eps_data[]{1.f, 2.f, 3.f, 4.f, 5.f, 6.f};
    float grad_output_data[]{1.f, -2.f, 3.f, 0.f, 5.2f, 6.f};

    double atol = 1e-5;
    double rtol = 1e-4;

    {
        std::vector<Array> inputs = {MakeArray(shape, data)};
        std::vector<Array> eps = {MakeArray(shape, eps_data)};
        std::vector<Array> grad_outputs = {MakeArray(shape, grad_output_data)};
        inputs[0].set_requires_grad(false);
        CheckCorrectBackwardComputation(inputs, grad_outputs, eps, atol, rtol);
    }
    {
        std::vector<Array> inputs = {MakeArray(shape, data)};
        std::vector<Array> eps = {MakeArray(shape, eps_data)};
        std::vector<Array> grad_outputs = {MakeArray(shape, grad_output_data)};
        inputs[0].set_requires_grad(false);
        CheckBrokenBackwardComputation(inputs, grad_outputs, eps, atol, rtol);
    }
    {
        std::vector<Array> inputs = {MakeArray(shape, data)};
        std::vector<Array> eps = {MakeArray(shape, eps_data)};
        std::vector<Array> grad_outputs = {MakeArray(shape, grad_output_data)};
        inputs[0].set_requires_grad(true);
        CheckCorrectBackwardComputation(inputs, grad_outputs, eps, atol, rtol);
    }
    {
        std::vector<Array> inputs = {MakeArray(shape, data)};
        std::vector<Array> eps = {MakeArray(shape, eps_data)};
        std::vector<Array> grad_outputs = {MakeArray(shape, grad_output_data)};
        inputs[0].set_requires_grad(true);
        CheckBrokenBackwardComputation(inputs, grad_outputs, eps, atol, rtol);
    }
}

TEST_F(CheckBackwardTest, BinaryBackward) {
    Shape shape{2, 3};

    float data1[]{1.f, 2.f, 3.f, 4.f, 5.f, 6.f};
    float data2[]{0.f, 1.f, 2.f, 3.f, 4.f, 5.f};
    float eps_data1[]{1.f, 2.f, 3.f, 4.f, 5.f, 6.f};
    float eps_data2[]{3.f, -2.f, 3.f, -4.f, 3.2f, 0.9f};
    float grad_output_data[]{1.f, -2.f, 3.f, 0.f, 5.2f, 6.f};

    double atol = 1e-5;
    double rtol = 1e-4;

    const int nperm = 4;
    bool requires_grads[nperm][2]{{false, false}, {false, true}, {true, false}, {true, true}};

    for (int i = 0; i < nperm; ++i) {
        {
            std::vector<Array> inputs = {MakeArray(shape, data1), MakeArray(shape, data2)};
            std::vector<Array> eps = {MakeArray(shape, eps_data1), MakeArray(shape, eps_data2)};
            std::vector<Array> grad_outputs = {MakeArray(shape, grad_output_data)};
            inputs[0].set_requires_grad(requires_grads[i][0]);
            inputs[1].set_requires_grad(requires_grads[i][1]);
            CheckCorrectBackwardComputation(inputs, grad_outputs, eps, atol, rtol);
        }
        {
            std::vector<Array> inputs = {MakeArray(shape, data1), MakeArray(shape, data2)};
            std::vector<Array> eps = {MakeArray(shape, eps_data1), MakeArray(shape, eps_data2)};
            std::vector<Array> grad_outputs = {MakeArray(shape, grad_output_data)};
            inputs[0].set_requires_grad(requires_grads[i][0]);
            inputs[1].set_requires_grad(requires_grads[i][1]);
            CheckBrokenBackwardComputation(inputs, grad_outputs, eps, atol, rtol);
        }
    }
}

}  // namespace
}  // namespace xchainer
<commit_msg>Remove redundant functions and cosmetic renamings<commit_after>#include "xchainer/gradient_check.h"

#include <algorithm>
#include <memory>
#include <string>
#include <vector>

#include <gtest/gtest-spi.h>
#include <gtest/gtest.h>
#include <gsl/gsl>

#include "xchainer/array.h"
#include "xchainer/array_repr.h"
#include "xchainer/check_backward.h"
#include "xchainer/device.h"
#include "xchainer/op_node.h"
#include "xchainer/shape.h"

namespace xchainer {
namespace {

std::vector<Array> WrongBackwardUnaryFunc(const std::vector<Array>& inputs) {
    const Array& lhs = inputs[0];

    Array out = Array::EmptyLike(lhs);
    out.set_requires_grad(lhs.requires_grad());

    if (out.requires_grad()) {
        std::shared_ptr<ArrayNode> lhs_node = lhs.mutable_node();
        std::shared_ptr<ArrayNode> out_node = out.RenewNode();
        int64_t out_rank = lhs_node->rank();
        auto next_nodes = std::vector<std::shared_ptr<ArrayNode>>{lhs_node};
        std::function<Array(const Array&)> empty_func;
        auto lhs_func = lhs.requires_grad() ? [](const Array& gout) { return gout * gout; } : empty_func;
        auto backward_functions = std::vector<std::function<Array(const Array&)>>{lhs_func};
        std::shared_ptr<OpNode> op_node = std::make_shared<OpNode>("broken_unary", out_rank, next_nodes, backward_functions);
        out_node->set_next_node(op_node);
        out_node->set_rank(out_rank + 1);
    }

    VisitDtype(lhs.dtype(), [&](auto pt) {
        using T = typename decltype(pt)::type;

        int64_t total_size = lhs.total_size();
        auto* ldata = static_cast<const T*>(lhs.data().get());
        auto* odata = static_cast<T*>(out.data().get());

        for (int64_t i = 0; i < total_size; i++) {
            odata[i] = ldata[i];
        }
    });

    return {out};
}

std::vector<Array> WrongBackwardBinaryFunc(const std::vector<Array>& inputs) {
    const Array& lhs = inputs[0];
    const Array& rhs = inputs[1];

    CheckEqual(lhs.dtype(), rhs.dtype());
    CheckEqual(lhs.shape(), rhs.shape());

    Array out = Array::EmptyLike(lhs);
    out.set_requires_grad(lhs.requires_grad() || rhs.requires_grad());

    if (out.requires_grad()) {
        std::shared_ptr<ArrayNode> lhs_node = lhs.mutable_node();
        std::shared_ptr<ArrayNode> rhs_node = rhs.mutable_node();
        std::shared_ptr<ArrayNode> out_node = out.RenewNode();
        int64_t out_rank = std::max(lhs_node->rank(), rhs_node->rank());
        auto next_nodes = std::vector<std::shared_ptr<ArrayNode>>{lhs_node, rhs_node};
        std::function<Array(const Array&)> empty_func;
        auto lhs_func = lhs.requires_grad() ? [rhs](const Array& gout) { return gout + rhs; } : empty_func;
        auto rhs_func = rhs.requires_grad() ? [lhs](const Array& gout) { return gout + lhs; } : empty_func;
        auto backward_functions = std::vector<std::function<Array(const Array&)>>{lhs_func, rhs_func};
        std::shared_ptr<OpNode> op_node = std::make_shared<OpNode>("test_mul", out_rank, next_nodes, backward_functions);
        out_node->set_next_node(op_node);
        out_node->set_rank(out_rank + 1);
    }

    VisitDtype(lhs.dtype(), [&](auto pt) {
        using T = typename decltype(pt)::type;

        int64_t total_size = lhs.total_size();
        auto* ldata = static_cast<const T*>(lhs.data().get());
        auto* rdata = static_cast<const T*>(rhs.data().get());
        auto* odata = static_cast<T*>(out.data().get());

        for (int64_t i = 0; i < total_size; i++) {
            odata[i] = ldata[i] * rdata[i];
        }
    });

    return {out};
}

class CheckBackwardTest : public ::testing::Test {
public:
    template <typename T>
    Array MakeArray(const Shape& shape, const T* data) {
        int64_t size = shape.total_size();
        auto a = std::make_unique<T[]>(size);
        std::copy(data, data + size, a.get());
        return Array::FromBuffer(shape, TypeToDtype<T>, std::move(a));
    }

    void CheckCorrectBackwardComputation(const std::vector<Array>& inputs, const std::vector<Array>& grad_outputs,
                                         const std::vector<Array>& eps, double atol, double rtol) {
        // Forward propagation using overloaded operators that correctly implement their corresponding backward computations
        auto fprop = inputs.size() == 1 ? [](const std::vector<Array>& inputs) -> std::vector<Array> { return {inputs[0]}; }
        : [](const std::vector<Array>& inputs) -> std::vector<Array> { return {inputs[0] * inputs[1]}; };
        CheckBackwardComputation(fprop, inputs, grad_outputs, eps, atol, rtol);
    }

    void CheckWrongBackwardComputation(const std::vector<Array>& inputs, const std::vector<Array>& grad_outputs,
                                       const std::vector<Array>& eps, double atol, double rtol) {
        auto fprop = inputs.size() == 1 ? &WrongBackwardUnaryFunc : &WrongBackwardBinaryFunc;
        if (std::any_of(inputs.begin(), inputs.end(), [](const Array& input) { return input.requires_grad(); })) {
            // Catch the gtest failure expected to be generated by CheckBackwardComputation but without failing this test
            EXPECT_NONFATAL_FAILURE(CheckBackwardComputation(fprop, inputs, grad_outputs, eps, atol, rtol), "Backward check failure");
        } else {
            // We cannot expect any failures in case none of the input std::vector<Array> require gradients
            CheckBackwardComputation(fprop, inputs, grad_outputs, eps, atol, rtol);
        }
    }
};

TEST_F(CheckBackwardTest, UnaryBackward) {
    Shape shape{2, 3};

    float data[]{1.f, 2.f, 3.f, 4.f, 5.f, 6.f};
    float eps_data[]{1.f, 2.f, 3.f, 4.f, 5.f, 6.f};
    float grad_output_data[]{1.f, -2.f, 3.f, 0.f, 5.2f, 6.f};

    double atol = 1e-5;
    double rtol = 1e-4;

    {
        std::vector<Array> inputs = {MakeArray(shape, data)};
        std::vector<Array> eps = {MakeArray(shape, eps_data)};
        std::vector<Array> grad_outputs = {MakeArray(shape, grad_output_data)};
        inputs[0].set_requires_grad(false);
        CheckCorrectBackwardComputation(inputs, grad_outputs, eps, atol, rtol);
    }
    {
        std::vector<Array> inputs = {MakeArray(shape, data)};
        std::vector<Array> eps = {MakeArray(shape, eps_data)};
        std::vector<Array> grad_outputs = {MakeArray(shape, grad_output_data)};
        inputs[0].set_requires_grad(false);
        CheckWrongBackwardComputation(inputs, grad_outputs, eps, atol, rtol);
    }
    {
        std::vector<Array> inputs = {MakeArray(shape, data)};
        std::vector<Array> eps = {MakeArray(shape, eps_data)};
        std::vector<Array> grad_outputs = {MakeArray(shape, grad_output_data)};
        inputs[0].set_requires_grad(true);
        CheckCorrectBackwardComputation(inputs, grad_outputs, eps, atol, rtol);
    }
    {
        std::vector<Array> inputs = {MakeArray(shape, data)};
        std::vector<Array> eps = {MakeArray(shape, eps_data)};
        std::vector<Array> grad_outputs = {MakeArray(shape, grad_output_data)};
        inputs[0].set_requires_grad(true);
        CheckWrongBackwardComputation(inputs, grad_outputs, eps, atol, rtol);
    }
}

TEST_F(CheckBackwardTest, BinaryBackward) {
    Shape shape{2, 3};

    float data1[]{1.f, 2.f, 3.f, 4.f, 5.f, 6.f};
    float data2[]{0.f, 1.f, 2.f, 3.f, 4.f, 5.f};
    float eps_data1[]{1.f, 2.f, 3.f, 4.f, 5.f, 6.f};
    float eps_data2[]{3.f, -2.f, 3.f, -4.f, 3.2f, 0.9f};
    float grad_output_data[]{1.f, -2.f, 3.f, 0.f, 5.2f, 6.f};

    double atol = 1e-5;
    double rtol = 1e-4;

    const int nperm = 4;
    bool requires_grads[nperm][2]{{false, false}, {false, true}, {true, false}, {true, true}};

    for (int i = 0; i < nperm; ++i) {
        {
            std::vector<Array> inputs = {MakeArray(shape, data1), MakeArray(shape, data2)};
            std::vector<Array> eps = {MakeArray(shape, eps_data1), MakeArray(shape, eps_data2)};
            std::vector<Array> grad_outputs = {MakeArray(shape, grad_output_data)};
            inputs[0].set_requires_grad(requires_grads[i][0]);
            inputs[1].set_requires_grad(requires_grads[i][1]);
            CheckCorrectBackwardComputation(inputs, grad_outputs, eps, atol, rtol);
        }
        {
            std::vector<Array> inputs = {MakeArray(shape, data1), MakeArray(shape, data2)};
            std::vector<Array> eps = {MakeArray(shape, eps_data1), MakeArray(shape, eps_data2)};
            std::vector<Array> grad_outputs = {MakeArray(shape, grad_output_data)};
            inputs[0].set_requires_grad(requires_grads[i][0]);
            inputs[1].set_requires_grad(requires_grads[i][1]);
            CheckWrongBackwardComputation(inputs, grad_outputs, eps, atol, rtol);
        }
    }
}

}  // namespace
}  // namespace xchainer
<|endoftext|>


<commit_before>#pragma once

#ifndef RAZ_OVERLAY_HPP
#define RAZ_OVERLAY_HPP

#include "RaZ/Render/Texture.hpp"

#include <functional>
#include <memory>
#include <string>
#include <unordered_map>
#include <vector>

struct GLFWwindow;

namespace Raz {

class Overlay;
using OverlayPtr = std::unique_ptr<Overlay>;

class OverlayWindow;
using OverlayWindowPtr = std::unique_ptr<OverlayWindow>;

enum class OverlayElementType {
  LABEL,
  COLORED_LABEL,
  BUTTON,
  CHECKBOX,
  SLIDER,
  TEXTBOX,
  LIST_BOX,
  DROPDOWN,
  TEXTURE,
  PROGRESS_BAR,
  SEPARATOR,
  FRAME_TIME,
  FPS_COUNTER
};

/// Overlay class, used to render GUI elements (labels, buttons, checkboxes, ...) into a Window.
class Overlay {
  friend OverlayWindow;

public:
  Overlay() = default;
  Overlay(const Overlay&) = delete;
  Overlay(Overlay&&) noexcept = default;

  bool isEmpty() const noexcept { return m_windows.empty(); }

  template <typename... Args>
  static OverlayPtr create(Args&&... args) { return std::make_unique<Overlay>(std::forward<Args>(args)...); }

  /// Initializes ImGui with the containing window.
  /// \param windowHandle Handle to initialize the overlay with.
  void initialize(GLFWwindow* windowHandle) const;
  /// Adds a new overlay window.
  /// \param title Window title.
  /// \return The newly added window.
  [[nodiscard]] OverlayWindow& addWindow(std::string title);
  /// Checks if the overlay is currently requesting the keyboard inputs.
  /// \return True if the keyboard focus is taken, false otherwise.
  bool hasKeyboardFocus() const;
  /// Checks if the overlay is currently requesting the mouse inputs.
  /// \return True if the mouse focus is taken, false otherwise.
  bool hasMouseFocus() const;
  /// Renders the overlay.
  void render() const;
  /// Destroys the overlay.
  void destroy() const;

  Overlay& operator=(const Overlay&) = delete;
  Overlay& operator=(Overlay&&) noexcept = default;

private:
  std::vector<OverlayWindow> m_windows {};
};

class OverlayElement {
  friend OverlayWindow;

public:
  OverlayElement() = default;
  explicit OverlayElement(std::string label) : m_label{ std::move(label) } {}

  virtual OverlayElementType getType() const = 0;

  virtual ~OverlayElement() = default;

private:
  std::string m_label {};
};

class OverlayLabel final : public OverlayElement {
  friend OverlayWindow;

public:
  explicit OverlayLabel(std::string label) : OverlayElement(std::move(label)) {}

  OverlayElementType getType() const override { return OverlayElementType::LABEL; }
};

class OverlayColoredLabel final : public OverlayElement {
  friend OverlayWindow;

public:
  explicit OverlayColoredLabel(std::string label, Vec4f color) : OverlayElement(std::move(label)), m_color{ color } {}

  OverlayElementType getType() const override { return OverlayElementType::COLORED_LABEL; }

private:
  Vec4f m_color {};
};

class OverlayButton final : public OverlayElement {
  friend OverlayWindow;

public:
  OverlayButton(std::string label, std::function<void()> actionClick) : OverlayElement(std::move(label)), m_actionClick{ std::move(actionClick) } {}

  OverlayElementType getType() const override { return OverlayElementType::BUTTON; }

private:
  std::function<void()> m_actionClick {};
};

class OverlayCheckbox final : public OverlayElement {
  friend OverlayWindow;

public:
  OverlayCheckbox(std::string label, std::function<void()> actionOn, std::function<void()> actionOff, bool initVal)
    : OverlayElement(std::move(label)), m_actionOn{ std::move(actionOn) }, m_actionOff{ std::move(actionOff) }, m_isChecked{ initVal } {}

  OverlayElementType getType() const override { return OverlayElementType::CHECKBOX; }

private:
  std::function<void()> m_actionOn {};
  std::function<void()> m_actionOff {};
  bool m_isChecked {};
};

class OverlaySlider final : public OverlayElement {
  friend OverlayWindow;

public:
  OverlaySlider(std::string label, std::function<void(float)> actionSlide, float minValue, float maxValue, float initValue)
    : OverlayElement(std::move(label)), m_actionSlide{ std::move(actionSlide) }, m_minValue{ minValue }, m_maxValue{ maxValue }, m_currentValue{ initValue } {}

  OverlayElementType getType() const override { return OverlayElementType::SLIDER; }

private:
  std::function<void(float)> m_actionSlide {};
  float m_minValue {};
  float m_maxValue {};
  float m_currentValue {};
};

class OverlayTextbox final : public OverlayElement {
  friend OverlayWindow;

public:
  OverlayTextbox(std::string label, std::function<void(const std::string&)> callback) : OverlayElement(std::move(label)), m_callback{ std::move(callback) } {}

  OverlayElementType getType() const override { return OverlayElementType::TEXTBOX; }

private:
  std::string m_text {};
  std::function<void(const std::string&)> m_callback {};
};

class OverlayListBox final : public OverlayElement {
  friend OverlayWindow;

public:
  OverlayListBox(std::string label, std::vector<std::string> entries,
                 std::function<void(const std::string&, std::size_t)> actionChanged, std::size_t initId = 0)
    : OverlayElement(std::move(label)),
      m_entries{ std::move(entries) }, m_actionChanged{ std::move(actionChanged) }, m_currentId{ initId }, m_currentVal{ m_entries[initId].c_str() } {}

  OverlayElementType getType() const override { return OverlayElementType::LIST_BOX; }

private:
  std::vector<std::string> m_entries {};
  std::function<void(const std::string&, std::size_t)> m_actionChanged {};
  std::size_t m_currentId {};
  const char* m_currentVal {};
};

class OverlayDropdown final : public OverlayElement {
  friend OverlayWindow;

public:
  OverlayDropdown(std::string label, std::vector<std::string> entries,
                  std::function<void(const std::string&, std::size_t)> actionChanged, std::size_t initId = 0)
    : OverlayElement(std::move(label)),
      m_entries{ std::move(entries) }, m_actionChanged{ std::move(actionChanged) }, m_currentId{ initId }, m_currentVal{ m_entries[initId].c_str() } {}

  OverlayElementType getType() const override { return OverlayElementType::DROPDOWN; }

private:
  std::vector<std::string> m_entries {};
  std::function<void(const std::string&, std::size_t)> m_actionChanged {};
  std::size_t m_currentId {};
  const char* m_currentVal {};
};

class OverlayTexture final : public OverlayElement {
  friend OverlayWindow;

public:
  OverlayTexture(const Texture& texture, unsigned int maxWidth, unsigned int maxHeight)
    : m_index{ texture.getIndex() }, m_width{ static_cast<float>(maxWidth) }, m_height{ static_cast<float>(maxHeight) } {}
  explicit OverlayTexture(const Texture& texture) : OverlayTexture(texture, texture.getImage().getWidth(), texture.getImage().getHeight()) {}

  OverlayElementType getType() const override { return OverlayElementType::TEXTURE; }

private:
  unsigned int m_index {};
  float m_width {};
  float m_height {};
};

class OverlayProgressBar final : public OverlayElement {
  friend OverlayWindow;

public:
  OverlayProgressBar(int minVal, int maxVal, bool showValues = false)
    : m_minVal{ minVal }, m_maxVal{ maxVal }, m_curVal{ minVal }, m_showValues{ showValues } {}

  OverlayElementType getType() const override { return OverlayElementType::PROGRESS_BAR; }
  int getCurrentValue() const noexcept { return m_curVal; }
  bool hasStarted() const noexcept { return m_curVal > m_minVal; }
  bool hasFinished() const noexcept { return m_curVal >= m_maxVal; }

  void setCurrentValue(int curVal) noexcept { m_curVal = curVal; }

  int operator++() noexcept { return ++m_curVal; }
  int operator++(int) noexcept { return m_curVal++; }
  int& operator+=(int val) noexcept { return m_curVal += val; }
  int operator--() noexcept { return --m_curVal; }
  int operator--(int) noexcept { return m_curVal--; }
  int& operator-=(int val) noexcept { return m_curVal -= val; }

private:
  int m_minVal {};
  int m_maxVal {};
  int m_curVal {};
  bool m_showValues {};
};

class OverlaySeparator final : public OverlayElement {
public:
  OverlayElementType getType() const override { return OverlayElementType::SEPARATOR; }
};

class OverlayFrameTime final : public OverlayElement {
public:
  explicit OverlayFrameTime(std::string formattedLabel) : OverlayElement(std::move(formattedLabel)) {}

  OverlayElementType getType() const override { return OverlayElementType::FRAME_TIME; }
};

class OverlayFpsCounter final : public OverlayElement {
public:
  explicit OverlayFpsCounter(std::string formattedLabel) : OverlayElement(std::move(formattedLabel)) {}

  OverlayElementType getType() const override { return OverlayElementType::FPS_COUNTER; }
};

/// OverlayWindow class, representing a specific window in the Overlay.
class OverlayWindow final {
public:
  explicit OverlayWindow(std::string title) noexcept : m_title{ std::move(title) } {}
  OverlayWindow(const OverlayWindow&) = delete;
  OverlayWindow(OverlayWindow&&) noexcept = default;

  /// Adds a label on the overlay window.
  /// \param label Text to be displayed.
  void addLabel(std::string label);
  /// Adds a colored label on the overlay window.
  /// \param label Text to be displayed.
  /// \param color Color to display the text with.
  void addColoredLabel(std::string label, Vec4f color);
  /// Adds a colored label on the overlay window.
  /// \param label Text to be displayed.
  /// \param red Text color's red component.
  /// \param green Text color's green component.
  /// \param blue Text color's blue component.
  /// \param alpha Text color's alpha component.
  void addColoredLabel(std::string label, float red, float green, float blue, float alpha = 1.f);
  /// Adds a button on the overlay window.
  /// \param label Text to be displayed beside the button.
  /// \param actionClick Action to be executed when clicked.
  void addButton(std::string label, std::function<void()> actionClick);
  /// Adds a checkbox on the overlay window.
  /// \param label Text to be displayed beside the checkbox.
  /// \param actionOn Action to be executed when toggled on.
  /// \param actionOff Action to be executed when toggled off.
  /// \param initVal Initial value, checked or not.
  void addCheckbox(std::string label, std::function<void()> actionOn, std::function<void()> actionOff, bool initVal);
  /// Adds a floating-point slider on the overlay window.
  /// \param label Text to be displayed beside the slider.
  /// \param actionSlide Action to be executed on a value change.
  /// \param minValue Lower value bound.
  /// \param maxValue Upper value bound.
  /// \param initValue Initial value.
  void addSlider(std::string label, std::function<void(float)> actionSlide, float minValue, float maxValue, float initValue);
  /// Adds a texbox on the overlay window.
  /// \param label Text to be displayed beside the checkbox.
  /// \param callback Function to be called every time the content is modified.
  void addTextbox(std::string label, std::function<void(const std::string&)> callback);
  /// Adds a list box on the overlay window.
  /// \param label Text to be displayed beside the list.
  /// \param entries Texts to fill the list with.
  /// \param actionChanged Action to be executed when a different element is selected. Receives the currently selected text & index.
  /// \param initId Index of the element to select at initialization. Must be less than the entry count.
  void addListBox(std::string label, std::vector<std::string> entries,
                  std::function<void(const std::string&, std::size_t)> actionChanged, std::size_t initId = 0);
  /// Adds a dropdown list on the overlay window.
  /// \param label Text to be displayed beside the dropdown.
  /// \param entries Texts to fill the dropdown with.
  /// \param actionChanged Action to be executed when a different element is selected. Receives the currently selected text & index.
  /// \param initId Index of the element to select at initialization. Must be less than the entry count.
  void addDropdown(std::string label, std::vector<std::string> entries,
                   std::function<void(const std::string&, std::size_t)> actionChanged, std::size_t initId = 0);
  /// Adds a texture on the overlay window.
  /// \param texture Texture to be displayed.
  /// \param maxWidth Maximum texture's width.
  /// \param maxHeight Maximum texture's height.
  void addTexture(const Texture& texture, unsigned int maxWidth, unsigned int maxHeight);
  /// Adds a progress bar on the overlay window.
  /// \param minVal Minimum value.
  /// \param maxVal Maximum value.
  /// \param showValues Show values ("<current>/<maximum>") instead of percentage.
  /// \return Reference to the newly added progress bar.
  [[nodiscard]] OverlayProgressBar& addProgressBar(int minVal, int maxVal, bool showValues = false);
  /// Adds a texture on the overlay window. The maximum width & height will be those of the texture.
  /// \param texture Texture to be displayed.
  void addTexture(const Texture& texture);
  /// Adds an horizontal separator on the overlay window.
  void addSeparator();
  /// Adds a frame time display on the overlay window.
  /// \param formattedLabel Text with a formatting placeholder to display the frame time (%.Xf, X being the precision after the comma).
  void addFrameTime(std::string formattedLabel);
  /// Adds a FPS (frames per second) counter on the overlay window.
  /// \param formattedLabel Text with a formatting placeholder to display the FPS (%.Xf, X being the precision after the comma).
  void addFpsCounter(std::string formattedLabel);
  /// Renders the window's elements.
  void render() const;

  OverlayWindow& operator=(const OverlayWindow&) = delete;
  OverlayWindow& operator=(OverlayWindow&&) noexcept = default;

private:
  std::string m_title {};
  std::vector<std::unique_ptr<OverlayElement>> m_elements {};
};

} // namespace Raz

#endif // RAZ_OVERLAY_HPP
<commit_msg>[Utils/Overlay] Overlay elements can't be copied or moved anymore<commit_after>#pragma once

#ifndef RAZ_OVERLAY_HPP
#define RAZ_OVERLAY_HPP

#include "RaZ/Render/Texture.hpp"

#include <functional>
#include <memory>
#include <string>
#include <unordered_map>
#include <vector>

struct GLFWwindow;

namespace Raz {

class Overlay;
using OverlayPtr = std::unique_ptr<Overlay>;

class OverlayWindow;
using OverlayWindowPtr = std::unique_ptr<OverlayWindow>;

enum class OverlayElementType {
  LABEL,
  COLORED_LABEL,
  BUTTON,
  CHECKBOX,
  SLIDER,
  TEXTBOX,
  LIST_BOX,
  DROPDOWN,
  TEXTURE,
  PROGRESS_BAR,
  SEPARATOR,
  FRAME_TIME,
  FPS_COUNTER
};

/// Overlay class, used to render GUI elements (labels, buttons, checkboxes, ...) into a Window.
class Overlay {
  friend OverlayWindow;

public:
  Overlay() = default;
  Overlay(const Overlay&) = delete;
  Overlay(Overlay&&) noexcept = default;

  bool isEmpty() const noexcept { return m_windows.empty(); }

  template <typename... Args>
  static OverlayPtr create(Args&&... args) { return std::make_unique<Overlay>(std::forward<Args>(args)...); }

  /// Initializes ImGui with the containing window.
  /// \param windowHandle Handle to initialize the overlay with.
  void initialize(GLFWwindow* windowHandle) const;
  /// Adds a new overlay window.
  /// \param title Window title.
  /// \return The newly added window.
  [[nodiscard]] OverlayWindow& addWindow(std::string title);
  /// Checks if the overlay is currently requesting the keyboard inputs.
  /// \return True if the keyboard focus is taken, false otherwise.
  bool hasKeyboardFocus() const;
  /// Checks if the overlay is currently requesting the mouse inputs.
  /// \return True if the mouse focus is taken, false otherwise.
  bool hasMouseFocus() const;
  /// Renders the overlay.
  void render() const;
  /// Destroys the overlay.
  void destroy() const;

  Overlay& operator=(const Overlay&) = delete;
  Overlay& operator=(Overlay&&) noexcept = default;

private:
  std::vector<OverlayWindow> m_windows {};
};

class OverlayElement {
  friend OverlayWindow;

public:
  OverlayElement() = default;
  OverlayElement(const OverlayElement&) = delete;
  OverlayElement(OverlayElement&&) noexcept = delete;
  explicit OverlayElement(std::string label) : m_label{ std::move(label) } {}

  virtual OverlayElementType getType() const = 0;

  OverlayElement& operator=(const OverlayElement&) = delete;
  OverlayElement& operator=(OverlayElement&&) noexcept = delete;

  virtual ~OverlayElement() = default;

private:
  std::string m_label {};
};

class OverlayLabel final : public OverlayElement {
  friend OverlayWindow;

public:
  explicit OverlayLabel(std::string label) : OverlayElement(std::move(label)) {}

  OverlayElementType getType() const override { return OverlayElementType::LABEL; }
};

class OverlayColoredLabel final : public OverlayElement {
  friend OverlayWindow;

public:
  explicit OverlayColoredLabel(std::string label, Vec4f color) : OverlayElement(std::move(label)), m_color{ color } {}

  OverlayElementType getType() const override { return OverlayElementType::COLORED_LABEL; }

private:
  Vec4f m_color {};
};

class OverlayButton final : public OverlayElement {
  friend OverlayWindow;

public:
  OverlayButton(std::string label, std::function<void()> actionClick) : OverlayElement(std::move(label)), m_actionClick{ std::move(actionClick) } {}

  OverlayElementType getType() const override { return OverlayElementType::BUTTON; }

private:
  std::function<void()> m_actionClick {};
};

class OverlayCheckbox final : public OverlayElement {
  friend OverlayWindow;

public:
  OverlayCheckbox(std::string label, std::function<void()> actionOn, std::function<void()> actionOff, bool initVal)
    : OverlayElement(std::move(label)), m_actionOn{ std::move(actionOn) }, m_actionOff{ std::move(actionOff) }, m_isChecked{ initVal } {}

  OverlayElementType getType() const override { return OverlayElementType::CHECKBOX; }

private:
  std::function<void()> m_actionOn {};
  std::function<void()> m_actionOff {};
  bool m_isChecked {};
};

class OverlaySlider final : public OverlayElement {
  friend OverlayWindow;

public:
  OverlaySlider(std::string label, std::function<void(float)> actionSlide, float minValue, float maxValue, float initValue)
    : OverlayElement(std::move(label)), m_actionSlide{ std::move(actionSlide) }, m_minValue{ minValue }, m_maxValue{ maxValue }, m_currentValue{ initValue } {}

  OverlayElementType getType() const override { return OverlayElementType::SLIDER; }

private:
  std::function<void(float)> m_actionSlide {};
  float m_minValue {};
  float m_maxValue {};
  float m_currentValue {};
};

class OverlayTextbox final : public OverlayElement {
  friend OverlayWindow;

public:
  OverlayTextbox(std::string label, std::function<void(const std::string&)> callback) : OverlayElement(std::move(label)), m_callback{ std::move(callback) } {}

  OverlayElementType getType() const override { return OverlayElementType::TEXTBOX; }

private:
  std::string m_text {};
  std::function<void(const std::string&)> m_callback {};
};

class OverlayListBox final : public OverlayElement {
  friend OverlayWindow;

public:
  OverlayListBox(std::string label, std::vector<std::string> entries,
                 std::function<void(const std::string&, std::size_t)> actionChanged, std::size_t initId = 0)
    : OverlayElement(std::move(label)),
      m_entries{ std::move(entries) }, m_actionChanged{ std::move(actionChanged) }, m_currentId{ initId }, m_currentVal{ m_entries[initId].c_str() } {}

  OverlayElementType getType() const override { return OverlayElementType::LIST_BOX; }

private:
  std::vector<std::string> m_entries {};
  std::function<void(const std::string&, std::size_t)> m_actionChanged {};
  std::size_t m_currentId {};
  const char* m_currentVal {};
};

class OverlayDropdown final : public OverlayElement {
  friend OverlayWindow;

public:
  OverlayDropdown(std::string label, std::vector<std::string> entries,
                  std::function<void(const std::string&, std::size_t)> actionChanged, std::size_t initId = 0)
    : OverlayElement(std::move(label)),
      m_entries{ std::move(entries) }, m_actionChanged{ std::move(actionChanged) }, m_currentId{ initId }, m_currentVal{ m_entries[initId].c_str() } {}

  OverlayElementType getType() const override { return OverlayElementType::DROPDOWN; }

private:
  std::vector<std::string> m_entries {};
  std::function<void(const std::string&, std::size_t)> m_actionChanged {};
  std::size_t m_currentId {};
  const char* m_currentVal {};
};

class OverlayTexture final : public OverlayElement {
  friend OverlayWindow;

public:
  OverlayTexture(const Texture& texture, unsigned int maxWidth, unsigned int maxHeight)
    : m_index{ texture.getIndex() }, m_width{ static_cast<float>(maxWidth) }, m_height{ static_cast<float>(maxHeight) } {}
  explicit OverlayTexture(const Texture& texture) : OverlayTexture(texture, texture.getImage().getWidth(), texture.getImage().getHeight()) {}

  OverlayElementType getType() const override { return OverlayElementType::TEXTURE; }

private:
  unsigned int m_index {};
  float m_width {};
  float m_height {};
};

class OverlayProgressBar final : public OverlayElement {
  friend OverlayWindow;

public:
  OverlayProgressBar(int minVal, int maxVal, bool showValues = false)
    : m_minVal{ minVal }, m_maxVal{ maxVal }, m_curVal{ minVal }, m_showValues{ showValues } {}

  OverlayElementType getType() const override { return OverlayElementType::PROGRESS_BAR; }
  int getCurrentValue() const noexcept { return m_curVal; }
  bool hasStarted() const noexcept { return m_curVal > m_minVal; }
  bool hasFinished() const noexcept { return m_curVal >= m_maxVal; }

  void setCurrentValue(int curVal) noexcept { m_curVal = curVal; }

  int operator++() noexcept { return ++m_curVal; }
  int operator++(int) noexcept { return m_curVal++; }
  int& operator+=(int val) noexcept { return m_curVal += val; }
  int operator--() noexcept { return --m_curVal; }
  int operator--(int) noexcept { return m_curVal--; }
  int& operator-=(int val) noexcept { return m_curVal -= val; }

private:
  int m_minVal {};
  int m_maxVal {};
  int m_curVal {};
  bool m_showValues {};
};

class OverlaySeparator final : public OverlayElement {
public:
  OverlayElementType getType() const override { return OverlayElementType::SEPARATOR; }
};

class OverlayFrameTime final : public OverlayElement {
public:
  explicit OverlayFrameTime(std::string formattedLabel) : OverlayElement(std::move(formattedLabel)) {}

  OverlayElementType getType() const override { return OverlayElementType::FRAME_TIME; }
};

class OverlayFpsCounter final : public OverlayElement {
public:
  explicit OverlayFpsCounter(std::string formattedLabel) : OverlayElement(std::move(formattedLabel)) {}

  OverlayElementType getType() const override { return OverlayElementType::FPS_COUNTER; }
};

/// OverlayWindow class, representing a specific window in the Overlay.
class OverlayWindow final {
public:
  explicit OverlayWindow(std::string title) noexcept : m_title{ std::move(title) } {}
  OverlayWindow(const OverlayWindow&) = delete;
  OverlayWindow(OverlayWindow&&) noexcept = default;

  /// Adds a label on the overlay window.
  /// \param label Text to be displayed.
  void addLabel(std::string label);
  /// Adds a colored label on the overlay window.
  /// \param label Text to be displayed.
  /// \param color Color to display the text with.
  void addColoredLabel(std::string label, Vec4f color);
  /// Adds a colored label on the overlay window.
  /// \param label Text to be displayed.
  /// \param red Text color's red component.
  /// \param green Text color's green component.
  /// \param blue Text color's blue component.
  /// \param alpha Text color's alpha component.
  void addColoredLabel(std::string label, float red, float green, float blue, float alpha = 1.f);
  /// Adds a button on the overlay window.
  /// \param label Text to be displayed beside the button.
  /// \param actionClick Action to be executed when clicked.
  void addButton(std::string label, std::function<void()> actionClick);
  /// Adds a checkbox on the overlay window.
  /// \param label Text to be displayed beside the checkbox.
  /// \param actionOn Action to be executed when toggled on.
  /// \param actionOff Action to be executed when toggled off.
  /// \param initVal Initial value, checked or not.
  void addCheckbox(std::string label, std::function<void()> actionOn, std::function<void()> actionOff, bool initVal);
  /// Adds a floating-point slider on the overlay window.
  /// \param label Text to be displayed beside the slider.
  /// \param actionSlide Action to be executed on a value change.
  /// \param minValue Lower value bound.
  /// \param maxValue Upper value bound.
  /// \param initValue Initial value.
  void addSlider(std::string label, std::function<void(float)> actionSlide, float minValue, float maxValue, float initValue);
  /// Adds a texbox on the overlay window.
  /// \param label Text to be displayed beside the checkbox.
  /// \param callback Function to be called every time the content is modified.
  void addTextbox(std::string label, std::function<void(const std::string&)> callback);
  /// Adds a list box on the overlay window.
  /// \param label Text to be displayed beside the list.
  /// \param entries Texts to fill the list with.
  /// \param actionChanged Action to be executed when a different element is selected. Receives the currently selected text & index.
  /// \param initId Index of the element to select at initialization. Must be less than the entry count.
  void addListBox(std::string label, std::vector<std::string> entries,
                  std::function<void(const std::string&, std::size_t)> actionChanged, std::size_t initId = 0);
  /// Adds a dropdown list on the overlay window.
  /// \param label Text to be displayed beside the dropdown.
  /// \param entries Texts to fill the dropdown with.
  /// \param actionChanged Action to be executed when a different element is selected. Receives the currently selected text & index.
  /// \param initId Index of the element to select at initialization. Must be less than the entry count.
  void addDropdown(std::string label, std::vector<std::string> entries,
                   std::function<void(const std::string&, std::size_t)> actionChanged, std::size_t initId = 0);
  /// Adds a texture on the overlay window.
  /// \param texture Texture to be displayed.
  /// \param maxWidth Maximum texture's width.
  /// \param maxHeight Maximum texture's height.
  void addTexture(const Texture& texture, unsigned int maxWidth, unsigned int maxHeight);
  /// Adds a progress bar on the overlay window.
  /// \param minVal Minimum value.
  /// \param maxVal Maximum value.
  /// \param showValues Show values ("<current>/<maximum>") instead of percentage.
  /// \return Reference to the newly added progress bar.
  [[nodiscard]] OverlayProgressBar& addProgressBar(int minVal, int maxVal, bool showValues = false);
  /// Adds a texture on the overlay window. The maximum width & height will be those of the texture.
  /// \param texture Texture to be displayed.
  void addTexture(const Texture& texture);
  /// Adds an horizontal separator on the overlay window.
  void addSeparator();
  /// Adds a frame time display on the overlay window.
  /// \param formattedLabel Text with a formatting placeholder to display the frame time (%.Xf, X being the precision after the comma).
  void addFrameTime(std::string formattedLabel);
  /// Adds a FPS (frames per second) counter on the overlay window.
  /// \param formattedLabel Text with a formatting placeholder to display the FPS (%.Xf, X being the precision after the comma).
  void addFpsCounter(std::string formattedLabel);
  /// Renders the window's elements.
  void render() const;

  OverlayWindow& operator=(const OverlayWindow&) = delete;
  OverlayWindow& operator=(OverlayWindow&&) noexcept = default;

private:
  std::string m_title {};
  std::vector<std::unique_ptr<OverlayElement>> m_elements {};
};

} // namespace Raz

#endif // RAZ_OVERLAY_HPP
<|endoftext|>