<commit_before>/***********************************************************************************************************************
**
** Copyright (c) 2011, 2015 ETH Zurich
** 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 the ETH Zurich 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.
**
***********************************************************************************************************************/

#include "AstQuery.h"

#include "OOModel/src/declarations/Class.h"
#include "OOModel/src/declarations/Project.h"

#include "../visitors/AllNodesOfType.h"
#include "QueryRegistry.h"

namespace InformationScripting {

const QStringList AstQuery::SCOPE_ARGUMENT_NAMES{"s", "scope"};
const QStringList AstQuery::NODETYPE_ARGUMENT_NAMES{"t", "type"};
const QStringList AstQuery::NAME_ARGUMENT_NAMES{"n", "name"};

AstQuery::AstQuery(QueryType type, Model::Node* target, QStringList args)
	: target_{target}, type_{type}
{
	args.prepend("AstQuery");
	argParser_.addOptions(
	{
		 {SCOPE_ARGUMENT_NAMES, "Scope argument", SCOPE_ARGUMENT_NAMES[1]},
		 {NODETYPE_ARGUMENT_NAMES, "AST Type argument", NODETYPE_ARGUMENT_NAMES[1]},
		 {NAME_ARGUMENT_NAMES, "Name of a symbol", NAME_ARGUMENT_NAMES[1]}
	});
	// Since all our options require values we don't want -abc to be interpreted as -a -b -c but as --abc
	argParser_.setSingleDashWordOptionMode(QCommandLineParser::ParseAsLongOptions);

	if (!argParser_.parse(args))
		qWarning() << "ASTQuery parse failure"; // TODO warn user

	QString scope = argParser_.value(SCOPE_ARGUMENT_NAMES[0]);
	if (scope == "g") scope_ = Scope::Global;
	else if (scope == "of") scope_ = Scope::Input;
}

QList<TupleSet> AstQuery::execute(QList<TupleSet> input)
{
	QList<TupleSet> result;
	switch (type_)
	{
		case QueryType::Classes:
			result = {classesQuery(input)};
			break;
		case QueryType::Methods:
			result = {methodsQuery(input)};
			break;
		case QueryType::BaseClasses:
			result = {baseClassesQuery(input)};
			break;
		case QueryType::ToClass:
			result = {toClassNode(input)};
			break;
		case QueryType::CallGraph:
			result = {callGraph(input)};
			break;
		case QueryType::Generic:
			result = {genericQuery(input)};
			break;
		case QueryType::GenericToParent:
			if (argParser_.value(NODETYPE_ARGUMENT_NAMES[0]).size() > 0)
				result = {toParentType(input, argParser_.value(NODETYPE_ARGUMENT_NAMES[0]))};
			else
				result = input; // TODO warning for user ?
			break;
		default:
			Q_ASSERT(false);
	}

	return result;
}

void AstQuery::registerDefaultQueries()
{
	auto& registry = QueryRegistry::instance();
	registry.registerQueryConstructor("classes", [](Model::Node* target, QStringList args) {
		return new AstQuery(AstQuery::QueryType::Classes, target, args);
	});
	registry.registerQueryConstructor("methods", [](Model::Node* target, QStringList args) {
		return new AstQuery(AstQuery::QueryType::Methods, target, args);
	});
	registry.registerQueryConstructor("bases", [](Model::Node* target, QStringList args) {
		return new AstQuery(AstQuery::QueryType::BaseClasses, target, args);
	});
	registry.registerQueryConstructor("toClass", [](Model::Node* target, QStringList args) {
		return new AstQuery(AstQuery::QueryType::ToClass, target, args);
	});
	registry.registerQueryConstructor("callgraph", [](Model::Node* target, QStringList args) {
		return new AstQuery(AstQuery::QueryType::CallGraph, target, args);
	});
	registry.registerQueryConstructor("ast", [](Model::Node* target, QStringList args) {
		return new AstQuery(AstQuery::QueryType::Generic, target, args);
	});
	registry.registerQueryConstructor("toParent", [](Model::Node* target, QStringList args) {
		return new AstQuery(AstQuery::QueryType::GenericToParent, target, args);
	});
}

TupleSet AstQuery::classesQuery(QList<TupleSet> input)
{
	TupleSet tuples;
	if (scope_ == Scope::Local)
	{
		auto parentProject = target_->firstAncestorOfType<OOModel::Project>();
		for (auto childClass : *parentProject->classes())
			tuples.add({{"ast", childClass}});
	}
	else
		tuples = typeQuery(input, "Class");
	return tuples;
}

TupleSet AstQuery::methodsQuery(QList<TupleSet> input)
{
	TupleSet tuples;
	if (scope_ == Scope::Local)
	{
		auto parentClass = target_->firstAncestorOfType<OOModel::Class>();
		for (auto method : *parentClass->methods())
			tuples.add({{"ast", method}});
	}
	else
		tuples = typeQuery(input, "Method");
	return tuples;
}

TupleSet AstQuery::baseClassesQuery(QList<TupleSet>)
{
	// TODO handle input
	TupleSet ts;
	if (scope_ == Scope::Local)
	{
		OOModel::Class* parentClass = DCast<OOModel::Class>(target_);
		if (!parentClass) parentClass = target_->firstAncestorOfType<OOModel::Class>();

		NamedProperty namedClass{"childClass", parentClass};
		ts.add({namedClass});

		addBaseEdgesFor(parentClass, namedClass, ts);
	}
	else if (scope_ == Scope::Global)
	{
		// TODO
	}
	return ts;
}

TupleSet AstQuery::toClassNode(QList<TupleSet> input)
{
	return toParentType(input, "Class");
}

TupleSet AstQuery::toParentType(QList<TupleSet> input, const QString& type)
{
	Q_ASSERT(input.size());
	auto ts = input.takeFirst();
	auto canBeParent = [type](const Tuple& t) {
		auto it = t.find("ast");
		if (it != t.end())
		{
			Model::Node* n = it->second;
			return n->firstAncestorOfType(type) != nullptr;
		}
		return false;
	};
	// TODO currently we remove all the converted nodes:
	auto tuples = ts.take(canBeParent);
	QSet<Model::Node*> parentNodes;
	for (auto tuple : tuples)
	{
		Model::Node* astNode = tuple["ast"];
		auto parentNode = astNode->firstAncestorOfType(type);
		parentNodes.insert(parentNode);
	}
	for (auto foundNode : parentNodes)
		ts.add({{"ast", foundNode}});
	return ts;
}

TupleSet AstQuery::callGraph(QList<TupleSet>)
{
	TupleSet ts;
	if (scope_ == Scope::Local)
	{
		auto methodTarget = target_->firstAncestorOfType<OOModel::Method>();
		Q_ASSERT(methodTarget);
		QSet<OOModel::Method*> seenMethods{methodTarget};
		auto methods = methodTarget->callees().toList();
		addCallInformation(ts, methodTarget, methods);
		while (!methods.empty())
		{
			auto currentMethod = methods.takeLast();
			if (seenMethods.contains(currentMethod)) continue;
			seenMethods.insert(currentMethod);
			auto newCallees = currentMethod->callees().toList();
			addCallInformation(ts, currentMethod, newCallees);
			methods << newCallees;
		}
	}
	// TODO handle other cases, global propably doesn't make sense.
	return ts;
}

TupleSet AstQuery::genericQuery(QList<TupleSet> input)
{
	QString typeArgument = argParser_.value(NODETYPE_ARGUMENT_NAMES[0]);
	if (typeArgument.size() > 0) return typeQuery(input, typeArgument);
	return {};
}

TupleSet AstQuery::typeQuery(QList<TupleSet> input, QString type)
{
	TupleSet tuples;

	Q_ASSERT(!type.isEmpty());

	if (scope_ == Scope::Local)
	{
		// TODO how to get the correct ancestor?
	}
	else if (scope_ == Scope::Global)
	{
		addNodesOfType(tuples, type);
	}
	else if (scope_ == Scope::Input)
	{
		Q_ASSERT(input.size());
		tuples = input.takeFirst();

		// TODO add the possibility to keep the input nodes:
		auto tuple = tuples.take("ast");
		for (const auto& t : tuple) addNodesOfType(tuples, type, t["ast"]);
	}
	return tuples;
}

void AstQuery::addBaseEdgesFor(OOModel::Class* childClass, NamedProperty& classNode, TupleSet& ts)
{
	auto bases = childClass->directBaseClasses();
	for (auto base : bases)
	{
		NamedProperty baseNode{"baseClass", base};
		ts.add({baseNode});
		ts.add({{"base class", {}}, {classNode}, {baseNode}});
		addBaseEdgesFor(base, baseNode, ts);
	}
}

void AstQuery::addCallInformation(TupleSet& ts, OOModel::Method* method, QList<OOModel::Method*> callees)
{
	NamedProperty namedCaller{"caller", method};
	ts.add({{namedCaller}});
	for (auto callee : callees)
	{
		NamedProperty namedCallee{"callee", callee};
		ts.add({{namedCallee}});
		ts.add({{"calls", {}}, namedCaller, namedCallee});
	}
}

void AstQuery::addNodesOfType(TupleSet& ts, const QString& typeName, Model::Node* from)
{
	if (!from) from = target_->manager()->root();
	auto allNodeOfType =  AllNodesOfType::allNodesOfType(from, typeName);
	for (auto node : allNodeOfType)
		ts.add({{"ast", node}});
}

} /* namespace InformationScripting */
<commit_msg>Change the meaning of Local scope in AstQuery<commit_after>/***********************************************************************************************************************
**
** Copyright (c) 2011, 2015 ETH Zurich
** 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 the ETH Zurich 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.
**
***********************************************************************************************************************/

#include "AstQuery.h"

#include "OOModel/src/declarations/Class.h"
#include "OOModel/src/declarations/Project.h"

#include "../visitors/AllNodesOfType.h"
#include "QueryRegistry.h"

