<commit_before>/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2008 by Sun Microsystems, Inc.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * $RCSfile: redline.hxx,v $
 * $Revision: 1.13 $
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org 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 version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/
#ifndef _REDLINE_HXX
#define _REDLINE_HXX

#include <tools/datetime.hxx>
#include <tools/string.hxx>

#define _SVSTDARR_USHORTS
#include <svtools/svstdarr.hxx>
#include <pam.hxx>

#ifndef IDOCUMENTREDLINEACCESS_HXX_INCLUDED
#include <IDocumentRedlineAccess.hxx>
#endif

class SfxItemSet;

class SwRedlineExtraData
{
    SwRedlineExtraData( const SwRedlineExtraData& );
    SwRedlineExtraData& operator=( const SwRedlineExtraData& );

protected:
    SwRedlineExtraData() {}

public:
    virtual ~SwRedlineExtraData();
    virtual SwRedlineExtraData* CreateNew() const = 0;

    virtual void Accept( SwPaM& rPam ) const;
    virtual void Reject( SwPaM& rPam ) const;
    virtual int operator == ( const SwRedlineExtraData& ) const;
};

class SwRedlineExtraData_FmtColl : public SwRedlineExtraData
{
    String sFmtNm;
    SfxItemSet* pSet;
    USHORT nPoolId;
public:
    SwRedlineExtraData_FmtColl( const String& rColl, USHORT nPoolFmtId,
                                const SfxItemSet* pSet = 0 );
    virtual ~SwRedlineExtraData_FmtColl();
    virtual SwRedlineExtraData* CreateNew() const;
    virtual void Reject( SwPaM& rPam ) const;
    virtual int operator == ( const SwRedlineExtraData& ) const;

    void SetItemSet( const SfxItemSet& rSet );
};

class SwRedlineExtraData_Format : public SwRedlineExtraData
{
    SvUShorts aWhichIds;

    SwRedlineExtraData_Format( const SwRedlineExtraData_Format& rCpy );

public:
    SwRedlineExtraData_Format( const SfxItemSet& rSet );
    virtual ~SwRedlineExtraData_Format();
    virtual SwRedlineExtraData* CreateNew() const;
    virtual void Reject( SwPaM& rPam ) const;
    virtual int operator == ( const SwRedlineExtraData& ) const;
};

class SwRedlineData
{
    friend class SwRedline;
    SwRedlineData* pNext;       // Verweis auf weitere Daten
    SwRedlineExtraData* pExtraData;

    String sComment;
    DateTime aStamp;
    RedlineType_t eType;
    USHORT nAuthor, nSeqNo;

public:
    SwRedlineData( RedlineType_t eT, USHORT nAut );
    SwRedlineData( const SwRedlineData& rCpy, BOOL bCpyNext = TRUE );

    // fuer sw3io: pNext/pExtraData gehen in eigenen Besitz ueber!
    SwRedlineData( RedlineType_t eT, USHORT nAut, const DateTime& rDT,
                   const String& rCmnt, SwRedlineData* pNxt,
                    SwRedlineExtraData* pExtraData = 0 );

    ~SwRedlineData();

    int operator==( const SwRedlineData& rCmp ) const
        {
            return nAuthor == rCmp.nAuthor &&
                    eType == rCmp.eType &&
                    sComment == rCmp.sComment &&
                    (( !pNext && !rCmp.pNext ) ||
                        ( pNext && rCmp.pNext && *pNext == *rCmp.pNext )) &&
                    (( !pExtraData && !rCmp.pExtraData ) ||
                        ( pExtraData && rCmp.pExtraData &&
                            *pExtraData == *rCmp.pExtraData ));
        }
    int operator!=( const SwRedlineData& rCmp ) const
        {   return !operator==( rCmp ); }

    RedlineType_t GetType() const
  { return ((RedlineType_t)(eType & nsRedlineType_t::REDLINE_NO_FLAG_MASK)); }
    RedlineType_t GetRealType() const { return eType; }
    USHORT GetAuthor() const                { return nAuthor; }
    const String& GetComment() const        { return sComment; }
    const DateTime& GetTimeStamp() const    { return aStamp; }
    inline const SwRedlineData* Next() const{ return pNext; }

    void SetComment( const String& rS )     { sComment = rS; }
    void SetAutoFmtFlag()
  { eType = (RedlineType_t)(eType | nsRedlineType_t::REDLINE_FORM_AUTOFMT); }
    int CanCombine( const SwRedlineData& rCmp ) const
        {
            return nAuthor == rCmp.nAuthor &&
                    eType == rCmp.eType &&
                    sComment == rCmp.sComment &&
                    GetTimeStamp() == rCmp.GetTimeStamp() &&
                    (( !pNext && !rCmp.pNext ) ||
                        ( pNext && rCmp.pNext &&
                        pNext->CanCombine( *rCmp.pNext ))) &&
                    (( !pExtraData && !rCmp.pExtraData ) ||
                        ( pExtraData && rCmp.pExtraData &&
                            *pExtraData == *rCmp.pExtraData ));
        }

    // ExtraData wird kopiert, der Pointer geht also NICHT in den Besitz
    // des RedlineObjectes!
    void SetExtraData( const SwRedlineExtraData* pData );
    const SwRedlineExtraData* GetExtraData() const { return pExtraData; }

    // fuers UI-seitige zusammenfassen von Redline-Actionen. Wird z.Z. nur
    // fuers Autoformat mit Redline benoetigt. Der Wert != 0 bedeutet dabei,
    // das es noch weitere geben kann!
    USHORT GetSeqNo() const                     { return nSeqNo; }
    void SetSeqNo( USHORT nNo )                 { nSeqNo = nNo; }

    String GetDescr() const;
};

class SwRedline : public SwPaM
{
    SwRedlineData* pRedlineData;
    SwNodeIndex* pCntntSect;
    BOOL bDelLastPara : 1;
    BOOL bIsLastParaDelete : 1;
    BOOL bIsVisible : 1;

    void MoveToSection();
    void CopyToSection();
    void DelCopyOfSection();
    void MoveFromSection();

public:
    SwRedline( RedlineType_t eType, const SwPaM& rPam );
    SwRedline( const SwRedlineData& rData, const SwPaM& rPam );
    SwRedline( const SwRedlineData& rData, const SwPosition& rPos );
    // fuer sw3io: pData geht in eigenen Besitz ueber!
    SwRedline(SwRedlineData* pData, const SwPosition& rPos, BOOL bVsbl,
               BOOL bDelLP, BOOL bIsPD) :
        SwPaM( rPos ), pRedlineData( pData ), pCntntSect( 0 ),
        bDelLastPara( bDelLP ), bIsLastParaDelete( bIsPD ), bIsVisible( bVsbl )
    {}
    SwRedline( const SwRedline& );
    virtual ~SwRedline();

    SwNodeIndex* GetContentIdx() const { return pCntntSect; }
    // fuers Undo
    void SetContentIdx( const SwNodeIndex* );

    BOOL IsVisible() const { return bIsVisible; }
    BOOL IsDelLastPara() const { return bDelLastPara; }

    // das BOOL besagt, ob nach dem setzen der Pos kein Bereich mehr
    // aufgespannt ist. -> TRUE, ansonten Bereich und FALSE
    void SetStart( const SwPosition& rPos, SwPosition* pSttPtr = 0 )
    {
        if( !pSttPtr ) pSttPtr = Start();
        *pSttPtr = rPos;
    }
    void SetEnd( const SwPosition& rPos, SwPosition* pEndPtr = 0 )
    {
        if( !pEndPtr ) pEndPtr = End();
        *pEndPtr = rPos;
    }
    // liegt eine gueltige Selektion vor?
    BOOL HasValidRange() const;

    const SwRedlineData& GetRedlineData(USHORT nPos = 0) const;
    int operator==( const SwRedlineData& rCmp ) const
        { return *pRedlineData == rCmp; }
    int operator!=( const SwRedlineData& rCmp ) const
        { return *pRedlineData != rCmp; }
    void SetAutoFmtFlag()               { pRedlineData->SetAutoFmtFlag(); }

    USHORT GetStackCount() const;
    USHORT GetAuthor( USHORT nPos = 0) const;
    const String& GetAuthorString( USHORT nPos = 0 ) const;
    const DateTime& GetTimeStamp( USHORT nPos = 0) const;
    RedlineType_t GetRealType( USHORT nPos = 0 ) const;
    RedlineType_t GetType( USHORT nPos = 0) const
  { return ( (RedlineType_t)(GetRealType( nPos ) & nsRedlineType_t::REDLINE_NO_FLAG_MASK)); }
    const String& GetComment( USHORT nPos = 0 ) const;

    void SetComment( const String& rS ) { pRedlineData->SetComment( rS ); }

    // ExtraData wird kopiert, der Pointer geht also NICHT in den Besitz
    // des RedlineObjectes!
    void SetExtraData( const SwRedlineExtraData* pData )
        { pRedlineData->SetExtraData( pData ); }
    const SwRedlineExtraData* GetExtraData() const
        { return pRedlineData->GetExtraData(); }

    // fuers UI-seitige zusammenfassen von Redline-Actionen. Wird z.Z. nur
    // fuers Autoformat mit Redline benoetigt. Der Wert != 0 bedeutet dabei,
    // das es noch weitere geben kann!
    USHORT GetSeqNo() const             { return pRedlineData->GetSeqNo(); }
    void SetSeqNo( USHORT nNo )         { pRedlineData->SetSeqNo( nNo ); }

    // Beim Hide/ShowOriginal wird 2 mal ueber die Liste gelaufen, damit
    //  die Del-Redlines per Copy und Delete versteckt werden. Beim Move
    //  wird sonst die Attributierung falsch behandelt.
    // Alle anderen Aufrufer muessen immer 0 angeben.
    void CallDisplayFunc( USHORT nLoop = 0 );
    void Show( USHORT nLoop = 0 );
    void Hide( USHORT nLoop = 0 );
    void ShowOriginal( USHORT nLoop = 0 );

    // calculates the intersection with text node number nNdIdx
    void CalcStartEnd( ULONG nNdIdx, USHORT& nStart, USHORT& nEnd ) const;

    void InvalidateRange();     // das Layout anstossen

    BOOL IsOwnRedline( const SwRedline& rRedl ) const
        { return GetAuthor() == rRedl.GetAuthor(); }
    BOOL CanCombine( const SwRedline& rRedl ) const;

    void PushData( const SwRedline& rRedl, BOOL bOwnAsNext = TRUE );
    BOOL PopData();

    // #111827#
    /**
       Returns textual description of this a redline data element of
       this redline.

       @param nPos index of the redline data element to describe

       The textual description of the selected element contains the
       kind of redline and the possibly shortened text of the redline.

       @return textual description of the selected redline data element
     */
    String GetDescr(USHORT nPos = 0);

    int operator==( const SwRedline& ) const;
    int operator<( const SwRedline& ) const;
};

#endif
<commit_msg>INTEGRATION: CWS xmlfilter04 (1.12.198); FILE MERGED 2008/03/17 13:43:45 os 1.12.198.1: #i86953# creating redlines via API<commit_after>/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2008 by Sun Microsystems, Inc.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * $RCSfile: redline.hxx,v $
 * $Revision: 1.14 $
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org 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 version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/
#ifndef _REDLINE_HXX
#define _REDLINE_HXX

#include <tools/datetime.hxx>
#include <tools/string.hxx>

#define _SVSTDARR_USHORTS
#include <svtools/svstdarr.hxx>
#include <pam.hxx>

#ifndef IDOCUMENTREDLINEACCESS_HXX_INCLUDED
#include <IDocumentRedlineAccess.hxx>
#endif

class SfxItemSet;

class SwRedlineExtraData
{
    SwRedlineExtraData( const SwRedlineExtraData& );
    SwRedlineExtraData& operator=( const SwRedlineExtraData& );

protected:
    SwRedlineExtraData() {}

public:
    virtual ~SwRedlineExtraData();
    virtual SwRedlineExtraData* CreateNew() const = 0;

