<commit_before>/*************************************************************************
 *
 *  $RCSfile: PolygonPoint.hxx,v $
 *
 *  $Revision: 1.2 $
 *
 *  last change: $Author: aw $ $Date: 2003-03-14 11:47:03 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 by Sun Microsystems, Inc.
 *  901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License version 2.1, as published by the Free Software Foundation.
 *
 *  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., 59 Temple Place, Suite 330, Boston,
 *  MA  02111-1307  USA
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (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.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/

#ifndef _POLYGON_POINT_HXX
#define _POLYGON_POINT_HXX

#include <vector>

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

template < class Point > class SimplePointEntry
{
    Point                                           maPoint;

public:
    SimplePointEntry()
    :   maPoint(Point::GetEmptyPoint())
    {
    }

    SimplePointEntry(const Point& rInitPoint)
    :   maPoint(rInitPoint)
    {
    }

    const Point& GetPoint() const
    {
        return maPoint;
    }

    void SetPoint(const Point& rValue)
    {
        maPoint = rValue;
    }

    sal_Bool operator==(const SimplePointEntry& rEntry) const
    {
        return (maPoint == rEntry.maPoint);
    }
};

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

template < class Vector > class SimpleBezierEntry
{
    Vector                                          maBackward;
    Vector                                          maForward;

public:
    SimpleBezierEntry()
    :   maBackward(Vector::GetEmptyVector()),
        maForward(Vector::GetEmptyVector())
    {
    }

    SimpleBezierEntry(const Vector& rInitBackward, const Vector& rInitForward)
    :   maBackward(rInitBackward),
        maForward(rInitForward)
    {
    }

    const Vector& GetBackwardVector() const
    {
        return maBackward;
    }

    void SetBackwardVector(const Vector& rValue)
    {
        maBackward = rValue;
    }

    const Vector& GetForwardVector() const
    {
        return maForward;
    }

    void SetForwardVector(const Vector& rValue)
    {
        maForward = rValue;
    }

    sal_Bool IsBezierNeeded()
    {
        if(maBackward != Vector::GetEmptyVector() || maForward != Vector::GetEmptyVector())
            return sal_True;
        return sal_False;
    }

    sal_Bool operator==(const SimpleBezierEntry& rEntry) const
    {
        return ((maBackward == rEntry.maBackward) && (maForward == rEntry.maForward));
    }
};

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

template < class Point, class Vector > class PolygonPointList
{
    typedef SimplePointEntry< Point > LocalSimplePointEntry;
    typedef SimpleBezierEntry< Vector > LocalSimpleBezierEntry;
    typedef ::std::vector< LocalSimplePointEntry > SimplePointVector;
    typedef ::std::vector< LocalSimpleBezierEntry > SimpleBezierVector;

    sal_uInt32                                      mnBezierCount;
    SimplePointVector                               maPoints;
    SimpleBezierVector*                             mpVectors;

    unsigned                                        mbIsClosed : 1;

    void ImplTryToChangeToSimple()
    {
        if(!mnBezierCount && mpVectors)
        {
            delete mpVectors;
            mpVectors = 0L;
        }
    }

public:
    sal_Bool IsBezier() const
    {
        return sal_Bool(mnBezierCount);
    }

    sal_Bool IsClosed() const
    {
        return sal_Bool(mbIsClosed);
    }

    void SetClosed(sal_Bool bNew)
    {
        mbIsClosed = bNew;
    }

    sal_uInt32 Count() const
    {
        return maPoints.size();
    }

    PolygonPointList()
    :   mnBezierCount(0L),
        mpVectors(0L),
        mbIsClosed(sal_False)
    {
        // complete initialization with defaults
    }

    PolygonPointList(const PolygonPointList& rSource)
    :   mnBezierCount(0L),
        maPoints(rSource.maPoints),
        mpVectors(0L),
        mbIsClosed(rSource.mbIsClosed)
    {
        // complete initialization using copy
        if(rSource.mpVectors && rSource.mnBezierCount)
        {
            mpVectors = new SimpleBezierVector(*rSource.mpVectors);
            mnBezierCount = rSource.mnBezierCount;
        }
    }

    PolygonPointList(const PolygonPointList& rSource, sal_uInt32 nIndex, sal_uInt32 nCount)
    :   mnBezierCount(0L),
        maPoints(nCount),
        mpVectors(0L),
        mbIsClosed(rSource.mbIsClosed)
    {
        // complete initialization using partly copy
        if(nCount)
        {
            // copy point data
            {
                SimplePointVector::const_iterator aStart(rSource.maPoints.begin());
                aStart += nIndex;
                SimplePointVector::const_iterator aEnd(aStart);
                aEnd += nCount;
                maPoints.insert(0L, aStart, aEnd);
            }

            // copy bezier data
            if(rSource.mpVectors && rSource.mnBezierCount)
            {
                mpVectors = new SimpleBezierVector();
                mpVectors->reserve(nCount);

                SimpleBezierVector::iterator aStart(mpVectors->begin());
                aStart += nIndex;
                SimpleBezierVector::iterator aEnd(aStart);
                aEnd += nCount;

                for( ; aStart != aEnd; ++aStart )
                {
                    if(aStart->IsBezierNeeded())
                    {
                        mnBezierCount++;
                    }

                    mpVectors->push_back(*aStart);
                }

                // maybe 0L == mbBezierCount, try to reduce
                ImplTryToChangeToSimple();
            }
        }
    }

    ~PolygonPointList()
    {
        if(mpVectors)
        {
            delete mpVectors;
        }
    }

    sal_Bool IsEqual(const PolygonPointList& rPointList) const
    {
        // same point count?
        if(maPoints.size() != rPointList.maPoints.size())
            return sal_False;

        // if zero points the polys are equal
        if(!maPoints.size())
            return sal_True;

        // if bezier count used it needs to be equal
        if(mnBezierCount != rPointList.mnBezierCount)
            return sal_False;

        // compare point content
        if(maPoints != rPointList.maPoints)
            return sal_False;

        // beziercounts are equal: if it's zero, we are done
        if(!mnBezierCount)
            return sal_True;

        // beziercounts are equal and not zero; compare them
        DBG_ASSERT(0L != mpVectors, "Error: Bezier list needs to exist here(!)");
        DBG_ASSERT(0L != rPointList.mpVectors, "Error: Bezier list needs to exist here(!)");

        return (*mpVectors == *rPointList.mpVectors);
    }

    const Point& GetPoint(sal_uInt32 nIndex) const
    {
        return maPoints[nIndex].GetPoint();
    }

    void SetPoint(sal_uInt32 nIndex, const Point& rValue)
    {
        maPoints[nIndex].SetPoint(rValue);
    }

    const Vector& GetBackwardVector(sal_uInt32 nIndex) const
    {
        if(mpVectors)
            return ((*mpVectors)[nIndex]).GetBackwardVector();
        else
            return Vector::GetEmptyVector();
    }

    void SetBackwardVector(sal_uInt32 nIndex, const Vector& rValue)
    {
        if(mpVectors)
        {
            LocalSimpleBezierEntry& rDest = (*mpVectors)[nIndex];
            sal_Bool bBezierNeededBefore(rDest.IsBezierNeeded());
            ((*mpVectors)[nIndex]).SetBackwardVector(rValue);
            sal_Bool bBezierNeededAfter(rDest.IsBezierNeeded());

            if(bBezierNeededBefore != bBezierNeededAfter)
            {
                if(bBezierNeededAfter)
                    mnBezierCount++;
                else
                    mnBezierCount--;
            }
        }
        else
        {
            sal_Bool bEmptyVector(rValue == Vector::GetEmptyVector());

            if(bEmptyVector)
                return;

            mpVectors = new SimpleBezierVector(maPoints.size());
            ((*mpVectors)[nIndex]).SetBackwardVector(rValue);
            mnBezierCount++;
        }
    }

    const Vector& GetForwardVector(sal_uInt32 nIndex) const
    {
        if(mpVectors)
            return ((*mpVectors)[nIndex]).GetForwardVector();
        else
            return Vector::GetEmptyVector();
    }

    void SetForwardVector(sal_uInt32 nIndex, const Vector& rValue)
    {
        if(mpVectors)
        {
            LocalSimpleBezierEntry& rDest = (*mpVectors)[nIndex];
            sal_Bool bBezierNeededBefore(rDest.IsBezierNeeded());
            ((*mpVectors)[nIndex]).SetForwardVector(rValue);
            sal_Bool bBezierNeededAfter(rDest.IsBezierNeeded());

            if(bBezierNeededBefore != bBezierNeededAfter)
            {
                if(bBezierNeededAfter)
                    mnBezierCount++;
                else
                    mnBezierCount--;
            }
        }
        else
        {
            sal_Bool bEmptyVector(rValue == Vector::GetEmptyVector());

            if(bEmptyVector)
                return;

            mpVectors = new SimpleBezierVector(maPoints.size());
            ((*mpVectors)[nIndex]).SetForwardVector(rValue);
            mnBezierCount++;
        }
    }

    void Insert(sal_uInt32 nIndex, const Point& rPoint, sal_uInt32 nCount)
    {
        if(nCount)
        {
            // maybe 0L == mbBezierCount, try to reduce
            ImplTryToChangeToSimple();

            // add nCount copies of rPoint
            {
                LocalSimplePointEntry aNode(rPoint);
                SimplePointVector::iterator aIndex(maPoints.begin());
                aIndex += nIndex;
                maPoints.insert(aIndex, nCount, aNode);
            }

            // add nCount empty entries to keep indices synchronized
            if(mpVectors)
            {
                LocalSimpleBezierEntry aNode;
                SimpleBezierVector::iterator aIndex(mpVectors->begin());
                aIndex += nIndex;
                mpVectors->insert(aIndex, nCount, aNode);
            }
        }
    }

    void Insert(sal_uInt32 nIndex, const PolygonPointList& rSource)
    {
        const sal_uInt32 nCount(rSource.maPoints.size());

        if(nCount)
        {
            // instert point data
            {
                SimplePointVector::iterator aIndex(maPoints.begin());
                aIndex += nIndex;

                SimplePointVector::const_iterator aStart(rSource.maPoints.begin());
                SimplePointVector::const_iterator aEnd(rSource.maPoints.end());

                maPoints.insert(aIndex, aStart, aEnd);
            }

            // insert bezier data
            if(rSource.mpVectors && rSource.mnBezierCount)
            {
                SimpleBezierVector::iterator aIndex(mpVectors->begin());
                aIndex += nIndex;

                SimpleBezierVector::iterator aStart(rSource.mpVectors->begin());
                SimpleBezierVector::iterator aEnd(rSource.mpVectors->end());

                if(!mpVectors)
                {
                    mpVectors = new SimpleBezierVector(maPoints.size() - nCount);
                }

                mpVectors->insert(aIndex, aStart, aEnd);

                mnBezierCount += rSource.mnBezierCount;
            }
            else
            {
                // maybe 0L == mbBezierCount, try to reduce
                ImplTryToChangeToSimple();

                // add nCount empty entries to keep indices synchronized
                if(mpVectors)
                {
                    LocalSimpleBezierEntry aNode;
                    SimpleBezierVector::iterator aIndex(mpVectors->begin());
                    aIndex += nIndex;
                    mpVectors->insert(aIndex, nCount, aNode);
                }
            }
        }
    }

    void Remove(sal_uInt32 nIndex, sal_uInt32 nCount)
    {
        if(nCount)
        {
            // maybe 0L == mbBezierCount, try to reduce
            ImplTryToChangeToSimple();

            // remove point data
            {
                SimplePointVector::iterator aStart(maPoints.begin());
                aStart += nIndex;
                const SimplePointVector::iterator aEnd(aStart + nCount);

                maPoints.erase(aStart, aEnd);
            }

            // remove bezier data
            if(mpVectors)
            {
                SimpleBezierVector::iterator aStart(mpVectors->begin());
                aStart += nIndex;
                const SimpleBezierVector::iterator aEnd(aStart + nCount);

                // take care for correct mnBezierCount BEFORE erase
                if(mnBezierCount)
                {
                    SimpleBezierVector::iterator aTestIter(aStart);

                    for( ; mnBezierCount && aTestIter != aEnd; ++aTestIter)
                    {
                        if(aTestIter->IsBezierNeeded())
                            mnBezierCount--;
                    }
                }

                if(mnBezierCount)
                {
                    // erase nodes
                    mpVectors->erase(aStart, aEnd);
                }
                else
                {
                    // try to reduce, maybe 0L == mnBezierCount
                    ImplTryToChangeToSimple();
                }
            }
        }
    }
};

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

#endif _POLYGON_POINT_HXX
<commit_msg>Added assigment operators for tuple, vector. Also added Flip() functionality for Polygon.<commit_after>/*************************************************************************
 *
 *  $RCSfile: PolygonPoint.hxx,v $
 *
 *  $Revision: 1.3 $
 *
 *  last change: $Author: aw $ $Date: 2003-03-14 14:35:29 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 by Sun Microsystems, Inc.
 *  901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License version 2.1, as published by the Free Software Foundation.
 *
 *  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., 59 Temple Place, Suite 330, Boston,
 *  MA  02111-1307  USA
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (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.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/

#ifndef _POLYGON_POINT_HXX
#define _POLYGON_POINT_HXX

#include <vector>

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

template < class Point > class SimplePointEntry
{
    Point                                           maPoint;

public:
    SimplePointEntry()
    :   maPoint(Point::GetEmptyPoint())
    {
    }

    SimplePointEntry(const Point& rInitPoint)
    :   maPoint(rInitPoint)
    {
    }

    const Point& GetPoint() const
    {
        return maPoint;
    }

    void SetPoint(const Point& rValue)
    {
        maPoint = rValue;
    }

    sal_Bool operator==(const SimplePointEntry& rEntry) const
    {
        return (maPoint == rEntry.maPoint);
    }
};

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

template < class Vector > class SimpleBezierEntry
{
    Vector                                          maBackward;
    Vector                                          maForward;

public:
    SimpleBezierEntry()
    :   maBackward(Vector::GetEmptyVector()),
        maForward(Vector::GetEmptyVector())
    {
    }

    SimpleBezierEntry(const Vector& rInitBackward, const Vector& rInitForward)
    :   maBackward(rInitBackward),
        maForward(rInitForward)
    {
    }

    const Vector& GetBackwardVector() const
    {
        return maBackward;
    }

    void SetBackwardVector(const Vector& rValue)
    {
        maBackward = rValue;
    }

    const Vector& GetForwardVector() const
    {
        return maForward;
    }

    void SetForwardVector(const Vector& rValue)
    {
        maForward = rValue;
    }

    sal_Bool IsBezierNeeded()
    {
        if(maBackward != Vector::GetEmptyVector() || maForward != Vector::GetEmptyVector())
            return sal_True;
        return sal_False;
    }

    sal_Bool operator==(const SimpleBezierEntry& rEntry) const
    {
        return ((maBackward == rEntry.maBackward) && (maForward == rEntry.maForward));
    }

    void DoInvertForFlip()
    {
        maBackward = -maBackward;
        maForward = -maForward;
    }
};

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

template < class Point, class Vector > class PolygonPointList
{
    typedef SimplePointEntry< Point > LocalSimplePointEntry;
    typedef SimpleBezierEntry< Vector > LocalSimpleBezierEntry;
    typedef ::std::vector< LocalSimplePointEntry > SimplePointVector;
    typedef ::std::vector< LocalSimpleBezierEntry > SimpleBezierVector;

    sal_uInt32                                      mnBezierCount;
    SimplePointVector                               maPoints;
    SimpleBezierVector*                             mpVectors;

    unsigned                                        mbIsClosed : 1;

    void ImplTryToReduceToPointVector()
    {
        if(!mnBezierCount && mpVectors)
        {
            delete mpVectors;
            mpVectors = 0L;
        }
    }

public:
    sal_Bool IsBezier() const
    {
        return sal_Bool(mnBezierCount);
    }

    sal_Bool IsClosed() const
    {
        return sal_Bool(mbIsClosed);
    }

    void SetClosed(sal_Bool bNew)
    {
        mbIsClosed = bNew;
    }

    sal_uInt32 Count() const
    {
        return maPoints.size();
    }

    PolygonPointList()
    :   mnBezierCount(0L),
        mpVectors(0L),
        mbIsClosed(sal_False)
    {
        // complete initialization with defaults
    }

    PolygonPointList(const PolygonPointList& rSource)
    :   mnBezierCount(0L),
        maPoints(rSource.maPoints),
        mpVectors(0L),
        mbIsClosed(rSource.mbIsClosed)
    {
        // complete initialization using copy
        if(rSource.mpVectors && rSource.mnBezierCount)
        {
            mpVectors = new SimpleBezierVector(*rSource.mpVectors);
            mnBezierCount = rSource.mnBezierCount;
        }
    }

    PolygonPointList(const PolygonPointList& rSource, sal_uInt32 nIndex, sal_uInt32 nCount)
    :   mnBezierCount(0L),
        maPoints(nCount),
        mpVectors(0L),
        mbIsClosed(rSource.mbIsClosed)
    {
        // complete initialization using partly copy
        if(nCount)
        {
            // copy point data
            {
                SimplePointVector::const_iterator aStart(rSource.maPoints.begin());
                aStart += nIndex;
                SimplePointVector::const_iterator aEnd(aStart);
                aEnd += nCount;
                maPoints.insert(0L, aStart, aEnd);
            }

            // copy bezier data
            if(rSource.mpVectors && rSource.mnBezierCount)
            {
                mpVectors = new SimpleBezierVector();
                mpVectors->reserve(nCount);

                SimpleBezierVector::iterator aStart(mpVectors->begin());
                aStart += nIndex;
                SimpleBezierVector::iterator aEnd(aStart);
                aEnd += nCount;

                for( ; aStart != aEnd; ++aStart )
                {
                    if(aStart->IsBezierNeeded())
                    {
                        mnBezierCount++;
                    }

                    mpVectors->push_back(*aStart);
                }

                // maybe vectors are not needed anymore, try to reduce memory footprint
                ImplTryToReduceToPointVector();
            }
        }
    }

    ~PolygonPointList()
    {
        if(mpVectors)
        {
            delete mpVectors;
        }
    }

    sal_Bool IsEqual(const PolygonPointList& rPointList) const
    {
        // same point count?
        if(maPoints.size() != rPointList.maPoints.size())
            return sal_False;

        // if zero points the polys are equal
        if(!maPoints.size())
            return sal_True;

        // if bezier count used it needs to be equal
        if(mnBezierCount != rPointList.mnBezierCount)
            return sal_False;

        // compare point content
        if(maPoints != rPointList.maPoints)
            return sal_False;

        // beziercounts are equal: if it's zero, we are done
        if(!mnBezierCount)
            return sal_True;

        // beziercounts are equal and not zero; compare them
        DBG_ASSERT(0L != mpVectors, "Error: Bezier list needs to exist here(!)");
        DBG_ASSERT(0L != rPointList.mpVectors, "Error: Bezier list needs to exist here(!)");

        return (*mpVectors == *rPointList.mpVectors);
    }

    const Point& GetPoint(sal_uInt32 nIndex) const
    {
        return maPoints[nIndex].GetPoint();
    }

    void SetPoint(sal_uInt32 nIndex, const Point& rValue)
    {
        maPoints[nIndex].SetPoint(rValue);
    }

    const Vector& GetBackwardVector(sal_uInt32 nIndex) const
    {
        if(mpVectors)
            return ((*mpVectors)[nIndex]).GetBackwardVector();
        else
            return Vector::GetEmptyVector();
    }

    void SetBackwardVector(sal_uInt32 nIndex, const Vector& rValue)
    {
        if(mpVectors)
        {
            LocalSimpleBezierEntry& rDest = (*mpVectors)[nIndex];
            sal_Bool bBezierNeededBefore(rDest.IsBezierNeeded());
            ((*mpVectors)[nIndex]).SetBackwardVector(rValue);
            sal_Bool bBezierNeededAfter(rDest.IsBezierNeeded());

            if(bBezierNeededBefore != bBezierNeededAfter)
            {
                if(bBezierNeededAfter)
                    mnBezierCount++;
                else
                    mnBezierCount--;
            }
        }
        else
        {
            sal_Bool bEmptyVector(rValue == Vector::GetEmptyVector());

            if(bEmptyVector)
                return;

            mpVectors = new SimpleBezierVector(maPoints.size());
            ((*mpVectors)[nIndex]).SetBackwardVector(rValue);
            mnBezierCount++;
        }
    }

    const Vector& GetForwardVector(sal_uInt32 nIndex) const
    {
        if(mpVectors)
            return ((*mpVectors)[nIndex]).GetForwardVector();
        else
            return Vector::GetEmptyVector();
    }

    void SetForwardVector(sal_uInt32 nIndex, const Vector& rValue)
    {
        if(mpVectors)
        {
            LocalSimpleBezierEntry& rDest = (*mpVectors)[nIndex];
            sal_Bool bBezierNeededBefore(rDest.IsBezierNeeded());
            ((*mpVectors)[nIndex]).SetForwardVector(rValue);
            sal_Bool bBezierNeededAfter(rDest.IsBezierNeeded());

            if(bBezierNeededBefore != bBezierNeededAfter)
            {
                if(bBezierNeededAfter)
                    mnBezierCount++;
                else
                    mnBezierCount--;
            }
        }
        else
        {
            sal_Bool bEmptyVector(rValue == Vector::GetEmptyVector());

            if(bEmptyVector)
                return;

            mpVectors = new SimpleBezierVector(maPoints.size());
            ((*mpVectors)[nIndex]).SetForwardVector(rValue);
            mnBezierCount++;
        }
    }

    void Insert(sal_uInt32 nIndex, const Point& rPoint, sal_uInt32 nCount)
    {
        if(nCount)
        {
            // maybe vectors are not needed anymore, try to reduce memory footprint
            ImplTryToReduceToPointVector();

            // add nCount copies of rPoint
            {
                LocalSimplePointEntry aNode(rPoint);
                SimplePointVector::iterator aIndex(maPoints.begin());
                aIndex += nIndex;
                maPoints.insert(aIndex, nCount, aNode);
            }

            // add nCount empty entries to keep indices synchronized
            if(mpVectors)
            {
                LocalSimpleBezierEntry aNode;
                SimpleBezierVector::iterator aIndex(mpVectors->begin());
                aIndex += nIndex;
                mpVectors->insert(aIndex, nCount, aNode);
            }
        }
    }

    void Insert(sal_uInt32 nIndex, const PolygonPointList& rSource)
    {
        const sal_uInt32 nCount(rSource.maPoints.size());

        if(nCount)
        {
            // instert point data
            {
                SimplePointVector::iterator aIndex(maPoints.begin());
                aIndex += nIndex;

                SimplePointVector::const_iterator aStart(rSource.maPoints.begin());
                SimplePointVector::const_iterator aEnd(rSource.maPoints.end());

                maPoints.insert(aIndex, aStart, aEnd);
            }

            // insert bezier data
            if(rSource.mpVectors && rSource.mnBezierCount)
            {
                SimpleBezierVector::iterator aIndex(mpVectors->begin());
                aIndex += nIndex;

                SimpleBezierVector::iterator aStart(rSource.mpVectors->begin());
                SimpleBezierVector::iterator aEnd(rSource.mpVectors->end());

                if(!mpVectors)
                {
                    mpVectors = new SimpleBezierVector(maPoints.size() - nCount);
                }

                mpVectors->insert(aIndex, aStart, aEnd);

                mnBezierCount += rSource.mnBezierCount;
            }
            else
            {
                // maybe vectors are not needed anymore, try to reduce memory footprint
                ImplTryToReduceToPointVector();

                // add nCount empty entries to keep indices synchronized
                if(mpVectors)
                {
                    LocalSimpleBezierEntry aNode;
                    SimpleBezierVector::iterator aIndex(mpVectors->begin());
                    aIndex += nIndex;
                    mpVectors->insert(aIndex, nCount, aNode);
                }
            }
        }
    }

    void Remove(sal_uInt32 nIndex, sal_uInt32 nCount)
    {
        if(nCount)
        {
            // maybe vectors are not needed anymore, try to reduce memory footprint
            ImplTryToReduceToPointVector();

            // remove point data
            {
                SimplePointVector::iterator aStart(maPoints.begin());
                aStart += nIndex;
                const SimplePointVector::iterator aEnd(aStart + nCount);

                maPoints.erase(aStart, aEnd);
            }

            // remove bezier data
            if(mpVectors)
            {
                SimpleBezierVector::iterator aStart(mpVectors->begin());
                aStart += nIndex;
                const SimpleBezierVector::iterator aEnd(aStart + nCount);

                // take care for correct mnBezierCount BEFORE erase
                if(mnBezierCount)
                {
                    SimpleBezierVector::iterator aTestIter(aStart);

                    for( ; mnBezierCount && aTestIter != aEnd; ++aTestIter)
                    {
                        if(aTestIter->IsBezierNeeded())
                            mnBezierCount--;
                    }
                }

                if(mnBezierCount)
                {
                    // erase nodes
                    mpVectors->erase(aStart, aEnd);
                }
                else
                {
                    // try to reduce, maybe 0L == mnBezierCount
                    ImplTryToReduceToPointVector();
                }
            }
        }
    }

    void Flip()
    {
        if(maPoints.size() > 1)
        {
            // maybe vectors are not needed anymore, try to reduce memory footprint
            ImplTryToReduceToPointVector();

            // calculate half size
            const sal_uInt32 nHalfSize(maPoints.size() >> 1L);

            // flip point data
            {
                SimplePointVector::iterator aStart(maPoints.begin());
                SimplePointVector::iterator aEnd(maPoints.end());

                for(sal_uInt32 a(0); a < nHalfSize; a++)
                {
                    LocalSimplePointEntry aTemp = *aStart;
                    *aStart++ = *aEnd;
                    *aEnd-- = aTemp;
                }
            }

            // flip bezier data
            if(mpVectors)
            {
                SimpleBezierVector::iterator aStart(mpVectors->begin());
                SimpleBezierVector::iterator aEnd(mpVectors->end());

                for(sal_uInt32 a(0); a < nHalfSize; a++)
                {
                    LocalSimpleBezierEntry aTemp = *aStart;
                    aTemp.DoInvertForFlip();
                    *aStart = *aEnd;
                    aStart->DoInvertForFlip();
                    aStart++;
                    *aEnd-- = aTemp;
                }

                // also flip vectors of middle point (if existing)
                if(maPoints.size() % 2)
                {
                    (*mpVectors)[nHalfSize].DoInvertForFlip();
                }
            }
        }
    }
};

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

#endif _POLYGON_POINT_HXX
<|endoftext|>


<commit_before>/*
 * Software License Agreement (BSD License)
 *
 *  Point Cloud Library (PCL) - www.pointclouds.org
 *  Copyright (c) 2010-2012, Willow Garage, Inc.
 *
 *  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 Willow Garage, Inc. 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.
 *
 *  $Id$
 *
 */

