<commit_before>/*
  Copyright 2013 SINTEF ICT, Applied Mathematics.
*/

#ifndef EQUELLERUNTIMECPU_HEADER_INCLUDED
#define EQUELLERUNTIMECPU_HEADER_INCLUDED

#include <opm/autodiff/AutoDiffBlock.hpp>
#include <opm/autodiff/AutoDiffHelpers.hpp>
#include <opm/core/utility/parameters/ParameterGroup.hpp>
#include <opm/core/grid/GridManager.hpp>
#include <opm/core/linalg/LinearSolverFactory.hpp>
#include <vector>
#include <string>
#include <map>

/// Topological entities.
template <int Codim>
struct TopologicalEntity
{
    TopologicalEntity() : index(-1) {}
    explicit TopologicalEntity(const int ind) : index(ind) {}
    int index;
    bool operator<(const TopologicalEntity& t) const { return index < t.index; }
    bool operator==(const TopologicalEntity& t) const { return index == t.index; }
};

/// Topological entity for cell.
typedef TopologicalEntity<0> Cell;

/// Topological entity for cell.
typedef TopologicalEntity<1> Face;

/// Topological collections.
typedef std::vector<Cell> CollOfCell;
typedef std::vector<Face> CollOfFace;

// Basic types. Note that we do not have Vector type defined
// although the CollOfVector type is.
typedef double Scalar;
typedef bool Bool;
typedef std::string String;

// Collections and sequences (apart from Collection Of Scalar).
typedef Eigen::Array<Scalar, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor> CollOfVector;
typedef Eigen::Array<bool, Eigen::Dynamic, 1> CollOfBool;
typedef std::vector<Scalar> SeqOfScalar;

/// The Collection Of Scalar type is based on Eigen and opm-autodiff.
/// It uses inheritance to provide extra interfaces for ease of use,
/// notably converting constructors.
class CollOfScalar : public Opm::AutoDiffBlock<double>
{
public:
    typedef Opm::AutoDiffBlock<double> ADB;
    //typedef ADB::V V;
    CollOfScalar()
        : ADB(ADB::null())
    {
    }
    CollOfScalar(const ADB& adb)
        : ADB(adb)
    {
    }
    CollOfScalar(const ADB::V& x)
        : ADB(ADB::constant(x))
    {
    }
};

/// This operator is not provided by AutoDiffBlock, so we must add it here.
inline CollOfScalar operator-(const CollOfScalar& x)
{
    return CollOfScalar::V::Zero(x.size()) - x;
}

/// This operator is not provided by AutoDiffBlock, so we must add it here.
inline CollOfScalar operator/(const Scalar& s, const CollOfScalar& x)
{
    return CollOfScalar::V::Constant(x.size(), s) / x;
}

/// This operator is not provided by AutoDiffBlock, so we must add it here.
inline CollOfScalar operator/(const CollOfScalar& x, const Scalar& s)
{
    return x / CollOfScalar::V::Constant(x.size(), s);
}

/// This operator is not provided by AutoDiffBlock, so we must add it here.
inline CollOfBool operator<(const Scalar& s, const CollOfScalar& x)
{
    return s < x.value();
}

/// This operator is not provided by AutoDiffBlock, so we must add it here.
        inline CollOfBool operator<(const CollOfScalar& x, const Scalar& s)
{
    return x.value() < s;
}

/// This operator is not provided by AutoDiffBlock, so we must add it here.
inline CollOfBool operator>(const Scalar& s, const CollOfScalar& x)
{
    return s > x.value();
}

/// This operator is not provided by AutoDiffBlock, so we must add it here.
inline CollOfBool operator>(const CollOfScalar& x, const Scalar& s)
{
    return x.value() > s;
}

/// This operator is not provided by AutoDiffBlock, so we must add it here.
inline CollOfBool operator<(const CollOfScalar& x, const CollOfScalar& y)
{
    return x.value() < y.value();
}

/// This operator is not provided by AutoDiffBlock, so we must add it here.
inline CollOfBool operator>(const CollOfScalar& x, const CollOfScalar& y)
{
    return x.value() > y.value();
}

/// This operator is not provided by AutoDiffBlock, so we must add it here.
inline CollOfBool operator>=(const CollOfScalar& x, const Scalar& s)
{
    return x.value() >= s;
}

/// The Equelle runtime class.
/// Contains methods corresponding to Equelle built-ins to make
/// it easy to generate C++ code for an Equelle program.
class EquelleRuntimeCPU
{
public:
    /// Constructor.
    EquelleRuntimeCPU(const Opm::parameter::ParameterGroup& param);

    /// Topology and geometry related.
    CollOfCell allCells() const;
    CollOfCell boundaryCells() const;
    CollOfCell interiorCells() const;
    CollOfFace allFaces() const;
    CollOfFace boundaryFaces() const;
    CollOfFace interiorFaces() const;
    CollOfCell firstCell(const CollOfFace& faces) const;
    CollOfCell secondCell(const CollOfFace& faces) const;
    CollOfScalar norm(const CollOfFace& faces) const;
    CollOfScalar norm(const CollOfCell& cells) const;
    CollOfScalar norm(const CollOfVector& vectors) const;
    CollOfVector centroid(const CollOfFace& faces) const;
    CollOfVector centroid(const CollOfCell& cells) const;
    CollOfVector normal(const CollOfFace& faces) const;

    /// Operators and math functions.
    CollOfScalar dot(const CollOfVector& v1, const CollOfVector& v2) const;
    CollOfScalar gradient(const CollOfScalar& cell_scalarfield) const;
    CollOfScalar negGradient(const CollOfScalar& cell_scalarfield) const;
    CollOfScalar divergence(const CollOfScalar& face_fluxes) const;
    CollOfScalar interiorDivergence(const CollOfScalar& face_fluxes) const;
    CollOfBool isEmpty(const CollOfCell& cells) const;
    CollOfBool isEmpty(const CollOfFace& faces) const;
    template <class EntityCollection>
    CollOfScalar operatorExtend(const Scalar data, const EntityCollection& to_set);
    template <class SomeCollection, class EntityCollection>
    SomeCollection operatorExtend(const SomeCollection& data, const EntityCollection& from_set, const EntityCollection& to_set);
    template <class SomeCollection, class EntityCollection>
    SomeCollection operatorOn(const SomeCollection& data, const EntityCollection& from_set, const EntityCollection& to_set);

    template <class SomeCollection>
    SomeCollection trinaryIf(const CollOfBool& predicate,
                             const SomeCollection& iftrue,
                             const SomeCollection& iffalse) const;

    /// Solver function.
    template <class ResidualFunctor>
    CollOfScalar newtonSolve(const ResidualFunctor& rescomp,
                             const CollOfScalar& u_initialguess);

    /// Output.
    void output(const String& tag, Scalar val) const;
    void output(const String& tag, const CollOfScalar& vals);

    /// Input.
    Scalar inputScalarWithDefault(const String& name,
                                          const Scalar default_value);
    CollOfFace inputDomainSubsetOf(const String& name,
                                   const CollOfFace& superset);
    CollOfCell inputDomainSubsetOf(const String& name,
                                   const CollOfCell& superset);
    template <class SomeCollection>
    CollOfScalar inputCollectionOfScalar(const String& name,
                                         const SomeCollection& coll);

    SeqOfScalar inputSequenceOfScalar(const String& name);

    /// Ensuring requirements that may be imposed by Equelle programs.
    void ensureGridDimensionMin(const int minimum_grid_dimension) const;

private:
    /// Topology helpers
    bool boundaryCell(const int cell_index) const;

    /// Creating primary variables.
    static CollOfScalar singlePrimaryVariable(const CollOfScalar& initial_values);

    /// Solver helper.
    CollOfScalar solveForUpdate(const CollOfScalar& residual) const;

    /// Norms.
    Scalar twoNorm(const CollOfScalar& vals) const;

    /// Data members.
    std::unique_ptr<Opm::GridManager> grid_manager_;
    const UnstructuredGrid& grid_;
    Opm::HelperOps ops_;
    Opm::LinearSolverFactory linsolver_;
    bool output_to_file_;
    int verbose_;
    const Opm::parameter::ParameterGroup& param_;
    std::map<std::string, int> outputcount_;
    // For newtonSolve().
    int max_iter_;
    double abs_res_tol_;
};

// Include the implementations of template members.
#include "EquelleRuntimeCPU_impl.hpp"

#endif // EQUELLERUNTIMECPU_HEADER_INCLUDED
<commit_msg>Added sqrt() for CollOfScalar.<commit_after>/*
  Copyright 2013 SINTEF ICT, Applied Mathematics.
*/

#ifndef EQUELLERUNTIMECPU_HEADER_INCLUDED
#define EQUELLERUNTIMECPU_HEADER_INCLUDED

#include <opm/autodiff/AutoDiffBlock.hpp>
#include <opm/autodiff/AutoDiffHelpers.hpp>
#include <opm/core/utility/parameters/ParameterGroup.hpp>
#include <opm/core/grid/GridManager.hpp>
#include <opm/core/linalg/LinearSolverFactory.hpp>
#include <vector>
#include <string>
#include <map>

/// Topological entities.
template <int Codim>
struct TopologicalEntity
{
    TopologicalEntity() : index(-1) {}
    explicit TopologicalEntity(const int ind) : index(ind) {}
    int index;
    bool operator<(const TopologicalEntity& t) const { return index < t.index; }
    bool operator==(const TopologicalEntity& t) const { return index == t.index; }
};

/// Topological entity for cell.
typedef TopologicalEntity<0> Cell;

/// Topological entity for cell.
typedef TopologicalEntity<1> Face;

/// Topological collections.
typedef std::vector<Cell> CollOfCell;
typedef std::vector<Face> CollOfFace;

// Basic types. Note that we do not have Vector type defined
// although the CollOfVector type is.
typedef double Scalar;
typedef bool Bool;
typedef std::string String;

// Collections and sequences (apart from Collection Of Scalar).
typedef Eigen::Array<Scalar, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor> CollOfVector;
typedef Eigen::Array<bool, Eigen::Dynamic, 1> CollOfBool;
typedef std::vector<Scalar> SeqOfScalar;

/// The Collection Of Scalar type is based on Eigen and opm-autodiff.
/// It uses inheritance to provide extra interfaces for ease of use,
/// notably converting constructors.
class CollOfScalar : public Opm::AutoDiffBlock<double>
{
public:
    typedef Opm::AutoDiffBlock<double> ADB;
    //typedef ADB::V V;
    CollOfScalar()
        : ADB(ADB::null())
    {
    }
    CollOfScalar(const ADB& adb)
        : ADB(adb)
    {
    }
    CollOfScalar(const ADB::V& x)
        : ADB(ADB::constant(x))
    {
    }
};

/// This operator is not provided by AutoDiffBlock, so we must add it here.
inline CollOfScalar operator-(const CollOfScalar& x)
{
    return CollOfScalar::V::Zero(x.size()) - x;
}

/// This operator is not provided by AutoDiffBlock, so we must add it here.
inline CollOfScalar operator/(const Scalar& s, const CollOfScalar& x)
{
    return CollOfScalar::V::Constant(x.size(), s) / x;
}

/// This operator is not provided by AutoDiffBlock, so we must add it here.
inline CollOfScalar operator/(const CollOfScalar& x, const Scalar& s)
{
    return x / CollOfScalar::V::Constant(x.size(), s);
}

/// This operator is not provided by AutoDiffBlock, so we must add it here.
inline CollOfBool operator<(const Scalar& s, const CollOfScalar& x)
{
    return s < x.value();
}

/// This operator is not provided by AutoDiffBlock, so we must add it here.
        inline CollOfBool operator<(const CollOfScalar& x, const Scalar& s)
{
    return x.value() < s;
}

/// This operator is not provided by AutoDiffBlock, so we must add it here.
inline CollOfBool operator>(const Scalar& s, const CollOfScalar& x)
{
    return s > x.value();
}