    virtual void Accept( SwPaM& rPam ) const;
    virtual void Reject( SwPaM& rPam ) const;
    virtual int operator == ( const SwRedlineExtraData& ) const;
};

class SwRedlineExtraData_FmtColl : public SwRedlineExtraData
{
    String sFmtNm;
    SfxItemSet* pSet;
    USHORT nPoolId;
public:
    SwRedlineExtraData_FmtColl( const String& rColl, USHORT nPoolFmtId,
                                const SfxItemSet* pSet = 0 );
    virtual ~SwRedlineExtraData_FmtColl();
    virtual SwRedlineExtraData* CreateNew() const;
    virtual void Reject( SwPaM& rPam ) const;
    virtual int operator == ( const SwRedlineExtraData& ) const;

    void SetItemSet( const SfxItemSet& rSet );
};

class SwRedlineExtraData_Format : public SwRedlineExtraData
{
    SvUShorts aWhichIds;

    SwRedlineExtraData_Format( const SwRedlineExtraData_Format& rCpy );

public:
    SwRedlineExtraData_Format( const SfxItemSet& rSet );
    virtual ~SwRedlineExtraData_Format();
    virtual SwRedlineExtraData* CreateNew() const;
    virtual void Reject( SwPaM& rPam ) const;
    virtual int operator == ( const SwRedlineExtraData& ) const;
};

class SwRedlineData
{
    friend class SwRedline;
    SwRedlineData* pNext;       // Verweis auf weitere Daten
    SwRedlineExtraData* pExtraData;

    String sComment;
    DateTime aStamp;
    RedlineType_t eType;
    USHORT nAuthor, nSeqNo;

public:
    SwRedlineData( RedlineType_t eT, USHORT nAut );
    SwRedlineData( const SwRedlineData& rCpy, BOOL bCpyNext = TRUE );

    // fuer sw3io: pNext/pExtraData gehen in eigenen Besitz ueber!
    SwRedlineData( RedlineType_t eT, USHORT nAut, const DateTime& rDT,
                   const String& rCmnt, SwRedlineData* pNxt,
                    SwRedlineExtraData* pExtraData = 0 );

    ~SwRedlineData();

    int operator==( const SwRedlineData& rCmp ) const
        {
            return nAuthor == rCmp.nAuthor &&
                    eType == rCmp.eType &&
                    sComment == rCmp.sComment &&
                    (( !pNext && !rCmp.pNext ) ||
                        ( pNext && rCmp.pNext && *pNext == *rCmp.pNext )) &&
                    (( !pExtraData && !rCmp.pExtraData ) ||
                        ( pExtraData && rCmp.pExtraData &&
                            *pExtraData == *rCmp.pExtraData ));
        }
    int operator!=( const SwRedlineData& rCmp ) const
        {   return !operator==( rCmp ); }

    RedlineType_t GetType() const
  { return ((RedlineType_t)(eType & nsRedlineType_t::REDLINE_NO_FLAG_MASK)); }
    RedlineType_t GetRealType() const { return eType; }
    USHORT GetAuthor() const                { return nAuthor; }
    const String& GetComment() const        { return sComment; }
    const DateTime& GetTimeStamp() const    { return aStamp; }
    inline const SwRedlineData* Next() const{ return pNext; }

    void SetComment( const String& rS )     { sComment = rS; }
    void SetTimeStamp( const DateTime& rDT ) { aStamp = rDT; }

    void SetAutoFmtFlag()
  { eType = (RedlineType_t)(eType | nsRedlineType_t::REDLINE_FORM_AUTOFMT); }
    int CanCombine( const SwRedlineData& rCmp ) const
        {
            return nAuthor == rCmp.nAuthor &&
                    eType == rCmp.eType &&
                    sComment == rCmp.sComment &&
                    GetTimeStamp() == rCmp.GetTimeStamp() &&
                    (( !pNext && !rCmp.pNext ) ||
                        ( pNext && rCmp.pNext &&
                        pNext->CanCombine( *rCmp.pNext ))) &&
                    (( !pExtraData && !rCmp.pExtraData ) ||
                        ( pExtraData && rCmp.pExtraData &&
                            *pExtraData == *rCmp.pExtraData ));
        }

    // ExtraData wird kopiert, der Pointer geht also NICHT in den Besitz
    // des RedlineObjectes!
    void SetExtraData( const SwRedlineExtraData* pData );
    const SwRedlineExtraData* GetExtraData() const { return pExtraData; }

    // fuers UI-seitige zusammenfassen von Redline-Actionen. Wird z.Z. nur
    // fuers Autoformat mit Redline benoetigt. Der Wert != 0 bedeutet dabei,
    // das es noch weitere geben kann!
    USHORT GetSeqNo() const                     { return nSeqNo; }
    void SetSeqNo( USHORT nNo )                 { nSeqNo = nNo; }

    String GetDescr() const;
};

class SwRedline : public SwPaM
{
    SwRedlineData* pRedlineData;
    SwNodeIndex* pCntntSect;
    BOOL bDelLastPara : 1;
    BOOL bIsLastParaDelete : 1;
    BOOL bIsVisible : 1;

    void MoveToSection();
    void CopyToSection();
    void DelCopyOfSection();
    void MoveFromSection();

public:
    SwRedline( RedlineType_t eType, const SwPaM& rPam );
    SwRedline( const SwRedlineData& rData, const SwPaM& rPam );
    SwRedline( const SwRedlineData& rData, const SwPosition& rPos );
    // fuer sw3io: pData geht in eigenen Besitz ueber!
    SwRedline(SwRedlineData* pData, const SwPosition& rPos, BOOL bVsbl,
               BOOL bDelLP, BOOL bIsPD) :
        SwPaM( rPos ), pRedlineData( pData ), pCntntSect( 0 ),
        bDelLastPara( bDelLP ), bIsLastParaDelete( bIsPD ), bIsVisible( bVsbl )
    {}
    SwRedline( const SwRedline& );
    virtual ~SwRedline();

    SwNodeIndex* GetContentIdx() const { return pCntntSect; }
    // fuers Undo
    void SetContentIdx( const SwNodeIndex* );

    BOOL IsVisible() const { return bIsVisible; }
    BOOL IsDelLastPara() const { return bDelLastPara; }

    // das BOOL besagt, ob nach dem setzen der Pos kein Bereich mehr
    // aufgespannt ist. -> TRUE, ansonten Bereich und FALSE
    void SetStart( const SwPosition& rPos, SwPosition* pSttPtr = 0 )
    {
        if( !pSttPtr ) pSttPtr = Start();
        *pSttPtr = rPos;
    }
    void SetEnd( const SwPosition& rPos, SwPosition* pEndPtr = 0 )
    {
        if( !pEndPtr ) pEndPtr = End();
        *pEndPtr = rPos;
    }
    // liegt eine gueltige Selektion vor?
    BOOL HasValidRange() const;

    const SwRedlineData& GetRedlineData(USHORT nPos = 0) const;
    int operator==( const SwRedlineData& rCmp ) const
        { return *pRedlineData == rCmp; }
    int operator!=( const SwRedlineData& rCmp ) const
        { return *pRedlineData != rCmp; }
    void SetAutoFmtFlag()               { pRedlineData->SetAutoFmtFlag(); }

    USHORT GetStackCount() const;
    USHORT GetAuthor( USHORT nPos = 0) const;
    const String& GetAuthorString( USHORT nPos = 0 ) const;
    const DateTime& GetTimeStamp( USHORT nPos = 0) const;
    RedlineType_t GetRealType( USHORT nPos = 0 ) const;
    RedlineType_t GetType( USHORT nPos = 0) const
  { return ( (RedlineType_t)(GetRealType( nPos ) & nsRedlineType_t::REDLINE_NO_FLAG_MASK)); }
    const String& GetComment( USHORT nPos = 0 ) const;

    void SetComment( const String& rS ) { pRedlineData->SetComment( rS ); }

    // ExtraData wird kopiert, der Pointer geht also NICHT in den Besitz
    // des RedlineObjectes!
    void SetExtraData( const SwRedlineExtraData* pData )
        { pRedlineData->SetExtraData( pData ); }
    const SwRedlineExtraData* GetExtraData() const
        { return pRedlineData->GetExtraData(); }

    // fuers UI-seitige zusammenfassen von Redline-Actionen. Wird z.Z. nur
    // fuers Autoformat mit Redline benoetigt. Der Wert != 0 bedeutet dabei,
    // das es noch weitere geben kann!
    USHORT GetSeqNo() const             { return pRedlineData->GetSeqNo(); }
    void SetSeqNo( USHORT nNo )         { pRedlineData->SetSeqNo( nNo ); }

    // Beim Hide/ShowOriginal wird 2 mal ueber die Liste gelaufen, damit
    //  die Del-Redlines per Copy und Delete versteckt werden. Beim Move
    //  wird sonst die Attributierung falsch behandelt.
    // Alle anderen Aufrufer muessen immer 0 angeben.
    void CallDisplayFunc( USHORT nLoop = 0 );
    void Show( USHORT nLoop = 0 );
    void Hide( USHORT nLoop = 0 );
    void ShowOriginal( USHORT nLoop = 0 );

    // calculates the intersection with text node number nNdIdx
    void CalcStartEnd( ULONG nNdIdx, USHORT& nStart, USHORT& nEnd ) const;

    void InvalidateRange();     // das Layout anstossen

    BOOL IsOwnRedline( const SwRedline& rRedl ) const
        { return GetAuthor() == rRedl.GetAuthor(); }
    BOOL CanCombine( const SwRedline& rRedl ) const;

    void PushData( const SwRedline& rRedl, BOOL bOwnAsNext = TRUE );
    BOOL PopData();

    // #111827#
    /**
       Returns textual description of this a redline data element of
       this redline.

       @param nPos index of the redline data element to describe

       The textual description of the selected element contains the
       kind of redline and the possibly shortened text of the redline.

       @return textual description of the selected redline data element
     */
    String GetDescr(USHORT nPos = 0);

    int operator==( const SwRedline& ) const;
    int operator<( const SwRedline& ) const;
};

#endif
<|endoftext|>


<commit_before>//
//   Copyright 2013 Pixar
//
//   Licensed under the Apache License, Version 2.0 (the "Apache License")
//   with the following modification; you may not use this file except in
//   compliance with the Apache License and the following modification to it:
//   Section 6. Trademarks. is deleted and replaced with:
//
//   6. Trademarks. This License does not grant permission to use the trade
//      names, trademarks, service marks, or product names of the Licensor
//      and its affiliates, except as required to comply with Section 4(c) of
//      the License and to reproduce the content of the NOTICE file.
//
//   You may obtain a copy of the Apache License at
//
//       http://www.apache.org/licenses/LICENSE-2.0
//
//   Unless required by applicable law or agreed to in writing, software
//   distributed under the Apache License with the above modification is
//   distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
//   KIND, either express or implied. See the Apache License for the specific
//   language governing permissions and limitations under the Apache License.
//

//------------------------------------------------------------------------------
// Tutorial description:
//
// Building on tutorial 0, this example shows how to instantiate a simple mesh,
// refine it uniformly and then interpolate both 'vertex' and 'face-varying'
// primvar data.
// The resulting interpolated data is output as an 'obj' file, with the
// 'face-varying' data recorded in the uv texture layout.
//

#include <opensubdiv/far/topologyDescriptor.h>
#include <opensubdiv/far/primvarRefiner.h>

#include <cstdio>

//------------------------------------------------------------------------------
// Face-varying implementation.
//
//
struct Vertex {

    // Minimal required interface ----------------------
    Vertex() { }

    Vertex(Vertex const & src) {
        _position[0] = src._position[0];
        _position[1] = src._position[1];
        _position[2] = src._position[2];
    }

    void Clear( void * =0 ) {
        _position[0]=_position[1]=_position[2]=0.0f;
    }

