<commit_before>/*  -*-c++-*-
 *  Copyright (C) 2008 Cedric Pinson <cedric.pinson@plopbyte.net>
 *  Copyright (C) 2017 Julien Valentin <mp3butcher@hotmail.com>
 *
 * This library is open source and may be redistributed and/or modified under
 * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
 * (at your option) any later version.  The full license is in LICENSE file
 * included with this distribution, and on the openscenegraph.org website.
 *
 * 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
 * OpenSceneGraph Public License for more details.
 */

#include <osgAnimation/VertexInfluence>
#include <osgAnimation/RigGeometry>
#include <osgAnimation/BoneMapVisitor>
#include <osg/Notify>
#include <iostream>
#include <algorithm>
#include <set>

using namespace osgAnimation;

struct invweight_ordered
{
    inline bool operator() (const BoneWeight& bw1, const BoneWeight& bw2) const
    {
        if (bw1.second > bw2.second)return true;
        if (bw1.second < bw2.second)return false;
        return(bw1.first < bw2.first);
    }
};

void VertexInfluenceMap::normalize(unsigned int numvert)
{

    typedef std::pair<float, std::vector<float*> > PerVertWeights;
    std::vector<PerVertWeights > localstore;
    localstore.resize(numvert);
    for(VertexInfluenceMap::iterator mapit = this->begin(); mapit != this->end(); ++mapit)
    {
        IndexWeightList &curvecinf = mapit->second;
        for(IndexWeightList::iterator curinf = curvecinf.begin(); curinf != curvecinf.end(); ++curinf)
        {
            VertexIndexWeight& inf = *curinf;
            localstore[inf.first].first += inf.second;
            localstore[inf.first].second.push_back(&inf.second);

        }
    }
    unsigned int vertid = 0;
    for(std::vector<PerVertWeights >::iterator itvert = localstore.begin();
    itvert != localstore.end();
    ++itvert, ++vertid)
    {
        PerVertWeights & weights = *itvert;
        if(weights.first< 1e-4)
        {
            OSG_WARN << "VertexInfluenceMap::normalize warning the vertex " <<vertid << " seems to have 0 weight, skip normalize for this vertex" << std::endl;
        }
        else
        {
            float mult = 1.0/weights.first;
            for (std::vector<float*>::iterator itf = weights.second.begin(); itf != weights.second.end(); ++itf)
                **itf *= mult;
        }
    }

}
///remove weakest influences in order to fit targetted numbonepervertex
void VertexInfluenceMap::cullInfluenceCountPerVertex(unsigned int numbonepervertex,float minweight, bool renormalize)
{

    typedef std::set<BoneWeight, invweight_ordered >  BoneWeightOrdered;
    std::map<int, BoneWeightOrdered > tempVec2Bones;
    for(VertexInfluenceMap::iterator mapit = this->begin(); mapit != this->end(); ++mapit)
    {
        const std::string& bonename = mapit->first;
        IndexWeightList &curvecinf = mapit->second;
        for(IndexWeightList::iterator curinf = curvecinf.begin(); curinf != curvecinf.end(); ++curinf)
        {
            VertexIndexWeight& inf = *curinf;
            if( bonename.empty())
            {
                OSG_WARN << "VertexInfluenceSet::cullInfluenceCountPerVertex warning vertex " << inf.first << " is not assigned to a bone" << std::endl;
            }
            else if(inf.second>minweight)tempVec2Bones[inf.first].insert(BoneWeight(bonename, inf.second));
        }
    }
    this->clear();
    for( std::map<int,BoneWeightOrdered >::iterator mapit = tempVec2Bones.begin(); mapit != tempVec2Bones.end(); ++mapit)
    {
        BoneWeightOrdered& bwset = mapit->second;
        unsigned int newsize = numbonepervertex<bwset.size()?numbonepervertex:bwset.size();
        float sum = 0.0f;
        while(bwset.size()>newsize)bwset.erase(*bwset.rbegin());
        if(renormalize)
        {
            for(BoneWeightOrdered::iterator bwit = bwset.begin(); bwit != bwset.end(); ++bwit)
                sum += bwit->second;
            if(sum > 1e-4)
            {
                sum = 1.0f/sum;
                for(BoneWeightOrdered::iterator bwit = bwset.begin(); bwit != bwset.end(); ++bwit)
                {
                    VertexInfluence & inf = (*this)[bwit->first];
                    inf.push_back(VertexIndexWeight(mapit->first, bwit->second*sum));
                    inf.setName(bwit->first);
                }
            }
        }
        else
        {
            for(BoneWeightOrdered::iterator bwit = bwset.begin(); bwit != bwset.end(); ++bwit)
            {
                VertexInfluence & inf = (*this)[bwit->first];
                inf.push_back(VertexIndexWeight(mapit->first,bwit->second));
                inf.setName(bwit->first);
            }

        }
    }
}

void VertexInfluenceMap::computePerVertexInfluenceList(std::vector<BoneWeightList>& vertex2Bones,unsigned int numvert)const
{
    vertex2Bones.resize(numvert);
    for (osgAnimation::VertexInfluenceMap::const_iterator it = begin(); it != end(); ++it)
    {
        const IndexWeightList& inflist = it->second;
        if (it->first.empty())
        {
            OSG_WARN << "VertexInfluenceMap::computePerVertexInfluenceList contains unamed bone IndexWeightList" << std::endl;
        }
        for(IndexWeightList::const_iterator infit = inflist.begin(); infit != inflist.end(); ++infit)
        {
            const VertexIndexWeight &iw = *infit;
            const unsigned int &index = iw.first;
            const float &weight = iw.second;
            vertex2Bones[index].push_back(BoneWeight(it->first, weight));;
        }
    }
}

// sort by name and weight
struct SortByNameAndWeight : public std::less<BoneWeight>
{
    bool operator()(const BoneWeight& b0,
                    const BoneWeight& b1) const
    {
        if (b0.first < b1.first)
            return true;
        else if (b0.first > b1.first)
            return false;
        return (b0.second < b1.second);
    }
};

struct SortByBoneWeightList : public std::less<BoneWeightList>
{
    bool operator()(const BoneWeightList& b0,
                    const BoneWeightList& b1) const
    {
        if (b0.size() < b1.size())
            return true;
        else if (b0.size() > b1.size())
            return false;

        int size = b0.size();
        for (int i = 0; i < size; i++)
        {
            if (SortByNameAndWeight()(b0[i], b1[i]))
                return true;
            else if (SortByNameAndWeight()(b1[i], b0[i]))
                return false;
        }
        return false;
    }
};
void VertexInfluenceMap::computeMinimalVertexGroupList(std::vector<VertexGroup>& uniqVertexGroupList, unsigned int numvert) const
{
    uniqVertexGroupList.clear();
    std::vector<BoneWeightList> vertex2Bones;
    computePerVertexInfluenceList(vertex2Bones,numvert);
    typedef std::map<BoneWeightList,VertexGroup, SortByBoneWeightList> UnifyBoneGroup;
    UnifyBoneGroup unifyBuffer;

    unsigned int vertexID = 0;
    for (std::vector<BoneWeightList>::iterator it = vertex2Bones.begin(); it != vertex2Bones.end(); ++it,++vertexID)
    {
        BoneWeightList &boneweightlist = *it;
        // sort the vector to have a consistent key
        std::sort(boneweightlist.begin(), boneweightlist.end(), SortByNameAndWeight());
        // we use the vector<BoneWeight> as key to differentiate group
        UnifyBoneGroup::iterator result = unifyBuffer.find(boneweightlist);
        if (result == unifyBuffer.end())
            unifyBuffer[boneweightlist].setBoneWeights(boneweightlist);
        unifyBuffer[boneweightlist].vertIDs().push_back(vertexID);
    }
    if(vertex2Bones.size() == unifyBuffer.size())
    {
        OSG_WARN << "VertexInfluenceMap::computeMinimalVertexGroupList is useless no duplicate VertexGroup" << std::endl;
    }
    uniqVertexGroupList.reserve(unifyBuffer.size());
    for (UnifyBoneGroup::iterator it = unifyBuffer.begin(); it != unifyBuffer.end(); ++it)
    {
        uniqVertexGroupList.push_back(it->second);
    }
}

//Experimental Bone removal stuff
typedef std::vector<osgAnimation::RigGeometry*> RigList;
class CollectRigVisitor : public osg::NodeVisitor
{
public:
    META_NodeVisitor(osgAnimation, CollectRigVisitor)
    CollectRigVisitor();

    void apply(osg::Geometry& node);
    inline const RigList& getRigList() const{return _map;}

protected:
    RigList _map;
};

CollectRigVisitor::CollectRigVisitor() : osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN) {}

void CollectRigVisitor::apply(osg::Geometry& node)
{
    RigGeometry* rig = dynamic_cast<RigGeometry*>(&node);
    if ( rig )
        _map.push_back(rig);
}

bool recursiveisUsefull( Bone* bone, std::set<std::string> foundnames) {
    for(unsigned int i=0; i<bone->getNumChildren(); ++i) {
        Bone* child = dynamic_cast< Bone* >(bone->getChild(i));
        if(child){
            if( foundnames.find(child->getName()) != foundnames.end() )
                return true;
            if( recursiveisUsefull(child,foundnames) )
                return true;
        }
    }
    return false;
}

void VertexInfluenceMap::removeUnexpressedBones(Skeleton &skel) const
{
    BoneMapVisitor mapVisitor;
    skel.accept(mapVisitor);

    CollectRigVisitor rigvis;
    skel.accept(rigvis);

    RigList  rigs = rigvis.getRigList();
    BoneMap boneMap = mapVisitor.getBoneMap();

    unsigned int removed=0;
    Bone* child, *par;

    std::set<std::string> usebones;
    for(RigList::iterator rigit = rigs.begin(); rigit != rigs.end(); ++rigit) {
        for(VertexInfluenceMap::iterator mapit = (*rigit)->getInfluenceMap()->begin();
                mapit != (*rigit)->getInfluenceMap()->end();
                ++mapit) {
            usebones.insert((*mapit).first);
        }
    }

    for(BoneMap::iterator bmit = boneMap.begin(); bmit != boneMap.end();) {
        if(usebones.find(bmit->second->getName()) == usebones.end()) {
            if( !(par = bmit->second->getBoneParent()) )
            {
                ++bmit;
                continue;
            }

            Bone * bone2rm = bmit->second.get();

            if( recursiveisUsefull(bone2rm,usebones)) {
                ++bmit;
                continue;
            }

            ///Bone can be removed
            ++ removed;
            OSG_INFO<<"removing useless bone: "<< bone2rm->getName() <<std::endl;
            osg::NodeList nodes;

            for(unsigned int numchild = 0; numchild < bone2rm->getNumChildren(); numchild++)
            {
                if( (child = dynamic_cast<Bone*>(bone2rm->getChild(numchild))) )
                {
                    if(par!=child &&child!=bone2rm) {
                        par->addChild(child);
                        nodes.push_back(child);
                    }
                }
            }
            for(unsigned int i=0; i<nodes.size(); ++i)
                bone2rm->removeChild(nodes[i]);
            par->removeChild(bone2rm);

            ///rebuild bonemap after bone removal
            BoneMapVisitor mapVis ;
            skel.accept(mapVis);
            boneMap = mapVis.getBoneMap();
            bmit = boneMap.begin();

        }
        else ++bmit;
    }
    OSG_WARN<<"Number of bone removed "<<removed<<std::endl;

}
<commit_msg>Code readability improvements<commit_after>/*  -*-c++-*-
 *  Copyright (C) 2008 Cedric Pinson <cedric.pinson@plopbyte.net>
 *  Copyright (C) 2017 Julien Valentin <mp3butcher@hotmail.com>
 *
 * This library is open source and may be redistributed and/or modified under
 * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
 * (at your option) any later version.  The full license is in LICENSE file
 * included with this distribution, and on the openscenegraph.org website.
 *
 * 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
 * OpenSceneGraph Public License for more details.
 */

