<commit_before>/*******************************
Copyright (c) 2016-2019 Grégoire Angerand

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
**********************************/

#include <y/core/FixedArray.h>
#include <y/core/Vector.h>

#include <y/mem/allocators.h>
#include <y/core/Range.h>
#include <y/math/Vec.h>
#include <y/utils/log.h>
#include <y/utils/perf.h>
#include <y/utils/name.h>

#include <typeindex>
#include <thread>

using namespace y;

struct ComponentRuntimeInfo {
	usize component_size = 0;
	void (*create)(void* dst, usize count) = nullptr;
	void (*destroy)(void* ptr, usize count) = nullptr;
	void (*move)(void* dst, void* src, usize count) = nullptr;

	template<typename T>
	static ComponentRuntimeInfo from_type() {
		return {
			sizeof(T),
			[](void* dst, usize count) {
				T* it = static_cast<T*>(dst);
				const T* end = it + count;
				for(; it != end; ++it) {
					::new(it) T();
				}
			},
			[](void* ptr, usize count) {
				T* it = static_cast<T*>(ptr);
				const T* end = it + count;
				for(; it != end; ++it) {
					it->~T();
				}
			},
			[](void* dst, void* src, usize count) {
				const T* beg = static_cast<T*>(src);
				const T* end = beg + count;
				std::move(beg, end, static_cast<T*>(dst));
			},
		};
	}
};

class Archetype;

static constexpr usize entities_per_chunk = 1024;

template<typename... Args>
struct ComponentIterator {
	public:
		static constexpr usize component_count = sizeof...(Args);

		using difference_type = usize;
		using iterator_category = std::random_access_iterator_tag;

		using reference = std::tuple<Args&...>;

		reference operator*() const {
			return make_refence_tuple<0>();
		}

		bool operator==(const ComponentIterator& other) const {
			return _index == other._index && _chunks == other._chunks;
		}

		bool operator!=(const ComponentIterator& other) const {
			return !operator==(other);
		}

		ComponentIterator& operator++() {
			++_index;
			return *this;
		}

		ComponentIterator& operator--() {
			--_index;
			return *this;
		}

		ComponentIterator operator++(int) {
			const auto it = *this;
			++*this;
			return it;
		}

		ComponentIterator operator--(int) {
			const auto it = *this;
			--*this;
			return it;
		}

		difference_type operator-(const ComponentIterator& other) const {
			return _index - other._index;
		}

		ComponentIterator& operator+=(usize n) {
			_index += n;
			return *this;
		}

		ComponentIterator& operator-=(usize n) {
			_index -= n;
			return *this;
		}

		ComponentIterator operator+(usize n) const {
			auto it = *this;
			it += n;
			return it;
		}

		ComponentIterator operator-(usize n) const {
			auto it = *this;
			it -= n;
			return it;
		}

	private:
		friend class Archetype;

		template<usize I = 0>
		auto make_refence_tuple() const {
			const usize chunk_index = _index / entities_per_chunk;
			const usize item_index = _index % entities_per_chunk;
			using type = std::remove_reference_t<std::tuple_element_t<I, reference>>;

			void* offset_chunk = static_cast<u8*>(_chunks[chunk_index]) + _offsets[I];
			type* chunk = static_cast<type*>(offset_chunk);
			if constexpr(I + 1 == component_count) {
				return std::tie(chunk[item_index]);
			} else {
				return std::tuple_cat(std::tie(chunk[item_index]),
									  make_refence_tuple<I + 1>());
			}
		}

		usize _index = 0;
		void** _chunks = nullptr;
		std::array<usize, component_count> _offsets;
};

class Archetype : NonCopyable {

	public:
		template<typename... Args>
		static Archetype create() {
			Archetype arc(sizeof...(Args));
			arc.set_types<0, Args...>();
			arc.add_chunk();
			return arc;
		}

		Archetype(Archetype&&) = default;
		Archetype& operator=(Archetype&&) = default;

		~Archetype() {
			for(usize i = 0; i != _component_count; ++i) {
				_component_infos[i].destroy(_chunk_data.last(), _last_chunk_size);
			}
			for(usize c = 0; c + 1 < _chunk_data.size(); ++c) {
				for(usize i = 0; i != _component_count; ++i) {
					_component_infos[i].destroy(_chunk_data[c], entities_per_chunk);
				}
			}

			for(void* c : _chunk_data) {
				_allocator.deallocate(c, _chunk_byte_size);
			}
		}

		usize size() const {
			return (_chunk_data.size() - 1) * entities_per_chunk + _last_chunk_size;
		}

		template<typename... Args>
		auto view() {
			ComponentIterator<Args...> begin;
			build_iterator<0>(begin);
			const auto end = begin + size();
			return core::Range(begin, end);
		}

		void add_entity() {
			if(_last_chunk_size == entities_per_chunk) {
				add_chunk();
			}
			u8* chunk_data = static_cast<u8*>(_chunk_data.last());
			for(usize i = 0; i != _component_count; ++i) {
				const usize offset = _component_offsets[i];
				_component_infos[i].create(chunk_data + offset, 1);
			}
			++_last_chunk_size;
		}

	private:
		Archetype(usize component_count) :
				_component_count(component_count),
				_component_offsets(std::make_unique<usize[]>(component_count)),
				_component_infos(std::make_unique<ComponentRuntimeInfo[]>(component_count)),
				_allocator(memory::global_allocator()) {
		}

		template<usize I, typename... Args>
		void set_types() {
			if constexpr(I < sizeof...(Args)) {
				using component_type = std::tuple_element_t<I, std::tuple<Args...>>;
				_component_offsets[I] = _chunk_byte_size;
				_component_infos[I] = ComponentRuntimeInfo::from_type<component_type>();
				_component_types.emplace_back(typeid(remove_cvref_t<component_type>));

				_chunk_byte_size = memory::align_up_to(_chunk_byte_size, sizeof(component_type));
				_chunk_byte_size += sizeof(component_type) * entities_per_chunk;

				set_types<I + 1, Args...>();
			}
		}

		template<typename T>
		usize type_index() const {
			const std::type_index type = typeid(T);
			for(usize i = 0; i != _component_count; ++i) {
				if(_component_types[i] == type) {
					return i;
				}
			}
			return y_fatal("Unknown component type.");
		}

		template<usize I, typename... Args>
		void build_iterator(ComponentIterator<Args...>& it) {
			if constexpr(I < sizeof...(Args)) {
				using reference = typename ComponentIterator<Args...>::reference;
				using type = remove_cvref_t<std::tuple_element_t<I, reference>>;
				it._offsets[I] = _component_offsets[type_index<type>()];
				build_iterator<I + 1>(it);
			} else {
				it._chunks = _chunk_data.begin();
			}
		}

		void add_chunk() {
			y_debug_assert(_last_chunk_size == entities_per_chunk || _chunk_data.is_empty());
			_last_chunk_size = 0;
			_chunk_data.emplace_back(_allocator.allocate(_chunk_byte_size));
		}

		usize _component_count = 0;
		std::unique_ptr<usize[]> _component_offsets;
		std::unique_ptr<ComponentRuntimeInfo[]> _component_infos;

		core::Vector<void*> _chunk_data;
		usize _last_chunk_size = 0;

		core::Vector<std::type_index> _component_types;

		memory::PolymorphicAllocatorContainer _allocator;
		usize _chunk_byte_size = 0;
};

int main() {
	Archetype arc = Archetype::create<int, float>();

	y_debug_assert(arc.size() == 0);

	arc.add_entity();
	arc.add_entity();

	y_debug_assert(arc.size() == 2);

	int base = 0;
	for(auto [i] : arc.view<int>()) {
		i = ++base;
	}

	for(auto [i] : arc.view<const int>()) {
		log_msg(fmt("% %", ct_type_name<decltype(i)>(), i));
	}
	return 0;
}

<commit_msg>ECS stuff<commit_after>/*******************************
Copyright (c) 2016-2019 Grégoire Angerand

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
**********************************/

#include <y/core/FixedArray.h>
#include <y/core/Vector.h>

#include <y/mem/allocators.h>
#include <y/core/Range.h>
#include <y/math/Vec.h>
#include <y/utils/log.h>
#include <y/utils/perf.h>
#include <y/utils/name.h>
#include <y/utils/sort.h>

#include <atomic>
#include <thread>

namespace y {
namespace detail {
static std::atomic<u32> global_type_index = 0;
}

template<typename T>
static u32 type_index() {
	static u32 index = detail::global_type_index++;
	return index;
}

class Archetype;
class EntityWorld;
class EntityBuilder;

static constexpr usize entities_per_chunk = 1024;

class EntityID {
	public:
		EntityID(u32 index = invalid_index, u32 version = 0) : _index(index), _version(version) {
		}

		u32 index() const {
			return _index;
		}

		u32 version() const {
			return _version;
		}

		bool is_valid() const {
			return _index != invalid_index;
		}

		u64 as_u64() const {
			return (u64(_index) << 32) | _version;
		}

	private:
		static constexpr u32 invalid_index = u32(-1);

		u32 _index = invalid_index;
		u32 _version = 0;
};

struct EntityData {
	EntityID id;
	Archetype* archetype = nullptr;
	usize archetype_index = 0;
};

template<typename... Args>
struct ComponentIterator {
	public:
		static constexpr usize component_count = sizeof...(Args);

		using difference_type = usize;
		using iterator_category = std::random_access_iterator_tag;

		using reference = std::tuple<Args&...>;

		reference operator*() const {
			return make_refence_tuple<0>();
		}

		bool operator==(const ComponentIterator& other) const {
			return _index == other._index && _chunks == other._chunks;
		}

		bool operator!=(const ComponentIterator& other) const {
			return !operator==(other);
		}

		ComponentIterator& operator++() {
			++_index;
			return *this;
		}

		ComponentIterator& operator--() {
			--_index;
			return *this;
		}

		ComponentIterator operator++(int) {
			const auto it = *this;
			++*this;
			return it;
		}

		ComponentIterator operator--(int) {
			const auto it = *this;
			--*this;
			return it;
		}

		difference_type operator-(const ComponentIterator& other) const {
			return _index - other._index;
		}

		ComponentIterator& operator+=(usize n) {
			_index += n;
			return *this;
		}

		ComponentIterator& operator-=(usize n) {
			_index -= n;
			return *this;
		}

		ComponentIterator operator+(usize n) const {
			auto it = *this;
			it += n;
			return it;
		}

		ComponentIterator operator-(usize n) const {
			auto it = *this;
			it -= n;
			return it;
		}

	private:
		friend class Archetype;

		template<usize I = 0>
		auto make_refence_tuple() const {
			const usize chunk_index = _index / entities_per_chunk;
			const usize item_index = _index % entities_per_chunk;
			using type = std::remove_reference_t<std::tuple_element_t<I, reference>>;

			void* offset_chunk = static_cast<u8*>(_chunks[chunk_index]) + _offsets[I];
			type* chunk = static_cast<type*>(offset_chunk);
			if constexpr(I + 1 == component_count) {
				return std::tie(chunk[item_index]);
			} else {
				return std::tuple_cat(std::tie(chunk[item_index]),
									  make_refence_tuple<I + 1>());
			}
		}

