<commit_before>/*
**  Copyright (C) 2012 Aldebaran Robotics
**  See COPYING for the license
*/
#include "remoteobject_p.hpp"
#include "object_p.hpp"
#include "metasignal_p.hpp"
#include <qimessaging/message.hpp>
#include <qimessaging/transportsocket.hpp>
#include <qi/log.hpp>
#include <boost/thread/mutex.hpp>
#include "metaobject_p.hpp"

namespace qi {

  static qi::MetaObject &createRemoteObjectSpecialMetaObject() {
    static qi::MetaObject *mo = 0;

    if (!mo) {
      mo = new qi::MetaObject;
      mo->_p->addMethod("I", "registerEvent::(III)");
      mo->_p->addMethod("v", "unregisterEvent::(III)");
      mo->_p->addMethod("({I(ssI)}{I(sI)})", "metaObject::(I)");

      assert(mo->methodId("registerEvent::(III)") == qi::Message::BoundObjectFunction_RegisterEvent);
      assert(mo->methodId("unregisterEvent::(III)") == qi::Message::BoundObjectFunction_UnregisterEvent);
      assert(mo->methodId("metaObject::(I)") == qi::Message::BoundObjectFunction_MetaObject);
    }
    return *mo;
  }

  RemoteObject::RemoteObject(unsigned int service, qi::TransportSocketPtr socket)
    : _socket()
    , _service(service)
    , _linkMessageDispatcher(0)
    , _self(makeDynamicObjectPtr(this))
  {
    //simple metaObject with only special methods. (<10)
    setMetaObject(createRemoteObjectSpecialMetaObject());
    setTransportSocket(socket);
    //init should be called to makesure the metaObject is valid.
  }

  RemoteObject::RemoteObject(unsigned int service, qi::MetaObject metaObject, TransportSocketPtr socket)
    : _socket(socket)
    , _service(service)
    , _linkMessageDispatcher(0)
    , _self(makeDynamicObjectPtr(this))
  {
    setMetaObject(metaObject);
    setTransportSocket(socket);
  }

  RemoteObject::~RemoteObject()
  {
    //close may already have been called. (by Session_Service.close)
    close();
  }

  //### RemoteObject

  void RemoteObject::setTransportSocket(qi::TransportSocketPtr socket) {
    if (socket == _socket)
      return;
    if (_socket)
      _socket->messagePendingDisconnect(_service, _linkMessageDispatcher);
    _socket = socket;
    //do not set the socket on the remote object
    if (socket)
      _linkMessageDispatcher = _socket->messagePendingConnect(_service, boost::bind<void>(&RemoteObject::onMessagePending, this, _1));
  }

  void RemoteObject::onMetaObject(qi::Future<qi::MetaObject> fut, qi::Promise<void> prom) {
    if (fut.hasError()) {
      prom.setError(fut.error());
      return;
    }
    setMetaObject(fut.value());
    prom.setValue(0);
  }

  //retrieve the metaObject from the network
  qi::Future<void> RemoteObject::fetchMetaObject() {
    qi::Promise<void> prom;
    qi::Future<qi::MetaObject> fut = _self->call<qi::MetaObject>("metaObject", 0U);
    fut.connect(boost::bind<void>(&RemoteObject::onMetaObject, this, _1, prom));
    return prom.future();
  }

  void RemoteObject::onMessagePending(const qi::Message &msg)
  {
    qi::Promise<GenericValue> promise;
    bool found = false;
    std::map<int, qi::Promise<GenericValue> >::iterator it;

    qiLogDebug("RemoteObject") << this << " msg " << msg.type() << " " << msg.buffer().size();
    {
      boost::mutex::scoped_lock lock(_mutex);
      it = _promises.find(msg.id());
      if (it != _promises.end()) {
        promise = _promises[msg.id()];
        _promises.erase(it);
        found = true;
      }
    }

    switch (msg.type()) {
      case qi::Message::Type_Reply:
      {
        if (!found) {
          qiLogError("remoteobject") << "no promise found for req id:" << msg.id()
          << "  obj: " << msg.service() << "  func: " << msg.function();
          return;
        }
        // Get call signature
        MetaMethod* mm =  metaObject().method(msg.function());
        if (!mm)
        {
          qiLogError("remoteobject") << "Result for unknown function "
           << msg.function();
           promise.setError("Result for unknown function");
           return;
        }
        Type* type = Type::fromSignature(mm->sigreturn());
        if (!type)
        {
          promise.setError("Unable to find a type for signature " + mm->sigreturn());
          return;
        }
        IDataStream in(msg.buffer());
        promise.setValue(type->deserialize(in));
        return;
      }
      case qi::Message::Type_Error: {
        qi::IDataStream ds(msg.buffer());
        std::string    err;
        std::string    sig;
        ds >> sig;
        if (sig != "s") {
          qiLogError("qi.RemoteObject") << "Invalid error signature: " << sig;
          //houston we have an error about the error..
          promise.setError("unknown error");
          return;
        }
        ds >> err;
        qiLogVerbose("remoteobject") << "Received error message"  << msg.address() << ":" << err;
        promise.setError(err);
        return;
      }
      case qi::Message::Type_Event: {
        SignalBase* sb = signalBase(msg.event());
        if (sb)
        {
          try {
            std::string sig = sb->signature();
            sig = signatureSplit(sig)[2];
            sig = sig.substr(1, sig.length()-2);
            GenericFunctionParameters args
              = GenericFunctionParameters::fromBuffer(sig, msg.buffer());
            sb->trigger(args);
            args.destroy();
          }
          catch (const std::exception& e)
          {
            qiLogWarning("remoteobject") << "Deserialize error on event: " << e.what();
          }
        }
        else
        {
          qiLogWarning("remoteobject") << "Event message on unknown signal " << msg.event();
          qiLogDebug("remoteobject") << metaObject().signalMap().size();
        }
        return;
      }
      default:
        qiLogError("remoteobject") << "Message " << msg.address() << " type not handled: " << msg.type();
        return;
    }
  }

  qi::Future<GenericValue> RemoteObject::metaCall(unsigned int method, const qi::GenericFunctionParameters &in, MetaCallType callType)
  {
    qi::Promise<GenericValue> out;
    qi::Message msg;
    msg.setBuffer(in.toBuffer());
#ifndef NDEBUG
    std::string sig = metaObject().method(method)->signature();
    sig = signatureSplit(sig)[2];
    // Remove extra tuple layer
    sig = sig.substr(1, sig.length()-2);
    if (sig != msg.buffer().signature())
    {
      qiLogError("remoteobject") << "call signature mismatch "
        << sig << ' '
        << msg.buffer().signature();
    }
#endif
    msg.setType(qi::Message::Type_Call);
    msg.setService(_service);
    msg.setObject(qi::Message::GenericObject_Main);
    msg.setFunction(method);
    qiLogDebug("remoteobject") << this << " metacall " << msg.service() << " "
     << msg.function() <<" " << msg.id();
    {
      boost::mutex::scoped_lock lock(_mutex);
      if (_promises.find(msg.id()) != _promises.end())
      {
        qiLogError("remoteobject") << "There is already a pending promise with id "
                                   << msg.id();
      }
      _promises[msg.id()] = out;
    }

    //error will come back as a error message
    if (!_socket || !_socket->isConnected() || !_socket->send(msg)) {
      qiLogError("remoteobject") << "error while sending answer";
      qi::MetaMethod*   meth = metaObject().method(method);
      std::stringstream ss;
      if (meth) {
        ss << "Network error while sending data to method: '";
        ss << meth->signature();;
        ss << "'";
      } else {
        ss << "Network error while sending data an unknown method (id=" << method << ")";
      }
      out.setError(ss.str());

      {
        boost::mutex::scoped_lock lock(_mutex);
        _promises.erase(msg.id());
      }
    }
    return out.future();
  }

  void RemoteObject::metaEmit(unsigned int event, const qi::GenericFunctionParameters &args)
  {
    // Bounce the emit request to server
    // TODO: one optimisation that could be done is to trigger the local
    // subscribers immediately.
    // But it is a bit complex, because the server will bounce the
    // event back to us.
    qi::Message msg;
    msg.setBuffer(args.toBuffer());
    msg.setType(Message::Type_Event);
    msg.setService(_service);
    msg.setObject(qi::Message::GenericObject_Main);
    msg.setFunction(event);
    if (!_socket->send(msg)) {
      qiLogError("remoteobject") << "error while emiting event";
    }
  }

  qi::Future<unsigned int> RemoteObject::connect(unsigned int event, const SignalSubscriber& sub)
  {
    // Bind the subscriber locally.
    unsigned int uid = DynamicObject::connect(event, sub);

    qiLogDebug("remoteobject") <<"connect() to " << event <<" gave " << uid;
    return _self->call<unsigned int>("registerEvent", _service, event, uid);
  }

  qi::Future<void> RemoteObject::disconnect(unsigned int linkId)
  {
    unsigned int event = linkId >> 16;
    //disconnect locally
    bool ok = DynamicObject::disconnect(linkId);
    if (!ok)
    {
      std::stringstream ss;
      ss << "Disconnection failure for " << linkId;
      qiLogWarning("qi.object") << ss.str();
      return qi::makeFutureError<void>(ss.str());
    }
    return _self->call<void>("unregisterEvent", _service, event, linkId);
  }

  void RemoteObject::close() {
    if (_socket)
      _socket->messagePendingDisconnect(_service, _linkMessageDispatcher);
  }

}
<commit_msg>remoteobject: better log on error<commit_after>/*
**  Copyright (C) 2012 Aldebaran Robotics
**  See COPYING for the license
*/
#include "remoteobject_p.hpp"
#include "object_p.hpp"
#include "metasignal_p.hpp"
#include <qimessaging/message.hpp>
#include <qimessaging/transportsocket.hpp>
#include <qi/log.hpp>
#include <boost/thread/mutex.hpp>
#include "metaobject_p.hpp"

namespace qi {

  static qi::MetaObject &createRemoteObjectSpecialMetaObject() {
    static qi::MetaObject *mo = 0;

    if (!mo) {
      mo = new qi::MetaObject;
      mo->_p->addMethod("I", "registerEvent::(III)");
      mo->_p->addMethod("v", "unregisterEvent::(III)");
      mo->_p->addMethod("({I(ssI)}{I(sI)})", "metaObject::(I)");

      assert(mo->methodId("registerEvent::(III)") == qi::Message::BoundObjectFunction_RegisterEvent);
      assert(mo->methodId("unregisterEvent::(III)") == qi::Message::BoundObjectFunction_UnregisterEvent);
      assert(mo->methodId("metaObject::(I)") == qi::Message::BoundObjectFunction_MetaObject);
    }
    return *mo;
  }

  RemoteObject::RemoteObject(unsigned int service, qi::TransportSocketPtr socket)
    : _socket()
    , _service(service)
    , _linkMessageDispatcher(0)
    , _self(makeDynamicObjectPtr(this))
  {
    //simple metaObject with only special methods. (<10)
    setMetaObject(createRemoteObjectSpecialMetaObject());
    setTransportSocket(socket);
    //init should be called to makesure the metaObject is valid.
  }

  RemoteObject::RemoteObject(unsigned int service, qi::MetaObject metaObject, TransportSocketPtr socket)
    : _socket(socket)
    , _service(service)
    , _linkMessageDispatcher(0)
    , _self(makeDynamicObjectPtr(this))
  {
    setMetaObject(metaObject);
    setTransportSocket(socket);
  }

