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