    void AddWithWeight(Vertex const & src, float weight) {
        _position[0]+=weight*src._position[0];
        _position[1]+=weight*src._position[1];
        _position[2]+=weight*src._position[2];
    }

    // Public interface ------------------------------------
    void SetPosition(float x, float y, float z) {
        _position[0]=x;
        _position[1]=y;
        _position[2]=z;
    }

    const float * GetPosition() const {
        return _position;
    }

private:
    float _position[3];
};

//------------------------------------------------------------------------------
// Face-varying container implementation.
//
// We are using a uv texture layout as a 'face-varying' primtiive variable
// attribute. Because face-varying data is specified 'per-face-per-vertex',
// we cannot use the same container that we use for 'vertex' or 'varying'
// data. We specify a new container, which only carries (u,v) coordinates.
// Similarly to our 'Vertex' container, we add a minimaliztic interpolation
// interface with a 'Clear()' and 'AddWithWeight()' methods.
//
struct FVarVertex {

    // Minimal required interface ----------------------
    void Clear() {
        u=v=0.0f;
    }

    void AddWithWeight(FVarVertex const & src, float weight) {
        u += weight * src.u;
        v += weight * src.v;
    }

    // Basic 'uv' layout channel
    float u,v;
};

//------------------------------------------------------------------------------
// Cube geometry from catmark_cube.h

// 'vertex' primitive variable data & topology
static float g_verts[8][3] = {{ -0.5f, -0.5f,  0.5f },
                              {  0.5f, -0.5f,  0.5f },
                              { -0.5f,  0.5f,  0.5f },
                              {  0.5f,  0.5f,  0.5f },
                              { -0.5f,  0.5f, -0.5f },
                              {  0.5f,  0.5f, -0.5f },
                              { -0.5f, -0.5f, -0.5f },
                              {  0.5f, -0.5f, -0.5f }};
static int g_nverts = 8,
           g_nfaces = 6;

static int g_vertsperface[6] = { 4, 4, 4, 4, 4, 4 };

static int g_vertIndices[24] = { 0, 1, 3, 2,
                                 2, 3, 5, 4,
                                 4, 5, 7, 6,
                                 6, 7, 1, 0,
                                 1, 7, 5, 3,
                                 6, 0, 2, 4  };

// 'face-varying' primitive variable data & topology
static float g_uvs[14][2] = {{ 0.375, 0.00 },
                             { 0.625, 0.00 },
                             { 0.375, 0.25 },
                             { 0.625, 0.25 },
                             { 0.375, 0.50 },
                             { 0.625, 0.50 },
                             { 0.375, 0.75 },
                             { 0.625, 0.75 },
                             { 0.375, 1.00 },
                             { 0.625, 1.00 },
                             { 0.875, 0.00 },
                             { 0.875, 0.25 },
                             { 0.125, 0.00 },
                             { 0.125, 0.25 }};

static int g_nuvs = 14;

static int g_uvIndices[24] = {  0,  1,  3,  2,
                                2,  3,  5,  4,
                                4,  5,  7,  6,
                                6,  7,  9,  8,
                                1, 10, 11,  3,
                               12,  0,  2, 13  };

using namespace OpenSubdiv;

//------------------------------------------------------------------------------
int main(int, char **) {

    int maxlevel = 3;

    typedef Far::TopologyDescriptor Descriptor;

    Sdc::SchemeType type = OpenSubdiv::Sdc::SCHEME_CATMARK;

    Sdc::Options options;
    options.SetVtxBoundaryInterpolation(Sdc::Options::VTX_BOUNDARY_EDGE_ONLY);
    options.SetFVarLinearInterpolation(Sdc::Options::FVAR_LINEAR_NONE);

    // Populate a topology descriptor with our raw data
    Descriptor desc;
    desc.numVertices  = g_nverts;
    desc.numFaces     = g_nfaces;
    desc.numVertsPerFace = g_vertsperface;
    desc.vertIndicesPerFace  = g_vertIndices;

    // Create a face-varying channel descriptor
    Descriptor::FVarChannel uvs;
    uvs.numValues = g_nuvs;
    uvs.valueIndices = g_uvIndices;

    // Add the channel topology to the main descriptor
    desc.numFVarChannels = 1;
    desc.fvarChannels = & uvs;

    // Instantiate a FarTopologyRefiner from the descriptor
    Far::TopologyRefiner * refiner =
        Far::TopologyRefinerFactory<Descriptor>::Create(desc,
            Far::TopologyRefinerFactory<Descriptor>::Options(type, options));

    // Uniformly refine the topolgy up to 'maxlevel'
    // note: fullTopologyInLastLevel must be true to work with face-varying data
    {
        Far::TopologyRefiner::UniformOptions refineOptions(maxlevel);
        refineOptions.fullTopologyInLastLevel = true;
        refiner->RefineUniform(refineOptions);
    }

    // Allocate and initialize the 'vertex' primvar data (see tutorial 2 for
    // more details).
    std::vector<Vertex> vbuffer(refiner->GetNumVerticesTotal());
    Vertex * verts = &vbuffer[0];

    for (int i=0; i<g_nverts; ++i) {
        verts[i].SetPosition(g_verts[i][0], g_verts[i][1], g_verts[i][2]);
    }

    // Allocate and initialize the single channel of 'face-varying' primvar data
    int channel = 0;

    std::vector<FVarVertex> fvBuffer(refiner->GetNumFVarValuesTotal(channel));
    FVarVertex * fvVerts = &fvBuffer[0];

    for (int i=0; i<g_nuvs; ++i) {
        fvVerts[i].u = g_uvs[i][0];
        fvVerts[i].v = g_uvs[i][1];
    }

    // Interpolate both vertex and face-varying primvar data
    Far::PrimvarRefiner primvarRefiner(*refiner);

    Vertex *     srcVert = verts;
    FVarVertex * srcFVar = fvVerts;

    for (int level = 1; level <= maxlevel; ++level) {
        Vertex *     dstVert = srcVert + refiner->GetLevel(level-1).GetNumVertices();
        FVarVertex * dstFVar = srcFVar + refiner->GetLevel(level-1).GetNumFVarValues(channel);

        primvarRefiner.Interpolate(level, srcVert, dstVert);
        primvarRefiner.InterpolateFaceVarying(level, srcFVar, dstFVar, channel);

        srcVert = dstVert;
        srcFVar = dstFVar;
    }

    { // Output OBJ of the highest level refined -----------

        Far::TopologyLevel const & refLastLevel = refiner->GetLevel(maxlevel);

        int nverts = refLastLevel.GetNumVertices();
        int nuvs   = refLastLevel.GetNumFVarValues(channel);
        int nfaces = refLastLevel.GetNumFaces();

        // Print vertex positions
        int firstOfLastVerts = refiner->GetNumVerticesTotal() - nverts;

        for (int vert = 0; vert < nverts; ++vert) {
            float const * pos = verts[firstOfLastVerts + vert].GetPosition();
            printf("v %f %f %f\n", pos[0], pos[1], pos[2]);
        }

        // Print uvs
        int firstOfLastUvs = refiner->GetNumFVarValuesTotal(channel) - nuvs;

        for (int fvvert = 0; fvvert < nuvs; ++fvvert) {
            FVarVertex const & uv = fvVerts[firstOfLastUvs + fvvert];
            printf("vt %f %f\n", uv.u, uv.v);
        }

        // Print faces
        for (int face = 0; face < nfaces; ++face) {

            Far::ConstIndexArray fverts = refLastLevel.GetFaceVertices(face);
            Far::ConstIndexArray fuvs   = refLastLevel.GetFaceFVarValues(face, channel);

            // all refined Catmark faces should be quads
            assert(fverts.size()==4 and fuvs.size()==4);

            printf("f ");
            for (int vert=0; vert<fverts.size(); ++vert) {
                // OBJ uses 1-based arrays...
                printf("%d/%d ", fverts[vert]+1, fuvs[vert]+1);
            }
            printf("\n");
        }
    }
}
//------------------------------------------------------------------------------
<commit_msg>Adding vertex color in the second face-varying channel.<commit_after>//
//   Copyright 2013 Pixar
//
//   Licensed under the Apache License, Version 2.0 (the "Apache License")
//   with the following modification; you may not use this file except in
//   compliance with the Apache License and the following modification to it:
//   Section 6. Trademarks. is deleted and replaced with:
//
//   6. Trademarks. This License does not grant permission to use the trade
//      names, trademarks, service marks, or product names of the Licensor
//      and its affiliates, except as required to comply with Section 4(c) of
//      the License and to reproduce the content of the NOTICE file.
//
//   You may obtain a copy of the Apache License at
//
//       http://www.apache.org/licenses/LICENSE-2.0
//
//   Unless required by applicable law or agreed to in writing, software
//   distributed under the Apache License with the above modification is
//   distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
//   KIND, either express or implied. See the Apache License for the specific
//   language governing permissions and limitations under the Apache License.
//

//------------------------------------------------------------------------------
// Tutorial description:
//
// Building on tutorial 0, this example shows how to instantiate a simple mesh,
// refine it uniformly and then interpolate both 'vertex' and 'face-varying'
// primvar data.
// The resulting interpolated data is output as an 'obj' file, with the
// 'face-varying' data recorded in the uv texture layout.
//

#include <opensubdiv/far/topologyDescriptor.h>
#include <opensubdiv/far/primvarRefiner.h>

#include <cstdio>

//------------------------------------------------------------------------------
// Face-varying implementation.
//
//
struct Vertex {

    // Minimal required interface ----------------------
    Vertex() { }

    Vertex(Vertex const & src) {
        _position[0] = src._position[0];
        _position[1] = src._position[1];
        _position[2] = src._position[2];
    }

    void Clear( void * =0 ) {
        _position[0]=_position[1]=_position[2]=0.0f;
    }

    void AddWithWeight(Vertex const & src, float weight) {
        _position[0]+=weight*src._position[0];
        _position[1]+=weight*src._position[1];
        _position[2]+=weight*src._position[2];
    }

    // Public interface ------------------------------------
    void SetPosition(float x, float y, float z) {
        _position[0]=x;
        _position[1]=y;
        _position[2]=z;
    }

    const float * GetPosition() const {
        return _position;
    }

private:
    float _position[3];
};

//------------------------------------------------------------------------------
// Face-varying container implementation.
//
// We are using a uv texture layout as a 'face-varying' primtiive variable
// attribute. Because face-varying data is specified 'per-face-per-vertex',
// we cannot use the same container that we use for 'vertex' or 'varying'
// data. We specify a new container, which only carries (u,v) coordinates.
// Similarly to our 'Vertex' container, we add a minimaliztic interpolation
// interface with a 'Clear()' and 'AddWithWeight()' methods.
//
struct FVarVertexUV {

    // Minimal required interface ----------------------
    void Clear() {
        u=v=0.0f;
    }

    void AddWithWeight(FVarVertexUV const & src, float weight) {
        u += weight * src.u;
        v += weight * src.v;
    }

    // Basic 'uv' layout channel
    float u,v;
};

struct FVarVertexColor {

    // Minimal required interface ----------------------
    void Clear() {
        r=g=b=a=0.0f;
    }

    void AddWithWeight(FVarVertexColor const & src, float weight) {
        r += weight * src.r;
        g += weight * src.g;
        b += weight * src.b;
        a += weight * src.a;
    }

    // Basic 'color' layout channel
    float r,g,b,a;
};

//------------------------------------------------------------------------------
// Cube geometry from catmark_cube.h

// 'vertex' primitive variable data & topology
static float g_verts[8][3] = {{ -0.5f, -0.5f,  0.5f },
                              {  0.5f, -0.5f,  0.5f },
                              { -0.5f,  0.5f,  0.5f },
                              {  0.5f,  0.5f,  0.5f },
                              { -0.5f,  0.5f, -0.5f },
                              {  0.5f,  0.5f, -0.5f },
                              { -0.5f, -0.5f, -0.5f },
                              {  0.5f, -0.5f, -0.5f }};