		usize _index = 0;
		void** _chunks = nullptr;
		std::array<usize, component_count> _offsets;
};

struct ComponentRuntimeInfo {
	usize chunk_offset = 0;
	usize component_size = 0;

	void (*create)(void* dst, usize count) = nullptr;
	void (*destroy)(void* ptr, usize count) = nullptr;
	void (*move)(void* dst, void* src, usize count) = nullptr;

	u32 type_id = u32(-1);

#ifdef Y_DEBUG
	std::string_view type_name = "unknown";
#endif

	void create_offset(void* chunk, usize index, usize count) const {
		create(static_cast<u8*>(chunk) + chunk_offset + index * component_size, count);
		log_msg(fmt("chunk = % + %[%]", chunk, chunk_offset, index));
	}

	void destroy_offset(void* chunk, usize index, usize count) const {
		destroy(static_cast<u8*>(chunk) + chunk_offset + index * component_size, count);
		log_msg(fmt("chunk = % + %[%]", chunk, chunk_offset, index));
	}

	void move_offset(void* dst, void* chunk, usize index, usize count) const {
		move(dst, static_cast<u8*>(chunk) + chunk_offset + index * component_size, count);
		log_msg(fmt("chunk = % + %[%]", chunk, chunk_offset, index));
	}

	template<typename T>
	static ComponentRuntimeInfo from_type(usize offset = 0) {
		return {
			offset,
			sizeof(T),
			[](void* dst, usize count) {
				log_msg(fmt("creating % %", count, ct_type_name<T>()));
				T* it = static_cast<T*>(dst);
				const T* end = it + count;
				for(; it != end; ++it) {
					::new(it) T();
				}
			},
			[](void* ptr, usize count) {
				log_msg(fmt("destroying % %", count, ct_type_name<T>()));
				T* it = static_cast<T*>(ptr);
				const T* end = it + count;
				for(; it != end; ++it) {
					it->~T();
				}
			},
			[](void* dst, void* src, usize count) {
				log_msg(fmt("moving % %", count, ct_type_name<T>()));
				T* it = static_cast<T*>(src);
				const T* end = it + count;
				T* out = static_cast<T*>(dst);
				while(it != end) {
					*out++ = std::move(*it++);
				}
			},
			type_index<T>(),

#ifdef Y_DEBUG
			ct_type_name<T>()
#endif
		};
	}
};

class Archetype : NonCopyable {

	public:
		template<typename... Args>
		static Archetype create() {
			Archetype arc(sizeof...(Args));
			arc.set_types<0, Args...>();
			arc.add_chunk();
			return arc;
		}

		Archetype(Archetype&&) = default;
		Archetype& operator=(Archetype&&) = default;

		~Archetype() {
			if(_component_infos) {
				for(usize i = 0; i != _component_count; ++i) {
					_component_infos[i].destroy_offset(_chunk_data.last(), 0, _last_chunk_size);
				}
				for(usize c = 0; c + 1 < _chunk_data.size(); ++c) {
					for(usize i = 0; i != _component_count; ++i) {
						_component_infos[i].destroy_offset(_chunk_data[c], 0, entities_per_chunk);
					}
				}

				for(void* c : _chunk_data) {
					_allocator.deallocate(c, _chunk_byte_size);
				}
			}
		}

		template<typename... Args>
		auto view() {
			ComponentIterator<Args...> begin;
			build_iterator<0>(begin);
			const auto end = begin + size();
			return core::Range(begin, end);
		}

		usize size() const {
			return (_chunk_data.size() - 1) * entities_per_chunk + _last_chunk_size;
		}

		core::Span<ComponentRuntimeInfo> component_infos() const {
			return core::Span<ComponentRuntimeInfo>(_component_infos.get(), _component_count);
		}

		void add_entity() {
			add_entities(1);
		}

		void add_entities(usize count) {
			if(_last_chunk_size == entities_per_chunk) {
				add_chunk();
			}

			const usize left_in_chunk = entities_per_chunk - _last_chunk_size;
			const usize first = std::min(left_in_chunk, count);

			void* chunk_data = _chunk_data.last();
			for(usize i = 0; i != _component_count; ++i) {
				_component_infos[i].create_offset(chunk_data, _last_chunk_size, first);
			}
			_last_chunk_size += first;

			if(first != count) {
				add_entities(count - first);
			}
		}

	private:
		friend class EntityWorld;

		Archetype(usize component_count) :
				_component_count(component_count),
				_component_infos(std::make_unique<ComponentRuntimeInfo[]>(component_count)),
				_allocator(memory::global_allocator()) {
		}

		template<usize I, typename... Args>
		void set_types() {
			if constexpr(I < sizeof...(Args)) {
				using component_type = std::tuple_element_t<I, std::tuple<Args...>>;
				_component_infos[I] = ComponentRuntimeInfo::from_type<component_type>();
				set_types<I + 1, Args...>();
			} else {
				log_msg(fmt("arch => %", ct_type_name<std::tuple<Args...>>()));
				const auto cmp = [](const ComponentRuntimeInfo& a, const ComponentRuntimeInfo& b) { return a.type_id < b.type_id; };
				sort(_component_infos.get(), _component_infos.get() + _component_count, cmp);

				y_debug_assert(_chunk_byte_size == 0);
				for(usize i = 0; i != _component_count; ++i) {
					_component_infos[i].chunk_offset = _chunk_byte_size;

					const usize size = _component_infos[i].component_size;
					_chunk_byte_size = memory::align_up_to(_chunk_byte_size, size);
					_chunk_byte_size += size * entities_per_chunk;
				}
			}
		}

		template<typename T>
		const ComponentRuntimeInfo* info() const {
			const u32 index = type_index<T>();
			for(usize i = 0; i != _component_count; ++i) {
				if(_component_infos[i].type_id == index) {
					return &_component_infos[i];
				}
			}
			return y_fatal("Unknown component type.");
		}

		template<usize I, typename... Args>
		void build_iterator(ComponentIterator<Args...>& it) {
			if constexpr(I < sizeof...(Args)) {
				using reference = typename ComponentIterator<Args...>::reference;
				using type = remove_cvref_t<std::tuple_element_t<I, reference>>;
				it._offsets[I] = info<type>()->chunk_offset;
				build_iterator<I + 1>(it);
			} else {
				it._chunks = _chunk_data.begin();
			}
		}

		void transfer_to(Archetype* arc, core::MutableSpan<EntityData> entities) {
			//y_fatal("unimplemented");
			const usize start = arc->size();
			arc->add_entities(entities.size());

			usize other_index = 0;
			for(usize i = 0; i != _component_count; ++i) {
				ComponentRuntimeInfo* other_info = nullptr;
				for(; other_index != arc->_component_count; ++other_index) {
					if(arc->_component_infos[other_index].type_id == _component_infos[i].type_id) {
						other_info = &arc->_component_infos[other_index];
						break;
					}
				}
				if(other_info) {
					for(usize e = 0; e != entities.size(); ++e) {
						EntityData& data = entities[e];
						const usize src_chunk_index = data.archetype_index / entities_per_chunk;
						const usize src_item_index = data.archetype_index % entities_per_chunk;

						const usize dst_index = start + e;
						const usize dst_chunk_index = dst_index / entities_per_chunk;
						const usize dst_item_index = dst_index % entities_per_chunk;
						const usize offset = other_info->chunk_offset + dst_item_index * other_info->component_size;
						void* dst = static_cast<u8*>(arc->_chunk_data[dst_chunk_index]) + offset;

						_component_infos[i].move_offset(dst, _chunk_data[src_chunk_index], src_item_index, 1);
					}
				}
			}

			for(usize e = 0; e != entities.size(); ++e) {
				EntityData& data = entities[e];
				data.archetype = arc;
				data.archetype_index = start + e;
			}

		}

		bool matches_type_indexes(core::Span<u32> type_indexes) const {
			y_debug_assert(std::is_sorted(type_indexes.begin(), type_indexes.end()));
			if(type_indexes.size() != _component_count) {
				return false;
			}
			for(usize i = 0; i != type_indexes.size(); ++i) {
				if(type_indexes[i] != _component_infos[i].type_id) {
					return false;
				}
			}
			return true;
		}

		void add_chunk() {
			y_debug_assert(_last_chunk_size == entities_per_chunk || _chunk_data.is_empty());
			_last_chunk_size = 0;
			_chunk_data.emplace_back(_allocator.allocate(_chunk_byte_size));
		}

		usize _component_count = 0;
		std::unique_ptr<ComponentRuntimeInfo[]> _component_infos;

		core::Vector<void*> _chunk_data;
		usize _last_chunk_size = 0;

		memory::PolymorphicAllocatorContainer _allocator;
		usize _chunk_byte_size = 0;
};

struct EntityBuilder : NonCopyable {
	public:
		EntityBuilder(EntityID id, EntityWorld& world) : _id(id), _world(world) {
		}

	private:
		EntityID _id;
		EntityWorld& _world;
};

class EntityWorld : NonCopyable {
	public:
		EntityID create_entity() {
			_entities.emplace_back();
			EntityData& ent = _entities.last();
			return ent.id = EntityID(_entities.size() - 1);
		}

		template<typename T>
		void add_component(EntityID id) {
			if(!exists(id)) {
				y_fatal("Entity doesn't exists.");
			}

			EntityData& data = _entities[id.index()];
			Archetype* old_arc = data.archetype;
			Archetype* new_arc = nullptr;

			core::Vector<u32> types;
			{
				{
					if(old_arc) {
						for(const ComponentRuntimeInfo& info : old_arc->component_infos()) {
							types << info.type_id;
						}
					}
					types << type_index<T>();
					sort(types.begin(), types.end());
				}

				for(Archetype& arc : _archetypes) {
					if(arc.matches_type_indexes(types)) {
						new_arc = &arc;
						break;
					}
				}

				if(!new_arc) {
					new_arc = &_archetypes.emplace_back(Archetype::create<T>()); // THIS IS FUCKED
				}
			}

			y_debug_assert(new_arc->_component_count == types.size());
			if(old_arc) {
				old_arc->transfer_to(new_arc, data);
			} else {
				new_arc->add_entity();
				data.archetype = new_arc;
			}
		}

		bool exists(EntityID id) const {
			if(id.index() >= _entities.size()) {
				return false;
			}
			return _entities[id.index()].id.version() == id.version();
		}

	private:
		core::Vector<EntityData> _entities;
		core::Vector<Archetype> _archetypes;
};
}

using namespace y;

struct Tester : NonCopyable {
	Tester() : x(0xFDFEFDFE12345678) {
	}

	Tester(Tester&& other) : x(other.x) {
		y_debug_assert(x == 0x0F0F0F0F0F0F0F0F || x == 0xFDFEFDFE12345678);
		other.x = 0x0F0F0F0F0F0F0F0F;
		log_msg("moved");
	}

	Tester& operator=(Tester&&) {
		y_fatal("!");
		return *this;
	}

	~Tester() {
		y_debug_assert(x == 0x0F0F0F0F0F0F0F0F || x == 0xFDFEFDFE12345678);
		log_msg("destroyed");
	}

	u64 x = 0;
};

