<commit_before>#pragma once

#include "GraphTypes.hpp"
namespace envire { namespace core
{
    /** Structure to store the parent and children relation for a vertex in a tree.
     */
    struct VertexRelation
    {
        VertexRelation* parentRelation; /**<can be NULL */
        GraphTraits::vertex_descriptor parent; /**<can be null_vertex */
        std::unordered_set<GraphTraits::vertex_descriptor> children;
    };

    /**A map that shows the vertex information (parent and children) of the vertices in a tree.
       The key is the vertex descriptor.*/
    using VertexRelationMap = std::unordered_map<GraphTraits::vertex_descriptor, VertexRelation>;

    class TreeView;
    /**A class that notifies TreeViews about updates */
    struct TreeUpdatePublisher
    {
        virtual ~TreeUpdatePublisher() {}
        /**Unsubscribe the view from the publisher */
        virtual void unsubscribeTreeView(TreeView* view) = 0;
        /**Subscribe the view to the publisher */
        virtual void subscribeTreeView(TreeView* view) = 0;
    };

    /** A TreeView is a tree shaped snapshot of the graph structure.
     *  it is generated by traversing the graph in bfs order, starting from a
     *  root node. The vertex_descriptors used in the graph are pointers to
     *  vertices in the graph and can be used to manipulate the graph.
     */
    class TreeView
    {
    public:

        TreeView(GraphTraits::vertex_descriptor root) : root(root) {}

        TreeView() : root(GraphTraits::null_vertex()) {}

        /**Creates a copy ***without*** retaining the treeUpdated subscribers  */
        TreeView(const TreeView& other) {*this = other;}

        /**Creates a copy ***without*** retaining the treeUpdated subscribers  */
        TreeView& operator=(const TreeView& other);

        TreeView(TreeView&& other) noexcept;

        virtual ~TreeView();

        /**If a publisher is set the TreeView will automatically unsubscribe
        * from the publisher on destruction. */
        void setPublisher(TreeUpdatePublisher* pub);

        bool isRoot(const GraphTraits::vertex_descriptor vd) const;

        /**Removes all content from this TreeView */
        void clear();

        /**Unsibscribe from the currently subscribed publisher */
        void unsubscribe();

        /**Returns true if an edge between a and b exists in @p view
         * and is not a cross-edge*/
        bool edgeExists(const GraphTraits::vertex_descriptor a, const GraphTraits::vertex_descriptor b) const;
        /**Returns true if @p vd exists in the view. */
        bool vertexExists(const GraphTraits::vertex_descriptor vd) const;

        /**visits all vertices in the tree starting at @p node in dfs order.
         * I.e. it first visits node, then all its children.
         * Calls @p f(vertex_descriptor node, vertex_descriptor parent) for each node.*/
        template <class Func>
        void visitDfs(const GraphTraits::vertex_descriptor node, Func f)
        {
          const auto& parent = tree[node].parent;
          const auto& children = tree[node].children;
          f(node, parent);
          for(const GraphTraits::vertex_descriptor child : children)
          {
            visitDfs(child, f);
          }
        }

        /**visits all vertices in the tree starting at @p node in bfs order.
         * Calls @p f(vertex_descriptor node, vertex_descriptor parent) for each node.*/
        template <class Func>
        void visitBfs(const GraphTraits::vertex_descriptor node, Func f)
        {
            std::deque<GraphTraits::vertex_descriptor> nodesToVisit;
            nodesToVisit.push_back(node);
            while(nodesToVisit.size() > 0)
            {
                const GraphTraits::vertex_descriptor current = nodesToVisit.front();
                nodesToVisit.pop_front();
                const GraphTraits::vertex_descriptor parent = getParent(current);
                f(current, parent);
                for(GraphTraits::vertex_descriptor child : tree[current].children)
                {
                    nodesToVisit.push_back(child);
                }
            }
        }

        /**Add a cross edge to the view.
         * Emits crossEdgeAdded event */
        void addCrossEdge(const GraphTraits::edge_descriptor edge);

        /**Add an edge to the view.
         * Emits edgeAdded*/
        void addEdge(GraphTraits::vertex_descriptor origin, GraphTraits::vertex_descriptor target);

        /**Adds the initial root node to the TreeView */
        void addRoot(GraphTraits::vertex_descriptor root);

        //FIXME comment exception?!
        GraphTraits::vertex_descriptor getParent(GraphTraits::vertex_descriptor node) const;

        /**The signals are invoked whenever the tree is updated by the TransformGraph
        * @note This is only the case if you requested an updating TreeView.
        *       Otherwise they'll never be invoked.
        */
        boost::signals2::signal<void (GraphTraits::edge_descriptor)> crossEdgeAdded;
        boost::signals2::signal<void (GraphTraits::vertex_descriptor origin,
                                      GraphTraits::vertex_descriptor target)> edgeAdded;

        /* The edges, that had to be removed to create the tree.
         * I.e. All edges that lead to a vertex that has already been discovered.
         * This does **not** include back-edges. I.e. edges that lead to a vertex that
         * has already been visited.
         * @note The TransformGraph always contains two edges between connected nodes (the edge and the inverse edge)
         *       However only one of them will be in the crossEdges. The other one automatically becomes a back-edge
         *       and is ignored. */
        std::vector<GraphTraits::edge_descriptor> crossEdges;

        /**The root node of this TreeView */
        GraphTraits::vertex_descriptor root;
        VertexRelationMap tree;
    protected:
        TreeUpdatePublisher* publisher = nullptr;/*< Used for automatic unsubscribing in dtor */
    };
}}<commit_msg>TreeView: Fix indentation<commit_after>#pragma once

#include "GraphTypes.hpp"
namespace envire { namespace core
{
    /** Structure to store the parent and children relation for a vertex in a tree.
     */
    struct VertexRelation
    {
        VertexRelation* parentRelation; /**<can be NULL */
        GraphTraits::vertex_descriptor parent; /**<can be null_vertex */
        std::unordered_set<GraphTraits::vertex_descriptor> children;
    };

    /**A map that shows the vertex information (parent and children) of the vertices in a tree.
       The key is the vertex descriptor.*/
    using VertexRelationMap = std::unordered_map<GraphTraits::vertex_descriptor, VertexRelation>;

    class TreeView;
    /**A class that notifies TreeViews about updates */
    struct TreeUpdatePublisher
    {
        virtual ~TreeUpdatePublisher() {}
        /**Unsubscribe the view from the publisher */
        virtual void unsubscribeTreeView(TreeView* view) = 0;
        /**Subscribe the view to the publisher */
        virtual void subscribeTreeView(TreeView* view) = 0;
    };

    /** A TreeView is a tree shaped snapshot of the graph structure.
     *  it is generated by traversing the graph in bfs order, starting from a
     *  root node. The vertex_descriptors used in the graph are pointers to
     *  vertices in the graph and can be used to manipulate the graph.
     */
    class TreeView
    {
    public:

        TreeView(GraphTraits::vertex_descriptor root) : root(root) {}

        TreeView() : root(GraphTraits::null_vertex()) {}

        /**Creates a copy ***without*** retaining the treeUpdated subscribers  */
        TreeView(const TreeView& other) {*this = other;}

        /**Creates a copy ***without*** retaining the treeUpdated subscribers  */
        TreeView& operator=(const TreeView& other);

        TreeView(TreeView&& other) noexcept;

        virtual ~TreeView();

        /**If a publisher is set the TreeView will automatically unsubscribe
        * from the publisher on destruction. */
        void setPublisher(TreeUpdatePublisher* pub);

        bool isRoot(const GraphTraits::vertex_descriptor vd) const;

        /**Removes all content from this TreeView */
        void clear();

        /**Unsibscribe from the currently subscribed publisher */
        void unsubscribe();

        /**Returns true if an edge between a and b exists in @p view
         * and is not a cross-edge*/
        bool edgeExists(const GraphTraits::vertex_descriptor a, const GraphTraits::vertex_descriptor b) const;
        /**Returns true if @p vd exists in the view. */
        bool vertexExists(const GraphTraits::vertex_descriptor vd) const;

        /**visits all vertices in the tree starting at @p node in dfs order.
         * I.e. it first visits node, then all its children.
         * Calls @p f(vertex_descriptor node, vertex_descriptor parent) for each node.*/
        template <class Func>
        void visitDfs(const GraphTraits::vertex_descriptor node, Func f)
        {
            const auto& parent = tree[node].parent;
            const auto& children = tree[node].children;
            f(node, parent);
            for(const GraphTraits::vertex_descriptor child : children)
            {
                visitDfs(child, f);
            }
        }

        /**visits all vertices in the tree starting at @p node in bfs order.
         * Calls @p f(vertex_descriptor node, vertex_descriptor parent) for each node.*/
        template <class Func>
        void visitBfs(const GraphTraits::vertex_descriptor node, Func f)
        {
            std::deque<GraphTraits::vertex_descriptor> nodesToVisit;
            nodesToVisit.push_back(node);
            while(nodesToVisit.size() > 0)
            {
                const GraphTraits::vertex_descriptor current = nodesToVisit.front();
                nodesToVisit.pop_front();
                const GraphTraits::vertex_descriptor parent = getParent(current);
                f(current, parent);
                for(GraphTraits::vertex_descriptor child : tree[current].children)
                {
                    nodesToVisit.push_back(child);
                }
            }
        }

        /**Add a cross edge to the view.
         * Emits crossEdgeAdded event */
        void addCrossEdge(const GraphTraits::edge_descriptor edge);

        /**Add an edge to the view.
         * Emits edgeAdded*/
        void addEdge(GraphTraits::vertex_descriptor origin, GraphTraits::vertex_descriptor target);

        /**Adds the initial root node to the TreeView */
        void addRoot(GraphTraits::vertex_descriptor root);

        //FIXME comment exception?!
        GraphTraits::vertex_descriptor getParent(GraphTraits::vertex_descriptor node) const;

        /**The signals are invoked whenever the tree is updated by the TransformGraph
        * @note This is only the case if you requested an updating TreeView.
        *       Otherwise they'll never be invoked.
        */
        boost::signals2::signal<void (GraphTraits::edge_descriptor)> crossEdgeAdded;
        boost::signals2::signal<void (GraphTraits::vertex_descriptor origin,
                                      GraphTraits::vertex_descriptor target)> edgeAdded;

        /* The edges, that had to be removed to create the tree.
         * I.e. All edges that lead to a vertex that has already been discovered.
         * This does **not** include back-edges. I.e. edges that lead to a vertex that
         * has already been visited.
         * @note The TransformGraph always contains two edges between connected nodes (the edge and the inverse edge)
         *       However only one of them will be in the crossEdges. The other one automatically becomes a back-edge
         *       and is ignored. */
        std::vector<GraphTraits::edge_descriptor> crossEdges;

        /**The root node of this TreeView */
        GraphTraits::vertex_descriptor root;
        VertexRelationMap tree;
    protected:
        TreeUpdatePublisher* publisher = nullptr;/*< Used for automatic unsubscribing in dtor */
    };
}}<|endoftext|>


<commit_before>#include "Model.h"

Model::Model(std::string filename)
{
	loadModel(filename);
}

Model::~Model()
{

}

void Model::loadModel(std::string& path)
{
	Assimp::Importer importer;
	const aiScene* scene = importer.ReadFile(path, aiProcess_Triangulate | aiProcess_FlipUVs | aiProcess_GenNormals | aiProcess_OptimizeMeshes);

	if (!scene || scene->mFlags == AI_SCENE_FLAGS_INCOMPLETE || !scene->mRootNode)
	{
		printf("ERROR::ASSIMP:: %s\n", importer.GetErrorString());
		return;
	}

	directory = path.substr(0, path.find_last_of('/'));

	this->processNode(scene->mRootNode, scene);
}

void Model::processNode(aiNode* node, const aiScene* scene)
{
	for (GLuint i = 0; i < node->mNumMeshes; i++)
	{
		aiMesh* mesh = scene->mMeshes[node->mMeshes[i]];
		meshes.push_back(processMesh(mesh, scene));
	}

	for (GLuint i = 0; i < node->mNumChildren; i++)
	{
		processNode(node->mChildren[i], scene);
	}
}

