text:
#include "stdfx/shaderfx.h"

// TnzStdfx includes
#include "stdfx.h"
#include "stdfx/shaderinterface.h"
#include "stdfx/shadingcontext.h"

// TnzBase includes
#include "tfxparam.h"
#include "tparamset.h"
#include "trenderresourcemanager.h"
#include "trenderer.h"

// TnzCore includes
#include "tthread.h"
#include "tfilepath.h"
#include "tstream.h"
#include "tfunctorinvoker.h"
#include "tmsgcore.h"

// Qt includes
#include <QDir>
#include <QOpenGLShaderProgram>
#include <QCoreApplication>
#include <QOffscreenSurface>

// Glew include
#include <GL/glew.h>

// Boost includes
#include <boost/any.hpp>
#include <boost/iterator/transform_iterator.hpp>
#include <boost/ptr_container/ptr_vector.hpp>

// Diagnostics include
//#define DIAGNOSTICS
#ifdef DIAGNOSTICS
#include "diagnostics.h"
#endif

//===================================================

//    Forward Declarations

class ShaderFxDeclaration;

//===================================================

//****************************************************************************
//    Local Namespace  stuff
//****************************************************************************

namespace {

// Classes

struct ContextLocker {
  ShadingContext &m_ctx;
  bool m_locked;

public:
  ContextLocker(ShadingContext &ctx) : m_ctx(ctx), m_locked(false) { relock(); }
  ~ContextLocker() {
    if (m_locked) unlock();
  }

  void relock() {
    assert(!m_locked), m_locked = true;
    m_ctx.makeCurrent();
  }

  void unlock() {
    assert(m_locked), m_locked = false;
    m_ctx.doneCurrent();
  }
};

struct ProgramBinder {
  QOpenGLShaderProgram *m_prog;

public:
  ProgramBinder(QOpenGLShaderProgram *prog) : m_prog(prog) { m_prog->bind(); }
  ~ProgramBinder() {
    glUseProgram(0);  // m_prog->release();
  }
};

struct RectF {
  GLfloat m_val[4];
  RectF(GLfloat x0, GLfloat y0, GLfloat x1, GLfloat y1) {
    m_val[0] = x0, m_val[1] = y0, m_val[2] = x1, m_val[3] = y1;
  }
  RectF(const TRectD &rect) {
    m_val[0] = rect.x0, m_val[1] = rect.y0, m_val[2] = rect.x1,
    m_val[3] = rect.y1;
  }

  operator TRectD() const {
    return TRectD(m_val[0], m_val[1], m_val[2], m_val[3]);
  }
  bool operator==(const RectF &rect) const {
    return (memcmp(m_val, rect.m_val, sizeof(this)) == 0);
  }
};

struct AffineF {
  GLfloat m_val[9];
  operator TAffine() const {
    return TAffine(m_val[0], m_val[3], m_val[6], m_val[1], m_val[4], m_val[7]);
  }
  // Observe that mat3 from GLSL stores elements column-wise; this explains the
  // weird indexing
};

// Global Variables

typedef std::map<QString, ShaderFxDeclaration *> FxDeclarationsMap;
FxDeclarationsMap l_shaderFxDeclarations;

enum Measures { NONE, PERCENT, LENGTH, ANGLE, MEASURESCOUNT };

static const std::string l_measureNames[MEASURESCOUNT] = {"", "percentage",
                                                          "fxLength", "angle"};

static const TParamUIConcept::Type
    l_conceptTypes[ShaderInterface::CONCEPTSCOUNT -
                   ShaderInterface::UI_CONCEPTS] = {
        TParamUIConcept::RADIUS,  TParamUIConcept::WIDTH,
        TParamUIConcept::ANGLE,   TParamUIConcept::POINT,
        TParamUIConcept::POINT_2, TParamUIConcept::VECTOR,
        TParamUIConcept::POLAR,   TParamUIConcept::SIZE,
        TParamUIConcept::QUAD,    TParamUIConcept::RECT,
        TParamUIConcept::COMPASS, TParamUIConcept::COMPASS_SPIN};

// Functions

inline bool isObsolete(const TFilePath &fp, const QDateTime &lastModified) {
  QFileInfo fInfo(QString::fromStdWString(fp.getWideString()));
  return (lastModified != fInfo.lastModified());
}

inline TRectD tileRect(const TTile &tile) {
  const TDimension &dim = tile.getRaster()->getSize();
  return TRectD(tile.m_pos, TDimensionD(dim.lx, dim.ly));
}

inline void ceilRect(TRectD &rect) {
  rect.x0 = tfloor(rect.x0), rect.y0 = tfloor(rect.y0);
  rect.x1 = tceil(rect.x1), rect.y1 = tceil(rect.y1);
}

}  // namespace

//****************************************************************************
//    Shader Fx  declaration
//****************************************************************************

class ShaderFx final : public TStandardZeraryFx {
  FX_PLUGIN_DECLARATION(ShaderFx)

  const ShaderInterface *m_shaderInterface;  //!< Shader fx 'description'.
  std::vector<boost::any>
      m_params;  //!< Parameters for the shader fx. The actual parameter
                 //!< type depends on the shader interface declaration.
  std::vector<TParamUIConcept>
      m_uiConcepts;  //!< UI concepts related to m_params.
  boost::ptr_vector<TRasterFxPort>
      m_inputPorts;  //!< Input ports for the shader fx.

public:
  ShaderFx() : m_shaderInterface() {
    assert(false);
  }  // Necessary due to TPersist inheritance, but must NOT be used
  ShaderFx(const ShaderInterface *shaderInterface)
      : m_shaderInterface(shaderInterface) {
    initialize();
  }

  // void setShaderInterface(const ShaderInterface& shaderInterface);
  void initialize();

  void getParamUIs(TParamUIConcept *&params, int &length) override;
  bool doGetBBox(double frame, TRectD &bBox,
                 const TRenderSettings &info) override;
  bool canHandle(const TRenderSettings &info, double frame) override;

  void doDryCompute(TRectD &rect, double frame,
                    const TRenderSettings &ri) override;
  void doCompute(TTile &tile, double frame, const TRenderSettings &ri) override;

private:
  QOpenGLShaderProgram *touchShaderProgram(
      const ShaderInterface::ShaderData &sd, ShadingContext &context,
      int varyingsCount = 0, const GLchar **varyings = 0);

  void bindParameters(QOpenGLShaderProgram *shaderProgram, double frame);

  void bindWorldTransform(QOpenGLShaderProgram *shaderProgram,
                          const TAffine &worldToDst);

  void getInputData(const TRectD &rect, double frame, const TRenderSettings &ri,
                    std::vector<TRectD> &inputRects,
                    std::vector<TAffine> &inputAffines,
                    ShadingContext &context);
};

//****************************************************************************
//    ShaderFxDeclaration  definition
//****************************************************************************

class ShaderFxDeclaration final : public TFxDeclaration {
  ShaderInterface m_shaderInterface;

public:
  ShaderFxDeclaration(const ShaderInterface &shaderInterface)
      : TFxDeclaration(
            TFxInfo(shaderInterface.mainShader().m_name.toStdString(), false))
      , m_shaderInterface(shaderInterface) {}

  TPersist *create() const override { return new ShaderFx(&m_shaderInterface); }
};

//****************************************************************************
//    ShadingContextManager  definition
//****************************************************************************

class ShadingContextManager final : public QObject {
  mutable QMutex m_mutex;

  std::unique_ptr<ShadingContext> m_shadingContext;
  TAtomicVar m_activeRenderInstances;
  std::unique_ptr<QOffscreenSurface> m_surface;

public:
  ShadingContextManager() {
    /*
The ShadingContext's QGLPixelBuffer must be destroyed *before* the global
QApplication
is. So, we will attach to a suitable parent object whose lifespan is shorter.

FYI - yes, this approach was adopted after a long and PAINFUL wrestling session
with Qt.
Suggestions are welcome as this is a tad beyond ridiculous...
*/

    QObject *mainScopeBoundObject =
        QCoreApplication::instance()->findChild<QObject *>("mainScope");

    assert(thread() ==
           mainScopeBoundObject
               ->thread());  // Parent object must be in the same thread,
    // setParent(mainScopeBoundObject);  // otherwise reparenting fails
    m_surface.reset(new QOffscreenSurface());
    m_surface->create();
    m_shadingContext.reset(new ShadingContext(m_surface.get()));
  }

  static ShadingContextManager *instance() {
    static ShadingContextManager *theManager = new ShadingContextManager;
    return theManager;
  }

  QMutex *mutex() const { return &m_mutex; }

  const ShadingContext &shadingContext() const { return *m_shadingContext; }
  ShadingContext &shadingContext() { return *m_shadingContext; }

  void onRenderInstanceStart() { ++m_activeRenderInstances; }

  void onRenderInstanceEnd() {
    if (--m_activeRenderInstances == 0) {
      QMutexLocker mLocker(&m_mutex);

      // Release the shading context's output buffer
      ::ContextLocker cLocker(*m_shadingContext);
      m_shadingContext->resize(0, 0);

#ifdef DIAGNOSTICS
      DIAGNOSTICS_DUMP("ShaderLogs");
      DIAGNOSTICS_CLEAR;
#endif
    }
  }

  ShadingContext::Support touchSupport() {
    struct {
      ShadingContextManager *m_this;
      ShadingContext::Support support() {
        QMutexLocker mLocker(&m_this->m_mutex);
        ::ContextLocker cLocker(*m_this->m_shadingContext);

        return ShadingContext::support();
      }
    } locals = {this};

    static ShadingContext::Support sup = locals.support();

    static bool sentMsg = false;
    if (!sentMsg) {
      switch (sup) {
      case ShadingContext::NO_PIXEL_BUFFER:
        DVGui::warning(QOpenGLShaderProgram::tr(
            "This system configuration does not support OpenGL Pixel Buffers. "
            "Shader Fxs will not be able to render."));
        break;

      case ShadingContext::NO_SHADERS:
        DVGui::warning(QOpenGLShaderProgram::tr(
            "This system configuration does not support OpenGL Shader "
            "Programs. Shader Fxs will not be able to render."));
        break;
      default:
        break;
      }

      sentMsg = true;
    }

    return sup;
  }

  QOffscreenSurface *getSurface() { return m_surface.get(); }
};

template class DV_EXPORT_API TFxDeclarationT<ShaderFx>;

//****************************************************************************
//    ShadingContextManagerDelegate  definition
//****************************************************************************

class MessageCreateContext final : public TThread::Message {
  ShadingContextManager *man;

public:
  MessageCreateContext(ShadingContextManager *ctx) : man(ctx) {}

  void onDeliver() override { man->onRenderInstanceEnd(); }

  TThread::Message *clone() const override {
    return new MessageCreateContext(*this);
  }
};

class SCMDelegate final : public TRenderResourceManager {
  T_RENDER_RESOURCE_MANAGER

  void onRenderInstanceStart(unsigned long id) override {
    ShadingContextManager::instance()->onRenderInstanceStart();
  }

  void onRenderInstanceEnd(unsigned long id) override {
    if (!TThread::isMainThread()) {
      /* tofflinegl のときとは逆で main thread に dispatch する */
      MessageCreateContext(ShadingContextManager::instance()).sendBlocking();
    } else {
      ShadingContextManager::instance()->onRenderInstanceEnd();
    }
  }
};

//-------------------------------------------------------------------

class SCMDelegateGenerator final : public TRenderResourceManagerGenerator {
public:
  SCMDelegateGenerator() : TRenderResourceManagerGenerator(false) {
    /*
Again, this has to do with the manager's lifetime issue.
The SCM must be created in the MAIN THREAD, but NOT BEFORE the
QCoreApplication itself has been created. The easiest way to do so
is scheduling a slot to be executed as soon as event processing starts.
*/

    struct InstanceSCM final : public TFunctorInvoker::BaseFunctor {
      void operator()() override { ShadingContextManager::instance(); }
    };

    TFunctorInvoker::instance()->invokeQueued(new InstanceSCM);
  }

  TRenderResourceManager *operator()() override { return new SCMDelegate; }
};

MANAGER_FILESCOPE_DECLARATION(SCMDelegate, SCMDelegateGenerator)

//****************************************************************************
//    Shader Fx  implementation
//****************************************************************************