  RemoteObject::~RemoteObject()
  {
    //close may already have been called. (by Session_Service.close)
    close();
  }

  //### RemoteObject

  void RemoteObject::setTransportSocket(qi::TransportSocketPtr socket) {
    if (socket == _socket)
      return;
    if (_socket)
      _socket->messagePendingDisconnect(_service, _linkMessageDispatcher);
    _socket = socket;
    //do not set the socket on the remote object
    if (socket)
      _linkMessageDispatcher = _socket->messagePendingConnect(_service, boost::bind<void>(&RemoteObject::onMessagePending, this, _1));
  }

  void RemoteObject::onMetaObject(qi::Future<qi::MetaObject> fut, qi::Promise<void> prom) {
    if (fut.hasError()) {
      prom.setError(fut.error());
      return;
    }
    setMetaObject(fut.value());
    prom.setValue(0);
  }

  //retrieve the metaObject from the network
  qi::Future<void> RemoteObject::fetchMetaObject() {
    qi::Promise<void> prom;
    qi::Future<qi::MetaObject> fut = _self->call<qi::MetaObject>("metaObject", 0U);
    fut.connect(boost::bind<void>(&RemoteObject::onMetaObject, this, _1, prom));
    return prom.future();
  }

  void RemoteObject::onMessagePending(const qi::Message &msg)
  {
    qi::Promise<GenericValue> promise;
    bool found = false;
    std::map<int, qi::Promise<GenericValue> >::iterator it;

    qiLogDebug("RemoteObject") << this << " msg " << msg.type() << " " << msg.buffer().size();
    {
      boost::mutex::scoped_lock lock(_mutex);
      it = _promises.find(msg.id());
      if (it != _promises.end()) {
        promise = _promises[msg.id()];
        _promises.erase(it);
        found = true;
      }
    }

    switch (msg.type()) {
      case qi::Message::Type_Reply:
      {
        if (!found) {
          qiLogError("remoteobject") << "no promise found for req id:" << msg.id()
          << "  obj: " << msg.service() << "  func: " << msg.function();
          return;
        }
        // Get call signature
        MetaMethod* mm =  metaObject().method(msg.function());
        if (!mm)
        {
          qiLogError("remoteobject") << "Result for unknown function "
           << msg.function();
           promise.setError("Result for unknown function");
           return;
        }
        Type* type = Type::fromSignature(mm->sigreturn());
        if (!type)
        {
          promise.setError("Unable to find a type for signature " + mm->sigreturn());
          return;
        }
        IDataStream in(msg.buffer());
        promise.setValue(type->deserialize(in));
        return;
      }
      case qi::Message::Type_Error: {
        qi::IDataStream ds(msg.buffer());
        std::string    err;
        std::string    sig;
        ds >> sig;
        if (sig != "s") {
          qiLogError("qi.RemoteObject") << "Invalid error signature: " << sig;
          //houston we have an error about the error..
          promise.setError("unknown error");
          return;
        }
        ds >> err;
        qiLogVerbose("remoteobject") << "Received error message"  << msg.address() << ":" << err;
        promise.setError(err);
        return;
      }
      case qi::Message::Type_Event: {
        SignalBase* sb = signalBase(msg.event());
        if (sb)
        {
          try {
            std::string sig = sb->signature();
            sig = signatureSplit(sig)[2];
            sig = sig.substr(1, sig.length()-2);
            GenericFunctionParameters args
              = GenericFunctionParameters::fromBuffer(sig, msg.buffer());
            sb->trigger(args);
            args.destroy();
          }
          catch (const std::exception& e)
          {
            qiLogWarning("remoteobject") << "Deserialize error on event: " << e.what();
          }
        }
        else
        {
          qiLogWarning("remoteobject") << "Event message on unknown signal " << msg.event();
          qiLogDebug("remoteobject") << metaObject().signalMap().size();
        }
        return;
      }
      default:
        qiLogError("remoteobject") << "Message " << msg.address() << " type not handled: " << msg.type();
        return;
    }
  }

  qi::Future<GenericValue> RemoteObject::metaCall(unsigned int method, const qi::GenericFunctionParameters &in, MetaCallType callType)
  {
    qi::Promise<GenericValue> out;
    qi::Message msg;
    msg.setBuffer(in.toBuffer());
#ifndef NDEBUG
    std::string sig = metaObject().method(method)->signature();
    sig = signatureSplit(sig)[2];
    // Remove extra tuple layer
    sig = sig.substr(1, sig.length()-2);
    if (sig != msg.buffer().signature())
    {
      qiLogError("remoteobject") << "call signature mismatch "
        << sig << ' '
        << msg.buffer().signature();
    }
#endif
    msg.setType(qi::Message::Type_Call);
    msg.setService(_service);
    msg.setObject(qi::Message::GenericObject_Main);
    msg.setFunction(method);
    qiLogDebug("remoteobject") << this << " metacall " << msg.service() << " "
     << msg.function() <<" " << msg.id();
    {
      boost::mutex::scoped_lock lock(_mutex);
      if (_promises.find(msg.id()) != _promises.end())
      {
        qiLogError("remoteobject") << "There is already a pending promise with id "
                                   << msg.id();
      }
      _promises[msg.id()] = out;
    }

    //error will come back as a error message
    if (!_socket || !_socket->isConnected() || !_socket->send(msg)) {
      qi::MetaMethod*   meth = metaObject().method(method);
      std::stringstream ss;
      if (meth) {
        ss << "Network error while sending data to method: '";
        ss << meth->signature();;
        ss << "'.";
      } else {
        ss << "Network error while sending data an unknown method (id=" << method << ").";
      }
      if (!_socket->isConnected())
        ss << " Socket is not connected.";
      qiLogError("remoteobject") << ss.str();
      out.setError(ss.str());

      {
        boost::mutex::scoped_lock lock(_mutex);
        _promises.erase(msg.id());
      }
    }
    return out.future();
  }

  void RemoteObject::metaEmit(unsigned int event, const qi::GenericFunctionParameters &args)
  {
    // Bounce the emit request to server
    // TODO: one optimisation that could be done is to trigger the local
    // subscribers immediately.
    // But it is a bit complex, because the server will bounce the
    // event back to us.
    qi::Message msg;
    msg.setBuffer(args.toBuffer());
    msg.setType(Message::Type_Event);
    msg.setService(_service);
    msg.setObject(qi::Message::GenericObject_Main);
    msg.setFunction(event);
    if (!_socket->send(msg)) {
      qiLogError("remoteobject") << "error while emiting event";
    }
  }

  qi::Future<unsigned int> RemoteObject::connect(unsigned int event, const SignalSubscriber& sub)
  {
    // Bind the subscriber locally.
    unsigned int uid = DynamicObject::connect(event, sub);

    qiLogDebug("remoteobject") <<"connect() to " << event <<" gave " << uid;
    return _self->call<unsigned int>("registerEvent", _service, event, uid);
  }

  qi::Future<void> RemoteObject::disconnect(unsigned int linkId)
  {
    unsigned int event = linkId >> 16;
    //disconnect locally
    bool ok = DynamicObject::disconnect(linkId);
    if (!ok)
    {
      std::stringstream ss;
      ss << "Disconnection failure for " << linkId;
      qiLogWarning("qi.object") << ss.str();
      return qi::makeFutureError<void>(ss.str());
    }
    return _self->call<void>("unregisterEvent", _service, event, linkId);
  }

  void RemoteObject::close() {
    if (_socket)
      _socket->messagePendingDisconnect(_service, _linkMessageDispatcher);
  }

}
<|endoftext|>


<commit_before>/* +---------------------------------------------------------------------------+
   |                     Mobile Robot Programming Toolkit (MRPT)               |
   |                          http://www.mrpt.org/                             |
   |                                                                           |
   | Copyright (c) 2005-2017, Individual contributors, see AUTHORS file        |
   | See: http://www.mrpt.org/Authors - All rights reserved.                   |
   | Released under BSD License. See details in http://www.mrpt.org/License    |
   +---------------------------------------------------------------------------+
   */

#include "../include/mrpt/gui/error_box.h"
#if MRPT_HAS_Qt5
#include <QErrorMessage>
#include <QString>
#else
#include <iostream>
#endif  // MRPT_HAS_Qt5

void GUI_IMPEXP mrpt::gui::tryCatch(
	const std::function<void()>& tryPart, const std::string& catchMessage)
{
	try
	{
		tryPart();
	}
	catch (std::exception& e)
	{
		showErrorMessage(catchMessage + e.what());
	}
	catch (...)
	{
		showErrorMessage("Untyped exception!");
	}
}

void GUI_IMPEXP mrpt::gui::showErrorMessage(const std::string& str)
{
#if MRPT_HAS_Qt5
	QErrorMessage msg;
	msg.showMessage(QString::fromStdString(str));
	msg.exec();
#else
	std::cout << str << std::endl;
#endif  // MRPT_HAS_Qt5
}
<commit_msg>added wxDialog in showErrorMessage<commit_after>/* +---------------------------------------------------------------------------+
   |                     Mobile Robot Programming Toolkit (MRPT)               |
   |                          http://www.mrpt.org/                             |
   |                                                                           |
   | Copyright (c) 2005-2017, Individual contributors, see AUTHORS file        |
   | See: http://www.mrpt.org/Authors - All rights reserved.                   |
   | Released under BSD License. See details in http://www.mrpt.org/License    |
   +---------------------------------------------------------------------------+
   */

#include "../include/mrpt/gui/error_box.h"
#if MRPT_HAS_Qt5
#include <QErrorMessage>
#include <QString>
#else
#include <iostream>
#endif  // MRPT_HAS_Qt5

void GUI_IMPEXP mrpt::gui::tryCatch(
	const std::function<void()>& tryPart, const std::string& catchMessage)
{
	try
	{
		tryPart();
	}
	catch (std::exception& e)
	{
		showErrorMessage(catchMessage + e.what());
	}
	catch (...)
	{
		showErrorMessage("Untyped exception!");
	}
}

void GUI_IMPEXP mrpt::gui::showErrorMessage(const std::string& str)
{
#if MRPT_HAS_Qt5
	QErrorMessage msg;
	msg.showMessage(QString::fromStdString(str));
	msg.exec();
#elif MRPT_HAS_WXWIDGETS
	wxMessageBox(_U(str), _("Exception"));
#else
	std::cout << str << std::endl;
#endif  // MRPT_HAS_Qt5
}
<|endoftext|>


<commit_before>#ifndef TRANSFORMWRITER_HPP_
#define TRANSFORMWRITER_HPP_

#include <sstream>
#include "boost/filesystem.hpp"

#include "CommandObserverBase.hpp"
#include "itkGradientDescentOptimizer.h"
#include "itkRegularStepGradientDescentOptimizer.h"

#include "Dirs.hpp"
#include "StackBase.hpp"
#include "IOHelpers.hpp"

using namespace std;
using namespace boost::filesystem;

class TransformWriter : public CommandObserverBase
{
public:
  typedef TransformWriter                  Self;
  typedef CommandObserverBase              Superclass;
  typedef itk::SmartPointer<Self>          Pointer;

  itkNewMacro( Self );

  virtual void Execute(const itk::Object * object, const itk::EventObject & event)
  {
    if( ! itk::IterationEvent().CheckEvent( &event ) )
      return;

    setCurrentIteration(object);

    saveTransform();
  }