namespace InformationScripting {

const QStringList AstQuery::SCOPE_ARGUMENT_NAMES{"s", "scope"};
const QStringList AstQuery::NODETYPE_ARGUMENT_NAMES{"t", "type"};
const QStringList AstQuery::NAME_ARGUMENT_NAMES{"n", "name"};

AstQuery::AstQuery(QueryType type, Model::Node* target, QStringList args)
	: target_{target}, type_{type}
{
	args.prepend("AstQuery");
	argParser_.addOptions(
	{
		 {SCOPE_ARGUMENT_NAMES, "Scope argument", SCOPE_ARGUMENT_NAMES[1]},
		 {NODETYPE_ARGUMENT_NAMES, "AST Type argument", NODETYPE_ARGUMENT_NAMES[1]},
		 {NAME_ARGUMENT_NAMES, "Name of a symbol", NAME_ARGUMENT_NAMES[1]}
	});
	// Since all our options require values we don't want -abc to be interpreted as -a -b -c but as --abc
	argParser_.setSingleDashWordOptionMode(QCommandLineParser::ParseAsLongOptions);

	if (!argParser_.parse(args))
		qWarning() << "ASTQuery parse failure"; // TODO warn user

	QString scope = argParser_.value(SCOPE_ARGUMENT_NAMES[0]);
	if (scope == "g") scope_ = Scope::Global;
	else if (scope == "of") scope_ = Scope::Input;
}

QList<TupleSet> AstQuery::execute(QList<TupleSet> input)
{
	QList<TupleSet> result;
	switch (type_)
	{
		case QueryType::Classes:
			result = {classesQuery(input)};
			break;
		case QueryType::Methods:
			result = {methodsQuery(input)};
			break;
		case QueryType::BaseClasses:
			result = {baseClassesQuery(input)};
			break;
		case QueryType::ToClass:
			result = {toClassNode(input)};
			break;
		case QueryType::CallGraph:
			result = {callGraph(input)};
			break;
		case QueryType::Generic:
			result = {genericQuery(input)};
			break;
		case QueryType::GenericToParent:
			if (argParser_.value(NODETYPE_ARGUMENT_NAMES[0]).size() > 0)
				result = {toParentType(input, argParser_.value(NODETYPE_ARGUMENT_NAMES[0]))};
			else
				result = input; // TODO warning for user ?
			break;
		default:
			Q_ASSERT(false);
	}

	return result;
}

void AstQuery::registerDefaultQueries()
{
	auto& registry = QueryRegistry::instance();
	registry.registerQueryConstructor("classes", [](Model::Node* target, QStringList args) {
		return new AstQuery(AstQuery::QueryType::Classes, target, args);
	});
	registry.registerQueryConstructor("methods", [](Model::Node* target, QStringList args) {
		return new AstQuery(AstQuery::QueryType::Methods, target, args);
	});
	registry.registerQueryConstructor("bases", [](Model::Node* target, QStringList args) {
		return new AstQuery(AstQuery::QueryType::BaseClasses, target, args);
	});
	registry.registerQueryConstructor("toClass", [](Model::Node* target, QStringList args) {
		return new AstQuery(AstQuery::QueryType::ToClass, target, args);
	});
	registry.registerQueryConstructor("callgraph", [](Model::Node* target, QStringList args) {
		return new AstQuery(AstQuery::QueryType::CallGraph, target, args);
	});
	registry.registerQueryConstructor("ast", [](Model::Node* target, QStringList args) {
		return new AstQuery(AstQuery::QueryType::Generic, target, args);
	});
	registry.registerQueryConstructor("toParent", [](Model::Node* target, QStringList args) {
		return new AstQuery(AstQuery::QueryType::GenericToParent, target, args);
	});
}

TupleSet AstQuery::classesQuery(QList<TupleSet> input)
{
	return typeQuery(input, "Class");
}

TupleSet AstQuery::methodsQuery(QList<TupleSet> input)
{
	return typeQuery(input, "Method");
}

TupleSet AstQuery::baseClassesQuery(QList<TupleSet>)
{
	// TODO handle input
	TupleSet ts;
	if (scope_ == Scope::Local)
	{
		OOModel::Class* parentClass = DCast<OOModel::Class>(target_);
		if (!parentClass) parentClass = target_->firstAncestorOfType<OOModel::Class>();

		NamedProperty namedClass{"childClass", parentClass};
		ts.add({namedClass});

		addBaseEdgesFor(parentClass, namedClass, ts);
	}
	else if (scope_ == Scope::Global)
	{
		// TODO
	}
	return ts;
}

TupleSet AstQuery::toClassNode(QList<TupleSet> input)
{
	return toParentType(input, "Class");
}

TupleSet AstQuery::toParentType(QList<TupleSet> input, const QString& type)
{
	Q_ASSERT(input.size());
	auto ts = input.takeFirst();
	auto canBeParent = [type](const Tuple& t) {
		auto it = t.find("ast");
		if (it != t.end())
		{
			Model::Node* n = it->second;
			return n->firstAncestorOfType(type) != nullptr;
		}
		return false;
	};
	// TODO currently we remove all the converted nodes:
	auto tuples = ts.take(canBeParent);
	QSet<Model::Node*> parentNodes;
	for (auto tuple : tuples)
	{
		Model::Node* astNode = tuple["ast"];
		auto parentNode = astNode->firstAncestorOfType(type);
		parentNodes.insert(parentNode);
	}
	for (auto foundNode : parentNodes)
		ts.add({{"ast", foundNode}});
	return ts;
}

TupleSet AstQuery::callGraph(QList<TupleSet>)
{
	TupleSet ts;
	if (scope_ == Scope::Local)
	{
		auto methodTarget = target_->firstAncestorOfType<OOModel::Method>();
		Q_ASSERT(methodTarget);
		QSet<OOModel::Method*> seenMethods{methodTarget};
		auto methods = methodTarget->callees().toList();
		addCallInformation(ts, methodTarget, methods);
		while (!methods.empty())
		{
			auto currentMethod = methods.takeLast();
			if (seenMethods.contains(currentMethod)) continue;
			seenMethods.insert(currentMethod);
			auto newCallees = currentMethod->callees().toList();
			addCallInformation(ts, currentMethod, newCallees);
			methods << newCallees;
		}
	}
	// TODO handle other cases, global propably doesn't make sense.
	return ts;
}

TupleSet AstQuery::genericQuery(QList<TupleSet> input)
{
	QString typeArgument = argParser_.value(NODETYPE_ARGUMENT_NAMES[0]);
	if (typeArgument.size() > 0) return typeQuery(input, typeArgument);
	return {};
}

TupleSet AstQuery::typeQuery(QList<TupleSet> input, QString type)
{
	TupleSet tuples;

	Q_ASSERT(!type.isEmpty());

	if (scope_ == Scope::Local)
		addNodesOfType(tuples, type, target_);
	else if (scope_ == Scope::Global)
		addNodesOfType(tuples, type);
	else if (scope_ == Scope::Input)
	{
		Q_ASSERT(input.size());
		tuples = input.takeFirst();

		// TODO add the possibility to keep the input nodes:
		auto tuple = tuples.take("ast");
		for (const auto& t : tuple) addNodesOfType(tuples, type, t["ast"]);
	}
	return tuples;
}

void AstQuery::addBaseEdgesFor(OOModel::Class* childClass, NamedProperty& classNode, TupleSet& ts)
{
	auto bases = childClass->directBaseClasses();
	for (auto base : bases)
	{
		NamedProperty baseNode{"baseClass", base};
		ts.add({baseNode});
		ts.add({{"base class", {}}, {classNode}, {baseNode}});
		addBaseEdgesFor(base, baseNode, ts);
	}
}

void AstQuery::addCallInformation(TupleSet& ts, OOModel::Method* method, QList<OOModel::Method*> callees)
{
	NamedProperty namedCaller{"caller", method};
	ts.add({{namedCaller}});
	for (auto callee : callees)
	{
		NamedProperty namedCallee{"callee", callee};
		ts.add({{namedCallee}});
		ts.add({{"calls", {}}, namedCaller, namedCallee});
	}
}

void AstQuery::addNodesOfType(TupleSet& ts, const QString& typeName, Model::Node* from)
{
	if (!from) from = target_->manager()->root();
	auto allNodeOfType =  AllNodesOfType::allNodesOfType(from, typeName);
	for (auto node : allNodeOfType)
		ts.add({{"ast", node}});
}

} /* namespace InformationScripting */
<|endoftext|>


<commit_before>#include <Internal/Logger/LoggerImpl.hpp>
#include <Utility/Utilities/Include/Logging/LogLevel.hpp>
#include <Utility/Utilities/Include/Logging/LogTag.hpp>
#include <Utility/Utilities/Include/Logging/LogTextData.hpp>
#include <Utility/Utilities/Include/Logging/LogLevelConverter.hpp>
#include <Utility/Utilities/Include/Logging/LogTagConverter.hpp>
#include <Utility/Utilities/Include/Logging/HelpFunctions.hpp>
#include <Utility/Utilities/Include/IO/FileMap/FileMap.hpp>

#include <Utility/Utilities/Include/String/VA_ListToString.hpp>
#include <Utility/Utilities/Include/String/StringHelper.hpp>
#include <Utility/Utilities/Include/PointerArithmetic/PointerArithmetic.hpp>

#include <iostream>
#include <algorithm>
#include <chrono>
#include <Windows.h>

namespace DoremiEngine
{
    namespace Logging
    {
        // TODORT, move to cpp
        struct ThreadMetaData
        {
            ThreadMetaData() : isApplicationOnline(nullptr), isThreadStillRunning(nullptr) {}

            ThreadMetaData(bool* p_isApplicationOnline, bool p_isThreadStillRunning)
                : isApplicationOnline(p_isApplicationOnline), isThreadStillRunning(new bool(p_isThreadStillRunning))
            {
            }

            ~ThreadMetaData()
            {
                if(isThreadStillRunning != nullptr)
                {
                    delete isThreadStillRunning;
                }
            }
            ThreadMetaData(const ThreadMetaData& threadMetaData) = delete;

            const bool* isApplicationOnline;
            bool* isThreadStillRunning;
        };

        using namespace Doremi::Utilities;
        using namespace Doremi::Utilities::Logging;

        void ThreadWork(ThreadMetaData* p_threadMetaData, Memory::ArbitrarySizeCirclebuffer* p_localBuffer, Memory::ArbitrarySizeCirclebuffer* m_outGoingBuffer);

        LoggerImpl::LoggerImpl()
            : m_localBuffer(nullptr), m_outGoingBuffer(nullptr), m_fileMap(nullptr), m_mutex(nullptr), m_applicationRunning(nullptr), m_threadMetaData(nullptr)
        {
#ifdef NO_LOGGER
            return;
#endif
            m_uniqueId = GetCurrentProcessId();
            Initialize();
        }

        LoggerImpl::~LoggerImpl()
        {
#ifdef NO_LOGGER
            return;
#endif
            try
            {
                if(m_threadMetaData != nullptr)
                {
                    *m_applicationRunning = false;
                    while(*m_threadMetaData->isThreadStillRunning == true)
                    {
                        using namespace std::literals;
                        std::this_thread::sleep_for(1ms);
                    }
                }
            }
            catch(...)
            {
                std::cout << "Failed to shutdown threads properly" << std::endl;
            }

            if(m_fileMap != nullptr)
            {
                delete m_fileMap;
            }

            if(m_localBuffer != nullptr)
            {
                delete m_localBuffer;
            }
            if(m_outGoingBuffer != nullptr)
            {
                delete m_outGoingBuffer;
            }
            if(m_mutex != nullptr)
            {
                delete m_mutex;
            }
            if(m_threadMetaData != nullptr)
            {
                delete m_threadMetaData;
            }
            if(m_applicationRunning != nullptr)
            {
                delete m_applicationRunning;
            }
        }

