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