trying to find a consistent and C++1x styled graph representation

This commit is contained in:
Hartmut Seichter 2019-01-05 10:13:16 +01:00
parent f6c7f1adbb
commit 2e151b87c6
13 changed files with 528 additions and 31 deletions

View file

@ -5,6 +5,6 @@ cmake_minimum_required(VERSION 3.8)
project(pixwerx)
set (CMAKE_CXX_STANDARD 14)
set (CMAKE_CXX_STANDARD 17)
add_subdirectory(src)

View file

@ -0,0 +1,164 @@
/*
* Copyright (C) 1999-2017 Hartmut Seichter
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#ifndef PW_CORE_LOG_HPP_
#define PW_CORE_LOG_HPP_
#include <pw/core/globals.hpp>
#include <vector>
#include <functional>
namespace pw {
class Log;
/**
* @brief the streaming interface for the logger
*/
class LogStream {
public:
LogStream(Log* log = nullptr);
~LogStream();
LogStream(const LogStream& other);
LogStream &operator << (const bool &value);
LogStream &operator << (const char *value);
LogStream& operator << (const std::string& value); ///! log a string
LogStream& operator << (const float &value); ///! log a float value
LogStream& operator << (const double &value); ///! log a double value
LogStream& operator << (const int &value); ///! log a int value
LogStream& operator << (const unsigned int &value); ///! log a int value
LogStream& operator << (const long &value); ///! log a long value
LogStream& operator << (const unsigned long &value); ///! log a int value
LogStream& operator << (const void *value); ///! pointer
protected:
Log* _log;
std::string _line;
};
/**
* @brief multipurpose logger used internally
*/
class Log {
public:
enum LogLevel {
kNone, //!< nothing will be logged, even no errors
kError, //!< only errors will be logged
kWarning, //!< log warnings (non-critical errors)
kMessage, //!< log messages (something to note but not an error)
kNotify, //!< log some more information
kInfo, //!< log verbose information
kAll = 0xFF //!< log absolutely everything
};
/** sets the logging level */
void setLevel(LogLevel level) {_level = level;}
/** gets the logging level */
LogLevel level() const { return _level; }
/**
* @brief get the stream interface of the logger
* @return return a temporary object that will write and flush the logger
*/
static LogStream s(LogLevel level = kInfo);
inline static LogStream d() { return s(Log::kInfo); }
inline static LogStream e() { return s(Log::kError); }
inline static LogStream w() { return s(Log::kWarning); }
/**
* @brief returns the instance of the logger
* @return
*/
static Log& get();
/**
* @brief write a message to the log
* @param message string
*/
void write(const std::string &message);
typedef std::function<void(const char*)> Callback;
typedef std::vector<Callback> CallbackList;
protected:
Log();
~Log();
CallbackList _callbacks;
LogLevel _level;
};
/**
* @brief helper for changing the log level in a scope
*/
struct ScopeLogLevel
{
Log::LogLevel levelOutside;
explicit ScopeLogLevel(Log::LogLevel level)
{
levelOutside = Log::get().level();
Log::get().setLevel(level);
}
~ScopeLogLevel()
{
Log::get().setLevel(levelOutside);
}
};
template <Log::LogLevel level>
struct tpScopeLog {
const char* info;
explicit tpScopeLog(const char* i) : info(i) {
Log::s(level) << info;
}
~tpScopeLog() {
Log::s(level) << info;
}
};
// some macros
#define LOG_INFO() Log::s()
#define LOG_FUNC() LOG_INFO() << __FUNCTION__ << " " << __LINE__ << " "
}
#endif

View file

@ -0,0 +1,57 @@
/* vim: set tabstop=4:softtabstop=4:shiftwidth=4:noexpandtab */
/*
* SSTT - Simplified Spatial Target Tracker
*
* (c) Copyrights 2007-2018 Hartmut Seichter
*/
#ifndef PW_CORE_TIMER_HPP_
#define PW_CORE_TIMER_HPP_
#include <pw/core/globals.hpp>
#include <chrono>
namespace pw {
/**
* @brief A simple timer
*/
class timer {
public:
const static unsigned int UnitMicroSeconds = 1000000;
const static unsigned int UnitMilliSeconds = 1000;
const static unsigned int UnitSeconds = 1;
typedef std::chrono::time_point<std::chrono::high_resolution_clock> tick_t;
timer(); /// c'tor
~timer(); /// d'tor
void reset(); /// reset the timer
/**
* @brief elapsed time based on the scale
* @param scale units the time will be reported
* @return value of the time since last @see reset
*/
double elapsed(unsigned int scale = UnitMilliSeconds) const;
/**
* @brief Now
* @param scale
* @return
*/
static double now(unsigned int scale = UnitMicroSeconds);
protected:
tick_t _start;
};
}
#endif

204
src/core/src/log.cpp Normal file
View file