void ShaderFx::initialize() {
  struct {
    ShaderFx *m_this;

    inline void addUiConcept(const ShaderInterface::Parameter &siParam,
                             const TParamP &param) {
      if (siParam.m_concept.m_type >= ShaderInterface::UI_CONCEPTS &&
          siParam.m_concept.m_type < ShaderInterface::CONCEPTSCOUNT) {
        m_this->m_uiConcepts.push_back(TParamUIConcept());

        TParamUIConcept &uiConcept = m_this->m_uiConcepts.back();
        uiConcept.m_type           = ::l_conceptTypes[siParam.m_concept.m_type -
                                            ShaderInterface::UI_CONCEPTS];
        uiConcept.m_label          = siParam.m_concept.m_label.toStdString();
        uiConcept.m_params.push_back(param);
      }
    }

    inline void addUiConcept(const ShaderInterface::ParameterConcept &concept) {
      if (!concept.isUI() || concept.m_parameterNames.empty()) return;

      TParamUIConcept uiConcept = {
          ::l_conceptTypes[concept.m_type - ShaderInterface::UI_CONCEPTS],
          concept.m_label.toStdString()};

      int n, nCount = int(concept.m_parameterNames.size());
      for (n = 0; n != nCount; ++n) {
        TParam *param = m_this->getParams()->getParam(
            concept.m_parameterNames[n].toStdString());
        if (!param) break;

        uiConcept.m_params.push_back(param);
      }

      if (uiConcept.m_params.size() == concept.m_parameterNames.size())
        m_this->m_uiConcepts.push_back(uiConcept);
    }

  } locals = {this};

  assert(m_params.empty());  // Interfaces should not be re-set

  // Allocate parameters following the specified interface
  const std::vector<ShaderInterface::Parameter> &siParams =
      m_shaderInterface->parameters();

  int p, pCount = int(siParams.size());
  m_params.reserve(pCount);

  for (p = 0; p != pCount; ++p) {
    const ShaderInterface::Parameter &siParam = siParams[p];

    switch (siParam.m_type) {
    case ShaderInterface::BOOL: {
      TBoolParamP param(siParam.m_default.m_bool);

      m_params.push_back(param);
      bindParam(this, siParam.m_name.toStdString(),
                *boost::unsafe_any_cast<TBoolParamP>(&m_params.back()));

      break;
    }

    case ShaderInterface::FLOAT: {
      TDoubleParamP param(siParam.m_default.m_float);
      param->setValueRange(siParam.m_range[0].m_float,
                           siParam.m_range[1].m_float);

      locals.addUiConcept(siParam, param);

      switch (siParam.m_concept.m_type) {
      case ShaderInterface::PERCENT:
        param->setMeasureName(l_measureNames[PERCENT]);
        break;

      case ShaderInterface::LENGTH:
      case ShaderInterface::RADIUS_UI:
      case ShaderInterface::WIDTH_UI:
      case ShaderInterface::SIZE_UI:
        param->setMeasureName(l_measureNames[LENGTH]);
        break;

      case ShaderInterface::ANGLE:
      case ShaderInterface::ANGLE_UI:
        param->setMeasureName(l_measureNames[ANGLE]);
        break;
      default:
        break;
      }

      m_params.push_back(param);
      bindParam(this, siParam.m_name.toStdString(),
                *boost::unsafe_any_cast<TDoubleParamP>(&m_params.back()));
      break;
    }

    case ShaderInterface::VEC2: {
      TPointParamP param(
          TPointD(siParam.m_default.m_vec2[0], siParam.m_default.m_vec2[1]));

      param->getX()->setValueRange(siParam.m_range[0].m_vec2[0],
                                   siParam.m_range[1].m_vec2[0]);
      param->getY()->setValueRange(siParam.m_range[0].m_vec2[1],
                                   siParam.m_range[1].m_vec2[1]);

      locals.addUiConcept(siParam, param);

      switch (siParam.m_concept.m_type) {
      case ShaderInterface::PERCENT:
        param->getX()->setMeasureName(l_measureNames[PERCENT]);
        param->getY()->setMeasureName(l_measureNames[PERCENT]);
        break;

      case ShaderInterface::LENGTH:
      case ShaderInterface::POINT:
      case ShaderInterface::POINT_UI:
      case ShaderInterface::VECTOR_UI:
      case ShaderInterface::WIDTH_UI:
      case ShaderInterface::SIZE_UI:
        param->getX()->setMeasureName(l_measureNames[LENGTH]);
        param->getY()->setMeasureName(l_measureNames[LENGTH]);
        break;

      case ShaderInterface::ANGLE:
      case ShaderInterface::ANGLE_UI:
        param->getX()->setMeasureName(l_measureNames[ANGLE]);
        param->getY()->setMeasureName(l_measureNames[ANGLE]);
        break;
      default:
        break;
      }

      m_params.push_back(param);
      bindParam(this, siParam.m_name.toStdString(),
                *boost::unsafe_any_cast<TPointParamP>(&m_params.back()));
      break;
    }

    case ShaderInterface::INT: {
      TIntParamP param(siParam.m_default.m_int);
      param->setValueRange(siParam.m_range[0].m_int, siParam.m_range[1].m_int);

      m_params.push_back(param);
      bindParam(this, siParam.m_name.toStdString(),
                *boost::unsafe_any_cast<TIntParamP>(&m_params.back()));
      break;
    }

    case ShaderInterface::RGBA: {
      TPixelParamP param(
          TPixel32(siParam.m_default.m_rgba[0], siParam.m_default.m_rgba[1],
                   siParam.m_default.m_rgba[2], siParam.m_default.m_rgba[3]));

      m_params.push_back(param);
      bindParam(this, siParam.m_name.toStdString(),
                *boost::unsafe_any_cast<TPixelParamP>(&m_params.back()));
      break;
    }

    case ShaderInterface::RGB: {
      TPixelParamP param(TPixel32(siParam.m_default.m_rgb[0],
                                  siParam.m_default.m_rgb[1],
                                  siParam.m_default.m_rgb[2]));

      param->enableMatte(false);

      m_params.push_back(param);
      bindParam(this, siParam.m_name.toStdString(),
                *boost::unsafe_any_cast<TPixelParamP>(&m_params.back()));
      break;
    }
    default:
      break;
    }
  }

  // Add composite UI concepts
  const std::vector<ShaderInterface::ParameterConcept> &parConcepts =
      m_shaderInterface->m_parConcepts;

  int c, cCount = int(parConcepts.size());
  for (c = 0; c != cCount; ++c) locals.addUiConcept(parConcepts[c]);

  // Add input ports
  const std::vector<QString> &inputPorts = m_shaderInterface->inputPorts();

  int i, iCount = int(inputPorts.size());
  m_inputPorts.reserve(iCount);

  for (i = 0; i != iCount; ++i) {
    m_inputPorts.push_back(new TRasterFxPort);
    addInputPort(inputPorts[i].toStdString(), m_inputPorts[i]);
  }
}

//-------------------------------------------------------------------

void ShaderFx::getParamUIs(TParamUIConcept *&params, int &length) {
  length = int(m_uiConcepts.size());
  params = new TParamUIConcept[length];

  std::copy(m_uiConcepts.begin(), m_uiConcepts.end(), params);
}

//-------------------------------------------------------------------

bool ShaderFx::doGetBBox(double frame, TRectD &bbox,
                         const TRenderSettings &info) {
  static const ::RectF infiniteRectF(-(std::numeric_limits<GLfloat>::max)(),
                                     -(std::numeric_limits<GLfloat>::max)(),
                                     (std::numeric_limits<GLfloat>::max)(),
                                     (std::numeric_limits<GLfloat>::max)());

  bbox = TConsts::infiniteRectD;

  const ShaderInterface::ShaderData &sd = m_shaderInterface->bboxShader();
  if (!sd.isValid()) return true;

  ShadingContextManager *manager = ShadingContextManager::instance();
  if (manager->touchSupport() != ShadingContext::OK) return true;

  // Remember: info.m_affine MUST NOT BE CONSIDERED in doGetBBox's
  // implementation
  ::RectF bboxF(infiniteRectF);

  QMutexLocker mLocker(manager->mutex());

  // ShadingContext& context = manager->shadingContext();
  std::shared_ptr<ShadingContext> shadingContextPtr(
      new ShadingContext(manager->getSurface()));
  ShadingContext &context = *shadingContextPtr.get();

  ::ContextLocker cLocker(context);

  // Build the varyings data
  QOpenGLShaderProgram *prog = 0;
  {
    const GLchar *varyingNames[] = {"outputBBox"};
    prog = touchShaderProgram(sd, context, 1, &varyingNames[0]);
  }

  int pCount = getInputPortCount();

  std::vector<RectF> inputBBoxes(pCount, ::RectF(TRectD()));

  for (int p = 0; p != pCount; ++p) {
    TRasterFxPort &port = m_inputPorts[p];
    if (port.isConnected()) {
      TRectD inputBBox;

      cLocker.unlock();
      mLocker.unlock();

      if (port->doGetBBox(frame, inputBBox, info))
        inputBBoxes[p] = (inputBBox == TConsts::infiniteRectD)
                             ? infiniteRectF
                             : ::RectF(inputBBox);

      mLocker.relock();
      cLocker.relock();
    }
  }

  {
    ProgramBinder progBinder(prog);

    // Bind uniform parameters
    bindParameters(prog, frame);

    prog->setUniformValue("infiniteRect", infiniteRectF.m_val[0],
                          infiniteRectF.m_val[1], infiniteRectF.m_val[2],
                          infiniteRectF.m_val[3]);

    prog->setUniformValueArray("inputBBox", inputBBoxes[0].m_val,
                               int(inputBBoxes.size()), 4);

    // Perform transform feedback
    const GLsizeiptr varyingSizes[] = {sizeof(::RectF)};
    GLvoid *bufs[]                  = {bboxF.m_val};

    context.transformFeedback(1, varyingSizes, bufs);
  }

  // Finalize output
  bbox = (bboxF == infiniteRectF) ? TConsts::infiniteRectD : TRectD(bboxF);
  return true;
}

//-------------------------------------------------------------------

bool ShaderFx::canHandle(const TRenderSettings &info, double frame) {
  return (m_shaderInterface->hwtType() == ShaderInterface::ANY)
             ? true
             : isAlmostIsotropic(info.m_affine);
}

//-------------------------------------------------------------------

QOpenGLShaderProgram *ShaderFx::touchShaderProgram(
    const ShaderInterface::ShaderData &sd, ShadingContext &context,
    int varyingsCount, const GLchar **varyings) {
  typedef std::pair<QOpenGLShaderProgram *, QDateTime> CompiledShader;

  struct locals {
    inline static void logCompilation(QOpenGLShaderProgram *program) {
      // Log shaders - observe that we'll look into the program's *children*,
      // not its
      // shaders. This is necessary as uncompiled shaders are not added to the
      // program.
      const QObjectList &children = program->children();

      int c, cCount = children.size();
      for (c = 0; c != cCount; ++c) {
        if (QOpenGLShader *shader =
                dynamic_cast<QOpenGLShader *>(children[c])) {
          const QString &log = shader->log();
          if (!log.isEmpty()) DVGui::info(log);
        }
      }

      // ShaderProgram linking logs
      const QString &log = program->log();
      if (!log.isEmpty()) DVGui::info(log);
    }
  };  // locals

  // ShadingContext& context =
  // ShadingContextManager::instance()->shadingContext();

  CompiledShader cs = context.shaderData(sd.m_name);
  if (!cs.first || ::isObsolete(sd.m_path, cs.second)) {
    cs = m_shaderInterface->makeProgram(sd, varyingsCount, varyings);
    context.addShaderProgram(sd.m_name, cs.first, cs.second);

    locals::logCompilation(cs.first);
  }

  assert(cs.first);
  return cs.first;
}

//-------------------------------------------------------------------

void ShaderFx::bindParameters(QOpenGLShaderProgram *program, double frame) {
  // Bind fx parameters
  const std::vector<ShaderInterface::Parameter> &siParams =
      m_shaderInterface->parameters();

  assert(siParams.size() == m_params.size());

  int p, pCount = int(siParams.size());
  for (p = 0; p != pCount; ++p) {
    const ShaderInterface::Parameter &siParam = siParams[p];

    switch (siParam.m_type) {
    case ShaderInterface::BOOL: {
      const TBoolParamP &param =
          *boost::unsafe_any_cast<TBoolParamP>(&m_params[p]);
      program->setUniformValue(siParam.m_name.toUtf8().data(),
                               (GLboolean)param->getValue());
      break;
    }

    case ShaderInterface::FLOAT: {
      const TDoubleParamP &param =
          *boost::unsafe_any_cast<TDoubleParamP>(&m_params[p]);
      program->setUniformValue(siParam.m_name.toUtf8().data(),
                               (GLfloat)param->getValue(frame));
      break;
    }

    case ShaderInterface::VEC2: {
      const TPointParamP &param =
          *boost::unsafe_any_cast<TPointParamP>(&m_params[p]);

      const TPointD &value = param->getValue(frame);
      program->setUniformValue(siParam.m_name.toUtf8().data(), (GLfloat)value.x,
                               (GLfloat)value.y);
      break;
    }

    case ShaderInterface::INT: {
      const TIntParamP &param =
          *boost::unsafe_any_cast<TIntParamP>(&m_params[p]);
      program->setUniformValue(siParam.m_name.toUtf8().data(),
                               (GLint)param->getValue());
      break;
    }

    case ShaderInterface::RGBA:
    case ShaderInterface::RGB: {
      const TPixelParamP &param =
          *boost::unsafe_any_cast<TPixelParamP>(&m_params[p]);

      const TPixel32 &value = param->getValue(frame);
      program->setUniformValue(
          siParam.m_name.toUtf8().data(), (GLfloat)value.r / 255.0f,
          (GLfloat)value.g / 255.0f, (GLfloat)value.b / 255.0f,
          (GLfloat)value.m / 255.0f);
      break;
    }
    default:
      break;
    }
  }
}

//-------------------------------------------------------------------