/// This operator is not provided by AutoDiffBlock, so we must add it here.
inline CollOfBool operator>(const CollOfScalar& x, const Scalar& s)
{
    return x.value() > s;
}

/// This operator is not provided by AutoDiffBlock, so we must add it here.
inline CollOfBool operator<(const CollOfScalar& x, const CollOfScalar& y)
{
    return x.value() < y.value();
}

/// This operator is not provided by AutoDiffBlock, so we must add it here.
inline CollOfBool operator>(const CollOfScalar& x, const CollOfScalar& y)
{
    return x.value() > y.value();
}

/// This operator is not provided by AutoDiffBlock, so we must add it here.
inline CollOfBool operator>=(const CollOfScalar& x, const Scalar& s)
{
    return x.value() >= s;
}

/// This function is not provided by AutoDiffBlock, so we must add it here.
inline CollOfScalar sqrt(const CollOfScalar& x)
{
    // d(sqrt(x))/dy = 1/(2*sqrt(x)) * dx/dy

    const auto& xjac = x.derivative();
    if (xjac.empty()) {
        return CollOfScalar(sqrt(x.value()));
    }
    const int num_blocks = xjac.size();
    std::vector<CollOfScalar::M> jac(num_blocks);
    typedef Eigen::DiagonalMatrix<Scalar, Eigen::Dynamic> D;
    const auto sqrt_x = sqrt(x.value());
    const D one_over_two_sqrt_x = (0.5/sqrt_x).matrix().asDiagonal();
    for (int block = 0; block < num_blocks; ++block) {
        jac[block] = one_over_two_sqrt_x * xjac[block];
    }
    return CollOfScalar::ADB::function(sqrt_x, jac);
}

/// The Equelle runtime class.
/// Contains methods corresponding to Equelle built-ins to make
/// it easy to generate C++ code for an Equelle program.
class EquelleRuntimeCPU
{
public:
    /// Constructor.
    EquelleRuntimeCPU(const Opm::parameter::ParameterGroup& param);

    /// Topology and geometry related.
    CollOfCell allCells() const;
    CollOfCell boundaryCells() const;
    CollOfCell interiorCells() const;
    CollOfFace allFaces() const;
    CollOfFace boundaryFaces() const;
    CollOfFace interiorFaces() const;
    CollOfCell firstCell(const CollOfFace& faces) const;
    CollOfCell secondCell(const CollOfFace& faces) const;
    CollOfScalar norm(const CollOfFace& faces) const;
    CollOfScalar norm(const CollOfCell& cells) const;
    CollOfScalar norm(const CollOfVector& vectors) const;
    CollOfVector centroid(const CollOfFace& faces) const;
    CollOfVector centroid(const CollOfCell& cells) const;
    CollOfVector normal(const CollOfFace& faces) const;

    /// Operators and math functions.
    CollOfScalar dot(const CollOfVector& v1, const CollOfVector& v2) const;
    CollOfScalar gradient(const CollOfScalar& cell_scalarfield) const;
    CollOfScalar negGradient(const CollOfScalar& cell_scalarfield) const;
    CollOfScalar divergence(const CollOfScalar& face_fluxes) const;
    CollOfScalar interiorDivergence(const CollOfScalar& face_fluxes) const;
    CollOfBool isEmpty(const CollOfCell& cells) const;
    CollOfBool isEmpty(const CollOfFace& faces) const;
    template <class EntityCollection>
    CollOfScalar operatorExtend(const Scalar data, const EntityCollection& to_set);
    template <class SomeCollection, class EntityCollection>
    SomeCollection operatorExtend(const SomeCollection& data, const EntityCollection& from_set, const EntityCollection& to_set);
    template <class SomeCollection, class EntityCollection>
    SomeCollection operatorOn(const SomeCollection& data, const EntityCollection& from_set, const EntityCollection& to_set);

    template <class SomeCollection>
    SomeCollection trinaryIf(const CollOfBool& predicate,
                             const SomeCollection& iftrue,
                             const SomeCollection& iffalse) const;

    /// Solver function.
    template <class ResidualFunctor>
    CollOfScalar newtonSolve(const ResidualFunctor& rescomp,
                             const CollOfScalar& u_initialguess);

    /// Output.
    void output(const String& tag, Scalar val) const;
    void output(const String& tag, const CollOfScalar& vals);

    /// Input.
    Scalar inputScalarWithDefault(const String& name,
                                          const Scalar default_value);
    CollOfFace inputDomainSubsetOf(const String& name,
                                   const CollOfFace& superset);
    CollOfCell inputDomainSubsetOf(const String& name,
                                   const CollOfCell& superset);
    template <class SomeCollection>
    CollOfScalar inputCollectionOfScalar(const String& name,
                                         const SomeCollection& coll);

    SeqOfScalar inputSequenceOfScalar(const String& name);

    /// Ensuring requirements that may be imposed by Equelle programs.
    void ensureGridDimensionMin(const int minimum_grid_dimension) const;

private:
    /// Topology helpers
    bool boundaryCell(const int cell_index) const;

    /// Creating primary variables.
    static CollOfScalar singlePrimaryVariable(const CollOfScalar& initial_values);

    /// Solver helper.
    CollOfScalar solveForUpdate(const CollOfScalar& residual) const;

    /// Norms.
    Scalar twoNorm(const CollOfScalar& vals) const;

    /// Data members.
    std::unique_ptr<Opm::GridManager> grid_manager_;
    const UnstructuredGrid& grid_;
    Opm::HelperOps ops_;
    Opm::LinearSolverFactory linsolver_;
    bool output_to_file_;
    int verbose_;
    const Opm::parameter::ParameterGroup& param_;
    std::map<std::string, int> outputcount_;
    // For newtonSolve().
    int max_iter_;
    double abs_res_tol_;
};

// Include the implementations of template members.
#include "EquelleRuntimeCPU_impl.hpp"

#endif // EQUELLERUNTIMECPU_HEADER_INCLUDED
<|endoftext|>


<commit_before>#include "halley/tools/assets/import_assets_database.h"
#include "halley/bytes/byte_serializer.h"
#include "halley/resources/resource_data.h"
#include "halley/tools/file/filesystem.h"

constexpr static int currentAssetVersion = 54;

using namespace Halley;

void ImportAssetsDatabaseEntry::serialize(Serializer& s) const
{
	s << assetId;
	s << srcDir;
	s << inputFiles;
	s << additionalInputFiles;
	s << outputFiles;
	int t = int(assetType);
	s << t;
}

void ImportAssetsDatabaseEntry::deserialize(Deserializer& s)
{
	s >> assetId;
	s >> srcDir;
	s >> inputFiles;
	s >> additionalInputFiles;
	s >> outputFiles;
	int t;
	s >> t;
	assetType = ImportAssetType(t);
}

void ImportAssetsDatabase::AssetEntry::serialize(Serializer& s) const
{
	s << asset;
}

void ImportAssetsDatabase::AssetEntry::deserialize(Deserializer& s)
{
	s >> asset;
}

void ImportAssetsDatabase::InputFileEntry::serialize(Serializer& s) const
{
	const int nTimestamps = int(timestamp.size());
	s << nTimestamps;
	for (int i = 0; i < nTimestamps; ++i) {
		s << timestamp[i];
	}
	s << metadata;
}

void ImportAssetsDatabase::InputFileEntry::deserialize(Deserializer& s)
{
	int nTimestamps;
	s >> nTimestamps;
	for (int i = 0; i < nTimestamps; ++i) {
		if (i < int(timestamp.size())) {
			s >> timestamp[i];
		}
	}
	for (int i = nTimestamps; i < int(timestamp.size()); ++i) {
		timestamp[i] = 0;
	}
	s >> metadata;
}

ImportAssetsDatabase::ImportAssetsDatabase(Path directory, Path dbFile, Path assetsDbFile, std::vector<String> platforms)
	: platforms(std::move(platforms))
	, directory(directory)
	, dbFile(dbFile)
	, assetsDbFile(assetsDbFile)
{
	load();
}

void ImportAssetsDatabase::load()
{
	std::lock_guard<std::mutex> lock(mutex);
	auto data = FileSystem::readFile(dbFile);
	if (data.size() > 0) {
		auto s = Deserializer(data);
		deserialize(s);
	}
}

void ImportAssetsDatabase::save() const
{
	std::lock_guard<std::mutex> lock(mutex);
	FileSystem::writeFile(dbFile, Serializer::toBytes(*this));
	for (auto& platform: platforms) {
		// TODO: fix this
		auto assetDb = makeAssetDatabase(platform);
		FileSystem::writeFile(assetsDbFile, Serializer::toBytes(*assetDb));
	}
}

bool ImportAssetsDatabase::needToLoadInputMetadata(const Path& path, std::array<int64_t, 3> timestamps) const
{
	std::lock_guard<std::mutex> lock(mutex);

	// Is it an unknown file?
	auto pathStr = path.toString();
	auto iter = inputFiles.find(pathStr);
	if (iter == inputFiles.end()) {
		return true;
	}

	// Any of the timestamps changed?
	for (int i = 0; i < timestamps.size(); ++i) {
		if (iter->second.timestamp[i] != timestamps[i]) {
			return true;
		}
	}

	return false;
}

void ImportAssetsDatabase::setInputFileMetadata(const Path& path, std::array<int64_t, 3> timestamps, const Metadata& data)
{
	std::lock_guard<std::mutex> lock(mutex);

	auto pathStr = path.toString();
	auto& input = inputFiles[pathStr];
	input.timestamp = timestamps;
	input.metadata = data;
}

Maybe<Metadata> ImportAssetsDatabase::getMetadata(const Path& path) const
{
	std::lock_guard<std::mutex> lock(mutex);

	auto pathStr = path.toString();
	auto iter = inputFiles.find(pathStr);
	if (iter == inputFiles.end()) {
		return {};
	} else {
		return iter->second.metadata;
	}
}

bool ImportAssetsDatabase::needsImporting(const ImportAssetsDatabaseEntry& asset) const
{
	std::lock_guard<std::mutex> lock(mutex);

	// Check if it failed loading last time
	auto iter = assetsFailed.find(asset.assetId);
	bool failed = iter != assetsFailed.end();
	if (!failed) {
		// No failures, check if this was imported before
		iter = assetsImported.find(asset.assetId);
		if (iter == assetsImported.end()) {
			// Asset didn't even exist before
			return true;
		}
	}

	// At this point, iter points to the failed one if it failed, or the the old successful one if it didn't.
	auto& oldAsset = iter->second.asset;

	// Input directory changed?
	if (asset.srcDir != oldAsset.srcDir) {
		return true;
	}

	// Total count of input files changed?
	if (asset.inputFiles.size() != oldAsset.inputFiles.size()) {
		return true;
	}

	// Any of the input files changed?
	// Note: We don't have to check old files on new input, because the size matches and all entries matched.
	for (auto& i: asset.inputFiles) {
		auto result = std::find_if(oldAsset.inputFiles.begin(), oldAsset.inputFiles.end(), [&](const TimestampedPath& entry) { return entry.first == i.first; });
		if (result == oldAsset.inputFiles.end()) {
			// File wasn't there before
			return true;
		} else if (result->second != i.second) {
			// Timestamp changed
			return true;
		}
	}

	// Any of the additional input files changed?
	for (auto& i: oldAsset.additionalInputFiles) {
		if (!FileSystem::exists(i.first)) {
			// File removed
			return true;
		} else if  (FileSystem::getLastWriteTime(i.first) != i.second) {
			// Timestamp changed
			return true;
		}
	}

	// Have any of the output files gone missing?
	if (!failed) {
		for (auto& o: oldAsset.outputFiles) {
			for (auto& version: o.platformVersions) {
				if (!FileSystem::exists(directory / version.second.filepath)) {
					return true;
				}
			}
		}
	}

	return false;
}

