added ARCANGLETO command implementation, optimization, fixes, debug

- added new ARCANGLETO command needed for PPTX custom shapes import
  - added added placeholder for unimplemented QUADRATICCURVETO command,
    skip it's data at least so that we don't break other things for now
  - cache equations results to optimize custom shapes calculation
    PPTX import creates such equations that made system busy for long
    time, this removes that issue
  - added lot of debug output to help with debugging of complex imported
    custom shapes
This commit is contained in:
Radek Doulik 2011-10-05 16:09:26 +02:00
parent 1c0ae973dd
commit fcdc9c4fa0
3 changed files with 129 additions and 11 deletions

View File

@ -103,9 +103,13 @@ class EnhancedCustomShape2d : public SfxItemSet
/*
*/
struct EquationResult {
sal_Bool bReady;
double fValue;
};
com::sun::star::uno::Sequence< rtl::OUString > seqEquations;
std::vector< ::boost::shared_ptr< EnhancedCustomShape::ExpressionNode > > vNodesSharedPtr;
std::vector< EquationResult > vEquationResults;
com::sun::star::uno::Sequence< com::sun::star::drawing::EnhancedCustomShapeSegment > seqSegments;
com::sun::star::uno::Sequence< com::sun::star::drawing::EnhancedCustomShapeParameterPair> seqCoordinates;

View File

