<commit_before>/******************************************************************************
*       SOFA, Simulation Open-Framework Architecture, version 1.0 beta 4      *
*                (c) 2006-2009 MGH, INRIA, USTL, UJF, CNRS                    *
*                                                                             *
* This library is free software; you can redistribute it and/or modify it     *
* under the terms of the GNU Lesser General Public License as published by    *
* the Free Software Foundation; either version 2.1 of the License, or (at     *
* your option) any later version.                                             *
*                                                                             *
* This library 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 Lesser General Public License *
* for more details.                                                           *
*                                                                             *
* You should have received a copy of the GNU Lesser General Public License    *
* along with this library; if not, write to the Free Software Foundation,     *
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA.          *
*******************************************************************************
*                               SOFA :: Modules                               *
*                                                                             *
* Authors: The SOFA Team and external contributors (see Authors.txt)          *
*                                                                             *
* Contact information: contact@sofa-framework.org                             *
******************************************************************************/
#include <sofa/component/forcefield/EdgePressureForceField.h>
#include <sofa/component/topology/EdgeSubsetData.inl>
#include <sofa/helper/gl/template.h>
#include <vector>
#include <set>

#ifdef _WIN32
#include <windows.h>
#endif

// #define DEBUG_TRIANGLEFEM

namespace sofa
{

namespace component
{

namespace forcefield
{

using namespace sofa::defaulttype;
using namespace core::componentmodel::topology;

template <class DataTypes> EdgePressureForceField<DataTypes>::~EdgePressureForceField()
{
}
// Handle topological changes
template <class DataTypes> void  EdgePressureForceField<DataTypes>::handleTopologyChange()
{
    std::list<const TopologyChange *>::const_iterator itBegin=_topology->firstChange();
    std::list<const TopologyChange *>::const_iterator itEnd=_topology->lastChange();

    edgePressureMap.handleTopologyEvents(itBegin,itEnd,_topology->getNbEdges());

}
template <class DataTypes> void EdgePressureForceField<DataTypes>::init()
{
    this->core::componentmodel::behavior::ForceField<DataTypes>::init();

    _topology = this->getContext()->getMeshTopology();
    this->getContext()->get(_completeTopology, core::objectmodel::BaseContext::SearchUp);

    this->getContext()->get(edgeGeo);

    assert(edgeGeo!=0);

    if (edgeGeo==NULL)
    {
        serr << "ERROR(EdgePressureForceField): object must have an EdgeSetTopology."<<sendl;
        return;
    }

    if(_completeTopology == NULL)
    {
        serr << "ERROR(EdgePressureForceField): assume that pressure vector is provdided otherwise TriangleSetTopology is required" << sendl;
    }

    if (dmin.getValue()!=dmax.getValue())
    {
        selectEdgesAlongPlane();
    }
    if (edgeList.getValue().size()>0)
    {
        selectEdgesFromString();
    }

    initEdgeInformation();

}

template <class DataTypes>
void EdgePressureForceField<DataTypes>::addForce(VecDeriv& f, const VecCoord& /*x*/, const VecDeriv& /*v*/)
{
    Deriv force;

    typename topology::EdgeSubsetData<EdgePressureInformation>::iterator it;

    for(it=edgePressureMap.begin(); it!=edgePressureMap.end(); it++ )
    {
        force=(*it).second.force/2;
        f[_topology->getEdge((*it).first)[0]]+=force;
        f[_topology->getEdge((*it).first)[1]]+=force;

    }
}

template <class DataTypes>
double EdgePressureForceField<DataTypes>::getPotentialEnergy(const VecCoord& /*x*/)
{
    serr<<"EdgePressureForceField::getPotentialEnergy-not-implemented !!!"<<sendl;
    return 0;
}

template<class DataTypes>
void EdgePressureForceField<DataTypes>::initEdgeInformation()
{
    const VecCoord& x = *this->mstate->getX();

    if(pressure.getValue().norm() > 0)
    {
        typename topology::EdgeSubsetData<EdgePressureInformation>::iterator it;

        for(it=edgePressureMap.begin(); it!=edgePressureMap.end(); it++ )
        {
            (*it).second.length=edgeGeo->computeRestEdgeLength((*it).first);
            (*it).second.force=pressure.getValue()*(*it).second.length;
        }
    }
    else // if no pressure is provided, assume that boundary edges received pressure along their normal
    {

        for(int i = 0; i < _topology->getNbEdges() ; i++)
        {
            Edge e = _topology->getEdge(i), f;

            Vec3d tang, n1, n2;
            n2 = Vec3d(0,0,1);
            tang = x[e[1]] - x[e[0]]; tang.normalize();

            Vec3d sum;
            bool found = false;
            int k = 0;
            while ((!found) && (k < _completeTopology->getNbEdges()))
            {
                f = _completeTopology->getEdge(k);

                Vec3d l1 = x[f[0]] - x[e[0]];
                Vec3d l2 = x[f[1]] - x[e[1]];

                if((l1.norm() < 1e-6) && (l2.norm() < 1e-6))
                {
                    found = true;
                }
                else
                    k++;

            }
            TrianglesAroundEdge t_a_E = _completeTopology->getTrianglesAroundEdge(k);

            if(t_a_E.size() == 1) // 2D cases
            {
                Triangle t = _completeTopology->getTriangle(t_a_E[0]);
                Vec3d vert;

                if((t[0] == e[0]) || (t[0] == e[1]))
                {
                    if((t[1] == e[0]) || (t[1] == e[1]))
                        vert = x[t[2]];
                    else
                        vert = x[t[1]];
                }
                else
                    vert = x[t[0]];

                Vec3d tt = vert - x[e[0]];
                n1 = n2.cross(tang);
                if(n1*tt < 0)
                {
                    n1 = -n1;
                }

                EdgePressureInformation ei;
                ei.length = edgeGeo->computeRestEdgeLength(i);
                ei.force = n1 * ei.length * p_intensity.getValue();
                edgePressureMap[i] = ei;
            }

        }
    }

    return;
}

template<class DataTypes>
void EdgePressureForceField<DataTypes>::updateEdgeInformation()
{
    /*typename topology::EdgeSubsetData<EdgePressureInformation>::iterator it;

    const VecCoord& x = *this->mstate->getX();

    for(it=edgePressureMap.begin(); it!=edgePressureMap.end(); it++ )
    {
    	Vec3d p1 = x[_topology->getEdge((*it).first)[0]];
    	Vec3d p2 = x[_topology->getEdge((*it).first)[1]];
    	Vec3d orig(0,0,0);

    	Vec3d tang = p2 - p1;
    	tang.norm();

    	Deriv myPressure;

    	if( (p1[0] - orig[0]) * tang[1] > 0)
    		myPressure[0] = tang[1];
    	else
    		myPressure[0] = - tang[1];

    	if( (p1[1] - orig[1]) * tang[0] > 0)
    		myPressure[1] = tang[0];
    	else
    		myPressure[1] = - tang[0];

    	//(*it).second.force=pressure.getValue()*((*it).second.length);
    	(*it).second.force=myPressure*((*it).second.length);

    }*/
    initEdgeInformation();
}

template <class DataTypes>
void EdgePressureForceField<DataTypes>::selectEdgesAlongPlane()
{
    const VecCoord& x = *this->mstate->getX0();
    std::vector<bool> vArray;
    unsigned int i;

    vArray.resize(x.size());

    for( i=0; i<x.size(); ++i)
    {
        vArray[i]=isPointInPlane(x[i]);
    }

    for (int n=0; n<_topology->getNbEdges(); ++n)
    {
        if ((vArray[_topology->getEdge(n)[0]]) && (vArray[_topology->getEdge(n)[1]]))
        {
            // insert a dummy element : computation of pressure done later
            EdgePressureInformation t;
            edgePressureMap[n]=t;
        }
    }
}

template <class DataTypes>
void EdgePressureForceField<DataTypes>::selectEdgesFromString()
{
    helper::vector<int> inputString=edgeList.getValue();
    for (unsigned int i = 0; i < inputString.size(); i++)
    {
        EdgePressureInformation t;
        edgePressureMap[inputString[i]]=t;

    }

}
template<class DataTypes>
void EdgePressureForceField<DataTypes>::draw()
{

    if (!this->getContext()->getShowForceFields()) return;
    if (!this->mstate) return;

    if (this->getContext()->getShowWireFrame())
        glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);

    const VecCoord& x = *this->mstate->getX();

    glDisable(GL_LIGHTING);

    typename topology::EdgeSubsetData<EdgePressureInformation>::iterator it;

    /*for(it=edgePressureMap.begin(); it!=edgePressureMap.end(); it++ )
    {
    	helper::gl::glVertexT(x[_topology->getEdge((*it).first)[0]]);
    	helper::gl::glVertexT(x[_topology->getEdge((*it).first)[1]]);
    }*/
    glEnd();

    glBegin(GL_LINES);
    glColor4f(1,1,0,1);

    for(it=edgePressureMap.begin(); it!=edgePressureMap.end(); it++ )
    {
        Vec3d p = (x[_topology->getEdge((*it).first)[0]] + x[_topology->getEdge((*it).first)[1]]) / 2.0;
        helper::gl::glVertexT(p);

        Vec3d f = (*it).second.force;
        f.normalize();
        f /= 5.0;
        helper::gl::glVertexT(p + f);
    }
    glEnd();

    if (this->getContext()->getShowWireFrame())
        glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);

}

} // namespace forcefield

} // namespace component

} // namespace sofa
<commit_msg>r6720/sofa-dev : Update: force pressure update<commit_after>/******************************************************************************
*       SOFA, Simulation Open-Framework Architecture, version 1.0 beta 4      *
*                (c) 2006-2009 MGH, INRIA, USTL, UJF, CNRS                    *
*                                                                             *
* This library is free software; you can redistribute it and/or modify it     *
* under the terms of the GNU Lesser General Public License as published by    *
* the Free Software Foundation; either version 2.1 of the License, or (at     *
* your option) any later version.                                             *
*                                                                             *
* This library 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 Lesser General Public License *
* for more details.                                                           *
*                                                                             *
* You should have received a copy of the GNU Lesser General Public License    *
* along with this library; if not, write to the Free Software Foundation,     *
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA.          *
*******************************************************************************
*                               SOFA :: Modules                               *
*                                                                             *
* Authors: The SOFA Team and external contributors (see Authors.txt)          *
*                                                                             *
* Contact information: contact@sofa-framework.org                             *
******************************************************************************/
#include <sofa/component/forcefield/EdgePressureForceField.h>
#include <sofa/component/topology/EdgeSubsetData.inl>
#include <sofa/helper/gl/template.h>
#include <vector>
#include <set>

#ifdef _WIN32
#include <windows.h>
#endif

// #define DEBUG_TRIANGLEFEM