#include <osgAnimation/VertexInfluence>
#include <osgAnimation/RigGeometry>
#include <osgAnimation/BoneMapVisitor>
#include <osg/Notify>
#include <iostream>
#include <algorithm>
#include <set>

using namespace osgAnimation;

struct invweight_ordered
{
    inline bool operator() (const BoneWeight& bw1, const BoneWeight& bw2) const
    {
        if (bw1.second > bw2.second)return true;
        if (bw1.second < bw2.second)return false;
        return(bw1.first < bw2.first);
    }
};

void VertexInfluenceMap::normalize(unsigned int numvert)
{

    typedef std::pair<float, std::vector<float*> > PerVertWeights;
    std::vector<PerVertWeights > localstore;
    localstore.resize(numvert);
    for(VertexInfluenceMap::iterator mapit = this->begin(); mapit != this->end(); ++mapit)
    {
        IndexWeightList &curvecinf = mapit->second;
        for(IndexWeightList::iterator curinf = curvecinf.begin(); curinf != curvecinf.end(); ++curinf)
        {
            VertexIndexWeight& inf = *curinf;
            localstore[inf.first].first += inf.second;
            localstore[inf.first].second.push_back(&inf.second);

        }
    }

    unsigned int vertid = 0;
    for(std::vector<PerVertWeights >::iterator itvert = localstore.begin();
    itvert != localstore.end();
    ++itvert, ++vertid)
    {
        PerVertWeights & weights = *itvert;
        if(weights.first< 1e-4)
        {
            OSG_WARN << "VertexInfluenceMap::normalize warning the vertex " <<vertid << " seems to have 0 weight, skip normalize for this vertex" << std::endl;
        }
        else
        {
            float mult = 1.0/weights.first;
            for (std::vector<float*>::iterator itf = weights.second.begin(); itf != weights.second.end(); ++itf)
            {
                **itf *= mult;
            }
        }
    }

}
///remove weakest influences in order to fit targetted numbonepervertex
void VertexInfluenceMap::cullInfluenceCountPerVertex(unsigned int numbonepervertex,float minweight, bool renormalize)
{

    typedef std::set<BoneWeight, invweight_ordered >  BoneWeightOrdered;
    std::map<int, BoneWeightOrdered > tempVec2Bones;
    for(VertexInfluenceMap::iterator mapit = this->begin(); mapit != this->end(); ++mapit)
    {
        const std::string& bonename = mapit->first;
        IndexWeightList &curvecinf = mapit->second;
        for(IndexWeightList::iterator curinf = curvecinf.begin(); curinf != curvecinf.end(); ++curinf)
        {
            VertexIndexWeight& inf = *curinf;
            if( bonename.empty())
            {
                OSG_WARN << "VertexInfluenceSet::cullInfluenceCountPerVertex warning vertex " << inf.first << " is not assigned to a bone" << std::endl;
            }
            else if(inf.second>minweight)
            {
                tempVec2Bones[inf.first].insert(BoneWeight(bonename, inf.second));
            }
        }
    }
    this->clear();
    for( std::map<int,BoneWeightOrdered >::iterator mapit = tempVec2Bones.begin(); mapit != tempVec2Bones.end(); ++mapit)
    {
        BoneWeightOrdered& bwset = mapit->second;
        unsigned int newsize = numbonepervertex<bwset.size()?numbonepervertex:bwset.size();
        float sum = 0.0f;
        while(bwset.size()>newsize)bwset.erase(*bwset.rbegin());
        if(renormalize)
        {
            for(BoneWeightOrdered::iterator bwit = bwset.begin(); bwit != bwset.end(); ++bwit)
            {
                sum += bwit->second;
            }

            if(sum > 1e-4)
            {
                sum = 1.0f/sum;
                for(BoneWeightOrdered::iterator bwit = bwset.begin(); bwit != bwset.end(); ++bwit)
                {
                    VertexInfluence & inf = (*this)[bwit->first];
                    inf.push_back(VertexIndexWeight(mapit->first, bwit->second*sum));
                    inf.setName(bwit->first);
                }
            }
        }
        else
        {
            for(BoneWeightOrdered::iterator bwit = bwset.begin(); bwit != bwset.end(); ++bwit)
            {
                VertexInfluence & inf = (*this)[bwit->first];
                inf.push_back(VertexIndexWeight(mapit->first,bwit->second));
                inf.setName(bwit->first);
            }
        }
    }
}

void VertexInfluenceMap::computePerVertexInfluenceList(std::vector<BoneWeightList>& vertex2Bones,unsigned int numvert)const
{
    vertex2Bones.resize(numvert);
    for (osgAnimation::VertexInfluenceMap::const_iterator it = begin(); it != end(); ++it)
    {
        const IndexWeightList& inflist = it->second;
        if (it->first.empty())
        {
            OSG_WARN << "VertexInfluenceMap::computePerVertexInfluenceList contains unamed bone IndexWeightList" << std::endl;
        }

        for(IndexWeightList::const_iterator infit = inflist.begin(); infit != inflist.end(); ++infit)
        {
            const VertexIndexWeight &iw = *infit;
            const unsigned int &index = iw.first;
            const float &weight = iw.second;
            vertex2Bones[index].push_back(BoneWeight(it->first, weight));;
        }
    }
}

// sort by name and weight
struct SortByNameAndWeight : public std::less<BoneWeight>
{
    bool operator()(const BoneWeight& b0, const BoneWeight& b1) const
    {
        if (b0.first < b1.first)
            return true;
        else if (b0.first > b1.first)
            return false;

        return (b0.second < b1.second);
    }
};

struct SortByBoneWeightList : public std::less<BoneWeightList>
{
    bool operator()(const BoneWeightList& b0,
                    const BoneWeightList& b1) const
    {
        if (b0.size() < b1.size())
            return true;
        else if (b0.size() > b1.size())
            return false;

        int size = b0.size();
        for (int i = 0; i < size; i++)
        {
            if (SortByNameAndWeight()(b0[i], b1[i]))
                return true;
            else if (SortByNameAndWeight()(b1[i], b0[i]))
                return false;
        }
        return false;
    }
};
void VertexInfluenceMap::computeMinimalVertexGroupList(std::vector<VertexGroup>& uniqVertexGroupList, unsigned int numvert) const
{
    uniqVertexGroupList.clear();
    std::vector<BoneWeightList> vertex2Bones;
    computePerVertexInfluenceList(vertex2Bones,numvert);
    typedef std::map<BoneWeightList,VertexGroup, SortByBoneWeightList> UnifyBoneGroup;
    UnifyBoneGroup unifyBuffer;

    unsigned int vertexID = 0;
    for (std::vector<BoneWeightList>::iterator it = vertex2Bones.begin(); it != vertex2Bones.end(); ++it,++vertexID)
    {
        BoneWeightList &boneweightlist = *it;
        // sort the vector to have a consistent key
        std::sort(boneweightlist.begin(), boneweightlist.end(), SortByNameAndWeight());

        // we use the vector<BoneWeight> as key to differentiate group
        UnifyBoneGroup::iterator result = unifyBuffer.find(boneweightlist);
        if (result == unifyBuffer.end())
        {
            unifyBuffer[boneweightlist].setBoneWeights(boneweightlist);
        }

        unifyBuffer[boneweightlist].vertIDs().push_back(vertexID);
    }

    if(vertex2Bones.size() == unifyBuffer.size())
    {
        OSG_WARN << "VertexInfluenceMap::computeMinimalVertexGroupList is useless no duplicate VertexGroup" << std::endl;
    }

    uniqVertexGroupList.reserve(unifyBuffer.size());
    for (UnifyBoneGroup::iterator it = unifyBuffer.begin(); it != unifyBuffer.end(); ++it)
    {
        uniqVertexGroupList.push_back(it->second);
    }
}

//Experimental Bone removal stuff
typedef std::vector<osgAnimation::RigGeometry*> RigList;
class CollectRigVisitor : public osg::NodeVisitor
{
public:
    META_NodeVisitor(osgAnimation, CollectRigVisitor)
    CollectRigVisitor();

    void apply(osg::Geometry& node);
    inline const RigList& getRigList() const{return _map;}

protected:
    RigList _map;
};

CollectRigVisitor::CollectRigVisitor() : osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN) {}

void CollectRigVisitor::apply(osg::Geometry& node)
{
    RigGeometry* rig = dynamic_cast<RigGeometry*>(&node);
    if ( rig )
        _map.push_back(rig);
}

bool recursiveisUsefull( Bone* bone, std::set<std::string> foundnames)
{
    for(unsigned int i=0; i<bone->getNumChildren(); ++i)
    {
        Bone* child = dynamic_cast< Bone* >(bone->getChild(i));
        if(child)
        {
            if( foundnames.find(child->getName()) != foundnames.end() )
                return true;
            if( recursiveisUsefull(child,foundnames) )
                return true;
        }
    }
    return false;
}

