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