xref: /trunk/main/sd/source/ui/func/fumorph.cxx (revision 79aad27f)
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
10*5b190011SAndrew Rist  *
11*5b190011SAndrew Rist  *   http://www.apache.org/licenses/LICENSE-2.0
12*5b190011SAndrew Rist  *
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.
19*5b190011SAndrew Rist  *
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