Mesh Model::processMesh(aiMesh* mesh, const aiScene* scene)
{
	std::vector<Vertex> vertices;
	std::vector<GLuint> indices;
	std::vector<Texture> textures;

	for (GLuint i = 0; i < mesh->mNumVertices; i++)
	{
		Vertex vertex;

		glm::vec3 vector;

		vector.x = mesh->mVertices[i].x;
		vector.y = mesh->mVertices[i].y;
		vector.z = mesh->mVertices[i].z;
		vertex.Position = vector;

		if (mesh->HasNormals())
		{
			vector.x = mesh->mNormals[i].x;
			vector.y = mesh->mNormals[i].y;
			vector.z = mesh->mNormals[i].z;
			vertex.Normal = vector;
		}
		else
		{
			vertex.Normal = glm::vec3(0.0f, 0.0f, 0.0f);
		}

		if (mesh->mTextureCoords[0])
		{
			glm::vec2 vec;
			vec.x = mesh->mTextureCoords[0][i].x;
			vec.y = mesh->mTextureCoords[0][i].y;
			vertex.TexCoords = vec;
		}
		else
		{
			vertex.TexCoords = glm::vec2(0.0f, 0.0f);
		}

		vertices.push_back(vertex);
	}

	for (GLuint i = 0; i < mesh->mNumFaces; i++)
	{
		aiFace face = mesh->mFaces[i];

		for (GLuint j = 0; j < face.mNumIndices; j++)
		{
			indices.push_back(face.mIndices[j]);
		}
	}

	if (mesh->mMaterialIndex >= 0)
	{
		aiMaterial* material = scene->mMaterials[mesh->mMaterialIndex];

		std::vector<Texture> diffuseMaps = loadMaterialTextures(material, aiTextureType_DIFFUSE, "texture_diffuse");
		textures.insert(textures.end(), diffuseMaps.begin(), diffuseMaps.end());

		std::vector<Texture> specularMaps = loadMaterialTextures(material, aiTextureType_SPECULAR, "texture_specular");
		textures.insert(textures.end(), specularMaps.begin(), specularMaps.end());
	}

	return Mesh(vertices, indices, textures);
}

std::vector<Texture> Model::loadMaterialTextures(aiMaterial* mat, aiTextureType type, std::string typeName)
{
	TextureLoader textureLoader = TextureLoader::instance();

	std::vector<Texture> textures;

	for (GLuint i = 0; i < mat->GetTextureCount(type); i++)
	{
		aiString str;
		mat->GetTexture(type, i, &str);

		GLboolean skip = false;
		for (GLuint j = 0; j < texturesLoaded.size(); j++)
		{
			if (texturesLoaded[j].path == str)
			{
				textures.push_back(texturesLoaded[j]);
				skip = true;
				break;
			}
		}
		if (!skip)
		{
			Texture texture;
			texture.id = textureLoader.loadTexture(directory + "/" + std::string(str.C_Str()));
			texture.type = typeName;
			texture.path = str;
			textures.push_back(texture);

			texturesLoaded.push_back(texture);
		}
	}
	return textures;
}

void Model::draw(ShaderProgram* shader)
{
	for (GLuint i = 0; i < meshes.size(); i++)
		meshes[i].Draw(shader);
}<commit_msg>Tangent and Bitangent fix<commit_after>#include "Model.h"

Model::Model(std::string filename)
{
	loadModel(filename);
}

Model::~Model()
{

}

void Model::loadModel(std::string& path)
{
	Assimp::Importer importer;
	const aiScene* scene = importer.ReadFile(path, aiProcess_Triangulate | aiProcess_FlipUVs | aiProcess_GenNormals | aiProcess_OptimizeMeshes | aiProcess_CalcTangentSpace);

	if (!scene || scene->mFlags == AI_SCENE_FLAGS_INCOMPLETE || !scene->mRootNode)
	{
		printf("ERROR::ASSIMP:: %s\n", importer.GetErrorString());
		return;
	}

	directory = path.substr(0, path.find_last_of('/'));

	this->processNode(scene->mRootNode, scene);
}

void Model::processNode(aiNode* node, const aiScene* scene)
{
	for (GLuint i = 0; i < node->mNumMeshes; i++)
	{
		aiMesh* mesh = scene->mMeshes[node->mMeshes[i]];
		meshes.push_back(processMesh(mesh, scene));
	}

	for (GLuint i = 0; i < node->mNumChildren; i++)
	{
		processNode(node->mChildren[i], scene);
	}
}

Mesh Model::processMesh(aiMesh* mesh, const aiScene* scene)
{
	std::vector<Vertex> vertices;
	std::vector<GLuint> indices;
	std::vector<Texture> textures;

	for (GLuint i = 0; i < mesh->mNumVertices; i++)
	{
		Vertex vertex;

		glm::vec3 vector;

		vector.x = mesh->mVertices[i].x;
		vector.y = mesh->mVertices[i].y;
		vector.z = mesh->mVertices[i].z;
		vertex.Position = vector;

		if (mesh->HasNormals())
		{
			vector.x = mesh->mNormals[i].x;
			vector.y = mesh->mNormals[i].y;
			vector.z = mesh->mNormals[i].z;
			vertex.Normal = vector;
		}
		else
		{
			vertex.Normal = glm::vec3(0.0f, 0.0f, 0.0f);
		}

		if (mesh->mTextureCoords[0])
		{
			glm::vec2 vec;
			vec.x = mesh->mTextureCoords[0][i].x;
			vec.y = mesh->mTextureCoords[0][i].y;
			vertex.TexCoords = vec;
		}
		else
		{
			vertex.TexCoords = glm::vec2(0.0f, 0.0f);
		}

		if (mesh->HasTangentsAndBitangents())
		{
			vector.x = mesh->mTangents[i].x;
			vector.y = mesh->mTangents[i].y;
			vector.z = mesh->mTangents[i].z;
			vertex.Tangent = vector;

			vector.x = mesh->mBitangents[i].x;
			vector.y = mesh->mBitangents[i].y;
			vector.z = mesh->mBitangents[i].z;
			vertex.Bitangent = vector;
		}
		else
		{
			vertex.TexCoords = glm::vec2(0.0f, 0.0f);
		}

		vertices.push_back(vertex);
	}

	for (GLuint i = 0; i < mesh->mNumFaces; i++)
	{
		aiFace face = mesh->mFaces[i];

		for (GLuint j = 0; j < face.mNumIndices; j++)
		{
			indices.push_back(face.mIndices[j]);
		}
	}

	if (mesh->mMaterialIndex >= 0)
	{
		aiMaterial* material = scene->mMaterials[mesh->mMaterialIndex];

		std::vector<Texture> diffuseMaps = loadMaterialTextures(material, aiTextureType_DIFFUSE, "texture_diffuse");
		textures.insert(textures.end(), diffuseMaps.begin(), diffuseMaps.end());

		std::vector<Texture> specularMaps = loadMaterialTextures(material, aiTextureType_HEIGHT, "texture_normal");

		std::vector<Texture> specularMaps = loadMaterialTextures(material, aiTextureType_SPECULAR, "texture_specular");
		textures.insert(textures.end(), specularMaps.begin(), specularMaps.end());
	}

	return Mesh(vertices, indices, textures);
}

std::vector<Texture> Model::loadMaterialTextures(aiMaterial* mat, aiTextureType type, std::string typeName)
{
	TextureLoader textureLoader = TextureLoader::instance();

	std::vector<Texture> textures;

	for (GLuint i = 0; i < mat->GetTextureCount(type); i++)
	{
		aiString str;
		mat->GetTexture(type, i, &str);

		GLboolean skip = false;
		for (GLuint j = 0; j < texturesLoaded.size(); j++)
		{
			if (texturesLoaded[j].path == str)
			{
				textures.push_back(texturesLoaded[j]);
				skip = true;
				break;
			}
		}
		if (!skip)
		{
			Texture texture;
			texture.id = textureLoader.loadTexture(directory + "/" + std::string(str.C_Str()));
			texture.type = typeName;
			texture.path = str;
			textures.push_back(texture);

			texturesLoaded.push_back(texture);
		}
	}
	return textures;
}

void Model::draw(ShaderProgram* shader)
{
	for (GLuint i = 0; i < meshes.size(); i++)
		meshes[i].Draw(shader);
}<|endoftext|>


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

#include <utility>
#include <tuple>
#include "dbShape.h"
#include "search_gui.h"

namespace gui {

// Build the rtree's for the block
void Search::init(odb::dbBlock* block)
{
  for (odb::dbNet* net : block->getNets()) {
    addNet(net);
    addSNet(net);
  }

  for (odb::dbInst* inst : block->getInsts()) {
    odb::dbPlacementStatus status = inst->getPlacementStatus();
    if (status == odb::dbPlacementStatus::NONE
        || status == odb::dbPlacementStatus::UNPLACED) {
      continue;
    }
    addInst(inst);
  }
}

void Search::addVia(odb::dbNet* net,
                    odb::dbShape* shape,
                    int x,
                    int y)
{
  if (shape->getType() == odb::dbShape::TECH_VIA) {
    odb::dbTechVia* via = shape->getTechVia();
    for (odb::dbBox* box : via->getBoxes()) {
      point_t ll(x + box->xMin(), y + box->yMin());
      point_t ur(x + box->xMax(), y + box->yMax());
      box_t bbox(ll, ur);
      polygon_t poly;
      bg::convert(bbox,poly);
      shapes_[box->getTechLayer()].insert(std::make_tuple(bbox,poly, net));
    }
  } else {
    odb::dbVia* via = shape->getVia();
    for (odb::dbBox* box : via->getBoxes()) {
      point_t ll(x + box->xMin(), y + box->yMin());
      point_t ur(x + box->xMax(), y + box->yMax());
      box_t bbox(ll, ur);
      polygon_t poly;
      bg::convert(bbox,poly);
      shapes_[box->getTechLayer()].insert(std::make_tuple(bbox,poly, net));
    }
  }
}

void Search::addSNet(odb::dbNet* net)
{
  odb::dbSet<odb::dbSWire> swires = net->getSWires();

  for (auto itr = swires.begin(); itr != swires.end(); ++itr) {
    odb::dbSWire* swire = *itr;
    odb::dbSet<odb::dbSBox> wires = swire->getWires();
    odb::dbSet<odb::dbSBox>::iterator box_itr;

    for (box_itr = wires.begin(); box_itr != wires.end(); ++box_itr) {
      odb::dbSBox* box = *box_itr;
      if (box->isVia()) {
        continue;
      }

      box_t bbox(point_t(box->xMin(), box->yMin()),
                 point_t(box->xMax(), box->yMax()));
      polygon_t poly;
      auto points = box->getGeomShape()->getPoints();
      for(auto point:points)
        bg::append(poly.outer(),point_t(point.getX(),point.getY()));
      shapes_[box->getTechLayer()].insert(std::make_tuple(bbox,poly, net));
    }
  }
}

void Search::addNet(odb::dbNet* net)
{
  odb::dbWire* wire = net->getWire();

  if (wire == NULL)
    return;

  odb::dbWireShapeItr itr;
  odb::dbShape s;

  for (itr.begin(wire); itr.next(s);) {
    int shapeId = itr.getShapeId();
    if (s.isVia()) {
      addVia(net, &s, itr._prev_x, itr._prev_y);
    } else {
      box_t box(point_t(s.xMin(), s.yMin()), point_t(s.xMax(), s.yMax()));
      polygon_t poly;
      bg::convert(box,poly);
      shapes_[s.getTechLayer()].insert(std::make_tuple(box,poly, net));
    }
  }
}

void Search::addInst(odb::dbInst* inst)
{
  odb::dbBox* bbox = inst->getBBox();
  point_t ll(bbox->xMin(), bbox->yMin());
  point_t ur(bbox->xMax(), bbox->yMax());
  box_t box(ll, ur);
  polygon_t poly;
  bg::convert(box,poly);
  insts_.insert(std::make_tuple(box,poly, inst));
}

void Search::clear()
{
  insts_.clear();
  shapes_.clear();
}

template <typename T>
class Search::MinSizePredicate
{
 public:
  MinSizePredicate(int min_size) : min_size_(min_size) {}
  bool operator()(const std::tuple<box_t,polygon_t, T>& o) const
  {
    box_t box = std::get<0>(o);
    const point_t& ll = box.min_corner();
    const point_t& ur = box.max_corner();
    int w = ur.x() - ll.x();
    int h = ur.y() - ll.y();
    return std::max(w, h) >= min_size_;
  }

