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 <tools/bigint.hxx> 32 #include <svx/svdopath.hxx> 33 #include <math.h> 34 #include <svx/xpool.hxx> 35 #include <svx/xpoly.hxx> 36 #include <svx/svdattr.hxx> 37 #include <svx/svdtrans.hxx> 38 #include <svx/svdetc.hxx> 39 #include <svx/svddrag.hxx> 40 #include <svx/svdmodel.hxx> 41 #include <svx/svdpage.hxx> 42 #include <svx/svdhdl.hxx> 43 #include <svx/svdview.hxx> // fuer MovCreate bei Freihandlinien 44 #include "svx/svdglob.hxx" // Stringcache 45 #include "svx/svdstr.hrc" // Objektname 46 47 #ifdef _MSC_VER 48 #pragma optimize ("",off) 49 #pragma warning(disable: 4748) // "... because optimizations are disabled ..." 50 #endif 51 52 #include <svx/xlnwtit.hxx> 53 #include <svx/xlnclit.hxx> 54 #include <svx/xflclit.hxx> 55 #include <svx/svdogrp.hxx> 56 #include <svx/polypolygoneditor.hxx> 57 #include <svx/xlntrit.hxx> 58 #include <vcl/salbtype.hxx> // FRound 59 #include "svdoimp.hxx" 60 #include <svx/sdr/contact/viewcontactofsdrpathobj.hxx> 61 #include <basegfx/matrix/b2dhommatrix.hxx> 62 63 // #104018# replace macros above with type-safe methods 64 inline sal_Int32 ImplTwipsToMM(sal_Int32 nVal) { return ((nVal * 127 + 36) / 72); } 65 inline sal_Int32 ImplMMToTwips(sal_Int32 nVal) { return ((nVal * 72 + 63) / 127); } 66 inline sal_Int64 ImplTwipsToMM(sal_Int64 nVal) { return ((nVal * 127 + 36) / 72); } 67 inline sal_Int64 ImplMMToTwips(sal_Int64 nVal) { return ((nVal * 72 + 63) / 127); } 68 inline double ImplTwipsToMM(double fVal) { return (fVal * (127.0 / 72.0)); } 69 inline double ImplMMToTwips(double fVal) { return (fVal * (72.0 / 127.0)); } 70 #include <basegfx/point/b2dpoint.hxx> 71 #include <basegfx/polygon/b2dpolypolygontools.hxx> 72 #include <basegfx/matrix/b2dhommatrix.hxx> 73 #include <basegfx/range/b2drange.hxx> 74 #include <basegfx/curve/b2dcubicbezier.hxx> 75 #include <basegfx/polygon/b2dpolygontools.hxx> 76 #include <svx/sdr/attribute/sdrtextattribute.hxx> 77 #include <svx/sdr/primitive2d/sdrattributecreator.hxx> 78 #include <basegfx/matrix/b2dhommatrixtools.hxx> 79 #include <svx/sdr/attribute/sdrformtextattribute.hxx> 80 81 using namespace sdr; 82 83 inline sal_uInt16 GetPrevPnt(sal_uInt16 nPnt, sal_uInt16 nPntMax, FASTBOOL bClosed) 84 { 85 if (nPnt>0) { 86 nPnt--; 87 } else { 88 nPnt=nPntMax; 89 if (bClosed) nPnt--; 90 } 91 return nPnt; 92 } 93 94 inline sal_uInt16 GetNextPnt(sal_uInt16 nPnt, sal_uInt16 nPntMax, FASTBOOL bClosed) 95 { 96 nPnt++; 97 if (nPnt>nPntMax || (bClosed && nPnt>=nPntMax)) nPnt=0; 98 return nPnt; 99 } 100 101 struct ImpSdrPathDragData : public SdrDragStatUserData 102 { 103 XPolygon aXP; // Ausschnitt aud dem Originalpolygon 104 FASTBOOL bValid; // sal_False = zu wenig Punkte 105 FASTBOOL bClosed; // geschlossenes Objekt? 106 sal_uInt16 nPoly; // Nummer des Polygons im PolyPolygon 107 sal_uInt16 nPnt; // Punktnummer innerhalb des obigen Polygons 108 sal_uInt16 nPntAnz; // Punktanzahl des Polygons 109 sal_uInt16 nPntMax; // Maximaler Index 110 FASTBOOL bBegPnt; // Gedraggter Punkt ist der Anfangspunkt einer Polyline 111 FASTBOOL bEndPnt; // Gedraggter Punkt ist der Endpunkt einer Polyline 112 sal_uInt16 nPrevPnt; // Index des vorherigen Punkts 113 sal_uInt16 nNextPnt; // Index des naechsten Punkts 114 FASTBOOL bPrevIsBegPnt; // Vorheriger Punkt ist Anfangspunkt einer Polyline 115 FASTBOOL bNextIsEndPnt; // Folgepunkt ist Endpunkt einer Polyline 116 sal_uInt16 nPrevPrevPnt; // Index des vorvorherigen Punkts 117 sal_uInt16 nNextNextPnt; // Index des uebernaechsten Punkts 118 FASTBOOL bControl; // Punkt ist ein Kontrollpunkt 119 FASTBOOL bIsPrevControl; // Punkt ist Kontrollpunkt vor einem Stuetzpunkt 120 FASTBOOL bIsNextControl; // Punkt ist Kontrollpunkt hinter einem Stuetzpunkt 121 FASTBOOL bPrevIsControl; // Falls nPnt ein StPnt: Davor ist ein Kontrollpunkt 122 FASTBOOL bNextIsControl; // Falls nPnt ein StPnt: Dahinter ist ein Kontrollpunkt 123 sal_uInt16 nPrevPrevPnt0; 124 sal_uInt16 nPrevPnt0; 125 sal_uInt16 nPnt0; 126 sal_uInt16 nNextPnt0; 127 sal_uInt16 nNextNextPnt0; 128 FASTBOOL bEliminate; // Punkt loeschen? (wird von MovDrag gesetzt) 129 130 // ## 131 sal_Bool mbMultiPointDrag; 132 const XPolyPolygon maOrig; 133 XPolyPolygon maMove; 134 Container maHandles; 135 136 public: 137 ImpSdrPathDragData(const SdrPathObj& rPO, const SdrHdl& rHdl, sal_Bool bMuPoDr, const SdrDragStat& rDrag); 138 void ResetPoly(const SdrPathObj& rPO); 139 sal_Bool IsMultiPointDrag() const { return mbMultiPointDrag; } 140 }; 141 142 ImpSdrPathDragData::ImpSdrPathDragData(const SdrPathObj& rPO, const SdrHdl& rHdl, sal_Bool bMuPoDr, const SdrDragStat& rDrag) 143 : aXP(5), 144 mbMultiPointDrag(bMuPoDr), 145 maOrig(rPO.GetPathPoly()), 146 maHandles(0) 147 { 148 if(mbMultiPointDrag) 149 { 150 const SdrMarkView& rMarkView = *rDrag.GetView(); 151 const SdrHdlList& rHdlList = rMarkView.GetHdlList(); 152 const sal_uInt32 nHdlCount = rHdlList.GetHdlCount(); 153 const SdrObject* pInteractionObject(nHdlCount && rHdlList.GetHdl(0) ? rHdlList.GetHdl(0)->GetObj() : 0); 154 155 for(sal_uInt32 a(0); a < nHdlCount; a++) 156 { 157 SdrHdl* pTestHdl = rHdlList.GetHdl(a); 158 159 if(pTestHdl && pTestHdl->IsSelected() && pTestHdl->GetObj() == pInteractionObject) 160 { 161 maHandles.Insert(pTestHdl, CONTAINER_APPEND); 162 } 163 } 164 165 maMove = maOrig; 166 bValid = sal_True; 167 } 168 else 169 { 170 bValid=sal_False; 171 bClosed=rPO.IsClosed(); // geschlossenes Objekt? 172 nPoly=(sal_uInt16)rHdl.GetPolyNum(); // Nummer des Polygons im PolyPolygon 173 nPnt=(sal_uInt16)rHdl.GetPointNum(); // Punktnummer innerhalb des obigen Polygons 174 const XPolygon aTmpXP(rPO.GetPathPoly().getB2DPolygon(nPoly)); 175 nPntAnz=aTmpXP.GetPointCount(); // Punktanzahl des Polygons 176 if (nPntAnz==0 || (bClosed && nPntAnz==1)) return; // min. 1Pt bei Line, min. 2 bei Polygon 177 nPntMax=nPntAnz-1; // Maximaler Index 178 bBegPnt=!bClosed && nPnt==0; // Gedraggter Punkt ist der Anfangspunkt einer Polyline 179 bEndPnt=!bClosed && nPnt==nPntMax; // Gedraggter Punkt ist der Endpunkt einer Polyline 180 if (bClosed && nPntAnz<=3) { // Falls Polygon auch nur eine Linie ist 181 bBegPnt=(nPntAnz<3) || nPnt==0; 182 bEndPnt=(nPntAnz<3) || nPnt==nPntMax-1; 183 } 184 nPrevPnt=nPnt; // Index des vorherigen Punkts 185 nNextPnt=nPnt; // Index des naechsten Punkts 186 if (!bBegPnt) nPrevPnt=GetPrevPnt(nPnt,nPntMax,bClosed); 187 if (!bEndPnt) nNextPnt=GetNextPnt(nPnt,nPntMax,bClosed); 188 bPrevIsBegPnt=bBegPnt || (!bClosed && nPrevPnt==0); 189 bNextIsEndPnt=bEndPnt || (!bClosed && nNextPnt==nPntMax); 190 nPrevPrevPnt=nPnt; // Index des vorvorherigen Punkts 191 nNextNextPnt=nPnt; // Index des uebernaechsten Punkts 192 if (!bPrevIsBegPnt) nPrevPrevPnt=GetPrevPnt(nPrevPnt,nPntMax,bClosed); 193 if (!bNextIsEndPnt) nNextNextPnt=GetNextPnt(nNextPnt,nPntMax,bClosed); 194 bControl=rHdl.IsPlusHdl(); // Punkt ist ein Kontrollpunkt 195 bIsPrevControl=sal_False; // Punkt ist Kontrollpunkt vor einem Stuetzpunkt 196 bIsNextControl=sal_False; // Punkt ist Kontrollpunkt hinter einem Stuetzpunkt 197 bPrevIsControl=sal_False; // Falls nPnt ein StPnt: Davor ist ein Kontrollpunkt 198 bNextIsControl=sal_False; // Falls nPnt ein StPnt: Dahinter ist ein Kontrollpunkt 199 if (bControl) { 200 bIsPrevControl=aTmpXP.IsControl(nPrevPnt); 201 bIsNextControl=!bIsPrevControl; 202 } else { 203 bPrevIsControl=!bBegPnt && !bPrevIsBegPnt && aTmpXP.GetFlags(nPrevPnt)==XPOLY_CONTROL; 204 bNextIsControl=!bEndPnt && !bNextIsEndPnt && aTmpXP.GetFlags(nNextPnt)==XPOLY_CONTROL; 205 } 206 nPrevPrevPnt0=nPrevPrevPnt; 207 nPrevPnt0 =nPrevPnt; 208 nPnt0 =nPnt; 209 nNextPnt0 =nNextPnt; 210 nNextNextPnt0=nNextNextPnt; 211 nPrevPrevPnt=0; 212 nPrevPnt=1; 213 nPnt=2; 214 nNextPnt=3; 215 nNextNextPnt=4; 216 bEliminate=sal_False; 217 ResetPoly(rPO); 218 bValid=sal_True; 219 } 220 } 221 222 void ImpSdrPathDragData::ResetPoly(const SdrPathObj& rPO) 223 { 224 const XPolygon aTmpXP(rPO.GetPathPoly().getB2DPolygon(nPoly)); 225 aXP[0]=aTmpXP[nPrevPrevPnt0]; aXP.SetFlags(0,aTmpXP.GetFlags(nPrevPrevPnt0)); 226 aXP[1]=aTmpXP[nPrevPnt0]; aXP.SetFlags(1,aTmpXP.GetFlags(nPrevPnt0)); 227 aXP[2]=aTmpXP[nPnt0]; aXP.SetFlags(2,aTmpXP.GetFlags(nPnt0)); 228 aXP[3]=aTmpXP[nNextPnt0]; aXP.SetFlags(3,aTmpXP.GetFlags(nNextPnt0)); 229 aXP[4]=aTmpXP[nNextNextPnt0]; aXP.SetFlags(4,aTmpXP.GetFlags(nNextNextPnt0)); 230 } 231 232 /*************************************************************************/ 233 234 struct ImpPathCreateUser : public SdrDragStatUserData 235 { 236 Point aBezControl0; 237 Point aBezStart; 238 Point aBezCtrl1; 239 Point aBezCtrl2; 240 Point aBezEnd; 241 Point aCircStart; 242 Point aCircEnd; 243 Point aCircCenter; 244 Point aLineStart; 245 Point aLineEnd; 246 Point aRectP1; 247 Point aRectP2; 248 Point aRectP3; 249 long nCircRadius; 250 long nCircStWink; 251 long nCircRelWink; 252 FASTBOOL bBezier; 253 FASTBOOL bBezHasCtrl0; 254 FASTBOOL bCurve; 255 FASTBOOL bCircle; 256 FASTBOOL bAngleSnap; 257 FASTBOOL bLine; 258 FASTBOOL bLine90; 259 FASTBOOL bRect; 260 FASTBOOL bMixedCreate; 261 sal_uInt16 nBezierStartPoint; 262 SdrObjKind eStartKind; 263 SdrObjKind eAktKind; 264 265 public: 266 ImpPathCreateUser(): nCircRadius(0),nCircStWink(0),nCircRelWink(0), 267 bBezier(sal_False),bBezHasCtrl0(sal_False),bCurve(sal_False),bCircle(sal_False),bAngleSnap(sal_False),bLine(sal_False),bLine90(sal_False),bRect(sal_False), 268 bMixedCreate(sal_False),nBezierStartPoint(0),eStartKind(OBJ_NONE),eAktKind(OBJ_NONE) { } 269 270 void ResetFormFlags() { bBezier=sal_False; bCurve=sal_False; bCircle=sal_False; bLine=sal_False; bRect=sal_False; } 271 FASTBOOL IsFormFlag() const { return bBezier || bCurve || bCircle || bLine || bRect; } 272 XPolygon GetFormPoly() const; 273 FASTBOOL CalcBezier(const Point& rP1, const Point& rP2, const Point& rDir, FASTBOOL bMouseDown); 274 XPolygon GetBezierPoly() const; 275 //int CalcCurve(const Point& rP1, const Point& rP2, const Point& rDir, SdrView* pView) { return sal_False; } 276 XPolygon GetCurvePoly() const { return XPolygon(); } 277 FASTBOOL CalcCircle(const Point& rP1, const Point& rP2, const Point& rDir, SdrView* pView); 278 XPolygon GetCirclePoly() const; 279 FASTBOOL CalcLine(const Point& rP1, const Point& rP2, const Point& rDir, SdrView* pView); 280 Point CalcLine(const Point& rCsr, long nDirX, long nDirY, SdrView* pView) const; 281 XPolygon GetLinePoly() const; 282 FASTBOOL CalcRect(const Point& rP1, const Point& rP2, const Point& rDir, SdrView* pView); 283 XPolygon GetRectPoly() const; 284 }; 285 286 XPolygon ImpPathCreateUser::GetFormPoly() const 287 { 288 if (bBezier) return GetBezierPoly(); 289 if (bCurve) return GetCurvePoly(); 290 if (bCircle) return GetCirclePoly(); 291 if (bLine) return GetLinePoly(); 292 if (bRect) return GetRectPoly(); 293 return XPolygon(); 294 } 295 296 FASTBOOL ImpPathCreateUser::CalcBezier(const Point& rP1, const Point& rP2, const Point& rDir, FASTBOOL bMouseDown) 297 { 298 FASTBOOL bRet=sal_True; 299 aBezStart=rP1; 300 aBezCtrl1=rP1+rDir; 301 aBezCtrl2=rP2; 302 303 // #i21479# 304 // Also copy the end point when no end point is set yet 305 if (!bMouseDown || (0L == aBezEnd.X() && 0L == aBezEnd.Y())) aBezEnd=rP2; 306 307 bBezier=bRet; 308 return bRet; 309 } 310 311 XPolygon ImpPathCreateUser::GetBezierPoly() const 312 { 313 XPolygon aXP(4); 314 aXP[0]=aBezStart; aXP.SetFlags(0,XPOLY_SMOOTH); 315 aXP[1]=aBezCtrl1; aXP.SetFlags(1,XPOLY_CONTROL); 316 aXP[2]=aBezCtrl2; aXP.SetFlags(2,XPOLY_CONTROL); 317 aXP[3]=aBezEnd; 318 return aXP; 319 } 320 321 FASTBOOL ImpPathCreateUser::CalcCircle(const Point& rP1, const Point& rP2, const Point& rDir, SdrView* pView) 322 { 323 long nTangAngle=GetAngle(rDir); 324 aCircStart=rP1; 325 aCircEnd=rP2; 326 aCircCenter=rP1; 327 long dx=rP2.X()-rP1.X(); 328 long dy=rP2.Y()-rP1.Y(); 329 long dAngle=GetAngle(Point(dx,dy))-nTangAngle; 330 dAngle=NormAngle360(dAngle); 331 long nTmpAngle=NormAngle360(9000-dAngle); 332 FASTBOOL bRet=nTmpAngle!=9000 && nTmpAngle!=27000; 333 long nRad=0; 334 if (bRet) { 335 double cs=cos(nTmpAngle*nPi180); 336 double nR=(double)GetLen(Point(dx,dy))/cs/2; 337 nRad=Abs(Round(nR)); 338 } 339 if (dAngle<18000) { 340 nCircStWink=NormAngle360(nTangAngle-9000); 341 nCircRelWink=NormAngle360(2*dAngle); 342 aCircCenter.X()+=Round(nRad*cos((nTangAngle+9000)*nPi180)); 343 aCircCenter.Y()-=Round(nRad*sin((nTangAngle+9000)*nPi180)); 344 } else { 345 nCircStWink=NormAngle360(nTangAngle+9000); 346 nCircRelWink=-NormAngle360(36000-2*dAngle); 347 aCircCenter.X()+=Round(nRad*cos((nTangAngle-9000)*nPi180)); 348 aCircCenter.Y()-=Round(nRad*sin((nTangAngle-9000)*nPi180)); 349 } 350 bAngleSnap=pView!=NULL && pView->IsAngleSnapEnabled(); 351 if (bAngleSnap) { 352 long nSA=pView->GetSnapAngle(); 353 if (nSA!=0) { // Winkelfang 354 FASTBOOL bNeg=nCircRelWink<0; 355 if (bNeg) nCircRelWink=-nCircRelWink; 356 nCircRelWink+=nSA/2; 357 nCircRelWink/=nSA; 358 nCircRelWink*=nSA; 359 nCircRelWink=NormAngle360(nCircRelWink); 360 if (bNeg) nCircRelWink=-nCircRelWink; 361 } 362 } 363 nCircRadius=nRad; 364 if (nRad==0 || Abs(nCircRelWink)<5) bRet=sal_False; 365 bCircle=bRet; 366 return bRet; 367 } 368 369 XPolygon ImpPathCreateUser::GetCirclePoly() const 370 { 371 if (nCircRelWink>=0) { 372 XPolygon aXP(aCircCenter,nCircRadius,nCircRadius, 373 sal_uInt16((nCircStWink+5)/10),sal_uInt16((nCircStWink+nCircRelWink+5)/10),sal_False); 374 aXP[0]=aCircStart; aXP.SetFlags(0,XPOLY_SMOOTH); 375 if (!bAngleSnap) aXP[aXP.GetPointCount()-1]=aCircEnd; 376 return aXP; 377 } else { 378 XPolygon aXP(aCircCenter,nCircRadius,nCircRadius, 379 sal_uInt16(NormAngle360(nCircStWink+nCircRelWink+5)/10),sal_uInt16((nCircStWink+5)/10),sal_False); 380 sal_uInt16 nAnz=aXP.GetPointCount(); 381 for (sal_uInt16 nNum=nAnz/2; nNum>0;) { 382 nNum--; // XPoly Punktreihenfolge umkehren 383 sal_uInt16 n2=nAnz-nNum-1; 384 Point aPt(aXP[nNum]); 385 aXP[nNum]=aXP[n2]; 386 aXP[n2]=aPt; 387 } 388 aXP[0]=aCircStart; aXP.SetFlags(0,XPOLY_SMOOTH); 389 if (!bAngleSnap) aXP[aXP.GetPointCount()-1]=aCircEnd; 390 return aXP; 391 } 392 } 393 394 Point ImpPathCreateUser::CalcLine(const Point& aCsr, long nDirX, long nDirY, SdrView* pView) const 395 { 396 long x=aCsr.X(),x1=x,x2=x; 397 long y=aCsr.Y(),y1=y,y2=y; 398 FASTBOOL bHLin=nDirY==0; 399 FASTBOOL bVLin=nDirX==0; 400 if (bHLin) y=0; 401 else if (bVLin) x=0; 402 else { 403 x1=BigMulDiv(y,nDirX,nDirY); 404 y2=BigMulDiv(x,nDirY,nDirX); 405 long l1=Abs(x1)+Abs(y1); 406 long l2=Abs(x2)+Abs(y2); 407 if ((l1<=l2) != (pView!=NULL && pView->IsBigOrtho())) { 408 x=x1; y=y1; 409 } else { 410 x=x2; y=y2; 411 } 412 } 413 return Point(x,y); 414 } 415 416 FASTBOOL ImpPathCreateUser::CalcLine(const Point& rP1, const Point& rP2, const Point& rDir, SdrView* pView) 417 { 418 aLineStart=rP1; 419 aLineEnd=rP2; 420 bLine90=sal_False; 421 if (rP1==rP2 || (rDir.X()==0 && rDir.Y()==0)) { bLine=sal_False; return sal_False; } 422 Point aTmpPt(rP2-rP1); 423 long nDirX=rDir.X(); 424 long nDirY=rDir.Y(); 425 Point aP1(CalcLine(aTmpPt, nDirX, nDirY,pView)); aP1-=aTmpPt; long nQ1=Abs(aP1.X())+Abs(aP1.Y()); 426 Point aP2(CalcLine(aTmpPt, nDirY,-nDirX,pView)); aP2-=aTmpPt; long nQ2=Abs(aP2.X())+Abs(aP2.Y()); 427 if (pView!=NULL && pView->IsOrtho()) nQ1=0; // Ortho schaltet rechtwinklig aus 428 bLine90=nQ1>2*nQ2; 429 if (!bLine90) { // glatter Uebergang 430 aLineEnd+=aP1; 431 } else { // rechtwinkliger Uebergang 432 aLineEnd+=aP2; 433 } 434 bLine=sal_True; 435 return sal_True; 436 } 437 438 XPolygon ImpPathCreateUser::GetLinePoly() const 439 { 440 XPolygon aXP(2); 441 aXP[0]=aLineStart; if (!bLine90) aXP.SetFlags(0,XPOLY_SMOOTH); 442 aXP[1]=aLineEnd; 443 return aXP; 444 } 445 446 FASTBOOL ImpPathCreateUser::CalcRect(const Point& rP1, const Point& rP2, const Point& rDir, SdrView* pView) 447 { 448 aRectP1=rP1; 449 aRectP2=rP1; 450 aRectP3=rP2; 451 if (rP1==rP2 || (rDir.X()==0 && rDir.Y()==0)) { bRect=sal_False; return sal_False; } 452 Point aTmpPt(rP2-rP1); 453 long nDirX=rDir.X(); 454 long nDirY=rDir.Y(); 455 long x=aTmpPt.X(); 456 long y=aTmpPt.Y(); 457 FASTBOOL bHLin=nDirY==0; 458 FASTBOOL bVLin=nDirX==0; 459 if (bHLin) y=0; 460 else if (bVLin) x=0; 461 else { 462 y=BigMulDiv(x,nDirY,nDirX); 463 long nHypLen=aTmpPt.Y()-y; 464 long nTangAngle=-GetAngle(rDir); 465 // sin=g/h, g=h*sin 466 double a=nTangAngle*nPi180; 467 double sn=sin(a); 468 double cs=cos(a); 469 double nGKathLen=nHypLen*sn; 470 y+=Round(nGKathLen*sn); 471 x+=Round(nGKathLen*cs); 472 } 473 aRectP2.X()+=x; 474 aRectP2.Y()+=y; 475 if (pView!=NULL && pView->IsOrtho()) { 476 long dx1=aRectP2.X()-aRectP1.X(); long dx1a=Abs(dx1); 477 long dy1=aRectP2.Y()-aRectP1.Y(); long dy1a=Abs(dy1); 478 long dx2=aRectP3.X()-aRectP2.X(); long dx2a=Abs(dx2); 479 long dy2=aRectP3.Y()-aRectP2.Y(); long dy2a=Abs(dy2); 480 FASTBOOL b1MoreThan2=dx1a+dy1a>dx2a+dy2a; 481 if (b1MoreThan2 != pView->IsBigOrtho()) { 482 long xtemp=dy2a-dx1a; if (dx1<0) xtemp=-xtemp; 483 long ytemp=dx2a-dy1a; if (dy1<0) ytemp=-ytemp; 484 aRectP2.X()+=xtemp; 485 aRectP2.Y()+=ytemp; 486 aRectP3.X()+=xtemp; 487 aRectP3.Y()+=ytemp; 488 } else { 489 long xtemp=dy1a-dx2a; if (dx2<0) xtemp=-xtemp; 490 long ytemp=dx1a-dy2a; if (dy2<0) ytemp=-ytemp; 491 aRectP3.X()+=xtemp; 492 aRectP3.Y()+=ytemp; 493 } 494 } 495 bRect=sal_True; 496 return sal_True; 497 } 498 499 XPolygon ImpPathCreateUser::GetRectPoly() const 500 { 501 XPolygon aXP(3); 502 aXP[0]=aRectP1; aXP.SetFlags(0,XPOLY_SMOOTH); 503 aXP[1]=aRectP2; 504 if (aRectP3!=aRectP2) aXP[2]=aRectP3; 505 return aXP; 506 } 507 508 /*************************************************************************/ 509 510 class ImpPathForDragAndCreate 511 { 512 SdrPathObj& mrSdrPathObject; 513 XPolyPolygon aPathPolygon; 514 SdrObjKind meObjectKind; 515 ImpSdrPathDragData* mpSdrPathDragData; 516 bool mbCreating; 517 518 public: 519 ImpPathForDragAndCreate(SdrPathObj& rSdrPathObject); 520 ~ImpPathForDragAndCreate(); 521 522 // drag stuff 523 bool beginPathDrag( SdrDragStat& rDrag ) const; 524 bool movePathDrag( SdrDragStat& rDrag ) const; 525 bool endPathDrag( SdrDragStat& rDrag ); 526 //void cancelSpecialDrag( SdrDragStat& rDrag ) const; 527 String getSpecialDragComment(const SdrDragStat& rDrag) const; 528 basegfx::B2DPolyPolygon getSpecialDragPoly(const SdrDragStat& rDrag) const; 529 530 // create stuff 531 FASTBOOL BegCreate(SdrDragStat& rStat); 532 FASTBOOL MovCreate(SdrDragStat& rStat); 533 FASTBOOL EndCreate(SdrDragStat& rStat, SdrCreateCmd eCmd); 534 FASTBOOL BckCreate(SdrDragStat& rStat); 535 void BrkCreate(SdrDragStat& rStat); 536 Pointer GetCreatePointer() const; 537 538 // helping stuff 539 bool IsClosed(SdrObjKind eKind) const { return eKind==OBJ_POLY || eKind==OBJ_PATHPOLY || eKind==OBJ_PATHFILL || eKind==OBJ_FREEFILL || eKind==OBJ_SPLNFILL; } 540 bool IsFreeHand(SdrObjKind eKind) const { return eKind==OBJ_FREELINE || eKind==OBJ_FREEFILL; } 541 bool IsBezier(SdrObjKind eKind) const { return eKind==OBJ_PATHLINE || eKind==OBJ_PATHFILL; } 542 bool IsCreating() const { return mbCreating; } 543 544 // get the polygon 545 basegfx::B2DPolyPolygon TakeObjectPolyPolygon(const SdrDragStat& rDrag) const; 546 basegfx::B2DPolyPolygon TakeDragPolyPolygon(const SdrDragStat& rDrag) const; 547 basegfx::B2DPolyPolygon getModifiedPolyPolygon() const { return aPathPolygon.getB2DPolyPolygon(); } 548 }; 549 550 ImpPathForDragAndCreate::ImpPathForDragAndCreate(SdrPathObj& rSdrPathObject) 551 : mrSdrPathObject(rSdrPathObject), 552 aPathPolygon(rSdrPathObject.GetPathPoly()), 553 meObjectKind(mrSdrPathObject.meKind), 554 mpSdrPathDragData(0), 555 mbCreating(false) 556 { 557 } 558 559 ImpPathForDragAndCreate::~ImpPathForDragAndCreate() 560 { 561 if(mpSdrPathDragData) 562 { 563 delete mpSdrPathDragData; 564 } 565 } 566 567 bool ImpPathForDragAndCreate::beginPathDrag( SdrDragStat& rDrag ) const 568 { 569 const SdrHdl* pHdl=rDrag.GetHdl(); 570 if(!pHdl) 571 return sal_False; 572 573 sal_Bool bMultiPointDrag(sal_True); 574 575 if(aPathPolygon[(sal_uInt16)pHdl->GetPolyNum()].IsControl((sal_uInt16)pHdl->GetPointNum())) 576 bMultiPointDrag = sal_False; 577 578 if(bMultiPointDrag) 579 { 580 const SdrMarkView& rMarkView = *rDrag.GetView(); 581 const SdrHdlList& rHdlList = rMarkView.GetHdlList(); 582 const sal_uInt32 nHdlCount = rHdlList.GetHdlCount(); 583 const SdrObject* pInteractionObject(nHdlCount && rHdlList.GetHdl(0) ? rHdlList.GetHdl(0)->GetObj() : 0); 584 sal_uInt32 nSelectedPoints(0); 585 586 for(sal_uInt32 a(0); a < nHdlCount; a++) 587 { 588 SdrHdl* pTestHdl = rHdlList.GetHdl(a); 589 590 if(pTestHdl && pTestHdl->IsSelected() && pTestHdl->GetObj() == pInteractionObject) 591 { 592 nSelectedPoints++; 593 } 594 } 595 596 if(nSelectedPoints <= 1) 597 bMultiPointDrag = sal_False; 598 } 599 600 ((ImpPathForDragAndCreate*)this)->mpSdrPathDragData = new ImpSdrPathDragData(mrSdrPathObject,*pHdl,bMultiPointDrag,rDrag); 601 602 if(!mpSdrPathDragData || !mpSdrPathDragData->bValid) 603 { 604 DBG_ERROR("ImpPathForDragAndCreate::BegDrag(): ImpSdrPathDragData ist ungueltig"); 605 delete mpSdrPathDragData; 606 ((ImpPathForDragAndCreate*)this)->mpSdrPathDragData = 0; 607 return false; 608 } 609 610 return true; 611 } 612 613 bool ImpPathForDragAndCreate::movePathDrag( SdrDragStat& rDrag ) const 614 { 615 if(!mpSdrPathDragData || !mpSdrPathDragData->bValid) 616 { 617 DBG_ERROR("ImpPathForDragAndCreate::MovDrag(): ImpSdrPathDragData ist ungueltig"); 618 return false; 619 } 620 621 if(mpSdrPathDragData->IsMultiPointDrag()) 622 { 623 Point aDelta(rDrag.GetNow() - rDrag.GetStart()); 624 625 if(aDelta.X() || aDelta.Y()) 626 { 627 for(sal_uInt32 a(0); a < mpSdrPathDragData->maHandles.Count(); a++) 628 { 629 SdrHdl* pHandle = (SdrHdl*)mpSdrPathDragData->maHandles.GetObject(a); 630 const sal_uInt16 nPolyIndex((sal_uInt16)pHandle->GetPolyNum()); 631 const sal_uInt16 nPointIndex((sal_uInt16)pHandle->GetPointNum()); 632 const XPolygon& rOrig = mpSdrPathDragData->maOrig[nPolyIndex]; 633 XPolygon& rMove = mpSdrPathDragData->maMove[nPolyIndex]; 634 const sal_uInt16 nPointCount(rOrig.GetPointCount()); 635 sal_Bool bClosed(rOrig[0] == rOrig[nPointCount-1]); 636 637 // move point itself 638 rMove[nPointIndex] = rOrig[nPointIndex] + aDelta; 639 640 // when point is first and poly closed, move close point, too. 641 if(nPointCount > 0 && !nPointIndex && bClosed) 642 { 643 rMove[nPointCount - 1] = rOrig[nPointCount - 1] + aDelta; 644 645 // when moving the last point it may be necessary to move the 646 // control point in front of this one, too. 647 if(nPointCount > 1 && rOrig.IsControl(nPointCount - 2)) 648 rMove[nPointCount - 2] = rOrig[nPointCount - 2] + aDelta; 649 } 650 651 // is a control point before this? 652 if(nPointIndex > 0 && rOrig.IsControl(nPointIndex - 1)) 653 { 654 // Yes, move it, too 655 rMove[nPointIndex - 1] = rOrig[nPointIndex - 1] + aDelta; 656 } 657 658 // is a control point after this? 659 if(nPointIndex + 1 < nPointCount && rOrig.IsControl(nPointIndex + 1)) 660 { 661 // Yes, move it, too 662 rMove[nPointIndex + 1] = rOrig[nPointIndex + 1] + aDelta; 663 } 664 } 665 } 666 } 667 else 668 { 669 mpSdrPathDragData->ResetPoly(mrSdrPathObject); 670 671 // Div. Daten lokal Kopieren fuer weniger Code und schnelleren Zugriff 672 FASTBOOL bClosed =mpSdrPathDragData->bClosed ; // geschlossenes Objekt? 673 sal_uInt16 nPnt =mpSdrPathDragData->nPnt ; // Punktnummer innerhalb des obigen Polygons 674 FASTBOOL bBegPnt =mpSdrPathDragData->bBegPnt ; // Gedraggter Punkt ist der Anfangspunkt einer Polyline 675 FASTBOOL bEndPnt =mpSdrPathDragData->bEndPnt ; // Gedraggter Punkt ist der Endpunkt einer Polyline 676 sal_uInt16 nPrevPnt =mpSdrPathDragData->nPrevPnt ; // Index des vorherigen Punkts 677 sal_uInt16 nNextPnt =mpSdrPathDragData->nNextPnt ; // Index des naechsten Punkts 678 FASTBOOL bPrevIsBegPnt =mpSdrPathDragData->bPrevIsBegPnt ; // Vorheriger Punkt ist Anfangspunkt einer Polyline 679 FASTBOOL bNextIsEndPnt =mpSdrPathDragData->bNextIsEndPnt ; // Folgepunkt ist Endpunkt einer Polyline 680 sal_uInt16 nPrevPrevPnt =mpSdrPathDragData->nPrevPrevPnt ; // Index des vorvorherigen Punkts 681 sal_uInt16 nNextNextPnt =mpSdrPathDragData->nNextNextPnt ; // Index des uebernaechsten Punkts 682 FASTBOOL bControl =mpSdrPathDragData->bControl ; // Punkt ist ein Kontrollpunkt 683 //int bIsPrevControl=mpSdrPathDragData->bIsPrevControl; // Punkt ist Kontrollpunkt vor einem Stuetzpunkt 684 FASTBOOL bIsNextControl=mpSdrPathDragData->bIsNextControl; // Punkt ist Kontrollpunkt hinter einem Stuetzpunkt 685 FASTBOOL bPrevIsControl=mpSdrPathDragData->bPrevIsControl; // Falls nPnt ein StPnt: Davor ist ein Kontrollpunkt 686 FASTBOOL bNextIsControl=mpSdrPathDragData->bNextIsControl; // Falls nPnt ein StPnt: Dahinter ist ein Kontrollpunkt 687 688 // Ortho bei Linien/Polygonen = Winkel beibehalten 689 if (!bControl && rDrag.GetView()!=NULL && rDrag.GetView()->IsOrtho()) { 690 FASTBOOL bBigOrtho=rDrag.GetView()->IsBigOrtho(); 691 Point aPos(rDrag.GetNow()); // die aktuelle Position 692 Point aPnt(mpSdrPathDragData->aXP[nPnt]); // der gedraggte Punkt 693 sal_uInt16 nPnt1=0xFFFF,nPnt2=0xFFFF; // seine Nachbarpunkte 694 Point aNeuPos1,aNeuPos2; // die neuen Alternativen fuer aPos 695 FASTBOOL bPnt1=sal_False,bPnt2=sal_False; // die neuen Alternativen gueltig? 696 if (!bClosed && mpSdrPathDragData->nPntAnz>=2) { // Mind. 2 Pt bei Linien 697 if (!bBegPnt) nPnt1=nPrevPnt; 698 if (!bEndPnt) nPnt2=nNextPnt; 699 } 700 if (bClosed && mpSdrPathDragData->nPntAnz>=3) { // Mind. 3 Pt bei Polygon 701 nPnt1=nPrevPnt; 702 nPnt2=nNextPnt; 703 } 704 if (nPnt1!=0xFFFF && !bPrevIsControl) { 705 Point aPnt1=mpSdrPathDragData->aXP[nPnt1]; 706 long ndx0=aPnt.X()-aPnt1.X(); 707 long ndy0=aPnt.Y()-aPnt1.Y(); 708 FASTBOOL bHLin=ndy0==0; 709 FASTBOOL bVLin=ndx0==0; 710 if (!bHLin || !bVLin) { 711 long ndx=aPos.X()-aPnt1.X(); 712 long ndy=aPos.Y()-aPnt1.Y(); 713 bPnt1=sal_True; 714 double nXFact=0; if (!bVLin) nXFact=(double)ndx/(double)ndx0; 715 double nYFact=0; if (!bHLin) nYFact=(double)ndy/(double)ndy0; 716 FASTBOOL bHor=bHLin || (!bVLin && (nXFact>nYFact) ==bBigOrtho); 717 FASTBOOL bVer=bVLin || (!bHLin && (nXFact<=nYFact)==bBigOrtho); 718 if (bHor) ndy=long(ndy0*nXFact); 719 if (bVer) ndx=long(ndx0*nYFact); 720 aNeuPos1=aPnt1; 721 aNeuPos1.X()+=ndx; 722 aNeuPos1.Y()+=ndy; 723 } 724 } 725 if (nPnt2!=0xFFFF && !bNextIsControl) { 726 Point aPnt2=mpSdrPathDragData->aXP[nPnt2]; 727 long ndx0=aPnt.X()-aPnt2.X(); 728 long ndy0=aPnt.Y()-aPnt2.Y(); 729 FASTBOOL bHLin=ndy0==0; 730 FASTBOOL bVLin=ndx0==0; 731 if (!bHLin || !bVLin) { 732 long ndx=aPos.X()-aPnt2.X(); 733 long ndy=aPos.Y()-aPnt2.Y(); 734 bPnt2=sal_True; 735 double nXFact=0; if (!bVLin) nXFact=(double)ndx/(double)ndx0; 736 double nYFact=0; if (!bHLin) nYFact=(double)ndy/(double)ndy0; 737 FASTBOOL bHor=bHLin || (!bVLin && (nXFact>nYFact) ==bBigOrtho); 738 FASTBOOL bVer=bVLin || (!bHLin && (nXFact<=nYFact)==bBigOrtho); 739 if (bHor) ndy=long(ndy0*nXFact); 740 if (bVer) ndx=long(ndx0*nYFact); 741 aNeuPos2=aPnt2; 742 aNeuPos2.X()+=ndx; 743 aNeuPos2.Y()+=ndy; 744 } 745 } 746 if (bPnt1 && bPnt2) { // beide Alternativen vorhanden (Konkurenz) 747 BigInt nX1(aNeuPos1.X()-aPos.X()); nX1*=nX1; 748 BigInt nY1(aNeuPos1.Y()-aPos.Y()); nY1*=nY1; 749 BigInt nX2(aNeuPos2.X()-aPos.X()); nX2*=nX2; 750 BigInt nY2(aNeuPos2.Y()-aPos.Y()); nY2*=nY2; 751 nX1+=nY1; // Korrekturabstand zum Quadrat 752 nX2+=nY2; // Korrekturabstand zum Quadrat 753 // Die Alternative mit dem geringeren Korrekturbedarf gewinnt 754 if (nX1<nX2) bPnt2=sal_False; else bPnt1=sal_False; 755 } 756 if (bPnt1) rDrag.Now()=aNeuPos1; 757 if (bPnt2) rDrag.Now()=aNeuPos2; 758 } 759 rDrag.SetActionRect(Rectangle(rDrag.GetNow(),rDrag.GetNow())); 760 761 // IBM Special: Punkte eliminieren, wenn die beiden angrenzenden 762 // Linien eh' fast 180 deg sind. 763 if (!bControl && rDrag.GetView()!=NULL && rDrag.GetView()->IsEliminatePolyPoints() && 764 !bBegPnt && !bEndPnt && !bPrevIsControl && !bNextIsControl) 765 { 766 Point aPt(mpSdrPathDragData->aXP[nNextPnt]); 767 aPt-=rDrag.GetNow(); 768 long nWink1=GetAngle(aPt); 769 aPt=rDrag.GetNow(); 770 aPt-=mpSdrPathDragData->aXP[nPrevPnt]; 771 long nWink2=GetAngle(aPt); 772 long nDiff=nWink1-nWink2; 773 nDiff=Abs(nDiff); 774 mpSdrPathDragData->bEliminate=nDiff<=rDrag.GetView()->GetEliminatePolyPointLimitAngle(); 775 if (mpSdrPathDragData->bEliminate) { // Position anpassen, damit Smooth an den Enden stimmt 776 aPt=mpSdrPathDragData->aXP[nNextPnt]; 777 aPt+=mpSdrPathDragData->aXP[nPrevPnt]; 778 aPt/=2; 779 rDrag.Now()=aPt; 780 } 781 } 782 783 // Um diese Entfernung wurde insgesamt gedraggd 784 Point aDiff(rDrag.GetNow()); aDiff-=mpSdrPathDragData->aXP[nPnt]; 785 786 // Insgesamt sind 8 Faelle moeglich: 787 // X 1. Weder rechts noch links Ctrl. 788 // o--X--o 2. Rechts und links Ctrl, gedraggd wird St. 789 // o--X 3. Nur links Ctrl, gedraggd wird St. 790 // X--o 4. Nur rechts Ctrl, gedraggd wird St. 791 // x--O--o 5. Rechts und links Ctrl, gedraggd wird links. 792 // x--O 6. Nur links Ctrl, gedraggd wird links. 793 // o--O--x 7. Rechts und links Ctrl, gedraggd wird rechts. 794 // O--x 8. Nur rechts Ctrl, gedraggd wird rechts. 795 // Zusaetzlich ist zu beachten, dass das Veraendern einer Linie (keine Kurve) 796 // eine evtl. Kurve am anderen Ende der Linie bewirkt, falls dort Smooth 797 // gesetzt ist (Kontrollpunktausrichtung an Gerade). 798 799 mpSdrPathDragData->aXP[nPnt]+=aDiff; 800 801 // Nun symmetrische PlusHandles etc. checken 802 if (bControl) { // Faelle 5,6,7,8 803 sal_uInt16 nSt=nPnt; // der zugehoerige Stuetzpunkt 804 sal_uInt16 nFix=nPnt; // der gegenueberliegende Kontrollpunkt 805 if (bIsNextControl) { // Wenn der naechste ein Kontrollpunkt ist, muss der vorh. der Stuetzpunkt sein 806 nSt=nPrevPnt; 807 nFix=nPrevPrevPnt; 808 } else { 809 nSt=nNextPnt; 810 nFix=nNextNextPnt; 811 } 812 if (mpSdrPathDragData->aXP.IsSmooth(nSt)) { 813 mpSdrPathDragData->aXP.CalcSmoothJoin(nSt,nPnt,nFix); 814 } 815 } 816 817 if (!bControl) { // Faelle 1,2,3,4 wobei bei 1 nix passiert und bei 3+4 unten noch mehr folgt 818 // die beiden Kontrollpunkte mit verschieben 819 if (bPrevIsControl) mpSdrPathDragData->aXP[nPrevPnt]+=aDiff; 820 if (bNextIsControl) mpSdrPathDragData->aXP[nNextPnt]+=aDiff; 821 // Kontrollpunkt ggf. an Gerade ausrichten 822 if (mpSdrPathDragData->aXP.IsSmooth(nPnt)) { 823 if (bPrevIsControl && !bNextIsControl && !bEndPnt) { // Fall 3 824 mpSdrPathDragData->aXP.CalcSmoothJoin(nPnt,nNextPnt,nPrevPnt); 825 } 826 if (bNextIsControl && !bPrevIsControl && !bBegPnt) { // Fall 4 827 mpSdrPathDragData->aXP.CalcSmoothJoin(nPnt,nPrevPnt,nNextPnt); 828 } 829 } 830 // Und nun noch die anderen Enden der Strecken ueberpruefen (nPnt+-1). 831 // Ist dort eine Kurve (IsControl(nPnt+-2)) mit SmoothJoin (nPnt+-1), 832 // so muss der entsprechende Kontrollpunkt (nPnt+-2) angepasst werden. 833 if (!bBegPnt && !bPrevIsControl && !bPrevIsBegPnt && mpSdrPathDragData->aXP.IsSmooth(nPrevPnt)) { 834 if (mpSdrPathDragData->aXP.IsControl(nPrevPrevPnt)) { 835 mpSdrPathDragData->aXP.CalcSmoothJoin(nPrevPnt,nPnt,nPrevPrevPnt); 836 } 837 } 838 if (!bEndPnt && !bNextIsControl && !bNextIsEndPnt && mpSdrPathDragData->aXP.IsSmooth(nNextPnt)) { 839 if (mpSdrPathDragData->aXP.IsControl(nNextNextPnt)) { 840 mpSdrPathDragData->aXP.CalcSmoothJoin(nNextPnt,nPnt,nNextNextPnt); 841 } 842 } 843 } 844 } 845 846 return true; 847 } 848 849 bool ImpPathForDragAndCreate::endPathDrag(SdrDragStat& rDrag) 850 { 851 Point aLinePt1; 852 Point aLinePt2; 853 bool bLineGlueMirror(OBJ_LINE == meObjectKind); 854 if (bLineGlueMirror) { // #40549# 855 XPolygon& rXP=aPathPolygon[0]; 856 aLinePt1=rXP[0]; 857 aLinePt2=rXP[1]; 858 } 859 860 if(!mpSdrPathDragData || !mpSdrPathDragData->bValid) 861 { 862 DBG_ERROR("ImpPathForDragAndCreate::MovDrag(): ImpSdrPathDragData ist ungueltig"); 863 return false; 864 } 865 866 if(mpSdrPathDragData->IsMultiPointDrag()) 867 { 868 aPathPolygon = mpSdrPathDragData->maMove; 869 } 870 else 871 { 872 const SdrHdl* pHdl=rDrag.GetHdl(); 873 874 // Referenz auf das Polygon 875 XPolygon& rXP=aPathPolygon[(sal_uInt16)pHdl->GetPolyNum()]; 876 877 // Die 5 Punkte die sich evtl. geaendert haben 878 if (!mpSdrPathDragData->bPrevIsBegPnt) rXP[mpSdrPathDragData->nPrevPrevPnt0]=mpSdrPathDragData->aXP[mpSdrPathDragData->nPrevPrevPnt]; 879 if (!mpSdrPathDragData->bNextIsEndPnt) rXP[mpSdrPathDragData->nNextNextPnt0]=mpSdrPathDragData->aXP[mpSdrPathDragData->nNextNextPnt]; 880 if (!mpSdrPathDragData->bBegPnt) rXP[mpSdrPathDragData->nPrevPnt0] =mpSdrPathDragData->aXP[mpSdrPathDragData->nPrevPnt]; 881 if (!mpSdrPathDragData->bEndPnt) rXP[mpSdrPathDragData->nNextPnt0] =mpSdrPathDragData->aXP[mpSdrPathDragData->nNextPnt]; 882 rXP[mpSdrPathDragData->nPnt0] =mpSdrPathDragData->aXP[mpSdrPathDragData->nPnt]; 883 884 // Letzter Punkt muss beim Geschlossenen immer gleich dem Ersten sein 885 if (mpSdrPathDragData->bClosed) rXP[rXP.GetPointCount()-1]=rXP[0]; 886 887 if (mpSdrPathDragData->bEliminate) 888 { 889 basegfx::B2DPolyPolygon aTempPolyPolygon(aPathPolygon.getB2DPolyPolygon()); 890 sal_uInt32 nPoly,nPnt; 891 892 if(PolyPolygonEditor::GetRelativePolyPoint(aTempPolyPolygon, rDrag.GetHdl()->GetSourceHdlNum(), nPoly, nPnt)) 893 { 894 basegfx::B2DPolygon aCandidate(aTempPolyPolygon.getB2DPolygon(nPoly)); 895 aCandidate.remove(nPnt); 896 897 if((IsClosed(meObjectKind) && aCandidate.count() < 3L) || aCandidate.count() < 2L) 898 { 899 aTempPolyPolygon.remove(nPoly); 900 } 901 else 902 { 903 aTempPolyPolygon.setB2DPolygon(nPoly, aCandidate); 904 } 905 } 906 907 aPathPolygon = XPolyPolygon(aTempPolyPolygon); 908 } 909 910 // Winkel anpassen fuer Text an einfacher Linie 911 if (bLineGlueMirror) 912 { // #40549# 913 Point aLinePt1_(aPathPolygon[0][0]); 914 Point aLinePt2_(aPathPolygon[0][1]); 915 FASTBOOL bXMirr=(aLinePt1_.X()>aLinePt2_.X())!=(aLinePt1.X()>aLinePt2.X()); 916 FASTBOOL bYMirr=(aLinePt1_.Y()>aLinePt2_.Y())!=(aLinePt1.Y()>aLinePt2.Y()); 917 if (bXMirr || bYMirr) { 918 Point aRef1(mrSdrPathObject.GetSnapRect().Center()); 919 if (bXMirr) { 920 Point aRef2(aRef1); 921 aRef2.Y()++; 922 mrSdrPathObject.NbcMirrorGluePoints(aRef1,aRef2); 923 } 924 if (bYMirr) { 925 Point aRef2(aRef1); 926 aRef2.X()++; 927 mrSdrPathObject.NbcMirrorGluePoints(aRef1,aRef2); 928 } 929 } 930 } 931 } 932 933 delete mpSdrPathDragData; 934 mpSdrPathDragData = 0; 935 936 return true; 937 } 938 939 /*void ImpPathForDragAndCreate::cancelSpecialDrag( SdrDragStat& rDrag ) const 940 { 941 ImpSdrPathDragData* pID=(ImpSdrPathDragData*)rDrag.GetUser(); 942 if (pID!=NULL) { 943 delete pID; 944 rDrag.SetUser(NULL); 945 } 946 }*/ 947 948 String ImpPathForDragAndCreate::getSpecialDragComment(const SdrDragStat& rDrag) const 949 { 950 XubString aStr; 951 const SdrHdl* pHdl = rDrag.GetHdl(); 952 const bool bCreateComment(rDrag.GetView() && &mrSdrPathObject == rDrag.GetView()->GetCreateObj()); 953 954 if(bCreateComment && rDrag.GetUser()) 955 { 956 // #i103058# re-add old creation comment mode 957 ImpPathCreateUser* pU = (ImpPathCreateUser*)rDrag.GetUser(); 958 const SdrObjKind eKindMerk(meObjectKind); 959 mrSdrPathObject.meKind = pU->eAktKind; 960 mrSdrPathObject.ImpTakeDescriptionStr(STR_ViewCreateObj, aStr); 961 mrSdrPathObject.meKind = eKindMerk; 962 963 Point aPrev(rDrag.GetPrev()); 964 Point aNow(rDrag.GetNow()); 965 966 if(pU->bLine) 967 aNow = pU->aLineEnd; 968 969 aNow -= aPrev; 970 aStr.AppendAscii(" ("); 971 972 XubString aMetr; 973 974 if(pU->bCircle) 975 { 976 mrSdrPathObject.GetModel()->TakeWinkStr(Abs(pU->nCircRelWink), aMetr); 977 aStr += aMetr; 978 aStr.AppendAscii(" r="); 979 mrSdrPathObject.GetModel()->TakeMetricStr(pU->nCircRadius, aMetr, sal_True); 980 aStr += aMetr; 981 } 982 983 aStr.AppendAscii("dx="); 984 mrSdrPathObject.GetModel()->TakeMetricStr(aNow.X(), aMetr, sal_True); 985 aStr += aMetr; 986 987 aStr.AppendAscii(" dy="); 988 mrSdrPathObject.GetModel()->TakeMetricStr(aNow.Y(), aMetr, sal_True); 989 aStr += aMetr; 990 991 if(!IsFreeHand(meObjectKind)) 992 { 993 sal_Int32 nLen(GetLen(aNow)); 994 aStr.AppendAscii(" l="); 995 mrSdrPathObject.GetModel()->TakeMetricStr(nLen, aMetr, sal_True); 996 aStr += aMetr; 997 998 sal_Int32 nWink(GetAngle(aNow)); 999 aStr += sal_Unicode(' '); 1000 mrSdrPathObject.GetModel()->TakeWinkStr(nWink, aMetr); 1001 aStr += aMetr; 1002 } 1003 1004 aStr += sal_Unicode(')'); 1005 } 1006 else if(!mrSdrPathObject.GetModel() || !pHdl) 1007 { 1008 // #i103058# fallback when no model and/or Handle, both needed 1009 // for else-path 1010 mrSdrPathObject.ImpTakeDescriptionStr(STR_DragPathObj, aStr); 1011 } 1012 else 1013 { 1014 // #i103058# standard for modification; model and handle needed 1015 ImpSdrPathDragData* pDragData = mpSdrPathDragData; 1016 1017 if(!pDragData) 1018 { 1019 // getSpecialDragComment is also used from create, so fallback to GetUser() 1020 // when mpSdrPathDragData is not set 1021 pDragData = (ImpSdrPathDragData*)rDrag.GetUser(); 1022 } 1023 1024 if(!pDragData) 1025 { 1026 DBG_ERROR("ImpPathForDragAndCreate::MovDrag(): ImpSdrPathDragData ist ungueltig"); 1027 return String(); 1028 } 1029 1030 if(!pDragData->IsMultiPointDrag() && pDragData->bEliminate) 1031 { 1032 // Punkt von ... 1033 mrSdrPathObject.ImpTakeDescriptionStr(STR_ViewMarkedPoint, aStr); 1034 1035 // %O loeschen 1036 XubString aStr2(ImpGetResStr(STR_EditDelete)); 1037 1038 // UNICODE: Punkt von ... loeschen 1039 aStr2.SearchAndReplaceAscii("%1", aStr); 1040 1041 return aStr2; 1042 } 1043 1044 // dx=0.00 dy=0.00 // Beide Seiten Bezier 1045 // dx=0.00 dy=0.00 l=0.00 0.00� // Anfang oder Ende oder eine Seite Bezier bzw. Hebel 1046 // dx=0.00 dy=0.00 l=0.00 0.00� / l=0.00 0.00� // Mittendrin 1047 XubString aMetr; 1048 Point aBeg(rDrag.GetStart()); 1049 Point aNow(rDrag.GetNow()); 1050 1051 aStr = String(); 1052 aStr.AppendAscii("dx="); 1053 mrSdrPathObject.GetModel()->TakeMetricStr(aNow.X() - aBeg.X(), aMetr, sal_True); 1054 aStr += aMetr; 1055 1056 aStr.AppendAscii(" dy="); 1057 mrSdrPathObject.GetModel()->TakeMetricStr(aNow.Y() - aBeg.Y(), aMetr, sal_True); 1058 aStr += aMetr; 1059 1060 if(!pDragData->IsMultiPointDrag()) 1061 { 1062 sal_uInt16 nPntNum((sal_uInt16)pHdl->GetPointNum()); 1063 const XPolygon& rXPoly = aPathPolygon[(sal_uInt16)rDrag.GetHdl()->GetPolyNum()]; 1064 sal_uInt16 nPntAnz((sal_uInt16)rXPoly.GetPointCount()); 1065 sal_Bool bClose(IsClosed(meObjectKind)); 1066 1067 if(bClose) 1068 nPntAnz--; 1069 1070 if(pHdl->IsPlusHdl()) 1071 { 1072 // Hebel 1073 sal_uInt16 nRef(nPntNum); 1074 1075 if(rXPoly.IsControl(nPntNum + 1)) 1076 nRef--; 1077 else 1078 nRef++; 1079 1080 aNow -= rXPoly[nRef]; 1081 1082 sal_Int32 nLen(GetLen(aNow)); 1083 aStr.AppendAscii(" l="); 1084 mrSdrPathObject.GetModel()->TakeMetricStr(nLen, aMetr, sal_True); 1085 aStr += aMetr; 1086 1087 sal_Int32 nWink(GetAngle(aNow)); 1088 aStr += sal_Unicode(' '); 1089 mrSdrPathObject.GetModel()->TakeWinkStr(nWink, aMetr); 1090 aStr += aMetr; 1091 } 1092 else if(nPntAnz > 1) 1093 { 1094 sal_uInt16 nPntMax(nPntAnz - 1); 1095 Point aPt1,aPt2; 1096 sal_Bool bIsClosed(IsClosed(meObjectKind)); 1097 sal_Bool bPt1(nPntNum > 0); 1098 sal_Bool bPt2(nPntNum < nPntMax); 1099 1100 if(bIsClosed && nPntAnz > 2) 1101 { 1102 bPt1 = sal_True; 1103 bPt2 = sal_True; 1104 } 1105 1106 sal_uInt16 nPt1,nPt2; 1107 1108 if(nPntNum > 0) 1109 nPt1 = nPntNum - 1; 1110 else 1111 nPt1 = nPntMax; 1112 1113 if(nPntNum < nPntMax) 1114 nPt2 = nPntNum + 1; 1115 else 1116 nPt2 = 0; 1117 1118 if(bPt1 && rXPoly.IsControl(nPt1)) 1119 bPt1 = sal_False; // Keine Anzeige 1120 1121 if(bPt2 && rXPoly.IsControl(nPt2)) 1122 bPt2 = sal_False; // von Bezierdaten 1123 1124 if(bPt1) 1125 { 1126 Point aPt(aNow); 1127 aPt -= rXPoly[nPt1]; 1128 1129 sal_Int32 nLen(GetLen(aPt)); 1130 aStr.AppendAscii(" l="); 1131 mrSdrPathObject.GetModel()->TakeMetricStr(nLen, aMetr, sal_True); 1132 aStr += aMetr; 1133 1134 sal_Int32 nWink(GetAngle(aPt)); 1135 aStr += sal_Unicode(' '); 1136 mrSdrPathObject.GetModel()->TakeWinkStr(nWink, aMetr); 1137 aStr += aMetr; 1138 } 1139 1140 if(bPt2) 1141 { 1142 if(bPt1) 1143 aStr.AppendAscii(" / "); 1144 else 1145 aStr.AppendAscii(" "); 1146 1147 Point aPt(aNow); 1148 aPt -= rXPoly[nPt2]; 1149 1150 sal_Int32 nLen(GetLen(aPt)); 1151 aStr.AppendAscii("l="); 1152 mrSdrPathObject.GetModel()->TakeMetricStr(nLen, aMetr, sal_True); 1153 aStr += aMetr; 1154 1155 sal_Int32 nWink(GetAngle(aPt)); 1156 aStr += sal_Unicode(' '); 1157 mrSdrPathObject.GetModel()->TakeWinkStr(nWink, aMetr); 1158 aStr += aMetr; 1159 } 1160 } 1161 } 1162 } 1163 1164 return aStr; 1165 } 1166 1167 basegfx::B2DPolyPolygon ImpPathForDragAndCreate::getSpecialDragPoly(const SdrDragStat& rDrag) const 1168 { 1169 if(!mpSdrPathDragData || !mpSdrPathDragData->bValid) 1170 { 1171 DBG_ERROR("ImpPathForDragAndCreate::MovDrag(): ImpSdrPathDragData ist ungueltig"); 1172 return basegfx::B2DPolyPolygon(); 1173 } 1174 1175 XPolyPolygon aRetval; 1176 1177 if(mpSdrPathDragData->IsMultiPointDrag()) 1178 { 1179 aRetval.Insert(mpSdrPathDragData->maMove); 1180 } 1181 else 1182 { 1183 const XPolygon& rXP=aPathPolygon[(sal_uInt16)rDrag.GetHdl()->GetPolyNum()]; 1184 if (rXP.GetPointCount()<=2) { //|| rXPoly.GetFlags(1)==XPOLY_CONTROL && rXPoly.GetPointCount()<=4 1185 XPolygon aXPoly(rXP); 1186 aXPoly[(sal_uInt16)rDrag.GetHdl()->GetPointNum()]=rDrag.GetNow(); 1187 aRetval.Insert(aXPoly); 1188 return aRetval.getB2DPolyPolygon(); 1189 } 1190 // Div. Daten lokal Kopieren fuer weniger Code und schnelleren Zugriff 1191 FASTBOOL bClosed =mpSdrPathDragData->bClosed ; // geschlossenes Objekt? 1192 sal_uInt16 nPntAnz =mpSdrPathDragData->nPntAnz ; // Punktanzahl 1193 sal_uInt16 nPnt =mpSdrPathDragData->nPnt ; // Punktnummer innerhalb des Polygons 1194 FASTBOOL bBegPnt =mpSdrPathDragData->bBegPnt ; // Gedraggter Punkt ist der Anfangspunkt einer Polyline 1195 FASTBOOL bEndPnt =mpSdrPathDragData->bEndPnt ; // Gedraggter Punkt ist der Endpunkt einer Polyline 1196 sal_uInt16 nPrevPnt =mpSdrPathDragData->nPrevPnt ; // Index des vorherigen Punkts 1197 sal_uInt16 nNextPnt =mpSdrPathDragData->nNextPnt ; // Index des naechsten Punkts 1198 FASTBOOL bPrevIsBegPnt =mpSdrPathDragData->bPrevIsBegPnt ; // Vorheriger Punkt ist Anfangspunkt einer Polyline 1199 FASTBOOL bNextIsEndPnt =mpSdrPathDragData->bNextIsEndPnt ; // Folgepunkt ist Endpunkt einer Polyline 1200 sal_uInt16 nPrevPrevPnt =mpSdrPathDragData->nPrevPrevPnt ; // Index des vorvorherigen Punkts 1201 sal_uInt16 nNextNextPnt =mpSdrPathDragData->nNextNextPnt ; // Index des uebernaechsten Punkts 1202 FASTBOOL bControl =mpSdrPathDragData->bControl ; // Punkt ist ein Kontrollpunkt 1203 //int bIsPrevControl=mpSdrPathDragData->bIsPrevControl; // Punkt ist Kontrollpunkt vor einem Stuetzpunkt 1204 FASTBOOL bIsNextControl=mpSdrPathDragData->bIsNextControl; // Punkt ist Kontrollpunkt hinter einem Stuetzpunkt 1205 FASTBOOL bPrevIsControl=mpSdrPathDragData->bPrevIsControl; // Falls nPnt ein StPnt: Davor ist ein Kontrollpunkt 1206 FASTBOOL bNextIsControl=mpSdrPathDragData->bNextIsControl; // Falls nPnt ein StPnt: Dahinter ist ein Kontrollpunkt 1207 XPolygon aXPoly(mpSdrPathDragData->aXP); 1208 XPolygon aLine1(2); 1209 XPolygon aLine2(2); 1210 XPolygon aLine3(2); 1211 XPolygon aLine4(2); 1212 if (bControl) { 1213 aLine1[1]=mpSdrPathDragData->aXP[nPnt]; 1214 if (bIsNextControl) { // bin ich Kontrollpunkt hinter der Stuetzstelle? 1215 aLine1[0]=mpSdrPathDragData->aXP[nPrevPnt]; 1216 aLine2[0]=mpSdrPathDragData->aXP[nNextNextPnt]; 1217 aLine2[1]=mpSdrPathDragData->aXP[nNextPnt]; 1218 if (mpSdrPathDragData->aXP.IsSmooth(nPrevPnt) && !bPrevIsBegPnt && mpSdrPathDragData->aXP.IsControl(nPrevPrevPnt)) { 1219 aXPoly.Insert(0,rXP[mpSdrPathDragData->nPrevPrevPnt0-1],XPOLY_CONTROL); 1220 aXPoly.Insert(0,rXP[mpSdrPathDragData->nPrevPrevPnt0-2],XPOLY_NORMAL); 1221 // Hebellienien fuer das gegenueberliegende Kurvensegment 1222 aLine3[0]=mpSdrPathDragData->aXP[nPrevPnt]; 1223 aLine3[1]=mpSdrPathDragData->aXP[nPrevPrevPnt]; 1224 aLine4[0]=rXP[mpSdrPathDragData->nPrevPrevPnt0-2]; 1225 aLine4[1]=rXP[mpSdrPathDragData->nPrevPrevPnt0-1]; 1226 } else { 1227 aXPoly.Remove(0,1); 1228 } 1229 } else { // ansonsten bin ich Kontrollpunkt vor der Stuetzstelle 1230 aLine1[0]=mpSdrPathDragData->aXP[nNextPnt]; 1231 aLine2[0]=mpSdrPathDragData->aXP[nPrevPrevPnt]; 1232 aLine2[1]=mpSdrPathDragData->aXP[nPrevPnt]; 1233 if (mpSdrPathDragData->aXP.IsSmooth(nNextPnt) && !bNextIsEndPnt && mpSdrPathDragData->aXP.IsControl(nNextNextPnt)) { 1234 aXPoly.Insert(XPOLY_APPEND,rXP[mpSdrPathDragData->nNextNextPnt0+1],XPOLY_CONTROL); 1235 aXPoly.Insert(XPOLY_APPEND,rXP[mpSdrPathDragData->nNextNextPnt0+2],XPOLY_NORMAL); 1236 // Hebellinien fuer das gegenueberliegende Kurvensegment 1237 aLine3[0]=mpSdrPathDragData->aXP[nNextPnt]; 1238 aLine3[1]=mpSdrPathDragData->aXP[nNextNextPnt]; 1239 aLine4[0]=rXP[mpSdrPathDragData->nNextNextPnt0+2]; 1240 aLine4[1]=rXP[mpSdrPathDragData->nNextNextPnt0+1]; 1241 } else { 1242 aXPoly.Remove(aXPoly.GetPointCount()-1,1); 1243 } 1244 } 1245 } else { // ansonsten kein Kontrollpunkt 1246 if (mpSdrPathDragData->bEliminate) { 1247 aXPoly.Remove(2,1); 1248 } 1249 if (bPrevIsControl) aXPoly.Insert(0,rXP[mpSdrPathDragData->nPrevPrevPnt0-1],XPOLY_NORMAL); 1250 else if (!bBegPnt && !bPrevIsBegPnt && mpSdrPathDragData->aXP.IsControl(nPrevPrevPnt)) { 1251 aXPoly.Insert(0,rXP[mpSdrPathDragData->nPrevPrevPnt0-1],XPOLY_CONTROL); 1252 aXPoly.Insert(0,rXP[mpSdrPathDragData->nPrevPrevPnt0-2],XPOLY_NORMAL); 1253 } else { 1254 aXPoly.Remove(0,1); 1255 if (bBegPnt) aXPoly.Remove(0,1); 1256 } 1257 if (bNextIsControl) aXPoly.Insert(XPOLY_APPEND,rXP[mpSdrPathDragData->nNextNextPnt0+1],XPOLY_NORMAL); 1258 else if (!bEndPnt && !bNextIsEndPnt && mpSdrPathDragData->aXP.IsControl(nNextNextPnt)) { 1259 aXPoly.Insert(XPOLY_APPEND,rXP[mpSdrPathDragData->nNextNextPnt0+1],XPOLY_CONTROL); 1260 aXPoly.Insert(XPOLY_APPEND,rXP[mpSdrPathDragData->nNextNextPnt0+2],XPOLY_NORMAL); 1261 } else { 1262 aXPoly.Remove(aXPoly.GetPointCount()-1,1); 1263 if (bEndPnt) aXPoly.Remove(aXPoly.GetPointCount()-1,1); 1264 } 1265 if (bClosed) { // "Birnenproblem": 2 Linien, 1 Kurve, alles Smooth, Punkt zw. beiden Linien wird gedraggt 1266 if (aXPoly.GetPointCount()>nPntAnz && aXPoly.IsControl(1)) { 1267 sal_uInt16 a=aXPoly.GetPointCount(); 1268 aXPoly[a-2]=aXPoly[2]; aXPoly.SetFlags(a-2,aXPoly.GetFlags(2)); 1269 aXPoly[a-1]=aXPoly[3]; aXPoly.SetFlags(a-1,aXPoly.GetFlags(3)); 1270 aXPoly.Remove(0,3); 1271 } 1272 } 1273 } 1274 aRetval.Insert(aXPoly); 1275 if (aLine1.GetPointCount()>1) aRetval.Insert(aLine1); 1276 if (aLine2.GetPointCount()>1) aRetval.Insert(aLine2); 1277 if (aLine3.GetPointCount()>1) aRetval.Insert(aLine3); 1278 if (aLine4.GetPointCount()>1) aRetval.Insert(aLine4); 1279 } 1280 1281 return aRetval.getB2DPolyPolygon(); 1282 } 1283 1284 FASTBOOL ImpPathForDragAndCreate::BegCreate(SdrDragStat& rStat) 1285 { 1286 bool bFreeHand(IsFreeHand(meObjectKind)); 1287 rStat.SetNoSnap(bFreeHand); 1288 rStat.SetOrtho8Possible(); 1289 aPathPolygon.Clear(); 1290 mbCreating=sal_True; 1291 FASTBOOL bMakeStartPoint=sal_True; 1292 SdrView* pView=rStat.GetView(); 1293 if (pView!=NULL && pView->IsUseIncompatiblePathCreateInterface() && 1294 (meObjectKind==OBJ_POLY || meObjectKind==OBJ_PLIN || meObjectKind==OBJ_PATHLINE || meObjectKind==OBJ_PATHFILL)) { 1295 bMakeStartPoint=sal_False; 1296 } 1297 aPathPolygon.Insert(XPolygon()); 1298 aPathPolygon[0][0]=rStat.GetStart(); 1299 if (bMakeStartPoint) { 1300 aPathPolygon[0][1]=rStat.GetNow(); 1301 } 1302 ImpPathCreateUser* pU=new ImpPathCreateUser; 1303 pU->eStartKind=meObjectKind; 1304 pU->eAktKind=meObjectKind; 1305 rStat.SetUser(pU); 1306 return sal_True; 1307 } 1308 1309 FASTBOOL ImpPathForDragAndCreate::MovCreate(SdrDragStat& rStat) 1310 { 1311 ImpPathCreateUser* pU=(ImpPathCreateUser*)rStat.GetUser(); 1312 SdrView* pView=rStat.GetView(); 1313 XPolygon& rXPoly=aPathPolygon[aPathPolygon.Count()-1]; 1314 if (pView!=NULL && pView->IsCreateMode()) { 1315 // ggf. auf anderes CreateTool umschalten 1316 sal_uInt16 nIdent; 1317 sal_uInt32 nInvent; 1318 pView->TakeCurrentObj(nIdent,nInvent); 1319 if (nInvent==SdrInventor && pU->eAktKind!=(SdrObjKind)nIdent) { 1320 SdrObjKind eNewKind=(SdrObjKind)nIdent; 1321 switch (eNewKind) { 1322 case OBJ_CARC: case OBJ_CIRC: case OBJ_CCUT: case OBJ_SECT: eNewKind=OBJ_CARC; 1323 case OBJ_RECT: 1324 case OBJ_LINE: case OBJ_PLIN: case OBJ_POLY: 1325 case OBJ_PATHLINE: case OBJ_PATHFILL: 1326 case OBJ_FREELINE: case OBJ_FREEFILL: 1327 case OBJ_SPLNLINE: case OBJ_SPLNFILL: { 1328 pU->eAktKind=eNewKind; 1329 pU->bMixedCreate=sal_True; 1330 pU->nBezierStartPoint=rXPoly.GetPointCount(); 1331 if (pU->nBezierStartPoint>0) pU->nBezierStartPoint--; 1332 } break; 1333 default: break; 1334 } // switch 1335 } 1336 } 1337 sal_uInt16 nActPoint=rXPoly.GetPointCount(); 1338 if (aPathPolygon.Count()>1 && rStat.IsMouseDown() && nActPoint<2) { 1339 rXPoly[0]=rStat.GetPos0(); 1340 rXPoly[1]=rStat.GetNow(); 1341 nActPoint=2; 1342 } 1343 if (nActPoint==0) { 1344 rXPoly[0]=rStat.GetPos0(); 1345 } else nActPoint--; 1346 FASTBOOL bFreeHand=IsFreeHand(pU->eAktKind); 1347 rStat.SetNoSnap(bFreeHand /*|| (pU->bMixed && pU->eAktKind==OBJ_LINE)*/); 1348 rStat.SetOrtho8Possible(pU->eAktKind!=OBJ_CARC && pU->eAktKind!=OBJ_RECT && (!pU->bMixedCreate || pU->eAktKind!=OBJ_LINE)); 1349 Point aActMerk(rXPoly[nActPoint]); 1350 rXPoly[nActPoint]=rStat.Now(); 1351 if (!pU->bMixedCreate && pU->eStartKind==OBJ_LINE && rXPoly.GetPointCount()>=1) { 1352 Point aPt(rStat.Start()); 1353 if (pView!=NULL && pView->IsCreate1stPointAsCenter()) { 1354 aPt+=aPt; 1355 aPt-=rStat.Now(); 1356 } 1357 rXPoly[0]=aPt; 1358 } 1359 OutputDevice* pOut=pView==NULL ? NULL : pView->GetFirstOutputDevice(); // GetWin(0); 1360 if (bFreeHand) { 1361 if (pU->nBezierStartPoint>nActPoint) pU->nBezierStartPoint=nActPoint; 1362 if (rStat.IsMouseDown() && nActPoint>0) { 1363 // keine aufeinanderfolgenden Punkte an zu Nahe gelegenen Positionen zulassen 1364 long nMinDist=1; 1365 if (pView!=NULL) nMinDist=pView->GetFreeHandMinDistPix(); 1366 if (pOut!=NULL) nMinDist=pOut->PixelToLogic(Size(nMinDist,0)).Width(); 1367 if (nMinDist<1) nMinDist=1; 1368 1369 Point aPt0(rXPoly[nActPoint-1]); 1370 Point aPt1(rStat.Now()); 1371 long dx=aPt0.X()-aPt1.X(); if (dx<0) dx=-dx; 1372 long dy=aPt0.Y()-aPt1.Y(); if (dy<0) dy=-dy; 1373 if (dx<nMinDist && dy<nMinDist) return sal_False; 1374 1375 // folgendes ist aus EndCreate kopiert (nur kleine Modifikationen) 1376 // und sollte dann mal in eine Methode zusammengefasst werden: 1377 1378 if (nActPoint-pU->nBezierStartPoint>=3 && ((nActPoint-pU->nBezierStartPoint)%3)==0) { 1379 rXPoly.PointsToBezier(nActPoint-3); 1380 rXPoly.SetFlags(nActPoint-1,XPOLY_CONTROL); 1381 rXPoly.SetFlags(nActPoint-2,XPOLY_CONTROL); 1382 1383 if (nActPoint>=6 && rXPoly.IsControl(nActPoint-4)) { 1384 rXPoly.CalcTangent(nActPoint-3,nActPoint-4,nActPoint-2); 1385 rXPoly.SetFlags(nActPoint-3,XPOLY_SMOOTH); 1386 } 1387 } 1388 rXPoly[nActPoint+1]=rStat.Now(); 1389 rStat.NextPoint(); 1390 } else { 1391 pU->nBezierStartPoint=nActPoint; 1392 } 1393 } 1394 1395 pU->ResetFormFlags(); 1396 if (IsBezier(pU->eAktKind)) { 1397 if (nActPoint>=2) { 1398 pU->CalcBezier(rXPoly[nActPoint-1],rXPoly[nActPoint],rXPoly[nActPoint-1]-rXPoly[nActPoint-2],rStat.IsMouseDown()); 1399 } else if (pU->bBezHasCtrl0) { 1400 pU->CalcBezier(rXPoly[nActPoint-1],rXPoly[nActPoint],pU->aBezControl0-rXPoly[nActPoint-1],rStat.IsMouseDown()); 1401 } 1402 } 1403 if (pU->eAktKind==OBJ_CARC && nActPoint>=2) { 1404 pU->CalcCircle(rXPoly[nActPoint-1],rXPoly[nActPoint],rXPoly[nActPoint-1]-rXPoly[nActPoint-2],pView); 1405 } 1406 if (pU->eAktKind==OBJ_LINE && nActPoint>=2) { 1407 pU->CalcLine(rXPoly[nActPoint-1],rXPoly[nActPoint],rXPoly[nActPoint-1]-rXPoly[nActPoint-2],pView); 1408 } 1409 if (pU->eAktKind==OBJ_RECT && nActPoint>=2) { 1410 pU->CalcRect(rXPoly[nActPoint-1],rXPoly[nActPoint],rXPoly[nActPoint-1]-rXPoly[nActPoint-2],pView); 1411 } 1412 1413 return sal_True; 1414 } 1415 1416 FASTBOOL ImpPathForDragAndCreate::EndCreate(SdrDragStat& rStat, SdrCreateCmd eCmd) 1417 { 1418 ImpPathCreateUser* pU=(ImpPathCreateUser*)rStat.GetUser(); 1419 FASTBOOL bRet=sal_False; 1420 SdrView* pView=rStat.GetView(); 1421 FASTBOOL bIncomp=pView!=NULL && pView->IsUseIncompatiblePathCreateInterface(); 1422 XPolygon& rXPoly=aPathPolygon[aPathPolygon.Count()-1]; 1423 sal_uInt16 nActPoint=rXPoly.GetPointCount()-1; 1424 Point aAktMerk(rXPoly[nActPoint]); 1425 rXPoly[nActPoint]=rStat.Now(); 1426 if (!pU->bMixedCreate && pU->eStartKind==OBJ_LINE) { 1427 if (rStat.GetPointAnz()>=2) eCmd=SDRCREATE_FORCEEND; 1428 bRet=eCmd==SDRCREATE_FORCEEND; 1429 if (bRet) { 1430 mbCreating=sal_False; 1431 delete pU; 1432 rStat.SetUser(NULL); 1433 } 1434 return bRet; 1435 } 1436 1437 if (!pU->bMixedCreate && IsFreeHand(pU->eStartKind)) { 1438 if (rStat.GetPointAnz()>=2) eCmd=SDRCREATE_FORCEEND; 1439 bRet=eCmd==SDRCREATE_FORCEEND; 1440 if (bRet) { 1441 mbCreating=sal_False; 1442 delete pU; 1443 rStat.SetUser(NULL); 1444 } 1445 return bRet; 1446 } 1447 if (eCmd==SDRCREATE_NEXTPOINT || eCmd==SDRCREATE_NEXTOBJECT) { 1448 // keine aufeinanderfolgenden Punkte an identischer Position zulassen 1449 if (nActPoint==0 || rStat.Now()!=rXPoly[nActPoint-1]) { 1450 if (bIncomp) { 1451 if (pU->nBezierStartPoint>nActPoint) pU->nBezierStartPoint=nActPoint; 1452 if (IsBezier(pU->eAktKind) && nActPoint-pU->nBezierStartPoint>=3 && ((nActPoint-pU->nBezierStartPoint)%3)==0) { 1453 rXPoly.PointsToBezier(nActPoint-3); 1454 rXPoly.SetFlags(nActPoint-1,XPOLY_CONTROL); 1455 rXPoly.SetFlags(nActPoint-2,XPOLY_CONTROL); 1456 1457 if (nActPoint>=6 && rXPoly.IsControl(nActPoint-4)) { 1458 rXPoly.CalcTangent(nActPoint-3,nActPoint-4,nActPoint-2); 1459 rXPoly.SetFlags(nActPoint-3,XPOLY_SMOOTH); 1460 } 1461 } 1462 } else { 1463 if (nActPoint==1 && IsBezier(pU->eAktKind) && !pU->bBezHasCtrl0) { 1464 pU->aBezControl0=rStat.GetNow();; 1465 pU->bBezHasCtrl0=sal_True; 1466 nActPoint--; 1467 } 1468 if (pU->IsFormFlag()) { 1469 sal_uInt16 nPtAnz0=rXPoly.GetPointCount(); 1470 rXPoly.Remove(nActPoint-1,2); // die letzten beiden Punkte entfernen und durch die Form ersetzen 1471 rXPoly.Insert(XPOLY_APPEND,pU->GetFormPoly()); 1472 sal_uInt16 nPtAnz1=rXPoly.GetPointCount(); 1473 for (sal_uInt16 i=nPtAnz0+1; i<nPtAnz1-1; i++) { // Damit BckAction richtig funktioniert 1474 if (!rXPoly.IsControl(i)) rStat.NextPoint(); 1475 } 1476 nActPoint=rXPoly.GetPointCount()-1; 1477 } 1478 } 1479 nActPoint++; 1480 rXPoly[nActPoint]=rStat.GetNow(); 1481 } 1482 if (eCmd==SDRCREATE_NEXTOBJECT) { 1483 if (rXPoly.GetPointCount()>=2) { 1484 pU->bBezHasCtrl0=sal_False; 1485 // nur einzelnes Polygon kann offen sein, deshalb schliessen 1486 rXPoly[nActPoint]=rXPoly[0]; 1487 XPolygon aXP; 1488 aXP[0]=rStat.GetNow(); 1489 aPathPolygon.Insert(aXP); 1490 } 1491 } 1492 } 1493 1494 sal_uInt16 nPolyAnz=aPathPolygon.Count(); 1495 if (nPolyAnz!=0) { 1496 // den letzten Punkt ggf. wieder loeschen 1497 if (eCmd==SDRCREATE_FORCEEND) { 1498 XPolygon& rXP=aPathPolygon[nPolyAnz-1]; 1499 sal_uInt16 nPtAnz=rXP.GetPointCount(); 1500 if (nPtAnz>=2) { 1501 if (!rXP.IsControl(nPtAnz-2)) { 1502 if (rXP[nPtAnz-1]==rXP[nPtAnz-2]) { 1503 rXP.Remove(nPtAnz-1,1); 1504 } 1505 } else { 1506 if (rXP[nPtAnz-3]==rXP[nPtAnz-2]) { 1507 rXP.Remove(nPtAnz-3,3); 1508 } 1509 } 1510 } 1511 } 1512 for (sal_uInt16 nPolyNum=nPolyAnz; nPolyNum>0;) { 1513 nPolyNum--; 1514 XPolygon& rXP=aPathPolygon[nPolyNum]; 1515 sal_uInt16 nPtAnz=rXP.GetPointCount(); 1516 // Polygone mit zu wenig Punkten werden geloescht 1517 if (nPolyNum<nPolyAnz-1 || eCmd==SDRCREATE_FORCEEND) { 1518 if (nPtAnz<2) aPathPolygon.Remove(nPolyNum); 1519 } 1520 } 1521 } 1522 pU->ResetFormFlags(); 1523 bRet=eCmd==SDRCREATE_FORCEEND; 1524 if (bRet) { 1525 mbCreating=sal_False; 1526 delete pU; 1527 rStat.SetUser(NULL); 1528 } 1529 return bRet; 1530 } 1531 1532 FASTBOOL ImpPathForDragAndCreate::BckCreate(SdrDragStat& rStat) 1533 { 1534 ImpPathCreateUser* pU=(ImpPathCreateUser*)rStat.GetUser(); 1535 if (aPathPolygon.Count()>0) { 1536 XPolygon& rXPoly=aPathPolygon[aPathPolygon.Count()-1]; 1537 sal_uInt16 nActPoint=rXPoly.GetPointCount(); 1538 if (nActPoint>0) { 1539 nActPoint--; 1540 // Das letzte Stueck einer Bezierkurve wird erstmal zu 'ner Linie 1541 rXPoly.Remove(nActPoint,1); 1542 if (nActPoint>=3 && rXPoly.IsControl(nActPoint-1)) { 1543 // Beziersegment am Ende sollte zwar nicht vorkommen, aber falls doch ... 1544 rXPoly.Remove(nActPoint-1,1); 1545 if (rXPoly.IsControl(nActPoint-2)) rXPoly.Remove(nActPoint-2,1); 1546 } 1547 } 1548 nActPoint=rXPoly.GetPointCount(); 1549 if (nActPoint>=4) { // Kein Beziersegment am Ende 1550 nActPoint--; 1551 if (rXPoly.IsControl(nActPoint-1)) { 1552 rXPoly.Remove(nActPoint-1,1); 1553 if (rXPoly.IsControl(nActPoint-2)) rXPoly.Remove(nActPoint-2,1); 1554 } 1555 } 1556 if (rXPoly.GetPointCount()<2) { 1557 aPathPolygon.Remove(aPathPolygon.Count()-1); 1558 } 1559 if (aPathPolygon.Count()>0) { 1560 XPolygon& rLocalXPoly=aPathPolygon[aPathPolygon.Count()-1]; 1561 sal_uInt16 nLocalActPoint=rLocalXPoly.GetPointCount(); 1562 if (nLocalActPoint>0) { 1563 nLocalActPoint--; 1564 rLocalXPoly[nLocalActPoint]=rStat.Now(); 1565 } 1566 } 1567 } 1568 pU->ResetFormFlags(); 1569 return aPathPolygon.Count()!=0; 1570 } 1571 1572 void ImpPathForDragAndCreate::BrkCreate(SdrDragStat& rStat) 1573 { 1574 ImpPathCreateUser* pU=(ImpPathCreateUser*)rStat.GetUser(); 1575 aPathPolygon.Clear(); 1576 mbCreating=sal_False; 1577 delete pU; 1578 rStat.SetUser(NULL); 1579 } 1580 1581 basegfx::B2DPolyPolygon ImpPathForDragAndCreate::TakeObjectPolyPolygon(const SdrDragStat& rDrag) const 1582 { 1583 basegfx::B2DPolyPolygon aRetval(aPathPolygon.getB2DPolyPolygon()); 1584 SdrView* pView = rDrag.GetView(); 1585 1586 if(pView && pView->IsUseIncompatiblePathCreateInterface()) 1587 return aRetval; 1588 1589 ImpPathCreateUser* pU = (ImpPathCreateUser*)rDrag.GetUser(); 1590 basegfx::B2DPolygon aNewPolygon(aRetval.count() ? aRetval.getB2DPolygon(aRetval.count() - 1L) : basegfx::B2DPolygon()); 1591 1592 if(pU->IsFormFlag() && aNewPolygon.count() > 1L) 1593 { 1594 // remove last segment and replace with current 1595 // do not forget to rescue the previous control point which will be lost when 1596 // the point it's associated with is removed 1597 const sal_uInt32 nChangeIndex(aNewPolygon.count() - 2); 1598 const basegfx::B2DPoint aSavedPrevCtrlPoint(aNewPolygon.getPrevControlPoint(nChangeIndex)); 1599 1600 aNewPolygon.remove(nChangeIndex, 2L); 1601 aNewPolygon.append(pU->GetFormPoly().getB2DPolygon()); 1602 1603 if(nChangeIndex < aNewPolygon.count()) 1604 { 1605 // if really something was added, set the saved prev control point at the 1606 // point where it belongs 1607 aNewPolygon.setPrevControlPoint(nChangeIndex, aSavedPrevCtrlPoint); 1608 } 1609 } 1610 1611 if(aRetval.count()) 1612 { 1613 aRetval.setB2DPolygon(aRetval.count() - 1L, aNewPolygon); 1614 } 1615 else 1616 { 1617 aRetval.append(aNewPolygon); 1618 } 1619 1620 return aRetval; 1621 } 1622 1623 basegfx::B2DPolyPolygon ImpPathForDragAndCreate::TakeDragPolyPolygon(const SdrDragStat& rDrag) const 1624 { 1625 basegfx::B2DPolyPolygon aRetval; 1626 SdrView* pView = rDrag.GetView(); 1627 1628 if(pView && pView->IsUseIncompatiblePathCreateInterface()) 1629 return aRetval; 1630 1631 ImpPathCreateUser* pU = (ImpPathCreateUser*)rDrag.GetUser(); 1632 1633 if(pU && pU->bBezier && rDrag.IsMouseDown()) 1634 { 1635 // no more XOR, no need for complicated helplines 1636 basegfx::B2DPolygon aHelpline; 1637 aHelpline.append(basegfx::B2DPoint(pU->aBezCtrl2.X(), pU->aBezCtrl2.Y())); 1638 aHelpline.append(basegfx::B2DPoint(pU->aBezEnd.X(), pU->aBezEnd.Y())); 1639 aRetval.append(aHelpline); 1640 } 1641 1642 return aRetval; 1643 } 1644 1645 Pointer ImpPathForDragAndCreate::GetCreatePointer() const 1646 { 1647 switch (meObjectKind) { 1648 case OBJ_LINE : return Pointer(POINTER_DRAW_LINE); 1649 case OBJ_POLY : return Pointer(POINTER_DRAW_POLYGON); 1650 case OBJ_PLIN : return Pointer(POINTER_DRAW_POLYGON); 1651 case OBJ_PATHLINE: return Pointer(POINTER_DRAW_BEZIER); 1652 case OBJ_PATHFILL: return Pointer(POINTER_DRAW_BEZIER); 1653 case OBJ_FREELINE: return Pointer(POINTER_DRAW_FREEHAND); 1654 case OBJ_FREEFILL: return Pointer(POINTER_DRAW_FREEHAND); 1655 case OBJ_SPLNLINE: return Pointer(POINTER_DRAW_FREEHAND); 1656 case OBJ_SPLNFILL: return Pointer(POINTER_DRAW_FREEHAND); 1657 case OBJ_PATHPOLY: return Pointer(POINTER_DRAW_POLYGON); 1658 case OBJ_PATHPLIN: return Pointer(POINTER_DRAW_POLYGON); 1659 default: break; 1660 } // switch 1661 return Pointer(POINTER_CROSS); 1662 } 1663 1664 /*************************************************************************/ 1665 1666 SdrPathObjGeoData::SdrPathObjGeoData() 1667 { 1668 } 1669 1670 SdrPathObjGeoData::~SdrPathObjGeoData() 1671 { 1672 } 1673 1674 ////////////////////////////////////////////////////////////////////////////// 1675 // DrawContact section 1676 1677 sdr::contact::ViewContact* SdrPathObj::CreateObjectSpecificViewContact() 1678 { 1679 return new sdr::contact::ViewContactOfSdrPathObj(*this); 1680 } 1681 1682 /*************************************************************************/ 1683 1684 TYPEINIT1(SdrPathObj,SdrTextObj); 1685 1686 SdrPathObj::SdrPathObj(SdrObjKind eNewKind) 1687 : meKind(eNewKind), 1688 mpDAC(0L) 1689 { 1690 bClosedObj = IsClosed(); 1691 } 1692 1693 SdrPathObj::SdrPathObj(SdrObjKind eNewKind, const basegfx::B2DPolyPolygon& rPathPoly) 1694 : maPathPolygon(rPathPoly), 1695 meKind(eNewKind), 1696 mpDAC(0L) 1697 { 1698 bClosedObj = IsClosed(); 1699 ImpForceKind(); 1700 } 1701 1702 SdrPathObj::~SdrPathObj() 1703 { 1704 impDeleteDAC(); 1705 } 1706 1707 sal_Bool ImpIsLine(const basegfx::B2DPolyPolygon& rPolyPolygon) 1708 { 1709 return (1L == rPolyPolygon.count() && 2L == rPolyPolygon.getB2DPolygon(0L).count()); 1710 } 1711 1712 Rectangle ImpGetBoundRect(const basegfx::B2DPolyPolygon& rPolyPolygon) 1713 { 1714 basegfx::B2DRange aRange(basegfx::tools::getRange(rPolyPolygon)); 1715 1716 return Rectangle( 1717 FRound(aRange.getMinX()), FRound(aRange.getMinY()), 1718 FRound(aRange.getMaxX()), FRound(aRange.getMaxY())); 1719 } 1720 1721 void SdrPathObj::ImpForceLineWink() 1722 { 1723 if(OBJ_LINE == meKind && ImpIsLine(GetPathPoly())) 1724 { 1725 const basegfx::B2DPolygon aPoly(GetPathPoly().getB2DPolygon(0L)); 1726 const basegfx::B2DPoint aB2DPoint0(aPoly.getB2DPoint(0L)); 1727 const basegfx::B2DPoint aB2DPoint1(aPoly.getB2DPoint(1L)); 1728 const Point aPoint0(FRound(aB2DPoint0.getX()), FRound(aB2DPoint0.getY())); 1729 const Point aPoint1(FRound(aB2DPoint1.getX()), FRound(aB2DPoint1.getY())); 1730 const Point aDelt(aPoint1 - aPoint0); 1731 1732 aGeo.nDrehWink=GetAngle(aDelt); 1733 aGeo.nShearWink=0; 1734 aGeo.RecalcSinCos(); 1735 aGeo.RecalcTan(); 1736 1737 // #101412# for SdrTextObj, keep aRect up to date 1738 aRect = Rectangle(aPoint0, aPoint1); 1739 aRect.Justify(); 1740 } 1741 } 1742 1743 void SdrPathObj::ImpForceKind() 1744 { 1745 if (meKind==OBJ_PATHPLIN) meKind=OBJ_PLIN; 1746 if (meKind==OBJ_PATHPOLY) meKind=OBJ_POLY; 1747 1748 if(GetPathPoly().areControlPointsUsed()) 1749 { 1750 switch (meKind) 1751 { 1752 case OBJ_LINE: meKind=OBJ_PATHLINE; break; 1753 case OBJ_PLIN: meKind=OBJ_PATHLINE; break; 1754 case OBJ_POLY: meKind=OBJ_PATHFILL; break; 1755 default: break; 1756 } 1757 } 1758 else 1759 { 1760 switch (meKind) 1761 { 1762 case OBJ_PATHLINE: meKind=OBJ_PLIN; break; 1763 case OBJ_FREELINE: meKind=OBJ_PLIN; break; 1764 case OBJ_PATHFILL: meKind=OBJ_POLY; break; 1765 case OBJ_FREEFILL: meKind=OBJ_POLY; break; 1766 default: break; 1767 } 1768 } 1769 1770 if (meKind==OBJ_LINE && !ImpIsLine(GetPathPoly())) meKind=OBJ_PLIN; 1771 if (meKind==OBJ_PLIN && ImpIsLine(GetPathPoly())) meKind=OBJ_LINE; 1772 1773 bClosedObj=IsClosed(); 1774 1775 if (meKind==OBJ_LINE) 1776 { 1777 ImpForceLineWink(); 1778 } 1779 else 1780 { 1781 // #i10659#, similar to #101412# but for polys with more than 2 points. 1782 // 1783 // Here i again need to fix something, because when Path-Polys are Copy-Pasted 1784 // between Apps with different measurements (e.g. 100TH_MM and TWIPS) there is 1785 // a scaling loop started from SdrExchangeView::Paste. This is principally nothing 1786 // wrong, but aRect is wrong here and not even updated by RecalcSnapRect(). If 1787 // this is the case, some size needs to be set here in aRect to avoid that the cyclus 1788 // through Rect2Poly - Poly2Rect does something badly wrong since that cycle is 1789 // BASED on aRect. That cycle is triggered in SdrTextObj::NbcResize() which is called 1790 // from the local Resize() implementation. 1791 // 1792 // Basic problem is that the member aRect in SdrTextObj basically is a unrotated 1793 // text rectangle for the text object itself and methods at SdrTextObj do handle it 1794 // in that way. Many draw objects derived from SdrTextObj 'abuse' aRect as SnapRect 1795 // which is basically wrong. To make the SdrText methods which deal with aRect directly 1796 // work it is necessary to always keep aRect updated. This e.g. not done after a Clone() 1797 // command for SdrPathObj. Since adding this update mechanism with #101412# to 1798 // ImpForceLineWink() for lines was very successful, i add it to where ImpForceLineWink() 1799 // was called, once here below and once on a 2nd place below. 1800 1801 // #i10659# for SdrTextObj, keep aRect up to date 1802 if(GetPathPoly().count()) 1803 { 1804 aRect = ImpGetBoundRect(GetPathPoly()); 1805 } 1806 } 1807 1808 // #i75974# adapt polygon state to object type. This may include a reinterpretation 1809 // of a closed geometry as open one, but with identical first and last point 1810 for(sal_uInt32 a(0); a < maPathPolygon.count(); a++) 1811 { 1812 basegfx::B2DPolygon aCandidate(maPathPolygon.getB2DPolygon(a)); 1813 1814 if((bool)IsClosed() != aCandidate.isClosed()) 1815 { 1816 // #i80213# really change polygon geometry; else e.g. the last point which 1817 // needs to be identical with the first one will be missing when opening 1818 // due to OBJ_PATH type 1819 if(aCandidate.isClosed()) 1820 { 1821 basegfx::tools::openWithGeometryChange(aCandidate); 1822 } 1823 else 1824 { 1825 basegfx::tools::closeWithGeometryChange(aCandidate); 1826 } 1827 1828 maPathPolygon.setB2DPolygon(a, aCandidate); 1829 } 1830 } 1831 } 1832 1833 void SdrPathObj::ImpSetClosed(sal_Bool bClose) 1834 { 1835 if(bClose) 1836 { 1837 switch (meKind) 1838 { 1839 case OBJ_LINE : meKind=OBJ_POLY; break; 1840 case OBJ_PLIN : meKind=OBJ_POLY; break; 1841 case OBJ_PATHLINE: meKind=OBJ_PATHFILL; break; 1842 case OBJ_FREELINE: meKind=OBJ_FREEFILL; break; 1843 case OBJ_SPLNLINE: meKind=OBJ_SPLNFILL; break; 1844 default: break; 1845 } 1846 1847 bClosedObj = sal_True; 1848 } 1849 else 1850 { 1851 switch (meKind) 1852 { 1853 case OBJ_POLY : meKind=OBJ_PLIN; break; 1854 case OBJ_PATHFILL: meKind=OBJ_PATHLINE; break; 1855 case OBJ_FREEFILL: meKind=OBJ_FREELINE; break; 1856 case OBJ_SPLNFILL: meKind=OBJ_SPLNLINE; break; 1857 default: break; 1858 } 1859 1860 bClosedObj = sal_False; 1861 } 1862 1863 ImpForceKind(); 1864 } 1865 1866 void SdrPathObj::TakeObjInfo(SdrObjTransformInfoRec& rInfo) const 1867 { 1868 rInfo.bNoContortion=sal_False; 1869 1870 FASTBOOL bCanConv = !HasText() || ImpCanConvTextToCurve(); 1871 FASTBOOL bIsPath = IsBezier() || IsSpline(); 1872 1873 rInfo.bEdgeRadiusAllowed = sal_False; 1874 rInfo.bCanConvToPath = bCanConv && !bIsPath; 1875 rInfo.bCanConvToPoly = bCanConv && bIsPath; 1876 rInfo.bCanConvToContour = !IsFontwork() && (rInfo.bCanConvToPoly || LineGeometryUsageIsNecessary()); 1877 } 1878 1879 sal_uInt16 SdrPathObj::GetObjIdentifier() const 1880 { 1881 return sal_uInt16(meKind); 1882 } 1883 1884 void SdrPathObj::operator=(const SdrObject& rObj) 1885 { 1886 SdrTextObj::operator=(rObj); 1887 SdrPathObj& rPath=(SdrPathObj&)rObj; 1888 maPathPolygon=rPath.GetPathPoly(); 1889 } 1890 1891 void SdrPathObj::TakeObjNameSingul(XubString& rName) const 1892 { 1893 if(OBJ_LINE == meKind) 1894 { 1895 sal_uInt16 nId(STR_ObjNameSingulLINE); 1896 1897 if(ImpIsLine(GetPathPoly())) 1898 { 1899 const basegfx::B2DPolygon aPoly(GetPathPoly().getB2DPolygon(0L)); 1900 const basegfx::B2DPoint aB2DPoint0(aPoly.getB2DPoint(0L)); 1901 const basegfx::B2DPoint aB2DPoint1(aPoly.getB2DPoint(1L)); 1902 const Point aPoint0(FRound(aB2DPoint0.getX()), FRound(aB2DPoint0.getY())); 1903 const Point aPoint1(FRound(aB2DPoint0.getX()), FRound(aB2DPoint0.getY())); 1904 1905 if(aB2DPoint0 != aB2DPoint1) 1906 { 1907 if(aB2DPoint0.getY() == aB2DPoint1.getY()) 1908 { 1909 nId = STR_ObjNameSingulLINE_Hori; 1910 } 1911 else if(aB2DPoint0.getX() == aB2DPoint1.getX()) 1912 { 1913 nId = STR_ObjNameSingulLINE_Vert; 1914 } 1915 else 1916 { 1917 const double fDx(fabs(aB2DPoint0.getX() - aB2DPoint1.getX())); 1918 const double fDy(fabs(aB2DPoint0.getY() - aB2DPoint1.getY())); 1919 1920 if(fDx == fDy) 1921 { 1922 nId = STR_ObjNameSingulLINE_Diag; 1923 } 1924 } 1925 } 1926 } 1927 1928 rName = ImpGetResStr(nId); 1929 } 1930 else if(OBJ_PLIN == meKind || OBJ_POLY == meKind) 1931 { 1932 const sal_Bool bClosed(OBJ_POLY == meKind); 1933 sal_uInt16 nId(0); 1934 1935 if(mpDAC && mpDAC->IsCreating()) 1936 { 1937 if(bClosed) 1938 { 1939 nId = STR_ObjNameSingulPOLY; 1940 } 1941 else 1942 { 1943 nId = STR_ObjNameSingulPLIN; 1944 } 1945 1946 rName = ImpGetResStr(nId); 1947 } 1948 else 1949 { 1950 // get point count 1951 sal_uInt32 nPointCount(0L); 1952 const sal_uInt32 nPolyCount(GetPathPoly().count()); 1953 1954 for(sal_uInt32 a(0L); a < nPolyCount; a++) 1955 { 1956 nPointCount += GetPathPoly().getB2DPolygon(a).count(); 1957 } 1958 1959 if(bClosed) 1960 { 1961 nId = STR_ObjNameSingulPOLY_PntAnz; 1962 } 1963 else 1964 { 1965 nId = STR_ObjNameSingulPLIN_PntAnz; 1966 } 1967 1968 rName = ImpGetResStr(nId); 1969 sal_uInt16 nPos(rName.SearchAscii("%2")); // #i96537# 1970 1971 if(STRING_NOTFOUND != nPos) 1972 { 1973 rName.Erase(nPos, 2); 1974 rName.Insert(UniString::CreateFromInt32(nPointCount), nPos); 1975 } 1976 } 1977 } 1978 else 1979 { 1980 switch (meKind) 1981 { 1982 case OBJ_PATHLINE: rName=ImpGetResStr(STR_ObjNameSingulPATHLINE); break; 1983 case OBJ_FREELINE: rName=ImpGetResStr(STR_ObjNameSingulFREELINE); break; 1984 case OBJ_SPLNLINE: rName=ImpGetResStr(STR_ObjNameSingulNATSPLN); break; 1985 case OBJ_PATHFILL: rName=ImpGetResStr(STR_ObjNameSingulPATHFILL); break; 1986 case OBJ_FREEFILL: rName=ImpGetResStr(STR_ObjNameSingulFREEFILL); break; 1987 case OBJ_SPLNFILL: rName=ImpGetResStr(STR_ObjNameSingulPERSPLN); break; 1988 default: break; 1989 } 1990 } 1991 1992 String aName(GetName()); 1993 if(aName.Len()) 1994 { 1995 rName += sal_Unicode(' '); 1996 rName += sal_Unicode('\''); 1997 rName += aName; 1998 rName += sal_Unicode('\''); 1999 } 2000 } 2001 2002 void SdrPathObj::TakeObjNamePlural(XubString& rName) const 2003 { 2004 switch(meKind) 2005 { 2006 case OBJ_LINE : rName=ImpGetResStr(STR_ObjNamePluralLINE ); break; 2007 case OBJ_PLIN : rName=ImpGetResStr(STR_ObjNamePluralPLIN ); break; 2008 case OBJ_POLY : rName=ImpGetResStr(STR_ObjNamePluralPOLY ); break; 2009 case OBJ_PATHLINE: rName=ImpGetResStr(STR_ObjNamePluralPATHLINE); break; 2010 case OBJ_FREELINE: rName=ImpGetResStr(STR_ObjNamePluralFREELINE); break; 2011 case OBJ_SPLNLINE: rName=ImpGetResStr(STR_ObjNamePluralNATSPLN); break; 2012 case OBJ_PATHFILL: rName=ImpGetResStr(STR_ObjNamePluralPATHFILL); break; 2013 case OBJ_FREEFILL: rName=ImpGetResStr(STR_ObjNamePluralFREEFILL); break; 2014 case OBJ_SPLNFILL: rName=ImpGetResStr(STR_ObjNamePluralPERSPLN); break; 2015 default: break; 2016 } 2017 } 2018 2019 basegfx::B2DPolyPolygon SdrPathObj::TakeXorPoly() const 2020 { 2021 return GetPathPoly(); 2022 } 2023 2024 sal_uInt32 SdrPathObj::GetHdlCount() const 2025 { 2026 sal_uInt32 nRetval(0L); 2027 const sal_uInt32 nPolyCount(GetPathPoly().count()); 2028 2029 for(sal_uInt32 a(0L); a < nPolyCount; a++) 2030 { 2031 nRetval += GetPathPoly().getB2DPolygon(a).count(); 2032 } 2033 2034 return nRetval; 2035 } 2036 2037 SdrHdl* SdrPathObj::GetHdl(sal_uInt32 nHdlNum) const 2038 { 2039 // #i73248# 2040 // Warn the user that this is ineffective and show alternatives. Should not be used at all. 2041 OSL_ENSURE(false, "SdrPathObj::GetHdl(): ineffective, use AddToHdlList instead (!)"); 2042 2043 // to have an alternative, get single handle using the ineffective way 2044 SdrHdl* pRetval = 0; 2045 SdrHdlList aLocalList(0); 2046 AddToHdlList(aLocalList); 2047 const sal_uInt32 nHdlCount(aLocalList.GetHdlCount()); 2048 2049 if(nHdlCount && nHdlNum < nHdlCount) 2050 { 2051 // remove and remember. The other created handles will be deleted again with the 2052 // destruction of the local list 2053 pRetval = aLocalList.RemoveHdl(nHdlNum); 2054 } 2055 2056 return pRetval; 2057 } 2058 2059 void SdrPathObj::AddToHdlList(SdrHdlList& rHdlList) const 2060 { 2061 // keep old stuff to be able to keep old SdrHdl stuff, too 2062 const XPolyPolygon aOldPathPolygon(GetPathPoly()); 2063 sal_uInt16 nPolyCnt=aOldPathPolygon.Count(); 2064 FASTBOOL bClosed=IsClosed(); 2065 sal_uInt16 nIdx=0; 2066 2067 for (sal_uInt16 i=0; i<nPolyCnt; i++) { 2068 const XPolygon& rXPoly=aOldPathPolygon.GetObject(i); 2069 sal_uInt16 nPntCnt=rXPoly.GetPointCount(); 2070 if (bClosed && nPntCnt>1) nPntCnt--; 2071 2072 for (sal_uInt16 j=0; j<nPntCnt; j++) { 2073 if (rXPoly.GetFlags(j)!=XPOLY_CONTROL) { 2074 const Point& rPnt=rXPoly[j]; 2075 SdrHdl* pHdl=new SdrHdl(rPnt,HDL_POLY); 2076 pHdl->SetPolyNum(i); 2077 pHdl->SetPointNum(j); 2078 pHdl->Set1PixMore(j==0); 2079 pHdl->SetSourceHdlNum(nIdx); 2080 nIdx++; 2081 rHdlList.AddHdl(pHdl); 2082 } 2083 } 2084 } 2085 } 2086 2087 sal_uInt32 SdrPathObj::GetPlusHdlCount(const SdrHdl& rHdl) const 2088 { 2089 // keep old stuff to be able to keep old SdrHdl stuff, too 2090 const XPolyPolygon aOldPathPolygon(GetPathPoly()); 2091 sal_uInt16 nCnt = 0; 2092 sal_uInt16 nPnt = (sal_uInt16)rHdl.GetPointNum(); 2093 sal_uInt16 nPolyNum = (sal_uInt16)rHdl.GetPolyNum(); 2094 2095 if(nPolyNum < aOldPathPolygon.Count()) 2096 { 2097 const XPolygon& rXPoly = aOldPathPolygon[nPolyNum]; 2098 sal_uInt16 nPntMax = rXPoly.GetPointCount(); 2099 if (nPntMax>0) 2100 { 2101 nPntMax--; 2102 if (nPnt<=nPntMax) 2103 { 2104 if (rXPoly.GetFlags(nPnt)!=XPOLY_CONTROL) 2105 { 2106 if (nPnt==0 && IsClosed()) nPnt=nPntMax; 2107 if (nPnt>0 && rXPoly.GetFlags(nPnt-1)==XPOLY_CONTROL) nCnt++; 2108 if (nPnt==nPntMax && IsClosed()) nPnt=0; 2109 if (nPnt<nPntMax && rXPoly.GetFlags(nPnt+1)==XPOLY_CONTROL) nCnt++; 2110 } 2111 } 2112 } 2113 } 2114 2115 return nCnt; 2116 } 2117 2118 SdrHdl* SdrPathObj::GetPlusHdl(const SdrHdl& rHdl, sal_uInt32 nPlusNum) const 2119 { 2120 // keep old stuff to be able to keep old SdrHdl stuff, too 2121 const XPolyPolygon aOldPathPolygon(GetPathPoly()); 2122 SdrHdl* pHdl = 0L; 2123 sal_uInt16 nPnt = (sal_uInt16)rHdl.GetPointNum(); 2124 sal_uInt16 nPolyNum = (sal_uInt16)rHdl.GetPolyNum(); 2125 2126 if (nPolyNum<aOldPathPolygon.Count()) 2127 { 2128 const XPolygon& rXPoly = aOldPathPolygon[nPolyNum]; 2129 sal_uInt16 nPntMax = rXPoly.GetPointCount(); 2130 2131 if (nPntMax>0) 2132 { 2133 nPntMax--; 2134 if (nPnt<=nPntMax) 2135 { 2136 pHdl=new SdrHdlBezWgt(&rHdl); 2137 pHdl->SetPolyNum(rHdl.GetPolyNum()); 2138 2139 if (nPnt==0 && IsClosed()) nPnt=nPntMax; 2140 if (nPnt>0 && rXPoly.GetFlags(nPnt-1)==XPOLY_CONTROL && nPlusNum==0) 2141 { 2142 pHdl->SetPos(rXPoly[nPnt-1]); 2143 pHdl->SetPointNum(nPnt-1); 2144 } 2145 else 2146 { 2147 if (nPnt==nPntMax && IsClosed()) nPnt=0; 2148 if (nPnt<rXPoly.GetPointCount()-1 && rXPoly.GetFlags(nPnt+1)==XPOLY_CONTROL) 2149 { 2150 pHdl->SetPos(rXPoly[nPnt+1]); 2151 pHdl->SetPointNum(nPnt+1); 2152 } 2153 } 2154 2155 pHdl->SetSourceHdlNum(rHdl.GetSourceHdlNum()); 2156 pHdl->SetPlusHdl(sal_True); 2157 } 2158 } 2159 } 2160 return pHdl; 2161 } 2162 2163 //////////////////////////////////////////////////////////////////////////////////////////////////// 2164 2165 bool SdrPathObj::hasSpecialDrag() const 2166 { 2167 return true; 2168 } 2169 2170 bool SdrPathObj::beginSpecialDrag(SdrDragStat& rDrag) const 2171 { 2172 ImpPathForDragAndCreate aDragAndCreate(*((SdrPathObj*)this)); 2173 2174 return aDragAndCreate.beginPathDrag(rDrag); 2175 } 2176 2177 bool SdrPathObj::applySpecialDrag(SdrDragStat& rDrag) 2178 { 2179 ImpPathForDragAndCreate aDragAndCreate(*this); 2180 bool bRetval(aDragAndCreate.beginPathDrag(rDrag)); 2181 2182 if(bRetval) 2183 { 2184 bRetval = aDragAndCreate.movePathDrag(rDrag); 2185 } 2186 2187 if(bRetval) 2188 { 2189 bRetval = aDragAndCreate.endPathDrag(rDrag); 2190 } 2191 2192 if(bRetval) 2193 { 2194 NbcSetPathPoly(aDragAndCreate.getModifiedPolyPolygon()); 2195 } 2196 2197 return bRetval; 2198 } 2199 2200 String SdrPathObj::getSpecialDragComment(const SdrDragStat& rDrag) const 2201 { 2202 String aRetval; 2203 2204 if(mpDAC) 2205 { 2206 // #i103058# also get a comment when in creation 2207 const bool bCreateComment(rDrag.GetView() && this == rDrag.GetView()->GetCreateObj()); 2208 2209 if(bCreateComment) 2210 { 2211 aRetval = mpDAC->getSpecialDragComment(rDrag); 2212 } 2213 } 2214 else 2215 { 2216 ImpPathForDragAndCreate aDragAndCreate(*((SdrPathObj*)this)); 2217 bool bDidWork(aDragAndCreate.beginPathDrag((SdrDragStat&)rDrag)); 2218 2219 if(bDidWork) 2220 { 2221 aRetval = aDragAndCreate.getSpecialDragComment(rDrag); 2222 } 2223 } 2224 2225 return aRetval; 2226 } 2227 2228 basegfx::B2DPolyPolygon SdrPathObj::getSpecialDragPoly(const SdrDragStat& rDrag) const 2229 { 2230 basegfx::B2DPolyPolygon aRetval; 2231 ImpPathForDragAndCreate aDragAndCreate(*((SdrPathObj*)this)); 2232 bool bDidWork(aDragAndCreate.beginPathDrag((SdrDragStat&)rDrag)); 2233 2234 if(bDidWork) 2235 { 2236 aRetval = aDragAndCreate.getSpecialDragPoly(rDrag); 2237 } 2238 2239 return aRetval; 2240 } 2241 2242 //////////////////////////////////////////////////////////////////////////////////////////////////// 2243 2244 FASTBOOL SdrPathObj::BegCreate(SdrDragStat& rStat) 2245 { 2246 impDeleteDAC(); 2247 return impGetDAC().BegCreate(rStat); 2248 } 2249 2250 FASTBOOL SdrPathObj::MovCreate(SdrDragStat& rStat) 2251 { 2252 return impGetDAC().MovCreate(rStat); 2253 } 2254 2255 FASTBOOL SdrPathObj::EndCreate(SdrDragStat& rStat, SdrCreateCmd eCmd) 2256 { 2257 FASTBOOL bRetval(impGetDAC().EndCreate(rStat, eCmd)); 2258 2259 if(bRetval && mpDAC) 2260 { 2261 SetPathPoly(mpDAC->getModifiedPolyPolygon()); 2262 2263 // #i75974# Check for AutoClose feature. Moved here from ImpPathForDragAndCreate::EndCreate 2264 // to be able to use the type-changing ImpSetClosed method 2265 if(!IsClosedObj()) 2266 { 2267 SdrView* pView = rStat.GetView(); 2268 2269 if(pView && pView->IsAutoClosePolys() && !pView->IsUseIncompatiblePathCreateInterface()) 2270 { 2271 OutputDevice* pOut = pView->GetFirstOutputDevice(); 2272 2273 if(pOut) 2274 { 2275 if(GetPathPoly().count()) 2276 { 2277 const basegfx::B2DPolygon aCandidate(GetPathPoly().getB2DPolygon(0)); 2278 2279 if(aCandidate.count() > 2) 2280 { 2281 // check distance of first and last point 2282 const sal_Int32 nCloseDist(pOut->PixelToLogic(Size(pView->GetAutoCloseDistPix(), 0)).Width()); 2283 const basegfx::B2DVector aDistVector(aCandidate.getB2DPoint(aCandidate.count() - 1) - aCandidate.getB2DPoint(0)); 2284 2285 if(aDistVector.getLength() <= (double)nCloseDist) 2286 { 2287 // close it 2288 ImpSetClosed(true); 2289 } 2290 } 2291 } 2292 } 2293 } 2294 } 2295 2296 impDeleteDAC(); 2297 } 2298 2299 return bRetval; 2300 } 2301 2302 FASTBOOL SdrPathObj::BckCreate(SdrDragStat& rStat) 2303 { 2304 return impGetDAC().BckCreate(rStat); 2305 } 2306 2307 void SdrPathObj::BrkCreate(SdrDragStat& rStat) 2308 { 2309 impGetDAC().BrkCreate(rStat); 2310 impDeleteDAC(); 2311 } 2312 2313 basegfx::B2DPolyPolygon SdrPathObj::TakeCreatePoly(const SdrDragStat& rDrag) const 2314 { 2315 basegfx::B2DPolyPolygon aRetval; 2316 2317 if(mpDAC) 2318 { 2319 aRetval = mpDAC->TakeObjectPolyPolygon(rDrag); 2320 aRetval.append(mpDAC->TakeDragPolyPolygon(rDrag)); 2321 } 2322 2323 return aRetval; 2324 } 2325 2326 // during drag or create, allow accessing the so-far created/modified polyPolygon 2327 basegfx::B2DPolyPolygon SdrPathObj::getObjectPolyPolygon(const SdrDragStat& rDrag) const 2328 { 2329 basegfx::B2DPolyPolygon aRetval; 2330 2331 if(mpDAC) 2332 { 2333 aRetval = mpDAC->TakeObjectPolyPolygon(rDrag); 2334 } 2335 2336 return aRetval; 2337 } 2338 2339 basegfx::B2DPolyPolygon SdrPathObj::getDragPolyPolygon(const SdrDragStat& rDrag) const 2340 { 2341 basegfx::B2DPolyPolygon aRetval; 2342 2343 if(mpDAC) 2344 { 2345 aRetval = mpDAC->TakeDragPolyPolygon(rDrag); 2346 } 2347 2348 return aRetval; 2349 } 2350 2351 Pointer SdrPathObj::GetCreatePointer() const 2352 { 2353 return impGetDAC().GetCreatePointer(); 2354 } 2355 2356 void SdrPathObj::NbcMove(const Size& rSiz) 2357 { 2358 maPathPolygon.transform(basegfx::tools::createTranslateB2DHomMatrix(rSiz.Width(), rSiz.Height())); 2359 2360 // #i19871# first modify locally, then call parent (to get correct SnapRect with GluePoints) 2361 SdrTextObj::NbcMove(rSiz); 2362 } 2363 2364 void SdrPathObj::NbcResize(const Point& rRef, const Fraction& xFact, const Fraction& yFact) 2365 { 2366 basegfx::B2DHomMatrix aTrans(basegfx::tools::createTranslateB2DHomMatrix(-rRef.X(), -rRef.Y())); 2367 aTrans = basegfx::tools::createScaleTranslateB2DHomMatrix( 2368 double(xFact), double(yFact), rRef.X(), rRef.Y()) * aTrans; 2369 maPathPolygon.transform(aTrans); 2370 2371 // #i19871# first modify locally, then call parent (to get correct SnapRect with GluePoints) 2372 SdrTextObj::NbcResize(rRef,xFact,yFact); 2373 } 2374 2375 void SdrPathObj::NbcRotate(const Point& rRef, long nWink, double sn, double cs) 2376 { 2377 // Thank JOE, the angles are defined mirrored to the mathematical meanings 2378 const basegfx::B2DHomMatrix aTrans(basegfx::tools::createRotateAroundPoint(rRef.X(), rRef.Y(), -nWink * nPi180)); 2379 maPathPolygon.transform(aTrans); 2380 2381 // #i19871# first modify locally, then call parent (to get correct SnapRect with GluePoints) 2382 SdrTextObj::NbcRotate(rRef,nWink,sn,cs); 2383 } 2384 2385 void SdrPathObj::NbcShear(const Point& rRefPnt, long nAngle, double fTan, FASTBOOL bVShear) 2386 { 2387 basegfx::B2DHomMatrix aTrans(basegfx::tools::createTranslateB2DHomMatrix(-rRefPnt.X(), -rRefPnt.Y())); 2388 2389 if(bVShear) 2390 { 2391 // Thank JOE, the angles are defined mirrored to the mathematical meanings 2392 aTrans.shearY(-fTan); 2393 } 2394 else 2395 { 2396 aTrans.shearX(-fTan); 2397 } 2398 2399 aTrans.translate(rRefPnt.X(), rRefPnt.Y()); 2400 maPathPolygon.transform(aTrans); 2401 2402 // #i19871# first modify locally, then call parent (to get correct SnapRect with GluePoints) 2403 SdrTextObj::NbcShear(rRefPnt,nAngle,fTan,bVShear); 2404 } 2405 2406 void SdrPathObj::NbcMirror(const Point& rRefPnt1, const Point& rRefPnt2) 2407 { 2408 const double fDiffX(rRefPnt2.X() - rRefPnt1.X()); 2409 const double fDiffY(rRefPnt2.Y() - rRefPnt1.Y()); 2410 const double fRot(atan2(fDiffY, fDiffX)); 2411 basegfx::B2DHomMatrix aTrans(basegfx::tools::createTranslateB2DHomMatrix(-rRefPnt1.X(), -rRefPnt1.Y())); 2412 aTrans.rotate(-fRot); 2413 aTrans.scale(1.0, -1.0); 2414 aTrans.rotate(fRot); 2415 aTrans.translate(rRefPnt1.X(), rRefPnt1.Y()); 2416 maPathPolygon.transform(aTrans); 2417 2418 // #97538# Do Joe's special handling for lines when mirroring, too 2419 ImpForceKind(); 2420 2421 // #i19871# first modify locally, then call parent (to get correct SnapRect with GluePoints) 2422 SdrTextObj::NbcMirror(rRefPnt1,rRefPnt2); 2423 } 2424 2425 void SdrPathObj::TakeUnrotatedSnapRect(Rectangle& rRect) const 2426 { 2427 if(!aGeo.nDrehWink) 2428 { 2429 rRect = GetSnapRect(); 2430 } 2431 else 2432 { 2433 XPolyPolygon aXPP(GetPathPoly()); 2434 RotateXPoly(aXPP,Point(),-aGeo.nSin,aGeo.nCos); 2435 rRect=aXPP.GetBoundRect(); 2436 Point aTmp(rRect.TopLeft()); 2437 RotatePoint(aTmp,Point(),aGeo.nSin,aGeo.nCos); 2438 aTmp-=rRect.TopLeft(); 2439 rRect.Move(aTmp.X(),aTmp.Y()); 2440 } 2441 } 2442 2443 void SdrPathObj::RecalcSnapRect() 2444 { 2445 if(GetPathPoly().count()) 2446 { 2447 maSnapRect = ImpGetBoundRect(GetPathPoly()); 2448 } 2449 } 2450 2451 void SdrPathObj::NbcSetSnapRect(const Rectangle& rRect) 2452 { 2453 Rectangle aOld(GetSnapRect()); 2454 2455 // #95736# Take RECT_EMPTY into account when calculating scale factors 2456 long nMulX = (RECT_EMPTY == rRect.Right()) ? 0 : rRect.Right() - rRect.Left(); 2457 2458 long nDivX = aOld.Right() - aOld.Left(); 2459 2460 // #95736# Take RECT_EMPTY into account when calculating scale factors 2461 long nMulY = (RECT_EMPTY == rRect.Bottom()) ? 0 : rRect.Bottom() - rRect.Top(); 2462 2463 long nDivY = aOld.Bottom() - aOld.Top(); 2464 if ( nDivX == 0 ) { nMulX = 1; nDivX = 1; } 2465 if ( nDivY == 0 ) { nMulY = 1; nDivY = 1; } 2466 Fraction aX(nMulX,nDivX); 2467 Fraction aY(nMulY,nDivY); 2468 NbcResize(aOld.TopLeft(), aX, aY); 2469 NbcMove(Size(rRect.Left() - aOld.Left(), rRect.Top() - aOld.Top())); 2470 } 2471 2472 sal_uInt32 SdrPathObj::GetSnapPointCount() const 2473 { 2474 return GetHdlCount(); 2475 } 2476 2477 Point SdrPathObj::GetSnapPoint(sal_uInt32 nSnapPnt) const 2478 { 2479 sal_uInt32 nPoly,nPnt; 2480 if(!PolyPolygonEditor::GetRelativePolyPoint(GetPathPoly(), nSnapPnt, nPoly, nPnt)) 2481 { 2482 DBG_ASSERT(sal_False,"SdrPathObj::GetSnapPoint: Punkt nSnapPnt nicht vorhanden!"); 2483 } 2484 2485 const basegfx::B2DPoint aB2DPoint(GetPathPoly().getB2DPolygon(nPoly).getB2DPoint(nPnt)); 2486 return Point(FRound(aB2DPoint.getX()), FRound(aB2DPoint.getY())); 2487 } 2488 2489 sal_Bool SdrPathObj::IsPolyObj() const 2490 { 2491 return sal_True; 2492 } 2493 2494 sal_uInt32 SdrPathObj::GetPointCount() const 2495 { 2496 const sal_uInt32 nPolyCount(GetPathPoly().count()); 2497 sal_uInt32 nRetval(0L); 2498 2499 for(sal_uInt32 a(0L); a < nPolyCount; a++) 2500 { 2501 nRetval += GetPathPoly().getB2DPolygon(a).count(); 2502 } 2503 2504 return nRetval; 2505 } 2506 2507 Point SdrPathObj::GetPoint(sal_uInt32 nHdlNum) const 2508 { 2509 Point aRetval; 2510 sal_uInt32 nPoly,nPnt; 2511 2512 if(PolyPolygonEditor::GetRelativePolyPoint(GetPathPoly(), nHdlNum, nPoly, nPnt)) 2513 { 2514 const basegfx::B2DPolygon aPoly(GetPathPoly().getB2DPolygon(nPoly)); 2515 const basegfx::B2DPoint aPoint(aPoly.getB2DPoint(nPnt)); 2516 aRetval = Point(FRound(aPoint.getX()), FRound(aPoint.getY())); 2517 } 2518 2519 return aRetval; 2520 } 2521 2522 void SdrPathObj::NbcSetPoint(const Point& rPnt, sal_uInt32 nHdlNum) 2523 { 2524 sal_uInt32 nPoly,nPnt; 2525 2526 if(PolyPolygonEditor::GetRelativePolyPoint(GetPathPoly(), nHdlNum, nPoly, nPnt)) 2527 { 2528 basegfx::B2DPolygon aNewPolygon(GetPathPoly().getB2DPolygon(nPoly)); 2529 aNewPolygon.setB2DPoint(nPnt, basegfx::B2DPoint(rPnt.X(), rPnt.Y())); 2530 maPathPolygon.setB2DPolygon(nPoly, aNewPolygon); 2531 2532 if(meKind==OBJ_LINE) 2533 { 2534 ImpForceLineWink(); 2535 } 2536 else 2537 { 2538 if(GetPathPoly().count()) 2539 { 2540 // #i10659# for SdrTextObj, keep aRect up to date 2541 aRect = ImpGetBoundRect(GetPathPoly()); // fuer SdrTextObj# 2542 } 2543 } 2544 2545 SetRectsDirty(); 2546 } 2547 } 2548 2549 sal_uInt32 SdrPathObj::NbcInsPointOld(const Point& rPos, sal_Bool bNewObj, sal_Bool bHideHim) 2550 { 2551 sal_uInt32 nNewHdl; 2552 2553 if(bNewObj) 2554 { 2555 nNewHdl = NbcInsPoint(0L, rPos, sal_True, bHideHim); 2556 } 2557 else 2558 { 2559 // look for smallest distance data 2560 const basegfx::B2DPoint aTestPoint(rPos.X(), rPos.Y()); 2561 sal_uInt32 nSmallestPolyIndex(0L); 2562 sal_uInt32 nSmallestEdgeIndex(0L); 2563 double fSmallestCut; 2564 basegfx::tools::getSmallestDistancePointToPolyPolygon(GetPathPoly(), aTestPoint, nSmallestPolyIndex, nSmallestEdgeIndex, fSmallestCut); 2565 2566 // create old polygon index from it 2567 sal_uInt32 nPolyIndex(nSmallestEdgeIndex); 2568 2569 for(sal_uInt32 a(0L); a < nSmallestPolyIndex; a++) 2570 { 2571 nPolyIndex += GetPathPoly().getB2DPolygon(a).count(); 2572 } 2573 2574 nNewHdl = NbcInsPoint(nPolyIndex, rPos, sal_False, bHideHim); 2575 } 2576 2577 ImpForceKind(); 2578 return nNewHdl; 2579 } 2580 2581 sal_uInt32 SdrPathObj::NbcInsPoint(sal_uInt32 /*nHdlNum*/, const Point& rPos, sal_Bool bNewObj, sal_Bool /*bHideHim*/) 2582 { 2583 sal_uInt32 nNewHdl; 2584 2585 if(bNewObj) 2586 { 2587 basegfx::B2DPolygon aNewPoly; 2588 const basegfx::B2DPoint aPoint(rPos.X(), rPos.Y()); 2589 aNewPoly.append(aPoint); 2590 aNewPoly.setClosed(IsClosed()); 2591 maPathPolygon.append(aNewPoly); 2592 SetRectsDirty(); 2593 nNewHdl = GetHdlCount(); 2594 } 2595 else 2596 { 2597 // look for smallest distance data 2598 const basegfx::B2DPoint aTestPoint(rPos.X(), rPos.Y()); 2599 sal_uInt32 nSmallestPolyIndex(0L); 2600 sal_uInt32 nSmallestEdgeIndex(0L); 2601 double fSmallestCut; 2602 basegfx::tools::getSmallestDistancePointToPolyPolygon(GetPathPoly(), aTestPoint, nSmallestPolyIndex, nSmallestEdgeIndex, fSmallestCut); 2603 basegfx::B2DPolygon aCandidate(GetPathPoly().getB2DPolygon(nSmallestPolyIndex)); 2604 const bool bBefore(!aCandidate.isClosed() && 0L == nSmallestEdgeIndex && 0.0 == fSmallestCut); 2605 const bool bAfter(!aCandidate.isClosed() && aCandidate.count() == nSmallestEdgeIndex + 2L && 1.0 == fSmallestCut); 2606 2607 if(bBefore) 2608 { 2609 // before first point 2610 aCandidate.insert(0L, aTestPoint); 2611 2612 if(aCandidate.areControlPointsUsed()) 2613 { 2614 if(aCandidate.isNextControlPointUsed(1)) 2615 { 2616 aCandidate.setNextControlPoint(0, interpolate(aTestPoint, aCandidate.getB2DPoint(1), (1.0 / 3.0))); 2617 aCandidate.setPrevControlPoint(1, interpolate(aTestPoint, aCandidate.getB2DPoint(1), (2.0 / 3.0))); 2618 } 2619 } 2620 2621 nNewHdl = 0L; 2622 } 2623 else if(bAfter) 2624 { 2625 // after last point 2626 aCandidate.append(aTestPoint); 2627 2628 if(aCandidate.areControlPointsUsed()) 2629 { 2630 if(aCandidate.isPrevControlPointUsed(aCandidate.count() - 2)) 2631 { 2632 aCandidate.setNextControlPoint(aCandidate.count() - 2, interpolate(aCandidate.getB2DPoint(aCandidate.count() - 2), aTestPoint, (1.0 / 3.0))); 2633 aCandidate.setPrevControlPoint(aCandidate.count() - 1, interpolate(aCandidate.getB2DPoint(aCandidate.count() - 2), aTestPoint, (2.0 / 3.0))); 2634 } 2635 } 2636 2637 nNewHdl = aCandidate.count() - 1L; 2638 } 2639 else 2640 { 2641 // in between 2642 bool bSegmentSplit(false); 2643 const sal_uInt32 nNextIndex((nSmallestEdgeIndex + 1) % aCandidate.count()); 2644 2645 if(aCandidate.areControlPointsUsed()) 2646 { 2647 if(aCandidate.isNextControlPointUsed(nSmallestEdgeIndex) || aCandidate.isPrevControlPointUsed(nNextIndex)) 2648 { 2649 bSegmentSplit = true; 2650 } 2651 } 2652 2653 if(bSegmentSplit) 2654 { 2655 // rebuild original segment to get the split data 2656 basegfx::B2DCubicBezier aBezierA, aBezierB; 2657 const basegfx::B2DCubicBezier aBezier( 2658 aCandidate.getB2DPoint(nSmallestEdgeIndex), 2659 aCandidate.getNextControlPoint(nSmallestEdgeIndex), 2660 aCandidate.getPrevControlPoint(nNextIndex), 2661 aCandidate.getB2DPoint(nNextIndex)); 2662 2663 // split and insert hit point 2664 aBezier.split(fSmallestCut, &aBezierA, &aBezierB); 2665 aCandidate.insert(nSmallestEdgeIndex + 1, aTestPoint); 2666 2667 // since we inserted hit point and not split point, we need to add an offset 2668 // to the control points to get the C1 continuity we want to achieve 2669 const basegfx::B2DVector aOffset(aTestPoint - aBezierA.getEndPoint()); 2670 aCandidate.setNextControlPoint(nSmallestEdgeIndex, aBezierA.getControlPointA() + aOffset); 2671 aCandidate.setPrevControlPoint(nSmallestEdgeIndex + 1, aBezierA.getControlPointB() + aOffset); 2672 aCandidate.setNextControlPoint(nSmallestEdgeIndex + 1, aBezierB.getControlPointA() + aOffset); 2673 aCandidate.setPrevControlPoint((nSmallestEdgeIndex + 2) % aCandidate.count(), aBezierB.getControlPointB() + aOffset); 2674 } 2675 else 2676 { 2677 aCandidate.insert(nSmallestEdgeIndex + 1L, aTestPoint); 2678 } 2679 2680 nNewHdl = nSmallestEdgeIndex + 1L; 2681 } 2682 2683 maPathPolygon.setB2DPolygon(nSmallestPolyIndex, aCandidate); 2684 2685 // create old polygon index from it 2686 for(sal_uInt32 a(0L); a < nSmallestPolyIndex; a++) 2687 { 2688 nNewHdl += GetPathPoly().getB2DPolygon(a).count(); 2689 } 2690 } 2691 2692 ImpForceKind(); 2693 return nNewHdl; 2694 } 2695 2696 SdrObject* SdrPathObj::RipPoint(sal_uInt32 nHdlNum, sal_uInt32& rNewPt0Index) 2697 { 2698 SdrPathObj* pNewObj = 0L; 2699 const basegfx::B2DPolyPolygon aLocalPolyPolygon(GetPathPoly()); 2700 sal_uInt32 nPoly, nPnt; 2701 2702 if(PolyPolygonEditor::GetRelativePolyPoint(aLocalPolyPolygon, nHdlNum, nPoly, nPnt)) 2703 { 2704 if(0L == nPoly) 2705 { 2706 const basegfx::B2DPolygon aCandidate(aLocalPolyPolygon.getB2DPolygon(nPoly)); 2707 const sal_uInt32 nPointCount(aCandidate.count()); 2708 2709 if(nPointCount) 2710 { 2711 if(IsClosed()) 2712 { 2713 // when closed, RipPoint means to open the polygon at the selected point. To 2714 // be able to do that, it is necessary to make the selected point the first one 2715 basegfx::B2DPolygon aNewPolygon(basegfx::tools::makeStartPoint(aCandidate, nPnt)); 2716 SetPathPoly(basegfx::B2DPolyPolygon(aNewPolygon)); 2717 ToggleClosed(); 2718 2719 // give back new position of old start point (historical reasons) 2720 rNewPt0Index = (nPointCount - nPnt) % nPointCount; 2721 } 2722 else 2723 { 2724 if(nPointCount >= 3L && nPnt != 0L && nPnt + 1L < nPointCount) 2725 { 2726 // split in two objects at point nPnt 2727 basegfx::B2DPolygon aSplitPolyA(aCandidate, 0L, nPnt + 1L); 2728 SetPathPoly(basegfx::B2DPolyPolygon(aSplitPolyA)); 2729 2730 pNewObj = (SdrPathObj*)Clone(); 2731 basegfx::B2DPolygon aSplitPolyB(aCandidate, nPnt, nPointCount - nPnt); 2732 pNewObj->SetPathPoly(basegfx::B2DPolyPolygon(aSplitPolyB)); 2733 } 2734 } 2735 } 2736 } 2737 } 2738 2739 return pNewObj; 2740 } 2741 2742 SdrObject* SdrPathObj::DoConvertToPolyObj(sal_Bool bBezier, bool bAddText) const 2743 { 2744 // #i89784# check for FontWork with activated HideContour 2745 const drawinglayer::attribute::SdrTextAttribute aText( 2746 drawinglayer::primitive2d::createNewSdrTextAttribute(GetObjectItemSet(), *getText(0))); 2747 const bool bHideContour( 2748 !aText.isDefault() && !aText.getSdrFormTextAttribute().isDefault() && aText.isHideContour()); 2749 2750 SdrObject* pRet = bHideContour ? 2751 0 : 2752 ImpConvertMakeObj(GetPathPoly(), IsClosed(), bBezier); 2753 2754 SdrPathObj* pPath = PTR_CAST(SdrPathObj, pRet); 2755 2756 if(pPath) 2757 { 2758 if(pPath->GetPathPoly().areControlPointsUsed()) 2759 { 2760 if(!bBezier) 2761 { 2762 // reduce all bezier curves 2763 pPath->SetPathPoly(basegfx::tools::adaptiveSubdivideByAngle(pPath->GetPathPoly())); 2764 } 2765 } 2766 else 2767 { 2768 if(bBezier) 2769 { 2770 // create bezier curves 2771 pPath->SetPathPoly(basegfx::tools::expandToCurve(pPath->GetPathPoly())); 2772 } 2773 } 2774 } 2775 2776 if(bAddText) 2777 { 2778 pRet = ImpConvertAddText(pRet, bBezier); 2779 } 2780 2781 return pRet; 2782 } 2783 2784 SdrObjGeoData* SdrPathObj::NewGeoData() const 2785 { 2786 return new SdrPathObjGeoData; 2787 } 2788 2789 void SdrPathObj::SaveGeoData(SdrObjGeoData& rGeo) const 2790 { 2791 SdrTextObj::SaveGeoData(rGeo); 2792 SdrPathObjGeoData& rPGeo = (SdrPathObjGeoData&) rGeo; 2793 rPGeo.maPathPolygon=GetPathPoly(); 2794 rPGeo.meKind=meKind; 2795 } 2796 2797 void SdrPathObj::RestGeoData(const SdrObjGeoData& rGeo) 2798 { 2799 SdrTextObj::RestGeoData(rGeo); 2800 SdrPathObjGeoData& rPGeo=(SdrPathObjGeoData&)rGeo; 2801 maPathPolygon=rPGeo.maPathPolygon; 2802 meKind=rPGeo.meKind; 2803 ImpForceKind(); // damit u.a. bClosed gesetzt wird 2804 } 2805 2806 void SdrPathObj::NbcSetPathPoly(const basegfx::B2DPolyPolygon& rPathPoly) 2807 { 2808 if(GetPathPoly() != rPathPoly) 2809 { 2810 maPathPolygon=rPathPoly; 2811 ImpForceKind(); 2812 SetRectsDirty(); 2813 } 2814 } 2815 2816 void SdrPathObj::SetPathPoly(const basegfx::B2DPolyPolygon& rPathPoly) 2817 { 2818 if(GetPathPoly() != rPathPoly) 2819 { 2820 Rectangle aBoundRect0; if (pUserCall!=NULL) aBoundRect0=GetLastBoundRect(); 2821 NbcSetPathPoly(rPathPoly); 2822 SetChanged(); 2823 BroadcastObjectChange(); 2824 SendUserCall(SDRUSERCALL_RESIZE,aBoundRect0); 2825 } 2826 } 2827 2828 void SdrPathObj::ToggleClosed() // long nOpenDistance) 2829 { 2830 Rectangle aBoundRect0; 2831 if(pUserCall != NULL) 2832 aBoundRect0 = GetLastBoundRect(); 2833 ImpSetClosed(!IsClosed()); // neuen ObjKind setzen 2834 ImpForceKind(); // wg. Line->Poly->PolyLine statt Line->Poly->Line 2835 SetRectsDirty(); 2836 SetChanged(); 2837 BroadcastObjectChange(); 2838 SendUserCall(SDRUSERCALL_RESIZE, aBoundRect0); 2839 } 2840 2841 // fuer friend class SdrPolyEditView auf einigen Compilern: 2842 void SdrPathObj::SetRectsDirty(sal_Bool bNotMyself) 2843 { 2844 SdrTextObj::SetRectsDirty(bNotMyself); 2845 } 2846 2847 ImpPathForDragAndCreate& SdrPathObj::impGetDAC() const 2848 { 2849 if(!mpDAC) 2850 { 2851 ((SdrPathObj*)this)->mpDAC = new ImpPathForDragAndCreate(*((SdrPathObj*)this)); 2852 } 2853 2854 return *mpDAC; 2855 } 2856 2857 void SdrPathObj::impDeleteDAC() const 2858 { 2859 if(mpDAC) 2860 { 2861 delete mpDAC; 2862 ((SdrPathObj*)this)->mpDAC = 0L; 2863 } 2864 } 2865 2866 //////////////////////////////////////////////////////////////////////////////////////////////////// 2867 // 2868 // transformation interface for StarOfficeAPI. This implements support for 2869 // homogen 3x3 matrices containing the transformation of the SdrObject. At the 2870 // moment it contains a shearX, rotation and translation, but for setting all linear 2871 // transforms like Scale, ShearX, ShearY, Rotate and Translate are supported. 2872 // 2873 //////////////////////////////////////////////////////////////////////////////////////////////////// 2874 // gets base transformation and rectangle of object. If it's an SdrPathObj it fills the PolyPolygon 2875 // with the base geometry and returns TRUE. Otherwise it returns FALSE. 2876 sal_Bool SdrPathObj::TRGetBaseGeometry(basegfx::B2DHomMatrix& rMatrix, basegfx::B2DPolyPolygon& rPolyPolygon) const 2877 { 2878 double fRotate(0.0); 2879 double fShearX(0.0); 2880 basegfx::B2DTuple aScale(1.0, 1.0); 2881 basegfx::B2DTuple aTranslate(0.0, 0.0); 2882 2883 if(GetPathPoly().count()) 2884 { 2885 // copy geometry 2886 basegfx::B2DHomMatrix aMoveToZeroMatrix; 2887 rPolyPolygon = GetPathPoly(); 2888 2889 if(OBJ_LINE == meKind) 2890 { 2891 // ignore shear and rotate, just use scale and translate 2892 OSL_ENSURE(GetPathPoly().count() > 0L && GetPathPoly().getB2DPolygon(0L).count() > 1L, "OBJ_LINE with too less polygons (!)"); 2893 // #i72287# use polygon without control points for range calculation. Do not change rPolyPolygon 2894 // itself, else this method will no longer return the full polygon information (curve will 2895 // be lost) 2896 const basegfx::B2DRange aPolyRangeNoCurve(basegfx::tools::getRange(rPolyPolygon)); 2897 aScale = aPolyRangeNoCurve.getRange(); 2898 aTranslate = aPolyRangeNoCurve.getMinimum(); 2899 2900 // define matrix for move polygon to zero point 2901 aMoveToZeroMatrix.translate(-aTranslate.getX(), -aTranslate.getY()); 2902 } 2903 else 2904 { 2905 if(aGeo.nShearWink || aGeo.nDrehWink) 2906 { 2907 // get rotate and shear in drawingLayer notation 2908 fRotate = aGeo.nDrehWink * F_PI18000; 2909 fShearX = aGeo.nShearWink * F_PI18000; 2910 2911 // build mathematically correct (negative shear and rotate) object transform 2912 // containing shear and rotate to extract unsheared, unrotated polygon 2913 basegfx::B2DHomMatrix aObjectMatrix; 2914 aObjectMatrix.shearX(tan((36000 - aGeo.nShearWink) * F_PI18000)); 2915 aObjectMatrix.rotate((36000 - aGeo.nDrehWink) * F_PI18000); 2916 2917 // create inverse from it and back-transform polygon 2918 basegfx::B2DHomMatrix aInvObjectMatrix(aObjectMatrix); 2919 aInvObjectMatrix.invert(); 2920 rPolyPolygon.transform(aInvObjectMatrix); 2921 2922 // get range from unsheared, unrotated polygon and extract scale and translate. 2923 // transform topLeft from it back to transformed state to get original 2924 // topLeft (rotation center) 2925 // #i72287# use polygon without control points for range calculation. Do not change rPolyPolygon 2926 // itself, else this method will no longer return the full polygon information (curve will 2927 // be lost) 2928 const basegfx::B2DRange aCorrectedRangeNoCurve(basegfx::tools::getRange(rPolyPolygon)); 2929 aTranslate = aObjectMatrix * aCorrectedRangeNoCurve.getMinimum(); 2930 aScale = aCorrectedRangeNoCurve.getRange(); 2931 2932 // define matrix for move polygon to zero point 2933 // #i112280# Added missing minus for Y-Translation 2934 aMoveToZeroMatrix.translate(-aCorrectedRangeNoCurve.getMinX(), -aCorrectedRangeNoCurve.getMinY()); 2935 } 2936 else 2937 { 2938 // get scale and translate from unsheared, unrotated polygon 2939 // #i72287# use polygon without control points for range calculation. Do not change rPolyPolygon 2940 // itself, else this method will no longer return the full polygon information (curve will 2941 // be lost) 2942 const basegfx::B2DRange aPolyRangeNoCurve(basegfx::tools::getRange(rPolyPolygon)); 2943 aScale = aPolyRangeNoCurve.getRange(); 2944 aTranslate = aPolyRangeNoCurve.getMinimum(); 2945 2946 // define matrix for move polygon to zero point 2947 aMoveToZeroMatrix.translate(-aTranslate.getX(), -aTranslate.getY()); 2948 } 2949 } 2950 2951 // move polygon to zero point with pre-defined matrix 2952 rPolyPolygon.transform(aMoveToZeroMatrix); 2953 } 2954 2955 // position maybe relative to anchorpos, convert 2956 if( pModel && pModel->IsWriter() ) 2957 { 2958 if(GetAnchorPos().X() || GetAnchorPos().Y()) 2959 { 2960 aTranslate -= basegfx::B2DTuple(GetAnchorPos().X(), GetAnchorPos().Y()); 2961 } 2962 } 2963 2964 // force MapUnit to 100th mm 2965 SfxMapUnit eMapUnit = GetObjectItemSet().GetPool()->GetMetric(0); 2966 if(eMapUnit != SFX_MAPUNIT_100TH_MM) 2967 { 2968 switch(eMapUnit) 2969 { 2970 case SFX_MAPUNIT_TWIP : 2971 { 2972 // postion 2973 aTranslate.setX(ImplTwipsToMM(aTranslate.getX())); 2974 aTranslate.setY(ImplTwipsToMM(aTranslate.getY())); 2975 2976 // size 2977 aScale.setX(ImplTwipsToMM(aScale.getX())); 2978 aScale.setY(ImplTwipsToMM(aScale.getY())); 2979 2980 // polygon 2981 basegfx::B2DHomMatrix aTwipsToMM; 2982 const double fFactorTwipsToMM(127.0 / 72.0); 2983 aTwipsToMM.scale(fFactorTwipsToMM, fFactorTwipsToMM); 2984 rPolyPolygon.transform(aTwipsToMM); 2985 2986 break; 2987 } 2988 default: 2989 { 2990 DBG_ERROR("TRGetBaseGeometry: Missing unit translation to 100th mm!"); 2991 } 2992 } 2993 } 2994 2995 // build return value matrix 2996 rMatrix = basegfx::tools::createScaleShearXRotateTranslateB2DHomMatrix( 2997 aScale, 2998 basegfx::fTools::equalZero(fShearX) ? 0.0 : tan(fShearX), 2999 basegfx::fTools::equalZero(fRotate) ? 0.0 : -fRotate, 3000 aTranslate); 3001 3002 return sal_True; 3003 } 3004 3005 // sets the base geometry of the object using infos contained in the homogen 3x3 matrix. 3006 // If it's an SdrPathObj it will use the provided geometry information. The Polygon has 3007 // to use (0,0) as upper left and will be scaled to the given size in the matrix. 3008 void SdrPathObj::TRSetBaseGeometry(const basegfx::B2DHomMatrix& rMatrix, const basegfx::B2DPolyPolygon& rPolyPolygon) 3009 { 3010 // break up matrix 3011 basegfx::B2DTuple aScale; 3012 basegfx::B2DTuple aTranslate; 3013 double fRotate, fShearX; 3014 rMatrix.decompose(aScale, aTranslate, fRotate, fShearX); 3015 3016 // #i75086# Old DrawingLayer (GeoStat and geometry) does not support holding negative scalings 3017 // in X and Y which equal a 180 degree rotation. Recognize it and react accordingly 3018 if(basegfx::fTools::less(aScale.getX(), 0.0) && basegfx::fTools::less(aScale.getY(), 0.0)) 3019 { 3020 aScale.setX(fabs(aScale.getX())); 3021 aScale.setY(fabs(aScale.getY())); 3022 fRotate = fmod(fRotate + F_PI, F_2PI); 3023 } 3024 3025 // copy poly 3026 basegfx::B2DPolyPolygon aNewPolyPolygon(rPolyPolygon); 3027 3028 // reset object shear and rotations 3029 aGeo.nDrehWink = 0; 3030 aGeo.RecalcSinCos(); 3031 aGeo.nShearWink = 0; 3032 aGeo.RecalcTan(); 3033 3034 // force metric to pool metric 3035 SfxMapUnit eMapUnit = GetObjectItemSet().GetPool()->GetMetric(0); 3036 if(eMapUnit != SFX_MAPUNIT_100TH_MM) 3037 { 3038 switch(eMapUnit) 3039 { 3040 case SFX_MAPUNIT_TWIP : 3041 { 3042 // position 3043 aTranslate.setX(ImplMMToTwips(aTranslate.getX())); 3044 aTranslate.setY(ImplMMToTwips(aTranslate.getY())); 3045 3046 // size 3047 aScale.setX(ImplMMToTwips(aScale.getX())); 3048 aScale.setY(ImplMMToTwips(aScale.getY())); 3049 3050 // polygon 3051 basegfx::B2DHomMatrix aMMToTwips; 3052 const double fFactorMMToTwips(72.0 / 127.0); 3053 aMMToTwips.scale(fFactorMMToTwips, fFactorMMToTwips); 3054 aNewPolyPolygon.transform(aMMToTwips); 3055 3056 break; 3057 } 3058 default: 3059 { 3060 DBG_ERROR("TRSetBaseGeometry: Missing unit translation to PoolMetric!"); 3061 } 3062 } 3063 } 3064 3065 if( pModel && pModel->IsWriter() ) 3066 { 3067 // if anchor is used, make position relative to it 3068 if(GetAnchorPos().X() || GetAnchorPos().Y()) 3069 { 3070 aTranslate += basegfx::B2DTuple(GetAnchorPos().X(), GetAnchorPos().Y()); 3071 } 3072 } 3073 3074 // create transformation for polygon, set values at aGeo direct 3075 basegfx::B2DHomMatrix aTransform; 3076 3077 // #i75086# 3078 // Given polygon is already scaled (for historical reasons), but not mirrored yet. 3079 // Thus, when scale is negative in X or Y, apply the needed mirroring accordingly. 3080 if(basegfx::fTools::less(aScale.getX(), 0.0) || basegfx::fTools::less(aScale.getY(), 0.0)) 3081 { 3082 aTransform.scale( 3083 basegfx::fTools::less(aScale.getX(), 0.0) ? -1.0 : 1.0, 3084 basegfx::fTools::less(aScale.getY(), 0.0) ? -1.0 : 1.0); 3085 } 3086 3087 if(!basegfx::fTools::equalZero(fShearX)) 3088 { 3089 aTransform.shearX(tan(-atan(fShearX))); 3090 aGeo.nShearWink = FRound(atan(fShearX) / F_PI18000); 3091 aGeo.RecalcTan(); 3092 } 3093 3094 if(!basegfx::fTools::equalZero(fRotate)) 3095 { 3096 // #i78696# 3097 // fRotate is matematically correct for linear transformations, so it's 3098 // the one to use for the geometry change 3099 aTransform.rotate(fRotate); 3100 3101 // #i78696# 3102 // fRotate is matematically correct, but aGeoStat.nDrehWink is 3103 // mirrored -> mirror value here 3104 aGeo.nDrehWink = NormAngle360(FRound(-fRotate / F_PI18000)); 3105 aGeo.RecalcSinCos(); 3106 } 3107 3108 if(!aTranslate.equalZero()) 3109 { 3110 // #i39529# absolute positioning, so get current position (without control points (!)) 3111 const basegfx::B2DRange aCurrentRange(basegfx::tools::getRange(aNewPolyPolygon)); 3112 aTransform.translate(aTranslate.getX() - aCurrentRange.getMinX(), aTranslate.getY() - aCurrentRange.getMinY()); 3113 } 3114 3115 // transform polygon and trigger change 3116 aNewPolyPolygon.transform(aTransform); 3117 SetPathPoly(aNewPolyPolygon); 3118 } 3119 3120 ////////////////////////////////////////////////////////////////////////////// 3121 // eof 3122