void ShaderFx::bindWorldTransform(QOpenGLShaderProgram *program,
                                  const TAffine &worldToDst) {
// Bind transformation affine
#if QT_VERSION >= 0x050500
  float qwToD[9] = {static_cast<float>(worldToDst.a11),
                    static_cast<float>(worldToDst.a12),
                    static_cast<float>(worldToDst.a13),
                    static_cast<float>(worldToDst.a21),
                    static_cast<float>(worldToDst.a22),
                    static_cast<float>(worldToDst.a23),
                    0.0f,
                    0.0f,
                    1.0f};
#else
  qreal qwToD[9] = {worldToDst.a11,
                    worldToDst.a12,
                    worldToDst.a13,
                    worldToDst.a21,
                    worldToDst.a22,
                    worldToDst.a23,
                    0.0,
                    0.0,
                    1.0};
#endif
  program->setUniformValue("worldToOutput", QMatrix3x3(qwToD));

  const TAffine &dToW = worldToDst.inv();
#if QT_VERSION >= 0x050500
  float qdToW[9] = {static_cast<float>(dToW.a11),
                    static_cast<float>(dToW.a12),
                    static_cast<float>(dToW.a13),
                    static_cast<float>(dToW.a21),
                    static_cast<float>(dToW.a22),
                    static_cast<float>(dToW.a23),
                    0.0f,
                    0.0f,
                    1.0f};
#else
  qreal qdToW[9] = {dToW.a11, dToW.a12, dToW.a13, dToW.a21, dToW.a22,
                    dToW.a23, 0.0,      0.0,      1.0};
#endif
  program->setUniformValue("outputToWorld", QMatrix3x3(qdToW));
}

//-------------------------------------------------------------------

void ShaderFx::getInputData(const TRectD &rect, double frame,
                            const TRenderSettings &ri,
                            std::vector<TRectD> &inputRects,
                            std::vector<TAffine> &inputAffines,
                            ShadingContext &context) {
  struct locals {
    static inline void addNames(std::vector<std::string> &names,
                                const char *prefix, int pCount) {
      for (int p = 0; p != pCount; ++p)
        names.push_back((prefix + QString("[%1]").arg(p)).toStdString());
    }
  };

  const ShaderInterface::ShaderData &sd = m_shaderInterface->inputPortsShader();
  if (!sd.isValid()) {
    inputRects.resize(getInputPortCount());
    std::fill(inputRects.begin(), inputRects.end(), rect);

    inputAffines.resize(getInputPortCount());
    std::fill(inputAffines.begin(), inputAffines.end(), ri.m_affine);

    return;
  }

  // ShadingContext& context =
  // ShadingContextManager::instance()->shadingContext();

  std::vector<GLfloat> buf;
  int pCount = getInputPortCount();

  // Build the varyings data
  QOpenGLShaderProgram *prog = 0;
  {
    // Unsubscripted varying arrays on transform feedback seems to be
    // unsupported
    // on ATI cards. We have to declare EACH array name - e.g. inputRect[0],
    // intputRect[1], etc..

    const GLchar *varyingPrefixes[] = {"inputRect", "worldToInput"};
    const int varyingsCount = sizeof(varyingPrefixes) / sizeof(GLchar *);

    std::vector<std::string> varyingStrings;
    varyingStrings.reserve(varyingsCount);

    for (int v = 0; v != varyingsCount; ++v)
      locals::addNames(varyingStrings, varyingPrefixes[v], pCount);

#if defined(__APPLE_CC__)
    /* OSX10.8 の clang -stdlib=libc++ だと link 時 &std::string::c_str が
     * undefined になってしまう */
    std::vector<const GLchar *> varyingNames(varyingStrings.size());
    auto conv = [](const std::string &i) { return i.c_str(); };
    std::transform(varyingStrings.begin(), varyingStrings.end(),
                   varyingNames.begin(), conv);
#else
    std::vector<const GLchar *> varyingNames(
        boost::make_transform_iterator(varyingStrings.begin(),
                                       std::mem_fun_ref(&std::string::c_str)),
        boost::make_transform_iterator(varyingStrings.end(),
                                       std::mem_fun_ref(&std::string::c_str)));
#endif
    prog = touchShaderProgram(sd, context, int(varyingNames.size()),
                              &varyingNames[0]);
  }

  {
    ProgramBinder progBinder(prog);

    // Build varying buffers
    int bufFloatsCount =
        pCount * (sizeof(RectF) + sizeof(AffineF)) / sizeof(GLfloat);
    buf.resize(bufFloatsCount);

    // Bind uniform parameters
    bindParameters(prog, frame);
    bindWorldTransform(prog, ri.m_affine);

    prog->setUniformValue("outputRect", (GLfloat)rect.x0, (GLfloat)rect.y0,
                          (GLfloat)rect.x1, (GLfloat)rect.y1);

    // Perform transform feedback
    const GLsizeiptr varyingSizes[] = {
        static_cast<GLsizeiptr>(bufFloatsCount * sizeof(GLfloat))};
    GLvoid *bufs[] = {&buf[0]};

    context.transformFeedback(1, varyingSizes, bufs);

#ifdef TRANSFORM_FEEDBACK_COUT
    std::cout << "trFeedback: ";
    for (int f = 0; f != bufFloatsCount; ++f) std::cout << buf[f] << " ";
    std::cout << "\n" << std::endl;
#endif
  }

  // Finalize output
  const RectF *rBufBegin(reinterpret_cast<const RectF *>(&buf[0])),
      *rBufEnd(rBufBegin + pCount);
  std::copy(rBufBegin, rBufEnd, &inputRects[0]);

  const AffineF *aBufBegin(reinterpret_cast<const AffineF *>(rBufEnd)),
      *aBufEnd(aBufBegin + pCount);
  std::copy(aBufBegin, aBufEnd, &inputAffines[0]);
}

//-------------------------------------------------------------------

void ShaderFx::doCompute(TTile &tile, double frame,
                         const TRenderSettings &info) {
  struct locals {
    struct TexturesStorage {
      ShadingContext &m_ctx;
      std::vector<GLuint> m_texIds;

      TexturesStorage(ShadingContext &ctx, int pCount) : m_ctx(ctx) {
        m_texIds.reserve(pCount);
      }

      ~TexturesStorage() {
        for (auto const &texId : m_texIds) {
          m_ctx.unloadTexture(texId);
        }
      }

      void load(const TRasterP &ras, GLuint texUnit) {
        if (ras) m_texIds.push_back(m_ctx.loadTexture(ras, texUnit));
      }
    };

    inline static QOpenGLFramebufferObjectFormat makeFormat(int bpp) {
      QOpenGLFramebufferObjectFormat fmt;
      if (bpp == 64) fmt.setInternalTextureFormat(GL_RGBA16);
      return fmt;
    }

    inline static void touchOutputSize(ShadingContext &context,
                                       const TDimension &size, int bpp) {
      const QOpenGLFramebufferObjectFormat &fmt = makeFormat(bpp);

      const TDimension &currentSize                    = context.size();
      const QOpenGLFramebufferObjectFormat &currentFmt = context.format();

      if (currentSize.lx < size.lx || currentSize.ly < size.ly ||
          currentFmt != fmt)
        context.resize(std::max(size.lx, currentSize.lx),
                       std::max(size.ly, currentSize.ly), fmt);
    }
  };  // locals

  ShadingContextManager *manager = ShadingContextManager::instance();
  if (manager->touchSupport() != ShadingContext::OK) return;

  QMutexLocker mLocker(
      manager->mutex());  // As GPU access can be considered sequential anyway,
                          // lock the full-scale mutex
  std::shared_ptr<ShadingContext> shadingContextPtr(
      new ShadingContext(manager->getSurface()));
  ShadingContext &context = *shadingContextPtr.get();
  // ShadingContext& context = manager->shadingContext();

  int pCount = getInputPortCount();

  const TRectD &tileRect = ::tileRect(tile);

  std::vector<TRectD> inputRects(pCount);
  std::vector<TAffine> inputAffines(pCount);

  // Calculate input tiles
  ::ContextLocker cLocker(context);

  std::unique_ptr<TTile[]> inTiles(
      new TTile[pCount]);  // NOTE: Input tiles must be STORED - they cannot
  // be passed immediately to OpenGL, since *other shader
  if (pCount > 0)  // fxs*, with the very same host context, could lie
  {                // inside this fx's input branches...
    getInputData(tileRect, frame, info, inputRects, inputAffines, context);

    // Release context and mutex
    cLocker.unlock();
    mLocker.unlock();

    for (int p = 0; p != pCount; ++p) {
      TRasterFxPort &port = m_inputPorts[p];
      if (port.isConnected()) {
        // Compute input tile
        TRectD &inRect = inputRects[p];
        if (inRect.getLx() > 0.0 && inRect.getLy() > 0.0) {
          ::ceilRect(inRect);

          TRenderSettings inputInfo(info);
          inputInfo.m_affine = inputAffines[p];

#ifdef TRANSFORM_FEEDBACK_COUT
          const TAffine &inAff = inputAffines[p];
          std::cout << "inRect " << p << ": " << inRect.x0 << " " << inRect.y0
                    << " " << inRect.x1 << " " << inRect.y1 << "\n";
          std::cout << "inAff  " << p << ": " << inAff.a11 << " " << inAff.a12
                    << " " << inAff.a13 << "\n";
          std::cout << "          " << inAff.a21 << " " << inAff.a22 << " "
                    << inAff.a23 << "\n"
                    << std::endl;
#endif

          port->allocateAndCompute(
              inTiles[p], inRect.getP00(),
              TDimension(tround(inRect.getLx()), tround(inRect.getLy())),
              tile.getRaster(), frame, inputInfo);
        }
      }
    }

    // Load input tiles on the GPU as textures
    mLocker.relock();
    cLocker.relock();

    // Input tiles are NOT supplied to OpenGL here - but rather just before
    // drawing.
    // It's probably because a uniform integer variable must have already been
    // bound
    // to prepare the associated sampler variable in the linkes program...
  }

  // Perform the actual fragment shading
  {
    locals::touchOutputSize(context, tile.getRaster()->getSize(), info.m_bpp);

    QOpenGLShaderProgram *program =
        touchShaderProgram(m_shaderInterface->mainShader(), context);
    {
      ProgramBinder binder(program);

      // Bind parameters and textures
      bindParameters(program, frame);
      bindWorldTransform(program, TTranslation(-tile.m_pos) * info.m_affine);

      // Setup input data, if any
      locals::TexturesStorage texStorage(context, pCount);

      if (pCount > 0) {
        std::vector<GLint> inputs(pCount);
        std::vector<QMatrix3x3> screenToInput(pCount);
        std::vector<QMatrix3x3> inputToScreen(pCount);

        for (int p = 0; p != pCount; ++p) {
          TAffine iToS(
              TTranslation(-tile.m_pos) *             // Output to Screen
              info.m_affine *                         // World to Output
              inputAffines[p].inv() *                 // Input to World
              TTranslation(inputRects[p].getP00()) *  // Texture to Input
              TScale(inputRects[p].getLx(), inputRects[p].getLy()));  //

          TAffine sToI(iToS.inv());

#if QT_VERSION >= 0x050500
          float qiToS[9] = {static_cast<float>(iToS.a11),
                            static_cast<float>(iToS.a12),
                            static_cast<float>(iToS.a13),
                            static_cast<float>(iToS.a21),
                            static_cast<float>(iToS.a22),
                            static_cast<float>(iToS.a23),
                            0.0f,
                            0.0f,
                            1.0f};
          float qsToI[9] = {static_cast<float>(sToI.a11),
                            static_cast<float>(sToI.a12),
                            static_cast<float>(sToI.a13),
                            static_cast<float>(sToI.a21),
                            static_cast<float>(sToI.a22),
                            static_cast<float>(sToI.a23),
                            0.0f,
                            0.0f,
                            1.0f};
#else
          qreal qiToS[9] = {iToS.a11, iToS.a12, iToS.a13, iToS.a21, iToS.a22,
                            iToS.a23, 0.0,      0.0,      1.0};

          qreal qsToI[9] = {sToI.a11, sToI.a12, sToI.a13, sToI.a21, sToI.a22,
                            sToI.a23, 0.0,      0.0,      1.0};
#endif
          inputs[p] = p, screenToInput[p] = QMatrix3x3(qsToI),
          inputToScreen[p] = QMatrix3x3(qiToS);
        }

        program->setUniformValueArray("inputImage", &inputs[0], pCount);
        program->setUniformValueArray("outputToInput", &screenToInput[0],
                                      pCount);
        program->setUniformValueArray("inputToOutput", &inputToScreen[0],
                                      pCount);

        // Load textures
        for (int p = 0; p != pCount; ++p)
          texStorage.load(inTiles[p].getRaster(), p);
      }

#ifdef DIAGNOSTICS
      DIAGNOSTICS_TIMER("Shader Overall Times | " +
                        m_shaderInterface->m_mainShader.m_name);
#endif

      context.draw(tile.getRaster());
    }
  }
}

//-------------------------------------------------------------------

void ShaderFx::doDryCompute(TRectD &rect, double frame,
                            const TRenderSettings &info) {
  ShadingContextManager *manager = ShadingContextManager::instance();
  if (manager->touchSupport() != ShadingContext::OK) return;

  QMutexLocker mLocker(manager->mutex());

  // ShadingContext& context = manager->shadingContext();
  std::shared_ptr<ShadingContext> shadingContextPtr(
      new ShadingContext(manager->getSurface()));
  ShadingContext &context = *shadingContextPtr.get();

  int pCount = getInputPortCount();
  if (pCount > 0) {
    ::ContextLocker cLocker(context);

    std::vector<TRectD> inputRects(pCount);
    std::vector<TAffine> inputAffines(pCount);

    getInputData(rect, frame, info, inputRects, inputAffines, context);

    for (int p = 0; p != pCount; ++p) {
      TRasterFxPort &port = m_inputPorts[p];
      if (port.isConnected()) {
        TRectD &inRect = inputRects[p];
        if (inRect.getLx() > 0.0 && inRect.getLy() > 0.0) {
          ::ceilRect(inRect);

          TRenderSettings inputInfo(info);
          inputInfo.m_affine = inputAffines[p];

          cLocker.unlock();
          mLocker.unlock();

          port->dryCompute(inRect, frame, inputInfo);

          mLocker.relock();
          cLocker.relock();
        }
      }
    }
  }
}