 private:
  int min_size_;
};

template <typename T>
class Search::MinHeightPredicate
{
 public:
  MinHeightPredicate(int min_height) : min_height_(min_height) {}
  bool operator()(const std::tuple<box_t,polygon_t, T>& o) const
  {
    box_t box = std::get<0>(o);
    const point_t& ll = box.min_corner();
    const point_t& ur = box.max_corner();
    int h = ur.y() - ll.y();
    return h >= min_height_;
  }

 private:
  int min_height_;
};

Search::ShapeRange Search::search_shapes(odb::dbTechLayer* layer,
                                         int xLo,
                                         int yLo,
                                         int xHi,
                                         int yHi,
                                         int minSize)
{
  auto it = shapes_.find(layer);
  if (it == shapes_.end()) {
    return ShapeRange();
  }

  auto& rtree = it->second;

  box_t query(point_t(xLo, yLo), point_t(xHi, yHi));
  if (minSize > 0) {
    return ShapeRange(
        rtree.qbegin(bgi::intersects(query)
                     && bgi::satisfies(MinSizePredicate<odb::dbNet*>(minSize))),
        rtree.qend());
  }

  return ShapeRange(rtree.qbegin(bgi::intersects(query)), rtree.qend());
}

Search::InstRange Search::search_insts(int xLo,
                                       int yLo,
                                       int xHi,
                                       int yHi,
                                       int minHeight)
{
  box_t query(point_t(xLo, yLo), point_t(xHi, yHi));
  if (minHeight > 0) {
    return InstRange(
        insts_.qbegin(
            bgi::intersects(query)
            && bgi::satisfies(MinHeightPredicate<odb::dbInst*>(minHeight))),
        insts_.qend());
  }

  return InstRange(insts_.qbegin(bgi::intersects(query)), insts_.qend());
}

}  // namespace gui
<commit_msg>include bug fix<commit_after>///////////////////////////////////////////////////////////////////////////////
// BSD 3-Clause License
//
// Copyright (c) 2019, OpenROAD
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice, this
//   list of conditions and the following disclaimer.
//
// * Redistributions in binary form must reproduce the above copyright notice,
//   this list of conditions and the following disclaimer in the documentation
//   and/or other materials provided with the distribution.
//
// * Neither the name of the copyright holder nor the names of its
//   contributors may be used to endorse or promote products derived from
//   this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.

#include <utility>
#include <tuple>
#include "dbShape.h"
#include "search.h"

namespace gui {

// Build the rtree's for the block
void Search::init(odb::dbBlock* block)
{
  for (odb::dbNet* net : block->getNets()) {
    addNet(net);
    addSNet(net);
  }

  for (odb::dbInst* inst : block->getInsts()) {
    odb::dbPlacementStatus status = inst->getPlacementStatus();
    if (status == odb::dbPlacementStatus::NONE
        || status == odb::dbPlacementStatus::UNPLACED) {
      continue;
    }
    addInst(inst);
  }
}

void Search::addVia(odb::dbNet* net,
                    odb::dbShape* shape,
                    int x,
                    int y)
{
  if (shape->getType() == odb::dbShape::TECH_VIA) {
    odb::dbTechVia* via = shape->getTechVia();
    for (odb::dbBox* box : via->getBoxes()) {
      point_t ll(x + box->xMin(), y + box->yMin());
      point_t ur(x + box->xMax(), y + box->yMax());
      box_t bbox(ll, ur);
      polygon_t poly;
      bg::convert(bbox,poly);
      shapes_[box->getTechLayer()].insert(std::make_tuple(bbox,poly, net));
    }
  } else {
    odb::dbVia* via = shape->getVia();
    for (odb::dbBox* box : via->getBoxes()) {
      point_t ll(x + box->xMin(), y + box->yMin());
      point_t ur(x + box->xMax(), y + box->yMax());
      box_t bbox(ll, ur);
      polygon_t poly;
      bg::convert(bbox,poly);
      shapes_[box->getTechLayer()].insert(std::make_tuple(bbox,poly, net));
    }
  }
}

void Search::addSNet(odb::dbNet* net)
{
  odb::dbSet<odb::dbSWire> swires = net->getSWires();

  for (auto itr = swires.begin(); itr != swires.end(); ++itr) {
    odb::dbSWire* swire = *itr;
    odb::dbSet<odb::dbSBox> wires = swire->getWires();
    odb::dbSet<odb::dbSBox>::iterator box_itr;

    for (box_itr = wires.begin(); box_itr != wires.end(); ++box_itr) {
      odb::dbSBox* box = *box_itr;
      if (box->isVia()) {
        continue;
      }

      box_t bbox(point_t(box->xMin(), box->yMin()),
                 point_t(box->xMax(), box->yMax()));
      polygon_t poly;
      auto points = box->getGeomShape()->getPoints();
      for(auto point:points)
        bg::append(poly.outer(),point_t(point.getX(),point.getY()));
      shapes_[box->getTechLayer()].insert(std::make_tuple(bbox,poly, net));
    }
  }
}

void Search::addNet(odb::dbNet* net)
{
  odb::dbWire* wire = net->getWire();

  if (wire == NULL)
    return;

  odb::dbWireShapeItr itr;
  odb::dbShape s;

  for (itr.begin(wire); itr.next(s);) {
    int shapeId = itr.getShapeId();
    if (s.isVia()) {
      addVia(net, &s, itr._prev_x, itr._prev_y);
    } else {
      box_t box(point_t(s.xMin(), s.yMin()), point_t(s.xMax(), s.yMax()));
      polygon_t poly;
      bg::convert(box,poly);
      shapes_[s.getTechLayer()].insert(std::make_tuple(box,poly, net));
    }
  }
}

void Search::addInst(odb::dbInst* inst)
{
  odb::dbBox* bbox = inst->getBBox();
  point_t ll(bbox->xMin(), bbox->yMin());
  point_t ur(bbox->xMax(), bbox->yMax());
  box_t box(ll, ur);
  polygon_t poly;
  bg::convert(box,poly);
  insts_.insert(std::make_tuple(box,poly, inst));
}

void Search::clear()
{
  insts_.clear();
  shapes_.clear();
}

template <typename T>
class Search::MinSizePredicate
{
 public:
  MinSizePredicate(int min_size) : min_size_(min_size) {}
  bool operator()(const std::tuple<box_t,polygon_t, T>& o) const
  {
    box_t box = std::get<0>(o);
    const point_t& ll = box.min_corner();
    const point_t& ur = box.max_corner();
    int w = ur.x() - ll.x();
    int h = ur.y() - ll.y();
    return std::max(w, h) >= min_size_;
  }

 private:
  int min_size_;
};

template <typename T>
class Search::MinHeightPredicate
{
 public:
  MinHeightPredicate(int min_height) : min_height_(min_height) {}
  bool operator()(const std::tuple<box_t,polygon_t, T>& o) const
  {
    box_t box = std::get<0>(o);
    const point_t& ll = box.min_corner();
    const point_t& ur = box.max_corner();
    int h = ur.y() - ll.y();
    return h >= min_height_;
  }

 private:
  int min_height_;
};

Search::ShapeRange Search::search_shapes(odb::dbTechLayer* layer,
                                         int xLo,
                                         int yLo,
                                         int xHi,
                                         int yHi,
                                         int minSize)
{
  auto it = shapes_.find(layer);
  if (it == shapes_.end()) {
    return ShapeRange();
  }

  auto& rtree = it->second;

  box_t query(point_t(xLo, yLo), point_t(xHi, yHi));
  if (minSize > 0) {
    return ShapeRange(
        rtree.qbegin(bgi::intersects(query)
                     && bgi::satisfies(MinSizePredicate<odb::dbNet*>(minSize))),
        rtree.qend());
  }

  return ShapeRange(rtree.qbegin(bgi::intersects(query)), rtree.qend());
}

Search::InstRange Search::search_insts(int xLo,
                                       int yLo,
                                       int xHi,
                                       int yHi,
                                       int minHeight)
{
  box_t query(point_t(xLo, yLo), point_t(xHi, yHi));
  if (minHeight > 0) {
    return InstRange(
        insts_.qbegin(
            bgi::intersects(query)
            && bgi::satisfies(MinHeightPredicate<odb::dbInst*>(minHeight))),
        insts_.qend());
  }

  return InstRange(insts_.qbegin(bgi::intersects(query)), insts_.qend());
}

}  // namespace gui
<|endoftext|>


<commit_before>#include "v4l2capture.h"
#include "v4l2camera.h"

V4L2Capture::V4L2Capture( const int cameras )
{
}

V4L2Capture::~V4L2Capture()
{
}

void V4L2Capture::addCamera( const std::string& a_fileName )
{
    m_cameras.push_back( new V4L2Camera( a_fileName ) );
    m_acquisition.push_back( false );
}

bool V4L2Capture::isTerminated()
{
    return m_terminate;
}

void V4L2Capture::start()
{
    for( unsigned int i = 0; i < m_cameras.size(); i++ )
    {
       m_threads.push_back( new boost::thread( boost::bind( &V4L2Capture::acquisition_thread, this, i ) ) );
    }
}

void V4L2Capture::stop()
{
    m_terminate = true;
}

void V4L2Capture::join()
{
    for( unsigned int i = 0; i < m_threads.size(); i++ )
    {
        m_threads[i]->join();
    }
}

void V4L2Capture::receive( const cuttlefish_msgs::V4L2Control* msg )
{
    const int camera = msg->camera_no();

    switch( msg->command() )
    {
    case cuttlefish_msgs::V4L2Control_CommandType_OPEN:
        break;
    case cuttlefish_msgs::V4L2Control_CommandType_CLOSE:
        break;
    case cuttlefish_msgs::V4L2Control_CommandType_START:
        break;
    case cuttlefish_msgs::V4L2Control_CommandType_STOP:
        break;
    case cuttlefish_msgs::V4L2Control_CommandType_TERMINATE:
        break;
    }
}