void ImportAssetsDatabase::markAsImported(const ImportAssetsDatabaseEntry& asset)
{
	AssetEntry entry;
	entry.asset = asset;
	entry.present = true;

	std::lock_guard<std::mutex> lock(mutex);
	assetsImported[asset.assetId] = entry;

	auto failIter = assetsFailed.find(asset.assetId);
	if (failIter != assetsFailed.end()) {
		assetsFailed.erase(failIter);
	}
}

void ImportAssetsDatabase::markDeleted(const ImportAssetsDatabaseEntry& asset)
{
	std::lock_guard<std::mutex> lock(mutex);
	assetsImported.erase(asset.assetId);
}

void ImportAssetsDatabase::markFailed(const ImportAssetsDatabaseEntry& asset)
{
	AssetEntry entry;
	entry.asset = asset;
	entry.present = true;

	std::lock_guard<std::mutex> lock(mutex);
	assetsFailed[asset.assetId] = entry;
}

void ImportAssetsDatabase::markAssetsAsStillPresent(const std::map<String, ImportAssetsDatabaseEntry>& assets)
{
	std::lock_guard<std::mutex> lock(mutex);
	for (auto& e: assetsImported) {
		e.second.present = assets.find(e.first) != assets.end();
	}
}

std::vector<ImportAssetsDatabaseEntry> ImportAssetsDatabase::getAllMissing() const
{
	std::lock_guard<std::mutex> lock(mutex);
	std::vector<ImportAssetsDatabaseEntry> result;
	for (auto& e : assetsImported) {
		if (!e.second.present) {
			result.push_back(e.second.asset);
		}
	}
	return result;
}

std::vector<AssetResource> ImportAssetsDatabase::getOutFiles(String assetId) const
{
	auto iter = assetsImported.find(assetId);
	if (iter != assetsImported.end()) {
		return iter->second.asset.outputFiles;
	} else {
		return {};
	}
}

void ImportAssetsDatabase::serialize(Serializer& s) const
{
	int version = currentAssetVersion;
	s << version;
	s << platforms;
	s << assetsImported;
	s << inputFiles;
}

void ImportAssetsDatabase::deserialize(Deserializer& s)
{
	int version;
	s >> version;
	if (version == currentAssetVersion) {
		std::vector<String> platformsRead;
		s >> platformsRead;
		if (platformsRead == platforms) {
			s >> assetsImported;
			s >> inputFiles;
		}
	}
}

std::unique_ptr<AssetDatabase> ImportAssetsDatabase::makeAssetDatabase(const String& platform) const
{
	auto result = std::make_unique<AssetDatabase>();
	for (auto& a: assetsImported) {
		auto& asset = a.second.asset;
		for (auto& o: asset.outputFiles) {
			auto iter = o.platformVersions.find(platform);
			const AssetResource::PlatformVersion* version = nullptr;
			if (iter != o.platformVersions.end()) {
				version = &iter->second;
			} else {
				iter = o.platformVersions.find("pc");
				if (iter != o.platformVersions.end()) {
					version = &iter->second;
				}
			}

			if (version) {
				result->addAsset(o.name, o.type, AssetDatabase::Entry(version->filepath, version->metadata));
			}
		}
	}
	return result;
}
<commit_msg>Bump asset version<commit_after>#include "halley/tools/assets/import_assets_database.h"
#include "halley/bytes/byte_serializer.h"
#include "halley/resources/resource_data.h"
#include "halley/tools/file/filesystem.h"

constexpr static int currentAssetVersion = 55;

using namespace Halley;

void ImportAssetsDatabaseEntry::serialize(Serializer& s) const
{
	s << assetId;
	s << srcDir;
	s << inputFiles;
	s << additionalInputFiles;
	s << outputFiles;
	int t = int(assetType);
	s << t;
}

void ImportAssetsDatabaseEntry::deserialize(Deserializer& s)
{
	s >> assetId;
	s >> srcDir;
	s >> inputFiles;
	s >> additionalInputFiles;
	s >> outputFiles;
	int t;
	s >> t;
	assetType = ImportAssetType(t);
}

void ImportAssetsDatabase::AssetEntry::serialize(Serializer& s) const
{
	s << asset;
}

void ImportAssetsDatabase::AssetEntry::deserialize(Deserializer& s)
{
	s >> asset;
}

void ImportAssetsDatabase::InputFileEntry::serialize(Serializer& s) const
{
	const int nTimestamps = int(timestamp.size());
	s << nTimestamps;
	for (int i = 0; i < nTimestamps; ++i) {
		s << timestamp[i];
	}
	s << metadata;
}

void ImportAssetsDatabase::InputFileEntry::deserialize(Deserializer& s)
{
	int nTimestamps;
	s >> nTimestamps;
	for (int i = 0; i < nTimestamps; ++i) {
		if (i < int(timestamp.size())) {
			s >> timestamp[i];
		}
	}
	for (int i = nTimestamps; i < int(timestamp.size()); ++i) {
		timestamp[i] = 0;
	}
	s >> metadata;
}

ImportAssetsDatabase::ImportAssetsDatabase(Path directory, Path dbFile, Path assetsDbFile, std::vector<String> platforms)
	: platforms(std::move(platforms))
	, directory(directory)
	, dbFile(dbFile)
	, assetsDbFile(assetsDbFile)
{
	load();
}

void ImportAssetsDatabase::load()
{
	std::lock_guard<std::mutex> lock(mutex);
	auto data = FileSystem::readFile(dbFile);
	if (data.size() > 0) {
		auto s = Deserializer(data);
		deserialize(s);
	}
}

void ImportAssetsDatabase::save() const
{
	std::lock_guard<std::mutex> lock(mutex);
	FileSystem::writeFile(dbFile, Serializer::toBytes(*this));
	for (auto& platform: platforms) {
		// TODO: fix this
		auto assetDb = makeAssetDatabase(platform);
		FileSystem::writeFile(assetsDbFile, Serializer::toBytes(*assetDb));
	}
}

bool ImportAssetsDatabase::needToLoadInputMetadata(const Path& path, std::array<int64_t, 3> timestamps) const
{
	std::lock_guard<std::mutex> lock(mutex);

	// Is it an unknown file?
	auto pathStr = path.toString();
	auto iter = inputFiles.find(pathStr);
	if (iter == inputFiles.end()) {
		return true;
	}

	// Any of the timestamps changed?
	for (int i = 0; i < timestamps.size(); ++i) {
		if (iter->second.timestamp[i] != timestamps[i]) {
			return true;
		}
	}

	return false;
}

void ImportAssetsDatabase::setInputFileMetadata(const Path& path, std::array<int64_t, 3> timestamps, const Metadata& data)
{
	std::lock_guard<std::mutex> lock(mutex);

	auto pathStr = path.toString();
	auto& input = inputFiles[pathStr];
	input.timestamp = timestamps;
	input.metadata = data;
}

Maybe<Metadata> ImportAssetsDatabase::getMetadata(const Path& path) const
{
	std::lock_guard<std::mutex> lock(mutex);

	auto pathStr = path.toString();
	auto iter = inputFiles.find(pathStr);
	if (iter == inputFiles.end()) {
		return {};
	} else {
		return iter->second.metadata;
	}
}

bool ImportAssetsDatabase::needsImporting(const ImportAssetsDatabaseEntry& asset) const
{
	std::lock_guard<std::mutex> lock(mutex);

	// Check if it failed loading last time
	auto iter = assetsFailed.find(asset.assetId);
	bool failed = iter != assetsFailed.end();
	if (!failed) {
		// No failures, check if this was imported before
		iter = assetsImported.find(asset.assetId);
		if (iter == assetsImported.end()) {
			// Asset didn't even exist before
			return true;
		}
	}

	// At this point, iter points to the failed one if it failed, or the the old successful one if it didn't.
	auto& oldAsset = iter->second.asset;

	// Input directory changed?
	if (asset.srcDir != oldAsset.srcDir) {
		return true;
	}

	// Total count of input files changed?
	if (asset.inputFiles.size() != oldAsset.inputFiles.size()) {
		return true;
	}

	// Any of the input files changed?
	// Note: We don't have to check old files on new input, because the size matches and all entries matched.
	for (auto& i: asset.inputFiles) {
		auto result = std::find_if(oldAsset.inputFiles.begin(), oldAsset.inputFiles.end(), [&](const TimestampedPath& entry) { return entry.first == i.first; });
		if (result == oldAsset.inputFiles.end()) {
			// File wasn't there before
			return true;
		} else if (result->second != i.second) {
			// Timestamp changed
			return true;
		}
	}

	// Any of the additional input files changed?
	for (auto& i: oldAsset.additionalInputFiles) {
		if (!FileSystem::exists(i.first)) {
			// File removed
			return true;
		} else if  (FileSystem::getLastWriteTime(i.first) != i.second) {
			// Timestamp changed
			return true;
		}
	}

	// Have any of the output files gone missing?
	if (!failed) {
		for (auto& o: oldAsset.outputFiles) {
			for (auto& version: o.platformVersions) {
				if (!FileSystem::exists(directory / version.second.filepath)) {
					return true;
				}
			}
		}
	}

	return false;
}

void ImportAssetsDatabase::markAsImported(const ImportAssetsDatabaseEntry& asset)
{
	AssetEntry entry;
	entry.asset = asset;
	entry.present = true;

	std::lock_guard<std::mutex> lock(mutex);
	assetsImported[asset.assetId] = entry;

	auto failIter = assetsFailed.find(asset.assetId);
	if (failIter != assetsFailed.end()) {
		assetsFailed.erase(failIter);
	}
}

void ImportAssetsDatabase::markDeleted(const ImportAssetsDatabaseEntry& asset)
{
	std::lock_guard<std::mutex> lock(mutex);
	assetsImported.erase(asset.assetId);
}

void ImportAssetsDatabase::markFailed(const ImportAssetsDatabaseEntry& asset)
{
	AssetEntry entry;
	entry.asset = asset;
	entry.present = true;

	std::lock_guard<std::mutex> lock(mutex);
	assetsFailed[asset.assetId] = entry;
}

void ImportAssetsDatabase::markAssetsAsStillPresent(const std::map<String, ImportAssetsDatabaseEntry>& assets)
{
	std::lock_guard<std::mutex> lock(mutex);
	for (auto& e: assetsImported) {
		e.second.present = assets.find(e.first) != assets.end();
	}
}

std::vector<ImportAssetsDatabaseEntry> ImportAssetsDatabase::getAllMissing() const
{
	std::lock_guard<std::mutex> lock(mutex);
	std::vector<ImportAssetsDatabaseEntry> result;
	for (auto& e : assetsImported) {
		if (!e.second.present) {
			result.push_back(e.second.asset);
		}
	}
	return result;
}

std::vector<AssetResource> ImportAssetsDatabase::getOutFiles(String assetId) const
{
	auto iter = assetsImported.find(assetId);
	if (iter != assetsImported.end()) {
		return iter->second.asset.outputFiles;
	} else {
		return {};
	}
}

void ImportAssetsDatabase::serialize(Serializer& s) const
{
	int version = currentAssetVersion;
	s << version;
	s << platforms;
	s << assetsImported;
	s << inputFiles;
}

void ImportAssetsDatabase::deserialize(Deserializer& s)
{
	int version;
	s >> version;
	if (version == currentAssetVersion) {
		std::vector<String> platformsRead;
		s >> platformsRead;
		if (platformsRead == platforms) {
			s >> assetsImported;
			s >> inputFiles;
		}
	}
}

std::unique_ptr<AssetDatabase> ImportAssetsDatabase::makeAssetDatabase(const String& platform) const
{
	auto result = std::make_unique<AssetDatabase>();
	for (auto& a: assetsImported) {
		auto& asset = a.second.asset;
		for (auto& o: asset.outputFiles) {
			auto iter = o.platformVersions.find(platform);
			const AssetResource::PlatformVersion* version = nullptr;
			if (iter != o.platformVersions.end()) {
				version = &iter->second;
			} else {
				iter = o.platformVersions.find("pc");
				if (iter != o.platformVersions.end()) {
					version = &iter->second;
				}
			}

			if (version) {
				result->addAsset(o.name, o.type, AssetDatabase::Entry(version->filepath, version->metadata));
			}
		}
	}
	return result;
}
<|endoftext|>


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

  Program:   Visualization Toolkit
  Module:    vtkViewTheme.cxx

  Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
  All rights reserved.
  See Copyright.txt or http://www.kitware.com/Copyright.htm for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notice for more information.