int main() {
	EntityWorld world;

	EntityID id = world.create_entity();
	world.add_component<Tester>(id);
	world.add_component<int>(id);
	world.add_component<float>(id);

	/*for(auto [i] : arc.view<const int>()) {
		log_msg(fmt("% %", ct_type_name<decltype(i)>(), i));
	}*/

	log_msg("Ok");
	return 0;
}

<|endoftext|>


<commit_before>/*
 *  Software License Agreement (BSD License)
 *
 *  Copyright (c) 2016-2020, Natalnet Laboratory for Perceptual Robotics
 *  All rights reserved.
 *  Redistribution and use in source and binary forms, with or without modification, are permitted provided
 *  that the following conditions are met:
 *
 *  1. Redistributions of source code must retain the above copyright notice, this list of conditions and
 *     the following disclaimer.
 *
 *  2. 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.
 *
 *  3. Neither the name of the copyright holder 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 HOLDER 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.
 *
 *  Author:
 *
 *  Bruno Silva
 */

#include <cstdio>
#include <string>

#include <event_logger.h>
#include <feature_tracker.h>

using namespace std;

/* #####################################################
 * #####                                           #####
 * #####               Private Impl.               #####
 * #####                                           #####
 * #####################################################
 */

float FeatureTracker::get_avg_track_length()
{
	const size_t N = tracklets_.size();

	size_t sum = 0;
	for(size_t i = 0; i < N; i++)
	{
		sum += (size_t) tracklets_[i].pts2D_.size();
	}

	return float(sum)/N;
}

void FeatureTracker::print_track_info()
{
	const size_t N = tracklets_.size();

	for(size_t i = 0; i < N; i++)
	{
		const size_t M = tracklets_[i].pts2D_.size();

		printf("track[%lu]: (size: %lu)\n\t", i, M);
		for(size_t j = 0; j < M; j++)
		{
			printf("[%lu](%f,%f)->", tracklets_[i].start_ + j, tracklets_[i].pts2D_[j].x, tracklets_[i].pts2D_[j].y);
		}
		printf("\n");
	}
}

float FeatureTracker::get_time_per_frame()
{
	float total_time = 0.0;
	for(size_t i = 0; i < op_time_.size(); i++)
	{
		total_time += op_time_[i];
	}

	return total_time;
}

bool FeatureTracker::write_tracking_info()
{
	if(tracking_info_.is_open())
	{
		if(frame_idx_ == 0)
		{
			//Add comment to the first line of file
			tracking_info_ << "#keypoints_at_motion added_pts inliers\n";
			tracking_info_ << 0 << " " << curr_pts_.size() << " " << 0 << "\n";
		}
		else
		{
			tracking_info_ << (curr_pts_.size() - added_pts_.size()) << " " << added_pts_.size() << " " << num_inliers_ << "\n";
		}
	}

	return tracking_info_.good();
}

bool FeatureTracker::write_timing_info()
{
	if(timing_info_.is_open())
	{
		if(frame_idx_ == 0)
		{
			//Add comment to the first line of file
			timing_info_ << "#tracking_time ransac_time detection_time\n";
		}

		timing_info_ << op_time_[0] << " " << op_time_[1] << " " << op_time_[2] << "\n";
	}

	return timing_info_.good();
}

bool FeatureTracker::write_heatmap_info()
{
	if(heatmap_info_.is_open())
	{
		if(frame_idx_ == 0)
		{
			//Add comment to the first line of file
			heatmap_info_ << "#(kp0_x, kp0_y), (kp1_x, kp1_y),..., (kpMi_x, kpMi_y)\n";
		}

		for(size_t i = 0; i < curr_pts_.size(); i++)
		{
			heatmap_info_ << "(" << (int) curr_pts_[i].x << "," << (int) curr_pts_[i].y << ") ";
		}
		heatmap_info_ << "\n";
	}

	return heatmap_info_.good();
}

/* #####################################################
 * #####                                           #####
 * #####               Public Impl.                #####
 * #####                                           #####
 * #####################################################
 */

FeatureTracker::FeatureTracker():
	initialized_(false),
	frame_idx_(0),
	num_inliers_(0),
	min_pts_(600),
	max_pts_(5000)
{

}

FeatureTracker::FeatureTracker(const int& min_pts, const int& max_pts, const bool& log_stats):
	initialized_(false),
	frame_idx_(0),
	num_inliers_(0),
	min_pts_(min_pts),
	max_pts_(max_pts)
{
	if(log_stats)
	{
		initialize_logger("timing_stats.txt", "tracking_stats.txt", "heatmap_stats.txt");
	}
}

void FeatureTracker::initialize_logger(const string& timing_file_name, const string& tracking_file_name,
		                               const string& heatmap_file_name)
{
	timing_info_.open(timing_file_name.c_str());
	if(!timing_info_.is_open())
	{
		MLOG_ERROR(EventLogger::M_TRACKING, "@FeatureTracker::initialize_logger: \
			                                there is a problem with the supplied \
			                                file for the timing information.\n");
		exit(-1);
	}

	tracking_info_.open(tracking_file_name.c_str());
	if(!tracking_info_.is_open())
	{
		MLOG_ERROR(EventLogger::M_TRACKING, "@FeatureTracker::initialize_logger: \
			                                there is a problem with the supplied \
			                                file for the tracking information.\n");
		exit(-1);
	}

	heatmap_info_.open(heatmap_file_name.c_str());
	if(!heatmap_info_.is_open())
	{
		MLOG_ERROR(EventLogger::M_TRACKING, "@FeatureTracker::initialize_logger: \
			                                there is a problem with the supplied \
			                                file for the heatmap information.\n");
		exit(-1);
	}

	MLOG_INFO(EventLogger::M_TRACKING, "@FeatureTracker::initialize_logger: saving \
		                               tracking information to %s\n",
		                               tracking_file_name.c_str());
	MLOG_INFO(EventLogger::M_TRACKING, "@FeatureTracker::initialize_logger: saving \
		                               timing information to %s\n",
		                               timing_file_name.c_str());
	MLOG_INFO(EventLogger::M_TRACKING, "@FeatureTracker::initialize_logger: saving \
		                               heatmap information to %s\n",
		                               heatmap_file_name.c_str());
}<commit_msg>Reordered initialization list to clear warning messages.<commit_after>/*
 *  Software License Agreement (BSD License)
 *
 *  Copyright (c) 2016-2020, Natalnet Laboratory for Perceptual Robotics
 *  All rights reserved.
 *  Redistribution and use in source and binary forms, with or without modification, are permitted provided
 *  that the following conditions are met:
 *
 *  1. Redistributions of source code must retain the above copyright notice, this list of conditions and
 *     the following disclaimer.
 *
 *  2. 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.
 *
 *  3. Neither the name of the copyright holder 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 HOLDER 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.
 *
 *  Author:
 *
 *  Bruno Silva
 */

#include <cstdio>
#include <string>

#include <event_logger.h>
#include <feature_tracker.h>

using namespace std;

/* #####################################################
 * #####                                           #####
 * #####               Private Impl.               #####
 * #####                                           #####
 * #####################################################
 */

float FeatureTracker::get_avg_track_length()
{
	const size_t N = tracklets_.size();

	size_t sum = 0;
	for(size_t i = 0; i < N; i++)
	{
		sum += (size_t) tracklets_[i].pts2D_.size();
	}

	return float(sum)/N;
}

void FeatureTracker::print_track_info()
{
	const size_t N = tracklets_.size();

	for(size_t i = 0; i < N; i++)
	{
		const size_t M = tracklets_[i].pts2D_.size();

		printf("track[%lu]: (size: %lu)\n\t", i, M);
		for(size_t j = 0; j < M; j++)
		{
			printf("[%lu](%f,%f)->", tracklets_[i].start_ + j, tracklets_[i].pts2D_[j].x, tracklets_[i].pts2D_[j].y);
		}
		printf("\n");
	}
}

float FeatureTracker::get_time_per_frame()
{
	float total_time = 0.0;
	for(size_t i = 0; i < op_time_.size(); i++)
	{
		total_time += op_time_[i];
	}

	return total_time;
}

bool FeatureTracker::write_tracking_info()
{
	if(tracking_info_.is_open())
	{
		if(frame_idx_ == 0)
		{
			//Add comment to the first line of file
			tracking_info_ << "#keypoints_at_motion added_pts inliers\n";
			tracking_info_ << 0 << " " << curr_pts_.size() << " " << 0 << "\n";
		}
		else
		{
			tracking_info_ << (curr_pts_.size() - added_pts_.size()) << " " << added_pts_.size() << " " << num_inliers_ << "\n";
		}
	}

	return tracking_info_.good();
}

bool FeatureTracker::write_timing_info()
{
	if(timing_info_.is_open())
	{
		if(frame_idx_ == 0)
		{
			//Add comment to the first line of file
			timing_info_ << "#tracking_time ransac_time detection_time\n";
		}

		timing_info_ << op_time_[0] << " " << op_time_[1] << " " << op_time_[2] << "\n";
	}

	return timing_info_.good();
}

bool FeatureTracker::write_heatmap_info()
{
	if(heatmap_info_.is_open())
	{
		if(frame_idx_ == 0)
		{
			//Add comment to the first line of file
			heatmap_info_ << "#(kp0_x, kp0_y), (kp1_x, kp1_y),..., (kpMi_x, kpMi_y)\n";
		}

		for(size_t i = 0; i < curr_pts_.size(); i++)
		{
			heatmap_info_ << "(" << (int) curr_pts_[i].x << "," << (int) curr_pts_[i].y << ") ";
		}
		heatmap_info_ << "\n";
	}

	return heatmap_info_.good();
}

/* #####################################################
 * #####                                           #####
 * #####               Public Impl.                #####
 * #####                                           #####
 * #####################################################
 */

FeatureTracker::FeatureTracker():
	initialized_(false),
	frame_idx_(0),
	min_pts_(600),
	max_pts_(5000),
	num_inliers_(0)
{

}

FeatureTracker::FeatureTracker(const int& min_pts, const int& max_pts, const bool& log_stats):
	initialized_(false),
	frame_idx_(0),
	min_pts_(min_pts),
	max_pts_(max_pts),
	num_inliers_(0)
{
	if(log_stats)
	{
		initialize_logger("timing_stats.txt", "tracking_stats.txt", "heatmap_stats.txt");
	}
}

void FeatureTracker::initialize_logger(const string& timing_file_name, const string& tracking_file_name,
		                               const string& heatmap_file_name)
{
	timing_info_.open(timing_file_name.c_str());
	if(!timing_info_.is_open())
	{
		MLOG_ERROR(EventLogger::M_TRACKING, "@FeatureTracker::initialize_logger: \
			                                there is a problem with the supplied \
			                                file for the timing information.\n");
		exit(-1);
	}

	tracking_info_.open(tracking_file_name.c_str());
	if(!tracking_info_.is_open())
	{
		MLOG_ERROR(EventLogger::M_TRACKING, "@FeatureTracker::initialize_logger: \
			                                there is a problem with the supplied \
			                                file for the tracking information.\n");
		exit(-1);
	}

	heatmap_info_.open(heatmap_file_name.c_str());
	if(!heatmap_info_.is_open())
	{
		MLOG_ERROR(EventLogger::M_TRACKING, "@FeatureTracker::initialize_logger: \
			                                there is a problem with the supplied \
			                                file for the heatmap information.\n");
		exit(-1);
	}

	MLOG_INFO(EventLogger::M_TRACKING, "@FeatureTracker::initialize_logger: saving \
		                               tracking information to %s\n",
		                               tracking_file_name.c_str());
	MLOG_INFO(EventLogger::M_TRACKING, "@FeatureTracker::initialize_logger: saving \
		                               timing information to %s\n",
		                               timing_file_name.c_str());
	MLOG_INFO(EventLogger::M_TRACKING, "@FeatureTracker::initialize_logger: saving \
		                               heatmap information to %s\n",
		                               heatmap_file_name.c_str());
}<|endoftext|>