void VertexInfluenceMap::removeUnexpressedBones(Skeleton &skel) const
{
    BoneMapVisitor mapVisitor;
    skel.accept(mapVisitor);

    CollectRigVisitor rigvis;
    skel.accept(rigvis);

    RigList  rigs = rigvis.getRigList();
    BoneMap boneMap = mapVisitor.getBoneMap();

    unsigned int removed=0;
    Bone* child, *par;

    std::set<std::string> usebones;
    for(RigList::iterator rigit = rigs.begin(); rigit != rigs.end(); ++rigit)
    {
        for(VertexInfluenceMap::iterator mapit = (*rigit)->getInfluenceMap()->begin();
            mapit != (*rigit)->getInfluenceMap()->end();
            ++mapit)
        {
            usebones.insert((*mapit).first);
        }
    }

    for(BoneMap::iterator bmit = boneMap.begin(); bmit != boneMap.end();)
    {
        if(usebones.find(bmit->second->getName()) == usebones.end())
        {
            if( !(par = bmit->second->getBoneParent()) )
            {
                ++bmit;
                continue;
            }

            Bone * bone2rm = bmit->second.get();

            if( recursiveisUsefull(bone2rm,usebones))
            {
                ++bmit;
                continue;
            }

            ///Bone can be removed
            ++ removed;
            OSG_INFO<<"removing useless bone: "<< bone2rm->getName() <<std::endl;
            osg::NodeList nodes;

            for(unsigned int numchild = 0; numchild < bone2rm->getNumChildren(); numchild++)
            {
                if( (child = dynamic_cast<Bone*>(bone2rm->getChild(numchild))) )
                {
                    if(par!=child &&child!=bone2rm) {
                        par->addChild(child);
                        nodes.push_back(child);
                    }
                }
            }
            for(unsigned int i=0; i<nodes.size(); ++i)
            {
                bone2rm->removeChild(nodes[i]);
            }
            par->removeChild(bone2rm);

            ///rebuild bonemap after bone removal
            BoneMapVisitor mapVis ;
            skel.accept(mapVis);
            boneMap = mapVis.getBoneMap();
            bmit = boneMap.begin();

        }
        else
        {
            ++bmit;
        }
    }
    OSG_WARN<<"Number of bone removed "<<removed<<std::endl;
}
<|endoftext|>


<commit_before>/*  -*-c++-*-
 *  Copyright (C) 2008 Cedric Pinson <cedric.pinson@plopbyte.net>
 *  Copyright (C) 2017 Julien Valentin <mp3butcher@hotmail.com>
 *
 * This library is open source and may be redistributed and/or modified under
 * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
 * (at your option) any later version.  The full license is in LICENSE file
 * included with this distribution, and on the openscenegraph.org website.
 *
 * 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
 * OpenSceneGraph Public License for more details.
 */

#include <osgAnimation/VertexInfluence>
#include <osgAnimation/RigGeometry>
#include <osgAnimation/BoneMapVisitor>
#include <osg/Notify>
#include <iostream>
#include <algorithm>
#include <set>

using namespace osgAnimation;

struct invweight_ordered
{
    inline bool operator() (const BoneWeight& bw1, const BoneWeight& bw2)
    {
        if (bw1.second > bw2.second)return true;
        if (bw1.second < bw2.second)return false;
        return(bw1.first < bw2.first);
    }
};

void VertexInfluenceMap::normalize(unsigned int numvert)
{

    typedef std::pair<float, std::vector<float*> > PerVertWeights;
    std::vector<PerVertWeights > localstore;
    localstore.resize(numvert);
    for(VertexInfluenceMap::iterator mapit = this->begin(); mapit != this->end(); ++mapit)
    {
        IndexWeightList &curvecinf = mapit->second;
        for(IndexWeightList::iterator curinf = curvecinf.begin(); curinf != curvecinf.end(); ++curinf)
        {
            VertexIndexWeight& inf = *curinf;
            localstore[inf.first].first += inf.second;
            localstore[inf.first].second.push_back(&inf.second);

        }
    }
    unsigned int vertid = 0;
    for(std::vector<PerVertWeights >::iterator itvert = localstore.begin();
    itvert != localstore.end();
    ++itvert, ++vertid)
    {
        PerVertWeights & weights = *itvert;
        if(weights.first< 1e-4)
        {
            OSG_WARN << "VertexInfluenceMap::normalize warning the vertex " <<vertid << " seems to have 0 weight, skip normalize for this vertex" << std::endl;
        }
        else
        {
            float mult = 1.0/weights.first;
            for (std::vector<float*>::iterator itf = weights.second.begin(); itf != weights.second.end(); ++itf)
                **itf *= mult;
        }
    }

}
///remove weakest influences in order to fit targetted numbonepervertex
void VertexInfluenceMap::cullInfluenceCountPerVertex(unsigned int numbonepervertex,float minweight, bool renormalize)
{

    typedef std::set<BoneWeight, invweight_ordered >  BoneWeightOrdered;
    std::map<int, BoneWeightOrdered > tempVec2Bones;
    for(VertexInfluenceMap::iterator mapit = this->begin(); mapit != this->end(); ++mapit)
    {
        const std::string& bonename = mapit->first;
        IndexWeightList &curvecinf = mapit->second;
        for(IndexWeightList::iterator curinf = curvecinf.begin(); curinf != curvecinf.end(); ++curinf)
        {
            VertexIndexWeight& inf = *curinf;
            if( bonename.empty())
            {
                OSG_WARN << "VertexInfluenceSet::cullInfluenceCountPerVertex warning vertex " << inf.first << " is not assigned to a bone" << std::endl;
            }
            else if(inf.second>minweight)tempVec2Bones[inf.first].insert(BoneWeight(bonename, inf.second));
        }
    }
    this->clear();
    for( std::map<int,BoneWeightOrdered >::iterator mapit = tempVec2Bones.begin(); mapit != tempVec2Bones.end(); ++mapit)
    {
        BoneWeightOrdered& bwset = mapit->second;
        unsigned int newsize = numbonepervertex<bwset.size()?numbonepervertex:bwset.size();
        float sum = 0.0f;
        while(bwset.size()>newsize)bwset.erase(*bwset.rbegin());
        if(renormalize)
        {
            for(BoneWeightOrdered::iterator bwit = bwset.begin(); bwit != bwset.end(); ++bwit)
                sum += bwit->second;
            if(sum > 1e-4)
            {
                sum = 1.0f/sum;
                for(BoneWeightOrdered::iterator bwit = bwset.begin(); bwit != bwset.end(); ++bwit)
                {
                    VertexInfluence & inf = (*this)[bwit->first];
                    inf.push_back(VertexIndexWeight(mapit->first, bwit->second*sum));
                    inf.setName(bwit->first);
                }
            }
        }
        else
        {
            for(BoneWeightOrdered::iterator bwit = bwset.begin(); bwit != bwset.end(); ++bwit)
            {
                VertexInfluence & inf = (*this)[bwit->first];
                inf.push_back(VertexIndexWeight(mapit->first,bwit->second));
                inf.setName(bwit->first);
            }

        }
    }
}

void VertexInfluenceMap::computePerVertexInfluenceList(std::vector<BoneWeightList>& vertex2Bones,unsigned int numvert)const
{
    vertex2Bones.resize(numvert);
    for (osgAnimation::VertexInfluenceMap::const_iterator it = begin(); it != end(); ++it)
    {
        const IndexWeightList& inflist = it->second;
        if (it->first.empty())
        {
            OSG_WARN << "VertexInfluenceMap::computePerVertexInfluenceList contains unamed bone IndexWeightList" << std::endl;
        }
        for(IndexWeightList::const_iterator infit = inflist.begin(); infit != inflist.end(); ++infit)
        {
            const VertexIndexWeight &iw = *infit;
            const unsigned int &index = iw.first;
            const float &weight = iw.second;
            vertex2Bones[index].push_back(BoneWeight(it->first, weight));;
        }
    }
}

// sort by name and weight
struct SortByNameAndWeight : public std::less<BoneWeight>
{
    bool operator()(const BoneWeight& b0,
                    const BoneWeight& b1) const
    {
        if (b0.first < b1.first)
            return true;
        else if (b0.first > b1.first)
            return false;
        return (b0.second < b1.second);
    }
};

struct SortByBoneWeightList : public std::less<BoneWeightList>
{
    bool operator()(const BoneWeightList& b0,
                    const BoneWeightList& b1) const
    {
        if (b0.size() < b1.size())
            return true;
        else if (b0.size() > b1.size())
            return false;

        int size = b0.size();
        for (int i = 0; i < size; i++)
        {
            if (SortByNameAndWeight()(b0[i], b1[i]))
                return true;
            else if (SortByNameAndWeight()(b1[i], b0[i]))
                return false;
        }
        return false;
    }
};
void VertexInfluenceMap::computeMinimalVertexGroupList(std::vector<VertexGroup>& uniqVertexGroupList, unsigned int numvert) const
{
    uniqVertexGroupList.clear();
    std::vector<BoneWeightList> vertex2Bones;
    computePerVertexInfluenceList(vertex2Bones,numvert);
    typedef std::map<BoneWeightList,VertexGroup, SortByBoneWeightList> UnifyBoneGroup;
    UnifyBoneGroup unifyBuffer;

    unsigned int vertexID = 0;
    for (std::vector<BoneWeightList>::iterator it = vertex2Bones.begin(); it != vertex2Bones.end(); ++it,++vertexID)
    {
        BoneWeightList &boneweightlist = *it;
        // sort the vector to have a consistent key
        std::sort(boneweightlist.begin(), boneweightlist.end(), SortByNameAndWeight());
        // we use the vector<BoneWeight> as key to differentiate group
        UnifyBoneGroup::iterator result = unifyBuffer.find(boneweightlist);
        if (result == unifyBuffer.end())
            unifyBuffer[boneweightlist].setBoneWeights(boneweightlist);
        unifyBuffer[boneweightlist].vertIDs().push_back(vertexID);
    }
    if(vertex2Bones.size() == unifyBuffer.size())
    {
        OSG_WARN << "VertexInfluenceMap::computeMinimalVertexGroupList is useless no duplicate VertexGroup" << std::endl;
    }
    uniqVertexGroupList.reserve(unifyBuffer.size());
    for (UnifyBoneGroup::iterator it = unifyBuffer.begin(); it != unifyBuffer.end(); ++it)
    {
        uniqVertexGroupList.push_back(it->second);
    }
}

//Experimental Bone removal stuff
typedef std::vector<osgAnimation::RigGeometry*> RigList;
class CollectRigVisitor : public osg::NodeVisitor
{
public:
    META_NodeVisitor(osgAnimation, CollectRigVisitor)
    CollectRigVisitor();

    void apply(osg::Geometry& node);
    inline const RigList& getRigList() const{return _map;}

protected:
    RigList _map;
};

CollectRigVisitor::CollectRigVisitor() : osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN) {}

void CollectRigVisitor::apply(osg::Geometry& node)
{
    RigGeometry* rig = dynamic_cast<RigGeometry*>(&node);
    if ( rig )
        _map.push_back(rig);
}

