1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include "svddrgm1.hxx"
21 #include "svdglob.hxx"
22 #include "svx/svdstr.hrc"
24 #include <basegfx/matrix/b2dhommatrix.hxx>
25 #include <basegfx/polygon/b2dpolygon.hxx>
26 #include <basegfx/polygon/b2dpolygontools.hxx>
27 #include <editeng/eeitem.hxx>
28 #include <svl/smplhint.hxx>
29 #include <svl/style.hxx>
31 #include <sdr/contact/viewcontactofsdredgeobj.hxx>
32 #include <sdr/properties/connectorproperties.hxx>
33 #include <svx/sdrhittesthelper.hxx>
34 #include <svx/svddrag.hxx>
35 #include <svx/svddrgv.hxx>
36 #include <svx/svdetc.hxx>
37 #include <svx/svdhdl.hxx>
38 #include <svx/svdmodel.hxx>
39 #include <svx/svdoedge.hxx>
40 #include <svx/svdpage.hxx>
41 #include <svx/svdpagv.hxx>
42 #include <svx/svdpool.hxx>
43 #include <svx/svdtrans.hxx>
44 #include <svx/svdview.hxx>
45 #include <svx/sxekitm.hxx>
46 #include <svx/sxelditm.hxx>
47 #include <svx/sxenditm.hxx>
48 #include <svx/xpoly.hxx>
49 #include <svx/xpool.hxx>
53 SdrObjConnection::~SdrObjConnection()
57 void SdrObjConnection::ResetVars()
71 bool SdrObjConnection::TakeGluePoint(SdrGluePoint
& rGP
, bool bSetAbsPos
) const
74 if (pObj
!=NULL
) { // one object has to be docked already!
76 rGP
=pObj
->GetVertexGluePoint(nConId
);
78 } else if (bAutoCorner
) {
79 rGP
=pObj
->GetCornerGluePoint(nConId
);
82 const SdrGluePointList
* pGPL
=pObj
->GetGluePointList();
84 sal_uInt16 nNum
=pGPL
->FindGluePoint(nConId
);
85 if (nNum
!=SDRGLUEPOINT_NOTFOUND
) {
92 if (bRet
&& bSetAbsPos
) {
93 Point
aPt(rGP
.GetAbsolutePos(*pObj
));
100 Point
& SdrEdgeInfoRec::ImpGetLineVersatzPoint(SdrEdgeLineCode eLineCode
)
103 case OBJ1LINE2
: return aObj1Line2
;
104 case OBJ1LINE3
: return aObj1Line3
;
105 case OBJ2LINE2
: return aObj2Line2
;
106 case OBJ2LINE3
: return aObj2Line3
;
107 case MIDDLELINE
: return aMiddleLine
;
112 sal_uInt16
SdrEdgeInfoRec::ImpGetPolyIdx(SdrEdgeLineCode eLineCode
, const XPolygon
& rXP
) const
115 case OBJ1LINE2
: return 1;
116 case OBJ1LINE3
: return 2;
117 case OBJ2LINE2
: return rXP
.GetPointCount()-3;
118 case OBJ2LINE3
: return rXP
.GetPointCount()-4;
119 case MIDDLELINE
: return nMiddleLine
;
124 bool SdrEdgeInfoRec::ImpIsHorzLine(SdrEdgeLineCode eLineCode
, const XPolygon
& rXP
) const
126 sal_uInt16 nIdx
=ImpGetPolyIdx(eLineCode
,rXP
);
127 bool bHorz
=nAngle1
==0 || nAngle1
==18000;
128 if (eLineCode
==OBJ2LINE2
|| eLineCode
==OBJ2LINE3
) {
129 nIdx
=rXP
.GetPointCount()-nIdx
;
130 bHorz
=nAngle2
==0 || nAngle2
==18000;
132 if ((nIdx
& 1)==1) bHorz
=!bHorz
;
136 void SdrEdgeInfoRec::ImpSetLineVersatz(SdrEdgeLineCode eLineCode
, const XPolygon
& rXP
, long nVal
)
138 Point
& rPt
=ImpGetLineVersatzPoint(eLineCode
);
139 if (ImpIsHorzLine(eLineCode
,rXP
)) rPt
.Y()=nVal
;
143 long SdrEdgeInfoRec::ImpGetLineVersatz(SdrEdgeLineCode eLineCode
, const XPolygon
& rXP
) const
145 const Point
& rPt
=ImpGetLineVersatzPoint(eLineCode
);
146 if (ImpIsHorzLine(eLineCode
,rXP
)) return rPt
.Y();
151 // BaseProperties section
153 sdr::properties::BaseProperties
* SdrEdgeObj::CreateObjectSpecificProperties()
155 return new sdr::properties::ConnectorProperties(*this);
159 // DrawContact section
161 sdr::contact::ViewContact
* SdrEdgeObj::CreateObjectSpecificViewContact()
163 return new sdr::contact::ViewContactOfSdrEdgeObj(*this);
168 TYPEINIT1(SdrEdgeObj
,SdrTextObj
);
170 SdrEdgeObj::SdrEdgeObj()
173 bEdgeTrackDirty(false),
174 bEdgeTrackUserDefined(false),
175 // Default is to allow default connects
176 mbSuppressDefaultConnect(false),
177 mbBoundRectCalculationRunning(false),
182 pEdgeTrack
=new XPolygon
;
186 SdrEdgeObj::~SdrEdgeObj()
188 DisconnectFromNode(true);
189 DisconnectFromNode(false);
193 void SdrEdgeObj::ImpSetAttrToEdgeInfo()
195 const SfxItemSet
& rSet
= GetObjectItemSet();
196 SdrEdgeKind eKind
= ((SdrEdgeKindItem
&)(rSet
.Get(SDRATTR_EDGEKIND
))).GetValue();
197 sal_Int32 nVal1
= ((SdrEdgeLine1DeltaItem
&)rSet
.Get(SDRATTR_EDGELINE1DELTA
)).GetValue();
198 sal_Int32 nVal2
= ((SdrEdgeLine2DeltaItem
&)rSet
.Get(SDRATTR_EDGELINE2DELTA
)).GetValue();
199 sal_Int32 nVal3
= ((SdrEdgeLine3DeltaItem
&)rSet
.Get(SDRATTR_EDGELINE3DELTA
)).GetValue();
201 if(eKind
== SDREDGE_ORTHOLINES
|| eKind
== SDREDGE_BEZIER
)
203 sal_Int32 nVals
[3] = { nVal1
, nVal2
, nVal3
};
206 if(aEdgeInfo
.nObj1Lines
>= 2 && n
< 3)
208 aEdgeInfo
.ImpSetLineVersatz(OBJ1LINE2
, *pEdgeTrack
, nVals
[n
]);
212 if(aEdgeInfo
.nObj1Lines
>= 3 && n
< 3)
214 aEdgeInfo
.ImpSetLineVersatz(OBJ1LINE3
, *pEdgeTrack
, nVals
[n
]);
218 if(aEdgeInfo
.nMiddleLine
!= 0xFFFF && n
< 3)
220 aEdgeInfo
.ImpSetLineVersatz(MIDDLELINE
, *pEdgeTrack
, nVals
[n
]);
224 if(aEdgeInfo
.nObj2Lines
>= 3 && n
< 3)
226 aEdgeInfo
.ImpSetLineVersatz(OBJ2LINE3
, *pEdgeTrack
, nVals
[n
]);
230 if(aEdgeInfo
.nObj2Lines
>= 2 && n
< 3)
232 aEdgeInfo
.ImpSetLineVersatz(OBJ2LINE2
, *pEdgeTrack
, nVals
[n
]);
236 else if(eKind
== SDREDGE_THREELINES
)
238 bool bHor1
= aEdgeInfo
.nAngle1
== 0 || aEdgeInfo
.nAngle1
== 18000;
239 bool bHor2
= aEdgeInfo
.nAngle2
== 0 || aEdgeInfo
.nAngle2
== 18000;
243 aEdgeInfo
.aObj1Line2
.X() = nVal1
;
247 aEdgeInfo
.aObj1Line2
.Y() = nVal1
;
252 aEdgeInfo
.aObj2Line2
.X() = nVal2
;
256 aEdgeInfo
.aObj2Line2
.Y() = nVal2
;
263 void SdrEdgeObj::ImpSetEdgeInfoToAttr()
265 const SfxItemSet
& rSet
= GetObjectItemSet();
266 SdrEdgeKind eKind
= ((SdrEdgeKindItem
&)(rSet
.Get(SDRATTR_EDGEKIND
))).GetValue();
267 sal_Int32 nValAnz
= ((SdrEdgeLineDeltaAnzItem
&)rSet
.Get(SDRATTR_EDGELINEDELTAANZ
)).GetValue();
268 sal_Int32 nVal1
= ((SdrEdgeLine1DeltaItem
&)rSet
.Get(SDRATTR_EDGELINE1DELTA
)).GetValue();
269 sal_Int32 nVal2
= ((SdrEdgeLine2DeltaItem
&)rSet
.Get(SDRATTR_EDGELINE2DELTA
)).GetValue();
270 sal_Int32 nVal3
= ((SdrEdgeLine3DeltaItem
&)rSet
.Get(SDRATTR_EDGELINE3DELTA
)).GetValue();
271 sal_Int32 nVals
[3] = { nVal1
, nVal2
, nVal3
};
274 if(eKind
== SDREDGE_ORTHOLINES
|| eKind
== SDREDGE_BEZIER
)
276 if(aEdgeInfo
.nObj1Lines
>= 2 && n
< 3)
278 nVals
[n
] = aEdgeInfo
.ImpGetLineVersatz(OBJ1LINE2
, *pEdgeTrack
);
282 if(aEdgeInfo
.nObj1Lines
>= 3 && n
< 3)
284 nVals
[n
] = aEdgeInfo
.ImpGetLineVersatz(OBJ1LINE3
, *pEdgeTrack
);
288 if(aEdgeInfo
.nMiddleLine
!= 0xFFFF && n
< 3)
290 nVals
[n
] = aEdgeInfo
.ImpGetLineVersatz(MIDDLELINE
, *pEdgeTrack
);
294 if(aEdgeInfo
.nObj2Lines
>= 3 && n
< 3)
296 nVals
[n
] = aEdgeInfo
.ImpGetLineVersatz(OBJ2LINE3
, *pEdgeTrack
);
300 if(aEdgeInfo
.nObj2Lines
>= 2 && n
< 3)
302 nVals
[n
] = aEdgeInfo
.ImpGetLineVersatz(OBJ2LINE2
, *pEdgeTrack
);
306 else if(eKind
== SDREDGE_THREELINES
)
308 bool bHor1
= aEdgeInfo
.nAngle1
== 0 || aEdgeInfo
.nAngle1
== 18000;
309 bool bHor2
= aEdgeInfo
.nAngle2
== 0 || aEdgeInfo
.nAngle2
== 18000;
312 nVals
[0] = bHor1
? aEdgeInfo
.aObj1Line2
.X() : aEdgeInfo
.aObj1Line2
.Y();
313 nVals
[1] = bHor2
? aEdgeInfo
.aObj2Line2
.X() : aEdgeInfo
.aObj2Line2
.Y();
316 if(n
!= nValAnz
|| nVals
[0] != nVal1
|| nVals
[1] != nVal2
|| nVals
[2] != nVal3
)
318 // Here no more notifying is necessary, just local changes are OK.
321 GetProperties().SetObjectItemDirect(SdrEdgeLineDeltaAnzItem(n
));
324 if(nVals
[0] != nVal1
)
326 GetProperties().SetObjectItemDirect(SdrEdgeLine1DeltaItem(nVals
[0]));
329 if(nVals
[1] != nVal2
)
331 GetProperties().SetObjectItemDirect(SdrEdgeLine2DeltaItem(nVals
[1]));
334 if(nVals
[2] != nVal3
)
336 GetProperties().SetObjectItemDirect(SdrEdgeLine3DeltaItem(nVals
[2]));
341 GetProperties().ClearObjectItemDirect(SDRATTR_EDGELINE3DELTA
);
346 GetProperties().ClearObjectItemDirect(SDRATTR_EDGELINE2DELTA
);
351 GetProperties().ClearObjectItemDirect(SDRATTR_EDGELINE1DELTA
);
356 void SdrEdgeObj::TakeObjInfo(SdrObjTransformInfoRec
& rInfo
) const
358 // #i54102# allow rotation, mirror and shear
359 rInfo
.bRotateFreeAllowed
= true;
360 rInfo
.bRotate90Allowed
= true;
361 rInfo
.bMirrorFreeAllowed
= true;
362 rInfo
.bMirror45Allowed
= true;
363 rInfo
.bMirror90Allowed
= true;
364 rInfo
.bTransparenceAllowed
= false;
365 rInfo
.bGradientAllowed
= false;
366 rInfo
.bShearAllowed
= true;
367 rInfo
.bEdgeRadiusAllowed
= false;
368 bool bCanConv
=!HasText() || ImpCanConvTextToCurve();
369 rInfo
.bCanConvToPath
=bCanConv
;
370 rInfo
.bCanConvToPoly
=bCanConv
;
371 rInfo
.bCanConvToContour
= (rInfo
.bCanConvToPoly
|| LineGeometryUsageIsNecessary());
374 sal_uInt16
SdrEdgeObj::GetObjIdentifier() const
376 return sal_uInt16(OBJ_EDGE
);
379 const Rectangle
& SdrEdgeObj::GetCurrentBoundRect() const
383 ((SdrEdgeObj
*)this)->ImpRecalcEdgeTrack();
386 return SdrTextObj::GetCurrentBoundRect();
389 const Rectangle
& SdrEdgeObj::GetSnapRect() const
393 ((SdrEdgeObj
*)this)->ImpRecalcEdgeTrack();
396 return SdrTextObj::GetSnapRect();
399 void SdrEdgeObj::RecalcSnapRect()
401 maSnapRect
=pEdgeTrack
->GetBoundRect();
404 void SdrEdgeObj::TakeUnrotatedSnapRect(Rectangle
& rRect
) const
409 bool SdrEdgeObj::IsNode() const
414 SdrGluePoint
SdrEdgeObj::GetVertexGluePoint(sal_uInt16 nNum
) const
417 sal_uInt16 nPntAnz
=pEdgeTrack
->GetPointCount();
420 Point aOfs
= GetSnapRect().Center();
421 if (nNum
==2 && GetConnectedNode(true)==NULL
) aPt
=(*pEdgeTrack
)[0];
422 else if (nNum
==3 && GetConnectedNode(false)==NULL
) aPt
=(*pEdgeTrack
)[nPntAnz
-1];
424 if ((nPntAnz
& 1) ==1) {
425 aPt
=(*pEdgeTrack
)[nPntAnz
/2];
427 Point
aPt1((*pEdgeTrack
)[nPntAnz
/2-1]);
428 Point
aPt2((*pEdgeTrack
)[nPntAnz
/2]);
437 SdrGluePoint
aGP(aPt
);
438 aGP
.SetPercent(false);
442 SdrGluePoint
SdrEdgeObj::GetCornerGluePoint(sal_uInt16 nNum
) const
444 return GetVertexGluePoint(nNum
);
447 const SdrGluePointList
* SdrEdgeObj::GetGluePointList() const
449 return NULL
; // no user defined glue points for connectors
452 SdrGluePointList
* SdrEdgeObj::ForceGluePointList()
454 return NULL
; // no user defined glue points for connectors
457 bool SdrEdgeObj::IsEdge() const
462 void SdrEdgeObj::ConnectToNode(bool bTail1
, SdrObject
* pObj
)
464 SdrObjConnection
& rCon
=GetConnection(bTail1
);
465 DisconnectFromNode(bTail1
);
467 pObj
->AddListener(*this);
470 // #i120437# If connection is set, reset bEdgeTrackUserDefined
471 bEdgeTrackUserDefined
= false;
477 void SdrEdgeObj::DisconnectFromNode(bool bTail1
)
479 SdrObjConnection
& rCon
=GetConnection(bTail1
);
480 if (rCon
.pObj
!=NULL
) {
481 rCon
.pObj
->RemoveListener(*this);
486 SdrObject
* SdrEdgeObj::GetConnectedNode(bool bTail1
) const
488 SdrObject
* pObj
=GetConnection(bTail1
).pObj
;
489 if (pObj
!=NULL
&& (pObj
->GetPage()!=pPage
|| !pObj
->IsInserted())) pObj
=NULL
;
493 bool SdrEdgeObj::CheckNodeConnection(bool bTail1
) const
496 const SdrObjConnection
& rCon
=GetConnection(bTail1
);
497 sal_uInt16 nPtAnz
=pEdgeTrack
->GetPointCount();
498 if (rCon
.pObj
!=NULL
&& rCon
.pObj
->GetPage()==pPage
&& nPtAnz
!=0) {
499 const SdrGluePointList
* pGPL
=rCon
.pObj
->GetGluePointList();
500 sal_uInt16 nConAnz
=pGPL
==NULL
? 0 : pGPL
->GetCount();
501 sal_uInt16 nGesAnz
=nConAnz
+8;
502 Point
aTail(bTail1
? (*pEdgeTrack
)[0] : (*pEdgeTrack
)[sal_uInt16(nPtAnz
-1)]);
503 for (sal_uInt16 i
=0; i
<nGesAnz
&& !bRet
; i
++) {
504 if (i
<nConAnz
) { // UserDefined
505 bRet
=aTail
==(*pGPL
)[i
].GetAbsolutePos(*rCon
.pObj
);
506 } else if (i
<nConAnz
+4) { // Vertex
507 SdrGluePoint
aPt(rCon
.pObj
->GetVertexGluePoint(i
-nConAnz
));
508 bRet
=aTail
==aPt
.GetAbsolutePos(*rCon
.pObj
);
510 SdrGluePoint
aPt(rCon
.pObj
->GetCornerGluePoint(i
-nConAnz
-4));
511 bRet
=aTail
==aPt
.GetAbsolutePos(*rCon
.pObj
);
518 void SdrEdgeObj::ImpSetTailPoint(bool bTail1
, const Point
& rPt
)
520 sal_uInt16 nPtAnz
=pEdgeTrack
->GetPointCount();
522 (*pEdgeTrack
)[0]=rPt
;
523 (*pEdgeTrack
)[1]=rPt
;
524 } else if (nPtAnz
==1) {
525 if (!bTail1
) (*pEdgeTrack
)[1]=rPt
;
526 else { (*pEdgeTrack
)[1]=(*pEdgeTrack
)[0]; (*pEdgeTrack
)[0]=rPt
; }
528 if (!bTail1
) (*pEdgeTrack
)[sal_uInt16(nPtAnz
-1)]=rPt
;
529 else (*pEdgeTrack
)[0]=rPt
;
531 ImpRecalcEdgeTrack();
535 void SdrEdgeObj::ImpDirtyEdgeTrack()
537 if ( !bEdgeTrackUserDefined
|| !(GetModel() && GetModel()->isLocked()) )
538 bEdgeTrackDirty
= true;
541 void SdrEdgeObj::ImpUndirtyEdgeTrack()
543 if (bEdgeTrackDirty
&& (GetModel() && GetModel()->isLocked()) ) {
544 ImpRecalcEdgeTrack();
548 void SdrEdgeObj::ImpRecalcEdgeTrack()
550 // #i120437# if bEdgeTrackUserDefined, do not recalculate
551 if(bEdgeTrackUserDefined
)
556 // #i120437# also not when model locked during import, but remember
557 if(!GetModel() || GetModel()->isLocked())
564 if(IsBoundRectCalculationRunning())
566 // This object is involved into another ImpRecalcEdgeTrack() call
567 // from another SdrEdgeObj. Do not calculate again to avoid loop.
568 // Also, do not change bEdgeTrackDirty so that it gets recalculated
569 // later at the first non-looping call.
575 // #i123048# If layouting was ever suppressed, it needs to be done once
576 // and the attr need to be set at EdgeInfo, else these attr *will be lost*
577 // in the following call to ImpSetEdgeInfoToAttr() sice they were never
579 *pEdgeTrack
=ImpCalcEdgeTrack(*pEdgeTrack
,aCon1
,aCon2
,&aEdgeInfo
);
580 ImpSetAttrToEdgeInfo();
581 mbSuppressed
= false;
584 // To not run in a depth loop, use a coloring algorithm on
585 // SdrEdgeObj BoundRect calculations
586 mbBoundRectCalculationRunning
= true;
588 Rectangle aBoundRect0
; if (pUserCall
!=NULL
) aBoundRect0
=GetCurrentBoundRect();
590 *pEdgeTrack
=ImpCalcEdgeTrack(*pEdgeTrack
,aCon1
,aCon2
,&aEdgeInfo
);
591 ImpSetEdgeInfoToAttr(); // copy values from aEdgeInfo into the pool
592 bEdgeTrackDirty
=false;
594 // Only redraw here, no object change
597 SendUserCall(SDRUSERCALL_RESIZE
,aBoundRect0
);
599 mbBoundRectCalculationRunning
= false;
603 sal_uInt16
SdrEdgeObj::ImpCalcEscAngle(SdrObject
* pObj
, const Point
& rPt
) const
605 if (pObj
==NULL
) return SDRESC_ALL
;
606 Rectangle
aR(pObj
->GetSnapRect());
607 long dxl
=rPt
.X()-aR
.Left();
608 long dyo
=rPt
.Y()-aR
.Top();
609 long dxr
=aR
.Right()-rPt
.X();
610 long dyu
=aR
.Bottom()-rPt
.Y();
611 bool bxMitt
=std::abs(dxl
-dxr
)<2;
612 bool byMitt
=std::abs(dyo
-dyu
)<2;
613 long dx
=std::min(dxl
,dxr
);
614 long dy
=std::min(dyo
,dyu
);
615 bool bDiag
=std::abs(dx
-dy
)<2;
616 if (bxMitt
&& byMitt
) return SDRESC_ALL
; // in the center
617 if (bDiag
) { // diagonally
619 if (byMitt
) nRet
|=SDRESC_VERT
;
620 if (bxMitt
) nRet
|=SDRESC_HORZ
;
621 if (dxl
<dxr
) { // left
622 if (dyo
<dyu
) nRet
|=SDRESC_LEFT
| SDRESC_TOP
;
623 else nRet
|=SDRESC_LEFT
| SDRESC_BOTTOM
;
625 if (dyo
<dyu
) nRet
|=SDRESC_RIGHT
| SDRESC_TOP
;
626 else nRet
|=SDRESC_RIGHT
| SDRESC_BOTTOM
;
630 if (dx
<dy
) { // horizontal
631 if (bxMitt
) return SDRESC_HORZ
;
632 if (dxl
<dxr
) return SDRESC_LEFT
;
633 else return SDRESC_RIGHT
;
635 if (byMitt
) return SDRESC_VERT
;
636 if (dyo
<dyu
) return SDRESC_TOP
;
637 else return SDRESC_BOTTOM
;
641 XPolygon
SdrEdgeObj::ImpCalcObjToCenter(const Point
& rStPt
, long nEscAngle
, const Rectangle
& rRect
, const Point
& rMeeting
) const
644 aXP
.Insert(XPOLY_APPEND
,rStPt
,XPOLY_NORMAL
);
645 bool bRts
=nEscAngle
==0;
646 bool bObn
=nEscAngle
==9000;
647 bool bLks
=nEscAngle
==18000;
648 bool bUnt
=nEscAngle
==27000;
650 Point
aP1(rStPt
); // mandatory difference first,...
651 if (bLks
) aP1
.X()=rRect
.Left();
652 if (bRts
) aP1
.X()=rRect
.Right();
653 if (bObn
) aP1
.Y()=rRect
.Top();
654 if (bUnt
) aP1
.Y()=rRect
.Bottom();
656 Point
aP2(aP1
); // ...now increase to Meeting height, if necessary
657 if (bLks
&& rMeeting
.X()<=aP2
.X()) aP2
.X()=rMeeting
.X();
658 if (bRts
&& rMeeting
.X()>=aP2
.X()) aP2
.X()=rMeeting
.X();
659 if (bObn
&& rMeeting
.Y()<=aP2
.Y()) aP2
.Y()=rMeeting
.Y();
660 if (bUnt
&& rMeeting
.Y()>=aP2
.Y()) aP2
.Y()=rMeeting
.Y();
661 aXP
.Insert(XPOLY_APPEND
,aP2
,XPOLY_NORMAL
);
664 if ((bLks
&& rMeeting
.X()>aP2
.X()) || (bRts
&& rMeeting
.X()<aP2
.X())) { // around
665 if (rMeeting
.Y()<aP2
.Y()) {
667 if (rMeeting
.Y()<aP3
.Y()) aP3
.Y()=rMeeting
.Y();
669 aP3
.Y()=rRect
.Bottom();
670 if (rMeeting
.Y()>aP3
.Y()) aP3
.Y()=rMeeting
.Y();
672 aXP
.Insert(XPOLY_APPEND
,aP3
,XPOLY_NORMAL
);
673 if (aP3
.Y()!=rMeeting
.Y()) {
674 aP3
.X()=rMeeting
.X();
675 aXP
.Insert(XPOLY_APPEND
,aP3
,XPOLY_NORMAL
);
678 if ((bObn
&& rMeeting
.Y()>aP2
.Y()) || (bUnt
&& rMeeting
.Y()<aP2
.Y())) { // around
679 if (rMeeting
.X()<aP2
.X()) {
680 aP3
.X()=rRect
.Left();
681 if (rMeeting
.X()<aP3
.X()) aP3
.X()=rMeeting
.X();
683 aP3
.X()=rRect
.Right();
684 if (rMeeting
.X()>aP3
.X()) aP3
.X()=rMeeting
.X();
686 aXP
.Insert(XPOLY_APPEND
,aP3
,XPOLY_NORMAL
);
687 if (aP3
.X()!=rMeeting
.X()) {
688 aP3
.Y()=rMeeting
.Y();
689 aXP
.Insert(XPOLY_APPEND
,aP3
,XPOLY_NORMAL
);
693 if (aXP
.GetPointCount()>4) {
694 OSL_FAIL("SdrEdgeObj::ImpCalcObjToCenter(): Polygon has more than 4 points!");
700 XPolygon
SdrEdgeObj::ImpCalcEdgeTrack(const XPolygon
& rTrack0
, SdrObjConnection
& rCon1
, SdrObjConnection
& rCon2
, SdrEdgeInfoRec
* pInfo
) const
703 SdrGluePoint aGP1
,aGP2
;
704 sal_uInt16 nEsc1
=SDRESC_ALL
,nEsc2
=SDRESC_ALL
;
705 Rectangle aBoundRect1
;
706 Rectangle aBoundRect2
;
707 Rectangle aBewareRect1
;
708 Rectangle aBewareRect2
;
709 // first, get the old corner points
710 if (rTrack0
.GetPointCount()!=0) {
712 sal_uInt16 nSiz
=rTrack0
.GetPointCount();
716 if (!aOutRect
.IsEmpty()) {
717 aPt1
=aOutRect
.TopLeft();
718 aPt2
=aOutRect
.BottomRight();
722 // #i54102# To allow interactive preview, do also if not inserted
723 bool bCon1
=rCon1
.pObj
!=NULL
&& rCon1
.pObj
->GetPage()==pPage
;
724 bool bCon2
=rCon2
.pObj
!=NULL
&& rCon2
.pObj
->GetPage()==pPage
;
726 const SfxItemSet
& rSet
= GetObjectItemSet();
729 if (rCon1
.pObj
==(SdrObject
*)this)
731 // check, just in case
732 aBoundRect1
=aOutRect
;
736 aBoundRect1
= rCon1
.pObj
->GetCurrentBoundRect();
738 aBoundRect1
.Move(rCon1
.aObjOfs
.X(),rCon1
.aObjOfs
.Y());
739 aBewareRect1
=aBoundRect1
;
741 sal_Int32 nH
= ((SdrEdgeNode1HorzDistItem
&)rSet
.Get(SDRATTR_EDGENODE1HORZDIST
)).GetValue();
742 sal_Int32 nV
= ((SdrEdgeNode1VertDistItem
&)rSet
.Get(SDRATTR_EDGENODE1VERTDIST
)).GetValue();
744 aBewareRect1
.Left()-=nH
;
745 aBewareRect1
.Right()+=nH
;
746 aBewareRect1
.Top()-=nV
;
747 aBewareRect1
.Bottom()+=nV
;
749 aBoundRect1
=Rectangle(aPt1
,aPt1
);
750 aBoundRect1
.Move(rCon1
.aObjOfs
.X(),rCon1
.aObjOfs
.Y());
751 aBewareRect1
=aBoundRect1
;
754 if (rCon2
.pObj
==(SdrObject
*)this) { // check, just in case
755 aBoundRect2
=aOutRect
;
759 aBoundRect2
= rCon2
.pObj
->GetCurrentBoundRect();
761 aBoundRect2
.Move(rCon2
.aObjOfs
.X(),rCon2
.aObjOfs
.Y());
762 aBewareRect2
=aBoundRect2
;
764 sal_Int32 nH
= ((SdrEdgeNode2HorzDistItem
&)rSet
.Get(SDRATTR_EDGENODE2HORZDIST
)).GetValue();
765 sal_Int32 nV
= ((SdrEdgeNode2VertDistItem
&)rSet
.Get(SDRATTR_EDGENODE2VERTDIST
)).GetValue();
767 aBewareRect2
.Left()-=nH
;
768 aBewareRect2
.Right()+=nH
;
769 aBewareRect2
.Top()-=nV
;
770 aBewareRect2
.Bottom()+=nV
;
772 aBoundRect2
=Rectangle(aPt2
,aPt2
);
773 aBoundRect2
.Move(rCon2
.aObjOfs
.X(),rCon2
.aObjOfs
.Y());
774 aBewareRect2
=aBoundRect2
;
777 sal_uIntPtr nBestQual
=0xFFFFFFFF;
778 SdrEdgeInfoRec aBestInfo
;
779 bool bAuto1
=bCon1
&& rCon1
.bBestVertex
;
780 bool bAuto2
=bCon2
&& rCon2
.bBestVertex
;
781 if (bAuto1
) rCon1
.bAutoVertex
=true;
782 if (bAuto2
) rCon2
.bAutoVertex
=true;
783 sal_uInt16 nBestAuto1
=0;
784 sal_uInt16 nBestAuto2
=0;
785 sal_uInt16 nAnz1
=bAuto1
? 4 : 1;
786 sal_uInt16 nAnz2
=bAuto2
? 4 : 1;
787 for (sal_uInt16 nNum1
=0; nNum1
<nAnz1
; nNum1
++) {
788 if (bAuto1
) rCon1
.nConId
=nNum1
;
789 if (bCon1
&& rCon1
.TakeGluePoint(aGP1
,true)) {
791 nEsc1
=aGP1
.GetEscDir();
792 if (nEsc1
==SDRESC_SMART
) nEsc1
=ImpCalcEscAngle(rCon1
.pObj
,aPt1
-rCon1
.aObjOfs
);
794 for (sal_uInt16 nNum2
=0; nNum2
<nAnz2
; nNum2
++) {
795 if (bAuto2
) rCon2
.nConId
=nNum2
;
796 if (bCon2
&& rCon2
.TakeGluePoint(aGP2
,true)) {
798 nEsc2
=aGP2
.GetEscDir();
799 if (nEsc2
==SDRESC_SMART
) nEsc2
=ImpCalcEscAngle(rCon2
.pObj
,aPt2
-rCon2
.aObjOfs
);
801 for (long nA1
=0; nA1
<36000; nA1
+=9000) {
802 sal_uInt16 nE1
=nA1
==0 ? SDRESC_RIGHT
: nA1
==9000 ? SDRESC_TOP
: nA1
==18000 ? SDRESC_LEFT
: nA1
==27000 ? SDRESC_BOTTOM
: 0;
803 for (long nA2
=0; nA2
<36000; nA2
+=9000) {
804 sal_uInt16 nE2
=nA2
==0 ? SDRESC_RIGHT
: nA2
==9000 ? SDRESC_TOP
: nA2
==18000 ? SDRESC_LEFT
: nA2
==27000 ? SDRESC_BOTTOM
: 0;
805 if ((nEsc1
&nE1
)!=0 && (nEsc2
&nE2
)!=0) {
807 SdrEdgeInfoRec aInfo
;
808 if (pInfo
!=NULL
) aInfo
=*pInfo
;
809 XPolygon
aXP(ImpCalcEdgeTrack(aPt1
,nA1
,aBoundRect1
,aBewareRect1
,aPt2
,nA2
,aBoundRect2
,aBewareRect2
,&nQual
,&aInfo
));
810 if (nQual
<nBestQual
) {
822 if (bAuto1
) rCon1
.nConId
=nBestAuto1
;
823 if (bAuto2
) rCon2
.nConId
=nBestAuto2
;
824 if (pInfo
!=NULL
) *pInfo
=aBestInfo
;
828 XPolygon
SdrEdgeObj::ImpCalcEdgeTrack(const Point
& rPt1
, long nAngle1
, const Rectangle
& rBoundRect1
, const Rectangle
& rBewareRect1
,
829 const Point
& rPt2
, long nAngle2
, const Rectangle
& rBoundRect2
, const Rectangle
& rBewareRect2
,
830 sal_uIntPtr
* pnQuality
, SdrEdgeInfoRec
* pInfo
) const
832 SdrEdgeKind eKind
=((SdrEdgeKindItem
&)(GetObjectItem(SDRATTR_EDGEKIND
))).GetValue();
833 bool bRts1
=nAngle1
==0;
834 bool bObn1
=nAngle1
==9000;
835 bool bLks1
=nAngle1
==18000;
836 bool bUnt1
=nAngle1
==27000;
837 bool bHor1
=bLks1
|| bRts1
;
838 bool bVer1
=bObn1
|| bUnt1
;
839 bool bRts2
=nAngle2
==0;
840 bool bObn2
=nAngle2
==9000;
841 bool bLks2
=nAngle2
==18000;
842 bool bUnt2
=nAngle2
==27000;
843 bool bHor2
=bLks2
|| bRts2
;
844 bool bVer2
=bObn2
|| bUnt2
;
845 bool bInfo
=pInfo
!=NULL
;
848 pInfo
->nAngle1
=nAngle1
;
849 pInfo
->nAngle2
=nAngle2
;
852 pInfo
->nMiddleLine
=0xFFFF;
856 Rectangle
aBoundRect1 (rBoundRect1
);
857 Rectangle
aBoundRect2 (rBoundRect2
);
858 Rectangle
aBewareRect1(rBewareRect1
);
859 Rectangle
aBewareRect2(rBewareRect2
);
860 Point
aMeeting((aPt1
.X()+aPt2
.X()+1)/2,(aPt1
.Y()+aPt2
.Y()+1)/2);
861 if (eKind
==SDREDGE_ONELINE
) {
865 if (pnQuality
!=NULL
) {
866 *pnQuality
=std::abs(rPt1
.X()-rPt2
.X())+std::abs(rPt1
.Y()-rPt2
.Y());
869 } else if (eKind
==SDREDGE_THREELINES
) {
875 if (bRts1
) aXP
[1].X()=aBewareRect1
.Right(); //+=500;
876 if (bObn1
) aXP
[1].Y()=aBewareRect1
.Top(); //-=500;
877 if (bLks1
) aXP
[1].X()=aBewareRect1
.Left(); //-=500;
878 if (bUnt1
) aXP
[1].Y()=aBewareRect1
.Bottom(); //+=500;
879 if (bRts2
) aXP
[2].X()=aBewareRect2
.Right(); //+=500;
880 if (bObn2
) aXP
[2].Y()=aBewareRect2
.Top(); //-=500;
881 if (bLks2
) aXP
[2].X()=aBewareRect2
.Left(); //-=500;
882 if (bUnt2
) aXP
[2].Y()=aBewareRect2
.Bottom(); //+=500;
883 if (pnQuality
!=NULL
) {
884 long nQ
=std::abs(aXP
[1].X()-aXP
[0].X())+std::abs(aXP
[1].Y()-aXP
[0].Y());
885 nQ
+=std::abs(aXP
[2].X()-aXP
[1].X())+std::abs(aXP
[2].Y()-aXP
[1].Y());
886 nQ
+=std::abs(aXP
[3].X()-aXP
[2].X())+std::abs(aXP
[3].Y()-aXP
[2].Y());
893 aXP
[1].X()+=pInfo
->aObj1Line2
.X();
895 aXP
[1].Y()+=pInfo
->aObj1Line2
.Y();
898 aXP
[2].X()+=pInfo
->aObj2Line2
.X();
900 aXP
[2].Y()+=pInfo
->aObj2Line2
.Y();
905 sal_uInt16 nIntersections
=0;
907 Point
aC1(aBewareRect1
.Center());
908 Point
aC2(aBewareRect2
.Center());
909 if (aBewareRect1
.Left()<=aBewareRect2
.Right() && aBewareRect1
.Right()>=aBewareRect2
.Left()) {
910 // overlapping on the x axis
911 long n1
=std::max(aBewareRect1
.Left(),aBewareRect2
.Left());
912 long n2
=std::min(aBewareRect1
.Right(),aBewareRect2
.Right());
913 aMeeting
.X()=(n1
+n2
+1)/2;
915 // otherwise the center point of the empty space
916 if (aC1
.X()<aC2
.X()) {
917 aMeeting
.X()=(aBewareRect1
.Right()+aBewareRect2
.Left()+1)/2;
919 aMeeting
.X()=(aBewareRect1
.Left()+aBewareRect2
.Right()+1)/2;
922 if (aBewareRect1
.Top()<=aBewareRect2
.Bottom() && aBewareRect1
.Bottom()>=aBewareRect2
.Top()) {
923 // overlapping on the x axis
924 long n1
=std::max(aBewareRect1
.Top(),aBewareRect2
.Top());
925 long n2
=std::min(aBewareRect1
.Bottom(),aBewareRect2
.Bottom());
926 aMeeting
.Y()=(n1
+n2
+1)/2;
928 // otherwise the center point of the empty space
929 if (aC1
.Y()<aC2
.Y()) {
930 aMeeting
.Y()=(aBewareRect1
.Bottom()+aBewareRect2
.Top()+1)/2;
932 aMeeting
.Y()=(aBewareRect1
.Top()+aBewareRect2
.Bottom()+1)/2;
935 // Here, there are three cases:
936 // 1. both go into the same direction
937 // 2. both go into opposite directions
938 // 3. one is vertical, the other is horizontal
939 long nXMin
=std::min(aBewareRect1
.Left(),aBewareRect2
.Left());
940 long nXMax
=std::max(aBewareRect1
.Right(),aBewareRect2
.Right());
941 long nYMin
=std::min(aBewareRect1
.Top(),aBewareRect2
.Top());
942 long nYMax
=std::max(aBewareRect1
.Bottom(),aBewareRect2
.Bottom());
943 bool bBewareOverlap
=aBewareRect1
.Right()>aBewareRect2
.Left() && aBewareRect1
.Left()<aBewareRect2
.Right() &&
944 aBewareRect1
.Bottom()>aBewareRect2
.Top() && aBewareRect1
.Top()<aBewareRect2
.Bottom();
945 unsigned nMainCase
=3;
946 if (nAngle1
==nAngle2
) nMainCase
=1;
947 else if ((bHor1
&& bHor2
) || (bVer1
&& bVer2
)) nMainCase
=2;
948 if (nMainCase
==1) { // case 1 (both go in one direction) is possible
949 if (bVer1
) aMeeting
.X()=(aPt1
.X()+aPt2
.X()+1)/2; // Here, this is better than
950 if (bHor1
) aMeeting
.Y()=(aPt1
.Y()+aPt2
.Y()+1)/2; // using center point of empty space
951 // bX1Ok means that the vertical exiting Obj1 doesn't conflict with Obj2, ...
952 bool bX1Ok
=aPt1
.X()<=aBewareRect2
.Left() || aPt1
.X()>=aBewareRect2
.Right();
953 bool bX2Ok
=aPt2
.X()<=aBewareRect1
.Left() || aPt2
.X()>=aBewareRect1
.Right();
954 bool bY1Ok
=aPt1
.Y()<=aBewareRect2
.Top() || aPt1
.Y()>=aBewareRect2
.Bottom();
955 bool bY2Ok
=aPt2
.Y()<=aBewareRect1
.Top() || aPt2
.Y()>=aBewareRect1
.Bottom();
956 if (bLks1
&& (bY1Ok
|| aBewareRect1
.Left()<aBewareRect2
.Right()) && (bY2Ok
|| aBewareRect2
.Left()<aBewareRect1
.Right())) {
959 if (bRts1
&& (bY1Ok
|| aBewareRect1
.Right()>aBewareRect2
.Left()) && (bY2Ok
|| aBewareRect2
.Right()>aBewareRect1
.Left())) {
962 if (bObn1
&& (bX1Ok
|| aBewareRect1
.Top()<aBewareRect2
.Bottom()) && (bX2Ok
|| aBewareRect2
.Top()<aBewareRect1
.Bottom())) {
965 if (bUnt1
&& (bX1Ok
|| aBewareRect1
.Bottom()>aBewareRect2
.Top()) && (bX2Ok
|| aBewareRect2
.Bottom()>aBewareRect1
.Top())) {
968 } else if (nMainCase
==2) {
970 if (bHor1
) { // both horizontal
972 (legend: line exits to the left (-|), right (|-))
974 2.1: Facing; overlap only on y axis
979 2.2, 2.3: Facing, offset vertically; no overlap on either
985 2.4, 2.5: One below the other; overlap only on y axis
990 2.6, 2.7: Not facing, offset vertically; no overlap on either
996 2.8: Not facing; overlap only on y axis
1001 2.9: The objects's BewareRects overlap on x and y axis
1003 These cases, with some modifications are also valid for
1004 horizontal line exits.
1005 Cases 2.1 through 2.7 are covered well enough with the
1006 default meetings. Only for cases 2.8 and 2.9 do we determine
1007 special meeting points here.
1010 // normalization; be aR1 the one exiting to the right,
1011 // be aR2 the one exiting to the left
1012 Rectangle
aBewR1(bRts1
? aBewareRect1
: aBewareRect2
);
1013 Rectangle
aBewR2(bRts1
? aBewareRect2
: aBewareRect1
);
1014 Rectangle
aBndR1(bRts1
? aBoundRect1
: aBoundRect2
);
1015 Rectangle
aBndR2(bRts1
? aBoundRect2
: aBoundRect1
);
1016 if (aBewR1
.Bottom()>aBewR2
.Top() && aBewR1
.Top()<aBewR2
.Bottom()) {
1017 // overlap on y axis; cases 2.1, 2.8, 2.9
1018 if (aBewR1
.Right()>aBewR2
.Left()) {
1020 Case 2.8: always going around on the outside
1023 Case 2.9 could also be a direct connection (in the
1024 case that the BewareRects overlap only slightly and
1025 the BoundRects don't overlap at all and if the
1026 line exits would otherwise violate the respective
1027 other object's BewareRect).
1029 bool bCase29Direct
= false;
1030 bool bCase29
=aBewR1
.Right()>aBewR2
.Left();
1031 if (aBndR1
.Right()<=aBndR2
.Left()) { // case 2.9 without BoundRect overlap
1032 if ((aPt1
.Y()>aBewareRect2
.Top() && aPt1
.Y()<aBewareRect2
.Bottom()) ||
1033 (aPt2
.Y()>aBewareRect1
.Top() && aPt2
.Y()<aBewareRect1
.Bottom())) {
1034 bCase29Direct
= true;
1037 if (!bCase29Direct
) {
1038 bool bObenLang
=std::abs(nYMin
-aMeeting
.Y())<=std::abs(nYMax
-aMeeting
.Y());
1045 // now make sure that the surrounded object
1047 if ((aBewR1
.Center().Y()<aBewR2
.Center().Y()) != bObenLang
) {
1048 aMeeting
.X()=aBewR2
.Right();
1050 aMeeting
.X()=aBewR1
.Left();
1054 // We need a direct connection (3-line Z connection),
1055 // because we have to violate the BewareRects.
1056 // Use rule of three to scale down the BewareRects.
1057 long nWant1
=aBewR1
.Right()-aBndR1
.Right(); // distance at Obj1
1058 long nWant2
=aBndR2
.Left()-aBewR2
.Left(); // distance at Obj2
1059 long nSpace
=aBndR2
.Left()-aBndR1
.Right(); // available space
1060 long nGet1
=BigMulDiv(nWant1
,nSpace
,nWant1
+nWant2
);
1061 long nGet2
=nSpace
-nGet1
;
1062 if (bRts1
) { // revert normalization
1063 aBewareRect1
.Right()+=nGet1
-nWant1
;
1064 aBewareRect2
.Left()-=nGet2
-nWant2
;
1066 aBewareRect2
.Right()+=nGet1
-nWant1
;
1067 aBewareRect1
.Left()-=nGet2
-nWant2
;
1069 nIntersections
++; // lower quality
1073 } else if (bVer1
) { // both horizontal
1074 Rectangle
aBewR1(bUnt1
? aBewareRect1
: aBewareRect2
);
1075 Rectangle
aBewR2(bUnt1
? aBewareRect2
: aBewareRect1
);
1076 Rectangle
aBndR1(bUnt1
? aBoundRect1
: aBoundRect2
);
1077 Rectangle
aBndR2(bUnt1
? aBoundRect2
: aBoundRect1
);
1078 if (aBewR1
.Right()>aBewR2
.Left() && aBewR1
.Left()<aBewR2
.Right()) {
1079 // overlap on y axis; cases 2.1, 2.8, 2.9
1080 if (aBewR1
.Bottom()>aBewR2
.Top()) {
1082 Case 2.8 always going around on the outside (bDirect=false).
1084 Case 2.9 could also be a direct connection (in the
1085 case that the BewareRects overlap only slightly and
1086 the BoundRects don't overlap at all and if the
1087 line exits would otherwise violate the respective
1088 other object's BewareRect).
1090 bool bCase29Direct
= false;
1091 bool bCase29
=aBewR1
.Bottom()>aBewR2
.Top();
1092 if (aBndR1
.Bottom()<=aBndR2
.Top()) { // case 2.9 without BoundRect overlap
1093 if ((aPt1
.X()>aBewareRect2
.Left() && aPt1
.X()<aBewareRect2
.Right()) ||
1094 (aPt2
.X()>aBewareRect1
.Left() && aPt2
.X()<aBewareRect1
.Right())) {
1095 bCase29Direct
= true;
1098 if (!bCase29Direct
) {
1099 bool bLinksLang
=std::abs(nXMin
-aMeeting
.X())<=std::abs(nXMax
-aMeeting
.X());
1106 // now make sure that the surrounded object
1108 if ((aBewR1
.Center().X()<aBewR2
.Center().X()) != bLinksLang
) {
1109 aMeeting
.Y()=aBewR2
.Bottom();
1111 aMeeting
.Y()=aBewR1
.Top();
1115 // We need a direct connection (3-line Z connection),
1116 // because we have to violate the BewareRects.
1117 // Use rule of three to scale down the BewareRects.
1118 long nWant1
=aBewR1
.Bottom()-aBndR1
.Bottom(); // difference at Obj1
1119 long nWant2
=aBndR2
.Top()-aBewR2
.Top(); // difference at Obj2
1120 long nSpace
=aBndR2
.Top()-aBndR1
.Bottom(); // available space
1121 long nGet1
=BigMulDiv(nWant1
,nSpace
,nWant1
+nWant2
);
1122 long nGet2
=nSpace
-nGet1
;
1123 if (bUnt1
) { // revert normalization
1124 aBewareRect1
.Bottom()+=nGet1
-nWant1
;
1125 aBewareRect2
.Top()-=nGet2
-nWant2
;
1127 aBewareRect2
.Bottom()+=nGet1
-nWant1
;
1128 aBewareRect1
.Top()-=nGet2
-nWant2
;
1130 nIntersections
++; // lower quality
1135 } else if (nMainCase
==3) { // case 3: one horizontal, the other vertical
1137 The line exits to the:
1146 * . * . * -- no overlap, at most might touch
1147 . . . . . -- overlap
1148 * . |- . * -- same height
1149 . . . . . -- overlap
1150 * . * . * -- no overlap, at most might touch
1152 Overall, there are 96 possible constellations, some of these can't even
1153 be unambiguously assigned to a certain case/method of handling.
1156 3.1: All those constellations that are covered reasonably well
1157 by the default MeetingPoint (20+12).
1159 T T T . _|_ _|_ . T T T these 12 * . * T * * . * . * * T * . * * . * . *
1160 . . . . _|_ _|_ . . . . constellations . . . . . . . . . T . . . . . T . . . .
1161 * . |- . * * . -| . * are covered * . |- . _|_ * . |- . T _|_ . -| . * T . -| . *
1162 . . . . T T . . . . only in . . . . _|_ . . . . . _|_ . . . . . . . . .
1163 _|__|__|_ . T T . _|__|__|_ part: * . * _|_ * * . * . * * _|_ * . * * . * . *
1165 The last 16 of these cases can be excluded, if the objects face each other openly.
1168 3.2: The objects face each other openly, thus a connection using only two lines is possible (4+20);
1169 This case is priority #1.
1170 * . * . T T . * . * these 20 * . * T * * T * . * * . * . * * . * . *
1171 . . . . . . . . . . constellations . . . T T T T . . . . . . . . . . . . .
1172 * . |- . * * . -| . * are covered * . |-_|__|_ _|__|_-| . * * . |- T T T T -| . *
1173 . . . . . . . . . . only in . . . _|__|_ _|__|_ . . . . . . . . . . . . .
1174 * . * . _|_ _|_ . * . * part: * . * _|_ * * _|_ * . * * . * . * * . * . *
1176 3.3: The line exits point away from the other object or or miss its back (52+4).
1177 _|__|__|__|_ * * _|__|__|__|_ * . . . * * . * . * these 4 * . * . * * . * . *
1178 _|__|__|__|_ . . _|__|__|__|_ T T T . . . . T T T constellations . . . T . . T . . .
1179 _|__|_ |- . * * . -| _|__|_ T T |- . * * . -| T T are covered * . |- . * * . -| . *
1180 _|__|__|_ . . . . _|__|__|_ T T T T . . T T T T only in . . . _|_ . . _|_ . . .
1181 * . * . * * . * . * T T T T * * T T T T part: * . * . * * . * . *
1185 Rectangle
aTmpR1(aBewareRect1
);
1186 Rectangle
aTmpR2(aBewareRect2
);
1187 if (bBewareOverlap
) {
1188 // overlapping BewareRects: use BoundRects for checking for case 3.2
1192 if ((((bRts1
&& aTmpR1
.Right ()<=aPt2
.X()) || (bLks1
&& aTmpR1
.Left()>=aPt2
.X())) &&
1193 ((bUnt2
&& aTmpR2
.Bottom()<=aPt1
.Y()) || (bObn2
&& aTmpR2
.Top ()>=aPt1
.Y()))) ||
1194 (((bRts2
&& aTmpR2
.Right ()<=aPt1
.X()) || (bLks2
&& aTmpR2
.Left()>=aPt1
.X())) &&
1195 ((bUnt1
&& aTmpR1
.Bottom()<=aPt2
.Y()) || (bObn1
&& aTmpR1
.Top ()>=aPt2
.Y())))) {
1196 // case 3.2 applies: connector with only 2 lines
1198 aMeeting
.X()=aPt2
.X();
1199 aMeeting
.Y()=aPt1
.Y();
1201 aMeeting
.X()=aPt1
.X();
1202 aMeeting
.Y()=aPt2
.Y();
1204 // in the case of overlapping BewareRects:
1205 aBewareRect1
=aTmpR1
;
1206 aBewareRect2
=aTmpR2
;
1207 } else if ((((bRts1
&& aBewareRect1
.Right ()>aBewareRect2
.Left ()) ||
1208 (bLks1
&& aBewareRect1
.Left ()<aBewareRect2
.Right ())) &&
1209 ((bUnt2
&& aBewareRect2
.Bottom()>aBewareRect1
.Top ()) ||
1210 (bObn2
&& aBewareRect2
.Top ()<aBewareRect1
.Bottom()))) ||
1211 (((bRts2
&& aBewareRect2
.Right ()>aBewareRect1
.Left ()) ||
1212 (bLks2
&& aBewareRect2
.Left ()<aBewareRect1
.Right ())) &&
1213 ((bUnt1
&& aBewareRect1
.Bottom()>aBewareRect2
.Top ()) ||
1214 (bObn1
&& aBewareRect1
.Top ()<aBewareRect2
.Bottom())))) {
1216 if (bRts1
|| bRts2
) { aMeeting
.X()=nXMax
; }
1217 if (bLks1
|| bLks2
) { aMeeting
.X()=nXMin
; }
1218 if (bUnt1
|| bUnt2
) { aMeeting
.Y()=nYMax
; }
1219 if (bObn1
|| bObn2
) { aMeeting
.Y()=nYMin
; }
1224 XPolygon
aXP1(ImpCalcObjToCenter(aPt1
,nAngle1
,aBewareRect1
,aMeeting
));
1225 XPolygon
aXP2(ImpCalcObjToCenter(aPt2
,nAngle2
,aBewareRect2
,aMeeting
));
1226 sal_uInt16 nXP1Anz
=aXP1
.GetPointCount();
1227 sal_uInt16 nXP2Anz
=aXP2
.GetPointCount();
1229 pInfo
->nObj1Lines
=nXP1Anz
; if (nXP1Anz
>1) pInfo
->nObj1Lines
--;
1230 pInfo
->nObj2Lines
=nXP2Anz
; if (nXP2Anz
>1) pInfo
->nObj2Lines
--;
1232 Point
aEP1(aXP1
[nXP1Anz
-1]);
1233 Point
aEP2(aXP2
[nXP2Anz
-1]);
1234 bool bInsMeetingPoint
=aEP1
.X()!=aEP2
.X() && aEP1
.Y()!=aEP2
.Y();
1235 bool bHorzE1
=aEP1
.Y()==aXP1
[nXP1Anz
-2].Y(); // is last line of XP1 horizontal?
1236 bool bHorzE2
=aEP2
.Y()==aXP2
[nXP2Anz
-2].Y(); // is last line of XP2 horizontal?
1237 if (aEP1
==aEP2
&& ((bHorzE1
&& bHorzE2
&& aEP1
.Y()==aEP2
.Y()) || (!bHorzE1
&& !bHorzE2
&& aEP1
.X()==aEP2
.X()))) {
1238 // special casing 'I' connectors
1239 nXP1Anz
--; aXP1
.Remove(nXP1Anz
,1);
1240 nXP2Anz
--; aXP2
.Remove(nXP2Anz
,1);
1242 if (bInsMeetingPoint
) {
1243 aXP1
.Insert(XPOLY_APPEND
,aMeeting
,XPOLY_NORMAL
);
1245 // Inserting a MeetingPoint adds 2 new lines,
1246 // either might become the center line.
1247 if (pInfo
->nObj1Lines
==pInfo
->nObj2Lines
) {
1248 pInfo
->nObj1Lines
++;
1249 pInfo
->nObj2Lines
++;
1251 if (pInfo
->nObj1Lines
>pInfo
->nObj2Lines
) {
1252 pInfo
->nObj2Lines
++;
1253 pInfo
->nMiddleLine
=nXP1Anz
-1;
1255 pInfo
->nObj1Lines
++;
1256 pInfo
->nMiddleLine
=nXP1Anz
;
1260 } else if (bInfo
&& aEP1
!=aEP2
&& nXP1Anz
+nXP2Anz
>=4) {
1261 // By connecting both ends, another line is added, this becomes the center line.
1262 pInfo
->nMiddleLine
=nXP1Anz
-1;
1264 sal_uInt16 nNum
=aXP2
.GetPointCount();
1265 if (aXP1
[nXP1Anz
-1]==aXP2
[nXP2Anz
-1] && nXP1Anz
>1 && nXP2Anz
>1) nNum
--;
1268 aXP1
.Insert(XPOLY_APPEND
,aXP2
[nNum
],XPOLY_NORMAL
);
1270 sal_uInt16 nPntAnz
=aXP1
.GetPointCount();
1272 if (bInfo
|| pnQuality
!=NULL
) {
1274 if (nPntAnz
==2) cForm
='I';
1275 else if (nPntAnz
==3) cForm
='L';
1276 else if (nPntAnz
==4) { // Z or U
1277 if (nAngle1
==nAngle2
) cForm
='U';
1279 } else if (nPntAnz
==6) { // S or C or ...
1280 if (nAngle1
!=nAngle2
) {
1281 // For type S, line 2 has the same direction as line 4.
1282 // For type C, the opposite is true.
1287 if (aP1
.Y()==aP2
.Y()) { // else both lines are horizontal
1288 if ((aP1
.X()<aP2
.X())==(aP3
.X()<aP4
.X())) cForm
='S';
1290 } else { // else both lines are vertical
1291 if ((aP1
.Y()<aP2
.Y())==(aP3
.Y()<aP4
.Y())) cForm
='S';
1294 } else cForm
='4'; // else is case 3 with 5 lines
1298 pInfo
->cOrthoForm
=cForm
;
1299 if (cForm
=='I' || cForm
=='L' || cForm
=='Z' || cForm
=='U') {
1300 pInfo
->nObj1Lines
=1;
1301 pInfo
->nObj2Lines
=1;
1302 if (cForm
=='Z' || cForm
=='U') {
1303 pInfo
->nMiddleLine
=1;
1305 pInfo
->nMiddleLine
=0xFFFF;
1307 } else if (cForm
=='S' || cForm
=='C') {
1308 pInfo
->nObj1Lines
=2;
1309 pInfo
->nObj2Lines
=2;
1310 pInfo
->nMiddleLine
=2;
1314 if (pnQuality
!=NULL
) {
1315 sal_uIntPtr nQual
=0;
1316 sal_uIntPtr nQual0
=nQual
; // prevent overruns
1317 bool bOverflow
= false;
1318 Point
aPt0(aXP1
[0]);
1319 for (sal_uInt16 nPntNum
=1; nPntNum
<nPntAnz
; nPntNum
++) {
1320 Point
aPt1b(aXP1
[nPntNum
]);
1321 nQual
+=std::abs(aPt1b
.X()-aPt0
.X())+std::abs(aPt1b
.Y()-aPt0
.Y());
1322 if (nQual
<nQual0
) bOverflow
= true;
1327 sal_uInt16 nTmp
=nPntAnz
;
1329 nTmp
=2; // Z shape with good quality (nTmp=2 instead of 4)
1330 sal_uIntPtr n1
=std::abs(aXP1
[1].X()-aXP1
[0].X())+std::abs(aXP1
[1].Y()-aXP1
[0].Y());
1331 sal_uIntPtr n2
=std::abs(aXP1
[2].X()-aXP1
[1].X())+std::abs(aXP1
[2].Y()-aXP1
[1].Y());
1332 sal_uIntPtr n3
=std::abs(aXP1
[3].X()-aXP1
[2].X())+std::abs(aXP1
[3].Y()-aXP1
[2].Y());
1333 // try to make lines lengths similar
1334 sal_uIntPtr nBesser
=0;
1337 if (n1
>=n2
) nBesser
=6;
1338 else if (n1
>=3*n3
) nBesser
=4;
1339 else if (n1
>=2*n3
) nBesser
=2;
1340 if (aXP1
[0].Y()!=aXP1
[1].Y()) nBesser
++; // vertical starting line gets a plus (for H/V-Prio)
1341 if (nQual
>nBesser
) nQual
-=nBesser
; else nQual
=0;
1345 nQual
+=(sal_uIntPtr
)nTmp
*0x01000000;
1346 if (nQual
<nQual0
|| nTmp
>15) bOverflow
= true;
1348 if (nPntAnz
>=2) { // check exit angle again
1349 Point
aP1(aXP1
[1]); aP1
-=aXP1
[0];
1350 Point
aP2(aXP1
[nPntAnz
-2]); aP2
-=aXP1
[nPntAnz
-1];
1351 long nAng1
=0; if (aP1
.X()<0) nAng1
=18000; if (aP1
.Y()>0) nAng1
=27000;
1352 if (aP1
.Y()<0) nAng1
=9000; if (aP1
.X()!=0 && aP1
.Y()!=0) nAng1
=1; // slant?!
1353 long nAng2
=0; if (aP2
.X()<0) nAng2
=18000; if (aP2
.Y()>0) nAng2
=27000;
1354 if (aP2
.Y()<0) nAng2
=9000; if (aP2
.X()!=0 && aP2
.Y()!=0) nAng2
=1; // slant?!
1355 if (nAng1
!=nAngle1
) nIntersections
++;
1356 if (nAng2
!=nAngle2
) nIntersections
++;
1359 // For the quality check, use the original Rects and at the same time
1360 // check whether one them was scaled down for the calculation of the
1361 // Edges (e. g. case 2.9)
1362 aBewareRect1
=rBewareRect1
;
1363 aBewareRect2
=rBewareRect2
;
1365 for (sal_uInt16 i
=0; i
<nPntAnz
; i
++) {
1366 Point
aPt1b(aXP1
[i
]);
1367 bool b1
=aPt1b
.X()>aBewareRect1
.Left() && aPt1b
.X()<aBewareRect1
.Right() &&
1368 aPt1b
.Y()>aBewareRect1
.Top() && aPt1b
.Y()<aBewareRect1
.Bottom();
1369 bool b2
=aPt1b
.X()>aBewareRect2
.Left() && aPt1b
.X()<aBewareRect2
.Right() &&
1370 aPt1b
.Y()>aBewareRect2
.Top() && aPt1b
.Y()<aBewareRect2
.Bottom();
1371 sal_uInt16 nInt0
=nIntersections
;
1372 if (i
==0 || i
==nPntAnz
-1) {
1373 if (b1
&& b2
) nIntersections
++;
1375 if (b1
) nIntersections
++;
1376 if (b2
) nIntersections
++;
1378 // check for overlaps
1379 if (i
>0 && nInt0
==nIntersections
) {
1380 if (aPt0
.Y()==aPt1b
.Y()) { // horizontal line
1381 if (aPt0
.Y()>aBewareRect1
.Top() && aPt0
.Y()<aBewareRect1
.Bottom() &&
1382 ((aPt0
.X()<=aBewareRect1
.Left() && aPt1b
.X()>=aBewareRect1
.Right()) ||
1383 (aPt1b
.X()<=aBewareRect1
.Left() && aPt0
.X()>=aBewareRect1
.Right()))) nIntersections
++;
1384 if (aPt0
.Y()>aBewareRect2
.Top() && aPt0
.Y()<aBewareRect2
.Bottom() &&
1385 ((aPt0
.X()<=aBewareRect2
.Left() && aPt1b
.X()>=aBewareRect2
.Right()) ||
1386 (aPt1b
.X()<=aBewareRect2
.Left() && aPt0
.X()>=aBewareRect2
.Right()))) nIntersections
++;
1387 } else { // vertical line
1388 if (aPt0
.X()>aBewareRect1
.Left() && aPt0
.X()<aBewareRect1
.Right() &&
1389 ((aPt0
.Y()<=aBewareRect1
.Top() && aPt1b
.Y()>=aBewareRect1
.Bottom()) ||
1390 (aPt1b
.Y()<=aBewareRect1
.Top() && aPt0
.Y()>=aBewareRect1
.Bottom()))) nIntersections
++;
1391 if (aPt0
.X()>aBewareRect2
.Left() && aPt0
.X()<aBewareRect2
.Right() &&
1392 ((aPt0
.Y()<=aBewareRect2
.Top() && aPt1b
.Y()>=aBewareRect2
.Bottom()) ||
1393 (aPt1b
.Y()<=aBewareRect2
.Top() && aPt0
.Y()>=aBewareRect2
.Bottom()))) nIntersections
++;
1398 if (nPntAnz
<=1) nIntersections
++;
1400 nQual
+=(sal_uIntPtr
)nIntersections
*0x10000000;
1401 if (nQual
<nQual0
|| nIntersections
>15) bOverflow
= true;
1403 if (bOverflow
|| nQual
==0xFFFFFFFF) nQual
=0xFFFFFFFE;
1406 if (bInfo
) { // now apply line offsets to aXP1
1407 if (pInfo
->nMiddleLine
!=0xFFFF) {
1408 sal_uInt16 nIdx
=pInfo
->ImpGetPolyIdx(MIDDLELINE
,aXP1
);
1409 if (pInfo
->ImpIsHorzLine(MIDDLELINE
,aXP1
)) {
1410 aXP1
[nIdx
].Y()+=pInfo
->aMiddleLine
.Y();
1411 aXP1
[nIdx
+1].Y()+=pInfo
->aMiddleLine
.Y();
1413 aXP1
[nIdx
].X()+=pInfo
->aMiddleLine
.X();
1414 aXP1
[nIdx
+1].X()+=pInfo
->aMiddleLine
.X();
1417 if (pInfo
->nObj1Lines
>=2) {
1418 sal_uInt16 nIdx
=pInfo
->ImpGetPolyIdx(OBJ1LINE2
,aXP1
);
1419 if (pInfo
->ImpIsHorzLine(OBJ1LINE2
,aXP1
)) {
1420 aXP1
[nIdx
].Y()+=pInfo
->aObj1Line2
.Y();
1421 aXP1
[nIdx
+1].Y()+=pInfo
->aObj1Line2
.Y();
1423 aXP1
[nIdx
].X()+=pInfo
->aObj1Line2
.X();
1424 aXP1
[nIdx
+1].X()+=pInfo
->aObj1Line2
.X();
1427 if (pInfo
->nObj1Lines
>=3) {
1428 sal_uInt16 nIdx
=pInfo
->ImpGetPolyIdx(OBJ1LINE3
,aXP1
);
1429 if (pInfo
->ImpIsHorzLine(OBJ1LINE3
,aXP1
)) {
1430 aXP1
[nIdx
].Y()+=pInfo
->aObj1Line3
.Y();
1431 aXP1
[nIdx
+1].Y()+=pInfo
->aObj1Line3
.Y();
1433 aXP1
[nIdx
].X()+=pInfo
->aObj1Line3
.X();
1434 aXP1
[nIdx
+1].X()+=pInfo
->aObj1Line3
.X();
1437 if (pInfo
->nObj2Lines
>=2) {
1438 sal_uInt16 nIdx
=pInfo
->ImpGetPolyIdx(OBJ2LINE2
,aXP1
);
1439 if (pInfo
->ImpIsHorzLine(OBJ2LINE2
,aXP1
)) {
1440 aXP1
[nIdx
].Y()+=pInfo
->aObj2Line2
.Y();
1441 aXP1
[nIdx
+1].Y()+=pInfo
->aObj2Line2
.Y();
1443 aXP1
[nIdx
].X()+=pInfo
->aObj2Line2
.X();
1444 aXP1
[nIdx
+1].X()+=pInfo
->aObj2Line2
.X();
1447 if (pInfo
->nObj2Lines
>=3) {
1448 sal_uInt16 nIdx
=pInfo
->ImpGetPolyIdx(OBJ2LINE3
,aXP1
);
1449 if (pInfo
->ImpIsHorzLine(OBJ2LINE3
,aXP1
)) {
1450 aXP1
[nIdx
].Y()+=pInfo
->aObj2Line3
.Y();
1451 aXP1
[nIdx
+1].Y()+=pInfo
->aObj2Line3
.Y();
1453 aXP1
[nIdx
].X()+=pInfo
->aObj2Line3
.X();
1454 aXP1
[nIdx
+1].X()+=pInfo
->aObj2Line3
.X();
1458 // make the connector a bezier curve, if appropriate
1459 if (eKind
==SDREDGE_BEZIER
&& nPntAnz
>2) {
1460 Point
* pPt1
=&aXP1
[0];
1461 Point
* pPt2
=&aXP1
[1];
1462 Point
* pPt3
=&aXP1
[nPntAnz
-2];
1463 Point
* pPt4
=&aXP1
[nPntAnz
-1];
1464 long dx1
=pPt2
->X()-pPt1
->X();
1465 long dy1
=pPt2
->Y()-pPt1
->Y();
1466 long dx2
=pPt3
->X()-pPt4
->X();
1467 long dy2
=pPt3
->Y()-pPt4
->Y();
1468 if (cForm
=='L') { // nPntAnz==3
1469 aXP1
.SetFlags(1,XPOLY_CONTROL
);
1471 aXP1
.Insert(2,aPt3
,XPOLY_CONTROL
);
1472 nPntAnz
=aXP1
.GetPointCount();
1474 pPt3
=&aXP1
[nPntAnz
-2];
1479 } else if (nPntAnz
>=4 && nPntAnz
<=6) { // Z or U or ...
1480 // To all others, the end points of the original lines become control
1481 // points for now. Thus, we need to do some more work for nPntAnz>4!
1482 aXP1
.SetFlags(1,XPOLY_CONTROL
);
1483 aXP1
.SetFlags(nPntAnz
-2,XPOLY_CONTROL
);
1490 // add a control point before and after center
1491 Point
aCenter(aXP1
[2]);
1492 long dx1b
=aCenter
.X()-aXP1
[1].X();
1493 long dy1b
=aCenter
.Y()-aXP1
[1].Y();
1494 long dx2b
=aCenter
.X()-aXP1
[3].X();
1495 long dy2b
=aCenter
.Y()-aXP1
[3].Y();
1496 aXP1
.Insert(2,aCenter
,XPOLY_CONTROL
);
1497 aXP1
.SetFlags(3,XPOLY_SYMMTR
);
1498 aXP1
.Insert(4,aCenter
,XPOLY_CONTROL
);
1499 aXP1
[2].X()-=dx1b
/2;
1500 aXP1
[2].Y()-=dy1b
/2;
1501 aXP1
[3].X()-=(dx1b
+dx2b
)/4;
1502 aXP1
[3].Y()-=(dy1b
+dy2b
)/4;
1503 aXP1
[4].X()-=dx2b
/2;
1504 aXP1
[4].Y()-=dy2b
/2;
1507 Point
aPt1b(aXP1
[2]);
1508 Point
aPt2b(aXP1
[3]);
1509 aXP1
.Insert(2,aPt1b
,XPOLY_CONTROL
);
1510 aXP1
.Insert(5,aPt2b
,XPOLY_CONTROL
);
1511 long dx
=aPt1b
.X()-aPt2b
.X();
1512 long dy
=aPt1b
.Y()-aPt2b
.Y();
1515 aXP1
.SetFlags(3,XPOLY_SYMMTR
);
1516 aXP1
.Remove(4,1); // because it's identical with aXP1[3]
1524 There could be a maximum of 64 different developments with with 5 lines, a
1525 maximum of 32 developments with 4 lines, a maximum of 16 developments with
1526 3 lines, a maximum of 8 developments with 2 lines.
1527 This gives us a total of 124 possibilities.
1528 Normalized for the 1st exit angle to the right, there remain 31 possibilities.
1529 Now, normalizing away the vertical mirroring, we get to a total of 16
1530 characteristic developments with 1 through 5 lines:
1532 1 line (type "I") --
1534 2 lines (type "L") __|
1536 3 lines (type "U") __ (type "Z") _
1539 4 lines #1 _| #2 | | #3 |_ #4 | |
1541 Of these, #1 is implausible, #2 is a rotated version of #3. This leaves
1542 #2 (from now on referred to as 4.1) and #4 (from now on referred to as 4.2).
1544 5 lines #1 _| #2 _| #3 ___ #4 _
1547 #5 |_ #6 |_ #7 _| | #8 ____
1549 Of these, 5.1, 5.2, 5.4 and 5.5 are implausible, 5.7 is a reversed version
1550 of 5.3. This leaves 5.3 (type "4"), 5.6 (type "S") and 5.8 (type "C").
1552 We now have discerned the 9 basic types to cover all 400 possible constellations
1553 of object positions and exit angles. 4 of the 9 types have got a center
1554 line (CL). The number of object margins per object varies between 0 and 3:
1561 4.2: y 0 1 = U+1, respectively 1+U
1562 4.4: n 0-2 0-2 = Z+1
1565 "C": n 0-3 0-3 = 1+U+1
1568 void SdrEdgeObj::Notify(SfxBroadcaster
& rBC
, const SfxHint
& rHint
)
1570 SfxSimpleHint
* pSimple
=PTR_CAST(SfxSimpleHint
,&rHint
);
1571 sal_uIntPtr nId
=pSimple
==0 ? 0 : pSimple
->GetId();
1572 bool bDataChg
=nId
==SFX_HINT_DATACHANGED
;
1573 bool bDying
=nId
==SFX_HINT_DYING
;
1574 bool bObj1
=aCon1
.pObj
!=NULL
&& aCon1
.pObj
->GetBroadcaster()==&rBC
;
1575 bool bObj2
=aCon2
.pObj
!=NULL
&& aCon2
.pObj
->GetBroadcaster()==&rBC
;
1576 if (bDying
&& (bObj1
|| bObj2
)) {
1577 // catch Dying, so AttrObj doesn't start broadcasting
1578 // about an alleged change of template
1579 if (bObj1
) aCon1
.pObj
=NULL
;
1580 if (bObj2
) aCon2
.pObj
=NULL
;
1583 if ( bObj1
|| bObj2
)
1585 bEdgeTrackUserDefined
= false;
1587 SdrTextObj::Notify(rBC
,rHint
);
1588 if (nNotifyingCount
==0) { // a locking flag
1589 ((SdrEdgeObj
*)this)->nNotifyingCount
++;
1590 SdrHint
* pSdrHint
=PTR_CAST(SdrHint
,&rHint
);
1591 if (bDataChg
) { // StyleSheet changed
1592 ImpSetAttrToEdgeInfo(); // when changing templates, copy values from Pool to aEdgeInfo
1595 (bObj1
&& aCon1
.pObj
->GetPage()==pPage
) ||
1596 (bObj2
&& aCon2
.pObj
->GetPage()==pPage
) ||
1597 (pSdrHint
&& pSdrHint
->GetKind()==HINT_OBJREMOVED
))
1599 // broadcasting only, if on the same page
1600 Rectangle aBoundRect0
; if (pUserCall
!=NULL
) aBoundRect0
=GetCurrentBoundRect();
1601 ImpDirtyEdgeTrack();
1603 // only redraw here, object hasn't actually changed
1606 SendUserCall(SDRUSERCALL_RESIZE
,aBoundRect0
);
1608 ((SdrEdgeObj
*)this)->nNotifyingCount
--;
1612 /** updates edges that are connected to the edges of this object
1613 as if the connected objects sent a repaint broadcast
1615 void SdrEdgeObj::Reformat()
1617 if( NULL
!= aCon1
.pObj
)
1619 SfxSimpleHint
aHint( SFX_HINT_DATACHANGED
);
1620 Notify( *const_cast<SfxBroadcaster
*>(aCon1
.pObj
->GetBroadcaster()), aHint
);
1623 if( NULL
!= aCon2
.pObj
)
1625 SfxSimpleHint
aHint( SFX_HINT_DATACHANGED
);
1626 Notify( *const_cast<SfxBroadcaster
*>(aCon2
.pObj
->GetBroadcaster()), aHint
);
1630 SdrEdgeObj
* SdrEdgeObj::Clone() const
1632 return CloneHelper
< SdrEdgeObj
>();
1635 SdrEdgeObj
& SdrEdgeObj::operator=(const SdrEdgeObj
& rObj
)
1639 SdrTextObj::operator=(rObj
);
1640 *pEdgeTrack
=*rObj
.pEdgeTrack
;
1641 bEdgeTrackDirty
=rObj
.bEdgeTrackDirty
;
1646 aEdgeInfo
=rObj
.aEdgeInfo
;
1650 OUString
SdrEdgeObj::TakeObjNameSingul() const
1652 OUStringBuffer
sName(ImpGetResStr(STR_ObjNameSingulEDGE
));
1654 OUString
aName(GetName());
1655 if (!aName
.isEmpty())
1659 sName
.append(aName
);
1662 return sName
.makeStringAndClear();
1665 OUString
SdrEdgeObj::TakeObjNamePlural() const
1667 return ImpGetResStr(STR_ObjNamePluralEDGE
);
1670 basegfx::B2DPolyPolygon
SdrEdgeObj::TakeXorPoly() const
1672 basegfx::B2DPolyPolygon aPolyPolygon
;
1674 if (bEdgeTrackDirty
)
1676 ((SdrEdgeObj
*)this)->ImpRecalcEdgeTrack();
1681 aPolyPolygon
.append(pEdgeTrack
->getB2DPolygon());
1684 return aPolyPolygon
;
1687 void SdrEdgeObj::SetEdgeTrackPath( const basegfx::B2DPolyPolygon
& rPoly
)
1689 if ( !rPoly
.count() )
1691 bEdgeTrackDirty
= true;
1692 bEdgeTrackUserDefined
= false;
1696 *pEdgeTrack
= XPolygon( rPoly
.getB2DPolygon( 0 ) );
1697 bEdgeTrackDirty
= false;
1698 bEdgeTrackUserDefined
= true;
1700 // #i110629# also set aRect and maSnapeRect depending on pEdgeTrack
1701 const Rectangle
aPolygonBounds(pEdgeTrack
->GetBoundRect());
1702 aRect
= aPolygonBounds
;
1703 maSnapRect
= aPolygonBounds
;
1707 basegfx::B2DPolyPolygon
SdrEdgeObj::GetEdgeTrackPath() const
1709 basegfx::B2DPolyPolygon aPolyPolygon
;
1711 if (bEdgeTrackDirty
)
1712 ((SdrEdgeObj
*)this)->ImpRecalcEdgeTrack();
1714 aPolyPolygon
.append( pEdgeTrack
->getB2DPolygon() );
1716 return aPolyPolygon
;
1719 sal_uInt32
SdrEdgeObj::GetHdlCount() const
1721 SdrEdgeKind eKind
=((SdrEdgeKindItem
&)(GetObjectItem(SDRATTR_EDGEKIND
))).GetValue();
1722 sal_uInt32
nHdlAnz(0L);
1723 sal_uInt32
nPntAnz(pEdgeTrack
->GetPointCount());
1729 if ((eKind
==SDREDGE_ORTHOLINES
|| eKind
==SDREDGE_BEZIER
) && nPntAnz
>= 4L)
1731 sal_uInt32
nO1(aEdgeInfo
.nObj1Lines
> 0L ? aEdgeInfo
.nObj1Lines
- 1L : 0L);
1732 sal_uInt32
nO2(aEdgeInfo
.nObj2Lines
> 0L ? aEdgeInfo
.nObj2Lines
- 1L : 0L);
1733 sal_uInt32
nM(aEdgeInfo
.nMiddleLine
!= 0xFFFF ? 1L : 0L);
1734 nHdlAnz
+= nO1
+ nO2
+ nM
;
1736 else if (eKind
==SDREDGE_THREELINES
&& nPntAnz
== 4L)
1738 if(GetConnectedNode(true))
1741 if(GetConnectedNode(false))
1749 SdrHdl
* SdrEdgeObj::GetHdl(sal_uInt32 nHdlNum
) const
1752 sal_uInt32
nPntAnz(pEdgeTrack
->GetPointCount());
1755 pHdl
=new ImpEdgeHdl((*pEdgeTrack
)[0],HDL_POLY
);
1756 if (aCon1
.pObj
!=NULL
&& aCon1
.bBestVertex
) pHdl
->Set1PixMore(true);
1757 } else if (nHdlNum
==1) {
1758 pHdl
=new ImpEdgeHdl((*pEdgeTrack
)[sal_uInt16(nPntAnz
-1)],HDL_POLY
);
1759 if (aCon2
.pObj
!=NULL
&& aCon2
.bBestVertex
) pHdl
->Set1PixMore(true);
1761 SdrEdgeKind eKind
=((SdrEdgeKindItem
&)(GetObjectItem(SDRATTR_EDGEKIND
))).GetValue();
1762 if (eKind
==SDREDGE_ORTHOLINES
|| eKind
==SDREDGE_BEZIER
) {
1763 sal_uInt32
nO1(aEdgeInfo
.nObj1Lines
> 0L ? aEdgeInfo
.nObj1Lines
- 1L : 0L);
1764 sal_uInt32
nO2(aEdgeInfo
.nObj2Lines
> 0L ? aEdgeInfo
.nObj2Lines
- 1L : 0L);
1765 sal_uInt32
nM(aEdgeInfo
.nMiddleLine
!= 0xFFFF ? 1L : 0L);
1766 sal_uInt32
nNum(nHdlNum
- 2L);
1768 pHdl
=new ImpEdgeHdl(Point(),HDL_POLY
);
1771 if (nNum
==0) ((ImpEdgeHdl
*)pHdl
)->SetLineCode(OBJ1LINE2
);
1772 if (nNum
==1) ((ImpEdgeHdl
*)pHdl
)->SetLineCode(OBJ1LINE3
);
1777 if (nNum
==0) ((ImpEdgeHdl
*)pHdl
)->SetLineCode(OBJ2LINE2
);
1778 if (nNum
==1) ((ImpEdgeHdl
*)pHdl
)->SetLineCode(OBJ2LINE3
);
1782 nPt
=aEdgeInfo
.nMiddleLine
;
1783 ((ImpEdgeHdl
*)pHdl
)->SetLineCode(MIDDLELINE
);
1788 Point
aPos((*pEdgeTrack
)[(sal_uInt16
)nPt
]);
1789 aPos
+=(*pEdgeTrack
)[(sal_uInt16
)nPt
+1];
1797 } else if (eKind
==SDREDGE_THREELINES
) {
1798 sal_uInt32
nNum(nHdlNum
);
1799 if (GetConnectedNode(true)==NULL
) nNum
++;
1800 Point
aPos((*pEdgeTrack
)[(sal_uInt16
)nNum
-1]);
1801 pHdl
=new ImpEdgeHdl(aPos
,HDL_POLY
);
1802 if (nNum
==2) ((ImpEdgeHdl
*)pHdl
)->SetLineCode(OBJ1LINE2
);
1803 if (nNum
==3) ((ImpEdgeHdl
*)pHdl
)->SetLineCode(OBJ2LINE2
);
1807 pHdl
->SetPointNum(nHdlNum
);
1815 bool SdrEdgeObj::hasSpecialDrag() const
1820 SdrObject
* SdrEdgeObj::getFullDragClone() const
1822 // use Clone operator
1823 SdrEdgeObj
* pRetval
= (SdrEdgeObj
*)Clone();
1825 // copy connections for clone, SdrEdgeObj::operator= does not do this
1826 pRetval
->ConnectToNode(true, GetConnectedNode(true));
1827 pRetval
->ConnectToNode(false, GetConnectedNode(false));
1832 bool SdrEdgeObj::beginSpecialDrag(SdrDragStat
& rDrag
) const
1837 rDrag
.SetEndDragChangesAttributes(true);
1839 if(rDrag
.GetHdl()->GetPointNum() < 2)
1841 rDrag
.SetNoSnap(true);
1847 bool SdrEdgeObj::applySpecialDrag(SdrDragStat
& rDragStat
)
1849 SdrEdgeObj
* pOriginalEdge
= dynamic_cast< SdrEdgeObj
* >(rDragStat
.GetHdl()->GetObj());
1850 const bool bOriginalEdgeModified(pOriginalEdge
== this);
1852 if(!bOriginalEdgeModified
&& pOriginalEdge
)
1854 // copy connections when clone is modified. This is needed because
1855 // as preparation to this modification the data from the original object
1856 // was copied to the clone using the operator=. As can be seen there,
1857 // that operator does not copy the connections (for good reason)
1858 ConnectToNode(true, pOriginalEdge
->GetConnection(true).GetObject());
1859 ConnectToNode(false, pOriginalEdge
->GetConnection(false).GetObject());
1862 if(rDragStat
.GetHdl()->GetPointNum() < 2)
1864 // start or end point connector drag
1865 const bool bDragA(0 == rDragStat
.GetHdl()->GetPointNum());
1866 const Point
aPointNow(rDragStat
.GetNow());
1868 if(rDragStat
.GetPageView())
1870 SdrObjConnection
* pDraggedOne(bDragA
? &aCon1
: &aCon2
);
1873 DisconnectFromNode(bDragA
);
1875 // look for new connection
1876 ImpFindConnector(aPointNow
, *rDragStat
.GetPageView(), *pDraggedOne
, pOriginalEdge
);
1878 if(pDraggedOne
->pObj
)
1880 // if found, officially connect to it; ImpFindConnector only
1882 SdrObject
* pNewConnection
= pDraggedOne
->pObj
;
1883 pDraggedOne
->pObj
= 0;
1884 ConnectToNode(bDragA
, pNewConnection
);
1887 if(rDragStat
.GetView() && !bOriginalEdgeModified
)
1889 // show IA helper, but only do this during IA, so not when the original
1890 // Edge gets modified in the last call
1891 rDragStat
.GetView()->SetConnectMarker(*pDraggedOne
, *rDragStat
.GetPageView());
1897 // change pEdgeTrack to modified position
1900 (*pEdgeTrack
)[0] = aPointNow
;
1904 (*pEdgeTrack
)[sal_uInt16(pEdgeTrack
->GetPointCount()-1)] = aPointNow
;
1908 // reset edge info's offsets, this is a end point drag
1909 aEdgeInfo
.aObj1Line2
= Point();
1910 aEdgeInfo
.aObj1Line3
= Point();
1911 aEdgeInfo
.aObj2Line2
= Point();
1912 aEdgeInfo
.aObj2Line3
= Point();
1913 aEdgeInfo
.aMiddleLine
= Point();
1917 // control point connector drag
1918 const ImpEdgeHdl
* pEdgeHdl
= (ImpEdgeHdl
*)rDragStat
.GetHdl();
1919 const SdrEdgeLineCode eLineCode
= pEdgeHdl
->GetLineCode();
1920 const Point
aDist(rDragStat
.GetNow() - rDragStat
.GetStart());
1921 sal_Int32
nDist(pEdgeHdl
->IsHorzDrag() ? aDist
.X() : aDist
.Y());
1923 nDist
+= aEdgeInfo
.ImpGetLineVersatz(eLineCode
, *pEdgeTrack
);
1924 aEdgeInfo
.ImpSetLineVersatz(eLineCode
, *pEdgeTrack
, nDist
);
1927 // force recalculation of EdgeTrack
1928 *pEdgeTrack
= ImpCalcEdgeTrack(*pEdgeTrack
, aCon1
, aCon2
, &aEdgeInfo
);
1929 bEdgeTrackDirty
=false;
1931 // save EdgeInfos and mark object as user modified
1932 ImpSetEdgeInfoToAttr();
1933 bEdgeTrackUserDefined
= false;
1937 if(bOriginalEdgeModified
&& rDragStat
.GetView())
1939 // hide connect marker helper again when original gets changed.
1940 // This happens at the end of the interaction
1941 rDragStat
.GetView()->HideConnectMarker();
1947 OUString
SdrEdgeObj::getSpecialDragComment(const SdrDragStat
& rDrag
) const
1949 const bool bCreateComment(rDrag
.GetView() && this == rDrag
.GetView()->GetCreateObj());
1958 ImpTakeDescriptionStr(STR_DragEdgeTail
, aStr
);
1966 basegfx::B2DPolygon
SdrEdgeObj::ImplAddConnectorOverlay(SdrDragMethod
& rDragMethod
, bool bTail1
, bool bTail2
, bool bDetail
) const
1968 basegfx::B2DPolygon aResult
;
1972 SdrObjConnection
aMyCon1(aCon1
);
1973 SdrObjConnection
aMyCon2(aCon2
);
1977 const basegfx::B2DPoint
aTemp(rDragMethod
.getCurrentTransformation() * basegfx::B2DPoint(aMyCon1
.aObjOfs
.X(), aMyCon1
.aObjOfs
.Y()));
1978 aMyCon1
.aObjOfs
.X() = basegfx::fround(aTemp
.getX());
1979 aMyCon1
.aObjOfs
.Y() = basegfx::fround(aTemp
.getY());
1984 const basegfx::B2DPoint
aTemp(rDragMethod
.getCurrentTransformation() * basegfx::B2DPoint(aMyCon2
.aObjOfs
.X(), aMyCon2
.aObjOfs
.Y()));
1985 aMyCon2
.aObjOfs
.X() = basegfx::fround(aTemp
.getX());
1986 aMyCon2
.aObjOfs
.Y() = basegfx::fround(aTemp
.getY());
1989 SdrEdgeInfoRec
aInfo(aEdgeInfo
);
1990 XPolygon
aXP(ImpCalcEdgeTrack(*pEdgeTrack
, aMyCon1
, aMyCon2
, &aInfo
));
1992 if(aXP
.GetPointCount())
1994 aResult
= aXP
.getB2DPolygon();
1999 Point
aPt1((*pEdgeTrack
)[0]);
2000 Point
aPt2((*pEdgeTrack
)[sal_uInt16(pEdgeTrack
->GetPointCount() - 1)]);
2002 if (aCon1
.pObj
&& (aCon1
.bBestConn
|| aCon1
.bBestVertex
))
2003 aPt1
= aCon1
.pObj
->GetSnapRect().Center();
2005 if (aCon2
.pObj
&& (aCon2
.bBestConn
|| aCon2
.bBestVertex
))
2006 aPt2
= aCon2
.pObj
->GetSnapRect().Center();
2010 const basegfx::B2DPoint
aTemp(rDragMethod
.getCurrentTransformation() * basegfx::B2DPoint(aPt1
.X(), aPt1
.Y()));
2011 aPt1
.X() = basegfx::fround(aTemp
.getX());
2012 aPt1
.Y() = basegfx::fround(aTemp
.getY());
2017 const basegfx::B2DPoint
aTemp(rDragMethod
.getCurrentTransformation() * basegfx::B2DPoint(aPt2
.X(), aPt2
.Y()));
2018 aPt2
.X() = basegfx::fround(aTemp
.getX());
2019 aPt2
.Y() = basegfx::fround(aTemp
.getY());
2022 aResult
.append(basegfx::B2DPoint(aPt1
.X(), aPt1
.Y()));
2023 aResult
.append(basegfx::B2DPoint(aPt2
.X(), aPt2
.Y()));
2029 bool SdrEdgeObj::BegCreate(SdrDragStat
& rDragStat
)
2031 rDragStat
.SetNoSnap(true);
2032 pEdgeTrack
->SetPointCount(2);
2033 (*pEdgeTrack
)[0]=rDragStat
.GetStart();
2034 (*pEdgeTrack
)[1]=rDragStat
.GetNow();
2035 if (rDragStat
.GetPageView()!=NULL
) {
2036 ImpFindConnector(rDragStat
.GetStart(),*rDragStat
.GetPageView(),aCon1
,this);
2037 ConnectToNode(true,aCon1
.pObj
);
2039 *pEdgeTrack
=ImpCalcEdgeTrack(*pEdgeTrack
,aCon1
,aCon2
,&aEdgeInfo
);
2043 bool SdrEdgeObj::MovCreate(SdrDragStat
& rDragStat
)
2045 sal_uInt16 nMax
=pEdgeTrack
->GetPointCount();
2046 (*pEdgeTrack
)[nMax
-1]=rDragStat
.GetNow();
2047 if (rDragStat
.GetPageView()!=NULL
) {
2048 ImpFindConnector(rDragStat
.GetNow(),*rDragStat
.GetPageView(),aCon2
,this);
2049 rDragStat
.GetView()->SetConnectMarker(aCon2
,*rDragStat
.GetPageView());
2051 SetBoundRectDirty();
2052 bSnapRectDirty
=true;
2053 ConnectToNode(false,aCon2
.pObj
);
2054 *pEdgeTrack
=ImpCalcEdgeTrack(*pEdgeTrack
,aCon1
,aCon2
,&aEdgeInfo
);
2055 bEdgeTrackDirty
=false;
2059 bool SdrEdgeObj::EndCreate(SdrDragStat
& rDragStat
, SdrCreateCmd eCmd
)
2061 bool bOk
=(eCmd
==SDRCREATE_FORCEEND
|| rDragStat
.GetPointAnz()>=2);
2063 ConnectToNode(true,aCon1
.pObj
);
2064 ConnectToNode(false,aCon2
.pObj
);
2065 if (rDragStat
.GetView()!=NULL
) {
2066 rDragStat
.GetView()->HideConnectMarker();
2068 ImpSetEdgeInfoToAttr(); // copy values from aEdgeInfo into the pool
2074 bool SdrEdgeObj::BckCreate(SdrDragStat
& rDragStat
)
2076 if (rDragStat
.GetView()!=NULL
) {
2077 rDragStat
.GetView()->HideConnectMarker();
2082 void SdrEdgeObj::BrkCreate(SdrDragStat
& rDragStat
)
2084 if (rDragStat
.GetView()!=NULL
) {
2085 rDragStat
.GetView()->HideConnectMarker();
2089 basegfx::B2DPolyPolygon
SdrEdgeObj::TakeCreatePoly(const SdrDragStat
& /*rStatDrag*/) const
2091 basegfx::B2DPolyPolygon aRetval
;
2092 aRetval
.append(pEdgeTrack
->getB2DPolygon());
2096 Pointer
SdrEdgeObj::GetCreatePointer() const
2098 return Pointer(POINTER_DRAW_CONNECT
);
2101 bool SdrEdgeObj::ImpFindConnector(const Point
& rPt
, const SdrPageView
& rPV
, SdrObjConnection
& rCon
, const SdrEdgeObj
* pThis
, OutputDevice
* pOut
)
2104 if (pOut
==NULL
) pOut
=rPV
.GetView().GetFirstOutputDevice();
2105 if (pOut
==NULL
) return false;
2106 SdrObjList
* pOL
=rPV
.GetObjList();
2107 const SetOfByte
& rVisLayer
=rPV
.GetVisibleLayers();
2108 // sensitive area of connectors is twice as large as the one of the handles
2109 sal_uInt16 nMarkHdSiz
=rPV
.GetView().GetMarkHdlSizePixel();
2110 Size
aHalfConSiz(nMarkHdSiz
,nMarkHdSiz
);
2111 aHalfConSiz
=pOut
->PixelToLogic(aHalfConSiz
);
2112 Rectangle
aMouseRect(rPt
,rPt
);
2113 aMouseRect
.Left() -=aHalfConSiz
.Width();
2114 aMouseRect
.Top() -=aHalfConSiz
.Height();
2115 aMouseRect
.Right() +=aHalfConSiz
.Width();
2116 aMouseRect
.Bottom()+=aHalfConSiz
.Height();
2117 sal_uInt16 nBoundHitTol
=(sal_uInt16
)aHalfConSiz
.Width()/2; if (nBoundHitTol
==0) nBoundHitTol
=1;
2118 sal_uIntPtr no
=pOL
->GetObjCount();
2120 SdrObjConnection aTestCon
;
2121 SdrObjConnection aBestCon
;
2123 while (no
>0 && !bFnd
) {
2124 // issue: group objects on different layers return LayerID=0!
2126 SdrObject
* pObj
=pOL
->GetObj(no
);
2127 if (rVisLayer
.IsSet(pObj
->GetLayer()) && pObj
->IsVisible() && // only visible objects
2128 (pThis
==NULL
|| pObj
!=(SdrObject
*)pThis
) && // don't connect it to itself
2131 Rectangle
aObjBound(pObj
->GetCurrentBoundRect());
2132 if (aObjBound
.IsOver(aMouseRect
)) {
2133 aTestCon
.ResetVars();
2134 bool bEdge
=HAS_BASE(SdrEdgeObj
,pObj
); // no BestCon for Edge
2135 // User-defined connectors have absolute priority.
2136 // After those come Vertex, Corner and center (Best), all prioritized equally.
2137 // Finally, a HitTest for the object.
2138 const SdrGluePointList
* pGPL
=pObj
->GetGluePointList();
2139 sal_uInt16 nConAnz
=pGPL
==NULL
? 0 : pGPL
->GetCount();
2140 sal_uInt16 nGesAnz
=nConAnz
+9;
2141 bool bUserFnd
= false;
2142 sal_uIntPtr nBestDist
=0xFFFFFFFF;
2143 for (sal_uInt16 i
=0; i
<nGesAnz
; i
++)
2145 bool bUser
=i
<nConAnz
;
2146 bool bVertex
=i
>=nConAnz
+0 && i
<nConAnz
+4;
2147 bool bCorner
=i
>=nConAnz
+4 && i
<nConAnz
+8;
2148 bool bCenter
=i
==nConAnz
+8;
2151 sal_uInt16 nConNum
=i
;
2153 const SdrGluePoint
& rGP
=(*pGPL
)[nConNum
];
2154 aConPos
=rGP
.GetAbsolutePos(*pObj
);
2155 nConNum
=rGP
.GetId();
2157 } else if (bVertex
&& !bUserFnd
) {
2158 nConNum
=nConNum
-nConAnz
;
2159 if (rPV
.GetView().IsAutoVertexConnectors()) {
2160 SdrGluePoint
aPt(pObj
->GetVertexGluePoint(nConNum
));
2161 aConPos
=aPt
.GetAbsolutePos(*pObj
);
2164 } else if (bCorner
&& !bUserFnd
) {
2166 if (rPV
.GetView().IsAutoCornerConnectors()) {
2167 SdrGluePoint
aPt(pObj
->GetCornerGluePoint(nConNum
));
2168 aConPos
=aPt
.GetAbsolutePos(*pObj
);
2172 else if (bCenter
&& !bUserFnd
&& !bEdge
)
2174 // Suppress default connect at object center
2175 if(!pThis
|| !pThis
->GetSuppressDefaultConnect())
2179 aConPos
=aObjBound
.Center();
2183 if (bOk
&& aMouseRect
.IsInside(aConPos
)) {
2184 if (bUser
) bUserFnd
= true;
2186 sal_uIntPtr nDist
=(sal_uIntPtr
)std::abs(aConPos
.X()-rPt
.X())+(sal_uIntPtr
)std::abs(aConPos
.Y()-rPt
.Y());
2187 if (nDist
<nBestDist
) {
2190 aTestCon
.nConId
=nConNum
;
2191 aTestCon
.bAutoCorner
=bCorner
;
2192 aTestCon
.bAutoVertex
=bVertex
;
2193 aTestCon
.bBestConn
=false; // bCenter;
2194 aTestCon
.bBestVertex
=bCenter
;
2198 // if no connector is hit, try HitTest again, for BestConnector (=bCenter)
2201 SdrObjectPrimitiveHit(*pObj
, rPt
, nBoundHitTol
, rPV
, &rVisLayer
, false))
2203 // Suppress default connect at object inside bound
2204 if(!pThis
|| !pThis
->GetSuppressDefaultConnect())
2208 aTestCon
.bBestConn
=true;
2212 Rectangle
aMouseRect2(rPt
,rPt
);
2213 aMouseRect
.Left() -=nBoundHitTol
;
2214 aMouseRect
.Top() -=nBoundHitTol
;
2215 aMouseRect
.Right() +=nBoundHitTol
;
2216 aMouseRect
.Bottom()+=nBoundHitTol
;
2217 aObjBound
.IsOver(aMouseRect2
);
2227 void SdrEdgeObj::NbcSetSnapRect(const Rectangle
& rRect
)
2229 const Rectangle
aOld(GetSnapRect());
2233 if(aRect
.IsEmpty() && 0 == pEdgeTrack
->GetPointCount())
2235 // #i110629# When initializing, do not scale on empty Rectangle; this
2236 // will mirror the underlying text object (!)
2242 long nMulX
= rRect
.Right() - rRect
.Left();
2243 long nDivX
= aOld
.Right() - aOld
.Left();
2244 long nMulY
= rRect
.Bottom() - rRect
.Top();
2245 long nDivY
= aOld
.Bottom() - aOld
.Top();
2246 if ( nDivX
== 0 ) { nMulX
= 1; nDivX
= 1; }
2247 if ( nDivY
== 0 ) { nMulY
= 1; nDivY
= 1; }
2248 Fraction
aX(nMulX
, nDivX
);
2249 Fraction
aY(nMulY
, nDivY
);
2250 NbcResize(aOld
.TopLeft(), aX
, aY
);
2251 NbcMove(Size(rRect
.Left() - aOld
.Left(), rRect
.Top() - aOld
.Top()));
2256 void SdrEdgeObj::NbcMove(const Size
& rSiz
)
2258 SdrTextObj::NbcMove(rSiz
);
2259 MoveXPoly(*pEdgeTrack
,rSiz
);
2262 void SdrEdgeObj::NbcResize(const Point
& rRefPnt
, const Fraction
& aXFact
, const Fraction
& aYFact
)
2264 SdrTextObj::NbcResize(rRefPnt
,aXFact
,aXFact
);
2265 ResizeXPoly(*pEdgeTrack
,rRefPnt
,aXFact
,aYFact
);
2267 // if resize is not from paste, forget user distances
2268 if(!GetModel()->IsPasteResize())
2270 aEdgeInfo
.aObj1Line2
= Point();
2271 aEdgeInfo
.aObj1Line3
= Point();
2272 aEdgeInfo
.aObj2Line2
= Point();
2273 aEdgeInfo
.aObj2Line3
= Point();
2274 aEdgeInfo
.aMiddleLine
= Point();
2278 // #i54102# added rotation support
2279 void SdrEdgeObj::NbcRotate(const Point
& rRef
, long nWink
, double sn
, double cs
)
2281 if(bEdgeTrackUserDefined
)
2283 // #i120437# special handling when track is imported, apply
2284 // transformation directly to imported track.
2285 SdrTextObj::NbcRotate(rRef
, nWink
, sn
, cs
);
2286 RotateXPoly(*pEdgeTrack
, rRef
, sn
, cs
);
2290 // handle start and end point if not connected
2291 bool bCon1
=aCon1
.pObj
!=NULL
&& aCon1
.pObj
->GetPage()==pPage
;
2292 bool bCon2
=aCon2
.pObj
!=NULL
&& aCon2
.pObj
->GetPage()==pPage
;
2294 if(!bCon1
&& pEdgeTrack
)
2296 RotatePoint((*pEdgeTrack
)[0],rRef
,sn
,cs
);
2297 ImpDirtyEdgeTrack();
2300 if(!bCon2
&& pEdgeTrack
)
2302 sal_uInt16 nPntAnz
= pEdgeTrack
->GetPointCount();
2303 RotatePoint((*pEdgeTrack
)[sal_uInt16(nPntAnz
-1)],rRef
,sn
,cs
);
2304 ImpDirtyEdgeTrack();
2309 // #i54102# added mirror support
2310 void SdrEdgeObj::NbcMirror(const Point
& rRef1
, const Point
& rRef2
)
2312 if(bEdgeTrackUserDefined
)
2314 // #i120437# special handling when track is imported, apply
2315 // transformation directly to imported track.
2316 SdrTextObj::NbcMirror(rRef1
, rRef2
);
2317 MirrorXPoly(*pEdgeTrack
, rRef1
, rRef2
);
2321 // handle start and end point if not connected
2322 bool bCon1
=aCon1
.pObj
!=NULL
&& aCon1
.pObj
->GetPage()==pPage
;
2323 bool bCon2
=aCon2
.pObj
!=NULL
&& aCon2
.pObj
->GetPage()==pPage
;
2325 if(!bCon1
&& pEdgeTrack
)
2327 MirrorPoint((*pEdgeTrack
)[0],rRef1
,rRef2
);
2328 ImpDirtyEdgeTrack();
2331 if(!bCon2
&& pEdgeTrack
)
2333 sal_uInt16 nPntAnz
= pEdgeTrack
->GetPointCount();
2334 MirrorPoint((*pEdgeTrack
)[sal_uInt16(nPntAnz
-1)],rRef1
,rRef2
);
2335 ImpDirtyEdgeTrack();
2340 // #i54102# added shear support
2341 void SdrEdgeObj::NbcShear(const Point
& rRef
, long nWink
, double tn
, bool bVShear
)
2343 if(bEdgeTrackUserDefined
)
2345 // #i120437# special handling when track is imported, apply
2346 // transformation directly to imported track.
2347 SdrTextObj::NbcShear(rRef
, nWink
, tn
, bVShear
);
2348 ShearXPoly(*pEdgeTrack
, rRef
, tn
, bVShear
);
2352 // handle start and end point if not connected
2353 bool bCon1
=aCon1
.pObj
!=NULL
&& aCon1
.pObj
->GetPage()==pPage
;
2354 bool bCon2
=aCon2
.pObj
!=NULL
&& aCon2
.pObj
->GetPage()==pPage
;
2356 if(!bCon1
&& pEdgeTrack
)
2358 ShearPoint((*pEdgeTrack
)[0],rRef
,tn
,bVShear
);
2359 ImpDirtyEdgeTrack();
2362 if(!bCon2
&& pEdgeTrack
)
2364 sal_uInt16 nPntAnz
= pEdgeTrack
->GetPointCount();
2365 ShearPoint((*pEdgeTrack
)[sal_uInt16(nPntAnz
-1)],rRef
,tn
,bVShear
);
2366 ImpDirtyEdgeTrack();
2371 SdrObject
* SdrEdgeObj::DoConvertToPolyObj(bool bBezier
, bool bAddText
) const
2373 basegfx::B2DPolyPolygon aPolyPolygon
;
2374 aPolyPolygon
.append(pEdgeTrack
->getB2DPolygon());
2375 SdrObject
* pRet
= ImpConvertMakeObj(aPolyPolygon
, false, bBezier
);
2379 pRet
= ImpConvertAddText(pRet
, bBezier
);
2385 sal_uInt32
SdrEdgeObj::GetSnapPointCount() const
2390 Point
SdrEdgeObj::GetSnapPoint(sal_uInt32 i
) const
2392 ((SdrEdgeObj
*)this)->ImpUndirtyEdgeTrack();
2393 sal_uInt16 nAnz
=pEdgeTrack
->GetPointCount();
2394 if (i
==0) return (*pEdgeTrack
)[0];
2395 else return (*pEdgeTrack
)[nAnz
-1];
2398 bool SdrEdgeObj::IsPolyObj() const
2403 sal_uInt32
SdrEdgeObj::GetPointCount() const
2408 Point
SdrEdgeObj::GetPoint(sal_uInt32 i
) const
2410 ((SdrEdgeObj
*)this)->ImpUndirtyEdgeTrack();
2411 sal_uInt16 nAnz
=pEdgeTrack
->GetPointCount();
2413 return (*pEdgeTrack
)[0];
2415 return (*pEdgeTrack
)[nAnz
-1];
2418 void SdrEdgeObj::NbcSetPoint(const Point
& rPnt
, sal_uInt32 i
)
2420 // TODO: Need an implementation to connect differently.
2421 ImpUndirtyEdgeTrack();
2422 sal_uInt16 nAnz
=pEdgeTrack
->GetPointCount();
2424 (*pEdgeTrack
)[0]=rPnt
;
2426 (*pEdgeTrack
)[nAnz
-1]=rPnt
;
2427 SetEdgeTrackDirty();
2431 SdrEdgeObjGeoData::SdrEdgeObjGeoData()
2432 : bEdgeTrackDirty(false)
2433 , bEdgeTrackUserDefined(false)
2435 pEdgeTrack
=new XPolygon
;
2438 SdrEdgeObjGeoData::~SdrEdgeObjGeoData()
2443 SdrObjGeoData
* SdrEdgeObj::NewGeoData() const
2445 return new SdrEdgeObjGeoData
;
2448 void SdrEdgeObj::SaveGeoData(SdrObjGeoData
& rGeo
) const
2450 SdrTextObj::SaveGeoData(rGeo
);
2451 SdrEdgeObjGeoData
& rEGeo
=(SdrEdgeObjGeoData
&)rGeo
;
2454 *rEGeo
.pEdgeTrack
=*pEdgeTrack
;
2455 rEGeo
.bEdgeTrackDirty
=bEdgeTrackDirty
;
2456 rEGeo
.bEdgeTrackUserDefined
=bEdgeTrackUserDefined
;
2457 rEGeo
.aEdgeInfo
=aEdgeInfo
;
2460 void SdrEdgeObj::RestGeoData(const SdrObjGeoData
& rGeo
)
2462 SdrTextObj::RestGeoData(rGeo
);
2463 SdrEdgeObjGeoData
& rEGeo
=(SdrEdgeObjGeoData
&)rGeo
;
2464 if (aCon1
.pObj
!=rEGeo
.aCon1
.pObj
) {
2465 if (aCon1
.pObj
!=NULL
) aCon1
.pObj
->RemoveListener(*this);
2467 if (aCon1
.pObj
!=NULL
) aCon1
.pObj
->AddListener(*this);
2469 if (aCon2
.pObj
!=rEGeo
.aCon2
.pObj
) {
2470 if (aCon2
.pObj
!=NULL
) aCon2
.pObj
->RemoveListener(*this);
2472 if (aCon2
.pObj
!=NULL
) aCon2
.pObj
->AddListener(*this);
2474 *pEdgeTrack
=*rEGeo
.pEdgeTrack
;
2475 bEdgeTrackDirty
=rEGeo
.bEdgeTrackDirty
;
2476 bEdgeTrackUserDefined
=rEGeo
.bEdgeTrackUserDefined
;
2477 aEdgeInfo
=rEGeo
.aEdgeInfo
;
2480 Point
SdrEdgeObj::GetTailPoint( bool bTail
) const
2482 if( pEdgeTrack
&& pEdgeTrack
->GetPointCount()!=0)
2484 const XPolygon
& rTrack0
= *pEdgeTrack
;
2491 const sal_uInt16 nSiz
= rTrack0
.GetPointCount() - 1;
2492 return rTrack0
[nSiz
];
2498 return aOutRect
.TopLeft();
2500 return aOutRect
.BottomRight();
2505 void SdrEdgeObj::SetTailPoint( bool bTail
, const Point
& rPt
)
2507 ImpSetTailPoint( bTail
, rPt
);
2511 /** this method is used by the api to set a glue point for a connection
2512 nId == -1 : The best default point is automatically chosen
2513 0 <= nId <= 3 : One of the default points is chosen
2514 nId >= 4 : A user defined glue point is chosen
2516 void SdrEdgeObj::setGluePointIndex( bool bTail
, sal_Int32 nIndex
/* = -1 */ )
2518 Rectangle aBoundRect0
; if (pUserCall
!=NULL
) aBoundRect0
=GetCurrentBoundRect();
2520 SdrObjConnection
& rConn1
= GetConnection( bTail
);
2522 rConn1
.SetAutoVertex( nIndex
>= 0 && nIndex
<= 3 );
2523 rConn1
.SetBestConnection( nIndex
< 0 );
2524 rConn1
.SetBestVertex( nIndex
< 0 );
2528 nIndex
-= 3; // the start api index is 0, whereas the implementation in svx starts from 1
2530 // for user defined glue points we have
2531 // to get the id for this index first
2532 const SdrGluePointList
* pList
= rConn1
.GetObject() ? rConn1
.GetObject()->GetGluePointList() : NULL
;
2533 if( pList
== NULL
|| SDRGLUEPOINT_NOTFOUND
== pList
->FindGluePoint((sal_uInt16
)nIndex
) )
2536 else if( nIndex
< 0 )
2541 rConn1
.SetConnectorId( (sal_uInt16
)nIndex
);
2545 ImpRecalcEdgeTrack();
2548 /** this method is used by the api to return a glue point id for a connection.
2549 See setGluePointId for possible return values */
2550 sal_Int32
SdrEdgeObj::getGluePointIndex( bool bTail
)
2552 SdrObjConnection
& rConn1
= GetConnection( bTail
);
2554 if( !rConn1
.IsBestConnection() )
2556 nId
= rConn1
.GetConnectorId();
2557 if( !rConn1
.IsAutoVertex() )
2558 nId
+= 3; // the start api index is 0, whereas the implementation in svx starts from 1
2563 // Implementation was missing; edge track needs to be invalidated additionally.
2564 void SdrEdgeObj::NbcSetAnchorPos(const Point
& rPnt
)
2566 // call parent functionality
2567 SdrTextObj::NbcSetAnchorPos(rPnt
);
2569 // Additionally, invalidate edge track
2570 ImpDirtyEdgeTrack();
2573 bool SdrEdgeObj::TRGetBaseGeometry(basegfx::B2DHomMatrix
& rMatrix
, basegfx::B2DPolyPolygon
& rPolyPolygon
) const
2575 // use base method from SdrObject, it's not rotatable and
2576 // a call to GetSnapRect() is used. That's what we need for Connector.
2577 return SdrObject::TRGetBaseGeometry(rMatrix
, rPolyPolygon
);
2580 void SdrEdgeObj::TRSetBaseGeometry(const basegfx::B2DHomMatrix
& rMatrix
, const basegfx::B2DPolyPolygon
& rPolyPolygon
)
2582 // where appropriate take care for existing connections. For now, just use the
2583 // implementation from SdrObject.
2584 SdrObject::TRSetBaseGeometry(rMatrix
, rPolyPolygon
);
2587 // for geometry access
2588 ::basegfx::B2DPolygon
SdrEdgeObj::getEdgeTrack() const
2592 const_cast< SdrEdgeObj
* >(this)->ImpRecalcEdgeTrack();
2597 return pEdgeTrack
->getB2DPolygon();
2601 return ::basegfx::B2DPolygon();
2605 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */