xref: /aoo41x/main/svx/source/svdraw/svdomeas.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 
27 #include <svx/svdomeas.hxx>
28 #include <math.h>
29 #include "svx/svditext.hxx" //
30 #include <svx/xpoly.hxx>
31 #include <svx/svdtrans.hxx>
32 #include <svx/svdhdl.hxx>
33 #include <svx/svdoutl.hxx>
34 #include <svx/svddrag.hxx>
35 #include <svx/svdpool.hxx>
36 #include <svx/svdattrx.hxx>
37 #include <svx/svdmodel.hxx>
38 #include <svx/svdview.hxx>
39 #include "svx/svdglob.hxx"   // StringCache
40 #include "svx/svdstr.hrc"    // Objektname
41 #include <svl/style.hxx>
42 #include <svl/smplhint.hxx>
43 #include <editeng/eeitem.hxx>
44 #include <svx/xlnstit.hxx>
45 #include <svx/xlnstwit.hxx>
46 #include <svx/xlnedit.hxx>
47 #include <svx/xlnwtit.hxx>
48 #include <svx/xlnedwit.hxx>
49 #include <svx/xlnstcit.hxx>
50 #include <svx/xlnedcit.hxx>
51 #include <editeng/outlobj.hxx>
52 #include <editeng/outliner.hxx>
53 #include <editeng/editobj.hxx>
54 #include <editeng/measfld.hxx>
55 #include <editeng/flditem.hxx>
56 #include <svx/svdogrp.hxx>
57 #include <svx/svdopath.hxx>
58 #include <svx/svdpage.hxx>
59 #include <unotools/syslocale.hxx>
60 #include "svdoimp.hxx"
61 #include <svx/sdr/properties/measureproperties.hxx>
62 #include <svx/sdr/contact/viewcontactofsdrmeasureobj.hxx>
63 #include <basegfx/point/b2dpoint.hxx>
64 #include <basegfx/polygon/b2dpolygon.hxx>
65 #include <basegfx/polygon/b2dpolypolygon.hxx>
66 #include <basegfx/matrix/b2dhommatrix.hxx>
67 #include <basegfx/matrix/b2dhommatrixtools.hxx>
68 
69 ////////////////////////////////////////////////////////////////////////////////////////////////////
70 
71 SdrMeasureObjGeoData::SdrMeasureObjGeoData() {}
72 SdrMeasureObjGeoData::~SdrMeasureObjGeoData() {}
73 
74 void SdrMeasureObj::TakeRepresentation( XubString& rStr, SdrMeasureFieldKind eMeasureFieldKind ) const
75 {
76 	rStr.Erase();
77 	Fraction aMeasureScale(1, 1);
78 	sal_Bool bTextRota90(sal_False);
79 	sal_Bool bShowUnit(sal_False);
80 	FieldUnit eMeasureUnit(FUNIT_NONE);
81 	FieldUnit eModUIUnit(FUNIT_NONE);
82 
83 	const SfxItemSet& rSet = GetMergedItemSet();
84 	bTextRota90 = ((SdrMeasureTextRota90Item&)rSet.Get(SDRATTR_MEASURETEXTROTA90)).GetValue();
85 	eMeasureUnit = ((SdrMeasureUnitItem&)rSet.Get(SDRATTR_MEASUREUNIT)).GetValue();
86 	aMeasureScale = ((SdrMeasureScaleItem&)rSet.Get(SDRATTR_MEASURESCALE)).GetValue();
87 	bShowUnit = ((SdrMeasureShowUnitItem&)rSet.Get(SDRATTR_MEASURESHOWUNIT)).GetValue();
88 	sal_Int16 nNumDigits = ((SdrMeasureDecimalPlacesItem&)rSet.Get(SDRATTR_MEASUREDECIMALPLACES)).GetValue();
89 
90 	//SdrModel* pModel = rObj.pModel;
91 
92 	switch(eMeasureFieldKind)
93 	{
94 		case SDRMEASUREFIELD_VALUE:
95 		{
96 			if(pModel)
97 			{
98 				eModUIUnit = pModel->GetUIUnit();
99 
100 				if(eMeasureUnit == FUNIT_NONE)
101 					eMeasureUnit = eModUIUnit;
102 
103 				sal_Int32 nLen(GetLen(aPt2 - aPt1));
104 				Fraction aFact(1,1);
105 
106 				if(eMeasureUnit != eModUIUnit)
107 				{
108 					// Zur Umrechnung der Einheiten
109 					aFact *= GetMapFactor(eModUIUnit, eMeasureUnit).X();
110 				}
111 
112 				if(aMeasureScale.GetNumerator() != aMeasureScale.GetDenominator())
113 				{
114 					aFact *= aMeasureScale;
115 				}
116 
117 				if(aFact.GetNumerator() != aFact.GetDenominator())
118 				{
119 					// Scaling ueber BigInt, um Ueberlaeufe zu vermeiden
120 					nLen = BigMulDiv(nLen, aFact.GetNumerator(), aFact.GetDenominator());
121 				}
122 
123 				pModel->TakeMetricStr(nLen, rStr, sal_True, nNumDigits);
124 
125 				if(!aFact.IsValid())
126 				{
127 					rStr = String();
128 					rStr += sal_Unicode('?');
129 				}
130 
131                 sal_Unicode cDec(SvtSysLocale().GetLocaleData().getNumDecimalSep().GetChar(0));
132 
133 				if(rStr.Search(cDec) != STRING_NOTFOUND)
134 				{
135 					xub_StrLen nLen2(rStr.Len() - 1);
136 
137 					while(rStr.GetChar(nLen2) == sal_Unicode('0'))
138 					{
139 						rStr.Erase(nLen2);
140 						nLen2--;
141 					}
142 
143 					if(rStr.GetChar(nLen2) == cDec)
144 					{
145 						rStr.Erase(nLen2);
146 						nLen2--;
147 					}
148 
149 					if(!rStr.Len())
150 						rStr += sal_Unicode('0');
151 				}
152 			}
153 			else
154 			{
155 				// falls kein Model da ... (z.B. Preview im Dialog)
156 				rStr = String();
157 				rStr.AppendAscii("4711");
158 			}
159 
160 			break;
161 		}
162 		case SDRMEASUREFIELD_UNIT:
163 		{
164 			if(bShowUnit)
165 			{
166 				if(pModel)
167 				{
168 					eModUIUnit = pModel->GetUIUnit();
169 
170 					if(eMeasureUnit == FUNIT_NONE)
171 						eMeasureUnit = eModUIUnit;
172 
173 					if(bShowUnit)
174 						pModel->TakeUnitStr(eMeasureUnit, rStr);
175 				}
176 			}
177 
178 			break;
179 		}
180 		case SDRMEASUREFIELD_ROTA90BLANCS:
181 		{
182 			if(bTextRota90)
183 			{
184 				rStr = String();
185 				rStr += sal_Unicode(' ');
186 			}
187 
188 			break;
189 		}
190 	}
191 }
192 
193 //////////////////////////////////////////////////////////////////////////////
194 // BaseProperties section
195 
196 sdr::properties::BaseProperties* SdrMeasureObj::CreateObjectSpecificProperties()
197 {
198 	return new sdr::properties::MeasureProperties(*this);
199 }
200 
201 //////////////////////////////////////////////////////////////////////////////
202 // DrawContact section
203 
204 sdr::contact::ViewContact* SdrMeasureObj::CreateObjectSpecificViewContact()
205 {
206 	return new sdr::contact::ViewContactOfSdrMeasureObj(*this);
207 }
208 
209 //////////////////////////////////////////////////////////////////////////////
210 
211 TYPEINIT1(SdrMeasureObj,SdrTextObj);
212 
213 SdrMeasureObj::SdrMeasureObj():
214 	bTextDirty(sal_False)
215 {
216 	// #i25616#
217 	mbSupportTextIndentingOnLineWidthChange = sal_False;
218 }
219 
220 SdrMeasureObj::SdrMeasureObj(const Point& rPt1, const Point& rPt2):
221 	aPt1(rPt1),
222 	aPt2(rPt2),
223 	bTextDirty(sal_False)
224 {
225 	// #i25616#
226 	mbSupportTextIndentingOnLineWidthChange = sal_False;
227 }
228 
229 SdrMeasureObj::~SdrMeasureObj()
230 {
231 }
232 
233 void SdrMeasureObj::TakeObjInfo(SdrObjTransformInfoRec& rInfo) const
234 {
235 	rInfo.bSelectAllowed    =sal_True;
236 	rInfo.bMoveAllowed      =sal_True;
237 	rInfo.bResizeFreeAllowed=sal_True;
238 	rInfo.bResizePropAllowed=sal_True;
239 	rInfo.bRotateFreeAllowed=sal_True;
240 	rInfo.bRotate90Allowed  =sal_True;
241 	rInfo.bMirrorFreeAllowed=sal_True;
242 	rInfo.bMirror45Allowed  =sal_True;
243 	rInfo.bMirror90Allowed  =sal_True;
244 	rInfo.bTransparenceAllowed = sal_False;
245 	rInfo.bGradientAllowed = sal_False;
246 	rInfo.bShearAllowed     =sal_True;
247 	rInfo.bEdgeRadiusAllowed=sal_False;
248 	rInfo.bNoOrthoDesired   =sal_True;
249 	rInfo.bNoContortion     =sal_False;
250 	rInfo.bCanConvToPath    =sal_False;
251 	rInfo.bCanConvToPoly    =sal_True;
252 	rInfo.bCanConvToPathLineToArea=sal_False;
253 	rInfo.bCanConvToPolyLineToArea=sal_False;
254 	rInfo.bCanConvToContour = (rInfo.bCanConvToPoly || LineGeometryUsageIsNecessary());
255 }
256 
257 sal_uInt16 SdrMeasureObj::GetObjIdentifier() const
258 {
259 	return (sal_uInt16)OBJ_MEASURE;
260 }
261 
262 struct ImpMeasureRec : public SdrDragStatUserData
263 {
264 	Point						aPt1;
265 	Point						aPt2;
266 	SdrMeasureKind				eKind;
267 	SdrMeasureTextHPos			eWantTextHPos;
268 	SdrMeasureTextVPos			eWantTextVPos;
269 	long						nLineDist;
270 	long						nHelplineOverhang;
271 	long						nHelplineDist;
272 	long						nHelpline1Len;
273 	long						nHelpline2Len;
274 	FASTBOOL					bBelowRefEdge;
275 	FASTBOOL					bTextRota90;
276 	FASTBOOL					bTextUpsideDown;
277 	long						nMeasureOverhang;
278 	FieldUnit					eMeasureUnit;
279 	Fraction					aMeasureScale;
280 	FASTBOOL					bShowUnit;
281 	String						aFormatString;
282 	FASTBOOL					bTextAutoAngle;
283 	long						nTextAutoAngleView;
284 	FASTBOOL					bTextIsFixedAngle;
285 	long						nTextFixedAngle;
286 };
287 
288 struct ImpLineRec
289 {
290 	Point						aP1;
291 	Point						aP2;
292 };
293 
294 struct ImpMeasurePoly
295 {
296 	ImpLineRec					aMainline1; // die mit dem 1. Pfeil
297 	ImpLineRec					aMainline2; // die mit dem 2. Pfeil
298 	ImpLineRec					aMainline3; // die dazwischen
299 	ImpLineRec					aHelpline1;
300 	ImpLineRec					aHelpline2;
301 	Rectangle					aTextRect;
302 	Size						aTextSize;
303 	long						nLineLen;
304 	long						nLineWink;
305 	long						nTextWink;
306 	long						nHlpWink;
307 	double						nLineSin;
308 	double						nLineCos;
309 	double						nHlpSin;
310 	double						nHlpCos;
311 	sal_uInt16						nMainlineAnz;
312 	SdrMeasureTextHPos			eUsedTextHPos;
313 	SdrMeasureTextVPos			eUsedTextVPos;
314 	long						nLineWdt2;  // Halbe Strichstaerke
315 	long						nArrow1Len; // Laenge des 1. Pfeils. Bei Center nur die Haelfte
316 	long						nArrow2Len; // Laenge des 2. Pfeils. Bei Center nur die Haelfte
317 	long						nArrow1Wdt; // Breite des 1. Pfeils
318 	long						nArrow2Wdt; // Breite des 2. Pfeils
319 	long						nShortLineLen; // Linienlaenge, wenn PfeileAussen
320 	FASTBOOL					bArrow1Center; // Pfeil 1 zentriert?
321 	FASTBOOL					bArrow2Center; // Pfeil 2 zentriert?
322 	FASTBOOL					bAutoUpsideDown; // UpsideDown durch Automatik
323 	FASTBOOL					bPfeileAussen;
324 	FASTBOOL					bBreakedLine;
325 };
326 
327 void SdrMeasureObj::ImpTakeAttr(ImpMeasureRec& rRec) const
328 {
329 	rRec.aPt1 = aPt1;
330 	rRec.aPt2 = aPt2;
331 
332 	const SfxItemSet& rSet = GetObjectItemSet();
333 	rRec.eKind            =((SdrMeasureKindItem&            )rSet.Get(SDRATTR_MEASUREKIND            )).GetValue();
334 	rRec.eWantTextHPos    =((SdrMeasureTextHPosItem&        )rSet.Get(SDRATTR_MEASURETEXTHPOS        )).GetValue();
335 	rRec.eWantTextVPos    =((SdrMeasureTextVPosItem&        )rSet.Get(SDRATTR_MEASURETEXTVPOS        )).GetValue();
336 	rRec.nLineDist        =((SdrMeasureLineDistItem&        )rSet.Get(SDRATTR_MEASURELINEDIST        )).GetValue();
337 	rRec.nHelplineOverhang=((SdrMeasureHelplineOverhangItem&)rSet.Get(SDRATTR_MEASUREHELPLINEOVERHANG)).GetValue();
338 	rRec.nHelplineDist    =((SdrMeasureHelplineDistItem&    )rSet.Get(SDRATTR_MEASUREHELPLINEDIST    )).GetValue();
339 	rRec.nHelpline1Len    =((SdrMeasureHelpline1LenItem&    )rSet.Get(SDRATTR_MEASUREHELPLINE1LEN    )).GetValue();
340 	rRec.nHelpline2Len    =((SdrMeasureHelpline2LenItem&    )rSet.Get(SDRATTR_MEASUREHELPLINE2LEN    )).GetValue();
341 	rRec.bBelowRefEdge    =((SdrMeasureBelowRefEdgeItem&    )rSet.Get(SDRATTR_MEASUREBELOWREFEDGE    )).GetValue();
342 	rRec.bTextRota90      =((SdrMeasureTextRota90Item&      )rSet.Get(SDRATTR_MEASURETEXTROTA90      )).GetValue();
343 	rRec.bTextUpsideDown  =((SdrMeasureTextUpsideDownItem&  )rSet.Get(SDRATTR_MEASURETEXTUPSIDEDOWN  )).GetValue();
344 	rRec.nMeasureOverhang =((SdrMeasureOverhangItem&        )rSet.Get(SDRATTR_MEASUREOVERHANG        )).GetValue();
345 	rRec.eMeasureUnit     =((SdrMeasureUnitItem&            )rSet.Get(SDRATTR_MEASUREUNIT            )).GetValue();
346 	rRec.aMeasureScale    =((SdrMeasureScaleItem&           )rSet.Get(SDRATTR_MEASURESCALE           )).GetValue();
347 	rRec.bShowUnit        =((SdrMeasureShowUnitItem&        )rSet.Get(SDRATTR_MEASURESHOWUNIT        )).GetValue();
348 	rRec.aFormatString    =((SdrMeasureFormatStringItem&    )rSet.Get(SDRATTR_MEASUREFORMATSTRING    )).GetValue();
349 	rRec.bTextAutoAngle    =((SdrMeasureTextAutoAngleItem&    )rSet.Get(SDRATTR_MEASURETEXTAUTOANGLE    )).GetValue();
350 	rRec.nTextAutoAngleView=((SdrMeasureTextAutoAngleViewItem&)rSet.Get(SDRATTR_MEASURETEXTAUTOANGLEVIEW)).GetValue();
351 	rRec.bTextIsFixedAngle =((SdrMeasureTextIsFixedAngleItem& )rSet.Get(SDRATTR_MEASURETEXTISFIXEDANGLE )).GetValue();
352 	rRec.nTextFixedAngle   =((SdrMeasureTextFixedAngleItem&   )rSet.Get(SDRATTR_MEASURETEXTFIXEDANGLE   )).GetValue();
353 }
354 
355 long impGetLineStartEndDistance(const basegfx::B2DPolyPolygon& rPolyPolygon, long nNewWidth, bool bCenter)
356 {
357 	const basegfx::B2DRange aPolygonRange(rPolyPolygon.getB2DRange());
358 	const double fOldWidth(aPolygonRange.getWidth() > 1.0 ? aPolygonRange.getWidth() : 1.0);
359 	const double fScale((double)nNewWidth / fOldWidth);
360 	long nHeight(basegfx::fround(aPolygonRange.getHeight() * fScale));
361 
362 	if(bCenter)
363 	{
364 		nHeight /= 2L;
365 	}
366 
367 	return nHeight;
368 }
369 
370 void SdrMeasureObj::ImpCalcGeometrics(const ImpMeasureRec& rRec, ImpMeasurePoly& rPol) const
371 {
372 	Point aP1(rRec.aPt1);
373 	Point aP2(rRec.aPt2);
374 	Point aDelt(aP2); aDelt-=aP1;
375 
376 	rPol.aTextSize=GetTextSize();
377 	rPol.nLineLen=GetLen(aDelt);
378 
379 	rPol.nLineWdt2=0;
380 	long nArrow1Len=0; bool bArrow1Center=false;
381 	long nArrow2Len=0; bool bArrow2Center=false;
382 	long nArrow1Wdt=0;
383 	long nArrow2Wdt=0;
384 	rPol.nArrow1Wdt=0;
385 	rPol.nArrow2Wdt=0;
386 	long nArrowNeed=0;
387 	long nShortLen=0;
388 	FASTBOOL bPfeileAussen=sal_False;
389 
390 	const SfxItemSet& rSet = GetObjectItemSet();
391 	sal_Int32 nLineWdt = ((XLineWidthItem&)(rSet.Get(XATTR_LINEWIDTH))).GetValue(); // Strichstaerke
392 	rPol.nLineWdt2 = (nLineWdt + 1) / 2;
393 
394 	nArrow1Wdt = ((const XLineStartWidthItem&)(rSet.Get(XATTR_LINESTARTWIDTH))).GetValue();
395 	if(nArrow1Wdt < 0)
396 		nArrow1Wdt = -nLineWdt * nArrow1Wdt / 100; // <0 = relativ
397 
398 	nArrow2Wdt = ((const XLineEndWidthItem&)(rSet.Get(XATTR_LINEENDWIDTH))).GetValue();
399 	if(nArrow2Wdt < 0)
400 		nArrow2Wdt = -nLineWdt * nArrow2Wdt / 100; // <0 = relativ
401 
402 	basegfx::B2DPolyPolygon aPol1(((const XLineStartItem&)(rSet.Get(XATTR_LINESTART))).GetLineStartValue());
403 	basegfx::B2DPolyPolygon aPol2(((const XLineEndItem&)(rSet.Get(XATTR_LINEEND))).GetLineEndValue());
404 	bArrow1Center = ((const XLineStartCenterItem&)(rSet.Get(XATTR_LINESTARTCENTER))).GetValue();
405 	bArrow2Center = ((const XLineEndCenterItem&)(rSet.Get(XATTR_LINEENDCENTER))).GetValue();
406 	nArrow1Len = impGetLineStartEndDistance(aPol1, nArrow1Wdt, bArrow1Center) - 1;
407 	nArrow2Len = impGetLineStartEndDistance(aPol2, nArrow2Wdt, bArrow2Center) - 1;
408 
409 	// nArrowLen ist bei bCenter bereits halbiert
410 	// Bei 2 Pfeilen a 4mm ist unter 10mm Schluss.
411 	nArrowNeed=nArrow1Len+nArrow2Len+(nArrow1Wdt+nArrow2Wdt)/2;
412 	if (rPol.nLineLen<nArrowNeed) bPfeileAussen=sal_True;
413 	nShortLen=(nArrow1Len+nArrow1Wdt + nArrow2Len+nArrow2Wdt) /2;
414 
415 	rPol.eUsedTextHPos=rRec.eWantTextHPos;
416 	rPol.eUsedTextVPos=rRec.eWantTextVPos;
417 	if (rPol.eUsedTextVPos==SDRMEASURE_TEXTVAUTO) rPol.eUsedTextVPos=SDRMEASURE_ABOVE;
418 	FASTBOOL bBrkLine=rPol.eUsedTextVPos==SDRMEASURETEXT_BREAKEDLINE;
419 	if (rPol.eUsedTextVPos==SDRMEASURETEXT_VERTICALCENTERED)
420 	{
421 		OutlinerParaObject* pOutlinerParaObject = SdrTextObj::GetOutlinerParaObject();
422 		if (pOutlinerParaObject!=NULL && pOutlinerParaObject->GetTextObject().GetParagraphCount()==1)
423 		{
424 			bBrkLine=sal_True; // Unterbrochene Linie, wenn nur 1 Absatz.
425 		}
426 	}
427 	rPol.bBreakedLine=bBrkLine;
428 	if (rPol.eUsedTextHPos==SDRMEASURE_TEXTHAUTO) { // bei zu breitem Text diesen eventuell nach aussen schieben
429 		FASTBOOL bOutside=sal_False;
430 		long nNeedSiz=!rRec.bTextRota90 ? rPol.aTextSize.Width() : rPol.aTextSize.Height();
431 		if (nNeedSiz>rPol.nLineLen) bOutside=sal_True; // Text passt nicht in die Mitte
432 		if (bBrkLine) {
433 			if (nNeedSiz+nArrowNeed>rPol.nLineLen) bPfeileAussen=sal_True; // Text passt in die Mitte, wenn die Pfeile nach aussen kommen
434 		} else {
435 			long nSmallNeed=nArrow1Len+nArrow2Len+(nArrow1Wdt+nArrow2Wdt)/2/4;
436 			if (nNeedSiz+nSmallNeed>rPol.nLineLen) bPfeileAussen=sal_True; // Text passt in die Mitte, wenn die Pfeile nach aussen kommen
437 		}
438 		rPol.eUsedTextHPos=bOutside ? SDRMEASURE_TEXTLEFTOUTSIDE : SDRMEASURE_TEXTINSIDE;
439 	}
440 	if (rPol.eUsedTextHPos!=SDRMEASURE_TEXTINSIDE) bPfeileAussen=sal_True;
441 	rPol.nArrow1Wdt=nArrow1Wdt;
442 	rPol.nArrow2Wdt=nArrow2Wdt;
443 	rPol.nShortLineLen=nShortLen;
444 	rPol.bPfeileAussen=bPfeileAussen;
445 	rPol.nArrow1Len=nArrow1Len;
446 	rPol.bArrow1Center=bArrow1Center;
447 	rPol.nArrow2Len=nArrow2Len;
448 	rPol.bArrow2Center=bArrow2Center;
449 
450 	rPol.nLineWink=GetAngle(aDelt);
451 	double a=rPol.nLineWink*nPi180;
452 	double nLineSin=sin(a);
453 	double nLineCos=cos(a);
454 	rPol.nLineSin=nLineSin;
455 	rPol.nLineCos=nLineCos;
456 
457 	rPol.nTextWink=rPol.nLineWink;
458 	if (rRec.bTextRota90) rPol.nTextWink+=9000;
459 
460 	rPol.bAutoUpsideDown=sal_False;
461 	if (rRec.bTextAutoAngle) {
462 		long nTmpWink=NormAngle360(rPol.nTextWink-rRec.nTextAutoAngleView);
463 		if (nTmpWink>=18000) {
464 			rPol.nTextWink+=18000;
465 			rPol.bAutoUpsideDown=sal_True;
466 		}
467 	}
468 
469 	if (rRec.bTextUpsideDown) rPol.nTextWink+=18000;
470 	rPol.nTextWink=NormAngle360(rPol.nTextWink);
471 	rPol.nHlpWink=rPol.nLineWink+9000;
472 	if (rRec.bBelowRefEdge) rPol.nHlpWink+=18000;
473 	rPol.nHlpWink=NormAngle360(rPol.nHlpWink);
474 	double nHlpSin=nLineCos;
475 	double nHlpCos=-nLineSin;
476 	if (rRec.bBelowRefEdge) {
477 		nHlpSin=-nHlpSin;
478 		nHlpCos=-nHlpCos;
479 	}
480 	rPol.nHlpSin=nHlpSin;
481 	rPol.nHlpCos=nHlpCos;
482 
483 	long nLineDist=rRec.nLineDist;
484 	long nOverhang=rRec.nHelplineOverhang;
485 	long nHelplineDist=rRec.nHelplineDist;
486 
487 	long dx= Round(nLineDist*nHlpCos);
488 	long dy=-Round(nLineDist*nHlpSin);
489 	long dxh1a= Round((nHelplineDist-rRec.nHelpline1Len)*nHlpCos);
490 	long dyh1a=-Round((nHelplineDist-rRec.nHelpline1Len)*nHlpSin);
491 	long dxh1b= Round((nHelplineDist-rRec.nHelpline2Len)*nHlpCos);
492 	long dyh1b=-Round((nHelplineDist-rRec.nHelpline2Len)*nHlpSin);
493 	long dxh2= Round((nLineDist+nOverhang)*nHlpCos);
494 	long dyh2=-Round((nLineDist+nOverhang)*nHlpSin);
495 
496 	// Masshilfslinie 1
497 	rPol.aHelpline1.aP1=Point(aP1.X()+dxh1a,aP1.Y()+dyh1a);
498 	rPol.aHelpline1.aP2=Point(aP1.X()+dxh2,aP1.Y()+dyh2);
499 
500 	// Masshilfslinie 2
501 	rPol.aHelpline2.aP1=Point(aP2.X()+dxh1b,aP2.Y()+dyh1b);
502 	rPol.aHelpline2.aP2=Point(aP2.X()+dxh2,aP2.Y()+dyh2);
503 
504 	// Masslinie(n)
505 	Point aMainlinePt1(aP1.X()+dx,aP1.Y()+dy);
506 	Point aMainlinePt2(aP2.X()+dx,aP2.Y()+dy);
507 	if (!bPfeileAussen) {
508 		rPol.aMainline1.aP1=aMainlinePt1;
509 		rPol.aMainline1.aP2=aMainlinePt2;
510 		rPol.aMainline2=rPol.aMainline1;
511 		rPol.aMainline3=rPol.aMainline1;
512 		rPol.nMainlineAnz=1;
513 		if (bBrkLine) {
514 			long nNeedSiz=!rRec.bTextRota90 ? rPol.aTextSize.Width() : rPol.aTextSize.Height();
515 			long nHalfLen=(rPol.nLineLen-nNeedSiz-nArrow1Wdt/4-nArrow2Wdt/4) /2;
516 			rPol.nMainlineAnz=2;
517 			rPol.aMainline1.aP2=aMainlinePt1;
518 			rPol.aMainline1.aP2.X()+=nHalfLen;
519 			RotatePoint(rPol.aMainline1.aP2,rPol.aMainline1.aP1,nLineSin,nLineCos);
520 			rPol.aMainline2.aP1=aMainlinePt2;
521 			rPol.aMainline2.aP1.X()-=nHalfLen;
522 			RotatePoint(rPol.aMainline2.aP1,rPol.aMainline2.aP2,nLineSin,nLineCos);
523 		}
524 	} else {
525 		long nLen1=nShortLen; // Pfeilbreite als Linienlaenge ausserhalb des Pfeils
526 		long nLen2=nShortLen;
527 		long nTextWdt=rRec.bTextRota90 ? rPol.aTextSize.Height() : rPol.aTextSize.Width();
528 		if (!bBrkLine) {
529 			if (rPol.eUsedTextHPos==SDRMEASURE_TEXTLEFTOUTSIDE) nLen1=nArrow1Len+nTextWdt;
530 			if (rPol.eUsedTextHPos==SDRMEASURE_TEXTRIGHTOUTSIDE) nLen2=nArrow2Len+nTextWdt;
531 		}
532 		rPol.aMainline1.aP1=aMainlinePt1;
533 		rPol.aMainline1.aP2=aMainlinePt1; rPol.aMainline1.aP2.X()-=nLen1; RotatePoint(rPol.aMainline1.aP2,aMainlinePt1,nLineSin,nLineCos);
534 		rPol.aMainline2.aP1=aMainlinePt2; rPol.aMainline2.aP1.X()+=nLen2; RotatePoint(rPol.aMainline2.aP1,aMainlinePt2,nLineSin,nLineCos);
535 		rPol.aMainline2.aP2=aMainlinePt2;
536 		rPol.aMainline3.aP1=aMainlinePt1;
537 		rPol.aMainline3.aP2=aMainlinePt2;
538 		rPol.nMainlineAnz=3;
539 		if (bBrkLine && rPol.eUsedTextHPos==SDRMEASURE_TEXTINSIDE) rPol.nMainlineAnz=2;
540 	}
541 }
542 
543 basegfx::B2DPolyPolygon SdrMeasureObj::ImpCalcXPoly(const ImpMeasurePoly& rPol) const
544 {
545 	basegfx::B2DPolyPolygon aRetval;
546 	basegfx::B2DPolygon aPartPolyA;
547 	aPartPolyA.append(basegfx::B2DPoint(rPol.aMainline1.aP1.X(), rPol.aMainline1.aP1.Y()));
548 	aPartPolyA.append(basegfx::B2DPoint(rPol.aMainline1.aP2.X(), rPol.aMainline1.aP2.Y()));
549 	aRetval.append(aPartPolyA);
550 
551 	if(rPol.nMainlineAnz > 1)
552 	{
553 		aPartPolyA.clear();
554 		aPartPolyA.append(basegfx::B2DPoint(rPol.aMainline2.aP1.X(), rPol.aMainline2.aP1.Y()));
555 		aPartPolyA.append(basegfx::B2DPoint(rPol.aMainline2.aP2.X(), rPol.aMainline2.aP2.Y()));
556 		aRetval.append(aPartPolyA);
557 	}
558 
559 	if(rPol.nMainlineAnz > 2)
560 	{
561 		aPartPolyA.clear();
562 		aPartPolyA.append(basegfx::B2DPoint(rPol.aMainline3.aP1.X(), rPol.aMainline3.aP1.Y()));
563 		aPartPolyA.append(basegfx::B2DPoint(rPol.aMainline3.aP2.X(), rPol.aMainline3.aP2.Y()));
564 		aRetval.append(aPartPolyA);
565 	}
566 
567 	aPartPolyA.clear();
568 	aPartPolyA.append(basegfx::B2DPoint(rPol.aHelpline1.aP1.X(), rPol.aHelpline1.aP1.Y()));
569 	aPartPolyA.append(basegfx::B2DPoint(rPol.aHelpline1.aP2.X(), rPol.aHelpline1.aP2.Y()));
570 	aRetval.append(aPartPolyA);
571 
572 	aPartPolyA.clear();
573 	aPartPolyA.append(basegfx::B2DPoint(rPol.aHelpline2.aP1.X(), rPol.aHelpline2.aP1.Y()));
574 	aPartPolyA.append(basegfx::B2DPoint(rPol.aHelpline2.aP2.X(), rPol.aHelpline2.aP2.Y()));
575 	aRetval.append(aPartPolyA);
576 
577 	return aRetval;
578 }
579 
580 FASTBOOL SdrMeasureObj::CalcFieldValue(const SvxFieldItem& rField, sal_uInt16 nPara, sal_uInt16 nPos,
581 	FASTBOOL bEdit,
582 	Color*& rpTxtColor, Color*& rpFldColor, XubString& rRet) const
583 {
584 	const SvxFieldData* pField=rField.GetField();
585 	SdrMeasureField* pMeasureField=PTR_CAST(SdrMeasureField,pField);
586 	if (pMeasureField!=NULL) {
587 		TakeRepresentation(rRet, pMeasureField->GetMeasureFieldKind());
588 		if (rpFldColor!=NULL) {
589 			if (!bEdit)
590 			{
591 				delete rpFldColor;
592 				rpFldColor=NULL;
593 			}
594 		}
595 		return sal_True;
596 	} else {
597 		return SdrTextObj::CalcFieldValue(rField,nPara,nPos,bEdit,rpTxtColor,rpFldColor,rRet);
598 	}
599 }
600 
601 void SdrMeasureObj::UndirtyText() const
602 {
603 	if (bTextDirty)
604 	{
605 		SdrOutliner& rOutliner=ImpGetDrawOutliner();
606 		OutlinerParaObject* pOutlinerParaObject = SdrTextObj::GetOutlinerParaObject();
607 		if(pOutlinerParaObject==NULL)
608 		{
609             rOutliner.QuickInsertField(SvxFieldItem(SdrMeasureField(SDRMEASUREFIELD_ROTA90BLANCS), EE_FEATURE_FIELD), ESelection(0,0));
610             rOutliner.QuickInsertField(SvxFieldItem(SdrMeasureField(SDRMEASUREFIELD_VALUE), EE_FEATURE_FIELD),ESelection(0,1));
611             rOutliner.QuickInsertField(SvxFieldItem(SdrMeasureField(SDRMEASUREFIELD_UNIT), EE_FEATURE_FIELD),ESelection(0,2));
612             rOutliner.QuickInsertField(SvxFieldItem(SdrMeasureField(SDRMEASUREFIELD_ROTA90BLANCS), EE_FEATURE_FIELD),ESelection(0,3));
613 
614 			if(GetStyleSheet())
615 				rOutliner.SetStyleSheet(0, GetStyleSheet());
616 
617 			rOutliner.SetParaAttribs(0, GetObjectItemSet());
618 
619 			// casting auf nonconst
620 			const_cast<SdrMeasureObj*>(this)->NbcSetOutlinerParaObject( rOutliner.CreateParaObject() );
621 		}
622 		else
623 		{
624 			rOutliner.SetText(*pOutlinerParaObject);
625 		}
626 
627 		rOutliner.SetUpdateMode(sal_True);
628 		rOutliner.UpdateFields();
629 		Size aSiz(rOutliner.CalcTextSize());
630 		rOutliner.Clear();
631 		// 3x casting auf nonconst
632 		((SdrMeasureObj*)this)->aTextSize=aSiz;
633 		((SdrMeasureObj*)this)->bTextSizeDirty=sal_False;
634 		((SdrMeasureObj*)this)->bTextDirty=sal_False;
635 	}
636 }
637 
638 void SdrMeasureObj::TakeUnrotatedSnapRect(Rectangle& rRect) const
639 {
640 	if (bTextDirty) UndirtyText();
641 	ImpMeasureRec aRec;
642 	ImpMeasurePoly aMPol;
643 	ImpTakeAttr(aRec);
644 	ImpCalcGeometrics(aRec,aMPol);
645 
646 	// TextSize ermitteln inkl. Textrahmenabstaende
647 	Size aTextSize2(aMPol.aTextSize);
648 	if (aTextSize2.Width()<1) aTextSize2.Width()=1;
649 	if (aTextSize2.Height()<1) aTextSize2.Height()=1;
650 	aTextSize2.Width()+=GetTextLeftDistance()+GetTextRightDistance();
651 	aTextSize2.Height()+=GetTextUpperDistance()+GetTextLowerDistance();
652 
653 	Point aPt1b(aMPol.aMainline1.aP1);
654 	long nLen=aMPol.nLineLen;
655 	long nLWdt=aMPol.nLineWdt2;
656 	long nArr1Len=aMPol.nArrow1Len;
657 	long nArr2Len=aMPol.nArrow2Len;
658 	if (aMPol.bBreakedLine) {
659 		// Bei Unterbrochener Linie und Outside muss der Text nicht neben den
660 		// Pfeil sondern neben die Linie an dem Pfeil plaziert werden
661 		nArr1Len=aMPol.nShortLineLen+aMPol.nArrow1Wdt/4;
662 		nArr2Len=aMPol.nShortLineLen+aMPol.nArrow2Wdt/4;
663 	}
664 
665 	Point aTextPos;
666 	FASTBOOL bRota90=aRec.bTextRota90;
667 	FASTBOOL bUpsideDown=aRec.bTextUpsideDown!=aMPol.bAutoUpsideDown;
668 	FASTBOOL bBelowRefEdge=aRec.bBelowRefEdge;
669 	SdrMeasureTextHPos eMH=aMPol.eUsedTextHPos;
670 	SdrMeasureTextVPos eMV=aMPol.eUsedTextVPos;
671 	if (!bRota90) {
672 		switch (eMH) {
673 			case SDRMEASURE_TEXTLEFTOUTSIDE: aTextPos.X()=aPt1b.X()-aTextSize2.Width()-nArr1Len-nLWdt; break;
674 			case SDRMEASURE_TEXTRIGHTOUTSIDE: aTextPos.X()=aPt1b.X()+nLen+nArr2Len+nLWdt; break;
675 			default: aTextPos.X()=aPt1b.X(); aTextSize2.Width()=nLen;
676 		}
677 		switch (eMV) {
678 			case SDRMEASURETEXT_VERTICALCENTERED:
679 			case SDRMEASURETEXT_BREAKEDLINE: aTextPos.Y()=aPt1b.Y()-aTextSize2.Height()/2; break;
680 			case SDRMEASURE_BELOW: {
681 				if (!bUpsideDown) aTextPos.Y()=aPt1b.Y()+nLWdt;
682 				else aTextPos.Y()=aPt1b.Y()-aTextSize2.Height()-nLWdt;
683 			} break;
684 			default: {
685 				if (!bUpsideDown) aTextPos.Y()=aPt1b.Y()-aTextSize2.Height()-nLWdt;
686 				else aTextPos.Y()=aPt1b.Y()+nLWdt;
687 			}
688 		}
689 		if (bUpsideDown) {
690 			aTextPos.X()+=aTextSize2.Width();
691 			aTextPos.Y()+=aTextSize2.Height();
692 		}
693 	} else { // also wenn bTextRota90==TRUE
694 		switch (eMH) {
695 			case SDRMEASURE_TEXTLEFTOUTSIDE: aTextPos.X()=aPt1b.X()-aTextSize2.Height()-nArr1Len; break;
696 			case SDRMEASURE_TEXTRIGHTOUTSIDE: aTextPos.X()=aPt1b.X()+nLen+nArr2Len; break;
697 			default: aTextPos.X()=aPt1b.X(); aTextSize2.Height()=nLen;
698 		}
699 		switch (eMV) {
700 			case SDRMEASURETEXT_VERTICALCENTERED:
701 			case SDRMEASURETEXT_BREAKEDLINE: aTextPos.Y()=aPt1b.Y()+aTextSize2.Width()/2; break;
702 			case SDRMEASURE_BELOW: {
703 				if (!bBelowRefEdge) aTextPos.Y()=aPt1b.Y()+aTextSize2.Width()+nLWdt;
704 				else aTextPos.Y()=aPt1b.Y()-nLWdt;
705 			} break;
706 			default: {
707 				if (!bBelowRefEdge) aTextPos.Y()=aPt1b.Y()-nLWdt;
708 				else aTextPos.Y()=aPt1b.Y()+aTextSize2.Width()+nLWdt;
709 			}
710 		}
711 		if (bUpsideDown) {
712 			aTextPos.X()+=aTextSize2.Height();
713 			aTextPos.Y()-=aTextSize2.Width();
714 		}
715 	}
716 	if (aMPol.nTextWink!=aGeo.nDrehWink) {
717 		((SdrMeasureObj*)this)->aGeo.nDrehWink=aMPol.nTextWink;
718 		((SdrMeasureObj*)this)->aGeo.RecalcSinCos();
719 	}
720 	RotatePoint(aTextPos,aPt1b,aMPol.nLineSin,aMPol.nLineCos);
721 	aTextSize2.Width()++; aTextSize2.Height()++; // wg. des komischen Verhaltens beim Rect-Ctor
722 	rRect=Rectangle(aTextPos,aTextSize2);
723 	rRect.Justify();
724 	((SdrMeasureObj*)this)->aRect=rRect;
725 
726 	if (aMPol.nTextWink!=aGeo.nDrehWink) {
727 		((SdrMeasureObj*)this)->aGeo.nDrehWink=aMPol.nTextWink;
728 		((SdrMeasureObj*)this)->aGeo.RecalcSinCos();
729 	}
730 }
731 
732 void SdrMeasureObj::operator=(const SdrObject& rObj)
733 {
734 	SdrTextObj::operator=(rObj);
735 	aPt1=((SdrMeasureObj&)rObj).aPt1;
736 	aPt2=((SdrMeasureObj&)rObj).aPt2;
737 	bTextDirty=((SdrMeasureObj&)rObj).bTextDirty;
738 }
739 
740 void SdrMeasureObj::TakeObjNameSingul(XubString& rName) const
741 {
742 	rName=ImpGetResStr(STR_ObjNameSingulMEASURE);
743 
744 	String aName( GetName() );
745 	if(aName.Len())
746 	{
747 		rName += sal_Unicode(' ');
748 		rName += sal_Unicode('\'');
749 		rName += aName;
750 		rName += sal_Unicode('\'');
751 	}
752 }
753 
754 void SdrMeasureObj::TakeObjNamePlural(XubString& rName) const
755 {
756 	rName=ImpGetResStr(STR_ObjNamePluralMEASURE);
757 }
758 
759 basegfx::B2DPolyPolygon SdrMeasureObj::TakeXorPoly() const
760 {
761 	ImpMeasureRec aRec;
762 	ImpMeasurePoly aMPol;
763 	ImpTakeAttr(aRec);
764 	ImpCalcGeometrics(aRec,aMPol);
765 	return ImpCalcXPoly(aMPol);
766 }
767 
768 sal_uInt32 SdrMeasureObj::GetHdlCount() const
769 {
770 	return 6L;
771 }
772 
773 SdrHdl* SdrMeasureObj::GetHdl(sal_uInt32 nHdlNum) const
774 {
775 	ImpMeasureRec aRec;
776 	ImpMeasurePoly aMPol;
777 	ImpTakeAttr(aRec);
778 	aRec.nHelplineDist=0;
779 	ImpCalcGeometrics(aRec,aMPol);
780 	Point aPt;
781 	//SdrHdlKind eHdl=HDL_POLY;
782 	switch (nHdlNum) {
783 		case 0: aPt=aMPol.aHelpline1.aP1; break;
784 		case 1: aPt=aMPol.aHelpline2.aP1; break;
785 		case 2: aPt=aPt1;       break;
786 		case 3: aPt=aPt2;       break;
787 		case 4: aPt=aMPol.aHelpline1.aP2; break;
788 		case 5: aPt=aMPol.aHelpline2.aP2; break;
789 	} // switch
790 	SdrHdl* pHdl=new ImpMeasureHdl(aPt,HDL_USER);
791 	pHdl->SetObjHdlNum(nHdlNum);
792 	pHdl->SetDrehWink(aMPol.nLineWink);
793 	return pHdl;
794 }
795 
796 ////////////////////////////////////////////////////////////////////////////////////////////////////
797 
798 bool SdrMeasureObj::hasSpecialDrag() const
799 {
800 	return true;
801 }
802 
803 bool SdrMeasureObj::beginSpecialDrag(SdrDragStat& rDrag) const
804 {
805 	const SdrHdl* pHdl = rDrag.GetHdl();
806 
807     if(pHdl)
808     {
809 		const sal_uInt32 nHdlNum(pHdl->GetObjHdlNum());
810 
811         if(nHdlNum != 2 && nHdlNum != 3)
812         {
813 			rDrag.SetEndDragChangesAttributes(true);
814 		}
815 
816         return true;
817 	}
818 
819     return false;
820 }
821 
822 bool SdrMeasureObj::applySpecialDrag(SdrDragStat& rDrag)
823 {
824     ImpMeasureRec aMeasureRec;
825 	const SdrHdl* pHdl = rDrag.GetHdl();
826 	const sal_uInt32 nHdlNum(pHdl->GetObjHdlNum());
827 
828 	ImpTakeAttr(aMeasureRec);
829 	ImpEvalDrag(aMeasureRec, rDrag);
830 
831 	switch (nHdlNum)
832     {
833 		case 2:
834         {
835             aPt1 = aMeasureRec.aPt1;
836             SetTextDirty();
837             break;
838         }
839 		case 3:
840         {
841             aPt2 = aMeasureRec.aPt2;
842             SetTextDirty();
843             break;
844         }
845 		default:
846 		{
847             switch(nHdlNum)
848 			{
849 				case 0:
850 				case 1:
851 				{
852                     ImpMeasureRec aOrigMeasureRec;
853 	                ImpTakeAttr(aOrigMeasureRec);
854 
855                     if(aMeasureRec.nHelpline1Len != aOrigMeasureRec.nHelpline1Len)
856 					{
857 						SetObjectItem(SdrMeasureHelpline1LenItem(aMeasureRec.nHelpline1Len));
858 					}
859 
860 					if(aMeasureRec.nHelpline2Len != aOrigMeasureRec.nHelpline2Len)
861 					{
862 						SetObjectItem(SdrMeasureHelpline2LenItem(aMeasureRec.nHelpline2Len));
863 					}
864 
865 					break;
866 				}
867 
868 				case 4:
869 				case 5:
870 				{
871                     ImpMeasureRec aOrigMeasureRec;
872 	                ImpTakeAttr(aOrigMeasureRec);
873 
874                     if(aMeasureRec.nLineDist != aOrigMeasureRec.nLineDist)
875 					{
876 						SetObjectItem(SdrMeasureLineDistItem(aMeasureRec.nLineDist));
877 					}
878 
879 					if(aMeasureRec.bBelowRefEdge != aOrigMeasureRec.bBelowRefEdge)
880 					{
881 						SetObjectItem(SdrMeasureBelowRefEdgeItem(aMeasureRec.bBelowRefEdge));
882 					}
883 				}
884 			}
885 		}
886 	} // switch
887 
888     SetRectsDirty();
889 	SetChanged();
890 
891     return true;
892 }
893 
894 String SdrMeasureObj::getSpecialDragComment(const SdrDragStat& /*rDrag*/) const
895 {
896 	XubString aStr;
897 	return aStr;
898 }
899 
900 void SdrMeasureObj::ImpEvalDrag(ImpMeasureRec& rRec, const SdrDragStat& rDrag) const
901 {
902 	long nLineWink=GetAngle(rRec.aPt2-rRec.aPt1);
903 	double a=nLineWink*nPi180;
904 	double nSin=sin(a);
905 	double nCos=cos(a);
906 
907 	const SdrHdl* pHdl=rDrag.GetHdl();
908 	sal_uInt32 nHdlNum(pHdl->GetObjHdlNum());
909 	FASTBOOL bOrtho=rDrag.GetView()!=NULL && rDrag.GetView()->IsOrtho();
910 	FASTBOOL bBigOrtho=bOrtho && rDrag.GetView()->IsBigOrtho();
911 	FASTBOOL bBelow=rRec.bBelowRefEdge;
912 	Point aPt(rDrag.GetNow());
913 
914 	switch (nHdlNum) {
915 		case 0: {
916 			RotatePoint(aPt,aPt1,nSin,-nCos);
917 			rRec.nHelpline1Len=aPt1.Y()-aPt.Y();
918 			if (bBelow) rRec.nHelpline1Len=-rRec.nHelpline1Len;
919 			if (bOrtho) rRec.nHelpline2Len=rRec.nHelpline1Len;
920 		} break;
921 		case 1: {
922 			RotatePoint(aPt,aPt2,nSin,-nCos);
923 			rRec.nHelpline2Len=aPt2.Y()-aPt.Y();
924 			if (bBelow) rRec.nHelpline2Len=-rRec.nHelpline2Len;
925 			if (bOrtho) rRec.nHelpline1Len=rRec.nHelpline2Len;
926 		} break;
927 		case 2: case 3: {
928 			FASTBOOL bAnf=nHdlNum==2;
929 			Point& rMov=bAnf ? rRec.aPt1 : rRec.aPt2;
930 			Point aMov(rMov);
931 			Point aFix(bAnf ? rRec.aPt2 : rRec.aPt1);
932 			if (bOrtho) {
933 				long ndx0=aMov.X()-aFix.X();
934 				long ndy0=aMov.Y()-aFix.Y();
935 				FASTBOOL bHLin=ndy0==0;
936 				FASTBOOL bVLin=ndx0==0;
937 				if (!bHLin || !bVLin) { // sonst ist aPt1==aPt2
938 					long ndx=aPt.X()-aFix.X();
939 					long ndy=aPt.Y()-aFix.Y();
940 					double nXFact=0; if (!bVLin) nXFact=(double)ndx/(double)ndx0;
941 					double nYFact=0; if (!bHLin) nYFact=(double)ndy/(double)ndy0;
942 					FASTBOOL bHor=bHLin || (!bVLin && (nXFact>nYFact) ==bBigOrtho);
943 					FASTBOOL bVer=bVLin || (!bHLin && (nXFact<=nYFact)==bBigOrtho);
944 					if (bHor) ndy=long(ndy0*nXFact);
945 					if (bVer) ndx=long(ndx0*nYFact);
946 					aPt=aFix;
947 					aPt.X()+=ndx;
948 					aPt.Y()+=ndy;
949 				} // else Ortho8
950 			}
951 			rMov=aPt;
952 		} break;
953 		case 4: case 5: {
954 			long nVal0=rRec.nLineDist;
955 			RotatePoint(aPt,(nHdlNum==4 ? aPt1 : aPt2),nSin,-nCos);
956 			rRec.nLineDist=aPt.Y()- (nHdlNum==4 ? aPt1.Y() : aPt2.Y());
957 			if (bBelow) rRec.nLineDist=-rRec.nLineDist;
958 			if (rRec.nLineDist<0) {
959 				rRec.nLineDist=-rRec.nLineDist;
960 				rRec.bBelowRefEdge=!bBelow;
961 			}
962 			rRec.nLineDist-=rRec.nHelplineOverhang;
963 			if (bOrtho) rRec.nLineDist=nVal0;
964 		} break;
965 	} // switch
966 }
967 
968 ////////////////////////////////////////////////////////////////////////////////////////////////////
969 
970 FASTBOOL SdrMeasureObj::BegCreate(SdrDragStat& rStat)
971 {
972 	rStat.SetOrtho8Possible();
973 	aPt1=rStat.GetStart();
974 	aPt2=rStat.GetNow();
975 	SetTextDirty();
976 	return sal_True;
977 }
978 
979 FASTBOOL SdrMeasureObj::MovCreate(SdrDragStat& rStat)
980 {
981 	SdrView* pView=rStat.GetView();
982 	aPt1=rStat.GetStart();
983 	aPt2=rStat.GetNow();
984 	if (pView!=NULL && pView->IsCreate1stPointAsCenter()) {
985 		aPt1+=aPt1;
986 		aPt1-=rStat.Now();
987 	}
988 	SetTextDirty();
989 	SetBoundRectDirty();
990 	bSnapRectDirty=sal_True;
991 	return sal_True;
992 }
993 
994 FASTBOOL SdrMeasureObj::EndCreate(SdrDragStat& rStat, SdrCreateCmd eCmd)
995 {
996 	SetTextDirty();
997 	SetRectsDirty();
998 	return (eCmd==SDRCREATE_FORCEEND || rStat.GetPointAnz()>=2);
999 }
1000 
1001 FASTBOOL SdrMeasureObj::BckCreate(SdrDragStat& /*rStat*/)
1002 {
1003 	return sal_False;
1004 }
1005 
1006 void SdrMeasureObj::BrkCreate(SdrDragStat& /*rStat*/)
1007 {
1008 }
1009 
1010 basegfx::B2DPolyPolygon SdrMeasureObj::TakeCreatePoly(const SdrDragStat& /*rDrag*/) const
1011 {
1012 	ImpMeasureRec aRec;
1013 	ImpMeasurePoly aMPol;
1014 
1015 	ImpTakeAttr(aRec);
1016 	ImpCalcGeometrics(aRec, aMPol);
1017 
1018 	return ImpCalcXPoly(aMPol);
1019 }
1020 
1021 Pointer SdrMeasureObj::GetCreatePointer() const
1022 {
1023 	return Pointer(POINTER_CROSS);
1024 }
1025 
1026 void SdrMeasureObj::NbcMove(const Size& rSiz)
1027 {
1028 	SdrTextObj::NbcMove(rSiz);
1029 	MovePoint(aPt1,rSiz);
1030 	MovePoint(aPt2,rSiz);
1031 }
1032 
1033 void SdrMeasureObj::NbcResize(const Point& rRef, const Fraction& xFact, const Fraction& yFact)
1034 {
1035 	SdrTextObj::NbcResize(rRef,xFact,yFact);
1036 	ResizePoint(aPt1,rRef,xFact,yFact);
1037 	ResizePoint(aPt2,rRef,xFact,yFact);
1038 	SetTextDirty();
1039 }
1040 
1041 void SdrMeasureObj::NbcRotate(const Point& rRef, long nWink, double sn, double cs)
1042 {
1043 	SdrTextObj::NbcRotate(rRef,nWink,sn,cs);
1044 	long nLen0=GetLen(aPt2-aPt1);
1045 	RotatePoint(aPt1,rRef,sn,cs);
1046 	RotatePoint(aPt2,rRef,sn,cs);
1047 	long nLen1=GetLen(aPt2-aPt1);
1048 	if (nLen1!=nLen0) { // Aha, Rundungsfehler
1049 		long dx=aPt2.X()-aPt1.X();
1050 		long dy=aPt2.Y()-aPt1.Y();
1051 		dx=BigMulDiv(dx,nLen0,nLen1);
1052 		dy=BigMulDiv(dy,nLen0,nLen1);
1053 		if (rRef==aPt2) {
1054 			aPt1.X()=aPt2.X()-dx;
1055 			aPt1.Y()=aPt2.Y()-dy;
1056 		} else {
1057 			aPt2.X()=aPt1.X()+dx;
1058 			aPt2.Y()=aPt1.Y()+dy;
1059 		}
1060 	}
1061 	SetRectsDirty();
1062 }
1063 
1064 void SdrMeasureObj::NbcMirror(const Point& rRef1, const Point& rRef2)
1065 {
1066 	SdrTextObj::NbcMirror(rRef1,rRef2);
1067 	MirrorPoint(aPt1,rRef1,rRef2);
1068 	MirrorPoint(aPt2,rRef1,rRef2);
1069 	SetRectsDirty();
1070 }
1071 
1072 void SdrMeasureObj::NbcShear(const Point& rRef, long nWink, double tn, FASTBOOL bVShear)
1073 {
1074 	SdrTextObj::NbcShear(rRef,nWink,tn,bVShear);
1075 	ShearPoint(aPt1,rRef,tn,bVShear);
1076 	ShearPoint(aPt2,rRef,tn,bVShear);
1077 	SetRectsDirty();
1078 	SetTextDirty();
1079 }
1080 
1081 long SdrMeasureObj::GetRotateAngle() const
1082 {
1083 	return GetAngle(aPt2-aPt1);
1084 }
1085 
1086 void SdrMeasureObj::RecalcSnapRect()
1087 {
1088 	// #94520# Added correct implementation here.
1089 	ImpMeasureRec aRec;
1090 	ImpMeasurePoly aMPol;
1091 	XPolyPolygon aXPP;
1092 
1093 	ImpTakeAttr(aRec);
1094 	ImpCalcGeometrics(aRec, aMPol);
1095 	aXPP = XPolyPolygon(ImpCalcXPoly(aMPol));
1096 	maSnapRect = aXPP.GetBoundRect();
1097 }
1098 
1099 sal_uInt32 SdrMeasureObj::GetSnapPointCount() const
1100 {
1101 	return 2L;
1102 }
1103 
1104 Point SdrMeasureObj::GetSnapPoint(sal_uInt32 i) const
1105 {
1106 	if (i==0) return aPt1;
1107 	else return aPt2;
1108 }
1109 
1110 sal_Bool SdrMeasureObj::IsPolyObj() const
1111 {
1112 	return sal_True;
1113 }
1114 
1115 sal_uInt32 SdrMeasureObj::GetPointCount() const
1116 {
1117 	return 2L;
1118 }
1119 
1120 Point SdrMeasureObj::GetPoint(sal_uInt32 i) const
1121 {
1122 	 return (0L == i) ? aPt1 : aPt2;
1123 }
1124 
1125 void SdrMeasureObj::NbcSetPoint(const Point& rPnt, sal_uInt32 i)
1126 {
1127 	if (0L == i)
1128 		aPt1=rPnt;
1129 	if (1L == i)
1130 		aPt2=rPnt;
1131 	SetRectsDirty();
1132 	SetTextDirty();
1133 }
1134 
1135 SdrObjGeoData* SdrMeasureObj::NewGeoData() const
1136 {
1137 	return new SdrMeasureObjGeoData;
1138 }
1139 
1140 void SdrMeasureObj::SaveGeoData(SdrObjGeoData& rGeo) const
1141 {
1142 	SdrTextObj::SaveGeoData(rGeo);
1143 	SdrMeasureObjGeoData& rMGeo=(SdrMeasureObjGeoData&)rGeo;
1144 	rMGeo.aPt1=aPt1;
1145 	rMGeo.aPt2=aPt2;
1146 }
1147 
1148 void SdrMeasureObj::RestGeoData(const SdrObjGeoData& rGeo)
1149 {
1150 	SdrTextObj::RestGeoData(rGeo);
1151 	SdrMeasureObjGeoData& rMGeo=(SdrMeasureObjGeoData&)rGeo;
1152 	aPt1=rMGeo.aPt1;
1153 	aPt2=rMGeo.aPt2;
1154 	SetTextDirty();
1155 }
1156 
1157 SdrObject* SdrMeasureObj::DoConvertToPolyObj(sal_Bool bBezier, bool bAddText) const
1158 {
1159 	// get XOR Poly as base
1160 	XPolyPolygon aTmpPolyPolygon(TakeXorPoly());
1161 
1162 	// get local ItemSet and StyleSheet
1163 	SfxItemSet aSet(GetObjectItemSet());
1164     SfxStyleSheet* pStyleSheet = GetStyleSheet();
1165 
1166     // prepare group
1167 	SdrObjGroup* pGroup = new SdrObjGroup;
1168 	pGroup->SetModel(GetModel());
1169 
1170 	// prepare parameters
1171 	basegfx::B2DPolyPolygon aPolyPoly;
1172 	SdrPathObj* pPath;
1173 	sal_uInt16 nCount(aTmpPolyPolygon.Count());
1174 	sal_uInt16 nLoopStart(0);
1175 
1176 	if(nCount == 3)
1177 	{
1178 		// three lines, first one is the middle one
1179 		aPolyPoly.clear();
1180 		aPolyPoly.append(aTmpPolyPolygon[0].getB2DPolygon());
1181 
1182 		pPath = new SdrPathObj(OBJ_PATHLINE, aPolyPoly);
1183 		pPath->SetModel(GetModel());
1184 		pPath->SetMergedItemSet(aSet);
1185         pPath->SetStyleSheet(pStyleSheet, true);
1186 		pGroup->GetSubList()->NbcInsertObject(pPath);
1187 		aSet.Put(XLineStartWidthItem(0L));
1188 		aSet.Put(XLineEndWidthItem(0L));
1189 		nLoopStart = 1;
1190 	}
1191 	else if(nCount == 4)
1192 	{
1193 		// four lines, middle line with gap, so there are two lines used
1194 		// which have one arrow each
1195 		//sal_Int32 nStartWidth = ((const XLineStartWidthItem&)(aSet.Get(XATTR_LINESTARTWIDTH))).GetValue();
1196 		sal_Int32 nEndWidth = ((const XLineEndWidthItem&)(aSet.Get(XATTR_LINEENDWIDTH))).GetValue();
1197 		aSet.Put(XLineEndWidthItem(0L));
1198 
1199 		aPolyPoly.clear();
1200 		aPolyPoly.append(aTmpPolyPolygon[0].getB2DPolygon());
1201 		pPath = new SdrPathObj(OBJ_PATHLINE, aPolyPoly);
1202 		pPath->SetModel(GetModel());
1203 		pPath->SetMergedItemSet(aSet);
1204         pPath->SetStyleSheet(pStyleSheet, true);
1205 
1206 		pGroup->GetSubList()->NbcInsertObject(pPath);
1207 
1208 		aSet.Put(XLineEndWidthItem(nEndWidth));
1209 		aSet.Put(XLineStartWidthItem(0L));
1210 
1211 		aPolyPoly.clear();
1212 		aPolyPoly.append(aTmpPolyPolygon[1].getB2DPolygon());
1213 		pPath = new SdrPathObj(OBJ_PATHLINE, aPolyPoly);
1214 		pPath->SetModel(GetModel());
1215 		pPath->SetMergedItemSet(aSet);
1216         pPath->SetStyleSheet(pStyleSheet, true);
1217 
1218 		pGroup->GetSubList()->NbcInsertObject(pPath);
1219 
1220 		aSet.Put(XLineEndWidthItem(0L));
1221 		nLoopStart = 2;
1222 	}
1223 	else if(nCount == 5)
1224 	{
1225 		// five lines, first two are the outer ones
1226 		//sal_Int32 nStartWidth = ((const XLineStartWidthItem&)(aSet.Get(XATTR_LINESTARTWIDTH))).GetValue();
1227 		sal_Int32 nEndWidth = ((const XLineEndWidthItem&)(aSet.Get(XATTR_LINEENDWIDTH))).GetValue();
1228 
1229 		aSet.Put(XLineEndWidthItem(0L));
1230 
1231 		aPolyPoly.clear();
1232 		aPolyPoly.append(aTmpPolyPolygon[0].getB2DPolygon());
1233 		pPath = new SdrPathObj(OBJ_PATHLINE, aPolyPoly);
1234 		pPath->SetModel(GetModel());
1235 		pPath->SetMergedItemSet(aSet);
1236         pPath->SetStyleSheet(pStyleSheet, true);
1237 
1238 		pGroup->GetSubList()->NbcInsertObject(pPath);
1239 
1240 		aSet.Put(XLineEndWidthItem(nEndWidth));
1241 		aSet.Put(XLineStartWidthItem(0L));
1242 
1243 		aPolyPoly.clear();
1244 		aPolyPoly.append(aTmpPolyPolygon[1].getB2DPolygon());
1245 		pPath = new SdrPathObj(OBJ_PATHLINE, aPolyPoly);
1246 		pPath->SetModel(GetModel());
1247 		pPath->SetMergedItemSet(aSet);
1248         pPath->SetStyleSheet(pStyleSheet, true);
1249 
1250 		pGroup->GetSubList()->NbcInsertObject(pPath);
1251 
1252 		aSet.Put(XLineEndWidthItem(0L));
1253 		nLoopStart = 2;
1254 	}
1255 
1256 	for(;nLoopStart<nCount;nLoopStart++)
1257 	{
1258 		aPolyPoly.clear();
1259 		aPolyPoly.append(aTmpPolyPolygon[nLoopStart].getB2DPolygon());
1260 		pPath = new SdrPathObj(OBJ_PATHLINE, aPolyPoly);
1261 		pPath->SetModel(GetModel());
1262 		pPath->SetMergedItemSet(aSet);
1263         pPath->SetStyleSheet(pStyleSheet, true);
1264 
1265 		pGroup->GetSubList()->NbcInsertObject(pPath);
1266 	}
1267 
1268     if(bAddText)
1269     {
1270     	return ImpConvertAddText(pGroup, bBezier);
1271     }
1272     else
1273     {
1274     	return pGroup;
1275     }
1276 }
1277 
1278 sal_Bool SdrMeasureObj::BegTextEdit(SdrOutliner& rOutl)
1279 {
1280 	UndirtyText();
1281 	return SdrTextObj::BegTextEdit(rOutl);
1282 }
1283 
1284 const Size& SdrMeasureObj::GetTextSize() const
1285 {
1286 	if (bTextDirty) UndirtyText();
1287 	return SdrTextObj::GetTextSize();
1288 }
1289 
1290 OutlinerParaObject* SdrMeasureObj::GetOutlinerParaObject() const
1291 {
1292 	if(bTextDirty)
1293 		UndirtyText();
1294 	return SdrTextObj::GetOutlinerParaObject();
1295 }
1296 
1297 void SdrMeasureObj::NbcSetOutlinerParaObject(OutlinerParaObject* pTextObject)
1298 {
1299 	SdrTextObj::NbcSetOutlinerParaObject(pTextObject);
1300 	if(SdrTextObj::GetOutlinerParaObject())
1301 		SetTextDirty(); // Text neu berechnen!
1302 }
1303 
1304 void SdrMeasureObj::TakeTextRect( SdrOutliner& rOutliner, Rectangle& rTextRect, FASTBOOL bNoEditText,
1305 	Rectangle* pAnchorRect, sal_Bool bLineWidth ) const
1306 {
1307 	if (bTextDirty) UndirtyText();
1308 	SdrTextObj::TakeTextRect( rOutliner, rTextRect, bNoEditText, pAnchorRect, bLineWidth );
1309 }
1310 
1311 void SdrMeasureObj::TakeTextAnchorRect(Rectangle& rAnchorRect) const
1312 {
1313 	if (bTextDirty) UndirtyText();
1314 	SdrTextObj::TakeTextAnchorRect(rAnchorRect);
1315 }
1316 
1317 void SdrMeasureObj::TakeTextEditArea(Size* pPaperMin, Size* pPaperMax, Rectangle* pViewInit, Rectangle* pViewMin) const
1318 {
1319 	if (bTextDirty) UndirtyText();
1320 	SdrTextObj::TakeTextEditArea(pPaperMin,pPaperMax,pViewInit,pViewMin);
1321 }
1322 
1323 sal_uInt16 SdrMeasureObj::GetOutlinerViewAnchorMode() const
1324 {
1325 	if (bTextDirty) UndirtyText();
1326 	ImpMeasureRec aRec;
1327 	ImpMeasurePoly aMPol;
1328 	ImpTakeAttr(aRec);
1329 	ImpCalcGeometrics(aRec,aMPol);
1330 
1331 	SdrTextHorzAdjust eTH=GetTextHorizontalAdjust();
1332 	SdrTextVertAdjust eTV=GetTextVerticalAdjust();
1333 	SdrMeasureTextHPos eMH=aMPol.eUsedTextHPos;
1334 	SdrMeasureTextVPos eMV=aMPol.eUsedTextVPos;
1335 	FASTBOOL bTextRota90=aRec.bTextRota90;
1336 	//int bTextUpsideDown=aRec.bTextUpsideDown;
1337 	FASTBOOL bBelowRefEdge=aRec.bBelowRefEdge;
1338 
1339 	// bTextUpsideDown muss hier noch ausgewertet werden!!!!
1340 	if (!bTextRota90) {
1341 		if (eMH==SDRMEASURE_TEXTLEFTOUTSIDE) eTH=SDRTEXTHORZADJUST_RIGHT;
1342 		if (eMH==SDRMEASURE_TEXTRIGHTOUTSIDE) eTH=SDRTEXTHORZADJUST_LEFT;
1343 		// bei eMH==SDRMEASURE_TEXTINSIDE kann horizontal geankert werden.
1344 		if (eMV==SDRMEASURE_ABOVE) eTV=SDRTEXTVERTADJUST_BOTTOM;
1345 		if (eMV==SDRMEASURE_BELOW) eTV=SDRTEXTVERTADJUST_TOP;
1346 		if (eMV==SDRMEASURETEXT_BREAKEDLINE || eMV==SDRMEASURETEXT_VERTICALCENTERED) eTV=SDRTEXTVERTADJUST_CENTER;
1347 	} else {
1348 		if (eMH==SDRMEASURE_TEXTLEFTOUTSIDE) eTV=SDRTEXTVERTADJUST_BOTTOM;
1349 		if (eMH==SDRMEASURE_TEXTRIGHTOUTSIDE) eTV=SDRTEXTVERTADJUST_TOP;
1350 		// bei eMH==SDRMEASURE_TEXTINSIDE kann vertikal geankert werden.
1351 		if (!bBelowRefEdge) {
1352 			if (eMV==SDRMEASURE_ABOVE) eTH=SDRTEXTHORZADJUST_LEFT;
1353 			if (eMV==SDRMEASURE_BELOW) eTH=SDRTEXTHORZADJUST_RIGHT;
1354 		} else {
1355 			if (eMV==SDRMEASURE_ABOVE) eTH=SDRTEXTHORZADJUST_RIGHT;
1356 			if (eMV==SDRMEASURE_BELOW) eTH=SDRTEXTHORZADJUST_LEFT;
1357 		}
1358 		if (eMV==SDRMEASURETEXT_BREAKEDLINE || eMV==SDRMEASURETEXT_VERTICALCENTERED) eTH=SDRTEXTHORZADJUST_CENTER;
1359 	}
1360 
1361 	EVAnchorMode eRet=ANCHOR_BOTTOM_HCENTER;
1362 	if (eTH==SDRTEXTHORZADJUST_LEFT) {
1363 		if (eTV==SDRTEXTVERTADJUST_TOP) eRet=ANCHOR_TOP_LEFT;
1364 		else if (eTV==SDRTEXTVERTADJUST_BOTTOM) eRet=ANCHOR_BOTTOM_LEFT;
1365 		else eRet=ANCHOR_VCENTER_LEFT;
1366 	} else if (eTH==SDRTEXTHORZADJUST_RIGHT) {
1367 		if (eTV==SDRTEXTVERTADJUST_TOP) eRet=ANCHOR_TOP_RIGHT;
1368 		else if (eTV==SDRTEXTVERTADJUST_BOTTOM) eRet=ANCHOR_BOTTOM_RIGHT;
1369 		else eRet=ANCHOR_VCENTER_RIGHT;
1370 	} else {
1371 		if (eTV==SDRTEXTVERTADJUST_TOP) eRet=ANCHOR_TOP_HCENTER;
1372 		else if (eTV==SDRTEXTVERTADJUST_BOTTOM) eRet=ANCHOR_BOTTOM_HCENTER;
1373 		else eRet=ANCHOR_VCENTER_HCENTER;
1374 	}
1375 	return (sal_uInt16)eRet;
1376 }
1377 
1378 //////////////////////////////////////////////////////////////////////////////
1379 // #i97878#
1380 // TRGetBaseGeometry/TRSetBaseGeometry needs to be based on two positions,
1381 // same as line geometry in SdrPathObj. Thus needs to be overloaded and
1382 // implemented since currently it is derived from SdrTextObj which uses
1383 // a functionality based on SnapRect which is not useful here
1384 
1385 inline double ImplTwipsToMM(double fVal) { return (fVal * (127.0 / 72.0)); }
1386 inline double ImplMMToTwips(double fVal) { return (fVal * (72.0 / 127.0)); }
1387 
1388 sal_Bool SdrMeasureObj::TRGetBaseGeometry(basegfx::B2DHomMatrix& rMatrix, basegfx::B2DPolyPolygon& /*rPolyPolygon*/) const
1389 {
1390     // handle the same as a simple line since the definition is based on two points
1391     const basegfx::B2DRange aRange(aPt1.X(), aPt1.Y(), aPt2.X(), aPt2.Y());
1392 	basegfx::B2DTuple aScale(aRange.getRange());
1393     basegfx::B2DTuple aTranslate(aRange.getMinimum());
1394 
1395 	// position maybe relative to anchorpos, convert
1396 	if( pModel->IsWriter() )
1397 	{
1398 		if(GetAnchorPos().X() || GetAnchorPos().Y())
1399 		{
1400 			aTranslate -= basegfx::B2DTuple(GetAnchorPos().X(), GetAnchorPos().Y());
1401 		}
1402 	}
1403 
1404 	// force MapUnit to 100th mm
1405 	SfxMapUnit eMapUnit = pModel->GetItemPool().GetMetric(0);
1406 	if(eMapUnit != SFX_MAPUNIT_100TH_MM)
1407 	{
1408 		switch(eMapUnit)
1409 		{
1410 			case SFX_MAPUNIT_TWIP :
1411 			{
1412 				// postion
1413 				aTranslate.setX(ImplTwipsToMM(aTranslate.getX()));
1414 				aTranslate.setY(ImplTwipsToMM(aTranslate.getY()));
1415 
1416 				// size
1417 				aScale.setX(ImplTwipsToMM(aScale.getX()));
1418 				aScale.setY(ImplTwipsToMM(aScale.getY()));
1419 
1420 				break;
1421 			}
1422 			default:
1423 			{
1424 				DBG_ERROR("TRGetBaseGeometry: Missing unit translation to 100th mm!");
1425 			}
1426 		}
1427 	}
1428 
1429 	// build return value matrix
1430 	rMatrix = basegfx::tools::createScaleTranslateB2DHomMatrix(aScale, aTranslate);
1431 
1432 	return sal_True;
1433 }
1434 
1435 void SdrMeasureObj::TRSetBaseGeometry(const basegfx::B2DHomMatrix& rMatrix, const basegfx::B2DPolyPolygon& /*rPolyPolygon*/)
1436 {
1437     // use given transformation to derive the two defining points from unit line
1438     basegfx::B2DPoint aPosA(rMatrix * basegfx::B2DPoint(0.0, 0.0));
1439     basegfx::B2DPoint aPosB(rMatrix * basegfx::B2DPoint(1.0, 0.0));
1440 
1441 	// force metric to pool metric
1442 	SfxMapUnit eMapUnit = pModel->GetItemPool().GetMetric(0);
1443 	if(eMapUnit != SFX_MAPUNIT_100TH_MM)
1444 	{
1445 		switch(eMapUnit)
1446 		{
1447 			case SFX_MAPUNIT_TWIP :
1448 			{
1449 				// position
1450                 aPosA.setX(ImplMMToTwips(aPosA.getX()));
1451                 aPosA.setY(ImplMMToTwips(aPosA.getY()));
1452                 aPosB.setX(ImplMMToTwips(aPosB.getX()));
1453                 aPosB.setY(ImplMMToTwips(aPosB.getY()));
1454 
1455 				break;
1456 			}
1457 			default:
1458 			{
1459 				DBG_ERROR("TRSetBaseGeometry: Missing unit translation to PoolMetric!");
1460 			}
1461 		}
1462 	}
1463 
1464 	if( pModel->IsWriter() )
1465 	{
1466 		// if anchor is used, make position relative to it
1467 		if(GetAnchorPos().X() || GetAnchorPos().Y())
1468 		{
1469             const basegfx::B2DVector aAnchorOffset(GetAnchorPos().X(), GetAnchorPos().Y());
1470 
1471             aPosA += aAnchorOffset;
1472             aPosB += aAnchorOffset;
1473 		}
1474 	}
1475 
1476     // derive new model data
1477     const Point aNewPt1(basegfx::fround(aPosA.getX()), basegfx::fround(aPosA.getY()));
1478     const Point aNewPt2(basegfx::fround(aPosB.getX()), basegfx::fround(aPosB.getY()));
1479 
1480     if(aNewPt1 != aPt1 || aNewPt2 != aPt2)
1481     {
1482         // set model values and broadcast
1483 		Rectangle aBoundRect0; if (pUserCall!=NULL) aBoundRect0=GetLastBoundRect();
1484 
1485         aPt1 = aNewPt1;
1486         aPt2 = aNewPt2;
1487 
1488         SetTextDirty();
1489         ActionChanged();
1490 		SetChanged();
1491 		BroadcastObjectChange();
1492 		SendUserCall(SDRUSERCALL_MOVEONLY,aBoundRect0);
1493     }
1494 }
1495 
1496 //////////////////////////////////////////////////////////////////////////////
1497 // eof
1498