<commit_before><commit_msg>gui: change scale bar view<commit_after><|endoftext|>


<commit_before>
#include "RVD.h"

namespace P_RVD
{
	RestrictedVoronoiDiagram::RestrictedVoronoiDiagram(Mesh* _M, Points* _P)
	{
		p_Mesh = _M;
		p_Points = _P;

		seeds_n = 5;
	}

	Vector3d RestrictedVoronoiDiagram::computeCenter(const Vector3i index_triangle)
	{
		Vector3d p1 = p_Mesh->meshVertices.getPoint(index_triangle.x);
		Vector3d p2 = p_Mesh->meshVertices.getPoint(index_triangle.y);
		Vector3d p3 = p_Mesh->meshVertices.getPoint(index_triangle.z);

		return Math::computeCenter(p1, p2, p3);
	}

	Vector3d RestrictedVoronoiDiagram::computeCenter(const t_index t1, const t_index t2, const t_index t3)
	{
		return computeCenter(Vector3i((int)t1, (int)t2, (int)t3));
	}

	std::vector<int> RestrictedVoronoiDiagram::findNearestPoints(const Vector3d _center, int _n)
	{
		std::map<double, t_index> dis_index_map;
		std::vector<int> nearest_N_index;
		std::vector<double> temp_dis;
		double t;
		for (int i = 0; i < p_Points->points_nb; ++i)
		{
			t = Math::computeDistance(p_Points->m_points[i], _center);

			while (dis_index_map.count(t) != 0)
				t += 0.00000000001;
			dis_index_map.insert(std::pair<double, t_index>(t, i));

			temp_dis.push_back(t);
		}

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

		for (int i = 0; i < _n; ++i)
		{
			nearest_N_index.push_back(dis_index_map[temp_dis[i]]);
		}
		return nearest_N_index;
	}

	bool RestrictedVoronoiDiagram::compute_RVD()
	{
		face_begin = 0;
		face_end = p_Mesh->meshFacets.getFacetsNumber();

		Polygon F;
		/*
			compute the RVD of each facet and each seed
		*/
		for (t_index t = face_begin; t < face_end; ++t)
		{
			Facet temp_facet = p_Mesh->meshFacets.getFacet(t);
			current_center = computeCenter(temp_facet.m_v1, temp_facet.m_v2, temp_facet.m_v3);

			current_near_points = findNearestPoints(current_center, seeds_n);

			for (t_index i = 0; i < seeds_n; ++i)
			{
				current_seed = current_near_points[i];

				F.initialize_from_mesh_facet(p_Mesh, t);

				/*
					compute the intersection between a cell and a facet
				*/
				intersect_cell_facet(current_seed, F);
			}
		}
		return true;
	}

	Polygon* RestrictedVoronoiDiagram::intersect_cell_facet(t_index seed, Polygon& F)
	{
		Vector3d temp_seed_position = p_Points->getPoint(seed);
		seed_neighbors = findNearestPoints(temp_seed_position, seeds_n);

		Polygon* ping = &F;
		Polygon* pong = &polygon_buffer;

		for (int i = 0; i < seeds_n; ++i)
		{
			int j = seed_neighbors[i];

			clip_by_plane(*ping, *pong, seed, (t_index)j);
			//swap ping and pong
			swap_polygons(ping, pong);
		}
		return &F;
	}

	void RestrictedVoronoiDiagram::swap_polygons(Polygon*& ping, Polygon*& pong)
	{
		if (ping != &empty_polygon && ping != &polygon_buffer) {
			// First clipping operation, ping points to F
			// (current facet copied)
			ping = &polygon_buffer;
			pong = &empty_polygon;
		}
		else {
			P_RVD::geo_swap(ping, pong);
		}
	}

	void RestrictedVoronoiDiagram::clip_by_plane(Polygon& ping, Polygon& pong, t_index i, t_index j)
	{
		// pong is the result of ping
		ping.clip_by_plane(pong, *p_Points, i, j);
	}
}<commit_msg>add intersect_cell_facet<commit_after>
#include "RVD.h"

namespace P_RVD
{
	RestrictedVoronoiDiagram::RestrictedVoronoiDiagram(Mesh* _M, Points* _P)
	{
		p_Mesh = _M;
		p_Points = _P;

		seeds_n = 5;
	}

	Vector3d RestrictedVoronoiDiagram::computeCenter(const Vector3i index_triangle)
	{
		Vector3d p1 = p_Mesh->meshVertices.getPoint(index_triangle.x);
		Vector3d p2 = p_Mesh->meshVertices.getPoint(index_triangle.y);
		Vector3d p3 = p_Mesh->meshVertices.getPoint(index_triangle.z);

		return Math::computeCenter(p1, p2, p3);
	}

	Vector3d RestrictedVoronoiDiagram::computeCenter(const t_index t1, const t_index t2, const t_index t3)
	{
		return computeCenter(Vector3i((int)t1, (int)t2, (int)t3));
	}

	std::vector<int> RestrictedVoronoiDiagram::findNearestPoints(const Vector3d _center, int _n)
	{
		std::map<double, t_index> dis_index_map;
		std::vector<int> nearest_N_index;
		std::vector<double> temp_dis;
		double t;
		for (int i = 0; i < p_Points->points_nb; ++i)
		{
			t = Math::computeDistance(p_Points->m_points[i], _center);

			while (dis_index_map.count(t) != 0)
				t += 0.00000000001;
			dis_index_map.insert(std::pair<double, t_index>(t, i));

			temp_dis.push_back(t);
		}

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

		for (int i = 0; i < _n; ++i)
		{
			nearest_N_index.push_back(dis_index_map[temp_dis[i]]);
		}
		return nearest_N_index;
	}

	bool RestrictedVoronoiDiagram::compute_RVD()
	{
		face_begin = 0;
		face_end = p_Mesh->meshFacets.getFacetsNumber();

		Polygon F;
		/*
			compute the RVD of each facet and each seed
		*/
		for (t_index t = face_begin; t < face_end; ++t)
		{
			Facet temp_facet = p_Mesh->meshFacets.getFacet(t);
			current_center = computeCenter(temp_facet.m_v1, temp_facet.m_v2, temp_facet.m_v3);

			current_near_points = findNearestPoints(current_center, seeds_n);

			for (t_index i = 0; i < seeds_n; ++i)
			{
				current_seed = current_near_points[i];

				F.initialize_from_mesh_facet(p_Mesh, t);

				/*
					compute the intersection between a cell and a facet
				*/
				current_polygon = intersect_cell_facet(current_seed, F);

				//muniplate the current polygon
			}
		}
		return true;
	}

	Polygon* RestrictedVoronoiDiagram::intersect_cell_facet(t_index seed, Polygon& F)
	{
		Vector3d temp_seed_position = p_Points->getPoint(seed);
		seed_neighbors = findNearestPoints(temp_seed_position, seeds_n);

		Polygon* ping = &F;
		Polygon* pong = &polygon_buffer;

		for (int i = 0; i < seeds_n; ++i)
		{
			int j = seed_neighbors[i];

			clip_by_plane(*ping, *pong, seed, (t_index)j);
			//swap ping and pong
			swap_polygons(ping, pong);
		}
		//swap the ping polygon and pong polygon
		//the result must be stored in the ping polygons
		return ping;
	}

	void RestrictedVoronoiDiagram::swap_polygons(Polygon*& ping, Polygon*& pong)
	{
		if (ping != &empty_polygon && ping != &polygon_buffer) {
			// First clipping operation, ping points to F
			// (current facet copied)
			ping = &polygon_buffer;
			pong = &empty_polygon;
		}
		else {
			P_RVD::geo_swap(ping, pong);
		}
	}

	void RestrictedVoronoiDiagram::clip_by_plane(Polygon& ping, Polygon& pong, t_index i, t_index j)
	{
		// pong is the result of ping
		ping.clip_by_plane(pong, *p_Points, i, j);
	}
}<|endoftext|>


<commit_before>/*
 * ---------------------------------------------------------------------
 * Numenta Platform for Intelligent Computing (NuPIC)
 * Copyright (C) 2013, Numenta, Inc.  Unless you have purchased from
 * Numenta, Inc. a separate commercial license for this software code, the
 * following terms and conditions apply:
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 3 as
 * published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 * See the GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see http://www.gnu.org/licenses.
 *
 * http://numenta.org/licenses/
 * ---------------------------------------------------------------------
 */

/**
 * Aligned memory allocation, needed when working with SSE.
 */

#ifndef NTA_ALIGNED_ALLOC_HPP
#define NTA_ALIGNED_ALLOC_HPP

#ifdef NUPIC2
#error "AlignedAlloc.hpp is not used and should not be part of NuPIC 2"
#endif

#ifdef NTA_PLATFORM_win32
#include <malloc.h> // for _aligned_malloc and _aligned_free
#endif

#include <stdlib.h>

//--------------------------------------------------------------------------------
/**
 * Provides aligned memory allocation and deallocation in a cross-platform fashion.
 * Working with aligned memory is more efficient when working with SSE instructions
 * because there are specialized, fast instructions to load aligned memory into the
 * XMM registers.
 *
 * On darwin86, malloc is guaranteed to return an aligned pointer:
 * "The malloc(), calloc(), valloc(), realloc(), and reallocf() functions allo-
 *  cate memory.  The allocated memory is aligned such that it can be used for
 *  any data type, including AltiVec- and SSE-related types.  The free() func-
 *  tion frees allocations that were created via the preceding allocation func-
 *  tions."
 *
 * However on Windows, special functions need to be used to achieve alignment.
 *
 * Note that there needs to be exactly as many calls to AlignedFree as there
 * are calls to AlignedMalloc.
 */
namespace nta {

  //--------------------------------------------------------------------------------
  /**
   * Aligned memory allocation. Call AlignedFree to deallocate.
   *
   * Parameters:
   * ==========
   * - size: size of the requested memory allocation, in bytes
   */
  inline void* AlignedMalloc(size_t size)
  {
#ifdef NTA_PLATFORM_win32
    // 16 is the alignment value we need for SSE
    return _aligned_malloc(size, 16);
#else
    return malloc(size);
#endif
  }

  //--------------------------------------------------------------------------------
  /**
   * Aligned memory deallocation. Call AlignedMalloc to allocate.
   *
   * Parameters:
   * ==========
   * - ptr: pointer to the memory to deallocate
   */
  inline void AlignedFree(void* ptr)
  {
#ifdef NTA_PLATFORM_win32
    _aligned_free(ptr);
#else
    free(ptr);
#endif
  }

}; // end namespace nta

//--------------------------------------------------------------------------------
#endif //NTA_ALIGNED_ALLOC_HPP
<commit_msg>AlignedAlloc.hpp is not intended for NUPIC2<commit_after><|endoftext|>