//------------------------------------------------------------------

const TPersistDeclaration *ShaderFx::getDeclaration() const {
  FxDeclarationsMap::iterator it =
      ::l_shaderFxDeclarations.find(m_shaderInterface->mainShader().m_name);

  return (it == ::l_shaderFxDeclarations.end()) ? 0 : it->second;
}

//****************************************************************************
//    Shader Interfaces  loading function
//****************************************************************************

void loadShaderInterfaces(const TFilePath &shadersFolder) {
  // Scan the shaders folder for xml (shader interface) files
  QDir shadersDir(QString::fromStdWString(shadersFolder.getWideString()));

  QStringList namesFilter("*.xml");
  QStringList files = shadersDir.entryList(namesFilter, QDir::Files,
                                           QDir::Name | QDir::LocaleAware);

  int f, fCount = files.size();
  for (f = 0; f != fCount; ++f) {
    TIStream is(shadersFolder + TFilePath(files[f].toStdWString()));

    // Try to load a ShaderInterface instance for the file
    ShaderInterface shaderInterface;
    is >> shaderInterface;

    if (shaderInterface.isValid()) {
      // Store a ShaderFx factory for the interface
      ::l_shaderFxDeclarations.insert(
          std::make_pair(shaderInterface.mainShader().m_name,
                         new ShaderFxDeclaration(shaderInterface)));
    }
  }
}


text:
/*******************************************************************************
*
*  Filename    : Common_Save.cc
*  Description : Common functions required by fitting methods
*  Author      : Yi-Mu "Enoch" Chen [ ensc@hep1.phys.ntu.edu.tw ]
*
*******************************************************************************/
#include "ManagerUtils/Maths/interface/Parameter.hpp"
#include "TstarAnalysis/LimitCalc/interface/Common.hpp"
#include "TstarAnalysis/LimitCalc/interface/SampleRooFitMgr.hpp"

#include "RooAddPdf.h"
#include "RooDataSet.h"
#include "RooFitResult.h"
#include "RooWorkspace.h"
#include "TFile.h"

#include <boost/format.hpp>
#include <fstream>
#include <string>
#include <vector>

using namespace std;
using namespace mgr;

/*******************************************************************************
*   Save results
*******************************************************************************/
static const string ws_name = "wspace";

void
SaveRooWorkSpace(
  RooAbsData*                data,
  const vector<RooAbsPdf*>&  pdflist,
  const vector<RooAbsReal*>& funclist
  )
{
  const string roofit_file = limnamer.RootFileName( "roofitobj" );
  RooWorkspace ws( ws_name.c_str(), ws_name.c_str() );

  cout << "Saving RooFit objects to " << roofit_file << endl;
  ws.import( *data );

  for( auto& pdf  : pdflist ){
    ws.import( *pdf  );
  }

  for( auto& func : funclist ){
    ws.import( *func );
  }

  ws.writeToFile( roofit_file.c_str() );

}

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

void
MakeCardCommon(
  ofstream&   cardfile,
  RooAbsData* data,
  RooAbsPdf*  bg_pdf,
  RooAbsPdf*  sig_pdf
  )
{
  cardfile << "imax 1" << endl;
  cardfile << "jmax *" << endl;
  cardfile << "kmax *" << endl;
  cardfile << "----------------------------------------" << endl;

  // Printing Objects
  cardfile << boost::format( "shapes %10s %15s %30s %s:%s" )
    %  "data_obs"
    %  limnamer.GetChannel()
    %  limnamer.RootFileName( "roofitobj" )
    %  ws_name
    %  data->GetName()
           << endl;

  cardfile << boost::format( "shapes %10s %15s %30s %s:%s" )
    % "bg"
    % limnamer.GetChannel()
    % limnamer.RootFileName( "roofitobj" )
    % ws_name
    % bg_pdf->GetName()
           << endl;

  cardfile << boost::format( "shapes %10s %15s %30s %s:%s" )
    % "sig"
    % limnamer.GetChannel()
    % limnamer.RootFileName( "roofitobj" )
    % ws_name
    % sig_pdf->GetName()
           << endl;
  cardfile << "----------------------------------------"  << endl;

  // Printing data correspondence
  cardfile <<  boost::format( "%12s %s" ) % "bin" % limnamer.GetChannel() << endl;
  cardfile <<  boost::format( "%12s %lg" )% "observation" % data->sumEntries() << endl;
  cardfile <<  "----------------------------------------" << endl;

  cardfile << boost::format( "%12s %15s %15s" )
    % "bin"
    % limnamer.GetChannel()
    % limnamer.GetChannel()
           << endl;

  cardfile << boost::format( "%12s %15s %15s" ) % "process"% "sig" % "bg" << endl;
  cardfile << boost::format( "%12s %15s %15s" ) % "process"% "-1" %  "1" << endl;

}

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

void
PrintNuisanceFloats(
  ofstream&        cardfile,
  const string&    nuisance_name,
  const string&    nuisance_type,
  const Parameter& sig_nuisance,
  const Parameter& bkg_nuisance
  )
{

  cardfile << boost::format( "%-20s %3s %15s %15s" )
    % nuisance_name
    % nuisance_type
    % HiggsDataCard( sig_nuisance,1 )
    % HiggsDataCard( bkg_nuisance,1 )
           << endl;
}

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

void
PrintNuisanceUniformFloats(
  ofstream&        cardfile,
  const string&    nuisance_name,
  const string&    nuisance_type,
  const Parameter& sig_nuisance,
  const Parameter& bkg_nuisance
  )
{

  cardfile << boost::format( "%-20s %3s %15s %15s" )
    % nuisance_name
    % nuisance_type
    % HiggsDataCard( sig_nuisance,3 )
    % HiggsDataCard( bkg_nuisance,3 )
           << endl;
}

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

void
PrintFloatParam(
  ofstream&         cardfile,
  const RooRealVar* var
  )
{
  const double value = var->getVal();
  const double loedge = value - 3* var->getErrorLo() ;
  const double hiedge = value + 3* var->getErrorHi() ;
  cardfile << boost::format( "%-45s %-10s %lf %lf" )
    % var->GetName()
    % "flatParam"
    % loedge
    % hiedge
           << endl;
}

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

void
PrintFlatParam(
  ofstream&         cardfile,
  const RooRealVar* var
  )
{
  cardfile << boost::format( "%-45s %s %lf %lf" )
    % var->GetName()
    % "param"
    % var->getVal()
    % var->getMax()
           << endl;
}

ext: cc

max_stars_repo_name: NTUHEP-Tstar/TstarAnalysis

max_issues_repo_name: NTUHEP-Tstar/TstarAnalysis

max_forks_repo_name: NTUHEP-Tstar/TstarAnalysis


text:
#include <iostream>
#include <map>
#include <atomic>
#include <functional>
#include <vector>
#include <string>
#include <opencv2/opencv.hpp>
#include <boost/asio.hpp>
#include <L298NHBridge.hpp>
#include <common.hpp>
#include <config.hpp>
#include <ObjectDetector.hpp>
#include <fstream>

using boost::asio::ip::tcp;
using namespace cv;
using namespace cv::dnn;

#define SEND(sck, ptr, n, err)  if (sck.is_open()) { \
                                    boost::asio::write(sck, boost::asio::buffer(ptr, n), err); \
                                    if (err) \
                                        std::cout << err.message() << std::endl; \
                                }

#define RECV(sck, ptr, n, err)  if (sck.is_open()) { \
                                    boost::asio::read(sck, boost::asio::buffer(ptr, n), err); \
                                    if (err) \
                                        std::cout << err.message() << std::endl; \
                                }

int main(int argc, const char *argv[]) {
    const std::vector<std::string> args(argv, argv + argc);
    if (args.size() > 1 && string::starts_with(args[1], "--config=")) {
        auto tokens = string::split(args[1], "=");
        if (tokens.size() >= 2) {
            try {
                config::load(tokens[1]);
            } catch (std::exception &ex) {
                std::cout << ex.what() << std::endl;
                exit(1);
            }
        }
    }
    // parse command line arguments, override config file parameters
    config::parse(args);

    std::cout << "OpenCV " << cv::getVersionString() << std::endl;

    // general parameters
    const int port = config::get_as<int>("PORT");
    const int width = config::get_as<int>("WIDTH");
    const int height = config::get_as<int>("HEIGHT");
    const int r_speed = config::get_as<int>("ROTATION_SPEED");
    const int d_speed = config::get_as<int>("DRIVE_SPEED");

    // L298N H-Bridge pins
    const int ENA = config::get_as<int>("ENA");
    const int IN1 = config::get_as<int>("IN1");
    const int IN2 = config::get_as<int>("IN2");
    const int IN3 = config::get_as<int>("IN3");
    const int IN4 = config::get_as<int>("IN4");
    const int ENB = config::get_as<int>("ENB");

    // object detector parameters
    const std::string net = config::get("NET");
    const std::string model = config::get(net + "_MODEL");
    const std::string config = config::get(net + "_CONFIG");
    const std::string framework = config::get_or_default<std::string>(net + "_FRAMEWORK", "");
    const float scale = config::get_or_default(net  + "_SCALE", 1.0f);
    const int backend = config::get_or_default<int>("BACKEND", 0);
    const int target = config::get_or_default<int>("TARGET", 0);
    const auto threshold = config::get_as<float>("THRESHOLD");
    const auto nms_threshold = config::get_as<float>("NMS_THRESHOLD");
    const int ddepth = config::get_or_default<int>("DEPTH", 0);

    std::cout << "Object Detector: " << net << std::endl;

    // setup H-Bridge
    L298NHBridge bridge(ENA, IN1, IN2, IN3, IN4, ENB);

    // open camera
    cv::VideoCapture camera(0);
    if (!camera.isOpened()) {
        std::cout << "unable to access camera" << std::endl;
        exit(1);
    }

    // set camera properties
    camera.set(cv::CAP_PROP_FRAME_WIDTH, width);
    camera.set(cv::CAP_PROP_FRAME_HEIGHT, height);

    std::cout << "frame width=" << camera.get(cv::CAP_PROP_FRAME_WIDTH) << std::endl
                << "frame_height=" << camera.get(cv::CAP_PROP_FRAME_HEIGHT) << std::endl
                << "camera FPS=" << camera.get(cv::CAP_PROP_FPS) << std::endl;

    // load object detector
    ObjectDetector detector;
    detector.readNet(model, config, framework);
    detector.getNet().setPreferableBackend(backend);
    detector.getNet().setPreferableTarget(target);
    detector.setConfidenceThreshold(threshold);
    detector.setNMSThreshold(nms_threshold);
    detector.setCrop(true);
    detector.setScale(scale);
    detector.setDDepth(ddepth);

    // check if list of classes can be loaded
    std::vector<std::string> classes;
    std::ifstream file(config::get("CLASSES"));
    if (file) {
        std::string line;
        while (std::getline(file, line, '\n')) {
            classes.push_back(line);
        }
        file.close();
    }

    detector.setClasses(classes);

    // setup boost socket
    boost::asio::io_service io_service;
    tcp::acceptor acceptor(io_service, tcp::endpoint(tcp::v4(), port));
    tcp::socket socket(io_service);

    // connect to client
    std::cout << "listening on port " << port << std::endl;
    std::cout << "waiting for connection..." << std::endl;
    try {
        acceptor.accept(socket);
    } catch (std::exception &ex) {
        std::cout << ex.what() << std::endl;
        std::cout << "connection failed" << std::endl;
        exit(1);
    }
    std::cout << "connection established" << std::endl;

    // map keyboard inputs to actions for host
	const std::map<char, std::function<void (void)>> actions = {
            { 'q', [&]{ bridge.stop_motors(); }},
            { 'w', [&]{ bridge.set_motors(-d_speed, d_speed); }},
            { 's', [&]{ bridge.set_motors(d_speed, -d_speed); }},
            { 'a', [&]{ bridge.set_motors(r_speed, r_speed); }},
            { 'd', [&]{ bridge.set_motors(-r_speed, -r_speed); }}
	};

    char c = 0x00;
    cv::Mat frame(width, height, CV_8SC3);
    std::vector<unsigned char> buffer(width * height * 3);
    boost::system::error_code error;

    // main control loop
	do {
	    const std::chrono::system_clock::time_point begin = std::chrono::system_clock::now();
	    // read controls if available
	    if (socket.available()) {
            RECV(socket, &c, 1, error);
            if (error) {
                std::cout << "unable to read data from socket" << std::endl;
                break;
            } else {
                if (c == 'x') {
                    std::cout << "connection terminated by peer" << std::endl;
                    break;
                } else {
                    const auto it = actions.find(c);
                    if (it != actions.end()) {
                        const auto &func = it->second;
                        func();
                    } else {
                        std::cout << "unrecognized action \'" << c << '\'' << std::endl;
                    }
                }
            }
	    }

	    if (!camera.read(frame)) {
	        std::cout << "cannot acquire camera image" << std::endl;
	        break;
	    }

	    cv::resize(frame, frame, cv::Size(320, 320));

	    std::vector<Prediction> pred = detector.run(frame);
        drawPredictions(frame, pred);

        cv::resize(frame, frame, cv::Size(320, 240));

        // send frame over getNetwork
	    uint32_t n = 0;
	    cv::imencode(".jpeg", frame, buffer);

	    n = htonl((uint32_t) buffer.size());
	    SEND(socket, &n, sizeof(n), error);
	    if (error) {
	        break;
	    }
	    SEND(socket, buffer.data(), buffer.size(), error);
	    if (error) {
	        break;
	    }

	    //const uint64_t elapsed_time = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now() - begin).count();
	    //const uint64_t fps = UINT64_C(1000) / elapsed_time;
    } while (true);
    std::cout << std::endl << "connection closed" << std::endl;

    if (socket.is_open()) {
        socket.close();
    }

	return EXIT_SUCCESS;
}