static int g_nverts = 8,
           g_nfaces = 6;

static int g_vertsperface[6] = { 4, 4, 4, 4, 4, 4 };

static int g_vertIndices[24] = { 0, 1, 3, 2,
                                 2, 3, 5, 4,
                                 4, 5, 7, 6,
                                 6, 7, 1, 0,
                                 1, 7, 5, 3,
                                 6, 0, 2, 4  };

// 'face-varying' primitive variable data & topology for UVs
static float g_uvs[14][2] = {{ 0.375, 0.00 },
                             { 0.625, 0.00 },
                             { 0.375, 0.25 },
                             { 0.625, 0.25 },
                             { 0.375, 0.50 },
                             { 0.625, 0.50 },
                             { 0.375, 0.75 },
                             { 0.625, 0.75 },
                             { 0.375, 1.00 },
                             { 0.625, 1.00 },
                             { 0.875, 0.00 },
                             { 0.875, 0.25 },
                             { 0.125, 0.00 },
                             { 0.125, 0.25 }};

static int g_nuvs = 14;

static int g_uvIndices[24] = {  0,  1,  3,  2,
                                2,  3,  5,  4,
                                4,  5,  7,  6,
                                6,  7,  9,  8,
                                1, 10, 11,  3,
                               12,  0,  2, 13  };

// 'face-varying' primitive variable data & topology for color
static float g_colors[24][4] = {{1.0, 1.0, 1.0, 1.0},
                                {1.0, 1.0, 1.0, 1.0},
                                {1.0, 1.0, 1.0, 1.0},
                                {1.0, 1.0, 1.0, 1.0},
                                {1.0, 1.0, 1.0, 1.0},
                                {1.0, 1.0, 1.0, 1.0},
                                {1.0, 1.0, 1.0, 1.0},
                                {1.0, 1.0, 1.0, 1.0},
                                {1.0, 1.0, 1.0, 1.0},
                                {1.0, 0.0, 0.0, 1.0},
                                {1.0, 0.0, 0.0, 1.0},
                                {1.0, 0.0, 0.0, 1.0},
                                {1.0, 1.0, 1.0, 1.0},
                                {1.0, 1.0, 1.0, 1.0},
                                {1.0, 1.0, 1.0, 1.0},
                                {1.0, 1.0, 1.0, 1.0},
                                {1.0, 1.0, 1.0, 1.0},
                                {1.0, 1.0, 1.0, 1.0},
                                {1.0, 1.0, 1.0, 1.0},
                                {1.0, 1.0, 1.0, 1.0},
                                {1.0, 1.0, 1.0, 1.0},
                                {1.0, 1.0, 1.0, 1.0},
                                {1.0, 1.0, 1.0, 1.0},
                                {1.0, 1.0, 1.0, 1.0}};

static int g_ncolors = 24;

static int g_colorIndices[24] = { 0,  3,  9,  6,
                                  7, 10, 15, 12,
                                 13, 16, 21, 18,
                                 19, 22,  4,  1,
                                  5, 23, 17, 11,
                                 20,  2,  8, 14 };

using namespace OpenSubdiv;

//------------------------------------------------------------------------------
int main(int, char **) {

    int maxlevel = 3;

    typedef Far::TopologyDescriptor Descriptor;

    Sdc::SchemeType type = OpenSubdiv::Sdc::SCHEME_CATMARK;

    Sdc::Options options;
    options.SetVtxBoundaryInterpolation(Sdc::Options::VTX_BOUNDARY_EDGE_ONLY);
    options.SetFVarLinearInterpolation(Sdc::Options::FVAR_LINEAR_NONE);

    // Populate a topology descriptor with our raw data
    Descriptor desc;
    desc.numVertices  = g_nverts;
    desc.numFaces     = g_nfaces;
    desc.numVertsPerFace = g_vertsperface;
    desc.vertIndicesPerFace  = g_vertIndices;

    int channelUV = 0;
    int channelColor = 1;

    // Create a face-varying channel descriptor
    Descriptor::FVarChannel channels[2];
    channels[channelUV].numValues = g_nuvs;
    channels[channelUV].valueIndices = g_uvIndices;
    channels[channelColor].numValues = g_ncolors;
    channels[channelColor].valueIndices = g_colorIndices;

    // Add the channel topology to the main descriptor
    desc.numFVarChannels = 2;
    desc.fvarChannels = channels;

    // Instantiate a FarTopologyRefiner from the descriptor
    Far::TopologyRefiner * refiner =
        Far::TopologyRefinerFactory<Descriptor>::Create(desc,
            Far::TopologyRefinerFactory<Descriptor>::Options(type, options));

    // Uniformly refine the topolgy up to 'maxlevel'
    // note: fullTopologyInLastLevel must be true to work with face-varying data
    {
        Far::TopologyRefiner::UniformOptions refineOptions(maxlevel);
        refineOptions.fullTopologyInLastLevel = true;
        refiner->RefineUniform(refineOptions);
    }

    // Allocate and initialize the 'vertex' primvar data (see tutorial 2 for
    // more details).
    std::vector<Vertex> vbuffer(refiner->GetNumVerticesTotal());
    Vertex * verts = &vbuffer[0];

    for (int i=0; i<g_nverts; ++i) {
        verts[i].SetPosition(g_verts[i][0], g_verts[i][1], g_verts[i][2]);
    }

    // Allocate and initialize the first channel of 'face-varying' primvar data (UVs)
    std::vector<FVarVertexUV> fvBufferUV(refiner->GetNumFVarValuesTotal(channelUV));
    FVarVertexUV * fvVertsUV = &fvBufferUV[0];
    for (int i=0; i<g_nuvs; ++i) {
        fvVertsUV[i].u = g_uvs[i][0];
        fvVertsUV[i].v = g_uvs[i][1];
    }

    // Allocate & interpolate the 'face-varying' primvar data (colors)
    std::vector<FVarVertexColor> fvBufferColor(refiner->GetNumFVarValuesTotal(channelColor));
    FVarVertexColor * fvVertsColor = &fvBufferColor[0];
    for (int i=0; i<g_ncolors; ++i) {
        fvVertsColor[i].r = g_colors[i][0];
        fvVertsColor[i].g = g_colors[i][1];
        fvVertsColor[i].b = g_colors[i][2];
        fvVertsColor[i].a = g_colors[i][3];
    }

    // Interpolate both vertex and face-varying primvar data
    Far::PrimvarRefiner primvarRefiner(*refiner);

    Vertex *     srcVert = verts;
    FVarVertexUV * srcFVarUV = fvVertsUV;
    FVarVertexColor * srcFVarColor = fvVertsColor;

    for (int level = 1; level <= maxlevel; ++level) {
        Vertex *     dstVert = srcVert + refiner->GetLevel(level-1).GetNumVertices();
        FVarVertexUV * dstFVarUV = srcFVarUV + refiner->GetLevel(level-1).GetNumFVarValues(channelUV);
        FVarVertexColor * dstFVarColor = srcFVarColor + refiner->GetLevel(level-1).GetNumFVarValues(channelColor);

        primvarRefiner.Interpolate(level, srcVert, dstVert);
        primvarRefiner.InterpolateFaceVarying(level, srcFVarUV, dstFVarUV, channelUV);
        primvarRefiner.InterpolateFaceVarying(level, srcFVarColor, dstFVarColor, channelColor);

        srcVert = dstVert;
        srcFVarUV = dstFVarUV;
        srcFVarColor = dstFVarColor;
    }

    { // Output OBJ of the highest level refined -----------

        Far::TopologyLevel const & refLastLevel = refiner->GetLevel(maxlevel);

        int nverts = refLastLevel.GetNumVertices();
        int nuvs   = refLastLevel.GetNumFVarValues(channelUV);
        int ncolors= refLastLevel.GetNumFVarValues(channelColor);
        int nfaces = refLastLevel.GetNumFaces();

        // Print vertex positions
        int firstOfLastVerts = refiner->GetNumVerticesTotal() - nverts;

        for (int vert = 0; vert < nverts; ++vert) {
            float const * pos = verts[firstOfLastVerts + vert].GetPosition();
            printf("v %f %f %f\n", pos[0], pos[1], pos[2]);
        }

        // Print uvs
        int firstOfLastUvs = refiner->GetNumFVarValuesTotal(channelUV) - nuvs;

        for (int fvvert = 0; fvvert < nuvs; ++fvvert) {
            FVarVertexUV const & uv = fvVertsUV[firstOfLastUvs + fvvert];
            printf("vt %f %f\n", uv.u, uv.v);
        }

        // Print colors
        int firstOfLastColors = refiner->GetNumFVarValuesTotal(channelColor) - ncolors;

        for (int fvvert = 0; fvvert < nuvs; ++fvvert) {
            FVarVertexColor const & c = fvVertsColor[firstOfLastColors + fvvert];
            printf("c %f %f %f %f\n", c.r, c.g, c.b, c.a);
        }

        // Print faces
        for (int face = 0; face < nfaces; ++face) {

            Far::ConstIndexArray fverts = refLastLevel.GetFaceVertices(face);
            Far::ConstIndexArray fuvs   = refLastLevel.GetFaceFVarValues(face, channelUV);

            // all refined Catmark faces should be quads
            assert(fverts.size()==4 and fuvs.size()==4);

            printf("f ");
            for (int vert=0; vert<fverts.size(); ++vert) {
                // OBJ uses 1-based arrays...
                printf("%d/%d ", fverts[vert]+1, fuvs[vert]+1);
            }
            printf("\n");
        }
    }
}
//------------------------------------------------------------------------------<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: DAVResourceAccess.hxx,v $
 *
 *  $Revision: 1.13 $
 *
 *  last change: $Author: rt $ $Date: 2005-09-09 16:07:32 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 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
 *
 ************************************************************************/

#ifndef _DAVRESOURCEACCESS_HXX_
#define _DAVRESOURCEACCESS_HXX_

#include <vector>

#ifndef _RTL_USTRING_HXX_
#include <rtl/ustring.hxx>
#endif
#ifndef _RTL_REF_HXX_
#include <rtl/ref.hxx>
#endif

#ifndef _OSL_MUTEX_HXX_
#include <osl/mutex.hxx>
#endif

#ifndef _COM_SUN_STAR_IO_XINPUTSTREAM_HPP_
#include <com/sun/star/io/XInputStream.hpp>
#endif
#ifndef _COM_SUN_STAR_IO_XOUTPUTSTREAM_HPP_
#include <com/sun/star/io/XOutputStream.hpp>
#endif
#ifndef _COM_SUN_STAR_UCB_LOCK_HPP_
#include <com/sun/star/ucb/Lock.hpp>
#endif
#ifndef _COM_SUN_STAR_UCB_XCOMMANDENVIRONMENT_HPP_
#include <com/sun/star/ucb/XCommandEnvironment.hpp>
#endif

#ifndef _DAVAUTHLISTENER_HXX_
#include "DAVAuthListener.hxx"
#endif
#ifndef _DAVEXCEPTION_HXX_
#include "DAVException.hxx"
#endif
#ifndef _DAVSESSION_HXX_
#include "DAVSession.hxx"
#endif
#ifndef _DAVRESOURCE_HXX_
#include "DAVResource.hxx"
#endif
#ifndef _DAVTYPES_HXX_
#include "DAVTypes.hxx"
#endif
#ifndef _NEONURI_HXX_
#include "NeonUri.hxx"
#endif

namespace webdav_ucp
{

class DAVSessionFactory;

class DAVResourceAccess
{
    osl::Mutex    m_aMutex;
    rtl::OUString m_aURL;
    rtl::OUString m_aPath;
    rtl::Reference< DAVSession > m_xSession;
    rtl::Reference< DAVSessionFactory > m_xSessionFactory;
    com::sun::star::uno::Reference<
        com::sun::star::lang::XMultiServiceFactory > m_xSMgr;
    std::vector< NeonUri > m_aRedirectURIs;

public:
    DAVResourceAccess() : m_xSessionFactory( 0 ) {}
    DAVResourceAccess( const com::sun::star::uno::Reference<
                        com::sun::star::lang::XMultiServiceFactory > & rSMgr,
                       rtl::Reference<
                        DAVSessionFactory > const & rSessionFactory,
                       const rtl::OUString & rURL );
    DAVResourceAccess( const DAVResourceAccess & rOther );