<commit_before>// $Header$

//__________________________________________________________________________
// ITSDigitsInfo
//
//

#include <Reve/TTreeTools.h>

#include "ITSDigitsInfo.h"
//#include <AliITSresponseSDD.h>
#include <AliITSCalibrationSDD.h>
#include <AliITSdigit.h>
#include <AliITSdigitSPD.h>

using namespace Reve;
using namespace Alieve;
using namespace std;

ClassImp(ITSDigitsInfo)

/**************************************************************************/

ITSDigitsInfo::ITSDigitsInfo() :
  TObject(),
  ReferenceCount(),
  fSPDmap(), fSDDmap(), fSSDmap(),
  fTree (0),
  fGeom (0),
  fSegSPD(0), fSegSDD(0), fSegSSD(0)
{}

/**************************************************************************/

ITSDigitsInfo:: ~ITSDigitsInfo()
{
  map<Int_t, TClonesArray*>::iterator j;
  for(j = fSPDmap.begin(); j != fSPDmap.end(); ++j)
    delete j->second;
  for(j = fSDDmap.begin(); j != fSDDmap.end(); ++j)
    delete j->second;
  for(j = fSSDmap.begin(); j != fSSDmap.end(); ++j)
    delete j->second;

  delete fSegSPD; delete fSegSDD; delete fSegSSD;
  delete fGeom;
  delete fTree;
}

/**************************************************************************/

void ITSDigitsInfo::SetTree(TTree* tree)
{
  static const Exc_t eH("ITSDigitsInfo::SetTree ");

  if(fGeom == 0) {
    fGeom = new AliITSgeom();
    fGeom->ReadNewFile("$REVESYS/alice-data/ITSgeometry.det");
    if(fGeom == 0)
      throw(eH + "can not load ITS geometry \n");
  }

  fTree = tree;

  SetITSSegmentation();

  // create tables for scaling
  // lowest scale factor refers to unscaled ITS module
  fSPDScaleX[0] = 1;
  fSPDScaleZ[0] = 1;
  fSDDScaleX[0] = 1;
  fSDDScaleZ[0] = 1;
  fSSDScale [0] = 1;
  // spd lows resolution is in the level of 8x2 readout chips
  Int_t nx = 8; // fSegSPD->Npx()/8; // 32
  Int_t nz = 6; // fSegSPD->Npz()/2; // 128

  fSPDScaleX[1] = Int_t(nx);
  fSPDScaleZ[1] = Int_t(nz);
  fSPDScaleX[2] = Int_t(nx*2);
  fSPDScaleZ[2] = Int_t(nz*2);
  fSPDScaleX[3] = Int_t(nx*3);
  fSPDScaleZ[3] = Int_t(nz*3);
  fSPDScaleX[4] = Int_t(nx*4);
  fSPDScaleZ[4] = Int_t(nz*4);

  fSDDScaleX[1] = 2;
  fSDDScaleZ[1] = 2;
  fSDDScaleX[2] = 8;
  fSDDScaleZ[2] = 8;
  fSDDScaleX[3] = 16;
  fSDDScaleZ[3] = 16;
  fSDDScaleX[4] = 25;
  fSDDScaleZ[4] = 25;

  fSSDScale[1] = 3;
  fSSDScale[2] = 9;
  fSSDScale[3] = 20;
  fSSDScale[4] = 30;

  // lowest scale factor refers unscaled ITS module
  fSPDScaleX[0] = 1;
  fSPDScaleZ[0] = 1;
  fSDDScaleX[0] = 1;
  fSDDScaleZ[0] = 1;
  fSSDScale [0] = 1;
}

/**************************************************************************/

void ITSDigitsInfo::SetITSSegmentation()
{
  // SPD
  fSegSPD = new AliITSsegmentationSPD(fGeom);
  //SPD geometry
  Int_t m;
  Float_t fNzSPD=160;
  Float_t fZ1pitchSPD=0.0425; Float_t fZ2pitchSPD=0.0625;
  Float_t fHlSPD=3.48;

  fSPDZCoord[0]=fZ1pitchSPD -fHlSPD;
  for (m=1; m<fNzSPD; m++) {
    Double_t dz=fZ1pitchSPD;
    if (m==31 || m==32 || m==63  || m==64  || m==95 || m==96 ||
        m==127 || m==128) dz=fZ2pitchSPD;
    fSPDZCoord[m]=fSPDZCoord[m-1]+dz;
  }

  for (m=0; m<fNzSPD; m++) {
    Double_t dz=1.*fZ1pitchSPD;
    if (m==31 || m==32 || m==63  || m==64  || m==95 || m==96 ||
	m==127 || m==128) dz=1.*fZ2pitchSPD;
    fSPDZCoord[m]-=dz;
  }

  // end of SPD geometry

  // SDD
  // response replaced by Calibration (March 2006).
  AliITSresponseSDD*   resp1 = new AliITSresponseSDD();
  AliITSCalibrationSDD* cal1 = new AliITSCalibrationSDD;
  cal1->SetResponse(resp1);
  fSegSDD = new AliITSsegmentationSDD(fGeom, cal1);

  // SSD
  fSegSSD = new AliITSsegmentationSSD(fGeom);
}

void ITSDigitsInfo::GetSPDLocalZ(Int_t j, Float_t& z)
{
  z = fSPDZCoord[j];
}

/**************************************************************************/

TClonesArray* ITSDigitsInfo::GetDigits(Int_t mod, Int_t subdet)
{
  switch(subdet) {
  case 0: {
    TClonesArray* digitsSPD = 0;
    map<Int_t, TClonesArray*>::iterator i = fSPDmap.find(mod);
    if(i == fSPDmap.end()) {
      fTree->SetBranchAddress("ITSDigitsSPD",&digitsSPD);
      fTree->GetEntry(mod);
      fSPDmap[mod] = digitsSPD;
      return digitsSPD;
    } else {
      return i->second;
    }
    break;
  }
  case 1: {
    TClonesArray* digitsSDD = 0;
    map<Int_t, TClonesArray*>::iterator i = fSDDmap.find(mod);
    if(i == fSDDmap.end()) {
      fTree->SetBranchAddress("ITSDigitsSDD",&digitsSDD);
      fTree->GetEntry(mod);
      fSDDmap[mod] = digitsSDD;
      return digitsSDD;
    } else {
      return i->second;
    }
    break;
  }
  case 2: {
    TClonesArray* digitsSSD = 0;
    map<Int_t, TClonesArray*>::iterator i = fSSDmap.find(mod);
    if(i == fSSDmap.end()) {
      fTree->SetBranchAddress("ITSDigitsSSD",&digitsSSD);
      fTree->GetEntry(mod);
      fSSDmap[mod] = digitsSSD;
      return digitsSSD;
    } else {
      return i->second;
    }
    break;
  }
  default:
    return 0;
  } //end switch
  return 0;
}

/**************************************************************************/

void ITSDigitsInfo::Print(Option_t* ) const
{
  printf("*********************************************************\n");
  printf("SPD module dimension (%f,%f) \n",fSegSPD->Dx()*0.0001, fSegSPD->Dz()*0.0001);
  printf("SPD first,last module:: %d,%d \n", fGeom->GetStartSPD(),fGeom->GetLastSPD() );
  printf("SPD num cells per module (x::%d,z::%d)\n",fSegSPD->Npx(), fSegSPD->Npz());
  Int_t iz=0,ix = 0;
  printf("SPD dimesion of (%d,%d) in pixel(%f,%f) \n", ix,iz, fSegSPD->Dpx(ix), fSegSPD->Dpz(iz));
  iz = 32;
  printf("SPD dimesion of pixel (%d,%d) are (%f,%f) \n", ix,iz, fSegSPD->Dpx(ix)*0.001, fSegSPD->Dpz(iz)*0.001);

  printf("*********************************************************\n");
  printf("SDD module dimension (%f,%f) \n",fSegSDD->Dx()*0.0001, fSegSDD->Dz()*0.0001);
  printf("SDD first,last module:: %d,%d \n", fGeom->GetStartSDD(),fGeom->GetLastSDD() );
  printf("SDD num cells per module (x::%d,z::%d)\n",fSegSDD->Npx(), fSegSDD->Npz());
  printf("SDD dimesion of pixel are (%f,%f) \n", fSegSDD->Dpx(1)*0.001,fSegSDD->Dpz(1)*0.001);
  printf("*********************************************************\n");
  printf("SSD module dimension (%f,%f) \n",fSegSSD->Dx()*0.0001, fSegSSD->Dz()*0.0001);
  printf("SSD first,last module:: %d,%d \n", fGeom->GetStartSSD(),fGeom->GetLastSSD() );
  printf("SSD strips in module %d \n",fSegSSD->Npx());
  printf("SSD strip sizes are (%f,%f) \n", fSegSSD->Dpx(1),fSegSSD->Dpz(1));
  fSegSSD->SetLayer(5); Float_t ap,an;  fSegSSD->Angles(ap,an);
  printf("SSD layer 5 stereoP %f stereoN %f angle \n",ap,an);
  fSegSSD->SetLayer(6);  fSegSSD->Angles(ap,an);
  printf("SSD layer 6 stereoP %f stereoN %f angle \n",ap,an);
}

/*
  printf("num cells %d,%d scaled %d,%d \n",fSegSPD->Npz(),fSegSPD->Npx(),Nz,Nx);
  printf("%d digits in ITSModule %d\n",ne, module);
  Float_t zn = i*(3.48*2)/Nz - 3.48 ;
  Float_t xo =  -fSegSPD->Dx()*0.00005 + fSegSPD->Dpx(0)*od->GetCoord2()*0.0001;
  Float_t xn =  -fSegSPD->Dx()*0.00005 + j*0.0001*fSegSPD->Dx()/Nx;
  Float_t dpx = 0.0001*fSegSPD->Dx()/Nx;
  Float_t dpz = 3.48*2/Nz;
  printf("Z::original (%3f) scaled (%3f, %3f) \n", zo, zn-dpz/2, zn+dpz/2);
  printf("X::original (%3f) scaled (%3f, %3f) \n", xo, xn-dpx/2, xn+dpx/2);
  printf("%d,%d maped to %d,%d \n", od->GetCoord1(), od->GetCoord2(), i,j );
*/
<commit_msg>Read digits via TBranch::GetEntry() instead of TTree::GetEntry() as SPD/SDD/SSD entries are interleaved.<commit_after>// $Header$

//__________________________________________________________________________
// ITSDigitsInfo
//
//

#include <Reve/TTreeTools.h>

#include "ITSDigitsInfo.h"
//#include <AliITSresponseSDD.h>
#include <AliITSCalibrationSDD.h>
#include <AliITSdigit.h>
#include <AliITSdigitSPD.h>

using namespace Reve;
using namespace Alieve;
using namespace std;

ClassImp(ITSDigitsInfo)

/**************************************************************************/

ITSDigitsInfo::ITSDigitsInfo() :
  TObject(),
  ReferenceCount(),
  fSPDmap(), fSDDmap(), fSSDmap(),
  fTree (0),
  fGeom (0),
  fSegSPD(0), fSegSDD(0), fSegSSD(0)
{}