        void LoggerImpl::Initialize()
        {
#ifdef NO_LOGGER
            return;
#endif
            m_localBuffer = new Memory::ArbitrarySizeCirclebuffer();
            m_outGoingBuffer = new Memory::ArbitrarySizeCirclebuffer();

            // TODOXX TODORT our hardcode better value from empirical tests
            // Create localbuffer
            m_localBuffer->Initialize(10000);

            // Create mutex
            m_mutex = CreateFileMapMutex();

            // Fetch shared memory from fileMap
            void* fileMapMemory = InitializeFileMap(Constants::IPC_FILEMAP_SIZE);

            // Intiailize outgoing buffer with shared memory and mutex
            m_outGoingBuffer->Initialize(fileMapMemory, Constants::IPC_FILEMAP_SIZE, m_mutex);
            m_applicationRunning = new bool(true);

            m_threadMetaData = new ThreadMetaData(m_applicationRunning, new bool(true));
            std::thread outGoingLoggingThread(ThreadWork, m_threadMetaData, m_localBuffer, m_outGoingBuffer);
            outGoingLoggingThread.detach();
            StartLoggingProcess();
        }

        void LoggerImpl::LogTextReal(const std::string& p_function, const uint16_t& p_line, const LogTag& p_logTag, const LogLevel& p_logLevel,
                                     const char* p_format, ...)
        {
            using namespace Doremi::Utilities::Logging;
            using namespace Doremi::Utilities;
            // Build a string from va_list
            va_list args;
            va_start(args, p_format);
            if(p_logLevel != LogLevel::MASS_DATA_PRINT)
            {
                printf("[%s:%s] ", LogTagConverter::convert(p_logTag).name.c_str(), LogLevelConverter::convert(p_logLevel).name.c_str());
                vprintf(p_format, args);
                printf("\n");
            }
#ifdef NO_LOGGER
            va_end(args);
            return;
#endif
            std::string message;
            String::toString(message, p_format, args);
            va_end(args);

            // Allocate buffer
            const uint16_t functionSize = p_function.size() + 1; // The plus one comes as the null terminator
            const uint16_t messageSize = message.size() + 1; // The plus one comes as the null terminator
            const uint32_t bufferSize = functionSize + messageSize + sizeof(TextMetaData);

            void* buffer = malloc(bufferSize); // TODORT only use one buffer and lock this buffer
            memset(buffer, 0, bufferSize); // Do not remove this, used to get null terminator in the strings
            char* charBuffer = static_cast<char*>(buffer);

            // Write textmetadata
            *static_cast<TextMetaData*>(buffer) = TextMetaData(p_logTag, p_logLevel, p_line, functionSize, messageSize);
            charBuffer = PointerArithmetic::Addition(charBuffer, sizeof(TextMetaData));

            // Function
            const std::size_t functionLength = p_function.copy(charBuffer, functionSize, 0); // Copy functionString to buffer
            charBuffer = PointerArithmetic::Addition(charBuffer, functionLength + 1); // The plus one comes as the null terminator

            // Message
            const std::size_t messageLength = message.copy(charBuffer, messageSize, 0); // Copy messageString to buffer
            charBuffer = PointerArithmetic::Addition(charBuffer, messageLength + 1); // The plus one comes as the null terminator

            using namespace Memory;
            Memory::CircleBufferHeader header;
            header.packageSize = bufferSize;
            header.packageType = CircleBufferType(CircleBufferTypeEnum::TEXT);
            bool succeed = false;

            while(!succeed)
            {
                try
                {
                    m_localBuffer->Produce(header, buffer);
                    succeed = true;
                }
                catch(...)
                {
                    // Do nothing
                    // TODOXX TODORT NOt very performance nice
                    std::this_thread::sleep_for(Logging::Constants::LOGGING_PRODUCE_TIME_WAIT);
                }
            }
            free(buffer);
        }

        void* LoggerImpl::InitializeFileMap(const std::size_t& p_size)
        {
            m_fileMap = new IO::FileMap();
            void* memory = m_fileMap->Initialize(Logging::BuildFileMapName(m_uniqueId), p_size);
            if(memory != nullptr)
            {
                return memory;
            }
            else
            {
                throw std::runtime_error("Failed to initialize filemap.");
            }
        }

        IO::Mutex* LoggerImpl::CreateFileMapMutex()
        {
            IO::Mutex* mutex = new IO::FileMapMutex();
            const bool success = mutex->Initialize(Logging::BuildFileMapMutexName(m_uniqueId));
            if(success)
            {
                return mutex;
            }
            else
            {
                delete mutex;
                throw std::runtime_error("Failed to initialize filemap mutex.");
            }
        }

        std::wstring LoggerImpl::BuildLoggingProcessArgumentString()
        {
            const std::wstring applicationPathW = String::s2ws(Constants::LOGGING_PROCESS_NAME).c_str();
            const std::wstring arguments = std::wstring(applicationPathW + std::wstring(L" ") + std::to_wstring(m_uniqueId));
            return arguments;
        }

        void LoggerImpl::StartLoggingProcess()
        {
            PROCESS_INFORMATION processInformation;
            STARTUPINFO startupInfo;
            ZeroMemory(&processInformation, sizeof(PROCESS_INFORMATION));
            ZeroMemory(&startupInfo, sizeof(STARTUPINFO));
            startupInfo.cb = sizeof(STARTUPINFO);
            std::wstring& arguments = BuildLoggingProcessArgumentString();

            if(!CreateProcess(NULL, &arguments[0], 0, 0, 0, CREATE_NEW_CONSOLE | CREATE_UNICODE_ENVIRONMENT, 0, 0, &startupInfo, &processInformation))
            {
                std::cout << GetLastError() << std::endl;
                throw std::runtime_error("Creating loggingprocess failed.");
            }
            CloseHandle(processInformation.hProcess);
            CloseHandle(processInformation.hThread);
        }

        void ThreadWork(ThreadMetaData* p_threadMetaData, Memory::ArbitrarySizeCirclebuffer* p_localBuffer, Memory::ArbitrarySizeCirclebuffer* m_outGoingBuffer)
        {
            try
            {
                bool messageExist = true;
                const uint32_t sizeofBuffer = 1000;
                void* buffer = malloc(sizeofBuffer); // TODORT TODOXX Might need to find a better value.
                Memory::CircleBufferHeader* header = new Memory::CircleBufferHeader();
                header->packageSize = sizeofBuffer; // TODORT TODOXX Might need to find a better value.
                bool succeed = false;

                // As long as the application is running or if there are some messages ongoing
                while(*p_threadMetaData->isApplicationOnline || messageExist)
                {
                    using namespace std::literals;
                    messageExist = p_localBuffer->Consume(header, buffer, sizeofBuffer);
                    if(messageExist)
                    {
                        succeed = false;
                        while(!succeed)
                        {
                            succeed = m_outGoingBuffer->Produce(*header, buffer);
                            if(!succeed)
                            {
                                std::this_thread::sleep_for(Logging::Constants::LOGGING_PRODUCE_TIME_WAIT);
                            }
                        }
                    }
                    else
                    {
                        // TODORT
                        // TODOXX Might not be long enough, or might be longer than required.
                        std::this_thread::sleep_for(Logging::Constants::LOGGING_PRODUCE_TIME_WAIT);
                    }
                }

                free(buffer);
                delete header;
                *p_threadMetaData->isThreadStillRunning = false;
            }
            catch(...)
            {
                *p_threadMetaData->isThreadStillRunning = false;
            }
        }
    }
}
<commit_msg>Removed unneccessary checks for null in logger<commit_after>#include <Internal/Logger/LoggerImpl.hpp>
#include <Utility/Utilities/Include/Logging/LogLevel.hpp>
#include <Utility/Utilities/Include/Logging/LogTag.hpp>
#include <Utility/Utilities/Include/Logging/LogTextData.hpp>
#include <Utility/Utilities/Include/Logging/LogLevelConverter.hpp>
#include <Utility/Utilities/Include/Logging/LogTagConverter.hpp>
#include <Utility/Utilities/Include/Logging/HelpFunctions.hpp>
#include <Utility/Utilities/Include/IO/FileMap/FileMap.hpp>

#include <Utility/Utilities/Include/String/VA_ListToString.hpp>
#include <Utility/Utilities/Include/String/StringHelper.hpp>
#include <Utility/Utilities/Include/PointerArithmetic/PointerArithmetic.hpp>

#include <iostream>
#include <algorithm>
#include <chrono>
#include <Windows.h>

namespace DoremiEngine
{
    namespace Logging
    {
        // TODORT, move to cpp
        struct ThreadMetaData
        {
            ThreadMetaData() : isApplicationOnline(nullptr), isThreadStillRunning(nullptr) {}

            ThreadMetaData(bool* p_isApplicationOnline, bool p_isThreadStillRunning)
                : isApplicationOnline(p_isApplicationOnline), isThreadStillRunning(new bool(p_isThreadStillRunning))
            {
            }

            ~ThreadMetaData() { delete isThreadStillRunning; }
            ThreadMetaData(const ThreadMetaData& threadMetaData) = delete;

            const bool* isApplicationOnline;
            bool* isThreadStillRunning;
        };

        using namespace Doremi::Utilities;
        using namespace Doremi::Utilities::Logging;

        void ThreadWork(ThreadMetaData* p_threadMetaData, Memory::ArbitrarySizeCirclebuffer* p_localBuffer, Memory::ArbitrarySizeCirclebuffer* m_outGoingBuffer);

        LoggerImpl::LoggerImpl()
            : m_localBuffer(nullptr), m_outGoingBuffer(nullptr), m_fileMap(nullptr), m_mutex(nullptr), m_applicationRunning(nullptr), m_threadMetaData(nullptr)
        {
#ifdef NO_LOGGER
            return;
#endif
            m_uniqueId = GetCurrentProcessId();
            Initialize();
        }

        LoggerImpl::~LoggerImpl()
        {
#ifdef NO_LOGGER
            return;
#endif
            try
            {
                if(m_threadMetaData != nullptr)
                {
                    *m_applicationRunning = false;
                    while(*m_threadMetaData->isThreadStillRunning == true)
                    {
                        using namespace std::literals;
                        std::this_thread::sleep_for(1ms);
                    }
                }
            }
            catch(...)
            {
                std::cout << "Failed to shutdown threads properly" << std::endl;
            }

            delete m_fileMap;
            delete m_localBuffer;
            delete m_outGoingBuffer;
            delete m_mutex;
            delete m_threadMetaData;
            delete m_applicationRunning;
        }

