1 /************************************************************************* 2 * 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * Copyright 2000, 2010 Oracle and/or its affiliates. 6 * 7 * OpenOffice.org - a multi-platform office productivity suite 8 * 9 * This file is part of OpenOffice.org. 10 * 11 * OpenOffice.org is free software: you can redistribute it and/or modify 12 * it under the terms of the GNU Lesser General Public License version 3 13 * only, as published by the Free Software Foundation. 14 * 15 * OpenOffice.org is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU Lesser General Public License version 3 for more details 19 * (a copy is included in the LICENSE file that accompanied this code). 20 * 21 * You should have received a copy of the GNU Lesser General Public License 22 * version 3 along with OpenOffice.org. If not, see 23 * <http://www.openoffice.org/license.html> 24 * for a copy of the LGPLv3 License. 25 * 26 ************************************************************************/ 27 28 // MARKER(update_precomp.py): autogen include statement, do not remove 29 #include "precompiled_sd.hxx" 30 31 //#define _FUMORPH_PRIVATE 32 #include "fumorph.hxx" 33 #include <svx/xfillit.hxx> 34 #include <svx/xlineit.hxx> 35 #include <vcl/msgbox.hxx> 36 #include <svx/svdpool.hxx> 37 #include <tools/poly.hxx> 38 #include <svx/svdopath.hxx> 39 #include <svx/svdogrp.hxx> 40 #include <editeng/eeitem.hxx> 41 42 #include "View.hxx" 43 #include "ViewShell.hxx" 44 #include "Window.hxx" 45 #include <basegfx/polygon/b2dpolygontools.hxx> 46 #include <basegfx/polygon/b2dpolypolygontools.hxx> 47 #include <basegfx/matrix/b2dhommatrix.hxx> 48 #include <basegfx/matrix/b2dhommatrixtools.hxx> 49 50 #include "strings.hrc" 51 #include "sdresid.hxx" 52 53 #include "sdabstdlg.hxx" 54 55 // #i48168# 56 #include <svx/svditer.hxx> 57 58 #include <basegfx/color/bcolor.hxx> 59 60 namespace sd { 61 62 #define ITEMVALUE( ItemSet, Id, Cast ) ( ( (const Cast&) (ItemSet).Get( (Id) ) ).GetValue() ) 63 TYPEINIT1( FuMorph, FuPoor ); 64 65 ////////////////////////////////////////////////////////////////////////////// 66 // constructor 67 // 68 FuMorph::FuMorph ( 69 ViewShell* pViewSh, 70 ::sd::Window* pWin, 71 ::sd::View* pView, 72 SdDrawDocument* pDoc, 73 SfxRequest& rReq ) 74 : FuPoor(pViewSh, pWin, pView, pDoc, rReq) 75 { 76 } 77 78 FunctionReference FuMorph::Create( ViewShell* pViewSh, ::sd::Window* pWin, ::sd::View* pView, SdDrawDocument* pDoc, SfxRequest& rReq ) 79 { 80 FunctionReference xFunc( new FuMorph( pViewSh, pWin, pView, pDoc, rReq ) ); 81 xFunc->DoExecute(rReq); 82 return xFunc; 83 } 84 85 void FuMorph::DoExecute( SfxRequest& ) 86 { 87 const SdrMarkList& rMarkList = mpView->GetMarkedObjectList(); 88 89 if(rMarkList.GetMarkCount() == 2) 90 { 91 // Clones erzeugen 92 SdrObject* pObj1 = rMarkList.GetMark(0)->GetMarkedSdrObj(); 93 SdrObject* pObj2 = rMarkList.GetMark(1)->GetMarkedSdrObj(); 94 SdrObject* pCloneObj1 = pObj1->Clone(); 95 SdrObject* pCloneObj2 = pObj2->Clone(); 96 97 // Text am Clone loeschen, da wir sonst kein richtiges PathObj bekommen 98 pCloneObj1->SetOutlinerParaObject(NULL); 99 pCloneObj2->SetOutlinerParaObject(NULL); 100 101 // Path-Objekte erzeugen 102 SdrObject* pPolyObj1 = pCloneObj1->ConvertToPolyObj(sal_False, sal_False); 103 SdrObject* pPolyObj2 = pCloneObj2->ConvertToPolyObj(sal_False, sal_False); 104 SdAbstractDialogFactory* pFact = SdAbstractDialogFactory::Create(); 105 AbstractMorphDlg* pDlg = pFact ? pFact->CreateMorphDlg( static_cast< ::Window*>(mpWindow), pObj1, pObj2 ) : 0; 106 if(pPolyObj1 && pPolyObj2 && pDlg && (pDlg->Execute() == RET_OK)) 107 { 108 List aPolyPolyList; 109 ::basegfx::B2DPolyPolygon aPolyPoly1; 110 ::basegfx::B2DPolyPolygon aPolyPoly2; 111 ::basegfx::B2DPolyPolygon* pPolyPoly; 112 113 pDlg->SaveSettings(); 114 115 // #i48168# Not always is the pPolyObj1/pPolyObj2 a SdrPathObj, it may also be a group object 116 // containing SdrPathObjs. To get the polygons, i add two iters here 117 SdrObjListIter aIter1(*pPolyObj1); 118 SdrObjListIter aIter2(*pPolyObj2); 119 120 while(aIter1.IsMore()) 121 { 122 SdrObject* pObj = aIter1.Next(); 123 if(pObj && pObj->ISA(SdrPathObj)) 124 aPolyPoly1.append(((SdrPathObj*)pObj)->GetPathPoly()); 125 } 126 127 while(aIter2.IsMore()) 128 { 129 SdrObject* pObj = aIter2.Next(); 130 if(pObj && pObj->ISA(SdrPathObj)) 131 aPolyPoly2.append(((SdrPathObj*)pObj)->GetPathPoly()); 132 } 133 134 // Morphing durchfuehren 135 if(aPolyPoly1.count() && aPolyPoly2.count()) 136 { 137 aPolyPoly1 = ::basegfx::tools::correctOrientations(aPolyPoly1); 138 aPolyPoly1.removeDoublePoints(); 139 ::basegfx::B2VectorOrientation eIsClockwise1(::basegfx::tools::getOrientation(aPolyPoly1.getB2DPolygon(0L))); 140 141 aPolyPoly2 = ::basegfx::tools::correctOrientations(aPolyPoly2); 142 aPolyPoly2.removeDoublePoints(); 143 ::basegfx::B2VectorOrientation eIsClockwise2(::basegfx::tools::getOrientation(aPolyPoly2.getB2DPolygon(0L))); 144 145 // set same orientation 146 if(eIsClockwise1 != eIsClockwise2) 147 aPolyPoly2.flip(); 148 149 // force same poly count 150 if(aPolyPoly1.count() < aPolyPoly2.count()) 151 ImpAddPolys(aPolyPoly1, aPolyPoly2); 152 else if(aPolyPoly2.count() < aPolyPoly1.count()) 153 ImpAddPolys(aPolyPoly2, aPolyPoly1); 154 155 // use orientation flag from dialog 156 if(!pDlg->IsOrientationFade()) 157 aPolyPoly2.flip(); 158 159 // force same point counts 160 for( sal_uInt32 a(0L); a < aPolyPoly1.count(); a++ ) 161 { 162 ::basegfx::B2DPolygon aSub1(aPolyPoly1.getB2DPolygon(a)); 163 ::basegfx::B2DPolygon aSub2(aPolyPoly2.getB2DPolygon(a)); 164 165 if(aSub1.count() < aSub2.count()) 166 ImpEqualizePolyPointCount(aSub1, aSub2); 167 else if(aSub2.count() < aSub1.count()) 168 ImpEqualizePolyPointCount(aSub2, aSub1); 169 170 aPolyPoly1.setB2DPolygon(a, aSub1); 171 aPolyPoly2.setB2DPolygon(a, aSub2); 172 } 173 174 if(ImpMorphPolygons(aPolyPoly1, aPolyPoly2, pDlg->GetFadeSteps(), aPolyPolyList)) 175 { 176 String aString(mpView->GetDescriptionOfMarkedObjects()); 177 178 aString.Append(sal_Unicode(' ')); 179 aString.Append(String(SdResId(STR_UNDO_MORPHING))); 180 181 mpView->BegUndo(aString); 182 ImpInsertPolygons(aPolyPolyList, pDlg->IsAttributeFade(), pObj1, pObj2); 183 mpView->EndUndo(); 184 } 185 186 // erzeugte Polygone wieder loeschen 187 for(pPolyPoly = (::basegfx::B2DPolyPolygon*)aPolyPolyList.First(); pPolyPoly; pPolyPoly = (::basegfx::B2DPolyPolygon *)aPolyPolyList.Next()) 188 { 189 delete pPolyPoly; 190 } 191 } 192 } 193 delete pDlg; 194 SdrObject::Free( pCloneObj1 ); 195 SdrObject::Free( pCloneObj2 ); 196 197 SdrObject::Free( pPolyObj1 ); 198 SdrObject::Free( pPolyObj2 ); 199 } 200 } 201 202 ::basegfx::B2DPolygon ImpGetExpandedPolygon(const ::basegfx::B2DPolygon& rCandidate, sal_uInt32 nNum) 203 { 204 if(rCandidate.count() && nNum && rCandidate.count() != nNum) 205 { 206 // length of step in dest poly 207 ::basegfx::B2DPolygon aRetval; 208 const double fStep(::basegfx::tools::getLength(rCandidate) / (double)(rCandidate.isClosed() ? nNum : nNum - 1L)); 209 double fDestPos(0.0); 210 double fSrcPos(0.0); 211 sal_uInt32 nSrcPos(0L); 212 sal_uInt32 nSrcPosNext((nSrcPos + 1L == rCandidate.count()) ? 0L : nSrcPos + 1L); 213 double fNextSrcLen(::basegfx::B2DVector(rCandidate.getB2DPoint(nSrcPos) - rCandidate.getB2DPoint(nSrcPosNext)).getLength()); 214 215 for(sal_uInt32 b(0L); b < nNum; b++) 216 { 217 // calc fDestPos in source 218 while(fSrcPos + fNextSrcLen < fDestPos) 219 { 220 fSrcPos += fNextSrcLen; 221 nSrcPos++; 222 nSrcPosNext = (nSrcPos + 1L == rCandidate.count()) ? 0L : nSrcPos + 1L; 223 fNextSrcLen = ::basegfx::B2DVector(rCandidate.getB2DPoint(nSrcPos) - rCandidate.getB2DPoint(nSrcPosNext)).getLength(); 224 } 225 226 // fDestPos is between fSrcPos and (fSrcPos + fNextSrcLen) 227 const double fLenA((fDestPos - fSrcPos) / fNextSrcLen); 228 const ::basegfx::B2DPoint aOld1(rCandidate.getB2DPoint(nSrcPos)); 229 const ::basegfx::B2DPoint aOld2(rCandidate.getB2DPoint(nSrcPosNext)); 230 ::basegfx::B2DPoint aNewPoint(basegfx::interpolate(aOld1, aOld2, fLenA)); 231 aRetval.append(aNewPoint); 232 233 // next step 234 fDestPos += fStep; 235 } 236 237 if(aRetval.count() >= 3L) 238 { 239 aRetval.setClosed(rCandidate.isClosed()); 240 } 241 242 return aRetval; 243 } 244 else 245 { 246 return rCandidate; 247 } 248 } 249 250 ////////////////////////////////////////////////////////////////////////////// 251 // make the point count of the polygons equal in adding points 252 // 253 void FuMorph::ImpEqualizePolyPointCount(::basegfx::B2DPolygon& rSmall, const ::basegfx::B2DPolygon& rBig) 254 { 255 // create poly with equal point count 256 const sal_uInt32 nCnt(rBig.count()); 257 ::basegfx::B2DPolygon aPoly1(ImpGetExpandedPolygon(rSmall, nCnt)); 258 259 // create transformation for rBig to do the compare 260 const ::basegfx::B2DRange aSrcSize(::basegfx::tools::getRange(rBig)); 261 const ::basegfx::B2DPoint aSrcPos(aSrcSize.getCenter()); 262 const ::basegfx::B2DRange aDstSize(::basegfx::tools::getRange(rSmall)); 263 const ::basegfx::B2DPoint aDstPos(aDstSize.getCenter()); 264 265 basegfx::B2DHomMatrix aTrans(basegfx::tools::createTranslateB2DHomMatrix(-aSrcPos.getX(), -aSrcPos.getY())); 266 aTrans.scale(aDstSize.getWidth() / aSrcSize.getWidth(), aDstSize.getHeight() / aSrcSize.getHeight()); 267 aTrans.translate(aDstPos.getX(), aDstPos.getY()); 268 269 // transpose points to have smooth linear blending 270 ::basegfx::B2DPolygon aPoly2; 271 aPoly2.append(::basegfx::B2DPoint(), nCnt); 272 sal_uInt32 nInd(ImpGetNearestIndex(aPoly1, aTrans * rBig.getB2DPoint(0L))); 273 274 for(sal_uInt32 a(0L); a < nCnt; a++) 275 { 276 aPoly2.setB2DPoint((a + nCnt - nInd) % nCnt, aPoly1.getB2DPoint(a)); 277 } 278 279 aPoly2.setClosed(rBig.isClosed()); 280 rSmall = aPoly2; 281 } 282 283 ////////////////////////////////////////////////////////////////////////////// 284 // 285 sal_uInt32 FuMorph::ImpGetNearestIndex(const ::basegfx::B2DPolygon& rPoly, const ::basegfx::B2DPoint& rPos) 286 { 287 double fMinDist = 0.0; 288 sal_uInt32 nActInd = 0; 289 290 for(sal_uInt32 a(0L); a < rPoly.count(); a++) 291 { 292 double fNewDist(::basegfx::B2DVector(rPoly.getB2DPoint(a) - rPos).getLength()); 293 294 if(!a || fNewDist < fMinDist) 295 { 296 fMinDist = fNewDist; 297 nActInd = a; 298 } 299 } 300 301 return nActInd; 302 } 303 304 ////////////////////////////////////////////////////////////////////////////// 305 // add to a point reduced polys until count is same 306 // 307 void FuMorph::ImpAddPolys(::basegfx::B2DPolyPolygon& rSmaller, const ::basegfx::B2DPolyPolygon& rBigger) 308 { 309 while(rSmaller.count() < rBigger.count()) 310 { 311 const ::basegfx::B2DPolygon aToBeCopied(rBigger.getB2DPolygon(rSmaller.count())); 312 const ::basegfx::B2DRange aToBeCopiedPolySize(::basegfx::tools::getRange(aToBeCopied)); 313 ::basegfx::B2DPoint aNewPoint(aToBeCopiedPolySize.getCenter()); 314 ::basegfx::B2DPolygon aNewPoly; 315 316 const ::basegfx::B2DRange aSrcSize(::basegfx::tools::getRange(rBigger.getB2DPolygon(0L))); 317 const ::basegfx::B2DPoint aSrcPos(aSrcSize.getCenter()); 318 const ::basegfx::B2DRange aDstSize(::basegfx::tools::getRange(rSmaller.getB2DPolygon(0L))); 319 const ::basegfx::B2DPoint aDstPos(aDstSize.getCenter()); 320 aNewPoint = aNewPoint - aSrcPos + aDstPos; 321 322 for(sal_uInt32 a(0L); a < aToBeCopied.count(); a++) 323 { 324 aNewPoly.append(aNewPoint); 325 } 326 327 rSmaller.append(aNewPoly); 328 } 329 } 330 331 ////////////////////////////////////////////////////////////////////////////// 332 // create group object with morphed polygons 333 // 334 void FuMorph::ImpInsertPolygons(List& rPolyPolyList3D, sal_Bool bAttributeFade, 335 const SdrObject* pObj1, const SdrObject* pObj2) 336 { 337 Color aStartFillCol; 338 Color aEndFillCol; 339 Color aStartLineCol; 340 Color aEndLineCol; 341 long nStartLineWidth = 0; 342 long nEndLineWidth = 0; 343 SdrPageView* pPageView = mpView->GetSdrPageView(); 344 SfxItemPool* pPool = pObj1->GetObjectItemPool(); 345 SfxItemSet aSet1( *pPool,SDRATTR_START,SDRATTR_NOTPERSIST_FIRST-1,EE_ITEMS_START,EE_ITEMS_END,0 ); 346 SfxItemSet aSet2( aSet1 ); 347 sal_Bool bLineColor = sal_False; 348 sal_Bool bFillColor = sal_False; 349 sal_Bool bLineWidth = sal_False; 350 sal_Bool bIgnoreLine = sal_False; 351 sal_Bool bIgnoreFill = sal_False; 352 353 aSet1.Put(pObj1->GetMergedItemSet()); 354 aSet2.Put(pObj2->GetMergedItemSet()); 355 356 const XLineStyle eLineStyle1 = ITEMVALUE( aSet1, XATTR_LINESTYLE, XLineStyleItem ); 357 const XLineStyle eLineStyle2 = ITEMVALUE( aSet2, XATTR_LINESTYLE, XLineStyleItem ); 358 const XFillStyle eFillStyle1 = ITEMVALUE( aSet1, XATTR_FILLSTYLE, XFillStyleItem ); 359 const XFillStyle eFillStyle2 = ITEMVALUE( aSet2, XATTR_FILLSTYLE, XFillStyleItem ); 360 361 if ( bAttributeFade ) 362 { 363 if ( ( eLineStyle1 != XLINE_NONE ) && ( eLineStyle2 != XLINE_NONE ) ) 364 { 365 bLineWidth = bLineColor = sal_True; 366 367 aStartLineCol = static_cast< XLineColorItem const & >( 368 aSet1.Get(XATTR_LINECOLOR)).GetColorValue(); 369 aEndLineCol = static_cast< XLineColorItem const & >( 370 aSet2.Get(XATTR_LINECOLOR)).GetColorValue(); 371 372 nStartLineWidth = ITEMVALUE( aSet1, XATTR_LINEWIDTH, XLineWidthItem ); 373 nEndLineWidth = ITEMVALUE( aSet2, XATTR_LINEWIDTH, XLineWidthItem ); 374 } 375 else if ( ( eLineStyle1 == XLINE_NONE ) && ( eLineStyle2 == XLINE_NONE ) ) 376 bIgnoreLine = sal_True; 377 378 if ( ( eFillStyle1 == XFILL_SOLID ) && ( eFillStyle2 == XFILL_SOLID ) ) 379 { 380 bFillColor = sal_True; 381 aStartFillCol = static_cast< XFillColorItem const & >( 382 aSet1.Get(XATTR_FILLCOLOR)).GetColorValue(); 383 aEndFillCol = static_cast< XFillColorItem const & >( 384 aSet2.Get(XATTR_FILLCOLOR)).GetColorValue(); 385 } 386 else if ( ( eFillStyle1 == XFILL_NONE ) && ( eFillStyle2 == XFILL_NONE ) ) 387 bIgnoreFill = sal_True; 388 } 389 390 if ( pPageView ) 391 { 392 SfxItemSet aSet( aSet1 ); 393 SdrObjGroup* pObjGroup = new SdrObjGroup; 394 SdrObjList* pObjList = pObjGroup->GetSubList(); 395 const sal_uLong nCount = rPolyPolyList3D.Count(); 396 const double fStep = 1. / ( nCount + 1 ); 397 const double fDelta = nEndLineWidth - nStartLineWidth; 398 double fFactor = fStep; 399 400 aSet.Put( XLineStyleItem( XLINE_SOLID ) ); 401 aSet.Put( XFillStyleItem( XFILL_SOLID ) ); 402 403 for ( sal_uLong i = 0; i < nCount; i++, fFactor += fStep ) 404 { 405 const ::basegfx::B2DPolyPolygon& rPolyPoly3D = *(::basegfx::B2DPolyPolygon*)rPolyPolyList3D.GetObject(i); 406 SdrPathObj* pNewObj = new SdrPathObj(OBJ_POLY, rPolyPoly3D); 407 408 // Linienfarbe 409 if ( bLineColor ) 410 { 411 const basegfx::BColor aLineColor(basegfx::interpolate(aStartLineCol.getBColor(), aEndLineCol.getBColor(), fFactor)); 412 aSet.Put( XLineColorItem( aEmptyStr, Color(aLineColor))); 413 } 414 else if ( bIgnoreLine ) 415 aSet.Put( XLineStyleItem( XLINE_NONE ) ); 416 417 // Fuellfarbe 418 if ( bFillColor ) 419 { 420 const basegfx::BColor aFillColor(basegfx::interpolate(aStartFillCol.getBColor(), aEndFillCol.getBColor(), fFactor)); 421 aSet.Put( XFillColorItem( aEmptyStr, Color(aFillColor))); 422 } 423 else if ( bIgnoreFill ) 424 aSet.Put( XFillStyleItem( XFILL_NONE ) ); 425 426 // Linienstaerke 427 if ( bLineWidth ) 428 aSet.Put( XLineWidthItem( nStartLineWidth + (long) ( fFactor * fDelta + 0.5 ) ) ); 429 430 pNewObj->SetMergedItemSetAndBroadcast(aSet); 431 432 pObjList->InsertObject( pNewObj, LIST_APPEND ); 433 } 434 435 if ( nCount ) 436 { 437 pObjList->InsertObject( pObj1->Clone(), 0 ); 438 pObjList->InsertObject( pObj2->Clone(), LIST_APPEND ); 439 mpView->DeleteMarked(); 440 mpView->InsertObjectAtView( pObjGroup, *pPageView, SDRINSERT_SETDEFLAYER ); 441 } 442 } 443 } 444 445 ////////////////////////////////////////////////////////////////////////////// 446 // create single morphed PolyPolygon 447 // 448 ::basegfx::B2DPolyPolygon* FuMorph::ImpCreateMorphedPolygon( 449 const ::basegfx::B2DPolyPolygon& rPolyPolyStart, 450 const ::basegfx::B2DPolyPolygon& rPolyPolyEnd, 451 double fMorphingFactor) 452 { 453 ::basegfx::B2DPolyPolygon* pNewPolyPolygon = new ::basegfx::B2DPolyPolygon(); 454 const double fFactor = 1.0 - fMorphingFactor; 455 456 for(sal_uInt32 a(0L); a < rPolyPolyStart.count(); a++) 457 { 458 const ::basegfx::B2DPolygon aPolyStart(rPolyPolyStart.getB2DPolygon(a)); 459 const ::basegfx::B2DPolygon aPolyEnd(rPolyPolyEnd.getB2DPolygon(a)); 460 const sal_uInt32 nCount(aPolyStart.count()); 461 ::basegfx::B2DPolygon aNewPolygon; 462 463 for(sal_uInt32 b(0L); b < nCount; b++) 464 { 465 const ::basegfx::B2DPoint& aPtStart(aPolyStart.getB2DPoint(b)); 466 const ::basegfx::B2DPoint& aPtEnd(aPolyEnd.getB2DPoint(b)); 467 aNewPolygon.append(aPtEnd + ((aPtStart - aPtEnd) * fFactor)); 468 } 469 470 aNewPolygon.setClosed(aPolyStart.isClosed() && aPolyEnd.isClosed()); 471 pNewPolyPolygon->append(aNewPolygon); 472 } 473 474 return pNewPolyPolygon; 475 } 476 477 ////////////////////////////////////////////////////////////////////////////// 478 // create morphed PolyPolygons 479 // 480 sal_Bool FuMorph::ImpMorphPolygons( 481 const ::basegfx::B2DPolyPolygon& rPolyPoly1, 482 const ::basegfx::B2DPolyPolygon& rPolyPoly2, 483 const sal_uInt16 nSteps, List& rPolyPolyList3D) 484 { 485 if(nSteps) 486 { 487 const ::basegfx::B2DRange aStartPolySize(::basegfx::tools::getRange(rPolyPoly1)); 488 const ::basegfx::B2DPoint aStartCenter(aStartPolySize.getCenter()); 489 const ::basegfx::B2DRange aEndPolySize(::basegfx::tools::getRange(rPolyPoly2)); 490 const ::basegfx::B2DPoint aEndCenter(aEndPolySize.getCenter()); 491 const ::basegfx::B2DPoint aDelta(aEndCenter - aStartCenter); 492 const double fFactor(1.0 / (nSteps + 1)); 493 double fValue(0.0); 494 495 for(sal_uInt16 i(0); i < nSteps; i++) 496 { 497 fValue += fFactor; 498 ::basegfx::B2DPolyPolygon* pNewPolyPoly2D = ImpCreateMorphedPolygon(rPolyPoly1, rPolyPoly2, fValue); 499 500 const ::basegfx::B2DRange aNewPolySize(::basegfx::tools::getRange(*pNewPolyPoly2D)); 501 const ::basegfx::B2DPoint aNewS(aNewPolySize.getCenter()); 502 const ::basegfx::B2DPoint aRealS(aStartCenter + (aDelta * fValue)); 503 const ::basegfx::B2DPoint aDiff(aRealS - aNewS); 504 505 pNewPolyPoly2D->transform(basegfx::tools::createTranslateB2DHomMatrix(aDiff)); 506 rPolyPolyList3D.Insert(pNewPolyPoly2D, LIST_APPEND); 507 } 508 } 509 return sal_True; 510 } 511 512 513 } // end of namespace sd 514