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