        void LoggerImpl::Initialize()
        {
#ifdef NO_LOGGER
            return;
#endif
            m_localBuffer = new Memory::ArbitrarySizeCirclebuffer();
            m_outGoingBuffer = new Memory::ArbitrarySizeCirclebuffer();

            // TODOXX TODORT our hardcode better value from empirical tests
            // Create localbuffer
            m_localBuffer->Initialize(10000);

            // Create mutex
            m_mutex = CreateFileMapMutex();

            // Fetch shared memory from fileMap
            void* fileMapMemory = InitializeFileMap(Constants::IPC_FILEMAP_SIZE);

            // Intiailize outgoing buffer with shared memory and mutex
            m_outGoingBuffer->Initialize(fileMapMemory, Constants::IPC_FILEMAP_SIZE, m_mutex);
            m_applicationRunning = new bool(true);

            m_threadMetaData = new ThreadMetaData(m_applicationRunning, new bool(true));
            std::thread outGoingLoggingThread(ThreadWork, m_threadMetaData, m_localBuffer, m_outGoingBuffer);
            outGoingLoggingThread.detach();
            StartLoggingProcess();
        }

        void LoggerImpl::LogTextReal(const std::string& p_function, const uint16_t& p_line, const LogTag& p_logTag, const LogLevel& p_logLevel,
                                     const char* p_format, ...)
        {
            using namespace Doremi::Utilities::Logging;
            using namespace Doremi::Utilities;
            // Build a string from va_list
            va_list args;
            va_start(args, p_format);
            if(p_logLevel != LogLevel::MASS_DATA_PRINT)
            {
                printf("[%s:%s] ", LogTagConverter::convert(p_logTag).name.c_str(), LogLevelConverter::convert(p_logLevel).name.c_str());
                vprintf(p_format, args);
                printf("\n");
            }
#ifdef NO_LOGGER
            va_end(args);
            return;
#endif
            std::string message;
            String::toString(message, p_format, args);
            va_end(args);

            // Allocate buffer
            const uint16_t functionSize = p_function.size() + 1; // The plus one comes as the null terminator
            const uint16_t messageSize = message.size() + 1; // The plus one comes as the null terminator
            const uint32_t bufferSize = functionSize + messageSize + sizeof(TextMetaData);

            void* buffer = malloc(bufferSize); // TODORT only use one buffer and lock this buffer
            memset(buffer, 0, bufferSize); // Do not remove this, used to get null terminator in the strings
            char* charBuffer = static_cast<char*>(buffer);

            // Write textmetadata
            *static_cast<TextMetaData*>(buffer) = TextMetaData(p_logTag, p_logLevel, p_line, functionSize, messageSize);
            charBuffer = PointerArithmetic::Addition(charBuffer, sizeof(TextMetaData));

            // Function
            const std::size_t functionLength = p_function.copy(charBuffer, functionSize, 0); // Copy functionString to buffer
            charBuffer = PointerArithmetic::Addition(charBuffer, functionLength + 1); // The plus one comes as the null terminator

            // Message
            const std::size_t messageLength = message.copy(charBuffer, messageSize, 0); // Copy messageString to buffer
            charBuffer = PointerArithmetic::Addition(charBuffer, messageLength + 1); // The plus one comes as the null terminator

            using namespace Memory;
            Memory::CircleBufferHeader header;
            header.packageSize = bufferSize;
            header.packageType = CircleBufferType(CircleBufferTypeEnum::TEXT);
            bool succeed = false;

            while(!succeed)
            {
                try
                {
                    m_localBuffer->Produce(header, buffer);
                    succeed = true;
                }
                catch(...)
                {
                    // Do nothing
                    // TODOXX TODORT NOt very performance nice
                    std::this_thread::sleep_for(Logging::Constants::LOGGING_PRODUCE_TIME_WAIT);
                }
            }
            free(buffer);
        }

        void* LoggerImpl::InitializeFileMap(const std::size_t& p_size)
        {
            m_fileMap = new IO::FileMap();
            void* memory = m_fileMap->Initialize(Logging::BuildFileMapName(m_uniqueId), p_size);
            if(memory != nullptr)
            {
                return memory;
            }
            else
            {
                throw std::runtime_error("Failed to initialize filemap.");
            }
        }

        IO::Mutex* LoggerImpl::CreateFileMapMutex()
        {
            IO::Mutex* mutex = new IO::FileMapMutex();
            const bool success = mutex->Initialize(Logging::BuildFileMapMutexName(m_uniqueId));
            if(success)
            {
                return mutex;
            }
            else
            {
                delete mutex;
                throw std::runtime_error("Failed to initialize filemap mutex.");
            }
        }

        std::wstring LoggerImpl::BuildLoggingProcessArgumentString()
        {
            const std::wstring applicationPathW = String::s2ws(Constants::LOGGING_PROCESS_NAME).c_str();
            const std::wstring arguments = std::wstring(applicationPathW + std::wstring(L" ") + std::to_wstring(m_uniqueId));
            return arguments;
        }

        void LoggerImpl::StartLoggingProcess()
        {
            PROCESS_INFORMATION processInformation;
            STARTUPINFO startupInfo;
            ZeroMemory(&processInformation, sizeof(PROCESS_INFORMATION));
            ZeroMemory(&startupInfo, sizeof(STARTUPINFO));
            startupInfo.cb = sizeof(STARTUPINFO);
            std::wstring& arguments = BuildLoggingProcessArgumentString();

            if(!CreateProcess(NULL, &arguments[0], 0, 0, 0, CREATE_NEW_CONSOLE | CREATE_UNICODE_ENVIRONMENT, 0, 0, &startupInfo, &processInformation))
            {
                std::cout << GetLastError() << std::endl;
                throw std::runtime_error("Creating loggingprocess failed.");
            }
            CloseHandle(processInformation.hProcess);
            CloseHandle(processInformation.hThread);
        }

        void ThreadWork(ThreadMetaData* p_threadMetaData, Memory::ArbitrarySizeCirclebuffer* p_localBuffer, Memory::ArbitrarySizeCirclebuffer* m_outGoingBuffer)
        {
            try
            {
                bool messageExist = true;
                const uint32_t sizeofBuffer = 1000;
                void* buffer = malloc(sizeofBuffer); // TODORT TODOXX Might need to find a better value.
                Memory::CircleBufferHeader* header = new Memory::CircleBufferHeader();
                header->packageSize = sizeofBuffer; // TODORT TODOXX Might need to find a better value.
                bool succeed = false;

                // As long as the application is running or if there are some messages ongoing
                while(*p_threadMetaData->isApplicationOnline || messageExist)
                {
                    using namespace std::literals;
                    messageExist = p_localBuffer->Consume(header, buffer, sizeofBuffer);
                    if(messageExist)
                    {
                        succeed = false;
                        while(!succeed)
                        {
                            succeed = m_outGoingBuffer->Produce(*header, buffer);
                            if(!succeed)
                            {
                                std::this_thread::sleep_for(Logging::Constants::LOGGING_PRODUCE_TIME_WAIT);
                            }
                        }
                    }
                    else
                    {
                        // TODORT
                        // TODOXX Might not be long enough, or might be longer than required.
                        std::this_thread::sleep_for(Logging::Constants::LOGGING_PRODUCE_TIME_WAIT);
                    }
                }

                free(buffer);
                delete header;
                *p_threadMetaData->isThreadStillRunning = false;
            }
            catch(...)
            {
                *p_threadMetaData->isThreadStillRunning = false;
            }
        }
    }
}
<|endoftext|>


<commit_before>/**
 *  @copyright Copyright 2020 The J-PET Framework Authors. All rights reserved.
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may find a copy of the License in the LICENCE file.
 *
 * 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.
 *
 *  @file EventCategorizerTools.cpp
 */

#include "EventCategorizerTools.h"
#include <TMath.h>
#include <vector>

using namespace std;

/**
* Method for determining type of event - back to back 2 gamma
*/
bool EventCategorizerTools::checkFor2Gamma(
  const JPetEvent& event, JPetStatistics& stats, bool saveHistos,
  double b2bSlotThetaDiff, double b2bTimeDiff
)
{
  if (event.getHits().size() < 2) {
    return false;
  }
  for (uint i = 0; i < event.getHits().size(); i++) {
    for (uint j = i + 1; j < event.getHits().size(); j++) {
      JPetHit firstHit, secondHit;
      if (event.getHits().at(i).getTime() < event.getHits().at(j).getTime()) {
        firstHit = event.getHits().at(i);
        secondHit = event.getHits().at(j);
      } else {
        firstHit = event.getHits().at(j);
        secondHit = event.getHits().at(i);
      }
      // Checking for back to back
      double timeDiff = fabs(firstHit.getTime() - secondHit.getTime());
      double deltaLor = (secondHit.getTime() - firstHit.getTime()) * kLightVelocity_cm_ps / 2.;
      double theta1 = min(firstHit.getBarrelSlot().getTheta(), secondHit.getBarrelSlot().getTheta());
      double theta2 = max(firstHit.getBarrelSlot().getTheta(), secondHit.getBarrelSlot().getTheta());
      double thetaDiff = min(theta2 - theta1, 360.0 - theta2 + theta1);
      if (saveHistos) {
        stats.fillHistogram("2Gamma_TimeDiff", timeDiff / 1000.0);
        stats.fillHistogram("2Gamma_DLOR", deltaLor);
        stats.fillHistogram("2Gamma_ThetaDiff", thetaDiff);
      }
      if (fabs(thetaDiff - 180.0) < b2bSlotThetaDiff && timeDiff < b2bTimeDiff) {
        if (saveHistos) {
          TVector3 annhilationPoint = calculateAnnihilationPoint(firstHit, secondHit);
          stats.fillHistogram("2Annih_TimeDiff", timeDiff / 1000.0);
          stats.fillHistogram("2Annih_DLOR", deltaLor);
          stats.fillHistogram("2Annih_ThetaDiff", thetaDiff);
          stats.fillHistogram("2Annih_XY", annhilationPoint.X(), annhilationPoint.Y());
          stats.fillHistogram("2Annih_Z", annhilationPoint.Z());
        }
        return true;
      }
    }
  }
  return false;
}