void V4L2Capture::acquisition_thread( const int camera_id )
{
   V4L2Camera* input = m_cameras.at( camera_id );
   /*
   input->stopCapture();
   sleep( 2 );

   int frame=0;
   input->init_mmap();
   input->readyCapture();

   barrier->wait();
   input->startCapture();

   image_t* image = data->localImage( id );
   image->info.width = settings::width;
   image->info.height = settings::height;
   image->info.Kb = 1.0;
   image->info.Kg = 1.0;
   image->info.Kr = 1.0;
   image->info.max_size = image->info.width * image->info.height * 2; // YUV = 2 bytes per pixel.
   image->data = new unsigned char[ image->info.max_size ];

   if( !( input->readyFrame() &&
          input->readFrame( image->data, image->info.size, image->info.timestamp )
          ) )
   {
      std::cerr << "Unable to read the first frame." << std::endl;
      return;
   }

   std::cerr << "Camera(" << id << ") - frame size: " << image->info.size << std::endl;

   bool ok = true;

   int accum_diff = 0; // only used by id == 0
   int accum_frames = 0; // only used by id == 0
   int accum_diff01 = 0; // only used by id == 0

   int default_exposure = 0;
   input->getAbsoluteExposure( default_exposure );

   while( true )
   {
      ok = input->readyFrame();

      if( !ok )
      {
         std::cerr << "readyFrame failed." << std::endl;
         break;
      }
      input->readFrame( (unsigned char*) image->data, image->info.size, image->info.timestamp );
      input->getAbsoluteExposure( image->info.exposure_time );

      if( image->info.exposure_time != default_exposure )
      {
         input->setAbsoluteExposure( default_exposure );
      }

      frame++;

      image->info.frame_number = frame;

      barrier->wait();

      if( id == 0 ) // only one thread executes this code.
      {
         int diff = 0;
         struct timeval min = image->info.timestamp;
         struct timeval max = image->info.timestamp;

         for( unsigned int i = 0; i < data->localGroupSize(); i++ )
         {
            struct timeval tv = m_outputData->localImage( i )->info.timestamp;

            if( timevaldiff( &min, &tv ) > 0 )
            {
               min = tv;
            }
            if( timevaldiff( &max, &tv ) < 0 )
            {
               max = tv;
            }
         }
         diff = abs( timevaldiff( &max, &min ) );
         int diff01 = timevaldiff( &m_outputData->localImage( 0 )->info.timestamp, &m_outputData->localImage( 1 )->info.timestamp );
         accum_diff01 += diff01;

         accum_diff += diff;
         accum_frames++;

         if( diff < 2500 )
         {
            data->writeAndNotify();
            std::cerr << "." << std::flush;
         }
         else
         {
            std::cerr << "\n" << "frame " << frame << " dropped - time delta: " << diff/1000.0 << " ms" << std::endl;
         }
         if( accum_frames > 5 )
         {
            if( ( accum_diff / accum_frames ) > 10000 )
            {
               m_needSync = true;
            }
            else
            {
               //int diff = accum_diff / ( accum_frames * 1000.0 ) + 0.5;

               if( accum_diff01 / accum_frames > 75 )
               {
                  diff = 1;
               }
               else if( accum_diff01 / accum_frames < -75 )
               {
                  diff = -1;
               }
               else
               {
                  diff = 0;
               }
               if( diff != 0 )
               {
                  input->setAbsoluteExposure( default_exposure + diff );
                  int value;
                  input->getAbsoluteExposure( value );
                  std::cout << "used exposure: " << value << std::endl;
                  accum_diff = 0;
                  accum_frames = 0;
                  accum_diff01 = 0;
               }
            }
         }
      }

      barrier->wait();
      if( m_needSync == true )
      {
         std::cerr << "sync required. - doing sync." << std::endl;
         input->stopCapture();
         input->readyCapture();
         barrier->wait();
         input->startCapture();

         if( id == 0 )
         {
            *need_sync = false;
            accum_diff = 0;
            accum_frames = 0;
            accum_diff01 = 0;
         }
      }

      if( id == 0 && accum_frames >= 50 )
      {
         std::cerr << "Avg: " << accum_diff / accum_frames / 1000.0 << " ms" << std::endl;
         accum_frames = 0;
         accum_diff = 0;
         accum_diff01 = 0;
      }
   }
   input->stopCapture();
   */
}
<commit_msg>fixed V4L2 constructor.<commit_after>#include "v4l2capture.h"
#include "v4l2camera.h"

V4L2Capture::V4L2Capture( const int cameras )
{
    std::string name = "/dev/video";
    for( int i = 0; i < cameras; i++ )
    {
        addCamera( name + std::to_string( i ) );
    }
}

V4L2Capture::~V4L2Capture()
{
}

void V4L2Capture::addCamera( const std::string& a_fileName )
{
    m_cameras.push_back( new V4L2Camera( a_fileName ) );
    m_acquisition.push_back( false );
}

bool V4L2Capture::isTerminated()
{
    return m_terminate;
}

void V4L2Capture::start()
{
    for( unsigned int i = 0; i < m_cameras.size(); i++ )
    {
       m_threads.push_back( new boost::thread( boost::bind( &V4L2Capture::acquisition_thread, this, i ) ) );
    }
}

void V4L2Capture::stop()
{
    m_terminate = true;
}

void V4L2Capture::join()
{
    for( unsigned int i = 0; i < m_threads.size(); i++ )
    {
        m_threads[i]->join();
    }
}

void V4L2Capture::receive( const cuttlefish_msgs::V4L2Control* msg )
{
    const int camera = msg->camera_no();

    switch( msg->command() )
    {
    case cuttlefish_msgs::V4L2Control_CommandType_OPEN:
        break;
    case cuttlefish_msgs::V4L2Control_CommandType_CLOSE:
        break;
    case cuttlefish_msgs::V4L2Control_CommandType_START:
        break;
    case cuttlefish_msgs::V4L2Control_CommandType_STOP:
        break;
    case cuttlefish_msgs::V4L2Control_CommandType_TERMINATE:
        break;
    }
}

void V4L2Capture::acquisition_thread( const int camera_id )
{
   V4L2Camera* input = m_cameras.at( camera_id );
   /*
   input->stopCapture();
   sleep( 2 );

   int frame=0;
   input->init_mmap();
   input->readyCapture();

   barrier->wait();
   input->startCapture();

   image_t* image = data->localImage( id );
   image->info.width = settings::width;
   image->info.height = settings::height;
   image->info.Kb = 1.0;
   image->info.Kg = 1.0;
   image->info.Kr = 1.0;
   image->info.max_size = image->info.width * image->info.height * 2; // YUV = 2 bytes per pixel.
   image->data = new unsigned char[ image->info.max_size ];

   if( !( input->readyFrame() &&
          input->readFrame( image->data, image->info.size, image->info.timestamp )
          ) )
   {
      std::cerr << "Unable to read the first frame." << std::endl;
      return;
   }

   std::cerr << "Camera(" << id << ") - frame size: " << image->info.size << std::endl;

   bool ok = true;

   int accum_diff = 0; // only used by id == 0
   int accum_frames = 0; // only used by id == 0
   int accum_diff01 = 0; // only used by id == 0

   int default_exposure = 0;
   input->getAbsoluteExposure( default_exposure );

   while( true )
   {
      ok = input->readyFrame();

      if( !ok )
      {
         std::cerr << "readyFrame failed." << std::endl;
         break;
      }
      input->readFrame( (unsigned char*) image->data, image->info.size, image->info.timestamp );
      input->getAbsoluteExposure( image->info.exposure_time );

      if( image->info.exposure_time != default_exposure )
      {
         input->setAbsoluteExposure( default_exposure );
      }

      frame++;

      image->info.frame_number = frame;

      barrier->wait();

      if( id == 0 ) // only one thread executes this code.
      {
         int diff = 0;
         struct timeval min = image->info.timestamp;
         struct timeval max = image->info.timestamp;

         for( unsigned int i = 0; i < data->localGroupSize(); i++ )
         {
            struct timeval tv = m_outputData->localImage( i )->info.timestamp;

            if( timevaldiff( &min, &tv ) > 0 )
            {
               min = tv;
            }
            if( timevaldiff( &max, &tv ) < 0 )
            {
               max = tv;
            }
         }
         diff = abs( timevaldiff( &max, &min ) );
         int diff01 = timevaldiff( &m_outputData->localImage( 0 )->info.timestamp, &m_outputData->localImage( 1 )->info.timestamp );
         accum_diff01 += diff01;

         accum_diff += diff;
         accum_frames++;

         if( diff < 2500 )
         {
            data->writeAndNotify();
            std::cerr << "." << std::flush;
         }
         else
         {
            std::cerr << "\n" << "frame " << frame << " dropped - time delta: " << diff/1000.0 << " ms" << std::endl;
         }
         if( accum_frames > 5 )
         {
            if( ( accum_diff / accum_frames ) > 10000 )
            {
               m_needSync = true;
            }
            else
            {
               //int diff = accum_diff / ( accum_frames * 1000.0 ) + 0.5;

               if( accum_diff01 / accum_frames > 75 )
               {
                  diff = 1;
               }
               else if( accum_diff01 / accum_frames < -75 )
               {
                  diff = -1;
               }
               else
               {
                  diff = 0;
               }
               if( diff != 0 )
               {
                  input->setAbsoluteExposure( default_exposure + diff );
                  int value;
                  input->getAbsoluteExposure( value );
                  std::cout << "used exposure: " << value << std::endl;
                  accum_diff = 0;
                  accum_frames = 0;
                  accum_diff01 = 0;
               }
            }
         }
      }

      barrier->wait();
      if( m_needSync == true )
      {
         std::cerr << "sync required. - doing sync." << std::endl;
         input->stopCapture();
         input->readyCapture();
         barrier->wait();
         input->startCapture();

         if( id == 0 )
         {
            *need_sync = false;
            accum_diff = 0;
            accum_frames = 0;
            accum_diff01 = 0;
         }
      }

      if( id == 0 && accum_frames >= 50 )
      {
         std::cerr << "Avg: " << accum_diff / accum_frames / 1000.0 << " ms" << std::endl;
         accum_frames = 0;
         accum_diff = 0;
         accum_diff01 = 0;
      }
   }
   input->stopCapture();
   */
}
<|endoftext|>


<commit_before>#include <QEventLoop>
#include <QTimer>

#include "connectiontester.h"
#include "iceflowcontrol.h"
#include "ice.h"

FlowAgent::FlowAgent():
  candidates_(nullptr),
  sessionID_(0)
{
}

FlowAgent::~FlowAgent()
{
  delete candidates_;
}

void FlowAgent::run() { }

void FlowAgent::setCandidates(QList<ICEPair *> *candidates)
{
  candidates_ = candidates;
}

void FlowAgent::setSessionID(uint32_t sessionID)
{
  sessionID_ = sessionID;
}

void FlowAgent::nominationDone(ICEPair *rtp, ICEPair *rtcp)
{
  if (nominated_mtx.try_lock())
  {
    nominated_rtp_  = rtp;
    nominated_rtcp_ = rtcp;
  }

  emit endNomination();
}

bool FlowAgent::waitForResponses(unsigned long timeout)
{
  QTimer timer;
  QEventLoop loop;

  timer.setSingleShot(true);

  connect(this,   &FlowAgent::endNomination, &loop, &QEventLoop::quit);
  connect(&timer, &QTimer::timeout,          &loop, &QEventLoop::quit);

  timer.start(20000);
  loop.exec();

  return timer.isActive();
}

void FlowController::run()
{
  Stun stun;

  // TODO how long should we sleep???
  for (volatile int i = 0; i < 10000000; ++i)
    ;

  if (candidates_ == nullptr || candidates_->size() == 0)
  {
    qDebug() << "ERROR: invalid candidates, unable to perform ICE candidate negotiation!";
    emit ready(nullptr, nullptr, sessionID_);
    return;
  }

  std::vector<std::unique_ptr<ConnectionTester>> workerThreads;

  for (int i = 0; i < candidates_->size(); i += 2)
  {
    workerThreads.push_back(std::make_unique<ConnectionTester>());

    connect(workerThreads.back().get(), &ConnectionTester::testingDone, this, &FlowAgent::nominationDone, Qt::DirectConnection);

    workerThreads.back()->setCandidatePair(candidates_->at(i), candidates_->at(i + 1));
    workerThreads.back()->isController(true);
    workerThreads.back()->start();
  }

  // we've spawned threads for each candidate, wait for responses at most 10 seconds
  if (!waitForResponses(10000))
  {
    qDebug() << "Remote didn't respond to our request in time!";
    emit ready(nullptr, nullptr, sessionID_);
    return;
  }

  // we got a response, suspend all threads and start nomination
  for (size_t i = 0; i < workerThreads.size(); ++i)
  {
    workerThreads[i]->quit();
    workerThreads[i]->wait();
  }

  if (!stun.sendNominationRequest(nominated_rtp_))
  {
    qDebug() << "Failed to nominate RTP candidate!";
    emit ready(nullptr, nullptr, sessionID_);
    return;
  }

  if (!stun.sendNominationRequest(nominated_rtcp_))
  {
    qDebug() << "Failed to nominate RTCP candidate!";
    emit ready(nominated_rtp_, nullptr, sessionID_);
    return;
  }

  nominated_rtp_->state  = PAIR_NOMINATED;
  nominated_rtcp_->state = PAIR_NOMINATED;

  emit ready(nominated_rtp_, nominated_rtcp_, sessionID_);
}