#include <pcl/outofcore/outofcore_node_data.h>

#include <pcl/console/print.h>

#include <iostream>
#include <fstream>
#include <sstream>

namespace pcl
{
  namespace outofcore
  {

    OutofcoreOctreeNodeMetadata::OutofcoreOctreeNodeMetadata ()
      : min_bb_ (),
        max_bb_ (),
        binary_point_filename_ (),
        midpoint_xyz_ (),
        directory_ (),
        metadata_filename_ ()
    {
    }

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

    OutofcoreOctreeNodeMetadata::~OutofcoreOctreeNodeMetadata ()
    {
    }

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

    Eigen::Vector3d
    OutofcoreOctreeNodeMetadata::getBoundingBoxMin () const
    {
      return (min_bb_);
    }

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

    void
    OutofcoreOctreeNodeMetadata::setBoundingBoxMin (const Eigen::Vector3d min_bb)
    {
      min_bb_ = min_bb;
      this->updateVoxelCenter ();
    }

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

    Eigen::Vector3d
    OutofcoreOctreeNodeMetadata::getBoundingBoxMax () const
    {
      return (max_bb_);
    }

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

    void
    OutofcoreOctreeNodeMetadata::setBoundingBoxMax (const Eigen::Vector3d max_bb)
    {
      max_bb_ = max_bb;
      this->updateVoxelCenter ();
    }

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