bool recursiveisUsefull( Bone* bone, std::set<std::string> foundnames) {
    for(unsigned int i=0; i<bone->getNumChildren(); ++i) {
        Bone* child = dynamic_cast< Bone* >(bone->getChild(i));
        if(child){
            if( foundnames.find(child->getName()) != foundnames.end() )
                return true;
            if( recursiveisUsefull(child,foundnames) )
                return true;
        }
    }
    return false;
}

void VertexInfluenceMap::removeUnexpressedBones(Skeleton &skel) const
{
    BoneMapVisitor mapVisitor;
    skel.accept(mapVisitor);

    CollectRigVisitor rigvis;
    skel.accept(rigvis);

    RigList  rigs = rigvis.getRigList();
    BoneMap boneMap = mapVisitor.getBoneMap();

    unsigned int removed=0;
    Bone* child, *par;

    std::set<std::string> usebones;
    for(RigList::iterator rigit = rigs.begin(); rigit != rigs.end(); ++rigit) {
        for(VertexInfluenceMap::iterator mapit = (*rigit)->getInfluenceMap()->begin();
                mapit != (*rigit)->getInfluenceMap()->end();
                ++mapit) {
            usebones.insert((*mapit).first);
        }
    }

    for(BoneMap::iterator bmit = boneMap.begin(); bmit != boneMap.end();) {
        if(usebones.find(bmit->second->getName()) == usebones.end()) {
            if( !(par = bmit->second->getBoneParent()) )
            {
                ++bmit;
                continue;
            }

            Bone * bone2rm = bmit->second.get();

            if( recursiveisUsefull(bone2rm,usebones)) {
                ++bmit;
                continue;
            }

            ///Bone can be removed
            ++ removed;
            OSG_INFO<<"removing useless bone: "<< bone2rm->getName() <<std::endl;
            osg::NodeList nodes;

            for(unsigned int numchild = 0; numchild < bone2rm->getNumChildren(); numchild++)
            {
                if( (child = dynamic_cast<Bone*>(bone2rm->getChild(numchild))) )
                {
                    if(par!=child &&child!=bone2rm) {
                        par->addChild(child);
                        nodes.push_back(child);
                    }
                }
            }
            for(unsigned int i=0; i<nodes.size(); ++i)
                bone2rm->removeChild(nodes[i]);
            par->removeChild(bone2rm);

            ///rebuild bonemap after bone removal
            BoneMapVisitor mapVis ;
            skel.accept(mapVis);
            boneMap = mapVis.getBoneMap();
            bmit = boneMap.begin();

        }
        else ++bmit;
    }
    OSG_WARN<<"Number of bone removed "<<removed<<std::endl;

}
<commit_msg>From Raymond de Vires, Windows build fix<commit_after>/*  -*-c++-*-
 *  Copyright (C) 2008 Cedric Pinson <cedric.pinson@plopbyte.net>
 *  Copyright (C) 2017 Julien Valentin <mp3butcher@hotmail.com>
 *
 * This library is open source and may be redistributed and/or modified under
 * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
 * (at your option) any later version.  The full license is in LICENSE file
 * included with this distribution, and on the openscenegraph.org website.
 *
 * 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
 * OpenSceneGraph Public License for more details.
 */

#include <osgAnimation/VertexInfluence>
#include <osgAnimation/RigGeometry>
#include <osgAnimation/BoneMapVisitor>
#include <osg/Notify>
#include <iostream>
#include <algorithm>
#include <set>

using namespace osgAnimation;

struct invweight_ordered
{
    inline bool operator() (const BoneWeight& bw1, const BoneWeight& bw2) const
    {
        if (bw1.second > bw2.second)return true;
        if (bw1.second < bw2.second)return false;
        return(bw1.first < bw2.first);
    }
};

void VertexInfluenceMap::normalize(unsigned int numvert)
{

    typedef std::pair<float, std::vector<float*> > PerVertWeights;
    std::vector<PerVertWeights > localstore;
    localstore.resize(numvert);
    for(VertexInfluenceMap::iterator mapit = this->begin(); mapit != this->end(); ++mapit)
    {
        IndexWeightList &curvecinf = mapit->second;
        for(IndexWeightList::iterator curinf = curvecinf.begin(); curinf != curvecinf.end(); ++curinf)
        {
            VertexIndexWeight& inf = *curinf;
            localstore[inf.first].first += inf.second;
            localstore[inf.first].second.push_back(&inf.second);

        }
    }
    unsigned int vertid = 0;
    for(std::vector<PerVertWeights >::iterator itvert = localstore.begin();
    itvert != localstore.end();
    ++itvert, ++vertid)
    {
        PerVertWeights & weights = *itvert;
        if(weights.first< 1e-4)
        {
            OSG_WARN << "VertexInfluenceMap::normalize warning the vertex " <<vertid << " seems to have 0 weight, skip normalize for this vertex" << std::endl;
        }
        else
        {
            float mult = 1.0/weights.first;
            for (std::vector<float*>::iterator itf = weights.second.begin(); itf != weights.second.end(); ++itf)
                **itf *= mult;
        }
    }

}
///remove weakest influences in order to fit targetted numbonepervertex
void VertexInfluenceMap::cullInfluenceCountPerVertex(unsigned int numbonepervertex,float minweight, bool renormalize)
{

    typedef std::set<BoneWeight, invweight_ordered >  BoneWeightOrdered;
    std::map<int, BoneWeightOrdered > tempVec2Bones;
    for(VertexInfluenceMap::iterator mapit = this->begin(); mapit != this->end(); ++mapit)
    {
        const std::string& bonename = mapit->first;
        IndexWeightList &curvecinf = mapit->second;
        for(IndexWeightList::iterator curinf = curvecinf.begin(); curinf != curvecinf.end(); ++curinf)
        {
            VertexIndexWeight& inf = *curinf;
            if( bonename.empty())
            {
                OSG_WARN << "VertexInfluenceSet::cullInfluenceCountPerVertex warning vertex " << inf.first << " is not assigned to a bone" << std::endl;
            }
            else if(inf.second>minweight)tempVec2Bones[inf.first].insert(BoneWeight(bonename, inf.second));
        }
    }
    this->clear();
    for( std::map<int,BoneWeightOrdered >::iterator mapit = tempVec2Bones.begin(); mapit != tempVec2Bones.end(); ++mapit)
    {
        BoneWeightOrdered& bwset = mapit->second;
        unsigned int newsize = numbonepervertex<bwset.size()?numbonepervertex:bwset.size();
        float sum = 0.0f;
        while(bwset.size()>newsize)bwset.erase(*bwset.rbegin());
        if(renormalize)
        {
            for(BoneWeightOrdered::iterator bwit = bwset.begin(); bwit != bwset.end(); ++bwit)
                sum += bwit->second;
            if(sum > 1e-4)
            {
                sum = 1.0f/sum;
                for(BoneWeightOrdered::iterator bwit = bwset.begin(); bwit != bwset.end(); ++bwit)
                {
                    VertexInfluence & inf = (*this)[bwit->first];
                    inf.push_back(VertexIndexWeight(mapit->first, bwit->second*sum));
                    inf.setName(bwit->first);
                }
            }
        }
        else
        {
            for(BoneWeightOrdered::iterator bwit = bwset.begin(); bwit != bwset.end(); ++bwit)
            {
                VertexInfluence & inf = (*this)[bwit->first];
                inf.push_back(VertexIndexWeight(mapit->first,bwit->second));
                inf.setName(bwit->first);
            }

        }
    }
}

void VertexInfluenceMap::computePerVertexInfluenceList(std::vector<BoneWeightList>& vertex2Bones,unsigned int numvert)const
{
    vertex2Bones.resize(numvert);
    for (osgAnimation::VertexInfluenceMap::const_iterator it = begin(); it != end(); ++it)
    {
        const IndexWeightList& inflist = it->second;
        if (it->first.empty())
        {
            OSG_WARN << "VertexInfluenceMap::computePerVertexInfluenceList contains unamed bone IndexWeightList" << std::endl;
        }
        for(IndexWeightList::const_iterator infit = inflist.begin(); infit != inflist.end(); ++infit)
        {
            const VertexIndexWeight &iw = *infit;
            const unsigned int &index = iw.first;
            const float &weight = iw.second;
            vertex2Bones[index].push_back(BoneWeight(it->first, weight));;
        }
    }
}

// sort by name and weight
struct SortByNameAndWeight : public std::less<BoneWeight>
{
    bool operator()(const BoneWeight& b0,
                    const BoneWeight& b1) const
    {
        if (b0.first < b1.first)
            return true;
        else if (b0.first > b1.first)
            return false;
        return (b0.second < b1.second);
    }
};

struct SortByBoneWeightList : public std::less<BoneWeightList>
{
    bool operator()(const BoneWeightList& b0,
                    const BoneWeightList& b1) const
    {
        if (b0.size() < b1.size())
            return true;
        else if (b0.size() > b1.size())
            return false;

        int size = b0.size();
        for (int i = 0; i < size; i++)
        {
            if (SortByNameAndWeight()(b0[i], b1[i]))
                return true;
            else if (SortByNameAndWeight()(b1[i], b0[i]))
                return false;
        }
        return false;
    }
};
void VertexInfluenceMap::computeMinimalVertexGroupList(std::vector<VertexGroup>& uniqVertexGroupList, unsigned int numvert) const
{
    uniqVertexGroupList.clear();
    std::vector<BoneWeightList> vertex2Bones;
    computePerVertexInfluenceList(vertex2Bones,numvert);
    typedef std::map<BoneWeightList,VertexGroup, SortByBoneWeightList> UnifyBoneGroup;
    UnifyBoneGroup unifyBuffer;

    unsigned int vertexID = 0;
    for (std::vector<BoneWeightList>::iterator it = vertex2Bones.begin(); it != vertex2Bones.end(); ++it,++vertexID)
    {
        BoneWeightList &boneweightlist = *it;
        // sort the vector to have a consistent key
        std::sort(boneweightlist.begin(), boneweightlist.end(), SortByNameAndWeight());
        // we use the vector<BoneWeight> as key to differentiate group
        UnifyBoneGroup::iterator result = unifyBuffer.find(boneweightlist);
        if (result == unifyBuffer.end())
            unifyBuffer[boneweightlist].setBoneWeights(boneweightlist);
        unifyBuffer[boneweightlist].vertIDs().push_back(vertexID);
    }
    if(vertex2Bones.size() == unifyBuffer.size())
    {
        OSG_WARN << "VertexInfluenceMap::computeMinimalVertexGroupList is useless no duplicate VertexGroup" << std::endl;
    }
    uniqVertexGroupList.reserve(unifyBuffer.size());
    for (UnifyBoneGroup::iterator it = unifyBuffer.begin(); it != unifyBuffer.end(); ++it)
    {
        uniqVertexGroupList.push_back(it->second);
    }
}