void FlowControllee::run()
{
  QTimer timer;
  QEventLoop loop;

  if (candidates_ == nullptr || candidates_->size() == 0)
  {
    qDebug() << "ERROR: invalid candidates, unable to perform ICE candidate negotiation!";
    emit ready(nullptr, nullptr, sessionID_);
    return;
  }

  std::vector<std::unique_ptr<ConnectionTester>> workerThreads;

  for (int i = 0; i < candidates_->size(); i += 2)
  {
    workerThreads.push_back(std::make_unique<ConnectionTester>());

    connect(workerThreads.back().get(), &ConnectionTester::testingDone, this, &FlowAgent::nominationDone, Qt::DirectConnection);

    workerThreads.back()->setCandidatePair(candidates_->at(i), candidates_->at(i + 1));
    workerThreads.back()->isController(false);
    workerThreads.back()->start();
  }

  // wait for nomination from remote, wait at most 20 seconds
  if (!waitForResponses(20000))
  {
    qDebug() << "Nomination from remote was not received in time!";
    emit ready(nullptr, nullptr, sessionID_);
    return;
  }

  // we got a nomination from remote, kill all threads and start the media transmission
  for (size_t i = 0; i < workerThreads.size(); ++i)
  {
    workerThreads[i]->quit();
    workerThreads[i]->wait();
  }

  emit ready(nominated_rtp_, nominated_rtcp_, sessionID_);
}
<commit_msg>Terminate threads before killing the FlowAgent<commit_after>#include <QEventLoop>
#include <QTimer>

#include "connectiontester.h"
#include "iceflowcontrol.h"
#include "ice.h"

FlowAgent::FlowAgent():
  candidates_(nullptr),
  sessionID_(0)
{
}

FlowAgent::~FlowAgent()
{
  delete candidates_;
}

void FlowAgent::run() { }

void FlowAgent::setCandidates(QList<ICEPair *> *candidates)
{
  candidates_ = candidates;
}

void FlowAgent::setSessionID(uint32_t sessionID)
{
  sessionID_ = sessionID;
}

void FlowAgent::nominationDone(ICEPair *rtp, ICEPair *rtcp)
{
  if (nominated_mtx.try_lock())
  {
    nominated_rtp_  = rtp;
    nominated_rtcp_ = rtcp;
  }

  emit endNomination();
}

bool FlowAgent::waitForResponses(unsigned long timeout)
{
  QTimer timer;
  QEventLoop loop;

  timer.setSingleShot(true);

  connect(this,   &FlowAgent::endNomination, &loop, &QEventLoop::quit);
  connect(&timer, &QTimer::timeout,          &loop, &QEventLoop::quit);

  timer.start(20000);
  loop.exec();

  return timer.isActive();
}

void FlowController::run()
{
  Stun stun;

  // TODO how long should we sleep???
  /* for (volatile int i = 0; i < 10000000; ++i) */
  /*   ; */

  if (candidates_ == nullptr || candidates_->size() == 0)
  {
    qDebug() << "ERROR: invalid candidates, unable to perform ICE candidate negotiation!";
    emit ready(nullptr, nullptr, sessionID_);
    return;
  }

  std::vector<std::unique_ptr<ConnectionTester>> workerThreads;

  for (int i = 0; i < candidates_->size(); i += 2)
  {
    workerThreads.push_back(std::make_unique<ConnectionTester>());

    connect(workerThreads.back().get(), &ConnectionTester::testingDone, this, &FlowAgent::nominationDone, Qt::DirectConnection);

    workerThreads.back()->setCandidatePair(candidates_->at(i), candidates_->at(i + 1));
    workerThreads.back()->isController(true);
    workerThreads.back()->start();
  }

  bool nominationSucceeded = waitForResponses(10000);

  // we got a response, suspend all threads and start nomination
  for (size_t i = 0; i < workerThreads.size(); ++i)
  {
    workerThreads[i]->quit();
    workerThreads[i]->wait();
  }

  // we've spawned threads for each candidate, wait for responses at most 10 seconds
  if (!nominationSucceeded)
  {
    qDebug() << "Remote didn't respond to our request in time!";
    emit ready(nullptr, nullptr, sessionID_);
    return;
  }

  if (!stun.sendNominationRequest(nominated_rtp_))
  {
    qDebug() << "Failed to nominate RTP candidate!";
    emit ready(nullptr, nullptr, sessionID_);
    return;
  }

  if (!stun.sendNominationRequest(nominated_rtcp_))
  {
    qDebug() << "Failed to nominate RTCP candidate!";
    emit ready(nominated_rtp_, nullptr, sessionID_);
    return;
  }

  nominated_rtp_->state  = PAIR_NOMINATED;
  nominated_rtcp_->state = PAIR_NOMINATED;

  emit ready(nominated_rtp_, nominated_rtcp_, sessionID_);
}

void FlowControllee::run()
{
  QTimer timer;
  QEventLoop loop;

  if (candidates_ == nullptr || candidates_->size() == 0)
  {
    qDebug() << "ERROR: invalid candidates, unable to perform ICE candidate negotiation!";
    emit ready(nullptr, nullptr, sessionID_);
    return;
  }

  std::vector<std::unique_ptr<ConnectionTester>> workerThreads;

  for (int i = 0; i < candidates_->size(); i += 2)
  {
    workerThreads.push_back(std::make_unique<ConnectionTester>());

    connect(workerThreads.back().get(), &ConnectionTester::testingDone, this, &FlowAgent::nominationDone, Qt::DirectConnection);

    workerThreads.back()->setCandidatePair(candidates_->at(i), candidates_->at(i + 1));
    workerThreads.back()->isController(false);
    workerThreads.back()->start();
  }

  bool nominationSucceeded = waitForResponses(20000);

  // kill all threads, regardless of whether nomination succeeded or not
  for (size_t i = 0; i < workerThreads.size(); ++i)
  {
    workerThreads[i]->quit();
    workerThreads[i]->wait();
  }

  // wait for nomination from remote, wait at most 20 seconds
  if (!nominationSucceeded)
  {
    qDebug() << "Nomination from remote was not received in time!";
    emit ready(nullptr, nullptr, sessionID_);
    return;
  }

  // media transmission can be started
  emit ready(nominated_rtp_, nominated_rtcp_, sessionID_);
}
<|endoftext|>


<commit_before>#include <Core/Utils/Observable.hpp>
#include <catch2/catch.hpp>

using Ra::Core::Utils::Observable;

class ObservableTest : public Observable<>
{};

class ObservableTest2 : public Observable<int>
{};

class A
{
  public:
    void f() { m_a++; }
    void f2( int a ) { m_a = a; }
    static void g() { m_b++; }
    static void g2( int b ) { m_b = b; }

    int m_a {0};
    static int m_b;
};

int A::m_b = 0;

TEST_CASE( "Core/Utils/Observable", "[Core][Core/Utils][Observable]" ) {
    ObservableTest test;
    ObservableTest2 test2;

    A a;
    int c  = 0;
    A::m_b = 0;

    using Observer  = std::function<void( void )>;
    using Observer2 = std::function<void( int )>;

    auto bf = std::bind( &A::f, &a );

    Observer obf         = bf;
    auto& observerTarget = obf.target_type();
    // "Type failed."
    REQUIRE( obf.target_type() == observerTarget );

    auto gid = test.attach( A::g );
    test.attach( bf );
    test.attach( [&c]() { c++; } );
    test.notify();

    REQUIRE( c == 1 );
    REQUIRE( a.m_a == 1 );
    REQUIRE( A::m_b == 1 );

    test.detach( gid );
    test.notify();

    REQUIRE( c == 2 );
    REQUIRE( a.m_a == 2 );
    // Test detach
    REQUIRE( A::m_b == 1 );

    test.attach( A::g );
    test.attach( A::g );
    test.attach( bf );
    test.attach( [&c]() { c++; } );
    test.notify();

    REQUIRE( c == 4 );
    REQUIRE( a.m_a == 4 );
    REQUIRE( A::m_b == 3 );

    test.detachAll();
    test.notify();

    // Test detach
    REQUIRE( c == 4 );
    REQUIRE( a.m_a == 4 );
    REQUIRE( A::m_b == 3 );

    test2.attachMember( &a, &A::f2 );
    test2.attach( &A::g2 );
    test2.attach( [&c]( int pc ) { c = pc; } );

    test2.notify( 5 );

    REQUIRE( c == 5 );
    REQUIRE( a.m_a == 5 );
    REQUIRE( A::m_b == 5 );

    test2.notify( 6 );

    REQUIRE( c == 6 );
    REQUIRE( a.m_a == 6 );
    REQUIRE( A::m_b == 6 );

    ObservableTest2 test2copy;
    test2.copyObserversTo( test2copy );

    test2.detachAll();
    test2.notify( 7 );

    REQUIRE( c == 6 );
    REQUIRE( a.m_a == 6 );
    REQUIRE( A::m_b == 6 );

    test2copy.notify( 7 );

    REQUIRE( c == 7 );
    REQUIRE( a.m_a == 7 );
    REQUIRE( A::m_b == 7 );
}
<commit_msg>[tests] comment and todo.<commit_after>#include <Core/Utils/Observable.hpp>
#include <catch2/catch.hpp>

using Ra::Core::Utils::Observable;

class ObservableTest : public Observable<>
{};

class ObservableTest2 : public Observable<int>
{};

class A
{
  public:
    void f() { m_a++; }
    void f2( int a ) { m_a = a; }
    static void g() { m_b++; }
    static void g2( int b ) { m_b = b; }

    int m_a {0};
    static int m_b;
};

int A::m_b = 0;

TEST_CASE( "Core/Utils/Observable", "[Core][Core/Utils][Observable]" ) {
    ObservableTest test;
    ObservableTest2 test2;

    A a;
    int c  = 0;
    A::m_b = 0;

    using Observer = std::function<void( void )>;
    ///\todo add more tests with
    // using Observer2 = std::function<void( int )>;

    auto bf = std::bind( &A::f, &a );

    Observer obf         = bf;
    auto& observerTarget = obf.target_type();
    // "Type failed."
    REQUIRE( obf.target_type() == observerTarget );

    auto gid = test.attach( A::g );
    test.attach( bf );
    test.attach( [&c]() { c++; } );
    test.notify();

    REQUIRE( c == 1 );
    REQUIRE( a.m_a == 1 );
    REQUIRE( A::m_b == 1 );

    test.detach( gid );
    test.notify();

    REQUIRE( c == 2 );
    REQUIRE( a.m_a == 2 );
    // Test detach
    REQUIRE( A::m_b == 1 );

    test.attach( A::g );
    test.attach( A::g );
    test.attach( bf );
    test.attach( [&c]() { c++; } );
    test.notify();

    REQUIRE( c == 4 );
    REQUIRE( a.m_a == 4 );
    REQUIRE( A::m_b == 3 );

    test.detachAll();
    test.notify();

    // Test detach
    REQUIRE( c == 4 );
    REQUIRE( a.m_a == 4 );
    REQUIRE( A::m_b == 3 );

    test2.attachMember( &a, &A::f2 );
    test2.attach( &A::g2 );
    test2.attach( [&c]( int pc ) { c = pc; } );

    test2.notify( 5 );

    REQUIRE( c == 5 );
    REQUIRE( a.m_a == 5 );
    REQUIRE( A::m_b == 5 );

    test2.notify( 6 );

    REQUIRE( c == 6 );
    REQUIRE( a.m_a == 6 );
    REQUIRE( A::m_b == 6 );

    ObservableTest2 test2copy;
    test2.copyObserversTo( test2copy );

    test2.detachAll();
    test2.notify( 7 );

    REQUIRE( c == 6 );
    REQUIRE( a.m_a == 6 );
    REQUIRE( A::m_b == 6 );

    test2copy.notify( 7 );

    REQUIRE( c == 7 );
    REQUIRE( a.m_a == 7 );
    REQUIRE( A::m_b == 7 );
}
<|endoftext|>