@ -0,0 +1,204 @@
/* vim: set tabstop=4:softtabstop=4:shiftwidth=4:noexpandtab */
/*
* SSTT - Simplified Spatial Target Tracker
*
* (c) Copyrights 2007-2018 Hartmut Seichter
*/
#include "pw/core/log.hpp"
#include <cstdarg>
#include <cstdio>
#include <sstream>
#include <thread>
namespace pw {
#if defined(ANDROID)
#include <android/log.h>
struct tpConsoleLog : tpLogCallback
{
void operator()(const char* cstr)
{
__android_log_print(ANDROID_LOG_INFO, "libsstt", "%s", cstr);
}
};
#else
struct tpConsoleLog
{
void operator()(const char* cstr) const
{
::fputs(cstr,stdout);
::fflush(stdout);
}
};
#endif
struct tpFileLog {
FILE* m_file;
tpFileLog() : m_file(fopen("libsstt.txt","a+"))
{
}
~tpFileLog()
{
if (m_file != nullptr) fclose(m_file);
}
void operator()(const char* stuff) {
if (m_file) ::fputs(stuff,m_file);
}
};
Log::Log() :
_level(Log::kNotify)
{
#if defined(_WINCE)
_callbacks.add(new tpFileLog());
#else
_callbacks.push_back(tpConsoleLog());
#endif
// drop some info
LogStream stream(this);
// stream << "SSTT " << versionString(kVersionFull) << " " << std::thread::hardware_concurrency() << " threads";
}
Log::~Log()
{
}
void Log::write(const std::string& message)
{
for (CallbackList::iterator i = _callbacks.begin();
i != _callbacks.end();
++i)
{
if (message.length()) (*i)(message.c_str());
}
}
/* static */
LogStream Log::s(Log::LogLevel level) {
return LogStream(&Log::get());
}
Log &Log::get() {
static Log the_log;
return the_log;
}
//
// tpLogStream
//
LogStream::LogStream(Log *log)
: _log(log)
{
// _line.append(std::to_string(Timer::now(Timer::UnitSeconds)) + " ");
}
LogStream::~LogStream()
{
_log->write(_line + "\n");
}
LogStream::LogStream(const LogStream &other)
: _log(other._log)
, _line(other._line)
{
}
LogStream &LogStream::operator <<(const bool &value)
{
_line.append(value ? "true" : "false");
return *this;
}
LogStream &LogStream::operator <<(const char* value)
{
_line.append(value);
return *this;
}
LogStream &LogStream::operator <<(const std::string &value)
{
_line.append(value);
return *this;
}
LogStream &LogStream::operator <<(const float &value)
{
std::stringstream ss;
ss << value;
(*this) << ss.str();
return *this;
}
LogStream &LogStream::operator <<(const double &value)
{
std::stringstream ss;
ss << value;
(*this) << ss.str();
return *this;
}
LogStream &LogStream::operator <<(const int &value)
{
std::stringstream ss;
ss << value;
(*this) << ss.str();
return *this;
}
LogStream &LogStream::operator <<(const unsigned int &value)
{
std::stringstream ss;
ss << value;
(*this) << ss.str();
return *this;
}
LogStream &LogStream::operator <<(const long &value)
{
std::stringstream ss;
ss << value;
(*this) << ss.str();
return *this;
}
LogStream &LogStream::operator <<(const unsigned long &value)
{
std::stringstream ss;
ss << value;
(*this) << ss.str();
return *this;
}
LogStream &LogStream::operator <<(const void *value)
{
std::stringstream ss;
ss << value;
(*this) << ss.str();
return *this;
}
}

41
src/core/src/timer.cpp Normal file
View file

@ -0,0 +1,41 @@
/* vim: set tabstop=4:softtabstop=4:shiftwidth=4:noexpandtab */
/*
* SSTT - Simplified Spatial Target Tracker
*
* (c) Copyrights 2007-2018 Hartmut Seichter
*/
#include "pw/core/timer.hpp"
namespace pw {
static timer global_timer;
timer::timer()
{
reset();
}
timer::~timer()
{
}
void timer::reset()
{
_start = std::chrono::high_resolution_clock::now();
}
double timer::elapsed( unsigned int scale ) const
{
std::chrono::duration<double> elapsed_seconds = std::chrono::high_resolution_clock::now() - _start;
return elapsed_seconds.count() * scale;
}
double timer::now( unsigned int scale )
{
return global_timer.elapsed(scale);
}
}

View file