    void
    OutofcoreOctreeNodeMetadata::getBoundingBox (Eigen::Vector3d &min_bb, Eigen::Vector3d &max_bb) const
    {
      min_bb = min_bb_;
      max_bb = max_bb_;
    }

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

    void
    OutofcoreOctreeNodeMetadata::setBoundingBox (const Eigen::Vector3d min_bb, const Eigen::Vector3d max_bb)
    {
      min_bb_ = min_bb;
      max_bb_ = max_bb;
      this->updateVoxelCenter ();
    }

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

    boost::filesystem::path
    OutofcoreOctreeNodeMetadata::getDirectoryPathname () const
    {
      return (directory_);
    }

////////////////////////////////////////////////////////////////////////////////
    void
    OutofcoreOctreeNodeMetadata::setDirectoryPathname (const boost::filesystem::path directory_pathname)
    {
      directory_ = directory_pathname;
    }

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

    boost::filesystem::path
    OutofcoreOctreeNodeMetadata::getPCDFilename () const
    {
      return (binary_point_filename_);
    }

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

    void
    OutofcoreOctreeNodeMetadata::setPCDFilename (const boost::filesystem::path point_filename)
    {
      binary_point_filename_ = point_filename;
    }

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

    int
    OutofcoreOctreeNodeMetadata::getOutofcoreVersion () const
    {
      return (outofcore_version_);
    }

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

    void OutofcoreOctreeNodeMetadata::setOutofcoreVersion (const int version)
    {
      outofcore_version_ = version;
    }

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

    boost::filesystem::path OutofcoreOctreeNodeMetadata::getMetadataFilename () const
    {
      return (metadata_filename_);
    }

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