/**
* Method for determining type of event - 3Gamma
*/
bool EventCategorizerTools::checkFor3Gamma(const JPetEvent& event, JPetStatistics& stats, bool saveHistos)
{
  if (event.getHits().size() < 3) return false;
  for (uint i = 0; i < event.getHits().size(); i++) {
    for (uint j = i + 1; j < event.getHits().size(); j++) {
      for (uint k = j + 1; k < event.getHits().size(); k++) {
        JPetHit firstHit = event.getHits().at(i);
        JPetHit secondHit = event.getHits().at(j);
        JPetHit thirdHit = event.getHits().at(k);

        vector<double> thetaAngles;
        thetaAngles.push_back(firstHit.getBarrelSlot().getTheta());
        thetaAngles.push_back(secondHit.getBarrelSlot().getTheta());
        thetaAngles.push_back(thirdHit.getBarrelSlot().getTheta());
        sort(thetaAngles.begin(), thetaAngles.end());

        vector<double> relativeAngles;
        relativeAngles.push_back(thetaAngles.at(1) - thetaAngles.at(0));
        relativeAngles.push_back(thetaAngles.at(2) - thetaAngles.at(1));
        relativeAngles.push_back(360.0 - thetaAngles.at(2) + thetaAngles.at(0));
        sort(relativeAngles.begin(), relativeAngles.end());
        double transformedX = relativeAngles.at(1) + relativeAngles.at(0);
        double transformedY = relativeAngles.at(1) - relativeAngles.at(0);

        if (saveHistos) {
          stats.fillHistogram("3Gamma_Angles", transformedX, transformedY);
        }
      }
    }
  }
  return true;
}

/**
* Method for determining type of event - prompt
*/
bool EventCategorizerTools::checkForPrompt(
  const JPetEvent& event, JPetStatistics& stats, bool saveHistos,
  double deexTOTCutMin, double deexTOTCutMax)
{
  for (unsigned i = 0; i < event.getHits().size(); i++) {
    double tot = calculateTOT(event.getHits().at(i), TOTCalculationType::kSimplified);
    if (tot > deexTOTCutMin && tot < deexTOTCutMax) {
      if (saveHistos) {
        stats.fillHistogram("Deex_TOT_cut", tot);
      }
      return true;
    }
  }
  return false;
}

/**
* Method for determining type of event - scatter
*/
bool EventCategorizerTools::checkForScatter(
  const JPetEvent& event, JPetStatistics& stats, bool saveHistos, double scatterTOFTimeDiff
)
{
  if (event.getHits().size() < 2) {
    return false;
  }
  for (uint i = 0; i < event.getHits().size(); i++) {
    for (uint j = i + 1; j < event.getHits().size(); j++) {
      JPetHit primaryHit, scatterHit;
      if (event.getHits().at(i).getTime() < event.getHits().at(j).getTime()) {
        primaryHit = event.getHits().at(i);
        scatterHit = event.getHits().at(j);
      } else {
        primaryHit = event.getHits().at(j);
        scatterHit = event.getHits().at(i);
      }

      double scattAngle = calculateScatteringAngle(primaryHit, scatterHit);
      double scattTOF = calculateScatteringTime(primaryHit, scatterHit);
      double timeDiff = scatterHit.getTime() - primaryHit.getTime();

      if (saveHistos) {
        stats.fillHistogram("ScatterTOF_TimeDiff", fabs(scattTOF - timeDiff));
      }

      if (fabs(scattTOF - timeDiff) < scatterTOFTimeDiff) {
        if (saveHistos) {
          stats.fillHistogram("ScatterAngle_PrimaryTOT", scattAngle, calculateTOT(primaryHit, TOTCalculationType::kSimplified));
          stats.fillHistogram("ScatterAngle_ScatterTOT", scattAngle, calculateTOT(scatterHit, TOTCalculationType::kSimplified));
        }
        return true;
      }
    }
  }
  return false;
}

/**
* Calculation of the total TOT of the hit - Time over Threshold:
* the sum of the TOTs on all of the thresholds (1-4) and on the both sides (A,B)
*/
double EventCategorizerTools::calculateTOT(const JPetHit& hit, TOTCalculationType type)
{
  double tot = 0.0;
  double weight = 1.;

  std::map<int, double> thrToTOT_sideA = hit.getSignalA().getRecoSignal().getRawSignal().getTOTsVsThresholdValue();
  std::map<int, double> thrToTOT_sideB = hit.getSignalB().getRecoSignal().getRawSignal().getTOTsVsThresholdValue();

  tot += calculateTOTside(thrToTOT_sideA, type);
  tot += calculateTOTside(thrToTOT_sideB, type);
  return tot;
}

double EventCategorizerTools::calculateTOTside(const std::map<int, double> & thrToTOT_side, TOTCalculationType type)
{
  double tot = 0., weight = 1.;
  if (!thrToTOT_side.empty()) {
    double firstThr = thrToTOT_side.begin()->first;
    tot += weight*it->second;
    if( thrToTOT_side.size() > 1 )
    {
      for (auto it = std::next(thrToTOT_side.begin(), 1); it != thrToTOT_side.end(); ++it) {
        switch(type) {
          case TOTCalculationType::kSimplified:
            weight = 1.;
            break;
          case TOTCalculationType::kThresholdRectangular:
            weight = (it->first - std::prev(it, 1)->first)/firstThr;
            break;
          case TOTCalculationType::kThresholdTrapeze:
            weight = (it->first - std::prev(it, 1)->first)/firstThr;
            tot += weight*(it->second - std::prev(it, 1)->second)/2;
            break;
        }
        tot += weight*it->second;
      }
    }
  }
  return tot;
}

/**
* Calculation of distance between two hits
*/
double EventCategorizerTools::calculateDistance(const JPetHit& hit1, const JPetHit& hit2)
{
  return (hit1.getPos() - hit2.getPos()).Mag();
}

/**
* Calculation of time that light needs to travel the distance between primary gamma
* and scattered gamma. Return value in picoseconds.
*/
double EventCategorizerTools::calculateScatteringTime(const JPetHit& hit1, const JPetHit& hit2)
{
  return calculateDistance(hit1, hit2) / kLightVelocity_cm_ps;
}

/**
* Calculation of scatter angle between primary hit and scattered hit.
* This function assumes that source of first gamma was in (0,0,0).
* Angle is calculated from scalar product, return value in degrees.
*/
double EventCategorizerTools::calculateScatteringAngle(const JPetHit& hit1, const JPetHit& hit2)
{
  return TMath::RadToDeg() * hit1.getPos().Angle(hit2.getPos() - hit1.getPos());
}

/**
* Calculation point in 3D, where annihilation occured
*/
TVector3 EventCategorizerTools::calculateAnnihilationPoint(const JPetHit& hitA, const JPetHit& hitB)
{
  double tof = EventCategorizerTools::calculateTOF(hitA, hitB);
  return calculateAnnihilationPoint(hitA.getPos(), hitB.getPos(), tof);
}

TVector3 EventCategorizerTools::calculateAnnihilationPoint(const TVector3& hitA, const TVector3& hitB, double tof)
{
  TVector3 middleOfLOR = 0.5 * (hitA + hitB);
  TVector3 versorOnLOR = (hitB - hitA).Unit()  ;

  double shift = 0.5 * tof  * kLightVelocity_cm_ps;
  TVector3 annihilationPoint(middleOfLOR.X() + shift * versorOnLOR.X(),
                             middleOfLOR.Y() + shift * versorOnLOR.Y(),
                             middleOfLOR.Z() + shift * versorOnLOR.Z());
  return annihilationPoint;
}

double EventCategorizerTools::calculateTOFByConvention(const JPetHit& hitA, const JPetHit& hitB)
{
  if (hitA.getBarrelSlot().getTheta() < hitB.getBarrelSlot().getTheta()) {
    return calculateTOF(hitA, hitB);
  } else {
    return calculateTOF(hitB, hitA);
  }
}

double EventCategorizerTools::calculateTOF(const JPetHit& hitA, const JPetHit& hitB)
{
  return EventCategorizerTools::calculateTOF(hitA.getTime(), hitB.getTime());
}

double EventCategorizerTools::calculateTOF(double time1, double time2)
{
  return (time1 - time2);
}

/**
* Calculating distance from the center of the decay plane
*/
double EventCategorizerTools::calculatePlaneCenterDistance(
  const JPetHit& firstHit, const JPetHit& secondHit, const JPetHit& thirdHit)
{
  TVector3 crossProd = (secondHit.getPos() - firstHit.getPos()).Cross(thirdHit.getPos() - secondHit.getPos());
  double distCoef = -crossProd.X() * secondHit.getPosX() - crossProd.Y() * secondHit.getPosY() - crossProd.Z() * secondHit.getPosZ();
  if (crossProd.Mag() != 0) {
    return fabs(distCoef) / crossProd.Mag();
  } else {
    ERROR("One of the hit has zero position vector - unable to calculate distance from the center of the surface");
    return -1.;
  }
}
<commit_msg>Fixing compile error<commit_after>/**
 *  @copyright Copyright 2020 The J-PET Framework Authors. All rights reserved.
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may find a copy of the License in the LICENCE file.
 *
 * 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.
 *
 *  @file EventCategorizerTools.cpp
 */

#include "EventCategorizerTools.h"
#include <TMath.h>
#include <vector>

using namespace std;

/**
* Method for determining type of event - back to back 2 gamma
*/
bool EventCategorizerTools::checkFor2Gamma(
  const JPetEvent& event, JPetStatistics& stats, bool saveHistos,
  double b2bSlotThetaDiff, double b2bTimeDiff
)
{
  if (event.getHits().size() < 2) {
    return false;
  }
  for (uint i = 0; i < event.getHits().size(); i++) {
    for (uint j = i + 1; j < event.getHits().size(); j++) {
      JPetHit firstHit, secondHit;
      if (event.getHits().at(i).getTime() < event.getHits().at(j).getTime()) {
        firstHit = event.getHits().at(i);
        secondHit = event.getHits().at(j);
      } else {
        firstHit = event.getHits().at(j);
        secondHit = event.getHits().at(i);
      }
      // Checking for back to back
      double timeDiff = fabs(firstHit.getTime() - secondHit.getTime());
      double deltaLor = (secondHit.getTime() - firstHit.getTime()) * kLightVelocity_cm_ps / 2.;
      double theta1 = min(firstHit.getBarrelSlot().getTheta(), secondHit.getBarrelSlot().getTheta());
      double theta2 = max(firstHit.getBarrelSlot().getTheta(), secondHit.getBarrelSlot().getTheta());
      double thetaDiff = min(theta2 - theta1, 360.0 - theta2 + theta1);
      if (saveHistos) {
        stats.fillHistogram("2Gamma_TimeDiff", timeDiff / 1000.0);
        stats.fillHistogram("2Gamma_DLOR", deltaLor);
        stats.fillHistogram("2Gamma_ThetaDiff", thetaDiff);
      }
      if (fabs(thetaDiff - 180.0) < b2bSlotThetaDiff && timeDiff < b2bTimeDiff) {
        if (saveHistos) {
          TVector3 annhilationPoint = calculateAnnihilationPoint(firstHit, secondHit);
          stats.fillHistogram("2Annih_TimeDiff", timeDiff / 1000.0);
          stats.fillHistogram("2Annih_DLOR", deltaLor);
          stats.fillHistogram("2Annih_ThetaDiff", thetaDiff);
          stats.fillHistogram("2Annih_XY", annhilationPoint.X(), annhilationPoint.Y());
          stats.fillHistogram("2Annih_Z", annhilationPoint.Z());
        }
        return true;
      }
    }
  }
  return false;
}