namespace sofa
{

namespace component
{

namespace forcefield
{

using namespace sofa::defaulttype;
using namespace core::componentmodel::topology;

template <class DataTypes> EdgePressureForceField<DataTypes>::~EdgePressureForceField()
{
}
// Handle topological changes
template <class DataTypes> void  EdgePressureForceField<DataTypes>::handleTopologyChange()
{
    std::list<const TopologyChange *>::const_iterator itBegin=_topology->firstChange();
    std::list<const TopologyChange *>::const_iterator itEnd=_topology->lastChange();

    edgePressureMap.handleTopologyEvents(itBegin,itEnd,_topology->getNbEdges());

}
template <class DataTypes> void EdgePressureForceField<DataTypes>::init()
{
    this->core::componentmodel::behavior::ForceField<DataTypes>::init();

    _topology = this->getContext()->getMeshTopology();
    this->getContext()->get(_completeTopology, core::objectmodel::BaseContext::SearchUp);

    this->getContext()->get(edgeGeo);

    assert(edgeGeo!=0);

    if (edgeGeo==NULL)
    {
        serr << "ERROR(EdgePressureForceField): object must have an EdgeSetTopology."<<sendl;
        return;
    }

    if(_completeTopology == NULL)
    {
        serr << "ERROR(EdgePressureForceField): assume that pressure vector is provdided otherwise TriangleSetTopology is required" << sendl;
    }

    if (dmin.getValue()!=dmax.getValue())
    {
        selectEdgesAlongPlane();
    }
    if (edgeList.getValue().size()>0)
    {
        selectEdgesFromString();
    }

    initEdgeInformation();

}

template <class DataTypes>
void EdgePressureForceField<DataTypes>::addForce(VecDeriv& f, const VecCoord& /*x*/, const VecDeriv& /*v*/)
{
    Deriv force;

    typename topology::EdgeSubsetData<EdgePressureInformation>::iterator it;

    for(it=edgePressureMap.begin(); it!=edgePressureMap.end(); it++ )
    {
        force=(*it).second.force/2;
        f[_topology->getEdge((*it).first)[0]]+=force;
        f[_topology->getEdge((*it).first)[1]]+=force;

    }
}

template <class DataTypes>
double EdgePressureForceField<DataTypes>::getPotentialEnergy(const VecCoord& /*x*/)
{
    serr<<"EdgePressureForceField::getPotentialEnergy-not-implemented !!!"<<sendl;
    return 0;
}

template<class DataTypes>
void EdgePressureForceField<DataTypes>::initEdgeInformation()
{
    const VecCoord& x = *this->mstate->getX();

    if(pressure.getValue().norm() > 0)
    {
        typename topology::EdgeSubsetData<EdgePressureInformation>::iterator it;

        for(it=edgePressureMap.begin(); it!=edgePressureMap.end(); it++ )
        {
            (*it).second.length=edgeGeo->computeRestEdgeLength((*it).first);
            (*it).second.force=pressure.getValue()*(*it).second.length;
        }
    }
    else // if no pressure is provided, assume that boundary edges received pressure along their normal
    {
        for(int i = 0; i < _topology->getNbEdges() ; i++)
        {
            Edge e = _topology->getEdge(i), f;

            Vec3d tang, n1, n2;
            n2 = Vec3d(0,0,1);
            tang = x[e[1]] - x[e[0]]; tang.normalize();

            Vec3d sum;
            bool found = false;
            int k = 0;
            while ((!found) && (k < _completeTopology->getNbEdges()))
            {
                f = _completeTopology->getEdge(k);

                Vec3d l1 = x[f[0]] - x[e[0]];
                Vec3d l2 = x[f[1]] - x[e[1]];

                if((l1.norm() < 1e-6) && (l2.norm() < 1e-6))
                {
                    found = true;
                }
                else
                    k++;

            }
            TrianglesAroundEdge t_a_E = _completeTopology->getTrianglesAroundEdge(k);

            if(t_a_E.size() == 1) // 2D cases
            {
                Triangle t = _completeTopology->getTriangle(t_a_E[0]);
                Vec3d vert;

                if((t[0] == e[0]) || (t[0] == e[1]))
                {
                    if((t[1] == e[0]) || (t[1] == e[1]))
                        vert = x[t[2]];
                    else
                        vert = x[t[1]];
                }
                else
                    vert = x[t[0]];

                Vec3d tt = vert - x[e[0]];
                n1 = n2.cross(tang);
                if(n1*tt < 0)
                {
                    n1 = -n1;
                }

                EdgePressureInformation ei;
                ei.length = edgeGeo->computeRestEdgeLength(i);
                ei.force = n1 * ei.length * p_intensity.getValue();
                edgePressureMap[i] = ei;
            }

        }
    }

    return;
}

template<class DataTypes>
void EdgePressureForceField<DataTypes>::updateEdgeInformation()
{
    /*typename topology::EdgeSubsetData<EdgePressureInformation>::iterator it;

    const VecCoord& x = *this->mstate->getX();

    for(it=edgePressureMap.begin(); it!=edgePressureMap.end(); it++ )
    {
    	Vec3d p1 = x[_topology->getEdge((*it).first)[0]];
    	Vec3d p2 = x[_topology->getEdge((*it).first)[1]];
    	Vec3d orig(0,0,0);

    	Vec3d tang = p2 - p1;
    	tang.norm();

    	Deriv myPressure;

    	if( (p1[0] - orig[0]) * tang[1] > 0)
    		myPressure[0] = tang[1];
    	else
    		myPressure[0] = - tang[1];

    	if( (p1[1] - orig[1]) * tang[0] > 0)
    		myPressure[1] = tang[0];
    	else
    		myPressure[1] = - tang[0];

    	//(*it).second.force=pressure.getValue()*((*it).second.length);
    	(*it).second.force=myPressure*((*it).second.length);

    }*/
    initEdgeInformation();
}

template <class DataTypes>
void EdgePressureForceField<DataTypes>::selectEdgesAlongPlane()
{
    const VecCoord& x = *this->mstate->getX0();
    std::vector<bool> vArray;
    unsigned int i;

    vArray.resize(x.size());

    for( i=0; i<x.size(); ++i)
    {
        vArray[i]=isPointInPlane(x[i]);
    }

    for (int n=0; n<_topology->getNbEdges(); ++n)
    {
        if ((vArray[_topology->getEdge(n)[0]]) && (vArray[_topology->getEdge(n)[1]]))
        {
            // insert a dummy element : computation of pressure done later
            EdgePressureInformation t;
            edgePressureMap[n]=t;
        }
    }
}

template <class DataTypes>
void EdgePressureForceField<DataTypes>::selectEdgesFromString()
{
    helper::vector<int> inputString=edgeList.getValue();
    for (unsigned int i = 0; i < inputString.size(); i++)
    {
        EdgePressureInformation t;
        edgePressureMap[inputString[i]]=t;

    }

}
template<class DataTypes>
void EdgePressureForceField<DataTypes>::draw()
{

    updateEdgeInformation();

    if (!this->getContext()->getShowForceFields()) return;
    if (!this->mstate) return;

    if (this->getContext()->getShowWireFrame())
        glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);

    const VecCoord& x = *this->mstate->getX();

    glDisable(GL_LIGHTING);

    typename topology::EdgeSubsetData<EdgePressureInformation>::iterator it;

    /*for(it=edgePressureMap.begin(); it!=edgePressureMap.end(); it++ )
    {
    	helper::gl::glVertexT(x[_topology->getEdge((*it).first)[0]]);
    	helper::gl::glVertexT(x[_topology->getEdge((*it).first)[1]]);
    }*/
    glEnd();

    glBegin(GL_LINES);
    glColor4f(1,1,0,1);

    for(it=edgePressureMap.begin(); it!=edgePressureMap.end(); it++ )
    {
        Vec3d p = (x[_topology->getEdge((*it).first)[0]] + x[_topology->getEdge((*it).first)[1]]) / 2.0;
        helper::gl::glVertexT(p);

        Vec3d f = (*it).second.force;
        f.normalize();
        f /= 5.0;
        helper::gl::glVertexT(p + f);
    }
    glEnd();

    if (this->getContext()->getShowWireFrame())
        glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);

}

} // namespace forcefield

} // namespace component

} // namespace sofa
<|endoftext|>


<commit_before>#include "demo.h"

Demo::Demo(void) {
	this->root = NULL;
	this->sceneMgr = NULL;
	this->window = NULL;

	this->resourcesCfg = "resources.cfg";
	this->pluginsCfg = "plugins.cfg";

	this->camera = NULL;

	this->shutDown = false;
}

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

Demo::~Demo(void) {
	// remove ourself as a Window listener
	Ogre::WindowEventUtilities::removeWindowEventListener(this->window, this);
	windowClosed(this->window);
}

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

bool Demo::start(void) {
	// construct Ogre::Root
	this->root = new Ogre::Root(this->pluginsCfg);

	// load the ressources
	this->loadRessources();

	// restore the config or show the configuration dialog and
	if(! this->root->restoreConfig() && ! this->root->showConfigDialog())
		return false;

	// initialise the system, create the default rendering window
	this->window = this->root->initialise(true, "Diablotin");

	// get the generic SceneManager
	this->sceneMgr = this->root->createSceneManager(Ogre::ST_GENERIC);

	// init the input manager and create the listeners
	this->initListeners();

	// create the scene
	this->initScene();

	// create the camera
	this->camera = this->sceneMgr->createCamera("mainCam");
	this->camera->setPosition(Ogre::Vector3(90, 25, 90));
	this->camera->lookAt(this->sceneMgr->getRootSceneNode()->getPosition());

	// create one viewport, entire window
	// use the same color for the fog and viewport background
	//Ogre::Viewport* viewPort = this->window->addViewport(this->camera);
	Ogre::Viewport* viewPort = this->window->addViewport(this->camera, 0);
	viewPort->setBackgroundColour(Ogre::ColourValue(0.0f, 0.0f, 0.0f));
	this->camera->setAspectRatio(Ogre::Real(viewPort->getActualWidth()) / Ogre::Real(viewPort->getActualHeight()));

	// start the scene rendering (main loop)
	this->root->startRendering();

	return true;
}

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

void Demo::initListeners(void) {
	// Init the input system
	OIS::ParamList pl;
	size_t windowHnd = 0;
	std::ostringstream windowHndStr;

	window->getCustomAttribute("WINDOW", &windowHnd);
	windowHndStr << windowHnd;
	pl.insert(std::make_pair(std::string("WINDOW"), windowHndStr.str()));

	this->inputManager = OIS::InputManager::createInputSystem(pl);

	this->keyboard = static_cast<OIS::Keyboard*>(inputManager->createInputObject(OIS::OISKeyboard, true));
	this->mouse = static_cast<OIS::Mouse*>(inputManager->createInputObject(OIS::OISMouse, true));

	// Set initial mouse clipping size
	windowResized(this->window);

	// Register the listeners
	Ogre::WindowEventUtilities::addWindowEventListener(this->window, this);
	this->root->addFrameListener(this);
	this->mouse->setEventCallback(this);
	this->keyboard->setEventCallback(this);

}

void Demo::initScene(void) {

	Ogre::Plane plane(Ogre::Vector3::UNIT_Y, 0);
	Ogre::MeshManager::getSingleton().createPlane("ground", Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME,
			plane, 150, 150, 20, 20, true, 1, 5, 5, Ogre::Vector3::UNIT_Z);
	Ogre::Entity* entGround = this->sceneMgr->createEntity("GroundEntity", "ground");
	entGround->setMaterialName("Rockwall");
	entGround->setCastShadows(false);
	Ogre::SceneNode *groundNode = this->sceneMgr->getRootSceneNode()->createChildSceneNode("ground");
	groundNode->attachObject(entGround);
	groundNode->setPosition(0, -50, 0);

	Ogre::SceneNode *headNodeObject = this->sceneMgr->getRootSceneNode()->createChildSceneNode("HeadNodeObject");
	Ogre::SceneNode *headNodeLight = this->sceneMgr->getRootSceneNode()->createChildSceneNode("HeadNodeLight");

	// charger le « mesh » à partir du nom de fichier et le nommer
	Ogre::Entity *entity = this->sceneMgr->createEntity("Suzanne", "suzanne.mesh");
	Ogre::SceneNode *nodeObjectSuzanne = headNodeObject->createChildSceneNode("NodeObjectSuzanne");
	nodeObjectSuzanne->attachObject(entity);
	nodeObjectSuzanne->setPosition(0, 0, 0);
	nodeObjectSuzanne->scale(10, 10, 10);

	/*Ogre::Entity *entity1 = this->sceneMgr->createEntity("SuzanneBoiteBas", "boite_bas.mesh");
	Ogre::Entity *entity2 = this->sceneMgr->createEntity("SuzanneBoiteFermeture", "fermeture.mesh");
	entity = this->sceneMgr->createEntity("SuzanneBoiteHaut", "boite_haut.mesh");
	Ogre::SceneNode *nodeObjectSuzanneBoiteHaut = headNodeObject->createChildSceneNode("NodeObjectSuzanneBoiteHaut");
	nodeObjectSuzanneBoiteHaut->attachObject(entity);
	nodeObjectSuzanneBoiteHaut->setPosition(0, 0, 0);
	nodeObjectSuzanneBoiteHaut->scale(10, 10, 10);*/

    // Set ambient light
    //this->sceneMgr->setAmbientLight(Ogre::ColourValue(0.5, 0.5, 0.5));
    this->sceneMgr->setAmbientLight(Ogre::ColourValue(1.0, 1.0, 1.0));

    // Create a light
    Ogre::Light* l = this->sceneMgr->createLight("MainLight");
    l->setPosition(20,80,50);
	Ogre::SceneNode *nodeLight1 = headNodeLight->createChildSceneNode("NodeLight1");
	nodeLight1->attachObject(l);
}

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