  // setters
	void setStack(StackBase *stack) { m_stack = stack; }

	void setSliceNumber(unsigned int sliceNumber) { m_sliceNumber = sliceNumber; }

	protected:
    void setCurrentIteration(const itk::Object * object)
    {
      typedef itk::RegularStepGradientDescentOptimizer RSGD;
      typedef itk::GradientDescentOptimizer GD;

      // optimizer base class does not have GetCurrentIteration method,
      // so runtime check to extract current iteration
      if(const GD* gd = dynamic_cast< const GD* >( object ))
        m_currentIteration = gd->GetCurrentIteration();
      if(const RSGD * rsgd = dynamic_cast< const RSGD* >( object ))
        m_currentIteration = rsgd->GetCurrentIteration();
    }

    void saveTransform()
    {
      // construct paths
      string dirPath = Dirs::IntermediateTransformsDir() +
                       transformType() + "/" +
                       m_stack->GetBasename(m_sliceNumber) + "/";

      create_directories(dirPath);
      stringstream filePath;
      filePath << dirPath << m_currentIteration;

      // save transform
      writeTransform(m_stack->GetTransform(m_sliceNumber), filePath.str());
    }

    const char *transformType()
    {
      return m_stack->GetTransform(m_sliceNumber)->GetNameOfClass();
    }

  private:
    StackBase *m_stack;
    unsigned int m_sliceNumber;
    unsigned long m_currentIteration;

};
#endif
<commit_msg>Fixed width formatting of intermediate transform file names.<commit_after>#ifndef TRANSFORMWRITER_HPP_
#define TRANSFORMWRITER_HPP_

#include <sstream>
#include <iomanip>
#include "boost/filesystem.hpp"

#include "CommandObserverBase.hpp"
#include "itkGradientDescentOptimizer.h"
#include "itkRegularStepGradientDescentOptimizer.h"

#include "Dirs.hpp"
#include "StackBase.hpp"
#include "IOHelpers.hpp"

using namespace std;
using namespace boost::filesystem;

class TransformWriter : public CommandObserverBase
{
public:
  typedef TransformWriter                  Self;
  typedef CommandObserverBase              Superclass;
  typedef itk::SmartPointer<Self>          Pointer;

  itkNewMacro( Self );

  virtual void Execute(const itk::Object * object, const itk::EventObject & event)
  {
    if( ! itk::IterationEvent().CheckEvent( &event ) )
      return;

    setCurrentIteration(object);

    saveTransform();
  }

  // setters
	void setStack(StackBase *stack) { m_stack = stack; }

	void setSliceNumber(unsigned int sliceNumber) { m_sliceNumber = sliceNumber; }

	protected:
    void setCurrentIteration(const itk::Object * object)
    {
      typedef itk::RegularStepGradientDescentOptimizer RSGD;
      typedef itk::GradientDescentOptimizer GD;

      // optimizer base class does not have GetCurrentIteration method,
      // so runtime check to extract current iteration
      if(const GD* gd = dynamic_cast< const GD* >( object ))
        m_currentIteration = gd->GetCurrentIteration();
      if(const RSGD * rsgd = dynamic_cast< const RSGD* >( object ))
        m_currentIteration = rsgd->GetCurrentIteration();
    }

    void saveTransform()
    {
      // construct paths
      string dirPath = Dirs::IntermediateTransformsDir() +
                       transformType() + "/" +
                       m_stack->GetBasename(m_sliceNumber) + "/";

      create_directories(dirPath);
      stringstream filePath;
      filePath << dirPath
        // leading zeros
        << setfill('0')
        // 4 digits wide
        << setw(4)
        << m_currentIteration;

      // save transform
      writeTransform(m_stack->GetTransform(m_sliceNumber), filePath.str());
    }

    const char *transformType()
    {
      return m_stack->GetTransform(m_sliceNumber)->GetNameOfClass();
    }

  private:
    StackBase *m_stack;
    unsigned int m_sliceNumber;
    unsigned long m_currentIteration;

};
#endif
<|endoftext|>


<commit_before>#ifndef KGR_KANGARU_INCLUDE_KANGARU_DETAIL_META_LIST_HPP
#define KGR_KANGARU_INCLUDE_KANGARU_DETAIL_META_LIST_HPP

#include <type_traits>

namespace kgr {
namespace detail {

template<typename... Types>
struct meta_list {};

template<std::size_t, typename>
struct meta_list_element;

template<std::size_t I>
struct meta_list_element<I, meta_list<>> {};

template<typename Head, typename... Tail>
struct meta_list_element<0, meta_list<Head, Tail...>> {
	using type = Head;
};

template<std::size_t I, typename Head, typename... Tail>
struct meta_list_element<I, meta_list<Head, Tail...>> : meta_list_element<I - 1, meta_list<Tail...>> {};

template <typename, typename>
struct meta_list_contains;

template <typename T>
struct meta_list_contains<T, meta_list<>> : std::false_type {};

template <typename T, typename Head, typename... Tail>
struct meta_list_contains<T, meta_list<Head, Tail...>> : meta_list_contains<T, meta_list<Tail...>> {};

template <typename T, typename... Tail>
struct meta_list_contains<T, meta_list<T, Tail...>> : std::true_type {};

template <typename>
struct meta_list_size;

template <typename... Types>
struct meta_list_size<meta_list<Types...>> {
	static constexpr std::size_t value = sizeof...(Types);
};

template<std::size_t I, typename List>
using meta_list_element_t = typename meta_list_element<I, List>::type;

template<typename>
struct meta_list_empty;

template<typename... Types>
struct meta_list_empty<meta_list<Types...>> : std::integral_constant<bool, sizeof...(Types) == 0> {};

} // namespace detail
} // namespace kgr

#endif // KGR_KANGARU_INCLUDE_KANGARU_DETAIL_META_LIST_HPP
<commit_msg>added transform support in meta_list<commit_after>#ifndef KGR_KANGARU_INCLUDE_KANGARU_DETAIL_META_LIST_HPP
#define KGR_KANGARU_INCLUDE_KANGARU_DETAIL_META_LIST_HPP

#include <type_traits>

namespace kgr {
namespace detail {

template<typename... Types>
struct meta_list {};

template<std::size_t, typename>
struct meta_list_element;

template<std::size_t I>
struct meta_list_element<I, meta_list<>> {};

template<typename Head, typename... Tail>
struct meta_list_element<0, meta_list<Head, Tail...>> {
	using type = Head;
};

template<std::size_t I, typename Head, typename... Tail>
struct meta_list_element<I, meta_list<Head, Tail...>> : meta_list_element<I - 1, meta_list<Tail...>> {};

template <typename, typename>
struct meta_list_contains;

template <typename T>
struct meta_list_contains<T, meta_list<>> : std::false_type {};

template <typename T, typename Head, typename... Tail>
struct meta_list_contains<T, meta_list<Head, Tail...>> : meta_list_contains<T, meta_list<Tail...>> {};

template <typename T, typename... Tail>
struct meta_list_contains<T, meta_list<T, Tail...>> : std::true_type {};

template <typename>
struct meta_list_size;

template<typename, template<typename...> class>
struct meta_list_transform;

template<typename... Types, template<typename> class F>
struct meta_list_transform<meta_list<Types...>, F> {
	using type = meta_list<F<Types>...>;
};

template<typename List, template<typename...> class F>
using meta_list_transform_t = typename meta_list_transform<List, F>::type;

template <typename... Types>
struct meta_list_size<meta_list<Types...>> {
	static constexpr std::size_t value = sizeof...(Types);
};

template<std::size_t I, typename List>
using meta_list_element_t = typename meta_list_element<I, List>::type;

template<typename>
struct meta_list_empty;

template<typename... Types>
struct meta_list_empty<meta_list<Types...>> : std::integral_constant<bool, sizeof...(Types) == 0> {};

} // namespace detail
} // namespace kgr

#endif // KGR_KANGARU_INCLUDE_KANGARU_DETAIL_META_LIST_HPP
<|endoftext|>


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

#include "Quantization.h"
#include "../MathUtil.h"
#include "../uiUtilities.h"
#include "../Internationalisation.h"
#include <gtk/gtk.h>
#include <math.h>
#include <string.h>
#include <boost/math/special_functions/round.hpp>

namespace transformation {

static const char * transformation_name = "quantization";

const char *Quantization::getName()
{
	return transformation_name;
}

const char *Quantization::getReadableName()
{
	return _("Quantization");
}

void Quantization::apply(Color *input, Color *output)
{
	if (clip_top) {
		float max_intensity = (value - 1) / value;
		output->rgb.red = MIN(max_intensity, boost::math::round(input->rgb.red * value) / value);
		output->rgb.green = MIN(max_intensity, boost::math::round(input->rgb.green * value) / value);
		output->rgb.blue = MIN(max_intensity, boost::math::round(input->rgb.blue * value) / value);
	}else{
		float actualmax = value - 1;
		output->rgb.red = boost::math::round(input->rgb.red * actualmax) / actualmax;
		output->rgb.green = boost::math::round(input->rgb.green * actualmax) / actualmax;
		output->rgb.blue = boost::math::round(input->rgb.blue * actualmax) / actualmax;
	}
}

Quantization::Quantization():Transformation(transformation_name, getReadableName())
{
	value = 16;
}

Quantization::Quantization(float value_):Transformation(transformation_name, getReadableName())
{
	value = value_;
}

Quantization::~Quantization()
{
}

void Quantization::serialize(struct dynvSystem *dynv)
{
	dynv_set_float(dynv, "value", value);
	dynv_set_bool(dynv, "clip-top", clip_top);
	Transformation::serialize(dynv);
}

void Quantization::deserialize(struct dynvSystem *dynv)
{
	value = dynv_get_float_wd(dynv, "value", 16);
	clip_top = dynv_get_bool_wd(dynv, "clip-top", 0);
}

boost::shared_ptr<Configuration> Quantization::getConfig(){
	boost::shared_ptr<QuantizationConfig> config = boost::shared_ptr<QuantizationConfig>(new QuantizationConfig(*this));
	return config;
}

QuantizationConfig::QuantizationConfig(Quantization &transformation){
	GtkWidget *table = gtk_table_new(2, 3, false);
	GtkWidget *widget;
	int table_y = 0;

	table_y=0;
	gtk_table_attach(GTK_TABLE(table), gtk_label_aligned_new(_("Value:"),0, 0.5, 0, 0), 0, 1, table_y, table_y + 1, GTK_FILL, GTK_FILL, 5, 5);
	value = widget = gtk_spin_button_new_with_range(2, 256, 1);
	gtk_spin_button_set_value(GTK_SPIN_BUTTON(widget), transformation.value);
	gtk_table_attach(GTK_TABLE(table), widget, 1, 2, table_y, table_y + 1, GtkAttachOptions(GTK_FILL | GTK_EXPAND), GTK_FILL, 5, 0);
	table_y++;
	clip_top = widget = gtk_check_button_new_with_label(_("Clip top-end"));
	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(widget), transformation.clip_top);
	gtk_table_attach(GTK_TABLE(table), widget, 1, 2, table_y, table_y + 1, GtkAttachOptions(GTK_FILL | GTK_EXPAND), GTK_FILL, 5, 0);

	main = table;
	gtk_widget_show_all(main);

	g_object_ref(main);
}

QuantizationConfig::~QuantizationConfig(){
	g_object_unref(main);
}