@ -31,6 +31,8 @@
namespace pw {
class transform;
/**
* @brief nodes represent the structure for the scene graph
*
@ -50,16 +52,16 @@ public:
friend class component;
//! standard c'tor
node(const std::string& name = "");
node();
//! copy c'tor
node(const node& node);
//! d'tor
virtual ~node();
~node();
//! cloning interface
virtual ref clone(const unsigned short& copymode) const;
ref clone(const unsigned short& copymode) const;
std::string name() const; //!< get name
void set_name(const std::string &name); //!< set name
@ -68,7 +70,7 @@ public:
inline ptr parent() const { return _path.back(); }
//! add a child node
ref add_child(ref anode);
ref add_child();
//! remove a child
void remove_child(ref child_node);
@ -89,7 +91,7 @@ public:
const component::array& components() const;
//! add a node component
void add_component(component::ref c);
void add_component(component::ref new_component);
//! remove a node component
void remove_component(component::ref c);
@ -111,6 +113,10 @@ public:
}
const transform* transform() const { return _transform; }
class transform* transform() { return _transform; }
protected:
ref_array _children; //!< list of children
@ -118,6 +124,8 @@ protected:
component::array _components; //<! components
class transform* _transform;
std::string _name;
// change mask

View file

@ -9,6 +9,8 @@ namespace pw {
class transform : public component {
public:
transform() = default;
using component::component;
using component::ref;

View file

@ -1,14 +1,19 @@
#include "pw/scene/node.hpp"
#include "pw/scene/transform.hpp"
#include <iostream>
namespace pw {
node::node(const std::string &name)
: _name(name)
node::node()
{
// generate node-name from cache generate
// add_component(std::make_shared<transform>());
}
node::node(const node &node)
: _children(node.children())
, _components(node.components())
, _name(node._name)
{
}
@ -28,21 +33,22 @@ void node::set_name(const std::string &name)
_name = name;
}
node::ref node::add_child(ref anode)
node::ref node::add_child()
{
// remove old nodepath
anode->_path.clear();
// create new node
node::ref new_node = std::make_shared<node>();
// take parent nodepath ...
if (!this->is_root()) anode->_path = this->_path;
if (!this->is_root()) new_node->_path = this->_path;
// add itself
anode->_path.push_back(this);
new_node->_path.push_back(this);
// add as child
_children.push_back(anode);
_children.push_back(new_node);
// return
return anode;
return new_node;
}
void node::remove_child(ref child_node)
@ -62,9 +68,19 @@ node::~node()
//
// components
//
void node::add_component(component::ref c)
void node::add_component(component::ref new_component)
{
_components.push_back(c);
if (new_component->singular()) {
for (auto c : _components) {
if (typeid(c.get()) == typeid (new_component.get())) {
// warn and/or override?
c = new_component;
std::cout << "Meh!" << std::endl;
return;
}
}
}
_components.push_back(new_component);
}
void node::remove_component(component::ref c)

View file

@ -1,12 +1,17 @@
#include "pw/scene/transform.hpp"
#include "pw/scene/node.hpp"
namespace pw {
void transform::set_local(const matrix44 &local)
{
// TODO need to rebuild the transforms: both -> global down and global up
_local = local;
// update the global transform
if (_node && _node->parent() && _node->parent()->find<transform>()) {
// this->_global = _node->find<transform>()->_global * _local;
}
}
void transform::set_global(const matrix44 &global)

View file

@ -22,11 +22,12 @@ int main(int argc,char **argv) {
using namespace pw;
node::ref n(new node("test"));
node::ref n = std::make_shared<node>();
n->set_name("root");
// check
{
n->add_child(std::make_shared<node>("sub"));
n->add_child()->set_name("node");
}
std::cout << "n name: " << n->name() << std::endl;
@ -49,7 +50,7 @@ int main(int argc,char **argv) {
print_node_path((n));
auto t = n->find<transform>();
auto t = n->transform();
if (t) std::cout << t->local().at(0,0) << std::endl;

View file

@ -40,13 +40,14 @@ int main(int argc,char **argv) {
using namespace pw;
node::ref root(std::make_shared<node>("root"));
root->add_child(std::make_shared<node>("sub-1"));
node::ref root(std::make_shared<node>());
root->set_name("root");
root->add_child()->set_name("sub-1");
node::ref sub_2_1 = std::make_shared<node>("sub-2-1");
// node::ref sub_2_1 = std::make_shared<node>("sub-2-1");
root->add_child(std::make_shared<node>("sub-3"))->add_child(sub_2_1);
root->add_child(std::make_shared<node>("sub-2"))->add_child(std::make_shared<node>("sub-2-2"));
// root->add_child(std::make_shared<node>("sub-3"))->add_child(sub_2_1);
// root->add_child(std::make_shared<node>("sub-2"))->add_child(std::make_shared<node>("sub-2-2"));
// std::cout << "sub-2-1 parent count: " << sub_2_1->parents().size() << std::endl;

View file

@ -8,7 +8,7 @@ void script_scene::load(sol::table &ns)
{
ns.new_usertype<node>("node",
sol::constructors<node(), node(std::string)>(),
sol::constructors<node()>(),
"add_child",&node::add_child,
"children",sol::readonly_property(&node::children),
"child_count",sol::readonly_property(&node::child_count),

View file

@ -39,12 +39,10 @@ local aa = pw.axisangle.new(v1,0.707)
print("aa.axis",aa.axis.x,aa.axis.y,aa.axis.z)
print("aa.angle",aa.angle)
local n_1 = pw.node.new("node-1")
local n_2 = pw.node.new("node-2")
local n_1 = pw.node.create()
n_1.name = "root"
print("node 1: ", n_1.name)
print("node 2: ", n_2.name)
--print(pw.node.create())