diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..baa0af25 --- /dev/null +++ b/.gitignore @@ -0,0 +1,23 @@ +.vs +Debug +Release +x64 +__pycache__ +*Moc.cpp +*.dll +*.lib +boost/bin.v2 +boost/stage +boost/b2.exe +boost/project-config.jam +boost/tools/build/src/engine/*.obj +boost/tools/build/src/engine/*.exe +CodeSubWars/.vs +CodeSubWars/log +CodeSubWars/doc/html +CodeSubWars/records +CodeSubWars/x64 +CodeSubWars/*.exe +CodeSubWars/*.exp +solid-3.5.4/lib +ARSTD/Lib diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 00000000..0f701d56 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "boost"] + path = boost + url = https://github.com/boostorg/boost diff --git a/ARSTD/ARSTD.vcxproj b/ARSTD/ARSTD.vcxproj new file mode 100644 index 00000000..d731cb92 --- /dev/null +++ b/ARSTD/ARSTD.vcxproj @@ -0,0 +1,290 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {963EE443-32FB-412F-B7D3-38E0053704B1} + + + MFCProj + + + + StaticLibrary + v143 + Dynamic + + + StaticLibrary + v143 + false + Unicode + + + StaticLibrary + v143 + Dynamic + MultiByte + + + StaticLibrary + v143 + false + Unicode + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>16.0.32002.118 + + + .\Release\ + .\Release\ + + + + .\Debug\ + .\Debug\ + + + + MaxSpeed + AnySuitable + Speed + false + ../boost;../arstd;../arstd/include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + StreamingSIMDExtensions + true + .\Release/ARSTD.pch + .\Release/ + .\Release/ + .\Release/ + Level3 + true + Default + + + Lib\ARSTD.lib + true + + + NDEBUG;%(PreprocessorDefinitions) + 0x0407 + + + + + MaxSpeed + AnySuitable + Speed + false + ../boost;../arstd;../arstd/include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + StreamingSIMDExtensions + true + .\Release/ARSTD.pch + .\Release/ + .\Release/ + .\Release/ + Level3 + true + Default + + + Lib\ARSTD.lib + true + + + NDEBUG;%(PreprocessorDefinitions) + 0x0407 + + + + + Disabled + ../boost;../arstd;../arstd/include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + true + .\Debug/ARSTD.pch + .\Debug/ + .\Debug/ + .\Debug/ + Level3 + true + EditAndContinue + Default + + + Lib\ARSTDD.lib + true + + + _DEBUG;%(PreprocessorDefinitions) + 0x0407 + + + + + Disabled + ../boost;../arstd;../arstd/include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + true + .\Debug/ARSTD.pch + .\Debug/ + .\Debug/ + .\Debug/ + Level3 + true + ProgramDatabase + Default + + + Lib\ARSTDD.lib + true + + + _DEBUG;%(PreprocessorDefinitions) + 0x0407 + + + + + + Disabled + Disabled + EnableFastChecks + EnableFastChecks + MaxSpeed + MaxSpeed + + + + Disabled + Disabled + EnableFastChecks + EnableFastChecks + MaxSpeed + MaxSpeed + + + + + + Disabled + Disabled + EnableFastChecks + EnableFastChecks + MaxSpeed + MaxSpeed + + + + Disabled + Disabled + EnableFastChecks + EnableFastChecks + MaxSpeed + MaxSpeed + + + Disabled + Disabled + EnableFastChecks + EnableFastChecks + MaxSpeed + MaxSpeed + + + Disabled + Disabled + EnableFastChecks + EnableFastChecks + MaxSpeed + MaxSpeed + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/ARSTD/ARSTD.vcxproj.filters b/ARSTD/ARSTD.vcxproj.filters new file mode 100644 index 00000000..a149082c --- /dev/null +++ b/ARSTD/ARSTD.vcxproj.filters @@ -0,0 +1,185 @@ + + + + + {4009fbd6-0269-4a00-886a-dd330da8daeb} + *.h,*.cpp + + + {9bd08d33-a63d-4f90-a0c8-9806acbf90d5} + *.h,*.cpp + + + {05b62ac4-3f93-47c4-af49-14f66a29db95} + + + {18656066-59f1-428a-b604-3f93d0a98427} + + + {ef8242ee-cb48-4905-9dbe-05d5652f92ea} + + + {3309d5c7-84ab-43b2-abc6-99a8eac7b9d0} + + + {317120b1-d591-48f0-803b-c1ac669a3a54} + + + {f5c53ba2-79c2-46d5-9a9f-eb546d4d418a} + + + + + Structures + + + Structures + + + Misc + + + Misc + + + Misc + + + Command + + + Command + + + Command + + + Command + + + OpenGL + + + Geometry + + + Math + + + + + Structures + + + Structures + + + Misc + + + Misc + + + Misc + + + Misc + + + Command + + + Command + + + Command + + + Command + + + Command + + + Command + + + Message + + + OpenGL + + + Common + + + Common + + + Geometry + + + Geometry + + + Geometry + + + Geometry + + + Geometry + + + Geometry + + + Geometry + + + Geometry + + + Math + + + Math + + + Math + + + Math + + + Math + + + Math + + + Math + + + Math + + + Math + + + Math + + + Math + + + Math + + + Math + + + Math + + + \ No newline at end of file diff --git a/ARSTD/ARSTD.vcxproj.user b/ARSTD/ARSTD.vcxproj.user new file mode 100644 index 00000000..88a55094 --- /dev/null +++ b/ARSTD/ARSTD.vcxproj.user @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/ARSTD/ARSTD/Command/BasicCommands.cpp b/ARSTD/ARSTD/Command/BasicCommands.cpp new file mode 100644 index 00000000..ed2a3bfb --- /dev/null +++ b/ARSTD/ARSTD/Command/BasicCommands.cpp @@ -0,0 +1,304 @@ +// Copyright (c) 2005-2022 Andreas Rose. All rights reserved. +// Released under the MIT license. (see license.txt) + + +#include +#include "BasicCommands.h" +#include "CommandProcessor.h" + + +namespace ARSTD +{ + + RepeatCommand::PtrType RepeatCommand::create(int nCycles) + { + return PtrType(new RepeatCommand(nCycles)); + } + + + RepeatCommand::~RepeatCommand() + { + } + + + ARSTD::Command::PtrType RepeatCommand::copy() const + { + return PtrType(new RepeatCommand(*this)); + } + + + void RepeatCommand::initialize() + { + } + + + void RepeatCommand::step() + { + bool bRepeatSuccessful = false; + if (m_nCurrentCycles != 0) + { + getCommandProcessor()->repeat(); + bRepeatSuccessful = true; + + if (m_nCurrentCycles > 0) + --m_nCurrentCycles; + } + + if (m_nCycles < 0) + setProgress(0.5); + else + setProgress(static_cast(m_nCycles - m_nCurrentCycles)/m_nCycles); + + //only if the repeating could not be "started" the command must finished directly otherwise this will done automaticaly + //by the repeat method call + if (!bRepeatSuccessful) + { + m_nCurrentCycles = m_nCycles; + getCommandProcessor()->finished(); + } + } + + + void RepeatCommand::cleanup() + { + } + + + uint64 RepeatCommand::getRessourceID() const + { + return 0; + } + + + std::string RepeatCommand::getName() const + { + return "Repeat"; + } + + + std::string RepeatCommand::getDetails() const + { + std::stringstream ss; + ss << "Repeats previous commands: cycle " << m_nCurrentCycles << " of " << m_nCycles; + return ss.str(); + } + + + RepeatCommand::RepeatCommand(int nCycles) + : m_nCycles(nCycles) + { + if (m_nCycles < 0) + m_nCycles = -1; + m_nCurrentCycles = m_nCycles; + } + + + RepeatCommand::RepeatCommand(const RepeatCommand& other) + : ARSTD::Command(other), + m_nCycles(other.m_nCycles), + m_nCurrentCycles(other.m_nCurrentCycles) + { + } + + + + + + PushCommand::PtrType PushCommand::create() + { + return PtrType(new PushCommand()); + } + + + PushCommand::~PushCommand() + { + } + + + ARSTD::Command::PtrType PushCommand::copy() const + { + return PtrType(new PushCommand(*this)); + } + + + void PushCommand::initialize() + { + } + + + void PushCommand::step() + { + getCommandProcessor()->push(); + setProgress(1); + getCommandProcessor()->finished(); + } + + + void PushCommand::cleanup() + { + } + + + uint64 PushCommand::getRessourceID() const + { + return 0; + } + + + std::string PushCommand::getName() const + { + return "Push"; + } + + + std::string PushCommand::getDetails() const + { + return "Pushs the current command processor context to a stack"; + } + + + PushCommand::PushCommand() + { + } + + + PushCommand::PushCommand(const PushCommand& other) + : ARSTD::Command(other) + { + } + + + + + + PopCommand::PtrType PopCommand::create() + { + return PtrType(new PopCommand()); + } + + + PopCommand::~PopCommand() + { + } + + + ARSTD::Command::PtrType PopCommand::copy() const + { + return PtrType(new PopCommand(*this)); + } + + + void PopCommand::initialize() + { + } + + + void PopCommand::step() + { + setProgress(1); + if (!getCommandProcessor()->pop()) + getCommandProcessor()->finished(); + } + + + void PopCommand::cleanup() + { + } + + + uint64 PopCommand::getRessourceID() const + { + return 0; + } + + + std::string PopCommand::getName() const + { + return "Pop"; + } + + + std::string PopCommand::getDetails() const + { + return "Pops the command processor context from a stack and make it current"; + } + + + PopCommand::PopCommand() + { + } + + + PopCommand::PopCommand(const PopCommand& other) + : ARSTD::Command(other) + { + } + + + + + + CleanupHistoryCommand::PtrType CleanupHistoryCommand::create() + { + return PtrType(new CleanupHistoryCommand()); + } + + + CleanupHistoryCommand::~CleanupHistoryCommand() + { + } + + + ARSTD::Command::PtrType CleanupHistoryCommand::copy() const + { + return PtrType(new CleanupHistoryCommand(*this)); + } + + + void CleanupHistoryCommand::initialize() + { + } + + + void CleanupHistoryCommand::step() + { + getCommandProcessor()->cleanupHistory(); + setProgress(1); + getCommandProcessor()->finished(); + } + + + void CleanupHistoryCommand::cleanup() + { + } + + + uint64 CleanupHistoryCommand::getRessourceID() const + { + return 0; + } + + + std::string CleanupHistoryCommand::getName() const + { + return "CleanupHistory"; + } + + + std::string CleanupHistoryCommand::getDetails() const + { + return "Cleans up the history of the command processor context"; + } + + + CleanupHistoryCommand::CleanupHistoryCommand() + { + } + + + CleanupHistoryCommand::CleanupHistoryCommand(const CleanupHistoryCommand& other) + : ARSTD::Command(other) + { + } + +} //namespace ARSTD diff --git a/ARSTD/ARSTD/Command/BasicCommands.h b/ARSTD/ARSTD/Command/BasicCommands.h new file mode 100644 index 00000000..2f0d8858 --- /dev/null +++ b/ARSTD/ARSTD/Command/BasicCommands.h @@ -0,0 +1,166 @@ +// Copyright (c) 2005-2022 Andreas Rose. All rights reserved. +// Released under the MIT license. (see license.txt) + + +#pragma once + +#include +#include "Command.h" + + +namespace ARSTD +{ + + /** + * This command makes commands executing again until the given number of cycles is reached. + * Its behavior is depend on how the command is executed.\n + * 1. The command is executed directly by the command processor: All previously _executed_ commands + * are executed again.\n + * 2. The command is part of macro command: All previously _attached_ commands are executed again. + * That means the repeat command attached to a macro command repeats only commands of this command + * also if this macro is attached to another macro.\n + * + * Example: two loops in one command plus a seperate repeat. 2 times 2 times 2 (8) torpedos with + * litte pauses are fired. (in python) + \code + * innerLoop = MacroCommand.create('InnerLoop') + * innerLoop.attach(CSWFireCommand.create(self.getFrontLeftWeaponBattery(), None)) + * innerLoop.attach(CSWWaitCommand.create(2.5)) + * innerLoop.attach(RepeatCommand.create(1)) + * + * outerLoop = MacroCommand.create('OuterLoop') + * outerLoop.attach(CSWWaitCommand.create(5)) + * outerLoop.attach(innerLoop) + * outerLoop.attach(RepeatCommand.create(1)) + * + * self.getCommandProcessor().execute(outerLoop) + * self.getCommandProcessor().execute(RepeatCommand.create(1)) + \endcode + */ + class RepeatCommand : public Command + { + public: + typedef std::shared_ptr PtrType; + + /** + * Creates a new repeat command. + * @param nCycles The number of cycles that all previous commands should repeat. If a negativ value is given + * the repeating does not terminate automatically. + * @return Returns the new constructed command. + */ + static PtrType create(int nCycles = -1); + + virtual ~RepeatCommand(); + + virtual ARSTD::Command::PtrType copy() const; + virtual void initialize(); + virtual void step(); + virtual void cleanup(); + virtual uint64 getRessourceID() const; + virtual std::string getName() const; + virtual std::string getDetails() const; + + protected: + RepeatCommand(int nCycles); + RepeatCommand(const RepeatCommand& other); + + int m_nCycles; + int m_nCurrentCycles; + }; + + + + /** + * This command makes the current command processor context beeing copied and stored to the top of a stack. + */ + class PushCommand : public Command + { + public: + typedef std::shared_ptr PtrType; + + /** + * Creates a new PushCommand command. + * @return Returns the new constructed command. + */ + static PtrType create(); + + virtual ~PushCommand(); + + virtual ARSTD::Command::PtrType copy() const; + virtual void initialize(); + virtual void step(); + virtual void cleanup(); + virtual uint64 getRessourceID() const; + virtual std::string getName() const; + virtual std::string getDetails() const; + + protected: + PushCommand(); + PushCommand(const PushCommand& other); + }; + + + + /** + * This command makes the topmost stored command processor context from a stack beeing restored and used as current context. + * If the stack is empty nothing will be done. + * @warning All commands that are in queue after this command are not executed. + */ + class PopCommand : public Command + { + public: + typedef std::shared_ptr PtrType; + + /** + * Creates a new PopCommand command. + * @return Returns the new constructed command. + */ + static PtrType create(); + + virtual ~PopCommand(); + + virtual ARSTD::Command::PtrType copy() const; + virtual void initialize(); + virtual void step(); + virtual void cleanup(); + virtual uint64 getRessourceID() const; + virtual std::string getName() const; + virtual std::string getDetails() const; + + protected: + PopCommand(); + PopCommand(const PopCommand& other); + }; + + + + /** + * This command makes the history (the list of executed commands) from the current command processor context beeing cleared. + */ + class CleanupHistoryCommand : public Command + { + public: + typedef std::shared_ptr PtrType; + + /** + * Creates a new CleanupHistoryCommand command. + * @return Returns the new constructed command. + */ + static PtrType create(); + + virtual ~CleanupHistoryCommand(); + + virtual ARSTD::Command::PtrType copy() const; + virtual void initialize(); + virtual void step(); + virtual void cleanup(); + virtual uint64 getRessourceID() const; + virtual std::string getName() const; + virtual std::string getDetails() const; + + protected: + CleanupHistoryCommand(); + CleanupHistoryCommand(const CleanupHistoryCommand& other); + }; + +} //namespace ARSTD \ No newline at end of file diff --git a/ARSTD/ARSTD/Command/Command.h b/ARSTD/ARSTD/Command/Command.h new file mode 100644 index 00000000..ea5581e1 --- /dev/null +++ b/ARSTD/ARSTD/Command/Command.h @@ -0,0 +1,105 @@ +// Copyright (c) 2005-2022 Andreas Rose. All rights reserved. +// Released under the MIT license. (see license.txt) + + +#pragma once + +#include +#include +#include "arstd/Common/Types.h" +#include "arstd/Command/ICommandHandler.h" + + +namespace ARSTD +{ + class CommandProcessor; + class MacroCommand; + + /** + * The base class of all Commands that can be executed by the CommandProcessor. + * @warning An instance of a command must _not_ used more than ones. To execute the same command again copy it first. + */ + class Command + { + public: + typedef std::shared_ptr PtrType; + + virtual ~Command() {} + + /** + * Returns a copy of the command. + * @return The copied command. + */ + virtual PtrType copy() const = 0; + + //This is called directly before execution (before the first step() is called). + virtual void initialize() = 0; + + //This is called periodically about every 10ms while executing. If the command is done + //finished() must be called. If finished() is never called the command never stops executing. + virtual void step() = 0; + + //This is called directly after finishing of execution or on breaking. + virtual void cleanup() = 0; + + //returns the or-combined ids of the used resources + virtual ARSTD::uint64 getRessourceID() const { return 0; } + + /** + * Returns the name of the command. + * @return The name of the command. + */ + virtual std::string getName() const = 0; + + //Returns some interesting stuff about the current command state. + //@return The detailed state depend command description. + virtual std::string getDetails() const { return "n.a."; } + + /** + * Returns whether the command was already executed. + * @return Returns true if the command was successfully executed otherwise false. + * If the progress has not reached 1 (or 100%) false is returned. + */ + virtual bool wasExecuted() const { return m_fProgress >= 1; } + + //is called if repeating will be initialized + virtual void resetProgress() { setProgress(0); } + + /** + * Returns the progress of command execution. + * @return The progress of the execution in range [0, 1]. + */ + virtual double getProgress() const { return m_fProgress; } + + friend CommandProcessor; + friend MacroCommand; + + protected: + Command() {} + Command(const Command& other) + : m_pCommandprocessor(other.m_pCommandprocessor), + m_fProgress(other.m_fProgress) + { + } + + ICommandHandler* getCommandProcessor() const { return m_pCommandprocessor; } + + //Sets the progress of command execution. + //@param fProgress The new progress of the execution in range [0, 1]. + void setProgress(double fProgress) + { + m_fProgress = fProgress; + if (m_fProgress < 0) m_fProgress = 0; + if (m_fProgress > 1) m_fProgress = 1; + } + + //This indicates the execution environment that the command is done. + //@warning This method is only valid to call inside step(). + void finished() { m_pCommandprocessor->finished(); } + + + ICommandHandler* m_pCommandprocessor; + double m_fProgress; + }; + +} //namespace ARSTD diff --git a/ARSTD/ARSTD/Command/CommandProcessor.cpp b/ARSTD/ARSTD/Command/CommandProcessor.cpp new file mode 100644 index 00000000..82b857ae --- /dev/null +++ b/ARSTD/ARSTD/Command/CommandProcessor.cpp @@ -0,0 +1,224 @@ +// Copyright (c) 2005-2022 Andreas Rose. All rights reserved. +// Released under the MIT license. (see license.txt) + +#include +#include + +#include "Command.h" +#include "CommandProcessorContext.h" +#include "CommandProcessor.h" + + +namespace ARSTD +{ + + CommandProcessor::PtrType CommandProcessor::create() + { + return PtrType(new CommandProcessor()); + } + + + CommandProcessor::~CommandProcessor() + { + } + + + void CommandProcessor::execute(Command::PtrType pCommand) + { + if (!m_pContext || !pCommand) + return; + + pCommand->m_pCommandprocessor = this; + pCommand->resetProgress(); + m_pContext->addCommand(pCommand); + + if (!m_pContext->getCurrentExecutingCommand()) + executeNext(); + } + + + void CommandProcessor::finished() + { + executeNext(); + } + + + void CommandProcessor::repeat() + { + if (!m_pContext) + return; + + if (m_pContext->getCurrentExecutingCommand()) + m_pContext->getCurrentExecutingCommand()->cleanup(); + + m_pContext->setAllCommandsToNotExecuted(); + ICommandHandler::CommandRange range = m_pContext->getWaitingCommands(); + ICommandHandler::CommandIterator it = range.first; + for (; it != range.second; ++it) + { + (*it)->resetProgress(); + } + executeNext(); + } + + + bool CommandProcessor::push() + { + if (!m_pContext) + return false; + + if (m_ContextStack.size() > 30) + throw std::runtime_error("ARSTD::CommandProcessor::push(): maximum context stack depth exceeded"); + + m_ContextStack.push_back(m_pContext->copy()); + return true; + } + + + bool CommandProcessor::pop() + { + if (m_ContextStack.empty()) + return false; + + if (m_pContext && m_pContext->getCurrentExecutingCommand()) + m_pContext->getCurrentExecutingCommand()->cleanup(); + + m_pContext = m_ContextStack.back(); + m_ContextStack.pop_back(); + return true; + } + + + void CommandProcessor::step() + { + if (!m_pContext) + return; + + if (m_pContext->getCurrentExecutingCommand()) + m_pContext->getCurrentExecutingCommand()->step(); + else + executeNext(); + } + + + void CommandProcessor::cleanup() + { + if (!m_pContext) + return; + + if (m_pContext->getCurrentExecutingCommand()) + m_pContext->getCurrentExecutingCommand()->cleanup(); + + m_pContext->cleanup(); + } + + + void CommandProcessor::cleanupStack() + { + cleanup(); + m_ContextStack.clear(); + } + + + void CommandProcessor::cleanupHistory() + { + if (!m_pContext) + return; + + m_pContext->cleanupHistory(); + } + + + void CommandProcessor::skipCurrent() + { + executeNext(); + } + + + bool CommandProcessor::isBusy() + { + if (!m_pContext) + return false; + + return m_pContext->getCurrentExecutingCommand() != nullptr; + } + + + double CommandProcessor::getCurrentCommandProgress() const + { + if (!m_pContext || !m_pContext->getCurrentExecutingCommand()) + return -1; + return m_pContext->getCurrentExecutingCommand()->getProgress(); + } + + + std::string CommandProcessor::getCurrentCommandName() const + { + if (!m_pContext || !m_pContext->getCurrentExecutingCommand()) + return ""; + return m_pContext->getCurrentExecutingCommand()->getName(); + } + + + std::string CommandProcessor::getCurrentCommandDetails() const + { + if (!m_pContext || !m_pContext->getCurrentExecutingCommand()) + return ""; + return m_pContext->getCurrentExecutingCommand()->getDetails(); + } + + + unsigned int CommandProcessor::getNumWaitingCommands() const + { + if (!m_pContext) + return 0; + return m_pContext->getNumWaitingCommands(); + } + + + CommandProcessor::CommandConstRange CommandProcessor::getWaitingCommands() const + { + if (!m_pContext) + return std::make_pair(CommandConstIterator(), CommandConstIterator()); + return m_pContext->getWaitingCommands(); + } + + + unsigned int CommandProcessor::getCurrentStackDepth() const + { + return static_cast(m_ContextStack.size()); + } + + + unsigned int CommandProcessor::getNumExecutedCommands() const + { + if (!m_pContext) + return 0; + return m_pContext->getNumExecutedCommands(); + } + + + CommandProcessor::CommandProcessor() + : m_pContext(CommandProcessorContext::create()) + { + } + + + void CommandProcessor::executeNext() + { + if (!m_pContext) + return; + + if (m_pContext->getCurrentExecutingCommand()) + m_pContext->getCurrentExecutingCommand()->cleanup(); + + m_pContext->incrementCurrentExecutingCommand(); + + if (m_pContext->getCurrentExecutingCommand()) + { + m_pContext->getCurrentExecutingCommand()->resetProgress(); + m_pContext->getCurrentExecutingCommand()->initialize(); + } + } + +} //namespace ARSTD diff --git a/ARSTD/ARSTD/Command/CommandProcessor.h b/ARSTD/ARSTD/Command/CommandProcessor.h new file mode 100644 index 00000000..27026610 --- /dev/null +++ b/ARSTD/ARSTD/Command/CommandProcessor.h @@ -0,0 +1,118 @@ +// Copyright (c) 2005-2022 Andreas Rose. All rights reserved. +// Released under the MIT license. (see license.txt) + + +#pragma once + +#include +#include +#include "ICommandHandler.h" + + +namespace ARSTD +{ + + class Command; + class CommandProcessorContext; + + /** + * This class encapsulates the management of commands. If commands are executed by the commandprocessor, they will be stored + * and executed one after another till all done. + */ + class CommandProcessor : public ICommandHandler + { + public: + typedef std::shared_ptr PtrType; + + static PtrType create(); + + ~CommandProcessor(); + + /** + * Execute the given command. If other commands are currently executed this command will be stored and executed next. + * @param pCommand The command that will be added to the execution queue. + */ + void execute(std::shared_ptr pCommand); + + virtual void finished(); + + /** + * Repeates all commands that were previously executed. + */ + virtual void repeat(); + + /** + * Copies the current context to a stack. + * @return True on success. + */ + virtual bool push(); + + /** + * Restores the topmost context from a stack and makes it current. + * @return True on success. + */ + virtual bool pop(); + + /** + * Removes only executed commands that are stored. + */ + virtual void cleanupHistory(); + + void step(); + + /** + * Removes all (executed and waiting) stored commands from the queue. + * @post isBusy() is false + */ + void cleanup(); + + //cleans up the stack and removes all (executed and waiting) stored commands from the queue. + //@post isBusy() is false + void cleanupStack(); + + /** + * Removes the currently executing command and do the next (if available). + */ + void skipCurrent(); + + /** + * Returns true if the processor is currently executing a command otherwise false. + * @return True if currently executing a command otherwise false. + */ + bool isBusy(); + + /** + * Returns the progress of the currently executing command. + * @return The progress of the executing command in range [0, 1]. If the processor is not busy -1 is returned. + */ + double getCurrentCommandProgress() const; + + /** + * Returns the name of the currently executing command. + * @return The current executing command name. If the processor is not busy "" is returned. + */ + std::string getCurrentCommandName() const; + std::string getCurrentCommandDetails() const; + + /** + * Returns the number of commands that currently waits of its execution. + * @return The number of currently waiting commands. + */ + unsigned int getNumWaitingCommands() const; + + ICommandHandler::CommandConstRange getWaitingCommands() const; + + unsigned int getCurrentStackDepth() const; + + unsigned int getNumExecutedCommands() const; + + protected: + CommandProcessor(); + + void executeNext(); + + std::shared_ptr m_pContext; + std::vector > m_ContextStack; + }; + +} //namespace ARSTD \ No newline at end of file diff --git a/ARSTD/ARSTD/Command/CommandProcessorContext.cpp b/ARSTD/ARSTD/Command/CommandProcessorContext.cpp new file mode 100644 index 00000000..57b0ca8b --- /dev/null +++ b/ARSTD/ARSTD/Command/CommandProcessorContext.cpp @@ -0,0 +1,158 @@ +// Copyright (c) 2005-2022 Andreas Rose. All rights reserved. +// Released under the MIT license. (see license.txt) + + +#include "CommandProcessorContext.h" +#include "Command.h" +#include "CommandProcessor.h" + + +namespace ARSTD +{ + + CommandProcessorContext::PtrType CommandProcessorContext::create() + { + return PtrType(new CommandProcessorContext()); + } + + + CommandProcessorContext::~CommandProcessorContext() + { + } + + + CommandProcessorContext::PtrType CommandProcessorContext::copy() + { + return PtrType(new CommandProcessorContext(*this)); + } + + + bool CommandProcessorContext::addCommand(Command::PtrType pCommand) + { + m_WaitingCommands.push_back(pCommand); + return true; + } + + + Command::PtrType CommandProcessorContext::getCurrentExecutingCommand() const + { + return m_pCurrentExecutingCommand; + } + + + void CommandProcessorContext::cleanup() + { + m_ExecutedCommands.clear(); + m_pCurrentExecutingCommand.reset(); + m_WaitingCommands.clear(); + } + + + void CommandProcessorContext::cleanupHistory() + { + m_ExecutedCommands.clear(); + } + + + void CommandProcessorContext::setCommandProcessor(CommandProcessor* pCommandProcessor) + { +// if (m_pCurrentExecutingCommand) m_pCurrentExecutingCommand->setCommandProcessor(pCommandProcessor); +// +// ICommandHandler::CommandContainer::const_iterator it = other.m_WaitingCommands.begin(); +// ICommandHandler::CommandContainer::const_iterator itEnd = other.m_WaitingCommands.end(); +// for (; it != itEnd; ++it) +// { +// (*it)->setCommandProcessor(pCommandProcessor); +// } + } + + + int CommandProcessorContext::getNumExecutedCommands() const + { + return static_cast(m_ExecutedCommands.size()); + } + + + int CommandProcessorContext::getNumWaitingCommands() const + { + return static_cast(m_WaitingCommands.size()); + } + + + ICommandHandler::CommandRange CommandProcessorContext::getWaitingCommands() + { + return std::make_pair(m_WaitingCommands.begin(), m_WaitingCommands.end()); + } + + + ICommandHandler::CommandConstRange CommandProcessorContext::getWaitingCommands() const + { + return std::make_pair(m_WaitingCommands.begin(), m_WaitingCommands.end()); + } + + + void CommandProcessorContext::incrementCurrentExecutingCommand() + { + if (m_pCurrentExecutingCommand) + m_ExecutedCommands.push_back(m_pCurrentExecutingCommand); + if (!m_WaitingCommands.empty()) + { + m_pCurrentExecutingCommand = m_WaitingCommands.front(); + m_WaitingCommands.pop_front(); + } + else + m_pCurrentExecutingCommand.reset(); + } + + + void CommandProcessorContext::setAllCommandsToNotExecuted() + { + ICommandHandler::CommandContainer newWaitingCommands; + + ICommandHandler::CommandConstIterator it = m_ExecutedCommands.begin(); + for (; it != m_ExecutedCommands.end(); ++it) + { + newWaitingCommands.push_back(*it); + } + + if (m_pCurrentExecutingCommand) + newWaitingCommands.push_back(m_pCurrentExecutingCommand); + + it = m_WaitingCommands.begin(); + for (; it != m_WaitingCommands.end(); ++it) + { + newWaitingCommands.push_back(*it); + } + + cleanup(); + m_WaitingCommands.swap(newWaitingCommands); + } + + + CommandProcessorContext::CommandProcessorContext() + { + } + + + CommandProcessorContext::CommandProcessorContext(const CommandProcessorContext& other) + { + ICommandHandler::CommandContainer::const_iterator it = other.m_ExecutedCommands.begin(); + ICommandHandler::CommandContainer::const_iterator itEnd = other.m_ExecutedCommands.end(); + for (; it != itEnd; ++it) + { + m_ExecutedCommands.push_back((*it)->copy()); + } + + if (other.m_pCurrentExecutingCommand) m_pCurrentExecutingCommand = other.m_pCurrentExecutingCommand->copy(); + + it = other.m_WaitingCommands.begin(); + itEnd = other.m_WaitingCommands.end(); + for (; it != itEnd; ++it) + { + m_WaitingCommands.push_back((*it)->copy()); + } + } + + + +} //namespace ARSTD \ No newline at end of file diff --git a/ARSTD/ARSTD/Command/CommandProcessorContext.h b/ARSTD/ARSTD/Command/CommandProcessorContext.h new file mode 100644 index 00000000..236feb58 --- /dev/null +++ b/ARSTD/ARSTD/Command/CommandProcessorContext.h @@ -0,0 +1,71 @@ +// Copyright (c) 2005-2022 Andreas Rose. All rights reserved. +// Released under the MIT license. (see license.txt) + + +#pragma once + +#include +#include "ICommandHandler.h" + + +namespace ARSTD +{ + + class Command; + class CommandProcessor; + + //the context that is mainly managed through a command processor + class CommandProcessorContext + { + public: + typedef std::shared_ptr PtrType; + + //creates a new empty context + static PtrType create(); + + ~CommandProcessorContext(); + + //makes a deep copy + PtrType copy(); + + //adds a command to the end + bool addCommand(std::shared_ptr pCommand); + + //returns the command the is currently executing. returns NULL if no command is currently executing. + std::shared_ptr getCurrentExecutingCommand() const; + + //empties the whole context + void cleanup(); + + //empties only the executed command container + void cleanupHistory(); + + //sets the commandprocessor to all commands + void setCommandProcessor(CommandProcessor* pCommandProcessor); + + //returns the number of executed commands + int getNumExecutedCommands() const; + + //returns the number of waiting commands + int getNumWaitingCommands() const; + + //returns a range of all waiting commands + ICommandHandler::CommandRange getWaitingCommands(); + ICommandHandler::CommandConstRange getWaitingCommands() const; + + //makes the current executing command to be the next available + void incrementCurrentExecutingCommand(); + + //marks all commands to not be executed + void setAllCommandsToNotExecuted(); + + protected: + CommandProcessorContext(); + CommandProcessorContext(const CommandProcessorContext& other); + + ICommandHandler::CommandContainer m_ExecutedCommands; + std::shared_ptr m_pCurrentExecutingCommand; + ICommandHandler::CommandContainer m_WaitingCommands; + }; + +} //namespace ARSTD \ No newline at end of file diff --git a/ARSTD/ARSTD/Command/ICommandHandler.h b/ARSTD/ARSTD/Command/ICommandHandler.h new file mode 100644 index 00000000..7a91835f --- /dev/null +++ b/ARSTD/ARSTD/Command/ICommandHandler.h @@ -0,0 +1,39 @@ +// Copyright (c) 2005-2022 Andreas Rose. All rights reserved. +// Released under the MIT license. (see license.txt) + + +#pragma once + +#include +#include + +namespace ARSTD +{ + + class Command; + + class ICommandHandler + { + public: + typedef std::shared_ptr PtrType; + typedef std::deque > CommandContainer; + typedef CommandContainer::iterator CommandIterator; + typedef CommandContainer::const_iterator CommandConstIterator; + typedef std::pair CommandRange; + typedef std::pair CommandConstRange; + + virtual ~ICommandHandler() {} + + //callback method that will be executed by the executing command to report finishing of itself + virtual void finished() = 0; + + //Repeates all commands that were previously executed. + virtual void repeat() = 0; + + //these methods are routed through to the "real" command processor if call in macrocommand + virtual bool push() = 0; + virtual bool pop() = 0; + virtual void cleanupHistory() = 0; + + }; +} \ No newline at end of file diff --git a/ARSTD/ARSTD/Command/MacroCommand.cpp b/ARSTD/ARSTD/Command/MacroCommand.cpp new file mode 100644 index 00000000..8c48e025 --- /dev/null +++ b/ARSTD/ARSTD/Command/MacroCommand.cpp @@ -0,0 +1,331 @@ +// Copyright (c) 2005-2022 Andreas Rose. All rights reserved. +// Released under the MIT license. (see license.txt) + + +#include +#include +#include +#include + +#include + +#include "MacroCommand.h" + + +namespace ARSTD +{ + + + MacroCommand::PtrType MacroCommand::create(const std::string& name) + { + return PtrType(new MacroCommand(name)); + } + + + Command::PtrType MacroCommand::copy() const + { + return PtrType(new MacroCommand(*this)); + } + + + void MacroCommand::initialize() + { + if (m_CommandContainer.empty()) + { + m_itCurrentExecutingCommand = m_CommandContainer.end(); + } + else + { + m_itCurrentExecutingCommand = m_CommandContainer.begin(); + assert(*m_itCurrentExecutingCommand); + (*m_itCurrentExecutingCommand)->initialize(); + } + } + + + void MacroCommand::step() + { + if (m_itCurrentExecutingCommand != m_CommandContainer.end()) + { + (*m_itCurrentExecutingCommand)->step(); + } + else + { + finished(); + } + } + + + void MacroCommand::cleanup() + { + if (m_itCurrentExecutingCommand != m_CommandContainer.end()) + { + (*m_itCurrentExecutingCommand)->cleanup(); + } + } + + + std::string MacroCommand::getName() const + { + return getName(0); + } + + + std::string MacroCommand::getDetails() const + { + return getDetails(0); + } + + + bool MacroCommand::wasExecuted() const + { + return getProgress() >= 1; + } + + + double MacroCommand::getProgress() const + { + double fProgress = 0; + + CommandContainer::const_iterator it = m_CommandContainer.begin(); + for (; it != m_CommandContainer.end(); ++it) + { + fProgress += (*it)->getProgress(); + } + if (!m_CommandContainer.empty()) + fProgress /= m_CommandContainer.size(); + + return fProgress; + } + + + void MacroCommand::resetProgress() + { + CommandContainer::iterator it = m_CommandContainer.begin(); + for (; it != m_CommandContainer.end(); ++it) + { + (*it)->resetProgress(); + } + } + + + ARSTD::uint64 MacroCommand::getRessourceID() const + { + ARSTD::uint64 id = 0; + + CommandContainer::const_iterator it = m_CommandContainer.begin(); + for (; it != m_CommandContainer.end(); ++it) + { + id += (*it)->getRessourceID(); + } + + return id; + } + + + void MacroCommand::finished() + { + if (m_itCurrentExecutingCommand != m_CommandContainer.end()) + (*m_itCurrentExecutingCommand)->cleanup(); + + if (m_itCurrentExecutingCommand != m_CommandContainer.end() && + m_itCurrentExecutingCommand != boost::prior(m_CommandContainer.end())) + { + ++m_itCurrentExecutingCommand; + (*m_itCurrentExecutingCommand)->resetProgress(); + (*m_itCurrentExecutingCommand)->initialize(); + } + else + { + m_itCurrentExecutingCommand = m_CommandContainer.end(); + getCommandProcessor()->finished(); + } + } + + + void MacroCommand::repeat() + { + if (m_CommandContainer.empty()) + { + m_itCurrentExecutingCommand = m_CommandContainer.end(); + return; + } + + if (m_itCurrentExecutingCommand != m_CommandContainer.end()) + (*m_itCurrentExecutingCommand)->cleanup(); + + m_itCurrentExecutingCommand = m_CommandContainer.begin(); + MacroCommand::resetProgress(); + (*m_itCurrentExecutingCommand)->initialize(); + } + + + bool MacroCommand::push() + { + return getCommandProcessor()->push(); + } + + + bool MacroCommand::pop() + { + return getCommandProcessor()->pop(); + } + + + void MacroCommand::cleanupHistory() + { + getCommandProcessor()->cleanupHistory(); + } + + + double MacroCommand::getCurrentCommandProgress() + { + if (m_itCurrentExecutingCommand == m_CommandContainer.end()) + return -1; + return (*m_itCurrentExecutingCommand)->getProgress(); + } + + + std::string MacroCommand::getCurrentCommandName() + { + if (m_itCurrentExecutingCommand == m_CommandContainer.end()) + return ""; + return (*m_itCurrentExecutingCommand)->getName(); + } + + + std::string MacroCommand::getCurrentCommandDetails() + { + if (m_itCurrentExecutingCommand == m_CommandContainer.end()) + return ""; + return (*m_itCurrentExecutingCommand)->getDetails(); + } + + + void MacroCommand::attach(Command::PtrType pCommand) + { + if (!pCommand) + return; + pCommand->m_pCommandprocessor = this; + pCommand->resetProgress(); + m_CommandContainer.push_back(pCommand); + m_itCurrentExecutingCommand = m_CommandContainer.end(); + } + + + void MacroCommand::detach(Command::PtrType pCommand) + { + CommandContainer::iterator itFound = std::find(m_CommandContainer.begin(), m_CommandContainer.end(), pCommand); + if (itFound != m_CommandContainer.end()) + m_CommandContainer.erase(itFound); + m_itCurrentExecutingCommand = m_CommandContainer.end(); + } + + + MacroCommand::MacroCommand(const std::string& name) + : m_Name(name) + { + m_itCurrentExecutingCommand = m_CommandContainer.end(); + } + + + MacroCommand::MacroCommand(const MacroCommand& other) + : Command(other), + m_Name(other.m_Name) + { + CommandContainer::const_iterator itOther = other.m_CommandContainer.begin(); + for (; itOther != other.m_CommandContainer.end(); ++itOther) + { + Command::PtrType pCopyCommand = (*itOther)->copy(); + pCopyCommand->m_pCommandprocessor = this; + m_CommandContainer.push_back(pCopyCommand); + } + + assert(m_CommandContainer.size() == other.m_CommandContainer.size()); + itOther = other.m_CommandContainer.begin(); + CommandContainer::iterator it = m_CommandContainer.begin(); + for (; itOther != other.m_CommandContainer.end() && it != m_CommandContainer.end(); ++itOther, ++it) + { + if (other.m_itCurrentExecutingCommand == itOther) + { + m_itCurrentExecutingCommand = it; + } + } + } + + + std::string MacroCommand::getName(int nHiearchy) const + { + std::string strSingleSpace = " "; + std::string strSingleSpaceMinOne = " "; + std::string strSpace = ""; + for (int i = 0; i < nHiearchy; ++i) strSpace += strSingleSpace; + + std::stringstream ss; + ss << strSpace; + if (nHiearchy != 0) ss << "+-"; + ss << m_Name << "\n"; + CommandContainer::const_iterator it = m_CommandContainer.begin(); + for (; it != m_CommandContainer.end(); ++it) + { + MacroCommand::PtrType pMC = std::dynamic_pointer_cast(*it); + if (pMC) + ss << pMC->getName(nHiearchy + 1); + else + { + if (it == m_itCurrentExecutingCommand) + { + ss << ">" << strSpace << strSingleSpaceMinOne; + } + else + { + ss << strSpace << strSingleSpace; + } + ss << "+-" << (*it)->getName() << "\n"; + } + } + + return ss.str(); + } + + + std::string MacroCommand::getDetails(int nHiearchy) const + { + std::string strSingleSpace = " "; + std::string strSingleSpaceMinOne = " "; + std::string strSpace = ""; + for (int i = 0; i < nHiearchy; ++i) strSpace += strSingleSpace; + + std::stringstream ss; + ss << strSpace; + if (nHiearchy != 0) ss << "+-"; + ss << m_Name << "\n"; + CommandContainer::const_iterator it = m_CommandContainer.begin(); + for (; it != m_CommandContainer.end(); ++it) + { + MacroCommand::PtrType pMC = std::dynamic_pointer_cast(*it); + if (pMC) + ss << pMC->getDetails(nHiearchy + 1); + else + { + if (it == m_itCurrentExecutingCommand) + { + ss << ">" << strSpace << strSingleSpaceMinOne; + } + else + { + ss << strSpace << strSingleSpace; + } + ss << "+-" << (*it)->getDetails() << "\n"; + } + } + + return ss.str(); + } + + + MacroCommand::~MacroCommand() + { + } + +} //namespace ARSTD \ No newline at end of file diff --git a/ARSTD/ARSTD/Command/MacroCommand.h b/ARSTD/ARSTD/Command/MacroCommand.h new file mode 100644 index 00000000..1446638d --- /dev/null +++ b/ARSTD/ARSTD/Command/MacroCommand.h @@ -0,0 +1,77 @@ +// Copyright (c) 2005-2022 Andreas Rose. All rights reserved. +// Released under the MIT license. (see license.txt) + + +#pragma once + +#include "Command.h" +#include "ICommandHandler.h" + +namespace ARSTD +{ + + /** + * This class provides functionality for defining macro commands. Macro commands are a list of other commands. These commands + * can also be MacroCommands. The order of the list is the same as the execution order. + */ + class MacroCommand : public Command, public ICommandHandler + { + public: + typedef std::shared_ptr PtrType; + + /** + * Creates a new MacroCommand. + * @param strName The name of the MacroCommand. + */ + static PtrType create(const std::string& strName); + + virtual ~MacroCommand(); + + virtual Command::PtrType copy() const; + virtual void initialize(); + virtual void step(); + virtual void cleanup(); + virtual ARSTD::uint64 getRessourceID() const; + virtual std::string getName() const; + virtual std::string getDetails() const; + + virtual bool wasExecuted() const; + virtual void resetProgress(); + virtual double getProgress() const; + + virtual void finished(); + virtual void repeat(); + virtual bool push(); + virtual bool pop(); + virtual void cleanupHistory(); + + double getCurrentCommandProgress(); + std::string getCurrentCommandName(); + std::string getCurrentCommandDetails(); + + /** + * Attaches a command or MacroCommand. + * @param pCommand The command that should be attached. + */ + void attach(Command::PtrType pCommand); + /** + * Detaches a command or MacroCommand. + * @param pCommand The command that should be detached. + */ + void detach(Command::PtrType pCommand); + + protected: + MacroCommand(const std::string& name); + MacroCommand(const MacroCommand& other); + + CommandRange getAttachedCommands(); + + std::string getName(int nHiearchy = 0) const; + std::string getDetails(int nHiearchy = 0) const; + + CommandContainer m_CommandContainer; + CommandIterator m_itCurrentExecutingCommand; + std::string m_Name; + }; + +} //namespace ARSTD \ No newline at end of file diff --git a/ARSTD/ARSTD/Common/Size3.h b/ARSTD/ARSTD/Common/Size3.h new file mode 100644 index 00000000..4b97f44b --- /dev/null +++ b/ARSTD/ARSTD/Common/Size3.h @@ -0,0 +1,161 @@ +// Copyright (c) 2005-2022 Andreas Rose. All rights reserved. +// Released under the MIT license. (see license.txt) + +#pragma once + +#include "arstd/Math/Math.h" + + +namespace ARSTD +{ + + template + class Size3 + { + public: + Size3(const Type& width = 0, const Type& height = 0, const Type& depth = 0); + explicit Size3(const Vector3& vecSize); + + template + explicit Size3(const Size3& other) + : m_Width(static_cast(other.getWidth())), + m_Height(static_cast(other.getHeight())), + m_Depth(static_cast(other.getDepth())) + { + } + + const Type& getWidth() const; + void setWidth(const Type& width); + + const Type& getHeight() const; + void setHeight(const Type& height); + + const Type& getDepth() const; + void setDepth(const Type& depth); + + const Type getVolume() const; + + Size3& operator *= (const Size3& size); + Size3& operator /= (const Size3& size); + + protected: + Type m_Width; + Type m_Height; + Type m_Depth; + }; + + + typedef Size3 Size3I; + typedef Size3 Size3UI; + typedef Size3 Size3F; + typedef Size3 Size3D; + + + template + Size3::Size3(const Type& width, const Type& height, const Type& depth) + : m_Width(width), + m_Height(height), + m_Depth(depth) + { + } + + + template + Size3::Size3(const Vector3& vecSize) + : m_Width(vecSize.x), + m_Height(vecSize.y), + m_Depth(vecSize.z) + { + } + + + template + const Type& Size3::getWidth() const + { + return m_Width; + } + + + template + void Size3::setWidth(const Type& width) + { + m_Width = width; + } + + + template + const Type& Size3::getHeight() const + { + return m_Height; + } + + + template + void Size3::setHeight(const Type& height) + { + m_Height = height; + } + + + template + const Type& Size3::getDepth() const + { + return m_Depth; + } + + + template + void Size3::setDepth(const Type& depth) + { + m_Depth = depth; + } + + + template + const Type Size3::getVolume() const + { + return m_Width*m_Height*m_Depth; + } + + + template + Size3& Size3::operator /= (const Size3& size) + { + m_Width /= size.m_Width; + m_Height /= size.m_Height; + m_Depth /= size.m_Depth; + return *this; + } + + + template + const Size3 operator * (const Size3& lhs, const Type& rhs) + { + return Size3(lhs.getWidth() * rhs, lhs.getHeight() * rhs, lhs.getDepth() * rhs); + } + + + template + const Size3 operator / (const Size3& lhs, const Size3& rhs) + { + return Size3(lhs) /= rhs; + } + + + template + bool equals(const Size3& lhs, const Size3& rhs, double fEpsilon) + { + return fabs(lhs.getWidth() - rhs.getWidth()) < fEpsilon && + fabs(lhs.getHeight() - rhs.getHeight()) < fEpsilon && + fabs(lhs.getDepth() - rhs.getDepth()) < fEpsilon; + } + + + template + bool operator == (const Size3& lhs, const Size3& rhs) + { + return equals(lhs, rhs, EPSILON); + } + + +} // namespace ARSTD diff --git a/ARSTD/ARSTD/Common/Types.h b/ARSTD/ARSTD/Common/Types.h new file mode 100644 index 00000000..57e9ea5e --- /dev/null +++ b/ARSTD/ARSTD/Common/Types.h @@ -0,0 +1,22 @@ +// Copyright (c) 2005-2022 Andreas Rose. All rights reserved. +// Released under the MIT license. (see license.txt) + +#pragma once + + +namespace ARSTD +{ + typedef unsigned char uchar; + typedef unsigned short ushort; + typedef unsigned int uint; + + typedef char int8; + typedef short int16; + typedef int int32; + typedef __int64 int64; + + typedef unsigned char uint8; + typedef unsigned short uint16; + typedef unsigned int uint32; + typedef unsigned __int64 uint64; +}; diff --git a/ARSTD/ARSTD/Geometry/AxisAlignedBoundingBox.h b/ARSTD/ARSTD/Geometry/AxisAlignedBoundingBox.h new file mode 100644 index 00000000..21431d0d --- /dev/null +++ b/ARSTD/ARSTD/Geometry/AxisAlignedBoundingBox.h @@ -0,0 +1,141 @@ +// Copyright (c) 2005-2022 Andreas Rose. All rights reserved. +// Released under the MIT license. (see license.txt) + +#pragma once + +#include +#include "arstd/Common/Size3.h" + +namespace ARSTD +{ + + template + class AxisAlignedBoundingBox + { + public: + static const AxisAlignedBoundingBox buildAroundPoints(const std::vector>& pointContainer); + + AxisAlignedBoundingBox(); + AxisAlignedBoundingBox(const Vector3& vecMin, const Vector3& vecMax); + AxisAlignedBoundingBox(const Vector3& vecMin, const Size3& size); + + template + explicit AxisAlignedBoundingBox(const AxisAlignedBoundingBox& other) + : m_vecMin(static_cast>(other.getMin())), + m_vecMax(static_cast>(other.getMax())) + { + } + + const Vector3& getMin() const; + void setMin(const Vector3& vecMin); + + const Vector3& getMax() const; + void setMax(const Vector3& vecMax); + + const Size3 getSize() const; + + const Type getWidth() const; + const Type getHeight() const; + const Type getDepth() const; + + protected: + Vector3 m_vecMin; + Vector3 m_vecMax; + }; + + + typedef AxisAlignedBoundingBox AxisAlignedBoundingBoxD; + + + + template + AxisAlignedBoundingBox::AxisAlignedBoundingBox() + { + } + + + template + AxisAlignedBoundingBox::AxisAlignedBoundingBox(const Vector3& vecMin, const Vector3& vecMax) + : m_vecMin(vecMin), + m_vecMax(vecMax) + { + } + + + template + AxisAlignedBoundingBox::AxisAlignedBoundingBox(const Vector3& vecMin, const Size3& size) + : m_vecMin(vecMin), + m_vecMax(vecMin + Vector3(size.getWidth(), size.getHeight(), size.getDepth())) + { + assert(size.getWidth() >= 0 && size.getHeight() >= 0 && size.getDepth() >= 0); + } + + + template + const Vector3& AxisAlignedBoundingBox::getMin() const + { + return m_vecMin; + } + + + template + void AxisAlignedBoundingBox::setMin(const Vector3& vecMin) + { + m_vecMin = vecMin; + } + + + template + const Vector3& AxisAlignedBoundingBox::getMax() const + { + return m_vecMax; + } + + + template + void AxisAlignedBoundingBox::setMax(const Vector3& vecMax) + { + m_vecMax = vecMax; + } + + + template + const Size3 AxisAlignedBoundingBox::getSize() const + { + return Size3(m_vecMax - m_vecMin); + } + + + template + const Type AxisAlignedBoundingBox::getWidth() const + { + return m_vecMax.x - m_vecMin.x; + } + + + template + const Type AxisAlignedBoundingBox::getHeight() const + { + return m_vecMax.y - m_vecMin.y; + } + + + template + const Type AxisAlignedBoundingBox::getDepth() const + { + return m_vecMax.z - m_vecMin.z; + } + + + template + const AxisAlignedBoundingBox AxisAlignedBoundingBox::buildAroundPoints(const std::vector>& points) + { + if (points.empty()) + return AxisAlignedBoundingBox(); + + auto minmax = getMinMax(points.begin(), points.end()); + return AxisAlignedBoundingBox(minmax.first, minmax.second); + } + + +} // namespace ARSTD diff --git a/ARSTD/ARSTD/Geometry/BoundingBox.h b/ARSTD/ARSTD/Geometry/BoundingBox.h new file mode 100644 index 00000000..0e6a10d6 --- /dev/null +++ b/ARSTD/ARSTD/Geometry/BoundingBox.h @@ -0,0 +1,231 @@ +// Copyright (c) 2005-2022 Andreas Rose. All rights reserved. +// Released under the MIT license. (see license.txt) + +#pragma once + +#include +#include "arstd/Common/Size3.h" +#include "arstd/Geometry/Rectangle3.h" +#include "arstd/Geometry/Segment3.h" +#include "arstd/Geometry/AxisAlignedBoundingBox.h" + + +namespace ARSTD +{ + + template + class BoundingBox + { + public: + BoundingBox(); + BoundingBox(const Matrix44& matCoordSys, const Size3& size); + explicit BoundingBox(const AxisAlignedBoundingBox& aabb); + + template + explicit BoundingBox(const BoundingBox& other) + : m_matCoordSys(static_cast< Matrix44 >(other.getCoordSystem())), + m_Size(static_cast< Size3 >(other.getSize())), + m_vecScalingCenter(static_cast>(other.getScalingCenter())) + { + validate(); + } + + void set(const Matrix44& matCoordSys, const Size3& size); + + const Matrix44& getCoordSystem() const; + + const Type getWidth() const; + const Type getHeight() const; + const Type getDepth() const; + + const Size3& getSize() const; + const Type getDiagonalLength() const; + + const Rectangle3 getRectangle(const unsigned int idx) const; + const Segment3 getSegment(const unsigned int idx) const; + const Vector3& getPoint(const unsigned int idx) const; + + bool isValid() const; + const Vector3 getCenter() const; + + void transform(const Matrix44& mat); + + + protected: + void validate(); + + Matrix44 m_matCoordSys; + Size3 m_Size; + Vector3 m_pPoints[8]; + }; + + + typedef BoundingBox BoundingBoxD; + + + template + BoundingBox::BoundingBox() + { + set(Matrix44(true), Size3(0, 0, 0)); + } + + + template + BoundingBox::BoundingBox(const Matrix44& matCoordSys, const Size3& size) + { + set(matCoordSys, size); + } + + + template + BoundingBox::BoundingBox(const AxisAlignedBoundingBox& aabb) + { + set(Matrix44(aabb.getMin()), Size3(aabb.getMax() - aabb.getMin())); + } + + + template + void BoundingBox::set(const Matrix44& matCoordSys, const Size3& size) + { + assert(size.getWidth() >= 0.0f && size.getHeight() >= 0.0f && size.getDepth() >= 0.0f); + + m_matCoordSys = matCoordSys; + m_Size = size; + validate(); + } + + + template + inline const Vector3& BoundingBox::getPoint(const unsigned int idx) const + { + assert(idx < 8); + + return m_pPoints[idx]; + } + + + template + const Matrix44& BoundingBox::getCoordSystem() const + { + return m_matCoordSys; + } + + + template + const Size3& BoundingBox::getSize() const + { + return m_Size; + } + + + template + inline const Rectangle3 BoundingBox::getRectangle(const unsigned int idx) const + { + assert(idx < 6); + + switch (idx) { + case 0: return Rectangle3(getPoint(0), getPoint(1), getPoint(2), getPoint(3)); break; + case 1: return Rectangle3(getPoint(0), getPoint(4), getPoint(5), getPoint(1)); break; + case 2: return Rectangle3(getPoint(0), getPoint(3), getPoint(7), getPoint(4)); break; + case 3: return Rectangle3(getPoint(4), getPoint(7), getPoint(6), getPoint(5)); break; + case 4: return Rectangle3(getPoint(3), getPoint(2), getPoint(6), getPoint(7)); break; + case 5: return Rectangle3(getPoint(1), getPoint(5), getPoint(6), getPoint(2)); break; + default: return Rectangle3(getPoint(0), getPoint(1), getPoint(2), getPoint(3)); break; + } + } + + + template + inline const Segment3 BoundingBox::getSegment(const unsigned int idx) const + { + assert(idx < 12); + + switch (idx) { + case 0: return Segment3(getPoint(0), getPoint(1)); break; + case 1: return Segment3(getPoint(1), getPoint(2)); break; + case 2: return Segment3(getPoint(2), getPoint(3)); break; + case 3: return Segment3(getPoint(3), getPoint(0)); break; + case 4: return Segment3(getPoint(4), getPoint(5)); break; + case 5: return Segment3(getPoint(5), getPoint(6)); break; + case 6: return Segment3(getPoint(6), getPoint(7)); break; + case 7: return Segment3(getPoint(7), getPoint(4)); break; + case 8: return Segment3(getPoint(0), getPoint(4)); break; + case 9: return Segment3(getPoint(1), getPoint(5)); break; + case 10: return Segment3(getPoint(2), getPoint(6)); break; + case 11: return Segment3(getPoint(3), getPoint(7)); break; + default: return Segment3(getPoint(0), getPoint(1)); break; + } + } + + + template + void BoundingBox::transform(const Matrix44& mat) + { + m_matCoordSys = mat * m_matCoordSys; + validate(); + } + + + template + inline bool BoundingBox::isValid() const + { + return static_cast(getDiagonalLength() > 0.0); + } + + + template + inline const Type BoundingBox::getWidth() const + { + return m_Size.getWidth(); + } + + + template + inline const Type BoundingBox::getHeight() const + { + return m_Size.getHeight(); + } + + + template + inline const Type BoundingBox::getDepth() const + { + return m_Size.getDepth(); + } + + + template + inline const Type BoundingBox::getDiagonalLength() const + { + return static_cast((m_matCoordSys.getXAxis() * m_Size.getWidth() + + m_matCoordSys.getYAxis() * m_Size.getHeight() + + m_matCoordSys.getZAxis() * m_Size.getDepth()).getLength()); + } + + + template + inline const Vector3 BoundingBox::getCenter() const + { + return m_matCoordSys.getTranslation() + m_matCoordSys.getXAxis() * m_Size.getWidth() * 0.5 + + m_matCoordSys.getYAxis() * m_Size.getHeight() * 0.5 + + m_matCoordSys.getZAxis() * m_Size.getDepth() * 0.5; + } + + + template + inline void BoundingBox::validate() + { + m_pPoints[0] = m_matCoordSys.getTranslation(); + m_pPoints[1] = m_pPoints[0] + m_matCoordSys.getXAxis() * m_Size.getWidth(); + m_pPoints[2] = m_pPoints[1] + m_matCoordSys.getZAxis() * m_Size.getDepth(); + m_pPoints[3] = m_pPoints[0] + m_matCoordSys.getZAxis() * m_Size.getDepth(); + + Vector3 vec(m_matCoordSys.getYAxis() * m_Size.getHeight()); + m_pPoints[4] = m_pPoints[0] + vec; + m_pPoints[5] = m_pPoints[1] + vec; + m_pPoints[6] = m_pPoints[2] + vec; + m_pPoints[7] = m_pPoints[3] + vec; + } + + +} //namespace ARSTD diff --git a/ARSTD/ARSTD/Geometry/Line3.h b/ARSTD/ARSTD/Geometry/Line3.h new file mode 100644 index 00000000..29731ccc --- /dev/null +++ b/ARSTD/ARSTD/Geometry/Line3.h @@ -0,0 +1,83 @@ +// Copyright (c) 2005-2022 Andreas Rose. All rights reserved. +// Released under the MIT license. (see license.txt) + +#pragma once + + +#include "arstd/Math/Math.h" +#include +#include + + +namespace ARSTD +{ + + template + class Line3 + { + public: + Line3(const Vector3& vecPointOnLine, const Vector3& vecDir); + + explicit Line3(const Ray3& ray); + + explicit Line3(const Segment3& segment); + + template + explicit Line3(const Line3& line) + : m_vecPoint(static_cast>(line.getPos())), + m_vecDir(static_cast>(line.getDir())) + { + } + + const Vector3& getPos() const; + const Vector3& getDir() const; + + protected: + Vector3 m_vecPoint; + Vector3 m_vecDir; + }; + + + typedef Line3 Line3D; + + + template + Line3::Line3(const Vector3& vecPointOnLine, const Vector3& vecDir) + : m_vecPoint(vecPointOnLine), + m_vecDir(vecDir) + { + assert((vecDir.getLength() < 1 + EPSILON) && (vecDir.getLength() > 1 - EPSILON)); + } + + + template + Line3::Line3(const Ray3& ray) + : m_vecPoint(ray.getPos()), + m_vecDir(ray.getDir()) + { + } + + + template + Line3::Line3(const Segment3& segment) + : m_vecPoint(segment.getPoint1()), + m_vecDir(segment.getDir()) + { + } + + + template + const Vector3& Line3::getPos() const + { + return m_vecPoint; + } + + + template + const Vector3& Line3::getDir() const + { + return m_vecDir; + } + + +} // namespace ARSTD diff --git a/ARSTD/ARSTD/Geometry/Mesh.cpp b/ARSTD/ARSTD/Geometry/Mesh.cpp new file mode 100644 index 00000000..a3b597f3 --- /dev/null +++ b/ARSTD/ARSTD/Geometry/Mesh.cpp @@ -0,0 +1,449 @@ +// Copyright (c) 2005-2022 Andreas Rose. All rights reserved. +// Released under the MIT license. (see license.txt) + +#include "arstd/Geometry/Mesh.h" +#include "windows.h" +#include "gl/gl.h" +#include + +#undef min +#undef max + +namespace ARSTD +{ + + using namespace std; + + + Mesh::PtrType Mesh::create(const VectorContainer& vertices, + const TriangleContainer& triangles, + const VectorContainer& normals) + { + return PtrType(new Mesh(vertices, triangles, normals)); + } + + + Mesh::PtrType Mesh::readSTL(const std::string& strFilename) + { + std::fstream stream(strFilename, ios::in | ios::binary); + return readSTL(stream); + } + + + Mesh::PtrType Mesh::readSTL(std::istream& iStream) + { + iStream.seekg(80, ios::cur); + + unsigned long nNumFaces; + iStream.read(reinterpret_cast(&nNumFaces), 4); + + VectorContainer vertices; + TriangleContainer triangles; + VertexIndexMap vertexIndexMap; + + Vector3F vertex[3]; + while (!iStream.eof() && !iStream.bad() && iStream.tellg() != std::istream::pos_type(-1)) + { + iStream.seekg(sizeof(Vector3F), ios::cur); //skip normal + + iStream.read(reinterpret_cast(vertex), sizeof(vertex)); + iStream.seekg(2, ios::cur); // skip last two bytes + + if (vertex[0] == vertex[1] || vertex[1] == vertex[2] || vertex[0] == vertex[2]) + continue; + + mergeVertices(vertices, vertexIndexMap, triangles, vertex); + } + + return create(vertices, triangles); + } + + + Mesh::PtrType Mesh::createBox(const Matrix44D& matWorldTObject, const Size3D& size) + { + assert(size.getWidth() >= 0 && size.getHeight() >= 0 && size.getDepth() >= 0); + Matrix44F mat(matWorldTObject); + Size3F s(size); + + VectorContainer vertices; + vertices.push_back(mat*Vector3F( 0, 0, 0)); + vertices.push_back(mat*Vector3F(s.getWidth(), 0, 0)); + vertices.push_back(mat*Vector3F(s.getWidth(), 0, s.getDepth())); + vertices.push_back(mat*Vector3F( 0, 0, s.getDepth())); + + vertices.push_back(mat*Vector3F( 0, s.getHeight(), 0)); + vertices.push_back(mat*Vector3F(s.getWidth(), s.getHeight(), 0)); + vertices.push_back(mat*Vector3F(s.getWidth(), s.getHeight(), s.getDepth())); + vertices.push_back(mat*Vector3F( 0, s.getHeight(), s.getDepth())); + + TriangleContainer triangles; + triangles.push_back(Triangle(0, 1, 2)); + triangles.push_back(Triangle(0, 2, 3)); + + triangles.push_back(Triangle(0, 3, 7)); + triangles.push_back(Triangle(0, 7, 4)); + + triangles.push_back(Triangle(1, 5, 6)); + triangles.push_back(Triangle(1, 6, 2)); + + triangles.push_back(Triangle(0, 5, 1)); + triangles.push_back(Triangle(0, 4, 5)); + + triangles.push_back(Triangle(3, 2, 6)); + triangles.push_back(Triangle(3, 6, 7)); + + triangles.push_back(Triangle(5, 4, 7)); + triangles.push_back(Triangle(5, 7, 6)); + + return create(vertices, triangles); + } + + + Mesh::PtrType Mesh::createCylinder(const Matrix44D& matWorldTObject, const double fLength, const double fBeginDiameter, + const double fEndDiameter, const bool bWithDisks, const uint nSides, const uint nSegments) + { + assert(fLength >= 0 && fBeginDiameter >= 0 && fEndDiameter >= 0); + + Matrix44F mat(matWorldTObject); + + uint nCntSegment; + uint nCntSide; + double fRadian; + + VectorContainer vertices; + if (bWithDisks) + vertices.push_back(mat*Vector3F(0, 0, 0)); + for (nCntSegment = 0; nCntSegment < nSegments + 1; ++nCntSegment) + { + fRadian = ((fEndDiameter - fBeginDiameter)*nCntSegment/nSegments + fBeginDiameter)*0.5; + for (nCntSide = 0; nCntSide < nSides; ++nCntSide) + { + double fAngle = 2*PI*static_cast(nCntSide)/static_cast(nSides); + vertices.push_back(mat*Vector3F(static_cast(fLength*nCntSegment/nSegments), static_cast(sin(fAngle)*fRadian), static_cast(cos(fAngle)*fRadian))); + } + } + if (bWithDisks) + vertices.push_back(mat*Vector3F(static_cast(fLength), 0, 0)); + + TriangleContainer triangles; + int nOff = 0; + if (bWithDisks) + nOff = 1; + for (nCntSegment = 0; nCntSegment < nSegments; ++nCntSegment) + { + for (nCntSide = 0; nCntSide < nSides; ++nCntSide) + { + triangles.push_back(Triangle(nOff + nCntSide + nCntSegment*nSides, + nOff + nCntSide + (nCntSegment + 1)*nSides, + nOff + (nCntSide + 1) % nSides + (nCntSegment + 1)*nSides)); + triangles.push_back(Triangle(nOff + nCntSide + nCntSegment*nSides, + nOff + (nCntSide + 1) % nSides + (nCntSegment + 1)*nSides, + nOff + (nCntSide + 1) % nSides + nCntSegment*nSides)); + } + } + + if (bWithDisks) + { + for (nCntSide = 0; nCntSide < nSides; ++nCntSide) + triangles.push_back(Triangle(0, 1 + nCntSide, 1 + (nCntSide + 1) % nSides)); + + for (nCntSide = 0; nCntSide < nSides; ++nCntSide) + { + triangles.push_back(Triangle(static_cast(vertices.size() - 1), + static_cast(vertices.size() - 2 - nCntSide), + static_cast(vertices.size() - 2 - (nCntSide + 1) % nSides))); + } + } + + return create(vertices, triangles); + } + + + Mesh::PtrType Mesh::createEllipsoid(const Matrix44D& matWorldTObject, const Vector3D& vecDiameter, + const uint nSides, const uint nSegments, + const uint nFromSegment, const uint nToSegment) + { + assert(nToSegment <= nSegments); + assert(nFromSegment <= nToSegment); + + Matrix44F mat(matWorldTObject); + + Vector3D vecRadian = vecDiameter/2.0; + + uint nCntSegment; + uint nCntSide; + VectorContainer vertices; + vertices.push_back(mat*Vector3F(static_cast(-vecRadian.x), 0, 0)); + for (nCntSegment = 0; nCntSegment < nSegments; ++nCntSegment) + { + double fNormalizedRadianAroundX = sin(PI*static_cast(nCntSegment)/static_cast(nSegments)); + for (nCntSide = 0; nCntSide < nSides; ++nCntSide) + { + double fAngle = 2*PI*static_cast(nCntSide)/static_cast(nSides); + Vector3F vecPoint(static_cast(-cos(PI*static_cast(nCntSegment)/static_cast(nSegments))*vecRadian.x), + static_cast(sin(fAngle)*fNormalizedRadianAroundX*vecRadian.y), + static_cast(cos(fAngle)*fNormalizedRadianAroundX*vecRadian.z)); + + vertices.push_back(mat*vecPoint); + } + } + vertices.push_back(mat*Vector3F(static_cast(vecRadian.x), 0, 0)); + + TriangleContainer triangles; + uint nMaxSegment = std::min(nToSegment, nSegments - 1); + for (nCntSegment = nFromSegment; nCntSegment < nMaxSegment; ++nCntSegment) + { + for (nCntSide = 0; nCntSide < nSides; ++nCntSide) + { + triangles.push_back(Triangle(1 + nCntSide + nCntSegment*nSides, + 1 + nCntSide + (nCntSegment + 1)*nSides, + 1 + (nCntSide + 1) % nSides + (nCntSegment + 1)*nSides)); + triangles.push_back(Triangle(1 + nCntSide + nCntSegment*nSides, + 1 + (nCntSide + 1) % nSides + (nCntSegment + 1)*nSides, + 1 + (nCntSide + 1) % nSides + nCntSegment*nSides)); + } + } + + if (nFromSegment == 0) + { + for (nCntSide = 0; nCntSide < nSides; ++nCntSide) + { + triangles.push_back(Triangle(0, 1 + nCntSide, 1 + (nCntSide + 1) % nSides)); + } + } + + if (nToSegment == nSegments) + { + for (nCntSide = 0; nCntSide < nSides; ++nCntSide) + { + triangles.push_back(Triangle(static_cast(vertices.size() - 1), + static_cast(vertices.size() - 2 - nCntSide), + static_cast(vertices.size() - 2 - (nCntSide + 1) % nSides))); + } + } + + return create(vertices, triangles); + } + + + Mesh::PtrType Mesh::copy(const PtrType pMesh) + { + return PtrType(new Mesh(*(pMesh.get()))); + } + + + Mesh::PtrType Mesh::transformed(const Matrix44D& mat) + { + if (m_Vertices.size() != m_Normals.size()) + return create(m_Vertices, m_Triangles, m_Normals); + + Matrix44F matF(mat); + VectorContainer vertices(m_Vertices); + for (auto& v : vertices) + v = matF*v; + + return create(vertices, m_Triangles); + } + + + void Mesh::render(int nNumerator, int nDenominator) const + { + assert(nNumerator > 0 && nDenominator > 0 && nNumerator <= nDenominator); + + glPushAttrib(GL_ENABLE_BIT | GL_POLYGON_BIT | GL_LIGHTING_BIT); + + glEnableClientState(GL_NORMAL_ARRAY); + glEnableClientState(GL_VERTEX_ARRAY); + + glNormalPointer(GL_FLOAT, 0, &m_Normals.front()); + glVertexPointer(3, GL_FLOAT, 0, &m_Vertices.front()); + + int nTrisToDrawAtOnce = static_cast(m_Triangles.size())/nDenominator; + glDrawElements(GL_TRIANGLES, nTrisToDrawAtOnce*3, GL_UNSIGNED_INT, &m_Triangles.front() + (nNumerator - 1)*nTrisToDrawAtOnce); + + glDisableClientState(GL_NORMAL_ARRAY); + glDisableClientState(GL_VERTEX_ARRAY); + +////draw normals +//glColor3d(0, 1, 1); +//glBegin(GL_LINES); +// VectorContainer::const_iterator itVert = m_Vertices.begin(); +// VectorContainer::const_iterator itNormal = m_Normals.begin(); +// for (; itVert != m_Vertices.end() && itNormal != m_Normals.end(); ++itVert, ++itNormal) +// { +// glVertex3dv(itVert->pData); +// glVertex3dv((*itVert + *itNormal*3.0).pData); +// } +//glEnd(); + + glPopAttrib(); + } + + + Mesh::VectorConstIterator Mesh::getVerticesBegin() const + { + return m_Vertices.begin(); + } + + + Mesh::VectorConstIterator Mesh::getVerticesEnd() const + { + return m_Vertices.end(); + } + + + uint Mesh::getNumVertices() const + { + return static_cast(m_Vertices.size()); + } + + + uint Mesh::getNumTriangles() const + { + return static_cast(m_Triangles.size()); + } + + + const AxisAlignedBoundingBoxD& Mesh::getAxisAlignedBoundingBox() const + { + return m_AxisAlignedBoundingBox; + } + + + void Mesh::add(const PtrType pMesh) + { + if (!pMesh) return; + + uint nSizeVertices = static_cast(m_Vertices.size()); + + m_Vertices.insert(m_Vertices.end(), pMesh->m_Vertices.begin(), pMesh->m_Vertices.end()); + m_Normals.insert(m_Normals.end(), pMesh->m_Normals.begin(), pMesh->m_Normals.end()); + + TriangleContainer::iterator it = pMesh->m_Triangles.begin(); + for (; it != pMesh->m_Triangles.end(); ++it) + { + it->indices[0] += nSizeVertices; + it->indices[1] += nSizeVertices; + it->indices[2] += nSizeVertices; + m_Triangles.push_back(*it); + } + + generateNormals(); + updateAxisAlignedBoundingBox(); + } + + + Mesh::Mesh() + { + } + + + Mesh::Mesh(const VectorContainer& vertices, + const TriangleContainer& triangles, + const VectorContainer& normals) + : m_Vertices(vertices), + m_Triangles(triangles), + m_Normals(normals) + { + if (normals.size() != vertices.size()) + generateNormals(); + updateAxisAlignedBoundingBox(); + } + + + Mesh::Mesh(const Mesh& other) + : m_Vertices(other.m_Vertices), + m_Triangles(other.m_Triangles), + m_Normals(other.m_Normals), + m_AxisAlignedBoundingBox(other.m_AxisAlignedBoundingBox) + { + } + + + void Mesh::generateNormals() + { + m_Normals.resize(m_Vertices.size()); + + for (uint i = 0; i < m_Triangles.size(); i++) + { + uint i0 = m_Triangles[i].indices[0]; + uint i1 = m_Triangles[i].indices[1]; + uint i2 = m_Triangles[i].indices[2]; + + assert(i0 < m_Vertices.size() && + i1 < m_Vertices.size() && + i2 < m_Vertices.size()); + + const Vector3F& vec0 = m_Vertices[i0]; + const Vector3F& vec1 = m_Vertices[i1]; + const Vector3F& vec2 = m_Vertices[i2]; + + Vector3F vecNormal = (vec1 - vec0)%(vec2 - vec0); + + m_Normals[i0] += vecNormal; + m_Normals[i1] += vecNormal; + m_Normals[i2] += vecNormal; + } + + for (auto& n : m_Normals) + { + float length = n.getLength(); + if (fabs(length) > EPSILON) + n.normalize(); + } + } + + + void Mesh::updateAxisAlignedBoundingBox() + { + if (m_Vertices.size() == 0) + { + m_AxisAlignedBoundingBox = AxisAlignedBoundingBoxD(); + } + else + { + auto minMax = getMinMax(m_Vertices.begin(), m_Vertices.end()); + m_AxisAlignedBoundingBox = AxisAlignedBoundingBoxD(Vector3D(minMax.first), Vector3D(minMax.second)); + } + } + + + void Mesh::mergeVertices(VectorContainer& vertices, + VertexIndexMap& vertexIndexMap, + TriangleContainer& triangles, + Vector3F vertex[3]) + { + uint nIndex[3]; + + for (int i = 0; i < 3; ++i) + { + auto range = vertexIndexMap.equal_range(vertex[i].x); + auto it = range.first; + + while (it != range.second) + { + if (vertices[it->second] == vertex[i]) + break; + ++it; + } + + if (it == range.second) + { + //vertex not found -> add new one + vertices.push_back(vertex[i]); + nIndex[i] = static_cast(vertices.size() - 1); + vertexIndexMap.insert(std::make_pair(vertex[i].x, nIndex[i])); + } + else + { + //vertex found -> set corresponding index + nIndex[i] = it->second; + } + } + + assert(nIndex[0] != nIndex[1] && nIndex[0] != nIndex[2] && nIndex[1] != nIndex[2]); + + triangles.push_back(Mesh::Triangle(nIndex[0], nIndex[1], nIndex[2])); + } + +} diff --git a/ARSTD/ARSTD/Geometry/Mesh.h b/ARSTD/ARSTD/Geometry/Mesh.h new file mode 100644 index 00000000..87539940 --- /dev/null +++ b/ARSTD/ARSTD/Geometry/Mesh.h @@ -0,0 +1,86 @@ +// Copyright (c) 2005-2022 Andreas Rose. All rights reserved. +// Released under the MIT license. (see license.txt) + +#pragma once +#pragma warning (disable: 4786) + + +#include +#include +#include "arstd/Geometry/AxisAlignedBoundingBox.h" + + +namespace ARSTD +{ + + + class Mesh + { + public: + struct Triangle + { + Triangle(uint i0 = 0, uint i1 = 0, uint i2 = 0) + { + indices[0] = i0; + indices[1] = i1; + indices[2] = i2; + } + + uint indices[3]; + }; + + typedef std::shared_ptr PtrType; + typedef std::vector VectorContainer; + typedef VectorContainer::const_iterator VectorConstIterator; + typedef std::vector TriangleContainer; + + static PtrType create(const VectorContainer& vertices, const TriangleContainer& triangles, const VectorContainer& normals = VectorContainer()); + + static Mesh::PtrType readSTL(const std::string& strFilename); + static Mesh::PtrType readSTL(std::istream& iStream); + + static Mesh::PtrType createBox(const Matrix44D& matWorldTObject, const Size3D& size); + static Mesh::PtrType createCylinder(const Matrix44D& matWorldTObject, const double fLength, const double fBeginDiameter, + const double fEndDiameter, const bool bWithDisks = false, const uint nSides = 15, const uint nSegments = 1); + static Mesh::PtrType createEllipsoid(const Matrix44D& matWorldTObject, const Vector3D& vecDiameter, + const uint nSides = 15, const uint nSegments = 15, + const uint nFromSegment = 0, const uint nToSegment = 15); + + static PtrType copy(const PtrType pMesh); + + PtrType transformed(const Matrix44D& mat); + + void render(int nNumerator = 1, int nDenominator = 1) const; + + VectorConstIterator getVerticesBegin() const; + VectorConstIterator getVerticesEnd() const; + uint getNumVertices() const; + uint getNumTriangles() const; + + const AxisAlignedBoundingBoxD& getAxisAlignedBoundingBox() const; + + void add(const PtrType pMesh); + + protected: + typedef std::multimap VertexIndexMap; + + Mesh(); + Mesh(const VectorContainer& vertices, const TriangleContainer& triangles, const VectorContainer& normals = VectorContainer()); + Mesh(const Mesh& other); + + void generateNormals(); + void updateAxisAlignedBoundingBox(); + + static void mergeVertices(Mesh::VectorContainer& vertices, + VertexIndexMap& vertexIndexMap, + Mesh::TriangleContainer& triangles, + Vector3F vertex[3]); + + VectorContainer m_Vertices; + TriangleContainer m_Triangles; + VectorContainer m_Normals; + AxisAlignedBoundingBoxD m_AxisAlignedBoundingBox; + }; + + +} diff --git a/ARSTD/ARSTD/Geometry/Plane.h b/ARSTD/ARSTD/Geometry/Plane.h new file mode 100644 index 00000000..391f28cd --- /dev/null +++ b/ARSTD/ARSTD/Geometry/Plane.h @@ -0,0 +1,192 @@ +// Copyright (c) 2005-2022 Andreas Rose. All rights reserved. +// Released under the MIT license. (see license.txt) + +#pragma once + + +#include "arstd/Math/Math.h" +#include "arstd/Geometry/Ray3.h" +#include "arstd/Geometry/Segment3.h" +#include "arstd/Geometry/Line3.h" + +namespace ARSTD +{ + + template + class Plane + { + public: + Plane(); + Plane(const Vector3& vecP0, const Vector3& vecP1, const Vector3& vecP2); + Plane(const Vector3& vecOrigin, const Vector3& vecNormal); + + template + explicit Plane(const Plane& other) + : m_vecNormal(static_cast>(other.getNormal())), + m_D(static_cast(other.getD())), + m_vecOrigin(static_cast>(other.getOrigin())) + { + } + + const Type& getA() const; + const Type& getB() const; + const Type& getC() const; + const Type& getD() const; + + const Vector3& getNormal() const; + void setNormal(const Vector3& vecNormal); + + const Vector3& getOrigin() const; + void setOrigin(const Vector3& vecOrigin); + + const Vector3 projectPoint(const Vector3& vecPoint) const; + + const Type distance(const Vector3& vecPoint) const; + + static bool equals(const Plane& lhs, const Plane& rhs, const Type& epsilon); + + protected: + Vector3 m_vecNormal; + Type m_D; + Vector3 m_vecOrigin; + }; + + + typedef Plane PlaneD; + + + template + Plane::Plane() + : m_vecNormal(1, 0, 0), + m_D(0.0), + m_vecOrigin(0, 0, 0) + { + } + + + template + Plane::Plane(const Vector3& vecP0, const Vector3& vecP1, const Vector3& vecP2) + : m_vecOrigin(vecP0), + m_vecNormal(((vecP1 - vecP0) % (vecP2 - vecP0)).getNormalized()) + { + m_D = -(vecP0 * m_vecNormal); + } + + + template + Plane::Plane(const Vector3& vecOrigin, const Vector3& vecNormal) + : m_vecOrigin(vecOrigin), + m_vecNormal(vecNormal.getNormalized()) + { + m_D = -(vecOrigin * m_vecNormal); + } + + + template + const Type& Plane::getA() const + { + return m_vecNormal.x; + } + + + template + const Type& Plane::getB() const + { + return m_vecNormal.y; + } + + + template + const Type& Plane::getC() const + { + return m_vecNormal.z; + } + + + template + const Type& Plane::getD() const + { + return m_D; + } + + + template + const Vector3& Plane::getNormal() const + { + return m_vecNormal; + } + + + template + void Plane::setNormal(const Vector3& vecNormal) + { + assert(vecNormal.length() == 1); + + m_vecNormal = vecNormal; + m_D = -(m_vecOrigin * vecNormal); + } + + + template + const Vector3& Plane::getOrigin() const + { + return m_vecOrigin; + } + + + template + void Plane::setOrigin(const Vector3& vecOrigin) + { + m_vecOrigin = vecOrigin; + m_D = -(m_vecOrigin * m_vecNormal); + } + + + template + const Vector3 Plane::projectPoint(const Vector3& vecPoint) const + { + Type fTz = (getA() * vecPoint.x + + getB() * vecPoint.y + + getC() * vecPoint.z + + getD()) * static_cast(-1.0); + Type fTn = getA() * m_vecNormal.x + + getB() * m_vecNormal.y + + getC() * m_vecNormal.z; + + if (fabs(fTn) < EPSILON) + return Vector3::ZERO; + + return vecPoint + m_vecNormal*fTz/fTn; + } + + + template + const Type Plane::distance(const Vector3& vecPoint) const + { + return fabs((vecPoint - getOrigin())*getNormal()); + } + + + template + bool Plane::equals(const Plane& lhs, const Plane& rhs, const Type& epsilon) + { + return lhs.getNormal() == rhs.getNormal() && + fabs(lhs.getD() - rhs.getD()) < epsilon; + } + + + template + inline bool operator == (const Plane& lhs, const Plane& rhs) + { + return Plane::equals(lhs, rhs, static_cast(EPSILON)); + } + + + template + inline bool operator != (const Plane& lhs, const Plane& rhs) + { + return !(lhs == rhs); + } + + +} // namespace ARSTD diff --git a/ARSTD/ARSTD/Geometry/Ray3.h b/ARSTD/ARSTD/Geometry/Ray3.h new file mode 100644 index 00000000..7a5f01be --- /dev/null +++ b/ARSTD/ARSTD/Geometry/Ray3.h @@ -0,0 +1,86 @@ +// Copyright (c) 2005-2022 Andreas Rose. All rights reserved. +// Released under the MIT license. (see license.txt) + +#pragma once + +#include "arstd/Math/Math.h" + + +namespace ARSTD +{ + + template + class Ray3 + { + public: + Ray3(const Vector3& vecPos, const Vector3& vecDir); + + template + explicit Ray3(const Ray3& other) + : m_vecPos(static_cast>(other.getPos())), + m_vecDir(static_cast>(other.getDir()())) + { + } + + const Vector3& getPos() const; + void setPos(const Vector3& vecPos); + + const Vector3& getDir() const; + void setDir(const Vector3& vecDir); + + void set(const Vector3& vecPos, const Vector3& vecDir); + + protected: + Vector3 m_vecPos; + Vector3 m_vecDir; + }; + + + typedef Ray3 Ray3D; + + + template + Ray3::Ray3(const Vector3& vecPos, const Vector3& vecDir) + : m_vecPos(vecPos), + m_vecDir(vecDir) + { + } + + + template + inline const Vector3& Ray3::getPos() const + { + return m_vecPos; + } + + + template + inline const Vector3& Ray3::getDir() const + { + return m_vecDir; + } + + + template + inline void Ray3::setPos(const Vector3& vecPos) + { + m_vecPos = vecPos; + } + + + template + inline void Ray3::setDir(const Vector3& vecDir) + { + m_vecDir = vecDir; + } + + + template + inline void Ray3::set(const Vector3& vecPos, const Vector3& vecDir) + { + m_vecPos = vecPos; + m_vecDir = vecDir; + } + + +} // namespace ARSTD diff --git a/ARSTD/ARSTD/Geometry/Rectangle3.h b/ARSTD/ARSTD/Geometry/Rectangle3.h new file mode 100644 index 00000000..135faba8 --- /dev/null +++ b/ARSTD/ARSTD/Geometry/Rectangle3.h @@ -0,0 +1,219 @@ +// Copyright (c) 2005-2022 Andreas Rose. All rights reserved. +// Released under the MIT license. (see license.txt) + +#pragma once + +#include +#include "arstd/Math/Math.h" +#include "arstd/Geometry/Segment3.h" + + +namespace ARSTD +{ + + template + class Rectangle3 + { + public: + typedef std::pair> ProjectionPoint; + + Rectangle3(const Vector3& vecPoint0, const Vector3& vecPoint1, + const Vector3& vecPoint2, const Vector3& vecPoint3); + + template + explicit Rectangle3(const Rectangle3& other) + : m_vecPoint0(static_cast>(other.getPoint0())), + m_vecPoint1(static_cast>(other.getPoint1())), + m_vecPoint2(static_cast>(other.getPoint2())), + m_vecPoint3(static_cast>(other.getPoint3())) + { + } + + const Vector3& getPoint0() const; + void setPoint0(const Vector3& vec); + const Vector3& getPoint1() const; + void setPoint1(const Vector3& vec); + const Vector3& getPoint2() const; + void setPoint2(const Vector3& vec); + const Vector3& getPoint3() const; + void setPoint3(const Vector3& vec); + + const Segment3 getSegment(uint nIdx) const; + + const Vector3 getNormal() const; + + const double getWidth() const; + const double getHeight() const; + + ProjectionPoint project(const Vector3& vecPoint) const; + + Type getDistanceTo(const Vector3& vecPoint) const; + + + protected: + Vector3 m_vecPoint0; + Vector3 m_vecPoint1; + Vector3 m_vecPoint2; + Vector3 m_vecPoint3; + }; + + + typedef Rectangle3 Rectangle3D; + + + template + Rectangle3::Rectangle3(const Vector3& vecPoint0, const Vector3& vecPoint1, + const Vector3& vecPoint2, const Vector3& vecPoint3) + : m_vecPoint0(vecPoint0), + m_vecPoint1(vecPoint1), + m_vecPoint2(vecPoint2), + m_vecPoint3(vecPoint3) + { + } + + + template + bool operator == (const Rectangle3& rect1, const Rectangle3& rect2) + { + return (rect1.getPoint0() == rect2.getPoint0() && + rect1.getPoint1() == rect2.getPoint1() && + rect1.getPoint2() == rect2.getPoint2() && + rect1.getPoint3() == rect2.getPoint3()); + } + + + template + const Vector3& Rectangle3::getPoint0() const + { + return m_vecPoint0; + } + + + template + void Rectangle3::setPoint0(const Vector3& vec) + { + m_vecPoint0 = vec; + } + + + template + const Vector3& Rectangle3::getPoint1() const + { + return m_vecPoint1; + } + + + template + void Rectangle3::setPoint1(const Vector3& vec) + { + m_vecPoint1 = vec; + } + + + template + const Vector3& Rectangle3::getPoint2() const + { + return m_vecPoint2; + } + + + template + void Rectangle3::setPoint2(const Vector3& vec) + { + m_vecPoint2 = vec; + } + + + template + const Vector3& Rectangle3::getPoint3() const + { + return m_vecPoint3; + } + + + template + void Rectangle3::setPoint3(const Vector3& vec) + { + m_vecPoint3 = vec; + } + + + template + const Segment3 Rectangle3::getSegment(uint nIdx) const + { + assert(nIdx <= 3); + switch (nIdx) + { + case 0: return Segment3(getPoint0(), getPoint1()); break; + case 1: return Segment3(getPoint1(), getPoint2()); break; + case 2: return Segment3(getPoint2(), getPoint3()); break; + case 3: return Segment3(getPoint3(), getPoint0()); break; + default: return Segment3(getPoint0(), getPoint1()); break; + } + } + + + template + const Vector3 Rectangle3::getNormal() const + { + return ((getPoint1() - getPoint2()) % (getPoint3() - getPoint2())).getNormalized(); + } + + + template + const double Rectangle3::getWidth() const + { + return distance(getPoint0(), getPoint1()); + } + + + template + const double Rectangle3::getHeight() const + { + return distance(getPoint0(), getPoint3()); + } + + + template + typename Rectangle3::ProjectionPoint Rectangle3::project(const Vector3& vecPoint) const + { + Plane plane(getPoint0(), getNormal()); + Vector3 vecPlaneProjectedPoint = plane.projectPoint(vecPoint); + + Vector3 vecXDir = (getPoint1() - getPoint0()).getNormalized(); + Vector3 vecYDir = (getPoint3() - getPoint0()).getNormalized(); + + double fXProjection = (vecPlaneProjectedPoint - getPoint0()) * vecXDir; + double fYProjection = (vecPlaneProjectedPoint - getPoint0()) * vecYDir; + + if (fXProjection >= 0 && fXProjection <= getWidth() && + fYProjection >= 0 && fYProjection <= getHeight()) + { + return ProjectionPoint(true, vecPlaneProjectedPoint); + } + else + { + return ProjectionPoint(false, Vector3()); + } + } + + + template + Type Rectangle3::getDistanceTo(const Vector3& vecPoint) const + { + ProjectionPoint projectedPoint = project(vecPoint); + if (projectedPoint.first) + return (projectedPoint.second - vecPoint).getLength(); + + Type minDistance = std::numeric_limits::max(); + for (int nCnt = 0; nCnt < 4; ++nCnt) + { + Type dist = getSegment(nCnt).getDistanceToPoint(vecPoint); + if (dist < minDistance) + minDistance = dist; + } + return minDistance; + } + + +} // namespace ARSTD diff --git a/ARSTD/ARSTD/Geometry/Segment3.h b/ARSTD/ARSTD/Geometry/Segment3.h new file mode 100644 index 00000000..349d2e2a --- /dev/null +++ b/ARSTD/ARSTD/Geometry/Segment3.h @@ -0,0 +1,153 @@ +// Copyright (c) 2005-2022 Andreas Rose. All rights reserved. +// Released under the MIT license. (see license.txt) + +#pragma once + +#include "arstd/Math/Math.h" + + +namespace ARSTD +{ + + + template + class Segment3 + { + public: + typedef std::pair> ProjectionPoint; + + Segment3(); + Segment3(const Vector3& vecPoint, const Vector3& vecPoint2); + + template + explicit Segment3(const Segment3& other) + : m_vecPoint1(static_cast>(other.getPoint1())), + m_vecPoint2(static_cast>(other.getPoint2())) + { + } + + const Vector3& getPoint1() const; + void setPoint1(const Vector3& vec); + const Vector3& getPoint2() const; + void setPoint2(const Vector3& vec); + + Vector3 getDir() const; + + Type getLength() const; + Type getLengthSqr() const; + + const ProjectionPoint projectPoint(const Vector3& vecPoint) const; + + Type getDistanceToPoint(const Vector3& vecPoint) const; + Type getSquaredDistanceToPoint(const Vector3& vecPoint) const; + + protected: + Vector3 m_vecPoint1; + Vector3 m_vecPoint2; + }; + + + typedef Segment3 Segment3D; + + + template + Segment3::Segment3() + : m_vecPoint1(0, 0, 0), + m_vecPoint2(0, 0, 0) + { + } + + + template + Segment3::Segment3(const Vector3& vecPoint1, const Vector3& vecPoint2) + : m_vecPoint1(vecPoint1), + m_vecPoint2(vecPoint2) + { + } + + + template + const Vector3& Segment3::getPoint1() const + { + return m_vecPoint1; + } + + + template + void Segment3::setPoint1(const Vector3& vec) + { + m_vecPoint1 = vec; + } + + + template + const Vector3& Segment3::getPoint2() const + { + return m_vecPoint2; + } + + + template + void Segment3::setPoint2(const Vector3& vec) + { + m_vecPoint2 = vec; + } + + + template + Vector3 Segment3::getDir() const + { + return m_vecPoint2 - m_vecPoint1; + } + + + template + Type Segment3::getLength() const + { + return std::sqrt(getLengthSqr()); + } + + + template + Type Segment3::getLengthSqr() const + { + return (m_vecPoint1 - m_vecPoint2).getSquaredLength(); + } + + + template + const typename Segment3::ProjectionPoint Segment3::projectPoint(const Vector3& vecPoint) const + { + Vector3 vecDir(m_vecPoint2 - m_vecPoint1); + vecDir.normalize(); + + double fProjection = (vecPoint - m_vecPoint1)*vecDir; + if (fProjection >= 0 && fProjection <= getLength()) + return ProjectionPoint(true, m_vecPoint1 + vecDir*fProjection); + + return ProjectionPoint(false, Vector3()); + } + + + template + Type Segment3::getDistanceToPoint(const Vector3& vecPoint) const + { + return std::sqrt(getSquaredDistanceToPoint(vecPoint)); + } + + + template + Type Segment3::getSquaredDistanceToPoint(const Vector3& vecPoint) const + { + ProjectionPoint result = projectPoint(vecPoint); + if (!result.first) + { + return std::min((m_vecPoint1 - vecPoint).getSquaredLength(), + (m_vecPoint2 - vecPoint).getSquaredLength()); + } + + return (result.second - vecPoint).getSquaredLength(); + } + + +} // namespace ARSTD diff --git a/ARSTD/ARSTD/Math/Constants.h b/ARSTD/ARSTD/Math/Constants.h new file mode 100644 index 00000000..c6dd7c28 --- /dev/null +++ b/ARSTD/ARSTD/Math/Constants.h @@ -0,0 +1,18 @@ +// Copyright (c) 2005-2022 Andreas Rose. All rights reserved. +// Released under the MIT license. (see license.txt) + +#pragma once + + +namespace ARSTD +{ + + + static const double PI = 3.1415926535897932384626433832795; + static const double PI_HALF = 3.1415926535897932384626433832795*0.5; + + static const double EPSILON = 0.001; + static const double EPSILON_SQUARED = 0.001*0.001; + + +} diff --git a/ARSTD/ARSTD/Math/Math.cpp b/ARSTD/ARSTD/Math/Math.cpp new file mode 100644 index 00000000..a221981a --- /dev/null +++ b/ARSTD/ARSTD/Math/Math.cpp @@ -0,0 +1,48 @@ +// Copyright (c) 2005-2022 Andreas Rose. All rights reserved. +// Released under the MIT license. (see license.txt) + +#pragma once + + +#include "Math.h" + + +namespace ARSTD +{ + + + double log2(double f) + { + static double fLog2Rec = 1.0/log(2.0); + if (f < 1.0) + return 0; + + return log(f)*fLog2Rec; + } + + + double log10(double f) + { + static double fLog10Rec = 1.0/log(10.0); + if (f < 1.0) + return 0; + + return log(f)*fLog10Rec; + } + + + double getInDegree(double fRad) + { + static double fVal = 180.0/PI; + return fRad*fVal; + } + + + double getInRad(double fDegree) + { + static double fVal = PI/180.0; + return fDegree*fVal; + } + + +} // namespace ARSTD diff --git a/ARSTD/ARSTD/Math/Math.h b/ARSTD/ARSTD/Math/Math.h new file mode 100644 index 00000000..7ad8f8d0 --- /dev/null +++ b/ARSTD/ARSTD/Math/Math.h @@ -0,0 +1,70 @@ +// Copyright (c) 2005-2022 Andreas Rose. All rights reserved. +// Released under the MIT license. (see license.txt) + +#pragma once + +#include +#include +#include +#include + +#undef min +#undef max + + +#include "arstd/Common/Types.h" +#include "Constants.h" + + +#include "Vector3.h" +#include "Vector4.h" +#include "Quaternion.h" +#include "Matrix33.h" +#include "Matrix44.h" +#include "Matrix.h" + + +namespace ARSTD +{ + + double log2(double); + double log10(double); + + double getInDegree(double fRad); + double getInRad(double fDegree); + + template + Type minimum(const Type& lhs, const Type& rhs) + { + return std::min(lhs, rhs); + } + + + template + Type maximum(const Type& lhs, const Type& rhs) + { + return std::max(lhs, rhs); + } + + + template + std::pair::value_type, + typename std::iterator_traits::value_type> + getMinMax(ForwardIterator itBegin, ForwardIterator itEnd) + { + typedef std::iterator_traits::value_type ValueType; + if (itBegin == itEnd) + return std::make_pair(ValueType(), ValueType()); + + ValueType min = std::numeric_limits::max(); + ValueType max = std::numeric_limits::min(); + for (ForwardIterator it = itBegin; it != itEnd; ++it) + { + min = minimum(min, *it); + max = maximum(max, *it); + } + + return std::make_pair(min, max); + } + + } diff --git a/ARSTD/ARSTD/Math/Matrix.h b/ARSTD/ARSTD/Math/Matrix.h new file mode 100644 index 00000000..037688e2 --- /dev/null +++ b/ARSTD/ARSTD/Math/Matrix.h @@ -0,0 +1,59 @@ +// Copyright (c) 2005-2022 Andreas Rose. All rights reserved. +// Released under the MIT license. (see license.txt) + +#pragma once + +namespace ARSTD +{ + + template + class Matrix + { + public: + explicit Matrix(const uint nRows = 1, const uint nColumns = 1, const Type& init = Type(0)); + explicit Matrix(const Matrix33& mat); + explicit Matrix(const Matrix44& mat); + + Matrix(const Matrix& other); + + ~Matrix(); + + static const std::pair, bool> inverse(const Matrix& mat); + + const uint getRows() const; + const uint getColumns() const; + + const Matrix getRow(const uint nRow) const; + const Matrix getColumn(const uint nColumn) const; + void setRow(const uint nRow, const Matrix vec); + void setColumn(const uint nColumn, const Matrix vec); + + void setZero(); + void setIdentity(); + bool invert(); + void transpose(); + const Matrix getTransposed() const; + + Type& operator()(const uint nRow, const uint nColumn = 0); + const Type& operator()(const uint nRow, const uint nColumn = 0) const; + + Type* getData(); + const Type* getData() const; + + void operator=(const Matrix& other); + + protected: + static const std::pair, bool> ordinaryInverse(const Matrix& mat); + static const std::pair, bool> pseudoInverse(const Matrix& mat); + + Type* m_pData; + uint m_nRows; + uint m_nColumns; + }; + + typedef Matrix MatrixD; + +} + + +#include "Matrix_Impl.h" diff --git a/ARSTD/ARSTD/Math/Matrix33.h b/ARSTD/ARSTD/Math/Matrix33.h new file mode 100644 index 00000000..acbf4b2b --- /dev/null +++ b/ARSTD/ARSTD/Math/Matrix33.h @@ -0,0 +1,156 @@ +// Copyright (c) 2005-2022 Andreas Rose. All rights reserved. +// Released under the MIT license. (see license.txt) + +#pragma once +#include + + +namespace ARSTD +{ + + template class Matrix; + + + template + struct Matrix33 + { + public: + enum ERow { ROW0 = 0, ROW1, ROW2}; + enum EColumn { COL0 = 0, COL1, COL2}; + + template + operator R() const + { + R r; + assign(r, *this); + return r; + } + + static const Matrix33 IDENTITY; + + static Matrix33 inverse(const Matrix33& mat); + + explicit Matrix33(bool bInitAsIdentity = true); + explicit Matrix33(const Quaternion& quat); + explicit Matrix33(const Matrix& mat); + Matrix33(const Vector3& vecXAxis, const Vector3& vecYAxis, const Vector3& vecZAxis); + + template + explicit Matrix33(const Matrix33& other) + { + for (int i = 0; i < 9; i++) + { + this->pData[i] = static_cast(other.pData[i]); + } + } + + Matrix33& operator *= (const Type& rhs); + Matrix33& operator += (const Matrix33& rhs); + Matrix33& operator -= (const Matrix33& rhs); + Matrix33& operator *= (const Matrix33& rhs); + + Vector3& getXAxis(); + const Vector3& getXAxis() const; + void setXAxis(const Vector3& vecXAxis); + + Vector3& getYAxis(); + const Vector3& getYAxis() const; + void setYAxis(const Vector3& vecYAxis); + + Vector3& getZAxis(); + const Vector3& getZAxis() const; + void setZAxis(const Vector3& vecZAxis); + + void get(Type& rotX, Type& rotY, Type& rotZ) const; + + Quaternion getAsQuaternion() const; + + void setIdentity(); + + bool isIdentity(const Type& epsilon = EPSILON) const; + + void set(const Matrix33& mat); + void set(const Quaternion& quat); + void set(const Vector3& vecAxis, const Type& angle); + + void transpose(); + + const Type determinant() const; + + void makeRotationMatrix(const EColumn& axis); + + union + { + Type pData[9]; + Type pData2[3][3]; + struct + { + Type xx, yx, zx; + Type xy, yy, zy; + Type xz, yz, zz; + }; + }; + }; + + + template + struct boost::qvm::mat_traits; + + template + struct boost::qvm::mat_traits> + { + typedef Type scalar_type; + static int const rows = 3; + static int const cols = 3; + + template + static scalar_type read_element(ARSTD::Matrix33 const& x) + { + return x.pData2[Col][Row]; + } + + template + static scalar_type& write_element(ARSTD::Matrix33& x) + { + return x.pData2[Col][Row]; + } + + static scalar_type read_element_idx(int row, int col, ARSTD::Matrix33 const& x) + { + return x.pData2[col][row]; + } + + static scalar_type& write_element_idx(int row, int col, ARSTD::Matrix33& x) + { + return x.pData2[col][row]; + } + }; + + + typedef Matrix33 Matrix33F; + typedef Matrix33 Matrix33D; + + + template + const Matrix33 operator * (const Matrix33& lhs, const Type2& rhs); + + template + const Matrix33 operator * (const Matrix33& lhs, const Matrix33& rhs); + + template + const Vector3 operator * (const Matrix33& lhs, const Vector3& rhs); + + template + bool equals(const Matrix33& lhs, const Matrix33& rhs, double fEpsilon = EPSILON); + + template + bool operator == (const Matrix33& lhs, const Matrix33& rhs); + + template + bool operator != (const Matrix33& lhs, const Matrix33& rhs); + + +} // namespace ARSTD + + +#include "Matrix33_Impl.h" diff --git a/ARSTD/ARSTD/Math/Matrix33_Impl.h b/ARSTD/ARSTD/Math/Matrix33_Impl.h new file mode 100644 index 00000000..db907138 --- /dev/null +++ b/ARSTD/ARSTD/Math/Matrix33_Impl.h @@ -0,0 +1,300 @@ +// Copyright (c) 2005-2022 Andreas Rose. All rights reserved. +// Released under the MIT license. (see license.txt) + +#include + +namespace ARSTD +{ + + + template + const Matrix33 Matrix33::IDENTITY = Matrix33(true); + + + template + Matrix33 Matrix33::inverse(const Matrix33& mat) + { + return boost::qvm::inverse(mat); + } + + + template + Matrix33::Matrix33(bool bInitAsIdentity) + { + if (bInitAsIdentity) + setIdentity(); + } + + + template + Matrix33::Matrix33(const Quaternion& quat) + { + set(quat); + } + + + template + Matrix33::Matrix33(const Matrix& mat) + { + assert(mat.getColumns() == 3 && mat.getRows() == 3); + memcpy(this->pData, mat.getData(), 9*sizeof(Type)); + } + + + template + Matrix33::Matrix33(const Vector3& vecXAxis, const Vector3& vecYAxis, + const Vector3& vecZAxis) + : xx(vecXAxis.x), + yx(vecXAxis.y), + zx(vecXAxis.z), + xy(vecYAxis.x), + yy(vecYAxis.y), + zy(vecYAxis.z), + xz(vecZAxis.x), + yz(vecZAxis.y), + zz(vecZAxis.z) + { + } + + + template + Matrix33& Matrix33::operator *= (const Type& rhs) + { + this->xx *= rhs; this->xy *= rhs; this->xz *= rhs; + this->yx *= rhs; this->yy *= rhs; this->yz *= rhs; + this->zx *= rhs; this->zy *= rhs; this->zz *= rhs; + + return *this; + } + + + template + Matrix33& Matrix33::operator += (const Matrix33& rhs) + { + this->xx += rhs.xx; this->xy += rhs.xy; this->xz += rhs.xz; + this->yx += rhs.yx; this->yy += rhs.yy; this->yz += rhs.yz; + this->zx += rhs.zx; this->zy += rhs.zy; this->zz += rhs.zz; + + return *this; + } + + + template + Matrix33& Matrix33::operator -= (const Matrix33& rhs) + { + this->xx -= rhs.xx; this->xy -= rhs.xy; this->xz -= rhs.xz; + this->yx -= rhs.yx; this->yy -= rhs.yy; this->yz -= rhs.yz; + this->zx -= rhs.zx; this->zy -= rhs.zy; this->zz -= rhs.zz; + + return *this; + } + + + template + Matrix33& Matrix33::operator *= (const Matrix33& rhs) + { + return boost::qvm::operator*=(*this, rhs); + } + + + template + Vector3& Matrix33::getXAxis() + { + return *reinterpret_cast*>(&this->xx); + } + + + template + const Vector3& Matrix33::getXAxis() const + { + return *reinterpret_cast*>(&this->xx); + } + + + template + void Matrix33::setXAxis(const Vector3& vecXAxis) + { + getXAxis() = vecXAxis; + } + + + template + Vector3& Matrix33::getYAxis() + { + return *reinterpret_cast*>(&this->xy); + } + + + template + const Vector3& Matrix33::getYAxis() const + { + return *reinterpret_cast*>(&this->xy); + } + + + template + void Matrix33::setYAxis(const Vector3& vecYAxis) + { + getYAxis() = vecYAxis; + } + + + template + Vector3& Matrix33::getZAxis() + { + return *reinterpret_cast*>(&this->xz); + } + + + template + const Vector3& Matrix33::getZAxis() const + { + return *reinterpret_cast*>(&this->xz); + } + + + template + void Matrix33::setZAxis(const Vector3& vecZAxis) + { + getZAxis() = vecZAxis; + } + + + template + void Matrix33::get(Type& rotX, Type& rotY, Type& rotZ) const + { + rotX = static_cast(atan2(this->yz, this->zz)); + rotY = static_cast(asin(-this->xz)); + rotZ = static_cast(atan2(this->xy, this->xx)); + } + + + template + Quaternion Matrix33::getAsQuaternion() const + { + return boost::qvm::convert_to>(*this); + } + + + template + void Matrix33::setIdentity() + { + boost::qvm::set_identity(*this); + } + + + template + bool Matrix33::isIdentity(const Type& epsilon) const + { + return equals(IDENTITY, *this, epsilon); + } + + + template + void Matrix33::set(const Matrix33& mat) + { + *this = mat; + } + + + template + void Matrix33::set(const Quaternion& quat) + { + *this = quat.getAsMatrix33(); + } + + + template + void Matrix33::set(const Vector3& vecAxis, const Type& angle) + { + boost::qvm::set_rot(*this, vecAxis, angle); + } + + + template + void Matrix33::transpose() + { + std::swap(this->yx, this->xy); + std::swap(this->zx, this->xz); + std::swap(this->zy, this->yz); + } + + + template + const Type Matrix33::determinant() const + { + return boost::qvm::determinant(*this); + } + + + template + void Matrix33::makeRotationMatrix(const EColumn& axis) + { + switch (axis) + { + case COL0: + getZAxis().normalize(); + setXAxis((getYAxis() % getZAxis()).getNormalized()); + setYAxis(getZAxis() % getXAxis()); + break; + + case COL1: + getXAxis().normalize(); + setYAxis((getZAxis() % getXAxis()).getNormalized()); + setZAxis(getXAxis() % getYAxis()); + break; + + case COL2: + getYAxis().normalize(); + setZAxis((getXAxis() % getYAxis()).getNormalized()); + setXAxis(getYAxis() % getZAxis()); + break; + } + } + + + template + const Matrix33 operator * (const Matrix33& lhs, const Type& rhs) + { + return Matrix33(lhs) *= rhs; + } + + + template + const Vector3 operator * (const Matrix33& mat, const Vector3& vec) + { + return boost::qvm::operator*(mat, vec); + } + + + template + const Matrix33 operator * (const Matrix33& lhs, const Matrix33& rhs) + { + return Matrix33(lhs) *= rhs; + } + + + template + bool equals(const Matrix33& lhs, const Matrix33& rhs, double fEpsilon) + { + if (&lhs == &rhs) + return true; + return boost::qvm::cmp(lhs, rhs, [fEpsilon](const Type& lc, const Type& rc) { return fabs(lc - rc) < fEpsilon; }); + } + + + template + bool operator == (const Matrix33& lhs, const Matrix33& rhs) + { + return equals(lhs, rhs, EPSILON); + } + + + template + bool operator != (const Matrix33& lhs, const Matrix33& rhs) + { + return !operator==(lhs, rhs); + } + + +} // namespace ARSTD diff --git a/ARSTD/ARSTD/Math/Matrix44.h b/ARSTD/ARSTD/Math/Matrix44.h new file mode 100644 index 00000000..f8c415ac --- /dev/null +++ b/ARSTD/ARSTD/Math/Matrix44.h @@ -0,0 +1,364 @@ +// Copyright (c) 2005-2022 Andreas Rose. All rights reserved. +// Released under the MIT license. (see license.txt) + +#pragma once +#include +#include + + +namespace ARSTD +{ + + template class Matrix; + + /** + * This represents a 4x4 Matrix + */ + template + struct Matrix44 + { + public: + enum ERow { ROW0 = 0, ROW1, ROW2, ROW3 }; + enum EColumn { COL0 = 0, COL1, COL2, COL3 }; + enum EAxis { XAXIS = 0, YAXIS, ZAXIS }; + + + template + operator R() const + { + R r; + assign(r, *this); + return r; + } + + /** + * The identity matrix. + */ + static const Matrix44 IDENTITY; + + /** + * Inverts the matrix + * @param mat The 4x4 matrix + * @return The inverted matrix + */ + static Matrix44 inverse(const Matrix44& mat); + + /** + * Spherical linear interpolation of two matrices + * @return The interpolated matrix + */ + static Matrix44 slerp(const Matrix44& mat1, const Matrix44& mat2, const double& t); + + /** + * Constructor, which is as default not initialized + * @param bInitAsIdentity If set to false the matrix is not initialized, otherwise an identity matrix is initialized + */ + explicit Matrix44(bool bInitAsIdentity = true); + + /** + * Contructs a translation matrix by given translation vector + * @param vecTranslation The translation vector + */ + explicit Matrix44(const Vector3& vecTranslation); + + /** + * Constructs a matrix with the given generic matrix elements + * @param mat The generic matrix from where to set + * @pre mat has to be a 4x4 matrix + */ + explicit Matrix44(const Matrix& mat); + + /** + * Constructs a matrix with a given rotation and translation + * The homogenous value (ww) of the 4th column is set to 1 + * @param rotation The rotation 3x3 matrix + * @param vecTranslation The translation vector + */ + Matrix44(const Matrix33& rotation, const Vector3& vecTranslation); + + /** + * Constructs a matrix with a given rotation and translation + * The homogenous value (ww) of the 4th column is set to 1 + * @param rotation The rotation quaternion + * @param vecTranslation The translation vector + */ + Matrix44(const Quaternion& rotation, const Vector3& vecTranslation); + + /** + * Constructs a matrix with 4 three-component vectors, one for each column + * The forth row of the matrix is set to (0 0 0 1) + * @param vecXAxis The x-axis vector + * @param vecYAxis The y-axis vector + * @param vecZAxis The z-axis vector + * @param vecTranslation The translation vector + */ + Matrix44(const Vector3& vecXAxis, const Vector3& vecYAxis, + const Vector3& vecZAxis, const Vector3& vecTranslation); + + /** + * Constructs a the matrix with 4 four-component vectors, one for each column + * @param vecXAxis The x-axis vector + * @param vecYAxis The y-axis vector + * @param vecZAxis The z-axis vector + * @param vecTranslation The translation that vector. + */ + Matrix44(const Vector4& vecColumn0, const Vector4& vecColumn1, + const Vector4& vecColumn2, const Vector4& vecColumn3); + + template + explicit Matrix44(const Matrix44& other) + { + for (int i = 0; i < 16; i++) + { + this->pData[i] = static_cast(other.pData[i]); + } + } + + /** + * Matrix multiplication + * @param other The other matrix + * @return The multiplied matrix + */ + Matrix44& operator *= (const Matrix44& other); + + /** + * Gives access to the x-axis of the 3x3 rotational part. + */ + Vector3& getXAxis(); + + /** + * Returns the x-axis vector + */ + const Vector3& getXAxis() const; + + /** + * Sets the x-axis vector + */ + void setXAxis(const Vector3& vecXAxis); + + /** + * Gives access to y-axis vector + */ + Vector3& getYAxis(); + + /** + * Returns the y-axis vector + */ + const Vector3& getYAxis() const; + + /** + * Sets the y-axis vector + */ + void setYAxis(const Vector3& vecYAxis); + + /** + * Gives access to the z-axis vector + */ + Vector3& getZAxis(); + + /** + * Returns the z-axis vector + */ + const Vector3& getZAxis() const; + + /** + * Sets the z-axis vector + */ + void setZAxis(const Vector3& vecZAxis); + + /** + * Gives access to the translation vector + */ + Vector3& getTranslation(); + + /** + * Returns the translation vector + */ + const Vector3& getTranslation() const; + + /** + * Sets the translation vector + */ + void setTranslation(const Vector3& vecTranslation); + + /** + * Sets the matrix to the identity + */ + void setIdentity(); + + /** + * Checks if the matrix is to identity matrix + * @param epsilon + * @return true, if the matrix is equal, otherwise false + */ + bool isIdentity(const Type& epsilon = EPSILON) const; + + /** + * Returns the rotation as 3x3 matrix + * @return The 3x3 matrix + */ + const Matrix33 getRotationAsMatrix33() const; + + /** + * Returns the rotation as quaternion + * @return The quaternion + */ + const Quaternion getRotationAsQuaternion() const; + + /** + * Sets the rotation using rotation axis and rotation angle + * @param vecAxis The rotation axis + * @param angle The rotation angle + */ + void setRotation(const Vector3& vecAxis, const Type& angle); + + /** + * Sets the rotation using 3x3 matrix + * @param mat The 3x3 Matrix + */ + void setRotation(const Matrix33& mat); + + /** + * Sets the rotation using quaternion + * @param rotation The quaternion + */ + void setRotation(const Quaternion& quat); + + /** + * Transposes the matrix + */ + void transpose(); + + /** + * Transposes the rotational part of the matrix only + */ + void transposeRot(); + + /** + * Inverts the matrix + */ + void invert(); + + /** + * Rebuilds a homogeneous transformation matrix by discarding a given axis + * @param axis The axis, that is discarded + */ + void makeHomogeneous(const EAxis& axis); + + union + { + Type pData[16]; + Type pData2[4][4]; + struct + { + Type xx, yx, zx, wx; + Type xy, yy, zy, wy; + Type xz, yz, zz, wz; + Type xw, yw, zw, ww; + }; + }; + }; + + + template + struct boost::qvm::mat_traits; + + template + struct boost::qvm::mat_traits> + { + typedef Type scalar_type; + static int const rows = 4; + static int const cols = 4; + + template + static scalar_type read_element(ARSTD::Matrix44 const& x) + { + return x.pData2[Col][Row]; + } + + template + static scalar_type& write_element(ARSTD::Matrix44& x) + { + return x.pData2[Col][Row]; + } + + static scalar_type read_element_idx(int row, int col, ARSTD::Matrix44 const& x) + { + return x.pData2[col][row]; + } + + static scalar_type& write_element_idx(int row, int col, ARSTD::Matrix44& x) + { + return x.pData2[col][row]; + } + }; + + + typedef Matrix44 Matrix44F; + typedef Matrix44 Matrix44D; + + + /** + * Matrix matrix multiplication + * @relates Matrix44 + */ + template + const Matrix44 operator * (const Matrix44& lhs, const Matrix44& rhs); + + /** + * Matrix vector multiplication assuming the 4th component of the vector to be 1 + * @relates Matrix44 + */ + template + const Vector3 operator * (const Matrix44& lhs, const Vector3& rhs); + + /** + * Matrix vector multiplication + * @relates Matrix44 + */ + template + const Vector4 operator * (const Matrix44& lhs, const Vector4& rhs); + + /** + * Compares two matrices with the epsilon given by the parameter fEpsilon + * @sa EPSILON + * @relates Matrix44 + */ + template + bool equals(const Matrix44& lhs, const Matrix44& rhs, double fEpsilon = EPSILON); + + /** + * Compares two matrices using default EPSILON + * @sa EPSILON + * @relates Matrix44 + */ + template + bool operator == (const Matrix44& lhs, const Matrix44& rhs); + + /** + * Compares two matrices using default EPSILON + * @sa EPSILON + * @relates Matrix44 + */ + template + bool operator != (const Matrix44& lhs, const Matrix44& rhs); + + /** + * Writes the matrix to a std output stream + * @relates Matrix44 + */ + template + std::ostream& operator << (std::ostream& stream, const Matrix44& mat); + + /** + * Reads a matrix from a std input stream + * @relates Matrix44 + */ + template + std::istream& operator >> (std::istream& stream, Matrix44& mat); + + +} // namespace ARSTD + + +#include "Matrix44_Impl.h" diff --git a/ARSTD/ARSTD/Math/Matrix44_Impl.h b/ARSTD/ARSTD/Math/Matrix44_Impl.h new file mode 100644 index 00000000..9eabb13b --- /dev/null +++ b/ARSTD/ARSTD/Math/Matrix44_Impl.h @@ -0,0 +1,383 @@ +// Copyright (c) 2005-2022 Andreas Rose. All rights reserved. +// Released under the MIT license. (see license.txt) + +#include +#include + +namespace ARSTD +{ + + template + const Matrix44 Matrix44::IDENTITY = Matrix44(true); + + + template + Matrix44 Matrix44::inverse(const Matrix44& mat) + { + return boost::qvm::inverse(mat); + } + + + template + Matrix44 Matrix44::slerp(const Matrix44& mat1, const Matrix44& mat2, const double& t) + { + return Matrix44(Quaternion::slerp(mat1.getRotationAsQuaternion(), mat2.getRotationAsQuaternion(), t), + Vector3::lerp(mat1.getTranslation(), mat2.getTranslation(), t)); + } + + + template + Matrix44::Matrix44(bool bInitAsIdentity) + { + if (bInitAsIdentity) + setIdentity(); + } + + + template + Matrix44::Matrix44(const Vector3& vecTranslation) + { + setIdentity(); + setTranslation(vecTranslation); + } + + + template + Matrix44::Matrix44(const Matrix& mat) + { + assert(mat.getColumns() == 4 && mat.getRows() == 4); + memcpy(this->pData, mat.getData(), 16*sizeof(Type)); + } + + + template + Matrix44::Matrix44(const Matrix33& rotation, const Vector3& vecTranslation) + { + setIdentity(); + setRotation(rotation); + setTranslation(vecTranslation); + } + + + template + Matrix44::Matrix44(const Quaternion& rotation, const Vector3& vecTranslation) + { + setIdentity(); + setRotation(rotation); + setTranslation(vecTranslation); + } + + + template + Matrix44::Matrix44(const Vector3& vecXAxis, const Vector3& vecYAxis, + const Vector3& vecZAxis, const Vector3& vecTranslation) + : xx(vecXAxis.x), + yx(vecXAxis.y), + zx(vecXAxis.z), + wx(0), + xy(vecYAxis.x), + yy(vecYAxis.y), + zy(vecYAxis.z), + wy(0), + xz(vecZAxis.x), + yz(vecZAxis.y), + zz(vecZAxis.z), + wz(0), + xw(vecTranslation.x), + yw(vecTranslation.y), + zw(vecTranslation.z), + ww(1) + { + } + + + template + Matrix44::Matrix44(const Vector4& vecColumn0, const Vector4& vecColumn1, + const Vector4& vecColumn2, const Vector4& vecColumn3) + : xx(vecColumn0.x), + yx(vecColumn0.y), + zx(vecColumn0.z), + wx(vecColumn0.w), + xy(vecColumn1.x), + yy(vecColumn1.y), + zy(vecColumn1.z), + wy(vecColumn1.w), + xz(vecColumn2.x), + yz(vecColumn2.y), + zz(vecColumn2.z), + wz(vecColumn2.w), + xw(vecColumn3.x), + yw(vecColumn3.y), + zw(vecColumn3.z), + ww(vecColumn3.w) + { + } + + + template + Matrix44& Matrix44::operator *= (const Matrix44& rhs) + { + return boost::qvm::operator*=(*this, rhs); + } + + + template + Vector3& Matrix44::getXAxis() + { + return *reinterpret_cast*>(&this->xx); + } + + + template + const Vector3& Matrix44::getXAxis() const + { + return *reinterpret_cast*>(&this->xx); + } + + + template + void Matrix44::setXAxis(const Vector3& vecXAxis) + { + getXAxis() = vecXAxis; + } + + + template + Vector3& Matrix44::getYAxis() + { + return *reinterpret_cast*>(&this->xy); + } + + + template + const Vector3& Matrix44::getYAxis() const + { + return *reinterpret_cast*>(&this->xy); + } + + + template + void Matrix44::setYAxis(const Vector3& vecYAxis) + { + getYAxis() = vecYAxis; + } + + + template + Vector3& Matrix44::getZAxis() + { + return *reinterpret_cast*>(&this->xz); + } + + + template + const Vector3& Matrix44::getZAxis() const + { + return *reinterpret_cast*>(&this->xz); + } + + + template + void Matrix44::setZAxis(const Vector3& vecZAxis) + { + getZAxis() = vecZAxis; + } + + + template + Vector3& Matrix44::getTranslation() + { + return *reinterpret_cast*>(&this->xw); + } + + + template + const Vector3& Matrix44::getTranslation() const + { + return *reinterpret_cast*>(&this->xw); + } + + + template + void Matrix44::setTranslation(const Vector3& vecTranslation) + { + getTranslation() = vecTranslation; + } + + + template + void Matrix44::setIdentity() + { + boost::qvm::set_identity(*this); + } + + + template + bool Matrix44::isIdentity(const Type& epsilon) const + { + return equals(IDENTITY, *this, epsilon); + } + + + template + const Matrix33 Matrix44::getRotationAsMatrix33() const + { + return Matrix33(getXAxis(), getYAxis(), getZAxis()); + } + + + template + const Quaternion Matrix44::getRotationAsQuaternion() const + { + return Quaternion(getRotationAsMatrix33()); + } + + + template + void Matrix44::setRotation(const Vector3& vecAxis, const Type& angle) + { + setRotation(Quaternion(vecAxis, angle)); + } + + + template + void Matrix44::setRotation(const Matrix33& mat) + { + setXAxis(mat.getXAxis()); + setYAxis(mat.getYAxis()); + setZAxis(mat.getZAxis()); + } + + + template + void Matrix44::setRotation(const Quaternion& quat) + { + assert(quat.length() - static_cast(1) <= EPSILON); + setRotation(quat.getAsMatrix33()); + } + + + template + void Matrix44::transpose() + { + std::swap(this->yx, this->xy); + std::swap(this->zx, this->xz); + std::swap(this->wx, this->xw); + std::swap(this->zy, this->yz); + std::swap(this->wy, this->yw); + std::swap(this->wz, this->zw); + } + + + template + void Matrix44::transposeRot() + { + std::swap(this->yx, this->xy); + std::swap(this->zx, this->xz); + std::swap(this->zy, this->yz); + } + + + template + void Matrix44::invert() + { + *this = boost::qvm::inverse(*this); + } + + + template + void Matrix44::makeHomogeneous(const EAxis& axisRemoved) + { + switch (axisRemoved) + { + case XAXIS: + getZAxis().normalize(); + setXAxis((getYAxis() % getZAxis()).getNormalized()); + setYAxis(getZAxis() % getXAxis()); + break; + + case YAXIS: + getXAxis().normalize(); + setYAxis((getZAxis() % getXAxis()).getNormalized()); + setZAxis(getXAxis() % getYAxis()); + break; + + case ZAXIS: + getYAxis().normalize(); + setZAxis((getXAxis() % getYAxis()).getNormalized()); + setXAxis(getYAxis() % getZAxis()); + break; + } + + this->wx = 0.0; + this->wy = 0.0; + this->wz = 0.0; + this->ww = 1.0; + } + + + template + const Matrix44 operator * (const Matrix44& lhs, const Matrix44& rhs) + { + return Matrix44(lhs) *= rhs; + } + + + template + const Vector3 operator * (const Matrix44& lhs, const Vector3& rhs) + { + return boost::qvm::transform_point(lhs, rhs); + } + + + template + const Vector4 operator * (const Matrix44& lhs, const Vector4& rhs) + { + return boost::qvm::operator*(lhs, rhs); + } + + + template + bool equals(const Matrix44& lhs, const Matrix44& rhs, double fEpsilon) + { + if (&lhs == &rhs) + return true; + return boost::qvm::cmp(lhs, rhs, [fEpsilon](const Type& lc, const Type& rc) { return fabs(lc - rc) < fEpsilon; }); + } + + + template + inline bool operator == (const Matrix44& lhs, const Matrix44& rhs) + { + return equals(lhs, rhs, EPSILON); + } + + + template + inline bool operator != (const Matrix44& lhs, const Matrix44& rhs) + { + return !(lhs == rhs); + } + + + template + std::ostream& operator << (std::ostream& stream, const Matrix44& mat) + { + return stream << mat.xx << " " << mat.xy << " " << mat.xz << " " << mat.xw << " " + << mat.yx << " " << mat.yy << " " << mat.yz << " " << mat.yw << " " + << mat.zx << " " << mat.zy << " " << mat.zz << " " << mat.zw << " " + << mat.wx << " " << mat.wy << " " << mat.wz << " " << mat.ww; + } + + + template + std::istream& operator >> (std::istream& stream, Matrix44& mat) + { + return stream >> mat.xx >> mat.xy >> mat.xz >> mat.xw + >> mat.yx >> mat.yy >> mat.yz >> mat.yw + >> mat.zx >> mat.zy >> mat.zz >> mat.zw + >> mat.wx >> mat.wy >> mat.wz >> mat.ww; + } + + +} // namespace ARSTD diff --git a/ARSTD/ARSTD/Math/Matrix_Impl.h b/ARSTD/ARSTD/Math/Matrix_Impl.h new file mode 100644 index 00000000..d5d26367 --- /dev/null +++ b/ARSTD/ARSTD/Math/Matrix_Impl.h @@ -0,0 +1,357 @@ +// Copyright (c) 2005-2022 Andreas Rose. All rights reserved. +// Released under the MIT license. (see license.txt) + +#include +#include + +namespace ARSTD +{ + + template + Matrix::Matrix(const uint nRows, const uint nColumns, const Type& init) + : m_pData(new Type[nRows*nColumns]), + m_nRows(nRows), + m_nColumns(nColumns) + { + assert(nRows > 0 && nColumns > 0); + + uint nElements = nRows*nColumns; + for (uint nCnt = 0; nCnt < nElements; ++nCnt) + { + m_pData[nCnt] = init; + } + } + + + template + Matrix::Matrix(const Matrix33& mat) + : m_pData(new Type[3*3]), + m_nRows(3), + m_nColumns(3) + { + memcpy(m_pData, mat.pData, 3*3*sizeof(Type)); + } + + + template + Matrix::Matrix(const Matrix44& mat) + : m_pData(new Type[4*4]), + m_nRows(4), + m_nColumns(4) + { + memcpy(m_pData, mat.pData, 4*4*sizeof(Type)); + } + + + template + Matrix::Matrix(const Matrix& other) + : m_pData(new Type[other.m_nRows*other.m_nColumns]), + m_nRows(other.m_nRows), + m_nColumns(other.m_nColumns) + { + memcpy(m_pData, other.m_pData, other.m_nRows*other.m_nColumns*sizeof(Type)); + } + + + template + Matrix::~Matrix() + { + delete [] m_pData; + } + + + template + const uint Matrix::getRows() const + { + return m_nRows; + } + + + template + const uint Matrix::getColumns() const + { + return m_nColumns; + } + + + template + const Matrix Matrix::getRow(const uint nRow) const + { + assert(nRow < m_nRows); + + Matrix vec(1, m_nColumns); + + uint nSrcIdx(nRow); + for (uint i = 0; i < m_nColumns; ++i) + { + vec.getData()[i] = m_pData[nSrcIdx]; + nSrcIdx += m_nRows; + } + + return vec; + } + + + template + const Matrix Matrix::getColumn(const uint nColumn) const + { + assert(nColumn < m_nColumns); + + Matrix vec(m_nRows); + memcpy(vec.getData(), m_pData + nColumn*m_nRows, m_nRows*sizeof(Type)); + + return vec; + } + + + template + void Matrix::setRow(const uint nRow, const Matrix vec) + { + assert(nRow < m_nRows && + vec.getColumns() == m_nColumns && + vec.getRows() == 1); + + uint nDstIdx(nRow); + for (uint i = 0; i < m_nColumns; ++i) + { + m_pData[nDstIdx] = vec.getData()[i]; + nDstIdx += m_nRows; + } + } + + + template + void Matrix::setColumn(const uint nColumn, const Matrix vec) + { + assert(nColumn < m_nColumns && + vec.getRows() == m_nRows && + vec.getColumns() == 1); + + memcpy(m_pData + nColumn*m_nRows, vec.getData(), m_nRows*sizeof(Type)); + } + + + template + void Matrix::setZero() + { + memset(m_pData, 0, m_nRows*m_nColumns*sizeof(Type)); + } + + + template + void Matrix::setIdentity() + { + this->setZero(); + uint nMax(std::min(m_nRows, m_nColumns)); + uint nInc(m_nRows + 1); + uint nIdx(0); + for (uint i = 0; i < nMax; ++i) + { + m_pData[nIdx] = 1; + nIdx += nInc; + } + } + + + template + const std::pair, bool> Matrix::inverse(const Matrix& mat) + { + if (mat.getRows() == mat.getColumns()) + return ordinaryInverse(mat); + else + return pseudoInverse(mat); + } + + + template + bool Matrix::invert() + { + std::pair, bool> result = inverse(*this); + if (result.second) + { + m_nRows = result.first.getRows(); + m_nColumns = result.first.getColumns(); + + delete [] m_pData; + m_pData = new Type[m_nRows*m_nColumns]; + memcpy(m_pData, result.first.getData(), m_nRows*m_nColumns*sizeof(Type)); + } + + return result.second; + } + + + template + void Matrix::transpose() + { + if (m_nRows == 1 || m_nColumns == 1) + { + std::swap(m_nRows, m_nColumns); + } + else + { + Type* pNewData = new Type[m_nRows*m_nColumns]; + + uint nNewRows(m_nColumns); + uint nNewColumns(m_nRows); + uint nDestIdx(0); + uint nSrcIdx(0); + uint i, j; + for (j = 0; j < nNewColumns; ++j) + { + nSrcIdx = j; + for (i = 0; i < nNewRows; ++i) + { + pNewData[nDestIdx] = m_pData[nSrcIdx]; + ++nDestIdx; + nSrcIdx += m_nRows; + } + } + + delete [] m_pData; + m_pData = pNewData; + m_nRows = nNewRows; + m_nColumns = nNewColumns; + } + } + + + template + const Matrix Matrix::getTransposed() const + { + Matrix mat(*this); + mat.transpose(); + + return mat; + } + + + template + typename Type& Matrix::operator()(const uint nRow, const uint nColumn) + { + assert(nRow < m_nRows && nColumn < m_nColumns); + + return m_pData[nRow + nColumn*m_nRows]; + } + + + template + typename const Type& Matrix::operator()(const uint nRow, const uint nColumn) const + { + assert(nRow < m_nRows && nColumn < m_nColumns); + + return m_pData[nRow + nColumn*m_nRows]; + } + + + template + Type* Matrix::getData() + { + return m_pData; + } + + + template + const Type* Matrix::getData() const + { + return m_pData; + } + + + template + void Matrix::operator=(const Matrix& other) + { + if (this == &other) + return; + + if (m_nRows != other.getRows() || + m_nColumns != other.getColumns()) + { + delete [] m_pData; + m_pData = new Type[other.m_nRows*other.m_nColumns]; + + m_nRows = other.m_nRows; + m_nColumns = other.m_nColumns; + } + + memcpy(m_pData, other.m_pData, other.m_nRows*other.m_nColumns*sizeof(Type)); + } + + + template + const std::pair, bool> Matrix::ordinaryInverse(const Matrix& mat) + { + assert(mat.getRows() == mat.getColumns()); + + uint i, j; + boost::numeric::ublas::matrix input(mat.getRows(), mat.getColumns()); + for (j = 0; j < mat.getColumns(); ++j) + { + for (i = 0; i < mat.getRows(); ++i) + input(i, j) = mat(i, j); + } + + boost::numeric::ublas::permutation_matrix permutationMatrix(input.size1()); + + int result = boost::numeric::ublas::lu_factorize(input, permutationMatrix); + if (result != 0) + return std::make_pair(mat, false); + + boost::numeric::ublas::matrix inverseOfInput(input.size1(), input.size2()); + inverseOfInput.assign(boost::numeric::ublas::identity_matrix(input.size1())); + + boost::numeric::ublas::lu_substitute(input, permutationMatrix, inverseOfInput); + + Matrix tmp(inverseOfInput.size1(), inverseOfInput.size2()); + for (j = 0; j < inverseOfInput.size2(); ++j) + { + for (i = 0; i < inverseOfInput.size1(); ++i) + tmp(j, i) = inverseOfInput(i, j); + } + + return std::make_pair(tmp, true); + } + + + template + const std::pair, bool> Matrix::pseudoInverse(const Matrix& mat) + { + assert(mat.getRows() != mat.getColumns()); + + Matrix matToInvertTransposed(mat); + matToInvertTransposed.transpose(); + + std::pair, bool> result = ordinaryInverse(matToInvertTransposed * mat); + if (!result.second) + return result; + + return std::make_pair(result.first * matToInvertTransposed, true); + } + + + template + const Matrix operator*(const Matrix& lhs, const Matrix& rhs) + { + assert(lhs.getColumns() == rhs.getRows()); + + uint nRows = lhs.getRows(); + uint nColumns = rhs.getColumns(); + uint nElements = lhs.getColumns(); + uint i, j, k; + Matrix res(nRows, nColumns); + + for (i = 0; i < nRows; ++i) + { + for (j = 0; j < nColumns; ++j) + { + for (k = 0; k < nElements; ++k) + { + res(i, j) += lhs(i, k)*rhs(k, j); + } + } + } + + return res; + } + +} diff --git a/ARSTD/ARSTD/Math/Quaternion.h b/ARSTD/ARSTD/Math/Quaternion.h new file mode 100644 index 00000000..b012fef9 --- /dev/null +++ b/ARSTD/ARSTD/Math/Quaternion.h @@ -0,0 +1,145 @@ +// Copyright (c) 2005-2022 Andreas Rose. All rights reserved. +// Released under the MIT license. (see license.txt) + +#pragma once +#include + + +namespace ARSTD +{ + + template struct Matrix33; + + + template + struct Quaternion + { + + template + operator R() const + { + R r; + assign(r, *this); + return r; + } + + static Quaternion slerp(const Quaternion& quat1, const Quaternion& quat2, const double& t); + + explicit Quaternion(const Type& w = 1, const Type& x = 0, const Type& y = 0, const Type& z = 0); + explicit Quaternion(const Vector3& vecAxis, const Type& angle); + explicit Quaternion(const Matrix33& mat); + + template + explicit Quaternion(const Quaternion& other) + { + w = static_cast(other.w); + x = static_cast(other.x); + y = static_cast(other.y); + z = static_cast(other.z); + } + + + Type length() const; + Type lengthSqr() const; + + Quaternion normalize(); + + const Matrix33 getAsMatrix33() const; + + Type getAngleBetween(const Quaternion& quat) const; + + void set(const Quaternion& quat); + void set(const Type& w, const Type& x, const Type& y, const Type& z); + void set(const Vector3& vecAxis, const Type& angle); + void set(const Matrix33& mat); + + Quaternion getInversed() const; + + static const bool equals(const Quaternion& lhs, const Quaternion& rhs, double fEpsilon); + + template + Quaternion& operator += (const Quaternion& other) + { + return boost::qvm::operator+=(*this, other); + } + + template + Quaternion& operator -= (const Quaternion& other) + { + return boost::qvm::operator-=(*this, other); + } + + template + Quaternion& operator *= (const Type2& scalar) + { + return boost::qvm::operator*=(*this, scalar); + } + + + union + { + Type pData[4]; + + struct + { + Type w; + Type x; + Type y; + Type z; + }; + }; + + }; + + + template + struct boost::qvm::quat_traits; + + template + struct boost::qvm::quat_traits> + { + typedef Type scalar_type; + + template + static scalar_type read_element(ARSTD::Quaternion const& x) + { + return x.pData[I]; + } + + template + static scalar_type& write_element(ARSTD::Quaternion& x) + { + return x.pData[I]; + } + }; + + + typedef Quaternion QuaternionD; + + + template + Quaternion operator - (const Quaternion& other); + + template + Quaternion operator + (const Quaternion& lhs, const Quaternion& rhs); + + template + Quaternion operator - (const Quaternion& lhs, const Quaternion& rhs); + + template + Quaternion operator * (const Quaternion& lhs, const Type& rhs); + + template + Quaternion operator * (const Quaternion& lhs, const Quaternion& rhs); + + template + Vector3 operator * (const Quaternion& lhs, const Vector3& rhs); + + template + const bool operator == (const Quaternion& lhs, const Quaternion& rhs); + + +} // namespace ARSTD + + +#include "Quaternion_Impl.h" diff --git a/ARSTD/ARSTD/Math/Quaternion_Impl.h b/ARSTD/ARSTD/Math/Quaternion_Impl.h new file mode 100644 index 00000000..22999376 --- /dev/null +++ b/ARSTD/ARSTD/Math/Quaternion_Impl.h @@ -0,0 +1,191 @@ +// Copyright (c) 2005-2022 Andreas Rose. All rights reserved. +// Released under the MIT license. (see license.txt) + +#include + + +namespace ARSTD +{ + + template + Quaternion Quaternion::slerp(const Quaternion& quat1, const Quaternion& quat2, const double& t) + { + if (t <= 0) + return quat1; + if (t >= 1) + return quat2; + + Quaternion quat2Tmp(quat2); + if (quat1.w*quat2.w + quat1.x*quat2.x + quat1.y*quat2.y + quat1.z*quat2.z < 0) + quat2Tmp = -quat2Tmp; + + return boost::qvm::slerp(quat1, quat2Tmp, t); + } + + + template + Quaternion::Quaternion(const Type& w, const Type& x, const Type& y, const Type& z) + : w(w), + x(x), + y(y), + z(z) + { + } + + template + Quaternion::Quaternion(const Vector3& vecAxis, const Type& angle) + { + set(vecAxis, angle); + } + + + template + Quaternion::Quaternion(const Matrix33& mat) + { + set(mat); + } + + + template + const bool Quaternion::equals(const Quaternion& lhs, const Quaternion& rhs, double fEpsilon) + { + if (&lhs == &rhs) + return true; + return boost::qvm::cmp(lhs, rhs, [fEpsilon](const Type& lc, const Type& rc) { return fabs(lc - rc) < fEpsilon; }); + } + + + template + Type Quaternion::length() const + { + return boost::qvm::mag(*this); + } + + + template + Type Quaternion::lengthSqr() const + { + return boost::qvm::mag_sqr(*this); + } + + + template + Quaternion Quaternion::normalize() + { + boost::qvm::normalize(*this); + } + + + template + const Matrix33 Quaternion::getAsMatrix33() const + { + return boost::qvm::convert_to>(*this); + } + + + template + Type Quaternion::getAngleBetween(const Quaternion& quat) const + { + if (&quat == this) + return 0; + if (quat == *this) + return 0; + if (-quat == *this) + return PI; + + Quaternion tmp(quat); + if (quat.w*this->w + quat.x*this->x + quat.y*this->y + quat.z*this->z < 0.0) + tmp = -tmp; + + return (*this*tmp.getInversed()).w; + } + + + template + void Quaternion::set(const Quaternion& quat) + { + *this = quat; + } + + + template + void Quaternion::set(const Type& w, const Type& x, const Type& y, const Type& z) + { + this->w = w; + this->x = x; + this->y = y; + this->z = z; + } + + + template + void Quaternion::set(const Vector3& vecAxis, const Type& angle) + { + boost::qvm::set_rot(*this, vecAxis, angle); + } + + + template + void Quaternion::set(const Matrix33& mat) + { + *this = mat.getAsQuaternion(); + } + + + template + Quaternion Quaternion::getInversed() const + { + return boost::qvm::inverse(*this); + } + + + template + Quaternion operator - (const Quaternion& other) + { + return boost::qvm::operator-(other); + } + + + template + Quaternion operator + (const Quaternion& lhs, const Quaternion& rhs) + { + return boost::qvm::operator+(lhs, rhs); + } + + + template + Quaternion operator - (const Quaternion& lhs, const Quaternion& rhs) + { + return boost::qvm::operator-(lhs, rhs); + } + + + template + Quaternion operator * (const Quaternion& lhs, const Type& rhs) + { + return boost::qvm::operator*(lhs, rhs); + } + + + template + Quaternion operator * (const Quaternion& lhs, const Quaternion& rhs) + { + return boost::qvm::operator*(lhs, rhs); + } + + + template + Vector3 operator * (const Quaternion& lhs, const Vector3& rhs) + { + return boost::qvm::operator*(lhs, rhs); + } + + + template + const bool operator == (const Quaternion& lhs, const Quaternion& rhs) + { + return boost::qvm::operator==(lhs, rhs); + } + + +} // namespace ARSTD diff --git a/ARSTD/ARSTD/Math/Vector3.h b/ARSTD/ARSTD/Math/Vector3.h new file mode 100644 index 00000000..6c438221 --- /dev/null +++ b/ARSTD/ARSTD/Math/Vector3.h @@ -0,0 +1,338 @@ +// Copyright (c) 2005-2022 Andreas Rose. All rights reserved. +// Released under the MIT license. (see license.txt) + +#pragma once +#include +#include + + +namespace ARSTD +{ + + /** + * This represents a 3-dimensional vector + */ + template + struct Vector3 + { + public: + + template + operator R() const + { + R r; + assign(r, *this); + return r; + } + + static const Vector3 ZERO; + + /** + * Linear interpolation of two vectors + * @return The interpolated vector + */ + static Vector3 lerp(const Vector3& vec1, const Vector3& vec2, const double& t); + + /** + * Constructs a vector from given components + * @param x x-component + * @param y y-component + * @param z z-component + */ + Vector3(const Type& x = 0, const Type& y = 0, const Type& z = 0); + + template + explicit Vector3(const Vector3& other) + : x(static_cast(other.x)), + y(static_cast(other.y)), + z(static_cast(other.z)) + { + } + + /** + * Returns the length + * @return length of the vector + */ + const Type getLength() const; + + /** + * Returns the squared length + * @return Squared length of the vector. + */ + const Type getSquaredLength() const; + + /** + * Normalizes the vector to a length of 1 + * @pre getLength() != 0.0 + * @post getLength() is 1 + * @return The normalized vector + */ + const Vector3& normalize(); + + /** + * Returns the normalized version of this vector + * @pre getLength() != 0.0 + * @return The normalized vector + */ + Vector3 getNormalized() const; + + /** + * Rotates the vector around given axis and angle + * @param vecAxis the axis the vector is rotated around + * @param angle the angle the vector is rotated around in rad + */ + Vector3 getRotated(const Vector3& vecAxis, const Type& angle) const; + + /** + * Returns the distance to given vector + */ + double getDistance(const Vector3& vec) const; + + /** + * Returns the angle the given vector + */ + Type getAngleBetween(const Vector3& vec) const; + Type getAngleBetweenInDegree(const Vector3& vec) const; + + /** + * Returns a some perpendicular vector + * @return The perpendicular vector + * @pre The length must be not zero + */ + Vector3 getPerpendicular() const; + + Vector3& operator += (const Vector3& vec); + Vector3& operator -= (const Vector3& vec); + Vector3& operator *= (const Type& scalar); + Vector3& operator /= (const Type& scalar); + + union + { + Type pData[3]; + struct + { + Type x; ///< The first component + Type y; ///< The second component + Type z; ///< The third component + }; + struct + { + Type r; ///< Alias of first component + Type g; ///< Alias of second component + Type b; ///< Alias of third component + }; + }; + }; + + + template + struct boost::qvm::vec_traits; + + template + struct boost::qvm::vec_traits> + { + typedef Type scalar_type; + static int const dim = 3; + + template + static scalar_type read_element(ARSTD::Vector3 const& x) + { + return x.pData[I]; + } + + template + static scalar_type& write_element(ARSTD::Vector3& x) + { + return x.pData[I]; + } + + static scalar_type read_element_idx(int i, ARSTD::Vector3 const& x) + { + return x.pData[i]; + } + + static scalar_type& write_element_idx(int i, ARSTD::Vector3& x) + { + return x.pData[i]; + } + + }; + + typedef Vector3 Vector3F; + typedef Vector3 Vector3D; + + + /** + * Negates all components + * @return The negated vector + * @relates Vector3 + */ + template + Vector3 operator - (const Vector3& vec); + + /** + * Calculates the dot product + * @return The dot product + * @relates Vector3 + */ + template + const Type operator * (const Vector3& lhs, const Vector3& rhs); + + /** + * Calculates the cross product + * @return The cross product + * @relates Vector3 + */ + template + Vector3 operator % (const Vector3& lhs, const Vector3& rhs); + + /** + * Calculates the addition + * @return The added vector + * @relates Vector3 + */ + template + Vector3 operator + (const Vector3& lhs, const Vector3& rhs); + + /** + * Multiplies a scalar by each component of a vector + * @return The result of the operation + * @relates Vector3 + */ + template + Vector3 operator * (const Vector3& lhs, const Type& rhs); + + /** + * Multiplies a scalar by each component of a vector + * @return The result of the operation + * @relates Vector3 + */ + template + Vector3 operator * (const Type& lhs, const Vector3& rhs); + + /** + * Divides each component of a vector by a scalar + * @return The result of the operation + * @relates Vector3 + */ + template + Vector3 operator / (const Vector3& lhs, const Type& rhs); + + /** + * Compares two vectors with the epsilon given by the parameter fEpsilon + * @return true, if the vectors are considered equal, false otherwise + * @relates Vector3 + */ + template + bool equals(const Vector3& lhs, const Vector3& rhs, double fEpsilon = EPSILON); + + /** + * Compares two matrices using default EPSILON + * @return true, if the vectors are considered equal, false otherwise + * @relates Vector3 + */ + template + bool operator == (const Vector3& lhs, const Vector3& rhs); + + /** + * Compares two matrices using default EPSILON + * @return true, if the vectors are considered as not equal, false otherwise + * @relates Vector3 + */ + template + bool operator != (const Vector3& lhs, const Vector3& rhs); + + /** + * Writes the vector to a std output stream + * @relates Vector3 + */ + template + std::ostream& operator << (std::ostream& stream, const Vector3& vec); + + /** + * Reads the vector from a std input stream + * @relates Vector3 + */ + template + std::istream& operator >> (std::istream& stream, Vector3& vec); + + /** + * Calculates the distance between to vectors + * @relates Vector3 + */ + template + Type distance(const Vector3& vec1, const Vector3& vec2); + + /** + * Calculates the component wise minimal vector from the given ones + * @relates Vector3 + */ + template + Vector3 minimum(const Vector3& lhs, const Vector3& rhs) + { + Vector3 tmp(lhs); + if (tmp.x > rhs.x) tmp.x = rhs.x; + if (tmp.y > rhs.y) tmp.y = rhs.y; + if (tmp.z > rhs.z) tmp.z = rhs.z; + return tmp; + } + + /** + * Calculates the component wise maximal vector from the given ones + * @relates Vector3 + */ + template + Vector3 maximum(const Vector3& lhs, const Vector3& rhs) + { + Vector3 tmp(lhs); + if (tmp.x < rhs.x) tmp.x = rhs.x; + if (tmp.y < rhs.y) tmp.y = rhs.y; + if (tmp.z < rhs.z) tmp.z = rhs.z; + return tmp; + } + + +} // namespace ARSTD + + +template<> class std::numeric_limits : public std::_Num_float_base +{ + public: + typedef ARSTD::Vector3F _Ty; + + static _Ty (__cdecl min)() + { + return _Ty(-std::numeric_limits::max(), + -std::numeric_limits::max(), + -std::numeric_limits::max()); + } + + static _Ty (__cdecl max)() + { + return _Ty(std::numeric_limits::max(), + std::numeric_limits::max(), + std::numeric_limits::max()); + } +}; + +template<> class std::numeric_limits : public std::_Num_float_base +{ +public: + typedef ARSTD::Vector3D _Ty; + + static _Ty(__cdecl min)() + { + return ARSTD::Vector3D(-std::numeric_limits::max(), + -std::numeric_limits::max(), + -std::numeric_limits::max()); + } + + static _Ty(__cdecl max)() + { + return ARSTD::Vector3D(std::numeric_limits::max(), + std::numeric_limits::max(), + std::numeric_limits::max()); + } +}; + +#include "Vector3_Impl.h" diff --git a/ARSTD/ARSTD/Math/Vector3_Impl.h b/ARSTD/ARSTD/Math/Vector3_Impl.h new file mode 100644 index 00000000..900d197b --- /dev/null +++ b/ARSTD/ARSTD/Math/Vector3_Impl.h @@ -0,0 +1,267 @@ +// Copyright (c) 2005-2022 Andreas Rose. All rights reserved. +// Released under the MIT license. (see license.txt) + +#include +#include "ARSTD/Math/Quaternion.h" + +namespace ARSTD +{ + + template + const Vector3 Vector3::ZERO(0, 0, 0); + + + template + Vector3 Vector3::lerp(const Vector3& vec1, const Vector3& vec2, const double& t) + { + if (t <= 0) + return vec1; + if (t >= 1) + return vec2; + + return vec1 + (vec2 - vec1)*t; + } + + + template + Vector3::Vector3(const Type& x, const Type& y, const Type& z) + : x(x), + y(y), + z(z) + { + } + + + template + const Type Vector3::getLength() const + { + return boost::qvm::mag(*this); + } + + + template + const Type Vector3::getSquaredLength() const + { + return boost::qvm::mag_sqr(*this); + } + + + template + const Vector3& Vector3::normalize() + { + boost::qvm::normalize(*this); + return *this; + } + + + template + Vector3 Vector3::getNormalized() const + { + return boost::qvm::normalized(*this); + } + + + template + Vector3 Vector3::getRotated(const Vector3& vecAxis, const Type& angle) const + { + return Quaternion(vecAxis, angle)*(*this); + } + + + template + double Vector3::getDistance(const Vector3& vec) const + { + return distance(*this, vec); + } + + + template + Type Vector3::getAngleBetween(const Vector3& vec) const + { + if (&vec == this) + return 0; + if (vec == *this) + return 0; + if (-vec == *this) + return PI; + if (vec == ZERO) + return 0; + if (*this == ZERO) + return 0; + + Type s = std::sqrt(getSquaredLength()*vec.getSquaredLength()); + assert(s != 0.0); + return acos(*this*vec)/s; + } + + + template + Type Vector3::getAngleBetweenInDegree(const Vector3& vec) const + { + return getInDegree(getAngleBetween(vec)); + } + + + template + Vector3 Vector3::getPerpendicular() const + { + if (*this == ZERO) + return Vector3(0, 0, 1); + Vector3 vec; + vec.y = -this->x; + vec.z = this->y; + vec.x = this->z; + + assert(vec.x != this->x || vec.y != this->y || vec.z != this->z); + assert(vec.getLength() > EPSILON); + return *this % vec; + } + + + template + Vector3& Vector3::operator += (const Vector3& vec) + { + this->x += vec.x; + this->y += vec.y; + this->z += vec.z; + return *this; + } + + + template + Vector3& Vector3::operator -= (const Vector3& vec) + { + this->x -= vec.x; + this->y -= vec.y; + this->z -= vec.z; + return *this; + } + + + template + Vector3& Vector3::operator *= (const Type& scalar) + { + this->x *= scalar; + this->y *= scalar; + this->z *= scalar; + return *this; + } + + + template + Vector3& Vector3::operator /= (const Type& scalar) + { + return this->operator *= (static_cast(1.0)/scalar); + } + + + template + Vector3 operator - (const Vector3& vec) + + { + return Vector3(-vec.x, -vec.y, -vec.z); + } + + + template + const Type operator * (const Vector3& lhs, const Vector3& rhs) + { + return boost::qvm::dot(lhs, rhs); + } + + + template + Vector3 operator % (const Vector3& lhs, const Vector3& rhs) + { + return boost::qvm::cross(lhs, rhs); + } + + + template + Vector3 operator + (const Vector3& lhs, const Vector3& rhs) + { + return Vector3(lhs) += rhs; + } + + + template + Vector3 operator - (const Vector3& lhs, const Vector3& rhs) + { + return Vector3(lhs) -= rhs; + } + + + template + Vector3 operator * (const Vector3& lhs, const Type& rhs) + { + return Vector3(lhs) *= rhs; + } + + + template + Vector3 operator * (const Type& lhs, const Vector3& rhs) + { + return Vector3(rhs) *= lhs; + } + + + template + Vector3 operator / (const Vector3& lhs, const Type& rhs) + { + return Vector3(lhs) *= static_cast(1.0)/rhs; + } + + + template + bool equals(const Vector3& lhs, const Vector3& rhs, double fEpsilon) + { + if (&lhs == &rhs) + return true; + + return fabs(lhs.x - rhs.x) < fEpsilon && + fabs(lhs.y - rhs.y) < fEpsilon && + fabs(lhs.z - rhs.z) < fEpsilon; + } + + + template + bool operator == (const Vector3& lhs, const Vector3& rhs) + { + return equals(lhs, rhs, EPSILON); + } + + + template + bool operator != (const Vector3& lhs, const Vector3& rhs) + { + return !(lhs == rhs); + } + + + template + std::ostream& operator << (std::ostream& stream, const Vector3& vec) + { + stream << vec.x << " " << vec.y << " " << vec.z; + return stream; + } + + + template + std::istream& operator >> (std::istream& stream, Vector3& vec) + { + stream >> vec.x >> vec.y >> vec.z; + return stream; + } + + + template + Type distance(const Vector3& lhs, const Vector3& rhs) + { + Type dx = lhs.x - rhs.x; + Type dy = lhs.y - rhs.y; + Type dz = lhs.z - rhs.z; + return static_cast(std::sqrt(dx*dx + dy*dy + dz*dz)); + } + + +} // namespace ARSTD diff --git a/ARSTD/ARSTD/Math/Vector4.h b/ARSTD/ARSTD/Math/Vector4.h new file mode 100644 index 00000000..e0fd8553 --- /dev/null +++ b/ARSTD/ARSTD/Math/Vector4.h @@ -0,0 +1,188 @@ +// Copyright (c) 2005-2022 Andreas Rose. All rights reserved. +// Released under the MIT license. (see license.txt) + +#pragma once +#include +#include + + +namespace ARSTD +{ + + /** + * This represents a 4-dimensional vector + */ + template + struct Vector4 + { + public: + + template + operator R() const + { + R r; + assign(r, *this); + return r; + } + + static const Vector4 ZERO; + + /** + * Constructs a vector from given components + * @param x x-component + * @param y y-component + * @param z z-component + * @param w w-component + */ + Vector4(const Type& x = 0, const Type& y = 0, const Type& z = 0, const Type& w = 1); + + template + Vector4(const Vector3& vec, const Type& w) + : x(static_cast(vec.x)), + y(static_cast(vec.y)), + z(static_cast(vec.z)), + w(w) + { + } + + template + explicit Vector4(const Vector4& other) + { + x = static_cast(other.x); + y = static_cast(other.y); + z = static_cast(other.z); + w = static_cast(other.w); + } + + /** + * Returns the length + * @return length of the vector + */ + const Type getLength() const; + + /** + * Returns the squared length + * @return Squared length of the vector. + */ + const Type getSquaredLength() const; + + /** + * Normalizes the vector to a length of 1 + * @pre getLength() != 0.0 + * @post getLength() is 1 + * @return The normalized vector + */ + const Vector4& normalize(); + + /** + * Returns the normalized version of this vector + * @pre getLength() != 0.0 + * @return The normalized vector + */ + Vector4 getNormalized() const; + + Vector4& operator += (const Vector4& vec); + Vector4& operator -= (const Vector4& vec); + Vector4& operator *= (const Type& scalar); + Vector4& operator /= (const Type& scalar); + + union + { + Type pData[4]; + struct + { + Type x; ///< The first component + Type y; ///< The second component + Type z; ///< The third component + Type w; ///< The fourth component + }; + struct + { + Type r; ///< Alias of first component + Type g; ///< Alias of second component + Type b; ///< Alias of third component + Type a; ///< Alias of fourth component + }; + }; + }; + + template + struct boost::qvm::vec_traits; + + template + struct boost::qvm::vec_traits> + { + typedef Type scalar_type; + static int const dim = 4; + + template + static scalar_type read_element(ARSTD::Vector4 const& x) + { + return x.pData[I]; + } + + template + static scalar_type& write_element(ARSTD::Vector4& x) + { + return x.pData[I]; + } + + static scalar_type read_element_idx(int i, ARSTD::Vector4 const& x) + { + return x.pData[i]; + } + + static scalar_type& write_element_idx(int i, ARSTD::Vector4& x) + { + return x.pData[i]; + } + }; + + + typedef Vector4 Vector4F; + typedef Vector4 Vector4D; + + + /** + * Compares two vectors with the epsilon given by the parameter fEpsilon + * @return true, if the vectors are considered equal, false otherwise + * @relates Vector4 + */ + template + bool equals(const Vector4& lhs, const Vector4& rhs, double fEpsilon = EPSILON); + + /** + * Compares two matrices using default EPSILON + * @return true, if the vectors are considered equal, false otherwise + * @relates Vector4 + */ + template + bool operator == (const Vector4& lhs, const Vector4& rhs); + + /** + * Compares two matrices using default EPSILON + * @return true, if the vectors are considered as not equal, false otherwise + * @relates Vector4 + */ + template + bool operator != (const Vector4& lhs, const Vector4& rhs); + + /** + * Writes the vector to a std output stream + * @relates Vector4 + */ + template + std::ostream& operator << (std::ostream& stream, const Vector4& vec); + + /** + * Reads the vector from a std input stream + * @relates Vector4 + */ + template + std::istream& operator >> (std::istream& stream, Vector4& vec); + + +} // namespace ARSTD + + +#include "Vector4_Impl.h" diff --git a/ARSTD/ARSTD/Math/Vector4_Impl.h b/ARSTD/ARSTD/Math/Vector4_Impl.h new file mode 100644 index 00000000..67a687b8 --- /dev/null +++ b/ARSTD/ARSTD/Math/Vector4_Impl.h @@ -0,0 +1,140 @@ +// Copyright (c) 2005-2022 Andreas Rose. All rights reserved. +// Released under the MIT license. (see license.txt) + +#include + + +namespace ARSTD +{ + + template + const Vector4 Vector4::ZERO(0, 0, 0, 0); + + + template + Vector4::Vector4(const Type& x, const Type& y, const Type& z, const Type& w) + : x(x), + y(y), + z(z), + w(w) + { + } + + + template + const Type Vector4::getLength() const + { + return boost::qvm::mag(*this); + } + + + template + const Type Vector4::getSquaredLength() const + { + return boost::qvm::mag_sqr(*this); + } + + + template + const Vector4& Vector4::normalize() + { + boost::qvm::normalize(*this); + return *this; + } + + + template + Vector4 Vector4::getNormalized() const + { + return boost::qvm::normalized(*this); + } + + + template + Vector4& Vector4::operator += (const Vector4& vec) + { + this->x += vec.x; + this->y += vec.y; + this->z += vec.z; + this->w += vec.w; + return *this; + } + + + template + Vector4& Vector4::operator -= (const Vector4& vec) + { + this->x -= vec.x; + this->y -= vec.y; + this->z -= vec.z; + this->w -= vec.w; + return *this; + } + + + template + Vector4& Vector4::operator *= (const Type& scalar) + { + this->x *= scalar; + this->y *= scalar; + this->z *= scalar; + this->w *= scalar; + return *this; + } + + + template + Vector4& Vector4::operator /= (const Type& scalar) + { + this->x /= scalar; + this->y /= scalar; + this->z /= scalar; + this->w /= scalar; + return *this; + } + + + template + bool equals(const Vector4& lhs, const Vector4& rhs, double fEpsilon) + { + if (&lhs == &rhs) + return true; + + return fabs(lhs.x - rhs.x) < fEpsilon && + fabs(lhs.y - rhs.y) < fEpsilon && + fabs(lhs.z - rhs.z) < fEpsilon && + fabs(lhs.w - rhs.w) < fEpsilon; + } + + + template + bool operator == (const Vector4& lhs, const Vector4& rhs) + { + return equals(lhs, rhs, EPSILON); + } + + + template + bool operator != (const Vector4& lhs, const Vector4& rhs) + { + return !(lhs == rhs); + } + + + template + std::ostream& operator << (std::ostream& stream, const Vector4& vec) + { + stream << vec.x << " " << vec.y << " " << vec.z << " " << vec.w; + return stream; + } + + + template + std::istream& operator >> (std::istream& stream, Vector4& vec) + { + stream >> vec.x >> vec.y >> vec.z >> vec.w; + return stream; + } + + +} // namespace ARSTD diff --git a/ARSTD/ARSTD/Message/Message.h b/ARSTD/ARSTD/Message/Message.h new file mode 100644 index 00000000..4715320b --- /dev/null +++ b/ARSTD/ARSTD/Message/Message.h @@ -0,0 +1,64 @@ +// Copyright (c) 2005-2022 Andreas Rose. All rights reserved. +// Released under the MIT license. (see license.txt) + + +#pragma once + +#include + +namespace ARSTD +{ + + template + class Message + { + public: + Message() {}; + virtual ~Message() {}; + + static void broadcastMessage(typename std::shared_ptr pObject, Message& message, int nMaxTreeDepth = 9999); + + static void sendMessage(typename std::shared_ptr pObject, Message& message); + + virtual void evaluateObject(typename std::shared_ptr pObject) {} + + protected: + Message(const Message& other); + }; + + + + template + void Message::broadcastMessage(typename std::shared_ptr pObject, Message& message, int nMaxTreeDepth) + { + if (nMaxTreeDepth < 0 || !pObject) + return; + + message.evaluateObject(pObject); + + if (nMaxTreeDepth <= 0) + return; + + ObjectType::ChildIterator it; + ObjectType::ChildRange range = pObject->getChildRange(); + for (it = range.first; it != range.second; ++it) + { + std::shared_ptr pChild = std::dynamic_pointer_cast(*it); + if (pChild) + { + broadcastMessage(pChild, message, nMaxTreeDepth - 1); + } + } + } + + + template + void Message::sendMessage(typename std::shared_ptr pObject, Message& message) + { + if (!pObject) + return; + + message.evaluateObject(pObject); + } + +} // namespace ARSTD diff --git a/ARSTD/ARSTD/Misc/PIDController.cpp b/ARSTD/ARSTD/Misc/PIDController.cpp new file mode 100644 index 00000000..cee2176e --- /dev/null +++ b/ARSTD/ARSTD/Misc/PIDController.cpp @@ -0,0 +1,81 @@ +// Copyright (c) 2005-2022 Andreas Rose. All rights reserved. +// Released under the MIT license. (see license.txt) + + +#include "arstd/Misc/PIDController.h" +#include "arstd/Misc/Time.h" + +namespace ARSTD +{ + + PIDController::PIDController(double fKp, double fKi, double fKd) + { + initialize(fKp, fKi, fKd); + } + + + PIDController::~PIDController() + { + } + + + void PIDController::setup(double fSetPoint) + { + initialize(m_fKp, m_fKi, m_fKd); + m_fSetPoint = fSetPoint; + } + + + void PIDController::setNewProcessValue(double fPV) + { + m_fProcessValue = fPV; + validate(); + } + + + double PIDController::getControlValue() const + { + return m_fCurrentControlValue; + } + + + void PIDController::initialize(double fKp, double fKi, double fKd) + { + m_fKp = fKp; + m_fKi = fKi; + m_fKd = fKd; + + m_fSetPoint = 0; + m_fProcessValue = 0; + m_fCurrentControlValue = 0; + m_fEk_1 = 0; + m_fEk_2 = 0; + + m_fOldTime = Time::getTime(); + m_nCalculations = 0; + } + + + void PIDController::validate() + { + double fCurrentTime = Time::getTime(); + double fElapsedTime = fCurrentTime - m_fOldTime; + m_fOldTime = fCurrentTime; + + double fEk = m_fSetPoint - m_fProcessValue; + + double fPk = m_fKp*(fEk - m_fEk_1); + double fIk = m_fKi*fEk*fElapsedTime; + double fDk = 0; + if (m_nCalculations < 2) + ++m_nCalculations; + else + fDk = m_fKd*(fEk - 2*m_fEk_1 + m_fEk_2)/fElapsedTime; + + m_fCurrentControlValue += fPk + fIk + fDk; + + m_fEk_2 = m_fEk_1; + m_fEk_1 = fEk; + } + +} //namespace ARSTD diff --git a/ARSTD/ARSTD/Misc/PIDController.h b/ARSTD/ARSTD/Misc/PIDController.h new file mode 100644 index 00000000..017f2974 --- /dev/null +++ b/ARSTD/ARSTD/Misc/PIDController.h @@ -0,0 +1,40 @@ +// Copyright (c) 2005-2022 Andreas Rose. All rights reserved. +// Released under the MIT license. (see license.txt) + + +#pragma once + +namespace ARSTD +{ + + class PIDController + { + public: + PIDController(double fKp, double fKi, double fKd); + ~PIDController(); + + void setup(double fSetPoint); + + void setNewProcessValue(double fPV); + + double getControlValue() const; + + protected: + void initialize(double fKp, double fKi, double fKd); + void validate(); + + double m_fKp; + double m_fKi; + double m_fKd; + + double m_fSetPoint; + double m_fProcessValue; + double m_fCurrentControlValue; + double m_fEk_1; + double m_fEk_2; + + double m_fOldTime; + int m_nCalculations; + }; + +} //namespace ARSTD diff --git a/ARSTD/ARSTD/Misc/Time.cpp b/ARSTD/ARSTD/Misc/Time.cpp new file mode 100644 index 00000000..f52c3044 --- /dev/null +++ b/ARSTD/ARSTD/Misc/Time.cpp @@ -0,0 +1,125 @@ +// Copyright (c) 2005-2022 Andreas Rose. All rights reserved. +// Released under the MIT license. (see license.txt) + + +#include +#include +#include + +#include "Time.h" + +namespace ARSTD +{ + + Time::PtrType Time::m_pInstance; + + + void Time::setTimeRatio(double fRatio) + { + initialize(); + + if (m_pInstance->m_Mode == MANUAL) + return; + + LARGE_INTEGER currentCount; + QueryPerformanceCounter(¤tCount); + m_pInstance->m_fElapsedTimeBeforeChangeTimeRatio += (currentCount.QuadPart - m_pInstance->m_StartCount.QuadPart)*m_pInstance->m_fCurrentTimeRatio/ + m_pInstance->m_PerformanceFrequency.QuadPart; + m_pInstance->m_StartCount = currentCount; + m_pInstance->m_fCurrentTimeRatio = fRatio; + } + + + double Time::getTimeRatio() + { + initialize(); + return m_pInstance->m_fCurrentTimeRatio; + } + + + double Time::getTime() + { + initialize(); + + if (m_pInstance->m_Mode == MANUAL) + return m_pInstance->m_fManualTime; + + LARGE_INTEGER currentCount; + QueryPerformanceCounter(¤tCount); + return m_pInstance->m_fElapsedTimeBeforeChangeTimeRatio + (currentCount.QuadPart - m_pInstance->m_StartCount.QuadPart)*m_pInstance->m_fCurrentTimeRatio/ + m_pInstance->m_PerformanceFrequency.QuadPart; + } + + + double Time::getRealTime() + { + initialize(); + + LARGE_INTEGER currentCount; + QueryPerformanceCounter(¤tCount); + return static_cast(currentCount.QuadPart - m_pInstance->m_RealStartCount.QuadPart)/m_pInstance->m_PerformanceFrequency.QuadPart; + } + + + void Time::step(double fDeltaTime) + { + initialize(); + + if (m_pInstance->m_Mode != MANUAL) + return; + + m_pInstance->m_fManualTime += fDeltaTime; + } + + + void Time::setTime(double fTime) + { + initialize(); + + if (m_pInstance->m_Mode == MANUAL) + return; + + m_pInstance->m_fElapsedTimeBeforeChangeTimeRatio = fTime; + } + + + void Time::reset(Mode mode, double fTime) + { + initialize(); + + m_pInstance->resetLocal(mode, fTime); + } + + + Time::Time(double fRatio) + : m_fTimeRatio(fRatio), + m_Mode(AUTOMATIC) + { + bool bResult = static_cast(QueryPerformanceCounter(&m_RealStartCount)); + bResult &= static_cast(QueryPerformanceFrequency(&m_PerformanceFrequency)); + if (!bResult) + throw std::runtime_error("High performance counter in not supported!"); + + resetLocal(AUTOMATIC, 0); + } + + + void Time::initialize() + { + if (!m_pInstance) + m_pInstance = Time::PtrType(new Time()); + } + + + void Time::resetLocal(Mode mode, double fTime) + { + m_Mode = mode; + m_fManualTime = 0; + m_fCurrentTimeRatio = m_fTimeRatio; + m_fElapsedTimeBeforeChangeTimeRatio = fTime; + + QueryPerformanceCounter(&m_StartCount); + } + + +} //namespace ARSTD \ No newline at end of file diff --git a/ARSTD/ARSTD/Misc/Time.h b/ARSTD/ARSTD/Misc/Time.h new file mode 100644 index 00000000..5f0e83c6 --- /dev/null +++ b/ARSTD/ARSTD/Misc/Time.h @@ -0,0 +1,54 @@ +// Copyright (c) 2005-2022 Andreas Rose. All rights reserved. +// Released under the MIT license. (see license.txt) + + +#pragma once + +#include +#include + +namespace ARSTD +{ + + class Time + { + public: + typedef std::shared_ptr