/**
* Method for determining type of event - 3Gamma
*/
bool EventCategorizerTools::checkFor3Gamma(const JPetEvent& event, JPetStatistics& stats, bool saveHistos)
{
  if (event.getHits().size() < 3) return false;
  for (uint i = 0; i < event.getHits().size(); i++) {
    for (uint j = i + 1; j < event.getHits().size(); j++) {
      for (uint k = j + 1; k < event.getHits().size(); k++) {
        JPetHit firstHit = event.getHits().at(i);
        JPetHit secondHit = event.getHits().at(j);
        JPetHit thirdHit = event.getHits().at(k);

        vector<double> thetaAngles;
        thetaAngles.push_back(firstHit.getBarrelSlot().getTheta());
        thetaAngles.push_back(secondHit.getBarrelSlot().getTheta());
        thetaAngles.push_back(thirdHit.getBarrelSlot().getTheta());
        sort(thetaAngles.begin(), thetaAngles.end());

        vector<double> relativeAngles;
        relativeAngles.push_back(thetaAngles.at(1) - thetaAngles.at(0));
        relativeAngles.push_back(thetaAngles.at(2) - thetaAngles.at(1));
        relativeAngles.push_back(360.0 - thetaAngles.at(2) + thetaAngles.at(0));
        sort(relativeAngles.begin(), relativeAngles.end());
        double transformedX = relativeAngles.at(1) + relativeAngles.at(0);
        double transformedY = relativeAngles.at(1) - relativeAngles.at(0);

        if (saveHistos) {
          stats.fillHistogram("3Gamma_Angles", transformedX, transformedY);
        }
      }
    }
  }
  return true;
}

/**
* Method for determining type of event - prompt
*/
bool EventCategorizerTools::checkForPrompt(
  const JPetEvent& event, JPetStatistics& stats, bool saveHistos,
  double deexTOTCutMin, double deexTOTCutMax)
{
  for (unsigned i = 0; i < event.getHits().size(); i++) {
    double tot = calculateTOT(event.getHits().at(i), TOTCalculationType::kSimplified);
    if (tot > deexTOTCutMin && tot < deexTOTCutMax) {
      if (saveHistos) {
        stats.fillHistogram("Deex_TOT_cut", tot);
      }
      return true;
    }
  }
  return false;
}

/**
* Method for determining type of event - scatter
*/
bool EventCategorizerTools::checkForScatter(
  const JPetEvent& event, JPetStatistics& stats, bool saveHistos, double scatterTOFTimeDiff
)
{
  if (event.getHits().size() < 2) {
    return false;
  }
  for (uint i = 0; i < event.getHits().size(); i++) {
    for (uint j = i + 1; j < event.getHits().size(); j++) {
      JPetHit primaryHit, scatterHit;
      if (event.getHits().at(i).getTime() < event.getHits().at(j).getTime()) {
        primaryHit = event.getHits().at(i);
        scatterHit = event.getHits().at(j);
      } else {
        primaryHit = event.getHits().at(j);
        scatterHit = event.getHits().at(i);
      }

      double scattAngle = calculateScatteringAngle(primaryHit, scatterHit);
      double scattTOF = calculateScatteringTime(primaryHit, scatterHit);
      double timeDiff = scatterHit.getTime() - primaryHit.getTime();

      if (saveHistos) {
        stats.fillHistogram("ScatterTOF_TimeDiff", fabs(scattTOF - timeDiff));
      }

      if (fabs(scattTOF - timeDiff) < scatterTOFTimeDiff) {
        if (saveHistos) {
          stats.fillHistogram("ScatterAngle_PrimaryTOT", scattAngle, calculateTOT(primaryHit, TOTCalculationType::kSimplified));
          stats.fillHistogram("ScatterAngle_ScatterTOT", scattAngle, calculateTOT(scatterHit, TOTCalculationType::kSimplified));
        }
        return true;
      }
    }
  }
  return false;
}

/**
* Calculation of the total TOT of the hit - Time over Threshold:
* the sum of the TOTs on all of the thresholds (1-4) and on the both sides (A,B)
*/
double EventCategorizerTools::calculateTOT(const JPetHit& hit, TOTCalculationType type)
{
  double tot = 0.0;
  double weight = 1.;

  std::map<int, double> thrToTOT_sideA = hit.getSignalA().getRecoSignal().getRawSignal().getTOTsVsThresholdValue();
  std::map<int, double> thrToTOT_sideB = hit.getSignalB().getRecoSignal().getRawSignal().getTOTsVsThresholdValue();

  tot += calculateTOTside(thrToTOT_sideA, type);
  tot += calculateTOTside(thrToTOT_sideB, type);
  return tot;
}

double EventCategorizerTools::calculateTOTside(const std::map<int, double> & thrToTOT_side, TOTCalculationType type)
{
  double tot = 0., weight = 1.;
  if (!thrToTOT_side.empty()) {
    double firstThr = thrToTOT_side.begin()->first;
    tot += weight*thrToTOT_side.begin()->second;
    if( thrToTOT_side.size() > 1 )
    {
      for (auto it = std::next(thrToTOT_side.begin(), 1); it != thrToTOT_side.end(); ++it) {
        switch(type) {
          case TOTCalculationType::kSimplified:
            weight = 1.;
            break;
          case TOTCalculationType::kThresholdRectangular:
            weight = (it->first - std::prev(it, 1)->first)/firstThr;
            break;
          case TOTCalculationType::kThresholdTrapeze:
            weight = (it->first - std::prev(it, 1)->first)/firstThr;
            tot += weight*(it->second - std::prev(it, 1)->second)/2;
            break;
        }
        tot += weight*it->second;
      }
    }
  }
  return tot;
}

/**
* Calculation of distance between two hits
*/
double EventCategorizerTools::calculateDistance(const JPetHit& hit1, const JPetHit& hit2)
{
  return (hit1.getPos() - hit2.getPos()).Mag();
}

/**
* Calculation of time that light needs to travel the distance between primary gamma
* and scattered gamma. Return value in picoseconds.
*/
double EventCategorizerTools::calculateScatteringTime(const JPetHit& hit1, const JPetHit& hit2)
{
  return calculateDistance(hit1, hit2) / kLightVelocity_cm_ps;
}

/**
* Calculation of scatter angle between primary hit and scattered hit.
* This function assumes that source of first gamma was in (0,0,0).
* Angle is calculated from scalar product, return value in degrees.
*/
double EventCategorizerTools::calculateScatteringAngle(const JPetHit& hit1, const JPetHit& hit2)
{
  return TMath::RadToDeg() * hit1.getPos().Angle(hit2.getPos() - hit1.getPos());
}

/**
* Calculation point in 3D, where annihilation occured
*/
TVector3 EventCategorizerTools::calculateAnnihilationPoint(const JPetHit& hitA, const JPetHit& hitB)
{
  double tof = EventCategorizerTools::calculateTOF(hitA, hitB);
  return calculateAnnihilationPoint(hitA.getPos(), hitB.getPos(), tof);
}

TVector3 EventCategorizerTools::calculateAnnihilationPoint(const TVector3& hitA, const TVector3& hitB, double tof)
{
  TVector3 middleOfLOR = 0.5 * (hitA + hitB);
  TVector3 versorOnLOR = (hitB - hitA).Unit()  ;

  double shift = 0.5 * tof  * kLightVelocity_cm_ps;
  TVector3 annihilationPoint(middleOfLOR.X() + shift * versorOnLOR.X(),
                             middleOfLOR.Y() + shift * versorOnLOR.Y(),
                             middleOfLOR.Z() + shift * versorOnLOR.Z());
  return annihilationPoint;
}

double EventCategorizerTools::calculateTOFByConvention(const JPetHit& hitA, const JPetHit& hitB)
{
  if (hitA.getBarrelSlot().getTheta() < hitB.getBarrelSlot().getTheta()) {
    return calculateTOF(hitA, hitB);
  } else {
    return calculateTOF(hitB, hitA);
  }
}

double EventCategorizerTools::calculateTOF(const JPetHit& hitA, const JPetHit& hitB)
{
  return EventCategorizerTools::calculateTOF(hitA.getTime(), hitB.getTime());
}

double EventCategorizerTools::calculateTOF(double time1, double time2)
{
  return (time1 - time2);
}

/**
* Calculating distance from the center of the decay plane
*/
double EventCategorizerTools::calculatePlaneCenterDistance(
  const JPetHit& firstHit, const JPetHit& secondHit, const JPetHit& thirdHit)
{
  TVector3 crossProd = (secondHit.getPos() - firstHit.getPos()).Cross(thirdHit.getPos() - secondHit.getPos());
  double distCoef = -crossProd.X() * secondHit.getPosX() - crossProd.Y() * secondHit.getPosY() - crossProd.Z() * secondHit.getPosZ();
  if (crossProd.Mag() != 0) {
    return fabs(distCoef) / crossProd.Mag();
  } else {
    ERROR("One of the hit has zero position vector - unable to calculate distance from the center of the surface");
    return -1.;
  }
}
<|endoftext|>


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

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

  Copyright (c) 2002 Insight 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.

=========================================================================*/

#ifdef _MSC_VER
#pragma warning ( disable : 4786 )
#endif

#include "itkImage.h"
#include "itkHoughTransform2DLinesImageFilter.h"
#include "itkImageFileReader.h"
#include "itkImageFileWriter.h"
#include "itkImageRegionIterator.h"
#include "itkThresholdImageFilter.h"
#include "itkMinimumMaximumImageCalculator.h"
#include <itkGradientMagnitudeImageFilter.h>
#include <itkDiscreteGaussianImageFilter.h>
#include <list>
#include "itkCastImageFilter.h"

/** Hough Point structure */
struct houghPoint
{
  double radius;
  double angle;
};