GtkWidget* QuantizationConfig::getWidget(){
	return main;
}

void QuantizationConfig::applyConfig(dynvSystem *dynv){
	dynv_set_float(dynv, "value", gtk_spin_button_get_value(GTK_SPIN_BUTTON(value)));
	dynv_set_bool(dynv, "clip-top", gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(clip_top)));
}

}

<commit_msg>resolve i18n conflict?<commit_after>/*
 * Copyright (c) 2009-2012, Albertas Vyšniauskas
 * All rights reserved.
 * Copyright (c) 2012, David Gowers (Portions regarding adaptation of GammaModification.(cpp|h) to quantise colors instead.)
 *
 * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
 *
 *     * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
 *     * Neither the name of the software author nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
 * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
 * OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "Quantization.h"
#include "../MathUtil.h"
#include "../uiUtilities.h"
#include "../Internationalisation.h"
#include <gtk/gtk.h>
#include <math.h>
#include <string.h>
#include <boost/math/special_functions/round.hpp>

namespace transformation {

static const char * transformation_name = "quantization";

const char *Quantization::getName()
{
	return transformation_name;
}

const char *Quantization::getReadableName()
{
	return _("Quantization");
}

void Quantization::apply(Color *input, Color *output)
{
	if (clip_top) {
		float max_intensity = (value - 1) / value;
		output->rgb.red = MIN(max_intensity, boost::math::round(input->rgb.red * value) / value);
		output->rgb.green = MIN(max_intensity, boost::math::round(input->rgb.green * value) / value);
		output->rgb.blue = MIN(max_intensity, boost::math::round(input->rgb.blue * value) / value);
	}else{
		float actualmax = value - 1;
		output->rgb.red = boost::math::round(input->rgb.red * actualmax) / actualmax;
		output->rgb.green = boost::math::round(input->rgb.green * actualmax) / actualmax;
		output->rgb.blue = boost::math::round(input->rgb.blue * actualmax) / actualmax;
	}
}

Quantization::Quantization():Transformation(transformation_name, getReadableName())
{
	value = 16;
}

Quantization::Quantization(float value_):Transformation(transformation_name, getReadableName())
{
	value = value_;
}

Quantization::~Quantization()
{
}

void Quantization::serialize(struct dynvSystem *dynv)
{
	dynv_set_float(dynv, "value", value);
	dynv_set_bool(dynv, "clip-top", clip_top);
	Transformation::serialize(dynv);
}

void Quantization::deserialize(struct dynvSystem *dynv)
{
	value = dynv_get_float_wd(dynv, "value", 16);
	clip_top = dynv_get_bool_wd(dynv, "clip-top", 0);
}

boost::shared_ptr<Configuration> Quantization::getConfig(){
	boost::shared_ptr<QuantizationConfig> config = boost::shared_ptr<QuantizationConfig>(new QuantizationConfig(*this));
	return config;
}

QuantizationConfig::QuantizationConfig(Quantization &transformation){
	GtkWidget *table = gtk_table_new(2, 3, false);
	GtkWidget *widget;
	int table_y = 0;

	table_y=0;
	gtk_table_attach(GTK_TABLE(table), gtk_label_aligned_new(_("Value:")),0, 0.5, 0, 0), 0, 1, table_y, table_y + 1, GTK_FILL, GTK_FILL, 5, 5);
	value = widget = gtk_spin_button_new_with_range(2, 256, 1);
	gtk_spin_button_set_value(GTK_SPIN_BUTTON(widget), transformation.value);
	gtk_table_attach(GTK_TABLE(table), widget, 1, 2, table_y, table_y + 1, GtkAttachOptions(GTK_FILL | GTK_EXPAND), GTK_FILL, 5, 0);
	table_y++;
	clip_top = widget = gtk_check_button_new_with_label(_("Clip top-end"));
	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(widget), transformation.clip_top);
	gtk_table_attach(GTK_TABLE(table), widget, 1, 2, table_y, table_y + 1, GtkAttachOptions(GTK_FILL | GTK_EXPAND), GTK_FILL, 5, 0);

	main = table;
	gtk_widget_show_all(main);

	g_object_ref(main);
}

QuantizationConfig::~QuantizationConfig(){
	g_object_unref(main);
}

GtkWidget* QuantizationConfig::getWidget(){
	return main;
}

void QuantizationConfig::applyConfig(dynvSystem *dynv){
	dynv_set_float(dynv, "value", gtk_spin_button_get_value(GTK_SPIN_BUTTON(value)));
	dynv_set_bool(dynv, "clip-top", gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(clip_top)));
}

}

<|endoftext|>


<commit_before>//
// Copyright (c) 2016 Kimball Thurston
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
// OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//

#include "tiff_reader.h"

#if defined(HAVE_LIBTIFF)
# include "file_per_sample_reader.h"
# include "image_frame.h"
# include "video_track.h"
# include "file_sequence.h"
# include <base/contract.h>
# include <base/scope_guard.h>
# include <base/string_util.h>
# include <base/file_system.h>
# include <base/env.h>

# include <tiffio.h>
# include <tiffio.hxx>

////////////////////////////////////////

namespace media
{

////////////////////////////////////////

namespace
{

static void tiff_warning_handler( const char *p, const char *fmt, va_list args )
{
}

static void tiff_error_handler( const char *p, const char *fmt, va_list args )
{
}

static void tiff_warning_handler_ext( thandle_t sp, const char *p, const char *fmt, va_list args )
{
}

static void tiff_error_handler_ext( thandle_t sp, const char *p, const char *fmt, va_list args )
{
}

////////////////////////////////////////

class tiff_read_track : public video_track
{
public:
	tiff_read_track( int64_t b, int64_t e, file_sequence &&fseq )
			: video_track( "<image>", b, e, sample_rate( 24, 1 ),
						   media::track_description( media::TRACK_VIDEO ) ),
			  _files( std::move( fseq ) )
	{}

	virtual image_frame *doRead( int64_t f );

	virtual void doWrite( int64_t , const image_frame & )
	{
		throw_logic( "reader asked to write a frame" );
	}

private:
	file_sequence _files;
};

////////////////////////////////////////

image_frame *
tiff_read_track::doRead( int64_t f )
{
	std::unique_ptr<image_frame> ret;

	base::uri u = _files.get_frame( f );
	std::string p = u.full_path();
	auto fs = base::file_system::get( u );
	base::istream stream = fs->open_read( u );

	auto terr = TIFFSetErrorHandler( tiff_error_handler );
	auto twarn = TIFFSetWarningHandler( tiff_warning_handler );
	auto terre = TIFFSetErrorHandlerExt( tiff_error_handler_ext );
	auto twarne = TIFFSetWarningHandlerExt( tiff_warning_handler_ext );
	on_scope_exit
	{
		TIFFSetErrorHandler( terr );
		TIFFSetWarningHandler( twarn );
		TIFFSetErrorHandlerExt( terre );
		TIFFSetWarningHandlerExt( twarne );
	};

	// We're just reading the header, so don't open for mapping
	TIFF *t = TIFFStreamOpen( p.c_str(), &stream );
	if ( t )
	{
		on_scope_exit{ TIFFFlushData( t ); TIFFClose( t ); };
		uint16_t bps, sf;
		float offX, offY;
		uint32_t sizeY, sizeX;

		TIFFGetFieldDefaulted( t, TIFFTAG_BITSPERSAMPLE, &bps );
		if ( ! TIFFGetField( t, TIFFTAG_SAMPLEFORMAT, &sf ) )
			sf = SAMPLEFORMAT_VOID;

		if ( ! TIFFGetField( t, TIFFTAG_XPOSITION, &offX ) )
			offX = 0.F;
		if ( ! TIFFGetField( t, TIFFTAG_YPOSITION, &offY ) )
			offY = 0.F;
		// Need to multiply offX by resolution.

		TIFFGetFieldDefaulted( t, TIFFTAG_IMAGEWIDTH, &sizeX );
		TIFFGetFieldDefaulted( t, TIFFTAG_IMAGELENGTH, &sizeY );

		uint16_t photo = 0;
		TIFFGetFieldDefaulted( t, TIFFTAG_PHOTOMETRIC, &photo );

		uint16_t samps = 0;
		if ( PHOTOMETRIC_PALETTE == photo )
		{
			// color, 3 planes
			samps = 3;
		}
		else
		{
			TIFFGetFieldDefaulted( t, TIFFTAG_SAMPLESPERPIXEL, &samps );
		}

		if ( sf == SAMPLEFORMAT_COMPLEXINT || sf == SAMPLEFORMAT_COMPLEXIEEEFP )
			throw_not_yet();

		uint16_t orient = 0;
		TIFFGetFieldDefaulted( t, TIFFTAG_ORIENTATION, &orient );
		switch ( orient )
		{
			default:

				break;
		}

		uint16_t isP = 0;
		TIFFGetFieldDefaulted( t, TIFFTAG_PLANARCONFIG, &isP );

		const char *channames[] = { "R", "G", "B", "A" };
		int64_t w = static_cast<int64_t>( sizeX );
		int64_t h = static_cast<int64_t>( sizeY );
		ret.reset( new image_frame( w, h ) );
		for ( uint16_t s = 0; s < samps; ++s )
		{
			image_buffer imgbuf;
			switch ( bps )
			{
				case 1:
					// don't handle 1-bit yet
					throw_not_yet();
					break;
				case 8:
					if ( sf == SAMPLEFORMAT_INT )
						imgbuf = image_buffer::simple_buffer<int8_t>( w, h );
					else
						imgbuf = image_buffer::simple_buffer<uint8_t>( w, h );
					break;
				case 16:
					std::cout << "initializing " << w << 'x' << h << " 16-bit image" << std::endl;
					if ( sf == SAMPLEFORMAT_INT )
						imgbuf = image_buffer::simple_buffer<int16_t>( w, h );
					else
						imgbuf = image_buffer::simple_buffer<uint16_t>( w, h );
					break;
				case 32:
					if ( sf == SAMPLEFORMAT_UINT )
						imgbuf = image_buffer::simple_buffer<uint32_t>( w, h );
					else if ( sf == SAMPLEFORMAT_INT )
						imgbuf = image_buffer::simple_buffer<int32_t>( w, h );
					else // void or ieeefp
						imgbuf = image_buffer::simple_buffer<float>( w, h );
					break;
				case 64:
					if ( sf == SAMPLEFORMAT_UINT )
						imgbuf = image_buffer::simple_buffer<uint64_t>( w, h );
					else if ( sf == SAMPLEFORMAT_INT )
						imgbuf = image_buffer::simple_buffer<int64_t>( w, h );
					else // void or ieeefp
						imgbuf = image_buffer::simple_buffer<double>( w, h );
					break;
				default:

					break;
			}

			if ( s < 4 )
				ret->add_channel( channames[s], imgbuf );
			else
				ret->add_channel( imgbuf );
		}

		if ( TIFFIsTiled( t ) )
		{
			uint32_t tileWidth = sizeX, tileLength = sizeY;

			TIFFGetField( t, TIFFTAG_TILEWIDTH, &tileWidth );
			TIFFGetField( t, TIFFTAG_TILELENGTH, &tileLength );

			throw_not_yet();
			if ( PLANARCONFIG_SEPARATE == isP )
			{
			}
			else
			{
			}
		}
		else
		{
			tmsize_t ssize = TIFFScanlineSize( t );
			if ( PLANARCONFIG_SEPARATE == isP )
			{
				std::cout << "reading planar TIFF straight to image" << std::endl;
				// need to read it in order of samples to prevent random access
				for ( uint16_t s = 0; s < samps; ++s )
				{
					uint8_t *dptr = reinterpret_cast<uint8_t *>( ret->at( s ).data() );
					precondition( ret->at( s ).ystride_bytes() == ssize, "invalid line stride assumption about scanline size" );
					for ( uint32_t row = 0; row < sizeY; ++row )
					{
						TIFFReadScanline( t, dptr, row, s );
						dptr += ssize;
					}
				}
			}
			else
			{
				std::unique_ptr<uint8_t[]> tmpbuf = std::unique_ptr<uint8_t[]>( new uint8_t[TIFFScanlineSize( t )] );
				std::cout << "reading interleaved TIFF to temporary buffer then copying to image" << std::endl;
				for ( uint32_t row = 0; row < sizeY; ++row )
				{
					TIFFReadScanline( t, tmpbuf.get(), row );
					for ( uint16_t s = 0; s < samps; ++s )
					{
						image_buffer &ib = ret->at( s );
						if ( row == 0 )
						{
							std::cout << " ---> ib " << s << " xstride " << ib.xstride_bytes() << " ystride " << ib.ystride_bytes() << std::endl;
						}
						uint8_t *dptr = reinterpret_cast<uint8_t *>( ib.data() );
						dptr += ib.ystride_bytes() * row;
						const uint8_t *sptr = tmpbuf.get();
						switch ( ib.bits() )
						{
							case 8:
								for ( uint32_t x = 0; x < sizeX; ++x )
									dptr[x] = sptr[x*samps + s];
								break;
							case 16:
							{
								uint16_t *dst16 = reinterpret_cast<uint16_t *>( dptr );
								const uint16_t *src16 = reinterpret_cast<const uint16_t *>( sptr );
								for ( uint32_t x = 0; x < sizeX; ++x )
									dst16[x] = src16[x*samps + s];
								break;
							}
							case 32:
							{
								uint32_t *dst32 = reinterpret_cast<uint32_t *>( dptr );
								const uint32_t *src32 = reinterpret_cast<const uint32_t *>( sptr );
								for ( uint32_t x = 0; x < sizeX; ++x )
									dst32[x] = src32[x*samps + s];
								break;
							}
							case 64:
							{
								uint64_t *dst64 = reinterpret_cast<uint64_t *>( dptr );
								const uint64_t *src64 = reinterpret_cast<const uint64_t *>( sptr );
								for ( uint32_t x = 0; x < sizeX; ++x )
									dst64[x] = src64[x*samps + s];
								break;
							}
							default:
								throw_not_yet();
						}
					}
				}
			}
		}

	}
	return ret.release();
}

////////////////////////////////////////

class TIFFReader : public file_per_sample_reader
{
public:
	TIFFReader( void )
			: file_per_sample_reader( "TIFF" )
	{
		_description = "TIFF Reader";
		_extensions.emplace_back( "tif" );
		_extensions.emplace_back( "tiff" );

		std::vector<uint8_t> magicBE{0x4D, 0x4D};
		_magics.emplace_back( std::move( magicBE ) );
		std::vector<uint8_t> magicLE{0x49, 0x49};
		_magics.emplace_back( std::move( magicLE ) );

		// MDI
		std::vector<uint8_t> magicMDILE{0x50, 0x45};
		_magics.emplace_back( std::move( magicMDILE ) );
		std::vector<uint8_t> magicMDIBE{0x45, 0x50};
		_magics.emplace_back( std::move( magicMDIBE ) );
	}
	virtual ~TIFFReader( void ) = default;

	virtual container create( const base::uri &u, const metadata &params );
};

container
TIFFReader::create( const base::uri &u, const metadata & )
{
	container result;

	int64_t start, last;
	file_sequence fseq( u );
	auto fs = scan_samples( start, last, fseq );

	result.add_track( std::make_shared<tiff_read_track>( start, last, std::move( fseq ) ) );

	return result;
}

}
#endif // HAVE_LIBTIFF

////////////////////////////////////////

void register_tiff_reader( void )
{
#if defined(HAVE_LIBTIFF)
	reader::register_reader( std::make_shared<TIFFReader>() );
#endif
}

} // namespace media

<commit_msg>remove useless flush<commit_after>//
// Copyright (c) 2016 Kimball Thurston
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
// OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//

#include "tiff_reader.h"

#if defined(HAVE_LIBTIFF)
# include "file_per_sample_reader.h"
# include "image_frame.h"
# include "video_track.h"
# include "file_sequence.h"
# include <base/contract.h>
# include <base/scope_guard.h>
# include <base/string_util.h>
# include <base/file_system.h>
# include <base/env.h>

# include <tiffio.h>
# include <tiffio.hxx>

////////////////////////////////////////

namespace media
{

////////////////////////////////////////

namespace
{

static void tiff_warning_handler( const char *p, const char *fmt, va_list args )
{
}

static void tiff_error_handler( const char *p, const char *fmt, va_list args )
{
}

static void tiff_warning_handler_ext( thandle_t sp, const char *p, const char *fmt, va_list args )
{
}

static void tiff_error_handler_ext( thandle_t sp, const char *p, const char *fmt, va_list args )
{
}

////////////////////////////////////////

class tiff_read_track : public video_track
{
public:
	tiff_read_track( int64_t b, int64_t e, file_sequence &&fseq )
			: video_track( "<image>", b, e, sample_rate( 24, 1 ),
						   media::track_description( media::TRACK_VIDEO ) ),
			  _files( std::move( fseq ) )
	{}

	virtual image_frame *doRead( int64_t f );

	virtual void doWrite( int64_t , const image_frame & )
	{
		throw_logic( "reader asked to write a frame" );
	}

private:
	file_sequence _files;
};

////////////////////////////////////////

image_frame *
tiff_read_track::doRead( int64_t f )
{
	std::unique_ptr<image_frame> ret;

	base::uri u = _files.get_frame( f );
	std::string p = u.full_path();
	auto fs = base::file_system::get( u );
	base::istream stream = fs->open_read( u );

	auto terr = TIFFSetErrorHandler( tiff_error_handler );
	auto twarn = TIFFSetWarningHandler( tiff_warning_handler );
	auto terre = TIFFSetErrorHandlerExt( tiff_error_handler_ext );
	auto twarne = TIFFSetWarningHandlerExt( tiff_warning_handler_ext );
	on_scope_exit
	{
		TIFFSetErrorHandler( terr );
		TIFFSetWarningHandler( twarn );
		TIFFSetErrorHandlerExt( terre );
		TIFFSetWarningHandlerExt( twarne );
	};

	// We're just reading the header, so don't open for mapping
	TIFF *t = TIFFStreamOpen( p.c_str(), &stream );
	if ( t )
	{
		on_scope_exit{ TIFFClose( t ); };
		uint16_t bps, sf;
		float offX, offY;
		uint32_t sizeY, sizeX;

		TIFFGetFieldDefaulted( t, TIFFTAG_BITSPERSAMPLE, &bps );
		if ( ! TIFFGetField( t, TIFFTAG_SAMPLEFORMAT, &sf ) )
			sf = SAMPLEFORMAT_VOID;

		if ( ! TIFFGetField( t, TIFFTAG_XPOSITION, &offX ) )
			offX = 0.F;
		if ( ! TIFFGetField( t, TIFFTAG_YPOSITION, &offY ) )
			offY = 0.F;
		// Need to multiply offX by resolution.

		TIFFGetFieldDefaulted( t, TIFFTAG_IMAGEWIDTH, &sizeX );
		TIFFGetFieldDefaulted( t, TIFFTAG_IMAGELENGTH, &sizeY );

		uint16_t photo = 0;
		TIFFGetFieldDefaulted( t, TIFFTAG_PHOTOMETRIC, &photo );

		uint16_t samps = 0;
		if ( PHOTOMETRIC_PALETTE == photo )
		{
			// color, 3 planes
			samps = 3;
		}
		else
		{
			TIFFGetFieldDefaulted( t, TIFFTAG_SAMPLESPERPIXEL, &samps );
		}

		if ( sf == SAMPLEFORMAT_COMPLEXINT || sf == SAMPLEFORMAT_COMPLEXIEEEFP )
			throw_not_yet();

		uint16_t orient = 0;
		TIFFGetFieldDefaulted( t, TIFFTAG_ORIENTATION, &orient );
		switch ( orient )
		{
			default:

				break;
		}

		uint16_t isP = 0;
		TIFFGetFieldDefaulted( t, TIFFTAG_PLANARCONFIG, &isP );

		const char *channames[] = { "R", "G", "B", "A" };
		int64_t w = static_cast<int64_t>( sizeX );
		int64_t h = static_cast<int64_t>( sizeY );
		ret.reset( new image_frame( w, h ) );
		for ( uint16_t s = 0; s < samps; ++s )
		{
			image_buffer imgbuf;
			switch ( bps )
			{
				case 1:
					// don't handle 1-bit yet
					throw_not_yet();
					break;
				case 8:
					if ( sf == SAMPLEFORMAT_INT )
						imgbuf = image_buffer::simple_buffer<int8_t>( w, h );
					else
						imgbuf = image_buffer::simple_buffer<uint8_t>( w, h );
					break;
				case 16:
					std::cout << "initializing " << w << 'x' << h << " 16-bit image" << std::endl;
					if ( sf == SAMPLEFORMAT_INT )
						imgbuf = image_buffer::simple_buffer<int16_t>( w, h );
					else
						imgbuf = image_buffer::simple_buffer<uint16_t>( w, h );
					break;
				case 32:
					if ( sf == SAMPLEFORMAT_UINT )
						imgbuf = image_buffer::simple_buffer<uint32_t>( w, h );
					else if ( sf == SAMPLEFORMAT_INT )
						imgbuf = image_buffer::simple_buffer<int32_t>( w, h );
					else // void or ieeefp
						imgbuf = image_buffer::simple_buffer<float>( w, h );
					break;
				case 64:
					if ( sf == SAMPLEFORMAT_UINT )
						imgbuf = image_buffer::simple_buffer<uint64_t>( w, h );
					else if ( sf == SAMPLEFORMAT_INT )
						imgbuf = image_buffer::simple_buffer<int64_t>( w, h );
					else // void or ieeefp
						imgbuf = image_buffer::simple_buffer<double>( w, h );
					break;
				default:

					break;
			}

			if ( s < 4 )
				ret->add_channel( channames[s], imgbuf );
			else
				ret->add_channel( imgbuf );
		}

		if ( TIFFIsTiled( t ) )
		{
			uint32_t tileWidth = sizeX, tileLength = sizeY;

			TIFFGetField( t, TIFFTAG_TILEWIDTH, &tileWidth );
			TIFFGetField( t, TIFFTAG_TILELENGTH, &tileLength );

			throw_not_yet();
			if ( PLANARCONFIG_SEPARATE == isP )
			{
			}
			else
			{
			}
		}
		else
		{
			tmsize_t ssize = TIFFScanlineSize( t );
			if ( PLANARCONFIG_SEPARATE == isP )
			{
				std::cout << "reading planar TIFF straight to image" << std::endl;
				// need to read it in order of samples to prevent random access
				for ( uint16_t s = 0; s < samps; ++s )
				{
					uint8_t *dptr = reinterpret_cast<uint8_t *>( ret->at( s ).data() );
					precondition( ret->at( s ).ystride_bytes() == ssize, "invalid line stride assumption about scanline size" );
					for ( uint32_t row = 0; row < sizeY; ++row )
					{
						TIFFReadScanline( t, dptr, row, s );
						dptr += ssize;
					}
				}
			}
			else
			{
				std::unique_ptr<uint8_t[]> tmpbuf = std::unique_ptr<uint8_t[]>( new uint8_t[TIFFScanlineSize( t )] );
				std::cout << "reading interleaved TIFF to temporary buffer then copying to image" << std::endl;
				for ( uint32_t row = 0; row < sizeY; ++row )
				{
					TIFFReadScanline( t, tmpbuf.get(), row );
					for ( uint16_t s = 0; s < samps; ++s )
					{
						image_buffer &ib = ret->at( s );
						if ( row == 0 )
						{
							std::cout << " ---> ib " << s << " xstride " << ib.xstride_bytes() << " ystride " << ib.ystride_bytes() << std::endl;
						}
						uint8_t *dptr = reinterpret_cast<uint8_t *>( ib.data() );
						dptr += ib.ystride_bytes() * row;
						const uint8_t *sptr = tmpbuf.get();
						switch ( ib.bits() )
						{
							case 8:
								for ( uint32_t x = 0; x < sizeX; ++x )
									dptr[x] = sptr[x*samps + s];
								break;
							case 16:
							{
								uint16_t *dst16 = reinterpret_cast<uint16_t *>( dptr );
								const uint16_t *src16 = reinterpret_cast<const uint16_t *>( sptr );
								for ( uint32_t x = 0; x < sizeX; ++x )
									dst16[x] = src16[x*samps + s];
								break;
							}
							case 32:
							{
								uint32_t *dst32 = reinterpret_cast<uint32_t *>( dptr );
								const uint32_t *src32 = reinterpret_cast<const uint32_t *>( sptr );
								for ( uint32_t x = 0; x < sizeX; ++x )
									dst32[x] = src32[x*samps + s];
								break;
							}
							case 64:
							{
								uint64_t *dst64 = reinterpret_cast<uint64_t *>( dptr );
								const uint64_t *src64 = reinterpret_cast<const uint64_t *>( sptr );
								for ( uint32_t x = 0; x < sizeX; ++x )
									dst64[x] = src64[x*samps + s];
								break;
							}
							default:
								throw_not_yet();
						}
					}
				}
			}
		}

	}
	return ret.release();
}

////////////////////////////////////////

class TIFFReader : public file_per_sample_reader
{
public:
	TIFFReader( void )
			: file_per_sample_reader( "TIFF" )
	{
		_description = "TIFF Reader";
		_extensions.emplace_back( "tif" );
		_extensions.emplace_back( "tiff" );

		std::vector<uint8_t> magicBE{0x4D, 0x4D};
		_magics.emplace_back( std::move( magicBE ) );
		std::vector<uint8_t> magicLE{0x49, 0x49};
		_magics.emplace_back( std::move( magicLE ) );

		// MDI
		std::vector<uint8_t> magicMDILE{0x50, 0x45};
		_magics.emplace_back( std::move( magicMDILE ) );
		std::vector<uint8_t> magicMDIBE{0x45, 0x50};
		_magics.emplace_back( std::move( magicMDIBE ) );
	}
	virtual ~TIFFReader( void ) = default;

	virtual container create( const base::uri &u, const metadata &params );
};

container
TIFFReader::create( const base::uri &u, const metadata & )
{
	container result;

	int64_t start, last;
	file_sequence fseq( u );
	auto fs = scan_samples( start, last, fseq );

	result.add_track( std::make_shared<tiff_read_track>( start, last, std::move( fseq ) ) );

	return result;
}

}
#endif // HAVE_LIBTIFF

////////////////////////////////////////

void register_tiff_reader( void )
{
#if defined(HAVE_LIBTIFF)
	reader::register_reader( std::make_shared<TIFFReader>() );
#endif
}

} // namespace media

<|endoftext|>


<commit_before>/*
 * Copyright 2015 Cloudius Systems
 */