/**************************************************************************/

ITSDigitsInfo:: ~ITSDigitsInfo()
{
  map<Int_t, TClonesArray*>::iterator j;
  for(j = fSPDmap.begin(); j != fSPDmap.end(); ++j)
    delete j->second;
  for(j = fSDDmap.begin(); j != fSDDmap.end(); ++j)
    delete j->second;
  for(j = fSSDmap.begin(); j != fSSDmap.end(); ++j)
    delete j->second;

  delete fSegSPD; delete fSegSDD; delete fSegSSD;
  delete fGeom;
  delete fTree;
}

/**************************************************************************/

void ITSDigitsInfo::SetTree(TTree* tree)
{
  static const Exc_t eH("ITSDigitsInfo::SetTree ");

  if(fGeom == 0) {
    fGeom = new AliITSgeom();
    fGeom->ReadNewFile("$REVESYS/alice-data/ITSgeometry.det");
    if(fGeom == 0)
      throw(eH + "can not load ITS geometry \n");
  }

  fTree = tree;

  SetITSSegmentation();

  // create tables for scaling
  // lowest scale factor refers to unscaled ITS module
  fSPDScaleX[0] = 1;
  fSPDScaleZ[0] = 1;
  fSDDScaleX[0] = 1;
  fSDDScaleZ[0] = 1;
  fSSDScale [0] = 1;
  // spd lows resolution is in the level of 8x2 readout chips
  Int_t nx = 8; // fSegSPD->Npx()/8; // 32
  Int_t nz = 6; // fSegSPD->Npz()/2; // 128

  fSPDScaleX[1] = Int_t(nx);
  fSPDScaleZ[1] = Int_t(nz);
  fSPDScaleX[2] = Int_t(nx*2);
  fSPDScaleZ[2] = Int_t(nz*2);
  fSPDScaleX[3] = Int_t(nx*3);
  fSPDScaleZ[3] = Int_t(nz*3);
  fSPDScaleX[4] = Int_t(nx*4);
  fSPDScaleZ[4] = Int_t(nz*4);

  fSDDScaleX[1] = 2;
  fSDDScaleZ[1] = 2;
  fSDDScaleX[2] = 8;
  fSDDScaleZ[2] = 8;
  fSDDScaleX[3] = 16;
  fSDDScaleZ[3] = 16;
  fSDDScaleX[4] = 25;
  fSDDScaleZ[4] = 25;

  fSSDScale[1] = 3;
  fSSDScale[2] = 9;
  fSSDScale[3] = 20;
  fSSDScale[4] = 30;

  // lowest scale factor refers unscaled ITS module
  fSPDScaleX[0] = 1;
  fSPDScaleZ[0] = 1;
  fSDDScaleX[0] = 1;
  fSDDScaleZ[0] = 1;
  fSSDScale [0] = 1;
}

/**************************************************************************/

void ITSDigitsInfo::SetITSSegmentation()
{
  // SPD
  fSegSPD = new AliITSsegmentationSPD(fGeom);
  //SPD geometry
  Int_t m;
  Float_t fNzSPD=160;
  Float_t fZ1pitchSPD=0.0425; Float_t fZ2pitchSPD=0.0625;
  Float_t fHlSPD=3.48;

  fSPDZCoord[0]=fZ1pitchSPD -fHlSPD;
  for (m=1; m<fNzSPD; m++) {
    Double_t dz=fZ1pitchSPD;
    if (m==31 || m==32 || m==63  || m==64  || m==95 || m==96 ||
        m==127 || m==128) dz=fZ2pitchSPD;
    fSPDZCoord[m]=fSPDZCoord[m-1]+dz;
  }

  for (m=0; m<fNzSPD; m++) {
    Double_t dz=1.*fZ1pitchSPD;
    if (m==31 || m==32 || m==63  || m==64  || m==95 || m==96 ||
	m==127 || m==128) dz=1.*fZ2pitchSPD;
    fSPDZCoord[m]-=dz;
  }

  // end of SPD geometry

  // SDD
  // response replaced by Calibration (March 2006).
  AliITSresponseSDD*   resp1 = new AliITSresponseSDD();
  AliITSCalibrationSDD* cal1 = new AliITSCalibrationSDD;
  cal1->SetResponse(resp1);
  fSegSDD = new AliITSsegmentationSDD(fGeom, cal1);

  // SSD
  fSegSSD = new AliITSsegmentationSSD(fGeom);
}

void ITSDigitsInfo::GetSPDLocalZ(Int_t j, Float_t& z)
{
  z = fSPDZCoord[j];
}

/**************************************************************************/

TClonesArray* ITSDigitsInfo::GetDigits(Int_t mod, Int_t subdet)
{
  switch(subdet) {
    case 0: {
      TClonesArray* digitsSPD = 0;
      map<Int_t, TClonesArray*>::iterator i = fSPDmap.find(mod);
      if(i == fSPDmap.end()) {
        TBranch* br =  fTree->GetBranch("ITSDigitsSPD");
        br->SetAddress(&digitsSPD);
	br->GetEntry(mod);
	fSPDmap[mod] = digitsSPD;
	return digitsSPD;
      } else {
	return i->second;
      }
      break;
    }
    case 1: {
      TClonesArray* digitsSDD = 0;
      map<Int_t, TClonesArray*>::iterator i = fSDDmap.find(mod);
      if(i == fSDDmap.end()) {
	TBranch* br =  fTree->GetBranch("ITSDigitsSDD");
        br->SetAddress(&digitsSDD);
	br->GetEntry(mod);
	fSDDmap[mod] = digitsSDD;
	return digitsSDD;
      } else {
	return i->second;
      }
      break;
    }
    case 2: {
      TClonesArray* digitsSSD = 0;
      map<Int_t, TClonesArray*>::iterator i = fSSDmap.find(mod);
      if(i == fSSDmap.end()) {
	TBranch* br =  fTree->GetBranch("ITSDigitsSSD");
        br->SetAddress(&digitsSSD);
	br->GetEntry(mod);

	fSSDmap[mod] = digitsSSD;
	return digitsSSD;
      } else {
	return i->second;
      }
      break;
    }
    default:
      return 0;
  } //end switch
  return 0;
}

/**************************************************************************/

void ITSDigitsInfo::Print(Option_t* ) const
{
  printf("*********************************************************\n");
  printf("SPD module dimension (%f,%f) \n",fSegSPD->Dx()*0.0001, fSegSPD->Dz()*0.0001);
  printf("SPD first,last module:: %d,%d \n", fGeom->GetStartSPD(),fGeom->GetLastSPD() );
  printf("SPD num cells per module (x::%d,z::%d)\n",fSegSPD->Npx(), fSegSPD->Npz());
  Int_t iz=0,ix = 0;
  printf("SPD dimesion of (%d,%d) in pixel(%f,%f) \n", ix,iz, fSegSPD->Dpx(ix), fSegSPD->Dpz(iz));
  iz = 32;
  printf("SPD dimesion of pixel (%d,%d) are (%f,%f) \n", ix,iz, fSegSPD->Dpx(ix)*0.001, fSegSPD->Dpz(iz)*0.001);

  printf("*********************************************************\n");
  printf("SDD module dimension (%f,%f) \n",fSegSDD->Dx()*0.0001, fSegSDD->Dz()*0.0001);
  printf("SDD first,last module:: %d,%d \n", fGeom->GetStartSDD(),fGeom->GetLastSDD() );
  printf("SDD num cells per module (x::%d,z::%d)\n",fSegSDD->Npx(), fSegSDD->Npz());
  printf("SDD dimesion of pixel are (%f,%f) \n", fSegSDD->Dpx(1)*0.001,fSegSDD->Dpz(1)*0.001);
  printf("*********************************************************\n");
  printf("SSD module dimension (%f,%f) \n",fSegSSD->Dx()*0.0001, fSegSSD->Dz()*0.0001);
  printf("SSD first,last module:: %d,%d \n", fGeom->GetStartSSD(),fGeom->GetLastSSD() );
  printf("SSD strips in module %d \n",fSegSSD->Npx());
  printf("SSD strip sizes are (%f,%f) \n", fSegSSD->Dpx(1),fSegSSD->Dpz(1));
  fSegSSD->SetLayer(5); Float_t ap,an;  fSegSSD->Angles(ap,an);
  printf("SSD layer 5 stereoP %f stereoN %f angle \n",ap,an);
  fSegSSD->SetLayer(6);  fSegSSD->Angles(ap,an);
  printf("SSD layer 6 stereoP %f stereoN %f angle \n",ap,an);
}

/*
  printf("num cells %d,%d scaled %d,%d \n",fSegSPD->Npz(),fSegSPD->Npx(),Nz,Nx);
  printf("%d digits in ITSModule %d\n",ne, module);
  Float_t zn = i*(3.48*2)/Nz - 3.48 ;
  Float_t xo =  -fSegSPD->Dx()*0.00005 + fSegSPD->Dpx(0)*od->GetCoord2()*0.0001;
  Float_t xn =  -fSegSPD->Dx()*0.00005 + j*0.0001*fSegSPD->Dx()/Nx;
  Float_t dpx = 0.0001*fSegSPD->Dx()/Nx;
  Float_t dpz = 3.48*2/Nz;
  printf("Z::original (%3f) scaled (%3f, %3f) \n", zo, zn-dpz/2, zn+dpz/2);
  printf("X::original (%3f) scaled (%3f, %3f) \n", xo, xn-dpx/2, xn+dpx/2);
  printf("%d,%d maped to %d,%d \n", od->GetCoord1(), od->GetCoord2(), i,j );
*/
<|endoftext|>


<commit_before>//Copyright (c) 2020 Ultimaker B.V.
//CuraEngine is released under the terms of the AGPLv3 or higher.

#include "RedistributeBeadingStrategy.h"

#include <algorithm>
#include <numeric>

