CurveBrush/CurveCreator.cpp

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 )
{
// 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( 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;
};