#pragma once

#include "query-result-reader.hh"

#include "core/shared_ptr.hh"

#include <experimental/optional>
#include <stdexcept>

#include <boost/any.hpp>

namespace query {

class no_such_column : public std::runtime_error {
public:
    using runtime_error::runtime_error;
};

class null_column_value : public std::runtime_error {
public:
    using runtime_error::runtime_error;
};

// Result set row is a set of cells that are associated with a row
// including regular column cells, partition keys, as well as static values.
class result_set_row {
    schema_ptr _schema;
    std::unordered_map<sstring, data_value> _cells;
public:
    result_set_row(schema_ptr schema, std::unordered_map<sstring, data_value>&& cells)
        : _schema{schema}
        , _cells{std::move(cells)}
    { }
    // Look up a deserialized row cell value by column name.
    template<typename T>
    std::experimental::optional<T>
    get(const sstring& column_name) const throw (no_such_column) {
        auto it = _cells.find(column_name);
        if (it == _cells.end()) {
            throw no_such_column(column_name);
        }
        auto&& value = it->second.value();
        if (value.empty()) {
            return std::experimental::nullopt;
        }
        return std::experimental::optional<T>{boost::any_cast<T>(value)};
    }
    template<typename T>
    T get_nonnull(const sstring& column_name) const throw (no_such_column, null_column_value) {
        auto v = get<T>(column_name);
        if (v) {
            return *v;
        }
        throw null_column_value(column_name);
    }
    friend inline bool operator==(const result_set_row& x, const result_set_row& y);
    friend inline bool operator!=(const result_set_row& x, const result_set_row& y);
    friend std::ostream& operator<<(std::ostream& out, const result_set_row& row);
};

inline bool operator==(const result_set_row& x, const result_set_row& y) {
    return x._schema == y._schema && x._cells == y._cells;
}

inline bool operator!=(const result_set_row& x, const result_set_row& y) {
    return !(x == y);
}

// Result set is an in-memory representation of query results in
// deserialized format. To obtain a result set, use the result_set_builder
// class as a visitor to query_result::consume() function.
class result_set {
    std::vector<result_set_row> _rows;
public:
    result_set(const std::vector<result_set_row>& rows)
        : _rows{std::move(rows)}
    { }
    bool empty() const {
        return _rows.empty();
    }
    const result_set_row& row(size_t idx) const throw (std::out_of_range) {
        if (idx >= _rows.size()) {
            throw std::out_of_range("no such row in result set: " + std::to_string(idx));
        }
        return _rows[idx];
    }
    const std::vector<result_set_row>& rows() const {
        return _rows;
    }
    friend inline bool operator==(const result_set& x, const result_set& y);
    friend std::ostream& operator<<(std::ostream& out, const result_set& rs);
};

inline bool operator==(const result_set& x, const result_set& y) {
    return x._rows == y._rows;
}

// Result set builder is passed as a visitor to query_result::consume()
// function. You can call the build() method to obtain a result set that
// contains cells from the visited results.
class result_set_builder {
    schema_ptr _schema;
    std::vector<result_set_row> _rows;
    std::unordered_map<sstring, data_value> _pkey_cells;
public:
    result_set_builder(schema_ptr schema);
    lw_shared_ptr<result_set> build() const;
    void accept_new_partition(const partition_key& key, uint32_t row_count);
    void accept_new_partition(uint32_t row_count);
    void accept_new_row(const clustering_key& key, const result_row_view& static_row, const result_row_view& row);
    void accept_new_row(const result_row_view &static_row, const result_row_view &row);
    void accept_partition_end(const result_row_view& static_row);
private:
    std::unordered_map<sstring, data_value> deserialize(const partition_key& key);
    std::unordered_map<sstring, data_value> deserialize(const clustering_key& key);
    std::unordered_map<sstring, data_value> deserialize(const result_row_view& row, bool is_static);
};

}
<commit_msg>query-result-set.hh: Add result_set_row::has() helper<commit_after>/*
 * Copyright 2015 Cloudius Systems
 */