=========================================================================*/
/*----------------------------------------------------------------------------
 Copyright (c) Sandia Corporation
 See Copyright.txt or http://www.paraview.org/HTML/Copyright.html for details.
----------------------------------------------------------------------------*/

#include "vtkViewTheme.h"

#include "vtkObjectFactory.h"

vtkCxxRevisionMacro(vtkViewTheme, "1.1");
vtkStandardNewMacro(vtkViewTheme);

vtkViewTheme::vtkViewTheme()
{
  this->SetPointColor(1, 1, 1);
  this->SetPointOpacity(1);
  this->SetPointHueRange(0.667, 0);
  this->SetPointSaturationRange(1, 1);
  this->SetPointValueRange(1, 1);
  this->SetPointAlphaRange(1, 1);

  this->SetCellColor(1, 1, 1);
  this->SetCellOpacity(0.5);
  this->SetCellHueRange(0.667, 0);
  this->SetCellSaturationRange(0.5, 1);
  this->SetCellValueRange(0.5, 1);
  this->SetCellAlphaRange(0.5, 1);

  this->SetOutlineColor(0,0,0);

  this->SetSelectedPointColor(1, 0, 1);
  this->SetSelectedPointOpacity(1);
  this->SetSelectedCellColor(1, 0, 1);
  this->SetSelectedCellOpacity(1);

  this->SetBackgroundColor(0.3, 0.3, 0.3);
  this->SetVertexLabelColor(1, 1, 1);
  this->SetEdgeLabelColor(.7, .7, .7);
}

vtkViewTheme::~vtkViewTheme()
{
}

vtkViewTheme* vtkViewTheme::CreateOceanTheme()
{
  vtkViewTheme* theme = vtkViewTheme::New();

  theme->SetBackgroundColor(1, 1, 1);
  theme->SetVertexLabelColor(0, 0, 0);
  theme->SetEdgeLabelColor(.2, .2, .2);

  theme->SetPointColor(0.5, 0.5, 0.5);
  theme->SetPointHueRange(0.667, 0);
  theme->SetPointSaturationRange(0.75, 0.75);
  theme->SetPointValueRange(0.75, 0.75);

  theme->SetCellColor(0.25, 0.25, 0.25);
  theme->SetCellOpacity(0.5);
  theme->SetCellHueRange(0.667, 0);
  theme->SetCellAlphaRange(0.5, 1);
  theme->SetCellValueRange(0.5, 1);
  theme->SetCellSaturationRange(0.5, 1);

  theme->SetOutlineColor(0,0,0);

  theme->SetSelectedPointColor(.3, .3, .5);
  theme->SetSelectedCellColor(.3, .3, .3);

  return theme;
}

vtkViewTheme* vtkViewTheme::CreateNeonTheme()
{
  vtkViewTheme* theme = vtkViewTheme::New();

  theme->SetBackgroundColor(0, 0, 0);
  theme->SetVertexLabelColor(1, 1, 1);
  theme->SetEdgeLabelColor(.7, .7, .7);

  theme->SetPointColor(0.5, 0.5, 0.5);
  theme->SetPointHueRange(0.667, 0);
  theme->SetPointSaturationRange(1, 1);
  theme->SetPointValueRange(1, 1);

  theme->SetCellColor(0.25, 0.25, 0.25);
  theme->SetCellOpacity(0.75);
  theme->SetCellHueRange(0.667, 0);
  theme->SetCellAlphaRange(0.75, 1);
  theme->SetCellValueRange(0.75, 1);
  theme->SetCellSaturationRange(1, 1);

  theme->SetOutlineColor(.5,.5,.5);

  theme->SetSelectedPointColor(1, 1, 1.0);
  theme->SetSelectedCellColor(1, 1, 1.0);

  return theme;
}

vtkViewTheme* vtkViewTheme::CreateMellowTheme()
{
  vtkViewTheme* theme = vtkViewTheme::New();

  theme->SetBackgroundColor(0.6, 0.6, 0.5); // Tan
  theme->SetVertexLabelColor(1, 1, 1);
  theme->SetEdgeLabelColor(.7, .7, 1);

  theme->SetPointColor(0.0, 0.0, 1.0);
  theme->SetPointHueRange(0.667, 0);

  theme->SetCellColor(0.25, 0.25, 0.25);
  theme->SetCellOpacity(0.4);
  theme->SetCellHueRange(0.667, 0);
  theme->SetCellAlphaRange(0.4, 1);
  theme->SetCellValueRange(0.5, 1);
  theme->SetCellSaturationRange(0.5, 1);

  theme->SetOutlineColor(0, 0, 0);

  theme->SetSelectedPointColor(1, 1, 1);
  theme->SetSelectedCellColor(0, 0, 0);

  return theme;
}

void vtkViewTheme::PrintSelf(ostream& os, vtkIndent indent)
{
  this->Superclass::PrintSelf(os, indent);
  os << indent << "PointColor: "
     << this->PointColor[0] << ","
     << this->PointColor[1] << ","
     << this->PointColor[2] << endl;
  os << indent << "PointOpacity: " << this->PointOpacity << endl;
  os << indent << "PointHueRange: "
     << this->PointHueRange[0] << ","
     << this->PointHueRange[1] << endl;
  os << indent << "PointSaturationRange: "
     << this->PointSaturationRange[0] << ","
     << this->PointSaturationRange[1] << endl;
  os << indent << "PointValueRange: "
     << this->PointValueRange[0] << ","
     << this->PointValueRange[1] << endl;
  os << indent << "PointAlphaRange: "
     << this->PointAlphaRange[0] << ","
     << this->PointAlphaRange[1] << endl;
  os << indent << "CellColor: "
     << this->CellColor[0] << ","
     << this->CellColor[1] << ","
     << this->CellColor[2] << endl;
  os << indent << "CellOpacity: " << this->CellOpacity << endl;
  os << indent << "CellHueRange: "
     << this->CellHueRange[0] << ","
     << this->CellHueRange[1] << endl;
  os << indent << "CellSaturationRange: "
     << this->CellSaturationRange[0] << ","
     << this->CellSaturationRange[1] << endl;
  os << indent << "CellValueRange: "
     << this->CellValueRange[0] << ","
     << this->CellValueRange[1] << endl;
  os << indent << "CellAlphaRange: "
     << this->CellAlphaRange[0] << ","
     << this->CellAlphaRange[1] << endl;
  os << indent << "OutlineColor: "
     << this->OutlineColor[0] << ","
     << this->OutlineColor[1] << ","
     << this->OutlineColor[2] << endl;
  os << indent << "SelectedPointColor: "
     << this->SelectedPointColor[0] << ","
     << this->SelectedPointColor[1] << ","
     << this->SelectedPointColor[2] << endl;
  os << indent << "SelectedPointOpacity: " << this->SelectedPointOpacity << endl;
  os << indent << "SelectedCellColor: "
     << this->SelectedCellColor[0] << ","
     << this->SelectedCellColor[1] << ","
     << this->SelectedCellColor[2] << endl;
  os << indent << "SelectedCellOpacity: " << this->SelectedCellOpacity << endl;
  os << indent << "BackgroundColor: "
     << this->BackgroundColor[0] << ","
     << this->BackgroundColor[1] << ","
     << this->BackgroundColor[2] << endl;
  os << indent << "VertexLabelColor: "
     << this->VertexLabelColor[0] << ","
     << this->VertexLabelColor[1] << ","
     << this->VertexLabelColor[2] << endl;
  os << indent << "EdgeLabelColor: "
     << this->EdgeLabelColor[0] << ","
     << this->EdgeLabelColor[1] << ","
     << this->EdgeLabelColor[2] << endl;
}
<commit_msg>ENH:  Changing the ocean theme parameters just a bit.<commit_after>/*=========================================================================

  Program:   Visualization Toolkit
  Module:    vtkViewTheme.cxx

  Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
  All rights reserved.
  See Copyright.txt or http://www.kitware.com/Copyright.htm for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notice for more information.

=========================================================================*/
/*----------------------------------------------------------------------------
 Copyright (c) Sandia Corporation
 See Copyright.txt or http://www.paraview.org/HTML/Copyright.html for details.
----------------------------------------------------------------------------*/

#include "vtkViewTheme.h"

#include "vtkObjectFactory.h"

vtkCxxRevisionMacro(vtkViewTheme, "1.2");
vtkStandardNewMacro(vtkViewTheme);

vtkViewTheme::vtkViewTheme()
{
  this->SetPointColor(1, 1, 1);
  this->SetPointOpacity(1);
  this->SetPointHueRange(0.667, 0);
  this->SetPointSaturationRange(1, 1);
  this->SetPointValueRange(1, 1);
  this->SetPointAlphaRange(1, 1);

  this->SetCellColor(1, 1, 1);
  this->SetCellOpacity(0.5);
  this->SetCellHueRange(0.667, 0);
  this->SetCellSaturationRange(0.5, 1);
  this->SetCellValueRange(0.5, 1);
  this->SetCellAlphaRange(0.5, 1);

  this->SetOutlineColor(0,0,0);

  this->SetSelectedPointColor(1, 0, 1);
  this->SetSelectedPointOpacity(1);
  this->SetSelectedCellColor(1, 0, 1);
  this->SetSelectedCellOpacity(1);

  this->SetBackgroundColor(0.3, 0.3, 0.3);
  this->SetVertexLabelColor(1, 1, 1);
  this->SetEdgeLabelColor(.7, .7, .7);
}

vtkViewTheme::~vtkViewTheme()
{
}

vtkViewTheme* vtkViewTheme::CreateOceanTheme()
{
  vtkViewTheme* theme = vtkViewTheme::New();

  theme->SetBackgroundColor(1, 1, 1);
  theme->SetVertexLabelColor(0, 0, 0);
  theme->SetEdgeLabelColor(.2, .2, .2);

  theme->SetPointColor(0.5, 0.5, 0.5);
  theme->SetPointHueRange(0.667, 0);
  theme->SetPointSaturationRange(0.75, 0.75);
  theme->SetPointValueRange(0.75, 0.75);

  theme->SetCellColor(0.25, 0.25, 0.25);
  theme->SetCellOpacity(0.3);
  theme->SetCellHueRange(0.667, 0);
  theme->SetCellAlphaRange(0.3, 1);
  theme->SetCellValueRange(0.5, 1);
  theme->SetCellSaturationRange(0.5, 1);

  theme->SetOutlineColor(0,0,0);

  theme->SetSelectedPointColor(.8, .3, .8);
  theme->SetSelectedCellColor(.8, .3, .8);

  return theme;
}

vtkViewTheme* vtkViewTheme::CreateNeonTheme()
{
  vtkViewTheme* theme = vtkViewTheme::New();

  theme->SetBackgroundColor(0, 0, 0);
  theme->SetVertexLabelColor(1, 1, 1);
  theme->SetEdgeLabelColor(.7, .7, .7);

  theme->SetPointColor(0.5, 0.5, 0.5);
  theme->SetPointHueRange(0.667, 0);
  theme->SetPointSaturationRange(1, 1);
  theme->SetPointValueRange(1, 1);

  theme->SetCellColor(0.25, 0.25, 0.25);
  theme->SetCellOpacity(0.75);
  theme->SetCellHueRange(0.667, 0);
  theme->SetCellAlphaRange(0.75, 1);
  theme->SetCellValueRange(0.75, 1);
  theme->SetCellSaturationRange(1, 1);

  theme->SetOutlineColor(.5,.5,.5);

  theme->SetSelectedPointColor(1, 1, 1.0);
  theme->SetSelectedCellColor(1, 1, 1.0);

  return theme;
}