void Demo::loadRessources(void) {
	// setup resources
	// Load resource paths from config file
	Ogre::ConfigFile cf;
	cf.load(this->resourcesCfg);

	// Go through all sections & settings in the file
	Ogre::ConfigFile::SectionIterator seci = cf.getSectionIterator();

	Ogre::String secName, typeName, archName;
	while (seci.hasMoreElements())
	{
		secName = seci.peekNextKey();
		Ogre::ConfigFile::SettingsMultiMap *settings = seci.getNext();
		Ogre::ConfigFile::SettingsMultiMap::iterator i;
		for (i = settings->begin(); i != settings->end(); ++i)
		{
			typeName = i->first;
			archName = i->second;
			Ogre::ResourceGroupManager::getSingleton().addResourceLocation(archName, typeName, secName);
		}
	}

	Ogre::ResourceGroupManager::getSingleton().initialiseAllResourceGroups();
}

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

bool Demo::frameRenderingQueued(const Ogre::FrameEvent& evt) {
	int newStatus;

	// Stop the rendering if the window was closed, or the application stoped
	if(this->window->isClosed() || this->shutDown)
		return false;

    // capture value of each device
    this->keyboard->capture();
    this->mouse->capture();

	return true;
}

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

void Demo::windowResized(Ogre::RenderWindow *rw)
{
	unsigned int width, height, depth;
	int left, top;

	// Adjust mouse clipping area
	rw->getMetrics(width, height, depth, left, top);
	const OIS::MouseState &ms = this->mouse->getMouseState();
	ms.width = width;
	ms.height = height;

}

void Demo::windowClosed(Ogre::RenderWindow *rw)
{
	// Only close for window that created OIS (the main window)
	if(rw == this->window)
	{
		if(this->inputManager)
		{
			// Unattach OIS before window shutdown (very important under Linux)
			this->inputManager->destroyInputObject(this->mouse);
			this->inputManager->destroyInputObject(this->keyboard);

			OIS::InputManager::destroyInputSystem(this->inputManager);
			this->inputManager = 0;
		}
	}

}

bool Demo::keyPressed(const OIS::KeyEvent &evt) {

	// Quit
	switch(evt.key)
	{
		case OIS::KC_ESCAPE:
			this->shutDown = true;
			break;

		case OIS::KC_UP:
			this->camera->move(Ogre::Vector3(0, 0, 5));
			break;

		case OIS::KC_DOWN:
			this->camera->move(Ogre::Vector3(0, 0, -5));
			break;

		case OIS::KC_H:
			this->camera->move(Ogre::Vector3(0, 5, 0));
			break;

		case OIS::KC_N:
			this->camera->move(Ogre::Vector3(0, -5, 0));
			break;

		case OIS::KC_G:
			this->camera->move(Ogre::Vector3(5, 0, 0));
			break;

		case OIS::KC_B:
			this->camera->move(Ogre::Vector3(-5, 0, 0));
			break;
	}

	std::cout << "PosCamera : " << this->camera->getPosition()[0] << "/" << this->camera->getPosition()[1] << "/" << this->camera->getPosition()[2] << std::endl;

	return true;
}

bool Demo::keyReleased(const OIS::KeyEvent &evt) {

	return true;
}

bool Demo::mouseMoved(const OIS::MouseEvent &evt) {

	float mRotateSpeed = 0.1f;

	this->camera->yaw(Ogre::Degree(-evt.state.X.rel * mRotateSpeed));
	this->camera->pitch(Ogre::Degree(-evt.state.Y.rel * mRotateSpeed));

	return true;
}

bool Demo::mousePressed(const OIS::MouseEvent &evt, OIS::MouseButtonID id) {

	return true;
}

bool Demo::mouseReleased(const OIS::MouseEvent &evt, OIS::MouseButtonID id) {

	return true;
}

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

int main(void) {
	Demo demo;

	try {
		demo.start();
	} catch( Ogre::Exception& e ) {
		std::cerr << "An exception has occured: " << e.getFullDescription().c_str() << std::endl;
		return 1;
	}

	return 0;
}

<commit_msg>Chargement des fichiers plugins.cfg et resources.cfg en fonction du mode de compilation (Debug ou Release)<commit_after>#include "demo.h"

Demo::Demo(void) {
	this->root = NULL;
	this->sceneMgr = NULL;
	this->window = NULL;

#ifdef _DEBUG
	this->resourcesCfg = "resources_d.cfg";
#else
	this->resourcesCfg = "resources.cfg";
#endif

#ifdef _DEBUG
	this->pluginsCfg = "plugins_d.cfg";
#else
	this->pluginsCfg = "plugins.cfg";
#endif

	this->camera = NULL;

	this->shutDown = false;
}

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

Demo::~Demo(void) {
	// remove ourself as a Window listener
	Ogre::WindowEventUtilities::removeWindowEventListener(this->window, this);
	windowClosed(this->window);
}

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

bool Demo::start(void) {
	// construct Ogre::Root
	this->root = new Ogre::Root(this->pluginsCfg);

	// load the ressources
	this->loadRessources();

	// restore the config or show the configuration dialog and
	if(! this->root->restoreConfig() && ! this->root->showConfigDialog())
		return false;

	// initialise the system, create the default rendering window
	this->window = this->root->initialise(true, "Diablotin");

	// get the generic SceneManager
	this->sceneMgr = this->root->createSceneManager(Ogre::ST_GENERIC);

	// init the input manager and create the listeners
	this->initListeners();

	// create the scene
	this->initScene();

	// create the camera
	this->camera = this->sceneMgr->createCamera("mainCam");
	this->camera->setPosition(Ogre::Vector3(90, 25, 90));
	this->camera->lookAt(this->sceneMgr->getRootSceneNode()->getPosition());

	// create one viewport, entire window
	// use the same color for the fog and viewport background
	//Ogre::Viewport* viewPort = this->window->addViewport(this->camera);
	Ogre::Viewport* viewPort = this->window->addViewport(this->camera, 0);
	viewPort->setBackgroundColour(Ogre::ColourValue(0.0f, 0.0f, 0.0f));
	this->camera->setAspectRatio(Ogre::Real(viewPort->getActualWidth()) / Ogre::Real(viewPort->getActualHeight()));

	// start the scene rendering (main loop)
	this->root->startRendering();

	return true;
}

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

void Demo::initListeners(void) {
	// Init the input system
	OIS::ParamList pl;
	size_t windowHnd = 0;
	std::ostringstream windowHndStr;

	window->getCustomAttribute("WINDOW", &windowHnd);
	windowHndStr << windowHnd;
	pl.insert(std::make_pair(std::string("WINDOW"), windowHndStr.str()));

	this->inputManager = OIS::InputManager::createInputSystem(pl);

	this->keyboard = static_cast<OIS::Keyboard*>(inputManager->createInputObject(OIS::OISKeyboard, true));
	this->mouse = static_cast<OIS::Mouse*>(inputManager->createInputObject(OIS::OISMouse, true));

	// Set initial mouse clipping size
	windowResized(this->window);

	// Register the listeners
	Ogre::WindowEventUtilities::addWindowEventListener(this->window, this);
	this->root->addFrameListener(this);
	this->mouse->setEventCallback(this);
	this->keyboard->setEventCallback(this);

}

void Demo::initScene(void) {

	Ogre::Plane plane(Ogre::Vector3::UNIT_Y, 0);
	Ogre::MeshManager::getSingleton().createPlane("ground", Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME,
			plane, 150, 150, 20, 20, true, 1, 5, 5, Ogre::Vector3::UNIT_Z);
	Ogre::Entity* entGround = this->sceneMgr->createEntity("GroundEntity", "ground");
	entGround->setMaterialName("Rockwall");
	entGround->setCastShadows(false);
	Ogre::SceneNode *groundNode = this->sceneMgr->getRootSceneNode()->createChildSceneNode("ground");
	groundNode->attachObject(entGround);
	groundNode->setPosition(0, -50, 0);

	Ogre::SceneNode *headNodeObject = this->sceneMgr->getRootSceneNode()->createChildSceneNode("HeadNodeObject");
	Ogre::SceneNode *headNodeLight = this->sceneMgr->getRootSceneNode()->createChildSceneNode("HeadNodeLight");

	// charger le « mesh » à partir du nom de fichier et le nommer
	Ogre::Entity *entity = this->sceneMgr->createEntity("Suzanne", "suzanne.mesh");
	Ogre::SceneNode *nodeObjectSuzanne = headNodeObject->createChildSceneNode("NodeObjectSuzanne");
	nodeObjectSuzanne->attachObject(entity);
	nodeObjectSuzanne->setPosition(0, 0, 0);
	nodeObjectSuzanne->scale(10, 10, 10);

	/*Ogre::Entity *entity1 = this->sceneMgr->createEntity("SuzanneBoiteBas", "boite_bas.mesh");
	Ogre::Entity *entity2 = this->sceneMgr->createEntity("SuzanneBoiteFermeture", "fermeture.mesh");
	entity = this->sceneMgr->createEntity("SuzanneBoiteHaut", "boite_haut.mesh");
	Ogre::SceneNode *nodeObjectSuzanneBoiteHaut = headNodeObject->createChildSceneNode("NodeObjectSuzanneBoiteHaut");
	nodeObjectSuzanneBoiteHaut->attachObject(entity);
	nodeObjectSuzanneBoiteHaut->setPosition(0, 0, 0);
	nodeObjectSuzanneBoiteHaut->scale(10, 10, 10);*/

    // Set ambient light
    //this->sceneMgr->setAmbientLight(Ogre::ColourValue(0.5, 0.5, 0.5));
    this->sceneMgr->setAmbientLight(Ogre::ColourValue(1.0, 1.0, 1.0));

    // Create a light
    Ogre::Light* l = this->sceneMgr->createLight("MainLight");
    l->setPosition(20,80,50);
	Ogre::SceneNode *nodeLight1 = headNodeLight->createChildSceneNode("NodeLight1");
	nodeLight1->attachObject(l);
}

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

void Demo::loadRessources(void) {
	// setup resources
	// Load resource paths from config file
	Ogre::ConfigFile cf;
	cf.load(this->resourcesCfg);

	// Go through all sections & settings in the file
	Ogre::ConfigFile::SectionIterator seci = cf.getSectionIterator();

	Ogre::String secName, typeName, archName;
	while (seci.hasMoreElements())
	{
		secName = seci.peekNextKey();
		Ogre::ConfigFile::SettingsMultiMap *settings = seci.getNext();
		Ogre::ConfigFile::SettingsMultiMap::iterator i;
		for (i = settings->begin(); i != settings->end(); ++i)
		{
			typeName = i->first;
			archName = i->second;
			Ogre::ResourceGroupManager::getSingleton().addResourceLocation(archName, typeName, secName);
		}
	}

	Ogre::ResourceGroupManager::getSingleton().initialiseAllResourceGroups();
}

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

bool Demo::frameRenderingQueued(const Ogre::FrameEvent& evt) {
	int newStatus;

	// Stop the rendering if the window was closed, or the application stoped
	if(this->window->isClosed() || this->shutDown)
		return false;

    // capture value of each device
    this->keyboard->capture();
    this->mouse->capture();

	return true;
}

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