#pragma once

#include "query-result-reader.hh"

#include "core/shared_ptr.hh"

#include <experimental/optional>
#include <stdexcept>

#include <boost/any.hpp>

namespace query {

class no_such_column : public std::runtime_error {
public:
    using runtime_error::runtime_error;
};

class null_column_value : public std::runtime_error {
public:
    using runtime_error::runtime_error;
};

// Result set row is a set of cells that are associated with a row
// including regular column cells, partition keys, as well as static values.
class result_set_row {
    schema_ptr _schema;
    std::unordered_map<sstring, data_value> _cells;
public:
    result_set_row(schema_ptr schema, std::unordered_map<sstring, data_value>&& cells)
        : _schema{schema}
        , _cells{std::move(cells)}
    { }
    bool has(const sstring& column_name) const {
        return _cells.count(column_name) > 0;
    }
    // Look up a deserialized row cell value by column name.
    template<typename T>
    std::experimental::optional<T>
    get(const sstring& column_name) const throw (no_such_column) {
        auto it = _cells.find(column_name);
        if (it == _cells.end()) {
            throw no_such_column(column_name);
        }
        auto&& value = it->second.value();
        if (value.empty()) {
            return std::experimental::nullopt;
        }
        return std::experimental::optional<T>{boost::any_cast<T>(value)};
    }
    template<typename T>
    T get_nonnull(const sstring& column_name) const throw (no_such_column, null_column_value) {
        auto v = get<T>(column_name);
        if (v) {
            return *v;
        }
        throw null_column_value(column_name);
    }
    friend inline bool operator==(const result_set_row& x, const result_set_row& y);
    friend inline bool operator!=(const result_set_row& x, const result_set_row& y);
    friend std::ostream& operator<<(std::ostream& out, const result_set_row& row);
};

inline bool operator==(const result_set_row& x, const result_set_row& y) {
    return x._schema == y._schema && x._cells == y._cells;
}

inline bool operator!=(const result_set_row& x, const result_set_row& y) {
    return !(x == y);
}

// Result set is an in-memory representation of query results in
// deserialized format. To obtain a result set, use the result_set_builder
// class as a visitor to query_result::consume() function.
class result_set {
    std::vector<result_set_row> _rows;
public:
    result_set(const std::vector<result_set_row>& rows)
        : _rows{std::move(rows)}
    { }
    bool empty() const {
        return _rows.empty();
    }
    const result_set_row& row(size_t idx) const throw (std::out_of_range) {
        if (idx >= _rows.size()) {
            throw std::out_of_range("no such row in result set: " + std::to_string(idx));
        }
        return _rows[idx];
    }
    const std::vector<result_set_row>& rows() const {
        return _rows;
    }
    friend inline bool operator==(const result_set& x, const result_set& y);
    friend std::ostream& operator<<(std::ostream& out, const result_set& rs);
};

inline bool operator==(const result_set& x, const result_set& y) {
    return x._rows == y._rows;
}

// Result set builder is passed as a visitor to query_result::consume()
// function. You can call the build() method to obtain a result set that
// contains cells from the visited results.
class result_set_builder {
    schema_ptr _schema;
    std::vector<result_set_row> _rows;
    std::unordered_map<sstring, data_value> _pkey_cells;
public:
    result_set_builder(schema_ptr schema);
    lw_shared_ptr<result_set> build() const;
    void accept_new_partition(const partition_key& key, uint32_t row_count);
    void accept_new_partition(uint32_t row_count);
    void accept_new_row(const clustering_key& key, const result_row_view& static_row, const result_row_view& row);
    void accept_new_row(const result_row_view &static_row, const result_row_view &row);
    void accept_partition_end(const result_row_view& static_row);
private:
    std::unordered_map<sstring, data_value> deserialize(const partition_key& key);
    std::unordered_map<sstring, data_value> deserialize(const clustering_key& key);
    std::unordered_map<sstring, data_value> deserialize(const result_row_view& row, bool is_static);
};

}
<|endoftext|>