    DAVResourceAccess & operator=( const DAVResourceAccess & rOther );

    void setURL( const rtl::OUString & rNewURL )
        throw( DAVException );

    const rtl::OUString & getURL() const { return m_aURL; }

    rtl::Reference< DAVSessionFactory > getSessionFactory() const
    { return m_xSessionFactory; }

    // DAV methods
    //

    void
    OPTIONS(  DAVCapabilities & rCapabilities,
              const com::sun::star::uno::Reference<
                  com::sun::star::ucb::XCommandEnvironment > & xEnv )
        throw( DAVException );

    // allprop & named
    void
    PROPFIND( const Depth nDepth,
              const std::vector< rtl::OUString > & rPropertyNames,
              std::vector< DAVResource > & rResources,
              const com::sun::star::uno::Reference<
                  com::sun::star::ucb::XCommandEnvironment > & xEnv )
        throw( DAVException );

    // propnames
    void
    PROPFIND( const Depth nDepth,
              std::vector< DAVResourceInfo > & rResInfo,
              const com::sun::star::uno::Reference<
                  com::sun::star::ucb::XCommandEnvironment > & xEnv )
        throw( DAVException );

    void
    PROPPATCH( const std::vector< ProppatchValue > & rValues,
               const com::sun::star::uno::Reference<
                   com::sun::star::ucb::XCommandEnvironment >& xEnv )
        throw( DAVException );

    void
    HEAD( const std::vector< rtl::OUString > & rHeaderNames, // empty == 'all'
          DAVResource & rResource,
          const com::sun::star::uno::Reference<
            com::sun::star::ucb::XCommandEnvironment >& xEnv )
        throw( DAVException );

    com::sun::star::uno::Reference< com::sun::star::io::XInputStream >
    GET( const com::sun::star::uno::Reference<
            com::sun::star::ucb::XCommandEnvironment > & xEnv )
        throw( DAVException );

    void
    GET( com::sun::star::uno::Reference<
            com::sun::star::io::XOutputStream > & rStream,
         const com::sun::star::uno::Reference<
            com::sun::star::ucb::XCommandEnvironment > & xEnv )
        throw( DAVException );

    com::sun::star::uno::Reference< com::sun::star::io::XInputStream >
    GET( const std::vector< rtl::OUString > & rHeaderNames, // empty == 'all'
         DAVResource & rResource,
         const com::sun::star::uno::Reference<
            com::sun::star::ucb::XCommandEnvironment > & xEnv )
        throw( DAVException );

    void
    GET( com::sun::star::uno::Reference<
            com::sun::star::io::XOutputStream > & rStream,
         const std::vector< rtl::OUString > & rHeaderNames, // empty == 'all'
         DAVResource & rResource,
         const com::sun::star::uno::Reference<
            com::sun::star::ucb::XCommandEnvironment > & xEnv )
        throw( DAVException );

    void
    PUT(      const com::sun::star::uno::Reference<
              com::sun::star::io::XInputStream > & rStream,
              const com::sun::star::uno::Reference<
                  com::sun::star::ucb::XCommandEnvironment > & xEnv )
        throw( DAVException );

    com::sun::star::uno::Reference< com::sun::star::io::XInputStream >
    POST(     const rtl::OUString & rContentType,
                const rtl::OUString & rReferer,
              const com::sun::star::uno::Reference<
                com::sun::star::io::XInputStream > & rInputStream,
              const com::sun::star::uno::Reference<
                com::sun::star::ucb::XCommandEnvironment >& xEnv )
        throw ( DAVException );

    void
    POST(     const rtl::OUString & rContentType,
              const rtl::OUString & rReferer,
              const com::sun::star::uno::Reference<
                com::sun::star::io::XInputStream > & rInputStream,
              com::sun::star::uno::Reference<
                com::sun::star::io::XOutputStream > & rOutputStream,
              const com::sun::star::uno::Reference<
                com::sun::star::ucb::XCommandEnvironment >& xEnv )
        throw ( DAVException );

    void
    MKCOL(    const com::sun::star::uno::Reference<
                  com::sun::star::ucb::XCommandEnvironment > & xEnv )
        throw( DAVException );

    void
    COPY(     const ::rtl::OUString & rSourcePath,
                 const ::rtl::OUString & rDestinationURI,
              sal_Bool bOverwrite,
              const com::sun::star::uno::Reference<
                  com::sun::star::ucb::XCommandEnvironment > & xEnv )
        throw( DAVException );

    void
    MOVE(     const ::rtl::OUString & rSourcePath,
              const ::rtl::OUString & rDestinationURI,
              sal_Bool bOverwrite,
              const com::sun::star::uno::Reference<
                  com::sun::star::ucb::XCommandEnvironment > & xEnv )
        throw( DAVException );

    void
    DESTROY(  const com::sun::star::uno::Reference<
                   com::sun::star::ucb::XCommandEnvironment > & xEnv )
        throw( DAVException );

    void
    LOCK (    const com::sun::star::ucb::Lock & rLock,
              const com::sun::star::uno::Reference<
                  com::sun::star::ucb::XCommandEnvironment > & xEnv )
        throw( DAVException );

    void
    UNLOCK (  const com::sun::star::ucb::Lock & rLock,
              const com::sun::star::uno::Reference<
                   com::sun::star::ucb::XCommandEnvironment > & xEnv )
        throw( DAVException );

private:
    const rtl::OUString & getRequestURI() const;
    sal_Bool detectRedirectCycle( const rtl::OUString& rRedirectURL );
    sal_Bool handleException( DAVException & e );
    void initialize()
        throw ( DAVException );
};

}; // namespace webdav_ucp

#endif // _DAVRESOURCEACCESS_HXX_
<commit_msg>INTEGRATION: CWS warnings01 (1.13.10); FILE MERGED 2005/11/10 18:10:19 pl 1.13.10.1: #i55991# removed warnings<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: DAVResourceAccess.hxx,v $
 *
 *  $Revision: 1.14 $
 *
 *  last change: $Author: hr $ $Date: 2006-06-20 05:34:16 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 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
 *
 ************************************************************************/

#ifndef _DAVRESOURCEACCESS_HXX_
#define _DAVRESOURCEACCESS_HXX_

#include <vector>

#ifndef _RTL_USTRING_HXX_
#include <rtl/ustring.hxx>
#endif
#ifndef _RTL_REF_HXX_
#include <rtl/ref.hxx>
#endif

#ifndef _OSL_MUTEX_HXX_
#include <osl/mutex.hxx>
#endif

#ifndef _COM_SUN_STAR_IO_XINPUTSTREAM_HPP_
#include <com/sun/star/io/XInputStream.hpp>
#endif
#ifndef _COM_SUN_STAR_IO_XOUTPUTSTREAM_HPP_
#include <com/sun/star/io/XOutputStream.hpp>
#endif
#ifndef _COM_SUN_STAR_UCB_LOCK_HPP_
#include <com/sun/star/ucb/Lock.hpp>
#endif
#ifndef _COM_SUN_STAR_UCB_XCOMMANDENVIRONMENT_HPP_
#include <com/sun/star/ucb/XCommandEnvironment.hpp>
#endif

#ifndef _DAVAUTHLISTENER_HXX_
#include "DAVAuthListener.hxx"
#endif
#ifndef _DAVEXCEPTION_HXX_
#include "DAVException.hxx"
#endif
#ifndef _DAVSESSION_HXX_
#include "DAVSession.hxx"
#endif
#ifndef _DAVRESOURCE_HXX_
#include "DAVResource.hxx"
#endif
#ifndef _DAVTYPES_HXX_
#include "DAVTypes.hxx"
#endif
#ifndef _NEONURI_HXX_
#include "NeonUri.hxx"
#endif

namespace webdav_ucp
{

class DAVSessionFactory;

class DAVResourceAccess
{
    osl::Mutex    m_aMutex;
    rtl::OUString m_aURL;
    rtl::OUString m_aPath;
    rtl::Reference< DAVSession > m_xSession;
    rtl::Reference< DAVSessionFactory > m_xSessionFactory;
    com::sun::star::uno::Reference<
        com::sun::star::lang::XMultiServiceFactory > m_xSMgr;
    std::vector< NeonUri > m_aRedirectURIs;

public:
    DAVResourceAccess() : m_xSessionFactory( 0 ) {}
    DAVResourceAccess( const com::sun::star::uno::Reference<
                        com::sun::star::lang::XMultiServiceFactory > & rSMgr,
                       rtl::Reference<
                        DAVSessionFactory > const & rSessionFactory,
                       const rtl::OUString & rURL );
    DAVResourceAccess( const DAVResourceAccess & rOther );

    DAVResourceAccess & operator=( const DAVResourceAccess & rOther );

    void setURL( const rtl::OUString & rNewURL )
        throw( DAVException );

    const rtl::OUString & getURL() const { return m_aURL; }

    rtl::Reference< DAVSessionFactory > getSessionFactory() const
    { return m_xSessionFactory; }

    // DAV methods
    //

    void
    OPTIONS(  DAVCapabilities & rCapabilities,
              const com::sun::star::uno::Reference<
                  com::sun::star::ucb::XCommandEnvironment > & xEnv )
        throw( DAVException );

    // allprop & named
    void
    PROPFIND( const Depth nDepth,
              const std::vector< rtl::OUString > & rPropertyNames,
              std::vector< DAVResource > & rResources,
              const com::sun::star::uno::Reference<
                  com::sun::star::ucb::XCommandEnvironment > & xEnv )
        throw( DAVException );

    // propnames
    void
    PROPFIND( const Depth nDepth,
              std::vector< DAVResourceInfo > & rResInfo,
              const com::sun::star::uno::Reference<
                  com::sun::star::ucb::XCommandEnvironment > & xEnv )
        throw( DAVException );

    void
    PROPPATCH( const std::vector< ProppatchValue > & rValues,
               const com::sun::star::uno::Reference<
                   com::sun::star::ucb::XCommandEnvironment >& xEnv )
        throw( DAVException );

    void
    HEAD( const std::vector< rtl::OUString > & rHeaderNames, // empty == 'all'
          DAVResource & rResource,
          const com::sun::star::uno::Reference<
            com::sun::star::ucb::XCommandEnvironment >& xEnv )
        throw( DAVException );

    com::sun::star::uno::Reference< com::sun::star::io::XInputStream >
    GET( const com::sun::star::uno::Reference<
            com::sun::star::ucb::XCommandEnvironment > & xEnv )
        throw( DAVException );

    void
    GET( com::sun::star::uno::Reference<
            com::sun::star::io::XOutputStream > & rStream,
         const com::sun::star::uno::Reference<
            com::sun::star::ucb::XCommandEnvironment > & xEnv )
        throw( DAVException );

    com::sun::star::uno::Reference< com::sun::star::io::XInputStream >
    GET( const std::vector< rtl::OUString > & rHeaderNames, // empty == 'all'
         DAVResource & rResource,
         const com::sun::star::uno::Reference<
            com::sun::star::ucb::XCommandEnvironment > & xEnv )
        throw( DAVException );

    void
    GET( com::sun::star::uno::Reference<
            com::sun::star::io::XOutputStream > & rStream,
         const std::vector< rtl::OUString > & rHeaderNames, // empty == 'all'
         DAVResource & rResource,
         const com::sun::star::uno::Reference<
            com::sun::star::ucb::XCommandEnvironment > & xEnv )
        throw( DAVException );