void Demo::windowResized(Ogre::RenderWindow *rw)
{
	unsigned int width, height, depth;
	int left, top;

	// Adjust mouse clipping area
	rw->getMetrics(width, height, depth, left, top);
	const OIS::MouseState &ms = this->mouse->getMouseState();
	ms.width = width;
	ms.height = height;

}

void Demo::windowClosed(Ogre::RenderWindow *rw)
{
	// Only close for window that created OIS (the main window)
	if(rw == this->window)
	{
		if(this->inputManager)
		{
			// Unattach OIS before window shutdown (very important under Linux)
			this->inputManager->destroyInputObject(this->mouse);
			this->inputManager->destroyInputObject(this->keyboard);

			OIS::InputManager::destroyInputSystem(this->inputManager);
			this->inputManager = 0;
		}
	}

}

bool Demo::keyPressed(const OIS::KeyEvent &evt) {

	// Quit
	switch(evt.key)
	{
		case OIS::KC_ESCAPE:
			this->shutDown = true;
			break;

		case OIS::KC_UP:
			this->camera->move(Ogre::Vector3(0, 0, 5));
			break;

		case OIS::KC_DOWN:
			this->camera->move(Ogre::Vector3(0, 0, -5));
			break;

		case OIS::KC_H:
			this->camera->move(Ogre::Vector3(0, 5, 0));
			break;

		case OIS::KC_N:
			this->camera->move(Ogre::Vector3(0, -5, 0));
			break;

		case OIS::KC_G:
			this->camera->move(Ogre::Vector3(5, 0, 0));
			break;

		case OIS::KC_B:
			this->camera->move(Ogre::Vector3(-5, 0, 0));
			break;
	}

	std::cout << "PosCamera : " << this->camera->getPosition()[0] << "/" << this->camera->getPosition()[1] << "/" << this->camera->getPosition()[2] << std::endl;

	return true;
}

bool Demo::keyReleased(const OIS::KeyEvent &evt) {

	return true;
}

bool Demo::mouseMoved(const OIS::MouseEvent &evt) {

	float mRotateSpeed = 0.1f;

	this->camera->yaw(Ogre::Degree(-evt.state.X.rel * mRotateSpeed));
	this->camera->pitch(Ogre::Degree(-evt.state.Y.rel * mRotateSpeed));

	return true;
}

bool Demo::mousePressed(const OIS::MouseEvent &evt, OIS::MouseButtonID id) {

	return true;
}

bool Demo::mouseReleased(const OIS::MouseEvent &evt, OIS::MouseButtonID id) {

	return true;
}

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

int main(void) {
	Demo demo;

	try {
		demo.start();
	} catch( Ogre::Exception& e ) {
		std::cerr << "An exception has occured: " << e.getFullDescription().c_str() << std::endl;
		return 1;
	}

	return 0;
}

<|endoftext|>


<commit_before>/******************************************************************************
*       SOFA, Simulation Open-Framework Architecture, version 1.0 RC 1        *
*                (c) 2006-2011 MGH, INRIA, USTL, UJF, CNRS                    *
*                                                                             *
* This library is free software; you can redistribute it and/or modify it     *
* under the terms of the GNU Lesser General Public License as published by    *
* the Free Software Foundation; either version 2.1 of the License, or (at     *
* your option) any later version.                                             *
*                                                                             *
* This library 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 Lesser General Public License *
* for more details.                                                           *
*                                                                             *
* You should have received a copy of the GNU Lesser General Public License    *
* along with this library; if not, write to the Free Software Foundation,     *
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA.          *
*******************************************************************************
*                               SOFA :: Modules                               *
*                                                                             *
* Authors: The SOFA Team and external contributors (see Authors.txt)          *
*                                                                             *
* Contact information: contact@sofa-framework.org                             *
******************************************************************************/
#ifndef SOFA_COMPONENT_MAPPING_DistanceFromTargetMapping_INL
#define SOFA_COMPONENT_MAPPING_DistanceFromTargetMapping_INL

#include "DistanceFromTargetMapping.h"
#include <sofa/core/visual/VisualParams.h>
#include <iostream>
using std::cerr;
using std::endl;

namespace sofa
{

namespace component
{

namespace mapping
{

using namespace sofa::defaulttype;

template <class TIn, class TOut>
DistanceFromTargetMapping<TIn, TOut>::DistanceFromTargetMapping()
    : Inherit()
    , f_indices(initData(&f_indices, "indices", "Indices of the parent points"))
    , f_targetPositions(initData(&f_targetPositions, "targetPositions", "Positions to compute the distances from"))
    , f_restDistances(initData(&f_restDistances, "restLengths", "Rest lengths of the connections."))
    , _arrowSize(-1)
    , _color( 1,0,0,1 )
{
}

template <class TIn, class TOut>
DistanceFromTargetMapping<TIn, TOut>::~DistanceFromTargetMapping()
{
}

template <class TIn, class TOut>
void DistanceFromTargetMapping<TIn, TOut>::createTarget( unsigned index, InCoord position, Real distance)
{
    helper::WriteAccessor< Data< vector<Real> > > distances(f_restDistances);
    helper::WriteAccessor< Data<vector<unsigned> > > indices(f_indices);
    helper::WriteAccessor< Data<InVecCoord > > targetPositions(f_targetPositions);

    indices.push_back(index);
    targetPositions.push_back(position);
    distances.push_back(distance);

//    cerr<<"DistanceFromTargetMapping<TIn, TOut>::createTarget index " << index << " at position " << position << ", distance = " << distances << endl;
}

template <class TIn, class TOut>
void DistanceFromTargetMapping<TIn, TOut>::updateTarget( unsigned index, InCoord position)
{
    helper::WriteAccessor< Data<InVecCoord > > targetPositions(f_targetPositions);
    helper::WriteAccessor< Data<vector<unsigned> > > indices(f_indices);
//    cerr<<"DistanceFromTargetMapping<TIn, TOut>::updateTarget index " << index << " at position " << position << endl;

    // find the target with given index
    unsigned i=0; while(i<indices.size() && indices[i]!=index) i++;

    targetPositions[i] = position;
}

template <class TIn, class TOut>
void DistanceFromTargetMapping<TIn, TOut>::clear()
{
    helper::WriteAccessor< Data< vector<Real> > > distances(f_restDistances);
    helper::WriteAccessor< Data<InVecCoord > > positions(f_targetPositions);
    helper::WriteAccessor< Data<vector<unsigned> > > indices(f_indices);

    distances.clear();
    positions.clear();
    indices.clear();

    this->getToModel()->resize( 0 );
}

template <class TIn, class TOut>
void DistanceFromTargetMapping<TIn, TOut>::init()
{
    assert( f_indices.getValue().size()==f_targetPositions.getValue().size()) ;

    // unset distances are set to 0
    if(f_restDistances.getValue().size() != f_indices.getValue().size())
    {
        helper::WriteAccessor< Data< vector<Real> > > distances(f_restDistances);
        unsigned prevsize = distances.size();
        distances.resize( f_indices.getValue().size() );
        for(unsigned i=prevsize; i<distances.size(); i++ )
            distances[i] = 0;
    }

    this->getToModel()->resize( f_indices.getValue().size() );

    baseMatrices.resize( 1 );
    baseMatrices[0] = &jacobian;

    stiffnessBaseMatrices.resize(1);
    stiffnessBaseMatrices[0] = &K;

    this->Inherit::init();  // applies the mapping, so after the Data init
}

template <class TIn, class TOut>
void DistanceFromTargetMapping<TIn, TOut>::apply(const core::MechanicalParams * /*mparams*/ , Data<OutVecCoord>& dOut, const Data<InVecCoord>& dIn)
{
    helper::WriteAccessor< Data<OutVecCoord> >  out = dOut;
    helper::ReadAccessor< Data<InVecCoord> >  in = dIn;
    helper::WriteAccessor<Data<vector<Real> > > restDistances(f_restDistances);
    helper::ReadAccessor< Data<vector<unsigned> > > indices(f_indices);
    helper::ReadAccessor< Data<InVecCoord > > targetPositions(f_targetPositions);

    jacobian.resizeBlocks(out.size(),in.size());
    directions.resize(out.size());
    invlengths.resize(out.size());

    for(unsigned i=0; i<indices.size(); i++ )
    {
        InDeriv& gap = directions[i];
        gap = TIn::coordDifference(in[indices[i]],targetPositions[i]);
        Real gapNorm = TIn::getDPos(gap).norm();
//        cerr<<"DistanceFromTargetMapping<TIn, TOut>::apply, gap = " << gap <<", norm = " << gapNorm << endl;
        out[i] = gapNorm - restDistances[i];  // output

        if( gapNorm>1.e-10 )
        {
            invlengths[i] = 1/gapNorm;
            gap *= invlengths[i];
        }
        else
        {
            invlengths[i] = 0;
            gap = InDeriv();
            gap[0]=1.0;  // arbitrary unit vector
        }

//        jacobian.beginRow(i);
        for(unsigned j=0; j<Nout; j++)
        {
            for(unsigned k=0; k<Nin; k++ )
            {
                jacobian.insertBack( i*Nout+j, indices[i]*Nin+k, gap[k] );
//                jacobian.add( i*Nout+j, indices[i]*Nin+k, gap[k] );
            }
        }

    }
//    cerr<<"DistanceFromTargetMapping<TIn, TOut>::apply, in = " << in << endl;
//    cerr<<"DistanceFromTargetMapping<TIn, TOut>::apply, target positions = " << positions << endl;
//    cerr<<"DistanceFromTargetMapping<TIn, TOut>::apply, out = " << out << endl;

    jacobian.compress();
//    cerr<<"DistanceFromTargetMapping<TIn, TOut>::apply, jacobian: "<<endl<< jacobian << endl;

}

template <class TIn, class TOut>
void DistanceFromTargetMapping<TIn, TOut>::applyJ(const core::MechanicalParams * /*mparams*/ , Data<OutVecDeriv>& dOut, const Data<InVecDeriv>& dIn)
{
    if( jacobian.rowSize() > 0 )
        jacobian.mult(dOut,dIn);
}

template <class TIn, class TOut>
void DistanceFromTargetMapping<TIn, TOut>::applyJT(const core::MechanicalParams * /*mparams*/ , Data<InVecDeriv>& dIn, const Data<OutVecDeriv>& dOut)
{
    if( jacobian.rowSize() > 0 )
        jacobian.addMultTranspose(dIn,dOut);
}

template <class TIn, class TOut>
void DistanceFromTargetMapping<TIn, TOut>::applyJT(const core::ConstraintParams*, Data<InMatrixDeriv>& , const Data<OutMatrixDeriv>& )
{
    //    cerr<<"DistanceFromTargetMapping<TIn, TOut>::applyJT does nothing " << endl;
}

template <class TIn, class TOut>
void DistanceFromTargetMapping<TIn, TOut>::applyDJT(const core::MechanicalParams* mparams, core::MultiVecDerivId parentDfId, core::ConstMultiVecDerivId )
{
    helper::WriteAccessor<Data<InVecDeriv> > parentForce (*parentDfId[this->fromModel.get(mparams)].write());
    helper::ReadAccessor<Data<InVecDeriv> > parentDisplacement (*mparams->readDx(this->fromModel));  // parent displacement
    Real kfactor = mparams->kFactor();
    helper::ReadAccessor<Data<OutVecDeriv> > childForce (*mparams->readF(this->toModel));
    helper::ReadAccessor< Data<vector<unsigned> > > indices(f_indices);

    for(unsigned i=0; i<indices.size(); i++ )
    {
        Mat<Nin,Nin,Real> b;  // = (I - uu^T)
        for(unsigned j=0; j<Nin; j++)
        {
            for(unsigned k=0; k<Nin; k++)
            {
                if( j==k )
                    b[j][k] = 1. - directions[i][j]*directions[i][k];
                else
                    b[j][k] =    - directions[i][j]*directions[i][k];
            }
        }
        b *= childForce[i][0] * invlengths[i] * kfactor;  // (I - uu^T)*f/l*kfactor     do not forget kfactor !
        // note that computing a block is not efficient here, but it would makes sense for storing a stiffness matrix

        InDeriv dx = parentDisplacement[indices[i]];
        InDeriv df;
        for(unsigned j=0; j<Nin; j++)
        {
            for(unsigned k=0; k<Nin; k++)
            {
                df[j]+=b[j][k]*dx[k];
            }
        }
       // InDeriv df = b*dx;
        parentForce[indices[i]] += df;
//        cerr<<"DistanceFromTargetMapping<TIn, TOut>::applyDJT, df = " << df << endl;
    }
}

template <class TIn, class TOut>
const sofa::defaulttype::BaseMatrix* DistanceFromTargetMapping<TIn, TOut>::getJ()
{
    return &jacobian;
}

template <class TIn, class TOut>
const vector<sofa::defaulttype::BaseMatrix*>* DistanceFromTargetMapping<TIn, TOut>::getJs()
{
    return &baseMatrices;
}

template <class TIn, class TOut>
const vector<defaulttype::BaseMatrix*>* DistanceFromTargetMapping<TIn, TOut>::getKs()
{
//    helper::ReadAccessor<Data<OutVecDeriv> > childForce (*this->toModel->read(core::ConstVecDerivId::force()));
    const OutVecDeriv& childForce = this->toModel->readForces().ref();
    helper::ReadAccessor< Data<vector<unsigned> > > indices(f_indices);
    helper::ReadAccessor<Data<InVecCoord> > in (*this->fromModel->read(core::ConstVecCoordId::position()));

    K.resizeBlocks(in.size(),in.size());
    for(size_t i=0; i<indices.size(); i++)
    {
        size_t idx = indices[i];

        Mat<Nin,Nin,Real> b;  // = (I - uu^T)
        for(unsigned j=0; j<Nin; j++)
        {
            for(unsigned k=0; k<Nin; k++)
            {
                if( j==k )
                    b[j][k] = 1. - directions[i][j]*directions[i][k];
                else
                    b[j][k] =    - directions[i][j]*directions[i][k];
            }
        }
        b *= childForce[i][0] * invlengths[i];  // (I - uu^T)*f/l

//        std::cerr<<SOFA_CLASS_METHOD<<childForce[i][0]<<std::endl;

        K.beginBlockRow(idx);
        K.createBlock(idx,b);
        K.endBlockRow();
    }
    K.compress();

    return &stiffnessBaseMatrices;
}

template <class TIn, class TOut>
void DistanceFromTargetMapping<TIn, TOut>::draw(const core::visual::VisualParams* vparams)
{
    if( _arrowSize<0 ) return;

    typename core::behavior::MechanicalState<In>::ReadVecCoord pos = this->getFromModel()->readPositions();
    helper::ReadAccessor< Data<InVecCoord > > targetPositions(f_targetPositions);
    helper::ReadAccessor< Data<vector<unsigned> > > indices(f_indices);

	vector< Vector3 > points;

    for(unsigned i=0; i<indices.size(); i++ )
    {
        points.push_back( Vector3(TIn::getCPos(targetPositions[i]) ) );
        points.push_back( Vector3(TIn::getCPos(pos[indices[i]]) ) );
    }

    if( !_arrowSize )
        vparams->drawTool()->drawLines ( points, 1, _color );
    else
        for (unsigned int i=0; i<points.size()/2; ++i)
            vparams->drawTool()->drawArrow( points[2*i+1], points[2*i], _arrowSize, _color );

}

} // namespace mapping

} // namespace component

} // namespace sofa