<commit_before>// Copyright 2015-2019 Elviss Strazdins. All rights reserved.

#ifndef OUZEL_MATH_QUATERNION_HPP
#define OUZEL_MATH_QUATERNION_HPP

#include <cmath>
#include <cstddef>
#include <limits>
#include "math/Vector.hpp"

namespace ouzel
{
    template <typename T> class Quaternion final
    {
    public:
        T v[4]{0};

        constexpr Quaternion() noexcept {}

        constexpr Quaternion(const T x, const T y, const T z, const T w) noexcept:
            v{x, y, z, w}
        {
        }

        inline T& operator[](size_t index) noexcept { return v[index]; }
        constexpr T operator[](size_t index) const noexcept { return v[index]; }

        inline T& x() noexcept { return v[0]; }
        constexpr T x() const noexcept { return v[0]; }

        inline T& y() noexcept { return v[1]; }
        constexpr T y() const noexcept { return v[1]; }

        inline T& z() noexcept { return v[2]; }
        constexpr T z() const noexcept { return v[2]; }

        inline T& w() noexcept { return v[3]; }
        constexpr T w() const noexcept { return v[3]; }

        static constexpr Quaternion identity() noexcept
        {
            return Quaternion(0, 0, 0, 1);
        }

        constexpr const Quaternion operator*(const Quaternion& q) const noexcept
        {
            return Quaternion(v[0] * q.v[3] + v[1] * q.v[2] - v[2] * q.v[1] + v[3] * q.v[0],
                              -v[0] * q.v[2] + v[1] * q.v[3] + v[2] * q.v[0] + v[3] * q.v[1],
                              v[0] * q.v[1] - v[1] * q.v[0] + v[2] * q.v[3] + v[3] * q.v[2],
                              -v[0] * q.v[0] - v[1] * q.v[1] - v[2] * q.v[2] + v[3] * q.v[3]);
        }

        inline Quaternion& operator*=(const Quaternion& q) noexcept
        {
            constexpr T tempX = v[0] * q.v[3] + v[1] * q.v[2] - v[2] * q.v[1] + v[3] * q.v[0];
            constexpr T tempY = -v[0] * q.v[2] + v[1] * q.v[3] + v[2] * q.v[0] + v[3] * q.v[1];
            constexpr T tempZ = v[0] * q.v[1] - v[1] * q.v[0] + v[2] * q.v[3] + v[3] * q.v[2];
            constexpr T tempW = -v[0] * q.v[0] - v[1] * q.v[1] - v[2] * q.v[2] + v[3] * q.v[3];

            v[0] = tempX;
            v[1] = tempY;
            v[2] = tempZ;
            v[3] = tempW;

            return *this;
        }

        constexpr const Quaternion operator*(const T scalar) const noexcept
        {
            return Quaternion(v[0] * scalar,
                              v[1] * scalar,
                              v[2] * scalar,
                              v[3] * scalar);
        }

        inline Quaternion& operator*=(const T scalar) noexcept
        {
            v[0] *= scalar;
            v[1] *= scalar;
            v[2] *= scalar;
            v[3] *= scalar;

            return *this;
        }

        constexpr const Quaternion operator/(const T scalar) const noexcept
        {
            return Quaternion(v[0] / scalar,
                              v[1] / scalar,
                              v[2] / scalar,
                              v[3] / scalar);
        }

        inline Quaternion& operator/=(const T scalar) noexcept
        {
            v[0] /= scalar;
            v[1] /= scalar;
            v[2] /= scalar;
            v[3] /= scalar;

            return *this;
        }

        constexpr const Quaternion operator-() const noexcept
        {
            return Quaternion(-v[0], -v[1], -v[2], -v[3]);
        }

        constexpr const Quaternion operator+(const Quaternion& q) const noexcept
        {
            return Quaternion(v[0] + q.v[0],
                              v[1] + q.v[1],
                              v[2] + q.v[2],
                              v[3] + q.v[3]);
        }

        inline Quaternion& operator+=(const Quaternion& q) noexcept
        {
            v[0] += q.v[0];
            v[1] += q.v[1];
            v[2] += q.v[2];
            v[3] += q.v[3];

            return *this;
        }

        constexpr const Quaternion operator-(const Quaternion& q) const noexcept
        {
            return Quaternion(v[0] - q.v[0],
                              v[1] - q.v[1],
                              v[2] - q.v[2],
                              v[3] - q.v[3]);
        }

        inline Quaternion& operator-=(const Quaternion& q) noexcept
        {
            v[0] -= q.v[0];
            v[1] -= q.v[1];
            v[2] -= q.v[2];
            v[3] -= q.v[3];

            return *this;
        }

        constexpr bool operator==(const Quaternion& q) const noexcept
        {
            return v[0] == q.v[0] && v[1] == q.v[1] && v[2] == q.v[2] && v[3] == q.v[3];
        }

        constexpr bool operator!=(const Quaternion& q) const noexcept
        {
            return v[0] != q.v[0] || v[1] != q.v[1] || v[2] != q.v[2] || v[3] != q.v[3];
        }

        inline void negate() noexcept
        {
            v[0] = -v[0];
            v[1] = -v[1];
            v[2] = -v[2];
            v[3] = -v[3];
        }

        inline void conjugate() noexcept
        {
            v[0] = -v[0];
            v[1] = -v[1];
            v[2] = -v[2];
        }

        inline void invert() noexcept
        {
            constexpr T n2 = v[0] * v[0] + v[1] * v[1] + v[2] * v[2] + v[3] * v[3]; // norm squared
            if (n2 <= std::numeric_limits<T>::min())
                return;

            // conjugate divided by norm squared
            v[0] = -v[0] / n2;
            v[1] = -v[1] / n2;
            v[2] = -v[2] / n2;
            v[3] = v[3] / n2;
        }

        inline auto getNorm() const noexcept
        {
            constexpr T n = v[0] * v[0] + v[1] * v[1] + v[2] * v[2] + v[3] * v[3];
            if (n == T(1)) // already normalized
                return 1;

            return std::sqrt(n);
        }

        void normalize() noexcept
        {
            constexpr T s = v[0] * v[0] + v[1] * v[1] + v[2] * v[2] + v[3] * v[3];
            if (s == T(1)) // already normalized
                return;

            T n = std::sqrt(s);
            if (n <= std::numeric_limits<T>::min()) // too close to zero
                return;

            n = T(1) / n;
            v[0] *= n;
            v[1] *= n;
            v[2] *= n;
            v[3] *= n;
        }

        Quaternion normalized() const noexcept
        {
            constexpr T s = v[0] * v[0] + v[1] * v[1] + v[2] * v[2] + v[3] * v[3];
            if (s == T(1)) // already normalized
                return *this;

            T n = std::sqrt(s);
            if (n <= std::numeric_limits<T>::min()) // too close to zero
                return *this;

            n = T(1) / n;
            return *this * n;
        }

        void rotate(const T angle, const Vector<3, T>& axis) noexcept
        {
            const auto normalizedAxis = axis.normalized();

            const T cosAngle = std::cos(angle / T(2));
            const T sinAngle = std::sin(angle / T(2));

            v[0] = normalizedAxis.v[0] * sinAngle;
            v[1] = normalizedAxis.v[1] * sinAngle;
            v[2] = normalizedAxis.v[2] * sinAngle;
            v[3] = cosAngle;
        }

        void getRotation(T& angle, Vector<3, T>& axis) const noexcept
        {
            angle = T(2) * std::acos(v[3]);
            const T s = std::sqrt(T(1) - v[3] * v[3]);
            if (s <= std::numeric_limits<T>::min()) // too close to zero
            {
                axis.v[0] = v[0];
                axis.v[1] = v[1];
                axis.v[2] = v[2];
            }
            else
            {
                axis.v[0] = v[0] / s;
                axis.v[1] = v[1] / s;
                axis.v[2] = v[2] / s;
            }
        }

        Vector<3, T> getEulerAngles() const noexcept
        {
            Vector<3, T> result;
            result.v[0] = std::atan2(2 * (v[1] * v[2] + v[3] * v[0]), v[3] * v[3] - v[0] * v[0] - v[1] * v[1] + v[2] * v[2]);
            result.v[1] = std::asin(-2 * (v[0] * v[2] - v[3] * v[1]));
            result.v[2] = std::atan2(2 * (v[0] * v[1] + v[3] * v[2]), v[3] * v[3] + v[0] * v[0] - v[1] * v[1] - v[2] * v[2]);
            return result;
        }

        inline auto getEulerAngleX() const noexcept
        {
            return std::atan2(T(2) * (v[1] * v[2] + v[3] * v[0]), v[3] * v[3] - v[0] * v[0] - v[1] * v[1] + v[2] * v[2]);
        }

        inline auto getEulerAngleY() const noexcept
        {
            return std::asin(T(-2) * (v[0] * v[2] - v[3] * v[1]));
        }

        inline auto getEulerAngleZ() const noexcept
        {
            return std::atan2(T(2) * (v[0] * v[1] + v[3] * v[2]), v[3] * v[3] + v[0] * v[0] - v[1] * v[1] - v[2] * v[2]);
        }

        void setEulerAngles(const Vector<3, T>& angles) noexcept
        {
            constexpr T angleR = angles.v[0] / T(2);
            const T sr = std::sin(angleR);
            const T cr = std::cos(angleR);

            constexpr T angleP = angles.v[1] / T(2);
            const T sp = std::sin(angleP);
            const T cp = std::cos(angleP);

            constexpr T angleY = angles.v[2] / T(2);
            const T sy = std::sin(angleY);
            const T cy = std::cos(angleY);

            const T cpcy = cp * cy;
            const T spcy = sp * cy;
            const T cpsy = cp * sy;
            const T spsy = sp * sy;

            v[0] = sr * cpcy - cr * spsy;
            v[1] = cr * spcy + sr * cpsy;
            v[2] = cr * cpsy - sr * spcy;
            v[3] = cr * cpcy + sr * spsy;
        }

        inline const Vector<3, T> operator*(const Vector<3, T>& vector) const noexcept
        {
            return rotateVector(vector);
        }

        inline Vector<3, T> rotateVector(const Vector<3, T>& vector) const noexcept
        {
            constexpr Vector<3, T> q(v[0], v[1], v[2]);
            const Vector<3, T> t = T(2) * q.cross(vector);
            return vector + (v[3] * t) + q.cross(t);
        }

        inline Vector<3, T> getRightVector() const noexcept
        {
            return rotateVector(Vector<3, T>(1, 0, 0));
        }

        inline Vector<3, T> getUpVector() const noexcept
        {
            return rotateVector(Vector<3, T>(0, 1, 0));
        }

        inline Vector<3, T> getForwardVector() const noexcept
        {
            return rotateVector(Vector<3, T>(0, 0, 1));
        }

        inline Quaternion& lerp(const Quaternion& q1, const Quaternion& q2, T t) noexcept
        {
            *this = (q1 * (T(1) - t)) + (q2 * t);
            return *this;
        }
    };