//Experimental Bone removal stuff
typedef std::vector<osgAnimation::RigGeometry*> RigList;
class CollectRigVisitor : public osg::NodeVisitor
{
public:
    META_NodeVisitor(osgAnimation, CollectRigVisitor)
    CollectRigVisitor();

    void apply(osg::Geometry& node);
    inline const RigList& getRigList() const{return _map;}

protected:
    RigList _map;
};

CollectRigVisitor::CollectRigVisitor() : osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN) {}

void CollectRigVisitor::apply(osg::Geometry& node)
{
    RigGeometry* rig = dynamic_cast<RigGeometry*>(&node);
    if ( rig )
        _map.push_back(rig);
}

bool recursiveisUsefull( Bone* bone, std::set<std::string> foundnames) {
    for(unsigned int i=0; i<bone->getNumChildren(); ++i) {
        Bone* child = dynamic_cast< Bone* >(bone->getChild(i));
        if(child){
            if( foundnames.find(child->getName()) != foundnames.end() )
                return true;
            if( recursiveisUsefull(child,foundnames) )
                return true;
        }
    }
    return false;
}

void VertexInfluenceMap::removeUnexpressedBones(Skeleton &skel) const
{
    BoneMapVisitor mapVisitor;
    skel.accept(mapVisitor);

    CollectRigVisitor rigvis;
    skel.accept(rigvis);

    RigList  rigs = rigvis.getRigList();
    BoneMap boneMap = mapVisitor.getBoneMap();

    unsigned int removed=0;
    Bone* child, *par;

    std::set<std::string> usebones;
    for(RigList::iterator rigit = rigs.begin(); rigit != rigs.end(); ++rigit) {
        for(VertexInfluenceMap::iterator mapit = (*rigit)->getInfluenceMap()->begin();
                mapit != (*rigit)->getInfluenceMap()->end();
                ++mapit) {
            usebones.insert((*mapit).first);
        }
    }

    for(BoneMap::iterator bmit = boneMap.begin(); bmit != boneMap.end();) {
        if(usebones.find(bmit->second->getName()) == usebones.end()) {
            if( !(par = bmit->second->getBoneParent()) )
            {
                ++bmit;
                continue;
            }

            Bone * bone2rm = bmit->second.get();

            if( recursiveisUsefull(bone2rm,usebones)) {
                ++bmit;
                continue;
            }

            ///Bone can be removed
            ++ removed;
            OSG_INFO<<"removing useless bone: "<< bone2rm->getName() <<std::endl;
            osg::NodeList nodes;

            for(unsigned int numchild = 0; numchild < bone2rm->getNumChildren(); numchild++)
            {
                if( (child = dynamic_cast<Bone*>(bone2rm->getChild(numchild))) )
                {
                    if(par!=child &&child!=bone2rm) {
                        par->addChild(child);
                        nodes.push_back(child);
                    }
                }
            }
            for(unsigned int i=0; i<nodes.size(); ++i)
                bone2rm->removeChild(nodes[i]);
            par->removeChild(bone2rm);

            ///rebuild bonemap after bone removal
            BoneMapVisitor mapVis ;
            skel.accept(mapVis);
            boneMap = mapVis.getBoneMap();
            bmit = boneMap.begin();

        }
        else ++bmit;
    }
    OSG_WARN<<"Number of bone removed "<<removed<<std::endl;

}
<|endoftext|>


<commit_before>#ifndef GUARD_handle_hpp
#define GUARD_handle_hpp

#include "sqloxx_exceptions.hpp"

namespace sqloxx
{

/**
 * Handle for handling business objects of type T where T is a class
 * derived from PersistentObject and is
 * managed via IdentityMap<T> to ensure only one instance of T exists in
 * memory at any one time, in relation to any given record in a given
 * database.
 *
 * @todo Testing and documentation.
 */
template <typename T>
class Handle
{
public:

	/** Construct a Handle<T> from a T*.
	 *
	 * @throws sqloxx::OverflowException if the maximum number
	 * of handles for this underlying instance of T has been reached.
	 * The circumstances under which this occurs depend on the
	 * implementation of T::notify_handle_construction(), but should
	 * be extremely rare.
	 *
	 * Exception safety: strong guarantee.
	 *
	 * @todo Testing.
	 */
	Handle(T* p_pointer);

	/**
	 * Preconditions:\n
	 * the object must have been managed
	 * throughout its life by (a single instance of) IdentityMap,
	 * and must only have ever been
	 * accessed via instances of Handle<Derived>; and\n
	 * The destructor of Derived must be non-throwing.
	 *
	 * Exception safety: nothrow guarantee, provided the
	 * preconditions are met.
	 *
	 * @todo Testing.
	 */
	~Handle();

	/**
	 * @throws sqloxx::OverflowException in the extremely unlikely
	 * event that the number of Handle instances pointing to the
	 * underlying instance of T is too large to be safely counted
	 * by the type PersistentObject<T, Connection>::HandleCounter.
	 *
	 * Exception safety: strong guarantee.
	 *
	 * @todo Testing.
	 */
	Handle(Handle const& rhs);

	/**
	 * @throws sqloxx::OverflowException in the extremely unlikely
	 * event that the number of Handle instances pointing to the
	 * underlying instance of T is too large to be safely counted
	 * by the type PersistentObject<T, Connection>::HandleCounter.
	 *
	 * Exception safety: strong guarantee.
	 *
	 * @todo Testing.
	 */
	Handle& operator=(Handle const& rhs);

	/**
	 * @return \e true if this Handle<T> is bound to some instance
	 * of T; otherwise returns \e false.
	 *
	 * Exception safety: nothrow guarantee.
	 *
	 * @todo Testing.
	 */
	operator bool() const;

	/**
	 * @todo Testing and documentation.
	 */
	T& operator*() const;

	/**
	 * @todo Testing and documentation.
	 */
	T* operator->() const;

private:
	T* m_pointer;
};

template <typename T>
Handle<T>::Handle(T* p_pointer):
	m_pointer(p_pointer)
{
	p_pointer->notify_handle_construction();
}

template <typename T>
Handle<T>::~Handle()
{
	m_pointer->notify_handle_destruction();
}

template <typename T>
Handle<T>::Handle(Handle const& rhs)
{
	m_pointer = rhs.m_pointer;
	m_pointer->notify_handle_copy_construction();
}

template <typename T>
Handle<T>&
Handle<T>::operator=(Handle const& rhs)
{
	// Strong guarantee, provided rhs has a valid pointer...
	rhs.m_pointer->notify_rhs_assignment_operation();

	// Nothrow guarantee, provided preconditions met, and
	// provided rhs has a valid pointer.
	m_pointer->notify_lhs_assignment_operation();

	m_pointer = rhs.m_pointer;  // nothrow

	return *this;  // throw, provided we have a valid pointer
}

template <typename T>
Handle<T>::operator bool() const
{
	return static_cast<bool>(m_pointer);  // nothrow
}

template <typename T>
T&
Handle<T>::operator*() const
{
	if (static_cast<bool>(m_pointer))  // nothrow
	{
		return *m_pointer;  // nothrow
	}
	throw (UnboundHandleException("Unbound Handle."));
}

template <typename T>
T*
Handle<T>::operator->() const
{
	if (static_cast<bool>(m_pointer))  // nothrow
	{
		return m_pointer;  // nothrow
	}
	throw (UnboundHandleException("Unbound Handle."));
}

}  // namespace sqloxx

#endif  // GUARD_handle_hpp
<commit_msg>Finished documentation of Handle<T>.<commit_after>#ifndef GUARD_handle_hpp
#define GUARD_handle_hpp

#include "sqloxx_exceptions.hpp"

namespace sqloxx
{

/**
 * Handle for handling business objects of type T where T is a class
 * derived from PersistentObject and is
 * managed via IdentityMap<T> to ensure only one instance of T exists in
 * memory at any one time, in relation to any given record in a given
 * database.
 *
 * @todo Testing.
 */
template <typename T>
class Handle
{
public:

	/** Construct a Handle<T> from a T*.
	 *
	 * @throws sqloxx::OverflowException if the maximum number
	 * of handles for this underlying instance of T has been reached.
	 * The circumstances under which this occurs depend on the
	 * implementation of T::notify_handle_construction(), but should
	 * be extremely rare.
	 *
	 * Exception safety: strong guarantee.
	 *
	 * @todo Testing.
	 */
	Handle(T* p_pointer);

	/**
	 * Preconditions:\n
	 * the object must have been managed
	 * throughout its life by (a single instance of) IdentityMap,
	 * and must only have ever been
	 * accessed via instances of Handle<Derived>; and\n
	 * The destructor of Derived must be non-throwing.
	 *
	 * Exception safety: nothrow guarantee, provided the
	 * preconditions are met.
	 *
	 * @todo Testing.
	 */
	~Handle();

	/**
	 * @throws sqloxx::OverflowException in the extremely unlikely
	 * event that the number of Handle instances pointing to the
	 * underlying instance of T is too large to be safely counted
	 * by the type PersistentObject<T, Connection>::HandleCounter.
	 *
	 * Exception safety: strong guarantee.
	 *
	 * @todo Testing.
	 */
	Handle(Handle const& rhs);

	/**
	 * @throws sqloxx::OverflowException in the extremely unlikely
	 * event that the number of Handle instances pointing to the
	 * underlying instance of T is too large to be safely counted
	 * by the type PersistentObject<T, Connection>::HandleCounter.
	 *
	 * Exception safety: strong guarantee.
	 *
	 * @todo Testing.
	 */
	Handle& operator=(Handle const& rhs);

	/**
	 * @returns \e true if this Handle<T> is bound to some instance
	 * of T; otherwise returns \e false.
	 *
	 * Exception safety: nothrow guarantee.
	 *
	 * @todo Testing.
	 */
	operator bool() const;

	/**
	 * @returns the instance of T that is handled by this Handle<T>.
	 *
	 * @throws UnboundHandleException if there is no instance of
	 * T bound to this Handle.
	 *
	 * Exception safety: strong guarantee.
	 *
	 * @todo Testing.
	 */
	T& operator*() const;