namespace cura
{
    BeadingStrategy::Beading RedistributeBeadingStrategy::compute(coord_t thickness, coord_t bead_count) const
    {
        Beading ret = parent->compute(thickness, bead_count);

        // Early out when the only walls are outer, the parent can have been trusted to handle it. TODO: False! Now we need to lock postition
        if (bead_count < 3)
        {
            if (bead_count == 2 && optimal_width_outer < (thickness / 2))
            {
                const coord_t back_pos = bead_count - 1;

                // Compensate for the outer wall lock factor:
                ret.bead_widths[0] = static_cast<coord_t>(outer_wall_lock_factor * optimal_width_outer + outer_wall_lock_inverse * ret.bead_widths[0]);
                ret.bead_widths[back_pos] = static_cast<coord_t>(outer_wall_lock_factor * optimal_width_outer + outer_wall_lock_inverse * ret.bead_widths[back_pos]);
                ret.toolpath_locations[0] = ret.bead_widths[0] / 2;
                ret.toolpath_locations[back_pos] = thickness - ret.bead_widths[back_pos] / 2;

                // Check if a third wall needs to be created, if so, do it, otherwise put the rest-width in leftovers:
                coord_t left_over = std::max(static_cast<coord_t>(0), thickness - (ret.bead_widths.front() + ret.bead_widths.back()));
                if (left_over >= this->getTransitionThickness(0))
                {
                    ret.bead_widths.insert(std::next(ret.bead_widths.begin()), left_over);
                    ret.toolpath_locations.insert(std::next(ret.toolpath_locations.begin()), thickness / 2);
                    ret.left_over = 0;
                }
                else
                {
                    ret.left_over = left_over;
                }
            }
            return ret;
        }

        // Determine outer bead ratio
        const coord_t outer_width = ret.bead_widths.front() + ret.bead_widths.back();
        const coord_t outer_width_optimal = optimal_width_outer * 2;
        const coord_t outer_width_deviation = static_cast<coord_t>(static_cast<double>(outer_width_optimal - outer_width) * outer_wall_lock_factor + 0.5);
        const coord_t outer_width_required = outer_width + outer_width_deviation;
        const Ratio outer_bead_ratio = static_cast<double>(outer_width_required) / static_cast<double>(outer_width);

        // Update outer beads
        ret.bead_widths.front() = static_cast<coord_t>(static_cast<double>(ret.bead_widths.front()) * outer_bead_ratio + 0.5);
        ret.bead_widths.back() = static_cast<coord_t>(static_cast<double>(ret.bead_widths.back()) * outer_bead_ratio + 0.5);

        // Determine inner bead ratio
        auto inner_bead_width_begin = std::next(ret.bead_widths.begin());
        auto inner_bead_width_end = std::prev(ret.bead_widths.end());
        const coord_t total_inner_bead_width =
            std::accumulate(inner_bead_width_begin, inner_bead_width_end, static_cast<coord_t>(0));
        const coord_t total_required_inner_bead_width =
            thickness - ret.bead_widths.front() - ret.bead_widths.back();
        const Ratio inner_bead_ratio =
            static_cast<double>(total_required_inner_bead_width) / static_cast<double>(total_inner_bead_width);

        for (auto bead_width_it = inner_bead_width_begin; bead_width_it < inner_bead_width_end; bead_width_it++)
        {
            *bead_width_it = static_cast<coord_t>(static_cast<double>(*bead_width_it) * inner_bead_ratio + 0.5);
        }

        // Filter out bead_widths that violate the transition width and recalculate if needed
        ret.bead_widths.erase(std::remove_if(ret.bead_widths.begin(), ret.bead_widths.end(),
                                             [&](const coord_t width)
                                             {
                                                 return width <= parent->getTransitionThickness(0);
                                             }), ret.bead_widths.end());
        if (ret.bead_widths.size() < ret.toolpath_locations.size())
        {
            const coord_t left_over = thickness - std::accumulate(ret.bead_widths.cbegin(), ret.bead_widths.cend(), static_cast<coord_t>(0));
            logWarning("Removed a bead -> leftover %d, no_beads -> %d, you should update!\n", left_over, ret.bead_widths.size());
        }
        bead_count = ret.bead_widths.size();
        ret.toolpath_locations.resize(bead_count);

        // Update the first half of the toolpath-locations with the updated bead-widths (starting from 0, up to half):
        coord_t last_coord = 0;
        coord_t last_width = 0;
        for (coord_t i_location = 0; i_location < bead_count / 2; ++i_location)
        {
            ret.toolpath_locations[i_location] = last_coord + (last_width + ret.bead_widths[i_location]) / 2;
            last_coord = ret.toolpath_locations[i_location];
            last_width = ret.bead_widths[i_location];
        }

        // Handle the position of any middle wall (note that the width will already have been set correctly):
        if (bead_count % 2 == 1)
        {
            ret.toolpath_locations[bead_count / 2] = thickness / 2;
        }

        // Update the last half of the toolpath-locations with the updated bead-widths (starting from thickness, down to half):
        last_coord = thickness;
        last_width = 0;
        for (coord_t i_location = bead_count - 1; i_location >= bead_count - (bead_count / 2); --i_location)
        {
            ret.toolpath_locations[i_location] = last_coord - (last_width + ret.bead_widths[i_location]) / 2;
            last_coord = ret.toolpath_locations[i_location];
            last_width = ret.bead_widths[i_location];
        }

        ret.left_over = thickness - std::accumulate(ret.bead_widths.cbegin(), ret.bead_widths.cend(), static_cast<coord_t>(0));
        return ret;
    }

    } // namespace cura
<commit_msg>Make sure that all beads still adhere to minimum width<commit_after>//Copyright (c) 2020 Ultimaker B.V.
//CuraEngine is released under the terms of the AGPLv3 or higher.

#include "RedistributeBeadingStrategy.h"

#include <algorithm>
#include <numeric>
#include <cassert>

namespace cura
{
    BeadingStrategy::Beading RedistributeBeadingStrategy::compute(coord_t thickness, coord_t bead_count) const
    {
        Beading ret = parent->compute(thickness, bead_count);

        // Early out when the only walls are outer, the parent can have been trusted to handle it. TODO: False! Now we need to lock postition
        if (bead_count < 3)
        {
            if (bead_count == 2 && optimal_width_outer < (thickness / 2))
            {
                const coord_t back_pos = bead_count - 1;

                // Compensate for the outer wall lock factor:
                ret.bead_widths[0] = static_cast<coord_t>(outer_wall_lock_factor * optimal_width_outer + outer_wall_lock_inverse * ret.bead_widths[0]);
                ret.bead_widths[back_pos] = static_cast<coord_t>(outer_wall_lock_factor * optimal_width_outer + outer_wall_lock_inverse * ret.bead_widths[back_pos]);
                ret.toolpath_locations[0] = ret.bead_widths[0] / 2;
                ret.toolpath_locations[back_pos] = thickness - ret.bead_widths[back_pos] / 2;

                // Check if a third wall needs to be created, if so, do it, otherwise put the rest-width in leftovers:
                coord_t left_over = std::max(static_cast<coord_t>(0), thickness - (ret.bead_widths.front() + ret.bead_widths.back()));
                if (left_over >= this->getTransitionThickness(0))
                {
                    ret.bead_widths.insert(std::next(ret.bead_widths.begin()), left_over);
                    ret.toolpath_locations.insert(std::next(ret.toolpath_locations.begin()), thickness / 2);
                    ret.left_over = 0;
                }
                else
                {
                    ret.left_over = left_over;
                }
            }
            return ret;
        }

        // Determine outer bead ratio
        const coord_t outer_width = ret.bead_widths.front() + ret.bead_widths.back();
        const coord_t outer_width_optimal = optimal_width_outer * 2;
        const coord_t outer_width_deviation = static_cast<coord_t>(static_cast<double>(outer_width_optimal - outer_width) * outer_wall_lock_factor + 0.5);
        const coord_t outer_width_required = outer_width + outer_width_deviation;
        const Ratio outer_bead_ratio = static_cast<double>(outer_width_required) / static_cast<double>(outer_width);

        // Update outer beads
        ret.bead_widths.front() = static_cast<coord_t>(static_cast<double>(ret.bead_widths.front()) * outer_bead_ratio + 0.5);
        ret.bead_widths.back() = static_cast<coord_t>(static_cast<double>(ret.bead_widths.back()) * outer_bead_ratio + 0.5);

        // Determine inner bead ratio
        auto inner_bead_width_begin = std::next(ret.bead_widths.begin());
        auto inner_bead_width_end = std::prev(ret.bead_widths.end());
        const coord_t total_inner_bead_width =
            std::accumulate(inner_bead_width_begin, inner_bead_width_end, static_cast<coord_t>(0));
        const coord_t total_required_inner_bead_width =
            thickness - ret.bead_widths.front() - ret.bead_widths.back();
        const Ratio inner_bead_ratio =
            static_cast<double>(total_required_inner_bead_width) / static_cast<double>(total_inner_bead_width);

        for (auto bead_width_it = inner_bead_width_begin; bead_width_it < inner_bead_width_end; bead_width_it++)
        {
            *bead_width_it = static_cast<coord_t>(static_cast<double>(*bead_width_it) * inner_bead_ratio + 0.5);
        }

        // Filter out bead_widths that violate the transition width and recalculate if needed
        const coord_t minimum_width = parent->getTransitionThickness(0);
        ret.bead_widths.erase(std::remove_if(ret.bead_widths.begin(), ret.bead_widths.end(),
                                             [&minimum_width](const coord_t width)
                                             {
                                                 return width <= minimum_width;
                                             }), ret.bead_widths.end());
        if (ret.bead_widths.size() < ret.toolpath_locations.size())
        {
            // NOTE: For now work under assumption that only 1 bead has to be added
            const coord_t left_over = thickness - std::accumulate(ret.bead_widths.cbegin(), ret.bead_widths.cend(), static_cast<coord_t>(0));
            // remove width from other beads, to give way for newly inserted bead
            const coord_t removal_width = (minimum_width - left_over) / ret.bead_widths.size();
            for (auto& bead_width : ret.bead_widths)
            {
                bead_width -= removal_width;
            }

            // Insert new bead with minimum width
            ret.bead_widths.insert(std::next(ret.bead_widths.begin()), minimum_width);
            ret.toolpath_locations.insert(std::next(ret.toolpath_locations.begin()), thickness / 2);

            logWarning("Removed a bead -> leftover %d, no_beads -> %d, you should update!\n", left_over, ret.bead_widths.size());
        }
        bead_count = static_cast<coord_t>(ret.bead_widths.size());
        ret.toolpath_locations.resize(bead_count);

        // Update the first half of the toolpath-locations with the updated bead-widths (starting from 0, up to half):
        coord_t last_coord = 0;
        coord_t last_width = 0;
        for (coord_t i_location = 0; i_location < bead_count / 2; ++i_location)
        {
            ret.toolpath_locations[i_location] = last_coord + (last_width + ret.bead_widths[i_location]) / 2;
            last_coord = ret.toolpath_locations[i_location];
            last_width = ret.bead_widths[i_location];
        }

        // Handle the position of any middle wall (note that the width will already have been set correctly):
        if (bead_count % 2 == 1)
        {
            ret.toolpath_locations[bead_count / 2] = thickness / 2;
        }

        // Update the last half of the toolpath-locations with the updated bead-widths (starting from thickness, down to half):
        last_coord = thickness;
        last_width = 0;
        for (coord_t i_location = bead_count - 1; i_location >= bead_count - (bead_count / 2); --i_location)
        {
            ret.toolpath_locations[i_location] = last_coord - (last_width + ret.bead_widths[i_location]) / 2;
            last_coord = ret.toolpath_locations[i_location];
            last_width = ret.bead_widths[i_location];
        }

        ret.left_over = thickness - std::accumulate(ret.bead_widths.cbegin(), ret.bead_widths.cend(), static_cast<coord_t>(0));
        assert(std::all_of(ret.bead_widths.begin(), ret.bead_widths.end(),
                           [&minimum_width](const coord_t width)
                           {
                             return width >= minimum_width;
                           }) && "All beads should be atleast the minimum bead width");
        return ret;
    }

    } // namespace cura
<|endoftext|>


<commit_before>/******************************************************************************\
* File:          tool.cpp
* Purpose:       Implementation of wxExTool class
* Author:        Anton van Wezenbeek
* RCS-ID:        $Id$
*
* Copyright (c) 1998-2009 Anton van Wezenbeek
* All rights are reserved. Reproduction in whole or part is prohibited
* without the written consent of the copyright owner.
\******************************************************************************/