    using QuaternionF = Quaternion<float>;
}

#endif // OUZEL_MATH_QUATERNION_HPP
<commit_msg>Fix the quaternion code<commit_after>// Copyright 2015-2019 Elviss Strazdins. All rights reserved.

#ifndef OUZEL_MATH_QUATERNION_HPP
#define OUZEL_MATH_QUATERNION_HPP

#include <cmath>
#include <cstddef>
#include <limits>
#include "math/Vector.hpp"

namespace ouzel
{
    template <typename T> class Quaternion final
    {
    public:
        T v[4]{0};

        constexpr Quaternion() noexcept {}

        constexpr Quaternion(const T x, const T y, const T z, const T w) noexcept:
            v{x, y, z, w}
        {
        }

        inline T& operator[](size_t index) noexcept { return v[index]; }
        constexpr T operator[](size_t index) const noexcept { return v[index]; }

        inline T& x() noexcept { return v[0]; }
        constexpr T x() const noexcept { return v[0]; }

        inline T& y() noexcept { return v[1]; }
        constexpr T y() const noexcept { return v[1]; }

        inline T& z() noexcept { return v[2]; }
        constexpr T z() const noexcept { return v[2]; }

        inline T& w() noexcept { return v[3]; }
        constexpr T w() const noexcept { return v[3]; }

        static constexpr Quaternion identity() noexcept
        {
            return Quaternion(0, 0, 0, 1);
        }

        constexpr const Quaternion operator*(const Quaternion& q) const noexcept
        {
            return Quaternion(v[0] * q.v[3] + v[1] * q.v[2] - v[2] * q.v[1] + v[3] * q.v[0],
                              -v[0] * q.v[2] + v[1] * q.v[3] + v[2] * q.v[0] + v[3] * q.v[1],
                              v[0] * q.v[1] - v[1] * q.v[0] + v[2] * q.v[3] + v[3] * q.v[2],
                              -v[0] * q.v[0] - v[1] * q.v[1] - v[2] * q.v[2] + v[3] * q.v[3]);
        }

        inline Quaternion& operator*=(const Quaternion& q) noexcept
        {
            constexpr T tempX = v[0] * q.v[3] + v[1] * q.v[2] - v[2] * q.v[1] + v[3] * q.v[0];
            constexpr T tempY = -v[0] * q.v[2] + v[1] * q.v[3] + v[2] * q.v[0] + v[3] * q.v[1];
            constexpr T tempZ = v[0] * q.v[1] - v[1] * q.v[0] + v[2] * q.v[3] + v[3] * q.v[2];
            constexpr T tempW = -v[0] * q.v[0] - v[1] * q.v[1] - v[2] * q.v[2] + v[3] * q.v[3];

            v[0] = tempX;
            v[1] = tempY;
            v[2] = tempZ;
            v[3] = tempW;

            return *this;
        }

        constexpr const Quaternion operator*(const T scalar) const noexcept
        {
            return Quaternion(v[0] * scalar,
                              v[1] * scalar,
                              v[2] * scalar,
                              v[3] * scalar);
        }

        inline Quaternion& operator*=(const T scalar) noexcept
        {
            v[0] *= scalar;
            v[1] *= scalar;
            v[2] *= scalar;
            v[3] *= scalar;

            return *this;
        }

        constexpr const Quaternion operator/(const T scalar) const noexcept
        {
            return Quaternion(v[0] / scalar,
                              v[1] / scalar,
                              v[2] / scalar,
                              v[3] / scalar);
        }

        inline Quaternion& operator/=(const T scalar) noexcept
        {
            v[0] /= scalar;
            v[1] /= scalar;
            v[2] /= scalar;
            v[3] /= scalar;

            return *this;
        }

        constexpr const Quaternion operator-() const noexcept
        {
            return Quaternion(-v[0], -v[1], -v[2], -v[3]);
        }

        constexpr const Quaternion operator+(const Quaternion& q) const noexcept
        {
            return Quaternion(v[0] + q.v[0],
                              v[1] + q.v[1],
                              v[2] + q.v[2],
                              v[3] + q.v[3]);
        }

        inline Quaternion& operator+=(const Quaternion& q) noexcept
        {
            v[0] += q.v[0];
            v[1] += q.v[1];
            v[2] += q.v[2];
            v[3] += q.v[3];

            return *this;
        }

        constexpr const Quaternion operator-(const Quaternion& q) const noexcept
        {
            return Quaternion(v[0] - q.v[0],
                              v[1] - q.v[1],
                              v[2] - q.v[2],
                              v[3] - q.v[3]);
        }

        inline Quaternion& operator-=(const Quaternion& q) noexcept
        {
            v[0] -= q.v[0];
            v[1] -= q.v[1];
            v[2] -= q.v[2];
            v[3] -= q.v[3];

            return *this;
        }

        constexpr bool operator==(const Quaternion& q) const noexcept
        {
            return v[0] == q.v[0] && v[1] == q.v[1] && v[2] == q.v[2] && v[3] == q.v[3];
        }

        constexpr bool operator!=(const Quaternion& q) const noexcept
        {
            return v[0] != q.v[0] || v[1] != q.v[1] || v[2] != q.v[2] || v[3] != q.v[3];
        }

        inline void negate() noexcept
        {
            v[0] = -v[0];
            v[1] = -v[1];
            v[2] = -v[2];
            v[3] = -v[3];
        }

        inline void conjugate() noexcept
        {
            v[0] = -v[0];
            v[1] = -v[1];
            v[2] = -v[2];
        }

        inline void invert() noexcept
        {
            constexpr T n2 = v[0] * v[0] + v[1] * v[1] + v[2] * v[2] + v[3] * v[3]; // norm squared
            if (n2 <= std::numeric_limits<T>::min())
                return;

            // conjugate divided by norm squared
            v[0] = -v[0] / n2;
            v[1] = -v[1] / n2;
            v[2] = -v[2] / n2;
            v[3] = v[3] / n2;
        }

        inline auto getNorm() const noexcept
        {
            constexpr T n = v[0] * v[0] + v[1] * v[1] + v[2] * v[2] + v[3] * v[3];
            if (n == T(1)) // already normalized
                return 1;

            return std::sqrt(n);
        }

        void normalize() noexcept
        {
            constexpr T s = v[0] * v[0] + v[1] * v[1] + v[2] * v[2] + v[3] * v[3];
            if (s == T(1)) // already normalized
                return;

            T n = std::sqrt(s);
            if (n <= std::numeric_limits<T>::min()) // too close to zero
                return;

            n = T(1) / n;
            v[0] *= n;
            v[1] *= n;
            v[2] *= n;
            v[3] *= n;
        }

        Quaternion normalized() const noexcept
        {
            constexpr T s = v[0] * v[0] + v[1] * v[1] + v[2] * v[2] + v[3] * v[3];
            if (s == T(1)) // already normalized
                return *this;

            T n = std::sqrt(s);
            if (n <= std::numeric_limits<T>::min()) // too close to zero
                return *this;

            n = T(1) / n;
            return *this * n;
        }

        void rotate(const T angle, const Vector<3, T>& axis) noexcept
        {
            const auto normalizedAxis = axis.normalized();

            const T cosAngle = std::cos(angle / T(2));
            const T sinAngle = std::sin(angle / T(2));

            v[0] = normalizedAxis.v[0] * sinAngle;
            v[1] = normalizedAxis.v[1] * sinAngle;
            v[2] = normalizedAxis.v[2] * sinAngle;
            v[3] = cosAngle;
        }

        void getRotation(T& angle, Vector<3, T>& axis) const noexcept
        {
            angle = T(2) * std::acos(v[3]);
            const T s = std::sqrt(T(1) - v[3] * v[3]);
            if (s <= std::numeric_limits<T>::min()) // too close to zero
            {
                axis.v[0] = v[0];
                axis.v[1] = v[1];
                axis.v[2] = v[2];
            }
            else
            {
                axis.v[0] = v[0] / s;
                axis.v[1] = v[1] / s;
                axis.v[2] = v[2] / s;
            }
        }

        Vector<3, T> getEulerAngles() const noexcept
        {
            Vector<3, T> result;
            result.v[0] = std::atan2(2 * (v[1] * v[2] + v[3] * v[0]), v[3] * v[3] - v[0] * v[0] - v[1] * v[1] + v[2] * v[2]);
            result.v[1] = std::asin(-2 * (v[0] * v[2] - v[3] * v[1]));
            result.v[2] = std::atan2(2 * (v[0] * v[1] + v[3] * v[2]), v[3] * v[3] + v[0] * v[0] - v[1] * v[1] - v[2] * v[2]);
            return result;
        }

        inline auto getEulerAngleX() const noexcept
        {
            return std::atan2(T(2) * (v[1] * v[2] + v[3] * v[0]), v[3] * v[3] - v[0] * v[0] - v[1] * v[1] + v[2] * v[2]);
        }

        inline auto getEulerAngleY() const noexcept
        {
            return std::asin(T(-2) * (v[0] * v[2] - v[3] * v[1]));
        }

        inline auto getEulerAngleZ() const noexcept
        {
            return std::atan2(T(2) * (v[0] * v[1] + v[3] * v[2]), v[3] * v[3] + v[0] * v[0] - v[1] * v[1] - v[2] * v[2]);
        }

        void setEulerAngles(const Vector<3, T>& angles) noexcept
        {
            const T angleR = angles.v[0] / T(2);
            const T sr = std::sin(angleR);
            const T cr = std::cos(angleR);

            const T angleP = angles.v[1] / T(2);
            const T sp = std::sin(angleP);
            const T cp = std::cos(angleP);

            const T angleY = angles.v[2] / T(2);
            const T sy = std::sin(angleY);
            const T cy = std::cos(angleY);

            const T cpcy = cp * cy;
            const T spcy = sp * cy;
            const T cpsy = cp * sy;
            const T spsy = sp * sy;

            v[0] = sr * cpcy - cr * spsy;
            v[1] = cr * spcy + sr * cpsy;
            v[2] = cr * cpsy - sr * spcy;
            v[3] = cr * cpcy + sr * spsy;
        }

        inline const Vector<3, T> operator*(const Vector<3, T>& vector) const noexcept
        {
            return rotateVector(vector);
        }

        inline Vector<3, T> rotateVector(const Vector<3, T>& vector) const noexcept
        {
            constexpr Vector<3, T> q(v[0], v[1], v[2]);
            const Vector<3, T> t = T(2) * q.cross(vector);
            return vector + (v[3] * t) + q.cross(t);
        }

        inline Vector<3, T> getRightVector() const noexcept
        {
            return rotateVector(Vector<3, T>(1, 0, 0));
        }

        inline Vector<3, T> getUpVector() const noexcept
        {
            return rotateVector(Vector<3, T>(0, 1, 0));
        }

        inline Vector<3, T> getForwardVector() const noexcept
        {
            return rotateVector(Vector<3, T>(0, 0, 1));
        }

        inline Quaternion& lerp(const Quaternion& q1, const Quaternion& q2, T t) noexcept
        {
            *this = (q1 * (T(1) - t)) + (q2 * t);
            return *this;
        }
    };

    using QuaternionF = Quaternion<float>;
}

#endif // OUZEL_MATH_QUATERNION_HPP
<|endoftext|>