	/**
	 * Indirection operator analagous to operator*(), for
	 * accessing members of T via the underlying pointer.
	 *
	 * @throws UnboundHandleException if there is no instance
	 * of T bound to this Handle.
	 *
	 * Exception safety: strong guarantee.
	 *
	 * @todo Testing.
	 */
	T* operator->() const;

private:
	T* m_pointer;
};

template <typename T>
Handle<T>::Handle(T* p_pointer):
	m_pointer(p_pointer)
{
	p_pointer->notify_handle_construction();
}

template <typename T>
Handle<T>::~Handle()
{
	m_pointer->notify_handle_destruction();
}

template <typename T>
Handle<T>::Handle(Handle const& rhs)
{
	m_pointer = rhs.m_pointer;
	m_pointer->notify_handle_copy_construction();
}

template <typename T>
Handle<T>&
Handle<T>::operator=(Handle const& rhs)
{
	// Strong guarantee, provided rhs has a valid pointer...
	rhs.m_pointer->notify_rhs_assignment_operation();

	// Nothrow guarantee, provided preconditions met, and
	// provided rhs has a valid pointer.
	m_pointer->notify_lhs_assignment_operation();

	m_pointer = rhs.m_pointer;  // nothrow

	return *this;  // throw, provided we have a valid pointer
}

template <typename T>
Handle<T>::operator bool() const
{
	return static_cast<bool>(m_pointer);  // nothrow
}

template <typename T>
T&
Handle<T>::operator*() const
{
	if (static_cast<bool>(m_pointer))  // nothrow
	{
		return *m_pointer;  // nothrow
	}
	throw (UnboundHandleException("Unbound Handle."));
}

template <typename T>
T*
Handle<T>::operator->() const
{
	if (static_cast<bool>(m_pointer))  // nothrow
	{
		return m_pointer;  // nothrow
	}
	throw (UnboundHandleException("Unbound Handle."));
}

}  // namespace sqloxx

#endif  // GUARD_handle_hpp
<|endoftext|>


