xref: /aoo41x/main/svx/source/svdraw/svdocirc.cxx (revision a5258243)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_svx.hxx"
30 #include <svl/style.hxx>
31 #include <tools/bigint.hxx>
32 #include <svx/xlnwtit.hxx>
33 #include <svx/xlnedwit.hxx>
34 #include <svx/xlnstwit.hxx>
35 #include <svx/xlnstit.hxx>
36 #include <svx/xlnedit.hxx>
37 #include <svx/svdocirc.hxx>
38 #include <math.h>
39 #include <svx/xpool.hxx>
40 #include <svx/svdattr.hxx>
41 #include <svx/svdpool.hxx>
42 #include <svx/svdattrx.hxx>
43 #include <svx/svdtrans.hxx>
44 #include <svx/svdetc.hxx>
45 #include <svx/svddrag.hxx>
46 #include <svx/svdmodel.hxx>
47 #include <svx/svdpage.hxx>
48 #include <svx/svdopath.hxx> // fuer die Objektkonvertierung
49 #include <svx/svdview.hxx>  // Zum Draggen (Ortho)
50 #include "svx/svdglob.hxx"   // StringCache
51 #include "svx/svdstr.hrc"    // Objektname
52 #include <editeng/eeitem.hxx>
53 #include "svdoimp.hxx"
54 #include <svx/sdr/properties/circleproperties.hxx>
55 #include <svx/sdr/contact/viewcontactofsdrcircobj.hxx>
56 #include <basegfx/point/b2dpoint.hxx>
57 #include <basegfx/polygon/b2dpolygon.hxx>
58 #include <basegfx/polygon/b2dpolygontools.hxx>
59 #include <basegfx/matrix/b2dhommatrix.hxx>
60 #include <basegfx/polygon/b2dpolygontools.hxx>
61 #include <basegfx/matrix/b2dhommatrixtools.hxx>
62 
63 //////////////////////////////////////////////////////////////////////////////
64 
65 Point GetWinkPnt(const Rectangle& rR, long nWink)
66 {
67 	Point aCenter(rR.Center());
68 	long nWdt=rR.Right()-rR.Left();
69 	long nHgt=rR.Bottom()-rR.Top();
70 	long nMaxRad=((nWdt>nHgt ? nWdt : nHgt)+1) /2;
71 	double a;
72 	a=nWink*nPi180;
73 	Point aRetval(Round(cos(a)*nMaxRad),-Round(sin(a)*nMaxRad));
74 	if (nWdt==0) aRetval.X()=0;
75 	if (nHgt==0) aRetval.Y()=0;
76 	if (nWdt!=nHgt) {
77 		if (nWdt>nHgt) {
78 			if (nWdt!=0) {
79 				// eventuelle Ueberlaeufe bei sehr grossen Objekten abfangen (Bug 23384)
80 				if (Abs(nHgt)>32767 || Abs(aRetval.Y())>32767) {
81 					aRetval.Y()=BigMulDiv(aRetval.Y(),nHgt,nWdt);
82 				} else {
83 					aRetval.Y()=aRetval.Y()*nHgt/nWdt;
84 				}
85 			}
86 		} else {
87 			if (nHgt!=0) {
88 				// eventuelle Ueberlaeufe bei sehr grossen Objekten abfangen (Bug 23384)
89 				if (Abs(nWdt)>32767 || Abs(aRetval.X())>32767) {
90 					aRetval.X()=BigMulDiv(aRetval.X(),nWdt,nHgt);
91 				} else {
92 					aRetval.X()=aRetval.X()*nWdt/nHgt;
93 				}
94 			}
95 		}
96 	}
97 	aRetval+=aCenter;
98     return aRetval;
99 }
100 
101 //////////////////////////////////////////////////////////////////////////////
102 // BaseProperties section
103 
104 sdr::properties::BaseProperties* SdrCircObj::CreateObjectSpecificProperties()
105 {
106 	return new sdr::properties::CircleProperties(*this);
107 }
108 
109 //////////////////////////////////////////////////////////////////////////////
110 // DrawContact section
111 
112 sdr::contact::ViewContact* SdrCircObj::CreateObjectSpecificViewContact()
113 {
114 	return new sdr::contact::ViewContactOfSdrCircObj(*this);
115 }
116 
117 //////////////////////////////////////////////////////////////////////////////
118 
119 TYPEINIT1(SdrCircObj,SdrRectObj);
120 
121 SdrCircObj::SdrCircObj(SdrObjKind eNewKind)
122 {
123 	nStartWink=0;
124 	nEndWink=36000;
125 	meCircleKind=eNewKind;
126 	bClosedObj=eNewKind!=OBJ_CARC;
127 }
128 
129 SdrCircObj::SdrCircObj(SdrObjKind eNewKind, const Rectangle& rRect):
130 	SdrRectObj(rRect)
131 {
132 	nStartWink=0;
133 	nEndWink=36000;
134 	meCircleKind=eNewKind;
135 	bClosedObj=eNewKind!=OBJ_CARC;
136 }
137 
138 SdrCircObj::SdrCircObj(SdrObjKind eNewKind, const Rectangle& rRect, long nNewStartWink, long nNewEndWink):
139 	SdrRectObj(rRect)
140 {
141 	long nWinkDif=nNewEndWink-nNewStartWink;
142 	nStartWink=NormAngle360(nNewStartWink);
143 	nEndWink=NormAngle360(nNewEndWink);
144 	if (nWinkDif==36000) nEndWink+=nWinkDif; // Vollkreis
145 	meCircleKind=eNewKind;
146 	bClosedObj=eNewKind!=OBJ_CARC;
147 }
148 
149 SdrCircObj::~SdrCircObj()
150 {
151 }
152 
153 void SdrCircObj::TakeObjInfo(SdrObjTransformInfoRec& rInfo) const
154 {
155 	FASTBOOL bCanConv=!HasText() || ImpCanConvTextToCurve();
156 	rInfo.bEdgeRadiusAllowed	= sal_False;
157 	rInfo.bCanConvToPath=bCanConv;
158 	rInfo.bCanConvToPoly=bCanConv;
159 	rInfo.bCanConvToContour = !IsFontwork() && (rInfo.bCanConvToPoly || LineGeometryUsageIsNecessary());
160 }
161 
162 sal_uInt16 SdrCircObj::GetObjIdentifier() const
163 {
164 	return sal_uInt16(meCircleKind);
165 }
166 
167 FASTBOOL SdrCircObj::PaintNeedsXPolyCirc() const
168 {
169 	// XPoly ist notwendig fuer alle gedrehten Ellipsenobjekte,
170 	// fuer alle Kreis- und Ellipsenabschnitte
171 	// und wenn nicht WIN dann (erstmal) auch fuer Kreis-/Ellipsenausschnitte
172 	// und Kreis-/Ellipsenboegen (wg. Genauigkeit)
173 	FASTBOOL bNeed=aGeo.nDrehWink!=0 || aGeo.nShearWink!=0 || meCircleKind==OBJ_CCUT;
174 	// Wenn nicht Win, dann fuer alle ausser Vollkreis (erstmal!!!)
175 	if (meCircleKind!=OBJ_CIRC) bNeed=sal_True;
176 
177 	const SfxItemSet& rSet = GetObjectItemSet();
178 	if(!bNeed)
179 	{
180 		// XPoly ist notwendig fuer alles was nicht LineSolid oder LineNone ist
181 		XLineStyle eLine = ((XLineStyleItem&)(rSet.Get(XATTR_LINESTYLE))).GetValue();
182 		bNeed = eLine != XLINE_NONE && eLine != XLINE_SOLID;
183 
184 		// XPoly ist notwendig fuer dicke Linien
185 		if(!bNeed && eLine != XLINE_NONE)
186 			bNeed = ((XLineWidthItem&)(rSet.Get(XATTR_LINEWIDTH))).GetValue() != 0;
187 
188 		// XPoly ist notwendig fuer Kreisboegen mit Linienenden
189 		if(!bNeed && meCircleKind == OBJ_CARC)
190 		{
191 			// Linienanfang ist da, wenn StartPolygon und StartWidth!=0
192 			bNeed=((XLineStartItem&)(rSet.Get(XATTR_LINESTART))).GetLineStartValue().count() != 0L &&
193 				  ((XLineStartWidthItem&)(rSet.Get(XATTR_LINESTARTWIDTH))).GetValue() != 0;
194 
195 			if(!bNeed)
196 			{
197 				// Linienende ist da, wenn EndPolygon und EndWidth!=0
198 				bNeed = ((XLineEndItem&)(rSet.Get(XATTR_LINEEND))).GetLineEndValue().count() != 0L &&
199 						((XLineEndWidthItem&)(rSet.Get(XATTR_LINEENDWIDTH))).GetValue() != 0;
200 			}
201 		}
202 	}
203 
204 	// XPoly ist notwendig, wenn Fill !=None und !=Solid
205 	if(!bNeed && meCircleKind != OBJ_CARC)
206 	{
207 		XFillStyle eFill=((XFillStyleItem&)(rSet.Get(XATTR_FILLSTYLE))).GetValue();
208 		bNeed = eFill != XFILL_NONE && eFill != XFILL_SOLID;
209 	}
210 
211 	if(!bNeed && meCircleKind != OBJ_CIRC && nStartWink == nEndWink)
212 		bNeed=sal_True; // Weil sonst Vollkreis gemalt wird
213 
214 	return bNeed;
215 }
216 
217 basegfx::B2DPolygon SdrCircObj::ImpCalcXPolyCirc(const SdrObjKind eCicrleKind, const Rectangle& rRect1, long nStart, long nEnd) const
218 {
219 	const basegfx::B2DRange aRange(rRect1.Left(), rRect1.Top(), rRect1.Right(), rRect1.Bottom());
220 	basegfx::B2DPolygon aCircPolygon;
221 
222 	if(OBJ_CIRC == eCicrleKind)
223 	{
224 		// create full circle. Do not use createPolygonFromEllipse; it's necessary
225         // to get the start point to the bottom of the circle to keep compatible to
226         // old geometry creation
227         aCircPolygon = basegfx::tools::createPolygonFromUnitCircle(1);
228 
229 		// needs own scaling and translation from unit circle to target size (same as
230         // would be in createPolygonFromEllipse)
231 		const basegfx::B2DPoint aCenter(aRange.getCenter());
232 		const basegfx::B2DHomMatrix aMatrix(basegfx::tools::createScaleTranslateB2DHomMatrix(
233 			aRange.getWidth() / 2.0, aRange.getHeight() / 2.0,
234 			aCenter.getX(), aCenter.getY()));
235 		aCircPolygon.transform(aMatrix);
236 	}
237 	else
238 	{
239 		// mirror start, end for geometry creation since model coordinate system is mirrored in Y
240         // #i111715# increase numerical correctness by first dividing and not using F_PI1800
241 		const double fStart((((36000 - nEnd) % 36000) / 18000.0) * F_PI);
242 		const double fEnd((((36000 - nStart) % 36000) / 18000.0) * F_PI);
243 
244 		// create circle segment. This is not closed by default
245 		aCircPolygon = basegfx::tools::createPolygonFromEllipseSegment(
246             aRange.getCenter(), aRange.getWidth() / 2.0, aRange.getHeight() / 2.0,
247             fStart, fEnd);
248 
249 		// check closing states
250 		const bool bCloseSegment(OBJ_CARC != eCicrleKind);
251 		const bool bCloseUsingCenter(OBJ_SECT == eCicrleKind);
252 
253 		if(bCloseSegment)
254 		{
255 			if(bCloseUsingCenter)
256 			{
257 				// add center point at start (for historical reasons)
258 				basegfx::B2DPolygon aSector;
259 				aSector.append(aRange.getCenter());
260 				aSector.append(aCircPolygon);
261 				aCircPolygon = aSector;
262 			}
263 
264 			// close
265 			aCircPolygon.setClosed(true);
266 		}
267 	}
268 
269 	// #i76950#
270 	if(aGeo.nShearWink || aGeo.nDrehWink)
271 	{
272 		// translate top left to (0,0)
273 		const basegfx::B2DPoint aTopLeft(aRange.getMinimum());
274         basegfx::B2DHomMatrix aMatrix(basegfx::tools::createTranslateB2DHomMatrix(
275             -aTopLeft.getX(), -aTopLeft.getY()));
276 
277 		// shear, rotate and back to top left (if needed)
278         aMatrix = basegfx::tools::createShearXRotateTranslateB2DHomMatrix(
279             aGeo.nShearWink ? tan((36000 - aGeo.nShearWink) * F_PI18000) : 0.0,
280             aGeo.nDrehWink ? (36000 - aGeo.nDrehWink) * F_PI18000 : 0.0,
281             aTopLeft) * aMatrix;
282 
283 		// apply transformation
284 		aCircPolygon.transform(aMatrix);
285 	}
286 
287 	return aCircPolygon;
288 }
289 
290 void SdrCircObj::RecalcXPoly()
291 {
292 	const basegfx::B2DPolygon aPolyCirc(ImpCalcXPolyCirc(meCircleKind, aRect, nStartWink, nEndWink));
293 	mpXPoly = new XPolygon(aPolyCirc);
294 }
295 
296 void SdrCircObj::TakeObjNameSingul(XubString& rName) const
297 {
298 	sal_uInt16 nID=STR_ObjNameSingulCIRC;
299 	if (aRect.GetWidth()==aRect.GetHeight() && aGeo.nShearWink==0) {
300 		switch (meCircleKind) {
301 			case OBJ_CIRC: nID=STR_ObjNameSingulCIRC; break;
302 			case OBJ_SECT: nID=STR_ObjNameSingulSECT; break;
303 			case OBJ_CARC: nID=STR_ObjNameSingulCARC; break;
304 			case OBJ_CCUT: nID=STR_ObjNameSingulCCUT; break;
305 			default: break;
306 		}
307 	} else {
308 		switch (meCircleKind) {
309 			case OBJ_CIRC: nID=STR_ObjNameSingulCIRCE; break;
310 			case OBJ_SECT: nID=STR_ObjNameSingulSECTE; break;
311 			case OBJ_CARC: nID=STR_ObjNameSingulCARCE; break;
312 			case OBJ_CCUT: nID=STR_ObjNameSingulCCUTE; break;
313 			default: break;
314 		}
315 	}
316 	rName=ImpGetResStr(nID);
317 
318 	String aName( GetName() );
319 	if(aName.Len())
320 	{
321 		rName += sal_Unicode(' ');
322 		rName += sal_Unicode('\'');
323 		rName += aName;
324 		rName += sal_Unicode('\'');
325 	}
326 }
327 
328 void SdrCircObj::TakeObjNamePlural(XubString& rName) const
329 {
330 	sal_uInt16 nID=STR_ObjNamePluralCIRC;
331 	if (aRect.GetWidth()==aRect.GetHeight() && aGeo.nShearWink==0) {
332 		switch (meCircleKind) {
333 			case OBJ_CIRC: nID=STR_ObjNamePluralCIRC; break;
334 			case OBJ_SECT: nID=STR_ObjNamePluralSECT; break;
335 			case OBJ_CARC: nID=STR_ObjNamePluralCARC; break;
336 			case OBJ_CCUT: nID=STR_ObjNamePluralCCUT; break;
337 			default: break;
338 		}
339 	} else {
340 		switch (meCircleKind) {
341 			case OBJ_CIRC: nID=STR_ObjNamePluralCIRCE; break;
342 			case OBJ_SECT: nID=STR_ObjNamePluralSECTE; break;
343 			case OBJ_CARC: nID=STR_ObjNamePluralCARCE; break;
344 			case OBJ_CCUT: nID=STR_ObjNamePluralCCUTE; break;
345 			default: break;
346 		}
347 	}
348 	rName=ImpGetResStr(nID);
349 }
350 
351 void SdrCircObj::operator=(const SdrObject& rObj)
352 {
353 	SdrRectObj::operator=(rObj);
354 
355 	nStartWink = ((SdrCircObj&)rObj).nStartWink;
356 	nEndWink = ((SdrCircObj&)rObj).nEndWink;
357 }
358 
359 basegfx::B2DPolyPolygon SdrCircObj::TakeXorPoly() const
360 {
361 	const basegfx::B2DPolygon aCircPolygon(ImpCalcXPolyCirc(meCircleKind, aRect, nStartWink, nEndWink));
362 	return basegfx::B2DPolyPolygon(aCircPolygon);
363 }
364 
365 struct ImpCircUser : public SdrDragStatUserData
366 {
367 	Rectangle					aR;
368 	Point						aCenter;
369 	Point						aRadius;
370 	Point						aP1;
371 	Point						aP2;
372 	long						nMaxRad;
373 	long						nHgt;
374 	long						nWdt;
375 	long						nStart;
376 	long						nEnd;
377 	long						nWink;
378 	FASTBOOL					bRight; // noch nicht implementiert
379 
380 public:
381 	ImpCircUser()
382 	:	nMaxRad(0),
383 		nHgt(0),
384 		nWdt(0),
385 		nStart(0),
386 		nEnd(0),
387 		bRight(sal_False)
388 	{}
389 	void SetCreateParams(SdrDragStat& rStat);
390 };
391 
392 sal_uInt32 SdrCircObj::GetHdlCount() const
393 {
394 	if(OBJ_CIRC != meCircleKind)
395 	{
396 		return 10L;
397 	}
398 	else
399 	{
400 		return 8L;
401 	}
402 }
403 
404 SdrHdl* SdrCircObj::GetHdl(sal_uInt32 nHdlNum) const
405 {
406 	if (meCircleKind==OBJ_CIRC)
407     {
408 		nHdlNum += 2L;
409     }
410 
411     SdrHdl* pH = NULL;
412 	Point aPnt;
413 	SdrHdlKind eLocalKind(HDL_MOVE);
414 	sal_uInt32 nPNum(0);
415 
416     switch (nHdlNum)
417     {
418 		case 0:
419             aPnt = GetWinkPnt(aRect,nStartWink);
420             eLocalKind = HDL_CIRC;
421             nPNum = 1;
422             break;
423 		case 1:
424             aPnt = GetWinkPnt(aRect,nEndWink);
425             eLocalKind = HDL_CIRC;
426             nPNum = 2L;
427             break;
428 		case 2:
429             aPnt = aRect.TopLeft();
430             eLocalKind = HDL_UPLFT;
431             break;
432 		case 3:
433             aPnt = aRect.TopCenter();
434             eLocalKind = HDL_UPPER;
435             break;
436 		case 4:
437             aPnt = aRect.TopRight();
438             eLocalKind = HDL_UPRGT;
439             break;
440 		case 5:
441             aPnt = aRect.LeftCenter();
442             eLocalKind = HDL_LEFT;
443             break;
444 		case 6:
445             aPnt = aRect.RightCenter();
446             eLocalKind = HDL_RIGHT;
447             break;
448 		case 7:
449             aPnt = aRect.BottomLeft();
450             eLocalKind = HDL_LWLFT;
451             break;
452 		case 8:
453             aPnt = aRect.BottomCenter();
454             eLocalKind = HDL_LOWER;
455             break;
456 		case 9:
457             aPnt = aRect.BottomRight();
458             eLocalKind = HDL_LWRGT;
459             break;
460 	}
461 
462     if (aGeo.nShearWink)
463     {
464         ShearPoint(aPnt,aRect.TopLeft(),aGeo.nTan);
465     }
466 
467 	if (aGeo.nDrehWink)
468     {
469         RotatePoint(aPnt,aRect.TopLeft(),aGeo.nSin,aGeo.nCos);
470     }
471 
472 	if (eLocalKind != HDL_MOVE)
473     {
474 		pH = new SdrHdl(aPnt,eLocalKind);
475 		pH->SetPointNum(nPNum);
476 		pH->SetObj((SdrObject*)this);
477 		pH->SetDrehWink(aGeo.nDrehWink);
478 	}
479 
480     return pH;
481 }
482 
483 ////////////////////////////////////////////////////////////////////////////////////////////////////
484 
485 bool SdrCircObj::hasSpecialDrag() const
486 {
487 	return true;
488 }
489 
490 bool SdrCircObj::beginSpecialDrag(SdrDragStat& rDrag) const
491 {
492 	const bool bWink(rDrag.GetHdl() && HDL_CIRC == rDrag.GetHdl()->GetKind());
493 
494 	if(bWink)
495 	{
496 		if(1 == rDrag.GetHdl()->GetPointNum() || 2 == rDrag.GetHdl()->GetPointNum())
497 		{
498 			rDrag.SetNoSnap(true);
499 		}
500 
501 		return true;
502 	}
503 
504     return SdrTextObj::beginSpecialDrag(rDrag);
505 }
506 
507 bool SdrCircObj::applySpecialDrag(SdrDragStat& rDrag)
508 {
509 	const bool bWink(rDrag.GetHdl() && HDL_CIRC == rDrag.GetHdl()->GetKind());
510 
511 	if(bWink)
512 	{
513 		Point aPt(rDrag.GetNow());
514 
515         if (aGeo.nDrehWink!=0)
516             RotatePoint(aPt,aRect.TopLeft(),-aGeo.nSin,aGeo.nCos);
517 
518         if (aGeo.nShearWink!=0)
519             ShearPoint(aPt,aRect.TopLeft(),-aGeo.nTan);
520 
521         aPt-=aRect.Center();
522 
523         long nWdt=aRect.Right()-aRect.Left();
524 		long nHgt=aRect.Bottom()-aRect.Top();
525 
526         if(nWdt>=nHgt)
527         {
528 			aPt.Y()=BigMulDiv(aPt.Y(),nWdt,nHgt);
529 		}
530         else
531         {
532 			aPt.X()=BigMulDiv(aPt.X(),nHgt,nWdt);
533 		}
534 
535         long nWink=NormAngle360(GetAngle(aPt));
536 
537         if (rDrag.GetView() && rDrag.GetView()->IsAngleSnapEnabled())
538         {
539 			long nSA=rDrag.GetView()->GetSnapAngle();
540 
541             if (nSA!=0)
542             {
543 				nWink+=nSA/2;
544 				nWink/=nSA;
545 				nWink*=nSA;
546 				nWink=NormAngle360(nWink);
547 			}
548 		}
549 
550 		if(1 == rDrag.GetHdl()->GetPointNum())
551 		{
552 			nStartWink = nWink;
553 		}
554 		else if(2 == rDrag.GetHdl()->GetPointNum())
555 		{
556 			nEndWink = nWink;
557 		}
558 
559 		SetRectsDirty();
560 		SetXPolyDirty();
561 		ImpSetCircInfoToAttr();
562 		SetChanged();
563 
564 		return true;
565 	}
566 	else
567 	{
568 		return SdrTextObj::applySpecialDrag(rDrag);
569 	}
570 }
571 
572 String SdrCircObj::getSpecialDragComment(const SdrDragStat& rDrag) const
573 {
574     const bool bCreateComment(rDrag.GetView() && this == rDrag.GetView()->GetCreateObj());
575 
576     if(bCreateComment)
577     {
578 		XubString aStr;
579 		ImpTakeDescriptionStr(STR_ViewCreateObj, aStr);
580 		const sal_uInt32 nPntAnz(rDrag.GetPointAnz());
581 
582 		if(OBJ_CIRC != meCircleKind && nPntAnz > 2)
583 		{
584 			ImpCircUser* pU = (ImpCircUser*)rDrag.GetUser();
585 			sal_Int32 nWink;
586 
587 			aStr.AppendAscii(" (");
588 
589 			if(3 == nPntAnz)
590             {
591 				nWink = pU->nStart;
592             }
593 			else
594             {
595 				nWink = pU->nEnd;
596             }
597 
598 			aStr += GetWinkStr(nWink,sal_False);
599 			aStr += sal_Unicode(')');
600 		}
601 
602         return aStr;
603     }
604     else
605     {
606 	    const bool bWink(rDrag.GetHdl() && HDL_CIRC == rDrag.GetHdl()->GetKind());
607 
608 	    if(bWink)
609 	    {
610 		    XubString aStr;
611             const sal_Int32 nWink(1 == rDrag.GetHdl()->GetPointNum() ? nStartWink : nEndWink);
612 
613 		    ImpTakeDescriptionStr(STR_DragCircAngle, aStr);
614 		    aStr.AppendAscii(" (");
615 		    aStr += GetWinkStr(nWink,sal_False);
616 		    aStr += sal_Unicode(')');
617 
618 		    return aStr;
619 	    }
620 	    else
621 	    {
622 		    return SdrTextObj::getSpecialDragComment(rDrag);
623 	    }
624     }
625 }
626 
627 ////////////////////////////////////////////////////////////////////////////////////////////////////
628 
629 void ImpCircUser::SetCreateParams(SdrDragStat& rStat)
630 {
631 	rStat.TakeCreateRect(aR);
632 	aR.Justify();
633 	aCenter=aR.Center();
634 	nWdt=aR.Right()-aR.Left();
635 	nHgt=aR.Bottom()-aR.Top();
636 	nMaxRad=((nWdt>nHgt ? nWdt : nHgt)+1) /2;
637 	nStart=0;
638 	nEnd=36000;
639 	if (rStat.GetPointAnz()>2) {
640 		Point aP(rStat.GetPoint(2)-aCenter);
641 		if (nWdt==0) aP.X()=0;
642 		if (nHgt==0) aP.Y()=0;
643 		if (nWdt>=nHgt) {
644 			if (nHgt!=0) aP.Y()=aP.Y()*nWdt/nHgt;
645 		} else {
646 			if (nWdt!=0) aP.X()=aP.X()*nHgt/nWdt;
647 		}
648 		nStart=NormAngle360(GetAngle(aP));
649 		if (rStat.GetView()!=NULL && rStat.GetView()->IsAngleSnapEnabled()) {
650 			long nSA=rStat.GetView()->GetSnapAngle();
651 			if (nSA!=0) { // Winkelfang
652 				nStart+=nSA/2;
653 				nStart/=nSA;
654 				nStart*=nSA;
655 				nStart=NormAngle360(nStart);
656 			}
657 		}
658 		aP1 = GetWinkPnt(aR,nStart);
659 		nEnd=nStart;
660 		aP2=aP1;
661 	} else aP1=aCenter;
662 	if (rStat.GetPointAnz()>3) {
663 		Point aP(rStat.GetPoint(3)-aCenter);
664 		if (nWdt>=nHgt) {
665 			aP.Y()=BigMulDiv(aP.Y(),nWdt,nHgt);
666 		} else {
667 			aP.X()=BigMulDiv(aP.X(),nHgt,nWdt);
668 		}
669 		nEnd=NormAngle360(GetAngle(aP));
670 		if (rStat.GetView()!=NULL && rStat.GetView()->IsAngleSnapEnabled()) {
671 			long nSA=rStat.GetView()->GetSnapAngle();
672 			if (nSA!=0) { // Winkelfang
673 				nEnd+=nSA/2;
674 				nEnd/=nSA;
675 				nEnd*=nSA;
676 				nEnd=NormAngle360(nEnd);
677 			}
678 		}
679 		aP2 = GetWinkPnt(aR,nEnd);
680 	} else aP2=aCenter;
681 }
682 
683 void SdrCircObj::ImpSetCreateParams(SdrDragStat& rStat) const
684 {
685 	ImpCircUser* pU=(ImpCircUser*)rStat.GetUser();
686 	if (pU==NULL) {
687 		pU=new ImpCircUser;
688 		rStat.SetUser(pU);
689 	}
690 	pU->SetCreateParams(rStat);
691 }
692 
693 FASTBOOL SdrCircObj::BegCreate(SdrDragStat& rStat)
694 {
695 	rStat.SetOrtho4Possible();
696 	Rectangle aRect1(rStat.GetStart(), rStat.GetNow());
697 	aRect1.Justify();
698 	rStat.SetActionRect(aRect1);
699 	aRect = aRect1;
700 	ImpSetCreateParams(rStat);
701 	return sal_True;
702 }
703 
704 FASTBOOL SdrCircObj::MovCreate(SdrDragStat& rStat)
705 {
706 	ImpSetCreateParams(rStat);
707 	ImpCircUser* pU=(ImpCircUser*)rStat.GetUser();
708 	rStat.SetActionRect(pU->aR);
709 	aRect=pU->aR; // fuer ObjName
710 	ImpJustifyRect(aRect);
711 	nStartWink=pU->nStart;
712 	nEndWink=pU->nEnd;
713 	SetBoundRectDirty();
714 	bSnapRectDirty=sal_True;
715 	SetXPolyDirty();
716 
717     // #i103058# push current angle settings to ItemSet to
718     // allow FullDrag visualisation
719     if(rStat.GetPointAnz() >= 4)
720     {
721         ImpSetCircInfoToAttr();
722     }
723 
724 	return sal_True;
725 }
726 
727 FASTBOOL SdrCircObj::EndCreate(SdrDragStat& rStat, SdrCreateCmd eCmd)
728 {
729 	ImpSetCreateParams(rStat);
730 	ImpCircUser* pU=(ImpCircUser*)rStat.GetUser();
731 	FASTBOOL bRet=sal_False;
732 	if (eCmd==SDRCREATE_FORCEEND && rStat.GetPointAnz()<4) meCircleKind=OBJ_CIRC;
733 	if (meCircleKind==OBJ_CIRC) {
734 		bRet=rStat.GetPointAnz()>=2;
735 		if (bRet) {
736 			aRect=pU->aR;
737 			ImpJustifyRect(aRect);
738 		}
739 	} else {
740 		rStat.SetNoSnap(rStat.GetPointAnz()>=2);
741 		rStat.SetOrtho4Possible(rStat.GetPointAnz()<2);
742 		bRet=rStat.GetPointAnz()>=4;
743 		if (bRet) {
744 			aRect=pU->aR;
745 			ImpJustifyRect(aRect);
746 			nStartWink=pU->nStart;
747 			nEndWink=pU->nEnd;
748 		}
749 	}
750 	bClosedObj=meCircleKind!=OBJ_CARC;
751 	SetRectsDirty();
752 	SetXPolyDirty();
753 	ImpSetCircInfoToAttr();
754 	if (bRet) {
755 		delete pU;
756 		rStat.SetUser(NULL);
757 	}
758 	return bRet;
759 }
760 
761 void SdrCircObj::BrkCreate(SdrDragStat& rStat)
762 {
763 	ImpCircUser* pU=(ImpCircUser*)rStat.GetUser();
764 	delete pU;
765 	rStat.SetUser(NULL);
766 }
767 
768 FASTBOOL SdrCircObj::BckCreate(SdrDragStat& rStat)
769 {
770 	rStat.SetNoSnap(rStat.GetPointAnz()>=3);
771 	rStat.SetOrtho4Possible(rStat.GetPointAnz()<3);
772 	return meCircleKind!=OBJ_CIRC;
773 }
774 
775 basegfx::B2DPolyPolygon SdrCircObj::TakeCreatePoly(const SdrDragStat& rDrag) const
776 {
777 	ImpCircUser* pU = (ImpCircUser*)rDrag.GetUser();
778 
779 	if(rDrag.GetPointAnz() < 4L)
780 	{
781 		// force to OBJ_CIRC to get full visualisation
782 		basegfx::B2DPolyPolygon aRetval(ImpCalcXPolyCirc(OBJ_CIRC, pU->aR, pU->nStart, pU->nEnd));
783 
784 		if(3L == rDrag.GetPointAnz())
785 		{
786 			// add edge to first point on ellipse
787 			basegfx::B2DPolygon aNew;
788 
789 			aNew.append(basegfx::B2DPoint(pU->aCenter.X(), pU->aCenter.Y()));
790 			aNew.append(basegfx::B2DPoint(pU->aP1.X(), pU->aP1.Y()));
791 			aRetval.append(aNew);
792 		}
793 
794 		return aRetval;
795 	}
796 	else
797 	{
798 		return basegfx::B2DPolyPolygon(ImpCalcXPolyCirc(meCircleKind, pU->aR, pU->nStart, pU->nEnd));
799 	}
800 }
801 
802 Pointer SdrCircObj::GetCreatePointer() const
803 {
804 	switch (meCircleKind) {
805 		case OBJ_CIRC: return Pointer(POINTER_DRAW_ELLIPSE);
806 		case OBJ_SECT: return Pointer(POINTER_DRAW_PIE);
807 		case OBJ_CARC: return Pointer(POINTER_DRAW_ARC);
808 		case OBJ_CCUT: return Pointer(POINTER_DRAW_CIRCLECUT);
809 		default: break;
810 	} // switch
811 	return Pointer(POINTER_CROSS);
812 }
813 
814 void SdrCircObj::NbcMove(const Size& aSiz)
815 {
816 	MoveRect(aRect,aSiz);
817 	MoveRect(aOutRect,aSiz);
818 	MoveRect(maSnapRect,aSiz);
819 	SetXPolyDirty();
820 	SetRectsDirty(sal_True);
821 }
822 
823 void SdrCircObj::NbcResize(const Point& rRef, const Fraction& xFact, const Fraction& yFact)
824 {
825 	long nWink0=aGeo.nDrehWink;
826 	FASTBOOL bNoShearRota=(aGeo.nDrehWink==0 && aGeo.nShearWink==0);
827 	SdrTextObj::NbcResize(rRef,xFact,yFact);
828 	bNoShearRota|=(aGeo.nDrehWink==0 && aGeo.nShearWink==0);
829 	if (meCircleKind!=OBJ_CIRC) {
830 		FASTBOOL bXMirr=(xFact.GetNumerator()<0) != (xFact.GetDenominator()<0);
831 		FASTBOOL bYMirr=(yFact.GetNumerator()<0) != (yFact.GetDenominator()<0);
832 		if (bXMirr || bYMirr) {
833 			// bei bXMirr!=bYMirr muessten eigentlich noch die beiden
834 			// Linienende vertauscht werden. Das ist jedoch mal wieder
835 			// schlecht (wg. zwangslaeufiger harter Formatierung).
836 			// Alternativ koennte ein bMirrored-Flag eingefuehrt werden
837 			// (Vielleicht ja mal grundsaetzlich, auch fuer gepiegelten Text, ...).
838 			long nS0=nStartWink;
839 			long nE0=nEndWink;
840 			if (bNoShearRota) {
841 				// Das RectObj spiegelt bei VMirror bereits durch durch 180deg Drehung.
842 				if (! (bXMirr && bYMirr)) {
843 					long nTmp=nS0;
844 					nS0=18000-nE0;
845 					nE0=18000-nTmp;
846 				}
847 			} else { // Spiegeln fuer verzerrte Ellipsen
848 				if (bXMirr!=bYMirr) {
849 					nS0+=nWink0;
850 					nE0+=nWink0;
851 					if (bXMirr) {
852 						long nTmp=nS0;
853 						nS0=18000-nE0;
854 						nE0=18000-nTmp;
855 					}
856 					if (bYMirr) {
857 						long nTmp=nS0;
858 						nS0=-nE0;
859 						nE0=-nTmp;
860 					}
861 					nS0-=aGeo.nDrehWink;
862 					nE0-=aGeo.nDrehWink;
863 				}
864 			}
865 			long nWinkDif=nE0-nS0;
866 			nStartWink=NormAngle360(nS0);
867 			nEndWink  =NormAngle360(nE0);
868 			if (nWinkDif==36000) nEndWink+=nWinkDif; // Vollkreis
869 		}
870 	}
871 	SetXPolyDirty();
872 	ImpSetCircInfoToAttr();
873 }
874 
875 void SdrCircObj::NbcShear(const Point& rRef, long nWink, double tn, FASTBOOL bVShear)
876 {
877 	SdrTextObj::NbcShear(rRef,nWink,tn,bVShear);
878 	SetXPolyDirty();
879 	ImpSetCircInfoToAttr();
880 }
881 
882 void SdrCircObj::NbcMirror(const Point& rRef1, const Point& rRef2)
883 {
884 	//long nWink0=aGeo.nDrehWink;
885 	FASTBOOL bFreeMirr=meCircleKind!=OBJ_CIRC;
886 	Point aTmpPt1;
887 	Point aTmpPt2;
888 	if (bFreeMirr) { // bei freier Spiegelachse einige Vorbereitungen Treffen
889 		Point aCenter(aRect.Center());
890 		long nWdt=aRect.GetWidth()-1;
891 		long nHgt=aRect.GetHeight()-1;
892 		long nMaxRad=((nWdt>nHgt ? nWdt : nHgt)+1) /2;
893 		double a;
894 		// Startpunkt
895 		a=nStartWink*nPi180;
896 		aTmpPt1=Point(Round(cos(a)*nMaxRad),-Round(sin(a)*nMaxRad));
897 		if (nWdt==0) aTmpPt1.X()=0;
898 		if (nHgt==0) aTmpPt1.Y()=0;
899 		aTmpPt1+=aCenter;
900 		// Endpunkt
901 		a=nEndWink*nPi180;
902 		aTmpPt2=Point(Round(cos(a)*nMaxRad),-Round(sin(a)*nMaxRad));
903 		if (nWdt==0) aTmpPt2.X()=0;
904 		if (nHgt==0) aTmpPt2.Y()=0;
905 		aTmpPt2+=aCenter;
906 		if (aGeo.nDrehWink!=0) {
907 			RotatePoint(aTmpPt1,aRect.TopLeft(),aGeo.nSin,aGeo.nCos);
908 			RotatePoint(aTmpPt2,aRect.TopLeft(),aGeo.nSin,aGeo.nCos);
909 		}
910 		if (aGeo.nShearWink!=0) {
911 			ShearPoint(aTmpPt1,aRect.TopLeft(),aGeo.nTan);
912 			ShearPoint(aTmpPt2,aRect.TopLeft(),aGeo.nTan);
913 		}
914 	}
915 	SdrTextObj::NbcMirror(rRef1,rRef2);
916 	if (meCircleKind!=OBJ_CIRC) { // Anpassung von Start- und Endwinkel
917 		MirrorPoint(aTmpPt1,rRef1,rRef2);
918 		MirrorPoint(aTmpPt2,rRef1,rRef2);
919 		// Unrotate:
920 		if (aGeo.nDrehWink!=0) {
921 			RotatePoint(aTmpPt1,aRect.TopLeft(),-aGeo.nSin,aGeo.nCos); // -sin fuer Umkehrung
922 			RotatePoint(aTmpPt2,aRect.TopLeft(),-aGeo.nSin,aGeo.nCos); // -sin fuer Umkehrung
923 		}
924 		// Unshear:
925 		if (aGeo.nShearWink!=0) {
926 			ShearPoint(aTmpPt1,aRect.TopLeft(),-aGeo.nTan); // -tan fuer Umkehrung
927 			ShearPoint(aTmpPt2,aRect.TopLeft(),-aGeo.nTan); // -tan fuer Umkehrung
928 		}
929 		Point aCenter(aRect.Center());
930 		aTmpPt1-=aCenter;
931 		aTmpPt2-=aCenter;
932 		// Weil gespiegelt sind die Winkel nun auch noch vertauscht
933 		nStartWink=GetAngle(aTmpPt2);
934 		nEndWink  =GetAngle(aTmpPt1);
935 		long nWinkDif=nEndWink-nStartWink;
936 		nStartWink=NormAngle360(nStartWink);
937 		nEndWink  =NormAngle360(nEndWink);
938 		if (nWinkDif==36000) nEndWink+=nWinkDif; // Vollkreis
939 	}
940 	SetXPolyDirty();
941 	ImpSetCircInfoToAttr();
942 }
943 
944 SdrObjGeoData* SdrCircObj::NewGeoData() const
945 {
946 	return new SdrCircObjGeoData;
947 }
948 
949 void SdrCircObj::SaveGeoData(SdrObjGeoData& rGeo) const
950 {
951 	SdrRectObj::SaveGeoData(rGeo);
952 	SdrCircObjGeoData& rCGeo=(SdrCircObjGeoData&)rGeo;
953 	rCGeo.nStartWink=nStartWink;
954 	rCGeo.nEndWink  =nEndWink;
955 }
956 
957 void SdrCircObj::RestGeoData(const SdrObjGeoData& rGeo)
958 {
959 	SdrRectObj::RestGeoData(rGeo);
960 	SdrCircObjGeoData& rCGeo=(SdrCircObjGeoData&)rGeo;
961 	nStartWink=rCGeo.nStartWink;
962 	nEndWink  =rCGeo.nEndWink;
963 	SetXPolyDirty();
964 	ImpSetCircInfoToAttr();
965 }
966 
967 void Union(Rectangle& rR, const Point& rP)
968 {
969 	if (rP.X()<rR.Left  ()) rR.Left  ()=rP.X();
970 	if (rP.X()>rR.Right ()) rR.Right ()=rP.X();
971 	if (rP.Y()<rR.Top   ()) rR.Top   ()=rP.Y();
972 	if (rP.Y()>rR.Bottom()) rR.Bottom()=rP.Y();
973 }
974 
975 void SdrCircObj::TakeUnrotatedSnapRect(Rectangle& rRect) const
976 {
977 	rRect=aRect;
978 	if (meCircleKind!=OBJ_CIRC) {
979 		const Point aPntStart(GetWinkPnt(aRect,nStartWink));
980 		const Point aPntEnd(GetWinkPnt(aRect,nEndWink));
981 		long a=nStartWink;
982 		long e=nEndWink;
983 		rRect.Left  ()=aRect.Right();
984 		rRect.Right ()=aRect.Left();
985 		rRect.Top   ()=aRect.Bottom();
986 		rRect.Bottom()=aRect.Top();
987 		Union(rRect,aPntStart);
988 		Union(rRect,aPntEnd);
989 		if ((a<=18000 && e>=18000) || (a>e && (a<=18000 || e>=18000))) {
990 			Union(rRect,aRect.LeftCenter());
991 		}
992 		if ((a<=27000 && e>=27000) || (a>e && (a<=27000 || e>=27000))) {
993 			Union(rRect,aRect.BottomCenter());
994 		}
995 		if (a>e) {
996 			Union(rRect,aRect.RightCenter());
997 		}
998 		if ((a<=9000 && e>=9000) || (a>e && (a<=9000 || e>=9000))) {
999 			Union(rRect,aRect.TopCenter());
1000 		}
1001 		if (meCircleKind==OBJ_SECT) {
1002 			Union(rRect,aRect.Center());
1003 		}
1004 		if (aGeo.nDrehWink!=0) {
1005 			Point aDst(rRect.TopLeft());
1006 			aDst-=aRect.TopLeft();
1007 			Point aDst0(aDst);
1008 			RotatePoint(aDst,Point(),aGeo.nSin,aGeo.nCos);
1009 			aDst-=aDst0;
1010 			rRect.Move(aDst.X(),aDst.Y());
1011 		}
1012 	}
1013 	if (aGeo.nShearWink!=0) {
1014 		long nDst=Round((rRect.Bottom()-rRect.Top())*aGeo.nTan);
1015 		if (aGeo.nShearWink>0) {
1016 			Point aRef(rRect.TopLeft());
1017 			rRect.Left()-=nDst;
1018 			Point aTmpPt(rRect.TopLeft());
1019 			RotatePoint(aTmpPt,aRef,aGeo.nSin,aGeo.nCos);
1020 			aTmpPt-=rRect.TopLeft();
1021 			rRect.Move(aTmpPt.X(),aTmpPt.Y());
1022 		} else {
1023 			rRect.Right()-=nDst;
1024 		}
1025 	}
1026 }
1027 
1028 void SdrCircObj::RecalcSnapRect()
1029 {
1030 	if (PaintNeedsXPolyCirc()) {
1031 		maSnapRect=GetXPoly().GetBoundRect();
1032 	} else {
1033 		TakeUnrotatedSnapRect(maSnapRect);
1034 	}
1035 }
1036 
1037 void SdrCircObj::NbcSetSnapRect(const Rectangle& rRect)
1038 {
1039 	if (aGeo.nDrehWink!=0 || aGeo.nShearWink!=0 || meCircleKind!=OBJ_CIRC) {
1040 		Rectangle aSR0(GetSnapRect());
1041 		long nWdt0=aSR0.Right()-aSR0.Left();
1042 		long nHgt0=aSR0.Bottom()-aSR0.Top();
1043 		long nWdt1=rRect.Right()-rRect.Left();
1044 		long nHgt1=rRect.Bottom()-rRect.Top();
1045 		NbcResize(maSnapRect.TopLeft(),Fraction(nWdt1,nWdt0),Fraction(nHgt1,nHgt0));
1046 		NbcMove(Size(rRect.Left()-aSR0.Left(),rRect.Top()-aSR0.Top()));
1047 	} else {
1048 		aRect=rRect;
1049 		ImpJustifyRect(aRect);
1050 	}
1051 	SetRectsDirty();
1052 	SetXPolyDirty();
1053 	ImpSetCircInfoToAttr();
1054 }
1055 
1056 sal_uInt32 SdrCircObj::GetSnapPointCount() const
1057 {
1058 	if (meCircleKind==OBJ_CIRC) {
1059 		return 1L;
1060 	} else {
1061 		return 3L;
1062 	}
1063 }
1064 
1065 Point SdrCircObj::GetSnapPoint(sal_uInt32 i) const
1066 {
1067 	switch (i) {
1068 		case 1 : return GetWinkPnt(aRect,nStartWink);
1069 		case 2 : return GetWinkPnt(aRect,nEndWink);
1070 		default: return aRect.Center();
1071 	}
1072 }
1073 
1074 void __EXPORT SdrCircObj::Notify(SfxBroadcaster& rBC, const SfxHint& rHint)
1075 {
1076 	SetXPolyDirty();
1077 	SdrRectObj::Notify(rBC,rHint);
1078 	ImpSetAttrToCircInfo();
1079 }
1080 
1081 ////////////////////////////////////////////////////////////////////////////////////////////////////
1082 
1083 void SdrCircObj::ImpSetAttrToCircInfo()
1084 {
1085 	const SfxItemSet& rSet = GetObjectItemSet();
1086 	SdrCircKind eNewKindA = ((SdrCircKindItem&)rSet.Get(SDRATTR_CIRCKIND)).GetValue();
1087 	SdrObjKind eNewKind = meCircleKind;
1088 
1089 	if(eNewKindA == SDRCIRC_FULL)
1090 		eNewKind = OBJ_CIRC;
1091 	else if(eNewKindA == SDRCIRC_SECT)
1092 		eNewKind = OBJ_SECT;
1093 	else if(eNewKindA == SDRCIRC_ARC)
1094 		eNewKind = OBJ_CARC;
1095 	else if(eNewKindA == SDRCIRC_CUT)
1096 		eNewKind = OBJ_CCUT;
1097 
1098 	sal_Int32 nNewStart = ((SdrCircStartAngleItem&)rSet.Get(SDRATTR_CIRCSTARTANGLE)).GetValue();
1099 	sal_Int32 nNewEnd = ((SdrCircEndAngleItem&)rSet.Get(SDRATTR_CIRCENDANGLE)).GetValue();
1100 
1101 	sal_Bool bKindChg = meCircleKind != eNewKind;
1102 	sal_Bool bWinkChg = nNewStart != nStartWink || nNewEnd != nEndWink;
1103 
1104 	if(bKindChg || bWinkChg)
1105 	{
1106 		meCircleKind = eNewKind;
1107 		nStartWink = nNewStart;
1108 		nEndWink = nNewEnd;
1109 
1110 		if(bKindChg || (meCircleKind != OBJ_CIRC && bWinkChg))
1111 		{
1112 			SetXPolyDirty();
1113 			SetRectsDirty();
1114 		}
1115 	}
1116 }
1117 
1118 void SdrCircObj::ImpSetCircInfoToAttr()
1119 {
1120 	SdrCircKind eNewKindA = SDRCIRC_FULL;
1121 	const SfxItemSet& rSet = GetObjectItemSet();
1122 
1123 	if(meCircleKind == OBJ_SECT)
1124 		eNewKindA = SDRCIRC_SECT;
1125 	else if(meCircleKind == OBJ_CARC)
1126 		eNewKindA = SDRCIRC_ARC;
1127 	else if(meCircleKind == OBJ_CCUT)
1128 		eNewKindA = SDRCIRC_CUT;
1129 
1130 	SdrCircKind eOldKindA = ((SdrCircKindItem&)rSet.Get(SDRATTR_CIRCKIND)).GetValue();
1131 	sal_Int32 nOldStartWink = ((SdrCircStartAngleItem&)rSet.Get(SDRATTR_CIRCSTARTANGLE)).GetValue();
1132 	sal_Int32 nOldEndWink = ((SdrCircEndAngleItem&)rSet.Get(SDRATTR_CIRCENDANGLE)).GetValue();
1133 
1134 	if(eNewKindA != eOldKindA || nStartWink != nOldStartWink || nEndWink != nOldEndWink)
1135 	{
1136 		// #81921# since SetItem() implicitly calls ImpSetAttrToCircInfo()
1137 		// setting the item directly is necessary here.
1138 		if(eNewKindA != eOldKindA)
1139 		{
1140 			GetProperties().SetObjectItemDirect(SdrCircKindItem(eNewKindA));
1141 		}
1142 
1143 		if(nStartWink != nOldStartWink)
1144 		{
1145 			GetProperties().SetObjectItemDirect(SdrCircStartAngleItem(nStartWink));
1146 		}
1147 
1148 		if(nEndWink != nOldEndWink)
1149 		{
1150 			GetProperties().SetObjectItemDirect(SdrCircEndAngleItem(nEndWink));
1151 		}
1152 
1153 		SetXPolyDirty();
1154 		ImpSetAttrToCircInfo();
1155 	}
1156 }
1157 
1158 SdrObject* SdrCircObj::DoConvertToPolyObj(sal_Bool bBezier, bool bAddText) const
1159 {
1160 	const sal_Bool bFill(OBJ_CARC == meCircleKind ? sal_False : sal_True);
1161 	const basegfx::B2DPolygon aCircPolygon(ImpCalcXPolyCirc(meCircleKind, aRect, nStartWink, nEndWink));
1162 	SdrObject* pRet = ImpConvertMakeObj(basegfx::B2DPolyPolygon(aCircPolygon), bFill, bBezier);
1163 
1164     if(bAddText)
1165     {
1166     	pRet = ImpConvertAddText(pRet, bBezier);
1167     }
1168 
1169 	return pRet;
1170 }
1171 
1172 //////////////////////////////////////////////////////////////////////////////
1173 // eof
1174