#endif
<commit_msg>r11095/sofa : Fix: Rigid manipulation with CompliantAttachButtonSetting component<commit_after>/******************************************************************************
*       SOFA, Simulation Open-Framework Architecture, version 1.0 RC 1        *
*                (c) 2006-2011 MGH, INRIA, USTL, UJF, CNRS                    *
*                                                                             *
* This library is free software; you can redistribute it and/or modify it     *
* under the terms of the GNU Lesser General Public License as published by    *
* the Free Software Foundation; either version 2.1 of the License, or (at     *
* your option) any later version.                                             *
*                                                                             *
* This library 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 Lesser General Public License *
* for more details.                                                           *
*                                                                             *
* You should have received a copy of the GNU Lesser General Public License    *
* along with this library; if not, write to the Free Software Foundation,     *
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA.          *
*******************************************************************************
*                               SOFA :: Modules                               *
*                                                                             *
* Authors: The SOFA Team and external contributors (see Authors.txt)          *
*                                                                             *
* Contact information: contact@sofa-framework.org                             *
******************************************************************************/
#ifndef SOFA_COMPONENT_MAPPING_DistanceFromTargetMapping_INL
#define SOFA_COMPONENT_MAPPING_DistanceFromTargetMapping_INL

#include "DistanceFromTargetMapping.h"
#include <sofa/core/visual/VisualParams.h>
#include <iostream>
using std::cerr;
using std::endl;

namespace sofa
{

namespace component
{

namespace mapping
{

using namespace sofa::defaulttype;

template <class TIn, class TOut>
DistanceFromTargetMapping<TIn, TOut>::DistanceFromTargetMapping()
    : Inherit()
    , f_indices(initData(&f_indices, "indices", "Indices of the parent points"))
    , f_targetPositions(initData(&f_targetPositions, "targetPositions", "Positions to compute the distances from"))
    , f_restDistances(initData(&f_restDistances, "restLengths", "Rest lengths of the connections."))
    , _arrowSize(-1)
    , _color( 1,0,0,1 )
{
}

template <class TIn, class TOut>
DistanceFromTargetMapping<TIn, TOut>::~DistanceFromTargetMapping()
{
}

template <class TIn, class TOut>
void DistanceFromTargetMapping<TIn, TOut>::createTarget( unsigned index, InCoord position, Real distance)
{
    helper::WriteAccessor< Data< vector<Real> > > distances(f_restDistances);
    helper::WriteAccessor< Data<vector<unsigned> > > indices(f_indices);
    helper::WriteAccessor< Data<InVecCoord > > targetPositions(f_targetPositions);

    indices.push_back(index);
    targetPositions.push_back(position);
    distances.push_back(distance);

//    cerr<<"DistanceFromTargetMapping<TIn, TOut>::createTarget index " << index << " at position " << position << ", distance = " << distances << endl;
}

template <class TIn, class TOut>
void DistanceFromTargetMapping<TIn, TOut>::updateTarget( unsigned index, InCoord position)
{
    helper::WriteAccessor< Data<InVecCoord > > targetPositions(f_targetPositions);
    helper::WriteAccessor< Data<vector<unsigned> > > indices(f_indices);
//    cerr<<"DistanceFromTargetMapping<TIn, TOut>::updateTarget index " << index << " at position " << position << endl;

    // find the target with given index
    unsigned i=0; while(i<indices.size() && indices[i]!=index) i++;

    targetPositions[i] = position;
}

template <class TIn, class TOut>
void DistanceFromTargetMapping<TIn, TOut>::clear()
{
    helper::WriteAccessor< Data< vector<Real> > > distances(f_restDistances);
    helper::WriteAccessor< Data<InVecCoord > > positions(f_targetPositions);
    helper::WriteAccessor< Data<vector<unsigned> > > indices(f_indices);

    distances.clear();
    positions.clear();
    indices.clear();

    this->getToModel()->resize( 0 );
}

template <class TIn, class TOut>
void DistanceFromTargetMapping<TIn, TOut>::init()
{
    assert( f_indices.getValue().size()==f_targetPositions.getValue().size()) ;

    // unset distances are set to 0
    if(f_restDistances.getValue().size() != f_indices.getValue().size())
    {
        helper::WriteAccessor< Data< vector<Real> > > distances(f_restDistances);
        unsigned prevsize = distances.size();
        distances.resize( f_indices.getValue().size() );
        for(unsigned i=prevsize; i<distances.size(); i++ )
            distances[i] = 0;
    }

    this->getToModel()->resize( f_indices.getValue().size() );

    baseMatrices.resize( 1 );
    baseMatrices[0] = &jacobian;

    stiffnessBaseMatrices.resize(1);
    stiffnessBaseMatrices[0] = &K;

    this->Inherit::init();  // applies the mapping, so after the Data init
}

template <class TIn, class TOut>
void DistanceFromTargetMapping<TIn, TOut>::apply(const core::MechanicalParams * /*mparams*/ , Data<OutVecCoord>& dOut, const Data<InVecCoord>& dIn)
{
    helper::WriteAccessor< Data<OutVecCoord> >  out = dOut;
    helper::ReadAccessor< Data<InVecCoord> >  in = dIn;
    helper::WriteAccessor<Data<vector<Real> > > restDistances(f_restDistances);
    helper::ReadAccessor< Data<vector<unsigned> > > indices(f_indices);
    helper::ReadAccessor< Data<InVecCoord > > targetPositions(f_targetPositions);

    jacobian.resizeBlocks(out.size(),in.size());
    directions.resize(out.size());
    invlengths.resize(out.size());

    for(unsigned i=0; i<indices.size(); i++ )
    {
        InDeriv& gap = directions[i];
        TIn::setDPos(gap, TIn::getDPos(TIn::coordDifference(in[indices[i]],targetPositions[i]))); //Hack for Rigid template, TODO: create a specialized function.
        Real gapNorm = TIn::getDPos(gap).norm();
//        cerr<<"DistanceFromTargetMapping<TIn, TOut>::apply, gap = " << gap <<", norm = " << gapNorm << endl;
        out[i] = gapNorm - restDistances[i];  // output

        if( gapNorm>1.e-10 )
        {
            invlengths[i] = 1/gapNorm;
            gap *= invlengths[i];
        }
        else
        {
            invlengths[i] = 0;
            gap = InDeriv();
            gap[0]=1.0;  // arbitrary unit vector
        }

//        jacobian.beginRow(i);
        for(unsigned j=0; j<Nout; j++)
        {
            for(unsigned k=0; k<Nin; k++ )
            {
                jacobian.insertBack( i*Nout+j, indices[i]*Nin+k, gap[k] );
//                jacobian.add( i*Nout+j, indices[i]*Nin+k, gap[k] );
            }
        }

    }
//    cerr<<"DistanceFromTargetMapping<TIn, TOut>::apply, in = " << in << endl;
//    cerr<<"DistanceFromTargetMapping<TIn, TOut>::apply, target positions = " << positions << endl;
//    cerr<<"DistanceFromTargetMapping<TIn, TOut>::apply, out = " << out << endl;

    jacobian.compress();
//    cerr<<"DistanceFromTargetMapping<TIn, TOut>::apply, jacobian: "<<endl<< jacobian << endl;

}

template <class TIn, class TOut>
void DistanceFromTargetMapping<TIn, TOut>::applyJ(const core::MechanicalParams * /*mparams*/ , Data<OutVecDeriv>& dOut, const Data<InVecDeriv>& dIn)
{
    if( jacobian.rowSize() > 0 )
        jacobian.mult(dOut,dIn);
}

template <class TIn, class TOut>
void DistanceFromTargetMapping<TIn, TOut>::applyJT(const core::MechanicalParams * /*mparams*/ , Data<InVecDeriv>& dIn, const Data<OutVecDeriv>& dOut)
{
    if( jacobian.rowSize() > 0 )
        jacobian.addMultTranspose(dIn,dOut);
}

template <class TIn, class TOut>
void DistanceFromTargetMapping<TIn, TOut>::applyJT(const core::ConstraintParams*, Data<InMatrixDeriv>& , const Data<OutMatrixDeriv>& )
{
    //    cerr<<"DistanceFromTargetMapping<TIn, TOut>::applyJT does nothing " << endl;
}

template <class TIn, class TOut>
void DistanceFromTargetMapping<TIn, TOut>::applyDJT(const core::MechanicalParams* mparams, core::MultiVecDerivId parentDfId, core::ConstMultiVecDerivId )
{
    helper::WriteAccessor<Data<InVecDeriv> > parentForce (*parentDfId[this->fromModel.get(mparams)].write());
    helper::ReadAccessor<Data<InVecDeriv> > parentDisplacement (*mparams->readDx(this->fromModel));  // parent displacement
    Real kfactor = mparams->kFactor();
    helper::ReadAccessor<Data<OutVecDeriv> > childForce (*mparams->readF(this->toModel));
    helper::ReadAccessor< Data<vector<unsigned> > > indices(f_indices);

    for(unsigned i=0; i<indices.size(); i++ )
    {
        Mat<Nin,Nin,Real> b;  // = (I - uu^T)
        for(unsigned j=0; j<Nin; j++)
        {
            for(unsigned k=0; k<Nin; k++)
            {
                if( j==k )
                    b[j][k] = 1. - directions[i][j]*directions[i][k];
                else
                    b[j][k] =    - directions[i][j]*directions[i][k];
            }
        }
        b *= childForce[i][0] * invlengths[i] * kfactor;  // (I - uu^T)*f/l*kfactor     do not forget kfactor !
        // note that computing a block is not efficient here, but it would makes sense for storing a stiffness matrix

        InDeriv dx = parentDisplacement[indices[i]];
        InDeriv df;
        for(unsigned j=0; j<Nin; j++)
        {
            for(unsigned k=0; k<Nin; k++)
            {
                df[j]+=b[j][k]*dx[k];
            }
        }
       // InDeriv df = b*dx;
        parentForce[indices[i]] += df;
//        cerr<<"DistanceFromTargetMapping<TIn, TOut>::applyDJT, df = " << df << endl;
    }
}

template <class TIn, class TOut>
const sofa::defaulttype::BaseMatrix* DistanceFromTargetMapping<TIn, TOut>::getJ()
{
    return &jacobian;
}

template <class TIn, class TOut>
const vector<sofa::defaulttype::BaseMatrix*>* DistanceFromTargetMapping<TIn, TOut>::getJs()
{
    return &baseMatrices;
}

template <class TIn, class TOut>
const vector<defaulttype::BaseMatrix*>* DistanceFromTargetMapping<TIn, TOut>::getKs()
{
//    helper::ReadAccessor<Data<OutVecDeriv> > childForce (*this->toModel->read(core::ConstVecDerivId::force()));
    const OutVecDeriv& childForce = this->toModel->readForces().ref();
    helper::ReadAccessor< Data<vector<unsigned> > > indices(f_indices);
    helper::ReadAccessor<Data<InVecCoord> > in (*this->fromModel->read(core::ConstVecCoordId::position()));

    K.resizeBlocks(in.size(),in.size());
    for(size_t i=0; i<indices.size(); i++)
    {
        size_t idx = indices[i];

        Mat<Nin,Nin,Real> b;  // = (I - uu^T)
        for(unsigned j=0; j<Nin; j++)
        {
            for(unsigned k=0; k<Nin; k++)
            {
                if( j==k )
                    b[j][k] = 1. - directions[i][j]*directions[i][k];
                else
                    b[j][k] =    - directions[i][j]*directions[i][k];
            }
        }
        b *= childForce[i][0] * invlengths[i];  // (I - uu^T)*f/l

//        std::cerr<<SOFA_CLASS_METHOD<<childForce[i][0]<<std::endl;

        K.beginBlockRow(idx);
        K.createBlock(idx,b);
        K.endBlockRow();
    }
    K.compress();

    return &stiffnessBaseMatrices;
}

template <class TIn, class TOut>
void DistanceFromTargetMapping<TIn, TOut>::draw(const core::visual::VisualParams* vparams)
{
    if( _arrowSize<0 ) return;

    typename core::behavior::MechanicalState<In>::ReadVecCoord pos = this->getFromModel()->readPositions();
    helper::ReadAccessor< Data<InVecCoord > > targetPositions(f_targetPositions);
    helper::ReadAccessor< Data<vector<unsigned> > > indices(f_indices);

	vector< Vector3 > points;

    for(unsigned i=0; i<indices.size(); i++ )
    {
        points.push_back( Vector3(TIn::getCPos(targetPositions[i]) ) );
        points.push_back( Vector3(TIn::getCPos(pos[indices[i]]) ) );
    }

    if( !_arrowSize )
        vparams->drawTool()->drawLines ( points, 1, _color );
    else
        for (unsigned int i=0; i<points.size()/2; ++i)
            vparams->drawTool()->drawArrow( points[2*i+1], points[2*i], _arrowSize, _color );

}

} // namespace mapping

} // namespace component

} // namespace sofa