    void OutofcoreOctreeNodeMetadata::setMetadataFilename (const boost::filesystem::path path_to_metadata)
    {
      directory_ = path_to_metadata.parent_path ();
      metadata_filename_ = path_to_metadata;
    }

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

    Eigen::Vector3d OutofcoreOctreeNodeMetadata::getVoxelCenter () const
    {
      return (midpoint_xyz_);
    }

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

    void OutofcoreOctreeNodeMetadata::serializeMetadataToDisk ()
    {
      boost::shared_ptr<cJSON> idx (cJSON_CreateObject (), cJSON_Delete);

      cJSON* cjson_outofcore_version = cJSON_CreateNumber (outofcore_version_);

      double min_array[3];
      double max_array[3];

      for(int i=0; i<3; i++)
      {
        min_array[i] = min_bb_[i];
        max_array[i] = max_bb_[i];
      }

      cJSON* cjson_bb_min = cJSON_CreateDoubleArray (min_array, 3);
      cJSON* cjson_bb_max = cJSON_CreateDoubleArray (max_array, 3);

      cJSON* cjson_bin_point_filename = cJSON_CreateString (binary_point_filename_.filename ().c_str ());

      cJSON_AddItemToObject (idx.get (), "version", cjson_outofcore_version);
      cJSON_AddItemToObject (idx.get (), "bb_min", cjson_bb_min);
      cJSON_AddItemToObject (idx.get (), "bb_max", cjson_bb_max);
      cJSON_AddItemToObject (idx.get (), "bin", cjson_bin_point_filename);

      char* idx_txt = cJSON_Print (idx.get ());

      std::ofstream f (metadata_filename_.c_str (), std::ios::out | std::ios::trunc);
      f << idx_txt;
      f.close ();

      free (idx_txt);
    }

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

    int OutofcoreOctreeNodeMetadata::loadMetadataFromDisk ()
    {
      if(directory_ != metadata_filename_.parent_path ())
      {
        PCL_ERROR ("directory_ is not set correctly\n");
      }

      //if the file to load doesn't exist, return failure
      if (!boost::filesystem::exists (metadata_filename_))
      {
        PCL_ERROR ("[pcl::outofcore::OutofcoreOctreeNodeMetadata] Can not find index metadata at %s.\n", metadata_filename_.c_str ());
        return (0);
      }
      else if(boost::filesystem::is_directory (metadata_filename_))
      {
        PCL_ERROR ("[pcl::outofcore::OutofcoreOctreeNodeMetadata] Got a directory, but no oct_idx metadata?\n");
        return (0);
      }

      //load CJSON
      std::vector<char> idx_input;
      boost::uintmax_t len = boost::filesystem::file_size (metadata_filename_);
      idx_input.resize (len + 1);

      std::ifstream f (metadata_filename_.c_str (), std::ios::in);
      f.read (&(idx_input.front ()), len);
      idx_input.back () = '\0';

      //Parse
      boost::shared_ptr<cJSON> idx (cJSON_Parse (&(idx_input.front ())), cJSON_Delete);

      cJSON* cjson_outofcore_version = cJSON_GetObjectItem (idx.get (), "version");
      cJSON* cjson_bb_min = cJSON_GetObjectItem (idx.get (), "bb_min");
      cJSON* cjson_bb_max = cJSON_GetObjectItem (idx.get (), "bb_max");
      cJSON* cjson_bin_point_filename = cJSON_GetObjectItem (idx.get (), "bin");

      for (int i = 0; i < 3; i++)
      {
        min_bb_[i] = cJSON_GetArrayItem (cjson_bb_min, i)->valuedouble;
        max_bb_[i] = cJSON_GetArrayItem (cjson_bb_max, i)->valuedouble;
      }
      outofcore_version_ = cjson_outofcore_version->valueint;

      binary_point_filename_= directory_ / cjson_bin_point_filename->valuestring;
      midpoint_xyz_ = (max_bb_+min_bb_)/static_cast<double>(2.0);

      //return success
      return (1);
    }

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

    int OutofcoreOctreeNodeMetadata::loadMetadataFromDisk (const boost::filesystem::path path_to_metadata)
    {
      this->setMetadataFilename (path_to_metadata);
      this->setDirectoryPathname (path_to_metadata.parent_path ());
      return (this->loadMetadataFromDisk ());
    }

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

    void OutofcoreOctreeNodeMetadata::updateVoxelCenter ()
    {
      midpoint_xyz_ = (this->max_bb_ + this->min_bb_)/static_cast<double>(2.0);
    }

////////////////////////////////////////////////////////////////////////////////
  }//namespace outofcore
}//namespace pcl

<commit_msg>outofcore fix C2664 windows compile error line 211<commit_after>/*
 * Software License Agreement (BSD License)
 *
 *  Point Cloud Library (PCL) - www.pointclouds.org
 *  Copyright (c) 2010-2012, Willow Garage, Inc.
 *
 *  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 Willow Garage, Inc. 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.
 *
 *  $Id$
 *
 */

#include <pcl/outofcore/outofcore_node_data.h>

#include <pcl/console/print.h>

#include <iostream>
#include <fstream>
#include <sstream>

namespace pcl
{
  namespace outofcore
  {

    OutofcoreOctreeNodeMetadata::OutofcoreOctreeNodeMetadata ()
      : min_bb_ (),
        max_bb_ (),
        binary_point_filename_ (),
        midpoint_xyz_ (),
        directory_ (),
        metadata_filename_ ()
    {
    }

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

    OutofcoreOctreeNodeMetadata::~OutofcoreOctreeNodeMetadata ()
    {
    }

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

    Eigen::Vector3d
    OutofcoreOctreeNodeMetadata::getBoundingBoxMin () const
    {
      return (min_bb_);
    }

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

    void
    OutofcoreOctreeNodeMetadata::setBoundingBoxMin (const Eigen::Vector3d min_bb)
    {
      min_bb_ = min_bb;
      this->updateVoxelCenter ();
    }

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

    Eigen::Vector3d
    OutofcoreOctreeNodeMetadata::getBoundingBoxMax () const
    {
      return (max_bb_);
    }

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

    void
    OutofcoreOctreeNodeMetadata::setBoundingBoxMax (const Eigen::Vector3d max_bb)
    {
      max_bb_ = max_bb;
      this->updateVoxelCenter ();
    }

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

    void
    OutofcoreOctreeNodeMetadata::getBoundingBox (Eigen::Vector3d &min_bb, Eigen::Vector3d &max_bb) const
    {
      min_bb = min_bb_;
      max_bb = max_bb_;
    }

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

    void
    OutofcoreOctreeNodeMetadata::setBoundingBox (const Eigen::Vector3d min_bb, const Eigen::Vector3d max_bb)
    {
      min_bb_ = min_bb;
      max_bb_ = max_bb;
      this->updateVoxelCenter ();
    }

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

    boost::filesystem::path
    OutofcoreOctreeNodeMetadata::getDirectoryPathname () const
    {
      return (directory_);
    }

////////////////////////////////////////////////////////////////////////////////
    void
    OutofcoreOctreeNodeMetadata::setDirectoryPathname (const boost::filesystem::path directory_pathname)
    {
      directory_ = directory_pathname;
    }

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

    boost::filesystem::path
    OutofcoreOctreeNodeMetadata::getPCDFilename () const
    {
      return (binary_point_filename_);
    }

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

    void
    OutofcoreOctreeNodeMetadata::setPCDFilename (const boost::filesystem::path point_filename)
    {
      binary_point_filename_ = point_filename;
    }

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

    int
    OutofcoreOctreeNodeMetadata::getOutofcoreVersion () const
    {
      return (outofcore_version_);
    }

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

    void OutofcoreOctreeNodeMetadata::setOutofcoreVersion (const int version)
    {
      outofcore_version_ = version;
    }

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

    boost::filesystem::path OutofcoreOctreeNodeMetadata::getMetadataFilename () const
    {
      return (metadata_filename_);
    }

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

    void OutofcoreOctreeNodeMetadata::setMetadataFilename (const boost::filesystem::path path_to_metadata)
    {
      directory_ = path_to_metadata.parent_path ();
      metadata_filename_ = path_to_metadata;
    }

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

    Eigen::Vector3d OutofcoreOctreeNodeMetadata::getVoxelCenter () const
    {
      return (midpoint_xyz_);
    }

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

    void OutofcoreOctreeNodeMetadata::serializeMetadataToDisk ()
    {
      boost::shared_ptr<cJSON> idx (cJSON_CreateObject (), cJSON_Delete);

      cJSON* cjson_outofcore_version = cJSON_CreateNumber (outofcore_version_);

      double min_array[3];
      double max_array[3];

      for(int i=0; i<3; i++)
      {
        min_array[i] = min_bb_[i];
        max_array[i] = max_bb_[i];
      }

      cJSON* cjson_bb_min = cJSON_CreateDoubleArray (min_array, 3);
      cJSON* cjson_bb_max = cJSON_CreateDoubleArray (max_array, 3);

      cJSON* cjson_bin_point_filename = cJSON_CreateString (static_cast<const char*>(binary_point_filename_.filename ().c_str ()));

      cJSON_AddItemToObject (idx.get (), "version", cjson_outofcore_version);
      cJSON_AddItemToObject (idx.get (), "bb_min", cjson_bb_min);
      cJSON_AddItemToObject (idx.get (), "bb_max", cjson_bb_max);
      cJSON_AddItemToObject (idx.get (), "bin", cjson_bin_point_filename);

      char* idx_txt = cJSON_Print (idx.get ());

      std::ofstream f (metadata_filename_.c_str (), std::ios::out | std::ios::trunc);
      f << idx_txt;
      f.close ();

      free (idx_txt);
    }

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