<commit_before>#include "index/LodRange.hpp"
#include "formats/shape/ShapeParser.hpp"
#include "index/GeoStore.hpp"
#include "index/InMemoryElementStore.hpp"
#include "index/PersistentElementStore.hpp"
#include "index/ShapeDataVisitor.hpp"

#include <stdexcept>
#include <unordered_map>

using namespace utymap::entities;
using namespace utymap::formats;
using namespace utymap::index;
using namespace utymap::mapcss;

class GeoStore::GeoStoreImpl
{
public:

    GeoStoreImpl(StringTable& stringTable) :
        stringTable_(stringTable)
    {
    }

    void registerStore(const std::string& storeKey, ElementStore& store)
    {
        storeMap_[storeKey] = &store;
    }

    void add(const std::string& storeKey, const Element& element, const LodRange& range, const StyleProvider& styleProvider)
    {
    }

    void add(const std::string& storeKey, const std::string& path, const LodRange& range, const StyleProvider& styleProvider)
    {
        ElementStore* elementStorePtr = storeMap_[storeKey];
        switch (getFormatTypeFromPath(path))
        {
            case FormatType::Shape:
            {
                ShapeDataVisitor shpVisitor(*elementStorePtr, styleProvider, stringTable_, range);
                utymap::formats::ShapeParser<ShapeDataVisitor> parser;
                parser.parse(path, shpVisitor);
                break;
            }
            default:
                throw std::domain_error("Not implemented.");
        }
    }

    void search(const QuadKey& quadKey, const utymap::mapcss::StyleProvider& styleProvider, ElementVisitor& visitor)
    {
        for (const auto& pair : storeMap_) {
            pair.second->search(quadKey, styleProvider, visitor);
        }
    }

    void search(const GeoCoordinate& coordinate, double radius, const StyleProvider& styleProvider, ElementVisitor& visitor)
    {
        throw std::domain_error("Not implemented");
    }

private:
    StringTable& stringTable_;
    std::unordered_map<std::string, ElementStore*> storeMap_;

    FormatType getFormatTypeFromPath(const std::string& path)
    {
        // TODO
        return FormatType::Shape;
    }
};

GeoStore::GeoStore(StringTable& stringTable) :
    pimpl_(std::unique_ptr<GeoStore::GeoStoreImpl>(new GeoStore::GeoStoreImpl(stringTable)))
{
}

GeoStore::~GeoStore()
{
}

void utymap::index::GeoStore::registerStore(const std::string& storeKey, ElementStore& store)
{
    pimpl_->registerStore(storeKey, store);
}

void utymap::index::GeoStore::add(const std::string& storeKey, const Element& element, const LodRange& range, const StyleProvider& styleProvider)
{
    pimpl_->add(storeKey, element, range, styleProvider);
}

void utymap::index::GeoStore::add(const std::string& storeKey, const std::string& path, const LodRange& range, const StyleProvider& styleProvider)
{
    pimpl_->add(storeKey, path, range, styleProvider);
}

void utymap::index::GeoStore::search(const QuadKey& quadKey, const utymap::mapcss::StyleProvider& styleProvider, ElementVisitor& visitor)
{
    pimpl_->search(quadKey, styleProvider, visitor);
}

void utymap::index::GeoStore::search(const GeoCoordinate& coordinate, double radius, const StyleProvider& styleProvider, ElementVisitor& visitor)
{
    pimpl_->search(coordinate, radius, styleProvider, visitor);
}
<commit_msg>index: do not visit the same element twice<commit_after>#include "entities/Element.hpp"
#include "index/LodRange.hpp"
#include "formats/shape/ShapeParser.hpp"
#include "index/GeoStore.hpp"
#include "index/InMemoryElementStore.hpp"
#include "index/PersistentElementStore.hpp"
#include "index/ShapeDataVisitor.hpp"

#include <set>
#include <stdexcept>
#include <cstdint>
#include <unordered_map>

using namespace utymap::entities;
using namespace utymap::formats;
using namespace utymap::index;
using namespace utymap::mapcss;

class GeoStore::GeoStoreImpl
{
    // Prevents to visit element twice if it exists in multiply stores.
    class FilterElementVisitor : public ElementVisitor
    {
    public:
        FilterElementVisitor(ElementVisitor& visitor) : visitor_(visitor)
        {
        }

        void visitNode(const Node& node) { visitIfNecessary(node); }

        void visitWay(const Way& way)  { visitIfNecessary(way); }

        void visitArea(const Area& area)  { visitIfNecessary(area); }

        void visitRelation(const Relation& relation)  { visitIfNecessary(relation); }

    private:

        inline bool visitIfNecessary(const Element& element)
        {
            if (element.id == 0 || ids_.find(element.id) == ids_.end())
            {
                element.accept(visitor_);
                ids_.insert(element.id);
            }
        }

        ElementVisitor& visitor_;
        std::set<std::uint64_t> ids_;
    };

public:

    GeoStoreImpl(StringTable& stringTable) :
        stringTable_(stringTable)
    {
    }

    void registerStore(const std::string& storeKey, ElementStore& store)
    {
        storeMap_[storeKey] = &store;
    }

    void add(const std::string& storeKey, const Element& element, const LodRange& range, const StyleProvider& styleProvider)
    {
    }

    void add(const std::string& storeKey, const std::string& path, const LodRange& range, const StyleProvider& styleProvider)
    {
        ElementStore* elementStorePtr = storeMap_[storeKey];
        switch (getFormatTypeFromPath(path))
        {
            case FormatType::Shape:
            {
                ShapeDataVisitor shpVisitor(*elementStorePtr, styleProvider, stringTable_, range);
                utymap::formats::ShapeParser<ShapeDataVisitor> parser;
                parser.parse(path, shpVisitor);
                break;
            }
            default:
                throw std::domain_error("Not implemented.");
        }
    }

    void search(const QuadKey& quadKey, const utymap::mapcss::StyleProvider& styleProvider, ElementVisitor& visitor)
    {
        FilterElementVisitor filter(visitor);
        for (const auto& pair : storeMap_) {
            pair.second->search(quadKey, styleProvider, filter);
        }
    }

    void search(const GeoCoordinate& coordinate, double radius, const StyleProvider& styleProvider, ElementVisitor& visitor)
    {
        throw std::domain_error("Not implemented");
    }

private:
    StringTable& stringTable_;
    std::unordered_map<std::string, ElementStore*> storeMap_;

    FormatType getFormatTypeFromPath(const std::string& path)
    {
        // TODO
        return FormatType::Shape;
    }
};

GeoStore::GeoStore(StringTable& stringTable) :
    pimpl_(std::unique_ptr<GeoStore::GeoStoreImpl>(new GeoStore::GeoStoreImpl(stringTable)))
{
}

GeoStore::~GeoStore()
{
}

void utymap::index::GeoStore::registerStore(const std::string& storeKey, ElementStore& store)
{
    pimpl_->registerStore(storeKey, store);
}

void utymap::index::GeoStore::add(const std::string& storeKey, const Element& element, const LodRange& range, const StyleProvider& styleProvider)
{
    pimpl_->add(storeKey, element, range, styleProvider);
}

void utymap::index::GeoStore::add(const std::string& storeKey, const std::string& path, const LodRange& range, const StyleProvider& styleProvider)
{
    pimpl_->add(storeKey, path, range, styleProvider);
}

void utymap::index::GeoStore::search(const QuadKey& quadKey, const utymap::mapcss::StyleProvider& styleProvider, ElementVisitor& visitor)
{
    pimpl_->search(quadKey, styleProvider, visitor);
}

void utymap::index::GeoStore::search(const GeoCoordinate& coordinate, double radius, const StyleProvider& styleProvider, ElementVisitor& visitor)
{
    pimpl_->search(coordinate, radius, styleProvider, visitor);
}
<|endoftext|>


<commit_before>/**
 This file is part of Deformable Shape Tracking (DEST).

 Copyright Christoph Heindl 2015

 Deformable Shape Tracking is free software: you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
 the Free Software Foundation, either version 3 of the License, or
 (at your option) any later version.

 Deformable Shape Tracking is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.

 You should have received a copy of the GNU General Public License
 along with Deformable Shape Tracking. If not, see <http://www.gnu.org/licenses/>.
 */

#include <dest/io/database_io.h>
#include <dest/util/log.h>
#include <dest/util/draw.h>
#include <dest/util/convert.h>
#include <dest/util/glob.h>
#include <dest/io/rect_io.h>
#include <opencv2/opencv.hpp>
#include <iomanip>
#include <fstream>

namespace dest {
    namespace io {

        ImportParameters::ImportParameters() {
            maxImageSideLength = std::numeric_limits<int>::max();
            generateVerticallyMirrored = false;
        }

        bool importDatabase(const std::string & directory, const std::string &rectangleFile, std::vector<core::Image>& images, std::vector<core::Shape>& shapes, std::vector<core::Rect>& rects, const ImportParameters & opts)
        {
            const bool isIMM = util::findFilesInDir(directory, "asf", true).size() > 0;
            const bool isIBUG = util::findFilesInDir(directory, "pts", true).size() > 0;

            if (isIMM)
                return importIMMFaceDatabase(directory, rectangleFile, images, shapes, rects, opts);
            else if (isIBUG)
                return importIBugAnnotatedFaceDatabase(directory, rectangleFile, images, shapes, rects, opts);
            else {
                DEST_LOG("Unknown database format." << std::endl);
                return false;
            }
        }

        bool imageNeedsScaling(cv::Size s, const ImportParameters &p, float &factor) {
            int maxLen = std::max<int>(s.width, s.height);
            if (maxLen > p.maxImageSideLength) {
                factor = static_cast<float>(p.maxImageSideLength) / static_cast<float>(maxLen);
                return true;
            } else {
                return false;
            }
        }

        void scaleImageShapeAndRect(cv::Mat &img, core::Shape &s, core::Rect &r, float factor) {
            cv::resize(img, img, cv::Size(0,0), factor, factor, CV_INTER_CUBIC);
            s *= factor;
            r *= factor;
        }

        void mirrorImageShapeAndRectVertically(const cv::Mat &img, const core::Shape &s, const core::Rect &r, cv::Mat &dstImage, core::Shape &dstShape, core::Rect &dstRect) {
            cv::flip(img, dstImage, 1);
            dstShape.resize(2, s.cols());
            for (core::Shape::Index i = 0; i < s.cols(); ++i) {
                dstShape(0, i) = static_cast<float>(img.cols - 1) - s(0, i);
                dstShape(1, i) = s(1, i);
            }

            for (core::Rect::Index i = 0; i < r.cols(); ++i) {
                dstRect(0, i) = static_cast<float>(img.cols - 1) - r(0, i);
                dstRect(1, i) = r(1, i);
            }
        }

        bool parseAsfFile(const std::string& fileName, core::Shape &s) {

            int landmarkCount = 0;

            std::ifstream file(fileName);

            std::string line;
            while (std::getline(file, line)) {
                if (line.size() > 0 && line[0] != '#') {
                    if (line.find(".jpg") != std::string::npos) {
                        // ignored: file name of jpg image
                    }
                    else if (line.size() < 10) {
                        int nbPoints = atol(line.c_str());

                        s.resize(2, nbPoints);
                        s.fill(0);
                    }
                    else {
                        std::stringstream stream(line);

                        std::string path;
                        std::string type;
                        float x, y;

                        stream >> path;
                        stream >> type;
                        stream >> x;
                        stream >> y;

                        s(0, landmarkCount) = x;
                        s(1, landmarkCount) = y;

                        ++landmarkCount;
                    }
                }
            }

            return s.rows() > 0 && s.cols() > 0;
        }