ext: cpp


text:
//==============================================================================
//         Copyright 2003 - 2013   LASMEA UMR 6602 CNRS/Univ. Clermont II
//         Copyright 2009 - 2013   LRI    UMR 8623 CNRS/Univ Paris Sud XI
//
//          Distributed under the Boost Software License, Version 1.0.
//                 See accompanying file LICENSE.txt or copy at
//                     http://www.boost.org/LICENSE_1_0.txt
//==============================================================================
#include <nt2/include/functions/rec.hpp>

#include <boost/dispatch/functor/meta/call.hpp>
#include <nt2/sdk/functor/meta/call.hpp>
#include <nt2/sdk/unit/tests/relation.hpp>
#include <nt2/sdk/unit/tests/type_expr.hpp>
#include <boost/simd/sdk/simd/io.hpp>
#include <boost/simd/sdk/simd/native.hpp>
#include <complex>
#include <nt2/sdk/complex/complex.hpp>
#include <nt2/sdk/complex/dry.hpp>
#include <nt2/sdk/unit/tests/ulp.hpp>
#include <nt2/sdk/meta/as_integer.hpp>
#include <nt2/include/functions/splat.hpp>
#include <nt2/sdk/unit/module.hpp>
#include <boost/simd/sdk/config.hpp>

#include <nt2/include/constants/mzero.hpp>
#include <nt2/include/constants/one.hpp>
#include <nt2/include/constants/zero.hpp>
#include <nt2/include/constants/inf.hpp>
#include <nt2/include/constants/minf.hpp>
#include <nt2/include/constants/nan.hpp>
#include <nt2/include/constants/cnan.hpp>
#include <nt2/include/constants/half.hpp>
#include <nt2/include/constants/mhalf.hpp>

NT2_TEST_CASE_TPL ( rec_real,  BOOST_SIMD_SIMD_REAL_TYPES)
{
  using nt2::rec;
  using nt2::tag::rec_;
  typedef typename std::complex<T> cT;
  using boost::simd::native;
  typedef BOOST_SIMD_DEFAULT_EXTENSION  ext_t;
  typedef native<cT,ext_t>                vcT;
  typedef typename nt2::dry<T>             dT;
  typedef native<dT,ext_t>                vdT;

  // specific values tests
#ifndef BOOST_SIMD_NO_INVALIDS
   NT2_TEST_EQUAL(nt2::rec(nt2::splat<vcT>(cT(nt2::Inf<T>(),  nt2::Inf<T>() ))), nt2::splat<vcT>(cT(nt2::Zero<cT>())));
   NT2_TEST_EQUAL(nt2::rec(nt2::splat<vcT>(cT(nt2::Minf<T>(), nt2::Minf<T>()))), nt2::splat<vcT>(cT(nt2::Zero<cT>())));
   NT2_TEST_EQUAL(nt2::rec(nt2::splat<vcT>(cT(nt2::Inf<T>(),  nt2::Zero<T>()))), nt2::splat<vcT>(cT(nt2::Zero<cT>())));
   NT2_TEST_EQUAL(nt2::rec(nt2::splat<vcT>(cT(nt2::Zero<T>(), nt2::Inf<T>( )))), nt2::splat<vcT>(cT(nt2::Zero<cT>())));
   NT2_TEST_EQUAL(nt2::rec(nt2::splat<vcT>(cT(nt2::Minf<T>(), nt2::Zero<T>()))), nt2::splat<vcT>(cT(nt2::Zero<cT>())));
   NT2_TEST_EQUAL(nt2::rec(nt2::splat<vcT>(cT(nt2::Zero<T>(), nt2::Minf<T>()))), nt2::splat<vcT>(cT(nt2::Zero<cT>())));
   NT2_TEST_EQUAL(nt2::rec(nt2::splat<vcT>(cT(nt2::Zero<T>(), nt2::Zero<T>()))), nt2::splat<vcT>(cT(nt2::Inf<cT>() )));
   NT2_TEST_EQUAL(nt2::rec(nt2::splat<vcT>(cT(nt2::Mzero<T>(),nt2::Zero<T>()))), nt2::splat<vcT>(cT(nt2::Minf<cT>())));
   NT2_TEST_EQUAL(nt2::rec(nt2::splat<vcT>(cT(nt2::Nan<T>(),  nt2::Nan<T>() ))), nt2::Cnan<vcT>());
   NT2_TEST_EQUAL(nt2::rec(nt2::splat<vcT>(cT(nt2::Nan<T>(),  nt2::One<T>() ))), nt2::Cnan<vcT>());
   NT2_TEST_EQUAL(nt2::rec(nt2::splat<vcT>(cT(nt2::One<T>(),  nt2::Nan<T>() ))), nt2::Cnan<vcT>());
   NT2_TEST_EQUAL(nt2::rec(nt2::splat<vcT>(cT(nt2::Nan<T>(),  nt2::Zero<T>()))), nt2::Nan<vcT>());
   NT2_TEST_EQUAL(nt2::rec(nt2::splat<vcT>(cT(nt2::Zero<T>(), nt2::Nan<T>() ))), nt2::splat<vcT>(cT(nt2::Zero<T>(), nt2::Nan<T>())));
#endif
   NT2_TEST_EQUAL(nt2::rec(nt2::One<vcT>()), nt2::One<vcT>());
   NT2_TEST_EQUAL(nt2::rec(nt2::One<vdT>()), nt2::One<vdT>());

   NT2_TEST_ULP_EQUAL(nt2::rec(nt2::splat<vcT>(cT(nt2::One<T>(), nt2::One<T>() ))),
                      nt2::splat<vcT>(cT(nt2::Half<T>(),nt2::Mhalf<T>())), 0.5);

}


text:
/************************************
 * ClassName: RSAUser
 * Function: 实现 RSA 加密使用者的类对象
 * *********************************/
#include "RSA.h"
#include "Random.h"
#include "AES.h"
#include <iostream>
#include <fstream>
#include <ctime>
#include <cstring>
#include <NTL/ZZ.h>
#include <NTL/ZZ_p.h>
#include <algorithm>

using namespace std;
using namespace NTL;

// _getch() 函数的系统移植问题解决
#ifdef _WIN32
#include <conio.h>
#elif __linux__
char _getch();
#endif

void printChoose() {
    cout << "Please choose the length of random prime: \n";
    cout << "1. 512  bits\n";
    cout << "2. 1024 bits\n";
}

RSAUser::RSAUser() {
    cout << "Create RSA user..." << endl;

}

void RSAUser::GenerateKey() {
    // 选择 RSA 素数的比特长度
    int m = 0;

    printChoose();
    do {
        char ch = _getch();
        switch(ch) {
            case '1': m = 8; break;
            case '2': m = 16; break;
            default: m = 0;
        }
    } while (m == 0);

    PrimeGen G(m);
    cout << "public key and private key are generating...\n";

    // 生成私钥的随机素数 p, q
    do {
        sk.p = G.GeneratePrime();
        sk.q = G.GeneratePrime();
    } while (sk.p == sk.q);

    // 生成公钥 n
    pk.n = sk.p * sk.q;
    ZZ Euler = (sk.p - 1) * (sk.q - 1);    // 欧拉函数数值

    do {
        pk.b = G.GenerateRandom() % Euler;
    } while(GCD(pk.b, Euler) != 1);

    // 使用 NTL 库中的求逆函数 InvModStatus()
    InvModStatus(sk.a, pk.b, Euler);
    cout << "All keys have been generated !\n";
    // 钥匙查看
    viewKey(m * 64);
}

// 发送 RSA 公钥
void RSAUser::SendPublicKey(RSAUser &B) {
    B.pk = this->pk;
}

// 创建临时密钥
void RSAUser::createTempKey() {
    PRNG G(2);
    k = G.GenerateRandom();
    cout << "Temp key has been created.\n";
    cout << "Do you want to view temp key, y/n ?\n";
    char ch = _getch();
    switch (ch) {
        case 'Y':
        case 'y':
            cout << "temp key\n";
            printKey(k, 128);
            break;
        default:
            break;
    }
}

// 加密信息，使用 CBC 模式
void RSAUser::EncryptMessage() {
    // 生成临时密钥
    createTempKey();
    // 利用公钥加密 k 得到 c1，此处使用 ZZ_p 类计算
    ZZ_p::init(pk.n);
    ZZ_p k_p = to_ZZ_p(k);
    M.c1 = rep(power(k_p, pk.b));

    // 将临时密钥 k 转化为 128 比特形式
    bitset<128> key(to_ulong(k));
    // 以此创建 AES 加密系统
    AES E(key);

    // 需要加密的文件路径输入
    string fileName, newfileName;
    cout << "Please input the file path: \n";
    cin >> fileName;
    _getch();   // 接收回车符

    // 密文存储为 源文件名 + ".cipher"
    newfileName = fileName + ".cipher";
    // 文件名作为信息传输
    M.fileName = fileName;

    // 打开文件
    ifstream fin(fileName, ios::binary);
    if (!fin) {
        cerr << "open file error.\n";
        exit(-1);
    }
    ofstream fout(newfileName, ios::binary);
    if (!fout) {
        cerr << "open file error.\n";
        exit(-1);
    }

    // 因为逐字符读取文件比较慢，使用缓存区的方式一次性读取 16*1024 字节
    bitset<128> buffer[512];
    // CBC 模式
    // former 记录密文 y(i-1) ，初始化为一个随机数
    PRNG G(2);
    M.IV = G.GenerateRandom();
    bitset<128> former(to_ulong(M.IV));
    // 将 IV 通过 RSA 加密发送
    ZZ_p IV_p = to_ZZ_p(M.IV);
    M.IV = rep(power(IV_p, pk.b));

    bitset<128> cipher;     // 密文

    // 开始读取需要加密的文件
    while (fin && !fin.eof()) {
        // 一次性读取最多 16*1024 字节的内容
        fin.read((char*)&buffer, 16*512);
        streamsize readNum = fin.gcount();
        streamsize i;
        for (i = 0; i < readNum / 16; i++) {
            cipher = E.AESEncrypt(former ^ buffer[i]);
            former = cipher;
            // 写入密文至文件中
            fout.write((char*)&cipher, 16);
        }
        streamsize end = readNum % 16;
        // 文件读取结束操作，使用 PKCS7Padding 处理末尾
        if (fin.eof()) {
            // 末尾填充的数字
            bitset<128> pkcs(16 - end);
            pkcs = pkcs << 120;
            for (streamsize j = 16; j > end; j--) {
                streamsize k = j - end - 1;
                buffer[i] = ((buffer[i] << k*8) ^ pkcs) >> k*8;
            }
            cipher = E.AESEncrypt(former ^ buffer[i]);
            fout.write((char*)&cipher, 16);
        }
    }

    cout << "File encryption finished.\n";
    cout << "Encrypted file is located at " << newfileName << endl;
    // 关闭文件
    fin.close();
    fout.close();
}

// 解密信息
void RSAUser::DecryptMessage() {
    // 利用密钥来解密 c1，得到临时密钥 k
    ZZ_p::init(pk.n);
    ZZ_p c1_p = to_ZZ_p(M.c1);
    k = rep(power(c1_p, sk.a));
    // 解密得到 IV
    ZZ_p IV_p = to_ZZ_p(M.IV);
    M.IV = rep(power(IV_p, sk.a));

    // 查看临时密钥
    cout << "Temp key has been decrypted.\n";
    cout << "Do you want to view temp key, y/n ?\n";
    char ch = _getch();
    switch (ch) {
        case 'Y':
        case 'y':
            cout << "temp key\n";
            printKey(k, 128);
            break;
        default:
            break;
    }

    // 使用密钥 k 解密
    bitset<128> key(to_ulong(k));
    // 创建 AES 加密解密系统
    AES D(key);

    // 密文文件
    string fileName = M.fileName + ".cipher";

    // 查找文件的名称中的 '\' 或者 '/' 最后出现位置
    int pos = M.fileName.length() - 1;
    for (; pos >= 0; pos--) {
        if (M.fileName[pos] == '/' || M.fileName[pos] == '\\')
            break;
    }
    // 解密文件位置
    string newfileName = M.fileName.insert(pos + 1, "new_");

    // 打开文件
    ifstream fin(fileName, ios::binary);
    if (!fin) {
        cerr << "open file error.\n";
        exit(-1);
    }
    ofstream fout(newfileName, ios::binary);
    if (!fout) {
        cerr << "open file error.\n";
        exit(-1);
    }

    // buffer 缓冲区读取
    bitset<128> buffer[512];
    // former 记录密文 C(i-1)，初始化为 M.IV
    bitset<128> former(to_ulong(M.IV));
    bitset<128> plain;      // 明文

    // 开始读取解密文件
    while (fin && !fin.eof()) {
        fin.read((char*)&buffer, 16*512);
        streamsize readNum = fin.gcount();

        bool flag = false;  // 判断是否结束的标志
        if (fin.eof() || fin.peek() == EOF) {
            flag = true;
        }
        streamsize i, bufferMax = readNum / 16;
        // 使用 end 记录需要解密的缓冲区最大编号
        if (flag) bufferMax--;

        for (i = 0; i < bufferMax; i++) {
            plain = D.AESDecrypt(buffer[i]) ^ former;
            former = buffer[i];
            // 写入解密文件
            fout.write((char*)&plain, 16);
        }
        // 处理 PKCS7Padding 结尾
        if (flag) {
            // end 表示额外填充的字节数
            // 最后一次解密
            plain = D.AESDecrypt(buffer[i]) ^ former;
            streamsize end = (plain >> 120).to_ulong();
            for (streamsize j = 16; j > end; j--) {
                // 最后的字节处理
                bitset<8> text((plain << (j-1)*8 >> 120).to_ulong());
                fout.write((char*)&text, 1);
            }
        }
    }

    cout << "File decryption finished.\n";
    cout << "Decrypted file is located at " << newfileName << endl;
    fin.close();
    fout.close();
}