#endif
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2012,2013 Renard Wellnitz
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <jni.h>
#include "image_processing.h"
#include <cstring>
#include "android/bitmap.h"
#include "allheaders.h"
#include <sstream>
#include <iostream>
#include <pthread.h>
#include <cmath>
#include "pageseg.h"
#include "PixBlurDetect.h"
#include "pixFunc.hpp"
#include "combine_pixa.h"
#include "ProgressCallback.h"
#include <fcntl.h>
#include <sstream>
#include <cmath>

using namespace std;

#ifdef __cplusplus
extern "C" {
#endif  /* __cplusplus */

    static jmethodID onProgressImage, onProgressText, onLayoutElements;
    static jfieldID field_mNativeData;
    static JavaVM* g_vm;

    class native_data_t : public ProgressCallback{

    public:
        virtual void sendMessage(int message) {
            JNIEnv *env;
            bool needDetach = false;
            // double check it's all ok
            int getEnvStat = g_vm->GetEnv((void **) &env, JNI_VERSION_1_6);
            if (getEnvStat == JNI_EDETACHED) {
                LOGW("GetEnv: not attached");
                needDetach = true;
                if (g_vm->AttachCurrentThread(&env, NULL) != 0) {
                    LOGE("Failed to attach");
                    return;
                }
            }

            env->CallVoidMethod(cachedObject, onProgressText, message);

            if (env->ExceptionCheck()) {
                env->ExceptionDescribe();
            }

            if (needDetach) {
                g_vm->DetachCurrentThread();
            }
        }

        virtual void sendPix(Pix* pix) {
            JNIEnv *env;
            bool needDetach = false;
            // double check it's all ok
            int getEnvStat = g_vm->GetEnv((void **) &env, JNI_VERSION_1_6);
            if (getEnvStat == JNI_EDETACHED) {
                LOGW("GetEnv: not attached");
                needDetach = true;
                if (g_vm->AttachCurrentThread(&env, NULL) != 0) {
                    LOGE("Failed to attach");
                    return;
                }
            }

            env->CallVoidMethod(cachedObject, onProgressImage, (jlong) pix);

            if (env->ExceptionCheck()) {
                env->ExceptionDescribe();
            }

            if (needDetach) {
                g_vm->DetachCurrentThread();
            }
        }

        jobject cachedObject;

        ~native_data_t(){
            JNIEnv *env;
            bool needDetach = false;
            int getEnvStat = g_vm->GetEnv((void **) &env, JNI_VERSION_1_6);
            if (getEnvStat == JNI_EDETACHED) {
                LOGW("GetEnv: not attached");
                needDetach = true;
                if (g_vm->AttachCurrentThread(&env, NULL) != 0) {
                    LOGE("Failed to attach");
                    return;
                }
            }

            env->DeleteGlobalRef(cachedObject);

            if (needDetach) {
                g_vm->DetachCurrentThread();
            }

        }
    };

    static inline native_data_t * get_native_data(JNIEnv *env, jobject object) {
        return (native_data_t *) (env->GetLongField(object, field_mNativeData));
    }

    jint JNI_OnLoad(JavaVM* vm, void* reserved) {
        g_vm = vm;
        return JNI_VERSION_1_6;
    }

    void Java_com_googlecode_tesseract_android_NativeBinding_nativeClassInit(JNIEnv *env, jobject _thiz) {
        jclass cls = env->FindClass("com/googlecode/tesseract/android/NativeBinding");
        onProgressImage = env->GetMethodID(cls, "onProgressImage", "(J)V");
        onProgressText = env->GetMethodID(cls, "onProgressText", "(I)V");
        onLayoutElements = env->GetMethodID(cls, "onLayoutElements", "(JJ)V");
        field_mNativeData = env->GetFieldID(cls, "mNativeData", "J");
    }

    void JNI_OnUnload(JavaVM *vm, void *reserved) {
    }

    void Java_com_googlecode_tesseract_android_NativeBinding_nativeConstruct(JNIEnv* env, jobject object) {

        native_data_t *nat = new native_data_t;

        nat->cachedObject = env->NewGlobalRef(object);

        env->SetLongField(object, field_mNativeData, (jlong) nat);
    }

    void Java_com_googlecode_tesseract_android_NativeBinding_nativeDestruct(JNIEnv* env, jobject object) {
        native_data_t *nat = (native_data_t *) (env->GetLongField(object, field_mNativeData));
        delete nat;
    }

    jlongArray Java_com_googlecode_tesseract_android_NativeBinding_combineSelectedPixa(JNIEnv *env, jobject thiz, jlong nativePixaText, jlong nativePixaImage, jintArray selectedTexts, jintArray selectedImages) {
        LOGV(__FUNCTION__);
        Pixa *pixaTexts = (PIXA *) nativePixaText;
        Pixa *pixaImages = (PIXA *) nativePixaImage;
        jint* textindexes = env->GetIntArrayElements(selectedTexts, NULL);
        jsize textCount = env->GetArrayLength(selectedTexts);
        jint* imageindexes = env->GetIntArrayElements(selectedImages, NULL);
        jsize imageCount = env->GetArrayLength(selectedImages);

        Pix* pixFinal;
        Pix* pixOcr;
        Boxa* boxaColumns;

        native_data_t *nat = get_native_data(env, thiz);

        combineSelectedPixa(pixaTexts, pixaImages, textindexes, textCount, imageindexes, imageCount, nat, &pixFinal, &pixOcr, &boxaColumns, false);
        nat->sendPix(pixFinal);

        jlongArray result;
        result = env->NewLongArray(3);
        if (result == NULL) {
            return NULL; /* out of memory error thrown */
        }

        jlong fill[3];
        fill[0] = (jlong) pixFinal;
        fill[1] = (jlong) pixOcr;
        fill[2] = (jlong) boxaColumns;
        // move from the temp structure to the java structure
        env->SetLongArrayRegion(result, 0, 3, fill);

        env->ReleaseIntArrayElements(selectedTexts, textindexes, 0);
        env->ReleaseIntArrayElements(selectedImages, imageindexes, 0);
        return result;
    }

    jint Java_com_googlecode_tesseract_android_NativeBinding_nativeAnalyseLayout(JNIEnv *env, jobject thiz, jint nativePix) {
        LOGV(__FUNCTION__);
        Pix *pixOrg = (PIX *) nativePix;
        Pix* pixTextlines = NULL;
        Pixa* pixaTexts, *pixaImages;
        Pix* pixb, *pixhm;

        native_data_t *nat = get_native_data(env, thiz);

        nat->sendMessage(MESSAGE_IMAGE_DETECTION);

        pixb = pixPrepareLayoutAnalysis(pixOrg, nat);

        nat->sendPix(pixb);

        segmentComplexLayout(pixOrg, NULL, pixb, &pixaImages, &pixaTexts, nat, false);

        pixDestroy(&pixb);

        env->CallVoidMethod(thiz, onLayoutElements, (jlong)pixaTexts, (jlong)pixaImages);

        return (jint) 0;
    }

    jobject Java_com_renard_ocr_cropimage_image_1processing_Blur_nativeBlurDetect(JNIEnv *env, jobject thiz, jlong nativePix) {
        Pix *pixOrg = (PIX *) nativePix;
        PixBlurDetect blurDetector(false);
        l_float32 blurValue;
        L_TIMER timer = startTimerNested();
        Box* maxBlurLoc = NULL;
        Pix* pixBlended = blurDetector.makeBlurIndicator(pixOrg,&blurValue, &maxBlurLoc);
        l_int32 w,h,x,y;
        boxGetGeometry(maxBlurLoc,&x,&y,&w,&h);
        //pixRenderBox(pixBlended,maxBlurLoc,2,L_SET_PIXELS);
        //create result
        jclass cls = env->FindClass("com/renard/ocr/cropimage/image_processing/BlurDetectionResult");
        jmethodID constructor = env->GetMethodID(cls, "<init>", "(JDJ)V");
        return env->NewObject(cls, constructor, (jlong)pixBlended, (jdouble)blurValue, (jlong)maxBlurLoc);
    }

    jlong Java_com_googlecode_tesseract_android_NativeBinding_nativeOCRBook(JNIEnv *env, jobject thiz, jlong nativePix) {
        LOGV(__FUNCTION__);
        Pix *pixOrg = (PIX *) nativePix;

        native_data_t *nat = get_native_data(env, thiz);

        Pix* pixText = pixPrepareForOcr(pixOrg, nat);

        return (jlong)pixText;

    }

#ifdef __cplusplus
}
#endif  /* __cplusplus */
<commit_msg>fix: crash when using column detection<commit_after>/*
 * Copyright (C) 2012,2013 Renard Wellnitz
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <jni.h>
#include "image_processing.h"
#include <cstring>
#include "android/bitmap.h"
#include "allheaders.h"
#include <sstream>
#include <iostream>
#include <pthread.h>
#include <cmath>
#include "pageseg.h"
#include "PixBlurDetect.h"
#include "pixFunc.hpp"
#include "combine_pixa.h"
#include "ProgressCallback.h"
#include <fcntl.h>
#include <sstream>
#include <cmath>

using namespace std;

#ifdef __cplusplus
extern "C" {
#endif  /* __cplusplus */

    static jmethodID onProgressImage, onProgressText, onLayoutElements;
    static jfieldID field_mNativeData;
    static JavaVM* g_vm;

    class native_data_t : public ProgressCallback{

    public:
        virtual void sendMessage(int message) {
            JNIEnv *env;
            bool needDetach = false;
            // double check it's all ok
            int getEnvStat = g_vm->GetEnv((void **) &env, JNI_VERSION_1_6);
            if (getEnvStat == JNI_EDETACHED) {
                LOGW("GetEnv: not attached");
                needDetach = true;
                if (g_vm->AttachCurrentThread(&env, NULL) != 0) {
                    LOGE("Failed to attach");
                    return;
                }
            }

            env->CallVoidMethod(cachedObject, onProgressText, message);

            if (env->ExceptionCheck()) {
                env->ExceptionDescribe();
            }

            if (needDetach) {
                g_vm->DetachCurrentThread();
            }
        }

        virtual void sendPix(Pix* pix) {
            JNIEnv *env;
            bool needDetach = false;
            // double check it's all ok
            int getEnvStat = g_vm->GetEnv((void **) &env, JNI_VERSION_1_6);
            if (getEnvStat == JNI_EDETACHED) {
                LOGW("GetEnv: not attached");
                needDetach = true;
                if (g_vm->AttachCurrentThread(&env, NULL) != 0) {
                    LOGE("Failed to attach");
                    return;
                }
            }

            env->CallVoidMethod(cachedObject, onProgressImage, (jlong) pix);

            if (env->ExceptionCheck()) {
                env->ExceptionDescribe();
            }

            if (needDetach) {
                g_vm->DetachCurrentThread();
            }
        }

        jobject cachedObject;

        ~native_data_t(){
            JNIEnv *env;
            bool needDetach = false;
            int getEnvStat = g_vm->GetEnv((void **) &env, JNI_VERSION_1_6);
            if (getEnvStat == JNI_EDETACHED) {
                LOGW("GetEnv: not attached");
                needDetach = true;
                if (g_vm->AttachCurrentThread(&env, NULL) != 0) {
                    LOGE("Failed to attach");
                    return;
                }
            }

            env->DeleteGlobalRef(cachedObject);

            if (needDetach) {
                g_vm->DetachCurrentThread();
            }

        }
    };

    static inline native_data_t * get_native_data(JNIEnv *env, jobject object) {
        return (native_data_t *) (env->GetLongField(object, field_mNativeData));
    }

    jint JNI_OnLoad(JavaVM* vm, void* reserved) {
        g_vm = vm;
        return JNI_VERSION_1_6;
    }

    void Java_com_googlecode_tesseract_android_NativeBinding_nativeClassInit(JNIEnv *env, jobject _thiz) {
        jclass cls = env->FindClass("com/googlecode/tesseract/android/NativeBinding");
        onProgressImage = env->GetMethodID(cls, "onProgressImage", "(J)V");
        onProgressText = env->GetMethodID(cls, "onProgressText", "(I)V");
        onLayoutElements = env->GetMethodID(cls, "onLayoutElements", "(JJ)V");
        field_mNativeData = env->GetFieldID(cls, "mNativeData", "J");
    }

    void JNI_OnUnload(JavaVM *vm, void *reserved) {
    }

    void Java_com_googlecode_tesseract_android_NativeBinding_nativeConstruct(JNIEnv* env, jobject object) {

        native_data_t *nat = new native_data_t;

        nat->cachedObject = env->NewGlobalRef(object);

        env->SetLongField(object, field_mNativeData, (jlong) nat);
    }

    void Java_com_googlecode_tesseract_android_NativeBinding_nativeDestruct(JNIEnv* env, jobject object) {
        native_data_t *nat = (native_data_t *) (env->GetLongField(object, field_mNativeData));
        delete nat;
    }

    jlongArray Java_com_googlecode_tesseract_android_NativeBinding_combineSelectedPixa(JNIEnv *env, jobject thiz, jlong nativePixaText, jlong nativePixaImage, jintArray selectedTexts, jintArray selectedImages) {
        LOGV(__FUNCTION__);
        Pixa *pixaTexts = (PIXA *) nativePixaText;
        Pixa *pixaImages = (PIXA *) nativePixaImage;
        jint* textindexes = env->GetIntArrayElements(selectedTexts, NULL);
        jsize textCount = env->GetArrayLength(selectedTexts);
        jint* imageindexes = env->GetIntArrayElements(selectedImages, NULL);
        jsize imageCount = env->GetArrayLength(selectedImages);

        Pix* pixFinal;
        Pix* pixOcr;
        Boxa* boxaColumns;

        native_data_t *nat = get_native_data(env, thiz);

        combineSelectedPixa(pixaTexts, pixaImages, textindexes, textCount, imageindexes, imageCount, nat, &pixFinal, &pixOcr, &boxaColumns, false);
        nat->sendPix(pixFinal);

        jlongArray result;
        result = env->NewLongArray(3);
        if (result == NULL) {
            return NULL; /* out of memory error thrown */
        }

        jlong fill[3];
        fill[0] = (jlong) pixFinal;
        fill[1] = (jlong) pixOcr;
        fill[2] = (jlong) boxaColumns;
        // move from the temp structure to the java structure
        env->SetLongArrayRegion(result, 0, 3, fill);

        env->ReleaseIntArrayElements(selectedTexts, textindexes, 0);
        env->ReleaseIntArrayElements(selectedImages, imageindexes, 0);
        return result;
    }

    jint Java_com_googlecode_tesseract_android_NativeBinding_nativeAnalyseLayout(JNIEnv *env, jobject thiz, jlong nativePix) {
        LOGV(__FUNCTION__);
        Pix *pixOrg = (PIX *) nativePix;
        Pix* pixTextlines = NULL;
        Pixa* pixaTexts, *pixaImages;
        Pix* pixb, *pixhm;

        native_data_t *nat = get_native_data(env, thiz);

        nat->sendMessage(MESSAGE_IMAGE_DETECTION);

        pixb = pixPrepareLayoutAnalysis(pixOrg, nat);

        nat->sendPix(pixb);

        segmentComplexLayout(pixOrg, NULL, pixb, &pixaImages, &pixaTexts, nat, false);

        pixDestroy(&pixb);

        env->CallVoidMethod(thiz, onLayoutElements, (jlong)pixaTexts, (jlong)pixaImages);

        return (jint) 0;
    }

    jobject Java_com_renard_ocr_cropimage_image_1processing_Blur_nativeBlurDetect(JNIEnv *env, jobject thiz, jlong nativePix) {
        Pix *pixOrg = (PIX *) nativePix;
        PixBlurDetect blurDetector(false);
        l_float32 blurValue;
        L_TIMER timer = startTimerNested();
        Box* maxBlurLoc = NULL;
        Pix* pixBlended = blurDetector.makeBlurIndicator(pixOrg,&blurValue, &maxBlurLoc);
        l_int32 w,h,x,y;
        boxGetGeometry(maxBlurLoc,&x,&y,&w,&h);
        //pixRenderBox(pixBlended,maxBlurLoc,2,L_SET_PIXELS);
        //create result
        jclass cls = env->FindClass("com/renard/ocr/cropimage/image_processing/BlurDetectionResult");
        jmethodID constructor = env->GetMethodID(cls, "<init>", "(JDJ)V");
        return env->NewObject(cls, constructor, (jlong)pixBlended, (jdouble)blurValue, (jlong)maxBlurLoc);
    }

    jlong Java_com_googlecode_tesseract_android_NativeBinding_nativeOCRBook(JNIEnv *env, jobject thiz, jlong nativePix) {
        LOGV(__FUNCTION__);
        Pix *pixOrg = (PIX *) nativePix;

        native_data_t *nat = get_native_data(env, thiz);

        Pix* pixText = pixPrepareForOcr(pixOrg, nat);

        return (jlong)pixText;

    }