    int OutofcoreOctreeNodeMetadata::loadMetadataFromDisk ()
    {
      if(directory_ != metadata_filename_.parent_path ())
      {
        PCL_ERROR ("directory_ is not set correctly\n");
      }

      //if the file to load doesn't exist, return failure
      if (!boost::filesystem::exists (metadata_filename_))
      {
        PCL_ERROR ("[pcl::outofcore::OutofcoreOctreeNodeMetadata] Can not find index metadata at %s.\n", metadata_filename_.c_str ());
        return (0);
      }
      else if(boost::filesystem::is_directory (metadata_filename_))
      {
        PCL_ERROR ("[pcl::outofcore::OutofcoreOctreeNodeMetadata] Got a directory, but no oct_idx metadata?\n");
        return (0);
      }

      //load CJSON
      std::vector<char> idx_input;
      boost::uintmax_t len = boost::filesystem::file_size (metadata_filename_);
      idx_input.resize (len + 1);

      std::ifstream f (metadata_filename_.c_str (), std::ios::in);
      f.read (&(idx_input.front ()), len);
      idx_input.back () = '\0';

      //Parse
      boost::shared_ptr<cJSON> idx (cJSON_Parse (&(idx_input.front ())), cJSON_Delete);

      cJSON* cjson_outofcore_version = cJSON_GetObjectItem (idx.get (), "version");
      cJSON* cjson_bb_min = cJSON_GetObjectItem (idx.get (), "bb_min");
      cJSON* cjson_bb_max = cJSON_GetObjectItem (idx.get (), "bb_max");
      cJSON* cjson_bin_point_filename = cJSON_GetObjectItem (idx.get (), "bin");

      for (int i = 0; i < 3; i++)
      {
        min_bb_[i] = cJSON_GetArrayItem (cjson_bb_min, i)->valuedouble;
        max_bb_[i] = cJSON_GetArrayItem (cjson_bb_max, i)->valuedouble;
      }
      outofcore_version_ = cjson_outofcore_version->valueint;

      binary_point_filename_= directory_ / cjson_bin_point_filename->valuestring;
      midpoint_xyz_ = (max_bb_+min_bb_)/static_cast<double>(2.0);

      //return success
      return (1);
    }

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

    int OutofcoreOctreeNodeMetadata::loadMetadataFromDisk (const boost::filesystem::path path_to_metadata)
    {
      this->setMetadataFilename (path_to_metadata);
      this->setDirectoryPathname (path_to_metadata.parent_path ());
      return (this->loadMetadataFromDisk ());
    }

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

    void OutofcoreOctreeNodeMetadata::updateVoxelCenter ()
    {
      midpoint_xyz_ = (this->max_bb_ + this->min_bb_)/static_cast<double>(2.0);
    }

////////////////////////////////////////////////////////////////////////////////
  }//namespace outofcore
}//namespace pcl

<|endoftext|>


<commit_before>/* -*- C++ -*-
 * (c) 2011 Helge Bahmann <hcb@chaoticmind.net>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 2.1
 * Refer to the file "COPYING" for details.
 */

#include <assert.h>
#include <signal.h>
#include <sys/wait.h>
#include <unistd.h>

#include <tscb/childproc-monitor>

std::atomic<int> called_count(0);

static void proc_handler(void)
{
	called_count.fetch_add(1, std::memory_order_relaxed);
}

static void throwing_proc_handler(void)
{
	called_count.fetch_add(1, std::memory_order_relaxed);
	throw std::runtime_error("foo");
}

static pid_t launch_temp_process(void)
{
	pid_t pid = fork();
	if (pid == 0) {
		_exit(0);
	}
	return pid;
}

static pid_t launch_pers_process(void)
{
	pid_t pid = fork();
	if (pid == 0) {
		for (;;) {
			sleep(60);
		}
	}
	return pid;
}

class sigchld_guard {
public:
	sigchld_guard(void)
	{
		sigset_t sigset;
		sigemptyset(&sigset);
		sigaddset(&sigset, SIGCHLD);
		sigprocmask(SIG_BLOCK, &sigset, NULL);
	}
	~sigchld_guard(void)
	{
		sigset_t sigset;
		sigemptyset(&sigset);
		sigaddset(&sigset, SIGCHLD);
		sigprocmask(SIG_BLOCK, &sigset, NULL);
	}
	void wait(void)
	{
		sigset_t sigset;
		sigemptyset(&sigset);
		sigaddset(&sigset, SIGCHLD);
		sigwaitinfo(&sigset, NULL);
	}
};

void test_basic_operation(void)
{
	sigchld_guard guard;
	tscb::childproc_monitor m;

	called_count.store(0);

	pid_t pid = launch_temp_process();

	tscb::connection c = m.watch_childproc(std::bind(proc_handler), pid);

	assert(called_count == 0);

	/* wait until child process has terminated */
	guard.wait();

	m.dispatch();
	assert(called_count == 1);
}

void test_cancel(void)
{
	sigchld_guard guard;
	tscb::childproc_monitor m;

	called_count.store(0);

	pid_t pid = launch_pers_process();

	tscb::connection c = m.watch_childproc(std::bind(proc_handler), pid);

	m.dispatch();

	/* not exited yet */
	assert(called_count == 0);

	c.disconnect();

	kill(pid, SIGTERM);
	/* wait until child process has terminated */
	guard.wait();

	/* callback cancelled, should not reap */
	m.dispatch();
	assert(called_count == 0);

	int status;
	waitpid(pid, &status, 0);
}

void test_ignore_unknown(void)
{
	sigchld_guard guard;
	tscb::childproc_monitor m;

	called_count.store(0);

	pid_t pid = launch_temp_process();

	/* wait until child process has terminated */
	guard.wait();

	/* but dispatcher does not yet know about it, so won't reap */
	m.dispatch();
	assert(called_count == 0);

	tscb::connection c = m.watch_childproc(std::bind(proc_handler), pid);

	/* now that dispatcher knows, it will reap */
	m.dispatch();
	assert(called_count == 1);
}

void test_throwing_handler(void)
{
	sigchld_guard guard;
	tscb::childproc_monitor m;

	called_count.store(0);

	pid_t pid1 = launch_temp_process();
	/* wait until child process has terminated */
	guard.wait();

	pid_t pid2 = launch_temp_process();
	/* wait until child process has terminated */
	guard.wait();

	tscb::connection c1 = m.watch_childproc(std::bind(throwing_proc_handler), pid1);
	tscb::connection c2 = m.watch_childproc(std::bind(throwing_proc_handler), pid2);

	try {
		m.dispatch();
		assert(false);
	}
	catch(std::runtime_error const&) {
	}

	assert(called_count == 1);

	try {
		m.dispatch();
		assert(false);
	}
	catch(std::runtime_error const&) {
	}

	assert(called_count == 2);
}

int main()
{
	test_basic_operation();
	test_cancel();
	test_ignore_unknown();
	test_throwing_handler();
}
<commit_msg>testprogs: use nullptr<commit_after>/* -*- C++ -*-
 * (c) 2011 Helge Bahmann <hcb@chaoticmind.net>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 2.1
 * Refer to the file "COPYING" for details.
 */

#include <assert.h>
#include <signal.h>
#include <sys/wait.h>
#include <unistd.h>

#include <tscb/childproc-monitor>

std::atomic<int> called_count(0);

static void proc_handler(void)
{
	called_count.fetch_add(1, std::memory_order_relaxed);
}

static void throwing_proc_handler(void)
{
	called_count.fetch_add(1, std::memory_order_relaxed);
	throw std::runtime_error("foo");
}

static pid_t launch_temp_process(void)
{
	pid_t pid = fork();
	if (pid == 0) {
		_exit(0);
	}
	return pid;
}

static pid_t launch_pers_process(void)
{
	pid_t pid = fork();
	if (pid == 0) {
		for (;;) {
			sleep(60);
		}
	}
	return pid;
}

class sigchld_guard {
public:
	sigchld_guard(void)
	{
		sigset_t sigset;
		sigemptyset(&sigset);
		sigaddset(&sigset, SIGCHLD);
		sigprocmask(SIG_BLOCK, &sigset, nullptr);
	}
	~sigchld_guard(void)
	{
		sigset_t sigset;
		sigemptyset(&sigset);
		sigaddset(&sigset, SIGCHLD);
		sigprocmask(SIG_BLOCK, &sigset, nullptr);
	}
	void wait(void)
	{
		sigset_t sigset;
		sigemptyset(&sigset);
		sigaddset(&sigset, SIGCHLD);
		sigwaitinfo(&sigset, nullptr);
	}
};

void test_basic_operation(void)
{
	sigchld_guard guard;
	tscb::childproc_monitor m;

	called_count.store(0);

	pid_t pid = launch_temp_process();

	tscb::connection c = m.watch_childproc(std::bind(proc_handler), pid);

	assert(called_count == 0);

	/* wait until child process has terminated */
	guard.wait();

	m.dispatch();
	assert(called_count == 1);
}

void test_cancel(void)
{
	sigchld_guard guard;
	tscb::childproc_monitor m;

	called_count.store(0);

	pid_t pid = launch_pers_process();

	tscb::connection c = m.watch_childproc(std::bind(proc_handler), pid);

	m.dispatch();

	/* not exited yet */
	assert(called_count == 0);

	c.disconnect();

	kill(pid, SIGTERM);
	/* wait until child process has terminated */
	guard.wait();

	/* callback cancelled, should not reap */
	m.dispatch();
	assert(called_count == 0);

	int status;
	waitpid(pid, &status, 0);
}

void test_ignore_unknown(void)
{
	sigchld_guard guard;
	tscb::childproc_monitor m;

	called_count.store(0);

	pid_t pid = launch_temp_process();

	/* wait until child process has terminated */
	guard.wait();

	/* but dispatcher does not yet know about it, so won't reap */
	m.dispatch();
	assert(called_count == 0);

	tscb::connection c = m.watch_childproc(std::bind(proc_handler), pid);

	/* now that dispatcher knows, it will reap */
	m.dispatch();
	assert(called_count == 1);
}