int main( int argc, char *argv[] )
{

  if( argc < 4 )
    {
    std::cerr << "Missing Parameters " << std::endl;
    std::cerr << "Usage: " << argv[0] << std::endl;
    std::cerr << " inputImage " << std::endl;
    std::cerr << " outputImage" << std::endl;
    std::cerr << " numberOfLines " << std::endl;
    std::cerr << " variance of the accumulator blurring (default = 5) " << std::endl;
    std::cerr << " radius of the disk to remove from the accumulator (default = 10) "<< std::endl;
    return 1;
    }

  typedef   unsigned char   PixelType;
  typedef   float           AccumulatorPixelType;
  const     unsigned int    Dimension = 2;
  typedef itk::Image< PixelType, Dimension >  ImageType;
  typedef itk::Image< AccumulatorPixelType, Dimension > AccumulatorImageType;

  typedef  unsigned char    OutputPixelType;
  typedef  itk::Image< OutputPixelType, Dimension > OutputImageType;
  typedef  itk::ImageFileReader< ImageType > ReaderType;
  typedef  itk::ImageFileWriter<  OutputImageType  > WriterType;

  ReaderType::Pointer reader = ReaderType::New();
  WriterType::Pointer writer = WriterType::New();

  reader->SetFileName( argv[1] );
  writer->SetFileName( argv[2] );

  typedef itk::CastImageFilter<
                        ImageType,
                        AccumulatorImageType    >    CastingFilterType;

  CastingFilterType::Pointer caster = CastingFilterType::New();

   try
    {
      reader->Update();
    }
  catch( itk::ExceptionObject & excep )
    {
    std::cerr << "Exception caught !" << std::endl;
    std::cerr << excep << std::endl;
    }

  ImageType::Pointer m_Image = reader->GetOutput();

  /** Allocate output */
  OutputImageType::Pointer  m_OutputImage = OutputImageType::New();

  OutputImageType::RegionType region;
  region.SetSize(m_Image->GetLargestPossibleRegion().GetSize());
  region.SetIndex(m_Image->GetLargestPossibleRegion().GetIndex());
  m_OutputImage->SetRegions( region );
  m_OutputImage->SetOrigin(m_Image->GetOrigin());
  m_OutputImage->SetSpacing(m_Image->GetSpacing());
  m_OutputImage->Allocate();
  m_OutputImage->FillBuffer(0);

  /** Aplly gradient filter to the input image */
  std::cout << "Applying gradient magnitude filter" << std::endl;
  typedef itk::GradientMagnitudeImageFilter<AccumulatorImageType,
                                            AccumulatorImageType> GradientFilterType;
  GradientFilterType::Pointer gradFilter =  GradientFilterType::New();
  caster->SetInput(m_Image);
  gradFilter->SetInput(caster->GetOutput());
  gradFilter->Update();

  /** Apply a threshold to the Grad(InputImage) */
  std::cout << "Thresholding" << std::endl;
  typedef itk::ThresholdImageFilter<AccumulatorImageType> ThresholdFilterType;
  ThresholdFilterType::Pointer threshFilter = ThresholdFilterType::New();
  threshFilter->SetInput( gradFilter->GetOutput());
  threshFilter->SetOutsideValue(0);
  unsigned char thresh_below = 0;
  unsigned char thresh_above = 255;
  threshFilter->ThresholdOutside(thresh_below,thresh_above);
  threshFilter->Update();

  /** Define the HoughTransform filter */
  std::cout << "Computing Hough Map" << std::endl;
  typedef itk::HoughTransform2DLinesImageFilter<AccumulatorPixelType,
                                                AccumulatorPixelType>   HoughTransformFilterType;
  HoughTransformFilterType::Pointer houghFilter = HoughTransformFilterType::New();
  houghFilter->SetInput(threshFilter->GetOutput());
  houghFilter->Update();
  AccumulatorImageType::Pointer m_Accumulator = houghFilter->GetOutput();
  houghFilter->SetNumberOfLines(atoi(argv[3]));
  houghFilter->SetVariance(atof(argv[4]));
  houghFilter->SetDiscRadius(atof(argv[5]));
  HoughTransformFilterType::LinesListType lines = houghFilter->GetLines(2);
  lines = houghFilter->GetLines(atoi(argv[3]));
  std::cout << "Found " << lines.size() << " line(s)." << std::endl;

  itk::Index<2> m_Index;
  /** Draw the resulting lines */
  HoughTransformFilterType::LinesListType::const_iterator it_lines = lines.begin();
  while(it_lines != lines.end())
  {
    // Draw the lines
    HoughTransformFilterType::LineType::PointListType points_list = (*it_lines)->GetPoints();
    HoughTransformFilterType::LineType::PointListType::const_iterator it_points = points_list.begin();

    itk::Size<2> size = m_OutputImage->GetLargestPossibleRegion().GetSize();
    float diag = sqrt((float)(size[0]*size[0]+size[1]*size[1]));

    double u[2];
    u[0] = (*it_points).GetPosition()[0];
    u[1] = (*it_points).GetPosition()[1];
    it_points++;
    double v[2];
    v[0] = u[0]-(*it_points).GetPosition()[0];
    v[1] = u[1]-(*it_points).GetPosition()[1];

    double norm = sqrt(v[0]*v[0]+v[1]*v[1]);
    v[0]/=norm;
    v[1]/=norm;

    for(int i=static_cast<int>(-diag);i<static_cast<int>(diag);i++)
    {
      m_Index[0]=(long int)(u[0]+i*v[0]);
      m_Index[1]=(long int)(u[1]+i*v[1]);

      if(m_Index[0]>=0 && m_Index[0]<(long)m_OutputImage->GetLargestPossibleRegion().GetSize()[0]
         && m_Index[1]>=0 && m_Index[1]<(long)m_OutputImage->GetLargestPossibleRegion().GetSize()[1])
      {
        m_OutputImage->SetPixel(m_Index,255);
      }
    }

    it_lines++;
  }

  writer->SetInput(m_OutputImage);

  try
    {
      writer->Update();
    }
  catch( itk::ExceptionObject & excep )
    {
    std::cerr << "Exception caught !" << std::endl;
    std::cerr << excep << std::endl;
    }

  return 0;
}

<commit_msg>ENH: Added comments for the Software Guide<commit_after>/*=========================================================================

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

  Copyright (c) 2002 Insight 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.

=========================================================================*/
#ifdef _MSC_VER
#pragma warning ( disable : 4786 )
#endif

// Software Guide : BeginLatex
//
// This example illustrates the use of the \doxygen{HoughTransform2DLinesImageFilter}
// to find straight lines in a 2-dimensional image.
//
// First, we include the header files of the filter.
//
// Software Guide : EndLatex

// Software Guide : BeginCodeSnippet
#include "itkHoughTransform2DLinesImageFilter.h"
// Software Guide : EndCodeSnippet

#include "itkImage.h"
#include "itkImageFileReader.h"
#include "itkImageFileWriter.h"
#include "itkImageRegionIterator.h"
#include "itkThresholdImageFilter.h"
#include "itkMinimumMaximumImageCalculator.h"
#include <itkGradientMagnitudeImageFilter.h>
#include <itkDiscreteGaussianImageFilter.h>
#include <list>
#include "itkCastImageFilter.h"