// 发送信息
void RSAUser::SendMessage(RSAUser& A) {
    A.M = this->M;
}

// PEM 格式打印输出
void RSAUser::PrintInPEM(const string s) {
	string res = "";
	size_t len = s.length() / 8;	// 比特串转化为字节的长度
	size_t i;
	unsigned char triBytes[3];		// 存储三个字节

	for (i = 0; i+3 <= len; i += 3) {
		for (int j = 0; j < 3; j++) {
			bitset<8> tmp(s.substr(8*i + 8*j, 8));
			triBytes[j] = tmp.to_ulong();
		}
		res += Base64Map[triBytes[0] >> 2];
		res += Base64Map[((triBytes[0]<<4) & 0x30) | (triBytes[1] >> 4)];
		res += Base64Map[((triBytes[1]<<2) & 0x3c) | (triBytes[2] >> 6)];
		res += Base64Map[triBytes[2] & 0x3f];
	}

	if (i < len) {
		if (len - i == 1) {
			bitset<8> tmp(s.substr(8*i, 8));
			triBytes[0] = tmp.to_ulong();
			res += Base64Map[triBytes[0] >> 2];
			res += Base64Map[(triBytes[0]<<4) & 0x30];
			res += "==";
		} else {
			for (int j = 0; j < 2; j++) {
				bitset<8> tmp(s.substr(8*i + 8*j, 8));
				triBytes[j] = tmp.to_ulong();
			}
			res += Base64Map[triBytes[0] >> 2];
			res += Base64Map[((triBytes[0]<<4) & 0x30) | (triBytes[1] >> 4)];
			res += Base64Map[(triBytes[1]<<2) & 0x3c];
			res += "=";
		}
	}

	cout << res << endl;
}

// DER(十六进制)格式打印
void RSAUser::PrintInDER(const string s) {
    cout << "modulus:";
    string pairstr = "";
    for (size_t i = 0; i < s.length(); i += 4) {
        int index = 0;

        for (size_t j = i; j < i + 4; j++) {
            index = index << 1;
            if (s[j] == '1') {
                index += 1;
            }
        }
        pairstr += HexTable[index];
        if (pairstr.length() == 2) {
            cout << pairstr;
            if (i + 4 < s.length()) {
                cout << ":";
            }
            pairstr = "";
        }
        if (i % 120 == 0) {
            cout << endl << '\t';
        }
    }
    cout << endl;
}

// ZZ 类型转化为 Bits
string RSAUser::ZZToBits(ZZ num, const size_t n) {
	string s = "";
	ZZ last;

	while (num != 0) {
		last = num % 2;
		if (last == 1) {
			s += '1';
		} else {
			s += '0';
		}
		num /= 2;
	}
	for (size_t i = s.length(); i < n; i++) {
		s += '0';
	}
	reverse(s.begin(), s.end());
	return s;
}

// 选择输出格式打印
void printFormat() {
    cout << "Please choose the format to print key :\n";
    cout << "1. DER (hexadecimal)\n";
    cout << "2. PEM\n";
}

// 查看钥匙，n 为 p,q 的比特位数
void RSAUser::viewKey(const size_t n) {
    // 查看公钥
    cout << "Do you want to view public key, y/n ?\n";
    char ch = _getch();

    switch(ch) {
        case 'Y':
        case 'y': {
            cout << "Public key\n";
            cout << "Print n in public key :\n";
            printKey(pk.n, n*2);
            cout << "Print b in public key :\n";
            printKey(pk.b, n*2);
            break;
        }
        default: break;
    }
    // 查看私钥
    cout << "Do you want to view private key, y/n ?\n";
    ch = _getch();

    if (ch == 'y' || ch == 'Y') {
        cout << "Attention, please not reveal this information !!!\n";
        cout << "Read the warning, continue, y/n ?\n";
        ch = _getch();

        switch(ch) {
            case 'Y':
            case 'y': {
                cout << "Private key\n";
                cout << "Print p in private key :\n";
                printKey(sk.p, n);
                cout << "Print q in private key :\n";
                printKey(sk.q, n);
                cout << "Print a in private key :\n";
                printKey(sk.a, n*2);
                break;
            }
            default: break;
        }
    }

}

// 打印每一个钥匙
void RSAUser::printKey(ZZ num, const size_t n) {
    string s = ZZToBits(num, n);
    printFormat();
    bool flag = false;
    while (!flag) {
        char ch = _getch();
        switch(ch) {
            case '1': {
                PrintInDER(s);
                flag = true;
                break;
            }
            case '2': {
                PrintInPEM(s);
                flag = true;
                break;
            }
            default: break;
        }
    }
}

max_stars_repo_name: yuanyangwangTJ/RSA

max_issues_repo_name: yuanyangwangTJ/RSA

max_forks_repo_name: yuanyangwangTJ/RSA


text:
#ifndef INCLUDED_STDDEFX
#include "stddefx.h"
#define INCLUDED_STDDEFX
#endif

#ifndef INCLUDED_COM_INTABLESTREAMTEST
#include "com_intablestreamtest.h"
#define INCLUDED_COM_INTABLESTREAMTEST
#endif

// Library headers.
#ifndef INCLUDED_BOOST_SHARED_PTR
#include <boost/shared_ptr.hpp>
#define INCLUDED_BOOST_SHARED_PTR
#endif

#ifndef INCLUDED_BOOST_TEST_TEST_TOOLS
#include <boost/test/test_tools.hpp>
#define INCLUDED_BOOST_TEST_TEST_TOOLS
#endif

#ifndef INCLUDED_BOOST_TEST_UNIT_TEST_SUITE
#include <boost/test/unit_test_suite.hpp>
#define INCLUDED_BOOST_TEST_UNIT_TEST_SUITE
#endif

// PCRaster library headers.
#ifndef INCLUDED_COM_EXCEPTION
#include "com_exception.h"
#define INCLUDED_COM_EXCEPTION
#endif

// Module headers.
#ifndef INCLUDED_COM_INTABLESTREAM
#include "com_intablestream.h"
#define INCLUDED_COM_INTABLESTREAM
#endif
#ifndef INCLUDED_COM_PATHNAME
#include "com_pathname.h"
#define INCLUDED_COM_PATHNAME
#endif
#ifndef INCLUDED_COM_FILE
#include "com_file.h"
#define INCLUDED_COM_FILE
#endif
/*!
  \file
  This file contains the implementation of the InTableStreamTest class.
*/

//------------------------------------------------------------------------------
// DEFINITION OF STATIC INTABLESTREAM MEMBERS
//------------------------------------------------------------------------------

//! suite
boost::unit_test::test_suite*com::InTableStreamTest::suite()
{
  boost::unit_test::test_suite* suite = BOOST_TEST_SUITE(__FILE__);
  boost::shared_ptr<InTableStreamTest> instance(new InTableStreamTest());

  suite->add(BOOST_CLASS_TEST_CASE(&InTableStreamTest::testRead, instance));
  suite->add(BOOST_CLASS_TEST_CASE(&InTableStreamTest::testRead2, instance));
  suite->add(BOOST_CLASS_TEST_CASE(&InTableStreamTest::testFormatErrors, instance));

  return suite;
}

//------------------------------------------------------------------------------
// DEFINITION OF INTABLESTREAM MEMBERS
//------------------------------------------------------------------------------

//! ctor
com::InTableStreamTest::InTableStreamTest()
{
}

//! setUp
void com::InTableStreamTest::setUp()
{
}

//! tearDown
void com::InTableStreamTest::tearDown()
{
}

void com::InTableStreamTest::testRead()
{
  const char *files[2] = {"zinc.unix.eas","zinc.dos.eas"};
  for(size_t i=0; i < 2; i++) {
    InTableStream tab(files[i]);
    BOOST_CHECK(tab.layout() == InTableStream::GEO_EAS);
    std::vector<double> d;
    tab >> d;
    BOOST_CHECK(d.size()==3);
    BOOST_CHECK(d[0]==181072);
    BOOST_CHECK(d[1]==333611);
    BOOST_CHECK(d[2]==1022);
  }

 PathName pn("inTableStream.txt");
 std::vector<double> d;

   const char *testSimples[3] = {
     //simple and some extra new lines
     "1\n2\n \n3\n",
    // no new line at end
     "1\n2\n3",
     "1\n2\n3 \n 4" };
   for(size_t i=0; i < 3; i++) {
     write(testSimples[i],pn);
     InTableStream tab(pn);
     BOOST_CHECK(tab.layout() == InTableStream::PLAIN_TXT);
     size_t v=1;
     while (tab >> d) {
      BOOST_CHECK(d.size()==1);
      BOOST_CHECK(d[0]==v++);
     }
     BOOST_CHECK(i < 2 ? v==4 : v==5);
   }
 { write("\n2\n\n0",pn);
   InTableStream tab(pn);
   BOOST_CHECK(tab.lineNrStartLastRead()==0);
   BOOST_CHECK(tab.layout() == InTableStream::PLAIN_TXT);
   BOOST_CHECK(tab.nrColumns() == 1);
   BOOST_CHECK(tab >> d);
   BOOST_CHECK(tab.lineNrStartLastRead()==2);
   BOOST_CHECK(d.size()==1&&d[0]==2);
   BOOST_CHECK(tab >> d);
   BOOST_CHECK(tab.lineNrStartLastRead()==4);
   BOOST_CHECK(d.size()==1&&d[0]==0);
   BOOST_CHECK(!(tab >> d));
 }
 { // geo eas with no data
   write("\n2\n\ntitle2 ",pn);
   InTableStream tab(pn);
   BOOST_CHECK(tab.layout() == InTableStream::GEO_EAS);
   BOOST_CHECK(tab.nrColumns() == 2);
   BOOST_CHECK(tab.columnNames()[0].empty());
   BOOST_CHECK(tab.columnNames()[1]=="title2");
   BOOST_CHECK(!(tab >> d));
   BOOST_CHECK(d.empty());
 }
 { // geo eas with numeric descriptions and a single line of data
   write("1\n2\n0\n0\n2 3",pn);
   InTableStream tab(pn);
   BOOST_CHECK(tab.layout() == InTableStream::GEO_EAS);
   BOOST_CHECK(tab.nrColumns() == 2);
   BOOST_CHECK(tab.columnNames()[0]=="0");
   BOOST_CHECK(tab.columnNames()[1]=="0");
   BOOST_CHECK(tab >> d);
   BOOST_CHECK(tab.lineNrStartLastRead()==5);
   BOOST_CHECK(d.size()==2&&d[0]==2 && d[1]==3);
   BOOST_CHECK(!(tab >> d));
 }
}

void com::InTableStreamTest::testRead2()
{
 PathName pn("inTableStream2.txt");
 std::vector<double> d;
 { // text with single line of data
   write("0",pn);
   InTableStream tab(pn);
   BOOST_CHECK(tab.layout() == InTableStream::PLAIN_TXT);
   BOOST_CHECK(tab.nrColumns() == 1);
   BOOST_CHECK(tab.columnNames()[0].empty());
   BOOST_CHECK(tab >> d);
   BOOST_CHECK(tab.lineNrStartLastRead()==1);
   BOOST_CHECK(d.size()==1&&d[0]==0);
   BOOST_CHECK(!(tab >> d));
 }
 { // text with 2 lines of data but irregular
   write("0\n1 2",pn);
   InTableStream tab(pn);
   BOOST_CHECK(tab.layout() == InTableStream::PLAIN_TXT);
   BOOST_CHECK(tab >> d);
   BOOST_CHECK(d.size()==1&&d[0]==0);
   BOOST_CHECK(tab >> d);
   BOOST_CHECK(d.size()==2&&d[0]==1 && d[1]==2);
   BOOST_CHECK(!(tab >> d));
 }
 { // file with only space
   write(" \t \n  ",pn);
   InTableStream tab(pn);
   BOOST_CHECK(tab.layout() == InTableStream::EMPTY);
   BOOST_CHECK(tab.nrColumns() == 0);
   BOOST_CHECK(!(tab >> d));
   // pretty useles and incorrect:
   // BOOST_CHECK(tab.lineNrStartLastRead()==1);
   BOOST_CHECK(d.empty());
 }
 { // empty file, 0 bytes
   write("",pn);
   BOOST_CHECK(size(pn)==0);
   InTableStream tab(pn);
   BOOST_CHECK(tab.layout() == InTableStream::EMPTY);
   BOOST_CHECK(tab.nrColumns() == 0);
   BOOST_CHECK(!(tab >> d));
   BOOST_CHECK(d.empty());
 }
 { // geoEas with incorrect data (1 record too long)
   com::write("geoEas d\n2\nt1\nt2\n1 2 3\n4 5 \n",pn);
   InTableStream tab(pn);
   BOOST_CHECK(tab.layout() == TableInfo::GEO_EAS);
   BOOST_CHECK(tab.nrColumns() == 2);
   BOOST_CHECK(tab >> d);
   BOOST_CHECK(d.size()==3);
   BOOST_CHECK(tab >> d);
   BOOST_CHECK(d.size()==2);
   BOOST_CHECK(!(tab >> d));
 }
}