<commit_before>/******************************************************************************
 * $Id$
 *
 * Project:  libLAS - http://liblas.org - A BSD library for LAS format data.
 * Purpose:  LAS Dimension implementation for C++ libLAS
 * Author:   Howard Butler, hobu.inc@gmail.com
 *
 ******************************************************************************
 * Copyright (c) 2010, Howard Butler
 *
 * 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 Martin Isenburg or Iowa Department
 *       of Natural Resources 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 <pdal/Dimension.hpp>

#include <pdal/GlobalEnvironment.hpp>

#include <boost/algorithm/string.hpp>
#include <boost/uuid/string_generator.hpp>
#include <boost/uuid/random_generator.hpp>
#include <boost/uuid/uuid_io.hpp>
#include <map>

#include <time.h>
#include <cstdlib>

namespace pdal
{

Dimension::Dimension(std::string const& name,
                     dimension::Interpretation interpretation,
                     dimension::size_type sizeInBytes,
                     std::string description)
    : m_name(name)
    , m_flags(0)
    , m_endian(pdal::Endian_Little)
    , m_byteSize(sizeInBytes)
    , m_description(description)
    , m_min(0.0)
    , m_max(0.0)
    , m_numericScale(1.0)
    , m_numericOffset(0.0)
    , m_byteOffset(0)
    , m_position(-1)
    , m_interpretation(interpretation)
    , m_uuid(boost::uuids::nil_uuid())
    , m_namespace(std::string(""))
    , m_parentDimensionID(boost::uuids::nil_uuid())

{

    if (!m_name.size())
    {
        // Generate a random name from the time
        ::time_t seconds;
        ::time(&seconds);

        std::ostringstream oss;
        srand(static_cast<unsigned int>(seconds));
        oss << "unnamed" << rand();
        m_name = oss.str();

    }

}

/// copy constructor
Dimension::Dimension(Dimension const& other)
    : m_name(other.m_name)
    , m_flags(other.m_flags)
    , m_endian(other.m_endian)
    , m_byteSize(other.m_byteSize)
    , m_description(other.m_description)
    , m_min(other.m_min)
    , m_max(other.m_max)
    , m_numericScale(other.m_numericScale)
    , m_numericOffset(other.m_numericOffset)
    , m_byteOffset(other.m_byteOffset)
    , m_position(other.m_position)
    , m_interpretation(other.m_interpretation)
    , m_uuid(other.m_uuid)
    , m_namespace(other.m_namespace)
    , m_parentDimensionID(other.m_parentDimensionID)
{
    return;
}

/// assignment operator
Dimension& Dimension::operator=(Dimension const& rhs)
{
    if (&rhs != this)
    {
        m_name = rhs.m_name;
        m_flags = rhs.m_flags;
        m_endian = rhs.m_endian;
        m_byteSize = rhs.m_byteSize;
        m_description = rhs.m_description;
        m_min = rhs.m_min;
        m_max = rhs.m_max;
        m_numericScale = rhs.m_numericScale;
        m_numericOffset = rhs.m_numericOffset;
        m_byteOffset = rhs.m_byteOffset;
        m_position = rhs.m_position;
        m_interpretation = rhs.m_interpretation;
        m_uuid = rhs.m_uuid;
        m_namespace = rhs.m_namespace;
        m_parentDimensionID = rhs.m_parentDimensionID;
    }

    return *this;
}

bool Dimension::operator==(const Dimension& other) const
{
    if (boost::iequals(m_name, other.m_name) &&
            m_flags == other.m_flags &&
            m_endian == other.m_endian &&
            m_byteSize == other.m_byteSize &&
            boost::iequals(m_description, other.m_description) &&
            Utils::compare_approx(m_min, other.m_min, (std::numeric_limits<double>::min)()) &&
            Utils::compare_approx(m_max, other.m_max, (std::numeric_limits<double>::min)()) &&
            Utils::compare_approx(m_numericScale, other.m_numericScale, (std::numeric_limits<double>::min)()) &&
            Utils::compare_approx(m_numericOffset, other.m_numericOffset, (std::numeric_limits<double>::min)()) &&
            m_byteOffset == other.m_byteOffset &&
            m_position == other.m_position &&
            m_interpretation == other.m_interpretation &&
            m_uuid == other.m_uuid &&
            m_parentDimensionID == other.m_parentDimensionID
       )
    {
        return true;
    }

    return false;
}

bool Dimension::operator!=(const Dimension& other) const
{
    return !(*this==other);
}

boost::property_tree::ptree Dimension::toPTree() const
{
    using boost::property_tree::ptree;
    ptree dim;
    dim.put("name", getName());
    dim.put("namespace", getNamespace());
    dim.put("parent", getParent());
    dim.put("description", getDescription());
    dim.put("bytesize", getByteSize());

    std::string e("little");
    if (getEndianness() == Endian_Big)
        e = std::string("big");
    dim.put("endianness", e);

    dim.put("minimum", getMinimum());
    dim.put("maximum", getMaximum());
    dim.put("scale", getNumericScale());
    dim.put("offset", getNumericOffset());

    dim.put("scale", getNumericScale());

    dim.put("position", getPosition());
    dim.put("byteoffset", getByteOffset());
    dim.put("isIgnored", isIgnored());

    std::stringstream oss;

    dimension::id t =  getUUID();
    oss << t;

    dim.put("uuid", oss.str());
    return dim;
}

void Dimension::setUUID(std::string const& id)
{
    boost::uuids::string_generator gen;
    m_uuid = gen(id);
}

void Dimension::createUUID()
{
    // GlobalEnvironment& env = pdal::GlobalEnvironment::get();
    // boost::uuids::basic_random_generator<boost::mt19937> gen(env.getRNG());
    // m_uuid = gen();

    boost::mt19937 ran;
    boost::uuids::basic_random_generator<boost::mt19937> gen(&ran);
    m_uuid = gen();
}

void Dimension::dump() const
{
    std::cout << *this;
}

std::string Dimension::getInterpretationName() const
{
    std::ostringstream type;
    dimension::Interpretation t = getInterpretation();
    boost::uint32_t bytesize = getByteSize();

    switch (t)
    {
        case dimension::SignedByte:
            if (bytesize == 1)
                type << "int8_t";
            break;
        case dimension::UnsignedByte:
            if (bytesize == 1)
                type << "uint8_t";
            break;

        case dimension::SignedInteger:
            if (bytesize == 1)
                type << "int8_t";
            else if (bytesize == 2)
                type << "int16_t";
            else if (bytesize == 4)
                type << "int32_t";
            else if (bytesize == 8)
                type << "int64_t";
            else
                type << "unknown";
            break;
        case dimension::UnsignedInteger:
            if (bytesize == 1)
                type << "uint8_t";
            else if (bytesize == 2)
                type << "uint16_t";
            else if (bytesize == 4)
                type << "uint32_t";
            else if (bytesize == 8)
                type << "uint64_t";
            else
                type << "unknown";
            break;

        case dimension::Float:
            if (bytesize == 4)
                type << "float";
            else if (bytesize == 8)
                type << "double";
            else
                type << "unknown";
            break;

        case dimension::Pointer:
            type << "pointer";
            break;
        case dimension::Undefined:
            type << "unknown";
            break;
    }

    return type.str();
}

dimension::Interpretation Dimension::getInterpretation(std::string const& interpretation)
{

    if (boost::iequals(interpretation, "int8_t") ||
            boost::iequals(interpretation, "int8"))
        return dimension::SignedInteger;

    if (boost::iequals(interpretation, "uint8_t") ||
            boost::iequals(interpretation, "uint8"))
        return dimension::UnsignedInteger;

    if (boost::iequals(interpretation, "int16_t") ||
            boost::iequals(interpretation, "int16"))
        return dimension::SignedInteger;

    if (boost::iequals(interpretation, "uint16_t") ||
            boost::iequals(interpretation, "uint16"))
        return dimension::UnsignedInteger;

    if (boost::iequals(interpretation, "int32_t") ||
            boost::iequals(interpretation, "int32"))
        return dimension::SignedInteger;

    if (boost::iequals(interpretation, "uint32_t") ||
            boost::iequals(interpretation, "uint32"))
        return dimension::UnsignedInteger;

    if (boost::iequals(interpretation, "int64_t") ||
            boost::iequals(interpretation, "int64"))
        return dimension::SignedInteger;

    if (boost::iequals(interpretation, "uint64_t") ||
            boost::iequals(interpretation, "uint64"))
        return dimension::UnsignedInteger;

    if (boost::iequals(interpretation, "float"))
        return dimension::Float;

    if (boost::iequals(interpretation, "double"))
        return dimension::Float;

    return dimension::Undefined;
}

std::ostream& operator<<(std::ostream& os, pdal::Dimension const& d)
{
    using boost::property_tree::ptree;
    ptree tree = d.toPTree();

    std::string const name = tree.get<std::string>("name");
    std::string const ns = tree.get<std::string>("namespace");

    std::ostringstream quoted_name;
    if (ns.size())
        quoted_name << "'" << ns << "." << name << "'";
    else
        quoted_name << "'" << name << "'";
    std::ostringstream pad;
    std::string const& cur = quoted_name.str();
    std::string::size_type size = cur.size();
    std::string::size_type buffer(24);
    std::string::size_type pad_size = buffer - size;
    if (size > buffer)
        pad_size = 4;
    for (std::string::size_type i=0; i != pad_size; i++)
    {
        pad << " ";
    }
    os << quoted_name.str() << pad.str() <<" -- "<< " size: " << tree.get<boost::uint32_t>("bytesize");

    double scale = tree.get<double>("scale");
    boost::uint32_t precision = Utils::getStreamPrecision(scale);
    os.setf(std::ios_base::fixed, std::ios_base::floatfield);
    os.precision(precision);
    os << " scale: " << scale;

    double offset = tree.get<double>("offset");
    os << " offset: " << offset;

    os << " ignored: " << tree.get<bool>("isIgnored");

    os << " uid: " << tree.get<std::string>("uuid");
    os << " parent: " << tree.get<std::string>("parent");

    os << std::endl;

    return os;
}

} // namespace pdal
<commit_msg>attempt to use the global RNG again<commit_after>/******************************************************************************
 * $Id$
 *
 * Project:  libLAS - http://liblas.org - A BSD library for LAS format data.
 * Purpose:  LAS Dimension implementation for C++ libLAS
 * Author:   Howard Butler, hobu.inc@gmail.com
 *
 ******************************************************************************
 * Copyright (c) 2010, Howard Butler
 *
 * 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 Martin Isenburg or Iowa Department
 *       of Natural Resources 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 <pdal/Dimension.hpp>

#include <pdal/GlobalEnvironment.hpp>

#include <boost/algorithm/string.hpp>
#include <boost/uuid/string_generator.hpp>
#include <boost/uuid/random_generator.hpp>
#include <boost/uuid/uuid_io.hpp>
#include <map>

#include <time.h>
#include <cstdlib>

namespace pdal
{

Dimension::Dimension(std::string const& name,
                     dimension::Interpretation interpretation,
                     dimension::size_type sizeInBytes,
                     std::string description)
    : m_name(name)
    , m_flags(0)
    , m_endian(pdal::Endian_Little)
    , m_byteSize(sizeInBytes)
    , m_description(description)
    , m_min(0.0)
    , m_max(0.0)
    , m_numericScale(1.0)
    , m_numericOffset(0.0)
    , m_byteOffset(0)
    , m_position(-1)
    , m_interpretation(interpretation)
    , m_uuid(boost::uuids::nil_uuid())
    , m_namespace(std::string(""))
    , m_parentDimensionID(boost::uuids::nil_uuid())

{

    if (!m_name.size())
    {
        // Generate a random name from the time
        ::time_t seconds;
        ::time(&seconds);

        std::ostringstream oss;
        srand(static_cast<unsigned int>(seconds));
        oss << "unnamed" << rand();
        m_name = oss.str();

    }

}

/// copy constructor
Dimension::Dimension(Dimension const& other)
    : m_name(other.m_name)
    , m_flags(other.m_flags)
    , m_endian(other.m_endian)
    , m_byteSize(other.m_byteSize)
    , m_description(other.m_description)
    , m_min(other.m_min)
    , m_max(other.m_max)
    , m_numericScale(other.m_numericScale)
    , m_numericOffset(other.m_numericOffset)
    , m_byteOffset(other.m_byteOffset)
    , m_position(other.m_position)
    , m_interpretation(other.m_interpretation)
    , m_uuid(other.m_uuid)
    , m_namespace(other.m_namespace)
    , m_parentDimensionID(other.m_parentDimensionID)
{
    return;
}

/// assignment operator
Dimension& Dimension::operator=(Dimension const& rhs)
{
    if (&rhs != this)
    {
        m_name = rhs.m_name;
        m_flags = rhs.m_flags;
        m_endian = rhs.m_endian;
        m_byteSize = rhs.m_byteSize;
        m_description = rhs.m_description;
        m_min = rhs.m_min;
        m_max = rhs.m_max;
        m_numericScale = rhs.m_numericScale;
        m_numericOffset = rhs.m_numericOffset;
        m_byteOffset = rhs.m_byteOffset;
        m_position = rhs.m_position;
        m_interpretation = rhs.m_interpretation;
        m_uuid = rhs.m_uuid;
        m_namespace = rhs.m_namespace;
        m_parentDimensionID = rhs.m_parentDimensionID;
    }

    return *this;
}

bool Dimension::operator==(const Dimension& other) const
{
    if (boost::iequals(m_name, other.m_name) &&
            m_flags == other.m_flags &&
            m_endian == other.m_endian &&
            m_byteSize == other.m_byteSize &&
            boost::iequals(m_description, other.m_description) &&
            Utils::compare_approx(m_min, other.m_min, (std::numeric_limits<double>::min)()) &&
            Utils::compare_approx(m_max, other.m_max, (std::numeric_limits<double>::min)()) &&
            Utils::compare_approx(m_numericScale, other.m_numericScale, (std::numeric_limits<double>::min)()) &&
            Utils::compare_approx(m_numericOffset, other.m_numericOffset, (std::numeric_limits<double>::min)()) &&
            m_byteOffset == other.m_byteOffset &&
            m_position == other.m_position &&
            m_interpretation == other.m_interpretation &&
            m_uuid == other.m_uuid &&
            m_parentDimensionID == other.m_parentDimensionID
       )
    {
        return true;
    }

    return false;
}

bool Dimension::operator!=(const Dimension& other) const
{
    return !(*this==other);
}

boost::property_tree::ptree Dimension::toPTree() const
{
    using boost::property_tree::ptree;
    ptree dim;
    dim.put("name", getName());
    dim.put("namespace", getNamespace());
    dim.put("parent", getParent());
    dim.put("description", getDescription());
    dim.put("bytesize", getByteSize());

    std::string e("little");
    if (getEndianness() == Endian_Big)
        e = std::string("big");
    dim.put("endianness", e);

    dim.put("minimum", getMinimum());
    dim.put("maximum", getMaximum());
    dim.put("scale", getNumericScale());
    dim.put("offset", getNumericOffset());

    dim.put("scale", getNumericScale());

    dim.put("position", getPosition());
    dim.put("byteoffset", getByteOffset());
    dim.put("isIgnored", isIgnored());

    std::stringstream oss;

    dimension::id t =  getUUID();
    oss << t;

    dim.put("uuid", oss.str());
    return dim;
}

void Dimension::setUUID(std::string const& id)
{
    boost::uuids::string_generator gen;
    m_uuid = gen(id);
}

void Dimension::createUUID()
{
    GlobalEnvironment& env = pdal::GlobalEnvironment::get();
    boost::uuids::basic_random_generator<boost::mt19937> gen(env.getRNG());
    m_uuid = gen();

    // boost::mt19937 ran;
    // boost::uuids::basic_random_generator<boost::mt19937> gen(&ran);
    // m_uuid = gen();
    //
    // m_uuid = boost::uuids::random_generator()();
}

void Dimension::dump() const
{
    std::cout << *this;
}

std::string Dimension::getInterpretationName() const
{
    std::ostringstream type;
    dimension::Interpretation t = getInterpretation();
    boost::uint32_t bytesize = getByteSize();

    switch (t)
    {
        case dimension::SignedByte:
            if (bytesize == 1)
                type << "int8_t";
            break;
        case dimension::UnsignedByte:
            if (bytesize == 1)
                type << "uint8_t";
            break;

        case dimension::SignedInteger:
            if (bytesize == 1)
                type << "int8_t";
            else if (bytesize == 2)
                type << "int16_t";
            else if (bytesize == 4)
                type << "int32_t";
            else if (bytesize == 8)
                type << "int64_t";
            else
                type << "unknown";
            break;
        case dimension::UnsignedInteger:
            if (bytesize == 1)
                type << "uint8_t";
            else if (bytesize == 2)
                type << "uint16_t";
            else if (bytesize == 4)
                type << "uint32_t";
            else if (bytesize == 8)
                type << "uint64_t";
            else
                type << "unknown";
            break;

        case dimension::Float:
            if (bytesize == 4)
                type << "float";
            else if (bytesize == 8)
                type << "double";
            else
                type << "unknown";
            break;

        case dimension::Pointer:
            type << "pointer";
            break;
        case dimension::Undefined:
            type << "unknown";
            break;
    }

    return type.str();
}

dimension::Interpretation Dimension::getInterpretation(std::string const& interpretation)
{

    if (boost::iequals(interpretation, "int8_t") ||
            boost::iequals(interpretation, "int8"))
        return dimension::SignedInteger;

    if (boost::iequals(interpretation, "uint8_t") ||
            boost::iequals(interpretation, "uint8"))
        return dimension::UnsignedInteger;

    if (boost::iequals(interpretation, "int16_t") ||
            boost::iequals(interpretation, "int16"))
        return dimension::SignedInteger;

    if (boost::iequals(interpretation, "uint16_t") ||
            boost::iequals(interpretation, "uint16"))
        return dimension::UnsignedInteger;

    if (boost::iequals(interpretation, "int32_t") ||
            boost::iequals(interpretation, "int32"))
        return dimension::SignedInteger;

    if (boost::iequals(interpretation, "uint32_t") ||
            boost::iequals(interpretation, "uint32"))
        return dimension::UnsignedInteger;

    if (boost::iequals(interpretation, "int64_t") ||
            boost::iequals(interpretation, "int64"))
        return dimension::SignedInteger;

    if (boost::iequals(interpretation, "uint64_t") ||
            boost::iequals(interpretation, "uint64"))
        return dimension::UnsignedInteger;

    if (boost::iequals(interpretation, "float"))
        return dimension::Float;

    if (boost::iequals(interpretation, "double"))
        return dimension::Float;

    return dimension::Undefined;
}

std::ostream& operator<<(std::ostream& os, pdal::Dimension const& d)
{
    using boost::property_tree::ptree;
    ptree tree = d.toPTree();

    std::string const name = tree.get<std::string>("name");
    std::string const ns = tree.get<std::string>("namespace");

    std::ostringstream quoted_name;
    if (ns.size())
        quoted_name << "'" << ns << "." << name << "'";
    else
        quoted_name << "'" << name << "'";
    std::ostringstream pad;
    std::string const& cur = quoted_name.str();
    std::string::size_type size = cur.size();
    std::string::size_type buffer(24);
    std::string::size_type pad_size = buffer - size;
    if (size > buffer)
        pad_size = 4;
    for (std::string::size_type i=0; i != pad_size; i++)
    {
        pad << " ";
    }
    os << quoted_name.str() << pad.str() <<" -- "<< " size: " << tree.get<boost::uint32_t>("bytesize");

    double scale = tree.get<double>("scale");
    boost::uint32_t precision = Utils::getStreamPrecision(scale);
    os.setf(std::ios_base::fixed, std::ios_base::floatfield);
    os.precision(precision);
    os << " scale: " << scale;

    double offset = tree.get<double>("offset");
    os << " offset: " << offset;

    os << " ignored: " << tree.get<bool>("isIgnored");

    os << " uid: " << tree.get<std::string>("uuid");
    os << " parent: " << tree.get<std::string>("parent");

    os << std::endl;

    return os;
}

} // namespace pdal
<|endoftext|>


<commit_before>/*
Copyright (c), Helios
All rights reserved.

Distributed under a permissive license. See COPYING.txt for details.
*/