@ -824,14 +824,18 @@ EnhancedCustomShape2d::EnhancedCustomShape2d( SdrObject* pAObj ) :
if ( nLength )
{
vNodesSharedPtr.resize( nLength );
vEquationResults.resize( nLength );
for ( i = 0; i < seqEquations.getLength(); i++ )
{
vEquationResults[ i ].bReady = sal_False;
try
{
vNodesSharedPtr[ i ] = EnhancedCustomShape::FunctionParser::parseFunction( seqEquations[ i ], *this );
}
catch ( EnhancedCustomShape::ParseError& )
{
OSL_TRACE("error: equation number: %d, parser failed ( %s )",
i, OUStringToOString( seqEquations[ i ], RTL_TEXTENCODING_ASCII_US ).getStr());
}
}
}
@ -876,20 +880,49 @@ double EnhancedCustomShape2d::GetAdjustValueAsDouble( const sal_Int32 nIndex ) c
double EnhancedCustomShape2d::GetEquationValueAsDouble( const sal_Int32 nIndex ) const
{
double fNumber = 0.0;
#if OSL_DEBUG_LEVEL > 1
static sal_uInt32 nLevel = 0;
#endif
if ( nIndex < (sal_Int32)vNodesSharedPtr.size() )
{
if ( vNodesSharedPtr[ nIndex ].get() )
try
{
fNumber = (*vNodesSharedPtr[ nIndex ])();
if ( !rtl::math::isFinite( fNumber ) )
fNumber = 0.0;
}
catch ( ... )
{
/* sal_Bool bUps = sal_True; */
if ( vNodesSharedPtr[ nIndex ].get() ) {
#if OSL_DEBUG_LEVEL > 1
nLevel ++;
#endif
try
{
if ( vEquationResults[ nIndex ].bReady )
fNumber = vEquationResults[ nIndex ].fValue;
else {
// cast to non const, so that we can optimize by caching
// equation results, without changing all the const in the stack
struct EquationResult &aResult = ((EnhancedCustomShape2d*)this)->vEquationResults[ nIndex ];
fNumber = aResult.fValue = (*vNodesSharedPtr[ nIndex ])();
aResult.bReady = sal_True;
if ( !rtl::math::isFinite( fNumber ) )
fNumber = 0.0;
#if OSL_DEBUG_LEVEL > 1
OSL_TRACE("equation %d (level: %d): %s --> %f (angle: %f)", nIndex,
nLevel, OUStringToOString( seqEquations[ nIndex ],
RTL_TEXTENCODING_ASCII_US ).getStr(), fNumber, 180.0*fNumber/10800000.0);
#endif
}
}
catch ( ... )
{
/* sal_Bool bUps = sal_True; */
OSL_TRACE("error: EnhancedCustomShape2d::GetEquationValueAsDouble failed");
}
#if OSL_DEBUG_LEVEL > 1
nLevel --;
#endif
}
OSL_TRACE(" ?%d --> %f (angle: %f)", nIndex,
fNumber, 180.0*fNumber/10800000.0);
}
return fNumber;
}
sal_Int32 EnhancedCustomShape2d::GetAdjustValueAsInteger( const sal_Int32 nIndex, const sal_Int32 nDefault ) const
@ -1457,6 +1490,7 @@ void EnhancedCustomShape2d::CreateSubPath( sal_uInt16& rSrcPt, sal_uInt16& rSegm
if ( rSrcPt < nCoordSize )
{
const Point aTempPoint(GetPoint( seqCoordinates[ rSrcPt++ ], sal_True, sal_True ));
OSL_TRACE("moveTo: %d,%d", aTempPoint.X(), aTempPoint.Y());
aNewB2DPolygon.append(basegfx::B2DPoint(aTempPoint.X(), aTempPoint.Y()));
}
}
@ -1591,11 +1625,19 @@ void EnhancedCustomShape2d::CreateSubPath( sal_uInt16& rSrcPt, sal_uInt16& rSegm
}
break;
case QUADRATICCURVETO : // TODO
for ( sal_Int32 i(0L); ( i < nPntCount ) && ( rSrcPt + 1 < nCoordSize ); i++ )
{
rSrcPt += 2;
}
break;
case LINETO :
{
for ( sal_Int32 i(0L); ( i < nPntCount ) && ( rSrcPt < nCoordSize ); i++ )
{
const Point aTempPoint(GetPoint( seqCoordinates[ rSrcPt++ ], sal_True, sal_True ));
OSL_TRACE("lineTo: %d,%d", aTempPoint.X(), aTempPoint.Y());
aNewB2DPolygon.append(basegfx::B2DPoint(aTempPoint.X(), aTempPoint.Y()));
}
}
@ -1638,6 +1680,54 @@ void EnhancedCustomShape2d::CreateSubPath( sal_uInt16& rSrcPt, sal_uInt16& rSegm
}
break;
case ARCANGLETO :
{
double fWR, fHR, fStartAngle, fSwingAngle;
for ( sal_uInt16 i = 0; ( i < nPntCount ) && ( rSrcPt + 1 < nCoordSize ); i++ )
{
GetParameter ( fWR, seqCoordinates[ (sal_uInt16)( rSrcPt ) ].First, sal_True, sal_False );
GetParameter ( fHR, seqCoordinates[ (sal_uInt16)( rSrcPt ) ].Second, sal_False, sal_True );
GetParameter ( fStartAngle, seqCoordinates[ (sal_uInt16)( rSrcPt + 1) ].First, sal_False, sal_False );
GetParameter ( fSwingAngle, seqCoordinates[ (sal_uInt16)( rSrcPt + 1 ) ].Second, sal_False, sal_False );
fWR *= fXScale;
fHR *= fYScale;
fStartAngle *= F_PI180;
fSwingAngle *= F_PI180;
OSL_TRACE("ARCANGLETO scale: %f x %f angles: %f, %f", fWR, fHR, fStartAngle, fSwingAngle);
sal_Bool bClockwise = fSwingAngle >= 0.0;
if (aNewB2DPolygon.count() > 0)
{
basegfx::B2DPoint aStartPointB2D( aNewB2DPolygon.getB2DPoint(aNewB2DPolygon.count() - 1 ) );
Point aStartPoint( aStartPointB2D.getX(), aStartPointB2D.getY() );
double fT = atan2((fWR*sin(fStartAngle)), (fHR*cos(fStartAngle)));
double fTE = atan2((fWR*sin(fStartAngle + fSwingAngle)), fHR*cos(fStartAngle + fSwingAngle));
OSL_TRACE("ARCANGLETO angles: %f, %f --> parameters: %f, %f", fStartAngle, fSwingAngle, fT, fTE );
Rectangle aRect ( Point ( aStartPoint.getX() - fWR*cos(fT) - fWR, aStartPoint.getY() - fHR*sin(fT) - fHR ),
Point ( aStartPoint.getX() - fWR*cos(fT) + fWR, aStartPoint.getY() - fHR*sin(fT) + fHR) );
Point aEndPoint ( aStartPoint.getX() - fWR*(cos(fT) - cos(fTE)), aStartPoint.getY() - fHR*(sin(fT) - sin(fTE)) );
OSL_TRACE("ARCANGLETO rect: %d, %d x %d, %d start: %d, %d end: %d, %d clockwise: %d",
aRect.Left(), aRect.Top(), aRect.Right(), aRect.Bottom(),
aStartPoint.X(), aStartPoint.Y(), aEndPoint.X(), aEndPoint.Y(), bClockwise);
aNewB2DPolygon.append(CreateArc( aRect, bClockwise ? aEndPoint : aStartPoint, bClockwise ? aStartPoint : aEndPoint, bClockwise));
}
rSrcPt += 2;
}
}
break;
case ELLIPTICALQUADRANTX :
case ELLIPTICALQUADRANTY :
{

View File

@ -163,6 +163,7 @@ public:
}
virtual double operator()() const
{
OSL_TRACE(" $%d --> %f (angle: %f)", mnIndex, mrCustoShape.GetAdjustValueAsDouble( mnIndex ), 180.0*mrCustoShape.GetAdjustValueAsDouble( mnIndex )/10800000.0);
return mrCustoShape.GetAdjustValueAsDouble( mnIndex );
}
virtual bool isConstant() const
@ -253,6 +254,29 @@ public:
}
virtual double operator()() const
{
#if OSL_DEBUG_LEVEL > 1
const char *funcName;
switch (meFunct) {
case ENUM_FUNC_PI : funcName = "pi"; break;
case ENUM_FUNC_LEFT : funcName = "left"; break;
case ENUM_FUNC_TOP : funcName = "top"; break;
case ENUM_FUNC_RIGHT : funcName = "right"; break;
case ENUM_FUNC_BOTTOM : funcName = "bottom"; break;
case ENUM_FUNC_XSTRETCH : funcName = "xstretch"; break;
case ENUM_FUNC_YSTRETCH : funcName = "ystretch"; break;
case ENUM_FUNC_HASSTROKE : funcName = "hasstroke"; break;
case ENUM_FUNC_HASFILL : funcName = "hasfill"; break;
case ENUM_FUNC_WIDTH : funcName = "width"; break;
case ENUM_FUNC_HEIGHT : funcName = "height"; break;
case ENUM_FUNC_LOGWIDTH : funcName = "logwidth"; break;
case ENUM_FUNC_LOGHEIGHT : funcName = "logheight"; break;
default: funcName = "???"; break;
}
OSL_TRACE(" %s --> %f (angle: %f)", funcName, getValue( mrCustoShape, meFunct ), 180.0*getValue( mrCustoShape, meFunct )/10800000.0);
#endif
return getValue( mrCustoShape, meFunct );
}
virtual bool isConstant() const