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