vtkViewTheme* vtkViewTheme::CreateMellowTheme()
{
  vtkViewTheme* theme = vtkViewTheme::New();

  theme->SetBackgroundColor(0.6, 0.6, 0.5); // Tan
  theme->SetVertexLabelColor(1, 1, 1);
  theme->SetEdgeLabelColor(.7, .7, 1);

  theme->SetPointColor(0.0, 0.0, 1.0);
  theme->SetPointHueRange(0.667, 0);

  theme->SetCellColor(0.25, 0.25, 0.25);
  theme->SetCellOpacity(0.4);
  theme->SetCellHueRange(0.667, 0);
  theme->SetCellAlphaRange(0.4, 1);
  theme->SetCellValueRange(0.5, 1);
  theme->SetCellSaturationRange(0.5, 1);

  theme->SetOutlineColor(0, 0, 0);

  theme->SetSelectedPointColor(1, 1, 1);
  theme->SetSelectedCellColor(0, 0, 0);

  return theme;
}

void vtkViewTheme::PrintSelf(ostream& os, vtkIndent indent)
{
  this->Superclass::PrintSelf(os, indent);
  os << indent << "PointColor: "
     << this->PointColor[0] << ","
     << this->PointColor[1] << ","
     << this->PointColor[2] << endl;
  os << indent << "PointOpacity: " << this->PointOpacity << endl;
  os << indent << "PointHueRange: "
     << this->PointHueRange[0] << ","
     << this->PointHueRange[1] << endl;
  os << indent << "PointSaturationRange: "
     << this->PointSaturationRange[0] << ","
     << this->PointSaturationRange[1] << endl;
  os << indent << "PointValueRange: "
     << this->PointValueRange[0] << ","
     << this->PointValueRange[1] << endl;
  os << indent << "PointAlphaRange: "
     << this->PointAlphaRange[0] << ","
     << this->PointAlphaRange[1] << endl;
  os << indent << "CellColor: "
     << this->CellColor[0] << ","
     << this->CellColor[1] << ","
     << this->CellColor[2] << endl;
  os << indent << "CellOpacity: " << this->CellOpacity << endl;
  os << indent << "CellHueRange: "
     << this->CellHueRange[0] << ","
     << this->CellHueRange[1] << endl;
  os << indent << "CellSaturationRange: "
     << this->CellSaturationRange[0] << ","
     << this->CellSaturationRange[1] << endl;
  os << indent << "CellValueRange: "
     << this->CellValueRange[0] << ","
     << this->CellValueRange[1] << endl;
  os << indent << "CellAlphaRange: "
     << this->CellAlphaRange[0] << ","
     << this->CellAlphaRange[1] << endl;
  os << indent << "OutlineColor: "
     << this->OutlineColor[0] << ","
     << this->OutlineColor[1] << ","
     << this->OutlineColor[2] << endl;
  os << indent << "SelectedPointColor: "
     << this->SelectedPointColor[0] << ","
     << this->SelectedPointColor[1] << ","
     << this->SelectedPointColor[2] << endl;
  os << indent << "SelectedPointOpacity: " << this->SelectedPointOpacity << endl;
  os << indent << "SelectedCellColor: "
     << this->SelectedCellColor[0] << ","
     << this->SelectedCellColor[1] << ","
     << this->SelectedCellColor[2] << endl;
  os << indent << "SelectedCellOpacity: " << this->SelectedCellOpacity << endl;
  os << indent << "BackgroundColor: "
     << this->BackgroundColor[0] << ","
     << this->BackgroundColor[1] << ","
     << this->BackgroundColor[2] << endl;
  os << indent << "VertexLabelColor: "
     << this->VertexLabelColor[0] << ","
     << this->VertexLabelColor[1] << ","
     << this->VertexLabelColor[2] << endl;
  os << indent << "EdgeLabelColor: "
     << this->EdgeLabelColor[0] << ","
     << this->EdgeLabelColor[1] << ","
     << this->EdgeLabelColor[2] << endl;
}
<|endoftext|>


<commit_before>/*
* Copyright (C) 2008-2011 J-P Nurmi jpnurmi@gmail.com
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
*/

#include "sessionmanager.h"
#include "sessionitem.h"
#include "connection.h"
#include "settings.h"
#include "session.h"
#include <QNetworkConfigurationManager>
#include <IrcCommand>

SessionManager::SessionManager(QDeclarativeContext* context) :
    m_context(context), m_network(0)
{
    updateModel();
}

bool SessionManager::isOnline() const
{
    return m_network && m_network->state() == QNetworkSession::Connected;
}

bool SessionManager::isOffline() const
{
    return !m_network || m_network->state() != QNetworkSession::Connected;
}

void SessionManager::addSession(Session* session)
{
    SessionItem* item = new SessionItem(session);
    connect(item, SIGNAL(alert(QObject*)), SIGNAL(alert(QObject*)));
    connect(item, SIGNAL(channelKeyRequired(QString)), SIGNAL(channelKeyRequired(QString)));
    m_items.append(item);
    updateModel();

    if (ensureNetwork())
        session->open();
}

void SessionManager::removeSession(Session* session)
{
    for (int i = 0; i < m_items.count(); ++i)
    {
        SessionItem* item = static_cast<SessionItem*>(m_items.at(i));
        if (item->session() == session)
        {
            item->quit();
            m_items.removeAt(i);
            item->deleteLater();
            updateModel();
            break;
        }
    }
}

bool SessionManager::ensureNetwork()
{
    if (!m_network || !m_network->isOpen())
    {
        QNetworkConfigurationManager manager;
        if (manager.capabilities() & QNetworkConfigurationManager::NetworkSessionRequired)
        {
            QNetworkConfiguration config = manager.defaultConfiguration();
            if (!m_network)
            {
                m_network = new QNetworkSession(config, this);
                connect(m_network, SIGNAL(stateChanged(QNetworkSession::State)), this, SLOT(onNetworkStateChanged(QNetworkSession::State)));
                connect(m_network, SIGNAL(stateChanged(QNetworkSession::State)), this, SIGNAL(onlineStateChanged()));
                connect(m_network, SIGNAL(stateChanged(QNetworkSession::State)), this, SIGNAL(offlineStateChanged()));
            }
            m_network->open();
        }
    }
    return m_network->isOpen();
}

void SessionManager::restore()
{
    Settings* settings = static_cast<Settings*>(m_context->contextProperty("Settings").value<QObject*>());
    if (settings)
    {
        foreach (const Connection& connection, settings->connections())
            addSession(Session::fromConnection(connection));
    }
}

void SessionManager::save()
{
    Settings* settings = static_cast<Settings*>(m_context->contextProperty("Settings").value<QObject*>());
    if (settings)
    {
        Connections connections;
        foreach (QObject* item, m_items)
        {
            SessionItem* sessionItem = static_cast<SessionItem*>(item);
            Connection connection = sessionItem->session()->toConnection();
            connection.channels = sessionItem->channels();
            connections += connection;
        }
        settings->setConnections(connections);
    }
}

void SessionManager::onNetworkStateChanged(QNetworkSession::State state)
{
    if (state == QNetworkSession::Connected)
    {
        foreach (QObject* item, m_items)
        {
            IrcSession* session = static_cast<SessionItem*>(item)->session();
            if (!session->isActive())
                session->open();
        }
    }
    else if (state == QNetworkSession::Closing)
    {
        foreach (QObject* item, m_items)
        {
            IrcSession* session = static_cast<SessionItem*>(item)->session();
            if (session->isActive())
                session->close();
        }
    }
}

void SessionManager::updateModel()
{
    m_context->setContextProperty("SessionModel", QVariant::fromValue(m_items));
}
<commit_msg>mobile ex: fixed a potential crash in SessionManager<commit_after>/*
* Copyright (C) 2008-2011 J-P Nurmi jpnurmi@gmail.com
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
*/

#include "sessionmanager.h"
#include "sessionitem.h"
#include "connection.h"
#include "settings.h"
#include "session.h"
#include <QNetworkConfigurationManager>
#include <IrcCommand>

SessionManager::SessionManager(QDeclarativeContext* context) :
    m_context(context), m_network(0)
{
    updateModel();
}

bool SessionManager::isOnline() const
{
    return m_network && m_network->state() == QNetworkSession::Connected;
}

bool SessionManager::isOffline() const
{
    return !m_network || m_network->state() != QNetworkSession::Connected;
}

void SessionManager::addSession(Session* session)
{
    SessionItem* item = new SessionItem(session);
    connect(item, SIGNAL(alert(QObject*)), SIGNAL(alert(QObject*)));
    connect(item, SIGNAL(channelKeyRequired(QString)), SIGNAL(channelKeyRequired(QString)));
    m_items.append(item);
    updateModel();

    if (ensureNetwork())
        session->open();
}

void SessionManager::removeSession(Session* session)
{
    for (int i = 0; i < m_items.count(); ++i)
    {
        SessionItem* item = static_cast<SessionItem*>(m_items.at(i));
        if (item->session() == session)
        {
            item->quit();
            m_items.removeAt(i);
            item->deleteLater();
            updateModel();
            break;
        }
    }
}

bool SessionManager::ensureNetwork()
{
    if (!m_network || !m_network->isOpen())
    {
        QNetworkConfigurationManager manager;
        if (manager.capabilities() & QNetworkConfigurationManager::NetworkSessionRequired)
        {
            QNetworkConfiguration config = manager.defaultConfiguration();
            if (!m_network)
            {
                m_network = new QNetworkSession(config, this);
                connect(m_network, SIGNAL(stateChanged(QNetworkSession::State)), this, SLOT(onNetworkStateChanged(QNetworkSession::State)));
                connect(m_network, SIGNAL(stateChanged(QNetworkSession::State)), this, SIGNAL(onlineStateChanged()));
                connect(m_network, SIGNAL(stateChanged(QNetworkSession::State)), this, SIGNAL(offlineStateChanged()));
            }
            m_network->open();
        }
    }
    return !m_network || m_network->isOpen();
}

void SessionManager::restore()
{
    Settings* settings = static_cast<Settings*>(m_context->contextProperty("Settings").value<QObject*>());
    if (settings)
    {
        foreach (const Connection& connection, settings->connections())
            addSession(Session::fromConnection(connection));
    }
}

void SessionManager::save()
{
    Settings* settings = static_cast<Settings*>(m_context->contextProperty("Settings").value<QObject*>());
    if (settings)
    {
        Connections connections;
        foreach (QObject* item, m_items)
        {
            SessionItem* sessionItem = static_cast<SessionItem*>(item);
            Connection connection = sessionItem->session()->toConnection();
            connection.channels = sessionItem->channels();
            connections += connection;
        }
        settings->setConnections(connections);
    }
}

void SessionManager::onNetworkStateChanged(QNetworkSession::State state)
{
    if (state == QNetworkSession::Connected)
    {
        foreach (QObject* item, m_items)
        {
            IrcSession* session = static_cast<SessionItem*>(item)->session();
            if (!session->isActive())
                session->open();
        }
    }
    else if (state == QNetworkSession::Closing)
    {
        foreach (QObject* item, m_items)
        {
            IrcSession* session = static_cast<SessionItem*>(item)->session();
            if (session->isActive())
                session->close();
        }
    }
}

void SessionManager::updateModel()
{
    m_context->setContextProperty("SessionModel", QVariant::fromValue(m_items));
}
<|endoftext|>


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

  Program:   Insight Segmentation & Registration Toolkit
  Module:    itkVotingBinaryImageFilterTest.cxx
  Language:  C++
  Date:      $Date$
  Version:   $Revision$

  Copyright (c) Insight Software Consortium. All rights reserved.
  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notices for more information.

=========================================================================*/
#if defined(_MSC_VER)
#pragma warning ( disable : 4786 )
#endif
#include "itkImage.h"
#include "itkRandomImageSource.h"
#include "itkBinaryThresholdImageFilter.h"
#include "itkVotingBinaryImageFilter.h"
#include "itkTextOutput.h"