int main( int argc, char *argv[] )
{

  if( argc < 4 )
    {
    std::cerr << "Missing Parameters " << std::endl;
    std::cerr << "Usage: " << argv[0] << std::endl;
    std::cerr << " inputImage " << std::endl;
    std::cerr << " outputImage" << std::endl;
    std::cerr << " numberOfLines " << std::endl;
    std::cerr << " variance of the accumulator blurring (default = 5) " << std::endl;
    std::cerr << " radius of the disk to remove from the accumulator (default = 10) "<< std::endl;
    return 1;
    }

  //  Software Guide : BeginLatex
  //
  //  Next, we declare the pixel type and image dimension and
  //  specify the image type to be used as input. We also specify the image type
  //  of the accumulator used in the HoughTransform filter
  //
  //  Software Guide : EndLatex

  // Software Guide : BeginCodeSnippet
  typedef   unsigned char   PixelType;
  typedef   float           AccumulatorPixelType;
  const     unsigned int    Dimension = 2;
  typedef itk::Image< PixelType, Dimension >  ImageType;
  ImageType::IndexType m_Index;
  typedef itk::Image< AccumulatorPixelType, Dimension > AccumulatorImageType;
  // Software Guide : EndCodeSnippet

  //  Software Guide : BeginLatex
  //
  //  We setup a reader to load the input image.
  //
  //  Software Guide : EndLatex
  // Software Guide : BeginCodeSnippet
  typedef  itk::ImageFileReader< ImageType > ReaderType;
  ReaderType::Pointer reader = ReaderType::New();
  reader->SetFileName( argv[1] );
  try
    {
      reader->Update();
    }
  catch( itk::ExceptionObject & excep )
    {
    std::cerr << "Exception caught !" << std::endl;
    std::cerr << excep << std::endl;
    }

  ImageType::Pointer m_Image = reader->GetOutput();
  // Software Guide : EndCodeSnippet

  //  Software Guide : BeginLatex
  //
  //  Once the image is loaded, we apply a \doxygen{GradientMagnitudeImageFilter} to segment edges.
  //  This needs to cast the input image using a \doxygen{CastImageFilter}.
  //
  //  Software Guide : EndLatex
  // Software Guide : BeginCodeSnippet
  typedef itk::CastImageFilter<
                        ImageType,
                        AccumulatorImageType    >    CastingFilterType;

  CastingFilterType::Pointer caster = CastingFilterType::New();

  std::cout << "Applying gradient magnitude filter" << std::endl;
  typedef itk::GradientMagnitudeImageFilter<AccumulatorImageType,
                                            AccumulatorImageType> GradientFilterType;
  GradientFilterType::Pointer gradFilter =  GradientFilterType::New();
  caster->SetInput(m_Image);
  gradFilter->SetInput(caster->GetOutput());
  gradFilter->Update();
  // Software Guide : EndCodeSnippet

  //  Software Guide : BeginLatex
  //
  //  The next step is to apply a threshold filter on the gradient magnitude image to keep only
  //  bright values. Only pixels with a high value will be used by the HoughTransformFilter.
  //
  //  Software Guide : EndLatex
  // Software Guide : BeginCodeSnippet
  std::cout << "Thresholding" << std::endl;
  typedef itk::ThresholdImageFilter<AccumulatorImageType> ThresholdFilterType;
  ThresholdFilterType::Pointer threshFilter = ThresholdFilterType::New();
  threshFilter->SetInput( gradFilter->GetOutput());
  threshFilter->SetOutsideValue(0);
  unsigned char thresh_below = 0;
  unsigned char thresh_above = 255;
  threshFilter->ThresholdOutside(thresh_below,thresh_above);
  threshFilter->Update();
  // Software Guide : EndCodeSnippet

  //  Software Guide : BeginLatex
  //
  //  We create the HoughTransform2DLinesImageFilter based on the pixel type of the input image
  //  (the resulting image from the ThresholdImageFilter).
  //
  //  Software Guide : EndLatex
  // Software Guide : BeginCodeSnippet
  std::cout << "Computing Hough Map" << std::endl;
  typedef itk::HoughTransform2DLinesImageFilter<AccumulatorPixelType,
                                                AccumulatorPixelType>   HoughTransformFilterType;
  HoughTransformFilterType::Pointer houghFilter = HoughTransformFilterType::New();
  // Software Guide : EndCodeSnippet

  //  Software Guide : BeginLatex
  //
  //  We set the input of the filter to be the resulting image of the ThresholdImageFilter
  //  We set also the number of lines we are looking.
  //  Basically, the filter computes the Hough map, blur it using a certain variance and find maxima
  //  in the Hough map. After a maximum is found, the local neighborhood, a circle, is removed from the
  //  Hough map. SetDiscRadius() defines the radius of this disc.
  //
  //  The output of the filter is the accumulator.
  //
  //  Software Guide : EndLatex
  // Software Guide : BeginCodeSnippet
  houghFilter->SetInput(threshFilter->GetOutput());
  houghFilter->SetNumberOfLines(atoi(argv[3]));
  houghFilter->SetVariance(atof(argv[4]));
  houghFilter->SetDiscRadius(atof(argv[5]));
  houghFilter->Update();
  AccumulatorImageType::Pointer m_Accumulator = houghFilter->GetOutput();
  // Software Guide : EndCodeSnippet

  //  Software Guide : BeginLatex
  //
  //  We can also get the lines as \doxygen{LineSpatialObject}. The GetLines() function
  //  return a list of those.
  //
  //  Software Guide : EndLatex
  // Software Guide : BeginCodeSnippet
  HoughTransformFilterType::LinesListType lines;
  lines = houghFilter->GetLines(atoi(argv[3]));
  std::cout << "Found " << lines.size() << " line(s)." << std::endl;
  // Software Guide : EndCodeSnippet

  //  Software Guide : BeginLatex
  //
  //  We can then allocate an image to draw the resulting lines as binary objects.
  //
  //  Software Guide : EndLatex
  // Software Guide : BeginCodeSnippet
  typedef  unsigned char    OutputPixelType;
  typedef  itk::Image< OutputPixelType, Dimension > OutputImageType;

  OutputImageType::Pointer  m_OutputImage = OutputImageType::New();

  OutputImageType::RegionType region;
  region.SetSize(m_Image->GetLargestPossibleRegion().GetSize());
  region.SetIndex(m_Image->GetLargestPossibleRegion().GetIndex());
  m_OutputImage->SetRegions( region );
  m_OutputImage->SetOrigin(m_Image->GetOrigin());
  m_OutputImage->SetSpacing(m_Image->GetSpacing());
  m_OutputImage->Allocate();
  m_OutputImage->FillBuffer(0);
  // Software Guide : EndCodeSnippet

  //  Software Guide : BeginLatex
  //
  //  We iterate through the list of lines and we draw them.
  //
  //  Software Guide : EndLatex
  // Software Guide : BeginCodeSnippet
  HoughTransformFilterType::LinesListType::const_iterator it_lines = lines.begin();
  while(it_lines != lines.end())
  {
  // Software Guide : EndCodeSnippet
  //  Software Guide : BeginLatex
  //
  //  We get the list of points which consists of two points to represent a straight line.
  //  Then, from these two points, we compute a fixed point $u$ and a unit
  //  vector \vec{v} to parameterize the line.
  //
  //  Software Guide : EndLatex
  // Software Guide : BeginCodeSnippet
    HoughTransformFilterType::LineType::PointListType points_list = (*it_lines)->GetPoints();
    HoughTransformFilterType::LineType::PointListType::const_iterator it_points = points_list.begin();

    double u[2];
    u[0] = (*it_points).GetPosition()[0];
    u[1] = (*it_points).GetPosition()[1];
    it_points++;
    double v[2];
    v[0] = u[0]-(*it_points).GetPosition()[0];
    v[1] = u[1]-(*it_points).GetPosition()[1];

    double norm = sqrt(v[0]*v[0]+v[1]*v[1]);
    v[0]/=norm;
    v[1]/=norm;
  // Software Guide : EndCodeSnippet
  //  Software Guide : BeginLatex
  //
  //  We draw a white pixel in the Output image to represent the line.
  //
  //  Software Guide : EndLatex
  // Software Guide : BeginCodeSnippet
    itk::Size<2> size = m_OutputImage->GetLargestPossibleRegion().GetSize();
    float diag = sqrt((float)(size[0]*size[0]+size[1]*size[1]));
    for(int i=static_cast<int>(-diag);i<static_cast<int>(diag);i++)
    {
      m_Index[0]=(long int)(u[0]+i*v[0]);
      m_Index[1]=(long int)(u[1]+i*v[1]);

      if(m_Index[0]>=0 && m_Index[0]<(long)m_OutputImage->GetLargestPossibleRegion().GetSize()[0]
         && m_Index[1]>=0 && m_Index[1]<(long)m_OutputImage->GetLargestPossibleRegion().GetSize()[1])
      {
        m_OutputImage->SetPixel(m_Index,255);
      }
    }
    it_lines++;
  }
  // Software Guide : EndCodeSnippet

  //  Software Guide : BeginLatex
  //
  //  We setup a writer to write out the binary image created.
  //
  //  Software Guide : EndLatex
  // Software Guide : BeginCodeSnippet
  typedef  itk::ImageFileWriter<  OutputImageType  > WriterType;
  WriterType::Pointer writer = WriterType::New();
  writer->SetFileName( argv[2] );
  writer->SetInput(m_OutputImage);

  try
    {
      writer->Update();
    }
  catch( itk::ExceptionObject & excep )
    {
    std::cerr << "Exception caught !" << std::endl;
    std::cerr << excep << std::endl;
    }
  // Software Guide : EndCodeSnippet

  return 0;
}

<|endoftext|>


<commit_before>/*
 * Copyright(c) Sophist Solutions, Inc. 1990-2015.  All rights reserved
 */
#ifndef _Stroika_Foundation_Characters_ToString_inl_
#define _Stroika_Foundation_Characters_ToString_inl_    1

/*
 ********************************************************************************
 ***************************** Implementation Details ***************************
 ********************************************************************************
 */
namespace   Stroika {
    namespace   Foundation {
        namespace   Characters {

            /*
             ********************************************************************************
             ********************************* ToString *************************************
             ********************************************************************************
             */
            template    <typename T>
            String  ToString (const T& t)
            {
                return t.ToString ();
            }

            // Predefined conversions
            template    <>
            inline  String  ToString (const String& t)
            {
                return t;
            }

#if 0
            /*
             * From section from section 3.9.1 of http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3337.pdf
             *      There are five standard signed integer types : signed char, short int, int,
             *      long int, and long long int. In this list, each type provides at least as much
             *      storage as those preceding it in the list.
             *      For each of the standard signed integer types, there exists a corresponding (but different)
             *      standard unsigned integer type: unsigned char, unsigned short int, unsigned int, unsigned long int,
             *      and unsigned long long int, each of which occupies the same amount of storage and has the
             *      same alignment requirements.
             */
#endif
            template    <>
            String  ToString (const int& t);

        }
    }
}
#endif  /*_Stroika_Foundation_Characters_ToString_inl_*/
<commit_msg>minor progress on ToString<commit_after>/*
 * Copyright(c) Sophist Solutions, Inc. 1990-2015.  All rights reserved
 */
#ifndef _Stroika_Foundation_Characters_ToString_inl_
#define _Stroika_Foundation_Characters_ToString_inl_    1

#include    <wchar.h>

#include    "Float2String.h"

/*
 ********************************************************************************
 ***************************** Implementation Details ***************************
 ********************************************************************************
 */
namespace   Stroika {
    namespace   Foundation {
        namespace   Characters {

            /*
             ********************************************************************************
             ********************************* ToString *************************************
             ********************************************************************************
             */
            template    <typename T>
            String  ToString (const T& t)
            {
                return t.ToString ();
            }

            // Predefined conversions
            template    <>
            inline  String  ToString (const String& t)
            {
                return t;
            }

#if 0
            /*
             * From section from section 3.9.1 of http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3337.pdf
             *      There are five standard signed integer types : signed char, short int, int,
             *      long int, and long long int. In this list, each type provides at least as much
             *      storage as those preceding it in the list.
             *      For each of the standard signed integer types, there exists a corresponding (but different)
             *      standard unsigned integer type: unsigned char, unsigned short int, unsigned int, unsigned long int,
             *      and unsigned long long int, each of which occupies the same amount of storage and has the
             *      same alignment requirements.
             */
#endif
            template    <typename T>
            inline  String  ToString (const T& t, typename enable_if < is_integral<T>::value>::type*)
            {
                wchar_t buf[1024];
                swprintf (buf, NElt (buf), L"%d", t);   //tmphack
                return buf;
            }
            template    <typename T>
            inline  String  ToString (const T& t, typename enable_if < is_floating_point<T>::value>::type*)
            {
                return Float2String (t);
            }

        }
    }
}
#endif  /*_Stroika_Foundation_Characters_ToString_inl_*/
<|endoftext|>


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

Program:   Medical Imaging & Interaction Toolkit
Language:  C++
Date:      $Date$
Version:   $Revision: 14645 $

Copyright (c) German Cancer Research Center, Division of Medical and
Biological Informatics. All rights reserved.
See MITKCopyright.txt or http://www.mitk.org/copyright.html 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.

=========================================================================*/

#include <Poco/ClassLibrary.h>

#include <berryIViewPart.h>
#include "src/internal/QmitkRegionGrowing.h"

POCO_BEGIN_NAMED_MANIFEST(berryIViewPart, berry::IViewPart)
  POCO_EXPORT_CLASS(QmitkRegionGrowing)
POCO_END_MANIFEST
<commit_msg>COMP: export correct class in manifest.cpp<commit_after>/*=========================================================================

Program:   Medical Imaging & Interaction Toolkit
Language:  C++
Date:      $Date$
Version:   $Revision: 14645 $

Copyright (c) German Cancer Research Center, Division of Medical and
Biological Informatics. All rights reserved.
See MITKCopyright.txt or http://www.mitk.org/copyright.html 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.

=========================================================================*/

#include <Poco/ClassLibrary.h>

#include <berryIViewPart.h>
#include "src/internal/QmitkRegionGrowingView.h"

POCO_BEGIN_NAMED_MANIFEST(berryIViewPart, berry::IViewPart)
  POCO_EXPORT_CLASS(QmitkRegionGrowingView)
POCO_END_MANIFEST
<|endoftext|>