#ifdef __cplusplus
}
#endif  /* __cplusplus */
<|endoftext|>


<commit_before>/*

Copyright (c) 2003, Arvid Norberg
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 author nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

*/

#include "libtorrent/pch.hpp"

#ifdef _WIN32
// windows part
#include "libtorrent/utf8.hpp"

#include <io.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>

#ifndef _MODE_T_
typedef int mode_t;
#endif

#ifdef UNICODE
#include "libtorrent/storage.hpp"
#endif

#else
// unix part
#define _FILE_OFFSET_BITS 64
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <errno.h>

#include <boost/static_assert.hpp>
// make sure the _FILE_OFFSET_BITS define worked
// on this platform
BOOST_STATIC_ASSERT(sizeof(lseek(0, 0, 0)) >= 8);

#endif

#include <boost/filesystem/operations.hpp>
#include "libtorrent/file.hpp"
#include <sstream>

#ifndef O_BINARY
#define O_BINARY 0
#endif

#ifndef O_RANDOM
#define O_RANDOM 0
#endif

#ifdef UNICODE
#include "libtorrent/storage.hpp"
#endif

namespace
{
	enum { mode_in = 1, mode_out = 2 };

	mode_t map_open_mode(int m)
	{
		if (m == (mode_in | mode_out)) return O_RDWR | O_CREAT | O_BINARY | O_RANDOM;
		if (m == mode_out) return O_WRONLY | O_CREAT | O_BINARY | O_RANDOM;
		if (m == mode_in) return O_RDONLY | O_BINARY | O_RANDOM;
		assert(false);
		return 0;
	}

#ifdef WIN32
	std::string utf8_native(std::string const& s)
	{
		try
		{
			std::wstring ws;
			libtorrent::utf8_wchar(s, ws);
			std::size_t size = wcstombs(0, ws.c_str(), 0);
			if (size == std::size_t(-1)) return s;
			std::string ret;
			ret.resize(size);
			size = wcstombs(&ret[0], ws.c_str(), size + 1);
			if (size == wchar_t(-1)) return s;
			ret.resize(size);
			return ret;
		}
		catch(std::exception)
		{
			return s;
		}
	}
#else
	std::string utf8_native(std::string const& s)
	{
		return s;
	}
#endif

}

namespace libtorrent
{

	namespace fs = boost::filesystem;

	const file::open_mode file::in(mode_in);
	const file::open_mode file::out(mode_out);

	const file::seek_mode file::begin(1);
	const file::seek_mode file::end(2);