int itkVotingBinaryImageFilterTest(int, char* [] )
{
  // Comment the following if you want to use the itk text output window
  itk::OutputWindow::SetInstance(itk::TextOutput::New());

  typedef itk::Image<unsigned short,2> ImageType;

  itk::RandomImageSource<ImageType>::Pointer random;
  random = itk::RandomImageSource<ImageType>::New();
  random->SetMin(   0 );
  random->SetMax( 100 );

  unsigned long randomSize[2];
  randomSize[0] = randomSize[1] = 8;
  random->SetSize(randomSize);

  float spacing[2] = {0.7, 2.1};
  random->SetSpacing( spacing );
  float origin[2] = {15, 400};
  random->SetOrigin( origin );

  ImageType::PixelType foreground =  97; // prime numbers are good testers
  ImageType::PixelType background =  29;

  itk::BinaryThresholdImageFilter<ImageType,ImageType>::Pointer thresholder;
  thresholder =  itk::BinaryThresholdImageFilter<ImageType,ImageType>::New();
  thresholder->SetInput( random->GetOutput() );
  thresholder->SetLowerThreshold(  30 );
  thresholder->SetUpperThreshold( 100 );
  thresholder->SetInsideValue( foreground );
  thresholder->SetOutsideValue( background );

  // Create a voting image
  itk::VotingBinaryImageFilter<ImageType, ImageType>::Pointer voting;
  voting = itk::VotingBinaryImageFilter<ImageType,ImageType>::New();
  voting->SetInput( thresholder->GetOutput());
  voting->SetForegroundValue( foreground );
  voting->SetBackgroundValue( background );

  // define the neighborhood size used for the voting filter (5x5)
  ImageType::SizeType neighRadius;
  neighRadius[0] = 1;
  neighRadius[1] = 1;
  voting->SetRadius(neighRadius);

  voting->SetBirthThreshold( 5 );
  voting->SetSurvivalThreshold( 0 );

  // run the algorithm
  voting->Update();

  itk::ImageRegionIterator<ImageType> it;
  it = itk::ImageRegionIterator<ImageType>(random->GetOutput(),
                               random->GetOutput()->GetBufferedRegion());
  std::cout << "Input image" << std::endl;
  unsigned int i;
  for (i=1; !it.IsAtEnd(); ++i, ++it)
    {
    std::cout << "\t" << it.Get();
    if ((i % 8) == 0)
      {
      std::cout << std::endl;
      }
    }

  it = itk::ImageRegionIterator<ImageType>(thresholder->GetOutput(),
                               thresholder->GetOutput()->GetBufferedRegion());
  std::cout << "Binary image" << std::endl;

  for (i=1; !it.IsAtEnd(); ++i, ++it)
    {
    std::cout << "\t" << it.Get();
    if ((i % 8) == 0)
      {
      std::cout << std::endl;
      }
    }

  std::cout << "Output image" << std::endl;
  it = itk::ImageRegionIterator<ImageType>(voting->GetOutput(),
                               voting->GetOutput()->GetBufferedRegion());
  for (i=1; !it.IsAtEnd(); ++i, ++it)
    {
    std::cout << "\t" << it.Get();
    if ((i % 8) == 0)
      {
      std::cout << std::endl;
      }
    }

  return EXIT_SUCCESS;
}

<commit_msg>ENH: added Print.<commit_after>/*=========================================================================

  Program:   Insight Segmentation & Registration Toolkit
  Module:    itkVotingBinaryImageFilterTest.cxx
  Language:  C++
  Date:      $Date$
  Version:   $Revision$

  Copyright (c) Insight Software Consortium. All rights reserved.
  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notices for more information.

=========================================================================*/
#if defined(_MSC_VER)
#pragma warning ( disable : 4786 )
#endif
#include "itkImage.h"
#include "itkRandomImageSource.h"
#include "itkBinaryThresholdImageFilter.h"
#include "itkVotingBinaryImageFilter.h"
#include "itkTextOutput.h"

int itkVotingBinaryImageFilterTest(int, char* [] )
{
  // Comment the following if you want to use the itk text output window
  itk::OutputWindow::SetInstance(itk::TextOutput::New());

  typedef itk::Image<unsigned short,2> ImageType;

  itk::RandomImageSource<ImageType>::Pointer random;
  random = itk::RandomImageSource<ImageType>::New();
  random->SetMin(   0 );
  random->SetMax( 100 );

  unsigned long randomSize[2];
  randomSize[0] = randomSize[1] = 8;
  random->SetSize(randomSize);

  float spacing[2] = {0.7, 2.1};
  random->SetSpacing( spacing );
  float origin[2] = {15, 400};
  random->SetOrigin( origin );

  ImageType::PixelType foreground =  97; // prime numbers are good testers
  ImageType::PixelType background =  29;

  itk::BinaryThresholdImageFilter<ImageType,ImageType>::Pointer thresholder;
  thresholder =  itk::BinaryThresholdImageFilter<ImageType,ImageType>::New();
  thresholder->SetInput( random->GetOutput() );
  thresholder->SetLowerThreshold(  30 );
  thresholder->SetUpperThreshold( 100 );
  thresholder->SetInsideValue( foreground );
  thresholder->SetOutsideValue( background );

  // Create a voting image
  itk::VotingBinaryImageFilter<ImageType, ImageType>::Pointer voting;
  voting = itk::VotingBinaryImageFilter<ImageType,ImageType>::New();
  voting->SetInput( thresholder->GetOutput());
  voting->SetForegroundValue( foreground );
  voting->SetBackgroundValue( background );

  // define the neighborhood size used for the voting filter (5x5)
  ImageType::SizeType neighRadius;
  neighRadius[0] = 1;
  neighRadius[1] = 1;
  voting->SetRadius(neighRadius);

  voting->SetBirthThreshold( 5 );
  voting->SetSurvivalThreshold( 0 );

  // run the algorithm
  voting->Update();
  voting->Print(std::cout);

  itk::ImageRegionIterator<ImageType> it;
  it = itk::ImageRegionIterator<ImageType>(random->GetOutput(),
                               random->GetOutput()->GetBufferedRegion());
  std::cout << "Input image" << std::endl;
  unsigned int i;
  for (i=1; !it.IsAtEnd(); ++i, ++it)
    {
    std::cout << "\t" << it.Get();
    if ((i % 8) == 0)
      {
      std::cout << std::endl;
      }
    }

  it = itk::ImageRegionIterator<ImageType>(thresholder->GetOutput(),
                               thresholder->GetOutput()->GetBufferedRegion());
  std::cout << "Binary image" << std::endl;

  for (i=1; !it.IsAtEnd(); ++i, ++it)
    {
    std::cout << "\t" << it.Get();
    if ((i % 8) == 0)
      {
      std::cout << std::endl;
      }
    }

  std::cout << "Output image" << std::endl;
  it = itk::ImageRegionIterator<ImageType>(voting->GetOutput(),
                               voting->GetOutput()->GetBufferedRegion());
  for (i=1; !it.IsAtEnd(); ++i, ++it)
    {
    std::cout << "\t" << it.Get();
    if ((i % 8) == 0)
      {
      std::cout << std::endl;
      }
    }

  return EXIT_SUCCESS;
}

<|endoftext|>


<commit_before>//   Copyright 2015 Patrick Putnam
//
//   Licensed under the Apache License, Version 2.0 (the "License");
//   you may not use this file except in compliance with the License.
//   You may obtain a copy of the License at
//
//       http://www.apache.org/licenses/LICENSE-2.0
//
//   Unless required by applicable law or agreed to in writing, software
//   distributed under the License is distributed on an "AS IS" BASIS,
//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//   See the License for the specific language governing permissions and
//   limitations under the License.
#ifndef QTL_LOGGING_PARAMETER_HPP_
#define QTL_LOGGING_PARAMETER_HPP_

#include <boost/property_tree/ptree.hpp>
#include "../common_strings.h"
#include "../logging_parameter.hpp"

#include <boost/lexical_cast.hpp>
#include <boost/foreach.hpp>

extern const string SAMPLING_K;
extern const string PAIRWISE_K;

struct sample_log_params {
    static const unsigned int   DEFAULT_SAMPLE_SIZE = 100;
    static const bool           DEFAULT_PAIRWISE = false;
    unsigned int    sample_size;
    bool            pairwise;

    sample_log_params( unsigned int ss = DEFAULT_SAMPLE_SIZE, bool p = DEFAULT_PAIRWISE ) :
        sample_size(ss)
        , pairwise(p)
    {}

    sample_log_params( boost::property_tree::ptree & params ) :
        sample_size(DEFAULT_SAMPLE_SIZE)
        , pairwise(DEFAULT_PAIRWISE)
    {
        if( params.empty() ) {
            // done for backwards compatiability
            // Check for data in the node
            std::ostringstream tmp;
            tmp << params.data();

            if(! tmp.str().empty() ) {
                // assume that any data was intended to be a sample size
                sample_size = boost::lexical_cast< unsigned int >( tmp.str() );
            }
            return;
        }

        sample_size = params.get< unsigned int >(SIZE_K, sample_size);

        pairwise = params.get< bool >( PAIRWISE_K, pairwise);
        params.put( SIZE_K, sample_size);
        params.put( PAIRWISE_K, pairwise );
    }

    sample_log_params( const sample_log_params & slp ) :
        sample_size( slp.sample_size )
        , pairwise( slp.pairwise ) {
    }

    virtual ~sample_log_params() {}
};

struct qtl_logging_parameter : public logging_parameter {

    std::vector< sample_log_params > m_sampling;

    qtl_logging_parameter( boost::property_tree::ptree & config ) :
        logging_parameter( config )
    {
        boost::property_tree::ptree lconfig;
        lconfig = config.get_child( LOG_BLOCK_K + "." + SAMPLING_K, lconfig );

        if( lconfig.empty() ) return;

        BOOST_FOREACH( auto& v, lconfig ) {
            sample_log_params tmp( v.second );
            m_sampling.push_back( tmp );
        }
    }

    virtual ~qtl_logging_parameter() {}
};
#endif  // QTL_LOGGING_PARAMETER_HPP_
<commit_msg>Changed names<commit_after>//   Copyright 2015 Patrick Putnam
//
//   Licensed under the Apache License, Version 2.0 (the "License");
//   you may not use this file except in compliance with the License.
//   You may obtain a copy of the License at
//
//       http://www.apache.org/licenses/LICENSE-2.0
//
//   Unless required by applicable law or agreed to in writing, software
//   distributed under the License is distributed on an "AS IS" BASIS,
//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//   See the License for the specific language governing permissions and
//   limitations under the License.
#ifndef QTL_LOGGING_PARAMETER_HPP_
#define QTL_LOGGING_PARAMETER_HPP_

#include <boost/property_tree/ptree.hpp>
#include "../common_strings.h"
#include "../logging_parameter.hpp"

#include <boost/lexical_cast.hpp>
#include <boost/foreach.hpp>

extern const string SAMPLING_K;
extern const string PAIRWISE_K;

struct sample_log_params {
    static const unsigned int   DEFAULT_SAMPLE_SIZE = 100;
    static const bool           DEFAULT_PAIRWISE = false;
    unsigned int    sample_size;
    bool            pairwise;

    sample_log_params( unsigned int ss = DEFAULT_SAMPLE_SIZE, bool p = DEFAULT_PAIRWISE ) :
        sample_size(ss)
        , pairwise(p)
    {}

    sample_log_params( boost::property_tree::ptree & params ) :
        sample_size(DEFAULT_SAMPLE_SIZE)
        , pairwise(DEFAULT_PAIRWISE)
    {
        if( params.empty() ) {
            // done for backwards compatiability
            // Check for data in the node
            std::ostringstream tmp;
            tmp << params.data();

            if(! tmp.str().empty() ) {
                // assume that any data was intended to be a sample size
                sample_size = boost::lexical_cast< unsigned int >( tmp.str() );
            }
            return;
        }

        sample_size = params.get< unsigned int >(SIZE_K, sample_size);

        pairwise = params.get< bool >( PAIRWISE_K, pairwise);
        params.put( SIZE_K, sample_size);
        params.put( PAIRWISE_K, pairwise );
    }