void com::InTableStreamTest::testFormatErrors()
{
 { // not a table file
   PathName pn("spawnScript");
   bool catched(false);
   try {
     InTableStream tab(pn);
   } catch (const FileFormatError& e) {

     BOOST_CHECK(e.messages().find("Format of file")!=std::string::npos);
     catched=true;
   }
   BOOST_CHECK(catched);
 }
 PathName pn("inTableStream.txt");

 { // geo eas but short on column names
   write("description\n3\ntitle1\ntitle2\n",pn);
   bool catched(false);
   try {
     InTableStream tab(pn);
   } catch (const FileFormatError& e) {
     BOOST_CHECK(e.messages().find("Format of file")!=std::string::npos);
     catched=true;
   }
   BOOST_CHECK(catched);
 }

 { // illegal format
   write("1\n2\n3\n4\n ac\n3\n",pn);
   InTableStream tab(pn);
   BOOST_CHECK(tab.layout() == InTableStream::PLAIN_TXT);
   std::vector<double> d;
   bool catched(false);
   try {
    while (tab >> d);
   } catch (const FilePositionError& e) {
     BOOST_CHECK(e.messages().find("ac")!=std::string::npos);
     BOOST_CHECK(e.lineNr()==5);
     BOOST_CHECK(e.columnNr()==2);
     catched=true;
   }
   BOOST_CHECK(catched);
 }
}

max_stars_repo_name: quanpands/wflow

max_issues_repo_name: quanpands/wflow

max_forks_repo_name: quanpands/wflow


text:
/**
 * Content
 * Definition of the Network class
 *
 * @author: Can Yang
 * @version: 2017.11.11
 */

#ifndef MM_NETWORK_HPP
#define MM_NETWORK_HPP
#include <ogrsf_frmts.h> // C++ API for GDAL
#include <iostream>
#include <cmath> // Calulating probability
#include <iomanip>
#include <algorithm> // Partial sort copy
#include <unordered_set> // Partial sort copy
// Data structures for Rtree
#include <boost/geometry/geometries/box.hpp>
#include <boost/geometry/index/rtree.hpp>
#include <boost/function_output_iterator.hpp>

#include "multilevel_debug.h"
#include "types.hpp"
#include "util.hpp"
#include "algorithm.hpp"
#include "gps.hpp"

namespace MM
{

// Define a type alias for the rtree used in map matching
/* Edge format in the network */
typedef boost::geometry::model::point
    <float, 2, boost::geometry::cs::cartesian> boost_point;

typedef boost::geometry::model::box<boost_point> boost_box;
// Item stored in rtree
typedef std::pair<boost_box,Edge*> Item;
typedef boost::geometry::index::rtree
    <Item,boost::geometry::index::quadratic<16> > Rtree; // Rtree definition

// This function is used for KNN sort
static bool candidate_compare(const Candidate &a, const Candidate &b)
{
  if (a.dist!=b.dist)
  {
    return a.dist<b.dist;
  }
  else
  {
    return a.edge->id<b.edge->id;
  }
};

class Network
{
public:
  /**
   *  Constructor of Network
   *
   *  A vector of network edges will be constructed
   *
   *  @param filename: the path to a network file in ESRI shapefile format
   *  @param id_name: the name of the id attribute
   *  @param source_name: the name of the source attribute
   *  @param target_name: the name of the target attribute
   *
   */
  /*
  Network(const std::string &filename,
          const std::string &id_name="id",
          const std::string &source_name="source",
          const std::string &target_name="target") {
    std::cout<<"Read network shp file from " << filename <<'\n';
    std::cout<<"Id column "<<id_name <<'\n';
    OGRRegisterAll();
    GDALDataset *poDS = (GDALDataset*) GDALOpenEx(filename.c_str(),
        GDAL_OF_VECTOR, NULL, NULL, NULL );
    if( poDS == NULL )
    {
      printf( "Open failed.\n" );
      exit( 1 );
    }
    OGRLayer  *ogrlayer = poDS->GetLayer(0);
    int NUM_FEATURES = ogrlayer->GetFeatureCount();
    std::cout<< "\tNumber of edges in file: " << NUM_FEATURES << '\n';
    network_edges= std::vector<Edge>(NUM_FEATURES);
    // Initialize network edges
    OGRFeatureDefn *ogrFDefn = ogrlayer->GetLayerDefn();
    OGRFeature *ogrFeature;
    // Fetch the field index given field name.
    int id_idx=ogrFDefn->GetFieldIndex(id_name.c_str());
    int source_idx=ogrFDefn->GetFieldIndex(source_name.c_str());
    int target_idx=ogrFDefn->GetFieldIndex(target_name.c_str());
    std::cout<< "\tSHP ID idx: " <<id_idx<< '\n';
    std::cout<< "\tSHP source idx: " <<source_idx<< '\n';
    std::cout<< "\tSHP target idx: " <<target_idx<< '\n';
    if (source_idx<0||target_idx<0||id_idx<0)
    {
      std::cout<<std::setw(12)<<""<< "id, source or target column not found \n";
      GDALClose( poDS );
      std::exit(EXIT_FAILURE);
    }

    if (wkbFlatten(ogrFDefn->GetGeomType()) != wkbLineString)
    {
      std::cout<<std::setw(12)<<""<< "Geometry type of network is " <<
          OGRGeometryTypeToName(ogrFDefn->GetGeomType())<<'\n';
      std::cout<<std::setw(12)<<""<< "It should be LineString"<< '\n';
      GDALClose( poDS );
      std::cout<<"Program stop"<< '\n';
      std::exit(EXIT_FAILURE);
    } else {
      std::cout<< "\tGeometry type is " << OGRGeometryTypeToName(
          ogrFDefn->GetGeomType())<<'\n';
    }
    OGRSpatialReference *ogrsr = ogrFDefn->GetGeomFieldDefn(0)->GetSpatialRef();
    if (ogrsr != nullptr) {
      srid = ogrsr->GetEPSGGeogCS();
      if (srid==-1)
      {
        srid= 4326;
        std::cout<< "\t---- Warning: srid is not found, set to 4326 for default"<< '\n';
      } else {
        std::cout<< "\tSRID is "<<srid<< '\n';
      }
    } else {
      srid= 4326;
      std::cout<< "\t---- Warning: srid is not found, set to 4326 for default"<< '\n';
    }
    std::unordered_set<int> nodeSet;
    while( (ogrFeature = ogrlayer->GetNextFeature()) != NULL)
    {
      int id = ogrFeature->GetFID();
      Edge *e = &network_edges[id];
      e->id = id;
      e->id_attr = std::string(ogrFeature->GetFieldAsString(id_idx));
      e->source = ogrFeature->GetFieldAsInteger(source_idx);
      e->target = ogrFeature->GetFieldAsInteger(target_idx);
      OGRGeometry *rawgeometry = ogrFeature->GetGeometryRef();
//             CS_DEBUG(3) std::cout<<"Line "<< __LINE__<<" ID "<< e->id <<" Length "<<((OGRLineString*) rawgeometry)->get_Length()<<"\n";
//             CS_DEBUG(3) std::cout<<"Line "<< __LINE__<<" ID "<< e->id <<" Points "<<((OGRLineString*) rawgeometry)->getNumPoints()<<"\n";
      // The cloned geometry has to be freed by OGRGeometryFactory
      // https://github.com/OSGeo/gdal/blob/93fb17379bccba28a43a03bb2c19b868f264ebe1/gdal/ogr/ogrlinestring.cpp#L141
#ifdef USE_BG_GEOMETRY
      e->geom = ogr2bg((OGRLineString*) rawgeometry);
#else
      e->geom = (OGRLineString*) rawgeometry->clone();
#endif
      e->length = e->geom->get_Length();
      if (e->source>max_node_id)
      {
        max_node_id = e->source;
      }
      if (e->target>max_node_id)
      {
        max_node_id = e->target;
      }
      if (nodeSet.find(e->source)==nodeSet.end()) {
        nodeSet.insert(e->source);
      }
      if (nodeSet.find(e->target)==nodeSet.end()) {
        nodeSet.insert(e->target);
      }
      OGRFeature::DestroyFeature(ogrFeature);
    }
    GDALClose( poDS );
    CS_DEBUG(3) std::cout<<"Line "<< __LINE__<< " Length "<<network_edges[0].geom->get_Length()<<"\n";
    std::cout<<"Read network finish."<< '\n';
    node_count = nodeSet.size();
    std::cout<<"\tThe maximum node ID is "<< max_node_id << '\n';
    std::cout<<"Node count is "<< node_count << '\n';
    std::cout<<"\tTotal number of edges read "<< network_edges.size()<< '\n';
  };   // Network constructor
  */
  Network(const std::string &shpTxt,
          const std::string &id_name="id",
          const std::string &source_name="source",
          const std::string &target_name="target") {

    std::unordered_set<int> nodeSet;

    std::vector<std::string> lines;
    boost::split(lines, shpTxt, boost::is_any_of(" "));

    network_edges = std::vector<Edge>(lines.size());

    for (int i = 0; i < lines.size(); i++) {
        std::string line = lines[i];
        std::vector<std::string> infos;
        boost::split(infos, line, boost::is_any_of(";"));

        int id = atoi(infos[0].c_str()) - 1;
        std::string id_attr = std::to_string(id);
        int source_id = atoi(infos[1].c_str());
        int target_id = atoi(infos[2].c_str());

        Edge *e = &network_edges[id];
        e->id = id;
        e->id_attr = id_attr;
        e->source = source_id;
        e->target = target_id;

        BGLineString *l = new BGLineString();
        std::vector<std::string> pos;
        boost::split(pos, infos[3], boost::is_any_of("|"));
        for (int j = 0; j < pos.size(); j++) {
            std::vector<std::string> p;
            boost::split(p, pos[j], boost::is_any_of(","));
            l->addPoint(atof(p[0].c_str()), atof(p[1].c_str()));
        }
        e->geom = l;
        e->length = e->geom->get_Length();

        if (e->source > max_node_id) {
            max_node_id = e->source;
        }
        if (e->target > max_node_id) {
            max_node_id = e->target;
        }
        if (nodeSet.find(e->source) == nodeSet.end()) {
            nodeSet.insert(e->source);
        }
        if (nodeSet.find(e->target) == nodeSet.end()) {
            nodeSet.insert(e->target);
        }
    }

    srid= 4326;
    node_count = nodeSet.size();

    std::cout<<"Read network finish."<< '\n';
    std::cout<<"\tThe maximum node ID is "<< max_node_id << '\n';
    std::cout<<"Node count is "<< node_count << '\n';
    std::cout<<"\tTotal number of edges read "<< network_edges.size()<< std::endl;
  };   // Network constructor

  ~Network()
  {
    std::cout<< "Cleaning network" << '\n';
    for (auto &item:network_edges)
    {
#ifdef USE_BG_GEOMETRY
      delete item.geom;
#else
      OGRGeometryFactory::destroyGeometry(item.geom);
#endif
    }
    std::cout<< "Cleaning network finished" << '\n';
  }

  int get_node_count(){
    return node_count;
  };
  // Get the edge vector
  std::vector<Edge> *get_edges()
  {
    return &network_edges;
  };
  // Get the ID attribute of an edge according to its index
  std::string get_edge_id_attr(int eid)
  {
    return network_edges[eid].id_attr;
  };
  int get_max_node_id()
  {
    return max_node_id;
  };
  // Construct a Rtree using the vector of edges
  void build_rtree_index()
  {
    // Build an rtree for candidate search
    std::cout<<"Start to construct boost rtree"<<'\n';
    // create some Items
    for (std::size_t i = 0; i < network_edges.size(); ++i)
    {
      // create a boost_box
      Edge *edge = &network_edges[i];
      CS_DEBUG(3) std::cout<<"Number of points is "<<edge->geom->getNumPoints()<<"\n";
      // boundary is returned is a multipoint geometry, but not the envelop
      // instead, it is only the first and last point
      double x1,y1,x2,y2;
      ALGORITHM::boundingbox_geometry(edge->geom,&x1,&y1,&x2,&y2);
      CS_DEBUG(3) std::cout<<"Process trajectory: "<<i<<'\n';
      CS_DEBUG(3) std::cout<<"x1,y1,x2,y2: "<<x1<<","<<y1<<","<<x2<<","<<y2<<'\n';
      boost_box b(boost_point(x1,y1), boost_point(x2,y2));
      rtree.insert(std::make_pair(b,edge));
    }
    std::cout<<"Finish construct boost rtree"<<'\n';
  };
  /**
   *  Search for k nearest neighboring (KNN) candidates of a
   *  trajectory within a search radius
   *
   *  @param trajectory: input trajectory
   *  @param k: the number of coordindates
   *  @param r: the search radius
   *  @return Traj_Candidates: a 2D vector of Candidates containing
   *  the candidates selected for each point in a trajectory
   *
   */
  Traj_Candidates search_tr_cs_knn(Trajectory &trajectory,std::size_t k,double radius, double gps_error = 50){
    return search_tr_cs_knn(trajectory.geom,k,radius,gps_error);
  }