#include "stdafx.h"
#include "Exception.h"
#include <DeserializerStream.h>

Win32Exception::Win32Exception(DWORD error): error(error){
	std::stringstream stream;
	stream << "Win32 error: " << error;
	this->message = stream.str();
}

HresultException::HresultException(const char *context, HRESULT hres){
	std::stringstream stream;
	stream << context << " failed with error 0x"
		<< std::hex << std::setw(8) << std::setfill('0') << hres
		<< " (";
	{
		_com_error error(hres);
		for (auto p = error.ErrorMessage(); *p; p++)
			stream << ((unsigned)*p < 0x80 ? (char)*p : '?');
	}
	stream << ")";
	this->message = stream.str();
}

FileNotFoundException::FileNotFoundException(const path_t &path): path(path){
	this->message = "File not found: ";
	this->message += this->path.string();
}

CantOpenOutputFileException::CantOpenOutputFileException(const path_t &path): path(path){
	this->message = "Can't open output file: ";
	this->message += this->path.string();
}

UnableToObtainGuidException::UnableToObtainGuidException(const path_t &path): path(path){
	this->message = "Unable to obtain file system GUID: ";
	this->message += this->path.string();
}

DeserializationException::DeserializationException(int type){
	this->message = "DeserializationError: ";
	switch ((DeserializerStream::ErrorType)type){
		case DeserializerStream::ErrorType::UnexpectedEndOfFile:
			this->message += "Unexpected end of file.";
			break;
		default:
			throw InvalidSwitchVariableException();
	}
}
<commit_msg>More error types for DeserializationException.<commit_after>/*
Copyright (c), Helios
All rights reserved.

Distributed under a permissive license. See COPYING.txt for details.
*/

#include "stdafx.h"
#include "Exception.h"
#include <DeserializerStream.h>

Win32Exception::Win32Exception(DWORD error): error(error){
	std::stringstream stream;
	stream << "Win32 error: " << error;
	this->message = stream.str();
}

HresultException::HresultException(const char *context, HRESULT hres){
	std::stringstream stream;
	stream << context << " failed with error 0x"
		<< std::hex << std::setw(8) << std::setfill('0') << hres
		<< " (";
	{
		_com_error error(hres);
		for (auto p = error.ErrorMessage(); *p; p++)
			stream << ((unsigned)*p < 0x80 ? (char)*p : '?');
	}
	stream << ")";
	this->message = stream.str();
}

FileNotFoundException::FileNotFoundException(const path_t &path): path(path){
	this->message = "File not found: ";
	this->message += this->path.string();
}

CantOpenOutputFileException::CantOpenOutputFileException(const path_t &path): path(path){
	this->message = "Can't open output file: ";
	this->message += this->path.string();
}

UnableToObtainGuidException::UnableToObtainGuidException(const path_t &path): path(path){
	this->message = "Unable to obtain file system GUID: ";
	this->message += this->path.string();
}

DeserializationException::DeserializationException(int type){
	this->message = "DeserializationError: ";
	switch ((DeserializerStream::ErrorType)type){
		case DeserializerStream::ErrorType::UnexpectedEndOfFile:
			this->message += "Unexpected end of file.";
			break;
		case DeserializerStream::ErrorType::InconsistentSmartPointers:
			this->message += "Serialized stream uses smart pointers inconsistently.";
			break;
		case DeserializerStream::ErrorType::UnknownObjectId:
			this->message += "Serialized stream contains a reference to an unknown object.";
			break;
		case DeserializerStream::ErrorType::InvalidProgramState:
			this->message += "The program is in an unknown state.";
			break;
		case DeserializerStream::ErrorType::MainObjectNotSerializable:
			this->message += "The root object is not an instance of a Serializable subclass.";
			break;
		default:
			throw InvalidSwitchVariableException();
	}
}
<|endoftext|>


<commit_before>#include "Game/Game.h"

#include <string>
#include <vector>
#include <stdexcept>
#include <csignal>
#include <cassert>

#include "Players/Player.h"
#include "Players/Proxy_Player.h"
#include "Players/Outside_Communicator.h"
#include "Game/Board.h"
#include "Game/Clock.h"
#include "Game/Color.h"
#include "Game/Game_Result.h"
#include "Moves/Move.h"

#include "Utility/String.h"

Game_Result play_game(Board board,
                      Clock game_clock,
                      const Player& white,
                      const Player& black,
                      const std::string& event_name,
                      const std::string& location,
                      const std::string& pgn_file_name)
{
    if(game_clock.is_in_use() && board.whose_turn() != game_clock.running_for())
    {
        throw std::runtime_error("Board and Clock do not agree on whose turn it is.");
    }

    std::vector<const Move*> game_record;
    Game_Result result;

    game_clock.start();

    while( ! result.game_has_ended())
    {
        const auto& player = board.whose_turn() == Piece_Color::WHITE ? white : black;
        const auto& move_chosen = player.choose_move(board, game_clock);

        result = game_clock.punch(board);
        if( ! result.game_has_ended())
        {
            result = board.play_move(move_chosen);
            game_record.push_back(&move_chosen);
        }
    }

    game_clock.stop();
    board.print_game_record(game_record,
                            white,
                            black,
                            pgn_file_name,
                            result,
                            game_clock,
                            event_name,
                            location);
    return result;
}

void play_game_with_outsider(const Player& player,
                             const std::string& event_name,
                             const std::string& location,
                             const std::string& game_file_name)
{
    const auto outsider = connect_to_outside(player);

    signal(SIGINT, SIG_IGN);
    signal(SIGTERM, SIG_IGN);

    Board board;
    Clock clock;
    Game_Result game_result;
    std::vector<const Move*> game_record;
    auto player_color = Piece_Color::BLACK;
    auto print_game_record = true;

    while( ! game_result.exit_program())
    {
        while( ! game_result.game_has_ended())
        {
            game_result = outsider->setup_turn(board, clock, game_record, player);
            if(game_result.game_has_ended())
            {
                break;
            }
            outsider->listen(clock);
            print_game_record = true;

            player_color = board.whose_turn();
            const auto& chosen_move = player.choose_move(board, clock);
            clock.punch(board);

            game_result = outsider->handle_move(board, chosen_move, game_record);
        }

        outsider->log("Game ended with: " + game_result.ending_reason());
        if(print_game_record && ! game_file_name.empty())
        {
            clock.stop();
            const auto opponent_proxy = outsider->create_proxy_player();
            const Player& white = (player_color == Piece_Color::WHITE ? player : opponent_proxy);
            const Player& black = (player_color == Piece_Color::BLACK ? player : opponent_proxy);
            board.print_game_record(game_record,
                                    white, black,
                                    String::add_to_file_name(game_file_name, "-" + color_text(player_color)),
                                    game_result,
                                    clock,
                                    event_name,
                                    location);
            print_game_record = false;
        }
    }
}
<commit_msg>Revert "Put loop-ending conditions in the loop conditional"<commit_after>#include "Game/Game.h"

#include <string>
#include <vector>
#include <stdexcept>
#include <csignal>
#include <cassert>

#include "Players/Player.h"
#include "Players/Proxy_Player.h"
#include "Players/Outside_Communicator.h"
#include "Game/Board.h"
#include "Game/Clock.h"
#include "Game/Color.h"
#include "Game/Game_Result.h"
#include "Moves/Move.h"

#include "Utility/String.h"

Game_Result play_game(Board board,
                      Clock game_clock,
                      const Player& white,
                      const Player& black,
                      const std::string& event_name,
                      const std::string& location,
                      const std::string& pgn_file_name)
{
    if(game_clock.is_in_use() && board.whose_turn() != game_clock.running_for())
    {
        throw std::runtime_error("Board and Clock do not agree on whose turn it is.");
    }

    std::vector<const Move*> game_record;
    Game_Result result;

    game_clock.start();

    while( ! result.game_has_ended())
    {
        const auto& player = board.whose_turn() == Piece_Color::WHITE ? white : black;
        const auto& move_chosen = player.choose_move(board, game_clock);

        result = game_clock.punch(board);
        if( ! result.game_has_ended())
        {
            result = board.play_move(move_chosen);
            game_record.push_back(&move_chosen);
        }
    }

    game_clock.stop();
    board.print_game_record(game_record,
                            white,
                            black,
                            pgn_file_name,
                            result,
                            game_clock,
                            event_name,
                            location);
    return result;
}

void play_game_with_outsider(const Player& player,
                             const std::string& event_name,
                             const std::string& location,
                             const std::string& game_file_name)
{
    const auto outsider = connect_to_outside(player);

    signal(SIGINT, SIG_IGN);
    signal(SIGTERM, SIG_IGN);

    Board board;
    Clock clock;
    Game_Result game_result;
    std::vector<const Move*> game_record;
    auto player_color = Piece_Color::BLACK;
    auto print_game_record = true;

    while(true)
    {
        while(true)
        {
            game_result = outsider->setup_turn(board, clock, game_record, player);
            if(game_result.game_has_ended())
            {
                break;
            }
            outsider->listen(clock);
            print_game_record = true;

            player_color = board.whose_turn();
            const auto& chosen_move = player.choose_move(board, clock);
            clock.punch(board);

            game_result = outsider->handle_move(board, chosen_move, game_record);
            if(game_result.game_has_ended())
            {
                break;
            }
        }

        outsider->log("Game ended with: " + game_result.ending_reason());
        if(print_game_record && ! game_file_name.empty())
        {
            clock.stop();
            const auto opponent_proxy = outsider->create_proxy_player();
            const Player& white = (player_color == Piece_Color::WHITE ? player : opponent_proxy);
            const Player& black = (player_color == Piece_Color::BLACK ? player : opponent_proxy);
            board.print_game_record(game_record,
                                    white, black,
                                    String::add_to_file_name(game_file_name, "-" + color_text(player_color)),
                                    game_result,
                                    clock,
                                    event_name,
                                    location);
            print_game_record = false;
        }

        if(game_result.exit_program())
        {
            return;
        }
    }
}
<|endoftext|>