        bool importIMMFaceDatabase(const std::string &directory, const std::string &rectangleFile, std::vector<core::Image> &images, std::vector<core::Shape> &shapes, std::vector<core::Rect>& rects, const ImportParameters &opts) {

            std::vector<std::string> paths = util::findFilesInDir(directory, "asf", true);
            DEST_LOG("Loading IMM database. Found " << paths.size() << " canditate entries." << std::endl);

            std::vector<core::Rect> loadedRects;
            io::importRectangles(rectangleFile, loadedRects);

            if (loadedRects.empty()) {
                DEST_LOG("No rectangles found, using tight bounds." << std::endl);
            } else {
                if (paths.size() != loadedRects.size()) {
                    DEST_LOG("Mismatch between number of shapes in database and rectangles found." << std::endl);
                    return false;
                }
            }

            size_t initialSize = images.size();

            for (size_t i = 0; i < paths.size(); ++i) {
                const std::string fileNameImg = paths[i] + ".jpg";
                const std::string fileNamePts = paths[i] + ".asf";

                core::Shape s;
                core::Rect r;
                bool asfOk = parseAsfFile(fileNamePts, s);
                cv::Mat cvImg = cv::imread(fileNameImg, cv::IMREAD_GRAYSCALE);

                if(asfOk && !cvImg.empty()) {

                    // Scale to image dimensions
                    s.row(0) *= static_cast<float>(cvImg.cols);
                    s.row(1) *= static_cast<float>(cvImg.rows);

                    if (loadedRects.empty()) {
                        r = core::shapeBounds(s);
                    } else {
                        r = loadedRects[i];
                    }

                    float f;
                    if (imageNeedsScaling(cvImg.size(), opts, f)) {
                        scaleImageShapeAndRect(cvImg, s, r, f);
                    }

                    core::Image img;
                    util::toDest(cvImg, img);

                    images.push_back(img);
                    shapes.push_back(s);
                    rects.push_back(r);

                    if (opts.generateVerticallyMirrored) {
                        cv::Mat cvFlipped;
                        core::Shape shapeFlipped;
                        core::Rect rectFlipped;
                        mirrorImageShapeAndRectVertically(cvImg, s, r, cvFlipped, shapeFlipped, rectFlipped);

                        core::Image imgFlipped;
                        util::toDest(cvFlipped, imgFlipped);

                        images.push_back(imgFlipped);
                        shapes.push_back(shapeFlipped);
                        rects.push_back(rectFlipped);
                    }
                }
            }

            DEST_LOG("Successfully loaded " << (shapes.size() - initialSize) << " entries from database." << std::endl);
            return shapes.size() > 0;
        }

        bool parsePtsFile(const std::string& fileName, core::Shape &s) {

            std::ifstream file(fileName);

            std::string line;
            std::getline(file, line); // Version
            std::getline(file, line); // NPoints

            int numPoints;
            std::stringstream str(line);
            str >> line >> numPoints;

            std::getline(file, line); // {

            s.resize(2, numPoints);
            s.fill(0);

            for (int i = 0; i < numPoints; ++i) {
                if (!std::getline(file, line)) {
                    DEST_LOG("Failed to read points." << std::endl);
                    return false;
                }
                str = std::stringstream(line);

                float x, y;
                str >> x >> y;

                s(0, i) = x - 1.f; // Matlab to C++ offset
                s(1, i) = y - 1.f;

            }

            return true;

        }

        bool importIBugAnnotatedFaceDatabase(const std::string &directory, const std::string &rectangleFile, std::vector<core::Image> &images, std::vector<core::Shape> &shapes, std::vector<core::Rect> &rects, const ImportParameters &opts) {

            std::vector<std::string> paths = util::findFilesInDir(directory, "pts", true);
            DEST_LOG("Loading ibug database. Found " << paths.size() << " canditate entries." << std::endl);

            std::vector<core::Rect> loadedRects;
            io::importRectangles(rectangleFile, loadedRects);

            if (loadedRects.empty()) {
                DEST_LOG("No rectangles found, using tight bounds." << std::endl);
            }
            else {
                if (paths.size() != loadedRects.size()) {
                    DEST_LOG("Mismatch between number of shapes in database and rectangles found." << std::endl);
                    return false;
                }
            }

            size_t initialSize = images.size();

            for (size_t i = 0; i < paths.size(); ++i) {
                const std::string fileNameImg = paths[i] + ".jpg";
                const std::string fileNamePts = paths[i] + ".pts";

                core::Shape s;
                core::Rect r;
                bool ptsOk = parsePtsFile(fileNamePts, s);
                cv::Mat cvImg = cv::imread(fileNameImg, cv::IMREAD_GRAYSCALE);

                if(ptsOk && !cvImg.empty()) {

                    if (loadedRects.empty()) {
                        r = core::shapeBounds(s);
                    }
                    else {
                        r = loadedRects[i];
                    }

                    float f;
                    if (imageNeedsScaling(cvImg.size(), opts, f)) {
                        scaleImageShapeAndRect(cvImg, s, r, f);
                    }

                    core::Image img;
                    util::toDest(cvImg, img);

                    images.push_back(img);
                    shapes.push_back(s);
                    rects.push_back(r);

                    if (opts.generateVerticallyMirrored) {
                        cv::Mat cvFlipped;
                        core::Shape shapeFlipped;
                        core::Rect rectFlipped;
                        mirrorImageShapeAndRectVertically(cvImg, s, r, cvFlipped, shapeFlipped, rectFlipped);

                        core::Image imgFlipped;
                        util::toDest(cvFlipped, imgFlipped);

                        images.push_back(imgFlipped);
                        shapes.push_back(shapeFlipped);
                        shapes.push_back(rectFlipped);
                    }
                }
            }

            DEST_LOG("Successfully loaded " << (shapes.size() - initialSize) << " entries from database." << std::endl);
            return (shapes.size() - initialSize) > 0;

        }

    }
}<commit_msg>Verbosity<commit_after>/**
 This file is part of Deformable Shape Tracking (DEST).

 Copyright Christoph Heindl 2015

 Deformable Shape Tracking is free software: you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
 the Free Software Foundation, either version 3 of the License, or
 (at your option) any later version.

 Deformable Shape Tracking is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.

 You should have received a copy of the GNU General Public License
 along with Deformable Shape Tracking. If not, see <http://www.gnu.org/licenses/>.
 */

#include <dest/io/database_io.h>
#include <dest/util/log.h>
#include <dest/util/draw.h>
#include <dest/util/convert.h>
#include <dest/util/glob.h>
#include <dest/io/rect_io.h>
#include <opencv2/opencv.hpp>
#include <iomanip>
#include <fstream>

namespace dest {
    namespace io {

        ImportParameters::ImportParameters() {
            maxImageSideLength = std::numeric_limits<int>::max();
            generateVerticallyMirrored = false;
        }

        bool importDatabase(const std::string & directory, const std::string &rectangleFile, std::vector<core::Image>& images, std::vector<core::Shape>& shapes, std::vector<core::Rect>& rects, const ImportParameters & opts)
        {
            const bool isIMM = util::findFilesInDir(directory, "asf", true).size() > 0;
            const bool isIBUG = util::findFilesInDir(directory, "pts", true).size() > 0;

            if (isIMM)
                return importIMMFaceDatabase(directory, rectangleFile, images, shapes, rects, opts);
            else if (isIBUG)
                return importIBugAnnotatedFaceDatabase(directory, rectangleFile, images, shapes, rects, opts);
            else {
                DEST_LOG("Unknown database format." << std::endl);
                return false;
            }
        }

        bool imageNeedsScaling(cv::Size s, const ImportParameters &p, float &factor) {
            int maxLen = std::max<int>(s.width, s.height);
            if (maxLen > p.maxImageSideLength) {
                factor = static_cast<float>(p.maxImageSideLength) / static_cast<float>(maxLen);
                return true;
            } else {
                return false;
            }
        }

        void scaleImageShapeAndRect(cv::Mat &img, core::Shape &s, core::Rect &r, float factor) {
            cv::resize(img, img, cv::Size(0,0), factor, factor, CV_INTER_CUBIC);
            s *= factor;
            r *= factor;
        }

        void mirrorImageShapeAndRectVertically(const cv::Mat &img, const core::Shape &s, const core::Rect &r, cv::Mat &dstImage, core::Shape &dstShape, core::Rect &dstRect) {
            cv::flip(img, dstImage, 1);
            dstShape.resize(2, s.cols());
            for (core::Shape::Index i = 0; i < s.cols(); ++i) {
                dstShape(0, i) = static_cast<float>(img.cols - 1) - s(0, i);
                dstShape(1, i) = s(1, i);
            }

            for (core::Rect::Index i = 0; i < r.cols(); ++i) {
                dstRect(0, i) = static_cast<float>(img.cols - 1) - r(0, i);
                dstRect(1, i) = r(1, i);
            }
        }

        bool parseAsfFile(const std::string& fileName, core::Shape &s) {

            int landmarkCount = 0;

            std::ifstream file(fileName);

            std::string line;
            while (std::getline(file, line)) {
                if (line.size() > 0 && line[0] != '#') {
                    if (line.find(".jpg") != std::string::npos) {
                        // ignored: file name of jpg image
                    }
                    else if (line.size() < 10) {
                        int nbPoints = atol(line.c_str());

                        s.resize(2, nbPoints);
                        s.fill(0);
                    }
                    else {
                        std::stringstream stream(line);

                        std::string path;
                        std::string type;
                        float x, y;

                        stream >> path;
                        stream >> type;
                        stream >> x;
                        stream >> y;

                        s(0, landmarkCount) = x;
                        s(1, landmarkCount) = y;

                        ++landmarkCount;
                    }
                }
            }

            return s.rows() > 0 && s.cols() > 0;
        }

        bool importIMMFaceDatabase(const std::string &directory, const std::string &rectangleFile, std::vector<core::Image> &images, std::vector<core::Shape> &shapes, std::vector<core::Rect>& rects, const ImportParameters &opts) {

            std::vector<std::string> paths = util::findFilesInDir(directory, "asf", true);
            DEST_LOG("Loading IMM database. Found " << paths.size() << " canditate entries." << std::endl);

            std::vector<core::Rect> loadedRects;
            io::importRectangles(rectangleFile, loadedRects);

            if (loadedRects.empty()) {
                DEST_LOG("No rectangles found, using tight axis aligned bounds." << std::endl);
            } else {
                if (paths.size() != loadedRects.size()) {
                    DEST_LOG("Mismatch between number of shapes in database and rectangles found." << std::endl);
                    return false;
                }
            }

            size_t initialSize = images.size();

            for (size_t i = 0; i < paths.size(); ++i) {
                const std::string fileNameImg = paths[i] + ".jpg";
                const std::string fileNamePts = paths[i] + ".asf";

                core::Shape s;
                core::Rect r;
                bool asfOk = parseAsfFile(fileNamePts, s);
                cv::Mat cvImg = cv::imread(fileNameImg, cv::IMREAD_GRAYSCALE);

                if(asfOk && !cvImg.empty()) {

                    // Scale to image dimensions
                    s.row(0) *= static_cast<float>(cvImg.cols);
                    s.row(1) *= static_cast<float>(cvImg.rows);

                    if (loadedRects.empty()) {
                        r = core::shapeBounds(s);
                    } else {
                        r = loadedRects[i];
                    }

                    float f;
                    if (imageNeedsScaling(cvImg.size(), opts, f)) {
                        scaleImageShapeAndRect(cvImg, s, r, f);
                    }

                    core::Image img;
                    util::toDest(cvImg, img);

                    images.push_back(img);
                    shapes.push_back(s);
                    rects.push_back(r);

                    if (opts.generateVerticallyMirrored) {
                        cv::Mat cvFlipped;
                        core::Shape shapeFlipped;
                        core::Rect rectFlipped;
                        mirrorImageShapeAndRectVertically(cvImg, s, r, cvFlipped, shapeFlipped, rectFlipped);

                        core::Image imgFlipped;
                        util::toDest(cvFlipped, imgFlipped);

                        images.push_back(imgFlipped);
                        shapes.push_back(shapeFlipped);
                        rects.push_back(rectFlipped);
                    }
                }
            }

            DEST_LOG("Successfully loaded " << (shapes.size() - initialSize) << " entries from database." << std::endl);
            return shapes.size() > 0;
        }