  /**
   *  Search for k nearest neighboring (KNN) candidates of a
   *  linestring within a search radius
   */
  Traj_Candidates search_tr_cs_knn(LineString *geom,std::size_t k,double radius,double gps_error)
  {
    int NumberPoints = geom->getNumPoints();
    Traj_Candidates tr_cs(NumberPoints);
    for (int i=0; i<NumberPoints; ++i)
    {
      CS_DEBUG(2) std::cout<<"Search candidates for point index "<<i<< '\n';
      // Construct a bounding boost_box
      double px = geom->getX(i);
      double py = geom->getY(i);
      Point_Candidates pcs;
      boost_box b(boost_point(geom->getX(i)-radius,geom->getY(i)-radius),boost_point(geom->getX(i)+radius,geom->getY(i)+radius));
      std::vector<Item> temp;
      // Rtree can only detect intersect with a the bounding box of the geometry stored.
      rtree.query(boost::geometry::index::intersects(b),std::back_inserter(temp));
      for (Item &i:temp)
      {
        // Check for detailed intersection
        // The two edges are all in OGR_linestring
        Edge *edge = i.second;
        float offset;
        double dist;
        ALGORITHM::linear_referencing(px,py,edge->geom,&dist,&offset);
        CS_DEBUG(2) std::cout<<"Edge id: "<<edge->id<< '\n';
        CS_DEBUG(2) std::cout<<"Dist: "<<dist<< '\n';
        CS_DEBUG(2) std::cout<<"Offset: "<<offset<< '\n';
        if (dist<=radius)
        {
          Candidate c = {offset,dist,Network::emission_prob(dist,gps_error),edge,NULL,0,0};
          pcs.push_back(c);
        }
      }
      if (pcs.empty())
      {
        return Traj_Candidates();
      };
      // KNN part
      if (pcs.size()<=k)
      {
        tr_cs[i]=pcs;
      }
      else
      {
        // Find the KNN neighbors
        CS_DEBUG(2) std::cout<<"Perform KNN search"<< '\n';
        tr_cs[i]=Point_Candidates(k);
        std::partial_sort_copy(
          pcs.begin(),pcs.end(),
          tr_cs[i].begin(),tr_cs[i].end(),
          candidate_compare);
      }
    }
    CS_DEBUG(1) UTIL::print_traj_candidates_summary(tr_cs);
    CS_DEBUG(2) UTIL::print_traj_candidates(tr_cs);
    return tr_cs;
  };

  /**
   * Added in 2018.01.17, by Diao
   * Modified in 2018.01.19 by Can
   *
   * a modified version of geometry path construction,
   * which the offset is taken into consideration, and the
   * final path with a correct start point and end point corresponding
   * to the original trajectory. Namely at both the first and last edge
   * in the complete path, only the part traversed is exported.
   *
   * Construct the geometry of a complete path,
   * @param o_path_ptr: a pointer to the o_path_ptr, where each element
   * is a Candidate object. This input is needed because the offset is used to
   * split the first and last edge in the complete path.
   * @param  complete_path: a pointer to a complete path, where each element
   * is an integer representing spatial contiguous edge index
   * @return  a pointer to the geometry of the complete path, The
   * caller should take care of freeing its memory.
   */
  LineString *complete_path_to_geometry(O_Path *o_path_ptr, C_Path *complete_path)
  {
    if (complete_path==nullptr || complete_path->empty()) return nullptr;
    // if (complete_path->empty()) return nullptr;
    LineString *line = new LineString();
    int NOsegs = o_path_ptr->size();
    int NCsegs = complete_path->size();
    GC_DEBUG(2) std::cout<< __FILE__ << __LINE__ <<" Optimal path size "<<NOsegs <<'\n';
    GC_DEBUG(2) std::cout<< __FILE__ << __LINE__ <<" Complete path size "<<NCsegs <<'\n';
    if (NCsegs ==1)
    {
      double firstoffset = (*o_path_ptr)[0]->offset;
      double lastoffset = (*o_path_ptr)[NOsegs-1]->offset;
      GC_DEBUG(2) std::cout<< "first offset " << firstoffset <<'\n';
      GC_DEBUG(2) std::cout<< "last offset " << lastoffset <<'\n';
      LineString * firstseg = network_edges[(*complete_path)[0]].geom;
      LineString * firstlineseg= ALGORITHM::cutoffseg_unique(firstoffset,lastoffset,firstseg);
      append_segs_to_line(line,firstlineseg,0);
      GC_DEBUG(2) UTIL::print_geometry(firstlineseg);
      // Free the memory
      delete firstlineseg;
    } else {
      double firstoffset = (*o_path_ptr)[0]->offset;
      double lastoffset = (*o_path_ptr)[NOsegs-1]->offset;
      LineString * firstseg = network_edges[(*complete_path)[0]].geom;
      LineString * lastseg = network_edges[(*complete_path)[NCsegs-1]].geom;
      LineString * firstlineseg= ALGORITHM::cutoffseg(firstoffset, firstseg, 0);
      LineString * lastlineseg= ALGORITHM::cutoffseg(lastoffset, lastseg, 1);
      GC_DEBUG(2) std::cout<< "First offset " << firstoffset <<'\n';
      GC_DEBUG(2) std::cout<< "First line " <<'\n';
      GC_DEBUG(2) UTIL::print_geometry(firstseg);
      GC_DEBUG(2) std::cout<< "First line cutoff " <<'\n';
      GC_DEBUG(2) UTIL::print_geometry(firstlineseg);
      GC_DEBUG(2) std::cout<< "last offset " << lastoffset <<'\n';
      GC_DEBUG(2) std::cout<< "Last line " <<'\n';
      GC_DEBUG(2) UTIL::print_geometry(lastseg);
      GC_DEBUG(2) std::cout<< "Last line cutoff " <<'\n';
      GC_DEBUG(2) UTIL::print_geometry(lastlineseg);
      append_segs_to_line(line,firstlineseg,0);
      if (NCsegs>2)
      {
        for(int i=1; i<NCsegs-1; ++i)
        {
          LineString * middleseg = network_edges[(*complete_path)[i]].geom;
          append_segs_to_line(line,middleseg,1);
        }
      };
      append_segs_to_line(line,lastlineseg,1);
      // Free the memory
      delete firstlineseg;
      delete lastlineseg;
    }
    GC_DEBUG(2) std::cout<< "Export result" <<'\n';
    GC_DEBUG(2) UTIL::print_geometry(line);
    return line;
  };

  /**
   * Detect if a complete path contains reverse movement
   *
   * @param  c_path_ptr : a pointer to a complete path
   */
  bool is_complete_path_reverse(C_Path *c_path_ptr)
  {
    if (c_path_ptr==nullptr) return false;
    C_Path &c_path=*c_path_ptr;
    int N = c_path.size();
    bool result=false;
    for(int i=0; i<N-1; ++i)
    {
      int ea = c_path[i];
      int eb = c_path[i+1];
      if (network_edges[ea].source==network_edges[eb].target)
      {
        result=true;
        break;
      }
    }
    return result;
  };
  /**
   * Calculate the emission probability
   * @param  dist:the distance a GPS point to a candidate point
   * @return  the emission probability
   */
  static double emission_prob(double dist,double gps_error)
  {
    double a = dist / gps_error;
    return exp(-0.5 * a * a);     // The unit should be in range of 0,1
  };

  static double emission_prob_to_dist(double eprob,double gps_error){
    return sqrt(-2 * log(eprob))*gps_error;
  };
private:
  /**
   * Concatenate a linestring segs to a linestring line, used in the
   * function complete_path_to_geometry
   *
   * @param line: pointer to a linestring which will be updated
   * @param segs: pointer to a linestring
   * @param offset: the number of points skipped in segs.
   */
  static void append_segs_to_line(LineString *line,LineString *segs,int offset=0)
  {
    int Npoints = segs->getNumPoints();
    DEBUG(2) std::cout<< "Number of points "<< Npoints <<'\n';
    for(int i=0; i<Npoints; ++i)
    {
      if (i>=offset)
      {
        line->addPoint(segs->getX(i),segs->getY(i));
      }
    }
  };
  int srid;   // Spatial reference id
  Rtree rtree;   // Network rtree structure
  std::vector<Edge> network_edges;   // all edges in the network
  int max_node_id = 0;   // a variable to record the maximum node ID
  int node_count = 0;
}; // Network
} // MM
#endif /* MM_NETWORK_HPP */

ext: hpp


text: #include <boost/fusion/algorithm/transformation/filter.hpp>

max_stars_repo_name: miathedev/BoostForArduino

max_issues_repo_name: miathedev/BoostForArduino

max_forks_repo_name: miathedev/BoostForArduino


text:
#pragma once

#include <boost/interprocess/managed_mapped_file.hpp>
#include <boost/interprocess/containers/map.hpp>
#include <boost/interprocess/containers/set.hpp>
#include <boost/interprocess/containers/flat_map.hpp>
#include <boost/interprocess/containers/deque.hpp>
#include <boost/interprocess/containers/string.hpp>
#include <boost/interprocess/containers/vector.hpp>
#include <boost/interprocess/allocators/allocator.hpp>
#include <boost/interprocess/sync/interprocess_sharable_mutex.hpp>
#include <boost/interprocess/sync/sharable_lock.hpp>
#include <boost/interprocess/sync/file_lock.hpp>

#include <type_traits>

namespace chainbase {

   namespace bip = boost::interprocess;

   #ifdef ENABLE_STD_ALLOCATOR
      template< typename T >
      using allocator = std::allocator< T >;

      typedef boost::shared_mutex read_write_mutex;
      typedef boost::shared_lock< read_write_mutex > read_lock;
   #else
      template< typename T >
      using allocator = bip::allocator<T, bip::managed_mapped_file::segment_manager>;

      typedef boost::interprocess::interprocess_sharable_mutex read_write_mutex;
      typedef boost::interprocess::sharable_lock< read_write_mutex > read_lock;
   #endif

   typedef boost::unique_lock< read_write_mutex > write_lock;

   #ifdef ENABLE_STD_ALLOCATOR
      #define _ENABLE_STD_ALLOCATOR 1
   #else
      #define _ENABLE_STD_ALLOCATOR 0
   #endif

   using shared_string = std::conditional< _ENABLE_STD_ALLOCATOR,
                        std::string,
                        bip::basic_string< char, std::char_traits< char >, allocator< char > >
                        >::type;

   template<typename T>
   using t_vector = typename std::conditional< _ENABLE_STD_ALLOCATOR,
                              std::vector<T, allocator<T> >,
                              bip::vector<T, allocator<T> >
                              >::type;

   template< typename FIRST_TYPE, typename SECOND_TYPE >
   using t_pair = std::pair< FIRST_TYPE, SECOND_TYPE >;

   template< typename FIRST_TYPE, typename SECOND_TYPE >
   using t_allocator_pair = allocator< t_pair< const FIRST_TYPE, SECOND_TYPE > >;

   template< typename KEY_TYPE, typename VALUE_TYPE, typename LESS_FUNC = std::less<KEY_TYPE>>
   using t_flat_map = typename std::conditional< _ENABLE_STD_ALLOCATOR,
      boost::container::flat_map< KEY_TYPE, VALUE_TYPE, LESS_FUNC, allocator< t_pair< KEY_TYPE, VALUE_TYPE > > >,
      bip::flat_map< KEY_TYPE, VALUE_TYPE, LESS_FUNC, allocator< t_pair< KEY_TYPE, VALUE_TYPE > > >
      >::type;

   template< typename KEY_TYPE, typename VALUE_TYPE, typename LESS_FUNC = std::less<KEY_TYPE>>
   using t_map = typename std::conditional< _ENABLE_STD_ALLOCATOR,
                              std::map< KEY_TYPE, VALUE_TYPE, LESS_FUNC, t_allocator_pair< KEY_TYPE, VALUE_TYPE > >,
                              bip::map< KEY_TYPE, VALUE_TYPE, LESS_FUNC, t_allocator_pair< KEY_TYPE, VALUE_TYPE > >
                              >::type;

   template< typename T >
   using t_deque = typename std::conditional< _ENABLE_STD_ALLOCATOR,
                  std::deque< T, allocator< T > >,
                  bip::deque< T, allocator< T > >
                  >::type;

   template< typename T, typename LESS_FUNC >
   using t_set = typename std::conditional< _ENABLE_STD_ALLOCATOR,
                  std::set< T, LESS_FUNC, allocator< T > >,
                  bip::set< T, LESS_FUNC, allocator< T >  >
                  >::type;

}

max_stars_repo_name: ZhengGuoDeveloper/steem

max_issues_repo_name: ZhengGuoDeveloper/steem

max_forks_repo_name: ZhengGuoDeveloper/steem