    sample_log_params( const sample_log_params & slp ) :
        sample_size( slp.sample_size )
        , pairwise( slp.pairwise ) {
    }

    virtual ~sample_log_params() {}
};

struct qtl_logging_parameter : public logging_parameter {

    std::vector< sample_log_params > m_sampling;

    qtl_logging_parameter( boost::property_tree::ptree & config ) :
        logging_parameter( config )
    {
        boost::property_tree::ptree lconfig;
        lconfig = config.get_child( LOG_BLOCK_K, lconfig );

        boost::property_tree::ptree samps;
        samps = lconfig.get_child( SAMPLING_K, samps );

        BOOST_FOREACH( auto& v, samps ) {
            sample_log_params tmp( v.second );
            m_sampling.push_back( tmp );
        }

        lconfig.put_child( SAMPLING_K, samps );
        config.put_child( LOG_BLOCK_K, lconfig );
    }

    virtual ~qtl_logging_parameter() {}
};
#endif  // QTL_LOGGING_PARAMETER_HPP_
<|endoftext|>


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

#ifndef PCL_SURFACE_IMPL_SURFEL_SMOOTHING_H_
#define PCL_SURFACE_IMPL_SURFEL_SMOOTHING_H_

#include "pcl/surface/surfel_smoothing.h"
#include <pcl/kdtree/kdtree_flann.h>
#include <pcl/kdtree/organized_data.h>

//////////////////////////////////////////////////////////////////////////////////////////////
template <typename PointT, typename PointNT> bool
pcl::SurfelSmoothing<PointT, PointNT>::initCompute ()
{
  if (!PCLBase<PointT>::initCompute ())
    return false;

  if (!normals_)
  {
    PCL_ERROR ("SurfelSmoothing: normal cloud not set\n");
    return false;
  }

  if (input_->points.size () != normals_->points.size ())
  {
    PCL_ERROR ("SurfelSmoothing: number of input points different from the number of given normals\n");
    return false;
  }

  // Initialize the spatial locator
  if (!tree_)
  {
    if (input_->isOrganized ())
      tree_.reset (new pcl::OrganizedDataIndex<PointT> ());
    else
      tree_.reset (new pcl::KdTreeFLANN<PointT> (false));
  }

  // create internal copies of the input - these will be modified
  interm_cloud_ = PointCloudInPtr (new PointCloudIn (*input_));
  interm_normals_ = NormalCloudPtr (new NormalCloud (*normals_));

  return (true);
}

//////////////////////////////////////////////////////////////////////////////////////////////
template <typename PointT, typename PointNT> float
pcl::SurfelSmoothing<PointT, PointNT>::smoothCloudIteration (PointCloudInPtr &output_positions,
                                                             NormalCloudPtr &output_normals)
{
  PCL_INFO ("SurfelSmoothing: cloud smoothing iteration starting ...\n");

  output_positions = PointCloudInPtr (new PointCloudIn);
  output_positions->points.resize (interm_cloud_->points.size ());
  output_normals = NormalCloudPtr (new NormalCloud);
  output_normals->points.resize (interm_cloud_->points.size ());

  std::vector<int> nn_indices;
  std::vector<float> nn_distances;

  std::vector<float> diffs (interm_cloud_->points.size ());
  float total_residual = 0.0f;

  for (size_t i = 0; i < interm_cloud_->points.size (); ++i)
  {
    Eigen::Vector4f smoothed_point  = Eigen::Vector4f::Zero ();
    Eigen::Vector4f smoothed_normal = Eigen::Vector4f::Zero ();

    // get neighbors
    // @todo using 5x the scale for searching instead of all the points to avoid O(N^2)
    tree_->radiusSearch (interm_cloud_->points[i], 5*scale_, nn_indices, nn_distances);
//    PCL_INFO ("NN: %u\n", nn_indices.size ());

    float theta_normalization_factor = 0.0;
    std::vector<float> theta (nn_indices.size ());
    for (size_t nn_index_i = 0; nn_index_i < nn_indices.size (); ++nn_index_i)
    {
      float dist = pcl::squaredEuclideanDistance (interm_cloud_->points[i], input_->points[nn_indices[nn_index_i]]);//interm_cloud_->points[nn_indices[nn_index_i]]);
      float theta_i = exp ( (-1) * dist / scale_squared_);
      theta_normalization_factor += theta_i;

      smoothed_normal += theta_i * interm_normals_->points[nn_indices[nn_index_i]].getNormalVector4fMap ();

      theta[nn_index_i] = theta_i;
    }

    smoothed_normal /= theta_normalization_factor;
    smoothed_normal(3) = 0.0f;
    smoothed_normal.normalize ();

    // find minimum along the normal
    float e_residual;
    smoothed_point = interm_cloud_->points[i].getVector4fMap ();
    while (1)
    {
      e_residual = 0.0f;
      smoothed_point(3) = 0.0f;
      for (size_t nn_index_i = 0; nn_index_i < nn_indices.size (); ++nn_index_i)
      {
        Eigen::Vector4f neighbor = input_->points[nn_indices[nn_index_i]].getVector4fMap ();//interm_cloud_->points[nn_indices[nn_index_i]].getVector4fMap ();
        neighbor(3) = 0.0f;
        float dot_product = smoothed_normal.dot (neighbor - smoothed_point);
        e_residual += theta[nn_index_i] * dot_product;// * dot_product;
      }
      e_residual /= theta_normalization_factor;
      if (e_residual < 1e-5) break;

      smoothed_point = smoothed_point + e_residual * smoothed_normal;
    }

    total_residual += e_residual;

    output_positions->points[i].getVector4fMap () = smoothed_point;
    output_normals->points[i].getNormalVector4fMap () = normals_->points[i].getNormalVector4fMap ();//smoothed_normal;

    // Calculate difference
//    diffs[i] = smoothed_normal.dot (smoothed_point - interm_cloud_->points[i].getVector4fMap ());
  }

  std::cerr << "Total residual after iteration: " << total_residual << std::endl;
  PCL_INFO("SurfelSmoothing done iteration\n");
  return total_residual;
}

template <typename PointT, typename PointNT> void
pcl::SurfelSmoothing<PointT, PointNT>::smoothPoint (size_t &point_index,
                                                    PointT &output_point,
                                                    PointNT &output_normal)
{
  Eigen::Vector4f average_normal = Eigen::Vector4f::Zero ();
  Eigen::Vector4f result_point = input_->points[point_index].getVector4fMap ();
  result_point(3) = 0.0f;

  // @todo parameter
  float error_residual_threshold_ = 1e-9;
  float error_residual = error_residual_threshold_ + 1;
  float last_error_residual = error_residual + 100;

  std::vector<int> nn_indices;
  std::vector<float> nn_distances;

  int big_iterations = 0;
  int max_big_iterations = 500;

  while (fabs (error_residual) < fabs (last_error_residual) -error_residual_threshold_ &&
         big_iterations < max_big_iterations)
  {
    average_normal = Eigen::Vector4f::Zero ();
    big_iterations ++;
//    PCL_INFO ("%f  ", error_residual);
    PointT aux_point; aux_point.x = result_point(0); aux_point.y = result_point(1); aux_point.z = result_point(2);
    tree_->radiusSearch (aux_point, 5*scale_, nn_indices, nn_distances);

    float theta_normalization_factor = 0.0;
    std::vector<float> theta (nn_indices.size ());
    for (size_t nn_index_i = 0; nn_index_i < nn_indices.size (); ++nn_index_i)
    {
      float dist = nn_distances[nn_index_i];
      float theta_i = exp ( (-1) * dist / scale_squared_);
      theta_normalization_factor += theta_i;

      average_normal += theta_i * normals_->points[nn_indices[nn_index_i]].getNormalVector4fMap ();
      theta[nn_index_i] = theta_i;
    }
    average_normal /= theta_normalization_factor;
    average_normal(3) = 0.0f;
    average_normal.normalize ();

    // find minimum along the normal
    float e_residual_along_normal;
    int small_iterations = 0;
    int max_small_iterations = 10;
    while (small_iterations < max_small_iterations)
    {
      small_iterations ++;

      e_residual_along_normal = 0.0f;
      for (size_t nn_index_i = 0; nn_index_i < nn_indices.size (); ++nn_index_i)
      {
        Eigen::Vector4f neighbor = input_->points[nn_indices[nn_index_i]].getVector4fMap ();
        neighbor(3) = 0.0f;
        float dot_product = average_normal.dot (neighbor - result_point);
        e_residual_along_normal += theta[nn_index_i] * dot_product;
      }
      e_residual_along_normal /= theta_normalization_factor;
      if (e_residual_along_normal < 1e-8) break;

      result_point = result_point + e_residual_along_normal * average_normal;
    }

    if (small_iterations == max_small_iterations)
      PCL_INFO ("passed the number of small iterations %d\n", small_iterations);

    last_error_residual = error_residual;
    error_residual = e_residual_along_normal;

    PCL_INFO ("last %f    current %f\n", last_error_residual, error_residual);
  }

  output_point.x = result_point(0);
  output_point.y = result_point(1);
  output_point.z = result_point(2);
  output_normal = normals_->points[point_index];

  if (big_iterations == max_big_iterations)
    PCL_INFO ("passed the number of BIG iterations: %d\n", big_iterations);
}

//////////////////////////////////////////////////////////////////////////////////////////////
template <typename PointT, typename PointNT> void
pcl::SurfelSmoothing<PointT, PointNT>::computeSmoothedCloud (PointCloudInPtr &output_positions,
                                                             NormalCloudPtr &output_normals)
{
  if (!initCompute ())
  {
    PCL_ERROR ("[pcl::SurfelSmoothing::computeSmoothedCloud]: SurfelSmoothing not initialized properly, skipping computeSmoothedCloud ().\n");
    return;
  }

  tree_->setInputCloud (input_);

  output_positions->points.resize (input_->points.size ());
  output_normals->points.resize (input_->points.size ());
  for (size_t i = 0; i < input_->points.size (); ++i)
  {
    smoothPoint (i, output_positions->points[i], output_normals->points[i]);
  }
/*
  // @todo make this a parameter
  size_t min_iterations = 0;
  size_t max_iterations = 200;
  float last_residual = std::numeric_limits<float>::max (), residual;
  for (size_t iteration = 0; iteration < max_iterations; ++iteration)
  {
    PCL_INFO ("Surfel smoothing iteration %u\n", iteration);
    residual = smoothCloudIteration (output_positions, output_normals);
    if (fabs (residual) > fabs (last_residual) -1e-8 && iteration > min_iterations) break;
//    if (fabs (residual) < 0.23) break;

    interm_cloud_ = output_positions;
    interm_normals_ = output_normals;
    last_residual = residual;
  }*/
}

//////////////////////////////////////////////////////////////////////////////////////////////
template <typename PointT, typename PointNT> void
pcl::SurfelSmoothing<PointT, PointNT>::extractSalientFeaturesBetweenScales (PointCloudInPtr &cloud2,
                                                                            NormalCloudPtr &cloud2_normals,
                                                                            boost::shared_ptr<std::vector<int> > &output_features)
{
  if (interm_cloud_->points.size () != cloud2->points.size () ||
      cloud2->points.size () != cloud2_normals->points.size ())
  {
    PCL_ERROR ("[pcl::SurfelSmoothing::extractSalientFeaturesBetweenScales]: Number of points in the clouds does not match.\n");
    return;
  }

  std::vector<float> diffs (cloud2->points.size ());
  for (size_t i = 0; i < cloud2->points.size (); ++i)
    diffs[i] = cloud2_normals->points[i].getNormalVector4fMap ().dot (cloud2->points[i].getVector4fMap () -
                                                                      interm_cloud_->points[i].getVector4fMap ());

  std::vector<int> nn_indices;
  std::vector<float> nn_distances;

  output_features->resize (cloud2->points.size ());
  for (size_t point_i = 0; point_i < cloud2->points.size (); ++point_i)
  {
    // Get neighbors
    tree_->radiusSearch (point_i, scale_, nn_indices, nn_distances);

    bool largest = true;
    bool smallest = true;
    for (std::vector<int>::iterator nn_index_it = nn_indices.begin (); nn_index_it != nn_indices.end (); ++nn_index_it)
    {
      if (diffs[point_i] < diffs[*nn_index_it])
        largest = false;
      else
        smallest = false;
    }

    if (largest == true || smallest == true)
      (*output_features)[point_i] = point_i;
  }
}

