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