void test_throwing_handler(void)
{
	sigchld_guard guard;
	tscb::childproc_monitor m;

	called_count.store(0);

	pid_t pid1 = launch_temp_process();
	/* wait until child process has terminated */
	guard.wait();

	pid_t pid2 = launch_temp_process();
	/* wait until child process has terminated */
	guard.wait();

	tscb::connection c1 = m.watch_childproc(std::bind(throwing_proc_handler), pid1);
	tscb::connection c2 = m.watch_childproc(std::bind(throwing_proc_handler), pid2);

	try {
		m.dispatch();
		assert(false);
	}
	catch(std::runtime_error const&) {
	}

	assert(called_count == 1);

	try {
		m.dispatch();
		assert(false);
	}
	catch(std::runtime_error const&) {
	}

	assert(called_count == 2);
}

int main()
{
	test_basic_operation();
	test_cancel();
	test_ignore_unknown();
	test_throwing_handler();
}
<|endoftext|>


<commit_before>#include <QDebug>
#include <QDir>
#include <QJsonDocument>
#include <QJsonArray>
#include <QJsonValue>
#include <QTemporaryFile>
#include <iostream>
#include "kernel.h"
#include "geometries.h"
#include "ilwiscontext.h"
#include "grid.h"

using namespace Ilwis;
GridBlockInternal::GridBlockInternal(quint32 lines , quint32 width) :  _size(Size<>(width, lines,1)),_initialized(false), _inMemory(false)
{
    _undef = undef<double>();
    _id = ++_blockid;
    _blockSize = _size.xsize()* _size.ysize();
}

GridBlockInternal::~GridBlockInternal() {

}

Size<> GridBlockInternal::size() const {
    return _size;
}

GridBlockInternal *GridBlockInternal::clone()
{
    GridBlockInternal *block = new GridBlockInternal(_size.xsize(), _size.ysize());
    block->prepare();
    block->_undef = _undef;
    block->_index = 0;
    block->_blockSize = _blockSize;
    if(!isLoaded())
        load();
    std::copy(_data.begin(), _data.end(), block->_data.begin());

    return block;

}

char *GridBlockInternal::blockAsMemory() {
    prepare();
    return (char *)&_data[0];
}

void GridBlockInternal::fill(const std::vector<double>& values) {

    if ( values.size() != _data.size())
        prepare();
    copy(values.begin(), values.end(), _data.begin());

}

quint32 GridBlockInternal::blockSize() {
    return _blockSize;
}

inline bool GridBlockInternal::unload() {
    _inMemory = false;
    if ( _tempName == sUNDEF) {
        QString name = QString("gridblock_%1").arg(_id);
        QDir localDir(context()->cacheLocation().toLocalFile());
        if ( !localDir.exists()) {
            localDir.mkpath(localDir.absolutePath());
        }
        _tempName = localDir.absolutePath() + "/" + name;
    }
    if ( _swapFile.isNull()) {
        _swapFile.reset(new QTemporaryFile(_tempName));

    }
    if(!_swapFile->open() ){
        return ERROR1(ERR_COULD_NOT_OPEN_WRITING_1,_tempName);
    }
    quint64 bytesNeeded = _data.size() * sizeof(double);
    quint64 total =_swapFile->write((char *)&_data[0], bytesNeeded);
    _swapFile->close();
    if ( total != bytesNeeded) {
        return ERROR1(ERR_COULD_NOT_OPEN_WRITING_1,_tempName);
    }
    _initialized = false;
    _data = std::vector<double>();

    return true;

}

bool GridBlockInternal::load() {
     _inMemory = true;
    prepare();
    if ( _tempName == sUNDEF) {
        return true; // totaly new block; never been swapped so no load needed
    }
    quint64 bytesNeeded = _data.size() * sizeof(double);
    if(!_swapFile->open() ){
        return ERROR1(ERR_COULD_NOT_OPEN_READING_1,_tempName);
    }
    quint64 total =_swapFile->read((char *)&_data[0], bytesNeeded);

    _swapFile->close();
    if ( total != bytesNeeded) {
        _inMemory = false;
        return ERROR1(ERR_COULD_NOT_OPEN_READING_1,_tempName);
    }
    return true;

}

//----------------------------------------------------------------------
Grid::Grid(const Size<> &sz,int maxlines) : _maxLines(maxlines){
    //Locker lock(_mutex);

    if ( _maxLines == iUNDEF){
         _maxLines = context()->configurationRef()("system-settings/grid-blocksize",500);
    }
    setSize(sz);
    quint64 bytesNeeded = _size.linearSize() * sizeof(double);
    quint64 mleft = context()->memoryLeft();
    _memUsed = std::min(bytesNeeded, mleft/2);
    context()->changeMemoryLeft(-_memUsed);
    int n = numberOfBlocks();
    _inMemoryIndex = std::max(1ULL, n * _memUsed / bytesNeeded);
    _blocksPerBand = n / sz.zsize();

}

quint32 Grid::blockSize(quint32 index) const {
    if ( index < _blockSizes.size() )
        return _blockSizes[index];
    return iUNDEF;
}

Grid::~Grid() {
    clear();
    context()->changeMemoryLeft(_memUsed);
}

Size<> Grid::size() const {
    return _size;
}

int Grid::maxLines() const
{
    return _maxLines;
}

Grid *Grid::clone(quint32 index1, quint32 index2)
{
    if ( index2 < index1){
        ERROR2(ERR_INVALID_INIT_FOR_2,TR("grid limits"),TR("clone grid"));
        return 0;
    }
    quint32 start = index1 == iUNDEF ? 0 : index1;
    quint32 end = index2 == iUNDEF ? _blocks.size() / _blocksPerBand : index2 + 1;

    Grid *grid = new Grid(Size<>(_size.xsize(), _size.ysize(), end - start), _maxLines);
    grid->prepare();

    quint32 startBlock = start * _blocksPerBand;
    quint32 endBlock = std::min(end * _blocksPerBand, (quint32)_blocks.size());
    for(int i=startBlock, j=0; i < endBlock; ++i, ++j) {
        grid->_blocks[j] = _blocks[i]->clone();
    }
    grid->_inMemoryIndex = 1;
    grid->_memUsed = _memUsed;
    return grid;

}

void Grid::clear() {
    _size = Size<>();
    _blockSizes.clear();
    for(quint32 i = 0; i < _blocks.size(); ++i) {
        delete _blocks[i];
    }
    _blocks.clear();
}

double Grid::value(const Pixel &pix) {
    if (pix.x <0 || pix.y < 0 || pix.x >= _size.xsize() || pix.y >= _size.ysize() )
        return rUNDEF;
   if ( pix.is3D() && (pix.z < 0 || pix.z >= _size.zsize()))
        return rUNDEF;

    quint32 yoff = (qint32)pix.y % _maxLines;
    quint32 block = pix.y / _maxLines;
    quint32 bandBlocks = _blocksPerBand * (pix.is3D() ? pix.z : 0);
    quint32 offset = _offsets[yoff][pix.x];
    return value(bandBlocks + block, offset);
}

inline double &Grid::value(quint32 block, int offset )  {
    if ( _allInMemory ) // no loads needed
        return _blocks[block]->at(offset);

    Locker lock(_mutex); // slower case. must prevent other threads to messup admin
    if ( !_blocks[block]->isLoaded())
      if(!update(block))
          throw ErrorObject(TR("Grid block is out of bounds"));

    return _blocks[block]->at(offset); // block is now in memory
}

inline void Grid::setValue(quint32 block, int offset, double v ) {
    if ( _allInMemory ) {
        _blocks[block]->at(offset) = v;
        return ;
    }

    Locker lock(_mutex);
    if ( !_blocks[block]->isLoaded())
        if(!update(block))
            return ;

    _blocks[block]->at(offset) = v;
}

quint32 Grid::blocks() const {
    return _blocks.size();
}

quint32 Grid::blocksPerBand() const {
    return _blocksPerBand;
}

void Grid::setBlockData(quint32 block, const std::vector<double>& data, bool creation) {
    if ( _allInMemory) { // no cache case
        _blocks[block]->fill(data);
        return ;
    }
    Locker lock(_mutex);
    if(!update(block, creation))
        return ;
    _blocks[_cache[block]]->fill(data);
}

char *Grid::blockAsMemory(quint32 block, bool creation) {
    if ( _allInMemory) { // no cache case
        GridBlockInternal *du = _blocks[block];
        char * p = du->blockAsMemory();
        return p;
    }
    Locker lock(_mutex);
    if(!update(block, creation))
        return 0;
    GridBlockInternal *du = _blocks[_cache[block]];
    char * p = du->blockAsMemory();
    return p;

}

void Grid::setSize(const Size<>& sz) {
    if ( _blocks.size() != 0)
        clear();
    _size = sz;
    if ( _size.zsize() == 0)
        _size.zsize(1); // 1 grid at least in the grid;

}

void Grid::setBandProperties(int n){
    _size.zsize(_size.zsize() + n);
    quint32 oldBlocks = _blocks.size();
    quint32 newBlocks = numberOfBlocks();
    _blocks.resize(newBlocks);
    _blockSizes.resize(newBlocks);
    _blockOffsets.resize(newBlocks);
    qint32 totalLines = _size.ysize();

    for(quint32 block = oldBlocks; block < _blocks.size(); ++block) {
        int linesPerBlock = std::min((qint32)_maxLines, totalLines);
        _blocks[block] = new GridBlockInternal(linesPerBlock, _size.xsize());
        _blockSizes[block] = linesPerBlock * _size.xsize();
        _blockOffsets[block] = block == 0 ? 0 : _blockOffsets[block-1] +  _blockSizes[block];
        totalLines -= _maxLines;
        if ( totalLines <= 0) // to next band
            totalLines = _size.ysize();
    }
}