#define PCL_INSTANTIATE_SurfelSmoothing(PointT,PointNT) template class PCL_EXPORTS pcl::SurfelSmoothing<PointT, PointNT>;

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

#ifndef PCL_SURFACE_IMPL_SURFEL_SMOOTHING_H_
#define PCL_SURFACE_IMPL_SURFEL_SMOOTHING_H_

#include "pcl/surface/surfel_smoothing.h"
#include <pcl/kdtree/kdtree_flann.h>
#include <pcl/kdtree/organized_data.h>

//////////////////////////////////////////////////////////////////////////////////////////////
template <typename PointT, typename PointNT> bool
pcl::SurfelSmoothing<PointT, PointNT>::initCompute ()
{
  if (!PCLBase<PointT>::initCompute ())
    return false;

  if (!normals_)
  {
    PCL_ERROR ("SurfelSmoothing: normal cloud not set\n");
    return false;
  }

  if (input_->points.size () != normals_->points.size ())
  {
    PCL_ERROR ("SurfelSmoothing: number of input points different from the number of given normals\n");
    return false;
  }

  // Initialize the spatial locator
  if (!tree_)
  {
    if (input_->isOrganized ())
      tree_.reset (new pcl::OrganizedDataIndex<PointT> ());
    else
      tree_.reset (new pcl::KdTreeFLANN<PointT> (false));
  }

  // create internal copies of the input - these will be modified
  interm_cloud_ = PointCloudInPtr (new PointCloudIn (*input_));
  interm_normals_ = NormalCloudPtr (new NormalCloud (*normals_));

  return (true);
}

//////////////////////////////////////////////////////////////////////////////////////////////
template <typename PointT, typename PointNT> float
pcl::SurfelSmoothing<PointT, PointNT>::smoothCloudIteration (PointCloudInPtr &output_positions,
                                                             NormalCloudPtr &output_normals)
{
//  PCL_INFO ("SurfelSmoothing: cloud smoothing iteration starting ...\n");

  output_positions = PointCloudInPtr (new PointCloudIn);
  output_positions->points.resize (interm_cloud_->points.size ());
  output_normals = NormalCloudPtr (new NormalCloud);
  output_normals->points.resize (interm_cloud_->points.size ());

  std::vector<int> nn_indices;
  std::vector<float> nn_distances;

  std::vector<float> diffs (interm_cloud_->points.size ());
  float total_residual = 0.0f;

  for (size_t i = 0; i < interm_cloud_->points.size (); ++i)
  {
    Eigen::Vector4f smoothed_point  = Eigen::Vector4f::Zero ();
    Eigen::Vector4f smoothed_normal = Eigen::Vector4f::Zero ();

    // get neighbors
    // @todo using 5x the scale for searching instead of all the points to avoid O(N^2)
    tree_->radiusSearch (interm_cloud_->points[i], 5*scale_, nn_indices, nn_distances);

    float theta_normalization_factor = 0.0;
    std::vector<float> theta (nn_indices.size ());
    for (size_t nn_index_i = 0; nn_index_i < nn_indices.size (); ++nn_index_i)
    {
      float dist = pcl::squaredEuclideanDistance (interm_cloud_->points[i], input_->points[nn_indices[nn_index_i]]);//interm_cloud_->points[nn_indices[nn_index_i]]);
      float theta_i = exp ( (-1) * dist / scale_squared_);
      theta_normalization_factor += theta_i;

      smoothed_normal += theta_i * interm_normals_->points[nn_indices[nn_index_i]].getNormalVector4fMap ();

      theta[nn_index_i] = theta_i;
    }

    smoothed_normal /= theta_normalization_factor;
    smoothed_normal(3) = 0.0f;
    smoothed_normal.normalize ();

    // find minimum along the normal
    float e_residual;
    smoothed_point = interm_cloud_->points[i].getVector4fMap ();
    while (1)
    {
      e_residual = 0.0f;
      smoothed_point(3) = 0.0f;
      for (size_t nn_index_i = 0; nn_index_i < nn_indices.size (); ++nn_index_i)
      {
        Eigen::Vector4f neighbor = input_->points[nn_indices[nn_index_i]].getVector4fMap ();//interm_cloud_->points[nn_indices[nn_index_i]].getVector4fMap ();
        neighbor(3) = 0.0f;
        float dot_product = smoothed_normal.dot (neighbor - smoothed_point);
        e_residual += theta[nn_index_i] * dot_product;// * dot_product;
      }
      e_residual /= theta_normalization_factor;
      if (e_residual < 1e-5) break;

      smoothed_point = smoothed_point + e_residual * smoothed_normal;
    }

    total_residual += e_residual;

    output_positions->points[i].getVector4fMap () = smoothed_point;
    output_normals->points[i].getNormalVector4fMap () = normals_->points[i].getNormalVector4fMap ();//smoothed_normal;
  }

//  std::cerr << "Total residual after iteration: " << total_residual << std::endl;
//  PCL_INFO("SurfelSmoothing done iteration\n");
  return total_residual;
}

template <typename PointT, typename PointNT> void
pcl::SurfelSmoothing<PointT, PointNT>::smoothPoint (size_t &point_index,
                                                    PointT &output_point,
                                                    PointNT &output_normal)
{
  Eigen::Vector4f average_normal = Eigen::Vector4f::Zero ();
  Eigen::Vector4f result_point = input_->points[point_index].getVector4fMap ();
  result_point(3) = 0.0f;

  // @todo parameter
  float error_residual_threshold_ = 1e-3;
  float error_residual = error_residual_threshold_ + 1;
  float last_error_residual = error_residual + 100;

  std::vector<int> nn_indices;
  std::vector<float> nn_distances;

  int big_iterations = 0;
  int max_big_iterations = 500;

  while (fabs (error_residual) < fabs (last_error_residual) -error_residual_threshold_ &&
         big_iterations < max_big_iterations)
  {
    average_normal = Eigen::Vector4f::Zero ();
    big_iterations ++;
    PointT aux_point; aux_point.x = result_point(0); aux_point.y = result_point(1); aux_point.z = result_point(2);
    tree_->radiusSearch (aux_point, 5*scale_, nn_indices, nn_distances);

    float theta_normalization_factor = 0.0;
    std::vector<float> theta (nn_indices.size ());
    for (size_t nn_index_i = 0; nn_index_i < nn_indices.size (); ++nn_index_i)
    {
      float dist = nn_distances[nn_index_i];
      float theta_i = exp ( (-1) * dist / scale_squared_);
      theta_normalization_factor += theta_i;

      average_normal += theta_i * normals_->points[nn_indices[nn_index_i]].getNormalVector4fMap ();
      theta[nn_index_i] = theta_i;
    }
    average_normal /= theta_normalization_factor;
    average_normal(3) = 0.0f;
    average_normal.normalize ();

    // find minimum along the normal
    float e_residual_along_normal = 2, last_e_residual_along_normal = 3;
    int small_iterations = 0;
    int max_small_iterations = 10;
    while ( fabs (e_residual_along_normal) < fabs (last_e_residual_along_normal) &&
        small_iterations < max_small_iterations)
    {
      small_iterations ++;

      e_residual_along_normal = 0.0f;
      for (size_t nn_index_i = 0; nn_index_i < nn_indices.size (); ++nn_index_i)
      {
        Eigen::Vector4f neighbor = input_->points[nn_indices[nn_index_i]].getVector4fMap ();
        neighbor(3) = 0.0f;
        float dot_product = average_normal.dot (neighbor - result_point);
        e_residual_along_normal += theta[nn_index_i] * dot_product;
      }
      e_residual_along_normal /= theta_normalization_factor;
      if (e_residual_along_normal < 1e-3) break;

      result_point = result_point + e_residual_along_normal * average_normal;
    }

//    if (small_iterations == max_small_iterations)
//      PCL_INFO ("passed the number of small iterations %d\n", small_iterations);

    last_error_residual = error_residual;
    error_residual = e_residual_along_normal;

//    PCL_INFO ("last %f    current %f\n", last_error_residual, error_residual);
  }

  output_point.x = result_point(0);
  output_point.y = result_point(1);
  output_point.z = result_point(2);
  output_normal = normals_->points[point_index];

  if (big_iterations == max_big_iterations)
    PCL_DEBUG ("[pcl::SurfelSmoothing::smoothPoint] Passed the number of BIG iterations: %d\n", big_iterations);
}

//////////////////////////////////////////////////////////////////////////////////////////////
template <typename PointT, typename PointNT> void
pcl::SurfelSmoothing<PointT, PointNT>::computeSmoothedCloud (PointCloudInPtr &output_positions,
                                                             NormalCloudPtr &output_normals)
{
  if (!initCompute ())
  {
    PCL_ERROR ("[pcl::SurfelSmoothing::computeSmoothedCloud]: SurfelSmoothing not initialized properly, skipping computeSmoothedCloud ().\n");
    return;
  }

  tree_->setInputCloud (input_);

  output_positions->header = input_->header;
  output_positions->height = input_->height;
  output_positions->width = input_->width;

  output_normals->header = input_->header;
  output_normals->height = input_->height;
  output_normals->width = input_->width;

  output_positions->points.resize (input_->points.size ());
  output_normals->points.resize (input_->points.size ());
  for (size_t i = 0; i < input_->points.size (); ++i)
  {
    smoothPoint (i, output_positions->points[i], output_normals->points[i]);
  }
}

//////////////////////////////////////////////////////////////////////////////////////////////
template <typename PointT, typename PointNT> void
pcl::SurfelSmoothing<PointT, PointNT>::extractSalientFeaturesBetweenScales (PointCloudInPtr &cloud2,
                                                                            NormalCloudPtr &cloud2_normals,
                                                                            boost::shared_ptr<std::vector<int> > &output_features)
{
  if (interm_cloud_->points.size () != cloud2->points.size () ||
      cloud2->points.size () != cloud2_normals->points.size ())
  {
    PCL_ERROR ("[pcl::SurfelSmoothing::extractSalientFeaturesBetweenScales]: Number of points in the clouds does not match.\n");
    return;
  }

  std::vector<float> diffs (cloud2->points.size ());
  for (size_t i = 0; i < cloud2->points.size (); ++i)
    diffs[i] = cloud2_normals->points[i].getNormalVector4fMap ().dot (cloud2->points[i].getVector4fMap () -
                                                                      interm_cloud_->points[i].getVector4fMap ());

  std::vector<int> nn_indices;
  std::vector<float> nn_distances;

  output_features->resize (cloud2->points.size ());
  for (size_t point_i = 0; point_i < cloud2->points.size (); ++point_i)
  {
    // Get neighbors
    tree_->radiusSearch (point_i, scale_, nn_indices, nn_distances);

    bool largest = true;
    bool smallest = true;
    for (std::vector<int>::iterator nn_index_it = nn_indices.begin (); nn_index_it != nn_indices.end (); ++nn_index_it)
    {
      if (diffs[point_i] < diffs[*nn_index_it])
        largest = false;
      else
        smallest = false;
    }

    if (largest == true || smallest == true)
      (*output_features)[point_i] = point_i;
  }
}

#define PCL_INSTANTIATE_SurfelSmoothing(PointT,PointNT) template class PCL_EXPORTS pcl::SurfelSmoothing<PointT, PointNT>;

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