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