- Main Page
- Related Pages
- Modules
- Namespaces
- Classes
- Files
- Directories
- Examples

# CurveBrush/CurveCreator.cpp

    #include "CurveCreator.h"

    #include <QtCore/QVector>
    #include <math.h>

    IMPLEMENT_CLASS( CurveCreator, BrushOperation, "CurveCreator" );

    static QVector< Store< Vector >* > gLines;

    QVector< Store<Vector>* >& CurveCreator::Lines() { return gLines; }

    CurveCreator::CurveCreator() :
    m_iCurrentCurve( -1 ),
    m_iDoState( 0 ), m_fSTimes(this, "Smooth", 0, 100, 1, 0)
    {
        m_fSTimes.SetValue(20);
        m_fSTimes.SetVisible(true);
        iLastFaceIndex = -1;
        iFirstPointIndex = -1;
    };

    void CurveCreator::BeginStroke( Mesh *, Modifier, TriggerType )
    {
        // start a new curve
        gLines.push_back( new Store<Vector> );

        // indicate we are in the middle of doing the operation.
        m_iDoState = 0;
        m_iCurrentCurve = gLines.size() - 1;
    };

    void CurveCreator::EndStroke( void )
    {
        if( gLines.back()->ItemCount() == 0 )
        {
            // we can get here if the user does a mouse click
            // with no mouse movement. since we don't want empty
            // curves in the array, remove the last one we added.
            m_iCurrentCurve = -1;
            gLines.pop_back();
        }
        else if (iFirstPointIndex >= 0 && iLastFaceIndex >= 0)
        {
            int iEndPointIndex = gLines.back()->ItemCount() - 1;
            if (iEndPointIndex - iFirstPointIndex + 1 >= 3 && m_fSTimes)
            {
                const int iPCount = iEndPointIndex - iFirstPointIndex + 1;
                QVector<Vector> aP(iPCount);
                for (int iS = 0; iS < m_fSTimes; ++iS)
                {
                    for (int i = iFirstPointIndex + 1; i < iEndPointIndex; ++i)
                        aP[i - iFirstPointIndex] = (gLines.back()->operator[](i-1) + gLines.back()->operator[](i)
                        + gLines.back()->operator[](i) + gLines.back()->operator[](i+1)) * 0.25f;

                    for (int i = iFirstPointIndex + 1; i < iEndPointIndex; ++i)
                        gLines.back()->operator[](i) = aP[i - iFirstPointIndex];
                }
            }
        }

        iLastFaceIndex = -1;
        iFirstPointIndex = -1;

        // treat this as an undoable operation.
        Kernel()->DoOperation( this );

        Kernel()->Redraw();
    };

    void CurveCreator::AddPatch( const SurfacePoint *, const Vector &, float, float, float, AxisAlignedBoundingBox & )
    {

    };

    void CurveCreator::MouseMove( float fX, float fY, float , float , AxisAlignedBoundingBox &a, float, float, float  )
    {
        // determine where the user clicked in 3d space
        SurfacePoint pp;
        ViewPort *pVPp = Kernel()->ViewPort();
        if( Kernel()->Scene()->ActiveCamera()->Pick( fX*pVPp->Width(), fY*pVPp->Height(), pp ) )
        {
            gLines.back()->Add( pp.WorldPosition() );

            // local smoothing which  only smooth the polylines on the same face, supposing the face is flat,
            // which means the smoothed points are still on face/mesh.
            // when the curve brush moves from face 1 to face 2, smooth the polylines of face 1.
            // when the curve brush stops, smoothe polylines of the last face, this is done in CurveCreator::EndStroke().
            if (iLastFaceIndex == -1 || iFirstPointIndex == -1)
            {
                iLastFaceIndex = pp.m_iFaceIndex;
                iFirstPointIndex = 0;
            }

            if (iFirstPointIndex >= 0 && iLastFaceIndex >= 0 &&
                pp.m_iFaceIndex != iLastFaceIndex)
            {
                int iEndPointIndex = gLines.back()->ItemCount() - 2;
                if (iEndPointIndex - iFirstPointIndex + 1 >= 3 && m_fSTimes)
                {
                    const int iPCount = iEndPointIndex - iFirstPointIndex + 1;
                    QVector<Vector> aP(iPCount);
                    for (int iS = 0; iS < m_fSTimes; ++iS)
                    {
                        for (int i = iFirstPointIndex + 1; i < iEndPointIndex; ++i)
                            aP[i - iFirstPointIndex] = (gLines.back()->operator[](i-1) + gLines.back()->operator[](i)
                            + gLines.back()->operator[](i) + gLines.back()->operator[](i+1)) * 0.25f;

                        for (int i = iFirstPointIndex + 1; i < iEndPointIndex; ++i)
                            gLines.back()->operator[](i) = aP[i - iFirstPointIndex];
                    }
                }

                iFirstPointIndex = gLines.back()->ItemCount() - 1;
                iLastFaceIndex = pp.m_iFaceIndex;
            }
        };

        // expand the dirty region of the viewport
        for( unsigned int i = 0; i < gLines.size(); ++i )
        {
            for( unsigned int j = 0; j < gLines[i]->ItemCount(); ++j )
                a.Extend( gLines[i]->operator[](j) );
        };
    };

    bool CurveCreator::ExecuteAndInvert( void )
    {
        if( m_iDoState == 0 )   // this is do
        {
            m_iLine.Clear();
            m_iDoState = 1;
        }
        else if( m_iDoState == 1 ) // this is undo
        {
            if( m_iCurrentCurve != -1 )
            {
                Store<Vector>* pLine = gLines.back();
                m_iLine = *pLine;
                gLines.pop_back();
                delete pLine;
                pLine = 0;
            };
            m_iDoState = 2;
        }
        else if( m_iDoState == 2 )  // this is redo
        {
            if( m_iCurrentCurve != -1 )
            {
                Store<Vector>* pNewLine = new Store<Vector>;
                *pNewLine = m_iLine;

                gLines.push_back( pNewLine );
            };
            m_iDoState = 1;
        };

        Kernel()->Redraw();

        return true;
    };

    void CurveCreator::Serialize( Stream &s )
    {
        // this method saves undo data
        s == m_iCurrentCurve == m_iLine == m_iDoState;
    };