    void
    PUT(      const com::sun::star::uno::Reference<
              com::sun::star::io::XInputStream > & rStream,
              const com::sun::star::uno::Reference<
                  com::sun::star::ucb::XCommandEnvironment > & xEnv )
        throw( DAVException );

    com::sun::star::uno::Reference< com::sun::star::io::XInputStream >
    POST(     const rtl::OUString & rContentType,
                const rtl::OUString & rReferer,
              const com::sun::star::uno::Reference<
                com::sun::star::io::XInputStream > & rInputStream,
              const com::sun::star::uno::Reference<
                com::sun::star::ucb::XCommandEnvironment >& xEnv )
        throw ( DAVException );

    void
    POST(     const rtl::OUString & rContentType,
              const rtl::OUString & rReferer,
              const com::sun::star::uno::Reference<
                com::sun::star::io::XInputStream > & rInputStream,
              com::sun::star::uno::Reference<
                com::sun::star::io::XOutputStream > & rOutputStream,
              const com::sun::star::uno::Reference<
                com::sun::star::ucb::XCommandEnvironment >& xEnv )
        throw ( DAVException );

    void
    MKCOL(    const com::sun::star::uno::Reference<
                  com::sun::star::ucb::XCommandEnvironment > & xEnv )
        throw( DAVException );

    void
    COPY(     const ::rtl::OUString & rSourcePath,
                 const ::rtl::OUString & rDestinationURI,
              sal_Bool bOverwrite,
              const com::sun::star::uno::Reference<
                  com::sun::star::ucb::XCommandEnvironment > & xEnv )
        throw( DAVException );

    void
    MOVE(     const ::rtl::OUString & rSourcePath,
              const ::rtl::OUString & rDestinationURI,
              sal_Bool bOverwrite,
              const com::sun::star::uno::Reference<
                  com::sun::star::ucb::XCommandEnvironment > & xEnv )
        throw( DAVException );

    void
    DESTROY(  const com::sun::star::uno::Reference<
                   com::sun::star::ucb::XCommandEnvironment > & xEnv )
        throw( DAVException );

    void
    LOCK (    const com::sun::star::ucb::Lock & rLock,
              const com::sun::star::uno::Reference<
                  com::sun::star::ucb::XCommandEnvironment > & xEnv )
        throw( DAVException );

    void
    UNLOCK (  const com::sun::star::ucb::Lock & rLock,
              const com::sun::star::uno::Reference<
                   com::sun::star::ucb::XCommandEnvironment > & xEnv )
        throw( DAVException );

private:
    const rtl::OUString & getRequestURI() const;
    sal_Bool detectRedirectCycle( const rtl::OUString& rRedirectURL );
    sal_Bool handleException( DAVException & e );
    void initialize()
        throw ( DAVException );
};

} // namespace webdav_ucp

#endif // _DAVRESOURCEACCESS_HXX_
<|endoftext|>


<commit_before>/*
 * Copyright 2015 Scientific Computation Research Center
 *
 * This work is open source software, licensed under the terms of the
 * BSD license as described in the LICENSE file in the top-level directory.
 */

#include <PCU.h>
#include "crv.h"
#include "crvAdapt.h"
#include <maEdgeSwap.h>
#include <maDoubleSplitCollapse.h>
#include <maShortEdgeRemover.h>
#include <maOperator.h>
#include <cassert>

/* This is similar to maShape.cc, conceptually, but different enough
 * that some duplicate code makes sense */

namespace crv {

static bool isCornerTriAngleLarge(ma::Mesh* m,
    ma::Entity* tri, int index)
{
  apf::Element* elem = apf::createElement(m->getCoordinateField(),tri);
  apf::NewArray<apf::Vector3> nodes;
  apf::getVectorNodes(elem,nodes);
  apf::destroyElement(elem);

  ma::Vector normal = ma::getTriNormal(m,tri);

  int P = m->getShape()->getOrder();
  int r = index*(P-1)+3; // index to the right
  int l = ((index+2) % 3)*(P-1)+3+P-2; // index to the left

  ma::Vector cornerNormal = apf::cross((nodes[r]-nodes[index]),
      (nodes[l]-nodes[index]));

  return cornerNormal*normal < 1e-10;

}

static ma::Entity* isLargeAngleTri(crv::Adapt* a, ma::Entity* e)
{
  ma::Mesh* m = a->mesh;
  ma::Entity* edges[3];
  m->getDownward(e,1,edges);
  for (int i = 0; i < 3; ++i)
  {
    ma::Entity* e0 = edges[i];
    ma::Entity* e1 = edges[(i+1) % 3];
    if(isBoundaryEntity(m,e0) && isBoundaryEntity(m,e1))
    {
      if(isCornerTriAngleLarge(m,e,(i+1) % 3)){
        return edges[(i+2) % 3];
      }
    }
  }

  return 0;
}

static ma::Entity* isLargeAngleTet(crv::Adapt* a, ma::Entity* e)

{
  ma::Mesh* m = a->mesh;
  ma::Entity* faces[4];
  m->getDownward(e,2,faces);
  for (int i = 0; i < 4; ++i)
  {
    ma::Entity* edge = isLargeAngleTri(a,faces[i]);
    if(edge) return edge;
  }
  return 0;
};

typedef ma::Entity* (*AngleFunction)(crv::Adapt* a, ma::Entity* e);

const AngleFunction isLargeAngle[4] =
{
    NULL,
    NULL,
    isLargeAngleTri,
    isLargeAngleTet
};

static long markEdgesOppLargeAngles(Adapt* a)
{
  ma::Entity* e;
  long count = 0;
  ma::Mesh* m = a->mesh;
  int dim = m->getDimension();
  ma::Iterator* it = m->begin(dim);
  while ((e = m->iterate(it)))
  {
    if(!hasTwoEdgesOnBoundary(m,e)) continue;
    ma::Entity* edge = isLargeAngle[dim](a,e);
    if (edge)
    {
      assert(m->getType(edge) == 1);
      ma::setFlag(a,edge,ma::SPLIT);
      if (a->mesh->isOwned(edge))
        ++count;
    }
  }
  m->end(it);
  return PCU_Add_Long(count);
}

// split large angles at their opposite edge.
static void fixLargeAngles(crv::Adapt* a)
{
  double t0 = PCU_Time();
  long count = crv::markEdgesOppLargeAngles(a);
//  long count = ma::markEdgesToSplit(a);
  if ( ! count) {
    return;
  }
  printf("found %d elements\n",count);
  assert(ma::checkFlagConsistency(a,1,ma::SPLIT));
  ma::Refine* r = a->refine;
  ma::resetCollection(r);
  ma::collectForTransfer(r);
  ma::addAllMarkedEdges(r);
  ma::splitElements(r);
  crv::snapRefineToBoundary(a);
  ma::processNewElements(r);
  ma::destroySplitElements(r);
  crv::repositionInterior(r);
  ma::forgetNewEntities(r);

  double t1 = PCU_Time();
  ma::print("Fixed %li boundary elements in %f seconds",count,t1-t0);
}

void fixElementShapes(crv::Adapt* a)
{
  fixLargeAngles(a);
  return;
}

}
<commit_msg>silence warning<commit_after>/*
 * Copyright 2015 Scientific Computation Research Center
 *
 * This work is open source software, licensed under the terms of the
 * BSD license as described in the LICENSE file in the top-level directory.
 */

#include <PCU.h>
#include "crv.h"
#include "crvAdapt.h"
#include <maEdgeSwap.h>
#include <maDoubleSplitCollapse.h>
#include <maShortEdgeRemover.h>
#include <maOperator.h>
#include <cassert>

/* This is similar to maShape.cc, conceptually, but different enough
 * that some duplicate code makes sense */