bool Grid::prepare() {
    Locker lock(_mutex);
    if ( _size.isNull()|| !_size.isValid() || _maxLines == 0) {
        return ERROR0("Grid size not properly initialized");
    }

    int nblocks = numberOfBlocks();
    qint32 totalLines = _size.ysize();
    _blocks.resize(nblocks);
    _blockSizes.resize(nblocks);
    _blockOffsets.resize(nblocks);
    _allInMemory = _blocks.size() <= _inMemoryIndex;

    for(quint32 i = 0; i < _blocks.size(); ++i) {
        int linesPerBlock = std::min((qint32)_maxLines, totalLines);
        _blocks[i] = new GridBlockInternal(linesPerBlock, _size.xsize());
        _blockSizes[i] = linesPerBlock * _size.xsize();
        _blockOffsets[i] = i == 0 ? 0 : _blockOffsets[i-1] +  _blockSizes[i];
        totalLines -= _maxLines;
        if ( totalLines <= 0) // to next band
            totalLines = _size.ysize();
    }
    _offsets.resize(_maxLines);
    for(quint32 y=0; y < _maxLines; ++y) {
        _offsets[y].resize(_size.xsize());
        for(quint32 x=0; x < _size.xsize(); ++x) {
            quint64 linearPos = y * size().xsize() + x;
            _offsets[y][x] = linearPos;
        }
    }
    return true;
}

int Grid::numberOfBlocks() {
    double rblocks = (double)_size.ysize() / _maxLines;
    int nblocks = (int)rblocks;
    double rest = rblocks - nblocks;
    if ( rest >= (1.0 / ( _maxLines + 1))) {
        nblocks++;
    }
    return nblocks * _size.zsize();
}

inline bool Grid::update(quint32 block, bool creation) {
    if ( block >= _blocks.size() ) // illegal, blocknumber is outside the allowed range
        return false;
    if ( !_blocks[block]->isLoaded()) { // if not loaded, load it from the temporary storage
        try{
        if(!_blocks[block]->load()){
            return false;
        }
        } catch (const OutOfMemoryError& err){ // probably exceeded memory cappacity, unload the blocks and try again.
            unload(false);
            if(!_blocks[block]->load()){
                return false;
            }

        }
    }
    if ( creation || _cache.size() == 0) { // at create time we want to preserver the original order in memory

        if ( block > _inMemoryIndex )
            _blocks[_cache.back()]->unload();
        _cache.push_back(block);
    }
    else if ( _cache.front() != block) {
        int index = _cache.indexOf(block);
        if (index >=0) { //  find the block and move it to the front of the list; blocks that are in use are at the front to prevent them being unloaded
            _cache.removeOne(index);
        }
        _cache.push_front(block); // block has now priority; if the block was not already in the list, the list will grow
        if ( index > (int)_inMemoryIndex) { // the index is bigger than allowed, so the last element of the list is unloaded
            return _blocks[_cache[_inMemoryIndex]]->unload();
        }

    }
    return true;
}

void Grid::unloadInternal(){
    _cache.clear();
    for(GridBlockInternal *block : _blocks) {
        block->unload();
    }
    _inMemoryIndex = 0;
}

void Grid::unload(bool uselock) {
    if ( uselock) {
        Locker lock(_mutex);
        unloadInternal();
    }else
        unloadInternal();
}

<commit_msg>added delayed loading of blocks<commit_after>#include "kernel.h"
#include "ilwiscontext.h"
#include "connectorinterface.h"
#include "geometries.h"
#include "raster.h"
#include "grid.h"

using namespace Ilwis;
GridBlockInternal::GridBlockInternal(quint32 blocknr, quint64 rasterid,quint32 lines , quint32 width) :  _size(Size<>(width, lines,1)),_id(blocknr),_rasterid(rasterid), _initialized(false), _inMemory(false)
{
    _undef = undef<double>();
    _blockSize = _size.xsize()* _size.ysize();
}

GridBlockInternal::~GridBlockInternal() {

}

Size<> GridBlockInternal::size() const {
    return _size;
}

GridBlockInternal *GridBlockInternal::clone()
{
    GridBlockInternal *block = new GridBlockInternal(_id, i64UNDEF, _size.xsize(), _size.ysize());
    block->prepare();
    block->_undef = _undef;
    block->_blockSize = _blockSize;
    if(!inMemory())
        loadFromCache();
    else if (!_initialized){
        needData();
    }
    std::copy(_data.begin(), _data.end(), block->_data.begin());

    return block;

}

char *GridBlockInternal::blockAsMemory() {
    prepare();
    return (char *)&_data[0];
}

void GridBlockInternal::fill(const std::vector<double>& values) {

    if ( values.size() != _data.size())
        prepare();
    copy(values.begin(), values.end(), _data.begin());

}

quint32 GridBlockInternal::blockSize() {
    return _blockSize;
}

inline bool GridBlockInternal::save2Cache() {
    _inMemory = false;
    if ( _tempName == sUNDEF) {
        QString name = QString("gridblock_%1").arg(_id);
        QDir localDir(context()->cacheLocation().toLocalFile());
        if ( !localDir.exists()) {
            localDir.mkpath(localDir.absolutePath());
        }
        _tempName = localDir.absolutePath() + "/" + name;
    }
    if ( _swapFile.isNull()) {
        _swapFile.reset(new QTemporaryFile(_tempName));

    }
    if(!_swapFile->open() ){
        return ERROR1(ERR_COULD_NOT_OPEN_WRITING_1,_tempName);
    }
    quint64 bytesNeeded = _data.size() * sizeof(double);
    quint64 total =_swapFile->write((char *)&_data[0], bytesNeeded);
    _swapFile->close();
    if ( total != bytesNeeded) {
        return ERROR1(ERR_COULD_NOT_OPEN_WRITING_1,_tempName);
    }
    _initialized = false;
    _data = std::vector<double>();

    return true;

}

bool GridBlockInternal::loadFromCache() {
     _inMemory = true;
    prepare();
    if ( _tempName == sUNDEF) {
        return true; // totaly new block; never been swapped so no load needed
    }
    quint64 bytesNeeded = _data.size() * sizeof(double);
    if(!_swapFile->open() ){
        return ERROR1(ERR_COULD_NOT_OPEN_READING_1,_tempName);
    }
    quint64 total =_swapFile->read((char *)&_data[0], bytesNeeded);

    _swapFile->close();
    if ( total != bytesNeeded) {
        _inMemory = false;
        return ERROR1(ERR_COULD_NOT_OPEN_READING_1,_tempName);
    }
    return true;

}

void GridBlockInternal::needData()
{
    IIlwisObject obj = mastercatalog()->get(_rasterid);
    if ( obj.isValid()){
        IRasterCoverage raster = obj.as<RasterCoverage>();
        raster->getData(_id);
    }
}

//----------------------------------------------------------------------
Grid::Grid(int maxlines) : _inMemoryIndex(iUNDEF), _memUsed(0),_blocksPerBand(0), _maxLines(maxlines){
    //Locker lock(_mutex);

    if ( _maxLines == iUNDEF){
         _maxLines = context()->configurationRef()("system-settings/grid-blocksize",500);
    }
}

quint32 Grid::blockSize(quint32 index) const {
    if ( index < _blockSizes.size() )
        return _blockSizes[index];
    return iUNDEF;
}

Grid::~Grid() {
    clear();
    context()->changeMemoryLeft(_memUsed);
}

Size<> Grid::size() const {
    return _size;
}

int Grid::maxLines() const
{
    return _maxLines;
}

Grid *Grid::clone(quint32 index1, quint32 index2)
{
    if ( index2 < index1){
        ERROR2(ERR_INVALID_INIT_FOR_2,TR("grid limits"),TR("clone grid"));
        return 0;
    }
    quint32 start = index1 == iUNDEF ? 0 : index1;
    quint32 end = index2 == iUNDEF ? _blocks.size() / _blocksPerBand : index2 + 1;

    Grid *grid = new Grid(_maxLines);
    grid->prepare(0,Size<>(_size.xsize(), _size.ysize(), end - start));

    quint32 startBlock = start * _blocksPerBand;
    quint32 endBlock = std::min(end * _blocksPerBand, (quint32)_blocks.size());
    for(int i=startBlock, j=0; i < endBlock; ++i, ++j) {
        grid->_blocks[j] = _blocks[i]->clone();
    }
    grid->_inMemoryIndex = 1;
    grid->_memUsed = _memUsed;
    return grid;

}

void Grid::clear() {
    _size = Size<>();
    _blockSizes = std::vector<quint32>();
    for(quint32 i = 0; i < _blocks.size(); ++i) {
        delete _blocks[i];
    }
    _blocks = std::vector< GridBlockInternal *>();
    _cache = QList<quint32>();
    _blockSizes =  std::vector<quint32>();
    _offsets = std::vector<std::vector<quint32>>();
    _blockOffsets = std::vector<quint32>();
    _inMemoryIndex = iUNDEF;
    _allInMemory = false;
    _size = Size<>();

}

double Grid::value(const Pixel &pix) {
    if (pix.x <0 || pix.y < 0 || pix.x >= _size.xsize() || pix.y >= _size.ysize() )
        return rUNDEF;
   if ( pix.is3D() && (pix.z < 0 || pix.z >= _size.zsize()))
        return rUNDEF;

    quint32 yoff = (qint32)pix.y % _maxLines;
    quint32 block = pix.y / _maxLines;
    quint32 bandBlocks = _blocksPerBand * (pix.is3D() ? pix.z : 0);
    quint32 offset = _offsets[yoff][pix.x];
    return value(bandBlocks + block, offset);
}

inline double &Grid::value(quint32 block, int offset )  {
    if ( _allInMemory ) // no loads needed
        return _blocks[block]->at(offset);

    Locker lock(_mutex); // slower case. must prevent other threads to messup admin
    if ( !_blocks[block]->inMemory())
      if(!update(block))
          throw ErrorObject(TR("Grid block is out of bounds"));

    return _blocks[block]->at(offset); // block is now in memory
}

inline void Grid::setValue(quint32 block, int offset, double v ) {
    if ( _allInMemory ) {
        _blocks[block]->at(offset) = v;
        return ;
    }

    Locker lock(_mutex);
    if ( !_blocks[block]->inMemory())
        if(!update(block))
            return ;

    _blocks[block]->at(offset) = v;
}

quint32 Grid::blocks() const {
    return _blocks.size();
}

quint32 Grid::blocksPerBand() const {
    return _blocksPerBand;
}

void Grid::setBlockData(quint32 block, const std::vector<double>& data, bool creation) {
    if ( _allInMemory) { // no cache case
        _blocks[block]->fill(data);
        return ;
    }
    Locker lock(_mutex);
    if(!update(block, creation))
        return ;
    _blocks[_cache[block]]->fill(data);
}