#include <wx/wxprec.h>
#ifndef WX_PRECOMP
#include <wx/wx.h>
#endif
#include <wx/config.h>
#include <wx/stdpaths.h>
#include <wx/textfile.h>
#include <wx/extension/tool.h>
#include <wx/extension/frame.h>
#include <wx/extension/log.h>
#include <wx/extension/statistics.h>
#include <wx/extension/vcs.h>

wxExTool* wxExTool::m_Self = NULL;

wxExTool::wxExTool(int type)
  : m_Id(type)
{
}

wxExTool* wxExTool::Get(bool createOnDemand)
{
  if (m_Self == NULL && createOnDemand)
  {
    m_Self = new wxExTool(0);

    m_Self->AddInfo(ID_TOOL_REVISION_RECENT, _("Recent revision from"));
    m_Self->AddInfo(ID_TOOL_REPORT_REVISION, _("Reported %ld revisions in"), _("Report &Revision"));
    m_Self->AddInfo(ID_TOOL_REPORT_COUNT, _("Counted"), _("Report &Count"));
    m_Self->AddInfo(ID_TOOL_REPORT_FIND, _("Found %ld matches in"));
    m_Self->AddInfo(ID_TOOL_REPORT_REPLACE, _("Replaced %ld matches in"));
    m_Self->AddInfo(ID_TOOL_REPORT_KEYWORD, _("Reported %ld keywords in"), _("Report &Keyword"));
  }

  return m_Self;
}

const wxString wxExTool::Info() const
{
  const auto it = m_Self->m_ToolInfo.find(m_Id);

  if (it != m_Self->m_ToolInfo.end())
  {
    return it->second.GetInfo();
  }

  wxFAIL;

  return wxEmptyString;
}

void wxExTool::Log(
  wxExStatistics<long>* stat,
  const wxString& caption,
  bool log_to_file) const
{
  wxString logtext(Info());

  if (logtext.Contains("%ld"))
  {
    logtext = logtext.Format(logtext, stat->Get(_("Actions Completed")));
  }

  logtext
    << " " << stat->Get(_("Files")) << " " << _("file(s)")
    << (!caption.empty() ? ": " + caption: "");

#if wxUSE_STATUSBAR
  wxExFrame::StatusText(logtext);
#endif

  if (log_to_file && stat->Get(_("Files")) != 0)
  {
    wxExLog::Get()->Log(logtext);

    if (IsCount())
    {
      wxString logtext;

      logtext
        << caption
        << stat->Get()
        << wxTextFile::GetEOL();

      wxExLog log(GetLogfileName());
      log.Log(logtext);
    }
  }
}

const wxFileName wxExTool::GetLogfileName() const
{
  wxFileName filename(
#ifdef wxExUSE_PORTABLE
    wxPathOnly(wxStandardPaths::Get().GetExecutablePath())
#else
    wxStandardPaths::Get().GetUserDataDir()
#endif
    + wxFileName::GetPathSeparator() + _("statistics.log"));

  return filename;
}

wxExTool* wxExTool::Set(wxExTool* tool)
{
  wxExTool* old = m_Self;
  m_Self = tool;
  return old;
}
<commit_msg>reordered<commit_after>/******************************************************************************\
* File:          tool.cpp
* Purpose:       Implementation of wxExTool class
* Author:        Anton van Wezenbeek
* RCS-ID:        $Id$
*
* Copyright (c) 1998-2009 Anton van Wezenbeek
* All rights are reserved. Reproduction in whole or part is prohibited
* without the written consent of the copyright owner.
\******************************************************************************/

#include <wx/wxprec.h>
#ifndef WX_PRECOMP
#include <wx/wx.h>
#endif
#include <wx/config.h>
#include <wx/stdpaths.h>
#include <wx/textfile.h>
#include <wx/extension/tool.h>
#include <wx/extension/frame.h>
#include <wx/extension/log.h>
#include <wx/extension/statistics.h>
#include <wx/extension/vcs.h>

wxExTool* wxExTool::m_Self = NULL;

wxExTool::wxExTool(int type)
  : m_Id(type)
{
}

wxExTool* wxExTool::Get(bool createOnDemand)
{
  if (m_Self == NULL && createOnDemand)
  {
    m_Self = new wxExTool(0);

    m_Self->AddInfo(ID_TOOL_REVISION_RECENT, _("Recent revision from"));
    m_Self->AddInfo(ID_TOOL_REPORT_REVISION, _("Reported %ld revisions in"), _("Report &Revision"));
    m_Self->AddInfo(ID_TOOL_REPORT_COUNT, _("Counted"), _("Report &Count"));
    m_Self->AddInfo(ID_TOOL_REPORT_FIND, _("Found %ld matches in"));
    m_Self->AddInfo(ID_TOOL_REPORT_REPLACE, _("Replaced %ld matches in"));
    m_Self->AddInfo(ID_TOOL_REPORT_KEYWORD, _("Reported %ld keywords in"), _("Report &Keyword"));
  }

  return m_Self;
}

const wxFileName wxExTool::GetLogfileName() const
{
  wxFileName filename(
#ifdef wxExUSE_PORTABLE
    wxPathOnly(wxStandardPaths::Get().GetExecutablePath())
#else
    wxStandardPaths::Get().GetUserDataDir()
#endif
    + wxFileName::GetPathSeparator() + _("statistics.log"));

  return filename;
}

const wxString wxExTool::Info() const
{
  const auto it = m_Self->m_ToolInfo.find(m_Id);

  if (it != m_Self->m_ToolInfo.end())
  {
    return it->second.GetInfo();
  }

  wxFAIL;

  return wxEmptyString;
}

void wxExTool::Log(
  wxExStatistics<long>* stat,
  const wxString& caption,
  bool log_to_file) const
{
  wxString logtext(Info());

  if (logtext.Contains("%ld"))
  {
    logtext = logtext.Format(logtext, stat->Get(_("Actions Completed")));
  }

  logtext
    << " " << stat->Get(_("Files")) << " " << _("file(s)")
    << (!caption.empty() ? ": " + caption: "");

#if wxUSE_STATUSBAR
  wxExFrame::StatusText(logtext);
#endif

  if (log_to_file && stat->Get(_("Files")) != 0)
  {
    wxExLog::Get()->Log(logtext);

    if (IsCount())
    {
      wxString logtext;

      logtext
        << caption
        << stat->Get()
        << wxTextFile::GetEOL();

      wxExLog log(GetLogfileName());
      log.Log(logtext);
    }
  }
}

wxExTool* wxExTool::Set(wxExTool* tool)
{
  wxExTool* old = m_Self;
  m_Self = tool;
  return old;
}
<|endoftext|>


<commit_before>// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE.chromium file.

#include "native_mate/wrappable.h"

#include "base/logging.h"
#include "native_mate/object_template_builder.h"

namespace mate {

Wrappable::Wrappable() {
}

Wrappable::~Wrappable() {
  MATE_PERSISTENT_RESET(wrapper_);
}

void Wrappable::Wrap(v8::Isolate* isolate, v8::Handle<v8::Object> wrapper) {
  MATE_SET_INTERNAL_FIELD_POINTER(wrapper, 0, this);
  MATE_PERSISTENT_ASSIGN(v8::Object, isolate, wrapper_, wrapper);
  MATE_PERSISTENT_SET_WEAK(wrapper_, this, WeakCallback);
}

// static
void Wrappable::BuildPrototype(v8::Isolate* isolate,
                               v8::Handle<v8::ObjectTemplate> prototype) {
}

ObjectTemplateBuilder Wrappable::GetObjectTemplateBuilder(
    v8::Isolate* isolate) {
  return ObjectTemplateBuilder(isolate);
}

// static
MATE_WEAK_CALLBACK(Wrappable::WeakCallback, v8::Object, Wrappable) {
  MATE_WEAK_CALLBACK_INIT(Wrappable);
  MATE_PERSISTENT_RESET(self->wrapper_);
  delete self;
}

v8::Handle<v8::Object> Wrappable::GetWrapper(v8::Isolate* isolate) {
  if (!wrapper_.IsEmpty()) {
    return MATE_PERSISTENT_TO_LOCAL(v8::Object, isolate, wrapper_);
  }

  v8::Local<v8::ObjectTemplate> templ =
      GetObjectTemplateBuilder(isolate).Build();
  CHECK(!templ.IsEmpty());
  CHECK_EQ(1, templ->InternalFieldCount());
  v8::Handle<v8::Object> wrapper = templ->NewInstance();
  Wrap(isolate, wrapper);
  return wrapper;
}

namespace internal {

void* FromV8Impl(v8::Isolate* isolate, v8::Handle<v8::Value> val) {
  if (!val->IsObject())
    return NULL;
  v8::Handle<v8::Object> obj = v8::Handle<v8::Object>::Cast(val);
  return MATE_GET_INTERNAL_FIELD_POINTER(obj, 0);
}

}  // namespace internal

}  // namespace mate
<commit_msg>Do not wrap an object when it's already wrapped.<commit_after>// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE.chromium file.

#include "native_mate/wrappable.h"

#include "base/logging.h"
#include "native_mate/object_template_builder.h"

namespace mate {

Wrappable::Wrappable() {
}

Wrappable::~Wrappable() {
  MATE_PERSISTENT_RESET(wrapper_);
}

void Wrappable::Wrap(v8::Isolate* isolate, v8::Handle<v8::Object> wrapper) {
  if (!wrapper_.IsEmpty())
    return;

  MATE_SET_INTERNAL_FIELD_POINTER(wrapper, 0, this);
  MATE_PERSISTENT_ASSIGN(v8::Object, isolate, wrapper_, wrapper);
  MATE_PERSISTENT_SET_WEAK(wrapper_, this, WeakCallback);
}

// static
void Wrappable::BuildPrototype(v8::Isolate* isolate,
                               v8::Handle<v8::ObjectTemplate> prototype) {
}

ObjectTemplateBuilder Wrappable::GetObjectTemplateBuilder(
    v8::Isolate* isolate) {
  return ObjectTemplateBuilder(isolate);
}

// static
MATE_WEAK_CALLBACK(Wrappable::WeakCallback, v8::Object, Wrappable) {
  MATE_WEAK_CALLBACK_INIT(Wrappable);
  MATE_PERSISTENT_RESET(self->wrapper_);
  delete self;
}

v8::Handle<v8::Object> Wrappable::GetWrapper(v8::Isolate* isolate) {
  if (!wrapper_.IsEmpty())
    return MATE_PERSISTENT_TO_LOCAL(v8::Object, isolate, wrapper_);

  v8::Local<v8::ObjectTemplate> templ =
      GetObjectTemplateBuilder(isolate).Build();
  CHECK(!templ.IsEmpty());
  CHECK_EQ(1, templ->InternalFieldCount());
  v8::Handle<v8::Object> wrapper = templ->NewInstance();
  Wrap(isolate, wrapper);
  return wrapper;
}

namespace internal {

void* FromV8Impl(v8::Isolate* isolate, v8::Handle<v8::Value> val) {
  if (!val->IsObject())
    return NULL;
  v8::Handle<v8::Object> obj = v8::Handle<v8::Object>::Cast(val);
  return MATE_GET_INTERNAL_FIELD_POINTER(obj, 0);
}

}  // namespace internal

}  // namespace mate
<|endoftext|>