namespace crv {

static bool isCornerTriAngleLarge(ma::Mesh* m,
    ma::Entity* tri, int index)
{
  apf::Element* elem = apf::createElement(m->getCoordinateField(),tri);
  apf::NewArray<apf::Vector3> nodes;
  apf::getVectorNodes(elem,nodes);
  apf::destroyElement(elem);

  ma::Vector normal = ma::getTriNormal(m,tri);

  int P = m->getShape()->getOrder();
  int r = index*(P-1)+3; // index to the right
  int l = ((index+2) % 3)*(P-1)+3+P-2; // index to the left

  ma::Vector cornerNormal = apf::cross((nodes[r]-nodes[index]),
      (nodes[l]-nodes[index]));

  return cornerNormal*normal < 1e-10;

}

static ma::Entity* isLargeAngleTri(crv::Adapt* a, ma::Entity* e)
{
  ma::Mesh* m = a->mesh;
  ma::Entity* edges[3];
  m->getDownward(e,1,edges);
  for (int i = 0; i < 3; ++i)
  {
    ma::Entity* e0 = edges[i];
    ma::Entity* e1 = edges[(i+1) % 3];
    if(isBoundaryEntity(m,e0) && isBoundaryEntity(m,e1))
    {
      if(isCornerTriAngleLarge(m,e,(i+1) % 3)){
        return edges[(i+2) % 3];
      }
    }
  }

  return 0;
}

static ma::Entity* isLargeAngleTet(crv::Adapt* a, ma::Entity* e)

{
  ma::Mesh* m = a->mesh;
  ma::Entity* faces[4];
  m->getDownward(e,2,faces);
  for (int i = 0; i < 4; ++i)
  {
    ma::Entity* edge = isLargeAngleTri(a,faces[i]);
    if(edge) return edge;
  }
  return 0;
};

typedef ma::Entity* (*AngleFunction)(crv::Adapt* a, ma::Entity* e);

const AngleFunction isLargeAngle[4] =
{
    NULL,
    NULL,
    isLargeAngleTri,
    isLargeAngleTet
};

static long markEdgesOppLargeAngles(Adapt* a)
{
  ma::Entity* e;
  long count = 0;
  ma::Mesh* m = a->mesh;
  int dim = m->getDimension();
  ma::Iterator* it = m->begin(dim);
  while ((e = m->iterate(it)))
  {
    if(!hasTwoEdgesOnBoundary(m,e)) continue;
    ma::Entity* edge = isLargeAngle[dim](a,e);
    if (edge)
    {
      assert(m->getType(edge) == 1);
      ma::setFlag(a,edge,ma::SPLIT);
      if (a->mesh->isOwned(edge))
        ++count;
    }
  }
  m->end(it);
  return PCU_Add_Long(count);
}

// split large angles at their opposite edge.
static void fixLargeAngles(crv::Adapt* a)
{
  double t0 = PCU_Time();
  long count = crv::markEdgesOppLargeAngles(a);
//  long count = ma::markEdgesToSplit(a);
  if ( ! count) {
    return;
  }
  printf("found %ld elements\n",count);
  assert(ma::checkFlagConsistency(a,1,ma::SPLIT));
  ma::Refine* r = a->refine;
  ma::resetCollection(r);
  ma::collectForTransfer(r);
  ma::addAllMarkedEdges(r);
  ma::splitElements(r);
  crv::snapRefineToBoundary(a);
  ma::processNewElements(r);
  ma::destroySplitElements(r);
  crv::repositionInterior(r);
  ma::forgetNewEntities(r);

  double t1 = PCU_Time();
  ma::print("Fixed %li boundary elements in %f seconds",count,t1-t0);
}

void fixElementShapes(crv::Adapt* a)
{
  fixLargeAngles(a);
  return;
}

}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2014 New Designs Unlimited, LLC
 * Opensource Automated License Plate Recognition [http://www.openalpr.com]
 *
 * This file is part of OpenAlpr.
 *
 * OpenAlpr is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License
 * version 3 as published by the Free Software Foundation
 *
 * This program 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 Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"

#include <iostream>
#include <stdio.h>
#include <sys/stat.h>

#include "licenseplatecandidate.h"
#include "stateidentifier.h"
#include "utility.h"
#include "support/filesystem.h"
#include "ocr.h"

using namespace std;
using namespace cv;
using namespace alpr;

// Given a directory full of lp images (named [statecode]#.png) crop out the alphanumeric characters.
// These will be used to train the OCR

#ifdef __APPLE__
const int LEFT_ARROW_KEY = 2;
const int RIGHT_ARROW_KEY = 3;
const int SPACE_KEY = 32;
const int ENTER_KEY = 13;
const int ESCAPE_KEY = 27;

const int DOWN_ARROW_KEY = 1;
const int UP_ARROW_KEY= 0;
const int DASHBOARD_COLUMNS = 9;

#else
const int LEFT_ARROW_KEY = 81;
const int RIGHT_ARROW_KEY = 83;
const int SPACE_KEY = 32;
const int ENTER_KEY = 10;
const int ESCAPE_KEY = 27;

const int DOWN_ARROW_KEY = 84;
const int UP_ARROW_KEY= 82;
const int DASHBOARD_COLUMNS = 3;

#endif

void showDashboard(vector<Mat> images, vector<bool> selectedImages, int selectedIndex);
vector<char> showCharSelection(Mat image, vector<Rect> charRegions, string state);

int main( int argc, const char** argv )
{
  string country;
  string inDir;
  string outDir;
  Mat frame;

  //Check if user specify image to process
  if(argc == 4)
  {
    country = argv[1];
    inDir = argv[2];
    outDir = argv[3];
  }
  else
  {
    printf("Use:\n\t%s country indirectory outdirectory\n",argv[0]);
    printf("Ex: \n\t%s eu ./pics/ ./out\n",argv[0]);
    return 0;
  }

  if (DirectoryExists(outDir.c_str()) == false)
  {
    printf("Output dir does not exist\n");
    return 0;
  }

  cout << "Usage: " << endl;
  cout << "\tn		-- Next plate" << endl;
  cout << "\tp		-- Previous plate" << endl;
  cout << "\tW		-- Select image and save characters according to OCR results, then go to next image" << endl;
  cout << "\ts		-- Save characters" << endl;
  cout << "\t<- and ->	-- Cycle between images" << endl;
  cout << "\tEnt/space	-- Select plate" << endl;
  cout << endl;
  cout << "Within a plate" << endl;
  cout << "\t<- and ->		-- Cycle between characters" << endl;
  cout << "\t[0-9A-Z]		-- Identify a character (saves the image)" << endl;
  cout << "\tESC/Ent/Space	-- Back to plate selection" << endl;

  Config config(country);
  OCR ocr(&config);

  if (DirectoryExists(inDir.c_str()))
  {
    vector<string> files = getFilesInDir(inDir.c_str());

    sort( files.begin(), files.end(), stringCompare );

    for (int i = 0; i< files.size(); i++)
    {
      if (hasEnding(files[i], ".png") || hasEnding(files[i], ".jpg"))
      {
        string fullpath = inDir + "/" + files[i];
        cout << fullpath << endl;
        frame = imread( fullpath.c_str() );
        resize(frame, frame, Size(config.ocrImageWidthPx, config.ocrImageHeightPx));

        imshow ("Original", frame);

	PipelineData pipeline_data(frame, Rect(0, 0, frame.cols, frame.rows), &config);
	cvtColor(frame, frame, CV_BGR2GRAY);
	pipeline_data.crop_gray = Mat(frame, Rect(0, 0, frame.cols, frame.rows));
        char statecode[3];
        statecode[0] = files[i][0];
        statecode[1] = files[i][1];
        statecode[2] = '\0';
        string statecodestr(statecode);

        CharacterAnalysis regionizer(&pipeline_data);

        if (abs(pipeline_data.textLines[0].angle) > 4)
        {
          // Rotate image:
          Mat rotated(frame.size(), frame.type());
          Mat rot_mat( 2, 3, CV_32FC1 );
          Point center = Point( frame.cols/2, frame.rows/2 );

          rot_mat = getRotationMatrix2D( center, pipeline_data.textLines[0].angle, 1.0 );
          warpAffine( frame, rotated, rot_mat, frame.size() );

          rotated.copyTo(frame);
	  pipeline_data.crop_gray = rotated;
        }

        CharacterSegmenter charSegmenter(&pipeline_data);

        //ocr.cleanCharRegions(charSegmenter.thresholds, charSegmenter.characters);

        ocr.performOCR(&pipeline_data);
        ocr.postProcessor.analyze(statecodestr, 25);
        cout << "OCR results: " << ocr.postProcessor.bestChars << endl;

        vector<bool> selectedBoxes(pipeline_data.thresholds.size());
        for (int z = 0; z < pipeline_data.thresholds.size(); z++)
          selectedBoxes[z] = false;

        int curDashboardSelection = 0;

        vector<char> humanInputs(pipeline_data.charRegions.size());

        for (int z = 0; z < pipeline_data.charRegions.size(); z++)
          humanInputs[z] = ' ';

        showDashboard(pipeline_data.thresholds, selectedBoxes, 0);

        char waitkey = (char) waitKey(50);

        while (waitkey != 'n' && waitkey != 'p')	 // Next image
        {
          if (waitkey == LEFT_ARROW_KEY) // left arrow key
          {
            if (curDashboardSelection > 0)
              curDashboardSelection--;
            showDashboard(pipeline_data.thresholds, selectedBoxes, curDashboardSelection);
          }
          else if (waitkey == RIGHT_ARROW_KEY) // right arrow key
          {
            if (curDashboardSelection < pipeline_data.thresholds.size() - 1)
              curDashboardSelection++;
            showDashboard(pipeline_data.thresholds, selectedBoxes, curDashboardSelection);
          }
          else if (waitkey == DOWN_ARROW_KEY)
          {
            if (curDashboardSelection + DASHBOARD_COLUMNS <= pipeline_data.thresholds.size() - 1)
              curDashboardSelection += DASHBOARD_COLUMNS;
            showDashboard(pipeline_data.thresholds, selectedBoxes, curDashboardSelection);
          }
          else if (waitkey == UP_ARROW_KEY)
          {
            if (curDashboardSelection - DASHBOARD_COLUMNS >= 0)
              curDashboardSelection -= DASHBOARD_COLUMNS;
            showDashboard(pipeline_data.thresholds, selectedBoxes, curDashboardSelection);
          }
          else if (waitkey == ENTER_KEY)
          {
	    if (pipeline_data.charRegions.size() > 0)
	    {
	      vector<char> tempdata = showCharSelection(pipeline_data.thresholds[curDashboardSelection], pipeline_data.charRegions, statecodestr);
	      for (int c = 0; c < pipeline_data.charRegions.size(); c++)
		humanInputs[c] = tempdata[c];
	    }
	    else
	    {
	      cout << "No character regions available in this image" << endl;
	    }
          }
          else if (waitkey == SPACE_KEY)
          {
            selectedBoxes[curDashboardSelection] = !selectedBoxes[curDashboardSelection];
            showDashboard(pipeline_data.thresholds, selectedBoxes, curDashboardSelection);
          }
          else if (waitkey == 's' || waitkey == 'S' || waitkey == 'W')
          {
            if (waitkey == 'W')
            {
              selectedBoxes[curDashboardSelection] = true;
              showDashboard(pipeline_data.thresholds, selectedBoxes, curDashboardSelection);
              const std::string& ocr_str = ocr.postProcessor.bestChars;
              humanInputs.assign(ocr_str.begin(), ocr_str.end());
            }

            bool somethingSelected = false;
            bool chardataTagged = false;
            for (int c = 0; c < pipeline_data.thresholds.size(); c++)
            {
              if (selectedBoxes[c])
              {
                somethingSelected = true;
                break;
              }
            }
            for (int c = 0; c < pipeline_data.charRegions.size(); c++)
            {
              if (humanInputs[c] != ' ')
              {
                chardataTagged = true;
                break;
              }
            }
            // Save
            if (somethingSelected && chardataTagged)
            {
              for (int c = 0; c < pipeline_data.charRegions.size(); c++)
              {
                if (humanInputs[c] == ' ')
                  continue;

                for (int t = 0; t < pipeline_data.thresholds.size(); t++)
                {
                  if (selectedBoxes[t] == false)
                    continue;

                  stringstream filename;
                  Mat cropped = pipeline_data.thresholds[t](pipeline_data.charRegions[c]);
                  filename << outDir << "/" << humanInputs[c] << "-" << t << "-" << files[i];
                  imwrite(filename.str(), cropped);
                  cout << "Writing char image: " << filename.str() << endl;
                }
              }
            }
            else if (somethingSelected == false)
              cout << "Did not select any boxes" << endl;
            else if (chardataTagged == false)
              cout << "You have not tagged any characters" << endl;

            if (waitkey == 'W')
            {
              waitkey = 'n';
              continue;
            }
          }

          waitkey = (char) waitKey(50);
        }

        if (waitkey == 'p')
          i = i - 2;
        if (i < -1)
          i = -1;
      }
    }
  }
}

void showDashboard(vector<Mat> images, vector<bool> selectedImages, int selectedIndex)
{
  vector<Mat> vecCopy;

  if (selectedIndex < 0)
    selectedIndex = 0;
  if (selectedIndex >= images.size())
    selectedIndex = images.size() -1;

  for (int i = 0; i < images.size(); i++)
  {
    Mat imgCopy(images[i].size(), images[i].type());
    images[i].copyTo(imgCopy);
    cvtColor(imgCopy, imgCopy, CV_GRAY2BGR);
    if (i == selectedIndex)
    {
      rectangle(imgCopy, Point(1,1), Point(imgCopy.size().width - 1, imgCopy.size().height -1), Scalar(0, 255, 0), 1);
    }
    if (selectedImages[i])
    {
      rectangle(imgCopy, Point(2,2), Point(imgCopy.size().width - 2, imgCopy.size().height -2), Scalar(255, 0, 0), 1);
    }

    vecCopy.push_back(imgCopy);
  }

  Mat dashboard = drawImageDashboard(vecCopy, vecCopy[0].type(), DASHBOARD_COLUMNS);

  imshow("Selection dashboard", dashboard);
}

vector<char> showCharSelection(Mat image, vector<Rect> charRegions, string state)
{
  int curCharIdx = 0;

  vector<char> humanInputs(charRegions.size());
  for (int i = 0; i < charRegions.size(); i++)
    humanInputs[i] = (char) SPACE_KEY;

  char waitkey = (char) waitKey(50);
  while (waitkey != ENTER_KEY && waitkey != ESCAPE_KEY)
  {
    Mat imgCopy(image.size(), image.type());
    image.copyTo(imgCopy);
    cvtColor(imgCopy, imgCopy, CV_GRAY2BGR);

    rectangle(imgCopy, charRegions[curCharIdx], Scalar(0, 255, 0), 1);

    imshow("Character selector", imgCopy);

    if (waitkey == LEFT_ARROW_KEY)
      curCharIdx--;
    else if (waitkey == RIGHT_ARROW_KEY )
      curCharIdx++;
    else if ((waitkey >= '0' && waitkey <= '9') || (waitkey >= 'a' && waitkey <= 'z') || waitkey == SPACE_KEY)
    {
      // Save the character to disk
      humanInputs[curCharIdx] = toupper((char) waitkey);
      curCharIdx++;

      if (curCharIdx >= charRegions.size())
      {
        waitkey = (char) ENTER_KEY;
        break;
      }
    }

    if (curCharIdx < 0)
      curCharIdx = 0;
    if (curCharIdx >= charRegions.size())
      curCharIdx = charRegions.size() -1;

    waitkey = (char) waitKey(50);
  }

  if (waitkey == ENTER_KEY)
  {
    // Save all the inputs
    for (int i = 0; i < charRegions.size(); i++)
    {
      if (humanInputs[i] != (char) SPACE_KEY)
        cout << "Tagged " << state << " char code: '" << humanInputs[i] << "' at char position: " << i << endl;
    }
  }

  destroyWindow("Character selector");

  return humanInputs;
}
<commit_msg>Fixed segfault in classifychars caused by rotation<commit_after>/*
 * Copyright (c) 2014 New Designs Unlimited, LLC
 * Opensource Automated License Plate Recognition [http://www.openalpr.com]
 *
 * This file is part of OpenAlpr.
 *
 * OpenAlpr is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License
 * version 3 as published by the Free Software Foundation
 *
 * This program 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 Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"

#include <iostream>
#include <stdio.h>
#include <sys/stat.h>

#include "licenseplatecandidate.h"
#include "stateidentifier.h"
#include "utility.h"
#include "support/filesystem.h"
#include "ocr.h"

using namespace std;
using namespace cv;
using namespace alpr;

// Given a directory full of lp images (named [statecode]#.png) crop out the alphanumeric characters.
// These will be used to train the OCR

#ifdef __APPLE__
const int LEFT_ARROW_KEY = 2;
const int RIGHT_ARROW_KEY = 3;
const int SPACE_KEY = 32;
const int ENTER_KEY = 13;
const int ESCAPE_KEY = 27;

const int DOWN_ARROW_KEY = 1;
const int UP_ARROW_KEY= 0;
const int DASHBOARD_COLUMNS = 9;

#else
const int LEFT_ARROW_KEY = 81;
const int RIGHT_ARROW_KEY = 83;
const int SPACE_KEY = 32;
const int ENTER_KEY = 10;
const int ESCAPE_KEY = 27;

const int DOWN_ARROW_KEY = 84;
const int UP_ARROW_KEY= 82;
const int DASHBOARD_COLUMNS = 3;

#endif

void showDashboard(vector<Mat> images, vector<bool> selectedImages, int selectedIndex);
vector<char> showCharSelection(Mat image, vector<Rect> charRegions, string state);

int main( int argc, const char** argv )
{
  string country;
  string inDir;
  string outDir;
  Mat frame;

  //Check if user specify image to process
  if(argc == 4)
  {
    country = argv[1];
    inDir = argv[2];
    outDir = argv[3];
  }
  else
  {
    printf("Use:\n\t%s country indirectory outdirectory\n",argv[0]);
    printf("Ex: \n\t%s eu ./pics/ ./out\n",argv[0]);
    return 0;
  }

  if (DirectoryExists(outDir.c_str()) == false)
  {
    printf("Output dir does not exist\n");
    return 0;
  }

  cout << "Usage: " << endl;
  cout << "\tn		-- Next plate" << endl;
  cout << "\tp		-- Previous plate" << endl;
  cout << "\tW		-- Select image and save characters according to OCR results, then go to next image" << endl;
  cout << "\ts		-- Save characters" << endl;
  cout << "\t<- and ->	-- Cycle between images" << endl;
  cout << "\tEnt/space	-- Select plate" << endl;
  cout << endl;
  cout << "Within a plate" << endl;
  cout << "\t<- and ->		-- Cycle between characters" << endl;
  cout << "\t[0-9A-Z]		-- Identify a character (saves the image)" << endl;
  cout << "\tESC/Ent/Space	-- Back to plate selection" << endl;

  Config config(country);
  config.debugGeneral = true;
  config.debugCharAnalysis = true;
  config.debugCharSegmenter = true;
  OCR ocr(&config);

  if (DirectoryExists(inDir.c_str()))
  {
    vector<string> files = getFilesInDir(inDir.c_str());

    sort( files.begin(), files.end(), stringCompare );

    for (int i = 0; i< files.size(); i++)
    {
      if (hasEnding(files[i], ".png") || hasEnding(files[i], ".jpg"))
      {
        string fullpath = inDir + "/" + files[i];
        cout << fullpath << endl;
        frame = imread( fullpath.c_str() );
        resize(frame, frame, Size(config.ocrImageWidthPx, config.ocrImageHeightPx));

        imshow ("Original", frame);

	PipelineData pipeline_data(frame, Rect(0, 0, frame.cols, frame.rows), &config);
	cvtColor(frame, frame, CV_BGR2GRAY);
	pipeline_data.crop_gray = Mat(frame, Rect(0, 0, frame.cols, frame.rows));
        char statecode[3];
        statecode[0] = files[i][0];
        statecode[1] = files[i][1];
        statecode[2] = '\0';
        string statecodestr(statecode);

        CharacterAnalysis regionizer(&pipeline_data);

        CharacterSegmenter charSegmenter(&pipeline_data);

        //ocr.cleanCharRegions(charSegmenter.thresholds, charSegmenter.characters);

        ocr.performOCR(&pipeline_data);
        ocr.postProcessor.analyze(statecodestr, 25);
        cout << "OCR results: " << ocr.postProcessor.bestChars << endl;

        vector<bool> selectedBoxes(pipeline_data.thresholds.size());
        for (int z = 0; z < pipeline_data.thresholds.size(); z++)
          selectedBoxes[z] = false;

        int curDashboardSelection = 0;

        vector<char> humanInputs(pipeline_data.charRegions.size());

        for (int z = 0; z < pipeline_data.charRegions.size(); z++)
          humanInputs[z] = ' ';

        showDashboard(pipeline_data.thresholds, selectedBoxes, 0);

        char waitkey = (char) waitKey(50);

        while (waitkey != 'n' && waitkey != 'p')	 // Next image
        {
          if (waitkey == LEFT_ARROW_KEY) // left arrow key
          {
            if (curDashboardSelection > 0)
              curDashboardSelection--;
            showDashboard(pipeline_data.thresholds, selectedBoxes, curDashboardSelection);
          }
          else if (waitkey == RIGHT_ARROW_KEY) // right arrow key
          {
            if (curDashboardSelection < pipeline_data.thresholds.size() - 1)
              curDashboardSelection++;
            showDashboard(pipeline_data.thresholds, selectedBoxes, curDashboardSelection);
          }
          else if (waitkey == DOWN_ARROW_KEY)
          {
            if (curDashboardSelection + DASHBOARD_COLUMNS <= pipeline_data.thresholds.size() - 1)
              curDashboardSelection += DASHBOARD_COLUMNS;
            showDashboard(pipeline_data.thresholds, selectedBoxes, curDashboardSelection);
          }
          else if (waitkey == UP_ARROW_KEY)
          {
            if (curDashboardSelection - DASHBOARD_COLUMNS >= 0)
              curDashboardSelection -= DASHBOARD_COLUMNS;
            showDashboard(pipeline_data.thresholds, selectedBoxes, curDashboardSelection);
          }
          else if (waitkey == ENTER_KEY)
          {
	    if (pipeline_data.charRegions.size() > 0)
	    {
	      vector<char> tempdata = showCharSelection(pipeline_data.thresholds[curDashboardSelection], pipeline_data.charRegions, statecodestr);
	      for (int c = 0; c < pipeline_data.charRegions.size(); c++)
		humanInputs[c] = tempdata[c];
	    }
	    else
	    {
	      cout << "No character regions available in this image" << endl;
	    }
          }
          else if (waitkey == SPACE_KEY)
          {
            selectedBoxes[curDashboardSelection] = !selectedBoxes[curDashboardSelection];
            showDashboard(pipeline_data.thresholds, selectedBoxes, curDashboardSelection);
          }
          else if (waitkey == 's' || waitkey == 'S' || waitkey == 'W')
          {
            if (waitkey == 'W')
            {
              selectedBoxes[curDashboardSelection] = true;
              showDashboard(pipeline_data.thresholds, selectedBoxes, curDashboardSelection);
              const std::string& ocr_str = ocr.postProcessor.bestChars;
              humanInputs.assign(ocr_str.begin(), ocr_str.end());
            }

            bool somethingSelected = false;
            bool chardataTagged = false;
            for (int c = 0; c < pipeline_data.thresholds.size(); c++)
            {
              if (selectedBoxes[c])
              {
                somethingSelected = true;
                break;
              }
            }
            for (int c = 0; c < pipeline_data.charRegions.size(); c++)
            {
              if (humanInputs[c] != ' ')
              {
                chardataTagged = true;
                break;
              }
            }
            // Save
            if (somethingSelected && chardataTagged)
            {
              for (int c = 0; c < pipeline_data.charRegions.size(); c++)
              {
                if (humanInputs[c] == ' ')
                  continue;

                for (int t = 0; t < pipeline_data.thresholds.size(); t++)
                {
                  if (selectedBoxes[t] == false)
                    continue;

                  stringstream filename;
                  Mat cropped = pipeline_data.thresholds[t](pipeline_data.charRegions[c]);
                  filename << outDir << "/" << humanInputs[c] << "-" << t << "-" << files[i];
                  imwrite(filename.str(), cropped);
                  cout << "Writing char image: " << filename.str() << endl;
                }
              }
            }
            else if (somethingSelected == false)
              cout << "Did not select any boxes" << endl;
            else if (chardataTagged == false)
              cout << "You have not tagged any characters" << endl;

            if (waitkey == 'W')
            {
              waitkey = 'n';
              continue;
            }
          }

          waitkey = (char) waitKey(50);
        }

        if (waitkey == 'p')
          i = i - 2;
        if (i < -1)
          i = -1;
      }
    }
  }
}

void showDashboard(vector<Mat> images, vector<bool> selectedImages, int selectedIndex)
{
  vector<Mat> vecCopy;

  if (selectedIndex < 0)
    selectedIndex = 0;
  if (selectedIndex >= images.size())
    selectedIndex = images.size() -1;

  for (int i = 0; i < images.size(); i++)
  {
    Mat imgCopy(images[i].size(), images[i].type());
    images[i].copyTo(imgCopy);
    cvtColor(imgCopy, imgCopy, CV_GRAY2BGR);
    if (i == selectedIndex)
    {
      rectangle(imgCopy, Point(1,1), Point(imgCopy.size().width - 1, imgCopy.size().height -1), Scalar(0, 255, 0), 1);
    }
    if (selectedImages[i])
    {
      rectangle(imgCopy, Point(2,2), Point(imgCopy.size().width - 2, imgCopy.size().height -2), Scalar(255, 0, 0), 1);
    }

    vecCopy.push_back(imgCopy);
  }

  Mat dashboard = drawImageDashboard(vecCopy, vecCopy[0].type(), DASHBOARD_COLUMNS);

  imshow("Selection dashboard", dashboard);
}

vector<char> showCharSelection(Mat image, vector<Rect> charRegions, string state)
{
  int curCharIdx = 0;

  vector<char> humanInputs(charRegions.size());
  for (int i = 0; i < charRegions.size(); i++)
    humanInputs[i] = (char) SPACE_KEY;

  char waitkey = (char) waitKey(50);
  while (waitkey != ENTER_KEY && waitkey != ESCAPE_KEY)
  {
    Mat imgCopy(image.size(), image.type());
    image.copyTo(imgCopy);
    cvtColor(imgCopy, imgCopy, CV_GRAY2BGR);

    rectangle(imgCopy, charRegions[curCharIdx], Scalar(0, 255, 0), 1);

    imshow("Character selector", imgCopy);

    if (waitkey == LEFT_ARROW_KEY)
      curCharIdx--;
    else if (waitkey == RIGHT_ARROW_KEY )
      curCharIdx++;
    else if ((waitkey >= '0' && waitkey <= '9') || (waitkey >= 'a' && waitkey <= 'z') || waitkey == SPACE_KEY)
    {
      // Save the character to disk
      humanInputs[curCharIdx] = toupper((char) waitkey);
      curCharIdx++;

      if (curCharIdx >= charRegions.size())
      {
        waitkey = (char) ENTER_KEY;
        break;
      }
    }

    if (curCharIdx < 0)
      curCharIdx = 0;
    if (curCharIdx >= charRegions.size())
      curCharIdx = charRegions.size() -1;

    waitkey = (char) waitKey(50);
  }

  if (waitkey == ENTER_KEY)
  {
    // Save all the inputs
    for (int i = 0; i < charRegions.size(); i++)
    {
      if (humanInputs[i] != (char) SPACE_KEY)
        cout << "Tagged " << state << " char code: '" << humanInputs[i] << "' at char position: " << i << endl;
    }
  }

  destroyWindow("Character selector");

  return humanInputs;
}
<|endoftext|>