1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: svdoedge.cxx,v $
10 * $Revision: 1.45.18.1 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_svx.hxx"
34 #include <svx/svdoedge.hxx>
35 #include <svx/xpool.hxx>
36 #include <svx/xpoly.hxx>
37 #include <svx/svdattrx.hxx>
38 #include <svx/svdpool.hxx>
39 #include <svx/svdmodel.hxx>
40 #include <svx/svdpage.hxx>
41 #include <svx/svdpagv.hxx>
42 #include <svx/svdview.hxx>
43 #include <svx/svddrag.hxx>
44 #include <svx/svddrgv.hxx>
45 #include "svddrgm1.hxx"
46 #include <svx/svdhdl.hxx>
47 #include <svx/svdtrans.hxx>
48 #include <svx/svdetc.hxx>
49 #include "svdglob.hxx" // StringCache
50 #include "svdstr.hrc" // Objektname
51 #include <svtools/style.hxx>
52 #include <svtools/smplhint.hxx>
53 #include <svx/eeitem.hxx>
54 #include "svdoimp.hxx"
55 #include <svx/sdr/properties/connectorproperties.hxx>
56 #include <svx/sdr/contact/viewcontactofsdredgeobj.hxx>
57 #include <basegfx/polygon/b2dpolygon.hxx>
58 #include <basegfx/polygon/b2dpolygontools.hxx>
59 #include <basegfx/matrix/b2dhommatrix.hxx>
60 #include <svx/sdrhittesthelper.hxx>
62 ////////////////////////////////////////////////////////////////////////////////////////////////////
64 SdrObjConnection::~SdrObjConnection()
68 void SdrObjConnection::ResetVars()
82 FASTBOOL
SdrObjConnection::TakeGluePoint(SdrGluePoint
& rGP
, FASTBOOL bSetAbsPos
) const
85 if (pObj
!=NULL
) { // Ein Obj muss schon angedockt sein!
87 rGP
=pObj
->GetVertexGluePoint(nConId
);
89 } else if (bAutoCorner
) {
90 rGP
=pObj
->GetCornerGluePoint(nConId
);
93 const SdrGluePointList
* pGPL
=pObj
->GetGluePointList();
95 USHORT nNum
=pGPL
->FindGluePoint(nConId
);
96 if (nNum
!=SDRGLUEPOINT_NOTFOUND
) {
103 if (bRet
&& bSetAbsPos
) {
104 Point
aPt(rGP
.GetAbsolutePos(*pObj
));
111 Point
& SdrEdgeInfoRec::ImpGetLineVersatzPoint(SdrEdgeLineCode eLineCode
)
114 case OBJ1LINE2
: return aObj1Line2
;
115 case OBJ1LINE3
: return aObj1Line3
;
116 case OBJ2LINE2
: return aObj2Line2
;
117 case OBJ2LINE3
: return aObj2Line3
;
118 case MIDDLELINE
: return aMiddleLine
;
123 USHORT
SdrEdgeInfoRec::ImpGetPolyIdx(SdrEdgeLineCode eLineCode
, const XPolygon
& rXP
) const
126 case OBJ1LINE2
: return 1;
127 case OBJ1LINE3
: return 2;
128 case OBJ2LINE2
: return rXP
.GetPointCount()-3;
129 case OBJ2LINE3
: return rXP
.GetPointCount()-4;
130 case MIDDLELINE
: return nMiddleLine
;
135 FASTBOOL
SdrEdgeInfoRec::ImpIsHorzLine(SdrEdgeLineCode eLineCode
, const XPolygon
& rXP
) const
137 USHORT nIdx
=ImpGetPolyIdx(eLineCode
,rXP
);
138 FASTBOOL bHorz
=nAngle1
==0 || nAngle1
==18000;
139 if (eLineCode
==OBJ2LINE2
|| eLineCode
==OBJ2LINE3
) {
140 nIdx
=rXP
.GetPointCount()-nIdx
; // #36314#
141 bHorz
=nAngle2
==0 || nAngle2
==18000; // #52000#
143 if ((nIdx
& 1)==1) bHorz
=!bHorz
;
147 void SdrEdgeInfoRec::ImpSetLineVersatz(SdrEdgeLineCode eLineCode
, const XPolygon
& rXP
, long nVal
)
149 Point
& rPt
=ImpGetLineVersatzPoint(eLineCode
);
150 if (ImpIsHorzLine(eLineCode
,rXP
)) rPt
.Y()=nVal
;
154 long SdrEdgeInfoRec::ImpGetLineVersatz(SdrEdgeLineCode eLineCode
, const XPolygon
& rXP
) const
156 const Point
& rPt
=ImpGetLineVersatzPoint(eLineCode
);
157 if (ImpIsHorzLine(eLineCode
,rXP
)) return rPt
.Y();
161 //////////////////////////////////////////////////////////////////////////////
162 // BaseProperties section
164 sdr::properties::BaseProperties
* SdrEdgeObj::CreateObjectSpecificProperties()
166 return new sdr::properties::ConnectorProperties(*this);
169 //////////////////////////////////////////////////////////////////////////////
170 // DrawContact section
172 sdr::contact::ViewContact
* SdrEdgeObj::CreateObjectSpecificViewContact()
174 return new sdr::contact::ViewContactOfSdrEdgeObj(*this);
177 //////////////////////////////////////////////////////////////////////////////
179 TYPEINIT1(SdrEdgeObj
,SdrTextObj
);
181 SdrEdgeObj::SdrEdgeObj()
184 bEdgeTrackDirty(sal_False
),
185 bEdgeTrackUserDefined(sal_False
),
186 // #109007# Default is to allow default connects
187 mbSuppressDefaultConnect(sal_False
),
189 mbBoundRectCalculationRunning(sal_False
)
193 pEdgeTrack
=new XPolygon
;
197 SdrEdgeObj::~SdrEdgeObj()
199 DisconnectFromNode(TRUE
);
200 DisconnectFromNode(FALSE
);
204 void SdrEdgeObj::ImpSetAttrToEdgeInfo()
206 const SfxItemSet
& rSet
= GetObjectItemSet();
207 SdrEdgeKind eKind
= ((SdrEdgeKindItem
&)(rSet
.Get(SDRATTR_EDGEKIND
))).GetValue();
208 sal_Int32 nVal1
= ((SdrEdgeLine1DeltaItem
&)rSet
.Get(SDRATTR_EDGELINE1DELTA
)).GetValue();
209 sal_Int32 nVal2
= ((SdrEdgeLine2DeltaItem
&)rSet
.Get(SDRATTR_EDGELINE2DELTA
)).GetValue();
210 sal_Int32 nVal3
= ((SdrEdgeLine3DeltaItem
&)rSet
.Get(SDRATTR_EDGELINE3DELTA
)).GetValue();
212 if(eKind
== SDREDGE_ORTHOLINES
|| eKind
== SDREDGE_BEZIER
)
214 sal_Int32 nVals
[3] = { nVal1
, nVal2
, nVal3
};
217 if(aEdgeInfo
.nObj1Lines
>= 2 && n
< 3)
219 aEdgeInfo
.ImpSetLineVersatz(OBJ1LINE2
, *pEdgeTrack
, nVals
[n
]);
223 if(aEdgeInfo
.nObj1Lines
>= 3 && n
< 3)
225 aEdgeInfo
.ImpSetLineVersatz(OBJ1LINE3
, *pEdgeTrack
, nVals
[n
]);
229 if(aEdgeInfo
.nMiddleLine
!= 0xFFFF && n
< 3)
231 aEdgeInfo
.ImpSetLineVersatz(MIDDLELINE
, *pEdgeTrack
, nVals
[n
]);
235 if(aEdgeInfo
.nObj2Lines
>= 3 && n
< 3)
237 aEdgeInfo
.ImpSetLineVersatz(OBJ2LINE3
, *pEdgeTrack
, nVals
[n
]);
241 if(aEdgeInfo
.nObj2Lines
>= 2 && n
< 3)
243 aEdgeInfo
.ImpSetLineVersatz(OBJ2LINE2
, *pEdgeTrack
, nVals
[n
]);
247 else if(eKind
== SDREDGE_THREELINES
)
249 BOOL bHor1
= aEdgeInfo
.nAngle1
== 0 || aEdgeInfo
.nAngle1
== 18000;
250 BOOL bHor2
= aEdgeInfo
.nAngle2
== 0 || aEdgeInfo
.nAngle2
== 18000;
254 aEdgeInfo
.aObj1Line2
.X() = nVal1
;
258 aEdgeInfo
.aObj1Line2
.Y() = nVal1
;
263 aEdgeInfo
.aObj2Line2
.X() = nVal2
;
267 aEdgeInfo
.aObj2Line2
.Y() = nVal2
;
275 void SdrEdgeObj::ImpSetEdgeInfoToAttr()
277 const SfxItemSet
& rSet
= GetObjectItemSet();
278 SdrEdgeKind eKind
= ((SdrEdgeKindItem
&)(rSet
.Get(SDRATTR_EDGEKIND
))).GetValue();
279 sal_Int32 nValAnz
= ((SdrEdgeLineDeltaAnzItem
&)rSet
.Get(SDRATTR_EDGELINEDELTAANZ
)).GetValue();
280 sal_Int32 nVal1
= ((SdrEdgeLine1DeltaItem
&)rSet
.Get(SDRATTR_EDGELINE1DELTA
)).GetValue();
281 sal_Int32 nVal2
= ((SdrEdgeLine2DeltaItem
&)rSet
.Get(SDRATTR_EDGELINE2DELTA
)).GetValue();
282 sal_Int32 nVal3
= ((SdrEdgeLine3DeltaItem
&)rSet
.Get(SDRATTR_EDGELINE3DELTA
)).GetValue();
283 sal_Int32 nVals
[3] = { nVal1
, nVal2
, nVal3
};
286 if(eKind
== SDREDGE_ORTHOLINES
|| eKind
== SDREDGE_BEZIER
)
288 if(aEdgeInfo
.nObj1Lines
>= 2 && n
< 3)
290 nVals
[n
] = aEdgeInfo
.ImpGetLineVersatz(OBJ1LINE2
, *pEdgeTrack
);
294 if(aEdgeInfo
.nObj1Lines
>= 3 && n
< 3)
296 nVals
[n
] = aEdgeInfo
.ImpGetLineVersatz(OBJ1LINE3
, *pEdgeTrack
);
300 if(aEdgeInfo
.nMiddleLine
!= 0xFFFF && n
< 3)
302 nVals
[n
] = aEdgeInfo
.ImpGetLineVersatz(MIDDLELINE
, *pEdgeTrack
);
306 if(aEdgeInfo
.nObj2Lines
>= 3 && n
< 3)
308 nVals
[n
] = aEdgeInfo
.ImpGetLineVersatz(OBJ2LINE3
, *pEdgeTrack
);
312 if(aEdgeInfo
.nObj2Lines
>= 2 && n
< 3)
314 nVals
[n
] = aEdgeInfo
.ImpGetLineVersatz(OBJ2LINE2
, *pEdgeTrack
);
318 else if(eKind
== SDREDGE_THREELINES
)
320 BOOL bHor1
= aEdgeInfo
.nAngle1
== 0 || aEdgeInfo
.nAngle1
== 18000;
321 BOOL bHor2
= aEdgeInfo
.nAngle2
== 0 || aEdgeInfo
.nAngle2
== 18000;
324 nVals
[0] = bHor1
? aEdgeInfo
.aObj1Line2
.X() : aEdgeInfo
.aObj1Line2
.Y();
325 nVals
[1] = bHor2
? aEdgeInfo
.aObj2Line2
.X() : aEdgeInfo
.aObj2Line2
.Y();
328 if(n
!= nValAnz
|| nVals
[0] != nVal1
|| nVals
[1] != nVal2
|| nVals
[2] != nVal3
)
330 // #75371# Here no more notifying is necessary, just local changes are OK.
333 GetProperties().SetObjectItemDirect(SdrEdgeLineDeltaAnzItem(n
));
336 if(nVals
[0] != nVal1
)
338 GetProperties().SetObjectItemDirect(SdrEdgeLine1DeltaItem(nVals
[0]));
341 if(nVals
[1] != nVal2
)
343 GetProperties().SetObjectItemDirect(SdrEdgeLine2DeltaItem(nVals
[1]));
346 if(nVals
[2] != nVal3
)
348 GetProperties().SetObjectItemDirect(SdrEdgeLine3DeltaItem(nVals
[2]));
353 GetProperties().ClearObjectItemDirect(SDRATTR_EDGELINE3DELTA
);
358 GetProperties().ClearObjectItemDirect(SDRATTR_EDGELINE2DELTA
);
363 GetProperties().ClearObjectItemDirect(SDRATTR_EDGELINE1DELTA
);
368 void SdrEdgeObj::TakeObjInfo(SdrObjTransformInfoRec
& rInfo
) const
370 rInfo
.bRotateFreeAllowed
=FALSE
;
371 rInfo
.bRotate90Allowed
=FALSE
;
372 rInfo
.bMirrorFreeAllowed
=FALSE
;
373 rInfo
.bMirror45Allowed
=FALSE
;
374 rInfo
.bMirror90Allowed
=FALSE
;
375 rInfo
.bTransparenceAllowed
= FALSE
;
376 rInfo
.bGradientAllowed
= FALSE
;
377 rInfo
.bShearAllowed
=FALSE
;
378 rInfo
.bEdgeRadiusAllowed
=FALSE
;
379 FASTBOOL bCanConv
=!HasText() || ImpCanConvTextToCurve();
380 rInfo
.bCanConvToPath
=bCanConv
;
381 rInfo
.bCanConvToPoly
=bCanConv
;
382 rInfo
.bCanConvToContour
= (rInfo
.bCanConvToPoly
|| LineGeometryUsageIsNecessary());
385 UINT16
SdrEdgeObj::GetObjIdentifier() const
387 return UINT16(OBJ_EDGE
);
390 const Rectangle
& SdrEdgeObj::GetCurrentBoundRect() const
394 ((SdrEdgeObj
*)this)->ImpRecalcEdgeTrack();
397 return SdrTextObj::GetCurrentBoundRect();
400 const Rectangle
& SdrEdgeObj::GetSnapRect() const
404 ((SdrEdgeObj
*)this)->ImpRecalcEdgeTrack();
407 return SdrTextObj::GetSnapRect();
410 void SdrEdgeObj::RecalcSnapRect()
412 maSnapRect
=pEdgeTrack
->GetBoundRect();
415 void SdrEdgeObj::TakeUnrotatedSnapRect(Rectangle
& rRect
) const
420 FASTBOOL
SdrEdgeObj::IsNode() const
425 SdrGluePoint
SdrEdgeObj::GetVertexGluePoint(USHORT nNum
) const
428 USHORT nPntAnz
=pEdgeTrack
->GetPointCount();
431 Point aOfs
= GetSnapRect().Center();
432 if (nNum
==2 && GetConnectedNode(TRUE
)==NULL
) aPt
=(*pEdgeTrack
)[0];
433 else if (nNum
==3 && GetConnectedNode(FALSE
)==NULL
) aPt
=(*pEdgeTrack
)[nPntAnz
-1];
435 if ((nPntAnz
& 1) ==1) {
436 aPt
=(*pEdgeTrack
)[nPntAnz
/2];
438 Point
aPt1((*pEdgeTrack
)[nPntAnz
/2-1]);
439 Point
aPt2((*pEdgeTrack
)[nPntAnz
/2]);
448 SdrGluePoint
aGP(aPt
);
449 aGP
.SetPercent(FALSE
);
453 SdrGluePoint
SdrEdgeObj::GetCornerGluePoint(USHORT nNum
) const
455 return GetVertexGluePoint(nNum
);
458 const SdrGluePointList
* SdrEdgeObj::GetGluePointList() const
460 return NULL
; // Keine benutzerdefinierten Klebepunkte fuer Verbinder #31671#
463 SdrGluePointList
* SdrEdgeObj::ForceGluePointList()
465 return NULL
; // Keine benutzerdefinierten Klebepunkte fuer Verbinder #31671#
468 FASTBOOL
SdrEdgeObj::IsEdge() const
473 void SdrEdgeObj::ConnectToNode(FASTBOOL bTail1
, SdrObject
* pObj
)
475 SdrObjConnection
& rCon
=GetConnection(bTail1
);
476 DisconnectFromNode(bTail1
);
478 pObj
->AddListener(*this);
484 void SdrEdgeObj::DisconnectFromNode(FASTBOOL bTail1
)
486 SdrObjConnection
& rCon
=GetConnection(bTail1
);
487 if (rCon
.pObj
!=NULL
) {
488 rCon
.pObj
->RemoveListener(*this);
493 SdrObject
* SdrEdgeObj::GetConnectedNode(FASTBOOL bTail1
) const
495 SdrObject
* pObj
=GetConnection(bTail1
).pObj
;
496 if (pObj
!=NULL
&& (pObj
->GetPage()!=pPage
|| !pObj
->IsInserted())) pObj
=NULL
;
500 FASTBOOL
SdrEdgeObj::CheckNodeConnection(FASTBOOL bTail1
) const
503 const SdrObjConnection
& rCon
=GetConnection(bTail1
);
504 USHORT nPtAnz
=pEdgeTrack
->GetPointCount();
505 if (rCon
.pObj
!=NULL
&& rCon
.pObj
->GetPage()==pPage
&& nPtAnz
!=0) {
506 const SdrGluePointList
* pGPL
=rCon
.pObj
->GetGluePointList();
507 USHORT nConAnz
=pGPL
==NULL
? 0 : pGPL
->GetCount();
508 USHORT nGesAnz
=nConAnz
+8;
509 Point
aTail(bTail1
? (*pEdgeTrack
)[0] : (*pEdgeTrack
)[USHORT(nPtAnz
-1)]);
510 for (USHORT i
=0; i
<nGesAnz
&& !bRet
; i
++) {
511 if (i
<nConAnz
) { // UserDefined
512 bRet
=aTail
==(*pGPL
)[i
].GetAbsolutePos(*rCon
.pObj
);
513 } else if (i
<nConAnz
+4) { // Vertex
514 SdrGluePoint
aPt(rCon
.pObj
->GetVertexGluePoint(i
-nConAnz
));
515 bRet
=aTail
==aPt
.GetAbsolutePos(*rCon
.pObj
);
517 SdrGluePoint
aPt(rCon
.pObj
->GetCornerGluePoint(i
-nConAnz
-4));
518 bRet
=aTail
==aPt
.GetAbsolutePos(*rCon
.pObj
);
525 void SdrEdgeObj::ImpSetTailPoint(FASTBOOL bTail1
, const Point
& rPt
)
527 USHORT nPtAnz
=pEdgeTrack
->GetPointCount();
529 (*pEdgeTrack
)[0]=rPt
;
530 (*pEdgeTrack
)[1]=rPt
;
531 } else if (nPtAnz
==1) {
532 if (!bTail1
) (*pEdgeTrack
)[1]=rPt
;
533 else { (*pEdgeTrack
)[1]=(*pEdgeTrack
)[0]; (*pEdgeTrack
)[0]=rPt
; }
535 if (!bTail1
) (*pEdgeTrack
)[USHORT(nPtAnz
-1)]=rPt
;
536 else (*pEdgeTrack
)[0]=rPt
;
538 ImpRecalcEdgeTrack();
542 void SdrEdgeObj::ImpDirtyEdgeTrack()
544 if ( !bEdgeTrackUserDefined
|| !(GetModel() && GetModel()->isLocked()) )
545 bEdgeTrackDirty
= sal_True
;
548 void SdrEdgeObj::ImpUndirtyEdgeTrack()
550 if (bEdgeTrackDirty
&& (GetModel() && GetModel()->isLocked()) ) {
551 ImpRecalcEdgeTrack();
555 void SdrEdgeObj::ImpRecalcEdgeTrack()
557 if ( bEdgeTrackUserDefined
&& (GetModel() && GetModel()->isLocked()) )
561 if(IsBoundRectCalculationRunning())
563 // this object is involved into another ImpRecalcEdgeTrack() call
564 // from another SdrEdgeObj. Do not calculate again to avoid loop.
565 // Also, do not change bEdgeTrackDirty so that it gets recalculated
566 // later at the first non-looping call.
569 else if(GetModel() && GetModel()->isLocked())
571 // avoid re-layout during imports/API call sequences
572 // #i45294# but calc EdgeTrack and secure properties there
573 ((SdrEdgeObj
*)this)->mbBoundRectCalculationRunning
= sal_True
;
574 *pEdgeTrack
=ImpCalcEdgeTrack(*pEdgeTrack
,aCon1
,aCon2
,&aEdgeInfo
);
575 ImpSetAttrToEdgeInfo();
576 bEdgeTrackDirty
=sal_False
;
577 ((SdrEdgeObj
*)this)->mbBoundRectCalculationRunning
= sal_False
;
581 // To not run in a depth loop, use a coloring algorythm on
582 // SdrEdgeObj BoundRect calculations
583 ((SdrEdgeObj
*)this)->mbBoundRectCalculationRunning
= sal_True
;
585 Rectangle aBoundRect0
; if (pUserCall
!=NULL
) aBoundRect0
=GetLastBoundRect();
587 // #110094#-14 if (!bEdgeTrackDirty) SendRepaintBroadcast();
588 *pEdgeTrack
=ImpCalcEdgeTrack(*pEdgeTrack
,aCon1
,aCon2
,&aEdgeInfo
);
589 ImpSetEdgeInfoToAttr(); // Die Werte aus aEdgeInfo in den Pool kopieren
590 bEdgeTrackDirty
=sal_False
;
592 // Only redraw here, no object change
594 // BroadcastObjectChange();
596 SendUserCall(SDRUSERCALL_RESIZE
,aBoundRect0
);
599 ((SdrEdgeObj
*)this)->mbBoundRectCalculationRunning
= sal_False
;
603 USHORT
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 FASTBOOL bxMitt
=Abs(dxl
-dxr
)<2;
612 FASTBOOL byMitt
=Abs(dyo
-dyu
)<2;
613 long dx
=Min(dxl
,dxr
);
614 long dy
=Min(dyo
,dyu
);
615 FASTBOOL bDiag
=Abs(dx
-dy
)<2;
616 if (bxMitt
&& byMitt
) return SDRESC_ALL
; // In der Mitte
617 if (bDiag
) { // diagonal
619 if (byMitt
) nRet
|=SDRESC_VERT
;
620 if (bxMitt
) nRet
|=SDRESC_HORZ
;
621 if (dxl
<dxr
) { // Links
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
) { // waagerecht
631 if (bxMitt
) return SDRESC_HORZ
;
632 if (dxl
<dxr
) return SDRESC_LEFT
;
633 else return SDRESC_RIGHT
;
634 } else { // senkrecht
635 if (byMitt
) return SDRESC_VERT
;
636 if (dyo
<dyu
) return SDRESC_TOP
;
637 else return SDRESC_BOTTOM
;
641 FASTBOOL
SdrEdgeObj::ImpStripPolyPoints(XPolygon
& /*rXP*/) const
643 // fehlende Implementation !!!
647 XPolygon
SdrEdgeObj::ImpCalcObjToCenter(const Point
& rStPt
, long nEscAngle
, const Rectangle
& rRect
, const Point
& rMeeting
) const
650 aXP
.Insert(XPOLY_APPEND
,rStPt
,XPOLY_NORMAL
);
651 FASTBOOL bRts
=nEscAngle
==0;
652 FASTBOOL bObn
=nEscAngle
==9000;
653 FASTBOOL bLks
=nEscAngle
==18000;
654 FASTBOOL bUnt
=nEscAngle
==27000;
656 Point
aP1(rStPt
); // erstmal den Pflichtabstand
657 if (bLks
) aP1
.X()=rRect
.Left();
658 if (bRts
) aP1
.X()=rRect
.Right();
659 if (bObn
) aP1
.Y()=rRect
.Top();
660 if (bUnt
) aP1
.Y()=rRect
.Bottom();
662 FASTBOOL bFinish
=FALSE
;
664 Point
aP2(aP1
); // Und nun den Pflichtabstand ggf. bis auf Meetinghoehe erweitern
665 if (bLks
&& rMeeting
.X()<=aP2
.X()) aP2
.X()=rMeeting
.X();
666 if (bRts
&& rMeeting
.X()>=aP2
.X()) aP2
.X()=rMeeting
.X();
667 if (bObn
&& rMeeting
.Y()<=aP2
.Y()) aP2
.Y()=rMeeting
.Y();
668 if (bUnt
&& rMeeting
.Y()>=aP2
.Y()) aP2
.Y()=rMeeting
.Y();
669 aXP
.Insert(XPOLY_APPEND
,aP2
,XPOLY_NORMAL
);
672 if ((bLks
&& rMeeting
.X()>aP2
.X()) || (bRts
&& rMeeting
.X()<aP2
.X())) { // Aussenrum
673 if (rMeeting
.Y()<aP2
.Y()) {
675 if (rMeeting
.Y()<aP3
.Y()) aP3
.Y()=rMeeting
.Y();
677 aP3
.Y()=rRect
.Bottom();
678 if (rMeeting
.Y()>aP3
.Y()) aP3
.Y()=rMeeting
.Y();
680 aXP
.Insert(XPOLY_APPEND
,aP3
,XPOLY_NORMAL
);
681 if (aP3
.Y()!=rMeeting
.Y()) {
682 aP3
.X()=rMeeting
.X();
683 aXP
.Insert(XPOLY_APPEND
,aP3
,XPOLY_NORMAL
);
686 if ((bObn
&& rMeeting
.Y()>aP2
.Y()) || (bUnt
&& rMeeting
.Y()<aP2
.Y())) { // Aussenrum
687 if (rMeeting
.X()<aP2
.X()) {
688 aP3
.X()=rRect
.Left();
689 if (rMeeting
.X()<aP3
.X()) aP3
.X()=rMeeting
.X();
691 aP3
.X()=rRect
.Right();
692 if (rMeeting
.X()>aP3
.X()) aP3
.X()=rMeeting
.X();
694 aXP
.Insert(XPOLY_APPEND
,aP3
,XPOLY_NORMAL
);
695 if (aP3
.X()!=rMeeting
.X()) {
696 aP3
.Y()=rMeeting
.Y();
697 aXP
.Insert(XPOLY_APPEND
,aP3
,XPOLY_NORMAL
);
702 if (aXP
.GetPointCount()>4) {
703 DBG_ERROR("SdrEdgeObj::ImpCalcObjToCenter(): Polygon hat mehr als 4 Punkte!");
709 XPolygon
SdrEdgeObj::ImpCalcEdgeTrack(const XPolygon
& rTrack0
, SdrObjConnection
& rCon1
, SdrObjConnection
& rCon2
, SdrEdgeInfoRec
* pInfo
) const
712 SdrGluePoint aGP1
,aGP2
;
713 USHORT nEsc1
=SDRESC_ALL
,nEsc2
=SDRESC_ALL
;
714 Rectangle aBoundRect1
;
715 Rectangle aBoundRect2
;
716 Rectangle aBewareRect1
;
717 Rectangle aBewareRect2
;
718 // Erstmal die alten Endpunkte wiederholen
719 if (rTrack0
.GetPointCount()!=0) {
721 USHORT nSiz
=rTrack0
.GetPointCount();
725 if (!aOutRect
.IsEmpty()) {
726 aPt1
=aOutRect
.TopLeft();
727 aPt2
=aOutRect
.BottomRight();
730 FASTBOOL bCon1
=rCon1
.pObj
!=NULL
&& rCon1
.pObj
->GetPage()==pPage
&& rCon1
.pObj
->IsInserted();
731 FASTBOOL bCon2
=rCon2
.pObj
!=NULL
&& rCon2
.pObj
->GetPage()==pPage
&& rCon2
.pObj
->IsInserted();
732 const SfxItemSet
& rSet
= GetObjectItemSet();
735 if (rCon1
.pObj
==(SdrObject
*)this)
737 // sicherheitshalber Abfragen #44515#
738 aBoundRect1
=aOutRect
;
742 aBoundRect1
= rCon1
.pObj
->GetCurrentBoundRect();
744 aBoundRect1
.Move(rCon1
.aObjOfs
.X(),rCon1
.aObjOfs
.Y());
745 aBewareRect1
=aBoundRect1
;
747 sal_Int32 nH
= ((SdrEdgeNode1HorzDistItem
&)rSet
.Get(SDRATTR_EDGENODE1HORZDIST
)).GetValue();
748 sal_Int32 nV
= ((SdrEdgeNode1VertDistItem
&)rSet
.Get(SDRATTR_EDGENODE1VERTDIST
)).GetValue();
750 aBewareRect1
.Left()-=nH
;
751 aBewareRect1
.Right()+=nH
;
752 aBewareRect1
.Top()-=nV
;
753 aBewareRect1
.Bottom()+=nV
;
755 aBoundRect1
=Rectangle(aPt1
,aPt1
);
756 aBoundRect1
.Move(rCon1
.aObjOfs
.X(),rCon1
.aObjOfs
.Y());
757 aBewareRect1
=aBoundRect1
;
760 if (rCon2
.pObj
==(SdrObject
*)this) { // sicherheitshalber Abfragen #44515#
761 aBoundRect2
=aOutRect
;
765 aBoundRect2
= rCon2
.pObj
->GetCurrentBoundRect();
767 aBoundRect2
.Move(rCon2
.aObjOfs
.X(),rCon2
.aObjOfs
.Y());
768 aBewareRect2
=aBoundRect2
;
770 sal_Int32 nH
= ((SdrEdgeNode2HorzDistItem
&)rSet
.Get(SDRATTR_EDGENODE2HORZDIST
)).GetValue();
771 sal_Int32 nV
= ((SdrEdgeNode2VertDistItem
&)rSet
.Get(SDRATTR_EDGENODE2VERTDIST
)).GetValue();
773 aBewareRect2
.Left()-=nH
;
774 aBewareRect2
.Right()+=nH
;
775 aBewareRect2
.Top()-=nV
;
776 aBewareRect2
.Bottom()+=nV
;
778 aBoundRect2
=Rectangle(aPt2
,aPt2
);
779 aBoundRect2
.Move(rCon2
.aObjOfs
.X(),rCon2
.aObjOfs
.Y());
780 aBewareRect2
=aBoundRect2
;
783 ULONG nBestQual
=0xFFFFFFFF;
784 SdrEdgeInfoRec aBestInfo
;
785 FASTBOOL bAuto1
=bCon1
&& rCon1
.bBestVertex
;
786 FASTBOOL bAuto2
=bCon2
&& rCon2
.bBestVertex
;
787 if (bAuto1
) rCon1
.bAutoVertex
=TRUE
;
788 if (bAuto2
) rCon2
.bAutoVertex
=TRUE
;
791 USHORT nAnz1
=bAuto1
? 4 : 1;
792 USHORT nAnz2
=bAuto2
? 4 : 1;
793 for (USHORT nNum1
=0; nNum1
<nAnz1
; nNum1
++) {
794 if (bAuto1
) rCon1
.nConId
=nNum1
;
795 if (bCon1
&& rCon1
.TakeGluePoint(aGP1
,TRUE
)) {
797 nEsc1
=aGP1
.GetEscDir();
798 if (nEsc1
==SDRESC_SMART
) nEsc1
=ImpCalcEscAngle(rCon1
.pObj
,aPt1
-rCon1
.aObjOfs
);
800 for (USHORT nNum2
=0; nNum2
<nAnz2
; nNum2
++) {
801 if (bAuto2
) rCon2
.nConId
=nNum2
;
802 if (bCon2
&& rCon2
.TakeGluePoint(aGP2
,TRUE
)) {
804 nEsc2
=aGP2
.GetEscDir();
805 if (nEsc2
==SDRESC_SMART
) nEsc2
=ImpCalcEscAngle(rCon2
.pObj
,aPt2
-rCon2
.aObjOfs
);
807 for (long nA1
=0; nA1
<36000; nA1
+=9000) {
808 USHORT nE1
=nA1
==0 ? SDRESC_RIGHT
: nA1
==9000 ? SDRESC_TOP
: nA1
==18000 ? SDRESC_LEFT
: nA1
==27000 ? SDRESC_BOTTOM
: 0;
809 for (long nA2
=0; nA2
<36000; nA2
+=9000) {
810 USHORT nE2
=nA2
==0 ? SDRESC_RIGHT
: nA2
==9000 ? SDRESC_TOP
: nA2
==18000 ? SDRESC_LEFT
: nA2
==27000 ? SDRESC_BOTTOM
: 0;
811 if ((nEsc1
&nE1
)!=0 && (nEsc2
&nE2
)!=0) {
813 SdrEdgeInfoRec aInfo
;
814 if (pInfo
!=NULL
) aInfo
=*pInfo
;
815 XPolygon
aXP(ImpCalcEdgeTrack(aPt1
,nA1
,aBoundRect1
,aBewareRect1
,aPt2
,nA2
,aBoundRect2
,aBewareRect2
,&nQual
,&aInfo
));
816 if (nQual
<nBestQual
) {
828 if (bAuto1
) rCon1
.nConId
=nBestAuto1
;
829 if (bAuto2
) rCon2
.nConId
=nBestAuto2
;
830 if (pInfo
!=NULL
) *pInfo
=aBestInfo
;
834 XPolygon
SdrEdgeObj::ImpCalcEdgeTrack(const Point
& rPt1
, long nAngle1
, const Rectangle
& rBoundRect1
, const Rectangle
& rBewareRect1
,
835 const Point
& rPt2
, long nAngle2
, const Rectangle
& rBoundRect2
, const Rectangle
& rBewareRect2
,
836 ULONG
* pnQuality
, SdrEdgeInfoRec
* pInfo
) const
838 SdrEdgeKind eKind
=((SdrEdgeKindItem
&)(GetObjectItem(SDRATTR_EDGEKIND
))).GetValue();
839 FASTBOOL bRts1
=nAngle1
==0;
840 FASTBOOL bObn1
=nAngle1
==9000;
841 FASTBOOL bLks1
=nAngle1
==18000;
842 FASTBOOL bUnt1
=nAngle1
==27000;
843 FASTBOOL bHor1
=bLks1
|| bRts1
;
844 FASTBOOL bVer1
=bObn1
|| bUnt1
;
845 FASTBOOL bRts2
=nAngle2
==0;
846 FASTBOOL bObn2
=nAngle2
==9000;
847 FASTBOOL bLks2
=nAngle2
==18000;
848 FASTBOOL bUnt2
=nAngle2
==27000;
849 FASTBOOL bHor2
=bLks2
|| bRts2
;
850 FASTBOOL bVer2
=bObn2
|| bUnt2
;
851 FASTBOOL bInfo
=pInfo
!=NULL
;
854 pInfo
->nAngle1
=nAngle1
;
855 pInfo
->nAngle2
=nAngle2
;
858 pInfo
->nMiddleLine
=0xFFFF;
862 Rectangle
aBoundRect1 (rBoundRect1
);
863 Rectangle
aBoundRect2 (rBoundRect2
);
864 Rectangle
aBewareRect1(rBewareRect1
);
865 Rectangle
aBewareRect2(rBewareRect2
);
866 Point
aMeeting((aPt1
.X()+aPt2
.X()+1)/2,(aPt1
.Y()+aPt2
.Y()+1)/2);
867 FASTBOOL bMeetingXMid
=TRUE
;
868 FASTBOOL bMeetingYMid
=TRUE
;
869 if (eKind
==SDREDGE_ONELINE
) {
873 if (pnQuality
!=NULL
) {
874 *pnQuality
=Abs(rPt1
.X()-rPt2
.X())+Abs(rPt1
.Y()-rPt2
.Y());
877 } else if (eKind
==SDREDGE_THREELINES
) {
883 if (bRts1
) aXP
[1].X()=aBewareRect1
.Right(); //+=500;
884 if (bObn1
) aXP
[1].Y()=aBewareRect1
.Top(); //-=500;
885 if (bLks1
) aXP
[1].X()=aBewareRect1
.Left(); //-=500;
886 if (bUnt1
) aXP
[1].Y()=aBewareRect1
.Bottom(); //+=500;
887 if (bRts2
) aXP
[2].X()=aBewareRect2
.Right(); //+=500;
888 if (bObn2
) aXP
[2].Y()=aBewareRect2
.Top(); //-=500;
889 if (bLks2
) aXP
[2].X()=aBewareRect2
.Left(); //-=500;
890 if (bUnt2
) aXP
[2].Y()=aBewareRect2
.Bottom(); //+=500;
891 if (pnQuality
!=NULL
) {
892 long nQ
=Abs(aXP
[1].X()-aXP
[0].X())+Abs(aXP
[1].Y()-aXP
[0].Y());
893 nQ
+=Abs(aXP
[2].X()-aXP
[1].X())+Abs(aXP
[2].Y()-aXP
[1].Y());
894 nQ
+=Abs(aXP
[3].X()-aXP
[2].X())+Abs(aXP
[3].Y()-aXP
[2].Y());
901 aXP
[1].X()+=pInfo
->aObj1Line2
.X();
903 aXP
[1].Y()+=pInfo
->aObj1Line2
.Y();
906 aXP
[2].X()+=pInfo
->aObj2Line2
.X();
908 aXP
[2].Y()+=pInfo
->aObj2Line2
.Y();
913 USHORT nIntersections
=0;
914 FASTBOOL bForceMeeting
=FALSE
; // Muss die Linie durch den MeetingPoint laufen?
916 Point
aC1(aBewareRect1
.Center());
917 Point
aC2(aBewareRect2
.Center());
918 if (aBewareRect1
.Left()<=aBewareRect2
.Right() && aBewareRect1
.Right()>=aBewareRect2
.Left()) {
919 // Ueberschneidung auf der X-Achse
920 long n1
=Max(aBewareRect1
.Left(),aBewareRect2
.Left());
921 long n2
=Min(aBewareRect1
.Right(),aBewareRect2
.Right());
922 aMeeting
.X()=(n1
+n2
+1)/2;
924 // Ansonsten den Mittelpunkt des Freiraums
925 if (aC1
.X()<aC2
.X()) {
926 aMeeting
.X()=(aBewareRect1
.Right()+aBewareRect2
.Left()+1)/2;
928 aMeeting
.X()=(aBewareRect1
.Left()+aBewareRect2
.Right()+1)/2;
931 if (aBewareRect1
.Top()<=aBewareRect2
.Bottom() && aBewareRect1
.Bottom()>=aBewareRect2
.Top()) {
932 // Ueberschneidung auf der Y-Achse
933 long n1
=Max(aBewareRect1
.Top(),aBewareRect2
.Top());
934 long n2
=Min(aBewareRect1
.Bottom(),aBewareRect2
.Bottom());
935 aMeeting
.Y()=(n1
+n2
+1)/2;
937 // Ansonsten den Mittelpunkt des Freiraums
938 if (aC1
.Y()<aC2
.Y()) {
939 aMeeting
.Y()=(aBewareRect1
.Bottom()+aBewareRect2
.Top()+1)/2;
941 aMeeting
.Y()=(aBewareRect1
.Top()+aBewareRect2
.Bottom()+1)/2;
944 // Im Prinzip gibt es 3 zu unterscheidene Faelle:
945 // 1. Beide in die selbe Richtung
946 // 2. Beide in genau entgegengesetzte Richtungen
947 // 3. Einer waagerecht und der andere senkrecht
948 long nXMin
=Min(aBewareRect1
.Left(),aBewareRect2
.Left());
949 long nXMax
=Max(aBewareRect1
.Right(),aBewareRect2
.Right());
950 long nYMin
=Min(aBewareRect1
.Top(),aBewareRect2
.Top());
951 long nYMax
=Max(aBewareRect1
.Bottom(),aBewareRect2
.Bottom());
952 //FASTBOOL bBoundOverlap=aBoundRect1.Right()>aBoundRect2.Left() && aBoundRect1.Left()<aBoundRect2.Right() &&
953 aBoundRect1
.Bottom()>aBoundRect2
.Top() && aBoundRect1
.Top()<aBoundRect2
.Bottom();
954 FASTBOOL bBewareOverlap
=aBewareRect1
.Right()>aBewareRect2
.Left() && aBewareRect1
.Left()<aBewareRect2
.Right() &&
955 aBewareRect1
.Bottom()>aBewareRect2
.Top() && aBewareRect1
.Top()<aBewareRect2
.Bottom();
956 unsigned nMainCase
=3;
957 if (nAngle1
==nAngle2
) nMainCase
=1;
958 else if ((bHor1
&& bHor2
) || (bVer1
&& bVer2
)) nMainCase
=2;
959 if (nMainCase
==1) { // Fall 1: Beide in eine Richtung moeglich.
960 if (bVer1
) aMeeting
.X()=(aPt1
.X()+aPt2
.X()+1)/2; // ist hier besser, als der
961 if (bHor1
) aMeeting
.Y()=(aPt1
.Y()+aPt2
.Y()+1)/2; // Mittelpunkt des Freiraums
962 // bX1Ok bedeutet, dass die Vertikale, die aus Obj1 austritt, keinen Konflikt mit Obj2 bildet, ...
963 FASTBOOL bX1Ok
=aPt1
.X()<=aBewareRect2
.Left() || aPt1
.X()>=aBewareRect2
.Right();
964 FASTBOOL bX2Ok
=aPt2
.X()<=aBewareRect1
.Left() || aPt2
.X()>=aBewareRect1
.Right();
965 FASTBOOL bY1Ok
=aPt1
.Y()<=aBewareRect2
.Top() || aPt1
.Y()>=aBewareRect2
.Bottom();
966 FASTBOOL bY2Ok
=aPt2
.Y()<=aBewareRect1
.Top() || aPt2
.Y()>=aBewareRect1
.Bottom();
967 if (bLks1
&& (bY1Ok
|| aBewareRect1
.Left()<aBewareRect2
.Right()) && (bY2Ok
|| aBewareRect2
.Left()<aBewareRect1
.Right())) {
971 if (bRts1
&& (bY1Ok
|| aBewareRect1
.Right()>aBewareRect2
.Left()) && (bY2Ok
|| aBewareRect2
.Right()>aBewareRect1
.Left())) {
975 if (bObn1
&& (bX1Ok
|| aBewareRect1
.Top()<aBewareRect2
.Bottom()) && (bX2Ok
|| aBewareRect2
.Top()<aBewareRect1
.Bottom())) {
979 if (bUnt1
&& (bX1Ok
|| aBewareRect1
.Bottom()>aBewareRect2
.Top()) && (bX2Ok
|| aBewareRect2
.Bottom()>aBewareRect1
.Top())) {
983 } else if (nMainCase
==2) {
986 if (bHor1
) { // beide waagerecht
987 /* 9 Moeglichkeiten: ù ù ù */
988 /* 2.1 Gegenueber, Ueberschneidung à ´ ù */
989 /* nur auf der Y-Achse ù ù ù */
990 /* 2.2, 2.3 Gegenueber, vertikal versetzt. Ã ù ù ù ù ù */
991 /* Ueberschneidung weder auf der ù ´ ù ù ´ ù */
992 /* X- noch auf der Y-Achse ù ù ù Ã ù ù */
993 /* 2.4, 2.5 Untereinander, ù Ã ù ù ù ù */
994 /* Ueberschneidung ù ´ ù ù ´ ù */
995 /* nur auf X-Achse ù ù ù ù Ã ù */
996 /* 2.6, 2.7 Gegeneinander, vertikal versetzt. ù ù Ã ù ù ù */
997 /* Ueberschneidung weder auf der ù ´ ù ù ´ ù */
998 /* X- noch auf der Y-Achse. ù ù ù ù ù Ã */
999 /* 2.8 Gegeneinander. ù ù ù */
1000 /* Ueberschneidung nur ù ´ Ã */
1001 /* auf der Y-Achse. ù ù ù */
1002 /* 2.9 Die BewareRects der Objekte ueberschneiden */
1003 /* sich auf X- und Y-Achse. */
1004 /* Die Faelle gelten entsprechend umgesetzt auch fuer */
1005 /* senkrechte Linienaustritte. */
1006 /* Die Faelle 2.1-2.7 werden mit dem Default-Meeting ausreichend*/
1007 /* gut behandelt. Spezielle MeetingPoints werden hier also nur */
1008 /* fuer 2.8 und 2.9 bestimmt. */
1010 // Normalisierung. aR1 soll der nach rechts und
1011 // aR2 der nach links austretende sein.
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 // Ueberschneidung auf der Y-Achse. Faelle 2.1, 2.8, 2.9
1018 if (aBewR1
.Right()>aBewR2
.Left()) {
1020 // Fall 2.8 ist immer Aussenrumlauf (bDirect=FALSE).
1021 // Fall 2.9 kann auch Direktverbindung sein (bei geringer
1022 // Ueberschneidung der BewareRects ohne Ueberschneidung der
1023 // Boundrects wenn die Linienaustritte sonst das BewareRect
1024 // des jeweils anderen Objekts verletzen wuerden.
1025 FASTBOOL bCase29Direct
=FALSE
;
1026 FASTBOOL bCase29
=aBewR1
.Right()>aBewR2
.Left();
1027 if (aBndR1
.Right()<=aBndR2
.Left()) { // Fall 2.9 und keine Boundrectueberschneidung
1028 if ((aPt1
.Y()>aBewareRect2
.Top() && aPt1
.Y()<aBewareRect2
.Bottom()) ||
1029 (aPt2
.Y()>aBewareRect1
.Top() && aPt2
.Y()<aBewareRect1
.Bottom())) {
1033 if (!bCase29Direct
) {
1034 FASTBOOL bObenLang
=Abs(nYMin
-aMeeting
.Y())<=Abs(nYMax
-aMeeting
.Y());
1042 // und nun noch dafuer sorgen, dass das
1043 // umzingelte Obj nicht durchquert wird
1044 if (aBewR1
.Center().Y()<aBewR2
.Center().Y() != bObenLang
) {
1045 aMeeting
.X()=aBewR2
.Right();
1047 aMeeting
.X()=aBewR1
.Left();
1052 // Direkte Verbindung (3-Linien Z-Verbindung), da
1053 // Verletzung der BewareRects unvermeidlich ist.
1054 // Via Dreisatz werden die BewareRects nun verkleinert.
1055 long nWant1
=aBewR1
.Right()-aBndR1
.Right(); // Abstand bei Obj1
1056 long nWant2
=aBndR2
.Left()-aBewR2
.Left(); // Abstand bei Obj2
1057 long nSpace
=aBndR2
.Left()-aBndR1
.Right(); // verfuegbarer Platz
1058 long nGet1
=BigMulDiv(nWant1
,nSpace
,nWant1
+nWant2
);
1059 long nGet2
=nSpace
-nGet1
;
1060 if (bRts1
) { // Normalisierung zurueckwandeln
1061 aBewareRect1
.Right()+=nGet1
-nWant1
;
1062 aBewareRect2
.Left()-=nGet2
-nWant2
;
1064 aBewareRect2
.Right()+=nGet1
-nWant1
;
1065 aBewareRect1
.Left()-=nGet2
-nWant2
;
1067 nIntersections
++; // Qualitaet herabsetzen
1071 } else if (bVer1
) { // beide senkrecht
1072 Rectangle
aBewR1(bUnt1
? aBewareRect1
: aBewareRect2
);
1073 Rectangle
aBewR2(bUnt1
? aBewareRect2
: aBewareRect1
);
1074 Rectangle
aBndR1(bUnt1
? aBoundRect1
: aBoundRect2
);
1075 Rectangle
aBndR2(bUnt1
? aBoundRect2
: aBoundRect1
);
1076 if (aBewR1
.Right()>aBewR2
.Left() && aBewR1
.Left()<aBewR2
.Right()) {
1077 // Ueberschneidung auf der Y-Achse. Faelle 2.1, 2.8, 2.9
1078 if (aBewR1
.Bottom()>aBewR2
.Top()) {
1080 // Fall 2.8 ist immer Aussenrumlauf (bDirect=FALSE).
1081 // Fall 2.9 kann auch Direktverbindung sein (bei geringer
1082 // Ueberschneidung der BewareRects ohne Ueberschneidung der
1083 // Boundrects wenn die Linienaustritte sonst das BewareRect
1084 // des jeweils anderen Objekts verletzen wuerden.
1085 FASTBOOL bCase29Direct
=FALSE
;
1086 FASTBOOL bCase29
=aBewR1
.Bottom()>aBewR2
.Top();
1087 if (aBndR1
.Bottom()<=aBndR2
.Top()) { // Fall 2.9 und keine Boundrectueberschneidung
1088 if ((aPt1
.X()>aBewareRect2
.Left() && aPt1
.X()<aBewareRect2
.Right()) ||
1089 (aPt2
.X()>aBewareRect1
.Left() && aPt2
.X()<aBewareRect1
.Right())) {
1093 if (!bCase29Direct
) {
1094 FASTBOOL bLinksLang
=Abs(nXMin
-aMeeting
.X())<=Abs(nXMax
-aMeeting
.X());
1102 // und nun noch dafuer sorgen, dass das
1103 // umzingelte Obj nicht durchquert wird
1104 if (aBewR1
.Center().X()<aBewR2
.Center().X() != bLinksLang
) {
1105 aMeeting
.Y()=aBewR2
.Bottom();
1107 aMeeting
.Y()=aBewR1
.Top();
1112 // Direkte Verbindung (3-Linien Z-Verbindung), da
1113 // Verletzung der BewareRects unvermeidlich ist.
1114 // Via Dreisatz werden die BewareRects nun verkleinert.
1115 long nWant1
=aBewR1
.Bottom()-aBndR1
.Bottom(); // Abstand bei Obj1
1116 long nWant2
=aBndR2
.Top()-aBewR2
.Top(); // Abstand bei Obj2
1117 long nSpace
=aBndR2
.Top()-aBndR1
.Bottom(); // verfuegbarer Platz
1118 long nGet1
=BigMulDiv(nWant1
,nSpace
,nWant1
+nWant2
);
1119 long nGet2
=nSpace
-nGet1
;
1120 if (bUnt1
) { // Normalisierung zurueckwandeln
1121 aBewareRect1
.Bottom()+=nGet1
-nWant1
;
1122 aBewareRect2
.Top()-=nGet2
-nWant2
;
1124 aBewareRect2
.Bottom()+=nGet1
-nWant1
;
1125 aBewareRect1
.Top()-=nGet2
-nWant2
;
1127 nIntersections
++; // Qualitaet herabsetzen
1132 } else if (nMainCase
==3) { // Fall 3: Einer waagerecht und der andere senkrecht. Sehr viele Fallunterscheidungen
1133 /* Kleine Legende: ù ú ù ú ù -> Ohne Ueberschneidung, maximal Beruehrung. */
1134 /* ú ú ú ú ú -> Ueberschneidung */
1135 /* ù ú Ã ú ù -> Selbe Hoehe */
1136 /* ú ú ú ú ú -> Ueberschneidung */
1137 /* ù ú ù ú ù -> Ohne Ueberschneidung, maximal Beruehrung. */
1138 /* Linienaustritte links ´, rechts Ã, oben Á und unten Â. */
1139 /* Insgesamt sind 96 Konstellationen moeglich, wobei einige nicht einmal */
1140 /* eindeutig einem Fall und damit einer Behandlungsmethode zugeordnet werden */
1142 /* 3.1: Hierzu moegen alle Konstellationen zaehlen, die durch den */
1143 /* Default-MeetingPoint zufriedenstellend abgedeckt sind (20+12). */
1144 /* Â Â Â ú Á Á ú Â Â Â Diese 12 ù ú ù Â ù ù ú ù ú ù ù Â ù ú ù ù ú ù ú ù */
1145 /* ú ú ú ú Á Á ú ú ú ú Konstel. ú ú ú ú ú ú ú ú ú Â ú ú ú ú ú Â ú ú ú ú */
1146 /* ù ú Ã ú ù ù ú ´ ú ù jedoch ù ú Ã ú Á ù ú Ã ú Â Á ú ´ ú ù Â ú ´ ú ù */
1147 /* ú ú ú ú Â Â ú ú ú ú nur zum ú ú ú ú Á ú ú ú ú ú Á ú ú ú ú ú ú ú ú ú */
1148 /* Á Á Á ú Â Â ú Á Á Á Teil: ù ú ù Á ù ù ú ù ú ù ù Á ù ú ù ù ú ù ú ù */
1149 /* Letztere 16 Faelle scheiden aus, sobald sich die Objekte offen */
1150 /* gegenueberstehen (siehe Fall 3.2). */
1151 /* 3.2: Die Objekte stehen sich offen gegenueber und somit ist eine */
1152 /* Verbindung mit lediglich 2 Linien moeglich (4+20). */
1153 /* Dieser Fall hat 1. Prioritaet. */
1154 /* ù ú ù ú Â Â ú ù ú ù Diese 20 ù ú ù Â ù ù Â ù ú ù ù ú ù ú ù ù ú ù ú ù */
1155 /* ú ú ú ú ú ú ú ú ú ú Konstel. ú ú ú Â Â Â Â ú ú ú ú ú ú ú ú ú ú ú ú ú */
1156 /* ù ú Ã ú ù ù ú ´ ú ù jedoch ù ú Ã Á Á Á Á ´ ú ù ù ú Ã Â Â Â Â ´ ú ù */
1157 /* ú ú ú ú ú ú ú ú ú ú nur zum ú ú ú Á Á Á Á ú ú ú ú ú ú ú ú ú ú ú ú ú */
1158 /* ù ú ù ú Á Á ú ù ú ù Teil: ù ú ù Á ù ù Á ù ú ù ù ú ù ú ù ù ú ù ú ù */
1159 /* 3.3: Die Linienaustritte zeigen vom anderen Objekt weg bzw. hinter */
1160 /* dessen Ruecken vorbei (52+4). */
1161 /* Á Á Á Á ù ù Á Á Á Á ù ú ú ú ù ù ú ù ú ù Diese 4 ù ú ù ú ù ù ú ù ú ù */
1162 /* Á Á Á Á ú ú Á Á Á Á Â Â Â ú ú ú ú Â Â Â Konstel. ú ú ú Â ú ú Â ú ú ú */
1163 /* Á Á Ã ú ù ù ú ´ Á Á Â Â Ã ú ù ù ú ´ Â Â jedoch ù ú Ã ú ù ù ú ´ ú ù */
1164 /* Á Á Á ú ú ú ú Á Á Á Â Â Â Â ú ú Â Â Â Â nur zum ú ú ú Á ú ú Á ú ú ú */
1165 /* ù ú ù ú ù ù ú ù ú ù Â Â Â Â ù ù Â Â Â Â Teil: ù ú ù ú ù ù ú ù ú ù */
1168 Rectangle
aTmpR1(aBewareRect1
);
1169 Rectangle
aTmpR2(aBewareRect2
);
1170 if (bBewareOverlap
) {
1171 // Ueberschneidung der BewareRects: BoundRects fuer Check auf Fall 3.2 verwenden.
1175 if ((((bRts1
&& aTmpR1
.Right ()<=aPt2
.X()) || (bLks1
&& aTmpR1
.Left()>=aPt2
.X())) &&
1176 ((bUnt2
&& aTmpR2
.Bottom()<=aPt1
.Y()) || (bObn2
&& aTmpR2
.Top ()>=aPt1
.Y()))) ||
1177 (((bRts2
&& aTmpR2
.Right ()<=aPt1
.X()) || (bLks2
&& aTmpR2
.Left()>=aPt1
.X())) &&
1178 ((bUnt1
&& aTmpR1
.Bottom()<=aPt2
.Y()) || (bObn1
&& aTmpR1
.Top ()>=aPt2
.Y())))) {
1179 // Fall 3.2 trifft zu: Verbindung mit lediglich 2 Linien
1184 aMeeting
.X()=aPt2
.X();
1185 aMeeting
.Y()=aPt1
.Y();
1187 aMeeting
.X()=aPt1
.X();
1188 aMeeting
.Y()=aPt2
.Y();
1190 // Falls Ueberschneidung der BewareRects:
1191 aBewareRect1
=aTmpR1
;
1192 aBewareRect2
=aTmpR2
;
1193 } else if ((((bRts1
&& aBewareRect1
.Right ()>aBewareRect2
.Left ()) ||
1194 (bLks1
&& aBewareRect1
.Left ()<aBewareRect2
.Right ())) &&
1195 ((bUnt2
&& aBewareRect2
.Bottom()>aBewareRect1
.Top ()) ||
1196 (bObn2
&& aBewareRect2
.Top ()<aBewareRect1
.Bottom()))) ||
1197 (((bRts2
&& aBewareRect2
.Right ()>aBewareRect1
.Left ()) ||
1198 (bLks2
&& aBewareRect2
.Left ()<aBewareRect1
.Right ())) &&
1199 ((bUnt1
&& aBewareRect1
.Bottom()>aBewareRect2
.Top ()) ||
1200 (bObn1
&& aBewareRect1
.Top ()<aBewareRect2
.Bottom())))) {
1203 if (bRts1
|| bRts2
) { aMeeting
.X()=nXMax
; bMeetingXMid
=FALSE
; }
1204 if (bLks1
|| bLks2
) { aMeeting
.X()=nXMin
; bMeetingXMid
=FALSE
; }
1205 if (bUnt1
|| bUnt2
) { aMeeting
.Y()=nYMax
; bMeetingYMid
=FALSE
; }
1206 if (bObn1
|| bObn2
) { aMeeting
.Y()=nYMin
; bMeetingYMid
=FALSE
; }
1211 XPolygon
aXP1(ImpCalcObjToCenter(aPt1
,nAngle1
,aBewareRect1
,aMeeting
));
1212 XPolygon
aXP2(ImpCalcObjToCenter(aPt2
,nAngle2
,aBewareRect2
,aMeeting
));
1213 USHORT nXP1Anz
=aXP1
.GetPointCount();
1214 USHORT nXP2Anz
=aXP2
.GetPointCount();
1216 pInfo
->nObj1Lines
=nXP1Anz
; if (nXP1Anz
>1) pInfo
->nObj1Lines
--;
1217 pInfo
->nObj2Lines
=nXP2Anz
; if (nXP2Anz
>1) pInfo
->nObj2Lines
--;
1219 Point
aEP1(aXP1
[nXP1Anz
-1]);
1220 Point
aEP2(aXP2
[nXP2Anz
-1]);
1221 FASTBOOL bInsMeetingPoint
=aEP1
.X()!=aEP2
.X() && aEP1
.Y()!=aEP2
.Y();
1222 FASTBOOL bHorzE1
=aEP1
.Y()==aXP1
[nXP1Anz
-2].Y(); // letzte Linie von XP1 horizontal?
1223 FASTBOOL bHorzE2
=aEP2
.Y()==aXP2
[nXP2Anz
-2].Y(); // letzte Linie von XP2 horizontal?
1224 if (aEP1
==aEP2
&& (bHorzE1
&& bHorzE2
&& aEP1
.Y()==aEP2
.Y()) || (!bHorzE1
&& !bHorzE2
&& aEP1
.X()==aEP2
.X())) {
1225 // Sonderbehandlung fuer 'I'-Verbinder
1226 nXP1Anz
--; aXP1
.Remove(nXP1Anz
,1);
1227 nXP2Anz
--; aXP2
.Remove(nXP2Anz
,1);
1231 if (bInsMeetingPoint
) {
1232 aXP1
.Insert(XPOLY_APPEND
,aMeeting
,XPOLY_NORMAL
);
1234 // Durch einfuegen des MeetingPoints kommen 2 weitere Linie hinzu.
1235 // Evtl. wird eine von diesen die Mittellinie.
1236 if (pInfo
->nObj1Lines
==pInfo
->nObj2Lines
) {
1237 pInfo
->nObj1Lines
++;
1238 pInfo
->nObj2Lines
++;
1240 if (pInfo
->nObj1Lines
>pInfo
->nObj2Lines
) {
1241 pInfo
->nObj2Lines
++;
1242 pInfo
->nMiddleLine
=nXP1Anz
-1;
1244 pInfo
->nObj1Lines
++;
1245 pInfo
->nMiddleLine
=nXP1Anz
;
1249 } else if (bInfo
&& aEP1
!=aEP2
&& nXP1Anz
+nXP2Anz
>=4) {
1250 // Durch Verbinden der beiden Enden kommt eine weitere Linie hinzu.
1251 // Dies wird die Mittellinie.
1252 pInfo
->nMiddleLine
=nXP1Anz
-1;
1254 USHORT nNum
=aXP2
.GetPointCount();
1255 if (aXP1
[nXP1Anz
-1]==aXP2
[nXP2Anz
-1] && nXP1Anz
>1 && nXP2Anz
>1) nNum
--;
1258 aXP1
.Insert(XPOLY_APPEND
,aXP2
[nNum
],XPOLY_NORMAL
);
1260 USHORT nPntAnz
=aXP1
.GetPointCount();
1262 if (bInfo
|| pnQuality
!=NULL
) {
1264 if (nPntAnz
==2) cForm
='I';
1265 else if (nPntAnz
==3) cForm
='L';
1266 else if (nPntAnz
==4) { // Z oder U
1267 if (nAngle1
==nAngle2
) cForm
='U';
1269 } else if (nPntAnz
==4) { /* Ú-¿ Ú-¿ */
1271 } else if (nPntAnz
==6) { // S oder C oder ...
1272 if (nAngle1
!=nAngle2
) {
1273 // Fuer Typ S hat Linie2 dieselbe Richtung wie Linie4.
1274 // Bei Typ C sind die beiden genau entgegengesetzt.
1279 if (aP1
.Y()==aP2
.Y()) { // beide Linien Horz
1280 if (aP1
.X()<aP2
.X()==aP3
.X()<aP4
.X()) cForm
='S';
1282 } else { // sonst beide Linien Vert
1283 if (aP1
.Y()<aP2
.Y()==aP3
.Y()<aP4
.Y()) cForm
='S';
1286 } else cForm
='4'; // sonst der 3. Fall mit 5 Linien
1287 } else cForm
='?'; //
1290 pInfo
->cOrthoForm
=cForm
;
1291 if (cForm
=='I' || cForm
=='L' || cForm
=='Z' || cForm
=='U') {
1292 pInfo
->nObj1Lines
=1;
1293 pInfo
->nObj2Lines
=1;
1294 if (cForm
=='Z' || cForm
=='U') {
1295 pInfo
->nMiddleLine
=1;
1297 pInfo
->nMiddleLine
=0xFFFF;
1299 } else if (cForm
=='S' || cForm
=='C') {
1300 pInfo
->nObj1Lines
=2;
1301 pInfo
->nObj2Lines
=2;
1302 pInfo
->nMiddleLine
=2;
1306 if (pnQuality
!=NULL
) {
1308 ULONG nQual0
=nQual
; // Ueberlaeufe vorbeugen
1309 FASTBOOL bOverflow
=FALSE
;
1310 Point
aPt0(aXP1
[0]);
1311 for (USHORT nPntNum
=1; nPntNum
<nPntAnz
; nPntNum
++) {
1312 Point
aPt1b(aXP1
[nPntNum
]);
1313 nQual
+=Abs(aPt1b
.X()-aPt0
.X())+Abs(aPt1b
.Y()-aPt0
.Y());
1314 if (nQual
<nQual0
) bOverflow
=TRUE
;
1319 USHORT nTmp
=nPntAnz
;
1321 nTmp
=2; // Z-Form hat gute Qualitaet (nTmp=2 statt 4)
1322 ULONG n1
=Abs(aXP1
[1].X()-aXP1
[0].X())+Abs(aXP1
[1].Y()-aXP1
[0].Y());
1323 ULONG n2
=Abs(aXP1
[2].X()-aXP1
[1].X())+Abs(aXP1
[2].Y()-aXP1
[1].Y());
1324 ULONG n3
=Abs(aXP1
[3].X()-aXP1
[2].X())+Abs(aXP1
[3].Y()-aXP1
[2].Y());
1325 // fuer moeglichst gleichlange Linien sorgen
1329 if (n1
>=n2
) nBesser
=6;
1330 else if (n1
>=3*n3
) nBesser
=4;
1331 else if (n1
>=2*n3
) nBesser
=2;
1332 if (aXP1
[0].Y()!=aXP1
[1].Y()) nBesser
++; // Senkrechte Startlinie kriegt auch noch einen Pluspunkt (fuer H/V-Prio)
1333 if (nQual
>nBesser
) nQual
-=nBesser
; else nQual
=0;
1337 nQual
+=(ULONG
)nTmp
*0x01000000;
1338 if (nQual
<nQual0
|| nTmp
>15) bOverflow
=TRUE
;
1340 if (nPntAnz
>=2) { // Austrittswinkel nochmal pruefen
1341 Point
aP1(aXP1
[1]); aP1
-=aXP1
[0];
1342 Point
aP2(aXP1
[nPntAnz
-2]); aP2
-=aXP1
[nPntAnz
-1];
1343 long nAng1
=0; if (aP1
.X()<0) nAng1
=18000; if (aP1
.Y()>0) nAng1
=27000;
1344 if (aP1
.Y()<0) nAng1
=9000; if (aP1
.X()!=0 && aP1
.Y()!=0) nAng1
=1; // Schraeg!?!
1345 long nAng2
=0; if (aP2
.X()<0) nAng2
=18000; if (aP2
.Y()>0) nAng2
=27000;
1346 if (aP2
.Y()<0) nAng2
=9000; if (aP2
.X()!=0 && aP2
.Y()!=0) nAng2
=1; // Schraeg!?!
1347 if (nAng1
!=nAngle1
) nIntersections
++;
1348 if (nAng2
!=nAngle2
) nIntersections
++;
1351 // Fuer den Qualitaetscheck wieder die Original-Rects verwenden und
1352 // gleichzeitig checken, ob eins fuer die Edge-Berechnung verkleinert
1353 // wurde (z.B. Fall 2.9)
1354 aBewareRect1
=rBewareRect1
;
1355 aBewareRect2
=rBewareRect2
;
1357 for (USHORT i
=0; i
<nPntAnz
; i
++) {
1358 Point
aPt1b(aXP1
[i
]);
1359 FASTBOOL b1
=aPt1b
.X()>aBewareRect1
.Left() && aPt1b
.X()<aBewareRect1
.Right() &&
1360 aPt1b
.Y()>aBewareRect1
.Top() && aPt1b
.Y()<aBewareRect1
.Bottom();
1361 FASTBOOL b2
=aPt1b
.X()>aBewareRect2
.Left() && aPt1b
.X()<aBewareRect2
.Right() &&
1362 aPt1b
.Y()>aBewareRect2
.Top() && aPt1b
.Y()<aBewareRect2
.Bottom();
1363 USHORT nInt0
=nIntersections
;
1364 if (i
==0 || i
==nPntAnz
-1) {
1365 if (b1
&& b2
) nIntersections
++;
1367 if (b1
) nIntersections
++;
1368 if (b2
) nIntersections
++;
1370 // und nun noch auf Ueberschneidungen checken
1371 if (i
>0 && nInt0
==nIntersections
) {
1372 if (aPt0
.Y()==aPt1b
.Y()) { // Horizontale Linie
1373 if (aPt0
.Y()>aBewareRect1
.Top() && aPt0
.Y()<aBewareRect1
.Bottom() &&
1374 ((aPt0
.X()<=aBewareRect1
.Left() && aPt1b
.X()>=aBewareRect1
.Right()) ||
1375 (aPt1b
.X()<=aBewareRect1
.Left() && aPt0
.X()>=aBewareRect1
.Right()))) nIntersections
++;
1376 if (aPt0
.Y()>aBewareRect2
.Top() && aPt0
.Y()<aBewareRect2
.Bottom() &&
1377 ((aPt0
.X()<=aBewareRect2
.Left() && aPt1b
.X()>=aBewareRect2
.Right()) ||
1378 (aPt1b
.X()<=aBewareRect2
.Left() && aPt0
.X()>=aBewareRect2
.Right()))) nIntersections
++;
1379 } else { // Vertikale Linie
1380 if (aPt0
.X()>aBewareRect1
.Left() && aPt0
.X()<aBewareRect1
.Right() &&
1381 ((aPt0
.Y()<=aBewareRect1
.Top() && aPt1b
.Y()>=aBewareRect1
.Bottom()) ||
1382 (aPt1b
.Y()<=aBewareRect1
.Top() && aPt0
.Y()>=aBewareRect1
.Bottom()))) nIntersections
++;
1383 if (aPt0
.X()>aBewareRect2
.Left() && aPt0
.X()<aBewareRect2
.Right() &&
1384 ((aPt0
.Y()<=aBewareRect2
.Top() && aPt1b
.Y()>=aBewareRect2
.Bottom()) ||
1385 (aPt1b
.Y()<=aBewareRect2
.Top() && aPt0
.Y()>=aBewareRect2
.Bottom()))) nIntersections
++;
1390 if (nPntAnz
<=1) nIntersections
++;
1392 nQual
+=(ULONG
)nIntersections
*0x10000000;
1393 if (nQual
<nQual0
|| nIntersections
>15) bOverflow
=TRUE
;
1395 if (bOverflow
|| nQual
==0xFFFFFFFF) nQual
=0xFFFFFFFE;
1398 if (bInfo
) { // nun die Linienversaetze auf aXP1 anwenden
1399 if (pInfo
->nMiddleLine
!=0xFFFF) {
1400 USHORT nIdx
=pInfo
->ImpGetPolyIdx(MIDDLELINE
,aXP1
);
1401 if (pInfo
->ImpIsHorzLine(MIDDLELINE
,aXP1
)) {
1402 aXP1
[nIdx
].Y()+=pInfo
->aMiddleLine
.Y();
1403 aXP1
[nIdx
+1].Y()+=pInfo
->aMiddleLine
.Y();
1405 aXP1
[nIdx
].X()+=pInfo
->aMiddleLine
.X();
1406 aXP1
[nIdx
+1].X()+=pInfo
->aMiddleLine
.X();
1409 if (pInfo
->nObj1Lines
>=2) {
1410 USHORT nIdx
=pInfo
->ImpGetPolyIdx(OBJ1LINE2
,aXP1
);
1411 if (pInfo
->ImpIsHorzLine(OBJ1LINE2
,aXP1
)) {
1412 aXP1
[nIdx
].Y()+=pInfo
->aObj1Line2
.Y();
1413 aXP1
[nIdx
+1].Y()+=pInfo
->aObj1Line2
.Y();
1415 aXP1
[nIdx
].X()+=pInfo
->aObj1Line2
.X();
1416 aXP1
[nIdx
+1].X()+=pInfo
->aObj1Line2
.X();
1419 if (pInfo
->nObj1Lines
>=3) {
1420 USHORT nIdx
=pInfo
->ImpGetPolyIdx(OBJ1LINE3
,aXP1
);
1421 if (pInfo
->ImpIsHorzLine(OBJ1LINE3
,aXP1
)) {
1422 aXP1
[nIdx
].Y()+=pInfo
->aObj1Line3
.Y();
1423 aXP1
[nIdx
+1].Y()+=pInfo
->aObj1Line3
.Y();
1425 aXP1
[nIdx
].X()+=pInfo
->aObj1Line3
.X();
1426 aXP1
[nIdx
+1].X()+=pInfo
->aObj1Line3
.X();
1429 if (pInfo
->nObj2Lines
>=2) {
1430 USHORT nIdx
=pInfo
->ImpGetPolyIdx(OBJ2LINE2
,aXP1
);
1431 if (pInfo
->ImpIsHorzLine(OBJ2LINE2
,aXP1
)) {
1432 aXP1
[nIdx
].Y()+=pInfo
->aObj2Line2
.Y();
1433 aXP1
[nIdx
+1].Y()+=pInfo
->aObj2Line2
.Y();
1435 aXP1
[nIdx
].X()+=pInfo
->aObj2Line2
.X();
1436 aXP1
[nIdx
+1].X()+=pInfo
->aObj2Line2
.X();
1439 if (pInfo
->nObj2Lines
>=3) {
1440 USHORT nIdx
=pInfo
->ImpGetPolyIdx(OBJ2LINE3
,aXP1
);
1441 if (pInfo
->ImpIsHorzLine(OBJ2LINE3
,aXP1
)) {
1442 aXP1
[nIdx
].Y()+=pInfo
->aObj2Line3
.Y();
1443 aXP1
[nIdx
+1].Y()+=pInfo
->aObj2Line3
.Y();
1445 aXP1
[nIdx
].X()+=pInfo
->aObj2Line3
.X();
1446 aXP1
[nIdx
+1].X()+=pInfo
->aObj2Line3
.X();
1450 // Nun mache ich ggf. aus dem Verbinder eine Bezierkurve
1451 if (eKind
==SDREDGE_BEZIER
&& nPntAnz
>2) {
1452 Point
* pPt1
=&aXP1
[0];
1453 Point
* pPt2
=&aXP1
[1];
1454 Point
* pPt3
=&aXP1
[nPntAnz
-2];
1455 Point
* pPt4
=&aXP1
[nPntAnz
-1];
1456 long dx1
=pPt2
->X()-pPt1
->X();
1457 long dy1
=pPt2
->Y()-pPt1
->Y();
1458 long dx2
=pPt3
->X()-pPt4
->X();
1459 long dy2
=pPt3
->Y()-pPt4
->Y();
1460 if (cForm
=='L') { // nPntAnz==3
1461 aXP1
.SetFlags(1,XPOLY_CONTROL
);
1463 aXP1
.Insert(2,aPt3
,XPOLY_CONTROL
);
1464 nPntAnz
=aXP1
.GetPointCount();
1467 pPt3
=&aXP1
[nPntAnz
-2];
1468 pPt4
=&aXP1
[nPntAnz
-1];
1473 } else if (nPntAnz
>=4 && nPntAnz
<=6) { // Z oder U oder ...
1474 // fuer Alle Anderen werden die Endpunkte der Ausgangslinien
1475 // erstmal zu Kontrollpunkten. Bei nPntAnz>4 ist also noch
1476 // Nacharbeit erforderlich!
1477 aXP1
.SetFlags(1,XPOLY_CONTROL
);
1478 aXP1
.SetFlags(nPntAnz
-2,XPOLY_CONTROL
);
1485 // Vor und hinter dem Mittelpunkt jeweils
1486 // noch einen Kontrollpunkt einfuegen
1487 Point
aCenter(aXP1
[2]);
1488 long dx1b
=aCenter
.X()-aXP1
[1].X();
1489 long dy1b
=aCenter
.Y()-aXP1
[1].Y();
1490 long dx2b
=aCenter
.X()-aXP1
[3].X();
1491 long dy2b
=aCenter
.Y()-aXP1
[3].Y();
1492 aXP1
.Insert(2,aCenter
,XPOLY_CONTROL
);
1493 aXP1
.SetFlags(3,XPOLY_SYMMTR
);
1494 aXP1
.Insert(4,aCenter
,XPOLY_CONTROL
);
1495 aXP1
[2].X()-=dx1b
/2;
1496 aXP1
[2].Y()-=dy1b
/2;
1497 aXP1
[3].X()-=(dx1b
+dx2b
)/4;
1498 aXP1
[3].Y()-=(dy1b
+dy2b
)/4;
1499 aXP1
[4].X()-=dx2b
/2;
1500 aXP1
[4].Y()-=dy2b
/2;
1503 Point
aPt1b(aXP1
[2]);
1504 Point
aPt2b(aXP1
[3]);
1505 aXP1
.Insert(2,aPt1b
,XPOLY_CONTROL
);
1506 aXP1
.Insert(5,aPt2b
,XPOLY_CONTROL
);
1507 long dx
=aPt1b
.X()-aPt2b
.X();
1508 long dy
=aPt1b
.Y()-aPt2b
.Y();
1511 aXP1
.SetFlags(3,XPOLY_SYMMTR
);
1512 //aXP1[4].X()+=dx/2;
1513 //aXP1[4].Y()+=dy/2;
1514 aXP1
.Remove(4,1); // weil identisch mit aXP1[3]
1522 Nach einer einfachen Rechnung koennte es max. 64 unterschiedliche Verlaeufe mit
1523 5 Linien, 32 mit 4 Linien, 16 mit 3, 8 mit 2 Linien und 4 mit 1 Linie geben=124.
1524 Normalisiert auf 1. Austrittswinkel nach rechts bleiben dann noch 31.
1525 Dann noch eine vertikale Spiegelung wegnormalisiert bleiben noch 16
1526 characteristische Verlaufszuege mit 1-5 Linien:
1527 Mit 1 Linie (Typ 'I'): --
1528 Mit 2 Linien (Typ 'L'): -Ù
1529 Mit 3 Linien (Typ 'U'): -¿ (Typ 'Z'): Ú-
1531 Mit 4 Linien: 1 ist nicht plausibel, 3 ist=2 (90deg Drehung). Verbleibt 2,4
1534 Mit 5 Linien: nicht plausibel sind 1,2,4,5. 7 ist identisch mit 3 (Richtungsumkehr)
1535 Bleibt also 3,6 und 8. '4' 'S' 'C'
1537 Ú-Ù Ú-Ù Ú-¿ Ú-¿ À¿ À¿ -Ù ³ Ú-¿ Ú-¿ À¿ Ú-¿
1538 -Ù -Ù -Ù Ù -Ù À- -Ù -Ù --Ù À Ù -Ù Ù -Ù À Ù
1539 Insgesamt sind also 9 Grundtypen zu unterscheiden die den 400 Konstellationen
1540 aus Objektposition und Austrittswinkeln zuzuordnen sind.
1541 4 der 9 Grundtypen haben eine 'Mittellinie'. Die Anzahl der zu Objektabstaende
1542 je Objekt variiert von 0-3:
1548 4.1: j 0 1 = U+1 bzw. 1+U
1549 4.2: n 0-2 0-2 = Z+1
1552 'C': n 0-3 0-3 = 1+U+1
1555 void __EXPORT
SdrEdgeObj::Notify(SfxBroadcaster
& rBC
, const SfxHint
& rHint
)
1557 SfxSimpleHint
* pSimple
=PTR_CAST(SfxSimpleHint
,&rHint
);
1558 ULONG nId
=pSimple
==0 ? 0 : pSimple
->GetId();
1559 FASTBOOL bDataChg
=nId
==SFX_HINT_DATACHANGED
;
1560 FASTBOOL bDying
=nId
==SFX_HINT_DYING
;
1561 FASTBOOL bObj1
=aCon1
.pObj
!=NULL
&& aCon1
.pObj
->GetBroadcaster()==&rBC
;
1562 FASTBOOL bObj2
=aCon2
.pObj
!=NULL
&& aCon2
.pObj
->GetBroadcaster()==&rBC
;
1563 if (bDying
&& (bObj1
|| bObj2
)) {
1564 // #35605# Dying vorher abfangen, damit AttrObj nicht
1565 // wg. vermeintlicher Vorlagenaenderung rumbroadcastet
1566 if (bObj1
) aCon1
.pObj
=NULL
;
1567 if (bObj2
) aCon2
.pObj
=NULL
;
1568 return; // Und mehr braucht hier nicht getan werden.
1570 if ( bObj1
|| bObj2
)
1572 bEdgeTrackUserDefined
= sal_False
;
1574 SdrTextObj::Notify(rBC
,rHint
);
1575 if (nNotifyingCount
==0) { // Hier nun auch ein VerriegelungsFlag
1576 ((SdrEdgeObj
*)this)->nNotifyingCount
++;
1577 SdrHint
* pSdrHint
=PTR_CAST(SdrHint
,&rHint
);
1578 if (bDataChg
) { // StyleSheet geaendert
1579 ImpSetAttrToEdgeInfo(); // Werte bei Vorlagenaenderung vom Pool nach aEdgeInfo kopieren
1582 (bObj1
&& aCon1
.pObj
->GetPage()==pPage
) ||
1583 (bObj2
&& aCon2
.pObj
->GetPage()==pPage
) ||
1584 (pSdrHint
&& pSdrHint
->GetKind()==HINT_OBJREMOVED
))
1586 // Broadcasting nur, wenn auf der selben Page
1587 Rectangle aBoundRect0
; if (pUserCall
!=NULL
) aBoundRect0
=GetLastBoundRect();
1588 // #110094#-14 if (!bEdgeTrackDirty) SendRepaintBroadcast();
1589 ImpDirtyEdgeTrack();
1591 // only redraw here, no objectchange
1593 // BroadcastObjectChange();
1595 SendUserCall(SDRUSERCALL_RESIZE
,aBoundRect0
);
1597 ((SdrEdgeObj
*)this)->nNotifyingCount
--;
1601 /** updates edges that are connected to the edges of this object
1602 as if the connected objects send a repaint broadcast
1605 void SdrEdgeObj::Reformat()
1607 if( NULL
!= aCon1
.pObj
)
1609 SfxSimpleHint
aHint( SFX_HINT_DATACHANGED
);
1610 Notify( *const_cast<SfxBroadcaster
*>(aCon1
.pObj
->GetBroadcaster()), aHint
);
1613 if( NULL
!= aCon2
.pObj
)
1615 SfxSimpleHint
aHint( SFX_HINT_DATACHANGED
);
1616 Notify( *const_cast<SfxBroadcaster
*>(aCon2
.pObj
->GetBroadcaster()), aHint
);
1620 void SdrEdgeObj::operator=(const SdrObject
& rObj
)
1622 SdrTextObj::operator=(rObj
);
1623 *pEdgeTrack
=*((SdrEdgeObj
&)rObj
).pEdgeTrack
;
1624 bEdgeTrackDirty
=((SdrEdgeObj
&)rObj
).bEdgeTrackDirty
;
1625 aCon1
=((SdrEdgeObj
&)rObj
).aCon1
;
1626 aCon2
=((SdrEdgeObj
&)rObj
).aCon2
;
1629 aEdgeInfo
=((SdrEdgeObj
&)rObj
).aEdgeInfo
;
1632 void SdrEdgeObj::TakeObjNameSingul(XubString
& rName
) const
1634 rName
=ImpGetResStr(STR_ObjNameSingulEDGE
);
1636 String
aName( GetName() );
1639 rName
+= sal_Unicode(' ');
1640 rName
+= sal_Unicode('\'');
1642 rName
+= sal_Unicode('\'');
1646 void SdrEdgeObj::TakeObjNamePlural(XubString
& rName
) const
1648 rName
=ImpGetResStr(STR_ObjNamePluralEDGE
);
1651 basegfx::B2DPolyPolygon
SdrEdgeObj::TakeXorPoly() const
1653 basegfx::B2DPolyPolygon aPolyPolygon
;
1655 if (bEdgeTrackDirty
)
1657 ((SdrEdgeObj
*)this)->ImpRecalcEdgeTrack();
1662 aPolyPolygon
.append(pEdgeTrack
->getB2DPolygon());
1665 return aPolyPolygon
;
1668 void SdrEdgeObj::SetEdgeTrackPath( const basegfx::B2DPolyPolygon
& rPoly
)
1670 if ( !rPoly
.count() )
1672 bEdgeTrackDirty
= sal_True
;
1673 bEdgeTrackUserDefined
= sal_False
;
1677 *pEdgeTrack
= XPolygon( rPoly
.getB2DPolygon( 0 ) );
1678 bEdgeTrackDirty
= sal_False
;
1679 bEdgeTrackUserDefined
= sal_True
;
1683 basegfx::B2DPolyPolygon
SdrEdgeObj::GetEdgeTrackPath() const
1685 basegfx::B2DPolyPolygon aPolyPolygon
;
1687 if (bEdgeTrackDirty
)
1688 ((SdrEdgeObj
*)this)->ImpRecalcEdgeTrack();
1690 aPolyPolygon
.append( pEdgeTrack
->getB2DPolygon() );
1692 return aPolyPolygon
;
1695 sal_uInt32
SdrEdgeObj::GetHdlCount() const
1697 SdrEdgeKind eKind
=((SdrEdgeKindItem
&)(GetObjectItem(SDRATTR_EDGEKIND
))).GetValue();
1698 sal_uInt32
nHdlAnz(0L);
1699 sal_uInt32
nPntAnz(pEdgeTrack
->GetPointCount());
1705 if ((eKind
==SDREDGE_ORTHOLINES
|| eKind
==SDREDGE_BEZIER
) && nPntAnz
>= 4L)
1707 sal_uInt32
nO1(aEdgeInfo
.nObj1Lines
> 0L ? aEdgeInfo
.nObj1Lines
- 1L : 0L);
1708 sal_uInt32
nO2(aEdgeInfo
.nObj2Lines
> 0L ? aEdgeInfo
.nObj2Lines
- 1L : 0L);
1709 sal_uInt32
nM(aEdgeInfo
.nMiddleLine
!= 0xFFFF ? 1L : 0L);
1710 nHdlAnz
+= nO1
+ nO2
+ nM
;
1712 else if (eKind
==SDREDGE_THREELINES
&& nPntAnz
== 4L)
1714 if(GetConnectedNode(TRUE
))
1717 if(GetConnectedNode(FALSE
))
1725 SdrHdl
* SdrEdgeObj::GetHdl(sal_uInt32 nHdlNum
) const
1728 sal_uInt32
nPntAnz(pEdgeTrack
->GetPointCount());
1731 pHdl
=new ImpEdgeHdl((*pEdgeTrack
)[0],HDL_POLY
);
1732 if (aCon1
.pObj
!=NULL
&& aCon1
.bBestVertex
) pHdl
->Set1PixMore(TRUE
);
1733 } else if (nHdlNum
==1) {
1734 pHdl
=new ImpEdgeHdl((*pEdgeTrack
)[USHORT(nPntAnz
-1)],HDL_POLY
);
1735 if (aCon2
.pObj
!=NULL
&& aCon2
.bBestVertex
) pHdl
->Set1PixMore(TRUE
);
1737 SdrEdgeKind eKind
=((SdrEdgeKindItem
&)(GetObjectItem(SDRATTR_EDGEKIND
))).GetValue();
1738 if (eKind
==SDREDGE_ORTHOLINES
|| eKind
==SDREDGE_BEZIER
) {
1739 sal_uInt32
nO1(aEdgeInfo
.nObj1Lines
> 0L ? aEdgeInfo
.nObj1Lines
- 1L : 0L);
1740 sal_uInt32
nO2(aEdgeInfo
.nObj2Lines
> 0L ? aEdgeInfo
.nObj2Lines
- 1L : 0L);
1741 sal_uInt32
nM(aEdgeInfo
.nMiddleLine
!= 0xFFFF ? 1L : 0L);
1742 sal_uInt32
nNum(nHdlNum
- 2L);
1744 pHdl
=new ImpEdgeHdl(Point(),HDL_POLY
);
1747 if (nNum
==0) ((ImpEdgeHdl
*)pHdl
)->SetLineCode(OBJ1LINE2
);
1748 if (nNum
==1) ((ImpEdgeHdl
*)pHdl
)->SetLineCode(OBJ1LINE3
);
1753 if (nNum
==0) ((ImpEdgeHdl
*)pHdl
)->SetLineCode(OBJ2LINE2
);
1754 if (nNum
==1) ((ImpEdgeHdl
*)pHdl
)->SetLineCode(OBJ2LINE3
);
1758 nPt
=aEdgeInfo
.nMiddleLine
;
1759 ((ImpEdgeHdl
*)pHdl
)->SetLineCode(MIDDLELINE
);
1764 Point
aPos((*pEdgeTrack
)[(sal_uInt16
)nPt
]);
1765 aPos
+=(*pEdgeTrack
)[(sal_uInt16
)nPt
+1];
1773 } else if (eKind
==SDREDGE_THREELINES
) {
1774 sal_uInt32
nNum(nHdlNum
);
1775 if (GetConnectedNode(TRUE
)==NULL
) nNum
++;
1776 Point
aPos((*pEdgeTrack
)[(sal_uInt16
)nNum
-1]);
1777 pHdl
=new ImpEdgeHdl(aPos
,HDL_POLY
);
1778 if (nNum
==2) ((ImpEdgeHdl
*)pHdl
)->SetLineCode(OBJ1LINE2
);
1779 if (nNum
==3) ((ImpEdgeHdl
*)pHdl
)->SetLineCode(OBJ2LINE2
);
1783 pHdl
->SetPointNum(nHdlNum
);
1789 ////////////////////////////////////////////////////////////////////////////////////////////////////
1791 bool SdrEdgeObj::hasSpecialDrag() const
1796 SdrObject
* SdrEdgeObj::getFullDragClone() const
1798 // use Clone operator
1799 SdrEdgeObj
* pRetval
= (SdrEdgeObj
*)Clone();
1801 // copy connections for clone, SdrEdgeObj::operator= does not do this
1802 pRetval
->ConnectToNode(true, GetConnectedNode(true));
1803 pRetval
->ConnectToNode(false, GetConnectedNode(false));
1808 bool SdrEdgeObj::beginSpecialDrag(SdrDragStat
& rDrag
) const
1813 rDrag
.SetEndDragChangesAttributes(true);
1815 if(rDrag
.GetHdl()->GetPointNum() < 2)
1817 rDrag
.SetNoSnap(true);
1823 bool SdrEdgeObj::applySpecialDrag(SdrDragStat
& rDragStat
)
1825 SdrEdgeObj
* pOriginalEdge
= dynamic_cast< SdrEdgeObj
* >(rDragStat
.GetHdl()->GetObj());
1826 const bool bOriginalEdgeModified(pOriginalEdge
== this);
1828 if(!bOriginalEdgeModified
&& pOriginalEdge
)
1830 // copy connections when clone is modified. This is needed because
1831 // as preparation to this modification the data from the original object
1832 // was copied to the clone using the operator=. As can be seen there,
1833 // that operator does not copy the connections (for good reason)
1834 ConnectToNode(true, pOriginalEdge
->GetConnection(true).GetObject());
1835 ConnectToNode(false, pOriginalEdge
->GetConnection(false).GetObject());
1838 if(rDragStat
.GetHdl()->GetPointNum() < 2)
1840 // start or end point connector drag
1841 const bool bDragA(0 == rDragStat
.GetHdl()->GetPointNum());
1842 const Point
aPointNow(rDragStat
.GetNow());
1844 if(rDragStat
.GetPageView())
1846 SdrObjConnection
* pDraggedOne(bDragA
? &aCon1
: &aCon2
);
1849 DisconnectFromNode(bDragA
);
1851 // look for new connection
1852 ImpFindConnector(aPointNow
, *rDragStat
.GetPageView(), *pDraggedOne
, pOriginalEdge
);
1854 if(pDraggedOne
->pObj
)
1856 // if found, officially connect to it; ImpFindConnector only
1858 SdrObject
* pNewConnection
= pDraggedOne
->pObj
;
1859 pDraggedOne
->pObj
= 0;
1860 ConnectToNode(bDragA
, pNewConnection
);
1863 if(rDragStat
.GetView() && !bOriginalEdgeModified
)
1865 // show IA helper, but only do this during IA, so not when the original
1866 // Edge gets modified in the last call
1867 rDragStat
.GetView()->SetConnectMarker(*pDraggedOne
, *rDragStat
.GetPageView());
1873 // change pEdgeTrack to modified position
1876 (*pEdgeTrack
)[0] = aPointNow
;
1880 (*pEdgeTrack
)[sal_uInt16(pEdgeTrack
->GetPointCount()-1)] = aPointNow
;
1884 // reset edge info's offsets, this is a end point drag
1885 aEdgeInfo
.aObj1Line2
= Point();
1886 aEdgeInfo
.aObj1Line3
= Point();
1887 aEdgeInfo
.aObj2Line2
= Point();
1888 aEdgeInfo
.aObj2Line3
= Point();
1889 aEdgeInfo
.aMiddleLine
= Point();
1893 // control point connector drag
1894 const ImpEdgeHdl
* pEdgeHdl
= (ImpEdgeHdl
*)rDragStat
.GetHdl();
1895 const SdrEdgeLineCode eLineCode
= pEdgeHdl
->GetLineCode();
1896 const Point
aDist(rDragStat
.GetNow() - rDragStat
.GetStart());
1897 sal_Int32
nDist(pEdgeHdl
->IsHorzDrag() ? aDist
.X() : aDist
.Y());
1899 nDist
+= aEdgeInfo
.ImpGetLineVersatz(eLineCode
, *pEdgeTrack
);
1900 aEdgeInfo
.ImpSetLineVersatz(eLineCode
, *pEdgeTrack
, nDist
);
1903 // force recalc EdgeTrack
1904 *pEdgeTrack
= ImpCalcEdgeTrack(*pEdgeTrack
, aCon1
, aCon2
, &aEdgeInfo
);
1905 bEdgeTrackDirty
=FALSE
;
1907 // save EdgeInfos and mark object as user modified
1908 ImpSetEdgeInfoToAttr();
1909 bEdgeTrackUserDefined
= false;
1913 if(bOriginalEdgeModified
&& rDragStat
.GetView())
1915 // hide connect marker helper again when original gets changed.
1916 // This happens at the end of the interaction
1917 rDragStat
.GetView()->HideConnectMarker();
1923 String
SdrEdgeObj::getSpecialDragComment(const SdrDragStat
& rDrag
) const
1925 const bool bCreateComment(rDrag
.GetView() && this == rDrag
.GetView()->GetCreateObj());
1934 ImpTakeDescriptionStr(STR_DragEdgeTail
, aStr
);
1940 ////////////////////////////////////////////////////////////////////////////////////////////////////
1942 basegfx::B2DPolygon
SdrEdgeObj::ImplAddConnectorOverlay(SdrDragMethod
& rDragMethod
, bool bTail1
, bool bTail2
, bool bDetail
) const
1944 basegfx::B2DPolygon aResult
;
1948 SdrObjConnection
aMyCon1(aCon1
);
1949 SdrObjConnection
aMyCon2(aCon2
);
1953 const basegfx::B2DPoint
aTemp(rDragMethod
.getCurrentTransformation() * basegfx::B2DPoint(aMyCon1
.aObjOfs
.X(), aMyCon1
.aObjOfs
.Y()));
1954 aMyCon1
.aObjOfs
.X() = basegfx::fround(aTemp
.getX());
1955 aMyCon1
.aObjOfs
.Y() = basegfx::fround(aTemp
.getY());
1960 const basegfx::B2DPoint
aTemp(rDragMethod
.getCurrentTransformation() * basegfx::B2DPoint(aMyCon2
.aObjOfs
.X(), aMyCon2
.aObjOfs
.Y()));
1961 aMyCon2
.aObjOfs
.X() = basegfx::fround(aTemp
.getX());
1962 aMyCon2
.aObjOfs
.Y() = basegfx::fround(aTemp
.getY());
1965 SdrEdgeInfoRec
aInfo(aEdgeInfo
);
1966 XPolygon
aXP(ImpCalcEdgeTrack(*pEdgeTrack
, aMyCon1
, aMyCon2
, &aInfo
));
1968 if(aXP
.GetPointCount())
1970 aResult
= aXP
.getB2DPolygon();
1975 Point
aPt1((*pEdgeTrack
)[0]);
1976 Point
aPt2((*pEdgeTrack
)[sal_uInt16(pEdgeTrack
->GetPointCount() - 1)]);
1978 if (aCon1
.pObj
&& (aCon1
.bBestConn
|| aCon1
.bBestVertex
))
1979 aPt1
= aCon1
.pObj
->GetSnapRect().Center();
1981 if (aCon2
.pObj
&& (aCon2
.bBestConn
|| aCon2
.bBestVertex
))
1982 aPt2
= aCon2
.pObj
->GetSnapRect().Center();
1986 const basegfx::B2DPoint
aTemp(rDragMethod
.getCurrentTransformation() * basegfx::B2DPoint(aPt1
.X(), aPt1
.Y()));
1987 aPt1
.X() = basegfx::fround(aTemp
.getX());
1988 aPt1
.Y() = basegfx::fround(aTemp
.getY());
1993 const basegfx::B2DPoint
aTemp(rDragMethod
.getCurrentTransformation() * basegfx::B2DPoint(aPt2
.X(), aPt2
.Y()));
1994 aPt2
.X() = basegfx::fround(aTemp
.getX());
1995 aPt2
.Y() = basegfx::fround(aTemp
.getY());
1998 aResult
.append(basegfx::B2DPoint(aPt1
.X(), aPt1
.Y()));
1999 aResult
.append(basegfx::B2DPoint(aPt2
.X(), aPt2
.Y()));
2005 FASTBOOL
SdrEdgeObj::BegCreate(SdrDragStat
& rDragStat
)
2007 rDragStat
.SetNoSnap(TRUE
);
2008 pEdgeTrack
->SetPointCount(2);
2009 (*pEdgeTrack
)[0]=rDragStat
.GetStart();
2010 (*pEdgeTrack
)[1]=rDragStat
.GetNow();
2011 if (rDragStat
.GetPageView()!=NULL
) {
2012 ImpFindConnector(rDragStat
.GetStart(),*rDragStat
.GetPageView(),aCon1
,this);
2013 ConnectToNode(TRUE
,aCon1
.pObj
);
2015 *pEdgeTrack
=ImpCalcEdgeTrack(*pEdgeTrack
,aCon1
,aCon2
,&aEdgeInfo
);
2019 FASTBOOL
SdrEdgeObj::MovCreate(SdrDragStat
& rDragStat
)
2021 USHORT nMax
=pEdgeTrack
->GetPointCount();
2022 (*pEdgeTrack
)[nMax
-1]=rDragStat
.GetNow();
2023 if (rDragStat
.GetPageView()!=NULL
) {
2024 ImpFindConnector(rDragStat
.GetNow(),*rDragStat
.GetPageView(),aCon2
,this);
2025 rDragStat
.GetView()->SetConnectMarker(aCon2
,*rDragStat
.GetPageView());
2027 SetBoundRectDirty();
2028 bSnapRectDirty
=TRUE
;
2029 ConnectToNode(FALSE
,aCon2
.pObj
);
2030 *pEdgeTrack
=ImpCalcEdgeTrack(*pEdgeTrack
,aCon1
,aCon2
,&aEdgeInfo
);
2031 bEdgeTrackDirty
=FALSE
;
2035 FASTBOOL
SdrEdgeObj::EndCreate(SdrDragStat
& rDragStat
, SdrCreateCmd eCmd
)
2037 FASTBOOL bOk
=(eCmd
==SDRCREATE_FORCEEND
|| rDragStat
.GetPointAnz()>=2);
2039 ConnectToNode(TRUE
,aCon1
.pObj
);
2040 ConnectToNode(FALSE
,aCon2
.pObj
);
2041 if (rDragStat
.GetView()!=NULL
) {
2042 rDragStat
.GetView()->HideConnectMarker();
2044 ImpSetEdgeInfoToAttr(); // Die Werte aus aEdgeInfo in den Pool kopieren
2050 FASTBOOL
SdrEdgeObj::BckCreate(SdrDragStat
& rDragStat
)
2052 if (rDragStat
.GetView()!=NULL
) {
2053 rDragStat
.GetView()->HideConnectMarker();
2058 void SdrEdgeObj::BrkCreate(SdrDragStat
& rDragStat
)
2060 if (rDragStat
.GetView()!=NULL
) {
2061 rDragStat
.GetView()->HideConnectMarker();
2065 basegfx::B2DPolyPolygon
SdrEdgeObj::TakeCreatePoly(const SdrDragStat
& /*rStatDrag*/) const
2067 basegfx::B2DPolyPolygon aRetval
;
2068 aRetval
.append(pEdgeTrack
->getB2DPolygon());
2072 Pointer
SdrEdgeObj::GetCreatePointer() const
2074 return Pointer(POINTER_DRAW_CONNECT
);
2077 FASTBOOL
SdrEdgeObj::ImpFindConnector(const Point
& rPt
, const SdrPageView
& rPV
, SdrObjConnection
& rCon
, const SdrEdgeObj
* pThis
, OutputDevice
* pOut
)
2080 if (pOut
==NULL
) pOut
=rPV
.GetView().GetFirstOutputDevice(); // GetWin(0);
2081 if (pOut
==NULL
) return FALSE
;
2082 SdrObjList
* pOL
=rPV
.GetObjList();
2083 const SetOfByte
& rVisLayer
=rPV
.GetVisibleLayers();
2084 // Sensitiver Bereich der Konnektoren ist doppelt so gross wie die Handles:
2085 USHORT nMarkHdSiz
=rPV
.GetView().GetMarkHdlSizePixel();
2086 Size
aHalfConSiz(nMarkHdSiz
,nMarkHdSiz
);
2087 aHalfConSiz
=pOut
->PixelToLogic(aHalfConSiz
);
2088 Size
aHalfCenterSiz(2*aHalfConSiz
.Width(),2*aHalfConSiz
.Height());
2089 Rectangle
aMouseRect(rPt
,rPt
);
2090 aMouseRect
.Left() -=aHalfConSiz
.Width();
2091 aMouseRect
.Top() -=aHalfConSiz
.Height();
2092 aMouseRect
.Right() +=aHalfConSiz
.Width();
2093 aMouseRect
.Bottom()+=aHalfConSiz
.Height();
2094 USHORT nBoundHitTol
=(USHORT
)aHalfConSiz
.Width()/2; if (nBoundHitTol
==0) nBoundHitTol
=1;
2095 ULONG no
=pOL
->GetObjCount();
2096 FASTBOOL bFnd
=FALSE
;
2097 SdrObjConnection aTestCon
;
2098 SdrObjConnection aBestCon
;
2099 FASTBOOL bTestBoundHit
=FALSE
;
2100 //FASTBOOL bBestBoundHit=FALSE;
2102 while (no
>0 && !bFnd
) {
2103 // Problem: Gruppenobjekt mit verschiedenen Layern liefert LayerID 0 !!!!
2105 SdrObject
* pObj
=pOL
->GetObj(no
);
2106 if (rVisLayer
.IsSet(pObj
->GetLayer()) && // nur sichtbare Objekte
2107 (pThis
==NULL
|| pObj
!=(SdrObject
*)pThis
) && // nicht an mich selbst connecten
2110 Rectangle
aObjBound(pObj
->GetCurrentBoundRect());
2111 if (aObjBound
.IsOver(aMouseRect
)) {
2112 aTestCon
.ResetVars();
2113 bTestBoundHit
=FALSE
;
2114 FASTBOOL bEdge
=HAS_BASE(SdrEdgeObj
,pObj
); // kein BestCon fuer Edge
2115 // Die Userdefined Konnektoren haben absolute Prioritaet.
2116 // Danach kommt Vertex, Corner und Mitte(Best) gleich priorisiert.
2117 // Zum Schluss kommt noch ein HitTest aufs Obj.
2118 const SdrGluePointList
* pGPL
=pObj
->GetGluePointList();
2119 USHORT nConAnz
=pGPL
==NULL
? 0 : pGPL
->GetCount();
2120 USHORT nGesAnz
=nConAnz
+9;
2121 FASTBOOL bUserFnd
=FALSE
;
2122 ULONG nBestDist
=0xFFFFFFFF;
2123 for (USHORT i
=0; i
<nGesAnz
; i
++)
2125 FASTBOOL bUser
=i
<nConAnz
;
2126 FASTBOOL bVertex
=i
>=nConAnz
+0 && i
<nConAnz
+4;
2127 FASTBOOL bCorner
=i
>=nConAnz
+4 && i
<nConAnz
+8;
2128 FASTBOOL bCenter
=i
==nConAnz
+8;
2133 const SdrGluePoint
& rGP
=(*pGPL
)[nConNum
];
2134 aConPos
=rGP
.GetAbsolutePos(*pObj
);
2135 nConNum
=rGP
.GetId();
2137 } else if (bVertex
&& !bUserFnd
) {
2138 nConNum
=nConNum
-nConAnz
;
2139 if (rPV
.GetView().IsAutoVertexConnectors()) {
2140 SdrGluePoint
aPt(pObj
->GetVertexGluePoint(nConNum
));
2141 aConPos
=aPt
.GetAbsolutePos(*pObj
);
2144 } else if (bCorner
&& !bUserFnd
) {
2146 if (rPV
.GetView().IsAutoCornerConnectors()) {
2147 SdrGluePoint
aPt(pObj
->GetCornerGluePoint(nConNum
));
2148 aConPos
=aPt
.GetAbsolutePos(*pObj
);
2152 else if (bCenter
&& !bUserFnd
&& !bEdge
)
2155 // Suppress default connect at object center
2156 if(!pThis
|| !pThis
->GetSuppressDefaultConnect())
2160 aConPos
=aObjBound
.Center();
2164 if (bOk
&& aMouseRect
.IsInside(aConPos
)) {
2165 if (bUser
) bUserFnd
=TRUE
;
2167 ULONG nDist
=(ULONG
)Abs(aConPos
.X()-rPt
.X())+(ULONG
)Abs(aConPos
.Y()-rPt
.Y());
2168 if (nDist
<nBestDist
) {
2171 aTestCon
.nConId
=nConNum
;
2172 aTestCon
.bAutoCorner
=bCorner
;
2173 aTestCon
.bAutoVertex
=bVertex
;
2174 aTestCon
.bBestConn
=FALSE
; // bCenter;
2175 aTestCon
.bBestVertex
=bCenter
;
2179 // Falls kein Konnektor getroffen wird nochmal
2180 // HitTest versucht fuer BestConnector (=bCenter)
2183 SdrObjectPrimitiveHit(*pObj
, rPt
, nBoundHitTol
, rPV
, &rVisLayer
, false))
2186 // Suppress default connect at object inside bound
2187 if(!pThis
|| !pThis
->GetSuppressDefaultConnect())
2191 aTestCon
.bBestConn
=TRUE
;
2195 Rectangle
aMouseRect2(rPt
,rPt
);
2196 aMouseRect
.Left() -=nBoundHitTol
;
2197 aMouseRect
.Top() -=nBoundHitTol
;
2198 aMouseRect
.Right() +=nBoundHitTol
;
2199 aMouseRect
.Bottom()+=nBoundHitTol
;
2200 bTestBoundHit
=aObjBound
.IsOver(aMouseRect2
);
2210 void SdrEdgeObj::NbcSetSnapRect(const Rectangle
& rRect
)
2212 Rectangle
aOld(GetSnapRect());
2213 long nMulX
= rRect
.Right() - rRect
.Left();
2214 long nDivX
= aOld
.Right() - aOld
.Left();
2215 long nMulY
= rRect
.Bottom() - rRect
.Top();
2216 long nDivY
= aOld
.Bottom() - aOld
.Top();
2217 if ( nDivX
== 0 ) { nMulX
= 1; nDivX
= 1; }
2218 if ( nDivY
== 0 ) { nMulY
= 1; nDivY
= 1; }
2219 Fraction
aX(nMulX
, nDivX
);
2220 Fraction
aY(nMulY
, nDivY
);
2221 NbcResize(aOld
.TopLeft(), aX
, aY
);
2222 NbcMove(Size(rRect
.Left() - aOld
.Left(), rRect
.Top() - aOld
.Top()));
2225 void SdrEdgeObj::NbcMove(const Size
& rSiz
)
2227 SdrTextObj::NbcMove(rSiz
);
2228 MoveXPoly(*pEdgeTrack
,rSiz
);
2231 void SdrEdgeObj::NbcResize(const Point
& rRefPnt
, const Fraction
& aXFact
, const Fraction
& aYFact
)
2233 SdrTextObj::NbcResize(rRefPnt
,aXFact
,aXFact
);
2234 ResizeXPoly(*pEdgeTrack
,rRefPnt
,aXFact
,aYFact
);
2236 // #75371# if resize is not from paste, forget user distances
2237 if(!GetModel()->IsPasteResize())
2240 aEdgeInfo
.aObj1Line2
= Point();
2241 aEdgeInfo
.aObj1Line3
= Point();
2242 aEdgeInfo
.aObj2Line2
= Point();
2243 aEdgeInfo
.aObj2Line3
= Point();
2244 aEdgeInfo
.aMiddleLine
= Point();
2248 SdrObject
* SdrEdgeObj::DoConvertToPolyObj(BOOL bBezier
) const
2250 basegfx::B2DPolyPolygon aPolyPolygon
;
2251 aPolyPolygon
.append(pEdgeTrack
->getB2DPolygon());
2252 SdrObject
* pRet
= ImpConvertMakeObj(aPolyPolygon
, sal_False
, bBezier
);
2253 pRet
= ImpConvertAddText(pRet
, bBezier
);
2258 sal_uInt32
SdrEdgeObj::GetSnapPointCount() const
2263 Point
SdrEdgeObj::GetSnapPoint(sal_uInt32 i
) const
2265 ((SdrEdgeObj
*)this)->ImpUndirtyEdgeTrack();
2266 USHORT nAnz
=pEdgeTrack
->GetPointCount();
2267 if (i
==0) return (*pEdgeTrack
)[0];
2268 else return (*pEdgeTrack
)[nAnz
-1];
2271 sal_Bool
SdrEdgeObj::IsPolyObj() const
2276 sal_uInt32
SdrEdgeObj::GetPointCount() const
2281 Point
SdrEdgeObj::GetPoint(sal_uInt32 i
) const
2283 ((SdrEdgeObj
*)this)->ImpUndirtyEdgeTrack();
2284 USHORT nAnz
=pEdgeTrack
->GetPointCount();
2286 return (*pEdgeTrack
)[0];
2288 return (*pEdgeTrack
)[nAnz
-1];
2291 void SdrEdgeObj::NbcSetPoint(const Point
& rPnt
, sal_uInt32 i
)
2293 // ToDo: Umconnekten fehlt noch
2294 ImpUndirtyEdgeTrack();
2295 USHORT nAnz
=pEdgeTrack
->GetPointCount();
2297 (*pEdgeTrack
)[0]=rPnt
;
2299 (*pEdgeTrack
)[nAnz
-1]=rPnt
;
2300 SetEdgeTrackDirty();
2304 SdrEdgeObjGeoData::SdrEdgeObjGeoData()
2306 pEdgeTrack
=new XPolygon
;
2309 SdrEdgeObjGeoData::~SdrEdgeObjGeoData()
2314 SdrObjGeoData
* SdrEdgeObj::NewGeoData() const
2316 return new SdrEdgeObjGeoData
;
2319 void SdrEdgeObj::SaveGeoData(SdrObjGeoData
& rGeo
) const
2321 SdrTextObj::SaveGeoData(rGeo
);
2322 SdrEdgeObjGeoData
& rEGeo
=(SdrEdgeObjGeoData
&)rGeo
;
2325 *rEGeo
.pEdgeTrack
=*pEdgeTrack
;
2326 rEGeo
.bEdgeTrackDirty
=bEdgeTrackDirty
;
2327 rEGeo
.bEdgeTrackUserDefined
=bEdgeTrackUserDefined
;
2328 rEGeo
.aEdgeInfo
=aEdgeInfo
;
2331 void SdrEdgeObj::RestGeoData(const SdrObjGeoData
& rGeo
)
2333 SdrTextObj::RestGeoData(rGeo
);
2334 SdrEdgeObjGeoData
& rEGeo
=(SdrEdgeObjGeoData
&)rGeo
;
2335 if (aCon1
.pObj
!=rEGeo
.aCon1
.pObj
) {
2336 if (aCon1
.pObj
!=NULL
) aCon1
.pObj
->RemoveListener(*this);
2338 if (aCon1
.pObj
!=NULL
) aCon1
.pObj
->AddListener(*this);
2340 if (aCon2
.pObj
!=rEGeo
.aCon2
.pObj
) {
2341 if (aCon2
.pObj
!=NULL
) aCon2
.pObj
->RemoveListener(*this);
2343 if (aCon2
.pObj
!=NULL
) aCon2
.pObj
->AddListener(*this);
2345 *pEdgeTrack
=*rEGeo
.pEdgeTrack
;
2346 bEdgeTrackDirty
=rEGeo
.bEdgeTrackDirty
;
2347 bEdgeTrackUserDefined
=rEGeo
.bEdgeTrackUserDefined
;
2348 aEdgeInfo
=rEGeo
.aEdgeInfo
;
2351 Point
SdrEdgeObj::GetTailPoint( BOOL bTail
) const
2353 if( pEdgeTrack
&& pEdgeTrack
->GetPointCount()!=0)
2355 const XPolygon
& rTrack0
= *pEdgeTrack
;
2362 const USHORT nSiz
= rTrack0
.GetPointCount() - 1;
2363 return rTrack0
[nSiz
];
2369 return aOutRect
.TopLeft();
2371 return aOutRect
.BottomRight();
2376 void SdrEdgeObj::SetTailPoint( BOOL bTail
, const Point
& rPt
)
2378 ImpSetTailPoint( bTail
, rPt
);
2382 /** this method is used by the api to set a glue point for a connection
2383 nId == -1 : The best default point is automaticly choosen
2384 0 <= nId <= 3 : One of the default points is choosen
2385 nId >= 4 : A user defined glue point is choosen
2387 void SdrEdgeObj::setGluePointIndex( sal_Bool bTail
, sal_Int32 nIndex
/* = -1 */ )
2389 Rectangle aBoundRect0
; if (pUserCall
!=NULL
) aBoundRect0
=GetCurrentBoundRect();
2390 // #110094#-14 BroadcastObjectChange();
2392 SdrObjConnection
& rConn1
= GetConnection( bTail
);
2394 rConn1
.SetAutoVertex( nIndex
>= 0 && nIndex
<= 3 );
2395 rConn1
.SetBestConnection( nIndex
< 0 );
2396 rConn1
.SetBestVertex( nIndex
< 0 );
2401 nIndex
-= 3; // SJ: the start api index is 0, whereas the implementation in svx starts from 1
2403 // for user defined glue points we have
2404 // to get the id for this index first
2405 const SdrGluePointList
* pList
= rConn1
.GetObject() ? rConn1
.GetObject()->GetGluePointList() : NULL
;
2406 if( pList
== NULL
|| SDRGLUEPOINT_NOTFOUND
== pList
->FindGluePoint((sal_uInt16
)nIndex
) )
2409 else if( nIndex
< 0 )
2414 rConn1
.SetConnectorId( (USHORT
)nIndex
);
2418 ImpRecalcEdgeTrack();
2419 // bEdgeTrackDirty=TRUE;
2422 /** this method is used by the api to return a glue point id for a connection.
2423 See setGluePointId for possible return values */
2424 sal_Int32
SdrEdgeObj::getGluePointIndex( sal_Bool bTail
)
2426 SdrObjConnection
& rConn1
= GetConnection( bTail
);
2428 if( !rConn1
.IsBestConnection() )
2430 nId
= rConn1
.GetConnectorId();
2431 if( !rConn1
.IsAutoVertex() )
2433 nId
+= 3; // SJ: the start api index is 0, whereas the implementation in svx starts from 1
2438 // #102344# Implementation was missing; edge track needs to be invalidated additionally.
2439 void SdrEdgeObj::NbcSetAnchorPos(const Point
& rPnt
)
2441 // call parent functionality
2442 SdrTextObj::NbcSetAnchorPos(rPnt
);
2444 // Additionally, invalidate edge track
2445 ImpDirtyEdgeTrack();
2448 sal_Bool
SdrEdgeObj::TRGetBaseGeometry(basegfx::B2DHomMatrix
& rMatrix
, basegfx::B2DPolyPolygon
& rPolyPolygon
) const
2450 // use base method from SdrObject, it's not rotatable and
2451 // a call to GetSnapRect() is used. That's what we need for Connector.
2452 return SdrObject::TRGetBaseGeometry(rMatrix
, rPolyPolygon
);
2455 void SdrEdgeObj::TRSetBaseGeometry(const basegfx::B2DHomMatrix
& rMatrix
, const basegfx::B2DPolyPolygon
& rPolyPolygon
)
2457 // evtl. take care for existing connections. For now, just use the
2458 // implementation from SdrObject.
2459 SdrObject::TRSetBaseGeometry(rMatrix
, rPolyPolygon
);
2462 // for geometry access
2463 ::basegfx::B2DPolygon
SdrEdgeObj::getEdgeTrack() const
2467 const_cast< SdrEdgeObj
* >(this)->ImpRecalcEdgeTrack();
2472 return pEdgeTrack
->getB2DPolygon();
2476 return ::basegfx::B2DPolygon();
2480 //////////////////////////////////////////////////////////////////////////////