	struct file::impl
	{
		impl()
			: m_fd(-1)
			, m_open_mode(0)
		{}

		impl(fs::path const& path, int mode)
			: m_fd(-1)
			, m_open_mode(0)
		{
			open(path, mode);
		}

		~impl()
		{
			close();
		}

		void open(fs::path const& path, int mode)
		{
			assert(path.is_complete());
			close();
#if defined(_WIN32) && defined(UNICODE)
			std::wstring wpath(safe_convert(path.native_file_string()));
			m_fd = ::_wopen(
				wpath.c_str()
				, map_open_mode(mode)
				, S_IREAD | S_IWRITE);
#else
#ifdef _WIN32
			m_fd = ::_open(
#else
			m_fd = ::open(
#endif
				utf8_native(path.native_file_string()).c_str()
				, map_open_mode(mode)
#ifdef _WIN32
				, S_IREAD | S_IWRITE);
#else
				, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
#endif
#endif
			if (m_fd == -1)
			{
				std::stringstream msg;
				msg << "open failed: '" << path.native_file_string() << "'. "
					<< strerror(errno);
				throw file_error(msg.str());
			}
			m_open_mode = mode;
		}

		void close()
		{
			if (m_fd == -1) return;

#ifdef _WIN32
			::_close(m_fd);
#else
			::close(m_fd);
#endif
			m_fd = -1;
			m_open_mode = 0;
		}

		size_type read(char* buf, size_type num_bytes)
		{
			assert(m_open_mode & mode_in);
			assert(m_fd != -1);

#ifdef _WIN32
			size_type ret = ::_read(m_fd, buf, num_bytes);
#else
			size_type ret = ::read(m_fd, buf, num_bytes);
#endif
			if (ret == -1)
			{
				std::stringstream msg;
				msg << "read failed: " << strerror(errno);
				throw file_error(msg.str());
			}
			return ret;
		}

		size_type write(const char* buf, size_type num_bytes)
		{
			assert(m_open_mode & mode_out);
			assert(m_fd != -1);

			// TODO: Test this a bit more, what happens with random failures in
			// the files?
//			if ((rand() % 100) > 80)
//				throw file_error("debug");

#ifdef _WIN32
			size_type ret = ::_write(m_fd, buf, num_bytes);
#else
			size_type ret = ::write(m_fd, buf, num_bytes);
#endif
			if (ret == -1)
			{
				std::stringstream msg;
				msg << "write failed: " << strerror(errno);
				throw file_error(msg.str());
			}
			return ret;
		}

		void set_size(size_type s)
		{
			size_type pos = tell();
			// Only set size if current file size not equals s.
			// 2 as "m" argument is to be sure seek() sets SEEK_END on
			// all compilers.
			if(s != seek(0, 2))
			{
				seek(s - 1);
				char dummy = 0;
				read(&dummy, 1);
				seek(s - 1);
				write(&dummy, 1);
			}
			seek(pos);
		}

		size_type seek(size_type offset, int m = 1)
		{
			assert(m_open_mode);
			assert(m_fd != -1);

			int seekdir = (m == 1)?SEEK_SET:SEEK_END;
#ifdef _WIN32
			size_type ret = _lseeki64(m_fd, offset, seekdir);
#else
			size_type ret = lseek(m_fd, offset, seekdir);
#endif

			// For some strange reason this fails
			// on win32. Use windows specific file
			// wrapper instead.
			if (ret == -1)
			{
				std::stringstream msg;
				msg << "seek failed: '" << strerror(errno)
					<< "' fd: " << m_fd
					<< " offset: " << offset
					<< " seekdir: " << seekdir;
				throw file_error(msg.str());
			}
			return ret;
		}

		size_type tell()
		{
			assert(m_open_mode);
			assert(m_fd != -1);

#ifdef _WIN32
			return _telli64(m_fd);
#else
			return lseek(m_fd, 0, SEEK_CUR);
#endif
		}

		int m_fd;
		int m_open_mode;
	};

	// pimpl forwardings

	file::file() : m_impl(new impl()) {}

	file::file(fs::path const& p, file::open_mode m)
		: m_impl(new impl(p, m.m_mask))
	{}

	file::~file() {}

	void file::open(fs::path const& p, file::open_mode m)
	{
		m_impl->open(p, m.m_mask);
	}

	void file::close()
	{
		m_impl->close();
	}

	size_type file::write(const char* buf, size_type num_bytes)
	{
		return m_impl->write(buf, num_bytes);
	}

	size_type file::read(char* buf, size_type num_bytes)
	{
		return m_impl->read(buf, num_bytes);
	}

	void file::set_size(size_type s)
	{
		m_impl->set_size(s);
	}

	size_type file::seek(size_type pos, file::seek_mode m)
	{
		return m_impl->seek(pos, m.m_val);
	}

	size_type file::tell()
	{
		return m_impl->tell();
	}

}
<commit_msg>changed to use ftruncate to allocate files<commit_after>/*

Copyright (c) 2003, Arvid Norberg
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 author nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

*/

#include "libtorrent/pch.hpp"

#ifdef _WIN32
// windows part
#include "libtorrent/utf8.hpp"

#include <io.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>

#ifndef _MODE_T_
typedef int mode_t;
#endif

#ifdef UNICODE
#include "libtorrent/storage.hpp"
#endif

#else
// unix part
#define _FILE_OFFSET_BITS 64
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <errno.h>

#include <boost/static_assert.hpp>
// make sure the _FILE_OFFSET_BITS define worked
// on this platform
BOOST_STATIC_ASSERT(sizeof(lseek(0, 0, 0)) >= 8);

#endif

#include <boost/filesystem/operations.hpp>
#include "libtorrent/file.hpp"
#include <sstream>

#ifndef O_BINARY
#define O_BINARY 0
#endif

#ifndef O_RANDOM
#define O_RANDOM 0
#endif

#ifdef UNICODE
#include "libtorrent/storage.hpp"
#endif

namespace
{
	enum { mode_in = 1, mode_out = 2 };

	mode_t map_open_mode(int m)
	{
		if (m == (mode_in | mode_out)) return O_RDWR | O_CREAT | O_BINARY | O_RANDOM;
		if (m == mode_out) return O_WRONLY | O_CREAT | O_BINARY | O_RANDOM;
		if (m == mode_in) return O_RDONLY | O_BINARY | O_RANDOM;
		assert(false);
		return 0;
	}

#ifdef WIN32
	std::string utf8_native(std::string const& s)
	{
		try
		{
			std::wstring ws;
			libtorrent::utf8_wchar(s, ws);
			std::size_t size = wcstombs(0, ws.c_str(), 0);
			if (size == std::size_t(-1)) return s;
			std::string ret;
			ret.resize(size);
			size = wcstombs(&ret[0], ws.c_str(), size + 1);
			if (size == wchar_t(-1)) return s;
			ret.resize(size);
			return ret;
		}
		catch(std::exception)
		{
			return s;
		}
	}
#else
	std::string utf8_native(std::string const& s)
	{
		return s;
	}
#endif

}

namespace libtorrent
{

	namespace fs = boost::filesystem;

	const file::open_mode file::in(mode_in);
	const file::open_mode file::out(mode_out);

	const file::seek_mode file::begin(1);
	const file::seek_mode file::end(2);

	struct file::impl
	{
		impl()
			: m_fd(-1)
			, m_open_mode(0)
		{}

		impl(fs::path const& path, int mode)
			: m_fd(-1)
			, m_open_mode(0)
		{
			open(path, mode);
		}

		~impl()
		{
			close();
		}

		void open(fs::path const& path, int mode)
		{
			assert(path.is_complete());
			close();
#if defined(_WIN32) && defined(UNICODE)
			std::wstring wpath(safe_convert(path.native_file_string()));
			m_fd = ::_wopen(
				wpath.c_str()
				, map_open_mode(mode)
				, S_IREAD | S_IWRITE);
#else
#ifdef _WIN32
			m_fd = ::_open(
#else
			m_fd = ::open(
#endif
				utf8_native(path.native_file_string()).c_str()
				, map_open_mode(mode)
#ifdef _WIN32
				, S_IREAD | S_IWRITE);
#else
				, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
#endif
#endif
			if (m_fd == -1)
			{
				std::stringstream msg;
				msg << "open failed: '" << path.native_file_string() << "'. "
					<< strerror(errno);
				throw file_error(msg.str());
			}
			m_open_mode = mode;
		}

		void close()
		{
			if (m_fd == -1) return;

#ifdef _WIN32
			::_close(m_fd);
#else
			::close(m_fd);
#endif
			m_fd = -1;
			m_open_mode = 0;
		}

		size_type read(char* buf, size_type num_bytes)
		{
			assert(m_open_mode & mode_in);
			assert(m_fd != -1);

#ifdef _WIN32
			size_type ret = ::_read(m_fd, buf, num_bytes);
#else
			size_type ret = ::read(m_fd, buf, num_bytes);
#endif
			if (ret == -1)
			{
				std::stringstream msg;
				msg << "read failed: " << strerror(errno);
				throw file_error(msg.str());
			}
			return ret;
		}

		size_type write(const char* buf, size_type num_bytes)
		{
			assert(m_open_mode & mode_out);
			assert(m_fd != -1);

			// TODO: Test this a bit more, what happens with random failures in
			// the files?
//			if ((rand() % 100) > 80)
//				throw file_error("debug");

#ifdef _WIN32
			size_type ret = ::_write(m_fd, buf, num_bytes);
#else
			size_type ret = ::write(m_fd, buf, num_bytes);
#endif
			if (ret == -1)
			{
				std::stringstream msg;
				msg << "write failed: " << strerror(errno);
				throw file_error(msg.str());
			}
			return ret;
		}

		void set_size(size_type s)
		{
#ifdef _WIN32
#error file.cpp is for posix systems only. use file_win.cpp on windows
#else
			if (ftruncate(m_fd, s) < 0)
			{
				std::stringstream msg;
				msg << "ftruncate failed: '" << strerror(errno);
				throw file_error(msg.str());
			}
#endif
		}

		size_type seek(size_type offset, int m = 1)
		{
			assert(m_open_mode);
			assert(m_fd != -1);

			int seekdir = (m == 1)?SEEK_SET:SEEK_END;
#ifdef _WIN32
			size_type ret = _lseeki64(m_fd, offset, seekdir);
#else
			size_type ret = lseek(m_fd, offset, seekdir);
#endif

			// For some strange reason this fails
			// on win32. Use windows specific file
			// wrapper instead.
			if (ret == -1)
			{
				std::stringstream msg;
				msg << "seek failed: '" << strerror(errno)
					<< "' fd: " << m_fd
					<< " offset: " << offset
					<< " seekdir: " << seekdir;
				throw file_error(msg.str());
			}
			return ret;
		}

		size_type tell()
		{
			assert(m_open_mode);
			assert(m_fd != -1);

#ifdef _WIN32
			return _telli64(m_fd);
#else
			return lseek(m_fd, 0, SEEK_CUR);
#endif
		}

		int m_fd;
		int m_open_mode;
	};

	// pimpl forwardings

	file::file() : m_impl(new impl()) {}

	file::file(fs::path const& p, file::open_mode m)
		: m_impl(new impl(p, m.m_mask))
	{}

	file::~file() {}

	void file::open(fs::path const& p, file::open_mode m)
	{
		m_impl->open(p, m.m_mask);
	}

	void file::close()
	{
		m_impl->close();
	}

	size_type file::write(const char* buf, size_type num_bytes)
	{
		return m_impl->write(buf, num_bytes);
	}

	size_type file::read(char* buf, size_type num_bytes)
	{
		return m_impl->read(buf, num_bytes);
	}

	void file::set_size(size_type s)
	{
		m_impl->set_size(s);
	}

	size_type file::seek(size_type pos, file::seek_mode m)
	{
		return m_impl->seek(pos, m.m_val);
	}

	size_type file::tell()
	{
		return m_impl->tell();
	}

}
<|endoftext|>