char *Grid::blockAsMemory(quint32 block, bool creation) {
    if ( _allInMemory) { // no cache case
        GridBlockInternal *du = _blocks[block];
        char * p = du->blockAsMemory();
        return p;
    }
    Locker lock(_mutex);
    if(!update(block, creation))
        return 0;
    GridBlockInternal *du = _blocks[_cache[block]];
    char * p = du->blockAsMemory();
    return p;

}

void Grid::setBandProperties(RasterCoverage *raster, int n){
    _size.zsize(_size.zsize() + n);
    quint32 oldBlocks = _blocks.size();
    quint32 newBlocks = numberOfBlocks();
    _blocks.resize(newBlocks);
    _blockSizes.resize(newBlocks);
    _blockOffsets.resize(newBlocks);
    qint32 totalLines = _size.ysize();

    for(quint32 block = oldBlocks; block < _blocks.size(); ++block) {
        int linesPerBlock = std::min((qint32)_maxLines, totalLines);
        _blocks[block] = new GridBlockInternal(block,raster ? raster->id() : i64UNDEF,linesPerBlock, _size.xsize());
        _blockSizes[block] = linesPerBlock * _size.xsize();
        _blockOffsets[block] = block == 0 ? 0 : _blockOffsets[block-1] +  _blockSizes[block];
        totalLines -= _maxLines;
        if ( totalLines <= 0) // to next band
            totalLines = _size.ysize();
    }
}

bool Grid::prepare(RasterCoverage *raster, const Size<> &sz) {
    Locker lock(_mutex);

    clear();
    _size = sz;

    if ( _size.isNull()|| !_size.isValid() || _maxLines == 0) {
        return false;
    }

    if ( _size.zsize() == 0)
        _size.zsize(1);
    quint64 bytesNeeded = _size.linearSize() * sizeof(double);
    quint64 mleft = context()->memoryLeft();
    _memUsed = std::min(bytesNeeded, mleft/2);
    context()->changeMemoryLeft(-_memUsed);
    int n = numberOfBlocks();
    _inMemoryIndex = std::max(1ULL, n * _memUsed / bytesNeeded);
    _blocksPerBand = n / sz.zsize();

    int nblocks = numberOfBlocks();
    qint32 totalLines = _size.ysize();
    _blocks.resize(nblocks);
    _blockSizes.resize(nblocks);
    _blockOffsets.resize(nblocks);
    _allInMemory = _blocks.size() <= _inMemoryIndex;

    for(quint32 i = 0; i < _blocks.size(); ++i) {
        int linesPerBlock = std::min((qint32)_maxLines, totalLines);
        _blocks[i] = new GridBlockInternal(i, raster ? raster->id() : i64UNDEF,linesPerBlock, _size.xsize());
        _blockSizes[i] = linesPerBlock * _size.xsize();
        _blockOffsets[i] = i == 0 ? 0 : _blockOffsets[i-1] +  _blockSizes[i];
        totalLines -= _maxLines;
        if ( totalLines <= 0) // to next band
            totalLines = _size.ysize();
    }
    _offsets.resize(_maxLines);
    for(quint32 y=0; y < _maxLines; ++y) {
        _offsets[y].resize(_size.xsize());
        for(quint32 x=0; x < _size.xsize(); ++x) {
            quint64 linearPos = y * size().xsize() + x;
            _offsets[y][x] = linearPos;
        }
    }
    return true;
}

int Grid::numberOfBlocks() {
    double rblocks = (double)_size.ysize() / _maxLines;
    int nblocks = (int)rblocks;
    double rest = rblocks - nblocks;
    if ( rest >= (1.0 / ( _maxLines + 1))) {
        nblocks++;
    }
    return nblocks * _size.zsize();
}

inline bool Grid::update(quint32 block, bool creation) {
    if ( block >= _blocks.size() ) // illegal, blocknumber is outside the allowed range
        return false;
    if ( !_blocks[block]->inMemory()) { // if not loaded, load it from the temporary storage
        try{
        if(!_blocks[block]->loadFromCache()){
            return false;
        }
        } catch (const OutOfMemoryError& err){ // probably exceeded memory cappacity, unload the blocks and try again.
            unload(false);
            if(!_blocks[block]->loadFromCache()){
                return false;
            }

        }
    }
    if ( creation || _cache.size() == 0) { // at create time we want to preserver the original order in memory

        if ( block > _inMemoryIndex )
            _blocks[_cache.back()]->save2Cache();
        _cache.push_back(block);
    }
    else if ( _cache.front() != block) {
        int index = _cache.indexOf(block);
        if (index >=0) { //  find the block and move it to the front of the list; blocks that are in use are at the front to prevent them being unloaded
            _cache.removeOne(index);
        }
        _cache.push_front(block); // block has now priority; if the block was not already in the list, the list will grow
        if ( index > (int)_inMemoryIndex) { // the index is bigger than allowed, so the last element of the list is unloaded
            return _blocks[_cache[_inMemoryIndex]]->save2Cache();
        }

    }
    return true;
}

void Grid::unloadInternal(){
    _cache.clear();
    for(GridBlockInternal *block : _blocks) {
        block->save2Cache();
    }
    _inMemoryIndex = 0;
}

void Grid::unload(bool uselock) {
    if ( uselock) {
        Locker lock(_mutex);
        unloadInternal();
    }else
        unloadInternal();
}

std::map<quint32, std::vector<quint32> > Grid::calcBlockLimits(const LoadOptions& options ){
    std::map<quint32, std::vector<quint32> > result;
    int blockplayer = blocksPerBand();
    if ( options._values.size() == 0){
        quint32 lastblock = 0;
        for(int layer = 0; layer < size().zsize(); ++layer){
            for(int block = 0; block < blockplayer; ++block){
                result[layer].push_back(lastblock + block);
            }
            lastblock += blockplayer;
        }
    }else {
        auto iter = options._values.find("blockindex");
        if ( iter != options._values.end()){
            quint32 index = iter->second.toUInt();
            int layer = index / blockplayer;
            result[layer].push_back(index);
        }

    }

    return result;

}

bool Grid::isValid() const
{
    return !(_size.isNull() || _size.isValid() || _inMemoryIndex == iUNDEF);
}

<|endoftext|>


<commit_before>#include <basedefs.h>
#include "../userinfo.h"
#include <string>
#include <sstream>

namespace anp
{
namespace firc
{
	struct UserInfoImpl
	{
		UserInfoImpl(const std::string &name, const std::string &user,
												const std::string &host):
		m_name(name),
		m_user(user),
		m_host(host),
		m_userStringIsDirty(true)
		{
		}

		void updateUserString() const
		{
			if ( m_userStringIsDirty )
			{
				std::stringstream ss;
				ss << m_name << '!' << m_user << '@' << m_host;
				m_userString = ss.str();
				m_userStringIsDirty = false;
			}
		}

		void invalidateUserString() const
		{
			m_userStringIsDirty = true;
		}

		std::string m_name;
		std::string m_user;
		std::string m_host;
		mutable std::string m_userString;
		mutable bool32 m_userStringIsDirty;
	};

	UserInfo::UserInfo(const std::string &name, const std::string &user,
											const std::string &host):
	m_impl(new UserInfoImpl(name, user, host))
	{
		m_impl->updateUserString();
	}

	const std::string &UserInfo::name() const
	{
		return m_impl->m_name;
	}

	const std::string &UserInfo::user() const
	{
		return m_impl->m_user;
	}

	const std::string &UserInfo::host() const
	{
		return m_impl->m_host;
	}

	const std::string &UserInfo::userString() const
	{
		m_impl->updateUserString();
		return m_impl->m_userString;
	}

	void UserInfo::setName(const std::string &name)
	{
		m_impl->m_name = name;
		m_impl->invalidateUserString();
	}

	void UserInfo::setUser(const std::string &user)
	{
		m_impl->m_user = user;
		m_impl->invalidateUserString();
	}

	void UserInfo::setHost(const std::string &host)
	{
		m_impl->m_host = host;
		m_impl->invalidateUserString();
	}
}
}
<commit_msg>Implemented missing UserInfo destructor.<commit_after>#include <basedefs.h>
#include "../userinfo.h"
#include <string>
#include <sstream>

namespace anp
{
namespace firc
{
	struct UserInfoImpl
	{
		UserInfoImpl(const std::string &name, const std::string &user,
												const std::string &host):
		m_name(name),
		m_user(user),
		m_host(host),
		m_userStringIsDirty(true)
		{
		}

		void updateUserString() const
		{
			if ( m_userStringIsDirty )
			{
				std::stringstream ss;
				ss << m_name << '!' << m_user << '@' << m_host;
				m_userString = ss.str();
				m_userStringIsDirty = false;
			}
		}

		void invalidateUserString() const
		{
			m_userStringIsDirty = true;
		}

		std::string m_name;
		std::string m_user;
		std::string m_host;
		mutable std::string m_userString;
		mutable bool32 m_userStringIsDirty;
	};

	UserInfo::UserInfo(const std::string &name, const std::string &user,
											const std::string &host):
	m_impl(new UserInfoImpl(name, user, host))
	{
		m_impl->updateUserString();
	}

	UserInfo::~UserInfo()
	{
		delete m_impl;
	}

	const std::string &UserInfo::name() const
	{
		return m_impl->m_name;
	}

	const std::string &UserInfo::user() const
	{
		return m_impl->m_user;
	}

	const std::string &UserInfo::host() const
	{
		return m_impl->m_host;
	}

	const std::string &UserInfo::userString() const
	{
		m_impl->updateUserString();
		return m_impl->m_userString;
	}

	void UserInfo::setName(const std::string &name)
	{
		m_impl->m_name = name;
		m_impl->invalidateUserString();
	}

	void UserInfo::setUser(const std::string &user)
	{
		m_impl->m_user = user;
		m_impl->invalidateUserString();
	}

	void UserInfo::setHost(const std::string &host)
	{
		m_impl->m_host = host;
		m_impl->invalidateUserString();
	}
}
}
<|endoftext|>