        bool parsePtsFile(const std::string& fileName, core::Shape &s) {

            std::ifstream file(fileName);

            std::string line;
            std::getline(file, line); // Version
            std::getline(file, line); // NPoints

            int numPoints;
            std::stringstream str(line);
            str >> line >> numPoints;

            std::getline(file, line); // {

            s.resize(2, numPoints);
            s.fill(0);

            for (int i = 0; i < numPoints; ++i) {
                if (!std::getline(file, line)) {
                    DEST_LOG("Failed to read points." << std::endl);
                    return false;
                }
                str = std::stringstream(line);

                float x, y;
                str >> x >> y;

                s(0, i) = x - 1.f; // Matlab to C++ offset
                s(1, i) = y - 1.f;

            }

            return true;

        }

        bool importIBugAnnotatedFaceDatabase(const std::string &directory, const std::string &rectangleFile, std::vector<core::Image> &images, std::vector<core::Shape> &shapes, std::vector<core::Rect> &rects, const ImportParameters &opts) {

            std::vector<std::string> paths = util::findFilesInDir(directory, "pts", true);
            DEST_LOG("Loading ibug database. Found " << paths.size() << " canditate entries." << std::endl);

            std::vector<core::Rect> loadedRects;
            io::importRectangles(rectangleFile, loadedRects);

            if (loadedRects.empty()) {
                DEST_LOG("No rectangles found, using tight axis aligned bounds." << std::endl);
            }
            else {
                if (paths.size() != loadedRects.size()) {
                    DEST_LOG("Mismatch between number of shapes in database and rectangles found." << std::endl);
                    return false;
                }
            }

            size_t initialSize = images.size();

            for (size_t i = 0; i < paths.size(); ++i) {
                const std::string fileNameImg = paths[i] + ".jpg";
                const std::string fileNamePts = paths[i] + ".pts";

                core::Shape s;
                core::Rect r;
                bool ptsOk = parsePtsFile(fileNamePts, s);
                cv::Mat cvImg = cv::imread(fileNameImg, cv::IMREAD_GRAYSCALE);

                if(ptsOk && !cvImg.empty()) {

                    if (loadedRects.empty()) {
                        r = core::shapeBounds(s);
                    }
                    else {
                        r = loadedRects[i];
                    }

                    float f;
                    if (imageNeedsScaling(cvImg.size(), opts, f)) {
                        scaleImageShapeAndRect(cvImg, s, r, f);
                    }

                    core::Image img;
                    util::toDest(cvImg, img);

                    images.push_back(img);
                    shapes.push_back(s);
                    rects.push_back(r);

                    if (opts.generateVerticallyMirrored) {
                        cv::Mat cvFlipped;
                        core::Shape shapeFlipped;
                        core::Rect rectFlipped;
                        mirrorImageShapeAndRectVertically(cvImg, s, r, cvFlipped, shapeFlipped, rectFlipped);

                        core::Image imgFlipped;
                        util::toDest(cvFlipped, imgFlipped);

                        images.push_back(imgFlipped);
                        shapes.push_back(shapeFlipped);
                        shapes.push_back(rectFlipped);
                    }
                }
            }

            DEST_LOG("Successfully loaded " << (shapes.size() - initialSize) << " entries from database." << std::endl);
            return (shapes.size() - initialSize) > 0;

        }

    }
}<|endoftext|>


<commit_before>// vim:ts=2:sw=2:expandtab:autoindent:filetype=cpp:
/*
Copyright (c) 2008 Aristid Breitkreuz, Ruediger Sonderfeld

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/

#include "flusspferd/io/stream_base.hpp"
#include "flusspferd/local_root_scope.hpp"
#include "flusspferd/create.hpp"
#include "flusspferd/string.hpp"
#include "flusspferd/string_io.hpp"
#include "flusspferd/create.hpp"
#include "flusspferd/blob.hpp"
#include <boost/scoped_array.hpp>
#include <cstdlib>

using namespace flusspferd;
using namespace flusspferd::io;

stream_base::stream_base(object const &o, std::streambuf *p)
  : native_object_base(o), streambuf(p)
{
  register_native_method("readWhole", &stream_base::read_whole);
  register_native_method("read", &stream_base::read);
  register_native_method("readWholeBlob", &stream_base::read_whole_blob);
  register_native_method("readBlob", &stream_base::read_blob);
  register_native_method("write", &stream_base::write);
  register_native_method("print", &stream_base::print);
  register_native_method("flush", &stream_base::flush);

  define_property("fieldSeparator", string(" "));
  define_property("recordSeparator", string("\n"));
}

stream_base::~stream_base()
{}

void stream_base::set_streambuf(std::streambuf *p) {
  streambuf = p;
}

object stream_base::class_info::create_prototype() {
  local_root_scope scope;

  object proto = create_object();

  create_native_method(proto, "readWhole", 0);
  create_native_method(proto, "read", 1);
  create_native_method(proto, "readWholeBlob", 0);
  create_native_method(proto, "readBlob", 1);
  create_native_method(proto, "write", 1);
  create_native_method(proto, "print", 0);
  create_native_method(proto, "flush", 0);

  return proto;
}

string stream_base::read_whole() {
  std::string data;
  char buf[4096];

  std::streamsize length;

  do {
    length = streambuf->sgetn(buf, sizeof(buf));
    if (length < 0)
      length = 0;
    data.append(buf, length);
  } while (length > 0);

  return string(data);
}

object stream_base::read_whole_blob() {
  unsigned const N = 4096;

  std::vector<char> data;

  std::streamsize length;

  do {
    data.resize(data.size() + N);
    length = streambuf->sgetn(&data[data.size() - N], N);
    if (length < 0)
      length = 0;
    data.resize(data.size() - N + length);
  } while (length > 0);

  return create_native_object<blob>(
      object(), (unsigned char const *)&data[0], data.size());
}

string stream_base::read(unsigned size) {
  if (!size)
    size = 4096;

  boost::scoped_array<char> buf(new char[size + 1]);

  std::streamsize length = streambuf->sgetn(buf.get(), size);
  if (length < 0)
    length = 0;
  buf[length] = '\0';

  return string(buf.get());
}

object stream_base::read_blob(unsigned size) {
  if (!size)
    size = 4096;

  boost::scoped_array<char> buf(new char[size]);

  std::streamsize length = streambuf->sgetn(buf.get(), size);
  if (length < 0)
    length = 0;

  return create_native_object<blob>(
      object(),
      (unsigned char const *) buf.get(),
      length);
}

void stream_base::write(value const &data) {
  if (data.is_string()) {
    string text = data.get_string();
    char const *str = text.c_str();
    streambuf->sputn(text.c_str(), std::strlen(str));
  } else if (data.is_object()) {
    native_object_base *ptr = native_object_base::get_native(data.get_object());
    blob &b = dynamic_cast<blob&>(*ptr);
    streambuf->sputn((char const*) b.get_data(), b.size());
  }
}

void stream_base::print(call_context &x) {
  local_root_scope scope;

  value delim_v = get_property("fieldSeparator");
  string delim;
  if (!delim_v.is_void_or_null())
    delim = delim_v.to_string();

  std::size_t n = x.arg.size();
  for (std::size_t i = 0; i < n; ++i) {
    write(x.arg[i].to_string());
    if (i < n - 1)
      write(delim);
  }

  value record_v = get_property("recordSeparator");
  if (!record_v.is_void_or_null())
    write(record_v.to_string());

  flush();
}

void stream_base::flush() {
  streambuf->pubsync();
}
<commit_msg>IO: add autoflush<commit_after>// vim:ts=2:sw=2:expandtab:autoindent:filetype=cpp:
/*
Copyright (c) 2008 Aristid Breitkreuz, Ruediger Sonderfeld

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/

#include "flusspferd/io/stream_base.hpp"
#include "flusspferd/local_root_scope.hpp"
#include "flusspferd/create.hpp"
#include "flusspferd/string.hpp"
#include "flusspferd/string_io.hpp"
#include "flusspferd/create.hpp"
#include "flusspferd/blob.hpp"
#include <boost/scoped_array.hpp>
#include <cstdlib>

using namespace flusspferd;
using namespace flusspferd::io;

stream_base::stream_base(object const &o, std::streambuf *p)
  : native_object_base(o), streambuf(p)
{
  register_native_method("readWhole", &stream_base::read_whole);
  register_native_method("read", &stream_base::read);
  register_native_method("readWholeBlob", &stream_base::read_whole_blob);
  register_native_method("readBlob", &stream_base::read_blob);
  register_native_method("write", &stream_base::write);
  register_native_method("print", &stream_base::print);
  register_native_method("flush", &stream_base::flush);

  define_property("fieldSeparator", string(" "));
  define_property("recordSeparator", string("\n"));
  define_property("autoflush", false);
}

stream_base::~stream_base()
{}

void stream_base::set_streambuf(std::streambuf *p) {
  streambuf = p;
}

object stream_base::class_info::create_prototype() {
  local_root_scope scope;

  object proto = create_object();

  create_native_method(proto, "readWhole", 0);
  create_native_method(proto, "read", 1);
  create_native_method(proto, "readWholeBlob", 0);
  create_native_method(proto, "readBlob", 1);
  create_native_method(proto, "write", 1);
  create_native_method(proto, "print", 0);
  create_native_method(proto, "flush", 0);

  return proto;
}

string stream_base::read_whole() {
  std::string data;
  char buf[4096];

  std::streamsize length;

  do {
    length = streambuf->sgetn(buf, sizeof(buf));
    if (length < 0)
      length = 0;
    data.append(buf, length);
  } while (length > 0);

  return string(data);
}

object stream_base::read_whole_blob() {
  unsigned const N = 4096;

  std::vector<char> data;

  std::streamsize length;

  do {
    data.resize(data.size() + N);
    length = streambuf->sgetn(&data[data.size() - N], N);
    if (length < 0)
      length = 0;
    data.resize(data.size() - N + length);
  } while (length > 0);

  return create_native_object<blob>(
      object(), (unsigned char const *)&data[0], data.size());
}

string stream_base::read(unsigned size) {
  if (!size)
    size = 4096;

  boost::scoped_array<char> buf(new char[size + 1]);

  std::streamsize length = streambuf->sgetn(buf.get(), size);
  if (length < 0)
    length = 0;
  buf[length] = '\0';

  return string(buf.get());
}

object stream_base::read_blob(unsigned size) {
  if (!size)
    size = 4096;

  boost::scoped_array<char> buf(new char[size]);

  std::streamsize length = streambuf->sgetn(buf.get(), size);
  if (length < 0)
    length = 0;

  return create_native_object<blob>(
      object(),
      (unsigned char const *) buf.get(),
      length);
}

void stream_base::write(value const &data) {
  if (data.is_string()) {
    string text = data.get_string();
    char const *str = text.c_str();
    streambuf->sputn(text.c_str(), std::strlen(str));
  } else if (data.is_object()) {
    native_object_base *ptr = native_object_base::get_native(data.get_object());
    blob &b = dynamic_cast<blob&>(*ptr);
    streambuf->sputn((char const*) b.get_data(), b.size());
  }
  //TODO slow?
  if (get_property("autoflush").to_boolean())
    flush();
}

void stream_base::print(call_context &x) {
  local_root_scope scope;

  value delim_v = get_property("fieldSeparator");
  string delim;
  if (!delim_v.is_void_or_null())
    delim = delim_v.to_string();

  std::size_t n = x.arg.size();
  for (std::size_t i = 0; i < n; ++i) {
    write(x.arg[i].to_string());
    if (i < n - 1)
      write(delim);
  }

  value record_v = get_property("recordSeparator");
  if (!record_v.is_void_or_null())
    write(record_v.to_string());

  flush();
}

void stream_base::flush() {
  streambuf->pubsync();
}
<|endoftext|>